aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/acpi_memhotplug.c34
-rw-r--r--drivers/acpi/acpica/acobject.h1
-rw-r--r--drivers/acpi/acpica/dsopcode.c24
-rw-r--r--drivers/acpi/acpica/exfldio.c6
-rw-r--r--drivers/acpi/osl.c25
-rw-r--r--drivers/acpi/system.c2
-rw-r--r--drivers/char/agp/parisc-agp.c2
-rw-r--r--drivers/char/tty_ldisc.c152
-rw-r--r--drivers/cpufreq/cpufreq.c27
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c6
-rw-r--r--drivers/edac/amd64_edac.c7
-rw-r--r--drivers/gpu/drm/drm_crtc.c2
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c6
-rw-r--r--drivers/gpu/drm/drm_irq.c2
-rw-r--r--drivers/gpu/drm/drm_modes.c2
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c15
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h4
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c4
-rw-r--r--drivers/gpu/drm/i915/i915_gem_debugfs.c2
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c239
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h45
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c2
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c40
-rw-r--r--drivers/gpu/drm/i915/intel_bios.h45
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c12
-rw-r--r--drivers/gpu/drm/i915/intel_display.c759
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c216
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h3
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c64
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c12
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c254
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c22
-rw-r--r--drivers/gpu/drm/radeon/r100.c3
-rw-r--r--drivers/gpu/drm/radeon/r600_cp.c22
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c17
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.h1
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c2
-rw-r--r--drivers/gpu/drm/radeon/rv515.c1
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c7
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c8
-rw-r--r--drivers/input/keyboard/matrix_keypad.c18
-rw-r--r--drivers/input/misc/wistron_btns.c16
-rw-r--r--drivers/input/serio/hp_sdc_mlc.c2
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h8
-rw-r--r--drivers/isdn/mISDN/l1oip_core.c2
-rw-r--r--drivers/md/linear.c2
-rw-r--r--drivers/md/md.c144
-rw-r--r--drivers/md/md.h2
-rw-r--r--drivers/md/multipath.c5
-rw-r--r--drivers/md/raid0.c1
-rw-r--r--drivers/md/raid1.c7
-rw-r--r--drivers/md/raid10.c4
-rw-r--r--drivers/md/raid5.c51
-rw-r--r--drivers/mfd/twl4030-irq.c55
-rw-r--r--drivers/mmc/host/sdhci-of.c2
-rw-r--r--drivers/mtd/maps/Kconfig7
-rw-r--r--drivers/mtd/maps/Makefile1
-rw-r--r--drivers/mtd/maps/sbc8240.c250
-rw-r--r--drivers/mtd/mtd_blkdevs.c6
-rw-r--r--drivers/mtd/mtdblock.c16
-rw-r--r--drivers/mtd/mtdcore.c7
-rw-r--r--drivers/mtd/onenand/omap2.c3
-rw-r--r--drivers/mtd/ubi/eba.c1
-rw-r--r--drivers/mtd/ubi/scan.c13
-rw-r--r--drivers/net/3c515.c4
-rw-r--r--drivers/net/3c59x.c10
-rw-r--r--drivers/net/eexpress.c6
-rw-r--r--drivers/net/ehea/ehea.h2
-rw-r--r--drivers/net/ehea/ehea_main.c3
-rw-r--r--drivers/net/gianfar_ethtool.c10
-rw-r--r--drivers/net/igbvf/vf.c4
-rw-r--r--drivers/net/ixgbe/ixgbe.h2
-rw-r--r--drivers/net/ixgbe/ixgbe_82598.c67
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c11
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c25
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h8
-rw-r--r--drivers/net/mlx4/en_tx.c1
-rw-r--r--drivers/net/netxen/netxen_nic_main.c37
-rw-r--r--drivers/net/pcnet32.c30
-rw-r--r--drivers/net/ppp_generic.c34
-rw-r--r--drivers/net/pppoe.c1
-rw-r--r--drivers/net/pppol2tp.c1
-rw-r--r--drivers/net/s6gmac.c2
-rw-r--r--drivers/net/sky2.c14
-rw-r--r--drivers/net/sky2.h1
-rw-r--r--drivers/net/tulip/de4x5.c6
-rw-r--r--drivers/net/wireless/airo.c13
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c7
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c1
-rw-r--r--drivers/net/wireless/iwmc3200wifi/netdev.c6
-rw-r--r--drivers/net/wireless/libertas/11d.c2
-rw-r--r--drivers/net/wireless/libertas/assoc.c18
-rw-r--r--drivers/net/wireless/libertas/scan.c3
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c2
-rw-r--r--drivers/parisc/ccio-dma.c1
-rw-r--r--drivers/parisc/dino.c2
-rw-r--r--drivers/parisc/eisa_eeprom.c2
-rw-r--r--drivers/parisc/hppb.c9
-rw-r--r--drivers/parisc/lba_pci.c2
-rw-r--r--drivers/parisc/pdc_stable.c2
-rw-r--r--drivers/pci/intel-iommu.c25
-rw-r--r--drivers/pci/setup-res.c4
-rw-r--r--drivers/platform/x86/Kconfig25
-rw-r--r--drivers/platform/x86/eeepc-laptop.c9
-rw-r--r--drivers/platform/x86/hp-wmi.c12
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c390
-rw-r--r--drivers/s390/scsi/zfcp_erp.c68
-rw-r--r--drivers/s390/scsi/zfcp_fc.c8
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c56
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c25
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c7
-rw-r--r--drivers/scsi/libfc/fc_exch.c23
-rw-r--r--drivers/scsi/libiscsi.c4
-rw-r--r--drivers/scsi/libsas/sas_expander.c147
-rw-r--r--drivers/scsi/libsas/sas_port.c19
-rw-r--r--drivers/scsi/qla4xxx/ql4_dbg.c15
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h9
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h7
-rw-r--r--drivers/scsi/qla4xxx/ql4_iocb.c133
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c145
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c10
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c40
-rw-r--r--drivers/scsi/qla4xxx/ql4_version.h2
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c4
-rw-r--r--drivers/scsi/sd.c20
-rw-r--r--drivers/serial/s3c2400.c8
-rw-r--r--drivers/serial/s3c2410.c8
-rw-r--r--drivers/serial/s3c2412.c8
-rw-r--r--drivers/serial/s3c2440.c8
-rw-r--r--drivers/serial/s3c24a0.c8
-rw-r--r--drivers/serial/s3c6400.c8
-rw-r--r--drivers/serial/serial_ks8695.c2
-rw-r--r--drivers/staging/b3dfg/Kconfig1
-rw-r--r--drivers/staging/heci/Kconfig1
-rw-r--r--drivers/staging/rspiusb/rspiusb.c2
-rw-r--r--drivers/staging/rt2860/rt_linux.h13
-rw-r--r--drivers/staging/rt2870/2870_main_dev.c67
-rw-r--r--drivers/staging/rt2870/common/2870_rtmp_init.c33
-rw-r--r--drivers/staging/rt2870/common/rtusb_io.c3
-rw-r--r--drivers/staging/rt2870/rt2870.h9
-rw-r--r--drivers/staging/rtl8192su/ieee80211.h2
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211.h2
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c3
-rw-r--r--drivers/staging/rtl8192su/r8192U_core.c2
-rw-r--r--drivers/usb/class/cdc-acm.c10
-rw-r--r--drivers/usb/class/cdc-acm.h2
-rw-r--r--drivers/usb/core/devio.c10
-rw-r--r--drivers/usb/host/ehci-hcd.c3
-rw-r--r--drivers/usb/host/ehci-q.c15
-rw-r--r--drivers/usb/host/ehci-sched.c1
-rw-r--r--drivers/usb/musb/Kconfig1
-rw-r--r--drivers/usb/serial/ftdi_sio.c3
-rw-r--r--drivers/usb/serial/ftdi_sio.h14
-rw-r--r--drivers/usb/serial/pl2303.c1
-rw-r--r--drivers/usb/serial/pl2303.h4
-rw-r--r--drivers/usb/storage/unusual_devs.h7
-rw-r--r--drivers/video/console/fbcon.c6
-rw-r--r--drivers/video/console/fbcon_rotate.h2
-rw-r--r--drivers/video/console/sticore.c9
-rw-r--r--drivers/video/mx3fb.c86
-rw-r--r--drivers/video/via/hw.c4
-rw-r--r--drivers/video/via/lcd.c15
-rw-r--r--drivers/video/via/viafbdev.c101
-rw-r--r--drivers/video/via/viafbdev.h3
-rw-r--r--drivers/w1/masters/omap_hdq.c1
-rw-r--r--drivers/watchdog/coh901327_wdt.c11
-rw-r--r--drivers/watchdog/ks8695_wdt.c4
176 files changed, 2785 insertions, 2051 deletions
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 7a0f4aa4fa1..9a62224cc27 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -38,6 +38,9 @@
#define _COMPONENT ACPI_MEMORY_DEVICE_COMPONENT
+#undef PREFIX
+#define PREFIX "ACPI:memory_hp:"
+
ACPI_MODULE_NAME("acpi_memhotplug");
MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
MODULE_DESCRIPTION("Hotplug Mem Driver");
@@ -153,6 +156,7 @@ acpi_memory_get_device(acpi_handle handle,
acpi_handle phandle;
struct acpi_device *device = NULL;
struct acpi_device *pdevice = NULL;
+ int result;
if (!acpi_bus_get_device(handle, &device) && device)
@@ -165,9 +169,9 @@ acpi_memory_get_device(acpi_handle handle,
}
/* Get the parent device */
- status = acpi_bus_get_device(phandle, &pdevice);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Cannot get acpi bus device"));
+ result = acpi_bus_get_device(phandle, &pdevice);
+ if (result) {
+ printk(KERN_WARNING PREFIX "Cannot get acpi bus device");
return -EINVAL;
}
@@ -175,9 +179,9 @@ acpi_memory_get_device(acpi_handle handle,
* Now add the notified device. This creates the acpi_device
* and invokes .add function
*/
- status = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Cannot add acpi bus"));
+ result = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
+ if (result) {
+ printk(KERN_WARNING PREFIX "Cannot add acpi bus");
return -EINVAL;
}
@@ -238,7 +242,12 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
num_enabled++;
continue;
}
-
+ /*
+ * If the memory block size is zero, please ignore it.
+ * Don't try to do the following memory hotplug flowchart.
+ */
+ if (!info->length)
+ continue;
if (node < 0)
node = memory_add_physaddr_to_nid(info->start_addr);
@@ -253,8 +262,15 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
mem_device->state = MEMORY_INVALID_STATE;
return -EINVAL;
}
-
- return result;
+ /*
+ * Sometimes the memory device will contain several memory blocks.
+ * When one memory block is hot-added to the system memory, it will
+ * be regarded as a success.
+ * Otherwise if the last memory block can't be hot-added to the system
+ * memory, it will be failure and the memory device can't be bound with
+ * driver.
+ */
+ return 0;
}
static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index 544dcf83492..eb6f038b03d 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -97,6 +97,7 @@
#define AOPOBJ_OBJECT_INITIALIZED 0x08
#define AOPOBJ_SETUP_COMPLETE 0x10
#define AOPOBJ_SINGLE_DATUM 0x20
+#define AOPOBJ_INVALID 0x40 /* Used if host OS won't allow an op_region address */
/******************************************************************************
*
diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c
index 584d766e6f1..b79978f7bc7 100644
--- a/drivers/acpi/acpica/dsopcode.c
+++ b/drivers/acpi/acpica/dsopcode.c
@@ -397,6 +397,30 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
extra_desc->extra.aml_length,
extra_desc->extra.aml_start);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Validate the region address/length via the host OS */
+
+ status = acpi_os_validate_address(obj_desc->region.space_id,
+ obj_desc->region.address,
+ (acpi_size) obj_desc->region.length,
+ acpi_ut_get_node_name(node));
+
+ if (ACPI_FAILURE(status)) {
+ /*
+ * Invalid address/length. We will emit an error message and mark
+ * the region as invalid, so that it will cause an additional error if
+ * it is ever used. Then return AE_OK.
+ */
+ ACPI_EXCEPTION((AE_INFO, status,
+ "During address validation of OpRegion [%4.4s]",
+ node->name.ascii));
+ obj_desc->common.flags |= AOPOBJ_INVALID;
+ status = AE_OK;
+ }
+
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c
index d4075b82102..6687be167f5 100644
--- a/drivers/acpi/acpica/exfldio.c
+++ b/drivers/acpi/acpica/exfldio.c
@@ -113,6 +113,12 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
}
}
+ /* Exit if Address/Length have been disallowed by the host OS */
+
+ if (rgn_desc->common.flags & AOPOBJ_INVALID) {
+ return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS);
+ }
+
/*
* Exit now for SMBus address space, it has a non-linear address space
* and the request cannot be directly validated
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 71670719d61..5691f165a95 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -189,11 +189,36 @@ acpi_status __init acpi_os_initialize(void)
return AE_OK;
}
+static void bind_to_cpu0(struct work_struct *work)
+{
+ set_cpus_allowed(current, cpumask_of_cpu(0));
+ kfree(work);
+}
+
+static void bind_workqueue(struct workqueue_struct *wq)
+{
+ struct work_struct *work;
+
+ work = kzalloc(sizeof(struct work_struct), GFP_KERNEL);
+ INIT_WORK(work, bind_to_cpu0);
+ queue_work(wq, work);
+}
+
acpi_status acpi_os_initialize1(void)
{
+ /*
+ * On some machines, a software-initiated SMI causes corruption unless
+ * the SMI runs on CPU 0. An SMI can be initiated by any AML, but
+ * typically it's done in GPE-related methods that are run via
+ * workqueues, so we can avoid the known corruption cases by binding
+ * the workqueues to CPU 0.
+ */
kacpid_wq = create_singlethread_workqueue("kacpid");
+ bind_workqueue(kacpid_wq);
kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify");
+ bind_workqueue(kacpi_notify_wq);
kacpi_hotplug_wq = create_singlethread_workqueue("kacpi_hotplug");
+ bind_workqueue(kacpi_hotplug_wq);
BUG_ON(!kacpid_wq);
BUG_ON(!kacpi_notify_wq);
BUG_ON(!kacpi_hotplug_wq);
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 0944daec064..9c61ab2177c 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -121,7 +121,7 @@ static void acpi_table_attr_init(struct acpi_table_attr *table_attr,
table_attr->attr.size = 0;
table_attr->attr.read = acpi_table_show;
table_attr->attr.attr.name = table_attr->name;
- table_attr->attr.attr.mode = 0444;
+ table_attr->attr.attr.mode = 0400;
return;
}
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index f4bb43fb801..e077701ae3d 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -225,7 +225,7 @@ static const struct agp_bridge_driver parisc_agp_driver = {
.configure = parisc_agp_configure,
.fetch_size = parisc_agp_fetch_size,
.tlb_flush = parisc_agp_tlbflush,
- .mask_memory = parisc_agp_mask_memory,
+ .mask_memory = parisc_agp_page_mask_memory,
.masks = parisc_agp_masks,
.agp_enable = parisc_agp_enable,
.cache_flush = global_cache_flush,
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index acd76b767d4..1733d3439ad 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -48,6 +48,41 @@ static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
/* Line disc dispatch table */
static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
+static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld)
+{
+ if (ld)
+ atomic_inc(&ld->users);
+ return ld;
+}
+
+static void put_ldisc(struct tty_ldisc *ld)
+{
+ unsigned long flags;
+
+ if (WARN_ON_ONCE(!ld))
+ return;
+
+ /*
+ * If this is the last user, free the ldisc, and
+ * release the ldisc ops.
+ *
+ * We really want an "atomic_dec_and_lock_irqsave()",
+ * but we don't have it, so this does it by hand.
+ */
+ local_irq_save(flags);
+ if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) {
+ struct tty_ldisc_ops *ldo = ld->ops;
+
+ ldo->refcount--;
+ module_put(ldo->owner);
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+ kfree(ld);
+ return;
+ }
+ local_irq_restore(flags);
+}
+
/**
* tty_register_ldisc - install a line discipline
* @disc: ldisc number
@@ -142,7 +177,7 @@ static struct tty_ldisc *tty_ldisc_try_get(int disc)
/* lock it */
ldops->refcount++;
ld->ops = ldops;
- ld->refcount = 0;
+ atomic_set(&ld->users, 1);
err = 0;
}
}
@@ -181,35 +216,6 @@ static struct tty_ldisc *tty_ldisc_get(int disc)
return ld;
}
-/**
- * tty_ldisc_put - drop ldisc reference
- * @ld: ldisc
- *
- * Drop a reference to a line discipline. Manage refcounts and
- * module usage counts. Free the ldisc once the recount hits zero.
- *
- * Locking:
- * takes tty_ldisc_lock to guard against ldisc races
- */
-
-static void tty_ldisc_put(struct tty_ldisc *ld)
-{
- unsigned long flags;
- int disc = ld->ops->num;
- struct tty_ldisc_ops *ldo;
-
- BUG_ON(disc < N_TTY || disc >= NR_LDISCS);
-
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- ldo = tty_ldiscs[disc];
- BUG_ON(ldo->refcount == 0);
- ldo->refcount--;
- module_put(ldo->owner);
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- WARN_ON(ld->refcount);
- kfree(ld);
-}
-
static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
{
return (*pos < NR_LDISCS) ? pos : NULL;
@@ -234,7 +240,7 @@ static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
if (IS_ERR(ld))
return 0;
seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i);
- tty_ldisc_put(ld);
+ put_ldisc(ld);
return 0;
}
@@ -288,20 +294,17 @@ static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
* Locking: takes tty_ldisc_lock
*/
-static int tty_ldisc_try(struct tty_struct *tty)
+static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
{
unsigned long flags;
struct tty_ldisc *ld;
- int ret = 0;
spin_lock_irqsave(&tty_ldisc_lock, flags);
- ld = tty->ldisc;
- if (test_bit(TTY_LDISC, &tty->flags)) {
- ld->refcount++;
- ret = 1;
- }
+ ld = NULL;
+ if (test_bit(TTY_LDISC, &tty->flags))
+ ld = get_ldisc(tty->ldisc);
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- return ret;
+ return ld;
}
/**
@@ -322,10 +325,11 @@ static int tty_ldisc_try(struct tty_struct *tty)
struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
{
+ struct tty_ldisc *ld;
+
/* wait_event is a macro */
- wait_event(tty_ldisc_wait, tty_ldisc_try(tty));
- WARN_ON(tty->ldisc->refcount == 0);
- return tty->ldisc;
+ wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL);
+ return ld;
}
EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
@@ -342,9 +346,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
{
- if (tty_ldisc_try(tty))
- return tty->ldisc;
- return NULL;
+ return tty_ldisc_try(tty);
}
EXPORT_SYMBOL_GPL(tty_ldisc_ref);
@@ -360,21 +362,15 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref);
void tty_ldisc_deref(struct tty_ldisc *ld)
{
- unsigned long flags;
-
- BUG_ON(ld == NULL);
-
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- if (ld->refcount == 0)
- printk(KERN_ERR "tty_ldisc_deref: no references.\n");
- else
- ld->refcount--;
- if (ld->refcount == 0)
- wake_up(&tty_ldisc_wait);
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ put_ldisc(ld);
}
EXPORT_SYMBOL_GPL(tty_ldisc_deref);
+static inline void tty_ldisc_put(struct tty_ldisc *ld)
+{
+ put_ldisc(ld);
+}
+
/**
* tty_ldisc_enable - allow ldisc use
* @tty: terminal to activate ldisc on
@@ -523,31 +519,6 @@ static int tty_ldisc_halt(struct tty_struct *tty)
}
/**
- * tty_ldisc_wait_idle - wait for the ldisc to become idle
- * @tty: tty to wait for
- *
- * Wait for the line discipline to become idle. The discipline must
- * have been halted for this to guarantee it remains idle.
- *
- * tty_ldisc_lock protects the ref counts currently.
- */
-
-static int tty_ldisc_wait_idle(struct tty_struct *tty)
-{
- unsigned long flags;
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- while (tty->ldisc->refcount) {
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- if (wait_event_timeout(tty_ldisc_wait,
- tty->ldisc->refcount == 0, 5 * HZ) == 0)
- return -EBUSY;
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- }
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- return 0;
-}
-
-/**
* tty_set_ldisc - set line discipline
* @tty: the terminal to set
* @ldisc: the line discipline
@@ -642,14 +613,6 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
flush_scheduled_work();
- /* Let any existing reference holders finish */
- retval = tty_ldisc_wait_idle(tty);
- if (retval < 0) {
- clear_bit(TTY_LDISC_CHANGING, &tty->flags);
- tty_ldisc_put(new_ldisc);
- return retval;
- }
-
mutex_lock(&tty->ldisc_mutex);
if (test_bit(TTY_HUPPED, &tty->flags)) {
/* We were raced by the hangup method. It will have stomped
@@ -795,7 +758,6 @@ void tty_ldisc_hangup(struct tty_struct *tty)
if (tty->ldisc) { /* Not yet closed */
/* Switch back to N_TTY */
tty_ldisc_halt(tty);
- tty_ldisc_wait_idle(tty);
tty_ldisc_reinit(tty);
/* At this point we have a closed ldisc and we want to
reopen it. We could defer this to the next open but
@@ -860,14 +822,6 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
tty_ldisc_halt(tty);
flush_scheduled_work();
- /*
- * Wait for any short term users (we know they are just driver
- * side waiters as the file is closing so user count on the file
- * side is zero.
- */
-
- tty_ldisc_wait_idle(tty);
-
mutex_lock(&tty->ldisc_mutex);
/*
* Now kill off the ldisc
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index b90eda8b344..fd69086d08d 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -858,6 +858,8 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
/* Check for existing affected CPUs.
* They may not be aware of it due to CPU Hotplug.
+ * cpufreq_cpu_put is called when the device is removed
+ * in __cpufreq_remove_dev()
*/
managed_policy = cpufreq_cpu_get(j);
if (unlikely(managed_policy)) {
@@ -884,7 +886,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
ret = sysfs_create_link(&sys_dev->kobj,
&managed_policy->kobj,
"cpufreq");
- if (!ret)
+ if (ret)
cpufreq_cpu_put(managed_policy);
/*
* Success. We only needed to be added to the mask.
@@ -924,6 +926,8 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
spin_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu(j, policy->cpus) {
+ if (!cpu_online(j))
+ continue;
per_cpu(cpufreq_cpu_data, j) = policy;
per_cpu(policy_cpu, j) = policy->cpu;
}
@@ -1244,13 +1248,22 @@ EXPORT_SYMBOL(cpufreq_get);
static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg)
{
- int cpu = sysdev->id;
int ret = 0;
+
+#ifdef __powerpc__
+ int cpu = sysdev->id;
unsigned int cur_freq = 0;
struct cpufreq_policy *cpu_policy;
dprintk("suspending cpu %u\n", cpu);
+ /*
+ * This whole bogosity is here because Powerbooks are made of fail.
+ * No sane platform should need any of the code below to be run.
+ * (it's entirely the wrong thing to do, as driver->get may
+ * reenable interrupts on some architectures).
+ */
+
if (!cpu_online(cpu))
return 0;
@@ -1309,6 +1322,7 @@ static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg)
out:
cpufreq_cpu_put(cpu_policy);
+#endif /* __powerpc__ */
return ret;
}
@@ -1322,12 +1336,18 @@ out:
*/
static int cpufreq_resume(struct sys_device *sysdev)
{
- int cpu = sysdev->id;
int ret = 0;
+
+#ifdef __powerpc__
+ int cpu = sysdev->id;
struct cpufreq_policy *cpu_policy;
dprintk("resuming cpu %u\n", cpu);
+ /* As with the ->suspend method, all the code below is
+ * only necessary because Powerbooks suck.
+ * See commit 42d4dc3f4e1e for jokes. */
+
if (!cpu_online(cpu))
return 0;
@@ -1391,6 +1411,7 @@ out:
schedule_work(&cpu_policy->update);
fail:
cpufreq_cpu_put(cpu_policy);
+#endif /* __powerpc__ */
return ret;
}
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 57490502b21..bdea7e2f94b 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -63,6 +63,7 @@ struct cpu_dbs_info_s {
unsigned int down_skip;
unsigned int requested_freq;
int cpu;
+ unsigned int enable:1;
/*
* percpu mutex that serializes governor limit change with
* do_dbs_timer invocation. We do not want do_dbs_timer to run
@@ -141,6 +142,9 @@ dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
struct cpufreq_policy *policy;
+ if (!this_dbs_info->enable)
+ return 0;
+
policy = this_dbs_info->cur_policy;
/*
@@ -497,6 +501,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
delay -= jiffies % delay;
+ dbs_info->enable = 1;
INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
queue_delayed_work_on(dbs_info->cpu, kconservative_wq, &dbs_info->work,
delay);
@@ -504,6 +509,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
{
+ dbs_info->enable = 0;
cancel_delayed_work_sync(&dbs_info->work);
}
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 24964c1d0af..e2a10bcba7a 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -868,6 +868,8 @@ static void amd64_read_dbam_reg(struct amd64_pvt *pvt)
goto err_reg;
}
+ return;
+
err_reg:
debugf0("Error reading F2x%03x.\n", reg);
}
@@ -2634,6 +2636,8 @@ static void amd64_read_mc_registers(struct amd64_pvt *pvt)
amd64_dump_misc_regs(pvt);
+ return;
+
err_reg:
debugf0("Reading an MC register failed\n");
@@ -2977,6 +2981,9 @@ static int amd64_check_ecc_enabled(struct amd64_pvt *pvt)
"ECC is enabled by BIOS, Proceeding "
"with EDAC module initialization\n");
+ /* Signal good ECC status */
+ ret = 0;
+
/* CLEAR the override, since BIOS controlled it */
ecc_enable_override = 0;
}
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 8fab7890a36..33be210d672 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1461,7 +1461,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
goto out;
}
- if (crtc_req->count_connectors > 0 && !mode && !fb) {
+ if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
DRM_DEBUG("Count connectors is %d but no mode or fb set\n",
crtc_req->count_connectors);
ret = -EINVAL;
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 3da9cfa3184..6aaa2cb2336 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -706,8 +706,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
struct drm_encoder **save_encoders, *new_encoder;
struct drm_framebuffer *old_fb = NULL;
bool save_enabled;
- bool mode_changed = false;
- bool fb_changed = false;
+ bool mode_changed = false; /* if true do a full mode set */
+ bool fb_changed = false; /* if true and !mode_changed just do a flip */
struct drm_connector *connector;
int count = 0, ro, fail = 0;
struct drm_crtc_helper_funcs *crtc_funcs;
@@ -758,6 +758,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
if (set->crtc->fb == NULL) {
DRM_DEBUG("crtc has no fb, full mode set\n");
mode_changed = true;
+ } else if (set->fb == NULL) {
+ mode_changed = true;
} else if ((set->fb->bits_per_pixel !=
set->crtc->fb->bits_per_pixel) ||
set->fb->depth != set->crtc->fb->depth)
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index b4a3dbcebe9..f85aaf21e78 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -566,7 +566,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
ret = drm_vblank_get(dev, crtc);
if (ret) {
- DRM_ERROR("failed to acquire vblank counter, %d\n", ret);
+ DRM_DEBUG("failed to acquire vblank counter, %d\n", ret);
return ret;
}
seq = drm_vblank_count(dev, crtc);
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 54f492a488a..7914097b09c 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -566,6 +566,8 @@ void drm_mode_connector_list_update(struct drm_connector *connector)
found_it = 1;
/* if equal delete the probed mode */
mode->status = pmode->status;
+ /* Merge type bits together */
+ mode->type |= pmode->type;
list_del(&pmode->head);
drm_mode_destroy(connector->dev, pmode);
break;
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 8c4783180bf..50d1f782768 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1186,6 +1186,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (ret)
goto out_iomapfree;
+ dev_priv->wq = create_workqueue("i915");
+ if (dev_priv->wq == NULL) {
+ DRM_ERROR("Failed to create our workqueue.\n");
+ ret = -ENOMEM;
+ goto out_iomapfree;
+ }
+
/* enable GEM by default */
dev_priv->has_gem = 1;
@@ -1211,7 +1218,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (!I915_NEED_GFX_HWS(dev)) {
ret = i915_init_phys_hws(dev);
if (ret != 0)
- goto out_iomapfree;
+ goto out_workqueue_free;
}
i915_get_mem_freq(dev);
@@ -1245,7 +1252,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
if (ret < 0) {
DRM_ERROR("failed to init modeset\n");
- goto out_rmmap;
+ goto out_workqueue_free;
}
}
@@ -1256,6 +1263,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
return 0;
+out_workqueue_free:
+ destroy_workqueue(dev_priv->wq);
out_iomapfree:
io_mapping_free(dev_priv->mm.gtt_mapping);
out_rmmap:
@@ -1269,6 +1278,8 @@ int i915_driver_unload(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ destroy_workqueue(dev_priv->wq);
+
io_mapping_free(dev_priv->mm.gtt_mapping);
if (dev_priv->mm.gtt_mtrr >= 0) {
mtrr_del(dev_priv->mm.gtt_mtrr, dev->agp->base,
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index d0875287588..7537f57d8a8 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -219,6 +219,7 @@ typedef struct drm_i915_private {
unsigned int lvds_vbt:1;
unsigned int int_crt_support:1;
unsigned int lvds_use_ssc:1;
+ unsigned int edp_support:1;
int lvds_ssc_freq;
struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
@@ -229,6 +230,8 @@ typedef struct drm_i915_private {
spinlock_t error_lock;
struct drm_i915_error_state *first_error;
+ struct work_struct error_work;
+ struct workqueue_struct *wq;
/* Register state */
u8 saveLBB;
@@ -888,6 +891,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
IS_I915GM(dev)))
#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IGDNG(dev))
#define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_IGDNG(dev))
+#define SUPPORTS_EDP(dev) (IS_IGDNG_M(dev))
#define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
/* dsparb controlled by hw only */
#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IGDNG(dev))
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 5bf420378b6..140bee142fc 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1570,7 +1570,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
}
if (was_empty && !dev_priv->mm.suspended)
- schedule_delayed_work(&dev_priv->mm.retire_work, HZ);
+ queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
return seqno;
}
@@ -1719,7 +1719,7 @@ i915_gem_retire_work_handler(struct work_struct *work)
i915_gem_retire_requests(dev);
if (!dev_priv->mm.suspended &&
!list_empty(&dev_priv->mm.request_list))
- schedule_delayed_work(&dev_priv->mm.retire_work, HZ);
+ queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
mutex_unlock(&dev->struct_mutex);
}
diff --git a/drivers/gpu/drm/i915/i915_gem_debugfs.c b/drivers/gpu/drm/i915/i915_gem_debugfs.c
index 9a44bfcb813..cb3b97405fb 100644
--- a/drivers/gpu/drm/i915/i915_gem_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_gem_debugfs.c
@@ -343,6 +343,8 @@ static int i915_error_state(struct seq_file *m, void *unused)
error = dev_priv->first_error;
+ seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
+ error->time.tv_usec);
seq_printf(m, "EIR: 0x%08x\n", error->eir);
seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er);
seq_printf(m, " INSTPM: 0x%08x\n", error->instpm);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 7ba23a69a0c..7ebc84c2881 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -190,7 +190,7 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
if (!i915_pipe_enabled(dev, pipe)) {
- DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe);
+ DRM_DEBUG("trying to get vblank count for disabled pipe %d\n", pipe);
return 0;
}
@@ -219,7 +219,7 @@ u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
int reg = pipe ? PIPEB_FRMCOUNT_GM45 : PIPEA_FRMCOUNT_GM45;
if (!i915_pipe_enabled(dev, pipe)) {
- DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe);
+ DRM_DEBUG("trying to get vblank count for disabled pipe %d\n", pipe);
return 0;
}
@@ -290,6 +290,35 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev)
return ret;
}
+/**
+ * i915_error_work_func - do process context error handling work
+ * @work: work struct
+ *
+ * Fire an error uevent so userspace can see that a hang or error
+ * was detected.
+ */
+static void i915_error_work_func(struct work_struct *work)
+{
+ drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+ error_work);
+ struct drm_device *dev = dev_priv->dev;
+ char *event_string = "ERROR=1";
+ char *envp[] = { event_string, NULL };
+
+ DRM_DEBUG("generating error event\n");
+
+ kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp);
+}
+
+/**
+ * i915_capture_error_state - capture an error record for later analysis
+ * @dev: drm device
+ *
+ * Should be called when an error is detected (either a hang or an error
+ * interrupt) to capture error state from the time of the error. Fills
+ * out a structure which becomes available in debugfs for user level tools
+ * to pick up.
+ */
static void i915_capture_error_state(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -325,12 +354,137 @@ static void i915_capture_error_state(struct drm_device *dev)
error->acthd = I915_READ(ACTHD_I965);
}
+ do_gettimeofday(&error->time);
+
dev_priv->first_error = error;
out:
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
}
+/**
+ * i915_handle_error - handle an error interrupt
+ * @dev: drm device
+ *
+ * Do some basic checking of regsiter state at error interrupt time and
+ * dump it to the syslog. Also call i915_capture_error_state() to make
+ * sure we get a record and make it available in debugfs. Fire a uevent
+ * so userspace knows something bad happened (should trigger collection
+ * of a ring dump etc.).
+ */
+static void i915_handle_error(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 eir = I915_READ(EIR);
+ u32 pipea_stats = I915_READ(PIPEASTAT);
+ u32 pipeb_stats = I915_READ(PIPEBSTAT);
+
+ i915_capture_error_state(dev);
+
+ printk(KERN_ERR "render error detected, EIR: 0x%08x\n",
+ eir);
+
+ if (IS_G4X(dev)) {
+ if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) {
+ u32 ipeir = I915_READ(IPEIR_I965);
+
+ printk(KERN_ERR " IPEIR: 0x%08x\n",
+ I915_READ(IPEIR_I965));
+ printk(KERN_ERR " IPEHR: 0x%08x\n",
+ I915_READ(IPEHR_I965));
+ printk(KERN_ERR " INSTDONE: 0x%08x\n",
+ I915_READ(INSTDONE_I965));
+ printk(KERN_ERR " INSTPS: 0x%08x\n",
+ I915_READ(INSTPS));
+ printk(KERN_ERR " INSTDONE1: 0x%08x\n",
+ I915_READ(INSTDONE1));
+ printk(KERN_ERR " ACTHD: 0x%08x\n",
+ I915_READ(ACTHD_I965));
+ I915_WRITE(IPEIR_I965, ipeir);
+ (void)I915_READ(IPEIR_I965);
+ }
+ if (eir & GM45_ERROR_PAGE_TABLE) {
+ u32 pgtbl_err = I915_READ(PGTBL_ER);
+ printk(KERN_ERR "page table error\n");
+ printk(KERN_ERR " PGTBL_ER: 0x%08x\n",
+ pgtbl_err);
+ I915_WRITE(PGTBL_ER, pgtbl_err);
+ (void)I915_READ(PGTBL_ER);
+ }
+ }
+
+ if (IS_I9XX(dev)) {
+ if (eir & I915_ERROR_PAGE_TABLE) {
+ u32 pgtbl_err = I915_READ(PGTBL_ER);
+ printk(KERN_ERR "page table error\n");
+ printk(KERN_ERR " PGTBL_ER: 0x%08x\n",
+ pgtbl_err);
+ I915_WRITE(PGTBL_ER, pgtbl_err);
+ (void)I915_READ(PGTBL_ER);
+ }
+ }
+
+ if (eir & I915_ERROR_MEMORY_REFRESH) {
+ printk(KERN_ERR "memory refresh error\n");
+ printk(KERN_ERR "PIPEASTAT: 0x%08x\n",
+ pipea_stats);
+ printk(KERN_ERR "PIPEBSTAT: 0x%08x\n",
+ pipeb_stats);
+ /* pipestat has already been acked */
+ }
+ if (eir & I915_ERROR_INSTRUCTION) {
+ printk(KERN_ERR "instruction error\n");
+ printk(KERN_ERR " INSTPM: 0x%08x\n",
+ I915_READ(INSTPM));
+ if (!IS_I965G(dev)) {
+ u32 ipeir = I915_READ(IPEIR);
+
+ printk(KERN_ERR " IPEIR: 0x%08x\n",
+ I915_READ(IPEIR));
+ printk(KERN_ERR " IPEHR: 0x%08x\n",
+ I915_READ(IPEHR));
+ printk(KERN_ERR " INSTDONE: 0x%08x\n",
+ I915_READ(INSTDONE));
+ printk(KERN_ERR " ACTHD: 0x%08x\n",
+ I915_READ(ACTHD));
+ I915_WRITE(IPEIR, ipeir);
+ (void)I915_READ(IPEIR);
+ } else {
+ u32 ipeir = I915_READ(IPEIR_I965);
+
+ printk(KERN_ERR " IPEIR: 0x%08x\n",
+ I915_READ(IPEIR_I965));
+ printk(KERN_ERR " IPEHR: 0x%08x\n",
+ I915_READ(IPEHR_I965));
+ printk(KERN_ERR " INSTDONE: 0x%08x\n",
+ I915_READ(INSTDONE_I965));
+ printk(KERN_ERR " INSTPS: 0x%08x\n",
+ I915_READ(INSTPS));
+ printk(KERN_ERR " INSTDONE1: 0x%08x\n",
+ I915_READ(INSTDONE1));
+ printk(KERN_ERR " ACTHD: 0x%08x\n",
+ I915_READ(ACTHD_I965));
+ I915_WRITE(IPEIR_I965, ipeir);
+ (void)I915_READ(IPEIR_I965);
+ }
+ }
+
+ I915_WRITE(EIR, eir);
+ (void)I915_READ(EIR);
+ eir = I915_READ(EIR);
+ if (eir) {
+ /*
+ * some errors might have become stuck,
+ * mask them.
+ */
+ DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir);
+ I915_WRITE(EMR, I915_READ(EMR) | eir);
+ I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
+ }
+
+ queue_work(dev_priv->wq, &dev_priv->error_work);
+}
+
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
@@ -372,6 +526,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
pipea_stats = I915_READ(PIPEASTAT);
pipeb_stats = I915_READ(PIPEBSTAT);
+ if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
+ i915_handle_error(dev);
+
/*
* Clear the PIPE(A|B)STAT regs before the IIR
*/
@@ -403,86 +560,13 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
DRM_DEBUG("hotplug event received, stat 0x%08x\n",
hotplug_status);
if (hotplug_status & dev_priv->hotplug_supported_mask)
- schedule_work(&dev_priv->hotplug_work);
+ queue_work(dev_priv->wq,
+ &dev_priv->hotplug_work);
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
I915_READ(PORT_HOTPLUG_STAT);
}
- if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) {
- u32 eir = I915_READ(EIR);
-
- i915_capture_error_state(dev);
-
- printk(KERN_ERR "render error detected, EIR: 0x%08x\n",
- eir);
- if (eir & I915_ERROR_PAGE_TABLE) {
- u32 pgtbl_err = I915_READ(PGTBL_ER);
- printk(KERN_ERR "page table error\n");
- printk(KERN_ERR " PGTBL_ER: 0x%08x\n",
- pgtbl_err);
- I915_WRITE(PGTBL_ER, pgtbl_err);
- (void)I915_READ(PGTBL_ER);
- }
- if (eir & I915_ERROR_MEMORY_REFRESH) {
- printk(KERN_ERR "memory refresh error\n");
- printk(KERN_ERR "PIPEASTAT: 0x%08x\n",
- pipea_stats);
- printk(KERN_ERR "PIPEBSTAT: 0x%08x\n",
- pipeb_stats);
- /* pipestat has already been acked */
- }
- if (eir & I915_ERROR_INSTRUCTION) {
- printk(KERN_ERR "instruction error\n");
- printk(KERN_ERR " INSTPM: 0x%08x\n",
- I915_READ(INSTPM));
- if (!IS_I965G(dev)) {
- u32 ipeir = I915_READ(IPEIR);
-
- printk(KERN_ERR " IPEIR: 0x%08x\n",
- I915_READ(IPEIR));
- printk(KERN_ERR " IPEHR: 0x%08x\n",
- I915_READ(IPEHR));
- printk(KERN_ERR " INSTDONE: 0x%08x\n",
- I915_READ(INSTDONE));
- printk(KERN_ERR " ACTHD: 0x%08x\n",
- I915_READ(ACTHD));
- I915_WRITE(IPEIR, ipeir);
- (void)I915_READ(IPEIR);
- } else {
- u32 ipeir = I915_READ(IPEIR_I965);
-
- printk(KERN_ERR " IPEIR: 0x%08x\n",
- I915_READ(IPEIR_I965));
- printk(KERN_ERR " IPEHR: 0x%08x\n",
- I915_READ(IPEHR_I965));
- printk(KERN_ERR " INSTDONE: 0x%08x\n",
- I915_READ(INSTDONE_I965));
- printk(KERN_ERR " INSTPS: 0x%08x\n",
- I915_READ(INSTPS));
- printk(KERN_ERR " INSTDONE1: 0x%08x\n",
- I915_READ(INSTDONE1));
- printk(KERN_ERR " ACTHD: 0x%08x\n",
- I915_READ(ACTHD_I965));
- I915_WRITE(IPEIR_I965, ipeir);
- (void)I915_READ(IPEIR_I965);
- }
- }
-
- I915_WRITE(EIR, eir);
- (void)I915_READ(EIR);
- eir = I915_READ(EIR);
- if (eir) {
- /*
- * some errors might have become stuck,
- * mask them.
- */
- DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir);
- I915_WRITE(EMR, I915_READ(EMR) | eir);
- I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
- }
- }
-
I915_WRITE(IIR, iir);
new_iir = I915_READ(IIR); /* Flush posted writes */
@@ -830,6 +914,7 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
atomic_set(&dev_priv->irq_received, 0);
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
+ INIT_WORK(&dev_priv->error_work, i915_error_work_func);
if (IS_IGDNG(dev)) {
igdng_irq_preinstall(dev);
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 6c085848409..2955083aa47 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1395,6 +1395,7 @@
#define TV_V_CHROMA_42 0x684a8
/* Display Port */
+#define DP_A 0x64000 /* eDP */
#define DP_B 0x64100
#define DP_C 0x64200
#define DP_D 0x64300
@@ -1437,13 +1438,22 @@
/* Mystic DPCD version 1.1 special mode */
#define DP_ENHANCED_FRAMING (1 << 18)
+/* eDP */
+#define DP_PLL_FREQ_270MHZ (0 << 16)
+#define DP_PLL_FREQ_160MHZ (1 << 16)
+#define DP_PLL_FREQ_MASK (3 << 16)
+
/** locked once port is enabled */
#define DP_PORT_REVERSAL (1 << 15)
+/* eDP */
+#define DP_PLL_ENABLE (1 << 14)
+
/** sends the clock on lane 15 of the PEG for debug */
#define DP_CLOCK_OUTPUT_ENABLE (1 << 13)
#define DP_SCRAMBLING_DISABLE (1 << 12)
+#define DP_SCRAMBLING_DISABLE_IGDNG (1 << 7)
/** limit RGB values to avoid confusing TVs */
#define DP_COLOR_RANGE_16_235 (1 << 8)
@@ -1463,6 +1473,13 @@
* is 20 bytes in each direction, hence the 5 fixed
* data registers
*/
+#define DPA_AUX_CH_CTL 0x64010
+#define DPA_AUX_CH_DATA1 0x64014
+#define DPA_AUX_CH_DATA2 0x64018
+#define DPA_AUX_CH_DATA3 0x6401c
+#define DPA_AUX_CH_DATA4 0x64020
+#define DPA_AUX_CH_DATA5 0x64024
+
#define DPB_AUX_CH_CTL 0x64110
#define DPB_AUX_CH_DATA1 0x64114
#define DPB_AUX_CH_DATA2 0x64118
@@ -1618,7 +1635,7 @@
#define I830_FIFO_LINE_SIZE 32
#define I945_FIFO_SIZE 127 /* 945 & 965 */
#define I915_FIFO_SIZE 95
-#define I855GM_FIFO_SIZE 255
+#define I855GM_FIFO_SIZE 127 /* In cachelines */
#define I830_FIFO_SIZE 95
#define I915_MAX_WM 0x3f
@@ -1848,6 +1865,8 @@
#define PFA_CTL_1 0x68080
#define PFB_CTL_1 0x68880
#define PF_ENABLE (1<<31)
+#define PFA_WIN_SZ 0x68074
+#define PFB_WIN_SZ 0x68874
/* legacy palette */
#define LGC_PALETTE_A 0x4a000
@@ -2208,4 +2227,28 @@
#define PCH_PP_OFF_DELAYS 0xc720c
#define PCH_PP_DIVISOR 0xc7210
+#define PCH_DP_B 0xe4100
+#define PCH_DPB_AUX_CH_CTL 0xe4110
+#define PCH_DPB_AUX_CH_DATA1 0xe4114
+#define PCH_DPB_AUX_CH_DATA2 0xe4118
+#define PCH_DPB_AUX_CH_DATA3 0xe411c
+#define PCH_DPB_AUX_CH_DATA4 0xe4120
+#define PCH_DPB_AUX_CH_DATA5 0xe4124
+
+#define PCH_DP_C 0xe4200
+#define PCH_DPC_AUX_CH_CTL 0xe4210
+#define PCH_DPC_AUX_CH_DATA1 0xe4214
+#define PCH_DPC_AUX_CH_DATA2 0xe4218
+#define PCH_DPC_AUX_CH_DATA3 0xe421c
+#define PCH_DPC_AUX_CH_DATA4 0xe4220
+#define PCH_DPC_AUX_CH_DATA5 0xe4224
+
+#define PCH_DP_D 0xe4300
+#define PCH_DPD_AUX_CH_CTL 0xe4310
+#define PCH_DPD_AUX_CH_DATA1 0xe4314
+#define PCH_DPD_AUX_CH_DATA2 0xe4318
+#define PCH_DPD_AUX_CH_DATA3 0xe431c
+#define PCH_DPD_AUX_CH_DATA4 0xe4320
+#define PCH_DPD_AUX_CH_DATA5 0xe4324
+
#endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 9e1d16e5c3e..1d04e1904ac 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -598,7 +598,7 @@ int i915_restore_state(struct drm_device *dev)
for (i = 0; i < 16; i++) {
I915_WRITE(SWF00 + (i << 2), dev_priv->saveSWF0[i]);
- I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]);
+ I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i]);
}
for (i = 0; i < 3; i++)
I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 7cc44719102..300aee3296c 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -97,14 +97,13 @@ static void
parse_lfp_panel_data(struct drm_i915_private *dev_priv,
struct bdb_header *bdb)
{
- struct drm_device *dev = dev_priv->dev;
struct bdb_lvds_options *lvds_options;
struct bdb_lvds_lfp_data *lvds_lfp_data;
struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
struct bdb_lvds_lfp_data_entry *entry;
struct lvds_dvo_timing *dvo_timing;
struct drm_display_mode *panel_fixed_mode;
- int lfp_data_size;
+ int lfp_data_size, dvo_timing_offset;
/* Defaults if we can't find VBT info */
dev_priv->lvds_dither = 0;
@@ -133,14 +132,16 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
entry = (struct bdb_lvds_lfp_data_entry *)
((uint8_t *)lvds_lfp_data->data + (lfp_data_size *
lvds_options->panel_type));
+ dvo_timing_offset = lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset -
+ lvds_lfp_data_ptrs->ptr[0].fp_timing_offset;
- /* On IGDNG mobile, LVDS data block removes panel fitting registers.
- So dec 2 dword from dvo_timing offset */
- if (IS_IGDNG(dev))
- dvo_timing = (struct lvds_dvo_timing *)
- ((u8 *)&entry->dvo_timing - 8);
- else
- dvo_timing = &entry->dvo_timing;
+ /*
+ * the size of fp_timing varies on the different platform.
+ * So calculate the DVO timing relative offset in LVDS data
+ * entry to get the DVO timing entry
+ */
+ dvo_timing = (struct lvds_dvo_timing *)
+ ((unsigned char *)entry + dvo_timing_offset);
panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
@@ -295,6 +296,25 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
}
return;
}
+
+static void
+parse_driver_features(struct drm_i915_private *dev_priv,
+ struct bdb_header *bdb)
+{
+ struct drm_device *dev = dev_priv->dev;
+ struct bdb_driver_features *driver;
+
+ /* set default for chips without eDP */
+ if (!SUPPORTS_EDP(dev)) {
+ dev_priv->edp_support = 0;
+ return;
+ }
+
+ driver = find_section(bdb, BDB_DRIVER_FEATURES);
+ if (driver && driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
+ dev_priv->edp_support = 1;
+}
+
/**
* intel_init_bios - initialize VBIOS settings & find VBT
* @dev: DRM device
@@ -345,6 +365,8 @@ intel_init_bios(struct drm_device *dev)
parse_lfp_panel_data(dev_priv, bdb);
parse_sdvo_panel_data(dev_priv, bdb);
parse_sdvo_device_mapping(dev_priv, bdb);
+ parse_driver_features(dev_priv, bdb);
+
pci_unmap_rom(pdev, bios);
return 0;
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index fe72e1c225d..0f8e5f69ac7 100644
--- a/drivers/gpu/drm/i915/intel_bios.h
+++ b/drivers/gpu/drm/i915/intel_bios.h
@@ -381,6 +381,51 @@ struct bdb_sdvo_lvds_options {
} __attribute__((packed));
+#define BDB_DRIVER_FEATURE_NO_LVDS 0
+#define BDB_DRIVER_FEATURE_INT_LVDS 1
+#define BDB_DRIVER_FEATURE_SDVO_LVDS 2
+#define BDB_DRIVER_FEATURE_EDP 3
+
+struct bdb_driver_features {
+ u8 boot_dev_algorithm:1;
+ u8 block_display_switch:1;
+ u8 allow_display_switch:1;
+ u8 hotplug_dvo:1;
+ u8 dual_view_zoom:1;
+ u8 int15h_hook:1;
+ u8 sprite_in_clone:1;
+ u8 primary_lfp_id:1;
+
+ u16 boot_mode_x;
+ u16 boot_mode_y;
+ u8 boot_mode_bpp;
+ u8 boot_mode_refresh;
+
+ u16 enable_lfp_primary:1;
+ u16 selective_mode_pruning:1;
+ u16 dual_frequency:1;
+ u16 render_clock_freq:1; /* 0: high freq; 1: low freq */
+ u16 nt_clone_support:1;
+ u16 power_scheme_ui:1; /* 0: CUI; 1: 3rd party */
+ u16 sprite_display_assign:1; /* 0: secondary; 1: primary */
+ u16 cui_aspect_scaling:1;
+ u16 preserve_aspect_ratio:1;
+ u16 sdvo_device_power_down:1;
+ u16 crt_hotplug:1;
+ u16 lvds_config:2;
+ u16 tv_hotplug:1;
+ u16 hdmi_config:2;
+
+ u8 static_display:1;
+ u8 reserved2:7;
+ u16 legacy_crt_max_x;
+ u16 legacy_crt_max_y;
+ u8 legacy_crt_max_refresh;
+
+ u8 hdmi_termination;
+ u8 custom_vbt_version;
+} __attribute__((packed));
+
bool intel_init_bios(struct drm_device *dev);
/*
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index d6a1a6e5539..4cf8e2e88a4 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -156,6 +156,9 @@ static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector)
temp = adpa = I915_READ(PCH_ADPA);
+ adpa &= ~ADPA_DAC_ENABLE;
+ I915_WRITE(PCH_ADPA, adpa);
+
adpa &= ~ADPA_CRT_HOTPLUG_MASK;
adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 |
@@ -169,13 +172,14 @@ static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector)
DRM_DEBUG("pch crt adpa 0x%x", adpa);
I915_WRITE(PCH_ADPA, adpa);
- /* This might not be needed as not specified in spec...*/
- udelay(1000);
+ while ((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) != 0)
+ ;
/* Check the status to see if both blue and green are on now */
adpa = I915_READ(PCH_ADPA);
- if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) ==
- ADPA_CRT_HOTPLUG_MONITOR_COLOR)
+ adpa &= ADPA_CRT_HOTPLUG_MONITOR_MASK;
+ if ((adpa == ADPA_CRT_HOTPLUG_MONITOR_COLOR) ||
+ (adpa == ADPA_CRT_HOTPLUG_MONITOR_MONO))
ret = true;
else
ret = false;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 508838ee31e..d6fce213341 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -34,6 +34,8 @@
#include "drm_crtc_helper.h"
+#define HAS_eDP (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))
+
bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
static void intel_update_watermarks(struct drm_device *dev);
@@ -88,7 +90,7 @@ struct intel_limit {
#define I8XX_P2_SLOW 4
#define I8XX_P2_FAST 2
#define I8XX_P2_LVDS_SLOW 14
-#define I8XX_P2_LVDS_FAST 14 /* No fast option */
+#define I8XX_P2_LVDS_FAST 7
#define I8XX_P2_SLOW_LIMIT 165000
#define I9XX_DOT_MIN 20000
@@ -268,6 +270,9 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
static bool
intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock);
+static bool
+intel_find_pll_igdng_dp(const intel_limit_t *, struct drm_crtc *crtc,
+ int target, int refclk, intel_clock_t *best_clock);
static const intel_limit_t intel_limits_i8xx_dvo = {
.dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX },
@@ -598,6 +603,23 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
return false;
}
+struct drm_connector *
+intel_pipe_get_output (struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ struct drm_connector *l_entry, *ret = NULL;
+
+ list_for_each_entry(l_entry, &mode_config->connector_list, head) {
+ if (l_entry->encoder &&
+ l_entry->encoder->crtc == crtc) {
+ ret = l_entry;
+ break;
+ }
+ }
+ return ret;
+}
+
#define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0)
/**
* Returns whether the given set of divisors are valid for a given refclk with
@@ -645,7 +667,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int err = target;
if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
- (I915_READ(LVDS) & LVDS_PORT_EN) != 0) {
+ (I915_READ(LVDS)) != 0) {
/*
* For LVDS, if the panel is on, just rely on its current
* settings for dual-channel. We haven't figured out how to
@@ -752,6 +774,30 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
}
static bool
+intel_find_pll_igdng_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
+ int target, int refclk, intel_clock_t *best_clock)
+{
+ struct drm_device *dev = crtc->dev;
+ intel_clock_t clock;
+ if (target < 200000) {
+ clock.n = 1;
+ clock.p1 = 2;
+ clock.p2 = 10;
+ clock.m1 = 12;
+ clock.m2 = 9;
+ } else {
+ clock.n = 2;
+ clock.p1 = 1;
+ clock.p2 = 10;
+ clock.m1 = 14;
+ clock.m2 = 8;
+ }
+ intel_clock(dev, refclk, &clock);
+ memcpy(best_clock, &clock, sizeof(intel_clock_t));
+ return true;
+}
+
+static bool
intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock)
{
@@ -763,6 +809,14 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int err_most = 47;
found = false;
+ /* eDP has only 2 clock choice, no n/m/p setting */
+ if (HAS_eDP)
+ return true;
+
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
+ return intel_find_pll_igdng_dp(limit, crtc, target,
+ refclk, best_clock);
+
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
LVDS_CLKB_POWER_UP)
@@ -998,6 +1052,90 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
return 0;
}
+/* Disable the VGA plane that we never use */
+static void i915_disable_vga (struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u8 sr1;
+ u32 vga_reg;
+
+ if (IS_IGDNG(dev))
+ vga_reg = CPU_VGACNTRL;
+ else
+ vga_reg = VGACNTRL;
+
+ if (I915_READ(vga_reg) & VGA_DISP_DISABLE)
+ return;
+
+ I915_WRITE8(VGA_SR_INDEX, 1);
+ sr1 = I915_READ8(VGA_SR_DATA);
+ I915_WRITE8(VGA_SR_DATA, sr1 | (1 << 5));
+ udelay(100);
+
+ I915_WRITE(vga_reg, VGA_DISP_DISABLE);
+}
+
+static void igdng_disable_pll_edp (struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 dpa_ctl;
+
+ DRM_DEBUG("\n");
+ dpa_ctl = I915_READ(DP_A);
+ dpa_ctl &= ~DP_PLL_ENABLE;
+ I915_WRITE(DP_A, dpa_ctl);
+}
+
+static void igdng_enable_pll_edp (struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 dpa_ctl;
+
+ dpa_ctl = I915_READ(DP_A);
+ dpa_ctl |= DP_PLL_ENABLE;
+ I915_WRITE(DP_A, dpa_ctl);
+ udelay(200);
+}
+
+
+static void igdng_set_pll_edp (struct drm_crtc *crtc, int clock)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 dpa_ctl;
+
+ DRM_DEBUG("eDP PLL enable for clock %d\n", clock);
+ dpa_ctl = I915_READ(DP_A);
+ dpa_ctl &= ~DP_PLL_FREQ_MASK;
+
+ if (clock < 200000) {
+ u32 temp;
+ dpa_ctl |= DP_PLL_FREQ_160MHZ;
+ /* workaround for 160Mhz:
+ 1) program 0x4600c bits 15:0 = 0x8124
+ 2) program 0x46010 bit 0 = 1
+ 3) program 0x46034 bit 24 = 1
+ 4) program 0x64000 bit 14 = 1
+ */
+ temp = I915_READ(0x4600c);
+ temp &= 0xffff0000;
+ I915_WRITE(0x4600c, temp | 0x8124);
+
+ temp = I915_READ(0x46010);
+ I915_WRITE(0x46010, temp | 1);
+
+ temp = I915_READ(0x46034);
+ I915_WRITE(0x46034, temp | (1 << 24));
+ } else {
+ dpa_ctl |= DP_PLL_FREQ_270MHZ;
+ }
+ I915_WRITE(DP_A, dpa_ctl);
+
+ udelay(500);
+}
+
static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct drm_device *dev = crtc->dev;
@@ -1015,6 +1153,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
int pf_ctl_reg = (pipe == 0) ? PFA_CTL_1 : PFB_CTL_1;
+ int pf_win_size = (pipe == 0) ? PFA_WIN_SZ : PFB_WIN_SZ;
int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
@@ -1028,7 +1167,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B;
int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
u32 temp;
- int tries = 5, j;
+ int tries = 5, j, n;
/* XXX: When our outputs are all unaware of DPMS modes other than off
* and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
@@ -1038,27 +1177,32 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
DRM_DEBUG("crtc %d dpms on\n", pipe);
- /* enable PCH DPLL */
- temp = I915_READ(pch_dpll_reg);
- if ((temp & DPLL_VCO_ENABLE) == 0) {
- I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
- I915_READ(pch_dpll_reg);
- }
-
- /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
- temp = I915_READ(fdi_rx_reg);
- I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE |
- FDI_SEL_PCDCLK |
- FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */
- I915_READ(fdi_rx_reg);
- udelay(200);
+ if (HAS_eDP) {
+ /* enable eDP PLL */
+ igdng_enable_pll_edp(crtc);
+ } else {
+ /* enable PCH DPLL */
+ temp = I915_READ(pch_dpll_reg);
+ if ((temp & DPLL_VCO_ENABLE) == 0) {
+ I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
+ I915_READ(pch_dpll_reg);
+ }
- /* Enable CPU FDI TX PLL, always on for IGDNG */
- temp = I915_READ(fdi_tx_reg);
- if ((temp & FDI_TX_PLL_ENABLE) == 0) {
- I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
- I915_READ(fdi_tx_reg);
- udelay(100);
+ /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
+ temp = I915_READ(fdi_rx_reg);
+ I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE |
+ FDI_SEL_PCDCLK |
+ FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */
+ I915_READ(fdi_rx_reg);
+ udelay(200);
+
+ /* Enable CPU FDI TX PLL, always on for IGDNG */
+ temp = I915_READ(fdi_tx_reg);
+ if ((temp & FDI_TX_PLL_ENABLE) == 0) {
+ I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
+ I915_READ(fdi_tx_reg);
+ udelay(100);
+ }
}
/* Enable CPU pipe */
@@ -1077,122 +1221,126 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
}
- /* enable CPU FDI TX and PCH FDI RX */
- temp = I915_READ(fdi_tx_reg);
- temp |= FDI_TX_ENABLE;
- temp |= FDI_DP_PORT_WIDTH_X4; /* default */
- temp &= ~FDI_LINK_TRAIN_NONE;
- temp |= FDI_LINK_TRAIN_PATTERN_1;
- I915_WRITE(fdi_tx_reg, temp);
- I915_READ(fdi_tx_reg);
+ if (!HAS_eDP) {
+ /* enable CPU FDI TX and PCH FDI RX */
+ temp = I915_READ(fdi_tx_reg);
+ temp |= FDI_TX_ENABLE;
+ temp |= FDI_DP_PORT_WIDTH_X4; /* default */
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ temp |= FDI_LINK_TRAIN_PATTERN_1;
+ I915_WRITE(fdi_tx_reg, temp);
+ I915_READ(fdi_tx_reg);
- temp = I915_READ(fdi_rx_reg);
- temp &= ~FDI_LINK_TRAIN_NONE;
- temp |= FDI_LINK_TRAIN_PATTERN_1;
- I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
- I915_READ(fdi_rx_reg);
+ temp = I915_READ(fdi_rx_reg);
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ temp |= FDI_LINK_TRAIN_PATTERN_1;
+ I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
+ I915_READ(fdi_rx_reg);
- udelay(150);
+ udelay(150);
- /* Train FDI. */
- /* umask FDI RX Interrupt symbol_lock and bit_lock bit
- for train result */
- temp = I915_READ(fdi_rx_imr_reg);
- temp &= ~FDI_RX_SYMBOL_LOCK;
- temp &= ~FDI_RX_BIT_LOCK;
- I915_WRITE(fdi_rx_imr_reg, temp);
- I915_READ(fdi_rx_imr_reg);
- udelay(150);
+ /* Train FDI. */
+ /* umask FDI RX Interrupt symbol_lock and bit_lock bit
+ for train result */
+ temp = I915_READ(fdi_rx_imr_reg);
+ temp &= ~FDI_RX_SYMBOL_LOCK;
+ temp &= ~FDI_RX_BIT_LOCK;
+ I915_WRITE(fdi_rx_imr_reg, temp);
+ I915_READ(fdi_rx_imr_reg);
+ udelay(150);
- temp = I915_READ(fdi_rx_iir_reg);
- DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+ temp = I915_READ(fdi_rx_iir_reg);
+ DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
- if ((temp & FDI_RX_BIT_LOCK) == 0) {
- for (j = 0; j < tries; j++) {
- temp = I915_READ(fdi_rx_iir_reg);
- DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
- if (temp & FDI_RX_BIT_LOCK)
- break;
- udelay(200);
- }
- if (j != tries)
+ if ((temp & FDI_RX_BIT_LOCK) == 0) {
+ for (j = 0; j < tries; j++) {
+ temp = I915_READ(fdi_rx_iir_reg);
+ DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+ if (temp & FDI_RX_BIT_LOCK)
+ break;
+ udelay(200);
+ }
+ if (j != tries)
+ I915_WRITE(fdi_rx_iir_reg,
+ temp | FDI_RX_BIT_LOCK);
+ else
+ DRM_DEBUG("train 1 fail\n");
+ } else {
I915_WRITE(fdi_rx_iir_reg,
temp | FDI_RX_BIT_LOCK);
- else
- DRM_DEBUG("train 1 fail\n");
- } else {
- I915_WRITE(fdi_rx_iir_reg,
- temp | FDI_RX_BIT_LOCK);
- DRM_DEBUG("train 1 ok 2!\n");
- }
- temp = I915_READ(fdi_tx_reg);
- temp &= ~FDI_LINK_TRAIN_NONE;
- temp |= FDI_LINK_TRAIN_PATTERN_2;
- I915_WRITE(fdi_tx_reg, temp);
-
- temp = I915_READ(fdi_rx_reg);
- temp &= ~FDI_LINK_TRAIN_NONE;
- temp |= FDI_LINK_TRAIN_PATTERN_2;
- I915_WRITE(fdi_rx_reg, temp);
+ DRM_DEBUG("train 1 ok 2!\n");
+ }
+ temp = I915_READ(fdi_tx_reg);
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ temp |= FDI_LINK_TRAIN_PATTERN_2;
+ I915_WRITE(fdi_tx_reg, temp);
+
+ temp = I915_READ(fdi_rx_reg);
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ temp |= FDI_LINK_TRAIN_PATTERN_2;
+ I915_WRITE(fdi_rx_reg, temp);
- udelay(150);
+ udelay(150);
- temp = I915_READ(fdi_rx_iir_reg);
- DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+ temp = I915_READ(fdi_rx_iir_reg);
+ DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
- if ((temp & FDI_RX_SYMBOL_LOCK) == 0) {
- for (j = 0; j < tries; j++) {
- temp = I915_READ(fdi_rx_iir_reg);
- DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
- if (temp & FDI_RX_SYMBOL_LOCK)
- break;
- udelay(200);
- }
- if (j != tries) {
+ if ((temp & FDI_RX_SYMBOL_LOCK) == 0) {
+ for (j = 0; j < tries; j++) {
+ temp = I915_READ(fdi_rx_iir_reg);
+ DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+ if (temp & FDI_RX_SYMBOL_LOCK)
+ break;
+ udelay(200);
+ }
+ if (j != tries) {
+ I915_WRITE(fdi_rx_iir_reg,
+ temp | FDI_RX_SYMBOL_LOCK);
+ DRM_DEBUG("train 2 ok 1!\n");
+ } else
+ DRM_DEBUG("train 2 fail\n");
+ } else {
I915_WRITE(fdi_rx_iir_reg,
temp | FDI_RX_SYMBOL_LOCK);
- DRM_DEBUG("train 2 ok 1!\n");
- } else
- DRM_DEBUG("train 2 fail\n");
- } else {
- I915_WRITE(fdi_rx_iir_reg, temp | FDI_RX_SYMBOL_LOCK);
- DRM_DEBUG("train 2 ok 2!\n");
- }
- DRM_DEBUG("train done\n");
+ DRM_DEBUG("train 2 ok 2!\n");
+ }
+ DRM_DEBUG("train done\n");
- /* set transcoder timing */
- I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg));
- I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg));
- I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg));
+ /* set transcoder timing */
+ I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg));
+ I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg));
+ I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg));
- I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg));
- I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg));
- I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg));
+ I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg));
+ I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg));
+ I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg));
- /* enable PCH transcoder */
- temp = I915_READ(transconf_reg);
- I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
- I915_READ(transconf_reg);
+ /* enable PCH transcoder */
+ temp = I915_READ(transconf_reg);
+ I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
+ I915_READ(transconf_reg);
- while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0)
- ;
+ while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0)
+ ;
- /* enable normal */
+ /* enable normal */
- temp = I915_READ(fdi_tx_reg);
- temp &= ~FDI_LINK_TRAIN_NONE;
- I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
- FDI_TX_ENHANCE_FRAME_ENABLE);
- I915_READ(fdi_tx_reg);
+ temp = I915_READ(fdi_tx_reg);
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
+ FDI_TX_ENHANCE_FRAME_ENABLE);
+ I915_READ(fdi_tx_reg);
- temp = I915_READ(fdi_rx_reg);
- temp &= ~FDI_LINK_TRAIN_NONE;
- I915_WRITE(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE |
- FDI_RX_ENHANCE_FRAME_ENABLE);
- I915_READ(fdi_rx_reg);
+ temp = I915_READ(fdi_rx_reg);
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ I915_WRITE(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE |
+ FDI_RX_ENHANCE_FRAME_ENABLE);
+ I915_READ(fdi_rx_reg);
- /* wait one idle pattern time */
- udelay(100);
+ /* wait one idle pattern time */
+ udelay(100);
+
+ }
intel_crtc_load_lut(crtc);
@@ -1200,8 +1348,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
case DRM_MODE_DPMS_OFF:
DRM_DEBUG("crtc %d dpms off\n", pipe);
- /* Disable the VGA plane that we never use */
- I915_WRITE(CPU_VGACNTRL, VGA_DISP_DISABLE);
+ i915_disable_vga(dev);
/* Disable display plane */
temp = I915_READ(dspcntr_reg);
@@ -1217,17 +1364,23 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
if ((temp & PIPEACONF_ENABLE) != 0) {
I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
I915_READ(pipeconf_reg);
+ n = 0;
/* wait for cpu pipe off, pipe state */
- while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0)
- ;
+ while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) {
+ n++;
+ if (n < 60) {
+ udelay(500);
+ continue;
+ } else {
+ DRM_DEBUG("pipe %d off delay\n", pipe);
+ break;
+ }
+ }
} else
DRM_DEBUG("crtc %d is disabled\n", pipe);
- /* IGDNG-A : disable cpu panel fitter ? */
- temp = I915_READ(pf_ctl_reg);
- if ((temp & PF_ENABLE) != 0) {
- I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE);
- I915_READ(pf_ctl_reg);
+ if (HAS_eDP) {
+ igdng_disable_pll_edp(crtc);
}
/* disable CPU FDI tx and PCH FDI rx */
@@ -1239,6 +1392,8 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE);
I915_READ(fdi_rx_reg);
+ udelay(100);
+
/* still set train pattern 1 */
temp = I915_READ(fdi_tx_reg);
temp &= ~FDI_LINK_TRAIN_NONE;
@@ -1250,14 +1405,25 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
temp |= FDI_LINK_TRAIN_PATTERN_1;
I915_WRITE(fdi_rx_reg, temp);
+ udelay(100);
+
/* disable PCH transcoder */
temp = I915_READ(transconf_reg);
if ((temp & TRANS_ENABLE) != 0) {
I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);
I915_READ(transconf_reg);
+ n = 0;
/* wait for PCH transcoder off, transcoder state */
- while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0)
- ;
+ while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0) {
+ n++;
+ if (n < 60) {
+ udelay(500);
+ continue;
+ } else {
+ DRM_DEBUG("transcoder %d off delay\n", pipe);
+ break;
+ }
+ }
}
/* disable PCH DPLL */
@@ -1275,6 +1441,22 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
I915_READ(fdi_rx_reg);
}
+ /* Disable CPU FDI TX PLL */
+ temp = I915_READ(fdi_tx_reg);
+ if ((temp & FDI_TX_PLL_ENABLE) != 0) {
+ I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE);
+ I915_READ(fdi_tx_reg);
+ udelay(100);
+ }
+
+ /* Disable PF */
+ temp = I915_READ(pf_ctl_reg);
+ if ((temp & PF_ENABLE) != 0) {
+ I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE);
+ I915_READ(pf_ctl_reg);
+ }
+ I915_WRITE(pf_win_size, 0);
+
/* Wait for the clocks to turn off. */
udelay(150);
break;
@@ -1342,7 +1524,7 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
//intel_crtc_dpms_video(crtc, FALSE); TODO
/* Disable the VGA plane that we never use */
- I915_WRITE(VGACNTRL, VGA_DISP_DISABLE);
+ i915_disable_vga(dev);
/* Disable display plane */
temp = I915_READ(dspcntr_reg);
@@ -1623,48 +1805,72 @@ static struct intel_watermark_params igd_cursor_hplloff_wm = {
IGD_FIFO_LINE_SIZE
};
static struct intel_watermark_params i945_wm_info = {
- I915_FIFO_LINE_SIZE,
+ I945_FIFO_SIZE,
I915_MAX_WM,
1,
- 0,
- IGD_FIFO_LINE_SIZE
+ 2,
+ I915_FIFO_LINE_SIZE
};
static struct intel_watermark_params i915_wm_info = {
- I945_FIFO_SIZE,
+ I915_FIFO_SIZE,
I915_MAX_WM,
1,
- 0,
+ 2,
I915_FIFO_LINE_SIZE
};
static struct intel_watermark_params i855_wm_info = {
I855GM_FIFO_SIZE,
I915_MAX_WM,
1,
- 0,
+ 2,
I830_FIFO_LINE_SIZE
};
static struct intel_watermark_params i830_wm_info = {
I830_FIFO_SIZE,
I915_MAX_WM,
1,
- 0,
+ 2,
I830_FIFO_LINE_SIZE
};
+/**
+ * intel_calculate_wm - calculate watermark level
+ * @clock_in_khz: pixel clock
+ * @wm: chip FIFO params
+ * @pixel_size: display pixel size
+ * @latency_ns: memory latency for the platform
+ *
+ * Calculate the watermark level (the level at which the display plane will
+ * start fetching from memory again). Each chip has a different display
+ * FIFO size and allocation, so the caller needs to figure that out and pass
+ * in the correct intel_watermark_params structure.
+ *
+ * As the pixel clock runs, the FIFO will be drained at a rate that depends
+ * on the pixel size. When it reaches the watermark level, it'll start
+ * fetching FIFO line sized based chunks from memory until the FIFO fills
+ * past the watermark point. If the FIFO drains completely, a FIFO underrun
+ * will occur, and a display engine hang could result.
+ */
static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
struct intel_watermark_params *wm,
int pixel_size,
unsigned long latency_ns)
{
- unsigned long bytes_required, wm_size;
+ long entries_required, wm_size;
+
+ entries_required = (clock_in_khz * pixel_size * latency_ns) / 1000000;
+ entries_required /= wm->cacheline_size;
- bytes_required = (clock_in_khz * pixel_size * latency_ns) / 1000000;
- bytes_required /= wm->cacheline_size;
- wm_size = wm->fifo_size - bytes_required - wm->guard_size;
+ DRM_DEBUG("FIFO entries required for mode: %d\n", entries_required);
- if (wm_size > wm->max_wm)
+ wm_size = wm->fifo_size - (entries_required + wm->guard_size);
+
+ DRM_DEBUG("FIFO watermark level: %d\n", wm_size);
+
+ /* Don't promote wm_size to unsigned... */
+ if (wm_size > (long)wm->max_wm)
wm_size = wm->max_wm;
- if (wm_size == 0)
+ if (wm_size <= 0)
wm_size = wm->default_wm;
return wm_size;
}
@@ -1799,8 +2005,40 @@ static void igd_enable_cxsr(struct drm_device *dev, unsigned long clock,
return;
}
-const static int latency_ns = 5000; /* default for non-igd platforms */
+const static int latency_ns = 3000; /* default for non-igd platforms */
+static int intel_get_fifo_size(struct drm_device *dev, int plane)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t dsparb = I915_READ(DSPARB);
+ int size;
+
+ if (IS_I9XX(dev)) {
+ if (plane == 0)
+ size = dsparb & 0x7f;
+ else
+ size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) -
+ (dsparb & 0x7f);
+ } else if (IS_I85X(dev)) {
+ if (plane == 0)
+ size = dsparb & 0x1ff;
+ else
+ size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) -
+ (dsparb & 0x1ff);
+ size >>= 1; /* Convert to cachelines */
+ } else if (IS_845G(dev)) {
+ size = dsparb & 0x7f;
+ size >>= 2; /* Convert to cachelines */
+ } else {
+ size = dsparb & 0x7f;
+ size >>= 1; /* Convert to cachelines */
+ }
+
+ DRM_DEBUG("FIFO size - (0x%08x) %s: %d\n", dsparb, plane ? "B" : "A",
+ size);
+
+ return size;
+}
static void i965_update_wm(struct drm_device *dev)
{
@@ -1817,101 +2055,89 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
int planeb_clock, int sr_hdisplay, int pixel_size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK;
- uint32_t fwater_hi = I915_READ(FW_BLC2) & LM_FIFO_WATERMARK;
- int bsize, asize, cwm, bwm = 1, awm = 1, srwm = 1;
- uint32_t dsparb = I915_READ(DSPARB);
- int planea_entries, planeb_entries;
- struct intel_watermark_params *wm_params;
+ uint32_t fwater_lo;
+ uint32_t fwater_hi;
+ int total_size, cacheline_size, cwm, srwm = 1;
+ int planea_wm, planeb_wm;
+ struct intel_watermark_params planea_params, planeb_params;
unsigned long line_time_us;
int sr_clock, sr_entries = 0;
+ /* Create copies of the base settings for each pipe */
if (IS_I965GM(dev) || IS_I945GM(dev))
- wm_params = &i945_wm_info;
+ planea_params = planeb_params = i945_wm_info;
else if (IS_I9XX(dev))
- wm_params = &i915_wm_info;
+ planea_params = planeb_params = i915_wm_info;
else
- wm_params = &i855_wm_info;
-
- planea_entries = intel_calculate_wm(planea_clock, wm_params,
- pixel_size, latency_ns);
- planeb_entries = intel_calculate_wm(planeb_clock, wm_params,
- pixel_size, latency_ns);
-
- DRM_DEBUG("FIFO entries - A: %d, B: %d\n", planea_entries,
- planeb_entries);
+ planea_params = planeb_params = i855_wm_info;
- if (IS_I9XX(dev)) {
- asize = dsparb & 0x7f;
- bsize = (dsparb >> DSPARB_CSTART_SHIFT) & 0x7f;
- } else {
- asize = dsparb & 0x1ff;
- bsize = (dsparb >> DSPARB_BEND_SHIFT) & 0x1ff;
- }
- DRM_DEBUG("FIFO size - A: %d, B: %d\n", asize, bsize);
+ /* Grab a couple of global values before we overwrite them */
+ total_size = planea_params.fifo_size;
+ cacheline_size = planea_params.cacheline_size;
- /* Two extra entries for padding */
- awm = asize - (planea_entries + 2);
- bwm = bsize - (planeb_entries + 2);
+ /* Update per-plane FIFO sizes */
+ planea_params.fifo_size = intel_get_fifo_size(dev, 0);
+ planeb_params.fifo_size = intel_get_fifo_size(dev, 1);
- /* Sanity check against potentially bad FIFO allocations */
- if (awm <= 0) {
- /* pipe is on but has too few FIFO entries */
- if (planea_entries != 0)
- DRM_DEBUG("plane A needs more FIFO entries\n");
- awm = 1;
- }
- if (bwm <= 0) {
- if (planeb_entries != 0)
- DRM_DEBUG("plane B needs more FIFO entries\n");
- bwm = 1;
- }
+ planea_wm = intel_calculate_wm(planea_clock, &planea_params,
+ pixel_size, latency_ns);
+ planeb_wm = intel_calculate_wm(planeb_clock, &planeb_params,
+ pixel_size, latency_ns);
+ DRM_DEBUG("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
/*
* Overlay gets an aggressive default since video jitter is bad.
*/
cwm = 2;
- /* Calc sr entries for one pipe configs */
- if (!planea_clock || !planeb_clock) {
+ /* Calc sr entries for one plane configs */
+ if (sr_hdisplay && (!planea_clock || !planeb_clock)) {
+ /* self-refresh has much higher latency */
+ const static int sr_latency_ns = 6000;
+
sr_clock = planea_clock ? planea_clock : planeb_clock;
- line_time_us = (sr_hdisplay * 1000) / sr_clock;
- sr_entries = (((latency_ns / line_time_us) + 1) * pixel_size *
- sr_hdisplay) / 1000;
- sr_entries = roundup(sr_entries / wm_params->cacheline_size, 1);
- if (sr_entries < wm_params->fifo_size)
- srwm = wm_params->fifo_size - sr_entries;
+ line_time_us = ((sr_hdisplay * 1000) / sr_clock);
+
+ /* Use ns/us then divide to preserve precision */
+ sr_entries = (((sr_latency_ns / line_time_us) + 1) *
+ pixel_size * sr_hdisplay) / 1000;
+ sr_entries = roundup(sr_entries / cacheline_size, 1);
+ DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
+ srwm = total_size - sr_entries;
+ if (srwm < 0)
+ srwm = 1;
+ if (IS_I9XX(dev))
+ I915_WRITE(FW_BLC_SELF, (srwm & 0x3f));
}
DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
- awm, bwm, cwm, srwm);
+ planea_wm, planeb_wm, cwm, srwm);
- fwater_lo = fwater_lo | ((bwm & 0x3f) << 16) | (awm & 0x3f);
- fwater_hi = fwater_hi | (cwm & 0x1f);
+ fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f);
+ fwater_hi = (cwm & 0x1f);
+
+ /* Set request length to 8 cachelines per fetch */
+ fwater_lo = fwater_lo | (1 << 24) | (1 << 8);
+ fwater_hi = fwater_hi | (1 << 8);
I915_WRITE(FW_BLC, fwater_lo);
I915_WRITE(FW_BLC2, fwater_hi);
- if (IS_I9XX(dev))
- I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f));
}
static void i830_update_wm(struct drm_device *dev, int planea_clock,
int pixel_size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t dsparb = I915_READ(DSPARB);
- uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK;
- unsigned int asize, awm;
- int planea_entries;
-
- planea_entries = intel_calculate_wm(planea_clock, &i830_wm_info,
- pixel_size, latency_ns);
+ uint32_t fwater_lo = I915_READ(FW_BLC) & ~0xfff;
+ int planea_wm;
- asize = dsparb & 0x7f;
+ i830_wm_info.fifo_size = intel_get_fifo_size(dev, 0);
- awm = asize - planea_entries;
+ planea_wm = intel_calculate_wm(planea_clock, &i830_wm_info,
+ pixel_size, latency_ns);
+ fwater_lo |= (3<<8) | planea_wm;
- fwater_lo = fwater_lo | awm;
+ DRM_DEBUG("Setting FIFO watermarks - A: %d\n", planea_wm);
I915_WRITE(FW_BLC, fwater_lo);
}
@@ -1984,7 +2210,7 @@ static void intel_update_watermarks(struct drm_device *dev)
if (enabled <= 0)
return;
- /* Single pipe configs can enable self refresh */
+ /* Single plane configs can enable self refresh */
if (enabled == 1 && IS_IGD(dev))
igd_enable_cxsr(dev, sr_clock, pixel_size);
else if (IS_IGD(dev))
@@ -2028,6 +2254,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
u32 dpll = 0, fp = 0, dspcntr, pipeconf;
bool ok, is_sdvo = false, is_dvo = false;
bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
+ bool is_edp = false;
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
const intel_limit_t *limit;
@@ -2043,6 +2270,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
int lvds_reg = LVDS;
u32 temp;
int sdvo_pixel_multiply;
+ int target_clock;
drm_vblank_pre_modeset(dev, pipe);
@@ -2074,6 +2302,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
case INTEL_OUTPUT_DISPLAYPORT:
is_dp = true;
break;
+ case INTEL_OUTPUT_EDP:
+ is_edp = true;
+ break;
}
num_outputs++;
@@ -2125,11 +2356,29 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
}
/* FDI link */
- if (IS_IGDNG(dev))
- igdng_compute_m_n(3, 4, /* lane num 4 */
- adjusted_mode->clock,
- 270000, /* lane clock */
- &m_n);
+ if (IS_IGDNG(dev)) {
+ int lane, link_bw;
+ /* eDP doesn't require FDI link, so just set DP M/N
+ according to current link config */
+ if (is_edp) {
+ struct drm_connector *edp;
+ target_clock = mode->clock;
+ edp = intel_pipe_get_output(crtc);
+ intel_edp_link_config(to_intel_output(edp),
+ &lane, &link_bw);
+ } else {
+ /* DP over FDI requires target mode clock
+ instead of link clock */
+ if (is_dp)
+ target_clock = mode->clock;
+ else
+ target_clock = adjusted_mode->clock;
+ lane = 4;
+ link_bw = 270000;
+ }
+ igdng_compute_m_n(3, lane, target_clock,
+ link_bw, &m_n);
+ }
if (IS_IGD(dev))
fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
@@ -2250,29 +2499,15 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
dpll_reg = pch_dpll_reg;
}
- if (dpll & DPLL_VCO_ENABLE) {
+ if (is_edp) {
+ igdng_disable_pll_edp(crtc);
+ } else if ((dpll & DPLL_VCO_ENABLE)) {
I915_WRITE(fp_reg, fp);
I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
I915_READ(dpll_reg);
udelay(150);
}
- if (IS_IGDNG(dev)) {
- /* enable PCH clock reference source */
- /* XXX need to change the setting for other outputs */
- u32 temp;
- temp = I915_READ(PCH_DREF_CONTROL);
- temp &= ~DREF_NONSPREAD_SOURCE_MASK;
- temp |= DREF_NONSPREAD_CK505_ENABLE;
- temp &= ~DREF_SSC_SOURCE_MASK;
- temp |= DREF_SSC_SOURCE_ENABLE;
- temp &= ~DREF_SSC1_ENABLE;
- /* if no eDP, disable source output to CPU */
- temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
- temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
- I915_WRITE(PCH_DREF_CONTROL, temp);
- }
-
/* The LVDS pin pair needs to be on before the DPLLs are enabled.
* This is an exception to the general rule that mode_set doesn't turn
* things on.
@@ -2304,23 +2539,25 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
if (is_dp)
intel_dp_set_m_n(crtc, mode, adjusted_mode);
- I915_WRITE(fp_reg, fp);
- I915_WRITE(dpll_reg, dpll);
- I915_READ(dpll_reg);
- /* Wait for the clocks to stabilize. */
- udelay(150);
-
- if (IS_I965G(dev) && !IS_IGDNG(dev)) {
- sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
- I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
- ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
- } else {
- /* write it again -- the BIOS does, after all */
+ if (!is_edp) {
+ I915_WRITE(fp_reg, fp);
I915_WRITE(dpll_reg, dpll);
+ I915_READ(dpll_reg);
+ /* Wait for the clocks to stabilize. */
+ udelay(150);
+
+ if (IS_I965G(dev) && !IS_IGDNG(dev)) {
+ sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
+ I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
+ ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
+ } else {
+ /* write it again -- the BIOS does, after all */
+ I915_WRITE(dpll_reg, dpll);
+ }
+ I915_READ(dpll_reg);
+ /* Wait for the clocks to stabilize. */
+ udelay(150);
}
- I915_READ(dpll_reg);
- /* Wait for the clocks to stabilize. */
- udelay(150);
I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
((adjusted_mode->crtc_htotal - 1) << 16));
@@ -2350,10 +2587,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
I915_WRITE(link_m1_reg, m_n.link_m);
I915_WRITE(link_n1_reg, m_n.link_n);
- /* enable FDI RX PLL too */
- temp = I915_READ(fdi_rx_reg);
- I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
- udelay(200);
+ if (is_edp) {
+ igdng_set_pll_edp(crtc, adjusted_mode->clock);
+ } else {
+ /* enable FDI RX PLL too */
+ temp = I915_READ(fdi_rx_reg);
+ I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
+ udelay(200);
+ }
}
I915_WRITE(pipeconf_reg, pipeconf);
@@ -2951,12 +3192,17 @@ static void intel_setup_outputs(struct drm_device *dev)
if (IS_IGDNG(dev)) {
int found;
+ if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED))
+ intel_dp_init(dev, DP_A);
+
if (I915_READ(HDMIB) & PORT_DETECTED) {
/* check SDVOB */
/* found = intel_sdvo_init(dev, HDMIB); */
found = 0;
if (!found)
intel_hdmi_init(dev, HDMIB);
+ if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
+ intel_dp_init(dev, PCH_DP_B);
}
if (I915_READ(HDMIC) & PORT_DETECTED)
@@ -2965,6 +3211,12 @@ static void intel_setup_outputs(struct drm_device *dev)
if (I915_READ(HDMID) & PORT_DETECTED)
intel_hdmi_init(dev, HDMID);
+ if (I915_READ(PCH_DP_C) & DP_DETECTED)
+ intel_dp_init(dev, PCH_DP_C);
+
+ if (I915_READ(PCH_DP_D) & DP_DETECTED)
+ intel_dp_init(dev, PCH_DP_D);
+
} else if (IS_I9XX(dev)) {
int found;
u32 reg;
@@ -3039,6 +3291,10 @@ static void intel_setup_outputs(struct drm_device *dev)
(1 << 1));
clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT);
break;
+ case INTEL_OUTPUT_EDP:
+ crtc_mask = (1 << 1);
+ clone_mask = (1 << INTEL_OUTPUT_EDP);
+ break;
}
encoder->possible_crtcs = crtc_mask;
encoder->possible_clones = intel_connector_clones(dev, clone_mask);
@@ -3148,6 +3404,9 @@ void intel_modeset_init(struct drm_device *dev)
if (IS_I965G(dev)) {
dev->mode_config.max_width = 8192;
dev->mode_config.max_height = 8192;
+ } else if (IS_I9XX(dev)) {
+ dev->mode_config.max_width = 4096;
+ dev->mode_config.max_height = 4096;
} else {
dev->mode_config.max_width = 2048;
dev->mode_config.max_height = 2048;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 6770ae88370..a6ff15ac548 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -40,6 +40,8 @@
#define DP_LINK_CONFIGURATION_SIZE 9
+#define IS_eDP(i) ((i)->type == INTEL_OUTPUT_EDP)
+
struct intel_dp_priv {
uint32_t output_reg;
uint32_t DP;
@@ -63,6 +65,19 @@ intel_dp_link_train(struct intel_output *intel_output, uint32_t DP,
static void
intel_dp_link_down(struct intel_output *intel_output, uint32_t DP);
+void
+intel_edp_link_config (struct intel_output *intel_output,
+ int *lane_num, int *link_bw)
+{
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+ *lane_num = dp_priv->lane_count;
+ if (dp_priv->link_bw == DP_LINK_BW_1_62)
+ *link_bw = 162000;
+ else if (dp_priv->link_bw == DP_LINK_BW_2_7)
+ *link_bw = 270000;
+}
+
static int
intel_dp_max_lane_count(struct intel_output *intel_output)
{
@@ -206,7 +221,13 @@ intel_dp_aux_ch(struct intel_output *intel_output,
* and would like to run at 2MHz. So, take the
* hrawclk value and divide by 2 and use that
*/
- aux_clock_divider = intel_hrawclk(dev) / 2;
+ if (IS_eDP(intel_output))
+ aux_clock_divider = 225; /* eDP input clock at 450Mhz */
+ else if (IS_IGDNG(dev))
+ aux_clock_divider = 62; /* IGDNG: input clock fixed at 125Mhz */
+ else
+ aux_clock_divider = intel_hrawclk(dev) / 2;
+
/* Must try at least 3 times according to DP spec */
for (try = 0; try < 5; try++) {
/* Load the send data into the aux channel data registers */
@@ -236,7 +257,7 @@ intel_dp_aux_ch(struct intel_output *intel_output,
}
/* Clear done status and any errors */
- I915_WRITE(ch_ctl, (ctl |
+ I915_WRITE(ch_ctl, (status |
DP_AUX_CH_CTL_DONE |
DP_AUX_CH_CTL_TIME_OUT_ERROR |
DP_AUX_CH_CTL_RECEIVE_ERROR));
@@ -295,7 +316,7 @@ intel_dp_aux_native_write(struct intel_output *intel_output,
return -1;
msg[0] = AUX_NATIVE_WRITE << 4;
msg[1] = address >> 8;
- msg[2] = address;
+ msg[2] = address & 0xff;
msg[3] = send_bytes - 1;
memcpy(&msg[4], send, send_bytes);
msg_bytes = send_bytes + 4;
@@ -387,8 +408,8 @@ intel_dp_i2c_init(struct intel_output *intel_output, const char *name)
memset(&dp_priv->adapter, '\0', sizeof (dp_priv->adapter));
dp_priv->adapter.owner = THIS_MODULE;
dp_priv->adapter.class = I2C_CLASS_DDC;
- strncpy (dp_priv->adapter.name, name, sizeof dp_priv->adapter.name - 1);
- dp_priv->adapter.name[sizeof dp_priv->adapter.name - 1] = '\0';
+ strncpy (dp_priv->adapter.name, name, sizeof(dp_priv->adapter.name) - 1);
+ dp_priv->adapter.name[sizeof(dp_priv->adapter.name) - 1] = '\0';
dp_priv->adapter.algo_data = &dp_priv->algo;
dp_priv->adapter.dev.parent = &intel_output->base.kdev;
@@ -493,22 +514,40 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
intel_dp_compute_m_n(3, lane_count,
mode->clock, adjusted_mode->clock, &m_n);
- if (intel_crtc->pipe == 0) {
- I915_WRITE(PIPEA_GMCH_DATA_M,
- ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
- m_n.gmch_m);
- I915_WRITE(PIPEA_GMCH_DATA_N,
- m_n.gmch_n);
- I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m);
- I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n);
+ if (IS_IGDNG(dev)) {
+ if (intel_crtc->pipe == 0) {
+ I915_WRITE(TRANSA_DATA_M1,
+ ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
+ m_n.gmch_m);
+ I915_WRITE(TRANSA_DATA_N1, m_n.gmch_n);
+ I915_WRITE(TRANSA_DP_LINK_M1, m_n.link_m);
+ I915_WRITE(TRANSA_DP_LINK_N1, m_n.link_n);
+ } else {
+ I915_WRITE(TRANSB_DATA_M1,
+ ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
+ m_n.gmch_m);
+ I915_WRITE(TRANSB_DATA_N1, m_n.gmch_n);
+ I915_WRITE(TRANSB_DP_LINK_M1, m_n.link_m);
+ I915_WRITE(TRANSB_DP_LINK_N1, m_n.link_n);
+ }
} else {
- I915_WRITE(PIPEB_GMCH_DATA_M,
- ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
- m_n.gmch_m);
- I915_WRITE(PIPEB_GMCH_DATA_N,
- m_n.gmch_n);
- I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m);
- I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n);
+ if (intel_crtc->pipe == 0) {
+ I915_WRITE(PIPEA_GMCH_DATA_M,
+ ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
+ m_n.gmch_m);
+ I915_WRITE(PIPEA_GMCH_DATA_N,
+ m_n.gmch_n);
+ I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m);
+ I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n);
+ } else {
+ I915_WRITE(PIPEB_GMCH_DATA_M,
+ ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
+ m_n.gmch_m);
+ I915_WRITE(PIPEB_GMCH_DATA_N,
+ m_n.gmch_n);
+ I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m);
+ I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n);
+ }
}
}
@@ -556,8 +595,38 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
if (intel_crtc->pipe == 1)
dp_priv->DP |= DP_PIPEB_SELECT;
+
+ if (IS_eDP(intel_output)) {
+ /* don't miss out required setting for eDP */
+ dp_priv->DP |= DP_PLL_ENABLE;
+ if (adjusted_mode->clock < 200000)
+ dp_priv->DP |= DP_PLL_FREQ_160MHZ;
+ else
+ dp_priv->DP |= DP_PLL_FREQ_270MHZ;
+ }
}
+static void igdng_edp_backlight_on (struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 pp;
+
+ DRM_DEBUG("\n");
+ pp = I915_READ(PCH_PP_CONTROL);
+ pp |= EDP_BLC_ENABLE;
+ I915_WRITE(PCH_PP_CONTROL, pp);
+}
+
+static void igdng_edp_backlight_off (struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 pp;
+
+ DRM_DEBUG("\n");
+ pp = I915_READ(PCH_PP_CONTROL);
+ pp &= ~EDP_BLC_ENABLE;
+ I915_WRITE(PCH_PP_CONTROL, pp);
+}
static void
intel_dp_dpms(struct drm_encoder *encoder, int mode)
@@ -569,11 +638,17 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
uint32_t dp_reg = I915_READ(dp_priv->output_reg);
if (mode != DRM_MODE_DPMS_ON) {
- if (dp_reg & DP_PORT_EN)
+ if (dp_reg & DP_PORT_EN) {
intel_dp_link_down(intel_output, dp_priv->DP);
+ if (IS_eDP(intel_output))
+ igdng_edp_backlight_off(dev);
+ }
} else {
- if (!(dp_reg & DP_PORT_EN))
+ if (!(dp_reg & DP_PORT_EN)) {
intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration);
+ if (IS_eDP(intel_output))
+ igdng_edp_backlight_on(dev);
+ }
}
dp_priv->dpms_mode = mode;
}
@@ -935,6 +1010,23 @@ intel_dp_link_down(struct intel_output *intel_output, uint32_t DP)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ DRM_DEBUG("\n");
+
+ if (IS_eDP(intel_output)) {
+ DP &= ~DP_PLL_ENABLE;
+ I915_WRITE(dp_priv->output_reg, DP);
+ POSTING_READ(dp_priv->output_reg);
+ udelay(100);
+ }
+
+ DP &= ~DP_LINK_TRAIN_MASK;
+ I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
+ POSTING_READ(dp_priv->output_reg);
+
+ udelay(17000);
+
+ if (IS_eDP(intel_output))
+ DP |= DP_LINK_TRAIN_OFF;
I915_WRITE(dp_priv->output_reg, DP & ~DP_PORT_EN);
POSTING_READ(dp_priv->output_reg);
}
@@ -978,6 +1070,24 @@ intel_dp_check_link_status(struct intel_output *intel_output)
intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration);
}
+static enum drm_connector_status
+igdng_dp_detect(struct drm_connector *connector)
+{
+ struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ enum drm_connector_status status;
+
+ status = connector_status_disconnected;
+ if (intel_dp_aux_native_read(intel_output,
+ 0x000, dp_priv->dpcd,
+ sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd))
+ {
+ if (dp_priv->dpcd[0] != 0)
+ status = connector_status_connected;
+ }
+ return status;
+}
+
/**
* Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
*
@@ -996,6 +1106,9 @@ intel_dp_detect(struct drm_connector *connector)
dp_priv->has_audio = false;
+ if (IS_IGDNG(dev))
+ return igdng_dp_detect(connector);
+
temp = I915_READ(PORT_HOTPLUG_EN);
I915_WRITE(PORT_HOTPLUG_EN,
@@ -1039,11 +1152,27 @@ intel_dp_detect(struct drm_connector *connector)
static int intel_dp_get_modes(struct drm_connector *connector)
{
struct intel_output *intel_output = to_intel_output(connector);
+ struct drm_device *dev = intel_output->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret;
/* We should parse the EDID data and find out if it has an audio sink
*/
- return intel_ddc_get_modes(intel_output);
+ ret = intel_ddc_get_modes(intel_output);
+ if (ret)
+ return ret;
+
+ /* if eDP has no EDID, try to use fixed panel mode from VBT */
+ if (IS_eDP(intel_output)) {
+ if (dev_priv->panel_fixed_mode != NULL) {
+ struct drm_display_mode *mode;
+ mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
+ drm_mode_probed_add(connector, mode);
+ return 1;
+ }
+ }
+ return 0;
}
static void
@@ -1106,6 +1235,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
struct drm_connector *connector;
struct intel_output *intel_output;
struct intel_dp_priv *dp_priv;
+ const char *name = NULL;
intel_output = kcalloc(sizeof(struct intel_output) +
sizeof(struct intel_dp_priv), 1, GFP_KERNEL);
@@ -1119,7 +1249,10 @@ intel_dp_init(struct drm_device *dev, int output_reg)
DRM_MODE_CONNECTOR_DisplayPort);
drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
- intel_output->type = INTEL_OUTPUT_DISPLAYPORT;
+ if (output_reg == DP_A)
+ intel_output->type = INTEL_OUTPUT_EDP;
+ else
+ intel_output->type = INTEL_OUTPUT_DISPLAYPORT;
connector->interlace_allowed = true;
connector->doublescan_allowed = 0;
@@ -1139,12 +1272,41 @@ intel_dp_init(struct drm_device *dev, int output_reg)
drm_sysfs_connector_add(connector);
/* Set up the DDC bus. */
- intel_dp_i2c_init(intel_output,
- (output_reg == DP_B) ? "DPDDC-B" :
- (output_reg == DP_C) ? "DPDDC-C" : "DPDDC-D");
+ switch (output_reg) {
+ case DP_A:
+ name = "DPDDC-A";
+ break;
+ case DP_B:
+ case PCH_DP_B:
+ name = "DPDDC-B";
+ break;
+ case DP_C:
+ case PCH_DP_C:
+ name = "DPDDC-C";
+ break;
+ case DP_D:
+ case PCH_DP_D:
+ name = "DPDDC-D";
+ break;
+ }
+
+ intel_dp_i2c_init(intel_output, name);
+
intel_output->ddc_bus = &dp_priv->adapter;
intel_output->hot_plug = intel_dp_hot_plug;
+ if (output_reg == DP_A) {
+ /* initialize panel mode from VBT if available for eDP */
+ if (dev_priv->lfp_lvds_vbt_mode) {
+ dev_priv->panel_fixed_mode =
+ drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
+ if (dev_priv->panel_fixed_mode) {
+ dev_priv->panel_fixed_mode->type |=
+ DRM_MODE_TYPE_PREFERRED;
+ }
+ }
+ }
+
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
* 0xd. Failure to do so will result in spurious interrupts being
* generated on the port when a cable is not attached.
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 004541c935a..d6f92ea1b55 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -55,6 +55,7 @@
#define INTEL_OUTPUT_TVOUT 5
#define INTEL_OUTPUT_HDMI 6
#define INTEL_OUTPUT_DISPLAYPORT 7
+#define INTEL_OUTPUT_EDP 8
#define INTEL_DVO_CHIP_NONE 0
#define INTEL_DVO_CHIP_LVDS 1
@@ -121,6 +122,8 @@ extern void intel_dp_init(struct drm_device *dev, int dp_reg);
void
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
+extern void intel_edp_link_config (struct intel_output *, int *, int *);
+
extern void intel_crtc_load_lut(struct drm_crtc *crtc);
extern void intel_encoder_prepare (struct drm_encoder *encoder);
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 9e30daae37d..1842290cded 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -130,16 +130,17 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
}
static enum drm_connector_status
-intel_hdmi_edid_detect(struct drm_connector *connector)
+intel_hdmi_detect(struct drm_connector *connector)
{
struct intel_output *intel_output = to_intel_output(connector);
struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
struct edid *edid = NULL;
enum drm_connector_status status = connector_status_disconnected;
+ hdmi_priv->has_hdmi_sink = false;
edid = drm_get_edid(&intel_output->base,
intel_output->ddc_bus);
- hdmi_priv->has_hdmi_sink = false;
+
if (edid) {
if (edid->input & DRM_EDID_INPUT_DIGITAL) {
status = connector_status_connected;
@@ -148,65 +149,8 @@ intel_hdmi_edid_detect(struct drm_connector *connector)
intel_output->base.display_info.raw_edid = NULL;
kfree(edid);
}
- return status;
-}
-
-static enum drm_connector_status
-igdng_hdmi_detect(struct drm_connector *connector)
-{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
-
- /* FIXME hotplug detect */
-
- hdmi_priv->has_hdmi_sink = false;
- return intel_hdmi_edid_detect(connector);
-}
-static enum drm_connector_status
-intel_hdmi_detect(struct drm_connector *connector)
-{
- struct drm_device *dev = connector->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
- u32 temp, bit;
-
- if (IS_IGDNG(dev))
- return igdng_hdmi_detect(connector);
-
- temp = I915_READ(PORT_HOTPLUG_EN);
-
- switch (hdmi_priv->sdvox_reg) {
- case SDVOB:
- temp |= HDMIB_HOTPLUG_INT_EN;
- break;
- case SDVOC:
- temp |= HDMIC_HOTPLUG_INT_EN;
- break;
- default:
- return connector_status_unknown;
- }
-
- I915_WRITE(PORT_HOTPLUG_EN, temp);
-
- POSTING_READ(PORT_HOTPLUG_EN);
-
- switch (hdmi_priv->sdvox_reg) {
- case SDVOB:
- bit = HDMIB_HOTPLUG_INT_STATUS;
- break;
- case SDVOC:
- bit = HDMIC_HOTPLUG_INT_STATUS;
- break;
- default:
- return connector_status_unknown;
- }
-
- if ((I915_READ(PORT_HOTPLUG_STAT) & bit) != 0)
- return intel_hdmi_edid_detect(connector);
- else
- return connector_status_disconnected;
+ return status;
}
static int intel_hdmi_get_modes(struct drm_connector *connector)
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 9ab38efffec..3f445a80c55 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -780,6 +780,14 @@ static const struct dmi_system_id intel_no_lvds[] = {
},
{
.callback = intel_no_lvds_dmi_callback,
+ .ident = "AOpen Mini PC MP915",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+ DMI_MATCH(DMI_BOARD_NAME, "i915GMx-F"),
+ },
+ },
+ {
+ .callback = intel_no_lvds_dmi_callback,
.ident = "Aopen i945GTt-VFA",
.matches = {
DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"),
@@ -884,6 +892,10 @@ void intel_lvds_init(struct drm_device *dev)
if (IS_IGDNG(dev)) {
if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
return;
+ if (dev_priv->edp_support) {
+ DRM_DEBUG("disable LVDS for eDP support\n");
+ return;
+ }
gpio = PCH_GPIOC;
}
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 4f0c30948bc..5371d933255 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -31,6 +31,7 @@
#include "drm.h"
#include "drm_crtc.h"
#include "intel_drv.h"
+#include "drm_edid.h"
#include "i915_drm.h"
#include "i915_drv.h"
#include "intel_sdvo_regs.h"
@@ -55,6 +56,12 @@ struct intel_sdvo_priv {
/* Pixel clock limitations reported by the SDVO device, in kHz */
int pixel_clock_min, pixel_clock_max;
+ /*
+ * For multiple function SDVO device,
+ * this is for current attached outputs.
+ */
+ uint16_t attached_output;
+
/**
* This is set if we're going to treat the device as TV-out.
*
@@ -114,6 +121,9 @@ struct intel_sdvo_priv {
u32 save_SDVOX;
};
+static bool
+intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags);
+
/**
* Writes the SDVOB or SDVOC with the given value, but always writes both
* SDVOB and SDVOC to work around apparent hardware issues (according to
@@ -1435,41 +1445,96 @@ void intel_sdvo_set_hotplug(struct drm_connector *connector, int on)
intel_sdvo_read_response(intel_output, &response, 2);
}
-static void
-intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
+static bool
+intel_sdvo_multifunc_encoder(struct intel_output *intel_output)
+{
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ int caps = 0;
+
+ if (sdvo_priv->caps.output_flags &
+ (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
+ caps++;
+ if (sdvo_priv->caps.output_flags &
+ (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1))
+ caps++;
+ if (sdvo_priv->caps.output_flags &
+ (SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID0))
+ caps++;
+ if (sdvo_priv->caps.output_flags &
+ (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_CVBS1))
+ caps++;
+ if (sdvo_priv->caps.output_flags &
+ (SDVO_OUTPUT_YPRPB0 | SDVO_OUTPUT_YPRPB1))
+ caps++;
+
+ if (sdvo_priv->caps.output_flags &
+ (SDVO_OUTPUT_SCART0 | SDVO_OUTPUT_SCART1))
+ caps++;
+
+ if (sdvo_priv->caps.output_flags &
+ (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1))
+ caps++;
+
+ return (caps > 1);
+}
+
+enum drm_connector_status
+intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
{
struct intel_output *intel_output = to_intel_output(connector);
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ enum drm_connector_status status = connector_status_connected;
struct edid *edid = NULL;
edid = drm_get_edid(&intel_output->base,
intel_output->ddc_bus);
if (edid != NULL) {
- sdvo_priv->is_hdmi = drm_detect_hdmi_monitor(edid);
+ /* Don't report the output as connected if it's a DVI-I
+ * connector with a non-digital EDID coming out.
+ */
+ if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) {
+ if (edid->input & DRM_EDID_INPUT_DIGITAL)
+ sdvo_priv->is_hdmi =
+ drm_detect_hdmi_monitor(edid);
+ else
+ status = connector_status_disconnected;
+ }
+
kfree(edid);
intel_output->base.display_info.raw_edid = NULL;
- }
+
+ } else if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
+ status = connector_status_disconnected;
+
+ return status;
}
static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector)
{
- u8 response[2];
+ uint16_t response;
u8 status;
struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
status = intel_sdvo_read_response(intel_output, &response, 2);
- DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]);
+ DRM_DEBUG("SDVO response %d %d\n", response & 0xff, response >> 8);
if (status != SDVO_CMD_STATUS_SUCCESS)
return connector_status_unknown;
- if ((response[0] != 0) || (response[1] != 0)) {
- intel_sdvo_hdmi_sink_detect(connector);
- return connector_status_connected;
- } else
+ if (response == 0)
return connector_status_disconnected;
+
+ if (intel_sdvo_multifunc_encoder(intel_output) &&
+ sdvo_priv->attached_output != response) {
+ if (sdvo_priv->controlled_output != response &&
+ intel_sdvo_output_setup(intel_output, response) != true)
+ return connector_status_unknown;
+ sdvo_priv->attached_output = response;
+ }
+ return intel_sdvo_hdmi_sink_detect(connector, response);
}
static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
@@ -1866,16 +1931,101 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device)
return 0x72;
}
+static bool
+intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
+{
+ struct drm_connector *connector = &intel_output->base;
+ struct drm_encoder *encoder = &intel_output->enc;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ bool ret = true, registered = false;
+
+ sdvo_priv->is_tv = false;
+ intel_output->needs_tv_clock = false;
+ sdvo_priv->is_lvds = false;
+
+ if (device_is_registered(&connector->kdev)) {
+ drm_sysfs_connector_remove(connector);
+ registered = true;
+ }
+
+ if (flags &
+ (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) {
+ if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
+ sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS0;
+ else
+ sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1;
+
+ encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
+ connector->connector_type = DRM_MODE_CONNECTOR_DVID;
+
+ if (intel_sdvo_get_supp_encode(intel_output,
+ &sdvo_priv->encode) &&
+ intel_sdvo_get_digital_encoding_mode(intel_output) &&
+ sdvo_priv->is_hdmi) {
+ /* enable hdmi encoding mode if supported */
+ intel_sdvo_set_encode(intel_output, SDVO_ENCODE_HDMI);
+ intel_sdvo_set_colorimetry(intel_output,
+ SDVO_COLORIMETRY_RGB256);
+ connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
+ }
+ } else if (flags & SDVO_OUTPUT_SVID0) {
+
+ sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0;
+ encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
+ connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
+ sdvo_priv->is_tv = true;
+ intel_output->needs_tv_clock = true;
+ } else if (flags & SDVO_OUTPUT_RGB0) {
+
+ sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
+ encoder->encoder_type = DRM_MODE_ENCODER_DAC;
+ connector->connector_type = DRM_MODE_CONNECTOR_VGA;
+ } else if (flags & SDVO_OUTPUT_RGB1) {
+
+ sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
+ encoder->encoder_type = DRM_MODE_ENCODER_DAC;
+ connector->connector_type = DRM_MODE_CONNECTOR_VGA;
+ } else if (flags & SDVO_OUTPUT_LVDS0) {
+
+ sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0;
+ encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
+ connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
+ sdvo_priv->is_lvds = true;
+ } else if (flags & SDVO_OUTPUT_LVDS1) {
+
+ sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1;
+ encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
+ connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
+ sdvo_priv->is_lvds = true;
+ } else {
+
+ unsigned char bytes[2];
+
+ sdvo_priv->controlled_output = 0;
+ memcpy(bytes, &sdvo_priv->caps.output_flags, 2);
+ DRM_DEBUG_KMS(I915_SDVO,
+ "%s: Unknown SDVO output type (0x%02x%02x)\n",
+ SDVO_NAME(sdvo_priv),
+ bytes[0], bytes[1]);
+ ret = false;
+ }
+
+ if (ret && registered)
+ ret = drm_sysfs_connector_add(connector) == 0 ? true : false;
+
+
+ return ret;
+
+}
+
bool intel_sdvo_init(struct drm_device *dev, int output_device)
{
struct drm_connector *connector;
struct intel_output *intel_output;
struct intel_sdvo_priv *sdvo_priv;
- int connector_type;
u8 ch[0x40];
int i;
- int encoder_type;
intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
if (!intel_output) {
@@ -1925,88 +2075,28 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
intel_output->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
/* In defaut case sdvo lvds is false */
- sdvo_priv->is_lvds = false;
intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps);
- if (sdvo_priv->caps.output_flags &
- (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) {
- if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
- sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS0;
- else
- sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1;
-
- encoder_type = DRM_MODE_ENCODER_TMDS;
- connector_type = DRM_MODE_CONNECTOR_DVID;
-
- if (intel_sdvo_get_supp_encode(intel_output,
- &sdvo_priv->encode) &&
- intel_sdvo_get_digital_encoding_mode(intel_output) &&
- sdvo_priv->is_hdmi) {
- /* enable hdmi encoding mode if supported */
- intel_sdvo_set_encode(intel_output, SDVO_ENCODE_HDMI);
- intel_sdvo_set_colorimetry(intel_output,
- SDVO_COLORIMETRY_RGB256);
- connector_type = DRM_MODE_CONNECTOR_HDMIA;
- }
- }
- else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_SVID0)
- {
- sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0;
- encoder_type = DRM_MODE_ENCODER_TVDAC;
- connector_type = DRM_MODE_CONNECTOR_SVIDEO;
- sdvo_priv->is_tv = true;
- intel_output->needs_tv_clock = true;
- }
- else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
- {
- sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
- encoder_type = DRM_MODE_ENCODER_DAC;
- connector_type = DRM_MODE_CONNECTOR_VGA;
- }
- else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1)
- {
- sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
- encoder_type = DRM_MODE_ENCODER_DAC;
- connector_type = DRM_MODE_CONNECTOR_VGA;
- }
- else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS0)
- {
- sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0;
- encoder_type = DRM_MODE_ENCODER_LVDS;
- connector_type = DRM_MODE_CONNECTOR_LVDS;
- sdvo_priv->is_lvds = true;
- }
- else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS1)
- {
- sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1;
- encoder_type = DRM_MODE_ENCODER_LVDS;
- connector_type = DRM_MODE_CONNECTOR_LVDS;
- sdvo_priv->is_lvds = true;
- }
- else
- {
- unsigned char bytes[2];
-
- sdvo_priv->controlled_output = 0;
- memcpy (bytes, &sdvo_priv->caps.output_flags, 2);
- DRM_DEBUG_KMS(I915_SDVO,
- "%s: Unknown SDVO output type (0x%02x%02x)\n",
- SDVO_NAME(sdvo_priv),
- bytes[0], bytes[1]);
- encoder_type = DRM_MODE_ENCODER_NONE;
- connector_type = DRM_MODE_CONNECTOR_Unknown;
+ if (intel_sdvo_output_setup(intel_output,
+ sdvo_priv->caps.output_flags) != true) {
+ DRM_DEBUG("SDVO output failed to setup on SDVO%c\n",
+ output_device == SDVOB ? 'B' : 'C');
goto err_i2c;
}
+
connector = &intel_output->base;
drm_connector_init(dev, connector, &intel_sdvo_connector_funcs,
- connector_type);
+ connector->connector_type);
+
drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
connector->interlace_allowed = 0;
connector->doublescan_allowed = 0;
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
- drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type);
+ drm_encoder_init(dev, &intel_output->enc,
+ &intel_sdvo_enc_funcs, intel_output->enc.encoder_type);
+
drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs);
drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index a43c98e3f07..da4ab4dc163 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1490,6 +1490,27 @@ static struct input_res {
{"1920x1080", 1920, 1080},
};
+/*
+ * Chose preferred mode according to line number of TV format
+ */
+static void
+intel_tv_chose_preferred_modes(struct drm_connector *connector,
+ struct drm_display_mode *mode_ptr)
+{
+ struct intel_output *intel_output = to_intel_output(connector);
+ const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
+
+ if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
+ mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
+ else if (tv_mode->nbr_end > 480) {
+ if (tv_mode->progressive == true && tv_mode->nbr_end < 720) {
+ if (mode_ptr->vdisplay == 720)
+ mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
+ } else if (mode_ptr->vdisplay == 1080)
+ mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
+ }
+}
+
/**
* Stub get_modes function.
*
@@ -1544,6 +1565,7 @@ intel_tv_get_modes(struct drm_connector *connector)
mode_ptr->clock = (int) tmp;
mode_ptr->type = DRM_MODE_TYPE_DRIVER;
+ intel_tv_chose_preferred_modes(connector, mode_ptr);
drm_mode_probed_add(connector, mode_ptr);
count++;
}
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 05a44896dff..f1ba8ff4113 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -722,13 +722,14 @@ int r100_cs_packet_parse(struct radeon_cs_parser *p,
unsigned idx)
{
struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx];
- uint32_t header = ib_chunk->kdata[idx];
+ uint32_t header;
if (idx >= ib_chunk->length_dw) {
DRM_ERROR("Can not parse packet at %d after CS end %d !\n",
idx, ib_chunk->length_dw);
return -EINVAL;
}
+ header = ib_chunk->kdata[idx];
pkt->idx = idx;
pkt->type = CP_PACKET_GET_TYPE(header);
pkt->count = CP_PACKET_GET_COUNT(header);
diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c
index 146f3570af8..20f17908b03 100644
--- a/drivers/gpu/drm/radeon/r600_cp.c
+++ b/drivers/gpu/drm/radeon/r600_cp.c
@@ -384,8 +384,9 @@ static void r600_cp_load_microcode(drm_radeon_private_t *dev_priv)
DRM_INFO("Loading RV670 PFP Microcode\n");
for (i = 0; i < PFP_UCODE_SIZE; i++)
RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV670_pfp_microcode[i]);
- } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) {
- DRM_INFO("Loading RS780 CP Microcode\n");
+ } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880)) {
+ DRM_INFO("Loading RS780/RS880 CP Microcode\n");
for (i = 0; i < PM4_UCODE_SIZE; i++) {
RADEON_WRITE(R600_CP_ME_RAM_DATA,
RS780_cp_microcode[i][0]);
@@ -396,7 +397,7 @@ static void r600_cp_load_microcode(drm_radeon_private_t *dev_priv)
}
RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
- DRM_INFO("Loading RS780 PFP Microcode\n");
+ DRM_INFO("Loading RS780/RS880 PFP Microcode\n");
for (i = 0; i < PFP_UCODE_SIZE; i++)
RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RS780_pfp_microcode[i]);
}
@@ -783,6 +784,7 @@ static void r600_gfx_init(struct drm_device *dev,
break;
case CHIP_RV610:
case CHIP_RS780:
+ case CHIP_RS880:
case CHIP_RV620:
dev_priv->r600_max_pipes = 1;
dev_priv->r600_max_tile_pipes = 1;
@@ -917,7 +919,8 @@ static void r600_gfx_init(struct drm_device *dev,
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV630) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780))
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880))
RADEON_WRITE(R600_DB_DEBUG, R600_PREZ_MUST_WAIT_FOR_POSTZ_DONE);
else
RADEON_WRITE(R600_DB_DEBUG, 0);
@@ -935,7 +938,8 @@ static void r600_gfx_init(struct drm_device *dev,
sq_ms_fifo_sizes = RADEON_READ(R600_SQ_MS_FIFO_SIZES);
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) {
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880)) {
sq_ms_fifo_sizes = (R600_CACHE_FIFO_SIZE(0xa) |
R600_FETCH_FIFO_HIWATER(0xa) |
R600_DONE_FIFO_HIWATER(0xe0) |
@@ -978,7 +982,8 @@ static void r600_gfx_init(struct drm_device *dev,
R600_NUM_ES_STACK_ENTRIES(0));
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) {
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880)) {
/* no vertex cache */
sq_config &= ~R600_VC_ENABLE;
@@ -1035,7 +1040,8 @@ static void r600_gfx_init(struct drm_device *dev,
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780))
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880))
RADEON_WRITE(R600_VGT_CACHE_INVALIDATION, R600_CACHE_INVALIDATION(R600_TC_ONLY));
else
RADEON_WRITE(R600_VGT_CACHE_INVALIDATION, R600_CACHE_INVALIDATION(R600_VC_AND_TC));
@@ -1078,6 +1084,7 @@ static void r600_gfx_init(struct drm_device *dev,
break;
case CHIP_RV610:
case CHIP_RS780:
+ case CHIP_RS880:
case CHIP_RV620:
gs_prim_buffer_depth = 32;
break;
@@ -1123,6 +1130,7 @@ static void r600_gfx_init(struct drm_device *dev,
switch (dev_priv->flags & RADEON_FAMILY_MASK) {
case CHIP_RV610:
case CHIP_RS780:
+ case CHIP_RS880:
case CHIP_RV620:
tc_cntl = R600_TC_L2_SIZE(8);
break;
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index a162ade74b7..9ff6dcb97f9 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -152,7 +152,9 @@ int radeon_mc_setup(struct radeon_device *rdev)
}
} else {
rdev->mc.vram_location = 0;
- rdev->mc.gtt_location = rdev->mc.mc_vram_size;
+ tmp = rdev->mc.mc_vram_size;
+ tmp = (tmp + rdev->mc.gtt_size - 1) & ~(rdev->mc.gtt_size - 1);
+ rdev->mc.gtt_location = tmp;
}
DRM_INFO("radeon: VRAM %uM\n", rdev->mc.real_vram_size >> 20);
DRM_INFO("radeon: VRAM from 0x%08X to 0x%08X\n",
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 3cfcee17dc5..0bd5879a495 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -318,6 +318,14 @@ static int __init radeon_init(void)
driver = &driver_old;
driver->num_ioctls = radeon_max_ioctl;
#if defined(CONFIG_DRM_RADEON_KMS)
+#ifdef CONFIG_VGA_CONSOLE
+ if (vgacon_text_force() && radeon_modeset == -1) {
+ DRM_INFO("VGACON disable radeon kernel modesetting.\n");
+ driver = &driver_old;
+ driver->driver_features &= ~DRIVER_MODESET;
+ radeon_modeset = 0;
+ }
+#endif
/* if enabled by default */
if (radeon_modeset == -1) {
DRM_INFO("radeon default to kernel modesetting.\n");
@@ -329,17 +337,8 @@ static int __init radeon_init(void)
driver->driver_features |= DRIVER_MODESET;
driver->num_ioctls = radeon_max_kms_ioctl;
}
-
/* if the vga console setting is enabled still
* let modprobe override it */
-#ifdef CONFIG_VGA_CONSOLE
- if (vgacon_text_force() && radeon_modeset == -1) {
- DRM_INFO("VGACON disable radeon kernel modesetting.\n");
- driver = &driver_old;
- driver->driver_features &= ~DRIVER_MODESET;
- radeon_modeset = 0;
- }
-#endif
#endif
return drm_init(driver);
}
diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h
index 127d0456f62..3933f8216a3 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.h
+++ b/drivers/gpu/drm/radeon/radeon_drv.h
@@ -143,6 +143,7 @@ enum radeon_family {
CHIP_RV635,
CHIP_RV670,
CHIP_RS780,
+ CHIP_RS880,
CHIP_RV770,
CHIP_RV730,
CHIP_RV710,
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 937a2f1cdb4..3357110e30c 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -58,6 +58,8 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
if (r) {
DRM_ERROR("Failed to initialize radeon, disabling IOCTL\n");
radeon_device_fini(rdev);
+ kfree(rdev);
+ dev->dev_private = NULL;
return r;
}
return 0;
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index dd9ac2fed6d..e98cae3bf4a 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -106,7 +106,7 @@ static inline uint32_t radeon_object_flags_from_domain(uint32_t domain)
flags |= TTM_PL_FLAG_VRAM | TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED;
}
if (domain & RADEON_GEM_DOMAIN_GTT) {
- flags |= TTM_PL_FLAG_TT | TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED;
+ flags |= TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING;
}
if (domain & RADEON_GEM_DOMAIN_CPU) {
flags |= TTM_PL_FLAG_SYSTEM | TTM_PL_MASK_CACHING;
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index 551e608702e..fd8f3ca716e 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -370,6 +370,7 @@ void rv515_vram_info(struct radeon_device *rdev)
rv515_vram_get_type(rdev);
+ r100_vram_init_sizes(rdev);
/* FIXME: we should enforce default clock in case GPU is not in
* default setup
*/
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 6538d423698..c2b0d710d10 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -1182,13 +1182,14 @@ static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type)
{
- struct ttm_mem_type_manager *man = &bdev->man[mem_type];
+ struct ttm_mem_type_manager *man;
int ret = -EINVAL;
if (mem_type >= TTM_NUM_MEM_TYPES) {
printk(KERN_ERR TTM_PFX "Illegal memory type %d\n", mem_type);
return ret;
}
+ man = &bdev->man[mem_type];
if (!man->has_type) {
printk(KERN_ERR TTM_PFX "Trying to take down uninitialized "
@@ -1575,6 +1576,10 @@ int ttm_bo_wait(struct ttm_buffer_object *bo,
driver->sync_obj_unref(&sync_obj);
driver->sync_obj_unref(&tmp_obj);
spin_lock(&bo->lock);
+ } else {
+ spin_unlock(&bo->lock);
+ driver->sync_obj_unref(&sync_obj);
+ spin_lock(&bo->lock);
}
}
return 0;
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index ce2e6f38ea0..ad4ada07c6c 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -150,7 +150,7 @@ static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src,
#ifdef CONFIG_X86
dst = kmap_atomic_prot(d, KM_USER0, prot);
#else
- if (prot != PAGE_KERNEL)
+ if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
dst = vmap(&d, 1, 0, prot);
else
dst = kmap(d);
@@ -163,7 +163,7 @@ static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src,
#ifdef CONFIG_X86
kunmap_atomic(dst, KM_USER0);
#else
- if (prot != PAGE_KERNEL)
+ if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
vunmap(dst);
else
kunmap(d);
@@ -186,7 +186,7 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst,
#ifdef CONFIG_X86
src = kmap_atomic_prot(s, KM_USER0, prot);
#else
- if (prot != PAGE_KERNEL)
+ if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
src = vmap(&s, 1, 0, prot);
else
src = kmap(s);
@@ -199,7 +199,7 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst,
#ifdef CONFIG_X86
kunmap_atomic(src, KM_USER0);
#else
- if (prot != PAGE_KERNEL)
+ if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
vunmap(src);
else
kunmap(s);
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index e9b2e7cb05b..541b981ff07 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -27,6 +27,7 @@ struct matrix_keypad {
const struct matrix_keypad_platform_data *pdata;
struct input_dev *input_dev;
unsigned short *keycodes;
+ unsigned int row_shift;
uint32_t last_key_state[MATRIX_MAX_COLS];
struct delayed_work work;
@@ -136,7 +137,7 @@ static void matrix_keypad_scan(struct work_struct *work)
if ((bits_changed & (1 << row)) == 0)
continue;
- code = (row << 4) + col;
+ code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
input_event(input_dev, EV_MSC, MSC_SCAN, code);
input_report_key(input_dev,
keypad->keycodes[code],
@@ -317,6 +318,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
struct matrix_keypad *keypad;
struct input_dev *input_dev;
unsigned short *keycodes;
+ unsigned int row_shift;
int i;
int err;
@@ -332,14 +334,11 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
return -EINVAL;
}
- if (!keymap_data->max_keymap_size) {
- dev_err(&pdev->dev, "invalid keymap data supplied\n");
- return -EINVAL;
- }
+ row_shift = get_count_order(pdata->num_col_gpios);
keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL);
- keycodes = kzalloc(keymap_data->max_keymap_size *
- sizeof(keypad->keycodes),
+ keycodes = kzalloc((pdata->num_row_gpios << row_shift) *
+ sizeof(*keycodes),
GFP_KERNEL);
input_dev = input_allocate_device();
if (!keypad || !keycodes || !input_dev) {
@@ -350,6 +349,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
keypad->input_dev = input_dev;
keypad->pdata = pdata;
keypad->keycodes = keycodes;
+ keypad->row_shift = row_shift;
keypad->stopped = true;
INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan);
spin_lock_init(&keypad->lock);
@@ -363,7 +363,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
input_dev->keycode = keycodes;
input_dev->keycodesize = sizeof(*keycodes);
- input_dev->keycodemax = keymap_data->max_keymap_size;
+ input_dev->keycodemax = pdata->num_row_gpios << keypad->row_shift;
for (i = 0; i < keymap_data->keymap_size; i++) {
unsigned int key = keymap_data->keymap[i];
@@ -371,7 +371,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
unsigned int col = KEY_COL(key);
unsigned short code = KEY_VAL(key);
- keycodes[(row << 4) + col] = code;
+ keycodes[MATRIX_SCAN_CODE(row, col, row_shift)] = code;
__set_bit(code, input_dev->keybit);
}
__clear_bit(KEY_RESERVED, input_dev->keybit);
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index 26e17a9a22e..27ee976eb54 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -611,6 +611,20 @@ static struct key_entry keymap_wistron_generic[] __initdata = {
{ KE_END, 0 }
};
+static struct key_entry keymap_prestigio[] __initdata = {
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_WIFI, 0x30 },
+ { KE_KEY, 0x22, {KEY_REWIND} },
+ { KE_KEY, 0x23, {KEY_FORWARD} },
+ { KE_KEY, 0x24, {KEY_PLAYPAUSE} },
+ { KE_KEY, 0x25, {KEY_STOPCD} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_END, 0 }
+};
+
+
/*
* If your machine is not here (which is currently rather likely), please send
* a list of buttons and their key codes (reported when loading this module
@@ -971,6 +985,8 @@ static int __init select_keymap(void)
if (keymap_name != NULL) {
if (strcmp (keymap_name, "1557/MS2141") == 0)
keymap = keymap_wistron_ms2141;
+ else if (strcmp (keymap_name, "prestigio") == 0)
+ keymap = keymap_prestigio;
else if (strcmp (keymap_name, "generic") == 0)
keymap = keymap_wistron_generic;
else {
diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c
index b587e2d576a..820e51673b2 100644
--- a/drivers/input/serio/hp_sdc_mlc.c
+++ b/drivers/input/serio/hp_sdc_mlc.c
@@ -296,7 +296,7 @@ static void hp_sdc_mlc_out(hil_mlc *mlc)
priv->tseq[3] = 0;
if (mlc->opacket & HIL_CTRL_APE) {
priv->tseq[3] |= HP_SDC_LPC_APE_IPF;
- down_trylock(&mlc->csem);
+ BUG_ON(down_trylock(&mlc->csem));
}
enqueue:
hp_sdc_enqueue_transaction(&priv->trans);
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 924e8ed7f2c..ae04d8a494e 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -78,6 +78,14 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
},
},
{
+ .ident = "ASUS G1S",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
+ DMI_MATCH(DMI_BOARD_NAME, "G1S"),
+ DMI_MATCH(DMI_BOARD_VERSION, "1.0"),
+ },
+ },
+ {
/* AUX LOOP command does not raise AUX IRQ */
.ident = "ASUS P65UP5",
.matches = {
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c
index c3b661a666c..7e5f30dbc0a 100644
--- a/drivers/isdn/mISDN/l1oip_core.c
+++ b/drivers/isdn/mISDN/l1oip_core.c
@@ -1480,7 +1480,7 @@ l1oip_init(void)
return -ENOMEM;
l1oip_cnt = 0;
- while (type[l1oip_cnt] && l1oip_cnt < MAX_CARDS) {
+ while (l1oip_cnt < MAX_CARDS && type[l1oip_cnt]) {
switch (type[l1oip_cnt] & 0xff) {
case 1:
pri = 0;
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 5810fa906af..5fe39c2a3d2 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -220,6 +220,7 @@ static int linear_run (mddev_t *mddev)
mddev->queue->unplug_fn = linear_unplug;
mddev->queue->backing_dev_info.congested_fn = linear_congested;
mddev->queue->backing_dev_info.congested_data = mddev;
+ md_integrity_register(mddev);
return 0;
}
@@ -256,6 +257,7 @@ static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev)
rcu_assign_pointer(mddev->private, newconf);
md_set_array_sectors(mddev, linear_size(mddev, 0, 0));
set_capacity(mddev->gendisk, mddev->array_sectors);
+ revalidate_disk(mddev->gendisk);
call_rcu(&oldconf->rcu, free_conf);
return 0;
}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index d4351ff0849..5b98bea4ff9 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1308,7 +1308,12 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
}
if (mddev->level != LEVEL_MULTIPATH) {
int role;
- role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
+ if (rdev->desc_nr < 0 ||
+ rdev->desc_nr >= le32_to_cpu(sb->max_dev)) {
+ role = 0xffff;
+ rdev->desc_nr = -1;
+ } else
+ role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
switch(role) {
case 0xffff: /* spare */
break;
@@ -1394,8 +1399,14 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
if (rdev2->desc_nr+1 > max_dev)
max_dev = rdev2->desc_nr+1;
- if (max_dev > le32_to_cpu(sb->max_dev))
+ if (max_dev > le32_to_cpu(sb->max_dev)) {
+ int bmask;
sb->max_dev = cpu_to_le32(max_dev);
+ rdev->sb_size = max_dev * 2 + 256;
+ bmask = queue_logical_block_size(rdev->bdev->bd_disk->queue)-1;
+ if (rdev->sb_size & bmask)
+ rdev->sb_size = (rdev->sb_size | bmask) + 1;
+ }
for (i=0; i<max_dev;i++)
sb->dev_roles[i] = cpu_to_le16(0xfffe);
@@ -1487,37 +1498,76 @@ static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2)
static LIST_HEAD(pending_raid_disks);
-static void md_integrity_check(mdk_rdev_t *rdev, mddev_t *mddev)
+/*
+ * Try to register data integrity profile for an mddev
+ *
+ * This is called when an array is started and after a disk has been kicked
+ * from the array. It only succeeds if all working and active component devices
+ * are integrity capable with matching profiles.
+ */
+int md_integrity_register(mddev_t *mddev)
+{
+ mdk_rdev_t *rdev, *reference = NULL;
+
+ if (list_empty(&mddev->disks))
+ return 0; /* nothing to do */
+ if (blk_get_integrity(mddev->gendisk))
+ return 0; /* already registered */
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
+ /* skip spares and non-functional disks */
+ if (test_bit(Faulty, &rdev->flags))
+ continue;
+ if (rdev->raid_disk < 0)
+ continue;
+ /*
+ * If at least one rdev is not integrity capable, we can not
+ * enable data integrity for the md device.
+ */
+ if (!bdev_get_integrity(rdev->bdev))
+ return -EINVAL;
+ if (!reference) {
+ /* Use the first rdev as the reference */
+ reference = rdev;
+ continue;
+ }
+ /* does this rdev's profile match the reference profile? */
+ if (blk_integrity_compare(reference->bdev->bd_disk,
+ rdev->bdev->bd_disk) < 0)
+ return -EINVAL;
+ }
+ /*
+ * All component devices are integrity capable and have matching
+ * profiles, register the common profile for the md device.
+ */
+ if (blk_integrity_register(mddev->gendisk,
+ bdev_get_integrity(reference->bdev)) != 0) {
+ printk(KERN_ERR "md: failed to register integrity for %s\n",
+ mdname(mddev));
+ return -EINVAL;
+ }
+ printk(KERN_NOTICE "md: data integrity on %s enabled\n",
+ mdname(mddev));
+ return 0;
+}
+EXPORT_SYMBOL(md_integrity_register);
+
+/* Disable data integrity if non-capable/non-matching disk is being added */
+void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev)
{
- struct mdk_personality *pers = mddev->pers;
- struct gendisk *disk = mddev->gendisk;
struct blk_integrity *bi_rdev = bdev_get_integrity(rdev->bdev);
- struct blk_integrity *bi_mddev = blk_get_integrity(disk);
+ struct blk_integrity *bi_mddev = blk_get_integrity(mddev->gendisk);
- /* Data integrity passthrough not supported on RAID 4, 5 and 6 */
- if (pers && pers->level >= 4 && pers->level <= 6)
+ if (!bi_mddev) /* nothing to do */
return;
-
- /* If rdev is integrity capable, register profile for mddev */
- if (!bi_mddev && bi_rdev) {
- if (blk_integrity_register(disk, bi_rdev))
- printk(KERN_ERR "%s: %s Could not register integrity!\n",
- __func__, disk->disk_name);
- else
- printk(KERN_NOTICE "Enabling data integrity on %s\n",
- disk->disk_name);
+ if (rdev->raid_disk < 0) /* skip spares */
return;
- }
-
- /* Check that mddev and rdev have matching profiles */
- if (blk_integrity_compare(disk, rdev->bdev->bd_disk) < 0) {
- printk(KERN_ERR "%s: %s/%s integrity mismatch!\n", __func__,
- disk->disk_name, rdev->bdev->bd_disk->disk_name);
- printk(KERN_NOTICE "Disabling data integrity on %s\n",
- disk->disk_name);
- blk_integrity_unregister(disk);
- }
+ if (bi_rdev && blk_integrity_compare(mddev->gendisk,
+ rdev->bdev->bd_disk) >= 0)
+ return;
+ printk(KERN_NOTICE "disabling data integrity on %s\n", mdname(mddev));
+ blk_integrity_unregister(mddev->gendisk);
}
+EXPORT_SYMBOL(md_integrity_add_rdev);
static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
{
@@ -1591,7 +1641,6 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
/* May as well allow recovery to be retried once */
mddev->recovery_disabled = 0;
- md_integrity_check(rdev, mddev);
return 0;
fail:
@@ -2657,6 +2706,7 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
ssize_t rv = len;
struct mdk_personality *pers;
void *priv;
+ mdk_rdev_t *rdev;
if (mddev->pers == NULL) {
if (len == 0)
@@ -2736,6 +2786,12 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
mddev_suspend(mddev);
mddev->pers->stop(mddev);
module_put(mddev->pers->owner);
+ /* Invalidate devices that are now superfluous */
+ list_for_each_entry(rdev, &mddev->disks, same_set)
+ if (rdev->raid_disk >= mddev->raid_disks) {
+ rdev->raid_disk = -1;
+ clear_bit(In_sync, &rdev->flags);
+ }
mddev->pers = pers;
mddev->private = priv;
strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
@@ -3685,17 +3741,8 @@ array_size_store(mddev_t *mddev, const char *buf, size_t len)
mddev->array_sectors = sectors;
set_capacity(mddev->gendisk, mddev->array_sectors);
- if (mddev->pers) {
- struct block_device *bdev = bdget_disk(mddev->gendisk, 0);
-
- if (bdev) {
- mutex_lock(&bdev->bd_inode->i_mutex);
- i_size_write(bdev->bd_inode,
- (loff_t)mddev->array_sectors << 9);
- mutex_unlock(&bdev->bd_inode->i_mutex);
- bdput(bdev);
- }
- }
+ if (mddev->pers)
+ revalidate_disk(mddev->gendisk);
return len;
}
@@ -4048,10 +4095,6 @@ static int do_md_run(mddev_t * mddev)
}
strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
- if (pers->level >= 4 && pers->level <= 6)
- /* Cannot support integrity (yet) */
- blk_integrity_unregister(mddev->gendisk);
-
if (mddev->reshape_position != MaxSector &&
pers->start_reshape == NULL) {
/* This personality cannot handle reshaping... */
@@ -4189,6 +4232,7 @@ static int do_md_run(mddev_t * mddev)
md_wakeup_thread(mddev->thread);
md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
+ revalidate_disk(mddev->gendisk);
mddev->changed = 1;
md_new_event(mddev);
sysfs_notify_dirent(mddev->sysfs_state);
@@ -5087,18 +5131,8 @@ static int update_size(mddev_t *mddev, sector_t num_sectors)
return -ENOSPC;
}
rv = mddev->pers->resize(mddev, num_sectors);
- if (!rv) {
- struct block_device *bdev;
-
- bdev = bdget_disk(mddev->gendisk, 0);
- if (bdev) {
- mutex_lock(&bdev->bd_inode->i_mutex);
- i_size_write(bdev->bd_inode,
- (loff_t)mddev->array_sectors << 9);
- mutex_unlock(&bdev->bd_inode->i_mutex);
- bdput(bdev);
- }
- }
+ if (!rv)
+ revalidate_disk(mddev->gendisk);
return rv;
}
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 9430a110db9..78f03168baf 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -431,5 +431,7 @@ extern int md_allow_write(mddev_t *mddev);
extern void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev);
extern void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors);
extern int md_check_no_bitmap(mddev_t *mddev);
+extern int md_integrity_register(mddev_t *mddev);
+void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev);
#endif /* _MD_MD_H */
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 237fe3fd235..7140909f666 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -313,6 +313,7 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
set_bit(In_sync, &rdev->flags);
rcu_assign_pointer(p->rdev, rdev);
err = 0;
+ md_integrity_add_rdev(rdev, mddev);
break;
}
@@ -345,7 +346,9 @@ static int multipath_remove_disk(mddev_t *mddev, int number)
/* lost the race, try later */
err = -EBUSY;
p->rdev = rdev;
+ goto abort;
}
+ md_integrity_register(mddev);
}
abort:
@@ -519,7 +522,7 @@ static int multipath_run (mddev_t *mddev)
mddev->queue->unplug_fn = multipath_unplug;
mddev->queue->backing_dev_info.congested_fn = multipath_congested;
mddev->queue->backing_dev_info.congested_data = mddev;
-
+ md_integrity_register(mddev);
return 0;
out_free_conf:
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 335f490dcad..898e2bdfee4 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -351,6 +351,7 @@ static int raid0_run(mddev_t *mddev)
blk_queue_merge_bvec(mddev->queue, raid0_mergeable_bvec);
dump_zones(mddev);
+ md_integrity_register(mddev);
return 0;
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 0569efba0c0..8726fd7ebce 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1144,7 +1144,7 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
rcu_assign_pointer(p->rdev, rdev);
break;
}
-
+ md_integrity_add_rdev(rdev, mddev);
print_conf(conf);
return err;
}
@@ -1178,7 +1178,9 @@ static int raid1_remove_disk(mddev_t *mddev, int number)
/* lost the race, try later */
err = -EBUSY;
p->rdev = rdev;
+ goto abort;
}
+ md_integrity_register(mddev);
}
abort:
@@ -2067,7 +2069,7 @@ static int run(mddev_t *mddev)
mddev->queue->unplug_fn = raid1_unplug;
mddev->queue->backing_dev_info.congested_fn = raid1_congested;
mddev->queue->backing_dev_info.congested_data = mddev;
-
+ md_integrity_register(mddev);
return 0;
out_no_mem:
@@ -2132,6 +2134,7 @@ static int raid1_resize(mddev_t *mddev, sector_t sectors)
return -EINVAL;
set_capacity(mddev->gendisk, mddev->array_sectors);
mddev->changed = 1;
+ revalidate_disk(mddev->gendisk);
if (sectors > mddev->dev_sectors &&
mddev->recovery_cp == MaxSector) {
mddev->recovery_cp = mddev->dev_sectors;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 7298a5e5a18..3d9020cf6f6 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1170,6 +1170,7 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
break;
}
+ md_integrity_add_rdev(rdev, mddev);
print_conf(conf);
return err;
}
@@ -1203,7 +1204,9 @@ static int raid10_remove_disk(mddev_t *mddev, int number)
/* lost the race, try later */
err = -EBUSY;
p->rdev = rdev;
+ goto abort;
}
+ md_integrity_register(mddev);
}
abort:
@@ -2225,6 +2228,7 @@ static int run(mddev_t *mddev)
if (conf->near_copies < mddev->raid_disks)
blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec);
+ md_integrity_register(mddev);
return 0;
out_free_conf:
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 37835538b58..2b521ee67df 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -3999,6 +3999,9 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
return 0;
}
+ /* Allow raid5_quiesce to complete */
+ wait_event(conf->wait_for_overlap, conf->quiesce != 2);
+
if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
return reshape_request(mddev, sector_nr, skipped);
@@ -4316,6 +4319,15 @@ raid5_size(mddev_t *mddev, sector_t sectors, int raid_disks)
return sectors * (raid_disks - conf->max_degraded);
}
+static void free_conf(raid5_conf_t *conf)
+{
+ shrink_stripes(conf);
+ safe_put_page(conf->spare_page);
+ kfree(conf->disks);
+ kfree(conf->stripe_hashtbl);
+ kfree(conf);
+}
+
static raid5_conf_t *setup_conf(mddev_t *mddev)
{
raid5_conf_t *conf;
@@ -4447,11 +4459,7 @@ static raid5_conf_t *setup_conf(mddev_t *mddev)
abort:
if (conf) {
- shrink_stripes(conf);
- safe_put_page(conf->spare_page);
- kfree(conf->disks);
- kfree(conf->stripe_hashtbl);
- kfree(conf);
+ free_conf(conf);
return ERR_PTR(-EIO);
} else
return ERR_PTR(-ENOMEM);
@@ -4629,12 +4637,8 @@ abort:
md_unregister_thread(mddev->thread);
mddev->thread = NULL;
if (conf) {
- shrink_stripes(conf);
print_raid5_conf(conf);
- safe_put_page(conf->spare_page);
- kfree(conf->disks);
- kfree(conf->stripe_hashtbl);
- kfree(conf);
+ free_conf(conf);
}
mddev->private = NULL;
printk(KERN_ALERT "raid5: failed to run raid set %s\n", mdname(mddev));
@@ -4649,13 +4653,10 @@ static int stop(mddev_t *mddev)
md_unregister_thread(mddev->thread);
mddev->thread = NULL;
- shrink_stripes(conf);
- kfree(conf->stripe_hashtbl);
mddev->queue->backing_dev_info.congested_fn = NULL;
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
sysfs_remove_group(&mddev->kobj, &raid5_attrs_group);
- kfree(conf->disks);
- kfree(conf);
+ free_conf(conf);
mddev->private = NULL;
return 0;
}
@@ -4857,6 +4858,7 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors)
return -EINVAL;
set_capacity(mddev->gendisk, mddev->array_sectors);
mddev->changed = 1;
+ revalidate_disk(mddev->gendisk);
if (sectors > mddev->dev_sectors && mddev->recovery_cp == MaxSector) {
mddev->recovery_cp = mddev->dev_sectors;
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
@@ -5002,7 +5004,7 @@ static int raid5_start_reshape(mddev_t *mddev)
spin_unlock_irqrestore(&conf->device_lock, flags);
}
mddev->raid_disks = conf->raid_disks;
- mddev->reshape_position = 0;
+ mddev->reshape_position = conf->reshape_progress;
set_bit(MD_CHANGE_DEVS, &mddev->flags);
clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
@@ -5057,7 +5059,6 @@ static void end_reshape(raid5_conf_t *conf)
*/
static void raid5_finish_reshape(mddev_t *mddev)
{
- struct block_device *bdev;
raid5_conf_t *conf = mddev->private;
if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
@@ -5066,15 +5067,7 @@ static void raid5_finish_reshape(mddev_t *mddev)
md_set_array_sectors(mddev, raid5_size(mddev, 0, 0));
set_capacity(mddev->gendisk, mddev->array_sectors);
mddev->changed = 1;
-
- bdev = bdget_disk(mddev->gendisk, 0);
- if (bdev) {
- mutex_lock(&bdev->bd_inode->i_mutex);
- i_size_write(bdev->bd_inode,
- (loff_t)mddev->array_sectors << 9);
- mutex_unlock(&bdev->bd_inode->i_mutex);
- bdput(bdev);
- }
+ revalidate_disk(mddev->gendisk);
} else {
int d;
mddev->degraded = conf->raid_disks;
@@ -5106,12 +5099,18 @@ static void raid5_quiesce(mddev_t *mddev, int state)
case 1: /* stop all writes */
spin_lock_irq(&conf->device_lock);
- conf->quiesce = 1;
+ /* '2' tells resync/reshape to pause so that all
+ * active stripes can drain
+ */
+ conf->quiesce = 2;
wait_event_lock_irq(conf->wait_for_stripe,
atomic_read(&conf->active_stripes) == 0 &&
atomic_read(&conf->active_aligned_reads) == 0,
conf->device_lock, /* nothing */);
+ conf->quiesce = 1;
spin_unlock_irq(&conf->device_lock);
+ /* allow reshape to continue */
+ wake_up(&conf->wait_for_overlap);
break;
case 0: /* re-enable writes */
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index bae61b22501..7d430835655 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -180,14 +180,9 @@ static struct completion irq_event;
static int twl4030_irq_thread(void *data)
{
long irq = (long)data;
- struct irq_desc *desc = irq_to_desc(irq);
static unsigned i2c_errors;
static const unsigned max_i2c_errors = 100;
- if (!desc) {
- pr_err("twl4030: Invalid IRQ: %ld\n", irq);
- return -EINVAL;
- }
current->flags |= PF_NOFREEZE;
@@ -240,7 +235,7 @@ static int twl4030_irq_thread(void *data)
}
local_irq_enable();
- desc->chip->unmask(irq);
+ enable_irq(irq);
}
return 0;
@@ -255,25 +250,13 @@ static int twl4030_irq_thread(void *data)
* thread. All we do here is acknowledge and mask the interrupt and wakeup
* the kernel thread.
*/
-static void handle_twl4030_pih(unsigned int irq, struct irq_desc *desc)
+static irqreturn_t handle_twl4030_pih(int irq, void *devid)
{
/* Acknowledge, clear *AND* mask the interrupt... */
- desc->chip->ack(irq);
- complete(&irq_event);
-}
-
-static struct task_struct *start_twl4030_irq_thread(long irq)
-{
- struct task_struct *thread;
-
- init_completion(&irq_event);
- thread = kthread_run(twl4030_irq_thread, (void *)irq, "twl4030-irq");
- if (!thread)
- pr_err("twl4030: could not create irq %ld thread!\n", irq);
-
- return thread;
+ disable_irq_nosync(irq);
+ complete(devid);
+ return IRQ_HANDLED;
}
-
/*----------------------------------------------------------------------*/
/*
@@ -734,18 +717,28 @@ int twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
}
/* install an irq handler to demultiplex the TWL4030 interrupt */
- task = start_twl4030_irq_thread(irq_num);
- if (!task) {
- pr_err("twl4030: irq thread FAIL\n");
- status = -ESRCH;
- goto fail;
- }
- set_irq_data(irq_num, task);
- set_irq_chained_handler(irq_num, handle_twl4030_pih);
- return status;
+ init_completion(&irq_event);
+ status = request_irq(irq_num, handle_twl4030_pih, IRQF_DISABLED,
+ "TWL4030-PIH", &irq_event);
+ if (status < 0) {
+ pr_err("twl4030: could not claim irq%d: %d\n", irq_num, status);
+ goto fail_rqirq;
+ }
+
+ task = kthread_run(twl4030_irq_thread, (void *)irq_num, "twl4030-irq");
+ if (IS_ERR(task)) {
+ pr_err("twl4030: could not create irq %d thread!\n", irq_num);
+ status = PTR_ERR(task);
+ goto fail_kthread;
+ }
+ return status;
+fail_kthread:
+ free_irq(irq_num, &irq_event);
+fail_rqirq:
+ /* clean up twl4030_sih_setup */
fail:
for (i = irq_base; i < irq_end; i++)
set_irq_chip_and_handler(i, NULL, NULL);
diff --git a/drivers/mmc/host/sdhci-of.c b/drivers/mmc/host/sdhci-of.c
index 908844327db..1e8aa590bb3 100644
--- a/drivers/mmc/host/sdhci-of.c
+++ b/drivers/mmc/host/sdhci-of.c
@@ -234,7 +234,7 @@ static int __devinit sdhci_of_probe(struct of_device *ofdev,
return -ENODEV;
host = sdhci_alloc_host(&ofdev->dev, sizeof(*of_host));
- if (!host)
+ if (IS_ERR(host))
return -ENOMEM;
of_host = sdhci_priv(host);
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 0b98654d8ee..7a58bd5522f 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -284,13 +284,6 @@ config MTD_L440GX
BE VERY CAREFUL.
-config MTD_SBC8240
- tristate "Flash device on SBC8240"
- depends on MTD_JEDECPROBE && 8260
- help
- Flash access on the SBC8240 board from Wind River. See
- <http://www.windriver.com/products/sbc8240/>
-
config MTD_TQM8XXL
tristate "CFI Flash device mapped on TQM8XXL"
depends on MTD_CFI && TQM8xxL
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 8bae7f9850c..5beb0662d72 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -50,7 +50,6 @@ obj-$(CONFIG_MTD_UCLINUX) += uclinux.o
obj-$(CONFIG_MTD_NETtel) += nettel.o
obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o
obj-$(CONFIG_MTD_H720X) += h720x-flash.o
-obj-$(CONFIG_MTD_SBC8240) += sbc8240.o
obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o
obj-$(CONFIG_MTD_IXP2000) += ixp2000.o
obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o
diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c
index d5374cdcb16..e69de29bb2d 100644
--- a/drivers/mtd/maps/sbc8240.c
+++ b/drivers/mtd/maps/sbc8240.c
@@ -1,250 +0,0 @@
-/*
- * Handle mapping of the flash memory access routines on the SBC8240 board.
- *
- * Carolyn Smith, Tektronix, Inc.
- *
- * This code is GPLed
- */
-
-/*
- * The SBC8240 has 2 flash banks.
- * Bank 0 is a 512 KiB AMD AM29F040B; 8 x 64 KiB sectors.
- * It contains the U-Boot code (7 sectors) and the environment (1 sector).
- * Bank 1 is 4 x 1 MiB AMD AM29LV800BT; 15 x 64 KiB sectors, 1 x 32 KiB sector,
- * 2 x 8 KiB sectors, 1 x 16 KiB sectors.
- * Both parts are JEDEC compatible.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/cfi.h>
-
-#ifdef CONFIG_MTD_PARTITIONS
-#include <linux/mtd/partitions.h>
-#endif
-
-#define DEBUG
-
-#ifdef DEBUG
-# define debugk(fmt,args...) printk(fmt ,##args)
-#else
-# define debugk(fmt,args...)
-#endif
-
-
-#define WINDOW_ADDR0 0xFFF00000 /* 512 KiB */
-#define WINDOW_SIZE0 0x00080000
-#define BUSWIDTH0 1
-
-#define WINDOW_ADDR1 0xFF000000 /* 4 MiB */
-#define WINDOW_SIZE1 0x00400000
-#define BUSWIDTH1 8
-
-#define MSG_PREFIX "sbc8240:" /* prefix for our printk()'s */
-#define MTDID "sbc8240-%d" /* for mtdparts= partitioning */
-
-
-static struct map_info sbc8240_map[2] = {
- {
- .name = "sbc8240 Flash Bank #0",
- .size = WINDOW_SIZE0,
- .bankwidth = BUSWIDTH0,
- },
- {
- .name = "sbc8240 Flash Bank #1",
- .size = WINDOW_SIZE1,
- .bankwidth = BUSWIDTH1,
- }
-};
-
-#define NUM_FLASH_BANKS ARRAY_SIZE(sbc8240_map)
-
-/*
- * The following defines the partition layout of SBC8240 boards.
- *
- * See include/linux/mtd/partitions.h for definition of the
- * mtd_partition structure.
- *
- * The *_max_flash_size is the maximum possible mapped flash size
- * which is not necessarily the actual flash size. It must correspond
- * to the value specified in the mapping definition defined by the
- * "struct map_desc *_io_desc" for the corresponding machine.
- */
-
-#ifdef CONFIG_MTD_PARTITIONS
-
-static struct mtd_partition sbc8240_uboot_partitions [] = {
- /* Bank 0 */
- {
- .name = "U-boot", /* U-Boot Firmware */
- .offset = 0,
- .size = 0x00070000, /* 7 x 64 KiB sectors */
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
- .name = "environment", /* U-Boot environment */
- .offset = 0x00070000,
- .size = 0x00010000, /* 1 x 64 KiB sector */
- },
-};
-
-static struct mtd_partition sbc8240_fs_partitions [] = {
- {
- .name = "jffs", /* JFFS filesystem */
- .offset = 0,
- .size = 0x003C0000, /* 4 * 15 * 64KiB */
- },
- {
- .name = "tmp32",
- .offset = 0x003C0000,
- .size = 0x00020000, /* 4 * 32KiB */
- },
- {
- .name = "tmp8a",
- .offset = 0x003E0000,
- .size = 0x00008000, /* 4 * 8KiB */
- },
- {
- .name = "tmp8b",
- .offset = 0x003E8000,
- .size = 0x00008000, /* 4 * 8KiB */
- },
- {
- .name = "tmp16",
- .offset = 0x003F0000,
- .size = 0x00010000, /* 4 * 16KiB */
- }
-};
-
-/* trivial struct to describe partition information */
-struct mtd_part_def
-{
- int nums;
- unsigned char *type;
- struct mtd_partition* mtd_part;
-};
-
-static struct mtd_info *sbc8240_mtd[NUM_FLASH_BANKS];
-static struct mtd_part_def sbc8240_part_banks[NUM_FLASH_BANKS];
-
-
-#endif /* CONFIG_MTD_PARTITIONS */
-
-
-static int __init init_sbc8240_mtd (void)
-{
- static struct _cjs {
- u_long addr;
- u_long size;
- } pt[NUM_FLASH_BANKS] = {
- {
- .addr = WINDOW_ADDR0,
- .size = WINDOW_SIZE0
- },
- {
- .addr = WINDOW_ADDR1,
- .size = WINDOW_SIZE1
- },
- };
-
- int devicesfound = 0;
- int i,j;
-
- for (i = 0; i < NUM_FLASH_BANKS; i++) {
- printk (KERN_NOTICE MSG_PREFIX
- "Probing 0x%08lx at 0x%08lx\n", pt[i].size, pt[i].addr);
-
- sbc8240_map[i].map_priv_1 =
- (unsigned long) ioremap (pt[i].addr, pt[i].size);
- if (!sbc8240_map[i].map_priv_1) {
- printk (MSG_PREFIX "failed to ioremap\n");
- for (j = 0; j < i; j++) {
- iounmap((void *) sbc8240_map[j].map_priv_1);
- sbc8240_map[j].map_priv_1 = 0;
- }
- return -EIO;
- }
- simple_map_init(&sbc8240_mtd[i]);
-
- sbc8240_mtd[i] = do_map_probe("jedec_probe", &sbc8240_map[i]);
-
- if (sbc8240_mtd[i]) {
- sbc8240_mtd[i]->module = THIS_MODULE;
- devicesfound++;
- } else {
- if (sbc8240_map[i].map_priv_1) {
- iounmap((void *) sbc8240_map[i].map_priv_1);
- sbc8240_map[i].map_priv_1 = 0;
- }
- }
- }
-
- if (!devicesfound) {
- printk(KERN_NOTICE MSG_PREFIX
- "No suppported flash chips found!\n");
- return -ENXIO;
- }
-
-#ifdef CONFIG_MTD_PARTITIONS
- sbc8240_part_banks[0].mtd_part = sbc8240_uboot_partitions;
- sbc8240_part_banks[0].type = "static image";
- sbc8240_part_banks[0].nums = ARRAY_SIZE(sbc8240_uboot_partitions);
- sbc8240_part_banks[1].mtd_part = sbc8240_fs_partitions;
- sbc8240_part_banks[1].type = "static file system";
- sbc8240_part_banks[1].nums = ARRAY_SIZE(sbc8240_fs_partitions);
-
- for (i = 0; i < NUM_FLASH_BANKS; i++) {
-
- if (!sbc8240_mtd[i]) continue;
- if (sbc8240_part_banks[i].nums == 0) {
- printk (KERN_NOTICE MSG_PREFIX
- "No partition info available, registering whole device\n");
- add_mtd_device(sbc8240_mtd[i]);
- } else {
- printk (KERN_NOTICE MSG_PREFIX
- "Using %s partition definition\n", sbc8240_part_banks[i].mtd_part->name);
- add_mtd_partitions (sbc8240_mtd[i],
- sbc8240_part_banks[i].mtd_part,
- sbc8240_part_banks[i].nums);
- }
- }
-#else
- printk(KERN_NOTICE MSG_PREFIX
- "Registering %d flash banks at once\n", devicesfound);
-
- for (i = 0; i < devicesfound; i++) {
- add_mtd_device(sbc8240_mtd[i]);
- }
-#endif /* CONFIG_MTD_PARTITIONS */
-
- return devicesfound == 0 ? -ENXIO : 0;
-}
-
-static void __exit cleanup_sbc8240_mtd (void)
-{
- int i;
-
- for (i = 0; i < NUM_FLASH_BANKS; i++) {
- if (sbc8240_mtd[i]) {
- del_mtd_device (sbc8240_mtd[i]);
- map_destroy (sbc8240_mtd[i]);
- }
- if (sbc8240_map[i].map_priv_1) {
- iounmap ((void *) sbc8240_map[i].map_priv_1);
- sbc8240_map[i].map_priv_1 = 0;
- }
- }
-}
-
-module_init (init_sbc8240_mtd);
-module_exit (cleanup_sbc8240_mtd);
-
-MODULE_LICENSE ("GPL");
-MODULE_AUTHOR ("Carolyn Smith <carolyn.smith@tektronix.com>");
-MODULE_DESCRIPTION ("MTD map driver for SBC8240 boards");
-
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index c3f62654b6d..7baba40c1ed 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -144,7 +144,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode)
struct mtd_blktrans_ops *tr = dev->tr;
int ret = -ENODEV;
- if (!try_module_get(dev->mtd->owner))
+ if (!get_mtd_device(NULL, dev->mtd->index))
goto out;
if (!try_module_get(tr->owner))
@@ -158,7 +158,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode)
ret = 0;
if (tr->open && (ret = tr->open(dev))) {
dev->mtd->usecount--;
- module_put(dev->mtd->owner);
+ put_mtd_device(dev->mtd);
out_tr:
module_put(tr->owner);
}
@@ -177,7 +177,7 @@ static int blktrans_release(struct gendisk *disk, fmode_t mode)
if (!ret) {
dev->mtd->usecount--;
- module_put(dev->mtd->owner);
+ put_mtd_device(dev->mtd);
module_put(tr->owner);
}
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index 208c6faa035..77db5ce24d9 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -29,6 +29,8 @@ static struct mtdblk_dev {
enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
} *mtdblks[MAX_MTD_DEVICES];
+static struct mutex mtdblks_lock;
+
/*
* Cache stuff...
*
@@ -270,15 +272,19 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
+ mutex_lock(&mtdblks_lock);
if (mtdblks[dev]) {
mtdblks[dev]->count++;
+ mutex_unlock(&mtdblks_lock);
return 0;
}
/* OK, it's not open. Create cache info for it */
mtdblk = kzalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
- if (!mtdblk)
+ if (!mtdblk) {
+ mutex_unlock(&mtdblks_lock);
return -ENOMEM;
+ }
mtdblk->count = 1;
mtdblk->mtd = mtd;
@@ -291,6 +297,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
}
mtdblks[dev] = mtdblk;
+ mutex_unlock(&mtdblks_lock);
DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
@@ -304,6 +311,8 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd)
DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
+ mutex_lock(&mtdblks_lock);
+
mutex_lock(&mtdblk->cache_mutex);
write_cached_data(mtdblk);
mutex_unlock(&mtdblk->cache_mutex);
@@ -316,6 +325,9 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd)
vfree(mtdblk->cache_data);
kfree(mtdblk);
}
+
+ mutex_unlock(&mtdblks_lock);
+
DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
return 0;
@@ -376,6 +388,8 @@ static struct mtd_blktrans_ops mtdblock_tr = {
static int __init init_mtdblock(void)
{
+ mutex_init(&mtdblks_lock);
+
return register_mtd_blktrans(&mtdblock_tr);
}
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index fac54a3fa3f..00ebf7af746 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -65,8 +65,8 @@ static void mtd_release(struct device *dev)
static int mtd_cls_suspend(struct device *dev, pm_message_t state)
{
struct mtd_info *mtd = dev_to_mtd(dev);
-
- if (mtd->suspend)
+
+ if (mtd && mtd->suspend)
return mtd->suspend(mtd);
else
return 0;
@@ -76,7 +76,7 @@ static int mtd_cls_resume(struct device *dev)
{
struct mtd_info *mtd = dev_to_mtd(dev);
- if (mtd->resume)
+ if (mtd && mtd->resume)
mtd->resume(mtd);
return 0;
}
@@ -298,6 +298,7 @@ int add_mtd_device(struct mtd_info *mtd)
mtd->dev.class = &mtd_class;
mtd->dev.devt = MTD_DEVT(i);
dev_set_name(&mtd->dev, "mtd%d", i);
+ dev_set_drvdata(&mtd->dev, mtd);
if (device_register(&mtd->dev) != 0) {
mtd_table[i] = NULL;
break;
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index 38d656b9b2e..0108ed42e87 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -266,7 +266,7 @@ static inline int omap2_onenand_bufferram_offset(struct mtd_info *mtd, int area)
if (ONENAND_CURRENT_BUFFERRAM(this)) {
if (area == ONENAND_DATARAM)
- return mtd->writesize;
+ return this->writesize;
if (area == ONENAND_SPARERAM)
return mtd->oobsize;
}
@@ -770,6 +770,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)
}
iounmap(c->onenand.base);
release_mem_region(c->phys_base, ONENAND_IO_SIZE);
+ gpmc_cs_free(c->gpmc_cs);
kfree(c);
return 0;
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 0f2034c3ed2..e4d9ef0c965 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -1254,6 +1254,7 @@ out_free:
if (!ubi->volumes[i])
continue;
kfree(ubi->volumes[i]->eba_tbl);
+ ubi->volumes[i]->eba_tbl = NULL;
}
return err;
}
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index a423131b617..b847745394b 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -781,11 +781,22 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
return -EINVAL;
}
+ /*
+ * Make sure that all PEBs have the same image sequence number.
+ * This allows us to detect situations when users flash UBI
+ * images incorrectly, so that the flash has the new UBI image
+ * and leftovers from the old one. This feature was added
+ * relatively recently, and the sequence number was always
+ * zero, because old UBI implementations always set it to zero.
+ * For this reasons, we do not panic if some PEBs have zero
+ * sequence number, while other PEBs have non-zero sequence
+ * number.
+ */
image_seq = be32_to_cpu(ech->image_seq);
if (!si->image_seq_set) {
ubi->image_seq = image_seq;
si->image_seq_set = 1;
- } else if (ubi->image_seq != image_seq) {
+ } else if (ubi->image_seq && ubi->image_seq != image_seq) {
ubi_err("bad image sequence number %d in PEB %d, "
"expected %d", image_seq, pnum, ubi->image_seq);
ubi_dbg_dump_ec_hdr(ech);
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 3e00fa8ea65..4a7c32895be 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -832,7 +832,9 @@ static int corkscrew_open(struct net_device *dev)
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
vp->rx_ring[i].addr = isa_virt_to_bus(skb->data);
}
- vp->rx_ring[i - 1].next = isa_virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
+ if (i != 0)
+ vp->rx_ring[i - 1].next =
+ isa_virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
outl(isa_virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
}
if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index c34aee91250..c2041685094 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -2721,13 +2721,15 @@ dump_tx_ring(struct net_device *dev)
&vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
issue_and_wait(dev, DownStall);
for (i = 0; i < TX_RING_SIZE; i++) {
- pr_err(" %d: @%p length %8.8x status %8.8x\n", i,
- &vp->tx_ring[i],
+ unsigned int length;
+
#if DO_ZEROCOPY
- le32_to_cpu(vp->tx_ring[i].frag[0].length),
+ length = le32_to_cpu(vp->tx_ring[i].frag[0].length);
#else
- le32_to_cpu(vp->tx_ring[i].length),
+ length = le32_to_cpu(vp->tx_ring[i].length);
#endif
+ pr_err(" %d: @%p length %8.8x status %8.8x\n",
+ i, &vp->tx_ring[i], length,
le32_to_cpu(vp->tx_ring[i].status));
}
if (!stalled)
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 1686dca2874..1f016d66684 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -1474,13 +1474,13 @@ static void eexp_hw_init586(struct net_device *dev)
outw(0x0000, ioaddr + 0x800c);
outw(0x0000, ioaddr + 0x800e);
- for (i = 0; i < (sizeof(start_code)); i+=32) {
+ for (i = 0; i < ARRAY_SIZE(start_code) * 2; i+=32) {
int j;
outw(i, ioaddr + SM_PTR);
- for (j = 0; j < 16; j+=2)
+ for (j = 0; j < 16 && (i+j)/2 < ARRAY_SIZE(start_code); j+=2)
outw(start_code[(i+j)/2],
ioaddr+0x4000+j);
- for (j = 0; j < 16; j+=2)
+ for (j = 0; j < 16 && (i+j+16)/2 < ARRAY_SIZE(start_code); j+=2)
outw(start_code[(i+j+16)/2],
ioaddr+0x8000+j);
}
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 78952f8324e..fa311a95099 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -40,7 +40,7 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0101"
+#define DRV_VERSION "EHEA_0102"
/* eHEA capability flags */
#define DLPAR_PORT_ADD_REM 1
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index e8d46cc1bec..977c3d35827 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -1545,6 +1545,9 @@ static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr)
{
int ret, i;
+ if (pr->qp)
+ netif_napi_del(&pr->napi);
+
ret = ehea_destroy_qp(pr->qp);
if (!ret) {
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index dbf06e9313c..2234118eedb 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -366,9 +366,8 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
return -EINVAL;
}
- priv->rxic = mk_ic_value(
- gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs),
- cvals->rx_max_coalesced_frames);
+ priv->rxic = mk_ic_value(cvals->rx_max_coalesced_frames,
+ gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs));
/* Set up tx coalescing */
if ((cvals->tx_coalesce_usecs == 0) ||
@@ -390,9 +389,8 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
return -EINVAL;
}
- priv->txic = mk_ic_value(
- gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs),
- cvals->tx_max_coalesced_frames);
+ priv->txic = mk_ic_value(cvals->tx_max_coalesced_frames,
+ gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs));
gfar_write(&priv->regs->rxic, 0);
if (priv->rxcoalescing)
diff --git a/drivers/net/igbvf/vf.c b/drivers/net/igbvf/vf.c
index 2a4faf9ade6..a9a61efa964 100644
--- a/drivers/net/igbvf/vf.c
+++ b/drivers/net/igbvf/vf.c
@@ -274,6 +274,8 @@ static s32 e1000_set_vfta_vf(struct e1000_hw *hw, u16 vid, bool set)
err = mbx->ops.read_posted(hw, msgbuf, 2);
+ msgbuf[0] &= ~E1000_VT_MSGTYPE_CTS;
+
/* if nacked the vlan was rejected */
if (!err && (msgbuf[0] == (E1000_VF_SET_VLAN | E1000_VT_MSGTYPE_NACK)))
err = -E1000_ERR_MAC_INIT;
@@ -317,6 +319,8 @@ static void e1000_rar_set_vf(struct e1000_hw *hw, u8 * addr, u32 index)
if (!ret_val)
ret_val = mbx->ops.read_posted(hw, msgbuf, 3);
+ msgbuf[0] &= ~E1000_VT_MSGTYPE_CTS;
+
/* if nacked the address was rejected, use "perm_addr" */
if (!ret_val &&
(msgbuf[0] == (E1000_VF_SET_MAC_ADDR | E1000_VT_MSGTYPE_NACK)))
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index 1b12c7ba275..e11d83d5852 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -96,6 +96,8 @@
#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000
#define IXGBE_TX_FLAGS_VLAN_SHIFT 16
+#define IXGBE_MAX_RSC_INT_RATE 162760
+
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct ixgbe_tx_buffer {
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
index b9923047ce1..522c03bc1da 100644
--- a/drivers/net/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -50,6 +50,51 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset,
u8 *eeprom_data);
/**
+ * ixgbe_set_pcie_completion_timeout - set pci-e completion timeout
+ * @hw: pointer to the HW structure
+ *
+ * The defaults for 82598 should be in the range of 50us to 50ms,
+ * however the hardware default for these parts is 500us to 1ms which is less
+ * than the 10ms recommended by the pci-e spec. To address this we need to
+ * increase the value to either 10ms to 250ms for capability version 1 config,
+ * or 16ms to 55ms for version 2.
+ **/
+void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw)
+{
+ struct ixgbe_adapter *adapter = hw->back;
+ u32 gcr = IXGBE_READ_REG(hw, IXGBE_GCR);
+ u16 pcie_devctl2;
+
+ /* only take action if timeout value is defaulted to 0 */
+ if (gcr & IXGBE_GCR_CMPL_TMOUT_MASK)
+ goto out;
+
+ /*
+ * if capababilities version is type 1 we can write the
+ * timeout of 10ms to 250ms through the GCR register
+ */
+ if (!(gcr & IXGBE_GCR_CAP_VER2)) {
+ gcr |= IXGBE_GCR_CMPL_TMOUT_10ms;
+ goto out;
+ }
+
+ /*
+ * for version 2 capabilities we need to write the config space
+ * directly in order to set the completion timeout value for
+ * 16ms to 55ms
+ */
+ pci_read_config_word(adapter->pdev,
+ IXGBE_PCI_DEVICE_CONTROL2, &pcie_devctl2);
+ pcie_devctl2 |= IXGBE_PCI_DEVICE_CONTROL2_16ms;
+ pci_write_config_word(adapter->pdev,
+ IXGBE_PCI_DEVICE_CONTROL2, pcie_devctl2);
+out:
+ /* disable completion timeout resend */
+ gcr &= ~IXGBE_GCR_CMPL_TMOUT_RESEND;
+ IXGBE_WRITE_REG(hw, IXGBE_GCR, gcr);
+}
+
+/**
* ixgbe_get_pcie_msix_count_82598 - Gets MSI-X vector count
* @hw: pointer to hardware structure
*
@@ -153,6 +198,26 @@ out:
}
/**
+ * ixgbe_start_hw_82598 - Prepare hardware for Tx/Rx
+ * @hw: pointer to hardware structure
+ *
+ * Starts the hardware using the generic start_hw function.
+ * Then set pcie completion timeout
+ **/
+s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw)
+{
+ s32 ret_val = 0;
+
+ ret_val = ixgbe_start_hw_generic(hw);
+
+ /* set the completion timeout for interface */
+ if (ret_val == 0)
+ ixgbe_set_pcie_completion_timeout(hw);
+
+ return ret_val;
+}
+
+/**
* ixgbe_get_link_capabilities_82598 - Determines link capabilities
* @hw: pointer to hardware structure
* @speed: pointer to link speed
@@ -1085,7 +1150,7 @@ out:
static struct ixgbe_mac_operations mac_ops_82598 = {
.init_hw = &ixgbe_init_hw_generic,
.reset_hw = &ixgbe_reset_hw_82598,
- .start_hw = &ixgbe_start_hw_generic,
+ .start_hw = &ixgbe_start_hw_82598,
.clear_hw_cntrs = &ixgbe_clear_hw_cntrs_generic,
.get_media_type = &ixgbe_get_media_type_82598,
.get_supported_physical_layer = &ixgbe_get_supported_physical_layer_82598,
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 2a978008fd6..79144e950a3 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -1975,7 +1975,10 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
* any other value means disable eitr, which is best
* served by setting the interrupt rate very high
*/
- adapter->eitr_param = IXGBE_MAX_INT_RATE;
+ if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
+ adapter->eitr_param = IXGBE_MAX_RSC_INT_RATE;
+ else
+ adapter->eitr_param = IXGBE_MAX_INT_RATE;
adapter->itr_setting = 0;
}
@@ -1999,13 +2002,13 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data)
ethtool_op_set_flags(netdev, data);
- if (!(adapter->flags & IXGBE_FLAG2_RSC_CAPABLE))
+ if (!(adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE))
return 0;
/* if state changes we need to update adapter->flags and reset */
if ((!!(data & ETH_FLAG_LRO)) !=
- (!!(adapter->flags & IXGBE_FLAG2_RSC_ENABLED))) {
- adapter->flags ^= IXGBE_FLAG2_RSC_ENABLED;
+ (!!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))) {
+ adapter->flags2 ^= IXGBE_FLAG2_RSC_ENABLED;
if (netif_running(netdev))
ixgbe_reinit_locked(adapter);
else
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 200454f30f6..110c65ab5cb 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -780,7 +780,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
prefetch(next_rxd);
cleaned_count++;
- if (adapter->flags & IXGBE_FLAG2_RSC_CAPABLE)
+ if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE)
rsc_count = ixgbe_get_rsc_count(rx_desc);
if (rsc_count) {
@@ -2036,7 +2036,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype);
}
} else {
- if (!(adapter->flags & IXGBE_FLAG2_RSC_ENABLED) &&
+ if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) &&
(netdev->mtu <= ETH_DATA_LEN))
rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
else
@@ -2165,7 +2165,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
}
- if (adapter->flags & IXGBE_FLAG2_RSC_ENABLED) {
+ if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
/* Enable 82599 HW-RSC */
for (i = 0; i < adapter->num_rx_queues; i++) {
j = adapter->rx_ring[i].reg_idx;
@@ -3812,8 +3812,8 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82598;
} else if (hw->mac.type == ixgbe_mac_82599EB) {
adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599;
- adapter->flags |= IXGBE_FLAG2_RSC_CAPABLE;
- adapter->flags |= IXGBE_FLAG2_RSC_ENABLED;
+ adapter->flags2 |= IXGBE_FLAG2_RSC_CAPABLE;
+ adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
adapter->ring_feature[RING_F_FDIR].indices =
IXGBE_MAX_FDIR_INDICES;
@@ -5360,12 +5360,19 @@ static int ixgbe_del_sanmac_netdev(struct net_device *dev)
static void ixgbe_netpoll(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ int i;
- disable_irq(adapter->pdev->irq);
adapter->flags |= IXGBE_FLAG_IN_NETPOLL;
- ixgbe_intr(adapter->pdev->irq, netdev);
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+ int num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+ for (i = 0; i < num_q_vectors; i++) {
+ struct ixgbe_q_vector *q_vector = adapter->q_vector[i];
+ ixgbe_msix_clean_many(0, q_vector);
+ }
+ } else {
+ ixgbe_intr(adapter->pdev->irq, netdev);
+ }
adapter->flags &= ~IXGBE_FLAG_IN_NETPOLL;
- enable_irq(adapter->pdev->irq);
}
#endif
@@ -5611,7 +5618,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
- if (adapter->flags & IXGBE_FLAG2_RSC_ENABLED)
+ if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
netdev->features |= NETIF_F_LRO;
/* make sure the EEPROM is good */
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index fa87309dc08..be90eb4575f 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -718,6 +718,12 @@
#define IXGBE_ECC_STATUS_82599 0x110E0
#define IXGBE_BAR_CTRL_82599 0x110F4
+/* PCI Express Control */
+#define IXGBE_GCR_CMPL_TMOUT_MASK 0x0000F000
+#define IXGBE_GCR_CMPL_TMOUT_10ms 0x00001000
+#define IXGBE_GCR_CMPL_TMOUT_RESEND 0x00010000
+#define IXGBE_GCR_CAP_VER2 0x00040000
+
/* Time Sync Registers */
#define IXGBE_TSYNCRXCTL 0x05188 /* Rx Time Sync Control register - RW */
#define IXGBE_TSYNCTXCTL 0x08C00 /* Tx Time Sync Control register - RW */
@@ -1521,6 +1527,7 @@
/* PCI Bus Info */
#define IXGBE_PCI_LINK_STATUS 0xB2
+#define IXGBE_PCI_DEVICE_CONTROL2 0xC8
#define IXGBE_PCI_LINK_WIDTH 0x3F0
#define IXGBE_PCI_LINK_WIDTH_1 0x10
#define IXGBE_PCI_LINK_WIDTH_2 0x20
@@ -1531,6 +1538,7 @@
#define IXGBE_PCI_LINK_SPEED_5000 0x2
#define IXGBE_PCI_HEADER_TYPE_REGISTER 0x0E
#define IXGBE_PCI_HEADER_TYPE_MULTIFUNC 0x80
+#define IXGBE_PCI_DEVICE_CONTROL2_16ms 0x0005
/* Number of 100 microseconds we wait for PCI Express master disable */
#define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800
diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c
index 08c43f2ae72..5a88b3f5769 100644
--- a/drivers/net/mlx4/en_tx.c
+++ b/drivers/net/mlx4/en_tx.c
@@ -249,6 +249,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
pci_unmap_page(mdev->pdev,
(dma_addr_t) be64_to_cpu(data->addr),
frag->size, PCI_DMA_TODEVICE);
+ ++data;
}
}
/* Stamp the freed descriptor */
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 637ac8b89ba..3cd8cfcf627 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -221,7 +221,7 @@ netxen_napi_disable(struct netxen_adapter *adapter)
}
}
-static int nx_set_dma_mask(struct netxen_adapter *adapter, uint8_t revision_id)
+static int nx_set_dma_mask(struct netxen_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
uint64_t mask, cmask;
@@ -229,19 +229,17 @@ static int nx_set_dma_mask(struct netxen_adapter *adapter, uint8_t revision_id)
adapter->pci_using_dac = 0;
mask = DMA_BIT_MASK(32);
- /*
- * Consistent DMA mask is set to 32 bit because it cannot be set to
- * 35 bits. For P3 also leave it at 32 bits for now. Only the rings
- * come off this pool.
- */
cmask = DMA_BIT_MASK(32);
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
#ifndef CONFIG_IA64
- if (revision_id >= NX_P3_B0)
- mask = DMA_BIT_MASK(39);
- else if (revision_id == NX_P2_C1)
mask = DMA_BIT_MASK(35);
#endif
+ } else {
+ mask = DMA_BIT_MASK(39);
+ cmask = mask;
+ }
+
if (pci_set_dma_mask(pdev, mask) == 0 &&
pci_set_consistent_dma_mask(pdev, cmask) == 0) {
adapter->pci_using_dac = 1;
@@ -256,7 +254,7 @@ static int
nx_update_dma_mask(struct netxen_adapter *adapter)
{
int change, shift, err;
- uint64_t mask, old_mask;
+ uint64_t mask, old_mask, old_cmask;
struct pci_dev *pdev = adapter->pdev;
change = 0;
@@ -272,14 +270,29 @@ nx_update_dma_mask(struct netxen_adapter *adapter)
if (change) {
old_mask = pdev->dma_mask;
+ old_cmask = pdev->dev.coherent_dma_mask;
+
mask = (1ULL<<(32+shift)) - 1;
err = pci_set_dma_mask(pdev, mask);
if (err)
- return pci_set_dma_mask(pdev, old_mask);
+ goto err_out;
+
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
+
+ err = pci_set_consistent_dma_mask(pdev, mask);
+ if (err)
+ goto err_out;
+ }
+ dev_info(&pdev->dev, "using %d-bit dma mask\n", 32+shift);
}
return 0;
+
+err_out:
+ pci_set_dma_mask(pdev, old_mask);
+ pci_set_consistent_dma_mask(pdev, old_cmask);
+ return err;
}
static void netxen_check_options(struct netxen_adapter *adapter)
@@ -1006,7 +1019,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
revision_id = pdev->revision;
adapter->ahw.revision_id = revision_id;
- err = nx_set_dma_mask(adapter, revision_id);
+ err = nx_set_dma_mask(adapter);
if (err)
goto err_out_free_netdev;
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 28368157dac..a646a445fda 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -1611,8 +1611,11 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
if (pcnet32_dwio_read_csr(ioaddr, 0) == 4
&& pcnet32_dwio_check(ioaddr)) {
a = &pcnet32_dwio;
- } else
+ } else {
+ if (pcnet32_debug & NETIF_MSG_PROBE)
+ printk(KERN_ERR PFX "No access methods\n");
goto err_release_region;
+ }
}
chip_version =
@@ -1719,7 +1722,9 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
ret = -ENOMEM;
goto err_release_region;
}
- SET_NETDEV_DEV(dev, &pdev->dev);
+
+ if (pdev)
+ SET_NETDEV_DEV(dev, &pdev->dev);
if (pcnet32_debug & NETIF_MSG_PROBE)
printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr);
@@ -1818,7 +1823,6 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
spin_lock_init(&lp->lock);
- SET_NETDEV_DEV(dev, &pdev->dev);
lp->name = chipname;
lp->shared_irq = shared;
lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */
@@ -1852,12 +1856,6 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
((cards_found >= MAX_UNITS) || full_duplex[cards_found]))
lp->options |= PCNET32_PORT_FD;
- if (!a) {
- if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(KERN_ERR PFX "No access methods\n");
- ret = -ENODEV;
- goto err_free_consistent;
- }
lp->a = *a;
/* prior to register_netdev, dev->name is not yet correct */
@@ -1973,14 +1971,13 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
return 0;
- err_free_ring:
+err_free_ring:
pcnet32_free_ring(dev);
- err_free_consistent:
pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block),
lp->init_block, lp->init_dma_addr);
- err_free_netdev:
+err_free_netdev:
free_netdev(dev);
- err_release_region:
+err_release_region:
release_region(ioaddr, PCNET32_TOTAL_SIZE);
return ret;
}
@@ -2089,6 +2086,7 @@ static void pcnet32_free_ring(struct net_device *dev)
static int pcnet32_open(struct net_device *dev)
{
struct pcnet32_private *lp = netdev_priv(dev);
+ struct pci_dev *pdev = lp->pci_dev;
unsigned long ioaddr = dev->base_addr;
u16 val;
int i;
@@ -2149,9 +2147,9 @@ static int pcnet32_open(struct net_device *dev)
lp->a.write_csr(ioaddr, 124, val);
/* Allied Telesyn AT 2700/2701 FX are 100Mbit only and do not negotiate */
- if (lp->pci_dev->subsystem_vendor == PCI_VENDOR_ID_AT &&
- (lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2700FX ||
- lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2701FX)) {
+ if (pdev && pdev->subsystem_vendor == PCI_VENDOR_ID_AT &&
+ (pdev->subsystem_device == PCI_SUBDEVICE_ID_AT_2700FX ||
+ pdev->subsystem_device == PCI_SUBDEVICE_ID_AT_2701FX)) {
if (lp->options & PCNET32_PORT_ASEL) {
lp->options = PCNET32_PORT_FD | PCNET32_PORT_100;
if (netif_msg_link(lp))
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 639d11bc444..cd37d739ac7 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -1384,7 +1384,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
/* create a fragment for each channel */
bits = B;
- while (nfree > 0 && len > 0) {
+ while (len > 0) {
list = list->next;
if (list == &ppp->channels) {
i = 0;
@@ -1431,29 +1431,31 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
*otherwise divide it according to the speed
*of the channel we are going to transmit on
*/
- if (pch->speed == 0) {
- flen = totlen/nfree ;
- if (nbigger > 0) {
- flen++;
- nbigger--;
- }
- } else {
- flen = (((totfree - nzero)*(totlen + hdrlen*totfree)) /
- ((totspeed*totfree)/pch->speed)) - hdrlen;
- if (nbigger > 0) {
- flen += ((totfree - nzero)*pch->speed)/totspeed;
- nbigger -= ((totfree - nzero)*pch->speed)/
+ if (nfree > 0) {
+ if (pch->speed == 0) {
+ flen = totlen/nfree ;
+ if (nbigger > 0) {
+ flen++;
+ nbigger--;
+ }
+ } else {
+ flen = (((totfree - nzero)*(totlen + hdrlen*totfree)) /
+ ((totspeed*totfree)/pch->speed)) - hdrlen;
+ if (nbigger > 0) {
+ flen += ((totfree - nzero)*pch->speed)/totspeed;
+ nbigger -= ((totfree - nzero)*pch->speed)/
totspeed;
+ }
}
+ nfree--;
}
- nfree--;
/*
*check if we are on the last channel or
*we exceded the lenght of the data to
*fragment
*/
- if ((nfree == 0) || (flen > len))
+ if ((nfree <= 0) || (flen > len))
flen = len;
/*
*it is not worth to tx on slow channels:
@@ -1467,7 +1469,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
continue;
}
- mtu = pch->chan->mtu + 2 - hdrlen;
+ mtu = pch->chan->mtu - hdrlen;
if (mtu < 4)
mtu = 4;
if (flen > mtu)
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index f0031f1f97e..5f2090233d7 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -1063,6 +1063,7 @@ static void *pppoe_seq_next(struct seq_file *seq, void *v, loff_t *pos)
else {
int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote);
+ po = NULL;
while (++hash < PPPOE_HASH_SIZE) {
po = pn->hash_table[hash];
if (po)
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index e7935d09c89..e0f9219a0ae 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -2680,6 +2680,7 @@ out_unregister_pppol2tp_proto:
static void __exit pppol2tp_exit(void)
{
unregister_pppox_proto(PX_PROTO_OL2TP);
+ unregister_pernet_gen_device(pppol2tp_net_id, &pppol2tp_net_ops);
proto_unregister(&pppol2tp_sk_proto);
}
diff --git a/drivers/net/s6gmac.c b/drivers/net/s6gmac.c
index 5345e47b35a..4525cbe8dd6 100644
--- a/drivers/net/s6gmac.c
+++ b/drivers/net/s6gmac.c
@@ -793,7 +793,7 @@ static inline int s6gmac_phy_start(struct net_device *dev)
struct s6gmac *pd = netdev_priv(dev);
int i = 0;
struct phy_device *p = NULL;
- while ((!(p = pd->mii.bus->phy_map[i])) && (i < PHY_MAX_ADDR))
+ while ((i < PHY_MAX_ADDR) && (!(p = pd->mii.bus->phy_map[i])))
i++;
p = phy_connect(dev, dev_name(&p->dev), &s6gmac_adjust_link, 0,
PHY_INTERFACE_MODE_RGMII);
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 3550c5dcd93..0a551d8f5d9 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -1488,6 +1488,8 @@ static int sky2_up(struct net_device *dev)
sky2_set_vlan_mode(hw, port, sky2->vlgrp != NULL);
#endif
+ sky2->restarting = 0;
+
err = sky2_rx_start(sky2);
if (err)
goto err_out;
@@ -1500,6 +1502,9 @@ static int sky2_up(struct net_device *dev)
sky2_set_multicast(dev);
+ /* wake queue incase we are restarting */
+ netif_wake_queue(dev);
+
if (netif_msg_ifup(sky2))
printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
return 0;
@@ -1533,6 +1538,8 @@ static inline int tx_dist(unsigned tail, unsigned head)
/* Number of list elements available for next tx */
static inline int tx_avail(const struct sky2_port *sky2)
{
+ if (unlikely(sky2->restarting))
+ return 0;
return sky2->tx_pending - tx_dist(sky2->tx_cons, sky2->tx_prod);
}
@@ -1818,6 +1825,10 @@ static int sky2_down(struct net_device *dev)
if (netif_msg_ifdown(sky2))
printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
+ /* explicitly shut off tx incase we're restarting */
+ sky2->restarting = 1;
+ netif_tx_disable(dev);
+
/* Force flow control off */
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
@@ -2359,7 +2370,7 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
{
struct sky2_port *sky2 = netdev_priv(dev);
- if (netif_running(dev)) {
+ if (likely(netif_running(dev) && !sky2->restarting)) {
netif_tx_lock(dev);
sky2_tx_complete(sky2, last);
netif_tx_unlock(dev);
@@ -4283,6 +4294,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
spin_lock_init(&sky2->phy_lock);
sky2->tx_pending = TX_DEF_PENDING;
sky2->rx_pending = RX_DEF_PENDING;
+ sky2->restarting = 0;
hw->dev[port] = dev;
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index b5549c9e510..4486b066b43 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -2051,6 +2051,7 @@ struct sky2_port {
u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */
u8 rx_csum;
u8 wol;
+ u8 restarting;
enum flow_control flow_mode;
enum flow_control flow_status;
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index eb72d2e9ab3..acfdccd4456 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -5059,7 +5059,7 @@ mii_get_phy(struct net_device *dev)
if ((id == 0) || (id == 65535)) continue; /* Valid ID? */
for (j=0; j<limit; j++) { /* Search PHY table */
if (id != phy_info[j].id) continue; /* ID match? */
- for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++);
+ for (k=0; k < DE4X5_MAX_PHY && lp->phy[k].id; k++);
if (k < DE4X5_MAX_PHY) {
memcpy((char *)&lp->phy[k],
(char *)&phy_info[j], sizeof(struct phy_table));
@@ -5072,7 +5072,7 @@ mii_get_phy(struct net_device *dev)
break;
}
if ((j == limit) && (i < DE4X5_MAX_MII)) {
- for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++);
+ for (k=0; k < DE4X5_MAX_PHY && lp->phy[k].id; k++);
lp->phy[k].addr = i;
lp->phy[k].id = id;
lp->phy[k].spd.reg = GENERIC_REG; /* ANLPA register */
@@ -5091,7 +5091,7 @@ mii_get_phy(struct net_device *dev)
purgatory:
lp->active = 0;
if (lp->phy[0].id) { /* Reset the PHY devices */
- for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++) { /*For each PHY*/
+ for (k=0; k < DE4X5_MAX_PHY && lp->phy[k].id; k++) { /*For each PHY*/
mii_wr(MII_CR_RST, MII_CR, lp->phy[k].addr, DE4X5_MII);
while (mii_rd(MII_CR, lp->phy[k].addr, DE4X5_MII) & MII_CR_RST);
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index c70604f0329..8ce5e4cee16 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -5918,20 +5918,19 @@ static int airo_set_essid(struct net_device *dev,
readSsidRid(local, &SSID_rid);
/* Check if we asked for `any' */
- if(dwrq->flags == 0) {
+ if (dwrq->flags == 0) {
/* Just send an empty SSID list */
memset(&SSID_rid, 0, sizeof(SSID_rid));
} else {
- int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ unsigned index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
/* Check the size of the string */
- if(dwrq->length > IW_ESSID_MAX_SIZE) {
+ if (dwrq->length > IW_ESSID_MAX_SIZE)
return -E2BIG ;
- }
+
/* Check if index is valid */
- if((index < 0) || (index >= 4)) {
+ if (index >= ARRAY_SIZE(SSID_rid.ssids))
return -EINVAL;
- }
/* Set the SSID */
memset(SSID_rid.ssids[index].ssid, 0,
@@ -6819,7 +6818,7 @@ static int airo_set_txpow(struct net_device *dev,
return -EINVAL;
}
clear_bit (FLAG_RADIO_OFF, &local->flags);
- for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
+ for (i = 0; i < 8 && cap_rid.txPowerLevels[i]; i++)
if (v == cap_rid.txPowerLevels[i]) {
readConfigRid(local, 1);
local->config.txPower = v;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index a2fda702b62..ce0e86c36a8 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -460,7 +460,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
integer = swab32(eep->modalHeader.antCtrlCommon);
eep->modalHeader.antCtrlCommon = integer;
- for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
integer = swab32(eep->modalHeader.antCtrlChain[i]);
eep->modalHeader.antCtrlChain[i] = integer;
}
@@ -914,7 +914,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
ctlMode, numCtlModes, isHt40CtlMode,
(pCtlMode[ctlMode] & EXT_ADDITIVE));
- for (i = 0; (i < AR5416_NUM_CTLS) &&
+ for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) &&
pEepData->ctlIndex[i]; i++) {
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
" LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index fbb3a573463..2de6471d4be 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -112,7 +112,7 @@ enum iwl3945_antenna {
#define IWL_TX_FIFO_NONE 7
/* Minimum number of queues. MAX_NUM is defined in hw specific files */
-#define IWL_MIN_NUM_QUEUES 4
+#define IWL39_MIN_NUM_QUEUES 4
#define IEEE80211_DATA_LEN 2304
#define IEEE80211_4ADDR_LEN 30
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 6ab07165ea2..18b135f510e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -1332,6 +1332,9 @@ int iwl_setup_mac(struct iwl_priv *priv)
hw->wiphy->custom_regulatory = true;
+ /* Firmware does not support this */
+ hw->wiphy->disable_beacon_hints = true;
+
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
/* we create the 802.11 header and a zero-length SSID element */
hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 11e08c06891..ca00cc8ad4c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -308,18 +308,18 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
return -ENODATA;
}
+ ptr = priv->eeprom;
+ if (!ptr) {
+ IWL_ERR(priv, "Invalid EEPROM/OTP memory\n");
+ return -ENOMEM;
+ }
+
/* 4 characters for byte 0xYY */
buf = kzalloc(buf_size, GFP_KERNEL);
if (!buf) {
IWL_ERR(priv, "Can not allocate Buffer\n");
return -ENOMEM;
}
-
- ptr = priv->eeprom;
- if (!ptr) {
- IWL_ERR(priv, "Invalid EEPROM/OTP memory\n");
- return -ENOMEM;
- }
pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s\n",
(priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
? "OTP" : "EEPROM");
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index e2d620f0b6e..650e20af20f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -258,8 +258,10 @@ struct iwl_channel_info {
#define IWL_TX_FIFO_HCCA_2 6
#define IWL_TX_FIFO_NONE 7
-/* Minimum number of queues. MAX_NUM is defined in hw specific files */
-#define IWL_MIN_NUM_QUEUES 4
+/* Minimum number of queues. MAX_NUM is defined in hw specific files.
+ * Set the minimum to accommodate the 4 standard TX queues, 1 command
+ * queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */
+#define IWL_MIN_NUM_QUEUES 10
/* Power management (not Tx power) structures */
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 2addf735b19..ffd5c61a755 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -566,6 +566,8 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
unsigned long flags;
spin_lock_irqsave(&priv->sta_lock, flags);
+ IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
+ keyconf->keyidx);
if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table))
IWL_ERR(priv, "index %d not used in uCode key table.\n",
@@ -573,6 +575,11 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
priv->default_wep_key--;
memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n");
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+ }
ret = iwl_send_static_wepkey_cmd(priv, 1);
IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
keyconf->keyidx, ret);
@@ -853,6 +860,11 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled. \n");
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+ }
ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags);
return ret;
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 9bbeec9427f..2e89040e63b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -720,8 +720,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
goto drop_unlock;
}
- spin_unlock_irqrestore(&priv->lock, flags);
-
hdr_len = ieee80211_hdrlen(fc);
/* Find (or create) index into station table for destination station */
@@ -729,7 +727,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);
- goto drop;
+ goto drop_unlock;
}
IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
@@ -750,14 +748,17 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
swq_id = iwl_virtual_agg_queue_num(swq_id, txq_id);
}
- priv->stations[sta_id].tid[tid].tfds_in_queue++;
}
txq = &priv->txq[txq_id];
q = &txq->q;
txq->swq_id = swq_id;
- spin_lock_irqsave(&priv->lock, flags);
+ if (unlikely(iwl_queue_space(q) < q->high_mark))
+ goto drop_unlock;
+
+ if (ieee80211_is_data_qos(fc))
+ priv->stations[sta_id].tid[tid].tfds_in_queue++;
/* Set up driver data for this TFD */
memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
@@ -902,7 +903,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
drop_unlock:
spin_unlock_irqrestore(&priv->lock, flags);
-drop:
return -1;
}
EXPORT_SYMBOL(iwl_tx_skb);
@@ -1171,6 +1171,8 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
IWL_ERR(priv, "Start AGG on invalid station\n");
return -ENXIO;
}
+ if (unlikely(tid >= MAX_TID_COUNT))
+ return -EINVAL;
if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n");
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 956798f2c80..523843369ca 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -3968,6 +3968,9 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
hw->wiphy->custom_regulatory = true;
+ /* Firmware does not support this */
+ hw->wiphy->disable_beacon_hints = true;
+
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;
/* we create the 802.11 header and a zero-length SSID element */
hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
@@ -4018,10 +4021,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
SET_IEEE80211_DEV(hw, &pdev->dev);
if ((iwl3945_mod_params.num_of_queues > IWL39_MAX_NUM_QUEUES) ||
- (iwl3945_mod_params.num_of_queues < IWL_MIN_NUM_QUEUES)) {
+ (iwl3945_mod_params.num_of_queues < IWL39_MIN_NUM_QUEUES)) {
IWL_ERR(priv,
"invalid queues_num, should be between %d and %d\n",
- IWL_MIN_NUM_QUEUES, IWL39_MAX_NUM_QUEUES);
+ IWL39_MIN_NUM_QUEUES, IWL39_MAX_NUM_QUEUES);
err = -EINVAL;
goto out_ieee80211_free_hw;
}
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index 834a7f544e5..e2334d12359 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -220,6 +220,7 @@ int iwm_store_rxiq_calib_result(struct iwm_priv *iwm)
eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ);
if (IS_ERR(eeprom_rxiq)) {
IWM_ERR(iwm, "Couldn't access EEPROM RX IQ entry\n");
+ kfree(rxiq);
return PTR_ERR(eeprom_rxiq);
}
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c
index aea5ccf24cc..bf294e41753 100644
--- a/drivers/net/wireless/iwmc3200wifi/netdev.c
+++ b/drivers/net/wireless/iwmc3200wifi/netdev.c
@@ -106,10 +106,8 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
int ret = 0;
wdev = iwm_wdev_alloc(sizeof_bus, dev);
- if (!wdev) {
- dev_err(dev, "no memory for wireless device instance\n");
- return ERR_PTR(-ENOMEM);
- }
+ if (IS_ERR(wdev))
+ return wdev;
iwm = wdev_to_iwm(wdev);
iwm->bus_ops = if_ops;
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c
index 9a5408e7d94..5c6968101f0 100644
--- a/drivers/net/wireless/libertas/11d.c
+++ b/drivers/net/wireless/libertas/11d.c
@@ -47,7 +47,7 @@ static u8 lbs_region_2_code(u8 *region)
{
u8 i;
- for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++)
+ for (i = 0; i < COUNTRY_CODE_LEN && region[i]; i++)
region[i] = toupper(region[i]);
for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index b9b37411903..d6997371c27 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -1,6 +1,7 @@
/* Copyright (C) 2006, Red Hat, Inc. */
#include <linux/types.h>
+#include <linux/kernel.h>
#include <linux/etherdevice.h>
#include <linux/ieee80211.h>
#include <linux/if_arp.h>
@@ -43,21 +44,21 @@ static int get_common_rates(struct lbs_private *priv,
u16 *rates_size)
{
u8 *card_rates = lbs_bg_rates;
- size_t num_card_rates = sizeof(lbs_bg_rates);
int ret = 0, i, j;
- u8 tmp[30];
+ u8 tmp[(ARRAY_SIZE(lbs_bg_rates) - 1) * (*rates_size - 1)];
size_t tmp_size = 0;
/* For each rate in card_rates that exists in rate1, copy to tmp */
- for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
- for (j = 0; rates[j] && (j < *rates_size); j++) {
+ for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && card_rates[i]; i++) {
+ for (j = 0; j < *rates_size && rates[j]; j++) {
if (rates[j] == card_rates[i])
tmp[tmp_size++] = card_rates[i];
}
}
lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
- lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates);
+ lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates,
+ ARRAY_SIZE(lbs_bg_rates));
lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
@@ -69,10 +70,7 @@ static int get_common_rates(struct lbs_private *priv,
lbs_pr_alert("Previously set fixed data rate %#x isn't "
"compatible with the network.\n", priv->cur_rate);
ret = -1;
- goto done;
}
- ret = 0;
-
done:
memset(rates, 0, *rates_size);
*rates_size = min_t(int, tmp_size, *rates_size);
@@ -322,7 +320,7 @@ static int lbs_associate(struct lbs_private *priv,
rates = (struct mrvl_ie_rates_param_set *) pos;
rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
memcpy(&rates->rates, &bss->rates, MAX_RATES);
- tmplen = MAX_RATES;
+ tmplen = min_t(u16, ARRAY_SIZE(rates->rates), MAX_RATES);
if (get_common_rates(priv, rates->rates, &tmplen)) {
ret = -1;
goto done;
@@ -598,7 +596,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
/* Copy Data rates from the rates recorded in scan response */
memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
- ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES);
+ ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), MAX_RATES);
memcpy(cmd.bss.rates, bss->rates, ratesize);
if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 601b5424967..6c95af3023c 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -5,6 +5,7 @@
* for sending scan commands to the firmware.
*/
#include <linux/types.h>
+#include <linux/kernel.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <asm/unaligned.h>
@@ -876,7 +877,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
iwe.u.bitrate.disabled = 0;
iwe.u.bitrate.value = 0;
- for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) {
+ for (j = 0; j < ARRAY_SIZE(bss->rates) && bss->rates[j]; j++) {
/* Bit rate given in 500 kb/s units */
iwe.u.bitrate.value = bss->rates[j] * 500000;
current_val = iwe_stream_add_value(info, start, current_val,
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 40b07b98822..3bd3c779fff 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -698,7 +698,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
&& !mac->pass_ctrl)
return 0;
- fc = *(__le16 *)buffer;
+ fc = get_unaligned((__le16*)buffer);
need_padding = ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc);
skb = dev_alloc_skb(length + (need_padding ? 2 : 0));
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index 0f0e0b919ef..a45b0c0d574 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -70,7 +70,6 @@
#undef CCIO_COLLECT_STATS
#endif
-#include <linux/proc_fs.h>
#include <asm/runway.h> /* for proc_runway_root */
#ifdef DEBUG_CCIO_INIT
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index c590974e981..d69bde6a234 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -614,7 +614,7 @@ dino_fixup_bus(struct pci_bus *bus)
dev_name(&bus->self->dev), i,
bus->self->resource[i].start,
bus->self->resource[i].end);
- pci_assign_resource(bus->self, i);
+ WARN_ON(pci_assign_resource(bus->self, i));
DBG("DEBUG %s after assign %d [0x%lx,0x%lx]\n",
dev_name(&bus->self->dev), i,
bus->self->resource[i].start,
diff --git a/drivers/parisc/eisa_eeprom.c b/drivers/parisc/eisa_eeprom.c
index 685d94e69d4..8c0b26e9b98 100644
--- a/drivers/parisc/eisa_eeprom.c
+++ b/drivers/parisc/eisa_eeprom.c
@@ -55,7 +55,7 @@ static ssize_t eisa_eeprom_read(struct file * file,
ssize_t ret;
int i;
- if (*ppos >= HPEE_MAX_LENGTH)
+ if (*ppos < 0 || *ppos >= HPEE_MAX_LENGTH)
return 0;
count = *ppos + count < HPEE_MAX_LENGTH ? count : HPEE_MAX_LENGTH - *ppos;
diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c
index 13856415b43..815db175d42 100644
--- a/drivers/parisc/hppb.c
+++ b/drivers/parisc/hppb.c
@@ -62,7 +62,8 @@ static int hppb_probe(struct parisc_device *dev)
}
card = card->next;
}
- printk(KERN_INFO "Found GeckoBoa at 0x%x\n", dev->hpa.start);
+ printk(KERN_INFO "Found GeckoBoa at 0x%llx\n",
+ (unsigned long long) dev->hpa.start);
card->hpa = dev->hpa.start;
card->mmio_region.name = "HP-PB Bus";
@@ -73,8 +74,10 @@ static int hppb_probe(struct parisc_device *dev)
status = ccio_request_resource(dev, &card->mmio_region);
if(status < 0) {
- printk(KERN_ERR "%s: failed to claim HP-PB bus space (%08x, %08x)\n",
- __FILE__, card->mmio_region.start, card->mmio_region.end);
+ printk(KERN_ERR "%s: failed to claim HP-PB "
+ "bus space (0x%08llx, 0x%08llx)\n",
+ __FILE__, (unsigned long long) card->mmio_region.start,
+ (unsigned long long) card->mmio_region.end);
}
return 0;
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index ede614616f8..3aeb3279c92 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -992,7 +992,7 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
return;
io_pdc_cell = kzalloc(sizeof(pdc_pat_cell_mod_maddr_block_t), GFP_KERNEL);
- if (!pa_pdc_cell) {
+ if (!io_pdc_cell) {
kfree(pa_pdc_cell);
return;
}
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
index f9f9a5f1bbd..13a64bc081b 100644
--- a/drivers/parisc/pdc_stable.c
+++ b/drivers/parisc/pdc_stable.c
@@ -370,7 +370,7 @@ pdcspath_layer_read(struct pdcspath_entry *entry, char *buf)
if (!i) /* entry is not ready */
return -ENODATA;
- for (i = 0; devpath->layers[i] && (likely(i < 6)); i++)
+ for (i = 0; i < 6 && devpath->layers[i]; i++)
out += sprintf(out, "%u ", devpath->layers[i]);
out += sprintf(out, "\n");
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index ebc9b8dca88..2314ad7ee5f 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -1505,7 +1505,6 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
}
set_bit(num, iommu->domain_ids);
- set_bit(iommu->seq_id, &domain->iommu_bmp);
iommu->domains[num] = domain;
id = num;
}
@@ -1648,6 +1647,14 @@ static int domain_context_mapped(struct pci_dev *pdev)
tmp->devfn);
}
+/* Returns a number of VTD pages, but aligned to MM page size */
+static inline unsigned long aligned_nrpages(unsigned long host_addr,
+ size_t size)
+{
+ host_addr &= ~PAGE_MASK;
+ return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
+}
+
static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
struct scatterlist *sg, unsigned long phys_pfn,
unsigned long nr_pages, int prot)
@@ -1675,7 +1682,7 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
uint64_t tmp;
if (!sg_res) {
- sg_res = (sg->offset + sg->length + VTD_PAGE_SIZE - 1) >> VTD_PAGE_SHIFT;
+ sg_res = aligned_nrpages(sg->offset, sg->length);
sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
sg->dma_length = sg->length;
pteval = page_to_phys(sg_page(sg)) | prot;
@@ -2415,14 +2422,6 @@ error:
return ret;
}
-/* Returns a number of VTD pages, but aligned to MM page size */
-static inline unsigned long aligned_nrpages(unsigned long host_addr,
- size_t size)
-{
- host_addr &= ~PAGE_MASK;
- return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
-}
-
/* This takes a number of _MM_ pages, not VTD pages */
static struct iova *intel_alloc_iova(struct device *dev,
struct dmar_domain *domain,
@@ -2551,6 +2550,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
int prot = 0;
int ret;
struct intel_iommu *iommu;
+ unsigned long paddr_pfn = paddr >> PAGE_SHIFT;
BUG_ON(dir == DMA_NONE);
@@ -2585,7 +2585,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
* is not a big problem
*/
ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
- paddr >> VTD_PAGE_SHIFT, size, prot);
+ mm_to_dma_pfn(paddr_pfn), size, prot);
if (ret)
goto error;
@@ -2875,7 +2875,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
- ret = domain_sg_mapping(domain, start_vpfn, sglist, mm_to_dma_pfn(size), prot);
+ ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
if (unlikely(ret)) {
/* clear the page */
dma_pte_clear_range(domain, start_vpfn,
@@ -3408,6 +3408,7 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width)
domain->iommu_count = 0;
domain->iommu_coherency = 0;
+ domain->iommu_snooping = 0;
domain->max_addr = 0;
/* always allocate the top pgd */
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index b711fb7181e..1898c7b4790 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -100,16 +100,16 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
{
struct resource *res = &dev->resource[resource];
struct resource *root;
- char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
int err;
root = pci_find_parent_resource(dev, res);
err = -EINVAL;
if (root != NULL)
- err = insert_resource(root, res);
+ err = request_resource(root, res);
if (err) {
+ const char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
dev_err(&dev->dev, "BAR %d: %s of %s %pR\n",
resource,
root ? "address space collision on" :
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 46dad12f952..77c6097ced8 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -277,31 +277,6 @@ config THINKPAD_ACPI_UNSAFE_LEDS
Say N here, unless you are building a kernel for your own
use, and need to control the important firmware LEDs.
-config THINKPAD_ACPI_DOCK
- bool "Legacy Docking Station Support"
- depends on THINKPAD_ACPI
- depends on ACPI_DOCK=n
- default n
- ---help---
- Allows the thinkpad_acpi driver to handle docking station events.
- This support was made obsolete by the generic ACPI docking station
- support (CONFIG_ACPI_DOCK). It will allow locking and removing the
- laptop from the docking station, but will not properly connect PCI
- devices.
-
- If you are not sure, say N here.
-
-config THINKPAD_ACPI_BAY
- bool "Legacy Removable Bay Support"
- depends on THINKPAD_ACPI
- default y
- ---help---
- Allows the thinkpad_acpi driver to handle removable bays. It will
- electrically disable the device in the bay, and also generate
- notifications when the bay lever is ejected or inserted.
-
- If you are not sure, say Y here.
-
config THINKPAD_ACPI_VIDEO
bool "Video output control support"
depends on THINKPAD_ACPI
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index ec560f16d72..222ffb892f2 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -143,6 +143,7 @@ struct eeepc_hotk {
struct rfkill *bluetooth_rfkill;
struct rfkill *wwan3g_rfkill;
struct hotplug_slot *hotplug_slot;
+ struct work_struct hotplug_work;
};
/* The actual device the driver binds to */
@@ -660,7 +661,7 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
return 0;
}
-static void eeepc_rfkill_hotplug(void)
+static void eeepc_hotplug_work(struct work_struct *work)
{
struct pci_dev *dev;
struct pci_bus *bus = pci_find_bus(0, 1);
@@ -701,7 +702,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
if (event != ACPI_NOTIFY_BUS_CHECK)
return;
- eeepc_rfkill_hotplug();
+ schedule_work(&ehotk->hotplug_work);
}
static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
@@ -892,7 +893,7 @@ static int eeepc_hotk_resume(struct acpi_device *device)
rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1);
- eeepc_rfkill_hotplug();
+ schedule_work(&ehotk->hotplug_work);
}
if (ehotk->bluetooth_rfkill)
@@ -1093,6 +1094,8 @@ static int eeepc_rfkill_init(struct device *dev)
{
int result = 0;
+ INIT_WORK(&ehotk->hotplug_work, eeepc_hotplug_work);
+
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index ca508564a18..a2ad53e1587 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -520,11 +520,13 @@ static int hp_wmi_resume_handler(struct platform_device *device)
* the input layer will only actually pass it on if the state
* changed.
*/
-
- input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
- input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
- hp_wmi_tablet_state());
- input_sync(hp_wmi_input_dev);
+ if (hp_wmi_input_dev) {
+ input_report_switch(hp_wmi_input_dev, SW_DOCK,
+ hp_wmi_dock_state());
+ input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
+ hp_wmi_tablet_state());
+ input_sync(hp_wmi_input_dev);
+ }
return 0;
}
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index a463fd72c49..e8560085250 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -239,12 +239,6 @@ struct ibm_init_struct {
};
static struct {
-#ifdef CONFIG_THINKPAD_ACPI_BAY
- u32 bay_status:1;
- u32 bay_eject:1;
- u32 bay_status2:1;
- u32 bay_eject2:1;
-#endif
u32 bluetooth:1;
u32 hotkey:1;
u32 hotkey_mask:1;
@@ -589,18 +583,6 @@ static int acpi_ec_write(int i, u8 v)
return 1;
}
-#if defined(CONFIG_THINKPAD_ACPI_DOCK) || defined(CONFIG_THINKPAD_ACPI_BAY)
-static int _sta(acpi_handle handle)
-{
- int status;
-
- if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
- status = 0;
-
- return status;
-}
-#endif
-
static int issue_thinkpad_cmos_command(int cmos_cmd)
{
if (!cmos_handle)
@@ -784,6 +766,8 @@ static int dispatch_procfs_write(struct file *file,
if (!ibm || !ibm->write)
return -EINVAL;
+ if (count > PAGE_SIZE - 2)
+ return -EINVAL;
kernbuf = kmalloc(count + 2, GFP_KERNEL);
if (!kernbuf)
@@ -4442,293 +4426,6 @@ static struct ibm_struct light_driver_data = {
};
/*************************************************************************
- * Dock subdriver
- */
-
-#ifdef CONFIG_THINKPAD_ACPI_DOCK
-
-static void dock_notify(struct ibm_struct *ibm, u32 event);
-static int dock_read(char *p);
-static int dock_write(char *buf);
-
-TPACPI_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
- "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
- "\\_SB.PCI0.PCI1.DOCK", /* all others */
- "\\_SB.PCI.ISA.SLCE", /* 570 */
- ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
-
-/* don't list other alternatives as we install a notify handler on the 570 */
-TPACPI_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
-
-static const struct acpi_device_id ibm_pci_device_ids[] = {
- {PCI_ROOT_HID_STRING, 0},
- {"", 0},
-};
-
-static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
- {
- .notify = dock_notify,
- .handle = &dock_handle,
- .type = ACPI_SYSTEM_NOTIFY,
- },
- {
- /* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING.
- * We just use it to get notifications of dock hotplug
- * in very old thinkpads */
- .hid = ibm_pci_device_ids,
- .notify = dock_notify,
- .handle = &pci_handle,
- .type = ACPI_SYSTEM_NOTIFY,
- },
-};
-
-static struct ibm_struct dock_driver_data[2] = {
- {
- .name = "dock",
- .read = dock_read,
- .write = dock_write,
- .acpi = &ibm_dock_acpidriver[0],
- },
- {
- .name = "dock",
- .acpi = &ibm_dock_acpidriver[1],
- },
-};
-
-#define dock_docked() (_sta(dock_handle) & 1)
-
-static int __init dock_init(struct ibm_init_struct *iibm)
-{
- vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n");
-
- TPACPI_ACPIHANDLE_INIT(dock);
-
- vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n",
- str_supported(dock_handle != NULL));
-
- return (dock_handle)? 0 : 1;
-}
-
-static int __init dock_init2(struct ibm_init_struct *iibm)
-{
- int dock2_needed;
-
- vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver part 2\n");
-
- if (dock_driver_data[0].flags.acpi_driver_registered &&
- dock_driver_data[0].flags.acpi_notify_installed) {
- TPACPI_ACPIHANDLE_INIT(pci);
- dock2_needed = (pci_handle != NULL);
- vdbg_printk(TPACPI_DBG_INIT,
- "dock PCI handler for the TP 570 is %s\n",
- str_supported(dock2_needed));
- } else {
- vdbg_printk(TPACPI_DBG_INIT,
- "dock subdriver part 2 not required\n");
- dock2_needed = 0;
- }
-
- return (dock2_needed)? 0 : 1;
-}
-
-static void dock_notify(struct ibm_struct *ibm, u32 event)
-{
- int docked = dock_docked();
- int pci = ibm->acpi->hid && ibm->acpi->device &&
- acpi_match_device_ids(ibm->acpi->device, ibm_pci_device_ids);
- int data;
-
- if (event == 1 && !pci) /* 570 */
- data = 1; /* button */
- else if (event == 1 && pci) /* 570 */
- data = 3; /* dock */
- else if (event == 3 && docked)
- data = 1; /* button */
- else if (event == 3 && !docked)
- data = 2; /* undock */
- else if (event == 0 && docked)
- data = 3; /* dock */
- else {
- printk(TPACPI_ERR "unknown dock event %d, status %d\n",
- event, _sta(dock_handle));
- data = 0; /* unknown */
- }
- acpi_bus_generate_proc_event(ibm->acpi->device, event, data);
- acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
- dev_name(&ibm->acpi->device->dev),
- event, data);
-}
-
-static int dock_read(char *p)
-{
- int len = 0;
- int docked = dock_docked();
-
- if (!dock_handle)
- len += sprintf(p + len, "status:\t\tnot supported\n");
- else if (!docked)
- len += sprintf(p + len, "status:\t\tundocked\n");
- else {
- len += sprintf(p + len, "status:\t\tdocked\n");
- len += sprintf(p + len, "commands:\tdock, undock\n");
- }
-
- return len;
-}
-
-static int dock_write(char *buf)
-{
- char *cmd;
-
- if (!dock_docked())
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (strlencmp(cmd, "undock") == 0) {
- if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) ||
- !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
- return -EIO;
- } else if (strlencmp(cmd, "dock") == 0) {
- if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
- return -EIO;
- } else
- return -EINVAL;
- }
-
- return 0;
-}
-
-#endif /* CONFIG_THINKPAD_ACPI_DOCK */
-
-/*************************************************************************
- * Bay subdriver
- */
-
-#ifdef CONFIG_THINKPAD_ACPI_BAY
-
-TPACPI_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
- "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
- "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
- "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
- ); /* A21e, R30, R31 */
-TPACPI_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
- "_EJ0", /* all others */
- ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
-TPACPI_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
- "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
- ); /* all others */
-TPACPI_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
- "_EJ0", /* 770x */
- ); /* all others */
-
-static int __init bay_init(struct ibm_init_struct *iibm)
-{
- vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n");
-
- TPACPI_ACPIHANDLE_INIT(bay);
- if (bay_handle)
- TPACPI_ACPIHANDLE_INIT(bay_ej);
- TPACPI_ACPIHANDLE_INIT(bay2);
- if (bay2_handle)
- TPACPI_ACPIHANDLE_INIT(bay2_ej);
-
- tp_features.bay_status = bay_handle &&
- acpi_evalf(bay_handle, NULL, "_STA", "qv");
- tp_features.bay_status2 = bay2_handle &&
- acpi_evalf(bay2_handle, NULL, "_STA", "qv");
-
- tp_features.bay_eject = bay_handle && bay_ej_handle &&
- (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental);
- tp_features.bay_eject2 = bay2_handle && bay2_ej_handle &&
- (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental);
-
- vdbg_printk(TPACPI_DBG_INIT,
- "bay 1: status %s, eject %s; bay 2: status %s, eject %s\n",
- str_supported(tp_features.bay_status),
- str_supported(tp_features.bay_eject),
- str_supported(tp_features.bay_status2),
- str_supported(tp_features.bay_eject2));
-
- return (tp_features.bay_status || tp_features.bay_eject ||
- tp_features.bay_status2 || tp_features.bay_eject2)? 0 : 1;
-}
-
-static void bay_notify(struct ibm_struct *ibm, u32 event)
-{
- acpi_bus_generate_proc_event(ibm->acpi->device, event, 0);
- acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
- dev_name(&ibm->acpi->device->dev),
- event, 0);
-}
-
-#define bay_occupied(b) (_sta(b##_handle) & 1)
-
-static int bay_read(char *p)
-{
- int len = 0;
- int occupied = bay_occupied(bay);
- int occupied2 = bay_occupied(bay2);
- int eject, eject2;
-
- len += sprintf(p + len, "status:\t\t%s\n",
- tp_features.bay_status ?
- (occupied ? "occupied" : "unoccupied") :
- "not supported");
- if (tp_features.bay_status2)
- len += sprintf(p + len, "status2:\t%s\n", occupied2 ?
- "occupied" : "unoccupied");
-
- eject = tp_features.bay_eject && occupied;
- eject2 = tp_features.bay_eject2 && occupied2;
-
- if (eject && eject2)
- len += sprintf(p + len, "commands:\teject, eject2\n");
- else if (eject)
- len += sprintf(p + len, "commands:\teject\n");
- else if (eject2)
- len += sprintf(p + len, "commands:\teject2\n");
-
- return len;
-}
-
-static int bay_write(char *buf)
-{
- char *cmd;
-
- if (!tp_features.bay_eject && !tp_features.bay_eject2)
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (tp_features.bay_eject && strlencmp(cmd, "eject") == 0) {
- if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1))
- return -EIO;
- } else if (tp_features.bay_eject2 &&
- strlencmp(cmd, "eject2") == 0) {
- if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1))
- return -EIO;
- } else
- return -EINVAL;
- }
-
- return 0;
-}
-
-static struct tp_acpi_drv_struct ibm_bay_acpidriver = {
- .notify = bay_notify,
- .handle = &bay_handle,
- .type = ACPI_SYSTEM_NOTIFY,
-};
-
-static struct ibm_struct bay_driver_data = {
- .name = "bay",
- .read = bay_read,
- .write = bay_write,
- .acpi = &ibm_bay_acpidriver,
-};
-
-#endif /* CONFIG_THINKPAD_ACPI_BAY */
-
-/*************************************************************************
* CMOS subdriver
*/
@@ -5945,14 +5642,48 @@ static struct backlight_ops ibm_backlight_data = {
/* --------------------------------------------------------------------- */
+/*
+ * These are only useful for models that have only one possibility
+ * of GPU. If the BIOS model handles both ATI and Intel, don't use
+ * these quirks.
+ */
+#define TPACPI_BRGHT_Q_NOEC 0x0001 /* Must NOT use EC HBRV */
+#define TPACPI_BRGHT_Q_EC 0x0002 /* Should or must use EC HBRV */
+#define TPACPI_BRGHT_Q_ASK 0x8000 /* Ask for user report */
+
+static const struct tpacpi_quirk brightness_quirk_table[] __initconst = {
+ /* Models with ATI GPUs known to require ECNVRAM mode */
+ TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */
+
+ /* Models with ATI GPUs (waiting confirmation) */
+ TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
+ TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
+ TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
+ TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
+
+ /* Models with Intel Extreme Graphics 2 (waiting confirmation) */
+ TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC),
+ TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC),
+ TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC),
+
+ /* Models with Intel GMA900 */
+ TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */
+ TPACPI_Q_IBM('7', '4', TPACPI_BRGHT_Q_NOEC), /* X41 */
+ TPACPI_Q_IBM('7', '5', TPACPI_BRGHT_Q_NOEC), /* X41 Tablet */
+};
+
static int __init brightness_init(struct ibm_init_struct *iibm)
{
int b;
+ unsigned long quirks;
vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
mutex_init(&brightness_mutex);
+ quirks = tpacpi_check_quirks(brightness_quirk_table,
+ ARRAY_SIZE(brightness_quirk_table));
+
/*
* We always attempt to detect acpi support, so as to switch
* Lenovo Vista BIOS to ACPI brightness mode even if we are not
@@ -6009,23 +5740,13 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
/* TPACPI_BRGHT_MODE_AUTO not implemented yet, just use default */
if (brightness_mode == TPACPI_BRGHT_MODE_AUTO ||
brightness_mode == TPACPI_BRGHT_MODE_MAX) {
- if (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) {
- /*
- * IBM models that define HBRV probably have
- * EC-based backlight level control
- */
- if (acpi_evalf(ec_handle, NULL, "HBRV", "qd"))
- /* T40-T43, R50-R52, R50e, R51e, X31-X41 */
- brightness_mode = TPACPI_BRGHT_MODE_ECNVRAM;
- else
- /* all other IBM ThinkPads */
- brightness_mode = TPACPI_BRGHT_MODE_UCMS_STEP;
- } else
- /* All Lenovo ThinkPads */
+ if (quirks & TPACPI_BRGHT_Q_EC)
+ brightness_mode = TPACPI_BRGHT_MODE_ECNVRAM;
+ else
brightness_mode = TPACPI_BRGHT_MODE_UCMS_STEP;
dbg_printk(TPACPI_DBG_BRGHT,
- "selected brightness_mode=%d\n",
+ "driver auto-selected brightness_mode=%d\n",
brightness_mode);
}
@@ -6052,6 +5773,15 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
"brightness is supported\n");
+ if (quirks & TPACPI_BRGHT_Q_ASK) {
+ printk(TPACPI_NOTICE
+ "brightness: will use unverified default: "
+ "brightness_mode=%d\n", brightness_mode);
+ printk(TPACPI_NOTICE
+ "brightness: please report to %s whether it works well "
+ "or not on your ThinkPad\n", TPACPI_MAIL);
+ }
+
ibm_backlight_device->props.max_brightness =
(tp_features.bright_16levels)? 15 : 7;
ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
@@ -7854,22 +7584,6 @@ static struct ibm_init_struct ibms_init[] __initdata = {
.init = light_init,
.data = &light_driver_data,
},
-#ifdef CONFIG_THINKPAD_ACPI_DOCK
- {
- .init = dock_init,
- .data = &dock_driver_data[0],
- },
- {
- .init = dock_init2,
- .data = &dock_driver_data[1],
- },
-#endif
-#ifdef CONFIG_THINKPAD_ACPI_BAY
- {
- .init = bay_init,
- .data = &bay_driver_data,
- },
-#endif
{
.init = cmos_init,
.data = &cmos_driver_data,
@@ -7968,12 +7682,6 @@ TPACPI_PARAM(hotkey);
TPACPI_PARAM(bluetooth);
TPACPI_PARAM(video);
TPACPI_PARAM(light);
-#ifdef CONFIG_THINKPAD_ACPI_DOCK
-TPACPI_PARAM(dock);
-#endif
-#ifdef CONFIG_THINKPAD_ACPI_BAY
-TPACPI_PARAM(bay);
-#endif /* CONFIG_THINKPAD_ACPI_BAY */
TPACPI_PARAM(cmos);
TPACPI_PARAM(led);
TPACPI_PARAM(beep);
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 8030e25152f..c75d6f35cb5 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -553,40 +553,35 @@ static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
_zfcp_erp_unit_reopen(unit, clear, id, ref);
}
-static void zfcp_erp_strategy_followup_actions(struct zfcp_erp_action *act)
+static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
{
- struct zfcp_adapter *adapter = act->adapter;
- struct zfcp_port *port = act->port;
- struct zfcp_unit *unit = act->unit;
- u32 status = act->status;
-
- /* initiate follow-up actions depending on success of finished action */
switch (act->action) {
-
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
- if (status == ZFCP_ERP_SUCCEEDED)
- _zfcp_erp_port_reopen_all(adapter, 0, "ersfa_1", NULL);
- else
- _zfcp_erp_adapter_reopen(adapter, 0, "ersfa_2", NULL);
+ _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL);
break;
-
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
- if (status == ZFCP_ERP_SUCCEEDED)
- _zfcp_erp_port_reopen(port, 0, "ersfa_3", NULL);
- else
- _zfcp_erp_adapter_reopen(adapter, 0, "ersfa_4", NULL);
+ _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL);
break;
-
case ZFCP_ERP_ACTION_REOPEN_PORT:
- if (status == ZFCP_ERP_SUCCEEDED)
- _zfcp_erp_unit_reopen_all(port, 0, "ersfa_5", NULL);
- else
- _zfcp_erp_port_forced_reopen(port, 0, "ersfa_6", NULL);
+ _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);
break;
-
case ZFCP_ERP_ACTION_REOPEN_UNIT:
- if (status != ZFCP_ERP_SUCCEEDED)
- _zfcp_erp_port_reopen(unit->port, 0, "ersfa_7", NULL);
+ _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL);
+ break;
+ }
+}
+
+static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act)
+{
+ switch (act->action) {
+ case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
+ _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL);
+ break;
+ case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
+ _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL);
+ break;
+ case ZFCP_ERP_ACTION_REOPEN_PORT:
+ _zfcp_erp_unit_reopen_all(act->port, 0, "ersfs_3", NULL);
break;
}
}
@@ -801,7 +796,7 @@ static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
return ZFCP_ERP_FAILED;
case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
- if (status & ZFCP_STATUS_PORT_PHYS_OPEN)
+ if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN))
return ZFCP_ERP_SUCCEEDED;
}
return ZFCP_ERP_FAILED;
@@ -853,11 +848,17 @@ void zfcp_erp_port_strategy_open_lookup(struct work_struct *work)
gid_pn_work);
retval = zfcp_fc_ns_gid_pn(&port->erp_action);
- if (retval == -ENOMEM)
- zfcp_erp_notify(&port->erp_action, ZFCP_ERP_NOMEM);
- port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
- if (retval)
- zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED);
+ if (!retval) {
+ port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
+ goto out;
+ }
+ if (retval == -ENOMEM) {
+ zfcp_erp_notify(&port->erp_action, ZFCP_STATUS_ERP_LOWMEM);
+ goto out;
+ }
+ /* all other error condtions */
+ zfcp_erp_notify(&port->erp_action, 0);
+out:
zfcp_port_put(port);
}
@@ -1289,7 +1290,10 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
retval = zfcp_erp_strategy_statechange(erp_action, retval);
if (retval == ZFCP_ERP_EXIT)
goto unlock;
- zfcp_erp_strategy_followup_actions(erp_action);
+ if (retval == ZFCP_ERP_SUCCEEDED)
+ zfcp_erp_strategy_followup_success(erp_action);
+ if (retval == ZFCP_ERP_FAILED)
+ zfcp_erp_strategy_followup_failed(erp_action);
unlock:
write_unlock(&adapter->erp_lock);
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 2f0705d76b7..47daebfa7e5 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -79,11 +79,9 @@ static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port)
mutex_unlock(&wka_port->mutex);
- wait_event_timeout(
- wka_port->completion_wq,
- wka_port->status == ZFCP_WKA_PORT_ONLINE ||
- wka_port->status == ZFCP_WKA_PORT_OFFLINE,
- HZ >> 1);
+ wait_event(wka_port->completion_wq,
+ wka_port->status == ZFCP_WKA_PORT_ONLINE ||
+ wka_port->status == ZFCP_WKA_PORT_OFFLINE);
if (wka_port->status == ZFCP_WKA_PORT_ONLINE) {
atomic_inc(&wka_port->refcount);
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index c57658f3d34..47795fbf081 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -670,8 +670,11 @@ static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter)
zfcp_fsf_sbal_check(adapter), 5 * HZ);
if (ret > 0)
return 0;
- if (!ret)
+ if (!ret) {
atomic_inc(&adapter->qdio_outb_full);
+ /* assume hanging outbound queue, try queue recovery */
+ zfcp_erp_adapter_reopen(adapter, 0, "fsrsg_1", NULL);
+ }
spin_lock_bh(&adapter->req_q_lock);
return -EIO;
@@ -722,7 +725,7 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter,
req = zfcp_fsf_alloc_qtcb(pool);
if (unlikely(!req))
- return ERR_PTR(-EIO);
+ return ERR_PTR(-ENOMEM);
if (adapter->req_no == 0)
adapter->req_no++;
@@ -1010,6 +1013,23 @@ skip_fsfstatus:
send_ct->handler(send_ct->handler_data);
}
+static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale,
+ struct scatterlist *sg_req,
+ struct scatterlist *sg_resp)
+{
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
+ sbale[2].addr = sg_virt(sg_req);
+ sbale[2].length = sg_req->length;
+ sbale[3].addr = sg_virt(sg_resp);
+ sbale[3].length = sg_resp->length;
+ sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
+}
+
+static int zfcp_fsf_one_sbal(struct scatterlist *sg)
+{
+ return sg_is_last(sg) && sg->length <= PAGE_SIZE;
+}
+
static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
struct scatterlist *sg_req,
struct scatterlist *sg_resp,
@@ -1020,30 +1040,30 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
int bytes;
if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) {
- if (sg_req->length > PAGE_SIZE || sg_resp->length > PAGE_SIZE ||
- !sg_is_last(sg_req) || !sg_is_last(sg_resp))
+ if (!zfcp_fsf_one_sbal(sg_req) || !zfcp_fsf_one_sbal(sg_resp))
return -EOPNOTSUPP;
- sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
- sbale[2].addr = sg_virt(sg_req);
- sbale[2].length = sg_req->length;
- sbale[3].addr = sg_virt(sg_resp);
- sbale[3].length = sg_resp->length;
- sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
+ zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
+ return 0;
+ }
+
+ /* use single, unchained SBAL if it can hold the request */
+ if (zfcp_fsf_one_sbal(sg_req) && zfcp_fsf_one_sbal(sg_resp)) {
+ zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
return 0;
}
bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
sg_req, max_sbals);
if (bytes <= 0)
- return -ENOMEM;
+ return -EIO;
req->qtcb->bottom.support.req_buf_length = bytes;
req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
sg_resp, max_sbals);
if (bytes <= 0)
- return -ENOMEM;
+ return -EIO;
req->qtcb->bottom.support.resp_buf_length = bytes;
return 0;
@@ -1607,10 +1627,10 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
case FSF_ACCESS_DENIED:
wka_port->status = ZFCP_WKA_PORT_OFFLINE;
break;
- case FSF_PORT_ALREADY_OPEN:
- break;
case FSF_GOOD:
wka_port->handle = header->port_handle;
+ /* fall through */
+ case FSF_PORT_ALREADY_OPEN:
wka_port->status = ZFCP_WKA_PORT_ONLINE;
}
out:
@@ -1731,15 +1751,16 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
zfcp_fsf_access_denied_port(req, port);
break;
case FSF_PORT_BOXED:
- zfcp_erp_port_boxed(port, "fscpph2", req);
- req->status |= ZFCP_STATUS_FSFREQ_ERROR |
- ZFCP_STATUS_FSFREQ_RETRY;
/* can't use generic zfcp_erp_modify_port_status because
* ZFCP_STATUS_COMMON_OPEN must not be reset for the port */
atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
list_for_each_entry(unit, &port->unit_list_head, list)
atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
&unit->status);
+ zfcp_erp_port_boxed(port, "fscpph2", req);
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR |
+ ZFCP_STATUS_FSFREQ_RETRY;
+
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
switch (header->fsf_status_qual.word[0]) {
@@ -2541,7 +2562,6 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
bytes = zfcp_qdio_sbals_from_sg(req, direction, fsf_cfdc->sg,
FSF_MAX_SBALS_PER_REQ);
if (bytes != ZFCP_CFDC_MAX_SIZE) {
- retval = -ENOMEM;
zfcp_fsf_req_free(req);
goto out;
}
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 967ede73f4c..6925a178468 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -167,20 +167,21 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
struct zfcp_unit *unit = scpnt->device->hostdata;
struct zfcp_fsf_req *old_req, *abrt_req;
unsigned long flags;
- unsigned long old_req_id = (unsigned long) scpnt->host_scribble;
+ unsigned long old_reqid = (unsigned long) scpnt->host_scribble;
int retval = SUCCESS;
int retry = 3;
+ char *dbf_tag;
/* avoid race condition between late normal completion and abort */
write_lock_irqsave(&adapter->abort_lock, flags);
spin_lock(&adapter->req_list_lock);
- old_req = zfcp_reqlist_find(adapter, old_req_id);
+ old_req = zfcp_reqlist_find(adapter, old_reqid);
spin_unlock(&adapter->req_list_lock);
if (!old_req) {
write_unlock_irqrestore(&adapter->abort_lock, flags);
zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL,
- old_req_id);
+ old_reqid);
return FAILED; /* completion could be in progress */
}
old_req->data = NULL;
@@ -189,7 +190,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
write_unlock_irqrestore(&adapter->abort_lock, flags);
while (retry--) {
- abrt_req = zfcp_fsf_abort_fcp_command(old_req_id, unit);
+ abrt_req = zfcp_fsf_abort_fcp_command(old_reqid, unit);
if (abrt_req)
break;
@@ -197,7 +198,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING)) {
zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL,
- old_req_id);
+ old_reqid);
return SUCCESS;
}
}
@@ -208,13 +209,14 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
abrt_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED)
- zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, abrt_req, 0);
+ dbf_tag = "okay";
else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED)
- zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, abrt_req, 0);
+ dbf_tag = "lte2";
else {
- zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, abrt_req, 0);
+ dbf_tag = "fail";
retval = FAILED;
}
+ zfcp_scsi_dbf_event_abort(dbf_tag, adapter, scpnt, abrt_req, old_reqid);
zfcp_fsf_req_free(abrt_req);
return retval;
}
@@ -534,6 +536,9 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port)
struct fc_rport_identifiers ids;
struct fc_rport *rport;
+ if (port->rport)
+ return;
+
ids.node_name = port->wwnn;
ids.port_name = port->wwpn;
ids.port_id = port->d_id;
@@ -557,8 +562,10 @@ static void zfcp_scsi_rport_block(struct zfcp_port *port)
{
struct fc_rport *rport = port->rport;
- if (rport)
+ if (rport) {
fc_remote_port_delete(rport);
+ port->rport = NULL;
+ }
}
void zfcp_scsi_schedule_rport_register(struct zfcp_port *port)
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index 3e51e64d110..0fe5cce818c 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -494,9 +494,14 @@ static ssize_t zfcp_sysfs_adapter_q_full_show(struct device *dev,
struct Scsi_Host *scsi_host = class_to_shost(dev);
struct zfcp_adapter *adapter =
(struct zfcp_adapter *) scsi_host->hostdata[0];
+ u64 util;
+
+ spin_lock_bh(&adapter->qdio_stat_lock);
+ util = adapter->req_q_util;
+ spin_unlock_bh(&adapter->qdio_stat_lock);
return sprintf(buf, "%d %llu\n", atomic_read(&adapter->qdio_outb_full),
- (unsigned long long)adapter->req_q_util);
+ (unsigned long long)util);
}
static DEVICE_ATTR(queue_full, S_IRUGO, zfcp_sysfs_adapter_q_full_show, NULL);
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index 2bc22be5f84..145ab9ba55e 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -415,9 +415,9 @@ static void fc_exch_timeout(struct work_struct *work)
e_stat = ep->esb_stat;
if (e_stat & ESB_ST_COMPLETE) {
ep->esb_stat = e_stat & ~ESB_ST_REC_QUAL;
+ spin_unlock_bh(&ep->ex_lock);
if (e_stat & ESB_ST_REC_QUAL)
fc_exch_rrq(ep);
- spin_unlock_bh(&ep->ex_lock);
goto done;
} else {
resp = ep->resp;
@@ -1624,14 +1624,14 @@ static void fc_exch_rrq(struct fc_exch *ep)
struct fc_lport *lp;
struct fc_els_rrq *rrq;
struct fc_frame *fp;
- struct fc_seq *rrq_sp;
u32 did;
lp = ep->lp;
fp = fc_frame_alloc(lp, sizeof(*rrq));
if (!fp)
- return;
+ goto retry;
+
rrq = fc_frame_payload_get(fp, sizeof(*rrq));
memset(rrq, 0, sizeof(*rrq));
rrq->rrq_cmd = ELS_RRQ;
@@ -1647,13 +1647,20 @@ static void fc_exch_rrq(struct fc_exch *ep)
fc_host_port_id(lp->host), FC_TYPE_ELS,
FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
- rrq_sp = fc_exch_seq_send(lp, fp, fc_exch_rrq_resp, NULL, ep,
- lp->e_d_tov);
- if (!rrq_sp) {
- ep->esb_stat |= ESB_ST_REC_QUAL;
- fc_exch_timer_set_locked(ep, ep->r_a_tov);
+ if (fc_exch_seq_send(lp, fp, fc_exch_rrq_resp, NULL, ep, lp->e_d_tov))
+ return;
+
+retry:
+ spin_lock_bh(&ep->ex_lock);
+ if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) {
+ spin_unlock_bh(&ep->ex_lock);
+ /* drop hold for rec qual */
+ fc_exch_release(ep);
return;
}
+ ep->esb_stat |= ESB_ST_REC_QUAL;
+ fc_exch_timer_set_locked(ep, ep->r_a_tov);
+ spin_unlock_bh(&ep->ex_lock);
}
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 716cc344c5d..a751f6230c2 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1974,10 +1974,10 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
* good and have never sent us a successful tmf response
* then sent more data for the cmd.
*/
- spin_lock(&session->lock);
+ spin_lock_bh(&session->lock);
fail_scsi_task(task, DID_ABORT);
conn->tmf_state = TMF_INITIAL;
- spin_unlock(&session->lock);
+ spin_unlock_bh(&session->lock);
iscsi_start_tx(conn);
goto success_unlocked;
case TMF_TIMEDOUT:
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 54fa1e42dc4..b3381959acc 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -766,6 +766,7 @@ static int sas_ex_join_wide_port(struct domain_device *parent, int phy_id)
if (!memcmp(phy->attached_sas_addr, ephy->attached_sas_addr,
SAS_ADDR_SIZE) && ephy->port) {
sas_port_add_phy(ephy->port, phy->phy);
+ phy->port = ephy->port;
phy->phy_state = PHY_DEVICE_DISCOVERED;
return 0;
}
@@ -945,11 +946,21 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
if (ex->ex_phy[i].phy_state == PHY_VACANT ||
ex->ex_phy[i].phy_state == PHY_NOT_PRESENT)
continue;
-
+ /*
+ * Due to races, the phy might not get added to the
+ * wide port, so we add the phy to the wide port here.
+ */
if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) ==
- SAS_ADDR(child->sas_addr))
+ SAS_ADDR(child->sas_addr)) {
ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED;
+ res = sas_ex_join_wide_port(dev, i);
+ if (!res)
+ SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n",
+ i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr));
+
+ }
}
+ res = 0;
}
return res;
@@ -1598,7 +1609,7 @@ static int sas_get_phy_attached_sas_addr(struct domain_device *dev,
}
static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id,
- int from_phy)
+ int from_phy, bool update)
{
struct expander_device *ex = &dev->ex_dev;
int res = 0;
@@ -1611,7 +1622,9 @@ static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id,
if (res)
goto out;
else if (phy_change_count != ex->ex_phy[i].phy_change_count) {
- ex->ex_phy[i].phy_change_count = phy_change_count;
+ if (update)
+ ex->ex_phy[i].phy_change_count =
+ phy_change_count;
*phy_id = i;
return 0;
}
@@ -1653,31 +1666,52 @@ out:
kfree(rg_req);
return res;
}
+/**
+ * sas_find_bcast_dev - find the device issue BROADCAST(CHANGE).
+ * @dev:domain device to be detect.
+ * @src_dev: the device which originated BROADCAST(CHANGE).
+ *
+ * Add self-configuration expander suport. Suppose two expander cascading,
+ * when the first level expander is self-configuring, hotplug the disks in
+ * second level expander, BROADCAST(CHANGE) will not only be originated
+ * in the second level expander, but also be originated in the first level
+ * expander (see SAS protocol SAS 2r-14, 7.11 for detail), it is to say,
+ * expander changed count in two level expanders will all increment at least
+ * once, but the phy which chang count has changed is the source device which
+ * we concerned.
+ */
static int sas_find_bcast_dev(struct domain_device *dev,
struct domain_device **src_dev)
{
struct expander_device *ex = &dev->ex_dev;
int ex_change_count = -1;
+ int phy_id = -1;
int res;
+ struct domain_device *ch;
res = sas_get_ex_change_count(dev, &ex_change_count);
if (res)
goto out;
- if (ex_change_count != -1 &&
- ex_change_count != ex->ex_change_count) {
- *src_dev = dev;
- ex->ex_change_count = ex_change_count;
- } else {
- struct domain_device *ch;
-
- list_for_each_entry(ch, &ex->children, siblings) {
- if (ch->dev_type == EDGE_DEV ||
- ch->dev_type == FANOUT_DEV) {
- res = sas_find_bcast_dev(ch, src_dev);
- if (src_dev)
- return res;
- }
+ if (ex_change_count != -1 && ex_change_count != ex->ex_change_count) {
+ /* Just detect if this expander phys phy change count changed,
+ * in order to determine if this expander originate BROADCAST,
+ * and do not update phy change count field in our structure.
+ */
+ res = sas_find_bcast_phy(dev, &phy_id, 0, false);
+ if (phy_id != -1) {
+ *src_dev = dev;
+ ex->ex_change_count = ex_change_count;
+ SAS_DPRINTK("Expander phy change count has changed\n");
+ return res;
+ } else
+ SAS_DPRINTK("Expander phys DID NOT change\n");
+ }
+ list_for_each_entry(ch, &ex->children, siblings) {
+ if (ch->dev_type == EDGE_DEV || ch->dev_type == FANOUT_DEV) {
+ res = sas_find_bcast_dev(ch, src_dev);
+ if (src_dev)
+ return res;
}
}
out:
@@ -1700,24 +1734,26 @@ static void sas_unregister_ex_tree(struct domain_device *dev)
}
static void sas_unregister_devs_sas_addr(struct domain_device *parent,
- int phy_id)
+ int phy_id, bool last)
{
struct expander_device *ex_dev = &parent->ex_dev;
struct ex_phy *phy = &ex_dev->ex_phy[phy_id];
struct domain_device *child, *n;
-
- list_for_each_entry_safe(child, n, &ex_dev->children, siblings) {
- if (SAS_ADDR(child->sas_addr) ==
- SAS_ADDR(phy->attached_sas_addr)) {
- if (child->dev_type == EDGE_DEV ||
- child->dev_type == FANOUT_DEV)
- sas_unregister_ex_tree(child);
- else
- sas_unregister_dev(child);
- break;
+ if (last) {
+ list_for_each_entry_safe(child, n,
+ &ex_dev->children, siblings) {
+ if (SAS_ADDR(child->sas_addr) ==
+ SAS_ADDR(phy->attached_sas_addr)) {
+ if (child->dev_type == EDGE_DEV ||
+ child->dev_type == FANOUT_DEV)
+ sas_unregister_ex_tree(child);
+ else
+ sas_unregister_dev(child);
+ break;
+ }
}
+ sas_disable_routing(parent, phy->attached_sas_addr);
}
- sas_disable_routing(parent, phy->attached_sas_addr);
memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
sas_port_delete_phy(phy->port, phy->phy);
if (phy->port->num_phys == 0)
@@ -1770,15 +1806,31 @@ static int sas_discover_new(struct domain_device *dev, int phy_id)
{
struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id];
struct domain_device *child;
- int res;
+ bool found = false;
+ int res, i;
SAS_DPRINTK("ex %016llx phy%d new device attached\n",
SAS_ADDR(dev->sas_addr), phy_id);
res = sas_ex_phy_discover(dev, phy_id);
if (res)
goto out;
+ /* to support the wide port inserted */
+ for (i = 0; i < dev->ex_dev.num_phys; i++) {
+ struct ex_phy *ex_phy_temp = &dev->ex_dev.ex_phy[i];
+ if (i == phy_id)
+ continue;
+ if (SAS_ADDR(ex_phy_temp->attached_sas_addr) ==
+ SAS_ADDR(ex_phy->attached_sas_addr)) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ sas_ex_join_wide_port(dev, phy_id);
+ return 0;
+ }
res = sas_ex_discover_devices(dev, phy_id);
- if (res)
+ if (!res)
goto out;
list_for_each_entry(child, &dev->ex_dev.children, siblings) {
if (SAS_ADDR(child->sas_addr) ==
@@ -1793,7 +1845,7 @@ out:
return res;
}
-static int sas_rediscover_dev(struct domain_device *dev, int phy_id)
+static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last)
{
struct expander_device *ex = &dev->ex_dev;
struct ex_phy *phy = &ex->ex_phy[phy_id];
@@ -1804,11 +1856,11 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id)
switch (res) {
case SMP_RESP_NO_PHY:
phy->phy_state = PHY_NOT_PRESENT;
- sas_unregister_devs_sas_addr(dev, phy_id);
+ sas_unregister_devs_sas_addr(dev, phy_id, last);
goto out; break;
case SMP_RESP_PHY_VACANT:
phy->phy_state = PHY_VACANT;
- sas_unregister_devs_sas_addr(dev, phy_id);
+ sas_unregister_devs_sas_addr(dev, phy_id, last);
goto out; break;
case SMP_RESP_FUNC_ACC:
break;
@@ -1816,7 +1868,7 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id)
if (SAS_ADDR(attached_sas_addr) == 0) {
phy->phy_state = PHY_EMPTY;
- sas_unregister_devs_sas_addr(dev, phy_id);
+ sas_unregister_devs_sas_addr(dev, phy_id, last);
} else if (SAS_ADDR(attached_sas_addr) ==
SAS_ADDR(phy->attached_sas_addr)) {
SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter\n",
@@ -1828,12 +1880,27 @@ out:
return res;
}
+/**
+ * sas_rediscover - revalidate the domain.
+ * @dev:domain device to be detect.
+ * @phy_id: the phy id will be detected.
+ *
+ * NOTE: this process _must_ quit (return) as soon as any connection
+ * errors are encountered. Connection recovery is done elsewhere.
+ * Discover process only interrogates devices in order to discover the
+ * domain.For plugging out, we un-register the device only when it is
+ * the last phy in the port, for other phys in this port, we just delete it
+ * from the port.For inserting, we do discovery when it is the
+ * first phy,for other phys in this port, we add it to the port to
+ * forming the wide-port.
+ */
static int sas_rediscover(struct domain_device *dev, const int phy_id)
{
struct expander_device *ex = &dev->ex_dev;
struct ex_phy *changed_phy = &ex->ex_phy[phy_id];
int res = 0;
int i;
+ bool last = true; /* is this the last phy of the port */
SAS_DPRINTK("ex %016llx phy%d originated BROADCAST(CHANGE)\n",
SAS_ADDR(dev->sas_addr), phy_id);
@@ -1848,13 +1915,13 @@ static int sas_rediscover(struct domain_device *dev, const int phy_id)
SAS_ADDR(changed_phy->attached_sas_addr)) {
SAS_DPRINTK("phy%d part of wide port with "
"phy%d\n", phy_id, i);
- goto out;
+ last = false;
+ break;
}
}
- res = sas_rediscover_dev(dev, phy_id);
+ res = sas_rediscover_dev(dev, phy_id, last);
} else
res = sas_discover_new(dev, phy_id);
-out:
return res;
}
@@ -1881,7 +1948,7 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
do {
phy_id = -1;
- res = sas_find_bcast_phy(dev, &phy_id, i);
+ res = sas_find_bcast_phy(dev, &phy_id, i, true);
if (phy_id == -1)
break;
res = sas_rediscover(dev, phy_id);
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index e6ac59c023f..fe8b74c706d 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -56,7 +56,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
}
}
- /* find a port */
+ /* see if the phy should be part of a wide port */
spin_lock_irqsave(&sas_ha->phy_port_lock, flags);
for (i = 0; i < sas_ha->num_phys; i++) {
port = sas_ha->sas_port[i];
@@ -69,12 +69,23 @@ static void sas_form_port(struct asd_sas_phy *phy)
SAS_DPRINTK("phy%d matched wide port%d\n", phy->id,
port->id);
break;
- } else if (*(u64 *) port->sas_addr == 0 && port->num_phys==0) {
- memcpy(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE);
- break;
}
spin_unlock(&port->phy_list_lock);
}
+ /* The phy does not match any existing port, create a new one */
+ if (i == sas_ha->num_phys) {
+ for (i = 0; i < sas_ha->num_phys; i++) {
+ port = sas_ha->sas_port[i];
+ spin_lock(&port->phy_list_lock);
+ if (*(u64 *)port->sas_addr == 0
+ && port->num_phys == 0) {
+ memcpy(port->sas_addr, phy->sas_addr,
+ SAS_ADDR_SIZE);
+ break;
+ }
+ spin_unlock(&port->phy_list_lock);
+ }
+ }
if (i >= sas_ha->num_phys) {
printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n",
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c
index fcc184cd066..cbceb0ebabf 100644
--- a/drivers/scsi/qla4xxx/ql4_dbg.c
+++ b/drivers/scsi/qla4xxx/ql4_dbg.c
@@ -15,19 +15,18 @@ void qla4xxx_dump_buffer(void *b, uint32_t size)
uint32_t cnt;
uint8_t *c = b;
- printk(" 0 1 2 3 4 5 6 7 8 9 Ah Bh Ch Dh Eh "
+ printk(" 0 1 2 3 4 5 6 7 8 9 Ah Bh Ch Dh Eh "
"Fh\n");
printk("------------------------------------------------------------"
"--\n");
- for (cnt = 0; cnt < size; cnt++, c++) {
- printk(KERN_DEBUG "%02x", *c);
- if (!(cnt % 16))
- printk(KERN_DEBUG "\n");
+ for (cnt = 0; cnt < size; c++) {
+ printk(KERN_INFO "%02x", *c);
+ if (!(++cnt % 16))
+ printk(KERN_INFO "\n");
else
- printk(KERN_DEBUG " ");
+ printk(KERN_INFO " ");
}
- if (cnt % 16)
- printk(KERN_DEBUG "\n");
+ printk(KERN_INFO "\n");
}
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index b586f27c3bd..81b5f29254e 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -100,7 +100,6 @@
#define MAX_SRBS MAX_CMDS_TO_RISC
#define MBOX_AEN_REG_COUNT 5
#define MAX_INIT_RETRIES 5
-#define IOCB_HIWAT_CUSHION 16
/*
* Buffer sizes
@@ -184,6 +183,11 @@ struct srb {
uint16_t cc_stat;
u_long r_start; /* Time we recieve a cmd from OS */
u_long u_start; /* Time when we handed the cmd to F/W */
+
+ /* Used for extended sense / status continuation */
+ uint8_t *req_sense_ptr;
+ uint16_t req_sense_len;
+ uint16_t reserved2;
};
/*
@@ -302,7 +306,6 @@ struct scsi_qla_host {
uint32_t tot_ddbs;
uint16_t iocb_cnt;
- uint16_t iocb_hiwat;
/* SRB cache. */
#define SRB_MIN_REQ 128
@@ -436,6 +439,8 @@ struct scsi_qla_host {
/* Map ddb_list entry by FW ddb index */
struct ddb_entry *fw_ddb_index_map[MAX_DDB_ENTRIES];
+ /* Saved srb for status continuation entry processing */
+ struct srb *status_srb;
};
static inline int is_qla4010(struct scsi_qla_host *ha)
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index 1b667a70cff..9cd7a608df3 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -572,6 +572,7 @@ struct conn_event_log_entry {
*************************************************************************/
#define IOCB_MAX_CDB_LEN 16 /* Bytes in a CBD */
#define IOCB_MAX_SENSEDATA_LEN 32 /* Bytes of sense data */
+#define IOCB_MAX_EXT_SENSEDATA_LEN 60 /* Bytes of extended sense data */
/* IOCB header structure */
struct qla4_header {
@@ -733,6 +734,12 @@ struct status_entry {
};
+/* Status Continuation entry */
+struct status_cont_entry {
+ struct qla4_header hdr; /* 00-03 */
+ uint8_t ext_sense_data[IOCB_MAX_EXT_SENSEDATA_LEN]; /* 04-63 */
+};
+
struct passthru0 {
struct qla4_header hdr; /* 00-03 */
uint32_t handle; /* 04-07 */
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index 912a67494ad..e0c32159749 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -10,9 +10,42 @@
#include "ql4_dbg.h"
#include "ql4_inline.h"
-
#include <scsi/scsi_tcq.h>
+static int
+qla4xxx_space_in_req_ring(struct scsi_qla_host *ha, uint16_t req_cnt)
+{
+ uint16_t cnt;
+
+ /* Calculate number of free request entries. */
+ if ((req_cnt + 2) >= ha->req_q_count) {
+ cnt = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
+ if (ha->request_in < cnt)
+ ha->req_q_count = cnt - ha->request_in;
+ else
+ ha->req_q_count = REQUEST_QUEUE_DEPTH -
+ (ha->request_in - cnt);
+ }
+
+ /* Check if room for request in request ring. */
+ if ((req_cnt + 2) < ha->req_q_count)
+ return 1;
+ else
+ return 0;
+}
+
+static void qla4xxx_advance_req_ring_ptr(struct scsi_qla_host *ha)
+{
+ /* Advance request queue pointer */
+ if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) {
+ ha->request_in = 0;
+ ha->request_ptr = ha->request_ring;
+ } else {
+ ha->request_in++;
+ ha->request_ptr++;
+ }
+}
+
/**
* qla4xxx_get_req_pkt - returns a valid entry in request queue.
* @ha: Pointer to host adapter structure.
@@ -26,35 +59,18 @@
static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
struct queue_entry **queue_entry)
{
- uint16_t request_in;
- uint8_t status = QLA_SUCCESS;
-
- *queue_entry = ha->request_ptr;
+ uint16_t req_cnt = 1;
- /* get the latest request_in and request_out index */
- request_in = ha->request_in;
- ha->request_out = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
-
- /* Advance request queue pointer and check for queue full */
- if (request_in == (REQUEST_QUEUE_DEPTH - 1)) {
- request_in = 0;
- ha->request_ptr = ha->request_ring;
- } else {
- request_in++;
- ha->request_ptr++;
- }
-
- /* request queue is full, try again later */
- if ((ha->iocb_cnt + 1) >= ha->iocb_hiwat) {
- /* restore request pointer */
- ha->request_ptr = *queue_entry;
- status = QLA_ERROR;
- } else {
- ha->request_in = request_in;
+ if (qla4xxx_space_in_req_ring(ha, req_cnt)) {
+ *queue_entry = ha->request_ptr;
memset(*queue_entry, 0, sizeof(**queue_entry));
+
+ qla4xxx_advance_req_ring_ptr(ha);
+ ha->req_q_count -= req_cnt;
+ return QLA_SUCCESS;
}
- return status;
+ return QLA_ERROR;
}
/**
@@ -100,21 +116,14 @@ exit_send_marker:
return status;
}
-static struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
- struct scsi_qla_host *ha)
+static struct continuation_t1_entry *
+qla4xxx_alloc_cont_entry(struct scsi_qla_host *ha)
{
struct continuation_t1_entry *cont_entry;
cont_entry = (struct continuation_t1_entry *)ha->request_ptr;
- /* Advance request queue pointer */
- if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) {
- ha->request_in = 0;
- ha->request_ptr = ha->request_ring;
- } else {
- ha->request_in++;
- ha->request_ptr++;
- }
+ qla4xxx_advance_req_ring_ptr(ha);
/* Load packet defaults */
cont_entry->hdr.entryType = ET_CONTINUE;
@@ -197,13 +206,10 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
struct scsi_cmnd *cmd = srb->cmd;
struct ddb_entry *ddb_entry;
struct command_t3_entry *cmd_entry;
-
int nseg;
uint16_t tot_dsds;
uint16_t req_cnt;
-
unsigned long flags;
- uint16_t cnt;
uint32_t index;
char tag[2];
@@ -217,6 +223,19 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
index = (uint32_t)cmd->request->tag;
+ /*
+ * Check to see if adapter is online before placing request on
+ * request queue. If a reset occurs and a request is in the queue,
+ * the firmware will still attempt to process the request, retrieving
+ * garbage for pointers.
+ */
+ if (!test_bit(AF_ONLINE, &ha->flags)) {
+ DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! "
+ "Do not issue command.\n",
+ ha->host_no, __func__));
+ goto queuing_error;
+ }
+
/* Calculate the number of request entries needed. */
nseg = scsi_dma_map(cmd);
if (nseg < 0)
@@ -224,17 +243,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
tot_dsds = nseg;
req_cnt = qla4xxx_calc_request_entries(tot_dsds);
-
- if (ha->req_q_count < (req_cnt + 2)) {
- cnt = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
- if (ha->request_in < cnt)
- ha->req_q_count = cnt - ha->request_in;
- else
- ha->req_q_count = REQUEST_QUEUE_DEPTH -
- (ha->request_in - cnt);
- }
-
- if (ha->req_q_count < (req_cnt + 2))
+ if (!qla4xxx_space_in_req_ring(ha, req_cnt))
goto queuing_error;
/* total iocbs active */
@@ -286,32 +295,10 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
break;
}
-
- /* Advance request queue pointer */
- ha->request_in++;
- if (ha->request_in == REQUEST_QUEUE_DEPTH) {
- ha->request_in = 0;
- ha->request_ptr = ha->request_ring;
- } else
- ha->request_ptr++;
-
-
+ qla4xxx_advance_req_ring_ptr(ha);
qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds);
wmb();
- /*
- * Check to see if adapter is online before placing request on
- * request queue. If a reset occurs and a request is in the queue,
- * the firmware will still attempt to process the request, retrieving
- * garbage for pointers.
- */
- if (!test_bit(AF_ONLINE, &ha->flags)) {
- DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! "
- "Do not issue command.\n",
- ha->host_no, __func__));
- goto queuing_error;
- }
-
srb->cmd->host_scribble = (unsigned char *)srb;
/* update counters */
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 799120fcb9b..8025ee16588 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -11,6 +11,98 @@
#include "ql4_inline.h"
/**
+ * qla4xxx_copy_sense - copy sense data into cmd sense buffer
+ * @ha: Pointer to host adapter structure.
+ * @sts_entry: Pointer to status entry structure.
+ * @srb: Pointer to srb structure.
+ **/
+static void qla4xxx_copy_sense(struct scsi_qla_host *ha,
+ struct status_entry *sts_entry,
+ struct srb *srb)
+{
+ struct scsi_cmnd *cmd = srb->cmd;
+ uint16_t sense_len;
+
+ memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ sense_len = le16_to_cpu(sts_entry->senseDataByteCnt);
+ if (sense_len == 0)
+ return;
+
+ /* Save total available sense length,
+ * not to exceed cmd's sense buffer size */
+ sense_len = min_t(uint16_t, sense_len, SCSI_SENSE_BUFFERSIZE);
+ srb->req_sense_ptr = cmd->sense_buffer;
+ srb->req_sense_len = sense_len;
+
+ /* Copy sense from sts_entry pkt */
+ sense_len = min_t(uint16_t, sense_len, IOCB_MAX_SENSEDATA_LEN);
+ memcpy(cmd->sense_buffer, sts_entry->senseData, sense_len);
+
+ DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: %s: sense key = %x, "
+ "ASL= %02x, ASC/ASCQ = %02x/%02x\n", ha->host_no,
+ cmd->device->channel, cmd->device->id,
+ cmd->device->lun, __func__,
+ sts_entry->senseData[2] & 0x0f,
+ sts_entry->senseData[7],
+ sts_entry->senseData[12],
+ sts_entry->senseData[13]));
+
+ DEBUG5(qla4xxx_dump_buffer(cmd->sense_buffer, sense_len));
+ srb->flags |= SRB_GOT_SENSE;
+
+ /* Update srb, in case a sts_cont pkt follows */
+ srb->req_sense_ptr += sense_len;
+ srb->req_sense_len -= sense_len;
+ if (srb->req_sense_len != 0)
+ ha->status_srb = srb;
+ else
+ ha->status_srb = NULL;
+}
+
+/**
+ * qla4xxx_status_cont_entry - Process a Status Continuations entry.
+ * @ha: SCSI driver HA context
+ * @sts_cont: Entry pointer
+ *
+ * Extended sense data.
+ */
+static void
+qla4xxx_status_cont_entry(struct scsi_qla_host *ha,
+ struct status_cont_entry *sts_cont)
+{
+ struct srb *srb = ha->status_srb;
+ struct scsi_cmnd *cmd;
+ uint8_t sense_len;
+
+ if (srb == NULL)
+ return;
+
+ cmd = srb->cmd;
+ if (cmd == NULL) {
+ DEBUG2(printk(KERN_INFO "scsi%ld: %s: Cmd already returned "
+ "back to OS srb=%p srb->state:%d\n", ha->host_no,
+ __func__, srb, srb->state));
+ ha->status_srb = NULL;
+ return;
+ }
+
+ /* Copy sense data. */
+ sense_len = min_t(uint16_t, srb->req_sense_len,
+ IOCB_MAX_EXT_SENSEDATA_LEN);
+ memcpy(srb->req_sense_ptr, sts_cont->ext_sense_data, sense_len);
+ DEBUG5(qla4xxx_dump_buffer(srb->req_sense_ptr, sense_len));
+
+ srb->req_sense_ptr += sense_len;
+ srb->req_sense_len -= sense_len;
+
+ /* Place command on done queue. */
+ if (srb->req_sense_len == 0) {
+ qla4xxx_srb_compl(ha, srb);
+ ha->status_srb = NULL;
+ }
+}
+
+/**
* qla4xxx_status_entry - processes status IOCBs
* @ha: Pointer to host adapter structure.
* @sts_entry: Pointer to status entry structure.
@@ -23,7 +115,6 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
struct srb *srb;
struct ddb_entry *ddb_entry;
uint32_t residual;
- uint16_t sensebytecnt;
srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle));
if (!srb) {
@@ -92,24 +183,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
break;
/* Copy Sense Data into sense buffer. */
- memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
-
- sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt);
- if (sensebytecnt == 0)
- break;
-
- memcpy(cmd->sense_buffer, sts_entry->senseData,
- min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE));
-
- DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
- "ASC/ASCQ = %02x/%02x\n", ha->host_no,
- cmd->device->channel, cmd->device->id,
- cmd->device->lun, __func__,
- sts_entry->senseData[2] & 0x0f,
- sts_entry->senseData[12],
- sts_entry->senseData[13]));
-
- srb->flags |= SRB_GOT_SENSE;
+ qla4xxx_copy_sense(ha, sts_entry, srb);
break;
case SCS_INCOMPLETE:
@@ -176,23 +250,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
break;
/* Copy Sense Data into sense buffer. */
- memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
-
- sensebytecnt =
- le16_to_cpu(sts_entry->senseDataByteCnt);
- if (sensebytecnt == 0)
- break;
-
- memcpy(cmd->sense_buffer, sts_entry->senseData,
- min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE));
-
- DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
- "ASC/ASCQ = %02x/%02x\n", ha->host_no,
- cmd->device->channel, cmd->device->id,
- cmd->device->lun, __func__,
- sts_entry->senseData[2] & 0x0f,
- sts_entry->senseData[12],
- sts_entry->senseData[13]));
+ qla4xxx_copy_sense(ha, sts_entry, srb);
} else {
/*
* If RISC reports underrun and target does not
@@ -268,9 +326,10 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
status_entry_exit:
- /* complete the request */
+ /* complete the request, if not waiting for status_continuation pkt */
srb->cc_stat = sts_entry->completionStatus;
- qla4xxx_srb_compl(ha, srb);
+ if (ha->status_srb == NULL)
+ qla4xxx_srb_compl(ha, srb);
}
/**
@@ -305,10 +364,7 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
/* process entry */
switch (sts_entry->hdr.entryType) {
case ET_STATUS:
- /*
- * Common status - Single completion posted in single
- * IOSB.
- */
+ /* Common status */
qla4xxx_status_entry(ha, sts_entry);
break;
@@ -316,9 +372,8 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
break;
case ET_STATUS_CONTINUATION:
- /* Just throw away the status continuation entries */
- DEBUG2(printk("scsi%ld: %s: Status Continuation entry "
- "- ignoring\n", ha->host_no, __func__));
+ qla4xxx_status_cont_entry(ha,
+ (struct status_cont_entry *) sts_entry);
break;
case ET_COMMAND:
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 051b0f5e8c8..09d6d4b76f3 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -385,16 +385,6 @@ int qla4xxx_get_firmware_status(struct scsi_qla_host * ha)
mbox_sts[0]));
return QLA_ERROR;
}
-
- /* High-water mark of IOCBs */
- ha->iocb_hiwat = mbox_sts[2];
- if (ha->iocb_hiwat > IOCB_HIWAT_CUSHION)
- ha->iocb_hiwat -= IOCB_HIWAT_CUSHION;
- else
- dev_info(&ha->pdev->dev, "WARNING!!! You have less than %d "
- "firmware IOCBs available (%d).\n",
- IOCB_HIWAT_CUSHION, ha->iocb_hiwat);
-
return QLA_SUCCESS;
}
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index ec9da6ce848..40e3cafb3a9 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -66,6 +66,7 @@ static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
static int qla4xxx_host_get_param(struct Scsi_Host *shost,
enum iscsi_host_param param, char *buf);
static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session);
+static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
/*
* SCSI host template entry points
@@ -89,6 +90,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
.eh_device_reset_handler = qla4xxx_eh_device_reset,
.eh_target_reset_handler = qla4xxx_eh_target_reset,
.eh_host_reset_handler = qla4xxx_eh_host_reset,
+ .eh_timed_out = qla4xxx_eh_cmd_timed_out,
.slave_configure = qla4xxx_slave_configure,
.slave_alloc = qla4xxx_slave_alloc,
@@ -124,6 +126,21 @@ static struct iscsi_transport qla4xxx_iscsi_transport = {
static struct scsi_transport_template *qla4xxx_scsi_transport;
+static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc)
+{
+ struct iscsi_cls_session *session;
+ struct ddb_entry *ddb_entry;
+
+ session = starget_to_session(scsi_target(sc->device));
+ ddb_entry = session->dd_data;
+
+ /* if we are not logged in then the LLD is going to clean up the cmd */
+ if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE)
+ return BLK_EH_RESET_TIMER;
+ else
+ return BLK_EH_NOT_HANDLED;
+}
+
static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session)
{
struct ddb_entry *ddb_entry = session->dd_data;
@@ -904,18 +921,17 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
/* Flush any pending ddb changed AENs */
qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+ qla4xxx_flush_active_srbs(ha);
+
/* Reset the firmware. If successful, function
* returns with ISP interrupts enabled.
*/
- if (status == QLA_SUCCESS) {
- DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n",
- ha->host_no, __func__));
- qla4xxx_flush_active_srbs(ha);
- if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
- status = qla4xxx_soft_reset(ha);
- else
- status = QLA_ERROR;
- }
+ DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n",
+ ha->host_no, __func__));
+ if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
+ status = qla4xxx_soft_reset(ha);
+ else
+ status = QLA_ERROR;
/* Flush any pending ddb changed AENs */
qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
@@ -1527,11 +1543,9 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
{
struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
struct ddb_entry *ddb_entry = cmd->device->hostdata;
- struct srb *sp;
int ret = FAILED, stat;
- sp = (struct srb *) cmd->SCp.ptr;
- if (!sp || !ddb_entry)
+ if (!ddb_entry)
return ret;
dev_info(&ha->pdev->dev,
@@ -1644,7 +1658,7 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
ha = (struct scsi_qla_host *) cmd->device->host->hostdata;
dev_info(&ha->pdev->dev,
- "scsi(%ld:%d:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no,
+ "scsi(%ld:%d:%d:%d): HOST RESET ISSUED.\n", ha->host_no,
cmd->device->channel, cmd->device->id, cmd->device->lun);
if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index ab984cb89ce..6980cb279c8 100644
--- a/drivers/scsi/qla4xxx/ql4_version.h
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -5,5 +5,5 @@
* See LICENSE.qla4xxx for copyright and licensing details.
*/
-#define QLA4XXX_DRIVER_VERSION "5.01.00-k8"
+#define QLA4XXX_DRIVER_VERSION "5.01.00-k9"
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 783e33c65eb..b47240ca4b1 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -990,7 +990,7 @@ int iscsi_offload_mesg(struct Scsi_Host *shost,
struct iscsi_uevent *ev;
int len = NLMSG_SPACE(sizeof(*ev) + data_size);
- skb = alloc_skb(len, GFP_NOIO);
+ skb = alloc_skb(len, GFP_ATOMIC);
if (!skb) {
printk(KERN_ERR "can not deliver iscsi offload message:OOM\n");
return -ENOMEM;
@@ -1012,7 +1012,7 @@ int iscsi_offload_mesg(struct Scsi_Host *shost,
memcpy((char *)ev + sizeof(*ev), data, data_size);
- return iscsi_multicast_skb(skb, ISCSI_NL_GRP_UIP, GFP_NOIO);
+ return iscsi_multicast_skb(skb, ISCSI_NL_GRP_UIP, GFP_ATOMIC);
}
EXPORT_SYMBOL_GPL(iscsi_offload_mesg);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 5616cd780ff..b7b9fec67a9 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1840,6 +1840,18 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
kfree(buffer);
}
+static int sd_try_extended_inquiry(struct scsi_device *sdp)
+{
+ /*
+ * Although VPD inquiries can go to SCSI-2 type devices,
+ * some USB ones crash on receiving them, and the pages
+ * we currently ask for are for SPC-3 and beyond
+ */
+ if (sdp->scsi_level > SCSI_SPC_2)
+ return 1;
+ return 0;
+}
+
/**
* sd_revalidate_disk - called the first time a new disk is seen,
* performs disk spin up, read_capacity, etc.
@@ -1877,8 +1889,12 @@ static int sd_revalidate_disk(struct gendisk *disk)
*/
if (sdkp->media_present) {
sd_read_capacity(sdkp, buffer);
- sd_read_block_limits(sdkp);
- sd_read_block_characteristics(sdkp);
+
+ if (sd_try_extended_inquiry(sdp)) {
+ sd_read_block_limits(sdkp);
+ sd_read_block_characteristics(sdkp);
+ }
+
sd_read_write_protect_flag(sdkp, buffer);
sd_read_cache_type(sdkp, buffer);
sd_read_app_tag_own(sdkp, buffer);
diff --git a/drivers/serial/s3c2400.c b/drivers/serial/s3c2400.c
index fb00ed5296e..fed1a9a1ffb 100644
--- a/drivers/serial/s3c2400.c
+++ b/drivers/serial/s3c2400.c
@@ -76,7 +76,7 @@ static int s3c2400_serial_probe(struct platform_device *dev)
return s3c24xx_serial_probe(dev, &s3c2400_uart_inf);
}
-static struct platform_driver s3c2400_serial_drv = {
+static struct platform_driver s3c2400_serial_driver = {
.probe = s3c2400_serial_probe,
.remove = __devexit_p(s3c24xx_serial_remove),
.driver = {
@@ -85,16 +85,16 @@ static struct platform_driver s3c2400_serial_drv = {
},
};
-s3c24xx_console_init(&s3c2400_serial_drv, &s3c2400_uart_inf);
+s3c24xx_console_init(&s3c2400_serial_driver, &s3c2400_uart_inf);
static inline int s3c2400_serial_init(void)
{
- return s3c24xx_serial_init(&s3c2400_serial_drv, &s3c2400_uart_inf);
+ return s3c24xx_serial_init(&s3c2400_serial_driver, &s3c2400_uart_inf);
}
static inline void s3c2400_serial_exit(void)
{
- platform_driver_unregister(&s3c2400_serial_drv);
+ platform_driver_unregister(&s3c2400_serial_driver);
}
module_init(s3c2400_serial_init);
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index b5d7cbcba2a..c99f0821cae 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -88,7 +88,7 @@ static int s3c2410_serial_probe(struct platform_device *dev)
return s3c24xx_serial_probe(dev, &s3c2410_uart_inf);
}
-static struct platform_driver s3c2410_serial_drv = {
+static struct platform_driver s3c2410_serial_driver = {
.probe = s3c2410_serial_probe,
.remove = __devexit_p(s3c24xx_serial_remove),
.driver = {
@@ -97,16 +97,16 @@ static struct platform_driver s3c2410_serial_drv = {
},
};
-s3c24xx_console_init(&s3c2410_serial_drv, &s3c2410_uart_inf);
+s3c24xx_console_init(&s3c2410_serial_driver, &s3c2410_uart_inf);
static int __init s3c2410_serial_init(void)
{
- return s3c24xx_serial_init(&s3c2410_serial_drv, &s3c2410_uart_inf);
+ return s3c24xx_serial_init(&s3c2410_serial_driver, &s3c2410_uart_inf);
}
static void __exit s3c2410_serial_exit(void)
{
- platform_driver_unregister(&s3c2410_serial_drv);
+ platform_driver_unregister(&s3c2410_serial_driver);
}
module_init(s3c2410_serial_init);
diff --git a/drivers/serial/s3c2412.c b/drivers/serial/s3c2412.c
index 11dcb90bdfe..6e057d8809d 100644
--- a/drivers/serial/s3c2412.c
+++ b/drivers/serial/s3c2412.c
@@ -121,7 +121,7 @@ static int s3c2412_serial_probe(struct platform_device *dev)
return s3c24xx_serial_probe(dev, &s3c2412_uart_inf);
}
-static struct platform_driver s3c2412_serial_drv = {
+static struct platform_driver s3c2412_serial_driver = {
.probe = s3c2412_serial_probe,
.remove = __devexit_p(s3c24xx_serial_remove),
.driver = {
@@ -130,16 +130,16 @@ static struct platform_driver s3c2412_serial_drv = {
},
};
-s3c24xx_console_init(&s3c2412_serial_drv, &s3c2412_uart_inf);
+s3c24xx_console_init(&s3c2412_serial_driver, &s3c2412_uart_inf);
static inline int s3c2412_serial_init(void)
{
- return s3c24xx_serial_init(&s3c2412_serial_drv, &s3c2412_uart_inf);
+ return s3c24xx_serial_init(&s3c2412_serial_driver, &s3c2412_uart_inf);
}
static inline void s3c2412_serial_exit(void)
{
- platform_driver_unregister(&s3c2412_serial_drv);
+ platform_driver_unregister(&s3c2412_serial_driver);
}
module_init(s3c2412_serial_init);
diff --git a/drivers/serial/s3c2440.c b/drivers/serial/s3c2440.c
index 06c5b0cc47a..69ff5d340f0 100644
--- a/drivers/serial/s3c2440.c
+++ b/drivers/serial/s3c2440.c
@@ -151,7 +151,7 @@ static int s3c2440_serial_probe(struct platform_device *dev)
return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);
}
-static struct platform_driver s3c2440_serial_drv = {
+static struct platform_driver s3c2440_serial_driver = {
.probe = s3c2440_serial_probe,
.remove = __devexit_p(s3c24xx_serial_remove),
.driver = {
@@ -160,16 +160,16 @@ static struct platform_driver s3c2440_serial_drv = {
},
};
-s3c24xx_console_init(&s3c2440_serial_drv, &s3c2440_uart_inf);
+s3c24xx_console_init(&s3c2440_serial_driver, &s3c2440_uart_inf);
static int __init s3c2440_serial_init(void)
{
- return s3c24xx_serial_init(&s3c2440_serial_drv, &s3c2440_uart_inf);
+ return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf);
}
static void __exit s3c2440_serial_exit(void)
{
- platform_driver_unregister(&s3c2440_serial_drv);
+ platform_driver_unregister(&s3c2440_serial_driver);
}
module_init(s3c2440_serial_init);
diff --git a/drivers/serial/s3c24a0.c b/drivers/serial/s3c24a0.c
index 786a067d62a..26c49e18bdd 100644
--- a/drivers/serial/s3c24a0.c
+++ b/drivers/serial/s3c24a0.c
@@ -92,7 +92,7 @@ static int s3c24a0_serial_probe(struct platform_device *dev)
return s3c24xx_serial_probe(dev, &s3c24a0_uart_inf);
}
-static struct platform_driver s3c24a0_serial_drv = {
+static struct platform_driver s3c24a0_serial_driver = {
.probe = s3c24a0_serial_probe,
.remove = __devexit_p(s3c24xx_serial_remove),
.driver = {
@@ -101,16 +101,16 @@ static struct platform_driver s3c24a0_serial_drv = {
},
};
-s3c24xx_console_init(&s3c24a0_serial_drv, &s3c24a0_uart_inf);
+s3c24xx_console_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf);
static int __init s3c24a0_serial_init(void)
{
- return s3c24xx_serial_init(&s3c24a0_serial_drv, &s3c24a0_uart_inf);
+ return s3c24xx_serial_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf);
}
static void __exit s3c24a0_serial_exit(void)
{
- platform_driver_unregister(&s3c24a0_serial_drv);
+ platform_driver_unregister(&s3c24a0_serial_driver);
}
module_init(s3c24a0_serial_init);
diff --git a/drivers/serial/s3c6400.c b/drivers/serial/s3c6400.c
index 48f1a3781f0..4be92ab5005 100644
--- a/drivers/serial/s3c6400.c
+++ b/drivers/serial/s3c6400.c
@@ -122,7 +122,7 @@ static int s3c6400_serial_probe(struct platform_device *dev)
return s3c24xx_serial_probe(dev, &s3c6400_uart_inf);
}
-static struct platform_driver s3c6400_serial_drv = {
+static struct platform_driver s3c6400_serial_driver = {
.probe = s3c6400_serial_probe,
.remove = __devexit_p(s3c24xx_serial_remove),
.driver = {
@@ -131,16 +131,16 @@ static struct platform_driver s3c6400_serial_drv = {
},
};
-s3c24xx_console_init(&s3c6400_serial_drv, &s3c6400_uart_inf);
+s3c24xx_console_init(&s3c6400_serial_driver, &s3c6400_uart_inf);
static int __init s3c6400_serial_init(void)
{
- return s3c24xx_serial_init(&s3c6400_serial_drv, &s3c6400_uart_inf);
+ return s3c24xx_serial_init(&s3c6400_serial_driver, &s3c6400_uart_inf);
}
static void __exit s3c6400_serial_exit(void)
{
- platform_driver_unregister(&s3c6400_serial_drv);
+ platform_driver_unregister(&s3c6400_serial_driver);
}
module_init(s3c6400_serial_init);
diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c
index 998e89dc5aa..e0665630e4d 100644
--- a/drivers/serial/serial_ks8695.c
+++ b/drivers/serial/serial_ks8695.c
@@ -549,7 +549,7 @@ static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = {
.mapbase = KS8695_UART_VA,
.iotype = SERIAL_IO_MEM,
.irq = KS8695_IRQ_UART_TX,
- .uartclk = CLOCK_TICK_RATE * 16,
+ .uartclk = KS8695_CLOCK_RATE * 16,
.fifosize = 16,
.ops = &ks8695uart_pops,
.flags = ASYNC_BOOT_AUTOCONF,
diff --git a/drivers/staging/b3dfg/Kconfig b/drivers/staging/b3dfg/Kconfig
index 524231047de..9e6573cf97d 100644
--- a/drivers/staging/b3dfg/Kconfig
+++ b/drivers/staging/b3dfg/Kconfig
@@ -1,5 +1,6 @@
config B3DFG
tristate "Brontes 3d Frame Framegrabber"
+ depends on PCI
default n
---help---
This driver provides support for the Brontes 3d Framegrabber
diff --git a/drivers/staging/heci/Kconfig b/drivers/staging/heci/Kconfig
index ae8d588d3a2..c7206f8bcd9 100644
--- a/drivers/staging/heci/Kconfig
+++ b/drivers/staging/heci/Kconfig
@@ -1,5 +1,6 @@
config HECI
tristate "Intel Management Engine Interface (MEI) Support"
+ depends on PCI
---help---
The Intel Management Engine Interface (Intel MEI) driver allows
applications to access the Active Management Technology
diff --git a/drivers/staging/rspiusb/rspiusb.c b/drivers/staging/rspiusb/rspiusb.c
index 2f8155c1968..04e2f92c0f6 100644
--- a/drivers/staging/rspiusb/rspiusb.c
+++ b/drivers/staging/rspiusb/rspiusb.c
@@ -716,6 +716,8 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx)
pdx->PixelUrb[frameInfo][i]->transfer_flags =
URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT;
}
+ if (i == 0)
+ return -EINVAL;
/* only interrupt when last URB completes */
pdx->PixelUrb[frameInfo][--i]->transfer_flags &= ~URB_NO_INTERRUPT;
pdx->pendedPixelUrbs[frameInfo] =
diff --git a/drivers/staging/rt2860/rt_linux.h b/drivers/staging/rt2860/rt_linux.h
index 85175c18243..25b53ac3f82 100644
--- a/drivers/staging/rt2860/rt_linux.h
+++ b/drivers/staging/rt2860/rt_linux.h
@@ -43,9 +43,6 @@
#include "rtmp_type.h"
#include <linux/module.h>
#include <linux/kernel.h>
-#if !defined(RT2860) && !defined(RT30xx)
-#include <linux/kthread.h>
-#endif
#include <linux/spinlock.h>
#include <linux/init.h>
@@ -166,9 +163,7 @@ typedef int (*HARD_START_XMIT_FUNC)(struct sk_buff *skb, struct net_device *net_
#ifndef RT30xx
typedef struct pid * THREAD_PID;
-#ifdef RT2860
#define THREAD_PID_INIT_VALUE NULL
-#endif
#define GET_PID(_v) find_get_pid(_v)
#define GET_PID_NUMBER(_v) pid_nr(_v)
#define CHECK_PID_LEGALITY(_pid) if (pid_nr(_pid) >= 0)
@@ -188,12 +183,12 @@ struct os_cookie {
dma_addr_t pAd_pa;
#endif
#ifdef RT2870
- struct usb_device *pUsb_Dev;
+ struct usb_device *pUsb_Dev;
#ifndef RT30xx
- struct task_struct *MLMEThr_task;
- struct task_struct *RTUSBCmdThr_task;
- struct task_struct *TimerQThr_task;
+ THREAD_PID MLMEThr_pid;
+ THREAD_PID RTUSBCmdThr_pid;
+ THREAD_PID TimerQThr_pid;
#endif
#ifdef RT30xx
struct pid *MLMEThr_pid;
diff --git a/drivers/staging/rt2870/2870_main_dev.c b/drivers/staging/rt2870/2870_main_dev.c
index dd01c64fbf6..a4e8696ca39 100644
--- a/drivers/staging/rt2870/2870_main_dev.c
+++ b/drivers/staging/rt2870/2870_main_dev.c
@@ -235,7 +235,7 @@ INT MlmeThread(
DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__func__));
#ifndef RT30xx
- pObj->MLMEThr_task = NULL;
+ pObj->MLMEThr_pid = THREAD_PID_INIT_VALUE;
#endif
#ifdef RT30xx
pObj->MLMEThr_pid = NULL;
@@ -348,7 +348,7 @@ INT RTUSBCmdThread(
DBGPRINT(RT_DEBUG_TRACE,( "<---RTUSBCmdThread\n"));
#ifndef RT30xx
- pObj->RTUSBCmdThr_task = NULL;
+ pObj->RTUSBCmdThr_pid = THREAD_PID_INIT_VALUE;
#endif
#ifdef RT30xx
pObj->RTUSBCmdThr_pid = NULL;
@@ -447,7 +447,7 @@ INT TimerQThread(
DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__func__));
#ifndef RT30xx
- pObj->TimerQThr_task = NULL;
+ pObj->TimerQThr_pid = THREAD_PID_INIT_VALUE;
#endif
#ifdef RT30xx
pObj->TimerQThr_pid = NULL;
@@ -883,46 +883,69 @@ VOID RT28xxThreadTerminate(
// Terminate Threads
#ifndef RT30xx
- BUG_ON(pObj->TimerQThr_task == NULL);
- CHECK_PID_LEGALITY(task_pid(pObj->TimerQThr_task))
+ CHECK_PID_LEGALITY(pObj->TimerQThr_pid)
{
POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie;
- printk(KERN_DEBUG "Terminate the TimerQThr pid=%d!\n",
- pid_nr(task_pid(pObj->TimerQThr_task)));
+ printk("Terminate the TimerQThr_pid=%d!\n", GET_PID_NUMBER(pObj->TimerQThr_pid));
mb();
pAd->TimerFunc_kill = 1;
mb();
- kthread_stop(pObj->TimerQThr_task);
- pObj->TimerQThr_task = NULL;
+ ret = KILL_THREAD_PID(pObj->TimerQThr_pid, SIGTERM, 1);
+ if (ret)
+ {
+ printk(KERN_WARNING "%s: unable to stop TimerQThread, pid=%d, ret=%d!\n",
+ pAd->net_dev->name, GET_PID_NUMBER(pObj->TimerQThr_pid), ret);
+ }
+ else
+ {
+ wait_for_completion(&pAd->TimerQComplete);
+ pObj->TimerQThr_pid = THREAD_PID_INIT_VALUE;
+ }
}
- BUG_ON(pObj->MLMEThr_task == NULL);
- CHECK_PID_LEGALITY(task_pid(pObj->MLMEThr_task))
+ CHECK_PID_LEGALITY(pObj->MLMEThr_pid)
{
- printk(KERN_DEBUG "Terminate the MLMEThr pid=%d!\n",
- pid_nr(task_pid(pObj->MLMEThr_task)));
+ printk("Terminate the MLMEThr_pid=%d!\n", GET_PID_NUMBER(pObj->MLMEThr_pid));
mb();
pAd->mlme_kill = 1;
//RT28XX_MLME_HANDLER(pAd);
mb();
- kthread_stop(pObj->MLMEThr_task);
- pObj->MLMEThr_task = NULL;
+ ret = KILL_THREAD_PID(pObj->MLMEThr_pid, SIGTERM, 1);
+ if (ret)
+ {
+ printk (KERN_WARNING "%s: unable to Mlme thread, pid=%d, ret=%d!\n",
+ pAd->net_dev->name, GET_PID_NUMBER(pObj->MLMEThr_pid), ret);
+ }
+ else
+ {
+ //wait_for_completion (&pAd->notify);
+ wait_for_completion (&pAd->mlmeComplete);
+ pObj->MLMEThr_pid = THREAD_PID_INIT_VALUE;
+ }
}
- BUG_ON(pObj->RTUSBCmdThr_task == NULL);
- CHECK_PID_LEGALITY(task_pid(pObj->RTUSBCmdThr_task))
+ CHECK_PID_LEGALITY(pObj->RTUSBCmdThr_pid)
{
- printk(KERN_DEBUG "Terminate the RTUSBCmdThr pid=%d!\n",
- pid_nr(task_pid(pObj->RTUSBCmdThr_task)));
+ printk("Terminate the RTUSBCmdThr_pid=%d!\n", GET_PID_NUMBER(pObj->RTUSBCmdThr_pid));
mb();
NdisAcquireSpinLock(&pAd->CmdQLock);
pAd->CmdQ.CmdQState = RT2870_THREAD_STOPED;
NdisReleaseSpinLock(&pAd->CmdQLock);
mb();
//RTUSBCMDUp(pAd);
- kthread_stop(pObj->RTUSBCmdThr_task);
- pObj->RTUSBCmdThr_task = NULL;
+ ret = KILL_THREAD_PID(pObj->RTUSBCmdThr_pid, SIGTERM, 1);
+ if (ret)
+ {
+ printk(KERN_WARNING "%s: unable to RTUSBCmd thread, pid=%d, ret=%d!\n",
+ pAd->net_dev->name, GET_PID_NUMBER(pObj->RTUSBCmdThr_pid), ret);
+ }
+ else
+ {
+ //wait_for_completion (&pAd->notify);
+ wait_for_completion (&pAd->CmdQComplete);
+ pObj->RTUSBCmdThr_pid = THREAD_PID_INIT_VALUE;
+ }
}
#endif
#ifdef RT30xx
@@ -1045,7 +1068,7 @@ BOOLEAN RT28XXChipsetCheck(
dev_p->descriptor.idProduct == rtusb_usb_id[i].idProduct)
{
#ifndef RT30xx
- printk(KERN_DEBUG "rt2870: idVendor = 0x%x, idProduct = 0x%x\n",
+ printk("rt2870: idVendor = 0x%x, idProduct = 0x%x\n",
#endif
#ifdef RT30xx
printk("rt2870: idVendor = 0x%x, idProduct = 0x%x\n",
diff --git a/drivers/staging/rt2870/common/2870_rtmp_init.c b/drivers/staging/rt2870/common/2870_rtmp_init.c
index 0f4c8af97e4..80909e9ab5a 100644
--- a/drivers/staging/rt2870/common/2870_rtmp_init.c
+++ b/drivers/staging/rt2870/common/2870_rtmp_init.c
@@ -700,8 +700,8 @@ NDIS_STATUS AdapterBlockAllocateMemory(
usb_dev = pObj->pUsb_Dev;
#ifndef RT30xx
- pObj->MLMEThr_task = NULL;
- pObj->RTUSBCmdThr_task = NULL;
+ pObj->MLMEThr_pid = THREAD_PID_INIT_VALUE;
+ pObj->RTUSBCmdThr_pid = THREAD_PID_INIT_VALUE;
#endif
#ifdef RT30xx
pObj->MLMEThr_pid = NULL;
@@ -743,7 +743,7 @@ NDIS_STATUS CreateThreads(
PRTMP_ADAPTER pAd = net_dev->ml_priv;
POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;
#ifndef RT30xx
- struct task_struct *tsk;
+ pid_t pid_number = -1;
#endif
#ifdef RT30xx
pid_t pid_number;
@@ -762,10 +762,10 @@ NDIS_STATUS CreateThreads(
// Creat MLME Thread
#ifndef RT30xx
- pObj->MLMEThr_task = NULL;
- tsk = kthread_run(MlmeThread, pAd, "%s", pAd->net_dev->name);
-
- if (IS_ERR(tsk)) {
+ pObj->MLMEThr_pid= THREAD_PID_INIT_VALUE;
+ pid_number = kernel_thread(MlmeThread, pAd, CLONE_VM);
+ if (pid_number < 0)
+ {
#endif
#ifdef RT30xx
pObj->MLMEThr_pid = NULL;
@@ -778,7 +778,7 @@ NDIS_STATUS CreateThreads(
}
#ifndef RT30xx
- pObj->MLMEThr_task = tsk;
+ pObj->MLMEThr_pid = GET_PID(pid_number);
#endif
#ifdef RT30xx
pObj->MLMEThr_pid = find_get_pid(pid_number);
@@ -788,10 +788,9 @@ NDIS_STATUS CreateThreads(
// Creat Command Thread
#ifndef RT30xx
- pObj->RTUSBCmdThr_task = NULL;
- tsk = kthread_run(RTUSBCmdThread, pAd, "%s", pAd->net_dev->name);
-
- if (IS_ERR(tsk) < 0)
+ pObj->RTUSBCmdThr_pid= THREAD_PID_INIT_VALUE;
+ pid_number = kernel_thread(RTUSBCmdThread, pAd, CLONE_VM);
+ if (pid_number < 0)
#endif
#ifdef RT30xx
pObj->RTUSBCmdThr_pid = NULL;
@@ -804,7 +803,7 @@ NDIS_STATUS CreateThreads(
}
#ifndef RT30xx
- pObj->RTUSBCmdThr_task = tsk;
+ pObj->RTUSBCmdThr_pid = GET_PID(pid_number);
#endif
#ifdef RT30xx
pObj->RTUSBCmdThr_pid = find_get_pid(pid_number);
@@ -812,9 +811,9 @@ NDIS_STATUS CreateThreads(
wait_for_completion(&(pAd->CmdQComplete));
#ifndef RT30xx
- pObj->TimerQThr_task = NULL;
- tsk = kthread_run(TimerQThread, pAd, "%s", pAd->net_dev->name);
- if (IS_ERR(tsk) < 0)
+ pObj->TimerQThr_pid= THREAD_PID_INIT_VALUE;
+ pid_number = kernel_thread(TimerQThread, pAd, CLONE_VM);
+ if (pid_number < 0)
#endif
#ifdef RT30xx
pObj->TimerQThr_pid = NULL;
@@ -826,7 +825,7 @@ NDIS_STATUS CreateThreads(
return NDIS_STATUS_FAILURE;
}
#ifndef RT30xx
- pObj->TimerQThr_task = tsk;
+ pObj->TimerQThr_pid = GET_PID(pid_number);
#endif
#ifdef RT30xx
pObj->TimerQThr_pid = find_get_pid(pid_number);
diff --git a/drivers/staging/rt2870/common/rtusb_io.c b/drivers/staging/rt2870/common/rtusb_io.c
index fd1b0c18f2a..704b5c2d509 100644
--- a/drivers/staging/rt2870/common/rtusb_io.c
+++ b/drivers/staging/rt2870/common/rtusb_io.c
@@ -984,8 +984,7 @@ NDIS_STATUS RTUSBEnqueueCmdFromNdis(
POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie;
#ifndef RT30xx
- BUG_ON(pObj->RTUSBCmdThr_task == NULL);
- CHECK_PID_LEGALITY(task_pid(pObj->RTUSBCmdThr_task))
+ CHECK_PID_LEGALITY(pObj->RTUSBCmdThr_pid)
#endif
#ifdef RT30xx
if (pObj->RTUSBCmdThr_pid < 0)
diff --git a/drivers/staging/rt2870/rt2870.h b/drivers/staging/rt2870/rt2870.h
index 29e3b53e52a..2b8872b2fd9 100644
--- a/drivers/staging/rt2870/rt2870.h
+++ b/drivers/staging/rt2870/rt2870.h
@@ -79,6 +79,7 @@
{ \
{USB_DEVICE(0x148F,0x2770)}, /* Ralink */ \
{USB_DEVICE(0x1737,0x0071)}, /* Linksys WUSB600N */ \
+ {USB_DEVICE(0x1737,0x0070)}, /* Linksys */ \
{USB_DEVICE(0x148F,0x2870)}, /* Ralink */ \
{USB_DEVICE(0x148F,0x3070)}, /* Ralink */ \
{USB_DEVICE(0x0B05,0x1731)}, /* Asus */ \
@@ -93,12 +94,14 @@
{USB_DEVICE(0x14B2,0x3C06)}, /* Conceptronic */ \
{USB_DEVICE(0x14B2,0x3C28)}, /* Conceptronic */ \
{USB_DEVICE(0x2019,0xED06)}, /* Planex Communications, Inc. */ \
+ {USB_DEVICE(0x2019,0xED14)}, /* Planex Communications, Inc. */ \
{USB_DEVICE(0x2019,0xAB25)}, /* Planex Communications, Inc. RT3070 */ \
{USB_DEVICE(0x07D1,0x3C09)}, /* D-Link */ \
{USB_DEVICE(0x07D1,0x3C11)}, /* D-Link */ \
{USB_DEVICE(0x14B2,0x3C07)}, /* AL */ \
{USB_DEVICE(0x14B2,0x3C12)}, /* AL */ \
{USB_DEVICE(0x050D,0x8053)}, /* Belkin */ \
+ {USB_DEVICE(0x050D,0x815C)}, /* Belkin */ \
{USB_DEVICE(0x14B2,0x3C23)}, /* Airlink */ \
{USB_DEVICE(0x14B2,0x3C27)}, /* Airlink */ \
{USB_DEVICE(0x07AA,0x002F)}, /* Corega */ \
@@ -587,16 +590,14 @@ VOID RTUSBBulkRxComplete(purbb_t pUrb, struct pt_regs *pt_regs);
#define RTUSBMlmeUp(pAd) \
{ \
POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; \
- BUG_ON(pObj->MLMEThr_task == NULL); \
- CHECK_PID_LEGALITY(task_pid(pObj->MLMEThr_task)) \
+ CHECK_PID_LEGALITY(pObj->MLMEThr_pid) \
up(&(pAd->mlme_semaphore)); \
}
#define RTUSBCMDUp(pAd) \
{ \
POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; \
- BUG_ON(pObj->RTUSBCmdThr_task == NULL); \
- CHECK_PID_LEGALITY(task_pid(pObj->RTUSBCmdThr_task)) \
+ CHECK_PID_LEGALITY(pObj->RTUSBCmdThr_pid) \
up(&(pAd->RTUSBCmd_semaphore)); \
}
#endif
diff --git a/drivers/staging/rtl8192su/ieee80211.h b/drivers/staging/rtl8192su/ieee80211.h
index 0edb09a536f..ea973931803 100644
--- a/drivers/staging/rtl8192su/ieee80211.h
+++ b/drivers/staging/rtl8192su/ieee80211.h
@@ -2645,7 +2645,7 @@ extern int ieee80211_encrypt_fragment(
struct sk_buff *frag,
int hdr_len);
-extern int ieee80211_xmit(struct sk_buff *skb,
+extern int rtl8192_ieee80211_xmit(struct sk_buff *skb,
struct net_device *dev);
extern void ieee80211_txb_free(struct ieee80211_txb *);
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211.h b/drivers/staging/rtl8192su/ieee80211/ieee80211.h
index 720bfcbfadc..5e3a2cbed2b 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211.h
@@ -2645,7 +2645,7 @@ extern int ieee80211_encrypt_fragment(
struct sk_buff *frag,
int hdr_len);
-extern int ieee80211_xmit(struct sk_buff *skb,
+extern int rtl8192_ieee80211_xmit(struct sk_buff *skb,
struct net_device *dev);
extern void ieee80211_txb_free(struct ieee80211_txb *);
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c
index 7294572b990..cba12b84be5 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c
@@ -618,7 +618,7 @@ void ieee80211_query_seqnum(struct ieee80211_device*ieee, struct sk_buff* skb, u
}
}
-int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
+int rtl8192_ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
struct ieee80211_device *ieee = netdev_priv(dev);
@@ -943,5 +943,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
return 1;
}
+EXPORT_SYMBOL(rtl8192_ieee80211_xmit);
EXPORT_SYMBOL(ieee80211_txb_free);
diff --git a/drivers/staging/rtl8192su/r8192U_core.c b/drivers/staging/rtl8192su/r8192U_core.c
index 4ab250743e8..70f81a8f129 100644
--- a/drivers/staging/rtl8192su/r8192U_core.c
+++ b/drivers/staging/rtl8192su/r8192U_core.c
@@ -12142,7 +12142,7 @@ static const struct net_device_ops rtl8192_netdev_ops = {
.ndo_set_mac_address = r8192_set_mac_adr,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
- .ndo_start_xmit = ieee80211_xmit,
+ .ndo_start_xmit = rtl8192_ieee80211_xmit,
};
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index e1f89416ef8..2bfc41ece0e 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -387,7 +387,6 @@ static void acm_rx_tasklet(unsigned long _acm)
struct acm_ru *rcv;
unsigned long flags;
unsigned char throttled;
- struct usb_host_endpoint *ep;
dbg("Entering acm_rx_tasklet");
@@ -463,14 +462,12 @@ urbs:
rcv->buffer = buf;
- ep = (usb_pipein(acm->rx_endpoint) ? acm->dev->ep_in : acm->dev->ep_out)
- [usb_pipeendpoint(acm->rx_endpoint)];
- if (usb_endpoint_xfer_int(&ep->desc))
+ if (acm->is_int_ep)
usb_fill_int_urb(rcv->urb, acm->dev,
acm->rx_endpoint,
buf->base,
acm->readsize,
- acm_read_bulk, rcv, ep->desc.bInterval);
+ acm_read_bulk, rcv, acm->bInterval);
else
usb_fill_bulk_urb(rcv->urb, acm->dev,
acm->rx_endpoint,
@@ -1183,6 +1180,9 @@ made_compressed_probe:
spin_lock_init(&acm->read_lock);
mutex_init(&acm->mutex);
acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
+ acm->is_int_ep = usb_endpoint_xfer_int(epread);
+ if (acm->is_int_ep)
+ acm->bInterval = epread->bInterval;
tty_port_init(&acm->port);
acm->port.ops = &acm_port_ops;
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index 1602324808b..c4a0ee8ffcc 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -126,6 +126,8 @@ struct acm {
unsigned int ctrl_caps; /* control capabilities from the class specific header */
unsigned int susp_count; /* number of suspended interfaces */
int combined_interfaces:1; /* control and data collapsed */
+ int is_int_ep:1; /* interrupt endpoints contrary to spec used */
+ u8 bInterval;
struct acm_wb *delayed_wb; /* write queued for a device about to be woken */
};
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 38b8bce782d..4247eccf858 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -595,7 +595,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
if (!ps)
goto out;
- ret = -ENOENT;
+ ret = -ENODEV;
/* usbdev device-node */
if (imajor(inode) == USB_DEVICE_MAJOR)
@@ -1321,7 +1321,8 @@ static int get_urb32(struct usbdevfs_urb *kurb,
struct usbdevfs_urb32 __user *uurb)
{
__u32 uptr;
- if (get_user(kurb->type, &uurb->type) ||
+ if (!access_ok(VERIFY_READ, uurb, sizeof(*uurb)) ||
+ __get_user(kurb->type, &uurb->type) ||
__get_user(kurb->endpoint, &uurb->endpoint) ||
__get_user(kurb->status, &uurb->status) ||
__get_user(kurb->flags, &uurb->flags) ||
@@ -1536,8 +1537,9 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)
u32 udata;
uioc = compat_ptr((long)arg);
- if (get_user(ctrl.ifno, &uioc->ifno) ||
- get_user(ctrl.ioctl_code, &uioc->ioctl_code) ||
+ if (!access_ok(VERIFY_READ, uioc, sizeof(*uioc)) ||
+ __get_user(ctrl.ifno, &uioc->ifno) ||
+ __get_user(ctrl.ioctl_code, &uioc->ioctl_code) ||
__get_user(udata, &uioc->data))
return -EFAULT;
ctrl.data = compat_ptr(udata);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 7d03549c333..11c627ce602 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -903,7 +903,8 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
/* already started */
break;
case QH_STATE_IDLE:
- WARN_ON(1);
+ /* QH might be waiting for a Clear-TT-Buffer */
+ qh_completions(ehci, qh);
break;
}
break;
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 9a1384747f3..7673554fa64 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -375,12 +375,11 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
*/
if ((token & QTD_STS_XACT) &&
QTD_CERR(token) == 0 &&
- --qh->xacterrs > 0 &&
+ ++qh->xacterrs < QH_XACTERR_MAX &&
!urb->unlinked) {
ehci_dbg(ehci,
"detected XactErr len %zu/%zu retry %d\n",
- qtd->length - QTD_LENGTH(token), qtd->length,
- QH_XACTERR_MAX - qh->xacterrs);
+ qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs);
/* reset the token in the qtd and the
* qh overlay (which still contains
@@ -494,7 +493,7 @@ halt:
last = qtd;
/* reinit the xacterr counter for the next qtd */
- qh->xacterrs = QH_XACTERR_MAX;
+ qh->xacterrs = 0;
}
/* last urb's completion might still need calling */
@@ -940,7 +939,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
head->qh_next.qh = qh;
head->hw_next = dma;
- qh->xacterrs = QH_XACTERR_MAX;
+ qh_get(qh);
+ qh->xacterrs = 0;
qh->qh_state = QH_STATE_LINKED;
/* qtd completions reported later by interrupt */
}
@@ -1080,7 +1080,7 @@ submit_async (
* the HC and TT handle it when the TT has a buffer ready.
*/
if (likely (qh->qh_state == QH_STATE_IDLE))
- qh_link_async (ehci, qh_get (qh));
+ qh_link_async(ehci, qh);
done:
spin_unlock_irqrestore (&ehci->lock, flags);
if (unlikely (qh == NULL))
@@ -1115,8 +1115,6 @@ static void end_unlink_async (struct ehci_hcd *ehci)
&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
qh_link_async (ehci, qh);
else {
- qh_put (qh); // refcount from async list
-
/* it's not free to turn the async schedule on/off; leave it
* active but idle for a while once it empties.
*/
@@ -1124,6 +1122,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
&& ehci->async->qh_next.qh == NULL)
timer_action (ehci, TIMER_ASYNC_OFF);
}
+ qh_put(qh); /* refcount from async list */
if (next) {
ehci->reclaim = NULL;
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 74f7f83b29a..edd61ee9032 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -542,6 +542,7 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
}
}
qh->qh_state = QH_STATE_LINKED;
+ qh->xacterrs = 0;
qh_get (qh);
/* update per-qh bandwidth for usbfs */
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 70073b157f0..803adcb5ac1 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -12,6 +12,7 @@ config USB_MUSB_HDRC
depends on !SUPERH
select NOP_USB_XCEIV if ARCH_DAVINCI
select TWL4030_USB if MACH_OMAP_3430SDP
+ select NOP_USB_XCEIV if MACH_OMAP3EVM
select USB_OTG_UTILS
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
help
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index b574878c78b..8fec5d4455c 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -699,6 +699,9 @@ static struct usb_device_id id_table_combined [] = {
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) },
{ USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) },
+ { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
+ { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 24dbd99e87d..8c92b88166a 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -954,6 +954,20 @@
#define AURICAL_USB_PID 0x0010 /* Aurical USB Audiometer */
/*
+ * Bayer Ascensia Contour blood glucose meter USB-converter cable.
+ * http://winglucofacts.com/cables/
+ */
+#define BAYER_VID 0x1A79
+#define BAYER_CONTOUR_CABLE_PID 0x6001
+
+/*
+ * Marvell OpenRD Base, Client
+ * http://www.open-rd.org
+ * OpenRD Base, Client use VID 0x0403
+ */
+#define MARVELL_OPENRD_PID 0x9e90
+
+/*
* BmRequestType: 1100 0000b
* bRequest: FTDI_E2_READ
* wValue: 0
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 7d15bfa7c2d..3e86815b270 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -95,6 +95,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
+ { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 12aac7d2462..ee9505e1dd9 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -126,3 +126,7 @@
/* Cressi Edy (diving computer) PC interface */
#define CRESSI_VENDOR_ID 0x04b8
#define CRESSI_EDY_PRODUCT_ID 0x0521
+
+/* Sony, USB data cable for CMD-Jxx mobile phones */
+#define SONY_VENDOR_ID 0x054c
+#define SONY_QN3USB_PRODUCT_ID 0x0437
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 1b9c5dd0fb2..7477d411959 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -838,6 +838,13 @@ UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
+/* Reported by Rogerio Brito <rbrito@ime.usp.br> */
+UNUSUAL_DEV( 0x067b, 0x2317, 0x0001, 0x001,
+ "Prolific Technology, Inc.",
+ "Mass Storage Device",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_NOT_LOCKABLE ),
+
/* Reported by Richard -=[]=- <micro_flyer@hotmail.com> */
/* Change to bcdDeviceMin (0x0100 to 0x0001) reported by
* Thomas Bartosik <tbartdev@gmx-topmail.de> */
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 471a9a60376..3a44695b9c0 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -1082,7 +1082,6 @@ static void fbcon_init(struct vc_data *vc, int init)
new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
new_cols /= vc->vc_font.width;
new_rows /= vc->vc_font.height;
- vc_resize(vc, new_cols, new_rows);
/*
* We must always set the mode. The mode of the previous console
@@ -1111,10 +1110,11 @@ static void fbcon_init(struct vc_data *vc, int init)
* vc_{cols,rows}, but we must not set those if we are only
* resizing the console.
*/
- if (!init) {
+ if (init) {
vc->vc_cols = new_cols;
vc->vc_rows = new_rows;
- }
+ } else
+ vc_resize(vc, new_cols, new_rows);
if (logo)
fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
diff --git a/drivers/video/console/fbcon_rotate.h b/drivers/video/console/fbcon_rotate.h
index 75be5ce53dc..e233444cda6 100644
--- a/drivers/video/console/fbcon_rotate.h
+++ b/drivers/video/console/fbcon_rotate.h
@@ -45,7 +45,7 @@ static inline void rotate_ud(const char *in, char *out, u32 width, u32 height)
width = (width + 7) & ~7;
for (i = 0; i < height; i++) {
- for (j = 0; j < width; j++) {
+ for (j = 0; j < width - shift; j++) {
if (pattern_test_bit(j, i, width, in))
pattern_set_bit(width - (1 + j + shift),
height - (1 + i),
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c
index ef7870f5ea0..857b3668b3b 100644
--- a/drivers/video/console/sticore.c
+++ b/drivers/video/console/sticore.c
@@ -957,9 +957,14 @@ static int __devinit sticore_pci_init(struct pci_dev *pd,
#ifdef CONFIG_PCI
unsigned long fb_base, rom_base;
unsigned int fb_len, rom_len;
+ int err;
struct sti_struct *sti;
- pci_enable_device(pd);
+ err = pci_enable_device(pd);
+ if (err < 0) {
+ dev_err(&pd->dev, "Cannot enable PCI device\n");
+ return err;
+ }
fb_base = pci_resource_start(pd, 0);
fb_len = pci_resource_len(pd, 0);
@@ -1048,7 +1053,7 @@ static void __devinit sti_init_roms(void)
/* Register drivers for native & PCI cards */
register_parisc_driver(&pa_sti_driver);
- pci_register_driver(&pci_sti_driver);
+ WARN_ON(pci_register_driver(&pci_sti_driver));
/* if we didn't find the given default sti, take the first one */
if (!default_sti)
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index f8778cde218..054ef29be47 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -669,7 +669,8 @@ static uint32_t bpp_to_pixfmt(int bpp)
}
static int mx3fb_blank(int blank, struct fb_info *fbi);
-static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len);
+static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len,
+ bool lock);
static int mx3fb_unmap_video_memory(struct fb_info *fbi);
/**
@@ -711,12 +712,7 @@ static void mx3fb_dma_done(void *arg)
complete(&mx3_fbi->flip_cmpl);
}
-/**
- * mx3fb_set_par() - set framebuffer parameters and change the operating mode.
- * @fbi: framebuffer information pointer.
- * @return: 0 on success or negative error code on failure.
- */
-static int mx3fb_set_par(struct fb_info *fbi)
+static int __set_par(struct fb_info *fbi, bool lock)
{
u32 mem_len;
struct ipu_di_signal_cfg sig_cfg;
@@ -727,10 +723,6 @@ static int mx3fb_set_par(struct fb_info *fbi)
struct idmac_video_param *video = &ichan->params.video;
struct scatterlist *sg = mx3_fbi->sg;
- dev_dbg(mx3fb->dev, "%s [%c]\n", __func__, list_empty(&ichan->queue) ? '-' : '+');
-
- mutex_lock(&mx3_fbi->mutex);
-
/* Total cleanup */
if (mx3_fbi->txd)
sdc_disable_channel(mx3_fbi);
@@ -742,10 +734,8 @@ static int mx3fb_set_par(struct fb_info *fbi)
if (fbi->fix.smem_start)
mx3fb_unmap_video_memory(fbi);
- if (mx3fb_map_video_memory(fbi, mem_len) < 0) {
- mutex_unlock(&mx3_fbi->mutex);
+ if (mx3fb_map_video_memory(fbi, mem_len, lock) < 0)
return -ENOMEM;
- }
}
sg_init_table(&sg[0], 1);
@@ -791,7 +781,6 @@ static int mx3fb_set_par(struct fb_info *fbi)
fbi->var.vsync_len,
fbi->var.lower_margin +
fbi->var.vsync_len, sig_cfg) != 0) {
- mutex_unlock(&mx3_fbi->mutex);
dev_err(fbi->device,
"mx3fb: Error initializing panel.\n");
return -EINVAL;
@@ -810,9 +799,30 @@ static int mx3fb_set_par(struct fb_info *fbi)
if (mx3_fbi->blank == FB_BLANK_UNBLANK)
sdc_enable_channel(mx3_fbi);
+ return 0;
+}
+
+/**
+ * mx3fb_set_par() - set framebuffer parameters and change the operating mode.
+ * @fbi: framebuffer information pointer.
+ * @return: 0 on success or negative error code on failure.
+ */
+static int mx3fb_set_par(struct fb_info *fbi)
+{
+ struct mx3fb_info *mx3_fbi = fbi->par;
+ struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;
+ struct idmac_channel *ichan = mx3_fbi->idmac_channel;
+ int ret;
+
+ dev_dbg(mx3fb->dev, "%s [%c]\n", __func__, list_empty(&ichan->queue) ? '-' : '+');
+
+ mutex_lock(&mx3_fbi->mutex);
+
+ ret = __set_par(fbi, true);
+
mutex_unlock(&mx3_fbi->mutex);
- return 0;
+ return ret;
}
/**
@@ -966,21 +976,11 @@ static int mx3fb_setcolreg(unsigned int regno, unsigned int red,
return ret;
}
-/**
- * mx3fb_blank() - blank the display.
- */
-static int mx3fb_blank(int blank, struct fb_info *fbi)
+static void __blank(int blank, struct fb_info *fbi)
{
struct mx3fb_info *mx3_fbi = fbi->par;
struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;
- dev_dbg(fbi->device, "%s, blank = %d, base %p, len %u\n", __func__,
- blank, fbi->screen_base, fbi->fix.smem_len);
-
- if (mx3_fbi->blank == blank)
- return 0;
-
- mutex_lock(&mx3_fbi->mutex);
mx3_fbi->blank = blank;
switch (blank) {
@@ -999,6 +999,23 @@ static int mx3fb_blank(int blank, struct fb_info *fbi)
sdc_set_brightness(mx3fb, mx3fb->backlight_level);
break;
}
+}
+
+/**
+ * mx3fb_blank() - blank the display.
+ */
+static int mx3fb_blank(int blank, struct fb_info *fbi)
+{
+ struct mx3fb_info *mx3_fbi = fbi->par;
+
+ dev_dbg(fbi->device, "%s, blank = %d, base %p, len %u\n", __func__,
+ blank, fbi->screen_base, fbi->fix.smem_len);
+
+ if (mx3_fbi->blank == blank)
+ return 0;
+
+ mutex_lock(&mx3_fbi->mutex);
+ __blank(blank, fbi);
mutex_unlock(&mx3_fbi->mutex);
return 0;
@@ -1198,6 +1215,7 @@ static int mx3fb_resume(struct platform_device *pdev)
* mx3fb_map_video_memory() - allocates the DRAM memory for the frame buffer.
* @fbi: framebuffer information pointer
* @mem_len: length of mapped memory
+ * @lock: do not lock during initialisation
* @return: Error code indicating success or failure
*
* This buffer is remapped into a non-cached, non-buffered, memory region to
@@ -1205,7 +1223,8 @@ static int mx3fb_resume(struct platform_device *pdev)
* area is remapped, all virtual memory access to the video memory should occur
* at the new region.
*/
-static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len)
+static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len,
+ bool lock)
{
int retval = 0;
dma_addr_t addr;
@@ -1221,10 +1240,12 @@ static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len)
goto err0;
}
- mutex_lock(&fbi->mm_lock);
+ if (lock)
+ mutex_lock(&fbi->mm_lock);
fbi->fix.smem_start = addr;
fbi->fix.smem_len = mem_len;
- mutex_unlock(&fbi->mm_lock);
+ if (lock)
+ mutex_unlock(&fbi->mm_lock);
dev_dbg(fbi->device, "allocated fb @ p=0x%08x, v=0x%p, size=%d.\n",
(uint32_t) fbi->fix.smem_start, fbi->screen_base, fbi->fix.smem_len);
@@ -1365,6 +1386,11 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
init_completion(&mx3fbi->flip_cmpl);
disable_irq(ichan->eof_irq);
dev_dbg(mx3fb->dev, "disabling irq %d\n", ichan->eof_irq);
+ ret = __set_par(fbi, false);
+ if (ret < 0)
+ goto esetpar;
+
+ __blank(FB_BLANK_UNBLANK, fbi);
dev_info(dev, "registered, using mode %s\n", fb_mode);
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index fcd53ceb88f..c8960003f47 100644
--- a/drivers/video/via/hw.c
+++ b/drivers/video/via/hw.c
@@ -2407,14 +2407,14 @@ int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
viafb_dvi_set_mode(viafb_get_mode_index
(viaparinfo->tmds_setting_info->h_active,
viaparinfo->tmds_setting_info->
- v_active, 1),
+ v_active),
video_bpp1, viaparinfo->
tmds_setting_info->iga_path);
} else {
viafb_dvi_set_mode(viafb_get_mode_index
(viaparinfo->tmds_setting_info->h_active,
viaparinfo->
- tmds_setting_info->v_active, 0),
+ tmds_setting_info->v_active),
video_bpp, viaparinfo->
tmds_setting_info->iga_path);
}
diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c
index 6c7290a6a44..78c6b338794 100644
--- a/drivers/video/via/lcd.c
+++ b/drivers/video/via/lcd.c
@@ -580,10 +580,7 @@ static void load_lcd_k400_patch_tbl(int set_hres, int set_vres,
int reg_num = 0;
struct io_reg *lcd_patch_reg = NULL;
- if (viaparinfo->lvds_setting_info->iga_path == IGA2)
- vmode_index = viafb_get_mode_index(set_hres, set_vres, 1);
- else
- vmode_index = viafb_get_mode_index(set_hres, set_vres, 0);
+ vmode_index = viafb_get_mode_index(set_hres, set_vres);
switch (panel_id) {
/* LCD 800x600 */
case LCD_PANEL_ID1_800X600:
@@ -761,10 +758,7 @@ static void load_lcd_p880_patch_tbl(int set_hres, int set_vres,
int reg_num = 0;
struct io_reg *lcd_patch_reg = NULL;
- if (viaparinfo->lvds_setting_info->iga_path == IGA2)
- vmode_index = viafb_get_mode_index(set_hres, set_vres, 1);
- else
- vmode_index = viafb_get_mode_index(set_hres, set_vres, 0);
+ vmode_index = viafb_get_mode_index(set_hres, set_vres);
switch (panel_id) {
case LCD_PANEL_ID5_1400X1050:
@@ -832,10 +826,7 @@ static void load_lcd_patch_regs(int set_hres, int set_vres,
{
int vmode_index;
- if (viaparinfo->lvds_setting_info->iga_path == IGA2)
- vmode_index = viafb_get_mode_index(set_hres, set_vres, 1);
- else
- vmode_index = viafb_get_mode_index(set_hres, set_vres, 0);
+ vmode_index = viafb_get_mode_index(set_hres, set_vres);
viafb_unlock_crt();
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index a0fec298216..72833f3334b 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -32,7 +32,6 @@ static u32 pseudo_pal[17];
/* video mode */
static char *viafb_mode = "640x480";
static char *viafb_mode1 = "640x480";
-static int viafb_resMode = VIA_RES_640X480;
/* Added for specifying active devices.*/
char *viafb_active_dev = "";
@@ -56,47 +55,47 @@ static void viafb_get_video_device(u32 *video_dev_info);
/* Mode information */
static const struct viafb_modeinfo viafb_modentry[] = {
- {480, 640, VIA_RES_480X640, "480x640"},
- {640, 480, VIA_RES_640X480, "640x480"},
- {800, 480, VIA_RES_800X480, "800x480"},
- {800, 600, VIA_RES_800X600, "800x600"},
- {1024, 768, VIA_RES_1024X768, "1024x768"},
- {1152, 864, VIA_RES_1152X864, "1152x864"},
- {1280, 1024, VIA_RES_1280X1024, "1280x1024"},
- {1600, 1200, VIA_RES_1600X1200, "1600x1200"},
- {1440, 1050, VIA_RES_1440X1050, "1440x1050"},
- {1280, 768, VIA_RES_1280X768, "1280x768"},
- {1280, 800, VIA_RES_1280X800, "1280x800"},
- {1280, 960, VIA_RES_1280X960, "1280x960"},
- {1920, 1440, VIA_RES_1920X1440, "1920x1440"},
- {848, 480, VIA_RES_848X480, "848x480"},
- {1400, 1050, VIA_RES_1400X1050, "1400x1050"},
- {720, 480, VIA_RES_720X480, "720x480"},
- {720, 576, VIA_RES_720X576, "720x576"},
- {1024, 512, VIA_RES_1024X512, "1024x512"},
- {1024, 576, VIA_RES_1024X576, "1024x576"},
- {1024, 600, VIA_RES_1024X600, "1024x600"},
- {1280, 720, VIA_RES_1280X720, "1280x720"},
- {1920, 1080, VIA_RES_1920X1080, "1920x1080"},
- {1366, 768, VIA_RES_1368X768, "1368x768"},
- {1680, 1050, VIA_RES_1680X1050, "1680x1050"},
- {960, 600, VIA_RES_960X600, "960x600"},
- {1000, 600, VIA_RES_1000X600, "1000x600"},
- {1024, 576, VIA_RES_1024X576, "1024x576"},
- {1024, 600, VIA_RES_1024X600, "1024x600"},
- {1088, 612, VIA_RES_1088X612, "1088x612"},
- {1152, 720, VIA_RES_1152X720, "1152x720"},
- {1200, 720, VIA_RES_1200X720, "1200x720"},
- {1280, 600, VIA_RES_1280X600, "1280x600"},
- {1360, 768, VIA_RES_1360X768, "1360x768"},
- {1440, 900, VIA_RES_1440X900, "1440x900"},
- {1600, 900, VIA_RES_1600X900, "1600x900"},
- {1600, 1024, VIA_RES_1600X1024, "1600x1024"},
- {1792, 1344, VIA_RES_1792X1344, "1792x1344"},
- {1856, 1392, VIA_RES_1856X1392, "1856x1392"},
- {1920, 1200, VIA_RES_1920X1200, "1920x1200"},
- {2048, 1536, VIA_RES_2048X1536, "2048x1536"},
- {0, 0, VIA_RES_INVALID, "640x480"}
+ {480, 640, VIA_RES_480X640},
+ {640, 480, VIA_RES_640X480},
+ {800, 480, VIA_RES_800X480},
+ {800, 600, VIA_RES_800X600},
+ {1024, 768, VIA_RES_1024X768},
+ {1152, 864, VIA_RES_1152X864},
+ {1280, 1024, VIA_RES_1280X1024},
+ {1600, 1200, VIA_RES_1600X1200},
+ {1440, 1050, VIA_RES_1440X1050},
+ {1280, 768, VIA_RES_1280X768,},
+ {1280, 800, VIA_RES_1280X800},
+ {1280, 960, VIA_RES_1280X960},
+ {1920, 1440, VIA_RES_1920X1440},
+ {848, 480, VIA_RES_848X480},
+ {1400, 1050, VIA_RES_1400X1050},
+ {720, 480, VIA_RES_720X480},
+ {720, 576, VIA_RES_720X576},
+ {1024, 512, VIA_RES_1024X512},
+ {1024, 576, VIA_RES_1024X576},
+ {1024, 600, VIA_RES_1024X600},
+ {1280, 720, VIA_RES_1280X720},
+ {1920, 1080, VIA_RES_1920X1080},
+ {1366, 768, VIA_RES_1368X768},
+ {1680, 1050, VIA_RES_1680X1050},
+ {960, 600, VIA_RES_960X600},
+ {1000, 600, VIA_RES_1000X600},
+ {1024, 576, VIA_RES_1024X576},
+ {1024, 600, VIA_RES_1024X600},
+ {1088, 612, VIA_RES_1088X612},
+ {1152, 720, VIA_RES_1152X720},
+ {1200, 720, VIA_RES_1200X720},
+ {1280, 600, VIA_RES_1280X600},
+ {1360, 768, VIA_RES_1360X768},
+ {1440, 900, VIA_RES_1440X900},
+ {1600, 900, VIA_RES_1600X900},
+ {1600, 1024, VIA_RES_1600X1024},
+ {1792, 1344, VIA_RES_1792X1344},
+ {1856, 1392, VIA_RES_1856X1392},
+ {1920, 1200, VIA_RES_1920X1200},
+ {2048, 1536, VIA_RES_2048X1536},
+ {0, 0, VIA_RES_INVALID}
};
static struct fb_ops viafb_ops;
@@ -177,7 +176,7 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
if (var->vmode & FB_VMODE_INTERLACED || var->vmode & FB_VMODE_DOUBLE)
return -EINVAL;
- vmode_index = viafb_get_mode_index(var->xres, var->yres, 0);
+ vmode_index = viafb_get_mode_index(var->xres, var->yres);
if (vmode_index == VIA_RES_INVALID) {
DEBUG_MSG(KERN_INFO
"viafb: Mode %dx%dx%d not supported!!\n",
@@ -233,14 +232,14 @@ static int viafb_set_par(struct fb_info *info)
viafb_update_device_setting(info->var.xres, info->var.yres,
info->var.bits_per_pixel, viafb_refresh, 0);
- vmode_index = viafb_get_mode_index(info->var.xres, info->var.yres, 0);
+ vmode_index = viafb_get_mode_index(info->var.xres, info->var.yres);
if (viafb_SAMM_ON == 1) {
DEBUG_MSG(KERN_INFO
"viafb_second_xres = %d, viafb_second_yres = %d, bpp = %d\n",
viafb_second_xres, viafb_second_yres, viafb_bpp1);
vmode_index1 = viafb_get_mode_index(viafb_second_xres,
- viafb_second_yres, 1);
+ viafb_second_yres);
DEBUG_MSG(KERN_INFO "->viafb_SAMM_ON: index=%d\n",
vmode_index1);
@@ -1262,7 +1261,7 @@ static int viafb_sync(struct fb_info *info)
return 0;
}
-int viafb_get_mode_index(int hres, int vres, int flag)
+int viafb_get_mode_index(int hres, int vres)
{
u32 i;
DEBUG_MSG(KERN_INFO "viafb_get_mode_index!\n");
@@ -1272,13 +1271,7 @@ int viafb_get_mode_index(int hres, int vres, int flag)
viafb_modentry[i].yres == vres)
break;
- viafb_resMode = viafb_modentry[i].mode_index;
- if (flag)
- viafb_mode1 = viafb_modentry[i].mode_res;
- else
- viafb_mode = viafb_modentry[i].mode_res;
-
- return viafb_resMode;
+ return viafb_modentry[i].mode_index;
}
static void check_available_device_to_enable(int device_id)
@@ -2199,7 +2192,7 @@ static int __devinit via_pci_probe(void)
strict_strtoul(tmpc, 0, &default_xres);
strict_strtoul(tmpm, 0, &default_yres);
- vmode_index = viafb_get_mode_index(default_xres, default_yres, 0);
+ vmode_index = viafb_get_mode_index(default_xres, default_yres);
DEBUG_MSG(KERN_INFO "0->index=%d\n", vmode_index);
if (viafb_SAMM_ON == 1) {
diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h
index a4158e87287..227b000feb3 100644
--- a/drivers/video/via/viafbdev.h
+++ b/drivers/video/via/viafbdev.h
@@ -81,7 +81,6 @@ struct viafb_modeinfo {
u32 xres;
u32 yres;
int mode_index;
- char *mode_res;
};
extern unsigned int viafb_second_virtual_yres;
extern unsigned int viafb_second_virtual_xres;
@@ -102,7 +101,7 @@ extern int strict_strtoul(const char *cp, unsigned int base,
void viafb_memory_pitch_patch(struct fb_info *info);
void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
int mode_index);
-int viafb_get_mode_index(int hres, int vres, int flag);
+int viafb_get_mode_index(int hres, int vres);
u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
*plvds_setting_info, struct lvds_chip_information
*plvds_chip_info, u8 index);
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
index a7e3b706b9d..0d92969404c 100644
--- a/drivers/w1/masters/omap_hdq.c
+++ b/drivers/w1/masters/omap_hdq.c
@@ -687,6 +687,7 @@ static int omap_hdq_remove(struct platform_device *pdev)
if (hdq_data->hdq_usecount) {
dev_dbg(&pdev->dev, "removed when use count is not zero\n");
+ mutex_unlock(&hdq_data->hdq_mutex);
return -EBUSY;
}
diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c
index fecb307d28e..aec7cefdef2 100644
--- a/drivers/watchdog/coh901327_wdt.c
+++ b/drivers/watchdog/coh901327_wdt.c
@@ -18,6 +18,7 @@
#include <linux/bitops.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
+#include <linux/delay.h>
#define DRV_NAME "WDOG COH 901 327"
@@ -92,6 +93,8 @@ static struct clk *clk;
static void coh901327_enable(u16 timeout)
{
u16 val;
+ unsigned long freq;
+ unsigned long delay_ns;
clk_enable(clk);
/* Restart timer if it is disabled */
@@ -102,6 +105,14 @@ static void coh901327_enable(u16 timeout)
/* Acknowledge any pending interrupt so it doesn't just fire off */
writew(U300_WDOG_IER_WILL_BARK_IRQ_ACK_ENABLE,
virtbase + U300_WDOG_IER);
+ /*
+ * The interrupt is cleared in the 32 kHz clock domain.
+ * Wait 3 32 kHz cycles for it to take effect
+ */
+ freq = clk_get_rate(clk);
+ delay_ns = (1000000000 + freq - 1) / freq; /* Freq to ns and round up */
+ delay_ns = 3 * delay_ns; /* Wait 3 cycles */
+ ndelay(delay_ns);
/* Enable the watchdog interrupt */
writew(U300_WDOG_IMR_WILL_BARK_IRQ_ENABLE, virtbase + U300_WDOG_IMR);
/* Activate the watchdog timer */
diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c
index 00b03eb43bf..e1c82769b08 100644
--- a/drivers/watchdog/ks8695_wdt.c
+++ b/drivers/watchdog/ks8695_wdt.c
@@ -66,7 +66,7 @@ static inline void ks8695_wdt_stop(void)
static inline void ks8695_wdt_start(void)
{
unsigned long tmcon;
- unsigned long tval = wdt_time * CLOCK_TICK_RATE;
+ unsigned long tval = wdt_time * KS8695_CLOCK_RATE;
spin_lock(&ks8695_lock);
/* disable timer0 */
@@ -103,7 +103,7 @@ static inline void ks8695_wdt_reload(void)
static int ks8695_wdt_settimeout(int new_time)
{
/*
- * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz
+ * All counting occurs at KS8695_CLOCK_RATE / 128 = 0.256 Hz
*
* Since WDV is a 16-bit counter, the maximum period is
* 65536 / 0.256 = 256 seconds.