summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/acpica/acconfig.h2
-rw-r--r--drivers/acpi/apei/Kconfig1
-rw-r--r--drivers/acpi/apei/apei-base.c2
-rw-r--r--drivers/base/power/clock_ops.c75
-rw-r--r--drivers/block/floppy.c8
-rw-r--r--drivers/block/xen-blkback/common.h2
-rw-r--r--drivers/block/xen-blkback/xenbus.c6
-rw-r--r--drivers/bluetooth/btusb.c6
-rw-r--r--drivers/bluetooth/btwilink.c16
-rw-r--r--drivers/char/tpm/Kconfig1
-rw-r--r--drivers/char/tpm/tpm.c9
-rw-r--r--drivers/char/tpm/tpm_nsc.c2
-rw-r--r--drivers/cpufreq/pcc-cpufreq.c3
-rw-r--r--drivers/firewire/ohci.c3
-rw-r--r--drivers/gpio/gpio-generic.c15
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c4
-rw-r--r--drivers/gpu/drm/i915/intel_display.c22
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h3
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c88
-rw-r--r--drivers/gpu/drm/radeon/atombios_dp.c16
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c58
-rw-r--r--drivers/gpu/drm/radeon/ni.c44
-rw-r--r--drivers/gpu/drm/radeon/r100.c22
-rw-r--r--drivers/gpu/drm/radeon/r200.c4
-rw-r--r--drivers/gpu/drm/radeon/r600.c14
-rw-r--r--drivers/gpu/drm/radeon/radeon.h7
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h8
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_cursor.c40
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c9
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c7
-rw-r--r--drivers/gpu/drm/radeon/rv770.c51
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c3
-rw-r--r--drivers/hid/hid-wacom.c2
-rw-r--r--drivers/hwmon/coretemp.c216
-rw-r--r--drivers/hwmon/ds620.c2
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c9
-rw-r--r--drivers/hwmon/w83791d.c4
-rw-r--r--drivers/ide/ide-disk.c7
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c10
-rw-r--r--drivers/input/keyboard/adp5588-keys.c1
-rw-r--r--drivers/input/misc/cm109.c2
-rw-r--r--drivers/input/mouse/bcm5974.c20
-rw-r--r--drivers/input/tablet/wacom_sys.c14
-rw-r--r--drivers/input/tablet/wacom_wac.c45
-rw-r--r--drivers/input/touchscreen/wacom_w8001.c2
-rw-r--r--drivers/iommu/dmar.c2
-rw-r--r--drivers/leds/ledtrig-timer.c2
-rw-r--r--drivers/media/video/omap/omap_vout.c13
-rw-r--r--drivers/media/video/omap3isp/ispccdc.c1
-rw-r--r--drivers/media/video/uvc/uvc_driver.c2
-rw-r--r--drivers/media/video/uvc/uvc_entity.c2
-rw-r--r--drivers/media/video/uvc/uvc_video.c10
-rw-r--r--drivers/media/video/uvc/uvcvideo.h2
-rw-r--r--drivers/media/video/v4l2-dev.c11
-rw-r--r--drivers/media/video/v4l2-device.c2
-rw-r--r--drivers/mfd/jz4740-adc.c2
-rw-r--r--drivers/mfd/max8997.c5
-rw-r--r--drivers/mfd/omap-usb-host.c2
-rw-r--r--drivers/mfd/tps65910-irq.c2
-rw-r--r--drivers/mfd/twl4030-madc.c5
-rw-r--r--drivers/mfd/wm8350-gpio.c4
-rw-r--r--drivers/misc/lis3lv02d/lis3lv02d.c14
-rw-r--r--drivers/misc/pti.c12
-rw-r--r--drivers/mmc/card/block.c3
-rw-r--r--drivers/net/Kconfig11
-rw-r--r--drivers/net/bnx2x/bnx2x.h124
-rw-r--r--drivers/net/bnx2x/bnx2x_cmn.c27
-rw-r--r--drivers/net/bnx2x/bnx2x_dcb.c1
-rw-r--r--drivers/net/bnx2x/bnx2x_ethtool.c48
-rw-r--r--drivers/net/bnx2x/bnx2x_link.c46
-rw-r--r--drivers/net/bnx2x/bnx2x_main.c178
-rw-r--r--drivers/net/bnx2x/bnx2x_reg.h19
-rw-r--r--drivers/net/bnx2x/bnx2x_stats.c7
-rw-r--r--drivers/net/bonding/bond_3ad.c3
-rw-r--r--drivers/net/bonding/bond_alb.c3
-rw-r--r--drivers/net/bonding/bond_main.c13
-rw-r--r--drivers/net/can/ti_hecc.c1
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.c23
-rw-r--r--drivers/net/cxgb3/l2t.c15
-rw-r--r--drivers/net/cxgb3/l2t.h16
-rw-r--r--drivers/net/cxgb4/cxgb4_main.c3
-rw-r--r--drivers/net/e1000/e1000_hw.c6
-rw-r--r--drivers/net/gianfar_ethtool.c8
-rw-r--r--drivers/net/greth.c12
-rw-r--r--drivers/net/greth.h1
-rw-r--r--drivers/net/ibmveth.c52
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c4
-rw-r--r--drivers/net/netconsole.c8
-rw-r--r--drivers/net/pch_gbe/pch_gbe.h12
-rw-r--r--drivers/net/pch_gbe/pch_gbe_main.c346
-rw-r--r--drivers/net/phy/dp83640.c4
-rw-r--r--drivers/net/ppp_generic.c7
-rw-r--r--drivers/net/pxa168_eth.c1
-rw-r--r--drivers/net/r8169.c32
-rw-r--r--drivers/net/sfc/efx.c18
-rw-r--r--drivers/net/sfc/io.h6
-rw-r--r--drivers/net/sfc/mcdi.c46
-rw-r--r--drivers/net/sfc/nic.c7
-rw-r--r--drivers/net/sfc/nic.h2
-rw-r--r--drivers/net/sfc/siena.c25
-rw-r--r--drivers/net/sfc/workarounds.h2
-rw-r--r--drivers/net/tg3.c2
-rw-r--r--drivers/net/usb/ipheth.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_calib.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c10
-rw-r--r--drivers/net/wireless/b43/main.c3
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c21
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c39
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-3945-rs.c13
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-core.c4
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-hcmd.c2
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-tx.c4
-rw-r--r--drivers/net/wireless/iwlegacy/iwl3945-base.c8
-rw-r--r--drivers/net/wireless/iwlegacy/iwl4965-base.c10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-ucode.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c30
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c47
-rw-r--r--drivers/net/wireless/rtlwifi/core.c8
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/trx.c11
-rw-r--r--drivers/net/wireless/rtlwifi/usb.c1
-rw-r--r--drivers/net/xen-netback/interface.c4
-rw-r--r--drivers/pci/pci.c6
-rw-r--r--drivers/pci/probe.c17
-rw-r--r--drivers/rtc/rtc-imxdi.c1
-rw-r--r--drivers/rtc/rtc-s3c.c26
-rw-r--r--drivers/s390/cio/cio.c8
-rw-r--r--drivers/scsi/3w-9xxx.c2
-rw-r--r--drivers/scsi/Kconfig1
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/aacraid/commsup.c2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c2
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/cxgb3i.c2
-rw-r--r--drivers/scsi/fcoe/fcoe.c13
-rw-r--r--drivers/scsi/hpsa.c57
-rw-r--r--drivers/scsi/isci/host.c13
-rw-r--r--drivers/scsi/isci/host.h3
-rw-r--r--drivers/scsi/isci/init.c47
-rw-r--r--drivers/scsi/isci/phy.c13
-rw-r--r--drivers/scsi/isci/registers.h12
-rw-r--r--drivers/scsi/isci/request.c30
-rw-r--r--drivers/scsi/isci/unsolicited_frame_control.c2
-rw-r--r--drivers/scsi/isci/unsolicited_frame_control.h2
-rw-r--r--drivers/scsi/libfc/fc_exch.c59
-rw-r--r--drivers/scsi/libfc/fc_fcp.c11
-rw-r--r--drivers/scsi/libfc/fc_lport.c11
-rw-r--r--drivers/scsi/libsas/sas_expander.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c36
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h5
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c3
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h29
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c282
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c109
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c25
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c30
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/spi/spi-fsl-spi.c3
-rw-r--r--drivers/spi/spi-imx.c4
-rw-r--r--drivers/spi/spi-topcliff-pch.c93
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c4
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c22
-rw-r--r--drivers/staging/zcache/zcache-main.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c270
-rw-r--r--drivers/target/target_core_cdb.c35
-rw-r--r--drivers/target/target_core_transport.c9
-rw-r--r--drivers/target/tcm_fc/tcm_fc.h12
-rw-r--r--drivers/target/tcm_fc/tfc_cmd.c90
-rw-r--r--drivers/target/tcm_fc/tfc_conf.c7
-rw-r--r--drivers/target/tcm_fc/tfc_io.c62
-rw-r--r--drivers/tty/serial/crisv10.c4
-rw-r--r--drivers/usb/host/xhci-hub.c2
-rw-r--r--drivers/usb/host/xhci-ring.c19
-rw-r--r--drivers/video/68328fb.c4
-rw-r--r--drivers/video/Kconfig34
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/acornfb.c5
-rw-r--r--drivers/video/arkfb.c9
-rw-r--r--drivers/video/atmel_lcdfb.c15
-rw-r--r--drivers/video/aty/radeon_base.c10
-rw-r--r--drivers/video/au1100fb.c181
-rw-r--r--drivers/video/au1100fb.h6
-rw-r--r--drivers/video/au1200fb.c299
-rw-r--r--drivers/video/backlight/adp8860_bl.c1
-rw-r--r--drivers/video/backlight/adp8870_bl.c1
-rw-r--r--drivers/video/bf54x-lq043fb.c2
-rw-r--r--drivers/video/bfin-lq035q1-fb.c2
-rw-r--r--drivers/video/bfin-t350mcqb-fb.c2
-rw-r--r--drivers/video/bfin_adv7393fb.c2
-rw-r--r--drivers/video/carminefb.c6
-rw-r--r--drivers/video/controlfb.c2
-rw-r--r--drivers/video/da8xx-fb.c186
-rw-r--r--drivers/video/fb-puv3.c4
-rw-r--r--drivers/video/fb_defio.c3
-rw-r--r--drivers/video/fbmem.c3
-rw-r--r--drivers/video/fbmon.c21
-rw-r--r--drivers/video/fbsysfs.c3
-rw-r--r--drivers/video/fsl-diu-fb.c992
-rw-r--r--drivers/video/g364fb.c5
-rw-r--r--drivers/video/grvga.c579
-rw-r--r--drivers/video/gxt4500.c4
-rw-r--r--drivers/video/hgafb.c4
-rw-r--r--drivers/video/imsttfb.c2
-rw-r--r--drivers/video/intelfb/intelfbhw.c6
-rw-r--r--drivers/video/mb862xx/mb862xx-i2c.c2
-rw-r--r--drivers/video/mb862xx/mb862xxfbdrv.c6
-rw-r--r--drivers/video/modedb.c444
-rw-r--r--drivers/video/msm/mddi.c2
-rw-r--r--drivers/video/msm/mdp.c6
-rw-r--r--drivers/video/mx3fb.c19
-rw-r--r--drivers/video/mxsfb.c1
-rw-r--r--drivers/video/neofb.c4
-rw-r--r--drivers/video/nuc900fb.c3
-rw-r--r--drivers/video/omap2/displays/panel-taal.c2
-rw-r--r--drivers/video/platinumfb.c2
-rw-r--r--drivers/video/pm2fb.c6
-rw-r--r--drivers/video/pm3fb.c6
-rw-r--r--drivers/video/ps3fb.c2
-rw-r--r--drivers/video/pxa3xx-gcu.c4
-rw-r--r--drivers/video/pxafb.c2
-rw-r--r--drivers/video/s3c-fb.c117
-rw-r--r--drivers/video/s3c2410fb.c3
-rw-r--r--drivers/video/s3fb.c9
-rw-r--r--drivers/video/sa1100fb.c3
-rw-r--r--drivers/video/savage/savagefb_driver.c16
-rw-r--r--drivers/video/sh_mobile_hdmi.c47
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c1162
-rw-r--r--drivers/video/sh_mobile_lcdcfb.h12
-rw-r--r--drivers/video/sh_mobile_meram.c208
-rw-r--r--drivers/video/sh_mobile_meram.h41
-rw-r--r--drivers/video/sis/sis_main.c30
-rw-r--r--drivers/video/skeletonfb.c2
-rw-r--r--drivers/video/sm501fb.c6
-rw-r--r--drivers/video/smscufx.c1994
-rw-r--r--drivers/video/tmiofb.c2
-rw-r--r--drivers/video/tridentfb.c4
-rw-r--r--drivers/video/udlfb.c187
-rw-r--r--drivers/video/valkyriefb.c2
-rw-r--r--drivers/video/vfb.c4
-rw-r--r--drivers/video/vga16fb.c2
-rw-r--r--drivers/video/via/dvi.c34
-rw-r--r--drivers/video/via/dvi.h3
-rw-r--r--drivers/video/via/global.c2
-rw-r--r--drivers/video/via/global.h2
-rw-r--r--drivers/video/via/hw.c544
-rw-r--r--drivers/video/via/hw.h285
-rw-r--r--drivers/video/via/lcd.c53
-rw-r--r--drivers/video/via/lcd.h7
-rw-r--r--drivers/video/via/share.h23
-rw-r--r--drivers/video/via/via-core.c2
-rw-r--r--drivers/video/via/via_modesetting.c104
-rw-r--r--drivers/video/via/via_modesetting.h23
-rw-r--r--drivers/video/via/viafbdev.c182
-rw-r--r--drivers/video/via/viamode.c60
-rw-r--r--drivers/video/via/viamode.h4
-rw-r--r--drivers/video/vt8500lcdfb.c6
-rw-r--r--drivers/video/vt8623fb.c9
-rw-r--r--drivers/video/xilinxfb.c1
-rw-r--r--drivers/watchdog/hpwdt.c9
-rw-r--r--drivers/watchdog/lantiq_wdt.c8
-rw-r--r--drivers/watchdog/sbc_epx_c3.c2
-rw-r--r--drivers/watchdog/watchdog_dev.c14
-rw-r--r--drivers/xen/events.c40
-rw-r--r--drivers/zorro/zorro.c7
273 files changed, 7498 insertions, 4571 deletions
diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h
index bc533dd..f895a24 100644
--- a/drivers/acpi/acpica/acconfig.h
+++ b/drivers/acpi/acpica/acconfig.h
@@ -121,7 +121,7 @@
/* Maximum sleep allowed via Sleep() operator */
-#define ACPI_MAX_SLEEP 20000 /* Two seconds */
+#define ACPI_MAX_SLEEP 2000 /* Two seconds */
/******************************************************************************
*
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index c34aa51..e3f4787 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -13,6 +13,7 @@ config ACPI_APEI_GHES
bool "APEI Generic Hardware Error Source"
depends on ACPI_APEI && X86
select ACPI_HED
+ select IRQ_WORK
select LLIST
select GENERIC_ALLOCATOR
help
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index 8041248..6154036 100644
--- a/drivers/acpi/apei/apei-base.c
+++ b/drivers/acpi/apei/apei-base.c
@@ -618,7 +618,7 @@ int apei_osc_setup(void)
};
capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
- capbuf[OSC_SUPPORT_TYPE] = 0;
+ capbuf[OSC_SUPPORT_TYPE] = 1;
capbuf[OSC_CONTROL_TYPE] = 0;
if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index 2c18d58..b97294e 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -42,6 +42,22 @@ static struct pm_clk_data *__to_pcd(struct device *dev)
}
/**
+ * pm_clk_acquire - Acquire a device clock.
+ * @dev: Device whose clock is to be acquired.
+ * @ce: PM clock entry corresponding to the clock.
+ */
+static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
+{
+ ce->clk = clk_get(dev, ce->con_id);
+ if (IS_ERR(ce->clk)) {
+ ce->status = PCE_STATUS_ERROR;
+ } else {
+ ce->status = PCE_STATUS_ACQUIRED;
+ dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
+ }
+}
+
+/**
* pm_clk_add - Start using a device clock for power management.
* @dev: Device whose clock is going to be used for power management.
* @con_id: Connection ID of the clock.
@@ -73,6 +89,8 @@ int pm_clk_add(struct device *dev, const char *con_id)
}
}
+ pm_clk_acquire(dev, ce);
+
spin_lock_irq(&pcd->lock);
list_add_tail(&ce->node, &pcd->clock_list);
spin_unlock_irq(&pcd->lock);
@@ -82,17 +100,12 @@ int pm_clk_add(struct device *dev, const char *con_id)
/**
* __pm_clk_remove - Destroy PM clock entry.
* @ce: PM clock entry to destroy.
- *
- * This routine must be called under the spinlock protecting the PM list of
- * clocks corresponding the the @ce's device.
*/
static void __pm_clk_remove(struct pm_clock_entry *ce)
{
if (!ce)
return;
- list_del(&ce->node);
-
if (ce->status < PCE_STATUS_ERROR) {
if (ce->status == PCE_STATUS_ENABLED)
clk_disable(ce->clk);
@@ -126,18 +139,22 @@ void pm_clk_remove(struct device *dev, const char *con_id)
spin_lock_irq(&pcd->lock);
list_for_each_entry(ce, &pcd->clock_list, node) {
- if (!con_id && !ce->con_id) {
- __pm_clk_remove(ce);
- break;
- } else if (!con_id || !ce->con_id) {
+ if (!con_id && !ce->con_id)
+ goto remove;
+ else if (!con_id || !ce->con_id)
continue;
- } else if (!strcmp(con_id, ce->con_id)) {
- __pm_clk_remove(ce);
- break;
- }
+ else if (!strcmp(con_id, ce->con_id))
+ goto remove;
}
spin_unlock_irq(&pcd->lock);
+ return;
+
+ remove:
+ list_del(&ce->node);
+ spin_unlock_irq(&pcd->lock);
+
+ __pm_clk_remove(ce);
}
/**
@@ -175,20 +192,27 @@ void pm_clk_destroy(struct device *dev)
{
struct pm_clk_data *pcd = __to_pcd(dev);
struct pm_clock_entry *ce, *c;
+ struct list_head list;
if (!pcd)
return;
dev->power.subsys_data = NULL;
+ INIT_LIST_HEAD(&list);
spin_lock_irq(&pcd->lock);
list_for_each_entry_safe_reverse(ce, c, &pcd->clock_list, node)
- __pm_clk_remove(ce);
+ list_move(&ce->node, &list);
spin_unlock_irq(&pcd->lock);
kfree(pcd);
+
+ list_for_each_entry_safe_reverse(ce, c, &list, node) {
+ list_del(&ce->node);
+ __pm_clk_remove(ce);
+ }
}
#endif /* CONFIG_PM */
@@ -196,23 +220,6 @@ void pm_clk_destroy(struct device *dev)
#ifdef CONFIG_PM_RUNTIME
/**
- * pm_clk_acquire - Acquire a device clock.
- * @dev: Device whose clock is to be acquired.
- * @con_id: Connection ID of the clock.
- */
-static void pm_clk_acquire(struct device *dev,
- struct pm_clock_entry *ce)
-{
- ce->clk = clk_get(dev, ce->con_id);
- if (IS_ERR(ce->clk)) {
- ce->status = PCE_STATUS_ERROR;
- } else {
- ce->status = PCE_STATUS_ACQUIRED;
- dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
- }
-}
-
-/**
* pm_clk_suspend - Disable clocks in a device's PM clock list.
* @dev: Device to disable the clocks for.
*/
@@ -230,9 +237,6 @@ int pm_clk_suspend(struct device *dev)
spin_lock_irqsave(&pcd->lock, flags);
list_for_each_entry_reverse(ce, &pcd->clock_list, node) {
- if (ce->status == PCE_STATUS_NONE)
- pm_clk_acquire(dev, ce);
-
if (ce->status < PCE_STATUS_ERROR) {
clk_disable(ce->clk);
ce->status = PCE_STATUS_ACQUIRED;
@@ -262,9 +266,6 @@ int pm_clk_resume(struct device *dev)
spin_lock_irqsave(&pcd->lock, flags);
list_for_each_entry(ce, &pcd->clock_list, node) {
- if (ce->status == PCE_STATUS_NONE)
- pm_clk_acquire(dev, ce);
-
if (ce->status < PCE_STATUS_ERROR) {
clk_enable(ce->clk);
ce->status = PCE_STATUS_ENABLED;
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 98de8f4..9955a53 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4250,7 +4250,7 @@ static int __init floppy_init(void)
use_virtual_dma = can_use_virtual_dma & 1;
fdc_state[0].address = FDC1;
if (fdc_state[0].address == -1) {
- del_timer(&fd_timeout);
+ del_timer_sync(&fd_timeout);
err = -ENODEV;
goto out_unreg_region;
}
@@ -4261,7 +4261,7 @@ static int __init floppy_init(void)
fdc = 0; /* reset fdc in case of unexpected interrupt */
err = floppy_grab_irq_and_dma();
if (err) {
- del_timer(&fd_timeout);
+ del_timer_sync(&fd_timeout);
err = -EBUSY;
goto out_unreg_region;
}
@@ -4318,7 +4318,7 @@ static int __init floppy_init(void)
user_reset_fdc(-1, FD_RESET_ALWAYS, false);
}
fdc = 0;
- del_timer(&fd_timeout);
+ del_timer_sync(&fd_timeout);
current_drive = 0;
initialized = true;
if (have_no_fdc) {
@@ -4368,7 +4368,7 @@ out_unreg_blkdev:
unregister_blkdev(FLOPPY_MAJOR, "fd");
out_put_disk:
while (dr--) {
- del_timer(&motor_off_timer[dr]);
+ del_timer_sync(&motor_off_timer[dr]);
if (disks[dr]->queue)
blk_cleanup_queue(disks[dr]->queue);
put_disk(disks[dr]);
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h
index 9e40b28..00c57c9 100644
--- a/drivers/block/xen-blkback/common.h
+++ b/drivers/block/xen-blkback/common.h
@@ -46,7 +46,7 @@
#define DRV_PFX "xen-blkback:"
#define DPRINTK(fmt, args...) \
- pr_debug(DRV_PFX "(%s:%d) " fmt ".\n", \
+ pr_debug(DRV_PFX "(%s:%d) " fmt ".\n", \
__func__, __LINE__, ##args)
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
index 3f129b4..5fd2010 100644
--- a/drivers/block/xen-blkback/xenbus.c
+++ b/drivers/block/xen-blkback/xenbus.c
@@ -590,7 +590,7 @@ static void frontend_changed(struct xenbus_device *dev,
/*
* Enforce precondition before potential leak point.
- * blkif_disconnect() is idempotent.
+ * xen_blkif_disconnect() is idempotent.
*/
xen_blkif_disconnect(be->blkif);
@@ -601,17 +601,17 @@ static void frontend_changed(struct xenbus_device *dev,
break;
case XenbusStateClosing:
- xen_blkif_disconnect(be->blkif);
xenbus_switch_state(dev, XenbusStateClosing);
break;
case XenbusStateClosed:
+ xen_blkif_disconnect(be->blkif);
xenbus_switch_state(dev, XenbusStateClosed);
if (xenbus_dev_is_online(dev))
break;
/* fall through if not online */
case XenbusStateUnknown:
- /* implies blkif_disconnect() via blkback_remove() */
+ /* implies xen_blkif_disconnect() via xen_blkbk_remove() */
device_unregister(&dev->dev);
break;
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 3ef4760..9cbac6b 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -72,9 +72,15 @@ static struct usb_device_id btusb_table[] = {
/* Apple MacBookAir3,1, MacBookAir3,2 */
{ USB_DEVICE(0x05ac, 0x821b) },
+ /* Apple MacBookAir4,1 */
+ { USB_DEVICE(0x05ac, 0x821f) },
+
/* Apple MacBookPro8,2 */
{ USB_DEVICE(0x05ac, 0x821a) },
+ /* Apple MacMini5,1 */
+ { USB_DEVICE(0x05ac, 0x8281) },
+
/* AVM BlueFRITZ! USB v2.0 */
{ USB_DEVICE(0x057c, 0x3800) },
diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c
index 65d27af..04d353f 100644
--- a/drivers/bluetooth/btwilink.c
+++ b/drivers/bluetooth/btwilink.c
@@ -125,6 +125,13 @@ static long st_receive(void *priv_data, struct sk_buff *skb)
/* protocol structure registered with shared transport */
static struct st_proto_s ti_st_proto[MAX_BT_CHNL_IDS] = {
{
+ .chnl_id = HCI_EVENT_PKT, /* HCI Events */
+ .hdr_len = sizeof(struct hci_event_hdr),
+ .offset_len_in_hdr = offsetof(struct hci_event_hdr, plen),
+ .len_size = 1, /* sizeof(plen) in struct hci_event_hdr */
+ .reserve = 8,
+ },
+ {
.chnl_id = HCI_ACLDATA_PKT, /* ACL */
.hdr_len = sizeof(struct hci_acl_hdr),
.offset_len_in_hdr = offsetof(struct hci_acl_hdr, dlen),
@@ -138,13 +145,6 @@ static struct st_proto_s ti_st_proto[MAX_BT_CHNL_IDS] = {
.len_size = 1, /* sizeof(dlen) in struct hci_sco_hdr */
.reserve = 8,
},
- {
- .chnl_id = HCI_EVENT_PKT, /* HCI Events */
- .hdr_len = sizeof(struct hci_event_hdr),
- .offset_len_in_hdr = offsetof(struct hci_event_hdr, plen),
- .len_size = 1, /* sizeof(plen) in struct hci_event_hdr */
- .reserve = 8,
- },
};
/* Called from HCI core to initialize the device */
@@ -240,7 +240,7 @@ static int ti_st_close(struct hci_dev *hdev)
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
- for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
+ for (i = MAX_BT_CHNL_IDS-1; i >= 0; i--) {
err = st_unregister(&ti_st_proto[i]);
if (err)
BT_ERR("st_unregister(%d) failed with error %d",
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index f6595ab..fa567f1 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -43,6 +43,7 @@ config TCG_NSC
config TCG_ATMEL
tristate "Atmel TPM Interface"
+ depends on PPC64 || HAS_IOPORT
---help---
If you have a TPM security chip from Atmel say Yes and it
will be accessible from within Linux. To compile this driver
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index caf8012..9ca5c02 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -383,6 +383,9 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
u32 count, ordinal;
unsigned long stop;
+ if (bufsiz > TPM_BUFSIZE)
+ bufsiz = TPM_BUFSIZE;
+
count = be32_to_cpu(*((__be32 *) (buf + 2)));
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
if (count == 0)
@@ -1102,6 +1105,7 @@ ssize_t tpm_read(struct file *file, char __user *buf,
{
struct tpm_chip *chip = file->private_data;
ssize_t ret_size;
+ int rc;
del_singleshot_timer_sync(&chip->user_read_timer);
flush_work_sync(&chip->work);
@@ -1112,8 +1116,11 @@ ssize_t tpm_read(struct file *file, char __user *buf,
ret_size = size;
mutex_lock(&chip->buffer_mutex);
- if (copy_to_user(buf, chip->data_buffer, ret_size))
+ rc = copy_to_user(buf, chip->data_buffer, ret_size);
+ memset(chip->data_buffer, 0, ret_size);
+ if (rc)
ret_size = -EFAULT;
+
mutex_unlock(&chip->buffer_mutex);
}
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 82facc9..4d24648 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -396,8 +396,6 @@ static void __exit cleanup_nsc(void)
if (pdev) {
tpm_nsc_remove(&pdev->dev);
platform_device_unregister(pdev);
- kfree(pdev);
- pdev = NULL;
}
platform_driver_unregister(&nsc_drv);
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index 7b0603e..cdc02ac 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -261,6 +261,9 @@ static int pcc_get_offset(int cpu)
pr = per_cpu(processors, cpu);
pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
+ if (!pr)
+ return -ENODEV;
+
status = acpi_evaluate_object(pr->handle, "PCCP", NULL, &buffer);
if (ACPI_FAILURE(status))
return -ENODEV;
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 57cd3a4..fd7170a 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -290,6 +290,9 @@ static const struct {
{PCI_VENDOR_ID_NEC, PCI_ANY_ID, PCI_ANY_ID,
QUIRK_CYCLE_TIMER},
+ {PCI_VENDOR_ID_O2, PCI_ANY_ID, PCI_ANY_ID,
+ QUIRK_NO_MSI},
+
{PCI_VENDOR_ID_RICOH, PCI_ANY_ID, PCI_ANY_ID,
QUIRK_CYCLE_TIMER},
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index 231714d..4e24436 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -351,7 +351,7 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc,
return 0;
}
-int __devexit bgpio_remove(struct bgpio_chip *bgc)
+int bgpio_remove(struct bgpio_chip *bgc)
{
int err = gpiochip_remove(&bgc->gc);
@@ -361,15 +361,10 @@ int __devexit bgpio_remove(struct bgpio_chip *bgc)
}
EXPORT_SYMBOL_GPL(bgpio_remove);
-int __devinit bgpio_init(struct bgpio_chip *bgc,
- struct device *dev,
- unsigned long sz,
- void __iomem *dat,
- void __iomem *set,
- void __iomem *clr,
- void __iomem *dirout,
- void __iomem *dirin,
- bool big_endian)
+int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
+ unsigned long sz, void __iomem *dat, void __iomem *set,
+ void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
+ bool big_endian)
{
int ret;
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index ce045a8..f07e425 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -67,11 +67,11 @@ module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600);
MODULE_PARM_DESC(i915_enable_rc6,
"Enable power-saving render C-state 6 (default: true)");
-unsigned int i915_enable_fbc __read_mostly = 1;
+unsigned int i915_enable_fbc __read_mostly = -1;
module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600);
MODULE_PARM_DESC(i915_enable_fbc,
"Enable frame buffer compression for power savings "
- "(default: false)");
+ "(default: -1 (use per-chip default))");
unsigned int i915_lvds_downclock __read_mostly = 0;
module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 56a8554..04411ad 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1799,6 +1799,7 @@ static void intel_update_fbc(struct drm_device *dev)
struct drm_framebuffer *fb;
struct intel_framebuffer *intel_fb;
struct drm_i915_gem_object *obj;
+ int enable_fbc;
DRM_DEBUG_KMS("\n");
@@ -1839,8 +1840,15 @@ static void intel_update_fbc(struct drm_device *dev)
intel_fb = to_intel_framebuffer(fb);
obj = intel_fb->obj;
- if (!i915_enable_fbc) {
- DRM_DEBUG_KMS("fbc disabled per module param (default off)\n");
+ enable_fbc = i915_enable_fbc;
+ if (enable_fbc < 0) {
+ DRM_DEBUG_KMS("fbc set to per-chip default\n");
+ enable_fbc = 1;
+ if (INTEL_INFO(dev)->gen <= 5)
+ enable_fbc = 0;
+ }
+ if (!enable_fbc) {
+ DRM_DEBUG_KMS("fbc disabled per module param\n");
dev_priv->no_fbc_reason = FBC_MODULE_PARAM;
goto out_disable;
}
@@ -4687,13 +4695,13 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
bpc = 6; /* min is 18bpp */
break;
case 24:
- bpc = min((unsigned int)8, display_bpc);
+ bpc = 8;
break;
case 30:
- bpc = min((unsigned int)10, display_bpc);
+ bpc = 10;
break;
case 48:
- bpc = min((unsigned int)12, display_bpc);
+ bpc = 12;
break;
default:
DRM_DEBUG("unsupported depth, assuming 24 bits\n");
@@ -4701,10 +4709,12 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
break;
}
+ display_bpc = min(display_bpc, bpc);
+
DRM_DEBUG_DRIVER("setting pipe bpc to %d (max display bpc %d)\n",
bpc, display_bpc);
- *pipe_bpp = bpc * 3;
+ *pipe_bpp = display_bpc * 3;
return display_bpc != bpc;
}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 0b2ee9d..fe1099d 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -337,9 +337,6 @@ extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
struct drm_connector *connector,
struct intel_load_detect_pipe *old);
-extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB);
-extern int intel_sdvo_supports_hotplug(struct drm_connector *connector);
-extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable);
extern void intelfb_restore(void);
extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno);
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 30fe554..6348c49 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -92,6 +92,11 @@ struct intel_sdvo {
*/
uint16_t attached_output;
+ /*
+ * Hotplug activation bits for this device
+ */
+ uint8_t hotplug_active[2];
+
/**
* This is used to select the color range of RBG outputs in HDMI mode.
* It is only valid when using TMDS encoding and 8 bit per color mode.
@@ -1208,74 +1213,20 @@ static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct in
return true;
}
-/* No use! */
-#if 0
-struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB)
-{
- struct drm_connector *connector = NULL;
- struct intel_sdvo *iout = NULL;
- struct intel_sdvo *sdvo;
-
- /* find the sdvo connector */
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- iout = to_intel_sdvo(connector);
-
- if (iout->type != INTEL_OUTPUT_SDVO)
- continue;
-
- sdvo = iout->dev_priv;
-
- if (sdvo->sdvo_reg == SDVOB && sdvoB)
- return connector;
-
- if (sdvo->sdvo_reg == SDVOC && !sdvoB)
- return connector;
-
- }
-
- return NULL;
-}
-
-int intel_sdvo_supports_hotplug(struct drm_connector *connector)
+static int intel_sdvo_supports_hotplug(struct intel_sdvo *intel_sdvo)
{
u8 response[2];
- u8 status;
- struct intel_sdvo *intel_sdvo;
- DRM_DEBUG_KMS("\n");
-
- if (!connector)
- return 0;
-
- intel_sdvo = to_intel_sdvo(connector);
return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT,
&response, 2) && response[0];
}
-void intel_sdvo_set_hotplug(struct drm_connector *connector, int on)
+static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder)
{
- u8 response[2];
- u8 status;
- struct intel_sdvo *intel_sdvo = to_intel_sdvo(connector);
-
- intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
- intel_sdvo_read_response(intel_sdvo, &response, 2);
-
- if (on) {
- intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0);
- status = intel_sdvo_read_response(intel_sdvo, &response, 2);
-
- intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
- } else {
- response[0] = 0;
- response[1] = 0;
- intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
- }
+ struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
- intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
- intel_sdvo_read_response(intel_sdvo, &response, 2);
+ intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &intel_sdvo->hotplug_active, 2);
}
-#endif
static bool
intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo)
@@ -2045,6 +1996,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
{
struct drm_encoder *encoder = &intel_sdvo->base.base;
struct drm_connector *connector;
+ struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
struct intel_connector *intel_connector;
struct intel_sdvo_connector *intel_sdvo_connector;
@@ -2062,7 +2014,17 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
intel_connector = &intel_sdvo_connector->base;
connector = &intel_connector->base;
- connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
+ if (intel_sdvo_supports_hotplug(intel_sdvo) & (1 << device)) {
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+ intel_sdvo->hotplug_active[0] |= 1 << device;
+ /* Some SDVO devices have one-shot hotplug interrupts.
+ * Ensure that they get re-enabled when an interrupt happens.
+ */
+ intel_encoder->hot_plug = intel_sdvo_enable_hotplug;
+ intel_sdvo_enable_hotplug(intel_encoder);
+ }
+ else
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
connector->connector_type = DRM_MODE_CONNECTOR_DVID;
@@ -2569,6 +2531,14 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
goto err;
+ /* Set up hotplug command - note paranoia about contents of reply.
+ * We assume that the hardware is in a sane state, and only touch
+ * the bits we think we understand.
+ */
+ intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG,
+ &intel_sdvo->hotplug_active, 2);
+ intel_sdvo->hotplug_active[0] &= ~0x3;
+
if (intel_sdvo_output_setup(intel_sdvo,
intel_sdvo->caps.output_flags) != true) {
DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n",
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index 7ad43c6..4da2388 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -115,6 +115,7 @@ static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector,
u8 msg[20];
int msg_bytes = send_bytes + 4;
u8 ack;
+ unsigned retry;
if (send_bytes > 16)
return -1;
@@ -125,20 +126,20 @@ static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector,
msg[3] = (msg_bytes << 4) | (send_bytes - 1);
memcpy(&msg[4], send, send_bytes);
- while (1) {
+ for (retry = 0; retry < 4; retry++) {
ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
msg, msg_bytes, NULL, 0, delay, &ack);
if (ret < 0)
return ret;
if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
- break;
+ return send_bytes;
else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
udelay(400);
else
return -EIO;
}
- return send_bytes;
+ return -EIO;
}
static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector,
@@ -149,26 +150,29 @@ static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector,
int msg_bytes = 4;
u8 ack;
int ret;
+ unsigned retry;
msg[0] = address;
msg[1] = address >> 8;
msg[2] = AUX_NATIVE_READ << 4;
msg[3] = (msg_bytes << 4) | (recv_bytes - 1);
- while (1) {
+ for (retry = 0; retry < 4; retry++) {
ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
msg, msg_bytes, recv, recv_bytes, delay, &ack);
- if (ret == 0)
- return -EPROTO;
if (ret < 0)
return ret;
if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
return ret;
else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
udelay(400);
+ else if (ret == 0)
+ return -EPROTO;
else
return -EIO;
}
+
+ return -EIO;
}
static void radeon_write_dpcd_reg(struct radeon_connector *radeon_connector,
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index dc0a5b5..c4ffa14f 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -1404,7 +1404,8 @@ int evergreen_cp_resume(struct radeon_device *rdev)
/* Initialize the ring buffer's read and write pointers */
WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA);
WREG32(CP_RB_RPTR_WR, 0);
- WREG32(CP_RB_WPTR, 0);
+ rdev->cp.wptr = 0;
+ WREG32(CP_RB_WPTR, rdev->cp.wptr);
/* set the wb address wether it's enabled or not */
WREG32(CP_RB_RPTR_ADDR,
@@ -1426,7 +1427,6 @@ int evergreen_cp_resume(struct radeon_device *rdev)
WREG32(CP_DEBUG, (1 << 27) | (1 << 28));
rdev->cp.rptr = RREG32(CP_RB_RPTR);
- rdev->cp.wptr = RREG32(CP_RB_WPTR);
evergreen_cp_start(rdev);
rdev->cp.ready = true;
@@ -1590,48 +1590,6 @@ static u32 evergreen_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
return backend_map;
}
-static void evergreen_program_channel_remap(struct radeon_device *rdev)
-{
- u32 tcp_chan_steer_lo, tcp_chan_steer_hi, mc_shared_chremap, tmp;
-
- tmp = RREG32(MC_SHARED_CHMAP);
- switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
- case 0:
- case 1:
- case 2:
- case 3:
- default:
- /* default mapping */
- mc_shared_chremap = 0x00fac688;
- break;
- }
-
- switch (rdev->family) {
- case CHIP_HEMLOCK:
- case CHIP_CYPRESS:
- case CHIP_BARTS:
- tcp_chan_steer_lo = 0x54763210;
- tcp_chan_steer_hi = 0x0000ba98;
- break;
- case CHIP_JUNIPER:
- case CHIP_REDWOOD:
- case CHIP_CEDAR:
- case CHIP_PALM:
- case CHIP_SUMO:
- case CHIP_SUMO2:
- case CHIP_TURKS:
- case CHIP_CAICOS:
- default:
- tcp_chan_steer_lo = 0x76543210;
- tcp_chan_steer_hi = 0x0000ba98;
- break;
- }
-
- WREG32(TCP_CHAN_STEER_LO, tcp_chan_steer_lo);
- WREG32(TCP_CHAN_STEER_HI, tcp_chan_steer_hi);
- WREG32(MC_SHARED_CHREMAP, mc_shared_chremap);
-}
-
static void evergreen_gpu_init(struct radeon_device *rdev)
{
u32 cc_rb_backend_disable = 0;
@@ -2078,8 +2036,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
WREG32(HDP_ADDR_CONFIG, gb_addr_config);
- evergreen_program_channel_remap(rdev);
-
num_shader_engines = ((RREG32(GB_ADDR_CONFIG) & NUM_SHADER_ENGINES(3)) >> 12) + 1;
grbm_gfx_index = INSTANCE_BROADCAST_WRITES;
@@ -3171,21 +3127,23 @@ int evergreen_suspend(struct radeon_device *rdev)
}
int evergreen_copy_blit(struct radeon_device *rdev,
- uint64_t src_offset, uint64_t dst_offset,
- unsigned num_pages, struct radeon_fence *fence)
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ unsigned num_gpu_pages,
+ struct radeon_fence *fence)
{
int r;
mutex_lock(&rdev->r600_blit.mutex);
rdev->r600_blit.vb_ib = NULL;
- r = evergreen_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE);
+ r = evergreen_blit_prepare_copy(rdev, num_gpu_pages * RADEON_GPU_PAGE_SIZE);
if (r) {
if (rdev->r600_blit.vb_ib)
radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
mutex_unlock(&rdev->r600_blit.mutex);
return r;
}
- evergreen_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE);
+ evergreen_kms_blit_copy(rdev, src_offset, dst_offset, num_gpu_pages * RADEON_GPU_PAGE_SIZE);
evergreen_blit_done_copy(rdev, fence);
mutex_unlock(&rdev->r600_blit.mutex);
return 0;
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index cbf57d7..8c79ca9 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -569,36 +569,6 @@ static u32 cayman_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
return backend_map;
}
-static void cayman_program_channel_remap(struct radeon_device *rdev)
-{
- u32 tcp_chan_steer_lo, tcp_chan_steer_hi, mc_shared_chremap, tmp;
-
- tmp = RREG32(MC_SHARED_CHMAP);
- switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
- case 0:
- case 1:
- case 2:
- case 3:
- default:
- /* default mapping */
- mc_shared_chremap = 0x00fac688;
- break;
- }
-
- switch (rdev->family) {
- case CHIP_CAYMAN:
- default:
- //tcp_chan_steer_lo = 0x54763210
- tcp_chan_steer_lo = 0x76543210;
- tcp_chan_steer_hi = 0x0000ba98;
- break;
- }
-
- WREG32(TCP_CHAN_STEER_LO, tcp_chan_steer_lo);
- WREG32(TCP_CHAN_STEER_HI, tcp_chan_steer_hi);
- WREG32(MC_SHARED_CHREMAP, mc_shared_chremap);
-}
-
static u32 cayman_get_disable_mask_per_asic(struct radeon_device *rdev,
u32 disable_mask_per_se,
u32 max_disable_mask_per_se,
@@ -842,8 +812,6 @@ static void cayman_gpu_init(struct radeon_device *rdev)
WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
WREG32(HDP_ADDR_CONFIG, gb_addr_config);
- cayman_program_channel_remap(rdev);
-
/* primary versions */
WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
WREG32(CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable);
@@ -1187,7 +1155,8 @@ int cayman_cp_resume(struct radeon_device *rdev)
/* Initialize the ring buffer's read and write pointers */
WREG32(CP_RB0_CNTL, tmp | RB_RPTR_WR_ENA);
- WREG32(CP_RB0_WPTR, 0);
+ rdev->cp.wptr = 0;
+ WREG32(CP_RB0_WPTR, rdev->cp.wptr);
/* set the wb address wether it's enabled or not */
WREG32(CP_RB0_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
@@ -1207,7 +1176,6 @@ int cayman_cp_resume(struct radeon_device *rdev)
WREG32(CP_RB0_BASE, rdev->cp.gpu_addr >> 8);
rdev->cp.rptr = RREG32(CP_RB0_RPTR);
- rdev->cp.wptr = RREG32(CP_RB0_WPTR);
/* ring1 - compute only */
/* Set ring buffer size */
@@ -1220,7 +1188,8 @@ int cayman_cp_resume(struct radeon_device *rdev)
/* Initialize the ring buffer's read and write pointers */
WREG32(CP_RB1_CNTL, tmp | RB_RPTR_WR_ENA);
- WREG32(CP_RB1_WPTR, 0);
+ rdev->cp1.wptr = 0;
+ WREG32(CP_RB1_WPTR, rdev->cp1.wptr);
/* set the wb address wether it's enabled or not */
WREG32(CP_RB1_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP1_RPTR_OFFSET) & 0xFFFFFFFC);
@@ -1232,7 +1201,6 @@ int cayman_cp_resume(struct radeon_device *rdev)
WREG32(CP_RB1_BASE, rdev->cp1.gpu_addr >> 8);
rdev->cp1.rptr = RREG32(CP_RB1_RPTR);
- rdev->cp1.wptr = RREG32(CP_RB1_WPTR);
/* ring2 - compute only */
/* Set ring buffer size */
@@ -1245,7 +1213,8 @@ int cayman_cp_resume(struct radeon_device *rdev)
/* Initialize the ring buffer's read and write pointers */
WREG32(CP_RB2_CNTL, tmp | RB_RPTR_WR_ENA);
- WREG32(CP_RB2_WPTR, 0);
+ rdev->cp2.wptr = 0;
+ WREG32(CP_RB2_WPTR, rdev->cp2.wptr);
/* set the wb address wether it's enabled or not */
WREG32(CP_RB2_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP2_RPTR_OFFSET) & 0xFFFFFFFC);
@@ -1257,7 +1226,6 @@ int cayman_cp_resume(struct radeon_device *rdev)
WREG32(CP_RB2_BASE, rdev->cp2.gpu_addr >> 8);
rdev->cp2.rptr = RREG32(CP_RB2_RPTR);
- rdev->cp2.wptr = RREG32(CP_RB2_WPTR);
/* start the rings */
cayman_cp_start(rdev);
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index f2204cb..7fcdbbb 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -721,11 +721,11 @@ void r100_fence_ring_emit(struct radeon_device *rdev,
int r100_copy_blit(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence)
{
uint32_t cur_pages;
- uint32_t stride_bytes = PAGE_SIZE;
+ uint32_t stride_bytes = RADEON_GPU_PAGE_SIZE;
uint32_t pitch;
uint32_t stride_pixels;
unsigned ndw;
@@ -737,7 +737,7 @@ int r100_copy_blit(struct radeon_device *rdev,
/* radeon pitch is /64 */
pitch = stride_bytes / 64;
stride_pixels = stride_bytes / 4;
- num_loops = DIV_ROUND_UP(num_pages, 8191);
+ num_loops = DIV_ROUND_UP(num_gpu_pages, 8191);
/* Ask for enough room for blit + flush + fence */
ndw = 64 + (10 * num_loops);
@@ -746,12 +746,12 @@ int r100_copy_blit(struct radeon_device *rdev,
DRM_ERROR("radeon: moving bo (%d) asking for %u dw.\n", r, ndw);
return -EINVAL;
}
- while (num_pages > 0) {
- cur_pages = num_pages;
+ while (num_gpu_pages > 0) {
+ cur_pages = num_gpu_pages;
if (cur_pages > 8191) {
cur_pages = 8191;
}
- num_pages -= cur_pages;
+ num_gpu_pages -= cur_pages;
/* pages are in Y direction - height
page width in X direction - width */
@@ -773,8 +773,8 @@ int r100_copy_blit(struct radeon_device *rdev,
radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16));
radeon_ring_write(rdev, 0);
radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16));
- radeon_ring_write(rdev, num_pages);
- radeon_ring_write(rdev, num_pages);
+ radeon_ring_write(rdev, num_gpu_pages);
+ radeon_ring_write(rdev, num_gpu_pages);
radeon_ring_write(rdev, cur_pages | (stride_pixels << 16));
}
radeon_ring_write(rdev, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0));
@@ -990,7 +990,8 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
/* Force read & write ptr to 0 */
WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA | RADEON_RB_NO_UPDATE);
WREG32(RADEON_CP_RB_RPTR_WR, 0);
- WREG32(RADEON_CP_RB_WPTR, 0);
+ rdev->cp.wptr = 0;
+ WREG32(RADEON_CP_RB_WPTR, rdev->cp.wptr);
/* set the wb address whether it's enabled or not */
WREG32(R_00070C_CP_RB_RPTR_ADDR,
@@ -1007,9 +1008,6 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
WREG32(RADEON_CP_RB_CNTL, tmp);
udelay(10);
rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
- rdev->cp.wptr = RREG32(RADEON_CP_RB_WPTR);
- /* protect against crazy HW on resume */
- rdev->cp.wptr &= rdev->cp.ptr_mask;
/* Set cp mode to bus mastering & enable cp*/
WREG32(RADEON_CP_CSQ_MODE,
REG_SET(RADEON_INDIRECT2_START, indirect2_start) |
diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c
index f240583..a1f3ba0 100644
--- a/drivers/gpu/drm/radeon/r200.c
+++ b/drivers/gpu/drm/radeon/r200.c
@@ -84,7 +84,7 @@ static int r200_get_vtx_size_0(uint32_t vtx_fmt_0)
int r200_copy_dma(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence)
{
uint32_t size;
@@ -93,7 +93,7 @@ int r200_copy_dma(struct radeon_device *rdev,
int r = 0;
/* radeon pitch is /64 */
- size = num_pages << PAGE_SHIFT;
+ size = num_gpu_pages << RADEON_GPU_PAGE_SHIFT;
num_loops = DIV_ROUND_UP(size, 0x1FFFFF);
r = radeon_ring_lock(rdev, num_loops * 4 + 64);
if (r) {
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index aa5571b..720dd99 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -2209,7 +2209,8 @@ int r600_cp_resume(struct radeon_device *rdev)
/* Initialize the ring buffer's read and write pointers */
WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA);
WREG32(CP_RB_RPTR_WR, 0);
- WREG32(CP_RB_WPTR, 0);
+ rdev->cp.wptr = 0;
+ WREG32(CP_RB_WPTR, rdev->cp.wptr);
/* set the wb address whether it's enabled or not */
WREG32(CP_RB_RPTR_ADDR,
@@ -2231,7 +2232,6 @@ int r600_cp_resume(struct radeon_device *rdev)
WREG32(CP_DEBUG, (1 << 27) | (1 << 28));
rdev->cp.rptr = RREG32(CP_RB_RPTR);
- rdev->cp.wptr = RREG32(CP_RB_WPTR);
r600_cp_start(rdev);
rdev->cp.ready = true;
@@ -2353,21 +2353,23 @@ void r600_fence_ring_emit(struct radeon_device *rdev,
}
int r600_copy_blit(struct radeon_device *rdev,
- uint64_t src_offset, uint64_t dst_offset,
- unsigned num_pages, struct radeon_fence *fence)
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ unsigned num_gpu_pages,
+ struct radeon_fence *fence)
{
int r;
mutex_lock(&rdev->r600_blit.mutex);
rdev->r600_blit.vb_ib = NULL;
- r = r600_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE);
+ r = r600_blit_prepare_copy(rdev, num_gpu_pages * RADEON_GPU_PAGE_SIZE);
if (r) {
if (rdev->r600_blit.vb_ib)
radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
mutex_unlock(&rdev->r600_blit.mutex);
return r;
}
- r600_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE);
+ r600_kms_blit_copy(rdev, src_offset, dst_offset, num_gpu_pages * RADEON_GPU_PAGE_SIZE);
r600_blit_done_copy(rdev, fence);
mutex_unlock(&rdev->r600_blit.mutex);
return 0;
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 32807ba..c1e056b 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -322,6 +322,7 @@ union radeon_gart_table {
#define RADEON_GPU_PAGE_SIZE 4096
#define RADEON_GPU_PAGE_MASK (RADEON_GPU_PAGE_SIZE - 1)
+#define RADEON_GPU_PAGE_SHIFT 12
struct radeon_gart {
dma_addr_t table_addr;
@@ -914,17 +915,17 @@ struct radeon_asic {
int (*copy_blit)(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence);
int (*copy_dma)(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence);
int (*copy)(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence);
uint32_t (*get_engine_clock)(struct radeon_device *rdev);
void (*set_engine_clock)(struct radeon_device *rdev, uint32_t eng_clock);
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 3d7a0d7..3dedaa0 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -75,7 +75,7 @@ uint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg);
int r100_copy_blit(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence);
int r100_set_surface_reg(struct radeon_device *rdev, int reg,
uint32_t tiling_flags, uint32_t pitch,
@@ -143,7 +143,7 @@ extern void r100_post_page_flip(struct radeon_device *rdev, int crtc);
extern int r200_copy_dma(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence);
void r200_set_safe_registers(struct radeon_device *rdev);
@@ -311,7 +311,7 @@ void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
int r600_ring_test(struct radeon_device *rdev);
int r600_copy_blit(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
- unsigned num_pages, struct radeon_fence *fence);
+ unsigned num_gpu_pages, struct radeon_fence *fence);
void r600_hpd_init(struct radeon_device *rdev);
void r600_hpd_fini(struct radeon_device *rdev);
bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
@@ -403,7 +403,7 @@ void evergreen_bandwidth_update(struct radeon_device *rdev);
void evergreen_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
int evergreen_copy_blit(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
- unsigned num_pages, struct radeon_fence *fence);
+ unsigned num_gpu_pages, struct radeon_fence *fence);
void evergreen_hpd_init(struct radeon_device *rdev);
void evergreen_hpd_fini(struct radeon_device *rdev);
bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index c4b8741..bce63fd 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -68,11 +68,11 @@ void radeon_connector_hotplug(struct drm_connector *connector)
if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
int saved_dpms = connector->dpms;
- if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd) &&
- radeon_dp_needs_link_train(radeon_connector))
- drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
- else
+ /* Only turn off the display it it's physically disconnected */
+ if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+ else if (radeon_dp_needs_link_train(radeon_connector))
+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
connector->dpms = saved_dpms;
}
}
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index 3189a7e..fde25c0 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -208,23 +208,25 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
int xorigin = 0, yorigin = 0;
int w = radeon_crtc->cursor_width;
- if (x < 0)
- xorigin = -x + 1;
- if (y < 0)
- yorigin = -y + 1;
- if (xorigin >= CURSOR_WIDTH)
- xorigin = CURSOR_WIDTH - 1;
- if (yorigin >= CURSOR_HEIGHT)
- yorigin = CURSOR_HEIGHT - 1;
-
if (ASIC_IS_AVIVO(rdev)) {
- int i = 0;
- struct drm_crtc *crtc_p;
-
/* avivo cursor are offset into the total surface */
x += crtc->x;
y += crtc->y;
- DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
+ }
+ DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
+
+ if (x < 0) {
+ xorigin = min(-x, CURSOR_WIDTH - 1);
+ x = 0;
+ }
+ if (y < 0) {
+ yorigin = min(-y, CURSOR_HEIGHT - 1);
+ y = 0;
+ }
+
+ if (ASIC_IS_AVIVO(rdev)) {
+ int i = 0;
+ struct drm_crtc *crtc_p;
/* avivo cursor image can't end on 128 pixel boundary or
* go past the end of the frame if both crtcs are enabled
@@ -253,16 +255,12 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
radeon_lock_cursor(crtc, true);
if (ASIC_IS_DCE4(rdev)) {
- WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset,
- ((xorigin ? 0 : x) << 16) |
- (yorigin ? 0 : y));
+ WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
} else if (ASIC_IS_AVIVO(rdev)) {
- WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset,
- ((xorigin ? 0 : x) << 16) |
- (yorigin ? 0 : y));
+ WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
@@ -276,8 +274,8 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
| yorigin));
WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
(RADEON_CUR_LOCK
- | ((xorigin ? 0 : x) << 16)
- | (yorigin ? 0 : y)));
+ | (x << 16)
+ | y));
/* offset is from DISP(2)_BASE_ADDRESS */
WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset +
(yorigin * 256)));
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 6cc17fb..6adb3e5 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -473,8 +473,8 @@ pflip_cleanup:
spin_lock_irqsave(&dev->event_lock, flags);
radeon_crtc->unpin_work = NULL;
unlock_free:
- drm_gem_object_unreference_unlocked(old_radeon_fb->obj);
spin_unlock_irqrestore(&dev->event_lock, flags);
+ drm_gem_object_unreference_unlocked(old_radeon_fb->obj);
radeon_fence_unref(&work->fence);
kfree(work);
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index 319d85d..13690f3 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -1507,7 +1507,14 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
switch (mode) {
case DRM_MODE_DPMS_ON:
args.ucAction = ATOM_ENABLE;
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ /* workaround for DVOOutputControl on some RS690 systems */
+ if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI) {
+ u32 reg = RREG32(RADEON_BIOS_3_SCRATCH);
+ WREG32(RADEON_BIOS_3_SCRATCH, reg & ~ATOM_S3_DFP2I_ACTIVE);
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ WREG32(RADEON_BIOS_3_SCRATCH, reg);
+ } else
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
args.ucAction = ATOM_LCD_BLON;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 9b86fb0..0b5468b 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -277,7 +277,12 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
DRM_ERROR("Trying to move memory with CP turned off.\n");
return -EINVAL;
}
- r = radeon_copy(rdev, old_start, new_start, new_mem->num_pages, fence);
+
+ BUILD_BUG_ON((PAGE_SIZE % RADEON_GPU_PAGE_SIZE) != 0);
+
+ r = radeon_copy(rdev, old_start, new_start,
+ new_mem->num_pages * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE), /* GPU pages */
+ fence);
/* FIXME: handle copy error */
r = ttm_bo_move_accel_cleanup(bo, (void *)fence, NULL,
evict, no_wait_reserve, no_wait_gpu, new_mem);
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 4720d00..b13c2ee 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -536,55 +536,6 @@ static u32 r700_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
return backend_map;
}
-static void rv770_program_channel_remap(struct radeon_device *rdev)
-{
- u32 tcp_chan_steer, mc_shared_chremap, tmp;
- bool force_no_swizzle;
-
- switch (rdev->family) {
- case CHIP_RV770:
- case CHIP_RV730:
- force_no_swizzle = false;
- break;
- case CHIP_RV710:
- case CHIP_RV740:
- default:
- force_no_swizzle = true;
- break;
- }
-
- tmp = RREG32(MC_SHARED_CHMAP);
- switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
- case 0:
- case 1:
- default:
- /* default mapping */
- mc_shared_chremap = 0x00fac688;
- break;
- case 2:
- case 3:
- if (force_no_swizzle)
- mc_shared_chremap = 0x00fac688;
- else
- mc_shared_chremap = 0x00bbc298;
- break;
- }
-
- if (rdev->family == CHIP_RV740)
- tcp_chan_steer = 0x00ef2a60;
- else
- tcp_chan_steer = 0x00fac688;
-
- /* RV770 CE has special chremap setup */
- if (rdev->pdev->device == 0x944e) {
- tcp_chan_steer = 0x00b08b08;
- mc_shared_chremap = 0x00b08b08;
- }
-
- WREG32(TCP_CHAN_STEER, tcp_chan_steer);
- WREG32(MC_SHARED_CHREMAP, mc_shared_chremap);
-}
-
static void rv770_gpu_init(struct radeon_device *rdev)
{
int i, j, num_qd_pipes;
@@ -785,8 +736,6 @@ static void rv770_gpu_init(struct radeon_device *rdev)
WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff));
WREG32(HDP_TILING_CONFIG, (gb_tiling_config & 0xffff));
- rv770_program_channel_remap(rdev);
-
WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index a4d38d8..ef06194 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -394,7 +394,8 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) {
if (bo->ttm == NULL) {
- ret = ttm_bo_add_ttm(bo, false);
+ bool zero = !(old_man->flags & TTM_MEMTYPE_FLAG_FIXED);
+ ret = ttm_bo_add_ttm(bo, zero);
if (ret)
goto out_err;
}
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index a597039..72ca689 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -373,6 +373,8 @@ static int wacom_probe(struct hid_device *hdev,
hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
input = hidinput->input;
+ __set_bit(INPUT_PROP_POINTER, input->propbit);
+
/* Basics */
input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 59d83e8..9323837 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -36,17 +36,25 @@
#include <linux/cpu.h>
#include <linux/pci.h>
#include <linux/smp.h>
+#include <linux/moduleparam.h>
#include <asm/msr.h>
#include <asm/processor.h>
#define DRVNAME "coretemp"
+/*
+ * force_tjmax only matters when TjMax can't be read from the CPU itself.
+ * When set, it replaces the driver's suboptimal heuristic.
+ */
+static int force_tjmax;
+module_param_named(tjmax, force_tjmax, int, 0444);
+MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
+
#define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */
#define NUM_REAL_CORES 16 /* Number of Real cores per cpu */
#define CORETEMP_NAME_LENGTH 17 /* String Length of attrs */
#define MAX_CORE_ATTRS 4 /* Maximum no of basic attrs */
-#define MAX_THRESH_ATTRS 3 /* Maximum no of Threshold attrs */
-#define TOTAL_ATTRS (MAX_CORE_ATTRS + MAX_THRESH_ATTRS)
+#define TOTAL_ATTRS (MAX_CORE_ATTRS + 1)
#define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)
#ifdef CONFIG_SMP
@@ -69,8 +77,6 @@
* This value is passed as "id" field to rdmsr/wrmsr functions.
* @status_reg: One of IA32_THERM_STATUS or IA32_PACKAGE_THERM_STATUS,
* from where the temperature values should be read.
- * @intrpt_reg: One of IA32_THERM_INTERRUPT or IA32_PACKAGE_THERM_INTERRUPT,
- * from where the thresholds are read.
* @attr_size: Total number of pre-core attrs displayed in the sysfs.
* @is_pkg_data: If this is 1, the temp_data holds pkgtemp data.
* Otherwise, temp_data holds coretemp data.
@@ -79,13 +85,11 @@
struct temp_data {
int temp;
int ttarget;
- int tmin;
int tjmax;
unsigned long last_updated;
unsigned int cpu;
u32 cpu_core_id;
u32 status_reg;
- u32 intrpt_reg;
int attr_size;
bool is_pkg_data;
bool valid;
@@ -143,19 +147,6 @@ static ssize_t show_crit_alarm(struct device *dev,
return sprintf(buf, "%d\n", (eax >> 5) & 1);
}
-static ssize_t show_max_alarm(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- u32 eax, edx;
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct platform_data *pdata = dev_get_drvdata(dev);
- struct temp_data *tdata = pdata->core_data[attr->index];
-
- rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
-
- return sprintf(buf, "%d\n", !!(eax & THERM_STATUS_THRESHOLD1));
-}
-
static ssize_t show_tjmax(struct device *dev,
struct device_attribute *devattr, char *buf)
{
@@ -174,83 +165,6 @@ static ssize_t show_ttarget(struct device *dev,
return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget);
}
-static ssize_t store_ttarget(struct device *dev,
- struct device_attribute *devattr,
- const char *buf, size_t count)
-{
- struct platform_data *pdata = dev_get_drvdata(dev);
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct temp_data *tdata = pdata->core_data[attr->index];
- u32 eax, edx;
- unsigned long val;
- int diff;
-
- if (strict_strtoul(buf, 10, &val))
- return -EINVAL;
-
- /*
- * THERM_MASK_THRESHOLD1 is 7 bits wide. Values are entered in terms
- * of milli degree celsius. Hence don't accept val > (127 * 1000)
- */
- if (val > tdata->tjmax || val > 127000)
- return -EINVAL;
-
- diff = (tdata->tjmax - val) / 1000;
-
- mutex_lock(&tdata->update_lock);
- rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx);
- eax = (eax & ~THERM_MASK_THRESHOLD1) |
- (diff << THERM_SHIFT_THRESHOLD1);
- wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx);
- tdata->ttarget = val;
- mutex_unlock(&tdata->update_lock);
-
- return count;
-}
-
-static ssize_t show_tmin(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct platform_data *pdata = dev_get_drvdata(dev);
-
- return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tmin);
-}
-
-static ssize_t store_tmin(struct device *dev,
- struct device_attribute *devattr,
- const char *buf, size_t count)
-{
- struct platform_data *pdata = dev_get_drvdata(dev);
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct temp_data *tdata = pdata->core_data[attr->index];
- u32 eax, edx;
- unsigned long val;
- int diff;
-
- if (strict_strtoul(buf, 10, &val))
- return -EINVAL;
-
- /*
- * THERM_MASK_THRESHOLD0 is 7 bits wide. Values are entered in terms
- * of milli degree celsius. Hence don't accept val > (127 * 1000)
- */
- if (val > tdata->tjmax || val > 127000)
- return -EINVAL;
-
- diff = (tdata->tjmax - val) / 1000;
-
- mutex_lock(&tdata->update_lock);
- rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx);
- eax = (eax & ~THERM_MASK_THRESHOLD0) |
- (diff << THERM_SHIFT_THRESHOLD0);
- wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx);
- tdata->tmin = val;
- mutex_unlock(&tdata->update_lock);
-
- return count;
-}
-
static ssize_t show_temp(struct device *dev,
struct device_attribute *devattr, char *buf)
{
@@ -374,7 +288,6 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
{
- /* The 100C is default for both mobile and non mobile CPUs */
int err;
u32 eax, edx;
u32 val;
@@ -385,7 +298,8 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
*/
err = rdmsr_safe_on_cpu(id, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
if (err) {
- dev_warn(dev, "Unable to read TjMax from CPU.\n");
+ if (c->x86_model > 0xe && c->x86_model != 0x1c)
+ dev_warn(dev, "Unable to read TjMax from CPU %u\n", id);
} else {
val = (eax >> 16) & 0xff;
/*
@@ -393,11 +307,17 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
* will be used
*/
if (val) {
- dev_info(dev, "TjMax is %d C.\n", val);
+ dev_dbg(dev, "TjMax is %d degrees C\n", val);
return val * 1000;
}
}
+ if (force_tjmax) {
+ dev_notice(dev, "TjMax forced to %d degrees C by user\n",
+ force_tjmax);
+ return force_tjmax * 1000;
+ }
+
/*
* An assumption is made for early CPUs and unreadable MSR.
* NOTE: the calculated value may not be correct.
@@ -414,21 +334,6 @@ static void __devinit get_ucode_rev_on_cpu(void *edx)
rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx);
}
-static int get_pkg_tjmax(unsigned int cpu, struct device *dev)
-{
- int err;
- u32 eax, edx, val;
-
- err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
- if (!err) {
- val = (eax >> 16) & 0xff;
- if (val)
- return val * 1000;
- }
- dev_warn(dev, "Unable to read Pkg-TjMax from CPU:%u\n", cpu);
- return 100000; /* Default TjMax: 100 degree celsius */
-}
-
static int create_name_attr(struct platform_data *pdata, struct device *dev)
{
sysfs_attr_init(&pdata->name_attr.attr);
@@ -442,19 +347,14 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
int attr_no)
{
int err, i;
- static ssize_t (*rd_ptr[TOTAL_ATTRS]) (struct device *dev,
+ static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
struct device_attribute *devattr, char *buf) = {
show_label, show_crit_alarm, show_temp, show_tjmax,
- show_max_alarm, show_ttarget, show_tmin };
- static ssize_t (*rw_ptr[TOTAL_ATTRS]) (struct device *dev,
- struct device_attribute *devattr, const char *buf,
- size_t count) = { NULL, NULL, NULL, NULL, NULL,
- store_ttarget, store_tmin };
- static const char *names[TOTAL_ATTRS] = {
+ show_ttarget };
+ static const char *const names[TOTAL_ATTRS] = {
"temp%d_label", "temp%d_crit_alarm",
"temp%d_input", "temp%d_crit",
- "temp%d_max_alarm", "temp%d_max",
- "temp%d_max_hyst" };
+ "temp%d_max" };
for (i = 0; i < tdata->attr_size; i++) {
snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, names[i],
@@ -462,10 +362,6 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr);
tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i];
tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;
- if (rw_ptr[i]) {
- tdata->sd_attrs[i].dev_attr.attr.mode |= S_IWUSR;
- tdata->sd_attrs[i].dev_attr.store = rw_ptr[i];
- }
tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
tdata->sd_attrs[i].index = attr_no;
err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr);
@@ -481,9 +377,9 @@ exit_free:
}
-static int __devinit chk_ucode_version(struct platform_device *pdev)
+static int __cpuinit chk_ucode_version(unsigned int cpu)
{
- struct cpuinfo_x86 *c = &cpu_data(pdev->id);
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
int err;
u32 edx;
@@ -494,17 +390,15 @@ static int __devinit chk_ucode_version(struct platform_device *pdev)
*/
if (c->x86_model == 0xe && c->x86_mask < 0xc) {
/* check for microcode update */
- err = smp_call_function_single(pdev->id, get_ucode_rev_on_cpu,
+ err = smp_call_function_single(cpu, get_ucode_rev_on_cpu,
&edx, 1);
if (err) {
- dev_err(&pdev->dev,
- "Cannot determine microcode revision of "
- "CPU#%u (%d)!\n", pdev->id, err);
+ pr_err("Cannot determine microcode revision of "
+ "CPU#%u (%d)!\n", cpu, err);
return -ENODEV;
} else if (edx < 0x39) {
- dev_err(&pdev->dev,
- "Errata AE18 not fixed, update BIOS or "
- "microcode of the CPU!\n");
+ pr_err("Errata AE18 not fixed, update BIOS or "
+ "microcode of the CPU!\n");
return -ENODEV;
}
}
@@ -538,8 +432,6 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
tdata->status_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_STATUS :
MSR_IA32_THERM_STATUS;
- tdata->intrpt_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_INTERRUPT :
- MSR_IA32_THERM_INTERRUPT;
tdata->is_pkg_data = pkg_flag;
tdata->cpu = cpu;
tdata->cpu_core_id = TO_CORE_ID(cpu);
@@ -548,11 +440,11 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
return tdata;
}
-static int create_core_data(struct platform_data *pdata,
- struct platform_device *pdev,
+static int create_core_data(struct platform_device *pdev,
unsigned int cpu, int pkg_flag)
{
struct temp_data *tdata;
+ struct platform_data *pdata = platform_get_drvdata(pdev);
struct cpuinfo_x86 *c = &cpu_data(cpu);
u32 eax, edx;
int err, attr_no;
@@ -588,20 +480,21 @@ static int create_core_data(struct platform_data *pdata,
goto exit_free;
/* We can access status register. Get Critical Temperature */
- if (pkg_flag)
- tdata->tjmax = get_pkg_tjmax(pdev->id, &pdev->dev);
- else
- tdata->tjmax = get_tjmax(c, cpu, &pdev->dev);
+ tdata->tjmax = get_tjmax(c, cpu, &pdev->dev);
/*
- * Test if we can access the intrpt register. If so, increase the
- * 'size' enough to have ttarget/tmin/max_alarm interfaces.
- * Initialize ttarget with bits 16:22 of MSR_IA32_THERM_INTERRUPT
+ * Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET.
+ * The target temperature is available on older CPUs but not in this
+ * register. Atoms don't have the register at all.
*/
- err = rdmsr_safe_on_cpu(cpu, tdata->intrpt_reg, &eax, &edx);
- if (!err) {
- tdata->attr_size += MAX_THRESH_ATTRS;
- tdata->ttarget = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000;
+ if (c->x86_model > 0xe && c->x86_model != 0x1c) {
+ err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET,
+ &eax, &edx);
+ if (!err) {
+ tdata->ttarget
+ = tdata->tjmax - ((eax >> 8) & 0xff) * 1000;
+ tdata->attr_size++;
+ }
}
pdata->core_data[attr_no] = tdata;
@@ -613,22 +506,20 @@ static int create_core_data(struct platform_data *pdata,
return 0;
exit_free:
+ pdata->core_data[attr_no] = NULL;
kfree(tdata);
return err;
}
static void coretemp_add_core(unsigned int cpu, int pkg_flag)
{
- struct platform_data *pdata;
struct platform_device *pdev = coretemp_get_pdev(cpu);
int err;
if (!pdev)
return;
- pdata = platform_get_drvdata(pdev);
-
- err = create_core_data(pdata, pdev, cpu, pkg_flag);
+ err = create_core_data(pdev, cpu, pkg_flag);
if (err)
dev_err(&pdev->dev, "Adding Core %u failed\n", cpu);
}
@@ -652,11 +543,6 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
struct platform_data *pdata;
int err;
- /* Check the microcode version of the CPU */
- err = chk_ucode_version(pdev);
- if (err)
- return err;
-
/* Initialize the per-package data structures */
pdata = kzalloc(sizeof(struct platform_data), GFP_KERNEL);
if (!pdata)
@@ -666,7 +552,7 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
if (err)
goto exit_free;
- pdata->phys_proc_id = TO_PHYS_ID(pdev->id);
+ pdata->phys_proc_id = pdev->id;
platform_set_drvdata(pdev, pdata);
pdata->hwmon_dev = hwmon_device_register(&pdev->dev);
@@ -718,7 +604,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
mutex_lock(&pdev_list_mutex);
- pdev = platform_device_alloc(DRVNAME, cpu);
+ pdev = platform_device_alloc(DRVNAME, TO_PHYS_ID(cpu));
if (!pdev) {
err = -ENOMEM;
pr_err("Device allocation failed\n");
@@ -738,7 +624,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
}
pdev_entry->pdev = pdev;
- pdev_entry->phys_proc_id = TO_PHYS_ID(cpu);
+ pdev_entry->phys_proc_id = pdev->id;
list_add_tail(&pdev_entry->list, &pdev_list);
mutex_unlock(&pdev_list_mutex);
@@ -799,6 +685,10 @@ static void __cpuinit get_core_online(unsigned int cpu)
return;
if (!pdev) {
+ /* Check the microcode version of the CPU */
+ if (chk_ucode_version(cpu))
+ return;
+
/*
* Alright, we have DTS support.
* We are bringing the _first_ core in this pkg
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c
index 257957c..4f7c3fc 100644
--- a/drivers/hwmon/ds620.c
+++ b/drivers/hwmon/ds620.c
@@ -72,7 +72,7 @@ struct ds620_data {
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
- u16 temp[3]; /* Register values, word */
+ s16 temp[3]; /* Register values, word */
};
/*
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index a561c3a..397fc59 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -978,6 +978,8 @@ static void pmbus_find_max_attr(struct i2c_client *client,
struct pmbus_limit_attr {
u16 reg; /* Limit register */
bool update; /* True if register needs updates */
+ bool low; /* True if low limit; for limits with compare
+ functions only */
const char *attr; /* Attribute name */
const char *alarm; /* Alarm attribute name */
u32 sbit; /* Alarm attribute status bit */
@@ -1029,7 +1031,8 @@ static bool pmbus_add_limit_attrs(struct i2c_client *client,
if (attr->compare) {
pmbus_add_boolean_cmp(data, name,
l->alarm, index,
- cbase, cindex,
+ l->low ? cindex : cbase,
+ l->low ? cbase : cindex,
attr->sbase + page, l->sbit);
} else {
pmbus_add_boolean_reg(data, name,
@@ -1366,11 +1369,13 @@ static const struct pmbus_sensor_attr power_attributes[] = {
static const struct pmbus_limit_attr temp_limit_attrs[] = {
{
.reg = PMBUS_UT_WARN_LIMIT,
+ .low = true,
.attr = "min",
.alarm = "min_alarm",
.sbit = PB_TEMP_UT_WARNING,
}, {
.reg = PMBUS_UT_FAULT_LIMIT,
+ .low = true,
.attr = "lcrit",
.alarm = "lcrit_alarm",
.sbit = PB_TEMP_UT_FAULT,
@@ -1399,11 +1404,13 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = {
static const struct pmbus_limit_attr temp_limit_attrs23[] = {
{
.reg = PMBUS_UT_WARN_LIMIT,
+ .low = true,
.attr = "min",
.alarm = "min_alarm",
.sbit = PB_TEMP_UT_WARNING,
}, {
.reg = PMBUS_UT_FAULT_LIMIT,
+ .low = true,
.attr = "lcrit",
.alarm = "lcrit_alarm",
.sbit = PB_TEMP_UT_FAULT,
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index 17cf1ab..8c2844e 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -329,8 +329,8 @@ static int w83791d_detect(struct i2c_client *client,
struct i2c_board_info *info);
static int w83791d_remove(struct i2c_client *client);
-static int w83791d_read(struct i2c_client *client, u8 register);
-static int w83791d_write(struct i2c_client *client, u8 register, u8 value);
+static int w83791d_read(struct i2c_client *client, u8 reg);
+static int w83791d_write(struct i2c_client *client, u8 reg, u8 value);
static struct w83791d_data *w83791d_update_device(struct device *dev);
#ifdef DEBUG
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 2747980..16f69be 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -435,7 +435,12 @@ static int idedisk_prep_fn(struct request_queue *q, struct request *rq)
if (!(rq->cmd_flags & REQ_FLUSH))
return BLKPREP_OK;
- cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+ if (rq->special) {
+ cmd = rq->special;
+ memset(cmd, 0, sizeof(*cmd));
+ } else {
+ cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+ }
/* FIXME: map struct ide_taskfile on rq->cmd[] */
BUG_ON(cmd == NULL);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 17bf9d9..6cd642a 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -287,7 +287,7 @@ void __free_ep(struct kref *kref)
if (test_bit(RELEASE_RESOURCES, &ep->com.flags)) {
cxgb3_remove_tid(ep->com.tdev, (void *)ep, ep->hwtid);
dst_release(ep->dst);
- l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+ l2t_release(ep->com.tdev, ep->l2t);
}
kfree(ep);
}
@@ -1178,7 +1178,7 @@ static int act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
release_tid(ep->com.tdev, GET_TID(rpl), NULL);
cxgb3_free_atid(ep->com.tdev, ep->atid);
dst_release(ep->dst);
- l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+ l2t_release(ep->com.tdev, ep->l2t);
put_ep(&ep->com);
return CPL_RET_BUF_DONE;
}
@@ -1377,7 +1377,7 @@ static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
if (!child_ep) {
printk(KERN_ERR MOD "%s - failed to allocate ep entry!\n",
__func__);
- l2t_release(L2DATA(tdev), l2t);
+ l2t_release(tdev, l2t);
dst_release(dst);
goto reject;
}
@@ -1956,7 +1956,7 @@ int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if (!err)
goto out;
- l2t_release(L2DATA(h->rdev.t3cdev_p), ep->l2t);
+ l2t_release(h->rdev.t3cdev_p, ep->l2t);
fail4:
dst_release(ep->dst);
fail3:
@@ -2127,7 +2127,7 @@ int iwch_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new,
PDBG("%s ep %p redirect to dst %p l2t %p\n", __func__, ep, new,
l2t);
dst_hold(new);
- l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+ l2t_release(ep->com.tdev, ep->l2t);
ep->l2t = l2t;
dst_release(old);
ep->dst = new;
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index 7b404e5..e34eeb8 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -668,4 +668,3 @@ module_exit(adp5588_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("ADP5588/87 Keypad driver");
-MODULE_ALIAS("platform:adp5588-keys");
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
index b09c7d1..ab86051 100644
--- a/drivers/input/misc/cm109.c
+++ b/drivers/input/misc/cm109.c
@@ -475,7 +475,7 @@ static void cm109_toggle_buzzer_sync(struct cm109_dev *dev, int on)
le16_to_cpu(dev->ctl_req->wIndex),
dev->ctl_data,
USB_PKT_LEN, USB_CTRL_SET_TIMEOUT);
- if (error && error != EINTR)
+ if (error < 0 && error != -EINTR)
err("%s: usb_control_msg() failed %d", __func__, error);
}
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index da28018..5ec617e 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -67,6 +67,10 @@
#define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245
#define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246
#define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247
+/* MacbookAir4,1 (unibody, July 2011) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI 0x0249
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO 0x024a
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS 0x024b
/* MacbookAir4,2 (unibody, July 2011) */
#define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI 0x024c
#define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO 0x024d
@@ -112,6 +116,10 @@ static const struct usb_device_id bcm5974_table[] = {
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ISO),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
+ /* MacbookAir4,1 */
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS),
/* MacbookAir4,2 */
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_ISO),
@@ -334,6 +342,18 @@ static const struct bcm5974_config bcm5974_config_table[] = {
{ DIM_X, DIM_X / SN_COORD, -4750, 5280 },
{ DIM_Y, DIM_Y / SN_COORD, -150, 6730 }
},
+ {
+ USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI,
+ USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO,
+ USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS,
+ HAS_INTEGRATED_BUTTON,
+ 0x84, sizeof(struct bt_data),
+ 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+ { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+ { DIM_X, DIM_X / SN_COORD, -4620, 5140 },
+ { DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
+ },
{}
};
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index d27c9d9..958b4eb 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -229,13 +229,6 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
get_unaligned_le16(&report[i + 3]);
i += 4;
}
- } else if (usage == WCM_DIGITIZER) {
- /* max pressure isn't reported
- features->pressure_max = (unsigned short)
- (report[i+4] << 8 | report[i + 3]);
- */
- features->pressure_max = 255;
- i += 4;
}
break;
@@ -291,13 +284,6 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
pen = 1;
i++;
break;
-
- case HID_USAGE_UNDEFINED:
- if (usage == WCM_DESKTOP && finger) /* capacity */
- features->pressure_max =
- get_unaligned_le16(&report[i + 3]);
- i += 4;
- break;
}
break;
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index c1c2f7b..0dc97ec 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -800,25 +800,26 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
int i;
for (i = 0; i < 2; i++) {
- int p = data[9 * i + 2];
- bool touch = p && !wacom->shared->stylus_in_proximity;
+ int offset = (data[1] & 0x80) ? (8 * i) : (9 * i);
+ bool touch = data[offset + 3] & 0x80;
- input_mt_slot(input, i);
- input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
/*
* Touch events need to be disabled while stylus is
* in proximity because user's hand is resting on touchpad
* and sending unwanted events. User expects tablet buttons
* to continue working though.
*/
+ touch = touch && !wacom->shared->stylus_in_proximity;
+
+ input_mt_slot(input, i);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
if (touch) {
- int x = get_unaligned_be16(&data[9 * i + 3]) & 0x7ff;
- int y = get_unaligned_be16(&data[9 * i + 5]) & 0x7ff;
+ int x = get_unaligned_be16(&data[offset + 3]) & 0x7ff;
+ int y = get_unaligned_be16(&data[offset + 5]) & 0x7ff;
if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) {
x <<= 5;
y <<= 5;
}
- input_report_abs(input, ABS_MT_PRESSURE, p);
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
}
@@ -1056,10 +1057,11 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
features->x_fuzz, 0);
input_set_abs_params(input_dev, ABS_Y, 0, features->y_max,
features->y_fuzz, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max,
- features->pressure_fuzz, 0);
if (features->device_type == BTN_TOOL_PEN) {
+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max,
+ features->pressure_fuzz, 0);
+
/* penabled devices have fixed resolution for each model */
input_abs_set_res(input_dev, ABS_X, features->x_resolution);
input_abs_set_res(input_dev, ABS_Y, features->y_resolution);
@@ -1098,6 +1100,8 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
__set_bit(BTN_STYLUS, input_dev->keybit);
__set_bit(BTN_STYLUS2, input_dev->keybit);
+
+ __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
break;
case WACOM_21UX2:
@@ -1126,6 +1130,9 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
}
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+
wacom_setup_cintiq(wacom_wac);
break;
@@ -1150,6 +1157,8 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
/* fall through */
case INTUOS:
+ __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
wacom_setup_intuos(wacom_wac);
break;
@@ -1165,6 +1174,8 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
wacom_setup_intuos(wacom_wac);
+
+ __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
break;
case TABLETPC2FG:
@@ -1183,26 +1194,40 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
case TABLETPC:
__clear_bit(ABS_MISC, input_dev->absbit);
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+
if (features->device_type != BTN_TOOL_PEN)
break; /* no need to process stylus stuff */
/* fall through */
case PL:
- case PTU:
case DTU:
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
+ __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_STYLUS, input_dev->keybit);
__set_bit(BTN_STYLUS2, input_dev->keybit);
+
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+ break;
+
+ case PTU:
+ __set_bit(BTN_STYLUS2, input_dev->keybit);
/* fall through */
case PENPARTNER:
+ __set_bit(BTN_TOOL_PEN, input_dev->keybit);
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
+ __set_bit(BTN_STYLUS, input_dev->keybit);
+
+ __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
break;
case BAMBOO_PT:
__clear_bit(ABS_MISC, input_dev->absbit);
+ __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
if (features->device_type == BTN_TOOL_DOUBLETAP) {
__set_bit(BTN_LEFT, input_dev->keybit);
__set_bit(BTN_FORWARD, input_dev->keybit);
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index c14412e..9941d39 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -383,6 +383,8 @@ static int w8001_setup(struct w8001 *w8001)
dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name));
+ __set_bit(INPUT_PROP_DIRECT, dev->propbit);
+
/* penabled? */
error = w8001_command(w8001, W8001_CMD_QUERY, true);
if (!error) {
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 3dc9bef..6dcc7e2 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -1388,7 +1388,7 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
return ret;
}
- ret = request_irq(irq, dmar_fault, 0, iommu->name, iommu);
+ ret = request_irq(irq, dmar_fault, IRQF_NO_THREAD, iommu->name, iommu);
if (ret)
printk(KERN_ERR "IOMMU: can't request irq\n");
return ret;
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index d87c9d0..328c64c 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -41,6 +41,7 @@ static ssize_t led_delay_on_store(struct device *dev,
if (count == size) {
led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off);
+ led_cdev->blink_delay_on = state;
ret = count;
}
@@ -69,6 +70,7 @@ static ssize_t led_delay_off_store(struct device *dev,
if (count == size) {
led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state);
+ led_cdev->blink_delay_off = state;
ret = count;
}
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
index ec4a31f..30d8896b 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/video/omap/omap_vout.c
@@ -2200,19 +2200,6 @@ static int __init omap_vout_probe(struct platform_device *pdev)
"'%s' Display already enabled\n",
def_display->name);
}
- /* set the update mode */
- if (def_display->caps &
- OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
- if (dssdrv->enable_te)
- dssdrv->enable_te(def_display, 0);
- if (dssdrv->set_update_mode)
- dssdrv->set_update_mode(def_display,
- OMAP_DSS_UPDATE_MANUAL);
- } else {
- if (dssdrv->set_update_mode)
- dssdrv->set_update_mode(def_display,
- OMAP_DSS_UPDATE_AUTO);
- }
}
}
diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c
index 9d3459d..80796eb 100644
--- a/drivers/media/video/omap3isp/ispccdc.c
+++ b/drivers/media/video/omap3isp/ispccdc.c
@@ -31,6 +31,7 @@
#include <linux/dma-mapping.h>
#include <linux/mm.h>
#include <linux/sched.h>
+#include <linux/slab.h>
#include <media/v4l2-event.h>
#include "isp.h"
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index d29f9c2..e4100b1 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -1961,7 +1961,7 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
list_for_each_entry(stream, &dev->streams, list) {
if (stream->intf == intf)
- return uvc_video_resume(stream);
+ return uvc_video_resume(stream, reset);
}
uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface "
diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/video/uvc/uvc_entity.c
index 48fea37..29e2399 100644
--- a/drivers/media/video/uvc/uvc_entity.c
+++ b/drivers/media/video/uvc/uvc_entity.c
@@ -49,7 +49,7 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain,
if (remote == NULL)
return -EINVAL;
- source = (UVC_ENTITY_TYPE(remote) != UVC_TT_STREAMING)
+ source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING)
? (remote->vdev ? &remote->vdev->entity : NULL)
: &remote->subdev.entity;
if (source == NULL)
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 8244167..ffd1158 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -1104,10 +1104,18 @@ int uvc_video_suspend(struct uvc_streaming *stream)
* buffers, making sure userspace applications are notified of the problem
* instead of waiting forever.
*/
-int uvc_video_resume(struct uvc_streaming *stream)
+int uvc_video_resume(struct uvc_streaming *stream, int reset)
{
int ret;
+ /* If the bus has been reset on resume, set the alternate setting to 0.
+ * This should be the default value, but some devices crash or otherwise
+ * misbehave if they don't receive a SET_INTERFACE request before any
+ * other video control request.
+ */
+ if (reset)
+ usb_set_interface(stream->dev->udev, stream->intfnum, 0);
+
stream->frozen = 0;
ret = uvc_commit_video(stream, &stream->ctrl);
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index df32a43..cbdd49b 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -638,7 +638,7 @@ extern void uvc_mc_cleanup_entity(struct uvc_entity *entity);
/* Video */
extern int uvc_video_init(struct uvc_streaming *stream);
extern int uvc_video_suspend(struct uvc_streaming *stream);
-extern int uvc_video_resume(struct uvc_streaming *stream);
+extern int uvc_video_resume(struct uvc_streaming *stream, int reset);
extern int uvc_video_enable(struct uvc_streaming *stream, int enable);
extern int uvc_probe_video(struct uvc_streaming *stream,
struct uvc_streaming_control *probe);
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 06f1400..d721565 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -173,6 +173,17 @@ static void v4l2_device_release(struct device *cd)
media_device_unregister_entity(&vdev->entity);
#endif
+ /* Do not call v4l2_device_put if there is no release callback set.
+ * Drivers that have no v4l2_device release callback might free the
+ * v4l2_dev instance in the video_device release callback below, so we
+ * must perform this check here.
+ *
+ * TODO: In the long run all drivers that use v4l2_device should use the
+ * v4l2_device release callback. This check will then be unnecessary.
+ */
+ if (v4l2_dev->release == NULL)
+ v4l2_dev = NULL;
+
/* Release video_device and perform other
cleanups as needed. */
vdev->release(vdev);
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index c72856c..e6a2c3b 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -38,6 +38,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
mutex_init(&v4l2_dev->ioctl_lock);
v4l2_prio_init(&v4l2_dev->prio);
kref_init(&v4l2_dev->ref);
+ get_device(dev);
v4l2_dev->dev = dev;
if (dev == NULL) {
/* If dev == NULL, then name must be filled in by the caller */
@@ -93,6 +94,7 @@ void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev)
dev_set_drvdata(v4l2_dev->dev, NULL);
+ put_device(v4l2_dev->dev);
v4l2_dev->dev = NULL;
}
EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c
index 21131c7..563654c 100644
--- a/drivers/mfd/jz4740-adc.c
+++ b/drivers/mfd/jz4740-adc.c
@@ -273,7 +273,7 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev)
ct->regs.ack = JZ_REG_ADC_STATUS;
ct->chip.irq_mask = irq_gc_mask_set_bit;
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
- ct->chip.irq_ack = irq_gc_ack;
+ ct->chip.irq_ack = irq_gc_ack_set_bit;
irq_setup_generic_chip(gc, IRQ_MSK(5), 0, 0, IRQ_NOPROBE | IRQ_LEVEL);
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
index 5d1fca0..f83103b 100644
--- a/drivers/mfd/max8997.c
+++ b/drivers/mfd/max8997.c
@@ -135,10 +135,13 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
max8997->dev = &i2c->dev;
max8997->i2c = i2c;
max8997->type = id->driver_data;
+ max8997->irq = i2c->irq;
if (!pdata)
goto err;
+ max8997->irq_base = pdata->irq_base;
+ max8997->ono = pdata->ono;
max8997->wakeup = pdata->wakeup;
mutex_init(&max8997->iolock);
@@ -152,6 +155,8 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
pm_runtime_set_active(max8997->dev);
+ max8997_irq_init(max8997);
+
mfd_add_devices(max8997->dev, -1, max8997_devs,
ARRAY_SIZE(max8997_devs),
NULL, 0);
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 29601e7..86e1458 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -676,7 +677,6 @@ static void usbhs_omap_tll_init(struct device *dev, u8 tll_channel_count)
| OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
| OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE);
- reg |= (1 << (i + 1));
} else
continue;
diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c
index 2bfad5c..a56be93 100644
--- a/drivers/mfd/tps65910-irq.c
+++ b/drivers/mfd/tps65910-irq.c
@@ -178,8 +178,10 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq,
switch (tps65910_chip_id(tps65910)) {
case TPS65910:
tps65910->irq_num = TPS65910_NUM_IRQ;
+ break;
case TPS65911:
tps65910->irq_num = TPS65911_NUM_IRQ;
+ break;
}
/* Register with genirq */
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c
index b5d598c..7cbf2aa 100644
--- a/drivers/mfd/twl4030-madc.c
+++ b/drivers/mfd/twl4030-madc.c
@@ -510,8 +510,9 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
u8 ch_msb, ch_lsb;
int ret;
- if (!req)
+ if (!req || !twl4030_madc)
return -EINVAL;
+
mutex_lock(&twl4030_madc->lock);
if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) {
ret = -EINVAL;
@@ -706,6 +707,8 @@ static int __devinit twl4030_madc_probe(struct platform_device *pdev)
if (!madc)
return -ENOMEM;
+ madc->dev = &pdev->dev;
+
/*
* Phoenix provides 2 interrupt lines. The first one is connected to
* the OMAP. The other one can be connected to the other processor such
diff --git a/drivers/mfd/wm8350-gpio.c b/drivers/mfd/wm8350-gpio.c
index ebf99be..d584f6b 100644
--- a/drivers/mfd/wm8350-gpio.c
+++ b/drivers/mfd/wm8350-gpio.c
@@ -37,7 +37,7 @@ static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir)
return ret;
}
-static int gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db)
+static int wm8350_gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db)
{
if (db == WM8350_GPIO_DEBOUNCE_ON)
return wm8350_set_bits(wm8350, WM8350_GPIO_DEBOUNCE,
@@ -210,7 +210,7 @@ int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func,
goto err;
if (gpio_set_polarity(wm8350, gpio, pol))
goto err;
- if (gpio_set_debounce(wm8350, gpio, debounce))
+ if (wm8350_gpio_set_debounce(wm8350, gpio, debounce))
goto err;
if (gpio_set_dir(wm8350, gpio, dir))
goto err;
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
index b928bc1..8b51cd6 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d.c
@@ -375,12 +375,14 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3)
* both have been read. So the value read will always be correct.
* Set BOOT bit to refresh factory tuning values.
*/
- lis3->read(lis3, CTRL_REG2, &reg);
- if (lis3->whoami == WAI_12B)
- reg |= CTRL2_BDU | CTRL2_BOOT;
- else
- reg |= CTRL2_BOOT_8B;
- lis3->write(lis3, CTRL_REG2, reg);
+ if (lis3->pdata) {
+ lis3->read(lis3, CTRL_REG2, &reg);
+ if (lis3->whoami == WAI_12B)
+ reg |= CTRL2_BDU | CTRL2_BOOT;
+ else
+ reg |= CTRL2_BOOT_8B;
+ lis3->write(lis3, CTRL_REG2, reg);
+ }
/* LIS3 power on delay is quite long */
msleep(lis3->pwron_delay / lis3lv02d_get_odr());
diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index 06df187..0b56e3f 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -165,6 +165,11 @@ static void pti_write_to_aperture(struct pti_masterchannel *mc,
static void pti_control_frame_built_and_sent(struct pti_masterchannel *mc,
const char *thread_name)
{
+ /*
+ * Since we access the comm member in current's task_struct, we only
+ * need to be as large as what 'comm' in that structure is.
+ */
+ char comm[TASK_COMM_LEN];
struct pti_masterchannel mccontrol = {.master = CONTROL_ID,
.channel = 0};
const char *thread_name_p;
@@ -172,13 +177,6 @@ static void pti_control_frame_built_and_sent(struct pti_masterchannel *mc,
u8 control_frame[CONTROL_FRAME_LEN];
if (!thread_name) {
- /*
- * Since we access the comm member in current's task_struct,
- * we only need to be as large as what 'comm' in that
- * structure is.
- */
- char comm[TASK_COMM_LEN];
-
if (!in_interrupt())
get_task_comm(comm, current);
else
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 1ff5486..4c1a648 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -926,6 +926,9 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
/*
* Reliable writes are used to implement Forced Unit Access and
* REQ_META accesses, and are supported only on MMCs.
+ *
+ * XXX: this really needs a good explanation of why REQ_META
+ * is treated special.
*/
bool do_rel_wr = ((req->cmd_flags & REQ_FUA) ||
(req->cmd_flags & REQ_META)) &&
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 8d0314d..a44874e 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2535,7 +2535,7 @@ config S6GMAC
source "drivers/net/stmmac/Kconfig"
config PCH_GBE
- tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7223 IOH GbE"
+ tristate "Intel EG20T PCH/OKI SEMICONDUCTOR IOH(ML7223/ML7831) GbE"
depends on PCI
select MII
---help---
@@ -2548,10 +2548,11 @@ config PCH_GBE
This driver enables Gigabit Ethernet function.
This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
- Output Hub), ML7223.
- ML7223 IOH is for MP(Media Phone) use.
- ML7223 is companion chip for Intel Atom E6xx series.
- ML7223 is completely compatible for Intel EG20T PCH.
+ Output Hub), ML7223/ML7831.
+ ML7223 IOH is for MP(Media Phone) use. ML7831 IOH is for general
+ purpose use.
+ ML7223/ML7831 is companion chip for Intel Atom E6xx series.
+ ML7223/ML7831 is completely compatible for Intel EG20T PCH.
config FTGMAC100
tristate "Faraday FTGMAC100 Gigabit Ethernet support"
diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h
index c423504..e46df53 100644
--- a/drivers/net/bnx2x/bnx2x.h
+++ b/drivers/net/bnx2x/bnx2x.h
@@ -315,6 +315,14 @@ union db_prod {
u32 raw;
};
+/* dropless fc FW/HW related params */
+#define BRB_SIZE(bp) (CHIP_IS_E3(bp) ? 1024 : 512)
+#define MAX_AGG_QS(bp) (CHIP_IS_E1(bp) ? \
+ ETH_MAX_AGGREGATION_QUEUES_E1 :\
+ ETH_MAX_AGGREGATION_QUEUES_E1H_E2)
+#define FW_DROP_LEVEL(bp) (3 + MAX_SPQ_PENDING + MAX_AGG_QS(bp))
+#define FW_PREFETCH_CNT 16
+#define DROPLESS_FC_HEADROOM 100
/* MC hsi */
#define BCM_PAGE_SHIFT 12
@@ -331,15 +339,35 @@ union db_prod {
/* SGE ring related macros */
#define NUM_RX_SGE_PAGES 2
#define RX_SGE_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_sge))
-#define MAX_RX_SGE_CNT (RX_SGE_CNT - 2)
+#define NEXT_PAGE_SGE_DESC_CNT 2
+#define MAX_RX_SGE_CNT (RX_SGE_CNT - NEXT_PAGE_SGE_DESC_CNT)
/* RX_SGE_CNT is promised to be a power of 2 */
#define RX_SGE_MASK (RX_SGE_CNT - 1)
#define NUM_RX_SGE (RX_SGE_CNT * NUM_RX_SGE_PAGES)
#define MAX_RX_SGE (NUM_RX_SGE - 1)
#define NEXT_SGE_IDX(x) ((((x) & RX_SGE_MASK) == \
- (MAX_RX_SGE_CNT - 1)) ? (x) + 3 : (x) + 1)
+ (MAX_RX_SGE_CNT - 1)) ? \
+ (x) + 1 + NEXT_PAGE_SGE_DESC_CNT : \
+ (x) + 1)
#define RX_SGE(x) ((x) & MAX_RX_SGE)
+/*
+ * Number of required SGEs is the sum of two:
+ * 1. Number of possible opened aggregations (next packet for
+ * these aggregations will probably consume SGE immidiatelly)
+ * 2. Rest of BRB blocks divided by 2 (block will consume new SGE only
+ * after placement on BD for new TPA aggregation)
+ *
+ * Takes into account NEXT_PAGE_SGE_DESC_CNT "next" elements on each page
+ */
+#define NUM_SGE_REQ (MAX_AGG_QS(bp) + \
+ (BRB_SIZE(bp) - MAX_AGG_QS(bp)) / 2)
+#define NUM_SGE_PG_REQ ((NUM_SGE_REQ + MAX_RX_SGE_CNT - 1) / \
+ MAX_RX_SGE_CNT)
+#define SGE_TH_LO(bp) (NUM_SGE_REQ + \
+ NUM_SGE_PG_REQ * NEXT_PAGE_SGE_DESC_CNT)
+#define SGE_TH_HI(bp) (SGE_TH_LO(bp) + DROPLESS_FC_HEADROOM)
+
/* Manipulate a bit vector defined as an array of u64 */
/* Number of bits in one sge_mask array element */
@@ -551,24 +579,43 @@ struct bnx2x_fastpath {
#define NUM_TX_RINGS 16
#define TX_DESC_CNT (BCM_PAGE_SIZE / sizeof(union eth_tx_bd_types))
-#define MAX_TX_DESC_CNT (TX_DESC_CNT - 1)
+#define NEXT_PAGE_TX_DESC_CNT 1
+#define MAX_TX_DESC_CNT (TX_DESC_CNT - NEXT_PAGE_TX_DESC_CNT)
#define NUM_TX_BD (TX_DESC_CNT * NUM_TX_RINGS)
#define MAX_TX_BD (NUM_TX_BD - 1)
#define MAX_TX_AVAIL (MAX_TX_DESC_CNT * NUM_TX_RINGS - 2)
#define NEXT_TX_IDX(x) ((((x) & MAX_TX_DESC_CNT) == \
- (MAX_TX_DESC_CNT - 1)) ? (x) + 2 : (x) + 1)
+ (MAX_TX_DESC_CNT - 1)) ? \
+ (x) + 1 + NEXT_PAGE_TX_DESC_CNT : \
+ (x) + 1)
#define TX_BD(x) ((x) & MAX_TX_BD)
#define TX_BD_POFF(x) ((x) & MAX_TX_DESC_CNT)
/* The RX BD ring is special, each bd is 8 bytes but the last one is 16 */
#define NUM_RX_RINGS 8
#define RX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_bd))
-#define MAX_RX_DESC_CNT (RX_DESC_CNT - 2)
+#define NEXT_PAGE_RX_DESC_CNT 2
+#define MAX_RX_DESC_CNT (RX_DESC_CNT - NEXT_PAGE_RX_DESC_CNT)
#define RX_DESC_MASK (RX_DESC_CNT - 1)
#define NUM_RX_BD (RX_DESC_CNT * NUM_RX_RINGS)
#define MAX_RX_BD (NUM_RX_BD - 1)
#define MAX_RX_AVAIL (MAX_RX_DESC_CNT * NUM_RX_RINGS - 2)
-#define MIN_RX_AVAIL 128
+
+/* dropless fc calculations for BDs
+ *
+ * Number of BDs should as number of buffers in BRB:
+ * Low threshold takes into account NEXT_PAGE_RX_DESC_CNT
+ * "next" elements on each page
+ */
+#define NUM_BD_REQ BRB_SIZE(bp)
+#define NUM_BD_PG_REQ ((NUM_BD_REQ + MAX_RX_DESC_CNT - 1) / \
+ MAX_RX_DESC_CNT)
+#define BD_TH_LO(bp) (NUM_BD_REQ + \
+ NUM_BD_PG_REQ * NEXT_PAGE_RX_DESC_CNT + \
+ FW_DROP_LEVEL(bp))
+#define BD_TH_HI(bp) (BD_TH_LO(bp) + DROPLESS_FC_HEADROOM)
+
+#define MIN_RX_AVAIL ((bp)->dropless_fc ? BD_TH_HI(bp) + 128 : 128)
#define MIN_RX_SIZE_TPA_HW (CHIP_IS_E1(bp) ? \
ETH_MIN_RX_CQES_WITH_TPA_E1 : \
@@ -579,7 +626,9 @@ struct bnx2x_fastpath {
MIN_RX_AVAIL))
#define NEXT_RX_IDX(x) ((((x) & RX_DESC_MASK) == \
- (MAX_RX_DESC_CNT - 1)) ? (x) + 3 : (x) + 1)
+ (MAX_RX_DESC_CNT - 1)) ? \
+ (x) + 1 + NEXT_PAGE_RX_DESC_CNT : \
+ (x) + 1)
#define RX_BD(x) ((x) & MAX_RX_BD)
/*
@@ -589,14 +638,31 @@ struct bnx2x_fastpath {
#define CQE_BD_REL (sizeof(union eth_rx_cqe) / sizeof(struct eth_rx_bd))
#define NUM_RCQ_RINGS (NUM_RX_RINGS * CQE_BD_REL)
#define RCQ_DESC_CNT (BCM_PAGE_SIZE / sizeof(union eth_rx_cqe))
-#define MAX_RCQ_DESC_CNT (RCQ_DESC_CNT - 1)
+#define NEXT_PAGE_RCQ_DESC_CNT 1
+#define MAX_RCQ_DESC_CNT (RCQ_DESC_CNT - NEXT_PAGE_RCQ_DESC_CNT)
#define NUM_RCQ_BD (RCQ_DESC_CNT * NUM_RCQ_RINGS)
#define MAX_RCQ_BD (NUM_RCQ_BD - 1)
#define MAX_RCQ_AVAIL (MAX_RCQ_DESC_CNT * NUM_RCQ_RINGS - 2)
#define NEXT_RCQ_IDX(x) ((((x) & MAX_RCQ_DESC_CNT) == \
- (MAX_RCQ_DESC_CNT - 1)) ? (x) + 2 : (x) + 1)
+ (MAX_RCQ_DESC_CNT - 1)) ? \
+ (x) + 1 + NEXT_PAGE_RCQ_DESC_CNT : \
+ (x) + 1)
#define RCQ_BD(x) ((x) & MAX_RCQ_BD)
+/* dropless fc calculations for RCQs
+ *
+ * Number of RCQs should be as number of buffers in BRB:
+ * Low threshold takes into account NEXT_PAGE_RCQ_DESC_CNT
+ * "next" elements on each page
+ */
+#define NUM_RCQ_REQ BRB_SIZE(bp)
+#define NUM_RCQ_PG_REQ ((NUM_BD_REQ + MAX_RCQ_DESC_CNT - 1) / \
+ MAX_RCQ_DESC_CNT)
+#define RCQ_TH_LO(bp) (NUM_RCQ_REQ + \
+ NUM_RCQ_PG_REQ * NEXT_PAGE_RCQ_DESC_CNT + \
+ FW_DROP_LEVEL(bp))
+#define RCQ_TH_HI(bp) (RCQ_TH_LO(bp) + DROPLESS_FC_HEADROOM)
+
/* This is needed for determining of last_max */
#define SUB_S16(a, b) (s16)((s16)(a) - (s16)(b))
@@ -685,24 +751,17 @@ struct bnx2x_fastpath {
#define FP_CSB_FUNC_OFF \
offsetof(struct cstorm_status_block_c, func)
-#define HC_INDEX_TOE_RX_CQ_CONS 0 /* Formerly Ustorm TOE CQ index */
- /* (HC_INDEX_U_TOE_RX_CQ_CONS) */
-#define HC_INDEX_ETH_RX_CQ_CONS 1 /* Formerly Ustorm ETH CQ index */
- /* (HC_INDEX_U_ETH_RX_CQ_CONS) */
-#define HC_INDEX_ETH_RX_BD_CONS 2 /* Formerly Ustorm ETH BD index */
- /* (HC_INDEX_U_ETH_RX_BD_CONS) */
-
-#define HC_INDEX_TOE_TX_CQ_CONS 4 /* Formerly Cstorm TOE CQ index */
- /* (HC_INDEX_C_TOE_TX_CQ_CONS) */
-#define HC_INDEX_ETH_TX_CQ_CONS_COS0 5 /* Formerly Cstorm ETH CQ index */
- /* (HC_INDEX_C_ETH_TX_CQ_CONS) */
-#define HC_INDEX_ETH_TX_CQ_CONS_COS1 6 /* Formerly Cstorm ETH CQ index */
- /* (HC_INDEX_C_ETH_TX_CQ_CONS) */
-#define HC_INDEX_ETH_TX_CQ_CONS_COS2 7 /* Formerly Cstorm ETH CQ index */
- /* (HC_INDEX_C_ETH_TX_CQ_CONS) */
+#define HC_INDEX_ETH_RX_CQ_CONS 1
-#define HC_INDEX_ETH_FIRST_TX_CQ_CONS HC_INDEX_ETH_TX_CQ_CONS_COS0
+#define HC_INDEX_OOO_TX_CQ_CONS 4
+#define HC_INDEX_ETH_TX_CQ_CONS_COS0 5
+
+#define HC_INDEX_ETH_TX_CQ_CONS_COS1 6
+
+#define HC_INDEX_ETH_TX_CQ_CONS_COS2 7
+
+#define HC_INDEX_ETH_FIRST_TX_CQ_CONS HC_INDEX_ETH_TX_CQ_CONS_COS0
#define BNX2X_RX_SB_INDEX \
(&fp->sb_index_values[HC_INDEX_ETH_RX_CQ_CONS])
@@ -1100,11 +1159,12 @@ struct bnx2x {
#define BP_PORT(bp) (bp->pfid & 1)
#define BP_FUNC(bp) (bp->pfid)
#define BP_ABS_FUNC(bp) (bp->pf_num)
-#define BP_E1HVN(bp) (bp->pfid >> 1)
-#define BP_VN(bp) (BP_E1HVN(bp)) /*remove when approved*/
-#define BP_L_ID(bp) (BP_E1HVN(bp) << 2)
-#define BP_FW_MB_IDX(bp) (BP_PORT(bp) +\
- BP_VN(bp) * ((CHIP_IS_E1x(bp) || (CHIP_MODE_IS_4_PORT(bp))) ? 2 : 1))
+#define BP_VN(bp) ((bp)->pfid >> 1)
+#define BP_MAX_VN_NUM(bp) (CHIP_MODE_IS_4_PORT(bp) ? 2 : 4)
+#define BP_L_ID(bp) (BP_VN(bp) << 2)
+#define BP_FW_MB_IDX_VN(bp, vn) (BP_PORT(bp) +\
+ (vn) * ((CHIP_IS_E1x(bp) || (CHIP_MODE_IS_4_PORT(bp))) ? 2 : 1))
+#define BP_FW_MB_IDX(bp) BP_FW_MB_IDX_VN(bp, BP_VN(bp))
struct net_device *dev;
struct pci_dev *pdev;
@@ -1767,7 +1827,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
#define MAX_DMAE_C_PER_PORT 8
#define INIT_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \
- BP_E1HVN(bp))
+ BP_VN(bp))
#define PMF_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \
E1HVN_MAX)
@@ -1793,7 +1853,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
/* must be used on a CID before placing it on a HW ring */
#define HW_CID(bp, x) ((BP_PORT(bp) << 23) | \
- (BP_E1HVN(bp) << BNX2X_SWCID_SHIFT) | \
+ (BP_VN(bp) << BNX2X_SWCID_SHIFT) | \
(x))
#define SP_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_spe))
diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c
index 37e5790..c4cbf97 100644
--- a/drivers/net/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/bnx2x/bnx2x_cmn.c
@@ -987,8 +987,6 @@ void __bnx2x_link_report(struct bnx2x *bp)
void bnx2x_init_rx_rings(struct bnx2x *bp)
{
int func = BP_FUNC(bp);
- int max_agg_queues = CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 :
- ETH_MAX_AGGREGATION_QUEUES_E1H_E2;
u16 ring_prod;
int i, j;
@@ -1001,7 +999,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
if (!fp->disable_tpa) {
/* Fill the per-aggregtion pool */
- for (i = 0; i < max_agg_queues; i++) {
+ for (i = 0; i < MAX_AGG_QS(bp); i++) {
struct bnx2x_agg_info *tpa_info =
&fp->tpa_info[i];
struct sw_rx_bd *first_buf =
@@ -1041,7 +1039,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
bnx2x_free_rx_sge_range(bp, fp,
ring_prod);
bnx2x_free_tpa_pool(bp, fp,
- max_agg_queues);
+ MAX_AGG_QS(bp));
fp->disable_tpa = 1;
ring_prod = 0;
break;
@@ -1137,9 +1135,7 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp)
bnx2x_free_rx_bds(fp);
if (!fp->disable_tpa)
- bnx2x_free_tpa_pool(bp, fp, CHIP_IS_E1(bp) ?
- ETH_MAX_AGGREGATION_QUEUES_E1 :
- ETH_MAX_AGGREGATION_QUEUES_E1H_E2);
+ bnx2x_free_tpa_pool(bp, fp, MAX_AGG_QS(bp));
}
}
@@ -3095,15 +3091,20 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index)
struct bnx2x_fastpath *fp = &bp->fp[index];
int ring_size = 0;
u8 cos;
+ int rx_ring_size = 0;
/* if rx_ring_size specified - use it */
- int rx_ring_size = bp->rx_ring_size ? bp->rx_ring_size :
- MAX_RX_AVAIL/BNX2X_NUM_RX_QUEUES(bp);
+ if (!bp->rx_ring_size) {
- /* allocate at least number of buffers required by FW */
- rx_ring_size = max_t(int, bp->disable_tpa ? MIN_RX_SIZE_NONTPA :
- MIN_RX_SIZE_TPA,
- rx_ring_size);
+ rx_ring_size = MAX_RX_AVAIL/BNX2X_NUM_RX_QUEUES(bp);
+
+ /* allocate at least number of buffers required by FW */
+ rx_ring_size = max_t(int, bp->disable_tpa ? MIN_RX_SIZE_NONTPA :
+ MIN_RX_SIZE_TPA, rx_ring_size);
+
+ bp->rx_ring_size = rx_ring_size;
+ } else
+ rx_ring_size = bp->rx_ring_size;
/* Common */
sb = &bnx2x_fp(bp, index, status_blk);
diff --git a/drivers/net/bnx2x/bnx2x_dcb.c b/drivers/net/bnx2x/bnx2x_dcb.c
index a1e004a..0b4acf6 100644
--- a/drivers/net/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/bnx2x/bnx2x_dcb.c
@@ -2120,6 +2120,7 @@ static u8 bnx2x_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap)
break;
case DCB_CAP_ATTR_DCBX:
*cap = BNX2X_DCBX_CAPS;
+ break;
default:
rval = -EINVAL;
break;
diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c
index 2218630..cf3e479 100644
--- a/drivers/net/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/bnx2x/bnx2x_ethtool.c
@@ -363,13 +363,50 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
}
/* advertise the requested speed and duplex if supported */
- cmd->advertising &= bp->port.supported[cfg_idx];
+ if (cmd->advertising & ~(bp->port.supported[cfg_idx])) {
+ DP(NETIF_MSG_LINK, "Advertisement parameters "
+ "are not supported\n");
+ return -EINVAL;
+ }
bp->link_params.req_line_speed[cfg_idx] = SPEED_AUTO_NEG;
- bp->link_params.req_duplex[cfg_idx] = DUPLEX_FULL;
- bp->port.advertising[cfg_idx] |= (ADVERTISED_Autoneg |
+ bp->link_params.req_duplex[cfg_idx] = cmd->duplex;
+ bp->port.advertising[cfg_idx] = (ADVERTISED_Autoneg |
cmd->advertising);
+ if (cmd->advertising) {
+
+ bp->link_params.speed_cap_mask[cfg_idx] = 0;
+ if (cmd->advertising & ADVERTISED_10baseT_Half) {
+ bp->link_params.speed_cap_mask[cfg_idx] |=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF;
+ }
+ if (cmd->advertising & ADVERTISED_10baseT_Full)
+ bp->link_params.speed_cap_mask[cfg_idx] |=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL;
+ if (cmd->advertising & ADVERTISED_100baseT_Full)
+ bp->link_params.speed_cap_mask[cfg_idx] |=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL;
+
+ if (cmd->advertising & ADVERTISED_100baseT_Half) {
+ bp->link_params.speed_cap_mask[cfg_idx] |=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF;
+ }
+ if (cmd->advertising & ADVERTISED_1000baseT_Half) {
+ bp->link_params.speed_cap_mask[cfg_idx] |=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_1G;
+ }
+ if (cmd->advertising & (ADVERTISED_1000baseT_Full |
+ ADVERTISED_1000baseKX_Full))
+ bp->link_params.speed_cap_mask[cfg_idx] |=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_1G;
+
+ if (cmd->advertising & (ADVERTISED_10000baseT_Full |
+ ADVERTISED_10000baseKX4_Full |
+ ADVERTISED_10000baseKR_Full))
+ bp->link_params.speed_cap_mask[cfg_idx] |=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_10G;
+ }
} else { /* forced speed */
/* advertise the requested speed and duplex if supported */
switch (speed) {
@@ -1310,10 +1347,7 @@ static void bnx2x_get_ringparam(struct net_device *dev,
if (bp->rx_ring_size)
ering->rx_pending = bp->rx_ring_size;
else
- if (bp->state == BNX2X_STATE_OPEN && bp->num_queues)
- ering->rx_pending = MAX_RX_AVAIL/bp->num_queues;
- else
- ering->rx_pending = MAX_RX_AVAIL;
+ ering->rx_pending = MAX_RX_AVAIL;
ering->rx_mini_pending = 0;
ering->rx_jumbo_pending = 0;
diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c
index d45b155..ba15bdc 100644
--- a/drivers/net/bnx2x/bnx2x_link.c
+++ b/drivers/net/bnx2x/bnx2x_link.c
@@ -778,9 +778,9 @@ static int bnx2x_ets_e3b0_set_cos_bw(struct bnx2x *bp,
{
u32 nig_reg_adress_crd_weight = 0;
u32 pbf_reg_adress_crd_weight = 0;
- /* Calculate and set BW for this COS*/
- const u32 cos_bw_nig = (bw * min_w_val_nig) / total_bw;
- const u32 cos_bw_pbf = (bw * min_w_val_pbf) / total_bw;
+ /* Calculate and set BW for this COS - use 1 instead of 0 for BW */
+ const u32 cos_bw_nig = ((bw ? bw : 1) * min_w_val_nig) / total_bw;
+ const u32 cos_bw_pbf = ((bw ? bw : 1) * min_w_val_pbf) / total_bw;
switch (cos_entry) {
case 0:
@@ -852,18 +852,12 @@ static int bnx2x_ets_e3b0_get_total_bw(
/* Calculate total BW requested */
for (cos_idx = 0; cos_idx < ets_params->num_of_cos; cos_idx++) {
if (bnx2x_cos_state_bw == ets_params->cos[cos_idx].state) {
-
- if (0 == ets_params->cos[cos_idx].params.bw_params.bw) {
- DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config BW"
- "was set to 0\n");
- return -EINVAL;
+ *total_bw +=
+ ets_params->cos[cos_idx].params.bw_params.bw;
}
- *total_bw +=
- ets_params->cos[cos_idx].params.bw_params.bw;
- }
}
- /*Check taotl BW is valid */
+ /* Check total BW is valid */
if ((100 != *total_bw) || (0 == *total_bw)) {
if (0 == *total_bw) {
DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config toatl BW"
@@ -1726,7 +1720,7 @@ static int bnx2x_xmac_enable(struct link_params *params,
/* Check loopback mode */
if (lb)
- val |= XMAC_CTRL_REG_CORE_LOCAL_LPBK;
+ val |= XMAC_CTRL_REG_LINE_LOCAL_LPBK;
REG_WR(bp, xmac_base + XMAC_REG_CTRL, val);
bnx2x_set_xumac_nig(params,
((vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) != 0), 1);
@@ -3630,6 +3624,12 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, val16);
+ /* Advertised and set FEC (Forward Error Correction) */
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+ MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT2,
+ (MDIO_WC_REG_AN_IEEE1BLK_AN_ADV2_FEC_ABILITY |
+ MDIO_WC_REG_AN_IEEE1BLK_AN_ADV2_FEC_REQ));
+
/* Enable CL37 BAM */
if (REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region, dev_info.
@@ -5924,7 +5924,7 @@ int bnx2x_set_led(struct link_params *params,
(tmp | EMAC_LED_OVERRIDE));
/*
* return here without enabling traffic
- * LED blink andsetting rate in ON mode.
+ * LED blink and setting rate in ON mode.
* In oper mode, enabling LED blink
* and setting rate is needed.
*/
@@ -5936,7 +5936,11 @@ int bnx2x_set_led(struct link_params *params,
* This is a work-around for HW issue found when link
* is up in CL73
*/
- REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
+ if ((!CHIP_IS_E3(bp)) ||
+ (CHIP_IS_E3(bp) &&
+ mode == LED_MODE_ON))
+ REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
+
if (CHIP_IS_E1x(bp) ||
CHIP_IS_E2(bp) ||
(mode == LED_MODE_ON))
@@ -10638,8 +10642,7 @@ static struct bnx2x_phy phy_warpcore = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
.addr = 0xff,
.def_md_devad = 0,
- .flags = (FLAGS_HW_LOCK_REQUIRED |
- FLAGS_TX_ERROR_CHECK),
+ .flags = FLAGS_HW_LOCK_REQUIRED,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
@@ -10765,8 +10768,7 @@ static struct bnx2x_phy phy_8706 = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
.addr = 0xff,
.def_md_devad = 0,
- .flags = (FLAGS_INIT_XGXS_FIRST |
- FLAGS_TX_ERROR_CHECK),
+ .flags = FLAGS_INIT_XGXS_FIRST,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
@@ -10797,8 +10799,7 @@ static struct bnx2x_phy phy_8726 = {
.addr = 0xff,
.def_md_devad = 0,
.flags = (FLAGS_HW_LOCK_REQUIRED |
- FLAGS_INIT_XGXS_FIRST |
- FLAGS_TX_ERROR_CHECK),
+ FLAGS_INIT_XGXS_FIRST),
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
@@ -10829,8 +10830,7 @@ static struct bnx2x_phy phy_8727 = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
.addr = 0xff,
.def_md_devad = 0,
- .flags = (FLAGS_FAN_FAILURE_DET_REQ |
- FLAGS_TX_ERROR_CHECK),
+ .flags = FLAGS_FAN_FAILURE_DET_REQ,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c
index f74582a..15f8000 100644
--- a/drivers/net/bnx2x/bnx2x_main.c
+++ b/drivers/net/bnx2x/bnx2x_main.c
@@ -407,8 +407,8 @@ u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
opcode |= (DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET);
opcode |= (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0);
- opcode |= ((BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT) |
- (BP_E1HVN(bp) << DMAE_COMMAND_DST_VN_SHIFT));
+ opcode |= ((BP_VN(bp) << DMAE_CMD_E1HVN_SHIFT) |
+ (BP_VN(bp) << DMAE_COMMAND_DST_VN_SHIFT));
opcode |= (DMAE_COM_SET_ERR << DMAE_COMMAND_ERR_POLICY_SHIFT);
#ifdef __BIG_ENDIAN
@@ -1419,7 +1419,7 @@ static void bnx2x_hc_int_enable(struct bnx2x *bp)
if (!CHIP_IS_E1(bp)) {
/* init leading/trailing edge */
if (IS_MF(bp)) {
- val = (0xee0f | (1 << (BP_E1HVN(bp) + 4)));
+ val = (0xee0f | (1 << (BP_VN(bp) + 4)));
if (bp->port.pmf)
/* enable nig and gpio3 attention */
val |= 0x1100;
@@ -1471,7 +1471,7 @@ static void bnx2x_igu_int_enable(struct bnx2x *bp)
/* init leading/trailing edge */
if (IS_MF(bp)) {
- val = (0xee0f | (1 << (BP_E1HVN(bp) + 4)));
+ val = (0xee0f | (1 << (BP_VN(bp) + 4)));
if (bp->port.pmf)
/* enable nig and gpio3 attention */
val |= 0x1100;
@@ -2287,7 +2287,7 @@ static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
int vn;
bp->vn_weight_sum = 0;
- for (vn = VN_0; vn < E1HVN_MAX; vn++) {
+ for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
u32 vn_cfg = bp->mf_config[vn];
u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
@@ -2320,12 +2320,18 @@ static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
}
+/* returns func by VN for current port */
+static inline int func_by_vn(struct bnx2x *bp, int vn)
+{
+ return 2 * vn + BP_PORT(bp);
+}
+
static void bnx2x_init_vn_minmax(struct bnx2x *bp, int vn)
{
struct rate_shaping_vars_per_vn m_rs_vn;
struct fairness_vars_per_vn m_fair_vn;
u32 vn_cfg = bp->mf_config[vn];
- int func = 2*vn + BP_PORT(bp);
+ int func = func_by_vn(bp, vn);
u16 vn_min_rate, vn_max_rate;
int i;
@@ -2422,7 +2428,7 @@ void bnx2x_read_mf_cfg(struct bnx2x *bp)
*
* and there are 2 functions per port
*/
- for (vn = VN_0; vn < E1HVN_MAX; vn++) {
+ for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
int /*abs*/func = n * (2 * vn + BP_PORT(bp)) + BP_PATH(bp);
if (func >= E1H_FUNC_MAX)
@@ -2454,7 +2460,7 @@ static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type)
/* calculate and set min-max rate for each vn */
if (bp->port.pmf)
- for (vn = VN_0; vn < E1HVN_MAX; vn++)
+ for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++)
bnx2x_init_vn_minmax(bp, vn);
/* always enable rate shaping and fairness */
@@ -2473,16 +2479,15 @@ static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type)
static inline void bnx2x_link_sync_notify(struct bnx2x *bp)
{
- int port = BP_PORT(bp);
int func;
int vn;
/* Set the attention towards other drivers on the same port */
- for (vn = VN_0; vn < E1HVN_MAX; vn++) {
- if (vn == BP_E1HVN(bp))
+ for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
+ if (vn == BP_VN(bp))
continue;
- func = ((vn << 1) | port);
+ func = func_by_vn(bp, vn);
REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
(LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
}
@@ -2577,7 +2582,7 @@ static void bnx2x_pmf_update(struct bnx2x *bp)
bnx2x_dcbx_pmf_update(bp);
/* enable nig attention */
- val = (0xff0f | (1 << (BP_E1HVN(bp) + 4)));
+ val = (0xff0f | (1 << (BP_VN(bp) + 4)));
if (bp->common.int_block == INT_BLOCK_HC) {
REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
@@ -2756,8 +2761,14 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
u16 tpa_agg_size = 0;
if (!fp->disable_tpa) {
- pause->sge_th_hi = 250;
- pause->sge_th_lo = 150;
+ pause->sge_th_lo = SGE_TH_LO(bp);
+ pause->sge_th_hi = SGE_TH_HI(bp);
+
+ /* validate SGE ring has enough to cross high threshold */
+ WARN_ON(bp->dropless_fc &&
+ pause->sge_th_hi + FW_PREFETCH_CNT >
+ MAX_RX_SGE_CNT * NUM_RX_SGE_PAGES);
+
tpa_agg_size = min_t(u32,
(min_t(u32, 8, MAX_SKB_FRAGS) *
SGE_PAGE_SIZE * PAGES_PER_SGE), 0xffff);
@@ -2771,10 +2782,21 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
/* pause - not for e1 */
if (!CHIP_IS_E1(bp)) {
- pause->bd_th_hi = 350;
- pause->bd_th_lo = 250;
- pause->rcq_th_hi = 350;
- pause->rcq_th_lo = 250;
+ pause->bd_th_lo = BD_TH_LO(bp);
+ pause->bd_th_hi = BD_TH_HI(bp);
+
+ pause->rcq_th_lo = RCQ_TH_LO(bp);
+ pause->rcq_th_hi = RCQ_TH_HI(bp);
+ /*
+ * validate that rings have enough entries to cross
+ * high thresholds
+ */
+ WARN_ON(bp->dropless_fc &&
+ pause->bd_th_hi + FW_PREFETCH_CNT >
+ bp->rx_ring_size);
+ WARN_ON(bp->dropless_fc &&
+ pause->rcq_th_hi + FW_PREFETCH_CNT >
+ NUM_RCQ_RINGS * MAX_RCQ_DESC_CNT);
pause->pri_map = 1;
}
@@ -2802,9 +2824,7 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
* For PF Clients it should be the maximum avaliable number.
* VF driver(s) may want to define it to a smaller value.
*/
- rxq_init->max_tpa_queues =
- (CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 :
- ETH_MAX_AGGREGATION_QUEUES_E1H_E2);
+ rxq_init->max_tpa_queues = MAX_AGG_QS(bp);
rxq_init->cache_line_log = BNX2X_RX_ALIGN_SHIFT;
rxq_init->fw_sb_id = fp->fw_sb_id;
@@ -4808,6 +4828,37 @@ void bnx2x_setup_ndsb_state_machine(struct hc_status_block_sm *hc_sm,
hc_sm->time_to_expire = 0xFFFFFFFF;
}
+
+/* allocates state machine ids. */
+static inline
+void bnx2x_map_sb_state_machines(struct hc_index_data *index_data)
+{
+ /* zero out state machine indices */
+ /* rx indices */
+ index_data[HC_INDEX_ETH_RX_CQ_CONS].flags &= ~HC_INDEX_DATA_SM_ID;
+
+ /* tx indices */
+ index_data[HC_INDEX_OOO_TX_CQ_CONS].flags &= ~HC_INDEX_DATA_SM_ID;
+ index_data[HC_INDEX_ETH_TX_CQ_CONS_COS0].flags &= ~HC_INDEX_DATA_SM_ID;
+ index_data[HC_INDEX_ETH_TX_CQ_CONS_COS1].flags &= ~HC_INDEX_DATA_SM_ID;
+ index_data[HC_INDEX_ETH_TX_CQ_CONS_COS2].flags &= ~HC_INDEX_DATA_SM_ID;
+
+ /* map indices */
+ /* rx indices */
+ index_data[HC_INDEX_ETH_RX_CQ_CONS].flags |=
+ SM_RX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
+
+ /* tx indices */
+ index_data[HC_INDEX_OOO_TX_CQ_CONS].flags |=
+ SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
+ index_data[HC_INDEX_ETH_TX_CQ_CONS_COS0].flags |=
+ SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
+ index_data[HC_INDEX_ETH_TX_CQ_CONS_COS1].flags |=
+ SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
+ index_data[HC_INDEX_ETH_TX_CQ_CONS_COS2].flags |=
+ SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
+}
+
static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
u8 vf_valid, int fw_sb_id, int igu_sb_id)
{
@@ -4839,6 +4890,7 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
hc_sm_p = sb_data_e2.common.state_machine;
sb_data_p = (u32 *)&sb_data_e2;
data_size = sizeof(struct hc_status_block_data_e2)/sizeof(u32);
+ bnx2x_map_sb_state_machines(sb_data_e2.index_data);
} else {
memset(&sb_data_e1x, 0,
sizeof(struct hc_status_block_data_e1x));
@@ -4853,6 +4905,7 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
hc_sm_p = sb_data_e1x.common.state_machine;
sb_data_p = (u32 *)&sb_data_e1x;
data_size = sizeof(struct hc_status_block_data_e1x)/sizeof(u32);
+ bnx2x_map_sb_state_machines(sb_data_e1x.index_data);
}
bnx2x_setup_ndsb_state_machine(&hc_sm_p[SM_RX_ID],
@@ -4890,7 +4943,7 @@ static void bnx2x_init_def_sb(struct bnx2x *bp)
int igu_seg_id;
int port = BP_PORT(bp);
int func = BP_FUNC(bp);
- int reg_offset;
+ int reg_offset, reg_offset_en5;
u64 section;
int index;
struct hc_sp_status_block_data sp_sb_data;
@@ -4913,6 +4966,8 @@ static void bnx2x_init_def_sb(struct bnx2x *bp)
reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+ reg_offset_en5 = (port ? MISC_REG_AEU_ENABLE5_FUNC_1_OUT_0 :
+ MISC_REG_AEU_ENABLE5_FUNC_0_OUT_0);
for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
int sindex;
/* take care of sig[0]..sig[4] */
@@ -4927,7 +4982,7 @@ static void bnx2x_init_def_sb(struct bnx2x *bp)
* and not 16 between the different groups
*/
bp->attn_group[index].sig[4] = REG_RD(bp,
- reg_offset + 0x10 + 0x4*index);
+ reg_offset_en5 + 0x4*index);
else
bp->attn_group[index].sig[4] = 0;
}
@@ -5802,7 +5857,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
* take the UNDI lock to protect undi_unload flow from accessing
* registers while we're resetting the chip
*/
- bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
+ bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
bnx2x_reset_common(bp);
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0xffffffff);
@@ -5814,7 +5869,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
}
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, val);
- bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
+ bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
bnx2x_init_block(bp, BLOCK_MISC, PHASE_COMMON);
@@ -6671,12 +6726,16 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
if (CHIP_MODE_IS_4_PORT(bp))
dsb_idx = BP_FUNC(bp);
else
- dsb_idx = BP_E1HVN(bp);
+ dsb_idx = BP_VN(bp);
prod_offset = (CHIP_INT_MODE_IS_BC(bp) ?
IGU_BC_BASE_DSB_PROD + dsb_idx :
IGU_NORM_BASE_DSB_PROD + dsb_idx);
+ /*
+ * igu prods come in chunks of E1HVN_MAX (4) -
+ * does not matters what is the current chip mode
+ */
for (i = 0; i < (num_segs * E1HVN_MAX);
i += E1HVN_MAX) {
addr = IGU_REG_PROD_CONS_MEMORY +
@@ -7568,9 +7627,12 @@ u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode)
u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
u8 *mac_addr = bp->dev->dev_addr;
u32 val;
+ u16 pmc;
+
/* The mac address is written to entries 1-4 to
- preserve entry 0 which is used by the PMF */
- u8 entry = (BP_E1HVN(bp) + 1)*8;
+ * preserve entry 0 which is used by the PMF
+ */
+ u8 entry = (BP_VN(bp) + 1)*8;
val = (mac_addr[0] << 8) | mac_addr[1];
EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + entry, val);
@@ -7579,6 +7641,11 @@ u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode)
(mac_addr[4] << 8) | mac_addr[5];
EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + entry + 4, val);
+ /* Enable the PME and clear the status */
+ pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmc);
+ pmc |= PCI_PM_CTRL_PME_ENABLE | PCI_PM_CTRL_PME_STATUS;
+ pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, pmc);
+
reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_EN;
} else
@@ -8546,10 +8613,12 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
/* Check if there is any driver already loaded */
val = REG_RD(bp, MISC_REG_UNPREPARED);
if (val == 0x1) {
- /* Check if it is the UNDI driver
+
+ bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
+ /*
+ * Check if it is the UNDI driver
* UNDI driver initializes CID offset for normal bell to 0x7
*/
- bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
val = REG_RD(bp, DORQ_REG_NORM_CID_OFST);
if (val == 0x7) {
u32 reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
@@ -8587,9 +8656,6 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
bnx2x_fw_command(bp, reset_code, 0);
}
- /* now it's safe to release the lock */
- bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
-
bnx2x_undi_int_disable(bp);
port = BP_PORT(bp);
@@ -8639,8 +8705,10 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
bp->fw_seq =
(SHMEM_RD(bp, func_mb[bp->pf_num].drv_mb_header) &
DRV_MSG_SEQ_NUMBER_MASK);
- } else
- bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
+ }
+
+ /* now it's safe to release the lock */
+ bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
}
}
@@ -8777,13 +8845,13 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
static void __devinit bnx2x_get_igu_cam_info(struct bnx2x *bp)
{
int pfid = BP_FUNC(bp);
- int vn = BP_E1HVN(bp);
int igu_sb_id;
u32 val;
u8 fid, igu_sb_cnt = 0;
bp->igu_base_sb = 0xff;
if (CHIP_INT_MODE_IS_BC(bp)) {
+ int vn = BP_VN(bp);
igu_sb_cnt = bp->igu_sb_cnt;
bp->igu_base_sb = (CHIP_MODE_IS_4_PORT(bp) ? pfid : vn) *
FP_SB_MAX_E1x;
@@ -9416,6 +9484,10 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
bp->igu_base_sb = 0;
} else {
bp->common.int_block = INT_BLOCK_IGU;
+
+ /* do not allow device reset during IGU info preocessing */
+ bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
+
val = REG_RD(bp, IGU_REG_BLOCK_CONFIGURATION);
if (val & IGU_BLOCK_CONFIGURATION_REG_BACKWARD_COMP_EN) {
@@ -9447,6 +9519,7 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
bnx2x_get_igu_cam_info(bp);
+ bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
}
/*
@@ -9473,7 +9546,7 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
bp->mf_ov = 0;
bp->mf_mode = 0;
- vn = BP_E1HVN(bp);
+ vn = BP_VN(bp);
if (!CHIP_IS_E1(bp) && !BP_NOMCP(bp)) {
BNX2X_DEV_INFO("shmem2base 0x%x, size %d, mfcfg offset %d\n",
@@ -9593,13 +9666,6 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
/* port info */
bnx2x_get_port_hwinfo(bp);
- if (!BP_NOMCP(bp)) {
- bp->fw_seq =
- (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
- DRV_MSG_SEQ_NUMBER_MASK);
- BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
- }
-
/* Get MAC addresses */
bnx2x_get_mac_hwinfo(bp);
@@ -9765,6 +9831,14 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
if (!BP_NOMCP(bp))
bnx2x_undi_unload(bp);
+ /* init fw_seq after undi_unload! */
+ if (!BP_NOMCP(bp)) {
+ bp->fw_seq =
+ (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
+ DRV_MSG_SEQ_NUMBER_MASK);
+ BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
+ }
+
if (CHIP_REV_IS_FPGA(bp))
dev_err(&bp->pdev->dev, "FPGA detected\n");
@@ -10259,17 +10333,21 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
/* clean indirect addresses */
pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
PCICFG_VENDOR_ID_OFFSET);
- /* Clean the following indirect addresses for all functions since it
+ /*
+ * Clean the following indirect addresses for all functions since it
* is not used by the driver.
*/
REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0, 0);
REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0, 0);
REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0);
REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0);
- REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0);
- REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0);
- REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0);
- REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0);
+
+ if (CHIP_IS_E1x(bp)) {
+ REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0);
+ REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0);
+ REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0);
+ REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0);
+ }
/*
* Enable internal target-read (in case we are probed after PF FLR).
diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h
index 40266c1..fc7bd0f 100644
--- a/drivers/net/bnx2x/bnx2x_reg.h
+++ b/drivers/net/bnx2x/bnx2x_reg.h
@@ -1384,6 +1384,18 @@
Latched ump_tx_parity; [31] MCP Latched scpad_parity; */
#define MISC_REG_AEU_ENABLE4_PXP_0 0xa108
#define MISC_REG_AEU_ENABLE4_PXP_1 0xa1a8
+/* [RW 32] fifth 32b for enabling the output for function 0 output0. Mapped
+ * as follows: [0] PGLUE config_space; [1] PGLUE misc_flr; [2] PGLUE B RBC
+ * attention [3] PGLUE B RBC parity; [4] ATC attention; [5] ATC parity; [6]
+ * mstat0 attention; [7] mstat0 parity; [8] mstat1 attention; [9] mstat1
+ * parity; [31-10] Reserved; */
+#define MISC_REG_AEU_ENABLE5_FUNC_0_OUT_0 0xa688
+/* [RW 32] Fifth 32b for enabling the output for function 1 output0. Mapped
+ * as follows: [0] PGLUE config_space; [1] PGLUE misc_flr; [2] PGLUE B RBC
+ * attention [3] PGLUE B RBC parity; [4] ATC attention; [5] ATC parity; [6]
+ * mstat0 attention; [7] mstat0 parity; [8] mstat1 attention; [9] mstat1
+ * parity; [31-10] Reserved; */
+#define MISC_REG_AEU_ENABLE5_FUNC_1_OUT_0 0xa6b0
/* [RW 1] set/clr general attention 0; this will set/clr bit 94 in the aeu
128 bit vector */
#define MISC_REG_AEU_GENERAL_ATTN_0 0xa000
@@ -5320,7 +5332,7 @@
#define XCM_REG_XX_OVFL_EVNT_ID 0x20058
#define XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_LOCAL_FAULT_STATUS (0x1<<0)
#define XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_REMOTE_FAULT_STATUS (0x1<<1)
-#define XMAC_CTRL_REG_CORE_LOCAL_LPBK (0x1<<3)
+#define XMAC_CTRL_REG_LINE_LOCAL_LPBK (0x1<<2)
#define XMAC_CTRL_REG_RX_EN (0x1<<1)
#define XMAC_CTRL_REG_SOFT_RESET (0x1<<6)
#define XMAC_CTRL_REG_TX_EN (0x1<<0)
@@ -5766,7 +5778,7 @@
#define HW_LOCK_RESOURCE_RECOVERY_LEADER_0 8
#define HW_LOCK_RESOURCE_RECOVERY_LEADER_1 9
#define HW_LOCK_RESOURCE_SPIO 2
-#define HW_LOCK_RESOURCE_UNDI 5
+#define HW_LOCK_RESOURCE_RESET 5
#define AEU_INPUTS_ATTN_BITS_ATC_HW_INTERRUPT (0x1<<4)
#define AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR (0x1<<5)
#define AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR (0x1<<18)
@@ -6853,6 +6865,9 @@ Theotherbitsarereservedandshouldbezero*/
#define MDIO_WC_REG_IEEE0BLK_AUTONEGNP 0x7
#define MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT0 0x10
#define MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1 0x11
+#define MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT2 0x12
+#define MDIO_WC_REG_AN_IEEE1BLK_AN_ADV2_FEC_ABILITY 0x4000
+#define MDIO_WC_REG_AN_IEEE1BLK_AN_ADV2_FEC_REQ 0x8000
#define MDIO_WC_REG_PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150 0x96
#define MDIO_WC_REG_XGXSBLK0_XGXSCONTROL 0x8000
#define MDIO_WC_REG_XGXSBLK0_MISCCONTROL1 0x800e
diff --git a/drivers/net/bnx2x/bnx2x_stats.c b/drivers/net/bnx2x/bnx2x_stats.c
index 771f680..9908f2bb 100644
--- a/drivers/net/bnx2x/bnx2x_stats.c
+++ b/drivers/net/bnx2x/bnx2x_stats.c
@@ -710,7 +710,8 @@ static int bnx2x_hw_stats_update(struct bnx2x *bp)
break;
case MAC_TYPE_NONE: /* unreached */
- BNX2X_ERR("stats updated by DMAE but no MAC active\n");
+ DP(BNX2X_MSG_STATS,
+ "stats updated by DMAE but no MAC active\n");
return -1;
default: /* unreached */
@@ -1391,7 +1392,7 @@ static void bnx2x_port_stats_base_init(struct bnx2x *bp)
static void bnx2x_func_stats_base_init(struct bnx2x *bp)
{
- int vn, vn_max = IS_MF(bp) ? E1HVN_MAX : E1VN_MAX;
+ int vn, vn_max = IS_MF(bp) ? BP_MAX_VN_NUM(bp) : E1VN_MAX;
u32 func_stx;
/* sanity */
@@ -1404,7 +1405,7 @@ static void bnx2x_func_stats_base_init(struct bnx2x *bp)
func_stx = bp->func_stx;
for (vn = VN_0; vn < vn_max; vn++) {
- int mb_idx = CHIP_IS_E1x(bp) ? 2*vn + BP_PORT(bp) : vn;
+ int mb_idx = BP_FW_MB_IDX_VN(bp, vn);
bp->func_stx = SHMEM_RD(bp, func_mb[mb_idx].fw_mb_param);
bnx2x_func_stats_init(bp);
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index a047eb9..47b928e 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2168,7 +2168,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
}
re_arm:
- queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
+ if (!bond->kill_timers)
+ queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
out:
read_unlock(&bond->lock);
}
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 7f8b20a3..d4fbd2e 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -1440,7 +1440,8 @@ void bond_alb_monitor(struct work_struct *work)
}
re_arm:
- queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks);
+ if (!bond->kill_timers)
+ queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks);
out:
read_unlock(&bond->lock);
}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 43f2ea5..6d79b78 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -777,6 +777,9 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
read_lock(&bond->lock);
+ if (bond->kill_timers)
+ goto out;
+
/* rejoin all groups on bond device */
__bond_resend_igmp_join_requests(bond->dev);
@@ -790,9 +793,9 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
__bond_resend_igmp_join_requests(vlan_dev);
}
- if (--bond->igmp_retrans > 0)
+ if ((--bond->igmp_retrans > 0) && !bond->kill_timers)
queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5);
-
+out:
read_unlock(&bond->lock);
}
@@ -2538,7 +2541,7 @@ void bond_mii_monitor(struct work_struct *work)
}
re_arm:
- if (bond->params.miimon)
+ if (bond->params.miimon && !bond->kill_timers)
queue_delayed_work(bond->wq, &bond->mii_work,
msecs_to_jiffies(bond->params.miimon));
out:
@@ -2886,7 +2889,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
}
re_arm:
- if (bond->params.arp_interval)
+ if (bond->params.arp_interval && !bond->kill_timers)
queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
out:
read_unlock(&bond->lock);
@@ -3154,7 +3157,7 @@ void bond_activebackup_arp_mon(struct work_struct *work)
bond_ab_arp_probe(bond);
re_arm:
- if (bond->params.arp_interval)
+ if (bond->params.arp_interval && !bond->kill_timers)
queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
out:
read_unlock(&bond->lock);
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index a812492..2adc294 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -46,6 +46,7 @@
#include <linux/skbuff.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/io.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index 805076c..da5a5d9 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -1146,12 +1146,14 @@ static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
if (te && te->ctx && te->client && te->client->redirect) {
update_tcb = te->client->redirect(te->ctx, old, new, e);
if (update_tcb) {
+ rcu_read_lock();
l2t_hold(L2DATA(tdev), e);
+ rcu_read_unlock();
set_l2t_ix(tdev, tid, e);
}
}
}
- l2t_release(L2DATA(tdev), e);
+ l2t_release(tdev, e);
}
/*
@@ -1264,7 +1266,7 @@ int cxgb3_offload_activate(struct adapter *adapter)
goto out_free;
err = -ENOMEM;
- L2DATA(dev) = t3_init_l2t(l2t_capacity);
+ RCU_INIT_POINTER(dev->l2opt, t3_init_l2t(l2t_capacity));
if (!L2DATA(dev))
goto out_free;
@@ -1298,16 +1300,24 @@ int cxgb3_offload_activate(struct adapter *adapter)
out_free_l2t:
t3_free_l2t(L2DATA(dev));
- L2DATA(dev) = NULL;
+ rcu_assign_pointer(dev->l2opt, NULL);
out_free:
kfree(t);
return err;
}
+static void clean_l2_data(struct rcu_head *head)
+{
+ struct l2t_data *d = container_of(head, struct l2t_data, rcu_head);
+ t3_free_l2t(d);
+}
+
+
void cxgb3_offload_deactivate(struct adapter *adapter)
{
struct t3cdev *tdev = &adapter->tdev;
struct t3c_data *t = T3C_DATA(tdev);
+ struct l2t_data *d;
remove_adapter(adapter);
if (list_empty(&adapter_list))
@@ -1315,8 +1325,11 @@ void cxgb3_offload_deactivate(struct adapter *adapter)
free_tid_maps(&t->tid_maps);
T3C_DATA(tdev) = NULL;
- t3_free_l2t(L2DATA(tdev));
- L2DATA(tdev) = NULL;
+ rcu_read_lock();
+ d = L2DATA(tdev);
+ rcu_read_unlock();
+ rcu_assign_pointer(tdev->l2opt, NULL);
+ call_rcu(&d->rcu_head, clean_l2_data);
if (t->nofail_skb)
kfree_skb(t->nofail_skb);
kfree(t);
diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c
index f452c40..4154097 100644
--- a/drivers/net/cxgb3/l2t.c
+++ b/drivers/net/cxgb3/l2t.c
@@ -300,14 +300,21 @@ static inline void reuse_entry(struct l2t_entry *e, struct neighbour *neigh)
struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
struct net_device *dev)
{
- struct l2t_entry *e;
- struct l2t_data *d = L2DATA(cdev);
+ struct l2t_entry *e = NULL;
+ struct l2t_data *d;
+ int hash;
u32 addr = *(u32 *) neigh->primary_key;
int ifidx = neigh->dev->ifindex;
- int hash = arp_hash(addr, ifidx, d);
struct port_info *p = netdev_priv(dev);
int smt_idx = p->port_id;
+ rcu_read_lock();
+ d = L2DATA(cdev);
+ if (!d)
+ goto done_rcu;
+
+ hash = arp_hash(addr, ifidx, d);
+
write_lock_bh(&d->lock);
for (e = d->l2tab[hash].first; e; e = e->next)
if (e->addr == addr && e->ifindex == ifidx &&
@@ -338,6 +345,8 @@ struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
}
done:
write_unlock_bh(&d->lock);
+done_rcu:
+ rcu_read_unlock();
return e;
}
diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h
index 7a12d52e..c5f5479 100644
--- a/drivers/net/cxgb3/l2t.h
+++ b/drivers/net/cxgb3/l2t.h
@@ -76,6 +76,7 @@ struct l2t_data {
atomic_t nfree; /* number of free entries */
rwlock_t lock;
struct l2t_entry l2tab[0];
+ struct rcu_head rcu_head; /* to handle rcu cleanup */
};
typedef void (*arp_failure_handler_func)(struct t3cdev * dev,
@@ -99,7 +100,7 @@ static inline void set_arp_failure_handler(struct sk_buff *skb,
/*
* Getting to the L2 data from an offload device.
*/
-#define L2DATA(dev) ((dev)->l2opt)
+#define L2DATA(cdev) (rcu_dereference((cdev)->l2opt))
#define W_TCB_L2T_IX 0
#define S_TCB_L2T_IX 7
@@ -126,15 +127,22 @@ static inline int l2t_send(struct t3cdev *dev, struct sk_buff *skb,
return t3_l2t_send_slow(dev, skb, e);
}
-static inline void l2t_release(struct l2t_data *d, struct l2t_entry *e)
+static inline void l2t_release(struct t3cdev *t, struct l2t_entry *e)
{
- if (atomic_dec_and_test(&e->refcnt))
+ struct l2t_data *d;
+
+ rcu_read_lock();
+ d = L2DATA(t);
+
+ if (atomic_dec_and_test(&e->refcnt) && d)
t3_l2e_free(d, e);
+
+ rcu_read_unlock();
}
static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e)
{
- if (atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */
+ if (d && atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */
atomic_dec(&d->nfree);
}
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index c9957b7..b4efa29 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -3712,6 +3712,9 @@ static int __devinit init_one(struct pci_dev *pdev,
setup_debugfs(adapter);
}
+ /* PCIe EEH recovery on powerpc platforms needs fundamental reset */
+ pdev->needs_freset = 1;
+
if (is_offload(adapter))
attach_ulds(adapter);
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 8545c7a..a5a89ec 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -4026,6 +4026,12 @@ s32 e1000_validate_eeprom_checksum(struct e1000_hw *hw)
checksum += eeprom_data;
}
+#ifdef CONFIG_PARISC
+ /* This is a signature and not a checksum on HP c8000 */
+ if ((hw->subsystem_vendor_id == 0x103C) && (eeprom_data == 0x16d6))
+ return E1000_SUCCESS;
+
+#endif
if (checksum == (u16) EEPROM_SUM)
return E1000_SUCCESS;
else {
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 25a8c2a..0caf3c3 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -1669,10 +1669,10 @@ static int gfar_get_cls_all(struct gfar_private *priv,
u32 i = 0;
list_for_each_entry(comp, &priv->rx_list.list, list) {
- if (i <= cmd->rule_cnt) {
- rule_locs[i] = comp->fs.location;
- i++;
- }
+ if (i == cmd->rule_cnt)
+ return -EMSGSIZE;
+ rule_locs[i] = comp->fs.location;
+ i++;
}
cmd->data = MAX_FILER_IDX;
diff --git a/drivers/net/greth.c b/drivers/net/greth.c
index 16ce45c..52a3900 100644
--- a/drivers/net/greth.c
+++ b/drivers/net/greth.c
@@ -428,6 +428,7 @@ greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
dma_sync_single_for_device(greth->dev, dma_addr, skb->len, DMA_TO_DEVICE);
status = GRETH_BD_EN | GRETH_BD_IE | (skb->len & GRETH_BD_LEN);
+ greth->tx_bufs_length[greth->tx_next] = skb->len & GRETH_BD_LEN;
/* Wrap around descriptor ring */
if (greth->tx_next == GRETH_TXBD_NUM_MASK) {
@@ -490,7 +491,8 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
if (nr_frags != 0)
status = GRETH_TXBD_MORE;
- status |= GRETH_TXBD_CSALL;
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ status |= GRETH_TXBD_CSALL;
status |= skb_headlen(skb) & GRETH_BD_LEN;
if (greth->tx_next == GRETH_TXBD_NUM_MASK)
status |= GRETH_BD_WR;
@@ -513,7 +515,9 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
greth->tx_skbuff[curr_tx] = NULL;
bdp = greth->tx_bd_base + curr_tx;
- status = GRETH_TXBD_CSALL | GRETH_BD_EN;
+ status = GRETH_BD_EN;
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ status |= GRETH_TXBD_CSALL;
status |= frag->size & GRETH_BD_LEN;
/* Wrap around descriptor ring */
@@ -641,6 +645,7 @@ static void greth_clean_tx(struct net_device *dev)
dev->stats.tx_fifo_errors++;
}
dev->stats.tx_packets++;
+ dev->stats.tx_bytes += greth->tx_bufs_length[greth->tx_last];
greth->tx_last = NEXT_TX(greth->tx_last);
greth->tx_free++;
}
@@ -695,6 +700,7 @@ static void greth_clean_tx_gbit(struct net_device *dev)
greth->tx_skbuff[greth->tx_last] = NULL;
greth_update_tx_stats(dev, stat);
+ dev->stats.tx_bytes += skb->len;
bdp = greth->tx_bd_base + greth->tx_last;
@@ -796,6 +802,7 @@ static int greth_rx(struct net_device *dev, int limit)
memcpy(skb_put(skb, pkt_len), phys_to_virt(dma_addr), pkt_len);
skb->protocol = eth_type_trans(skb, dev);
+ dev->stats.rx_bytes += pkt_len;
dev->stats.rx_packets++;
netif_receive_skb(skb);
}
@@ -910,6 +917,7 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
skb->protocol = eth_type_trans(skb, dev);
dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
netif_receive_skb(skb);
greth->rx_skbuff[greth->rx_cur] = newskb;
diff --git a/drivers/net/greth.h b/drivers/net/greth.h
index 9a0040d..232a622 100644
--- a/drivers/net/greth.h
+++ b/drivers/net/greth.h
@@ -103,6 +103,7 @@ struct greth_private {
unsigned char *tx_bufs[GRETH_TXBD_NUM];
unsigned char *rx_bufs[GRETH_RXBD_NUM];
+ u16 tx_bufs_length[GRETH_TXBD_NUM];
u16 tx_next;
u16 tx_last;
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 3e66792..d393f1e 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -636,8 +636,8 @@ static int ibmveth_open(struct net_device *netdev)
netdev_err(netdev, "unable to request irq 0x%x, rc %d\n",
netdev->irq, rc);
do {
- rc = h_free_logical_lan(adapter->vdev->unit_address);
- } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY));
+ lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
+ } while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY));
goto err_out;
}
@@ -757,7 +757,7 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data)
struct ibmveth_adapter *adapter = netdev_priv(dev);
unsigned long set_attr, clr_attr, ret_attr;
unsigned long set_attr6, clr_attr6;
- long ret, ret6;
+ long ret, ret4, ret6;
int rc1 = 0, rc2 = 0;
int restart = 0;
@@ -770,6 +770,8 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data)
set_attr = 0;
clr_attr = 0;
+ set_attr6 = 0;
+ clr_attr6 = 0;
if (data) {
set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
@@ -784,16 +786,20 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data)
if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) &&
!(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) &&
(ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) {
- ret = h_illan_attributes(adapter->vdev->unit_address, clr_attr,
+ ret4 = h_illan_attributes(adapter->vdev->unit_address, clr_attr,
set_attr, &ret_attr);
- if (ret != H_SUCCESS) {
+ if (ret4 != H_SUCCESS) {
netdev_err(dev, "unable to change IPv4 checksum "
"offload settings. %d rc=%ld\n",
- data, ret);
+ data, ret4);
+
+ h_illan_attributes(adapter->vdev->unit_address,
+ set_attr, clr_attr, &ret_attr);
+
+ if (data == 1)
+ dev->features &= ~NETIF_F_IP_CSUM;
- ret = h_illan_attributes(adapter->vdev->unit_address,
- set_attr, clr_attr, &ret_attr);
} else {
adapter->fw_ipv4_csum_support = data;
}
@@ -804,15 +810,18 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data)
if (ret6 != H_SUCCESS) {
netdev_err(dev, "unable to change IPv6 checksum "
"offload settings. %d rc=%ld\n",
- data, ret);
+ data, ret6);
+
+ h_illan_attributes(adapter->vdev->unit_address,
+ set_attr6, clr_attr6, &ret_attr);
+
+ if (data == 1)
+ dev->features &= ~NETIF_F_IPV6_CSUM;
- ret = h_illan_attributes(adapter->vdev->unit_address,
- set_attr6, clr_attr6,
- &ret_attr);
} else
adapter->fw_ipv6_csum_support = data;
- if (ret != H_SUCCESS || ret6 != H_SUCCESS)
+ if (ret4 == H_SUCCESS || ret6 == H_SUCCESS)
adapter->rx_csum = data;
else
rc1 = -EIO;
@@ -930,6 +939,7 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb,
union ibmveth_buf_desc descs[6];
int last, i;
int force_bounce = 0;
+ dma_addr_t dma_addr;
/*
* veth handles a maximum of 6 segments including the header, so
@@ -994,17 +1004,16 @@ retry_bounce:
}
/* Map the header */
- descs[0].fields.address = dma_map_single(&adapter->vdev->dev, skb->data,
- skb_headlen(skb),
- DMA_TO_DEVICE);
- if (dma_mapping_error(&adapter->vdev->dev, descs[0].fields.address))
+ dma_addr = dma_map_single(&adapter->vdev->dev, skb->data,
+ skb_headlen(skb), DMA_TO_DEVICE);
+ if (dma_mapping_error(&adapter->vdev->dev, dma_addr))
goto map_failed;
descs[0].fields.flags_len = desc_flags | skb_headlen(skb);
+ descs[0].fields.address = dma_addr;
/* Map the frags */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- unsigned long dma_addr;
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
dma_addr = dma_map_page(&adapter->vdev->dev, frag->page,
@@ -1026,7 +1035,12 @@ retry_bounce:
netdev->stats.tx_bytes += skb->len;
}
- for (i = 0; i < skb_shinfo(skb)->nr_frags + 1; i++)
+ dma_unmap_single(&adapter->vdev->dev,
+ descs[0].fields.address,
+ descs[0].fields.flags_len & IBMVETH_BUF_LEN_MASK,
+ DMA_TO_DEVICE);
+
+ for (i = 1; i < skb_shinfo(skb)->nr_frags + 1; i++)
dma_unmap_page(&adapter->vdev->dev, descs[i].fields.address,
descs[i].fields.flags_len & IBMVETH_BUF_LEN_MASK,
DMA_TO_DEVICE);
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 2279039..e1fcc95 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -1321,8 +1321,8 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
if (ring_is_rsc_enabled(rx_ring))
pkt_is_rsc = ixgbe_get_rsc_state(rx_desc);
- /* if this is a skb from previous receive DMA will be 0 */
- if (rx_buffer_info->dma) {
+ /* linear means we are building an skb from multiple pages */
+ if (!skb_is_nonlinear(skb)) {
u16 hlen;
if (pkt_is_rsc &&
!(staterr & IXGBE_RXD_STAT_EOP) &&
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index dfc8272..ed2a397 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -799,5 +799,11 @@ static void __exit cleanup_netconsole(void)
}
}
-module_init(init_netconsole);
+/*
+ * Use late_initcall to ensure netconsole is
+ * initialized after network device driver if built-in.
+ *
+ * late_initcall() and module_init() are identical if built as module.
+ */
+late_initcall(init_netconsole);
module_exit(cleanup_netconsole);
diff --git a/drivers/net/pch_gbe/pch_gbe.h b/drivers/net/pch_gbe/pch_gbe.h
index 59fac77..a09a0719 100644
--- a/drivers/net/pch_gbe/pch_gbe.h
+++ b/drivers/net/pch_gbe/pch_gbe.h
@@ -127,8 +127,8 @@ struct pch_gbe_regs {
/* Reset */
#define PCH_GBE_ALL_RST 0x80000000 /* All reset */
-#define PCH_GBE_TX_RST 0x40000000 /* TX MAC, TX FIFO, TX DMA reset */
-#define PCH_GBE_RX_RST 0x04000000 /* RX MAC, RX FIFO, RX DMA reset */
+#define PCH_GBE_TX_RST 0x00008000 /* TX MAC, TX FIFO, TX DMA reset */
+#define PCH_GBE_RX_RST 0x00004000 /* RX MAC, RX FIFO, RX DMA reset */
/* TCP/IP Accelerator Control */
#define PCH_GBE_EX_LIST_EN 0x00000008 /* External List Enable */
@@ -276,6 +276,9 @@ struct pch_gbe_regs {
#define PCH_GBE_RX_DMA_EN 0x00000002 /* Enables Receive DMA */
#define PCH_GBE_TX_DMA_EN 0x00000001 /* Enables Transmission DMA */
+/* RX DMA STATUS */
+#define PCH_GBE_IDLE_CHECK 0xFFFFFFFE
+
/* Wake On LAN Status */
#define PCH_GBE_WLS_BR 0x00000008 /* Broadcas Address */
#define PCH_GBE_WLS_MLT 0x00000004 /* Multicast Address */
@@ -471,6 +474,7 @@ struct pch_gbe_tx_desc {
struct pch_gbe_buffer {
struct sk_buff *skb;
dma_addr_t dma;
+ unsigned char *rx_buffer;
unsigned long time_stamp;
u16 length;
bool mapped;
@@ -511,6 +515,9 @@ struct pch_gbe_tx_ring {
struct pch_gbe_rx_ring {
struct pch_gbe_rx_desc *desc;
dma_addr_t dma;
+ unsigned char *rx_buff_pool;
+ dma_addr_t rx_buff_pool_logic;
+ unsigned int rx_buff_pool_size;
unsigned int size;
unsigned int count;
unsigned int next_to_use;
@@ -622,6 +629,7 @@ struct pch_gbe_adapter {
unsigned long rx_buffer_len;
unsigned long tx_queue_len;
bool have_msi;
+ bool rx_stop_flag;
};
extern const char pch_driver_version[];
diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c
index eac3c5c..b8b4ba2 100644
--- a/drivers/net/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/pch_gbe/pch_gbe_main.c
@@ -20,7 +20,6 @@
#include "pch_gbe.h"
#include "pch_gbe_api.h"
-#include <linux/prefetch.h>
#define DRV_VERSION "1.00"
const char pch_driver_version[] = DRV_VERSION;
@@ -34,11 +33,15 @@ const char pch_driver_version[] = DRV_VERSION;
#define PCH_GBE_WATCHDOG_PERIOD (1 * HZ) /* watchdog time */
#define PCH_GBE_COPYBREAK_DEFAULT 256
#define PCH_GBE_PCI_BAR 1
+#define PCH_GBE_RESERVE_MEMORY 0x200000 /* 2MB */
/* Macros for ML7223 */
#define PCI_VENDOR_ID_ROHM 0x10db
#define PCI_DEVICE_ID_ROHM_ML7223_GBE 0x8013
+/* Macros for ML7831 */
+#define PCI_DEVICE_ID_ROHM_ML7831_GBE 0x8802
+
#define PCH_GBE_TX_WEIGHT 64
#define PCH_GBE_RX_WEIGHT 64
#define PCH_GBE_RX_BUFFER_WRITE 16
@@ -52,6 +55,7 @@ const char pch_driver_version[] = DRV_VERSION;
)
/* Ethertype field values */
+#define PCH_GBE_MAX_RX_BUFFER_SIZE 0x2880
#define PCH_GBE_MAX_JUMBO_FRAME_SIZE 10318
#define PCH_GBE_FRAME_SIZE_2048 2048
#define PCH_GBE_FRAME_SIZE_4096 4096
@@ -83,10 +87,12 @@ const char pch_driver_version[] = DRV_VERSION;
#define PCH_GBE_INT_ENABLE_MASK ( \
PCH_GBE_INT_RX_DMA_CMPLT | \
PCH_GBE_INT_RX_DSC_EMP | \
+ PCH_GBE_INT_RX_FIFO_ERR | \
PCH_GBE_INT_WOL_DET | \
PCH_GBE_INT_TX_CMPLT \
)
+#define PCH_GBE_INT_DISABLE_ALL 0
static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT;
@@ -138,6 +144,27 @@ static void pch_gbe_wait_clr_bit(void *reg, u32 bit)
if (!tmp)
pr_err("Error: busy bit is not cleared\n");
}
+
+/**
+ * pch_gbe_wait_clr_bit_irq - Wait to clear a bit for interrupt context
+ * @reg: Pointer of register
+ * @busy: Busy bit
+ */
+static int pch_gbe_wait_clr_bit_irq(void *reg, u32 bit)
+{
+ u32 tmp;
+ int ret = -1;
+ /* wait busy */
+ tmp = 20;
+ while ((ioread32(reg) & bit) && --tmp)
+ udelay(5);
+ if (!tmp)
+ pr_err("Error: busy bit is not cleared\n");
+ else
+ ret = 0;
+ return ret;
+}
+
/**
* pch_gbe_mac_mar_set - Set MAC address register
* @hw: Pointer to the HW structure
@@ -189,6 +216,17 @@ static void pch_gbe_mac_reset_hw(struct pch_gbe_hw *hw)
return;
}
+static void pch_gbe_mac_reset_rx(struct pch_gbe_hw *hw)
+{
+ /* Read the MAC address. and store to the private data */
+ pch_gbe_mac_read_mac_addr(hw);
+ iowrite32(PCH_GBE_RX_RST, &hw->reg->RESET);
+ pch_gbe_wait_clr_bit_irq(&hw->reg->RESET, PCH_GBE_RX_RST);
+ /* Setup the MAC address */
+ pch_gbe_mac_mar_set(hw, hw->mac.addr, 0);
+ return;
+}
+
/**
* pch_gbe_mac_init_rx_addrs - Initialize receive address's
* @hw: Pointer to the HW structure
@@ -671,13 +709,8 @@ static void pch_gbe_setup_rctl(struct pch_gbe_adapter *adapter)
tcpip = ioread32(&hw->reg->TCPIP_ACC);
- if (netdev->features & NETIF_F_RXCSUM) {
- tcpip &= ~PCH_GBE_RX_TCPIPACC_OFF;
- tcpip |= PCH_GBE_RX_TCPIPACC_EN;
- } else {
- tcpip |= PCH_GBE_RX_TCPIPACC_OFF;
- tcpip &= ~PCH_GBE_RX_TCPIPACC_EN;
- }
+ tcpip |= PCH_GBE_RX_TCPIPACC_OFF;
+ tcpip &= ~PCH_GBE_RX_TCPIPACC_EN;
iowrite32(tcpip, &hw->reg->TCPIP_ACC);
return;
}
@@ -717,13 +750,6 @@ static void pch_gbe_configure_rx(struct pch_gbe_adapter *adapter)
iowrite32(rdba, &hw->reg->RX_DSC_BASE);
iowrite32(rdlen, &hw->reg->RX_DSC_SIZE);
iowrite32((rdba + rdlen), &hw->reg->RX_DSC_SW_P);
-
- /* Enables Receive DMA */
- rxdma = ioread32(&hw->reg->DMA_CTRL);
- rxdma |= PCH_GBE_RX_DMA_EN;
- iowrite32(rxdma, &hw->reg->DMA_CTRL);
- /* Enables Receive */
- iowrite32(PCH_GBE_MRE_MAC_RX_EN, &hw->reg->MAC_RX_EN);
}
/**
@@ -1097,6 +1123,48 @@ void pch_gbe_update_stats(struct pch_gbe_adapter *adapter)
spin_unlock_irqrestore(&adapter->stats_lock, flags);
}
+static void pch_gbe_stop_receive(struct pch_gbe_adapter *adapter)
+{
+ struct pch_gbe_hw *hw = &adapter->hw;
+ u32 rxdma;
+ u16 value;
+ int ret;
+
+ /* Disable Receive DMA */
+ rxdma = ioread32(&hw->reg->DMA_CTRL);
+ rxdma &= ~PCH_GBE_RX_DMA_EN;
+ iowrite32(rxdma, &hw->reg->DMA_CTRL);
+ /* Wait Rx DMA BUS is IDLE */
+ ret = pch_gbe_wait_clr_bit_irq(&hw->reg->RX_DMA_ST, PCH_GBE_IDLE_CHECK);
+ if (ret) {
+ /* Disable Bus master */
+ pci_read_config_word(adapter->pdev, PCI_COMMAND, &value);
+ value &= ~PCI_COMMAND_MASTER;
+ pci_write_config_word(adapter->pdev, PCI_COMMAND, value);
+ /* Stop Receive */
+ pch_gbe_mac_reset_rx(hw);
+ /* Enable Bus master */
+ value |= PCI_COMMAND_MASTER;
+ pci_write_config_word(adapter->pdev, PCI_COMMAND, value);
+ } else {
+ /* Stop Receive */
+ pch_gbe_mac_reset_rx(hw);
+ }
+}
+
+static void pch_gbe_start_receive(struct pch_gbe_hw *hw)
+{
+ u32 rxdma;
+
+ /* Enables Receive DMA */
+ rxdma = ioread32(&hw->reg->DMA_CTRL);
+ rxdma |= PCH_GBE_RX_DMA_EN;
+ iowrite32(rxdma, &hw->reg->DMA_CTRL);
+ /* Enables Receive */
+ iowrite32(PCH_GBE_MRE_MAC_RX_EN, &hw->reg->MAC_RX_EN);
+ return;
+}
+
/**
* pch_gbe_intr - Interrupt Handler
* @irq: Interrupt number
@@ -1123,7 +1191,17 @@ static irqreturn_t pch_gbe_intr(int irq, void *data)
if (int_st & PCH_GBE_INT_RX_FRAME_ERR)
adapter->stats.intr_rx_frame_err_count++;
if (int_st & PCH_GBE_INT_RX_FIFO_ERR)
- adapter->stats.intr_rx_fifo_err_count++;
+ if (!adapter->rx_stop_flag) {
+ adapter->stats.intr_rx_fifo_err_count++;
+ pr_debug("Rx fifo over run\n");
+ adapter->rx_stop_flag = true;
+ int_en = ioread32(&hw->reg->INT_EN);
+ iowrite32((int_en & ~PCH_GBE_INT_RX_FIFO_ERR),
+ &hw->reg->INT_EN);
+ pch_gbe_stop_receive(adapter);
+ int_st |= ioread32(&hw->reg->INT_ST);
+ int_st = int_st & ioread32(&hw->reg->INT_EN);
+ }
if (int_st & PCH_GBE_INT_RX_DMA_ERR)
adapter->stats.intr_rx_dma_err_count++;
if (int_st & PCH_GBE_INT_TX_FIFO_ERR)
@@ -1135,21 +1213,18 @@ static irqreturn_t pch_gbe_intr(int irq, void *data)
/* When Rx descriptor is empty */
if ((int_st & PCH_GBE_INT_RX_DSC_EMP)) {
adapter->stats.intr_rx_dsc_empty_count++;
- pr_err("Rx descriptor is empty\n");
+ pr_debug("Rx descriptor is empty\n");
int_en = ioread32(&hw->reg->INT_EN);
iowrite32((int_en & ~PCH_GBE_INT_RX_DSC_EMP), &hw->reg->INT_EN);
if (hw->mac.tx_fc_enable) {
/* Set Pause packet */
pch_gbe_mac_set_pause_packet(hw);
}
- if ((int_en & (PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT))
- == 0) {
- return IRQ_HANDLED;
- }
}
/* When request status is Receive interruption */
- if ((int_st & (PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT))) {
+ if ((int_st & (PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT)) ||
+ (adapter->rx_stop_flag == true)) {
if (likely(napi_schedule_prep(&adapter->napi))) {
/* Enable only Rx Descriptor empty */
atomic_inc(&adapter->irq_sem);
@@ -1185,29 +1260,23 @@ pch_gbe_alloc_rx_buffers(struct pch_gbe_adapter *adapter,
unsigned int i;
unsigned int bufsz;
- bufsz = adapter->rx_buffer_len + PCH_GBE_DMA_ALIGN;
+ bufsz = adapter->rx_buffer_len + NET_IP_ALIGN;
i = rx_ring->next_to_use;
while ((cleaned_count--)) {
buffer_info = &rx_ring->buffer_info[i];
- skb = buffer_info->skb;
- if (skb) {
- skb_trim(skb, 0);
- } else {
- skb = netdev_alloc_skb(netdev, bufsz);
- if (unlikely(!skb)) {
- /* Better luck next round */
- adapter->stats.rx_alloc_buff_failed++;
- break;
- }
- /* 64byte align */
- skb_reserve(skb, PCH_GBE_DMA_ALIGN);
-
- buffer_info->skb = skb;
- buffer_info->length = adapter->rx_buffer_len;
+ skb = netdev_alloc_skb(netdev, bufsz);
+ if (unlikely(!skb)) {
+ /* Better luck next round */
+ adapter->stats.rx_alloc_buff_failed++;
+ break;
}
+ /* align */
+ skb_reserve(skb, NET_IP_ALIGN);
+ buffer_info->skb = skb;
+
buffer_info->dma = dma_map_single(&pdev->dev,
- skb->data,
+ buffer_info->rx_buffer,
buffer_info->length,
DMA_FROM_DEVICE);
if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma)) {
@@ -1240,6 +1309,36 @@ pch_gbe_alloc_rx_buffers(struct pch_gbe_adapter *adapter,
return;
}
+static int
+pch_gbe_alloc_rx_buffers_pool(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_rx_ring *rx_ring, int cleaned_count)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct pch_gbe_buffer *buffer_info;
+ unsigned int i;
+ unsigned int bufsz;
+ unsigned int size;
+
+ bufsz = adapter->rx_buffer_len;
+
+ size = rx_ring->count * bufsz + PCH_GBE_RESERVE_MEMORY;
+ rx_ring->rx_buff_pool = dma_alloc_coherent(&pdev->dev, size,
+ &rx_ring->rx_buff_pool_logic,
+ GFP_KERNEL);
+ if (!rx_ring->rx_buff_pool) {
+ pr_err("Unable to allocate memory for the receive poll buffer\n");
+ return -ENOMEM;
+ }
+ memset(rx_ring->rx_buff_pool, 0, size);
+ rx_ring->rx_buff_pool_size = size;
+ for (i = 0; i < rx_ring->count; i++) {
+ buffer_info = &rx_ring->buffer_info[i];
+ buffer_info->rx_buffer = rx_ring->rx_buff_pool + bufsz * i;
+ buffer_info->length = bufsz;
+ }
+ return 0;
+}
+
/**
* pch_gbe_alloc_tx_buffers - Allocate transmit buffers
* @adapter: Board private structure
@@ -1285,7 +1384,7 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
struct sk_buff *skb;
unsigned int i;
unsigned int cleaned_count = 0;
- bool cleaned = false;
+ bool cleaned = true;
pr_debug("next_to_clean : %d\n", tx_ring->next_to_clean);
@@ -1296,7 +1395,6 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
while ((tx_desc->gbec_status & DSC_INIT16) == 0x0000) {
pr_debug("gbec_status:0x%04x\n", tx_desc->gbec_status);
- cleaned = true;
buffer_info = &tx_ring->buffer_info[i];
skb = buffer_info->skb;
@@ -1339,8 +1437,10 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
tx_desc = PCH_GBE_TX_DESC(*tx_ring, i);
/* weight of a sort for tx, to avoid endless transmit cleanup */
- if (cleaned_count++ == PCH_GBE_TX_WEIGHT)
+ if (cleaned_count++ == PCH_GBE_TX_WEIGHT) {
+ cleaned = false;
break;
+ }
}
pr_debug("called pch_gbe_unmap_and_free_tx_resource() %d count\n",
cleaned_count);
@@ -1380,7 +1480,7 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
unsigned int i;
unsigned int cleaned_count = 0;
bool cleaned = false;
- struct sk_buff *skb, *new_skb;
+ struct sk_buff *skb;
u8 dma_status;
u16 gbec_status;
u32 tcp_ip_status;
@@ -1401,13 +1501,12 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
rx_desc->gbec_status = DSC_INIT16;
buffer_info = &rx_ring->buffer_info[i];
skb = buffer_info->skb;
+ buffer_info->skb = NULL;
/* unmap dma */
dma_unmap_single(&pdev->dev, buffer_info->dma,
buffer_info->length, DMA_FROM_DEVICE);
buffer_info->mapped = false;
- /* Prefetch the packet */
- prefetch(skb->data);
pr_debug("RxDecNo = 0x%04x Status[DMA:0x%02x GBE:0x%04x "
"TCP:0x%08x] BufInf = 0x%p\n",
@@ -1427,70 +1526,16 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
pr_err("Receive CRC Error\n");
} else {
/* get receive length */
- /* length convert[-3] */
- length = (rx_desc->rx_words_eob) - 3;
-
- /* Decide the data conversion method */
- if (!(netdev->features & NETIF_F_RXCSUM)) {
- /* [Header:14][payload] */
- if (NET_IP_ALIGN) {
- /* Because alignment differs,
- * the new_skb is newly allocated,
- * and data is copied to new_skb.*/
- new_skb = netdev_alloc_skb(netdev,
- length + NET_IP_ALIGN);
- if (!new_skb) {
- /* dorrop error */
- pr_err("New skb allocation "
- "Error\n");
- goto dorrop;
- }
- skb_reserve(new_skb, NET_IP_ALIGN);
- memcpy(new_skb->data, skb->data,
- length);
- skb = new_skb;
- } else {
- /* DMA buffer is used as SKB as it is.*/
- buffer_info->skb = NULL;
- }
- } else {
- /* [Header:14][padding:2][payload] */
- /* The length includes padding length */
- length = length - PCH_GBE_DMA_PADDING;
- if ((length < copybreak) ||
- (NET_IP_ALIGN != PCH_GBE_DMA_PADDING)) {
- /* Because alignment differs,
- * the new_skb is newly allocated,
- * and data is copied to new_skb.
- * Padding data is deleted
- * at the time of a copy.*/
- new_skb = netdev_alloc_skb(netdev,
- length + NET_IP_ALIGN);
- if (!new_skb) {
- /* dorrop error */
- pr_err("New skb allocation "
- "Error\n");
- goto dorrop;
- }
- skb_reserve(new_skb, NET_IP_ALIGN);
- memcpy(new_skb->data, skb->data,
- ETH_HLEN);
- memcpy(&new_skb->data[ETH_HLEN],
- &skb->data[ETH_HLEN +
- PCH_GBE_DMA_PADDING],
- length - ETH_HLEN);
- skb = new_skb;
- } else {
- /* Padding data is deleted
- * by moving header data.*/
- memmove(&skb->data[PCH_GBE_DMA_PADDING],
- &skb->data[0], ETH_HLEN);
- skb_reserve(skb, NET_IP_ALIGN);
- buffer_info->skb = NULL;
- }
- }
- /* The length includes FCS length */
- length = length - ETH_FCS_LEN;
+ /* length convert[-3], length includes FCS length */
+ length = (rx_desc->rx_words_eob) - 3 - ETH_FCS_LEN;
+ if (rx_desc->rx_words_eob & 0x02)
+ length = length - 4;
+ /*
+ * buffer_info->rx_buffer: [Header:14][payload]
+ * skb->data: [Reserve:2][Header:14][payload]
+ */
+ memcpy(skb->data, buffer_info->rx_buffer, length);
+
/* update status of driver */
adapter->stats.rx_bytes += length;
adapter->stats.rx_packets++;
@@ -1509,7 +1554,6 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
pr_debug("Receive skb->ip_summed: %d length: %d\n",
skb->ip_summed, length);
}
-dorrop:
/* return some buffers to hardware, one at a time is too slow */
if (unlikely(cleaned_count >= PCH_GBE_RX_BUFFER_WRITE)) {
pch_gbe_alloc_rx_buffers(adapter, rx_ring,
@@ -1714,9 +1758,15 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter)
pr_err("Error: can't bring device up\n");
return err;
}
+ err = pch_gbe_alloc_rx_buffers_pool(adapter, rx_ring, rx_ring->count);
+ if (err) {
+ pr_err("Error: can't bring device up\n");
+ return err;
+ }
pch_gbe_alloc_tx_buffers(adapter, tx_ring);
pch_gbe_alloc_rx_buffers(adapter, rx_ring, rx_ring->count);
adapter->tx_queue_len = netdev->tx_queue_len;
+ pch_gbe_start_receive(&adapter->hw);
mod_timer(&adapter->watchdog_timer, jiffies);
@@ -1734,6 +1784,7 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter)
void pch_gbe_down(struct pch_gbe_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
+ struct pch_gbe_rx_ring *rx_ring = adapter->rx_ring;
/* signal that we're down so the interrupt handler does not
* reschedule our watchdog timer */
@@ -1752,6 +1803,12 @@ void pch_gbe_down(struct pch_gbe_adapter *adapter)
pch_gbe_reset(adapter);
pch_gbe_clean_tx_ring(adapter, adapter->tx_ring);
pch_gbe_clean_rx_ring(adapter, adapter->rx_ring);
+
+ pci_free_consistent(adapter->pdev, rx_ring->rx_buff_pool_size,
+ rx_ring->rx_buff_pool, rx_ring->rx_buff_pool_logic);
+ rx_ring->rx_buff_pool_logic = 0;
+ rx_ring->rx_buff_pool_size = 0;
+ rx_ring->rx_buff_pool = NULL;
}
/**
@@ -2004,6 +2061,8 @@ static int pch_gbe_change_mtu(struct net_device *netdev, int new_mtu)
{
struct pch_gbe_adapter *adapter = netdev_priv(netdev);
int max_frame;
+ unsigned long old_rx_buffer_len = adapter->rx_buffer_len;
+ int err;
max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
@@ -2018,14 +2077,24 @@ static int pch_gbe_change_mtu(struct net_device *netdev, int new_mtu)
else if (max_frame <= PCH_GBE_FRAME_SIZE_8192)
adapter->rx_buffer_len = PCH_GBE_FRAME_SIZE_8192;
else
- adapter->rx_buffer_len = PCH_GBE_MAX_JUMBO_FRAME_SIZE;
- netdev->mtu = new_mtu;
- adapter->hw.mac.max_frame_size = max_frame;
+ adapter->rx_buffer_len = PCH_GBE_MAX_RX_BUFFER_SIZE;
- if (netif_running(netdev))
- pch_gbe_reinit_locked(adapter);
- else
+ if (netif_running(netdev)) {
+ pch_gbe_down(adapter);
+ err = pch_gbe_up(adapter);
+ if (err) {
+ adapter->rx_buffer_len = old_rx_buffer_len;
+ pch_gbe_up(adapter);
+ return -ENOMEM;
+ } else {
+ netdev->mtu = new_mtu;
+ adapter->hw.mac.max_frame_size = max_frame;
+ }
+ } else {
pch_gbe_reset(adapter);
+ netdev->mtu = new_mtu;
+ adapter->hw.mac.max_frame_size = max_frame;
+ }
pr_debug("max_frame : %d rx_buffer_len : %d mtu : %d max_frame_size : %d\n",
max_frame, (u32) adapter->rx_buffer_len, netdev->mtu,
@@ -2099,33 +2168,39 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget)
{
struct pch_gbe_adapter *adapter =
container_of(napi, struct pch_gbe_adapter, napi);
- struct net_device *netdev = adapter->netdev;
int work_done = 0;
bool poll_end_flag = false;
bool cleaned = false;
+ u32 int_en;
pr_debug("budget : %d\n", budget);
- /* Keep link state information with original netdev */
- if (!netif_carrier_ok(netdev)) {
- poll_end_flag = true;
- } else {
- cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring);
- pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget);
+ pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget);
+ cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring);
- if (cleaned)
- work_done = budget;
- /* If no Tx and not enough Rx work done,
- * exit the polling mode
- */
- if ((work_done < budget) || !netif_running(netdev))
- poll_end_flag = true;
- }
+ if (!cleaned)
+ work_done = budget;
+ /* If no Tx and not enough Rx work done,
+ * exit the polling mode
+ */
+ if (work_done < budget)
+ poll_end_flag = true;
if (poll_end_flag) {
napi_complete(napi);
+ if (adapter->rx_stop_flag) {
+ adapter->rx_stop_flag = false;
+ pch_gbe_start_receive(&adapter->hw);
+ }
pch_gbe_irq_enable(adapter);
- }
+ } else
+ if (adapter->rx_stop_flag) {
+ adapter->rx_stop_flag = false;
+ pch_gbe_start_receive(&adapter->hw);
+ int_en = ioread32(&adapter->hw.reg->INT_EN);
+ iowrite32((int_en | PCH_GBE_INT_RX_FIFO_ERR),
+ &adapter->hw.reg->INT_EN);
+ }
pr_debug("poll_end_flag : %d work_done : %d budget : %d\n",
poll_end_flag, work_done, budget);
@@ -2452,6 +2527,13 @@ static DEFINE_PCI_DEVICE_TABLE(pch_gbe_pcidev_id) = {
.class = (PCI_CLASS_NETWORK_ETHERNET << 8),
.class_mask = (0xFFFF00)
},
+ {.vendor = PCI_VENDOR_ID_ROHM,
+ .device = PCI_DEVICE_ID_ROHM_ML7831_GBE,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = (PCI_CLASS_NETWORK_ETHERNET << 8),
+ .class_mask = (0xFFFF00)
+ },
/* required last entry */
{0}
};
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index cb6e0b4..edd7304 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -589,7 +589,7 @@ static void decode_rxts(struct dp83640_private *dp83640,
prune_rx_ts(dp83640);
if (list_empty(&dp83640->rxpool)) {
- pr_warning("dp83640: rx timestamp pool is empty\n");
+ pr_debug("dp83640: rx timestamp pool is empty\n");
goto out;
}
rxts = list_first_entry(&dp83640->rxpool, struct rxts, list);
@@ -612,7 +612,7 @@ static void decode_txts(struct dp83640_private *dp83640,
skb = skb_dequeue(&dp83640->tx_queue);
if (!skb) {
- pr_warning("dp83640: have timestamp but tx_queue empty\n");
+ pr_debug("dp83640: have timestamp but tx_queue empty\n");
return;
}
ns = phy2txts(phy_txts);
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 10e5d98..edfa15d 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -1465,7 +1465,12 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
continue;
}
- mtu = pch->chan->mtu - hdrlen;
+ /*
+ * hdrlen includes the 2-byte PPP protocol field, but the
+ * MTU counts only the payload excluding the protocol field.
+ * (RFC1661 Section 2)
+ */
+ mtu = pch->chan->mtu - (hdrlen - 2);
if (mtu < 4)
mtu = 4;
if (flen > mtu)
diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c
index 1a3033d..d17d062 100644
--- a/drivers/net/pxa168_eth.c
+++ b/drivers/net/pxa168_eth.c
@@ -40,6 +40,7 @@
#include <linux/clk.h>
#include <linux/phy.h>
#include <linux/io.h>
+#include <linux/interrupt.h>
#include <linux/types.h>
#include <asm/pgtable.h>
#include <asm/system.h>
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 02339b3..c236670 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -407,6 +407,7 @@ enum rtl_register_content {
RxOK = 0x0001,
/* RxStatusDesc */
+ RxBOVF = (1 << 24),
RxFOVF = (1 << 23),
RxRWT = (1 << 22),
RxRES = (1 << 21),
@@ -682,6 +683,7 @@ struct rtl8169_private {
struct mii_if_info mii;
struct rtl8169_counters counters;
u32 saved_wolopts;
+ u32 opts1_mask;
struct rtl_fw {
const struct firmware *fw;
@@ -710,6 +712,7 @@ MODULE_FIRMWARE(FIRMWARE_8168D_1);
MODULE_FIRMWARE(FIRMWARE_8168D_2);
MODULE_FIRMWARE(FIRMWARE_8168E_1);
MODULE_FIRMWARE(FIRMWARE_8168E_2);
+MODULE_FIRMWARE(FIRMWARE_8168E_3);
MODULE_FIRMWARE(FIRMWARE_8105E_1);
static int rtl8169_open(struct net_device *dev);
@@ -3077,6 +3080,14 @@ static void rtl8169_phy_reset(struct net_device *dev,
netif_err(tp, link, dev, "PHY reset failed\n");
}
+static bool rtl_tbi_enabled(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ return (tp->mac_version == RTL_GIGA_MAC_VER_01) &&
+ (RTL_R8(PHYstatus) & TBI_Enable);
+}
+
static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
@@ -3109,7 +3120,7 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full : 0));
- if (RTL_R8(PHYstatus) & TBI_Enable)
+ if (rtl_tbi_enabled(tp))
netif_info(tp, link, dev, "TBI auto-negotiating\n");
}
@@ -3319,9 +3330,16 @@ static void r810x_phy_power_up(struct rtl8169_private *tp)
static void r810x_pll_power_down(struct rtl8169_private *tp)
{
+ void __iomem *ioaddr = tp->mmio_addr;
+
if (__rtl8169_get_wol(tp) & WAKE_ANY) {
rtl_writephy(tp, 0x1f, 0x0000);
rtl_writephy(tp, MII_BMCR, 0x0000);
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_29 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_30)
+ RTL_W32(RxConfig, RTL_R32(RxConfig) | AcceptBroadcast |
+ AcceptMulticast | AcceptMyPhys);
return;
}
@@ -3417,7 +3435,8 @@ static void r8168_pll_power_down(struct rtl8169_private *tp)
rtl_writephy(tp, MII_BMCR, 0x0000);
if (tp->mac_version == RTL_GIGA_MAC_VER_32 ||
- tp->mac_version == RTL_GIGA_MAC_VER_33)
+ tp->mac_version == RTL_GIGA_MAC_VER_33 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_34)
RTL_W32(RxConfig, RTL_R32(RxConfig) | AcceptBroadcast |
AcceptMulticast | AcceptMyPhys);
return;
@@ -3727,8 +3746,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->features |= rtl_try_msi(pdev, ioaddr, cfg);
RTL_W8(Cfg9346, Cfg9346_Lock);
- if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) &&
- (RTL_R8(PHYstatus) & TBI_Enable)) {
+ if (rtl_tbi_enabled(tp)) {
tp->set_speed = rtl8169_set_speed_tbi;
tp->get_settings = rtl8169_gset_tbi;
tp->phy_reset_enable = rtl8169_tbi_reset_enable;
@@ -3777,6 +3795,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->intr_event = cfg->intr_event;
tp->napi_event = cfg->napi_event;
+ tp->opts1_mask = (tp->mac_version != RTL_GIGA_MAC_VER_01) ?
+ ~(RxBOVF | RxFOVF) : ~0;
+
init_timer(&tp->timer);
tp->timer.data = (unsigned long) dev;
tp->timer.function = rtl8169_phy_timer;
@@ -3988,6 +4009,7 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
while (RTL_R8(TxPoll) & NPQ)
udelay(20);
} else if (tp->mac_version == RTL_GIGA_MAC_VER_34) {
+ RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
while (!(RTL_R32(TxConfig) & TXCFG_EMPTY))
udelay(100);
} else {
@@ -5314,7 +5336,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
u32 status;
rmb();
- status = le32_to_cpu(desc->opts1);
+ status = le32_to_cpu(desc->opts1) & tp->opts1_mask;
if (status & DescOwn)
break;
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index faca764..b59abc7 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1050,7 +1050,6 @@ static int efx_init_io(struct efx_nic *efx)
{
struct pci_dev *pci_dev = efx->pci_dev;
dma_addr_t dma_mask = efx->type->max_dma_mask;
- bool use_wc;
int rc;
netif_dbg(efx, probe, efx->net_dev, "initialising I/O\n");
@@ -1101,21 +1100,8 @@ static int efx_init_io(struct efx_nic *efx)
rc = -EIO;
goto fail3;
}
-
- /* bug22643: If SR-IOV is enabled then tx push over a write combined
- * mapping is unsafe. We need to disable write combining in this case.
- * MSI is unsupported when SR-IOV is enabled, and the firmware will
- * have removed the MSI capability. So write combining is safe if
- * there is an MSI capability.
- */
- use_wc = (!EFX_WORKAROUND_22643(efx) ||
- pci_find_capability(pci_dev, PCI_CAP_ID_MSI));
- if (use_wc)
- efx->membase = ioremap_wc(efx->membase_phys,
- efx->type->mem_map_size);
- else
- efx->membase = ioremap_nocache(efx->membase_phys,
- efx->type->mem_map_size);
+ efx->membase = ioremap_nocache(efx->membase_phys,
+ efx->type->mem_map_size);
if (!efx->membase) {
netif_err(efx, probe, efx->net_dev,
"could not map memory BAR at %llx+%x\n",
diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h
index cc97880..751d1ec 100644
--- a/drivers/net/sfc/io.h
+++ b/drivers/net/sfc/io.h
@@ -103,7 +103,6 @@ static inline void efx_writeo(struct efx_nic *efx, efx_oword_t *value,
_efx_writed(efx, value->u32[2], reg + 8);
_efx_writed(efx, value->u32[3], reg + 12);
#endif
- wmb();
mmiowb();
spin_unlock_irqrestore(&efx->biu_lock, flags);
}
@@ -126,7 +125,6 @@ static inline void efx_sram_writeq(struct efx_nic *efx, void __iomem *membase,
__raw_writel((__force u32)value->u32[0], membase + addr);
__raw_writel((__force u32)value->u32[1], membase + addr + 4);
#endif
- wmb();
mmiowb();
spin_unlock_irqrestore(&efx->biu_lock, flags);
}
@@ -141,7 +139,6 @@ static inline void efx_writed(struct efx_nic *efx, efx_dword_t *value,
/* No lock required */
_efx_writed(efx, value->u32[0], reg);
- wmb();
}
/* Read a 128-bit CSR, locking as appropriate. */
@@ -152,7 +149,6 @@ static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value,
spin_lock_irqsave(&efx->biu_lock, flags);
value->u32[0] = _efx_readd(efx, reg + 0);
- rmb();
value->u32[1] = _efx_readd(efx, reg + 4);
value->u32[2] = _efx_readd(efx, reg + 8);
value->u32[3] = _efx_readd(efx, reg + 12);
@@ -175,7 +171,6 @@ static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase,
value->u64[0] = (__force __le64)__raw_readq(membase + addr);
#else
value->u32[0] = (__force __le32)__raw_readl(membase + addr);
- rmb();
value->u32[1] = (__force __le32)__raw_readl(membase + addr + 4);
#endif
spin_unlock_irqrestore(&efx->biu_lock, flags);
@@ -249,7 +244,6 @@ static inline void _efx_writeo_page(struct efx_nic *efx, efx_oword_t *value,
_efx_writed(efx, value->u32[2], reg + 8);
_efx_writed(efx, value->u32[3], reg + 12);
#endif
- wmb();
}
#define efx_writeo_page(efx, value, reg, page) \
_efx_writeo_page(efx, value, \
diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c
index 3dd45ed..81a4253 100644
--- a/drivers/net/sfc/mcdi.c
+++ b/drivers/net/sfc/mcdi.c
@@ -50,20 +50,6 @@ static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx)
return &nic_data->mcdi;
}
-static inline void
-efx_mcdi_readd(struct efx_nic *efx, efx_dword_t *value, unsigned reg)
-{
- struct siena_nic_data *nic_data = efx->nic_data;
- value->u32[0] = (__force __le32)__raw_readl(nic_data->mcdi_smem + reg);
-}
-
-static inline void
-efx_mcdi_writed(struct efx_nic *efx, const efx_dword_t *value, unsigned reg)
-{
- struct siena_nic_data *nic_data = efx->nic_data;
- __raw_writel((__force u32)value->u32[0], nic_data->mcdi_smem + reg);
-}
-
void efx_mcdi_init(struct efx_nic *efx)
{
struct efx_mcdi_iface *mcdi;
@@ -84,8 +70,8 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd,
const u8 *inbuf, size_t inlen)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
- unsigned pdu = MCDI_PDU(efx);
- unsigned doorbell = MCDI_DOORBELL(efx);
+ unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
+ unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx);
unsigned int i;
efx_dword_t hdr;
u32 xflags, seqno;
@@ -106,28 +92,29 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd,
MCDI_HEADER_SEQ, seqno,
MCDI_HEADER_XFLAGS, xflags);
- efx_mcdi_writed(efx, &hdr, pdu);
+ efx_writed(efx, &hdr, pdu);
for (i = 0; i < inlen; i += 4)
- efx_mcdi_writed(efx, (const efx_dword_t *)(inbuf + i),
- pdu + 4 + i);
+ _efx_writed(efx, *((__le32 *)(inbuf + i)), pdu + 4 + i);
+
+ /* Ensure the payload is written out before the header */
+ wmb();
/* ring the doorbell with a distinctive value */
- EFX_POPULATE_DWORD_1(hdr, EFX_DWORD_0, 0x45789abc);
- efx_mcdi_writed(efx, &hdr, doorbell);
+ _efx_writed(efx, (__force __le32) 0x45789abc, doorbell);
}
static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
- unsigned int pdu = MCDI_PDU(efx);
+ unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
int i;
BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT);
BUG_ON(outlen & 3 || outlen >= 0x100);
for (i = 0; i < outlen; i += 4)
- efx_mcdi_readd(efx, (efx_dword_t *)(outbuf + i), pdu + 4 + i);
+ *((__le32 *)(outbuf + i)) = _efx_readd(efx, pdu + 4 + i);
}
static int efx_mcdi_poll(struct efx_nic *efx)
@@ -135,7 +122,7 @@ static int efx_mcdi_poll(struct efx_nic *efx)
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
unsigned int time, finish;
unsigned int respseq, respcmd, error;
- unsigned int pdu = MCDI_PDU(efx);
+ unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
unsigned int rc, spins;
efx_dword_t reg;
@@ -161,7 +148,8 @@ static int efx_mcdi_poll(struct efx_nic *efx)
time = get_seconds();
- efx_mcdi_readd(efx, &reg, pdu);
+ rmb();
+ efx_readd(efx, &reg, pdu);
/* All 1's indicates that shared memory is in reset (and is
* not a valid header). Wait for it to come out reset before
@@ -188,7 +176,7 @@ static int efx_mcdi_poll(struct efx_nic *efx)
respseq, mcdi->seqno);
rc = EIO;
} else if (error) {
- efx_mcdi_readd(efx, &reg, pdu + 4);
+ efx_readd(efx, &reg, pdu + 4);
switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) {
#define TRANSLATE_ERROR(name) \
case MC_CMD_ERR_ ## name: \
@@ -222,21 +210,21 @@ out:
/* Test and clear MC-rebooted flag for this port/function */
int efx_mcdi_poll_reboot(struct efx_nic *efx)
{
- unsigned int addr = MCDI_REBOOT_FLAG(efx);
+ unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_REBOOT_FLAG(efx);
efx_dword_t reg;
uint32_t value;
if (efx_nic_rev(efx) < EFX_REV_SIENA_A0)
return false;
- efx_mcdi_readd(efx, &reg, addr);
+ efx_readd(efx, &reg, addr);
value = EFX_DWORD_FIELD(reg, EFX_DWORD_0);
if (value == 0)
return 0;
EFX_ZERO_DWORD(reg);
- efx_mcdi_writed(efx, &reg, addr);
+ efx_writed(efx, &reg, addr);
if (value == MC_STATUS_DWORD_ASSERT)
return -EINTR;
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index bafa23a..3edfbaf 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -1936,13 +1936,6 @@ void efx_nic_get_regs(struct efx_nic *efx, void *buf)
size = min_t(size_t, table->step, 16);
- if (table->offset >= efx->type->mem_map_size) {
- /* No longer mapped; return dummy data */
- memcpy(buf, "\xde\xc0\xad\xde", 4);
- buf += table->rows * size;
- continue;
- }
-
for (i = 0; i < table->rows; i++) {
switch (table->step) {
case 4: /* 32-bit register or SRAM */
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h
index 4bd1f28..7443f99 100644
--- a/drivers/net/sfc/nic.h
+++ b/drivers/net/sfc/nic.h
@@ -143,12 +143,10 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx)
/**
* struct siena_nic_data - Siena NIC state
* @mcdi: Management-Controller-to-Driver Interface
- * @mcdi_smem: MCDI shared memory mapping. The mapping is always uncacheable.
* @wol_filter_id: Wake-on-LAN packet filter id
*/
struct siena_nic_data {
struct efx_mcdi_iface mcdi;
- void __iomem *mcdi_smem;
int wol_filter_id;
};
diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
index 5735e84..2c3bd93 100644
--- a/drivers/net/sfc/siena.c
+++ b/drivers/net/sfc/siena.c
@@ -250,26 +250,12 @@ static int siena_probe_nic(struct efx_nic *efx)
efx_reado(efx, &reg, FR_AZ_CS_DEBUG);
efx->net_dev->dev_id = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1;
- /* Initialise MCDI */
- nic_data->mcdi_smem = ioremap_nocache(efx->membase_phys +
- FR_CZ_MC_TREG_SMEM,
- FR_CZ_MC_TREG_SMEM_STEP *
- FR_CZ_MC_TREG_SMEM_ROWS);
- if (!nic_data->mcdi_smem) {
- netif_err(efx, probe, efx->net_dev,
- "could not map MCDI at %llx+%x\n",
- (unsigned long long)efx->membase_phys +
- FR_CZ_MC_TREG_SMEM,
- FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS);
- rc = -ENOMEM;
- goto fail1;
- }
efx_mcdi_init(efx);
/* Recover from a failed assertion before probing */
rc = efx_mcdi_handle_assertion(efx);
if (rc)
- goto fail2;
+ goto fail1;
/* Let the BMC know that the driver is now in charge of link and
* filter settings. We must do this before we reset the NIC */
@@ -324,7 +310,6 @@ fail4:
fail3:
efx_mcdi_drv_attach(efx, false, NULL);
fail2:
- iounmap(nic_data->mcdi_smem);
fail1:
kfree(efx->nic_data);
return rc;
@@ -404,8 +389,6 @@ static int siena_init_nic(struct efx_nic *efx)
static void siena_remove_nic(struct efx_nic *efx)
{
- struct siena_nic_data *nic_data = efx->nic_data;
-
efx_nic_free_buffer(efx, &efx->irq_status);
siena_reset_hw(efx, RESET_TYPE_ALL);
@@ -415,8 +398,7 @@ static void siena_remove_nic(struct efx_nic *efx)
efx_mcdi_drv_attach(efx, false, NULL);
/* Tear down the private nic state */
- iounmap(nic_data->mcdi_smem);
- kfree(nic_data);
+ kfree(efx->nic_data);
efx->nic_data = NULL;
}
@@ -656,7 +638,8 @@ const struct efx_nic_type siena_a0_nic_type = {
.default_mac_ops = &efx_mcdi_mac_operations,
.revision = EFX_REV_SIENA_A0,
- .mem_map_size = FR_CZ_MC_TREG_SMEM, /* MC_TREG_SMEM mapped separately */
+ .mem_map_size = (FR_CZ_MC_TREG_SMEM +
+ FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS),
.txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL,
.rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL,
.buf_tbl_base = FR_BZ_BUF_FULL_TBL,
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index 99ff114..e4dd3a7 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -38,8 +38,6 @@
#define EFX_WORKAROUND_15783 EFX_WORKAROUND_ALWAYS
/* Legacy interrupt storm when interrupt fifo fills */
#define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA
-/* Write combining and sriov=enabled are incompatible */
-#define EFX_WORKAROUND_22643 EFX_WORKAROUND_SIENA
/* Spurious parity errors in TSORT buffers */
#define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index dc3fbf6..4a1374d 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -6234,12 +6234,10 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
-#ifdef BCM_KERNEL_SUPPORTS_8021Q
if (vlan_tx_tag_present(skb)) {
base_flags |= TXD_FLAG_VLAN;
vlan = vlan_tx_tag_get(skb);
}
-#endif
if (tg3_flag(tp, USE_JUMBO_BDFLAG) &&
!mss && skb->len > VLAN_ETH_FRAME_LEN)
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c
index 15772b1..13c1f04 100644
--- a/drivers/net/usb/ipheth.c
+++ b/drivers/net/usb/ipheth.c
@@ -59,6 +59,7 @@
#define USB_PRODUCT_IPHONE_3G 0x1292
#define USB_PRODUCT_IPHONE_3GS 0x1294
#define USB_PRODUCT_IPHONE_4 0x1297
+#define USB_PRODUCT_IPHONE_4_VZW 0x129c
#define IPHETH_USBINTF_CLASS 255
#define IPHETH_USBINTF_SUBCLASS 253
@@ -98,6 +99,10 @@ static struct usb_device_id ipheth_table[] = {
USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4,
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
IPHETH_USBINTF_PROTO) },
+ { USB_DEVICE_AND_INTERFACE_INFO(
+ USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4_VZW,
+ IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
+ IPHETH_USBINTF_PROTO) },
{ }
};
MODULE_DEVICE_TABLE(usb, ipheth_table);
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index 2d4c091..2d394af 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -41,7 +41,8 @@ static bool ar9002_hw_is_cal_supported(struct ath_hw *ah,
case ADC_DC_CAL:
/* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */
if (!IS_CHAN_B(chan) &&
- !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
+ !((IS_CHAN_2GHZ(chan) || IS_CHAN_A_FAST_CLOCK(ah, chan)) &&
+ IS_CHAN_HT20(chan)))
supported = true;
break;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index 2339728..3e69c63 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -1514,7 +1514,7 @@ static const u32 ar9300_2p2_mac_core[][2] = {
{0x00008258, 0x00000000},
{0x0000825c, 0x40000000},
{0x00008260, 0x00080922},
- {0x00008264, 0x9bc00010},
+ {0x00008264, 0x9d400010},
{0x00008268, 0xffffffff},
{0x0000826c, 0x0000ffff},
{0x00008270, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 1baca8e..fcafec0 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -671,7 +671,7 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
REG_WRITE_ARRAY(&ah->iniModesAdditional,
modesIndex, regWrites);
- if (AR_SREV_9300(ah))
+ if (AR_SREV_9330(ah))
REG_WRITE_ARRAY(&ah->iniModesAdditional, 1, regWrites);
if (AR_SREV_9340(ah) && !ah->is_clk_25mhz)
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 6530694..722967b 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2303,6 +2303,12 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
mutex_lock(&sc->mutex);
cancel_delayed_work_sync(&sc->tx_complete_work);
+ if (ah->ah_flags & AH_UNPLUGGED) {
+ ath_dbg(common, ATH_DBG_ANY, "Device has been unplugged!\n");
+ mutex_unlock(&sc->mutex);
+ return;
+ }
+
if (sc->sc_flags & SC_OP_INVALID) {
ath_dbg(common, ATH_DBG_ANY, "Device not present\n");
mutex_unlock(&sc->mutex);
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 9a48501..4c21f8c 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -205,14 +205,22 @@ static void ath_rx_remove_buffer(struct ath_softc *sc,
static void ath_rx_edma_cleanup(struct ath_softc *sc)
{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_buf *bf;
ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP);
ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP);
list_for_each_entry(bf, &sc->rx.rxbuf, list) {
- if (bf->bf_mpdu)
+ if (bf->bf_mpdu) {
+ dma_unmap_single(sc->dev, bf->bf_buf_addr,
+ common->rx_bufsize,
+ DMA_BIDIRECTIONAL);
dev_kfree_skb_any(bf->bf_mpdu);
+ bf->bf_buf_addr = 0;
+ bf->bf_mpdu = NULL;
+ }
}
INIT_LIST_HEAD(&sc->rx.rxbuf);
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 26f1ab8..e293a79 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1632,7 +1632,8 @@ static void handle_irq_beacon(struct b43_wldev *dev)
u32 cmd, beacon0_valid, beacon1_valid;
if (!b43_is_mode(wl, NL80211_IFTYPE_AP) &&
- !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
+ !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) &&
+ !b43_is_mode(wl, NL80211_IFTYPE_ADHOC))
return;
/* This is the bottom half of the asynchronous beacon update. */
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 3774dd0..ef9ad79 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -1903,15 +1903,17 @@ static void ipw2100_down(struct ipw2100_priv *priv)
static int ipw2100_net_init(struct net_device *dev)
{
struct ipw2100_priv *priv = libipw_priv(dev);
+
+ return ipw2100_up(priv, 1);
+}
+
+static int ipw2100_wdev_init(struct net_device *dev)
+{
+ struct ipw2100_priv *priv = libipw_priv(dev);
const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
struct wireless_dev *wdev = &priv->ieee->wdev;
- int ret;
int i;
- ret = ipw2100_up(priv, 1);
- if (ret)
- return ret;
-
memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
/* fill-out priv->ieee->bg_band */
@@ -6350,9 +6352,13 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
"Error calling register_netdev.\n");
goto fail;
}
+ registered = 1;
+
+ err = ipw2100_wdev_init(dev);
+ if (err)
+ goto fail;
mutex_lock(&priv->action_mutex);
- registered = 1;
IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
@@ -6389,7 +6395,8 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
fail_unlock:
mutex_unlock(&priv->action_mutex);
-
+ wiphy_unregister(priv->ieee->wdev.wiphy);
+ kfree(priv->ieee->bg_band.channels);
fail:
if (dev) {
if (registered)
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 87813c3..4ffebed 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -11425,16 +11425,23 @@ static void ipw_bg_down(struct work_struct *work)
/* Called by register_netdev() */
static int ipw_net_init(struct net_device *dev)
{
+ int rc = 0;
+ struct ipw_priv *priv = libipw_priv(dev);
+
+ mutex_lock(&priv->mutex);
+ if (ipw_up(priv))
+ rc = -EIO;
+ mutex_unlock(&priv->mutex);
+
+ return rc;
+}
+
+static int ipw_wdev_init(struct net_device *dev)
+{
int i, rc = 0;
struct ipw_priv *priv = libipw_priv(dev);
const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
struct wireless_dev *wdev = &priv->ieee->wdev;
- mutex_lock(&priv->mutex);
-
- if (ipw_up(priv)) {
- rc = -EIO;
- goto out;
- }
memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
@@ -11519,13 +11526,9 @@ static int ipw_net_init(struct net_device *dev)
set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
/* With that information in place, we can now register the wiphy... */
- if (wiphy_register(wdev->wiphy)) {
+ if (wiphy_register(wdev->wiphy))
rc = -EIO;
- goto out;
- }
-
out:
- mutex_unlock(&priv->mutex);
return rc;
}
@@ -11832,14 +11835,22 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
goto out_remove_sysfs;
}
+ err = ipw_wdev_init(net_dev);
+ if (err) {
+ IPW_ERROR("failed to register wireless device\n");
+ goto out_unregister_netdev;
+ }
+
#ifdef CONFIG_IPW2200_PROMISCUOUS
if (rtap_iface) {
err = ipw_prom_alloc(priv);
if (err) {
IPW_ERROR("Failed to register promiscuous network "
"device (error %d).\n", err);
- unregister_netdev(priv->net_dev);
- goto out_remove_sysfs;
+ wiphy_unregister(priv->ieee->wdev.wiphy);
+ kfree(priv->ieee->a_band.channels);
+ kfree(priv->ieee->bg_band.channels);
+ goto out_unregister_netdev;
}
}
#endif
@@ -11851,6 +11862,8 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
return 0;
+ out_unregister_netdev:
+ unregister_netdev(priv->net_dev);
out_remove_sysfs:
sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
out_release_irq:
diff --git a/drivers/net/wireless/iwlegacy/iwl-3945-rs.c b/drivers/net/wireless/iwlegacy/iwl-3945-rs.c
index 977bd24..164bcae 100644
--- a/drivers/net/wireless/iwlegacy/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlegacy/iwl-3945-rs.c
@@ -822,12 +822,15 @@ static void iwl3945_rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
out:
- rs_sta->last_txrate_idx = index;
- if (sband->band == IEEE80211_BAND_5GHZ)
- info->control.rates[0].idx = rs_sta->last_txrate_idx -
- IWL_FIRST_OFDM_RATE;
- else
+ if (sband->band == IEEE80211_BAND_5GHZ) {
+ if (WARN_ON_ONCE(index < IWL_FIRST_OFDM_RATE))
+ index = IWL_FIRST_OFDM_RATE;
+ rs_sta->last_txrate_idx = index;
+ info->control.rates[0].idx = index - IWL_FIRST_OFDM_RATE;
+ } else {
+ rs_sta->last_txrate_idx = index;
info->control.rates[0].idx = rs_sta->last_txrate_idx;
+ }
IWL_DEBUG_RATE(priv, "leave: %d\n", index);
}
diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c
index 35cd2537..e5971fe 100644
--- a/drivers/net/wireless/iwlegacy/iwl-core.c
+++ b/drivers/net/wireless/iwlegacy/iwl-core.c
@@ -937,7 +937,7 @@ void iwl_legacy_irq_handle_error(struct iwl_priv *priv)
&priv->contexts[IWL_RXON_CTX_BSS]);
#endif
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
/* Keep the restart process from trying to send host
* commands by clearing the INIT status bit */
@@ -1746,7 +1746,7 @@ int iwl_legacy_force_reset(struct iwl_priv *priv, bool external)
/* Set the FW error flag -- cleared on iwl_down */
set_bit(STATUS_FW_ERROR, &priv->status);
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
/*
* Keep the restart process from trying to send host
* commands by clearing the INIT status bit
diff --git a/drivers/net/wireless/iwlegacy/iwl-hcmd.c b/drivers/net/wireless/iwlegacy/iwl-hcmd.c
index 62b4b09..ce1fc9f 100644
--- a/drivers/net/wireless/iwlegacy/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlegacy/iwl-hcmd.c
@@ -167,7 +167,7 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
goto out;
}
- ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ ret = wait_event_timeout(priv->wait_command_queue,
!test_bit(STATUS_HCMD_ACTIVE, &priv->status),
HOST_COMPLETE_TIMEOUT);
if (!ret) {
diff --git a/drivers/net/wireless/iwlegacy/iwl-tx.c b/drivers/net/wireless/iwlegacy/iwl-tx.c
index 4fff995..ef9e268 100644
--- a/drivers/net/wireless/iwlegacy/iwl-tx.c
+++ b/drivers/net/wireless/iwlegacy/iwl-tx.c
@@ -625,6 +625,8 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
cmd = txq->cmd[cmd_index];
meta = &txq->meta[cmd_index];
+ txq->time_stamp = jiffies;
+
pci_unmap_single(priv->pci_dev,
dma_unmap_addr(meta, mapping),
dma_unmap_len(meta, len),
@@ -645,7 +647,7 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n",
iwl_legacy_get_cmd_string(cmd->hdr.cmd));
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
}
/* Mark as unmapped */
diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c
index 795826a..66ee1562 100644
--- a/drivers/net/wireless/iwlegacy/iwl3945-base.c
+++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c
@@ -841,7 +841,7 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
wiphy_rfkill_set_hw_state(priv->hw->wiphy,
test_bit(STATUS_RF_KILL_HW, &priv->status));
else
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
}
/**
@@ -2269,7 +2269,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
iwl3945_reg_txpower_periodic(priv);
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
return;
@@ -2300,7 +2300,7 @@ static void __iwl3945_down(struct iwl_priv *priv)
iwl_legacy_clear_driver_stations(priv);
/* Unblock any waiting calls */
- wake_up_interruptible_all(&priv->wait_command_queue);
+ wake_up_all(&priv->wait_command_queue);
/* Wipe out the EXIT_PENDING status bit if we are not actually
* exiting the module */
@@ -2853,7 +2853,7 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
/* Wait for START_ALIVE from ucode. Otherwise callbacks from
* mac80211 will not be run successfully. */
- ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ ret = wait_event_timeout(priv->wait_command_queue,
test_bit(STATUS_READY, &priv->status),
UCODE_READY_TIMEOUT);
if (!ret) {
diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c
index 1433466..aa0c253 100644
--- a/drivers/net/wireless/iwlegacy/iwl4965-base.c
+++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c
@@ -576,7 +576,7 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
wiphy_rfkill_set_hw_state(priv->hw->wiphy,
test_bit(STATUS_RF_KILL_HW, &priv->status));
else
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
}
/**
@@ -926,7 +926,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
handled |= CSR_INT_BIT_FH_TX;
/* Wake up uCode load routine, now that load is complete */
priv->ucode_write_complete = 1;
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
}
if (inta & ~handled) {
@@ -1795,7 +1795,7 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
iwl4965_rf_kill_ct_config(priv);
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
iwl_legacy_power_update_mode(priv, true);
IWL_DEBUG_INFO(priv, "Updated power mode\n");
@@ -1828,7 +1828,7 @@ static void __iwl4965_down(struct iwl_priv *priv)
iwl_legacy_clear_driver_stations(priv);
/* Unblock any waiting calls */
- wake_up_interruptible_all(&priv->wait_command_queue);
+ wake_up_all(&priv->wait_command_queue);
/* Wipe out the EXIT_PENDING status bit if we are not actually
* exiting the module */
@@ -2266,7 +2266,7 @@ int iwl4965_mac_start(struct ieee80211_hw *hw)
/* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from
* mac80211 will not be run successfully. */
- ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ ret = wait_event_timeout(priv->wait_command_queue,
test_bit(STATUS_READY, &priv->status),
UCODE_READY_TIMEOUT);
if (!ret) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index a895a09..5621100 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -167,7 +167,7 @@ static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv)
memset(&cmd, 0, sizeof(cmd));
iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
- memcpy(&cmd.radio_sensor_offset, offset_calib, sizeof(offset_calib));
+ memcpy(&cmd.radio_sensor_offset, offset_calib, sizeof(*offset_calib));
if (!(cmd.radio_sensor_offset))
cmd.radio_sensor_offset = DEFAULT_RADIO_SENSOR_OFFSET;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index b0ae4de..f9c3cd9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2140,7 +2140,12 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+ /*
+ * Including the following line will crash some AP's. This
+ * workaround removes the stimulus which causes the crash until
+ * the AP software can be fixed.
hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+ */
hw->flags |= IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index dd6937e..77e528f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -405,31 +405,33 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
mutex_lock(&priv->mutex);
- if (test_bit(STATUS_SCANNING, &priv->status) &&
- priv->scan_type != IWL_SCAN_NORMAL) {
- IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
- ret = -EAGAIN;
- goto out_unlock;
- }
-
- /* mac80211 will only ask for one band at a time */
- priv->scan_request = req;
- priv->scan_vif = vif;
-
/*
* If an internal scan is in progress, just set
* up the scan_request as per above.
*/
if (priv->scan_type != IWL_SCAN_NORMAL) {
- IWL_DEBUG_SCAN(priv, "SCAN request during internal scan\n");
+ IWL_DEBUG_SCAN(priv,
+ "SCAN request during internal scan - defer\n");
+ priv->scan_request = req;
+ priv->scan_vif = vif;
ret = 0;
- } else
+ } else {
+ priv->scan_request = req;
+ priv->scan_vif = vif;
+ /*
+ * mac80211 will only ask for one band at a time
+ * so using channels[0] here is ok
+ */
ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
req->channels[0]->band);
+ if (ret) {
+ priv->scan_request = NULL;
+ priv->scan_vif = NULL;
+ }
+ }
IWL_DEBUG_MAC80211(priv, "leave\n");
-out_unlock:
mutex_unlock(&priv->mutex);
return ret;
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c
index a6b2b1d..222d410 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c
@@ -771,6 +771,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
cmd = txq->cmd[cmd_index];
meta = &txq->meta[cmd_index];
+ txq->time_stamp = jiffies;
+
iwlagn_unmap_tfd(priv, meta, &txq->tfds[index], DMA_BIDIRECTIONAL);
/* Input error checking is done when commands are added to queue. */
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index ef67f67..0019dfd 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -3697,14 +3697,15 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i)
rt2800_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, &reg);
/* Apparently the data is read from end to start */
- rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3,
- (u32 *)&rt2x00dev->eeprom[i]);
- rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2,
- (u32 *)&rt2x00dev->eeprom[i + 2]);
- rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1,
- (u32 *)&rt2x00dev->eeprom[i + 4]);
- rt2800_register_read_lock(rt2x00dev, EFUSE_DATA0,
- (u32 *)&rt2x00dev->eeprom[i + 6]);
+ rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, &reg);
+ /* The returned value is in CPU order, but eeprom is le */
+ rt2x00dev->eeprom[i] = cpu_to_le32(reg);
+ rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, &reg);
+ *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg);
+ rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, &reg);
+ *(u32 *)&rt2x00dev->eeprom[i + 4] = cpu_to_le32(reg);
+ rt2800_register_read_lock(rt2x00dev, EFUSE_DATA0, &reg);
+ *(u32 *)&rt2x00dev->eeprom[i + 6] = cpu_to_le32(reg);
mutex_unlock(&rt2x00dev->csr_mutex);
}
@@ -3870,19 +3871,23 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
return -ENODEV;
}
- if (!rt2x00_rf(rt2x00dev, RF2820) &&
- !rt2x00_rf(rt2x00dev, RF2850) &&
- !rt2x00_rf(rt2x00dev, RF2720) &&
- !rt2x00_rf(rt2x00dev, RF2750) &&
- !rt2x00_rf(rt2x00dev, RF3020) &&
- !rt2x00_rf(rt2x00dev, RF2020) &&
- !rt2x00_rf(rt2x00dev, RF3021) &&
- !rt2x00_rf(rt2x00dev, RF3022) &&
- !rt2x00_rf(rt2x00dev, RF3052) &&
- !rt2x00_rf(rt2x00dev, RF3320) &&
- !rt2x00_rf(rt2x00dev, RF5370) &&
- !rt2x00_rf(rt2x00dev, RF5390)) {
- ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ switch (rt2x00dev->chip.rf) {
+ case RF2820:
+ case RF2850:
+ case RF2720:
+ case RF2750:
+ case RF3020:
+ case RF2020:
+ case RF3021:
+ case RF3022:
+ case RF3052:
+ case RF3320:
+ case RF5370:
+ case RF5390:
+ break;
+ default:
+ ERROR(rt2x00dev, "Invalid RF chipset 0x%x detected.\n",
+ rt2x00dev->chip.rf);
return -ENODEV;
}
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index 1bdc1aa..04c4e9e 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -610,6 +610,11 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
mac->link_state = MAC80211_NOLINK;
memset(mac->bssid, 0, 6);
+
+ /* reset sec info */
+ rtl_cam_reset_sec_info(hw);
+
+ rtl_cam_reset_all_entry(hw);
mac->vendor = PEER_UNKNOWN;
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
@@ -1063,6 +1068,9 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
*or clear all entry here.
*/
rtl_cam_delete_one_entry(hw, mac_addr, key_idx);
+
+ rtl_cam_reset_sec_info(hw);
+
break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index 906e7aa..3e52a54 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -549,15 +549,16 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
(tcb_desc->rts_use_shortpreamble ? 1 : 0)
: (tcb_desc->rts_use_shortgi ? 1 : 0)));
if (mac->bw_40) {
- if (tcb_desc->packet_bw) {
+ if (rate_flag & IEEE80211_TX_RC_DUP_DATA) {
SET_TX_DESC_DATA_BW(txdesc, 1);
SET_TX_DESC_DATA_SC(txdesc, 3);
+ } else if(rate_flag & IEEE80211_TX_RC_40_MHZ_WIDTH){
+ SET_TX_DESC_DATA_BW(txdesc, 1);
+ SET_TX_DESC_DATA_SC(txdesc, mac->cur_40_prime_sc);
} else {
SET_TX_DESC_DATA_BW(txdesc, 0);
- if (rate_flag & IEEE80211_TX_RC_DUP_DATA)
- SET_TX_DESC_DATA_SC(txdesc,
- mac->cur_40_prime_sc);
- }
+ SET_TX_DESC_DATA_SC(txdesc, 0);
+ }
} else {
SET_TX_DESC_DATA_BW(txdesc, 0);
SET_TX_DESC_DATA_SC(txdesc, 0);
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index 8b1cef0..4bf3cf4 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -863,6 +863,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb,
u8 tid = 0;
u16 seq_number = 0;
+ memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
if (ieee80211_is_auth(fc)) {
RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
rtl_ips_nic_on(hw);
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index 0ca86f9..1825629 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -327,12 +327,12 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
xenvif_get(vif);
rtnl_lock();
- if (netif_running(vif->dev))
- xenvif_up(vif);
if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN)
dev_set_mtu(vif->dev, ETH_DATA_LEN);
netdev_update_features(vif->dev);
netif_carrier_on(vif->dev);
+ if (netif_running(vif->dev))
+ xenvif_up(vif);
rtnl_unlock();
return 0;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 4e84fd4..e9651f0 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -77,7 +77,7 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE;
unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE;
-enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_SAFE;
+enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF;
/*
* The default CLS is used if arch didn't set CLS explicitly and not
@@ -3568,10 +3568,14 @@ static int __init pci_setup(char *str)
pci_hotplug_io_size = memparse(str + 9, &str);
} else if (!strncmp(str, "hpmemsize=", 10)) {
pci_hotplug_mem_size = memparse(str + 10, &str);
+ } else if (!strncmp(str, "pcie_bus_tune_off", 17)) {
+ pcie_bus_config = PCIE_BUS_TUNE_OFF;
} else if (!strncmp(str, "pcie_bus_safe", 13)) {
pcie_bus_config = PCIE_BUS_SAFE;
} else if (!strncmp(str, "pcie_bus_perf", 13)) {
pcie_bus_config = PCIE_BUS_PERFORMANCE;
+ } else if (!strncmp(str, "pcie_bus_peer2peer", 18)) {
+ pcie_bus_config = PCIE_BUS_PEER2PEER;
} else {
printk(KERN_ERR "PCI: Unknown option `%s'\n",
str);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index b1187ff..6ab6bd3 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1351,7 +1351,8 @@ static int pcie_find_smpss(struct pci_dev *dev, void *data)
* will occur as normal.
*/
if (dev->is_hotplug_bridge && (!list_is_singular(&dev->bus->devices) ||
- dev->bus->self->pcie_type != PCI_EXP_TYPE_ROOT_PORT))
+ (dev->bus->self &&
+ dev->bus->self->pcie_type != PCI_EXP_TYPE_ROOT_PORT)))
*smpss = 0;
if (*smpss > dev->pcie_mpss)
@@ -1457,12 +1458,24 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
*/
void pcie_bus_configure_settings(struct pci_bus *bus, u8 mpss)
{
- u8 smpss = mpss;
+ u8 smpss;
if (!pci_is_pcie(bus->self))
return;
+ if (pcie_bus_config == PCIE_BUS_TUNE_OFF)
+ return;
+
+ /* FIXME - Peer to peer DMA is possible, though the endpoint would need
+ * to be aware to the MPS of the destination. To work around this,
+ * simply force the MPS of the entire system to the smallest possible.
+ */
+ if (pcie_bus_config == PCIE_BUS_PEER2PEER)
+ smpss = 0;
+
if (pcie_bus_config == PCIE_BUS_SAFE) {
+ smpss = mpss;
+
pcie_find_smpss(bus->self, &smpss);
pci_walk_bus(bus, pcie_find_smpss, &smpss);
}
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index 2dd3c01..d93a960 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -35,6 +35,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
+#include <linux/sched.h>
#include <linux/workqueue.h>
/* DryIce Register Definitions */
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 4e7c04e..7639ab9 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -51,6 +51,27 @@ static enum s3c_cpu_type s3c_rtc_cpu_type;
static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
+static void s3c_rtc_alarm_clk_enable(bool enable)
+{
+ static DEFINE_SPINLOCK(s3c_rtc_alarm_clk_lock);
+ static bool alarm_clk_enabled;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&s3c_rtc_alarm_clk_lock, irq_flags);
+ if (enable) {
+ if (!alarm_clk_enabled) {
+ clk_enable(rtc_clk);
+ alarm_clk_enabled = true;
+ }
+ } else {
+ if (alarm_clk_enabled) {
+ clk_disable(rtc_clk);
+ alarm_clk_enabled = false;
+ }
+ }
+ spin_unlock_irqrestore(&s3c_rtc_alarm_clk_lock, irq_flags);
+}
+
/* IRQ Handlers */
static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
@@ -64,6 +85,9 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
writeb(S3C2410_INTP_ALM, s3c_rtc_base + S3C2410_INTP);
clk_disable(rtc_clk);
+
+ s3c_rtc_alarm_clk_enable(false);
+
return IRQ_HANDLED;
}
@@ -97,6 +121,8 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
writeb(tmp, s3c_rtc_base + S3C2410_RTCALM);
clk_disable(rtc_clk);
+ s3c_rtc_alarm_clk_enable(enabled);
+
return 0;
}
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index cbde448..eb3140e 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -654,8 +654,8 @@ static struct io_subchannel_private console_priv;
static int console_subchannel_in_use;
/*
- * Use tpi to get a pending interrupt, call the interrupt handler and
- * return a pointer to the subchannel structure.
+ * Use cio_tpi to get a pending interrupt and call the interrupt handler.
+ * Return non-zero if an interrupt was processed, zero otherwise.
*/
static int cio_tpi(void)
{
@@ -667,6 +667,10 @@ static int cio_tpi(void)
tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id;
if (tpi(NULL) != 1)
return 0;
+ if (tpi_info->adapter_IO) {
+ do_adapter_IO(tpi_info->isc);
+ return 1;
+ }
irb = (struct irb *)&S390_lowcore.irb;
/* Store interrupt response block to lowcore. */
if (tsch(tpi_info->schid, irb) != 0)
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index b7bd5b0..3868ab2 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -1800,10 +1800,12 @@ static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_
switch (retval) {
case SCSI_MLQUEUE_HOST_BUSY:
twa_free_request_id(tw_dev, request_id);
+ twa_unmap_scsi_data(tw_dev, request_id);
break;
case 1:
tw_dev->state[request_id] = TW_S_COMPLETED;
twa_free_request_id(tw_dev, request_id);
+ twa_unmap_scsi_data(tw_dev, request_id);
SCpnt->result = (DID_ERROR << 16);
done(SCpnt);
retval = 0;
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 8d9dae8..3878b73 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -837,6 +837,7 @@ config SCSI_ISCI
# (temporary): known alpha quality driver
depends on EXPERIMENTAL
select SCSI_SAS_LIBSAS
+ select SCSI_SAS_HOST_SMP
---help---
This driver supports the 6Gb/s SAS capabilities of the storage
control unit found in the Intel(R) C600 series chipset.
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 3c08f53..6153a66 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -88,7 +88,7 @@ obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o
obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o
obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/
-obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx/
+obj-$(CONFIG_SCSI_QLA_ISCSI) += libiscsi.o qla4xxx/
obj-$(CONFIG_SCSI_LPFC) += lpfc/
obj-$(CONFIG_SCSI_BFA_FC) += bfa/
obj-$(CONFIG_SCSI_PAS16) += pas16.o
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index e7d0d47..e5f2d7d 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -1283,6 +1283,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
kfree(aac->queues);
aac->queues = NULL;
free_irq(aac->pdev->irq, aac);
+ if (aac->msi)
+ pci_disable_msi(aac->pdev);
kfree(aac->fsa_dev);
aac->fsa_dev = NULL;
quirks = aac_get_driver_ident(index)->quirks;
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index 9ae80cd..dba72a4 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -563,7 +563,7 @@ int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn,
nopout_wqe->itt = ((u16)task->itt |
(ISCSI_TASK_TYPE_MPATH <<
ISCSI_TMF_REQUEST_TYPE_SHIFT));
- nopout_wqe->ttt = nopout_hdr->ttt;
+ nopout_wqe->ttt = be32_to_cpu(nopout_hdr->ttt);
nopout_wqe->flags = 0;
if (!unsol)
nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION;
diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
index bd22041..f586448 100644
--- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
+++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
@@ -913,7 +913,7 @@ static void l2t_put(struct cxgbi_sock *csk)
struct t3cdev *t3dev = (struct t3cdev *)csk->cdev->lldev;
if (csk->l2t) {
- l2t_release(L2DATA(t3dev), csk->l2t);
+ l2t_release(t3dev, csk->l2t);
csk->l2t = NULL;
cxgbi_sock_put(csk);
}
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index ba710e3..5d0e9a2 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -432,6 +432,8 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
u8 flogi_maddr[ETH_ALEN];
const struct net_device_ops *ops;
+ rtnl_lock();
+
/*
* Don't listen for Ethernet packets anymore.
* synchronize_net() ensures that the packet handlers are not running
@@ -461,6 +463,8 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
" specific feature for LLD.\n");
}
+ rtnl_unlock();
+
/* Release the self-reference taken during fcoe_interface_create() */
fcoe_interface_put(fcoe);
}
@@ -1951,11 +1955,8 @@ static void fcoe_destroy_work(struct work_struct *work)
fcoe_if_destroy(port->lport);
/* Do not tear down the fcoe interface for NPIV port */
- if (!npiv) {
- rtnl_lock();
+ if (!npiv)
fcoe_interface_cleanup(fcoe);
- rtnl_unlock();
- }
mutex_unlock(&fcoe_config_mutex);
}
@@ -2009,8 +2010,9 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)
printk(KERN_ERR "fcoe: Failed to create interface (%s)\n",
netdev->name);
rc = -EIO;
+ rtnl_unlock();
fcoe_interface_cleanup(fcoe);
- goto out_nodev;
+ goto out_nortnl;
}
/* Make this the "master" N_Port */
@@ -2027,6 +2029,7 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)
out_nodev:
rtnl_unlock();
+out_nortnl:
mutex_unlock(&fcoe_config_mutex);
return rc;
}
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index ec61bdb..b200b73 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -676,6 +676,16 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno,
BUG_ON(entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA);
removed[*nremoved] = h->dev[entry];
(*nremoved)++;
+
+ /*
+ * New physical devices won't have target/lun assigned yet
+ * so we need to preserve the values in the slot we are replacing.
+ */
+ if (new_entry->target == -1) {
+ new_entry->target = h->dev[entry]->target;
+ new_entry->lun = h->dev[entry]->lun;
+ }
+
h->dev[entry] = new_entry;
added[*nadded] = new_entry;
(*nadded)++;
@@ -1548,10 +1558,17 @@ static inline void hpsa_set_bus_target_lun(struct hpsa_scsi_dev_t *device,
}
static int hpsa_update_device_info(struct ctlr_info *h,
- unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device)
+ unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device,
+ unsigned char *is_OBDR_device)
{
-#define OBDR_TAPE_INQ_SIZE 49
+
+#define OBDR_SIG_OFFSET 43
+#define OBDR_TAPE_SIG "$DR-10"
+#define OBDR_SIG_LEN (sizeof(OBDR_TAPE_SIG) - 1)
+#define OBDR_TAPE_INQ_SIZE (OBDR_SIG_OFFSET + OBDR_SIG_LEN)
+
unsigned char *inq_buff;
+ unsigned char *obdr_sig;
inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
if (!inq_buff)
@@ -1583,6 +1600,16 @@ static int hpsa_update_device_info(struct ctlr_info *h,
else
this_device->raid_level = RAID_UNKNOWN;
+ if (is_OBDR_device) {
+ /* See if this is a One-Button-Disaster-Recovery device
+ * by looking for "$DR-10" at offset 43 in inquiry data.
+ */
+ obdr_sig = &inq_buff[OBDR_SIG_OFFSET];
+ *is_OBDR_device = (this_device->devtype == TYPE_ROM &&
+ strncmp(obdr_sig, OBDR_TAPE_SIG,
+ OBDR_SIG_LEN) == 0);
+ }
+
kfree(inq_buff);
return 0;
@@ -1716,7 +1743,7 @@ static int add_msa2xxx_enclosure_device(struct ctlr_info *h,
return 0;
}
- if (hpsa_update_device_info(h, scsi3addr, this_device))
+ if (hpsa_update_device_info(h, scsi3addr, this_device, NULL))
return 0;
(*nmsa2xxx_enclosures)++;
hpsa_set_bus_target_lun(this_device, bus, target, 0);
@@ -1808,7 +1835,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
*/
struct ReportLUNdata *physdev_list = NULL;
struct ReportLUNdata *logdev_list = NULL;
- unsigned char *inq_buff = NULL;
u32 nphysicals = 0;
u32 nlogicals = 0;
u32 ndev_allocated = 0;
@@ -1824,11 +1850,9 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
GFP_KERNEL);
physdev_list = kzalloc(reportlunsize, GFP_KERNEL);
logdev_list = kzalloc(reportlunsize, GFP_KERNEL);
- inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL);
- if (!currentsd || !physdev_list || !logdev_list ||
- !inq_buff || !tmpdevice) {
+ if (!currentsd || !physdev_list || !logdev_list || !tmpdevice) {
dev_err(&h->pdev->dev, "out of memory\n");
goto out;
}
@@ -1863,7 +1887,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
/* adjust our table of devices */
nmsa2xxx_enclosures = 0;
for (i = 0; i < nphysicals + nlogicals + 1; i++) {
- u8 *lunaddrbytes;
+ u8 *lunaddrbytes, is_OBDR = 0;
/* Figure out where the LUN ID info is coming from */
lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position,
@@ -1874,7 +1898,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
continue;
/* Get device type, vendor, model, device id */
- if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice))
+ if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice,
+ &is_OBDR))
continue; /* skip it if we can't talk to it. */
figure_bus_target_lun(h, lunaddrbytes, &bus, &target, &lun,
tmpdevice);
@@ -1898,7 +1923,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
hpsa_set_bus_target_lun(this_device, bus, target, lun);
switch (this_device->devtype) {
- case TYPE_ROM: {
+ case TYPE_ROM:
/* We don't *really* support actual CD-ROM devices,
* just "One Button Disaster Recovery" tape drive
* which temporarily pretends to be a CD-ROM drive.
@@ -1906,15 +1931,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
* device by checking for "$DR-10" in bytes 43-48 of
* the inquiry data.
*/
- char obdr_sig[7];
-#define OBDR_TAPE_SIG "$DR-10"
- strncpy(obdr_sig, &inq_buff[43], 6);
- obdr_sig[6] = '\0';
- if (strncmp(obdr_sig, OBDR_TAPE_SIG, 6) != 0)
- /* Not OBDR device, ignore it. */
- break;
- }
- ncurrent++;
+ if (is_OBDR)
+ ncurrent++;
break;
case TYPE_DISK:
if (i < nphysicals)
@@ -1947,7 +1965,6 @@ out:
for (i = 0; i < ndev_allocated; i++)
kfree(currentsd[i]);
kfree(currentsd);
- kfree(inq_buff);
kfree(physdev_list);
kfree(logdev_list);
}
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 26072f1..6981b77 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -531,6 +531,9 @@ static void sci_controller_process_completions(struct isci_host *ihost)
break;
case SCU_COMPLETION_TYPE_EVENT:
+ sci_controller_event_completion(ihost, ent);
+ break;
+
case SCU_COMPLETION_TYPE_NOTIFY: {
event_cycle ^= ((event_get+1) & SCU_MAX_EVENTS) <<
(SMU_COMPLETION_QUEUE_GET_EVENT_CYCLE_BIT_SHIFT - SCU_MAX_EVENTS_SHIFT);
@@ -1091,6 +1094,7 @@ static void isci_host_completion_routine(unsigned long data)
struct isci_request *request;
struct isci_request *next_request;
struct sas_task *task;
+ u16 active;
INIT_LIST_HEAD(&completed_request_list);
INIT_LIST_HEAD(&errored_request_list);
@@ -1181,6 +1185,13 @@ static void isci_host_completion_routine(unsigned long data)
}
}
+ /* the coalesence timeout doubles at each encoding step, so
+ * update it based on the ilog2 value of the outstanding requests
+ */
+ active = isci_tci_active(ihost);
+ writel(SMU_ICC_GEN_VAL(NUMBER, active) |
+ SMU_ICC_GEN_VAL(TIMER, ISCI_COALESCE_BASE + ilog2(active)),
+ &ihost->smu_registers->interrupt_coalesce_control);
}
/**
@@ -1471,7 +1482,7 @@ static void sci_controller_ready_state_enter(struct sci_base_state_machine *sm)
struct isci_host *ihost = container_of(sm, typeof(*ihost), sm);
/* set the default interrupt coalescence number and timeout value. */
- sci_controller_set_interrupt_coalescence(ihost, 0x10, 250);
+ sci_controller_set_interrupt_coalescence(ihost, 0, 0);
}
static void sci_controller_ready_state_exit(struct sci_base_state_machine *sm)
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 062101a..9f33831 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -369,6 +369,9 @@ static inline struct isci_host *dev_to_ihost(struct domain_device *dev)
#define ISCI_TAG_SEQ(tag) (((tag) >> 12) & (SCI_MAX_SEQ-1))
#define ISCI_TAG_TCI(tag) ((tag) & (SCI_MAX_IO_REQUESTS-1))
+/* interrupt coalescing baseline: 9 == 3 to 5us interrupt delay per command */
+#define ISCI_COALESCE_BASE 9
+
/* expander attached sata devices require 3 rnc slots */
static inline int sci_remote_device_node_count(struct isci_remote_device *idev)
{
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 61e0d09..29aa34e 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -59,10 +59,19 @@
#include <linux/firmware.h>
#include <linux/efi.h>
#include <asm/string.h>
+#include <scsi/scsi_host.h>
#include "isci.h"
#include "task.h"
#include "probe_roms.h"
+#define MAJ 1
+#define MIN 0
+#define BUILD 0
+#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
+ __stringify(BUILD)
+
+MODULE_VERSION(DRV_VERSION);
+
static struct scsi_transport_template *isci_transport_template;
static DEFINE_PCI_DEVICE_TABLE(isci_id_table) = {
@@ -113,6 +122,22 @@ unsigned char max_concurr_spinup = 1;
module_param(max_concurr_spinup, byte, 0);
MODULE_PARM_DESC(max_concurr_spinup, "Max concurrent device spinup");
+static ssize_t isci_show_id(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = container_of(dev, typeof(*shost), shost_dev);
+ struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
+ struct isci_host *ihost = container_of(sas_ha, typeof(*ihost), sas_ha);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", ihost->id);
+}
+
+static DEVICE_ATTR(isci_id, S_IRUGO, isci_show_id, NULL);
+
+struct device_attribute *isci_host_attrs[] = {
+ &dev_attr_isci_id,
+ NULL
+};
+
static struct scsi_host_template isci_sht = {
.module = THIS_MODULE,
@@ -138,6 +163,7 @@ static struct scsi_host_template isci_sht = {
.slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
+ .shost_attrs = isci_host_attrs,
};
static struct sas_domain_function_template isci_transport_ops = {
@@ -232,17 +258,6 @@ static int isci_register_sas_ha(struct isci_host *isci_host)
return 0;
}
-static ssize_t isci_show_id(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct Scsi_Host *shost = container_of(dev, typeof(*shost), shost_dev);
- struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
- struct isci_host *ihost = container_of(sas_ha, typeof(*ihost), sas_ha);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", ihost->id);
-}
-
-static DEVICE_ATTR(isci_id, S_IRUGO, isci_show_id, NULL);
-
static void isci_unregister(struct isci_host *isci_host)
{
struct Scsi_Host *shost;
@@ -251,7 +266,6 @@ static void isci_unregister(struct isci_host *isci_host)
return;
shost = isci_host->shost;
- device_remove_file(&shost->shost_dev, &dev_attr_isci_id);
sas_unregister_ha(&isci_host->sas_ha);
@@ -415,14 +429,8 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
if (err)
goto err_shost_remove;
- err = device_create_file(&shost->shost_dev, &dev_attr_isci_id);
- if (err)
- goto err_unregister_ha;
-
return isci_host;
- err_unregister_ha:
- sas_unregister_ha(&(isci_host->sas_ha));
err_shost_remove:
scsi_remove_host(shost);
err_shost:
@@ -540,7 +548,8 @@ static __init int isci_init(void)
{
int err;
- pr_info("%s: Intel(R) C600 SAS Controller Driver\n", DRV_NAME);
+ pr_info("%s: Intel(R) C600 SAS Controller Driver - version %s\n",
+ DRV_NAME, DRV_VERSION);
isci_transport_template = sas_domain_attach_transport(&isci_transport_ops);
if (!isci_transport_template)
diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c
index 79313a7..430fc8f 100644
--- a/drivers/scsi/isci/phy.c
+++ b/drivers/scsi/isci/phy.c
@@ -104,6 +104,7 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy,
u32 parity_count = 0;
u32 llctl, link_rate;
u32 clksm_value = 0;
+ u32 sp_timeouts = 0;
iphy->link_layer_registers = reg;
@@ -211,6 +212,18 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy,
llctl |= SCU_SAS_LLCTL_GEN_VAL(MAX_LINK_RATE, link_rate);
writel(llctl, &iphy->link_layer_registers->link_layer_control);
+ sp_timeouts = readl(&iphy->link_layer_registers->sas_phy_timeouts);
+
+ /* Clear the default 0x36 (54us) RATE_CHANGE timeout value. */
+ sp_timeouts &= ~SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0xFF);
+
+ /* Set RATE_CHANGE timeout value to 0x3B (59us). This ensures SCU can
+ * lock with 3Gb drive when SCU max rate is set to 1.5Gb.
+ */
+ sp_timeouts |= SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0x3B);
+
+ writel(sp_timeouts, &iphy->link_layer_registers->sas_phy_timeouts);
+
if (is_a2(ihost->pdev)) {
/* Program the max ARB time for the PHY to 700us so we inter-operate with
* the PMC expander which shuts down PHYs if the expander PHY generates too
diff --git a/drivers/scsi/isci/registers.h b/drivers/scsi/isci/registers.h
index 9b266c7..00afc73 100644
--- a/drivers/scsi/isci/registers.h
+++ b/drivers/scsi/isci/registers.h
@@ -1299,6 +1299,18 @@ struct scu_transport_layer_registers {
#define SCU_AFE_XCVRCR_OFFSET 0x00DC
#define SCU_AFE_LUTCR_OFFSET 0x00E0
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_ALIGN_DETECTION_SHIFT (0UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_ALIGN_DETECTION_MASK (0x000000FFUL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_HOT_PLUG_SHIFT (8UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_HOT_PLUG_MASK (0x0000FF00UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_COMSAS_DETECTION_SHIFT (16UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_COMSAS_DETECTION_MASK (0x00FF0000UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_RATE_CHANGE_SHIFT (24UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_RATE_CHANGE_MASK (0xFF000000UL)
+
+#define SCU_SAS_PHYTOV_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_##name, value)
+
#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_SHIFT (0)
#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_MASK (0x00000003)
#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1 (0)
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index a46e07a..b5d3a8c 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -732,12 +732,20 @@ sci_io_request_terminate(struct isci_request *ireq)
sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
return SCI_SUCCESS;
case SCI_REQ_TASK_WAIT_TC_RESP:
+ /* The task frame was already confirmed to have been
+ * sent by the SCU HW. Since the state machine is
+ * now only waiting for the task response itself,
+ * abort the request and complete it immediately
+ * and don't wait for the task response.
+ */
sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
return SCI_SUCCESS;
case SCI_REQ_ABORTING:
- sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
- return SCI_SUCCESS;
+ /* If a request has a termination requested twice, return
+ * a failure indication, since HW confirmation of the first
+ * abort is still outstanding.
+ */
case SCI_REQ_COMPLETED:
default:
dev_warn(&ireq->owning_controller->pdev->dev,
@@ -2399,22 +2407,19 @@ static void isci_task_save_for_upper_layer_completion(
}
}
-static void isci_request_process_stp_response(struct sas_task *task,
- void *response_buffer)
+static void isci_process_stp_response(struct sas_task *task, struct dev_to_host_fis *fis)
{
- struct dev_to_host_fis *d2h_reg_fis = response_buffer;
struct task_status_struct *ts = &task->task_status;
struct ata_task_resp *resp = (void *)&ts->buf[0];
- resp->frame_len = le16_to_cpu(*(__le16 *)(response_buffer + 6));
- memcpy(&resp->ending_fis[0], response_buffer + 16, 24);
+ resp->frame_len = sizeof(*fis);
+ memcpy(resp->ending_fis, fis, sizeof(*fis));
ts->buf_valid_size = sizeof(*resp);
- /**
- * If the device fault bit is set in the status register, then
+ /* If the device fault bit is set in the status register, then
* set the sense data and return.
*/
- if (d2h_reg_fis->status & ATA_DF)
+ if (fis->status & ATA_DF)
ts->stat = SAS_PROTO_RESPONSE;
else
ts->stat = SAM_STAT_GOOD;
@@ -2428,7 +2433,6 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
{
struct sas_task *task = isci_request_access_task(request);
struct ssp_response_iu *resp_iu;
- void *resp_buf;
unsigned long task_flags;
struct isci_remote_device *idev = isci_lookup_device(task->dev);
enum service_response response = SAS_TASK_UNDELIVERED;
@@ -2565,9 +2569,7 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
task);
if (sas_protocol_ata(task->task_proto)) {
- resp_buf = &request->stp.rsp;
- isci_request_process_stp_response(task,
- resp_buf);
+ isci_process_stp_response(task, &request->stp.rsp);
} else if (SAS_PROTOCOL_SSP == task->task_proto) {
/* crack the iu response buffer. */
diff --git a/drivers/scsi/isci/unsolicited_frame_control.c b/drivers/scsi/isci/unsolicited_frame_control.c
index e9e1e2a..16f88ab 100644
--- a/drivers/scsi/isci/unsolicited_frame_control.c
+++ b/drivers/scsi/isci/unsolicited_frame_control.c
@@ -72,7 +72,7 @@ int sci_unsolicited_frame_control_construct(struct isci_host *ihost)
*/
buf_len = SCU_MAX_UNSOLICITED_FRAMES * SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
header_len = SCU_MAX_UNSOLICITED_FRAMES * sizeof(struct scu_unsolicited_frame_header);
- size = buf_len + header_len + SCU_MAX_UNSOLICITED_FRAMES * sizeof(dma_addr_t);
+ size = buf_len + header_len + SCU_MAX_UNSOLICITED_FRAMES * sizeof(uf_control->address_table.array[0]);
/*
* The Unsolicited Frame buffers are set at the start of the UF
diff --git a/drivers/scsi/isci/unsolicited_frame_control.h b/drivers/scsi/isci/unsolicited_frame_control.h
index 31cb950..75d8966 100644
--- a/drivers/scsi/isci/unsolicited_frame_control.h
+++ b/drivers/scsi/isci/unsolicited_frame_control.h
@@ -214,7 +214,7 @@ struct sci_uf_address_table_array {
* starting address of the UF address table.
* 64-bit pointers are required by the hardware.
*/
- dma_addr_t *array;
+ u64 *array;
/**
* This field specifies the physical address location for the UF
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index 01ff082..d261e98 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -494,6 +494,9 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
*/
error = lport->tt.frame_send(lport, fp);
+ if (fh->fh_type == FC_TYPE_BLS)
+ return error;
+
/*
* Update the exchange and sequence flags,
* assuming all frames for the sequence have been sent.
@@ -575,42 +578,35 @@ static void fc_seq_set_resp(struct fc_seq *sp,
}
/**
- * fc_seq_exch_abort() - Abort an exchange and sequence
- * @req_sp: The sequence to be aborted
+ * fc_exch_abort_locked() - Abort an exchange
+ * @ep: The exchange to be aborted
* @timer_msec: The period of time to wait before aborting
*
- * Generally called because of a timeout or an abort from the upper layer.
+ * Locking notes: Called with exch lock held
+ *
+ * Return value: 0 on success else error code
*/
-static int fc_seq_exch_abort(const struct fc_seq *req_sp,
- unsigned int timer_msec)
+static int fc_exch_abort_locked(struct fc_exch *ep,
+ unsigned int timer_msec)
{
struct fc_seq *sp;
- struct fc_exch *ep;
struct fc_frame *fp;
int error;
- ep = fc_seq_exch(req_sp);
-
- spin_lock_bh(&ep->ex_lock);
if (ep->esb_stat & (ESB_ST_COMPLETE | ESB_ST_ABNORMAL) ||
- ep->state & (FC_EX_DONE | FC_EX_RST_CLEANUP)) {
- spin_unlock_bh(&ep->ex_lock);
+ ep->state & (FC_EX_DONE | FC_EX_RST_CLEANUP))
return -ENXIO;
- }
/*
* Send the abort on a new sequence if possible.
*/
sp = fc_seq_start_next_locked(&ep->seq);
- if (!sp) {
- spin_unlock_bh(&ep->ex_lock);
+ if (!sp)
return -ENOMEM;
- }
ep->esb_stat |= ESB_ST_SEQ_INIT | ESB_ST_ABNORMAL;
if (timer_msec)
fc_exch_timer_set_locked(ep, timer_msec);
- spin_unlock_bh(&ep->ex_lock);
/*
* If not logged into the fabric, don't send ABTS but leave
@@ -633,6 +629,28 @@ static int fc_seq_exch_abort(const struct fc_seq *req_sp,
}
/**
+ * fc_seq_exch_abort() - Abort an exchange and sequence
+ * @req_sp: The sequence to be aborted
+ * @timer_msec: The period of time to wait before aborting
+ *
+ * Generally called because of a timeout or an abort from the upper layer.
+ *
+ * Return value: 0 on success else error code
+ */
+static int fc_seq_exch_abort(const struct fc_seq *req_sp,
+ unsigned int timer_msec)
+{
+ struct fc_exch *ep;
+ int error;
+
+ ep = fc_seq_exch(req_sp);
+ spin_lock_bh(&ep->ex_lock);
+ error = fc_exch_abort_locked(ep, timer_msec);
+ spin_unlock_bh(&ep->ex_lock);
+ return error;
+}
+
+/**
* fc_exch_timeout() - Handle exchange timer expiration
* @work: The work_struct identifying the exchange that timed out
*/
@@ -1715,6 +1733,7 @@ static void fc_exch_reset(struct fc_exch *ep)
int rc = 1;
spin_lock_bh(&ep->ex_lock);
+ fc_exch_abort_locked(ep, 0);
ep->state |= FC_EX_RST_CLEANUP;
if (cancel_delayed_work(&ep->timeout_work))
atomic_dec(&ep->ex_refcnt); /* drop hold for timer */
@@ -1962,6 +1981,7 @@ static struct fc_seq *fc_exch_seq_send(struct fc_lport *lport,
struct fc_exch *ep;
struct fc_seq *sp = NULL;
struct fc_frame_header *fh;
+ struct fc_fcp_pkt *fsp = NULL;
int rc = 1;
ep = fc_exch_alloc(lport, fp);
@@ -1984,8 +2004,10 @@ static struct fc_seq *fc_exch_seq_send(struct fc_lport *lport,
fc_exch_setup_hdr(ep, fp, ep->f_ctl);
sp->cnt++;
- if (ep->xid <= lport->lro_xid && fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD)
+ if (ep->xid <= lport->lro_xid && fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD) {
+ fsp = fr_fsp(fp);
fc_fcp_ddp_setup(fr_fsp(fp), ep->xid);
+ }
if (unlikely(lport->tt.frame_send(lport, fp)))
goto err;
@@ -1999,7 +2021,8 @@ static struct fc_seq *fc_exch_seq_send(struct fc_lport *lport,
spin_unlock_bh(&ep->ex_lock);
return sp;
err:
- fc_fcp_ddp_done(fr_fsp(fp));
+ if (fsp)
+ fc_fcp_ddp_done(fsp);
rc = fc_exch_done_locked(ep);
spin_unlock_bh(&ep->ex_lock);
if (!rc)
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index afb63c8..4c41ee8 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -2019,6 +2019,11 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd)
struct fc_fcp_internal *si;
int rc = FAILED;
unsigned long flags;
+ int rval;
+
+ rval = fc_block_scsi_eh(sc_cmd);
+ if (rval)
+ return rval;
lport = shost_priv(sc_cmd->device->host);
if (lport->state != LPORT_ST_READY)
@@ -2068,9 +2073,9 @@ int fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
int rc = FAILED;
int rval;
- rval = fc_remote_port_chkready(rport);
+ rval = fc_block_scsi_eh(sc_cmd);
if (rval)
- goto out;
+ return rval;
lport = shost_priv(sc_cmd->device->host);
@@ -2116,6 +2121,8 @@ int fc_eh_host_reset(struct scsi_cmnd *sc_cmd)
FC_SCSI_DBG(lport, "Resetting host\n");
+ fc_block_scsi_eh(sc_cmd);
+
lport->tt.lport_reset(lport);
wait_tmo = jiffies + FC_HOST_RESET_TIMEOUT;
while (!fc_fcp_lport_queue_ready(lport) && time_before(jiffies,
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index e55ed9c..628f347 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -88,6 +88,7 @@
*/
#include <linux/timer.h>
+#include <linux/delay.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
@@ -1029,8 +1030,16 @@ static void fc_lport_enter_reset(struct fc_lport *lport)
FCH_EVT_LIPRESET, 0);
fc_vports_linkchange(lport);
fc_lport_reset_locked(lport);
- if (lport->link_up)
+ if (lport->link_up) {
+ /*
+ * Wait upto resource allocation time out before
+ * doing re-login since incomplete FIP exchanged
+ * from last session may collide with exchanges
+ * in new session.
+ */
+ msleep(lport->r_a_tov);
fc_lport_enter_flogi(lport);
+ }
}
/**
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index f84084b..c9e3dc0 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -1721,7 +1721,7 @@ static int sas_find_bcast_dev(struct domain_device *dev,
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)
+ if (*src_dev)
return res;
}
}
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 7836eb0..a31e05f 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1786,13 +1786,16 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
}
- if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) {
+ if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) {
if (ha->fw_attributes & BIT_4) {
+ int prot = 0;
vha->flags.difdix_supported = 1;
ql_dbg(ql_dbg_user, vha, 0x7082,
"Registered for DIF/DIX type 1 and 3 protection.\n");
+ if (ql2xenabledif == 1)
+ prot = SHOST_DIX_TYPE0_PROTECTION;
scsi_host_set_prot(vha->host,
- SHOST_DIF_TYPE1_PROTECTION
+ prot | SHOST_DIF_TYPE1_PROTECTION
| SHOST_DIF_TYPE2_PROTECTION
| SHOST_DIF_TYPE3_PROTECTION
| SHOST_DIX_TYPE1_PROTECTION
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 2155071..d79cd8a 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -8,24 +8,24 @@
/*
* Table for showing the current message id in use for particular level
* Change this table for addition of log/debug messages.
- * -----------------------------------------------------
- * | Level | Last Value Used |
- * -----------------------------------------------------
- * | Module Init and Probe | 0x0116 |
- * | Mailbox commands | 0x111e |
- * | Device Discovery | 0x2083 |
- * | Queue Command and IO tracing | 0x302e |
- * | DPC Thread | 0x401c |
- * | Async Events | 0x5059 |
- * | Timer Routines | 0x600d |
- * | User Space Interactions | 0x709c |
- * | Task Management | 0x8043 |
- * | AER/EEH | 0x900f |
- * | Virtual Port | 0xa007 |
- * | ISP82XX Specific | 0xb027 |
- * | MultiQ | 0xc00b |
- * | Misc | 0xd00b |
- * -----------------------------------------------------
+ * ----------------------------------------------------------------------
+ * | Level | Last Value Used | Holes |
+ * ----------------------------------------------------------------------
+ * | Module Init and Probe | 0x0116 | |
+ * | Mailbox commands | 0x1126 | |
+ * | Device Discovery | 0x2083 | |
+ * | Queue Command and IO tracing | 0x302e | 0x3008 |
+ * | DPC Thread | 0x401c | |
+ * | Async Events | 0x5059 | |
+ * | Timer Routines | 0x600d | |
+ * | User Space Interactions | 0x709d | |
+ * | Task Management | 0x8041 | |
+ * | AER/EEH | 0x900f | |
+ * | Virtual Port | 0xa007 | |
+ * | ISP82XX Specific | 0xb04f | |
+ * | MultiQ | 0xc00b | |
+ * | Misc | 0xd00b | |
+ * ----------------------------------------------------------------------
*/
#include "qla_def.h"
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index cc5a792..a03eaf4 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2529,6 +2529,7 @@ struct qla_hw_data {
#define DT_ISP8021 BIT_14
#define DT_ISP_LAST (DT_ISP8021 << 1)
+#define DT_T10_PI BIT_25
#define DT_IIDMA BIT_26
#define DT_FWI2 BIT_27
#define DT_ZIO_SUPPORTED BIT_28
@@ -2572,6 +2573,7 @@ struct qla_hw_data {
#define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha))
#define IS_ALOGIO_CAPABLE(ha) (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha))
+#define IS_T10_PI_CAPABLE(ha) ((ha)->device_type & DT_T10_PI)
#define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA)
#define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2)
#define IS_ZIO_SUPPORTED(ha) ((ha)->device_type & DT_ZIO_SUPPORTED)
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 691783a..aa69486 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -537,6 +537,11 @@ struct sts_entry_24xx {
/*
* If DIF Error is set in comp_status, these additional fields are
* defined:
+ *
+ * !!! NOTE: Firmware sends expected/actual DIF data in big endian
+ * format; but all of the "data" field gets swab32-d in the beginning
+ * of qla2x00_status_entry().
+ *
* &data[10] : uint8_t report_runt_bg[2]; - computed guard
* &data[12] : uint8_t actual_dif[8]; - DIF Data received
* &data[20] : uint8_t expected_dif[8]; - DIF Data computed
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index def6942..37da04d 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -3838,15 +3838,12 @@ qla2x00_loop_resync(scsi_qla_host_t *vha)
req = vha->req;
rsp = req->rsp;
- atomic_set(&vha->loop_state, LOOP_UPDATE);
clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
if (vha->flags.online) {
if (!(rval = qla2x00_fw_ready(vha))) {
/* Wait at most MAX_TARGET RSCNs for a stable link. */
wait_time = 256;
do {
- atomic_set(&vha->loop_state, LOOP_UPDATE);
-
/* Issue a marker after FW becomes ready. */
qla2x00_marker(vha, req, rsp, 0, 0,
MK_SYNC_ALL);
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index d2e904b..9902834 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -102,3 +102,32 @@ qla2x00_set_fcport_state(fc_port_t *fcport, int state)
fcport->d_id.b.al_pa);
}
}
+
+static inline int
+qla2x00_hba_err_chk_enabled(srb_t *sp)
+{
+ /*
+ * Uncomment when corresponding SCSI changes are done.
+ *
+ if (!sp->cmd->prot_chk)
+ return 0;
+ *
+ */
+
+ switch (scsi_get_prot_op(sp->cmd)) {
+ case SCSI_PROT_READ_STRIP:
+ case SCSI_PROT_WRITE_INSERT:
+ if (ql2xenablehba_err_chk >= 1)
+ return 1;
+ break;
+ case SCSI_PROT_READ_PASS:
+ case SCSI_PROT_WRITE_PASS:
+ if (ql2xenablehba_err_chk >= 2)
+ return 1;
+ break;
+ case SCSI_PROT_READ_INSERT:
+ case SCSI_PROT_WRITE_STRIP:
+ return 1;
+ }
+ return 0;
+}
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 49d6906..dbec896 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -709,20 +709,28 @@ struct fw_dif_context {
*
*/
static inline void
-qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
+qla24xx_set_t10dif_tags(srb_t *sp, struct fw_dif_context *pkt,
unsigned int protcnt)
{
- struct sd_dif_tuple *spt;
+ struct scsi_cmnd *cmd = sp->cmd;
scsi_qla_host_t *vha = shost_priv(cmd->device->host);
- unsigned char op = scsi_get_prot_op(cmd);
switch (scsi_get_prot_type(cmd)) {
- /* For TYPE 0 protection: no checking */
case SCSI_PROT_DIF_TYPE0:
- pkt->ref_tag_mask[0] = 0x00;
- pkt->ref_tag_mask[1] = 0x00;
- pkt->ref_tag_mask[2] = 0x00;
- pkt->ref_tag_mask[3] = 0x00;
+ /*
+ * No check for ql2xenablehba_err_chk, as it would be an
+ * I/O error if hba tag generation is not done.
+ */
+ pkt->ref_tag = cpu_to_le32((uint32_t)
+ (0xffffffff & scsi_get_lba(cmd)));
+
+ if (!qla2x00_hba_err_chk_enabled(sp))
+ break;
+
+ pkt->ref_tag_mask[0] = 0xff;
+ pkt->ref_tag_mask[1] = 0xff;
+ pkt->ref_tag_mask[2] = 0xff;
+ pkt->ref_tag_mask[3] = 0xff;
break;
/*
@@ -730,20 +738,16 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
* match LBA in CDB + N
*/
case SCSI_PROT_DIF_TYPE2:
- if (!ql2xenablehba_err_chk)
- break;
-
- if (scsi_prot_sg_count(cmd)) {
- spt = page_address(sg_page(scsi_prot_sglist(cmd))) +
- scsi_prot_sglist(cmd)[0].offset;
- pkt->app_tag = swab32(spt->app_tag);
- pkt->app_tag_mask[0] = 0xff;
- pkt->app_tag_mask[1] = 0xff;
- }
+ pkt->app_tag = __constant_cpu_to_le16(0);
+ pkt->app_tag_mask[0] = 0x0;
+ pkt->app_tag_mask[1] = 0x0;
pkt->ref_tag = cpu_to_le32((uint32_t)
(0xffffffff & scsi_get_lba(cmd)));
+ if (!qla2x00_hba_err_chk_enabled(sp))
+ break;
+
/* enable ALL bytes of the ref tag */
pkt->ref_tag_mask[0] = 0xff;
pkt->ref_tag_mask[1] = 0xff;
@@ -763,26 +767,15 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
* 16 bit app tag.
*/
case SCSI_PROT_DIF_TYPE1:
- if (!ql2xenablehba_err_chk)
+ pkt->ref_tag = cpu_to_le32((uint32_t)
+ (0xffffffff & scsi_get_lba(cmd)));
+ pkt->app_tag = __constant_cpu_to_le16(0);
+ pkt->app_tag_mask[0] = 0x0;
+ pkt->app_tag_mask[1] = 0x0;
+
+ if (!qla2x00_hba_err_chk_enabled(sp))
break;
- if (protcnt && (op == SCSI_PROT_WRITE_STRIP ||
- op == SCSI_PROT_WRITE_PASS)) {
- spt = page_address(sg_page(scsi_prot_sglist(cmd))) +
- scsi_prot_sglist(cmd)[0].offset;
- ql_dbg(ql_dbg_io, vha, 0x3008,
- "LBA from user %p, lba = 0x%x for cmd=%p.\n",
- spt, (int)spt->ref_tag, cmd);
- pkt->ref_tag = swab32(spt->ref_tag);
- pkt->app_tag_mask[0] = 0x0;
- pkt->app_tag_mask[1] = 0x0;
- } else {
- pkt->ref_tag = cpu_to_le32((uint32_t)
- (0xffffffff & scsi_get_lba(cmd)));
- pkt->app_tag = __constant_cpu_to_le16(0);
- pkt->app_tag_mask[0] = 0x0;
- pkt->app_tag_mask[1] = 0x0;
- }
/* enable ALL bytes of the ref tag */
pkt->ref_tag_mask[0] = 0xff;
pkt->ref_tag_mask[1] = 0xff;
@@ -798,8 +791,162 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
scsi_get_prot_type(cmd), cmd);
}
+struct qla2_sgx {
+ dma_addr_t dma_addr; /* OUT */
+ uint32_t dma_len; /* OUT */
+
+ uint32_t tot_bytes; /* IN */
+ struct scatterlist *cur_sg; /* IN */
+
+ /* for book keeping, bzero on initial invocation */
+ uint32_t bytes_consumed;
+ uint32_t num_bytes;
+ uint32_t tot_partial;
+
+ /* for debugging */
+ uint32_t num_sg;
+ srb_t *sp;
+};
static int
+qla24xx_get_one_block_sg(uint32_t blk_sz, struct qla2_sgx *sgx,
+ uint32_t *partial)
+{
+ struct scatterlist *sg;
+ uint32_t cumulative_partial, sg_len;
+ dma_addr_t sg_dma_addr;
+
+ if (sgx->num_bytes == sgx->tot_bytes)
+ return 0;
+
+ sg = sgx->cur_sg;
+ cumulative_partial = sgx->tot_partial;
+
+ sg_dma_addr = sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ sgx->dma_addr = sg_dma_addr + sgx->bytes_consumed;
+
+ if ((cumulative_partial + (sg_len - sgx->bytes_consumed)) >= blk_sz) {
+ sgx->dma_len = (blk_sz - cumulative_partial);
+ sgx->tot_partial = 0;
+ sgx->num_bytes += blk_sz;
+ *partial = 0;
+ } else {
+ sgx->dma_len = sg_len - sgx->bytes_consumed;
+ sgx->tot_partial += sgx->dma_len;
+ *partial = 1;
+ }
+
+ sgx->bytes_consumed += sgx->dma_len;
+
+ if (sg_len == sgx->bytes_consumed) {
+ sg = sg_next(sg);
+ sgx->num_sg++;
+ sgx->cur_sg = sg;
+ sgx->bytes_consumed = 0;
+ }
+
+ return 1;
+}
+
+static int
+qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *ha, srb_t *sp,
+ uint32_t *dsd, uint16_t tot_dsds)
+{
+ void *next_dsd;
+ uint8_t avail_dsds = 0;
+ uint32_t dsd_list_len;
+ struct dsd_dma *dsd_ptr;
+ struct scatterlist *sg_prot;
+ uint32_t *cur_dsd = dsd;
+ uint16_t used_dsds = tot_dsds;
+
+ uint32_t prot_int;
+ uint32_t partial;
+ struct qla2_sgx sgx;
+ dma_addr_t sle_dma;
+ uint32_t sle_dma_len, tot_prot_dma_len = 0;
+ struct scsi_cmnd *cmd = sp->cmd;
+
+ prot_int = cmd->device->sector_size;
+
+ memset(&sgx, 0, sizeof(struct qla2_sgx));
+ sgx.tot_bytes = scsi_bufflen(sp->cmd);
+ sgx.cur_sg = scsi_sglist(sp->cmd);
+ sgx.sp = sp;
+
+ sg_prot = scsi_prot_sglist(sp->cmd);
+
+ while (qla24xx_get_one_block_sg(prot_int, &sgx, &partial)) {
+
+ sle_dma = sgx.dma_addr;
+ sle_dma_len = sgx.dma_len;
+alloc_and_fill:
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ?
+ QLA_DSDS_PER_IOCB : used_dsds;
+ dsd_list_len = (avail_dsds + 1) * 12;
+ used_dsds -= avail_dsds;
+
+ /* allocate tracking DS */
+ dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC);
+ if (!dsd_ptr)
+ return 1;
+
+ /* allocate new list */
+ dsd_ptr->dsd_addr = next_dsd =
+ dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC,
+ &dsd_ptr->dsd_list_dma);
+
+ if (!next_dsd) {
+ /*
+ * Need to cleanup only this dsd_ptr, rest
+ * will be done by sp_free_dma()
+ */
+ kfree(dsd_ptr);
+ return 1;
+ }
+
+ list_add_tail(&dsd_ptr->list,
+ &((struct crc_context *)sp->ctx)->dsd_list);
+
+ sp->flags |= SRB_CRC_CTX_DSD_VALID;
+
+ /* add new list to cmd iocb or last list */
+ *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
+ *cur_dsd++ = dsd_list_len;
+ cur_dsd = (uint32_t *)next_dsd;
+ }
+ *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(sle_dma_len);
+ avail_dsds--;
+
+ if (partial == 0) {
+ /* Got a full protection interval */
+ sle_dma = sg_dma_address(sg_prot) + tot_prot_dma_len;
+ sle_dma_len = 8;
+
+ tot_prot_dma_len += sle_dma_len;
+ if (tot_prot_dma_len == sg_dma_len(sg_prot)) {
+ tot_prot_dma_len = 0;
+ sg_prot = sg_next(sg_prot);
+ }
+
+ partial = 1; /* So as to not re-enter this block */
+ goto alloc_and_fill;
+ }
+ }
+ /* Null termination */
+ *cur_dsd++ = 0;
+ *cur_dsd++ = 0;
+ *cur_dsd++ = 0;
+ return 0;
+}
+static int
qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd,
uint16_t tot_dsds)
{
@@ -981,7 +1128,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
struct scsi_cmnd *cmd;
struct scatterlist *cur_seg;
int sgc;
- uint32_t total_bytes;
+ uint32_t total_bytes = 0;
uint32_t data_bytes;
uint32_t dif_bytes;
uint8_t bundling = 1;
@@ -1023,8 +1170,10 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
__constant_cpu_to_le16(CF_READ_DATA);
}
- tot_prot_dsds = scsi_prot_sg_count(cmd);
- if (!tot_prot_dsds)
+ if ((scsi_get_prot_op(sp->cmd) == SCSI_PROT_READ_INSERT) ||
+ (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_STRIP) ||
+ (scsi_get_prot_op(sp->cmd) == SCSI_PROT_READ_STRIP) ||
+ (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_INSERT))
bundling = 0;
/* Allocate CRC context from global pool */
@@ -1047,7 +1196,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
INIT_LIST_HEAD(&crc_ctx_pkt->dsd_list);
- qla24xx_set_t10dif_tags(cmd, (struct fw_dif_context *)
+ qla24xx_set_t10dif_tags(sp, (struct fw_dif_context *)
&crc_ctx_pkt->ref_tag, tot_prot_dsds);
cmd_pkt->crc_context_address[0] = cpu_to_le32(LSD(crc_ctx_dma));
@@ -1076,7 +1225,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
fcp_cmnd->additional_cdb_len |= 2;
int_to_scsilun(sp->cmd->device->lun, &fcp_cmnd->lun);
- host_to_fcp_swap((uint8_t *)&fcp_cmnd->lun, sizeof(fcp_cmnd->lun));
memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len);
cmd_pkt->fcp_cmnd_dseg_address[0] = cpu_to_le32(
@@ -1107,15 +1255,28 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */
/* Compute dif len and adjust data len to incude protection */
- total_bytes = data_bytes;
dif_bytes = 0;
blk_size = cmd->device->sector_size;
- if (scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) {
- dif_bytes = (data_bytes / blk_size) * 8;
- total_bytes += dif_bytes;
+ dif_bytes = (data_bytes / blk_size) * 8;
+
+ switch (scsi_get_prot_op(sp->cmd)) {
+ case SCSI_PROT_READ_INSERT:
+ case SCSI_PROT_WRITE_STRIP:
+ total_bytes = data_bytes;
+ data_bytes += dif_bytes;
+ break;
+
+ case SCSI_PROT_READ_STRIP:
+ case SCSI_PROT_WRITE_INSERT:
+ case SCSI_PROT_READ_PASS:
+ case SCSI_PROT_WRITE_PASS:
+ total_bytes = data_bytes + dif_bytes;
+ break;
+ default:
+ BUG();
}
- if (!ql2xenablehba_err_chk)
+ if (!qla2x00_hba_err_chk_enabled(sp))
fw_prot_opts |= 0x10; /* Disable Guard tag checking */
if (!bundling) {
@@ -1151,7 +1312,12 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
cmd_pkt->control_flags |=
__constant_cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE);
- if (qla24xx_walk_and_build_sglist(ha, sp, cur_dsd,
+
+ if (!bundling && tot_prot_dsds) {
+ if (qla24xx_walk_and_build_sglist_no_difb(ha, sp,
+ cur_dsd, tot_dsds))
+ goto crc_queuing_error;
+ } else if (qla24xx_walk_and_build_sglist(ha, sp, cur_dsd,
(tot_dsds - tot_prot_dsds)))
goto crc_queuing_error;
@@ -1414,6 +1580,22 @@ qla24xx_dif_start_scsi(srb_t *sp)
goto queuing_error;
else
sp->flags |= SRB_DMA_VALID;
+
+ if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) ||
+ (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) {
+ struct qla2_sgx sgx;
+ uint32_t partial;
+
+ memset(&sgx, 0, sizeof(struct qla2_sgx));
+ sgx.tot_bytes = scsi_bufflen(cmd);
+ sgx.cur_sg = scsi_sglist(cmd);
+ sgx.sp = sp;
+
+ nseg = 0;
+ while (qla24xx_get_one_block_sg(
+ cmd->device->sector_size, &sgx, &partial))
+ nseg++;
+ }
} else
nseg = 0;
@@ -1428,6 +1610,11 @@ qla24xx_dif_start_scsi(srb_t *sp)
goto queuing_error;
else
sp->flags |= SRB_CRC_PROT_DMA_VALID;
+
+ if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) ||
+ (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) {
+ nseg = scsi_bufflen(cmd) / cmd->device->sector_size;
+ }
} else {
nseg = 0;
}
@@ -1454,6 +1641,7 @@ qla24xx_dif_start_scsi(srb_t *sp)
/* Build header part of command packet (excluding the OPCODE). */
req->current_outstanding_cmd = handle;
req->outstanding_cmds[handle] = sp;
+ sp->handle = handle;
sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
req->cnt -= req_cnt;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index b16b772..8a7591f 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -719,7 +719,6 @@ skip_rio:
vha->flags.rscn_queue_overflow = 1;
}
- atomic_set(&vha->loop_state, LOOP_UPDATE);
atomic_set(&vha->loop_down_timer, 0);
vha->flags.management_server_logged_in = 0;
@@ -1435,25 +1434,27 @@ struct scsi_dif_tuple {
* ASC/ASCQ fields in the sense buffer with ILLEGAL_REQUEST
* to indicate to the kernel that the HBA detected error.
*/
-static inline void
+static inline int
qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
{
struct scsi_qla_host *vha = sp->fcport->vha;
struct scsi_cmnd *cmd = sp->cmd;
- struct scsi_dif_tuple *ep =
- (struct scsi_dif_tuple *)&sts24->data[20];
- struct scsi_dif_tuple *ap =
- (struct scsi_dif_tuple *)&sts24->data[12];
+ uint8_t *ap = &sts24->data[12];
+ uint8_t *ep = &sts24->data[20];
uint32_t e_ref_tag, a_ref_tag;
uint16_t e_app_tag, a_app_tag;
uint16_t e_guard, a_guard;
- e_ref_tag = be32_to_cpu(ep->ref_tag);
- a_ref_tag = be32_to_cpu(ap->ref_tag);
- e_app_tag = be16_to_cpu(ep->app_tag);
- a_app_tag = be16_to_cpu(ap->app_tag);
- e_guard = be16_to_cpu(ep->guard);
- a_guard = be16_to_cpu(ap->guard);
+ /*
+ * swab32 of the "data" field in the beginning of qla2x00_status_entry()
+ * would make guard field appear at offset 2
+ */
+ a_guard = le16_to_cpu(*(uint16_t *)(ap + 2));
+ a_app_tag = le16_to_cpu(*(uint16_t *)(ap + 0));
+ a_ref_tag = le32_to_cpu(*(uint32_t *)(ap + 4));
+ e_guard = le16_to_cpu(*(uint16_t *)(ep + 2));
+ e_app_tag = le16_to_cpu(*(uint16_t *)(ep + 0));
+ e_ref_tag = le32_to_cpu(*(uint32_t *)(ep + 4));
ql_dbg(ql_dbg_io, vha, 0x3023,
"iocb(s) %p Returned STATUS.\n", sts24);
@@ -1465,6 +1466,63 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag,
a_app_tag, e_app_tag, a_guard, e_guard);
+ /*
+ * Ignore sector if:
+ * For type 3: ref & app tag is all 'f's
+ * For type 0,1,2: app tag is all 'f's
+ */
+ if ((a_app_tag == 0xffff) &&
+ ((scsi_get_prot_type(cmd) != SCSI_PROT_DIF_TYPE3) ||
+ (a_ref_tag == 0xffffffff))) {
+ uint32_t blocks_done, resid;
+ sector_t lba_s = scsi_get_lba(cmd);
+
+ /* 2TB boundary case covered automatically with this */
+ blocks_done = e_ref_tag - (uint32_t)lba_s + 1;
+
+ resid = scsi_bufflen(cmd) - (blocks_done *
+ cmd->device->sector_size);
+
+ scsi_set_resid(cmd, resid);
+ cmd->result = DID_OK << 16;
+
+ /* Update protection tag */
+ if (scsi_prot_sg_count(cmd)) {
+ uint32_t i, j = 0, k = 0, num_ent;
+ struct scatterlist *sg;
+ struct sd_dif_tuple *spt;
+
+ /* Patch the corresponding protection tags */
+ scsi_for_each_prot_sg(cmd, sg,
+ scsi_prot_sg_count(cmd), i) {
+ num_ent = sg_dma_len(sg) / 8;
+ if (k + num_ent < blocks_done) {
+ k += num_ent;
+ continue;
+ }
+ j = blocks_done - k - 1;
+ k = blocks_done;
+ break;
+ }
+
+ if (k != blocks_done) {
+ qla_printk(KERN_WARNING, sp->fcport->vha->hw,
+ "unexpected tag values tag:lba=%x:%llx)\n",
+ e_ref_tag, (unsigned long long)lba_s);
+ return 1;
+ }
+
+ spt = page_address(sg_page(sg)) + sg->offset;
+ spt += j;
+
+ spt->app_tag = 0xffff;
+ if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE3)
+ spt->ref_tag = 0xffffffff;
+ }
+
+ return 0;
+ }
+
/* check guard */
if (e_guard != a_guard) {
scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
@@ -1472,28 +1530,30 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
set_driver_byte(cmd, DRIVER_SENSE);
set_host_byte(cmd, DID_ABORT);
cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
- return;
+ return 1;
}
- /* check appl tag */
- if (e_app_tag != a_app_tag) {
+ /* check ref tag */
+ if (e_ref_tag != a_ref_tag) {
scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x2);
+ 0x10, 0x3);
set_driver_byte(cmd, DRIVER_SENSE);
set_host_byte(cmd, DID_ABORT);
cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
- return;
+ return 1;
}
- /* check ref tag */
- if (e_ref_tag != a_ref_tag) {
+ /* check appl tag */
+ if (e_app_tag != a_app_tag) {
scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x3);
+ 0x10, 0x2);
set_driver_byte(cmd, DRIVER_SENSE);
set_host_byte(cmd, DID_ABORT);
cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
- return;
+ return 1;
}
+
+ return 1;
}
/**
@@ -1767,7 +1827,7 @@ check_scsi_status:
break;
case CS_DIF_ERROR:
- qla2x00_handle_dif_error(sp, sts24);
+ logit = qla2x00_handle_dif_error(sp, sts24);
break;
default:
cp->result = DID_ERROR << 16;
@@ -2468,11 +2528,10 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
goto skip_msi;
}
- if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX ||
- !QLA_MSIX_FW_MODE_1(ha->fw_attributes))) {
+ if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX)) {
ql_log(ql_log_warn, vha, 0x0035,
"MSI-X; Unsupported ISP2432 (0x%X, 0x%X).\n",
- ha->pdev->revision, ha->fw_attributes);
+ ha->pdev->revision, QLA_MSIX_CHIP_REV_24XX);
goto skip_msix;
}
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index c706ed3..f488cc6 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -472,7 +472,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
host->can_queue = base_vha->req->length + 128;
host->this_id = 255;
host->cmd_per_lun = 3;
- if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif)
+ if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif)
host->max_cmd_len = 32;
else
host->max_cmd_len = MAX_CMDSZ;
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index 5cbf33a..049807c 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -2208,6 +2208,7 @@ qla82xx_msix_rsp_q(int irq, void *dev_id)
struct qla_hw_data *ha;
struct rsp_que *rsp;
struct device_reg_82xx __iomem *reg;
+ unsigned long flags;
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -2218,11 +2219,11 @@ qla82xx_msix_rsp_q(int irq, void *dev_id)
ha = rsp->hw;
reg = &ha->iobase->isp82;
- spin_lock_irq(&ha->hardware_lock);
+ spin_lock_irqsave(&ha->hardware_lock, flags);
vha = pci_get_drvdata(ha->pdev);
qla24xx_process_response_queue(vha, rsp);
WRT_REG_DWORD(&reg->host_int, 0);
- spin_unlock_irq(&ha->hardware_lock);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
return IRQ_HANDLED;
}
@@ -2838,6 +2839,16 @@ sufficient_dsds:
int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
+ /* build FCP_CMND IU */
+ memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd));
+ int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun);
+ ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len;
+
+ if (cmd->sc_data_direction == DMA_TO_DEVICE)
+ ctx->fcp_cmnd->additional_cdb_len |= 1;
+ else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+ ctx->fcp_cmnd->additional_cdb_len |= 2;
+
/*
* Update tagged queuing modifier -- default is TSK_SIMPLE (0).
*/
@@ -2854,16 +2865,6 @@ sufficient_dsds:
}
}
- /* build FCP_CMND IU */
- memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd));
- int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun);
- ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len;
-
- if (cmd->sc_data_direction == DMA_TO_DEVICE)
- ctx->fcp_cmnd->additional_cdb_len |= 1;
- else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
- ctx->fcp_cmnd->additional_cdb_len |= 2;
-
memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
fcp_dl = (uint32_t *)(ctx->fcp_cmnd->cdb + 16 +
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index e02df27..4cace3f 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -106,17 +106,21 @@ MODULE_PARM_DESC(ql2xmaxqdepth,
"Maximum queue depth to report for target devices.");
/* Do not change the value of this after module load */
-int ql2xenabledif = 1;
+int ql2xenabledif = 0;
module_param(ql2xenabledif, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xenabledif,
" Enable T10-CRC-DIF "
- " Default is 0 - No DIF Support. 1 - Enable it");
+ " Default is 0 - No DIF Support. 1 - Enable it"
+ ", 2 - Enable DIF for all types, except Type 0.");
-int ql2xenablehba_err_chk;
+int ql2xenablehba_err_chk = 2;
module_param(ql2xenablehba_err_chk, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xenablehba_err_chk,
- " Enable T10-CRC-DIF Error isolation by HBA"
- " Default is 0 - Error isolation disabled, 1 - Enable it");
+ " Enable T10-CRC-DIF Error isolation by HBA:\n"
+ " Default is 1.\n"
+ " 0 -- Error isolation disabled\n"
+ " 1 -- Error isolation enabled only for DIX Type 0\n"
+ " 2 -- Error isolation enabled for all Types\n");
int ql2xiidmaenable=1;
module_param(ql2xiidmaenable, int, S_IRUGO);
@@ -909,7 +913,14 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
"Abort command mbx success.\n");
wait = 1;
}
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
qla2x00_sp_compl(ha, sp);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ /* Did the command return during mailbox execution? */
+ if (ret == FAILED && !CMD_SP(cmd))
+ ret = SUCCESS;
/* Wait for the command to be returned. */
if (wait) {
@@ -2251,7 +2262,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
host->this_id = 255;
host->cmd_per_lun = 3;
host->unique_id = host->host_no;
- if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif)
+ if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif)
host->max_cmd_len = 32;
else
host->max_cmd_len = MAX_CMDSZ;
@@ -2378,13 +2389,16 @@ skip_dpc:
"Detected hba at address=%p.\n",
ha);
- if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) {
+ if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) {
if (ha->fw_attributes & BIT_4) {
+ int prot = 0;
base_vha->flags.difdix_supported = 1;
ql_dbg(ql_dbg_init, base_vha, 0x00f1,
"Registering for DIF/DIX type 1 and 3 protection.\n");
+ if (ql2xenabledif == 1)
+ prot = SHOST_DIX_TYPE0_PROTECTION;
scsi_host_set_prot(host,
- SHOST_DIF_TYPE1_PROTECTION
+ prot | SHOST_DIF_TYPE1_PROTECTION
| SHOST_DIF_TYPE2_PROTECTION
| SHOST_DIF_TYPE3_PROTECTION
| SHOST_DIX_TYPE1_PROTECTION
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 062c97b..13b6357 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.03.07.03-k"
+#define QLA2XXX_VERSION "8.03.07.07-k"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 3
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index d240755..24cacff 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -825,6 +825,9 @@ static void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
{
struct device *dev = mspi->dev;
+ if (!(mspi->flags & SPI_CPM_MODE))
+ return;
+
dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE);
dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 8ac6542..fa594d6 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -786,9 +786,11 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
if (cs_gpio < 0)
cs_gpio = mxc_platform_info->chipselect[i];
+
+ spi_imx->chipselect[i] = cs_gpio;
if (cs_gpio < 0)
continue;
- spi_imx->chipselect[i] = cs_gpio;
+
ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME);
if (ret) {
while (i > 0) {
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index 1d23f38..6a80749 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -50,6 +50,8 @@
#define PCH_RX_THOLD 7
#define PCH_RX_THOLD_MAX 15
+#define PCH_TX_THOLD 2
+
#define PCH_MAX_BAUDRATE 5000000
#define PCH_MAX_FIFO_DEPTH 16
@@ -58,6 +60,7 @@
#define PCH_SLEEP_TIME 10
#define SSN_LOW 0x02U
+#define SSN_HIGH 0x03U
#define SSN_NO_CONTROL 0x00U
#define PCH_MAX_CS 0xFF
#define PCI_DEVICE_ID_GE_SPI 0x8816
@@ -316,16 +319,19 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
/* if transfer complete interrupt */
if (reg_spsr_val & SPSR_FI_BIT) {
- if (tx_index < bpw_len)
+ if ((tx_index == bpw_len) && (rx_index == tx_index)) {
+ /* disable interrupts */
+ pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL);
+
+ /* transfer is completed;
+ inform pch_spi_process_messages */
+ data->transfer_complete = true;
+ data->transfer_active = false;
+ wake_up(&data->wait);
+ } else {
dev_err(&data->master->dev,
"%s : Transfer is not completed", __func__);
- /* disable interrupts */
- pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL);
-
- /* transfer is completed;inform pch_spi_process_messages */
- data->transfer_complete = true;
- data->transfer_active = false;
- wake_up(&data->wait);
+ }
}
}
@@ -348,16 +354,26 @@ static irqreturn_t pch_spi_handler(int irq, void *dev_id)
"%s returning due to suspend\n", __func__);
return IRQ_NONE;
}
- if (data->use_dma)
- return IRQ_NONE;
io_remap_addr = data->io_remap_addr;
spsr = io_remap_addr + PCH_SPSR;
reg_spsr_val = ioread32(spsr);
- if (reg_spsr_val & SPSR_ORF_BIT)
- dev_err(&board_dat->pdev->dev, "%s Over run error", __func__);
+ if (reg_spsr_val & SPSR_ORF_BIT) {
+ dev_err(&board_dat->pdev->dev, "%s Over run error\n", __func__);
+ if (data->current_msg->complete != 0) {
+ data->transfer_complete = true;
+ data->current_msg->status = -EIO;
+ data->current_msg->complete(data->current_msg->context);
+ data->bcurrent_msg_processing = false;
+ data->current_msg = NULL;
+ data->cur_trans = NULL;
+ }
+ }
+
+ if (data->use_dma)
+ return IRQ_NONE;
/* Check if the interrupt is for SPI device */
if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) {
@@ -756,10 +772,6 @@ static void pch_spi_set_ir(struct pch_spi_data *data)
wait_event_interruptible(data->wait, data->transfer_complete);
- pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL);
- dev_dbg(&data->master->dev,
- "%s:no more control over SSN-writing 0 to SSNXCR.", __func__);
-
/* clear all interrupts */
pch_spi_writereg(data->master, PCH_SPSR,
pch_spi_readreg(data->master, PCH_SPSR));
@@ -815,10 +827,11 @@ static void pch_spi_copy_rx_data_for_dma(struct pch_spi_data *data, int bpw)
}
}
-static void pch_spi_start_transfer(struct pch_spi_data *data)
+static int pch_spi_start_transfer(struct pch_spi_data *data)
{
struct pch_spi_dma_ctrl *dma;
unsigned long flags;
+ int rtn;
dma = &data->dma;
@@ -833,19 +846,23 @@ static void pch_spi_start_transfer(struct pch_spi_data *data)
initiating the transfer. */
dev_dbg(&data->master->dev,
"%s:waiting for transfer to get over\n", __func__);
- wait_event_interruptible(data->wait, data->transfer_complete);
+ rtn = wait_event_interruptible_timeout(data->wait,
+ data->transfer_complete,
+ msecs_to_jiffies(2 * HZ));
dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent,
DMA_FROM_DEVICE);
+
+ dma_sync_sg_for_cpu(&data->master->dev, dma->sg_tx_p, dma->nent,
+ DMA_FROM_DEVICE);
+ memset(data->dma.tx_buf_virt, 0, PAGE_SIZE);
+
async_tx_ack(dma->desc_rx);
async_tx_ack(dma->desc_tx);
kfree(dma->sg_tx_p);
kfree(dma->sg_rx_p);
spin_lock_irqsave(&data->lock, flags);
- pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL);
- dev_dbg(&data->master->dev,
- "%s:no more control over SSN-writing 0 to SSNXCR.", __func__);
/* clear fifo threshold, disable interrupts, disable SPI transfer */
pch_spi_setclr_reg(data->master, PCH_SPCR, 0,
@@ -858,6 +875,8 @@ static void pch_spi_start_transfer(struct pch_spi_data *data)
pch_spi_clear_fifo(data->master);
spin_unlock_irqrestore(&data->lock, flags);
+
+ return rtn;
}
static void pch_dma_rx_complete(void *arg)
@@ -1023,8 +1042,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
/* set receive fifo threshold and transmit fifo threshold */
pch_spi_setclr_reg(data->master, PCH_SPCR,
((size - 1) << SPCR_RFIC_FIELD) |
- ((PCH_MAX_FIFO_DEPTH - PCH_DMA_TRANS_SIZE) <<
- SPCR_TFIC_FIELD),
+ (PCH_TX_THOLD << SPCR_TFIC_FIELD),
MASK_RFIC_SPCR_BITS | MASK_TFIC_SPCR_BITS);
spin_unlock_irqrestore(&data->lock, flags);
@@ -1035,13 +1053,20 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
/* offset, length setting */
sg = dma->sg_rx_p;
for (i = 0; i < num; i++, sg++) {
- if (i == 0) {
- sg->offset = 0;
+ if (i == (num - 2)) {
+ sg->offset = size * i;
+ sg->offset = sg->offset * (*bpw / 8);
sg_set_page(sg, virt_to_page(dma->rx_buf_virt), rem,
sg->offset);
sg_dma_len(sg) = rem;
+ } else if (i == (num - 1)) {
+ sg->offset = size * (i - 1) + rem;
+ sg->offset = sg->offset * (*bpw / 8);
+ sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size,
+ sg->offset);
+ sg_dma_len(sg) = size;
} else {
- sg->offset = rem + size * (i - 1);
+ sg->offset = size * i;
sg->offset = sg->offset * (*bpw / 8);
sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size,
sg->offset);
@@ -1065,6 +1090,16 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
dma->desc_rx = desc_rx;
/* TX */
+ if (data->bpw_len > PCH_DMA_TRANS_SIZE) {
+ num = data->bpw_len / PCH_DMA_TRANS_SIZE;
+ size = PCH_DMA_TRANS_SIZE;
+ rem = 16;
+ } else {
+ num = 1;
+ size = data->bpw_len;
+ rem = data->bpw_len;
+ }
+
dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
sg_init_table(dma->sg_tx_p, num); /* Initialize SG table */
/* offset, length setting */
@@ -1162,6 +1197,7 @@ static void pch_spi_process_messages(struct work_struct *pwork)
if (data->use_dma)
pch_spi_request_dma(data,
data->current_msg->spi->bits_per_word);
+ pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL);
do {
/* If we are already processing a message get the next
transfer structure from the message otherwise retrieve
@@ -1184,7 +1220,8 @@ static void pch_spi_process_messages(struct work_struct *pwork)
if (data->use_dma) {
pch_spi_handle_dma(data, &bpw);
- pch_spi_start_transfer(data);
+ if (!pch_spi_start_transfer(data))
+ goto out;
pch_spi_copy_rx_data_for_dma(data, bpw);
} else {
pch_spi_set_tx(data, &bpw);
@@ -1222,6 +1259,8 @@ static void pch_spi_process_messages(struct work_struct *pwork)
} while (data->cur_trans != NULL);
+out:
+ pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH);
if (data->use_dma)
pch_spi_release_dma(data);
}
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index 6859af0..7611def 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -241,8 +241,10 @@ static int labpc_eeprom_write_insn(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data);
static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd);
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_ISA_DMA_API
static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd);
+#endif
+#ifdef CONFIG_COMEDI_PCI
static int labpc_find_device(struct comedi_device *dev, int bus, int slot);
#endif
static int labpc_dio_mem_callback(int dir, int port, int data,
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index 4403e5f..f8b88ad 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -1364,26 +1364,16 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
}
#ifdef XGIFB_PAN
-static int XGIfb_pan_var(struct fb_var_screeninfo *var)
+static int XGIfb_pan_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
unsigned int base;
/* printk("Inside pan_var"); */
- if (var->xoffset > (var->xres_virtual - var->xres)) {
- /* printk("Pan: xo: %d xv %d xr %d\n",
- var->xoffset, var->xres_virtual, var->xres); */
- return -EINVAL;
- }
- if (var->yoffset > (var->yres_virtual - var->yres)) {
- /* printk("Pan: yo: %d yv %d yr %d\n",
- var->yoffset, var->yres_virtual, var->yres); */
- return -EINVAL;
- }
- base = var->yoffset * var->xres_virtual + var->xoffset;
+ base = var->yoffset * info->var.xres_virtual + var->xoffset;
/* calculate base bpp dep. */
- switch (var->bits_per_pixel) {
+ switch (info->var.bits_per_pixel) {
case 16:
base >>= 1;
break;
@@ -1681,9 +1671,9 @@ static int XGIfb_pan_display(struct fb_var_screeninfo *var,
/* printk("\nInside pan_display:\n"); */
- if (var->xoffset > (var->xres_virtual - var->xres))
+ if (var->xoffset > (info->var.xres_virtual - info->var.xres))
return -EINVAL;
- if (var->yoffset > (var->yres_virtual - var->yres))
+ if (var->yoffset > (info->var.yres_virtual - info->var.yres))
return -EINVAL;
if (var->vmode & FB_VMODE_YWRAP) {
@@ -1696,7 +1686,7 @@ static int XGIfb_pan_display(struct fb_var_screeninfo *var,
> info->var.yres_virtual)
return -EINVAL;
}
- err = XGIfb_pan_var(var);
+ err = XGIfb_pan_var(var, info);
if (err < 0)
return err;
diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c
index a3f5162..462fbc2 100644
--- a/drivers/staging/zcache/zcache-main.c
+++ b/drivers/staging/zcache/zcache-main.c
@@ -1242,7 +1242,7 @@ static int zcache_pampd_get_data_and_free(char *data, size_t *bufsize, bool raw,
int ret = 0;
BUG_ON(!is_ephemeral(pool));
- zbud_decompress(virt_to_page(data), pampd);
+ zbud_decompress((struct page *)(data), pampd);
zbud_free_and_delist((struct zbud_hdr *)pampd);
atomic_dec(&zcache_curr_eph_pampd_count);
return ret;
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 497b2e7..5b77316 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -1430,7 +1430,7 @@ static int iscsi_enforce_integrity_rules(
u8 DataSequenceInOrder = 0;
u8 ErrorRecoveryLevel = 0, SessionType = 0;
u8 IFMarker = 0, OFMarker = 0;
- u8 IFMarkInt_Reject = 0, OFMarkInt_Reject = 0;
+ u8 IFMarkInt_Reject = 1, OFMarkInt_Reject = 1;
u32 FirstBurstLength = 0, MaxBurstLength = 0;
struct iscsi_param *param = NULL;
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index a0d23bc..f00137f 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -875,40 +875,6 @@ void iscsit_inc_session_usage_count(struct iscsi_session *sess)
}
/*
- * Used before iscsi_do[rx,tx]_data() to determine iov and [rx,tx]_marker
- * array counts needed for sync and steering.
- */
-static int iscsit_determine_sync_and_steering_counts(
- struct iscsi_conn *conn,
- struct iscsi_data_count *count)
-{
- u32 length = count->data_length;
- u32 marker, markint;
-
- count->sync_and_steering = 1;
-
- marker = (count->type == ISCSI_RX_DATA) ?
- conn->of_marker : conn->if_marker;
- markint = (count->type == ISCSI_RX_DATA) ?
- (conn->conn_ops->OFMarkInt * 4) :
- (conn->conn_ops->IFMarkInt * 4);
- count->ss_iov_count = count->iov_count;
-
- while (length > 0) {
- if (length >= marker) {
- count->ss_iov_count += 3;
- count->ss_marker_count += 2;
-
- length -= marker;
- marker = markint;
- } else
- length = 0;
- }
-
- return 0;
-}
-
-/*
* Setup conn->if_marker and conn->of_marker values based upon
* the initial marker-less interval. (see iSCSI v19 A.2)
*/
@@ -1290,7 +1256,7 @@ int iscsit_fe_sendpage_sg(
struct kvec iov;
u32 tx_hdr_size, data_len;
u32 offset = cmd->first_data_sg_off;
- int tx_sent;
+ int tx_sent, iov_off;
send_hdr:
tx_hdr_size = ISCSI_HDR_LEN;
@@ -1310,9 +1276,19 @@ send_hdr:
}
data_len = cmd->tx_size - tx_hdr_size - cmd->padding;
- if (conn->conn_ops->DataDigest)
+ /*
+ * Set iov_off used by padding and data digest tx_data() calls below
+ * in order to determine proper offset into cmd->iov_data[]
+ */
+ if (conn->conn_ops->DataDigest) {
data_len -= ISCSI_CRC_LEN;
-
+ if (cmd->padding)
+ iov_off = (cmd->iov_data_count - 2);
+ else
+ iov_off = (cmd->iov_data_count - 1);
+ } else {
+ iov_off = (cmd->iov_data_count - 1);
+ }
/*
* Perform sendpage() for each page in the scatterlist
*/
@@ -1341,8 +1317,7 @@ send_pg:
send_padding:
if (cmd->padding) {
- struct kvec *iov_p =
- &cmd->iov_data[cmd->iov_data_count-1];
+ struct kvec *iov_p = &cmd->iov_data[iov_off++];
tx_sent = tx_data(conn, iov_p, 1, cmd->padding);
if (cmd->padding != tx_sent) {
@@ -1356,8 +1331,7 @@ send_padding:
send_datacrc:
if (conn->conn_ops->DataDigest) {
- struct kvec *iov_d =
- &cmd->iov_data[cmd->iov_data_count];
+ struct kvec *iov_d = &cmd->iov_data[iov_off];
tx_sent = tx_data(conn, iov_d, 1, ISCSI_CRC_LEN);
if (ISCSI_CRC_LEN != tx_sent) {
@@ -1431,8 +1405,7 @@ static int iscsit_do_rx_data(
struct iscsi_data_count *count)
{
int data = count->data_length, rx_loop = 0, total_rx = 0, iov_len;
- u32 rx_marker_val[count->ss_marker_count], rx_marker_iov = 0;
- struct kvec iov[count->ss_iov_count], *iov_p;
+ struct kvec *iov_p;
struct msghdr msg;
if (!conn || !conn->sock || !conn->conn_ops)
@@ -1440,93 +1413,8 @@ static int iscsit_do_rx_data(
memset(&msg, 0, sizeof(struct msghdr));
- if (count->sync_and_steering) {
- int size = 0;
- u32 i, orig_iov_count = 0;
- u32 orig_iov_len = 0, orig_iov_loc = 0;
- u32 iov_count = 0, per_iov_bytes = 0;
- u32 *rx_marker, old_rx_marker = 0;
- struct kvec *iov_record;
-
- memset(&rx_marker_val, 0,
- count->ss_marker_count * sizeof(u32));
- memset(&iov, 0, count->ss_iov_count * sizeof(struct kvec));
-
- iov_record = count->iov;
- orig_iov_count = count->iov_count;
- rx_marker = &conn->of_marker;
-
- i = 0;
- size = data;
- orig_iov_len = iov_record[orig_iov_loc].iov_len;
- while (size > 0) {
- pr_debug("rx_data: #1 orig_iov_len %u,"
- " orig_iov_loc %u\n", orig_iov_len, orig_iov_loc);
- pr_debug("rx_data: #2 rx_marker %u, size"
- " %u\n", *rx_marker, size);
-
- if (orig_iov_len >= *rx_marker) {
- iov[iov_count].iov_len = *rx_marker;
- iov[iov_count++].iov_base =
- (iov_record[orig_iov_loc].iov_base +
- per_iov_bytes);
-
- iov[iov_count].iov_len = (MARKER_SIZE / 2);
- iov[iov_count++].iov_base =
- &rx_marker_val[rx_marker_iov++];
- iov[iov_count].iov_len = (MARKER_SIZE / 2);
- iov[iov_count++].iov_base =
- &rx_marker_val[rx_marker_iov++];
- old_rx_marker = *rx_marker;
-
- /*
- * OFMarkInt is in 32-bit words.
- */
- *rx_marker = (conn->conn_ops->OFMarkInt * 4);
- size -= old_rx_marker;
- orig_iov_len -= old_rx_marker;
- per_iov_bytes += old_rx_marker;
-
- pr_debug("rx_data: #3 new_rx_marker"
- " %u, size %u\n", *rx_marker, size);
- } else {
- iov[iov_count].iov_len = orig_iov_len;
- iov[iov_count++].iov_base =
- (iov_record[orig_iov_loc].iov_base +
- per_iov_bytes);
-
- per_iov_bytes = 0;
- *rx_marker -= orig_iov_len;
- size -= orig_iov_len;
-
- if (size)
- orig_iov_len =
- iov_record[++orig_iov_loc].iov_len;
-
- pr_debug("rx_data: #4 new_rx_marker"
- " %u, size %u\n", *rx_marker, size);
- }
- }
- data += (rx_marker_iov * (MARKER_SIZE / 2));
-
- iov_p = &iov[0];
- iov_len = iov_count;
-
- if (iov_count > count->ss_iov_count) {
- pr_err("iov_count: %d, count->ss_iov_count:"
- " %d\n", iov_count, count->ss_iov_count);
- return -1;
- }
- if (rx_marker_iov > count->ss_marker_count) {
- pr_err("rx_marker_iov: %d, count->ss_marker"
- "_count: %d\n", rx_marker_iov,
- count->ss_marker_count);
- return -1;
- }
- } else {
- iov_p = count->iov;
- iov_len = count->iov_count;
- }
+ iov_p = count->iov;
+ iov_len = count->iov_count;
while (total_rx < data) {
rx_loop = kernel_recvmsg(conn->sock, &msg, iov_p, iov_len,
@@ -1541,16 +1429,6 @@ static int iscsit_do_rx_data(
rx_loop, total_rx, data);
}
- if (count->sync_and_steering) {
- int j;
- for (j = 0; j < rx_marker_iov; j++) {
- pr_debug("rx_data: #5 j: %d, offset: %d\n",
- j, rx_marker_val[j]);
- conn->of_marker_offset = rx_marker_val[j];
- }
- total_rx -= (rx_marker_iov * (MARKER_SIZE / 2));
- }
-
return total_rx;
}
@@ -1559,8 +1437,7 @@ static int iscsit_do_tx_data(
struct iscsi_data_count *count)
{
int data = count->data_length, total_tx = 0, tx_loop = 0, iov_len;
- u32 tx_marker_val[count->ss_marker_count], tx_marker_iov = 0;
- struct kvec iov[count->ss_iov_count], *iov_p;
+ struct kvec *iov_p;
struct msghdr msg;
if (!conn || !conn->sock || !conn->conn_ops)
@@ -1573,98 +1450,8 @@ static int iscsit_do_tx_data(
memset(&msg, 0, sizeof(struct msghdr));
- if (count->sync_and_steering) {
- int size = 0;
- u32 i, orig_iov_count = 0;
- u32 orig_iov_len = 0, orig_iov_loc = 0;
- u32 iov_count = 0, per_iov_bytes = 0;
- u32 *tx_marker, old_tx_marker = 0;
- struct kvec *iov_record;
-
- memset(&tx_marker_val, 0,
- count->ss_marker_count * sizeof(u32));
- memset(&iov, 0, count->ss_iov_count * sizeof(struct kvec));
-
- iov_record = count->iov;
- orig_iov_count = count->iov_count;
- tx_marker = &conn->if_marker;
-
- i = 0;
- size = data;
- orig_iov_len = iov_record[orig_iov_loc].iov_len;
- while (size > 0) {
- pr_debug("tx_data: #1 orig_iov_len %u,"
- " orig_iov_loc %u\n", orig_iov_len, orig_iov_loc);
- pr_debug("tx_data: #2 tx_marker %u, size"
- " %u\n", *tx_marker, size);
-
- if (orig_iov_len >= *tx_marker) {
- iov[iov_count].iov_len = *tx_marker;
- iov[iov_count++].iov_base =
- (iov_record[orig_iov_loc].iov_base +
- per_iov_bytes);
-
- tx_marker_val[tx_marker_iov] =
- (size - *tx_marker);
- iov[iov_count].iov_len = (MARKER_SIZE / 2);
- iov[iov_count++].iov_base =
- &tx_marker_val[tx_marker_iov++];
- iov[iov_count].iov_len = (MARKER_SIZE / 2);
- iov[iov_count++].iov_base =
- &tx_marker_val[tx_marker_iov++];
- old_tx_marker = *tx_marker;
-
- /*
- * IFMarkInt is in 32-bit words.
- */
- *tx_marker = (conn->conn_ops->IFMarkInt * 4);
- size -= old_tx_marker;
- orig_iov_len -= old_tx_marker;
- per_iov_bytes += old_tx_marker;
-
- pr_debug("tx_data: #3 new_tx_marker"
- " %u, size %u\n", *tx_marker, size);
- pr_debug("tx_data: #4 offset %u\n",
- tx_marker_val[tx_marker_iov-1]);
- } else {
- iov[iov_count].iov_len = orig_iov_len;
- iov[iov_count++].iov_base
- = (iov_record[orig_iov_loc].iov_base +
- per_iov_bytes);
-
- per_iov_bytes = 0;
- *tx_marker -= orig_iov_len;
- size -= orig_iov_len;
-
- if (size)
- orig_iov_len =
- iov_record[++orig_iov_loc].iov_len;
-
- pr_debug("tx_data: #5 new_tx_marker"
- " %u, size %u\n", *tx_marker, size);
- }
- }
-
- data += (tx_marker_iov * (MARKER_SIZE / 2));
-
- iov_p = &iov[0];
- iov_len = iov_count;
-
- if (iov_count > count->ss_iov_count) {
- pr_err("iov_count: %d, count->ss_iov_count:"
- " %d\n", iov_count, count->ss_iov_count);
- return -1;
- }
- if (tx_marker_iov > count->ss_marker_count) {
- pr_err("tx_marker_iov: %d, count->ss_marker"
- "_count: %d\n", tx_marker_iov,
- count->ss_marker_count);
- return -1;
- }
- } else {
- iov_p = count->iov;
- iov_len = count->iov_count;
- }
+ iov_p = count->iov;
+ iov_len = count->iov_count;
while (total_tx < data) {
tx_loop = kernel_sendmsg(conn->sock, &msg, iov_p, iov_len,
@@ -1679,9 +1466,6 @@ static int iscsit_do_tx_data(
tx_loop, total_tx, data);
}
- if (count->sync_and_steering)
- total_tx -= (tx_marker_iov * (MARKER_SIZE / 2));
-
return total_tx;
}
@@ -1702,12 +1486,6 @@ int rx_data(
c.data_length = data;
c.type = ISCSI_RX_DATA;
- if (conn->conn_ops->OFMarker &&
- (conn->conn_state >= TARG_CONN_STATE_LOGGED_IN)) {
- if (iscsit_determine_sync_and_steering_counts(conn, &c) < 0)
- return -1;
- }
-
return iscsit_do_rx_data(conn, &c);
}
@@ -1728,12 +1506,6 @@ int tx_data(
c.data_length = data;
c.type = ISCSI_TX_DATA;
- if (conn->conn_ops->IFMarker &&
- (conn->conn_state >= TARG_CONN_STATE_LOGGED_IN)) {
- if (iscsit_determine_sync_and_steering_counts(conn, &c) < 0)
- return -1;
- }
-
return iscsit_do_tx_data(conn, &c);
}
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c
index 89ae923..f04d4ef 100644
--- a/drivers/target/target_core_cdb.c
+++ b/drivers/target/target_core_cdb.c
@@ -24,6 +24,7 @@
*/
#include <linux/kernel.h>
+#include <linux/ctype.h>
#include <asm/unaligned.h>
#include <scsi/scsi.h>
@@ -154,6 +155,37 @@ target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
return 0;
}
+static void
+target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf_off)
+{
+ unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0];
+ unsigned char *buf = buf_off;
+ int cnt = 0, next = 1;
+ /*
+ * Generate up to 36 bits of VENDOR SPECIFIC IDENTIFIER starting on
+ * byte 3 bit 3-0 for NAA IEEE Registered Extended DESIGNATOR field
+ * format, followed by 64 bits of VENDOR SPECIFIC IDENTIFIER EXTENSION
+ * to complete the payload. These are based from VPD=0x80 PRODUCT SERIAL
+ * NUMBER set via vpd_unit_serial in target_core_configfs.c to ensure
+ * per device uniqeness.
+ */
+ while (*p != '\0') {
+ if (cnt >= 13)
+ break;
+ if (!isxdigit(*p)) {
+ p++;
+ continue;
+ }
+ if (next != 0) {
+ buf[cnt++] |= hex_to_bin(*p++);
+ next = 0;
+ } else {
+ buf[cnt] = hex_to_bin(*p++) << 4;
+ next = 1;
+ }
+ }
+}
+
/*
* Device identification VPD, for a complete list of
* DESIGNATOR TYPEs see spc4r17 Table 459.
@@ -219,8 +251,7 @@ target_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
* VENDOR_SPECIFIC_IDENTIFIER and
* VENDOR_SPECIFIC_IDENTIFIER_EXTENTION
*/
- buf[off++] |= hex_to_bin(dev->se_sub_dev->t10_wwn.unit_serial[0]);
- hex2bin(&buf[off], &dev->se_sub_dev->t10_wwn.unit_serial[1], 12);
+ target_parse_naa_6h_vendor_specific(dev, &buf[off]);
len = 20;
off = (len + 4);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 8d0c58e..a4b0a8d 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -977,15 +977,17 @@ static void target_qf_do_work(struct work_struct *work)
{
struct se_device *dev = container_of(work, struct se_device,
qf_work_queue);
+ LIST_HEAD(qf_cmd_list);
struct se_cmd *cmd, *cmd_tmp;
spin_lock_irq(&dev->qf_cmd_lock);
- list_for_each_entry_safe(cmd, cmd_tmp, &dev->qf_cmd_list, se_qf_node) {
+ list_splice_init(&dev->qf_cmd_list, &qf_cmd_list);
+ spin_unlock_irq(&dev->qf_cmd_lock);
+ list_for_each_entry_safe(cmd, cmd_tmp, &qf_cmd_list, se_qf_node) {
list_del(&cmd->se_qf_node);
atomic_dec(&dev->dev_qf_count);
smp_mb__after_atomic_dec();
- spin_unlock_irq(&dev->qf_cmd_lock);
pr_debug("Processing %s cmd: %p QUEUE_FULL in work queue"
" context: %s\n", cmd->se_tfo->get_fabric_name(), cmd,
@@ -997,10 +999,7 @@ static void target_qf_do_work(struct work_struct *work)
* has been added to head of queue
*/
transport_add_cmd_to_queue(cmd, cmd->t_state);
-
- spin_lock_irq(&dev->qf_cmd_lock);
}
- spin_unlock_irq(&dev->qf_cmd_lock);
}
unsigned char *transport_dump_cmd_direction(struct se_cmd *cmd)
diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h
index bd4fe21..3749d8b 100644
--- a/drivers/target/tcm_fc/tcm_fc.h
+++ b/drivers/target/tcm_fc/tcm_fc.h
@@ -98,8 +98,7 @@ struct ft_tpg {
struct list_head list; /* linkage in ft_lport_acl tpg_list */
struct list_head lun_list; /* head of LUNs */
struct se_portal_group se_tpg;
- struct task_struct *thread; /* processing thread */
- struct se_queue_obj qobj; /* queue for processing thread */
+ struct workqueue_struct *workqueue;
};
struct ft_lport_acl {
@@ -110,16 +109,10 @@ struct ft_lport_acl {
struct se_wwn fc_lport_wwn;
};
-enum ft_cmd_state {
- FC_CMD_ST_NEW = 0,
- FC_CMD_ST_REJ
-};
-
/*
* Commands
*/
struct ft_cmd {
- enum ft_cmd_state state;
u32 lun; /* LUN from request */
struct ft_sess *sess; /* session held for cmd */
struct fc_seq *seq; /* sequence in exchange mgr */
@@ -127,7 +120,7 @@ struct ft_cmd {
struct fc_frame *req_frame;
unsigned char *cdb; /* pointer to CDB inside frame */
u32 write_data_len; /* data received on writes */
- struct se_queue_req se_req;
+ struct work_struct work;
/* Local sense buffer */
unsigned char ft_sense_buffer[TRANSPORT_SENSE_BUFFER];
u32 was_ddp_setup:1; /* Set only if ddp is setup */
@@ -177,7 +170,6 @@ int ft_is_state_remove(struct se_cmd *);
/*
* other internal functions.
*/
-int ft_thread(void *);
void ft_recv_req(struct ft_sess *, struct fc_frame *);
struct ft_tpg *ft_lport_find_tpg(struct fc_lport *);
struct ft_node_acl *ft_acl_get(struct ft_tpg *, struct fc_rport_priv *);
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c
index 5654dc2..80fbcde 100644
--- a/drivers/target/tcm_fc/tfc_cmd.c
+++ b/drivers/target/tcm_fc/tfc_cmd.c
@@ -62,8 +62,8 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
int count;
se_cmd = &cmd->se_cmd;
- pr_debug("%s: cmd %p state %d sess %p seq %p se_cmd %p\n",
- caller, cmd, cmd->state, cmd->sess, cmd->seq, se_cmd);
+ pr_debug("%s: cmd %p sess %p seq %p se_cmd %p\n",
+ caller, cmd, cmd->sess, cmd->seq, se_cmd);
pr_debug("%s: cmd %p cdb %p\n",
caller, cmd, cmd->cdb);
pr_debug("%s: cmd %p lun %d\n", caller, cmd, cmd->lun);
@@ -90,38 +90,6 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0);
}
-static void ft_queue_cmd(struct ft_sess *sess, struct ft_cmd *cmd)
-{
- struct ft_tpg *tpg = sess->tport->tpg;
- struct se_queue_obj *qobj = &tpg->qobj;
- unsigned long flags;
-
- qobj = &sess->tport->tpg->qobj;
- spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
- list_add_tail(&cmd->se_req.qr_list, &qobj->qobj_list);
- atomic_inc(&qobj->queue_cnt);
- spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
-
- wake_up_process(tpg->thread);
-}
-
-static struct ft_cmd *ft_dequeue_cmd(struct se_queue_obj *qobj)
-{
- unsigned long flags;
- struct se_queue_req *qr;
-
- spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
- if (list_empty(&qobj->qobj_list)) {
- spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
- return NULL;
- }
- qr = list_first_entry(&qobj->qobj_list, struct se_queue_req, qr_list);
- list_del(&qr->qr_list);
- atomic_dec(&qobj->queue_cnt);
- spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
- return container_of(qr, struct ft_cmd, se_req);
-}
-
static void ft_free_cmd(struct ft_cmd *cmd)
{
struct fc_frame *fp;
@@ -282,9 +250,7 @@ u32 ft_get_task_tag(struct se_cmd *se_cmd)
int ft_get_cmd_state(struct se_cmd *se_cmd)
{
- struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
-
- return cmd->state;
+ return 0;
}
int ft_is_state_remove(struct se_cmd *se_cmd)
@@ -505,6 +471,8 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd)
return 0;
}
+static void ft_send_work(struct work_struct *work);
+
/*
* Handle incoming FCP command.
*/
@@ -523,7 +491,9 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp)
goto busy;
}
cmd->req_frame = fp; /* hold frame during cmd */
- ft_queue_cmd(sess, cmd);
+
+ INIT_WORK(&cmd->work, ft_send_work);
+ queue_work(sess->tport->tpg->workqueue, &cmd->work);
return;
busy:
@@ -563,12 +533,13 @@ void ft_recv_req(struct ft_sess *sess, struct fc_frame *fp)
/*
* Send new command to target.
*/
-static void ft_send_cmd(struct ft_cmd *cmd)
+static void ft_send_work(struct work_struct *work)
{
+ struct ft_cmd *cmd = container_of(work, struct ft_cmd, work);
struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame);
struct se_cmd *se_cmd;
struct fcp_cmnd *fcp;
- int data_dir;
+ int data_dir = 0;
u32 data_len;
int task_attr;
int ret;
@@ -675,42 +646,3 @@ static void ft_send_cmd(struct ft_cmd *cmd)
err:
ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
}
-
-/*
- * Handle request in the command thread.
- */
-static void ft_exec_req(struct ft_cmd *cmd)
-{
- pr_debug("cmd state %x\n", cmd->state);
- switch (cmd->state) {
- case FC_CMD_ST_NEW:
- ft_send_cmd(cmd);
- break;
- default:
- break;
- }
-}
-
-/*
- * Processing thread.
- * Currently one thread per tpg.
- */
-int ft_thread(void *arg)
-{
- struct ft_tpg *tpg = arg;
- struct se_queue_obj *qobj = &tpg->qobj;
- struct ft_cmd *cmd;
-
- while (!kthread_should_stop()) {
- schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);
- if (kthread_should_stop())
- goto out;
-
- cmd = ft_dequeue_cmd(qobj);
- if (cmd)
- ft_exec_req(cmd);
- }
-
-out:
- return 0;
-}
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c
index b15879d..8fa39b7 100644
--- a/drivers/target/tcm_fc/tfc_conf.c
+++ b/drivers/target/tcm_fc/tfc_conf.c
@@ -327,7 +327,6 @@ static struct se_portal_group *ft_add_tpg(
tpg->index = index;
tpg->lport_acl = lacl;
INIT_LIST_HEAD(&tpg->lun_list);
- transport_init_queue_obj(&tpg->qobj);
ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg,
tpg, TRANSPORT_TPG_TYPE_NORMAL);
@@ -336,8 +335,8 @@ static struct se_portal_group *ft_add_tpg(
return NULL;
}
- tpg->thread = kthread_run(ft_thread, tpg, "ft_tpg%lu", index);
- if (IS_ERR(tpg->thread)) {
+ tpg->workqueue = alloc_workqueue("tcm_fc", 0, 1);
+ if (!tpg->workqueue) {
kfree(tpg);
return NULL;
}
@@ -356,7 +355,7 @@ static void ft_del_tpg(struct se_portal_group *se_tpg)
pr_debug("del tpg %s\n",
config_item_name(&tpg->se_tpg.tpg_group.cg_item));
- kthread_stop(tpg->thread);
+ destroy_workqueue(tpg->workqueue);
/* Wait for sessions to be freed thru RCU, for BUG_ON below */
synchronize_rcu();
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c
index c37f4cd..d35ea5a 100644
--- a/drivers/target/tcm_fc/tfc_io.c
+++ b/drivers/target/tcm_fc/tfc_io.c
@@ -219,43 +219,41 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp)
if (cmd->was_ddp_setup) {
BUG_ON(!ep);
BUG_ON(!lport);
- }
-
- /*
- * Doesn't expect payload if DDP is setup. Payload
- * is expected to be copied directly to user buffers
- * due to DDP (Large Rx offload),
- */
- buf = fc_frame_payload_get(fp, 1);
- if (buf)
- pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, "
+ /*
+ * Since DDP (Large Rx offload) was setup for this request,
+ * payload is expected to be copied directly to user buffers.
+ */
+ buf = fc_frame_payload_get(fp, 1);
+ if (buf)
+ pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, "
"cmd->sg_cnt 0x%x. DDP was setup"
" hence not expected to receive frame with "
- "payload, Frame will be dropped if "
- "'Sequence Initiative' bit in f_ctl is "
+ "payload, Frame will be dropped if"
+ "'Sequence Initiative' bit in f_ctl is"
"not set\n", __func__, ep->xid, f_ctl,
cmd->sg, cmd->sg_cnt);
- /*
- * Invalidate HW DDP context if it was setup for respective
- * command. Invalidation of HW DDP context is requited in both
- * situation (success and error).
- */
- ft_invl_hw_context(cmd);
+ /*
+ * Invalidate HW DDP context if it was setup for respective
+ * command. Invalidation of HW DDP context is requited in both
+ * situation (success and error).
+ */
+ ft_invl_hw_context(cmd);
- /*
- * If "Sequence Initiative (TSI)" bit set in f_ctl, means last
- * write data frame is received successfully where payload is
- * posted directly to user buffer and only the last frame's
- * header is posted in receive queue.
- *
- * If "Sequence Initiative (TSI)" bit is not set, means error
- * condition w.r.t. DDP, hence drop the packet and let explict
- * ABORTS from other end of exchange timer trigger the recovery.
- */
- if (f_ctl & FC_FC_SEQ_INIT)
- goto last_frame;
- else
- goto drop;
+ /*
+ * If "Sequence Initiative (TSI)" bit set in f_ctl, means last
+ * write data frame is received successfully where payload is
+ * posted directly to user buffer and only the last frame's
+ * header is posted in receive queue.
+ *
+ * If "Sequence Initiative (TSI)" bit is not set, means error
+ * condition w.r.t. DDP, hence drop the packet and let explict
+ * ABORTS from other end of exchange timer trigger the recovery.
+ */
+ if (f_ctl & FC_FC_SEQ_INIT)
+ goto last_frame;
+ else
+ goto drop;
+ }
rel_off = ntohl(fh->fh_parm_offset);
frame_len = fr_len(fp);
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 225123b..58be715 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -4450,7 +4450,7 @@ static int __init rs_init(void)
#if defined(CONFIG_ETRAX_RS485)
#if defined(CONFIG_ETRAX_RS485_ON_PA)
- if (cris_io_interface_allocate_pins(if_ser0, 'a', rs485_pa_bit,
+ if (cris_io_interface_allocate_pins(if_serial_0, 'a', rs485_pa_bit,
rs485_pa_bit)) {
printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
"RS485 pin\n");
@@ -4459,7 +4459,7 @@ static int __init rs_init(void)
}
#endif
#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
- if (cris_io_interface_allocate_pins(if_ser0, 'g', rs485_pa_bit,
+ if (cris_io_interface_allocate_pins(if_serial_0, 'g', rs485_pa_bit,
rs485_port_g_bit)) {
printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
"RS485 pin\n");
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 1e96d1f..723f823 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -761,7 +761,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
memset(buf, 0, retval);
status = 0;
- mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC;
+ mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC;
spin_lock_irqsave(&xhci->lock, flags);
/* For each port, did anything change? If so, set that bit in buf. */
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 54139a2..952e2de 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1934,8 +1934,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
int status = -EINPROGRESS;
struct urb_priv *urb_priv;
struct xhci_ep_ctx *ep_ctx;
+ struct list_head *tmp;
u32 trb_comp_code;
int ret = 0;
+ int td_num = 0;
slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
xdev = xhci->devs[slot_id];
@@ -1957,6 +1959,12 @@ static int handle_tx_event(struct xhci_hcd *xhci,
return -ENODEV;
}
+ /* Count current td numbers if ep->skip is set */
+ if (ep->skip) {
+ list_for_each(tmp, &ep_ring->td_list)
+ td_num++;
+ }
+
event_dma = le64_to_cpu(event->buffer);
trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
/* Look for common error cases */
@@ -2068,7 +2076,18 @@ static int handle_tx_event(struct xhci_hcd *xhci,
goto cleanup;
}
+ /* We've skipped all the TDs on the ep ring when ep->skip set */
+ if (ep->skip && td_num == 0) {
+ ep->skip = false;
+ xhci_dbg(xhci, "All tds on the ep_ring skipped. "
+ "Clear skip flag.\n");
+ ret = 0;
+ goto cleanup;
+ }
+
td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list);
+ if (ep->skip)
+ td_num--;
/* Is this a TRB in the currently executing TD? */
event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c
index 75a39ea..a425d65 100644
--- a/drivers/video/68328fb.c
+++ b/drivers/video/68328fb.c
@@ -378,8 +378,8 @@ static int mc68x328fb_pan_display(struct fb_var_screeninfo *var,
|| var->xoffset)
return -EINVAL;
} else {
- if (var->xoffset + var->xres > info->var.xres_virtual ||
- var->yoffset + var->yres > info->var.yres_virtual)
+ if (var->xoffset + info->var.xres > info->var.xres_virtual ||
+ var->yoffset + info->var.yres > info->var.yres_virtual)
return -EINVAL;
}
info->var.xoffset = var->xoffset;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 549b9606..8165c55 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -259,6 +259,15 @@ config FB_TILEBLITTING
comment "Frame buffer hardware drivers"
depends on FB
+config FB_GRVGA
+ tristate "Aeroflex Gaisler framebuffer support"
+ depends on FB && SPARC
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ This enables support for the SVGACTRL framebuffer in the GRLIB IP library from Aeroflex Gaisler.
+
config FB_CIRRUS
tristate "Cirrus Logic support"
depends on FB && (ZORRO || PCI)
@@ -1756,9 +1765,10 @@ config FB_AU1100
config FB_AU1200
bool "Au1200 LCD Driver"
depends on (FB = y) && MIPS && SOC_AU1200
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select FB_SYS_FOPS
help
This is the framebuffer driver for the AMD Au1200 SOC. It can drive
various panels and CRTs by passing in kernel cmd line option
@@ -2027,7 +2037,7 @@ config FB_TMIO_ACCELL
config FB_S3C
tristate "Samsung S3C framebuffer support"
- depends on FB && S3C_DEV_FB
+ depends on FB && (S3C_DEV_FB || S5P_DEV_FIMD0)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -2110,6 +2120,22 @@ config FB_SM501
If unsure, say N.
+config FB_SMSCUFX
+ tristate "SMSC UFX6000/7000 USB Framebuffer support"
+ depends on FB && USB
+ select FB_MODE_HELPERS
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select FB_SYS_FOPS
+ select FB_DEFERRED_IO
+ ---help---
+ This is a kernel framebuffer driver for SMSC UFX USB devices.
+ Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and
+ mplayer -vo fbdev. Supports both UFX6000 (USB 2.0) and UFX7000
+ (USB 3.0) devices.
+ To compile as a module, choose M here: the module name is smscufx.
+
config FB_UDL
tristate "Displaylink USB Framebuffer support"
depends on FB && USB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 8b83129..9b9d8ff 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o
obj-$(CONFIG_FB_ARC) += arcfb.o
obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
+obj-$(CONFIG_FB_GRVGA) += grvga.o
obj-$(CONFIG_FB_PM2) += pm2fb.o
obj-$(CONFIG_FB_PM3) += pm3fb.o
@@ -127,6 +128,7 @@ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
obj-$(CONFIG_FB_PS3) += ps3fb.o
obj-$(CONFIG_FB_SM501) += sm501fb.o
obj-$(CONFIG_FB_UDL) += udlfb.o
+obj-$(CONFIG_FB_SMSCUFX) += smscufx.o
obj-$(CONFIG_FB_XILINX) += xilinxfb.o
obj-$(CONFIG_SH_MIPI_DSI) += sh_mipi_dsi.o
obj-$(CONFIG_FB_SH_MOBILE_HDMI) += sh_mobile_hdmi.o
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c
index 6183a57..b303f17 100644
--- a/drivers/video/acornfb.c
+++ b/drivers/video/acornfb.c
@@ -850,9 +850,10 @@ acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
u_int y_bottom = var->yoffset;
if (!(var->vmode & FB_VMODE_YWRAP))
- y_bottom += var->yres;
+ y_bottom += info->var.yres;
- BUG_ON(y_bottom > var->yres_virtual);
+ if (y_bottom > info->var.yres_virtual)
+ return -EINVAL;
acornfb_update_dma(info, var);
diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c
index 8686429..555dd4c 100644
--- a/drivers/video/arkfb.c
+++ b/drivers/video/arkfb.c
@@ -908,13 +908,14 @@ static int arkfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info
unsigned int offset;
/* Calculate the offset */
- if (var->bits_per_pixel == 0) {
- offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2);
+ if (info->var.bits_per_pixel == 0) {
+ offset = (var->yoffset / 16) * (info->var.xres_virtual / 2)
+ + (var->xoffset / 2);
offset = offset >> 2;
} else {
offset = (var->yoffset * info->fix.line_length) +
- (var->xoffset * var->bits_per_pixel / 8);
- offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 3);
+ (var->xoffset * info->var.bits_per_pixel / 8);
+ offset = offset >> ((info->var.bits_per_pixel == 4) ? 2 : 3);
}
/* Set the offset */
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 817ab60..244d55b 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -39,7 +39,8 @@
| FBINFO_HWACCEL_YPAN)
static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
- struct fb_var_screeninfo *var)
+ struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
}
@@ -50,14 +51,16 @@ static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
| FBINFO_HWACCEL_YPAN)
static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
- struct fb_var_screeninfo *var)
+ struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
u32 dma2dcfg;
u32 pixeloff;
- pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
+ pixeloff = (var->xoffset * info->var.bits_per_pixel) & 0x1f;
- dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
+ dma2dcfg = (info->var.xres_virtual - info->var.xres)
+ * info->var.bits_per_pixel / 8;
dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
@@ -249,14 +252,14 @@ static void atmel_lcdfb_update_dma(struct fb_info *info,
unsigned long dma_addr;
dma_addr = (fix->smem_start + var->yoffset * fix->line_length
- + var->xoffset * var->bits_per_pixel / 8);
+ + var->xoffset * info->var.bits_per_pixel / 8);
dma_addr &= ~3UL;
/* Set framebuffer DMA base address and pixel offset */
lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
- atmel_lcdfb_update_dma2d(sinfo, var);
+ atmel_lcdfb_update_dma2d(sinfo, var, info);
}
static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 32f8cf6..1506848 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -845,16 +845,16 @@ static int radeonfb_pan_display (struct fb_var_screeninfo *var,
{
struct radeonfb_info *rinfo = info->par;
- if ((var->xoffset + var->xres > var->xres_virtual)
- || (var->yoffset + var->yres > var->yres_virtual))
- return -EINVAL;
+ if ((var->xoffset + info->var.xres > info->var.xres_virtual)
+ || (var->yoffset + info->var.yres > info->var.yres_virtual))
+ return -EINVAL;
if (rinfo->asleep)
return 0;
radeon_fifo_wait(2);
- OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset)
- * var->bits_per_pixel / 8) & ~7);
+ OUTREG(CRTC_OFFSET, (var->yoffset * info->fix.line_length +
+ var->xoffset * info->var.bits_per_pixel / 8) & ~7);
return 0;
}
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index 01a8fde..649cb35 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -110,12 +110,6 @@ static struct fb_var_screeninfo au1100fb_var __devinitdata = {
.vmode = FB_VMODE_NONINTERLACED,
};
-static struct au1100fb_drv_info drv_info;
-
-static int nocursor = 0;
-module_param(nocursor, int, 0644);
-MODULE_PARM_DESC(nocursor, "cursor enable/disable");
-
/* fb_blank
* Blank the screen. Depending on the mode, the screen will be
* activated with the backlight color, or desactivated
@@ -132,7 +126,7 @@ static int au1100fb_fb_blank(int blank_mode, struct fb_info *fbi)
/* Turn on panel */
fbdev->regs->lcd_control |= LCD_CONTROL_GO;
#ifdef CONFIG_MIPS_PB1100
- if (drv_info.panel_idx == 1) {
+ if (fbdev->panel_idx == 1) {
au_writew(au_readw(PB1100_G_CONTROL)
| (PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
PB1100_G_CONTROL);
@@ -147,7 +141,7 @@ static int au1100fb_fb_blank(int blank_mode, struct fb_info *fbi)
/* Turn off panel */
fbdev->regs->lcd_control &= ~LCD_CONTROL_GO;
#ifdef CONFIG_MIPS_PB1100
- if (drv_info.panel_idx == 1) {
+ if (fbdev->panel_idx == 1) {
au_writew(au_readw(PB1100_G_CONTROL)
& ~(PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
PB1100_G_CONTROL);
@@ -428,17 +422,6 @@ int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
return 0;
}
-/* fb_cursor
- * Used to disable cursor drawing...
- */
-int au1100fb_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
-{
- if (nocursor)
- return 0;
- else
- return -EINVAL; /* just to force soft_cursor() call */
-}
-
static struct fb_ops au1100fb_ops =
{
.owner = THIS_MODULE,
@@ -450,13 +433,53 @@ static struct fb_ops au1100fb_ops =
.fb_imageblit = cfb_imageblit,
.fb_rotate = au1100fb_fb_rotate,
.fb_mmap = au1100fb_fb_mmap,
- .fb_cursor = au1100fb_fb_cursor,
};
/*-------------------------------------------------------------------------*/
-/* AU1100 LCD controller device driver */
+static int au1100fb_setup(struct au1100fb_device *fbdev)
+{
+ char *this_opt, *options;
+ int num_panels = ARRAY_SIZE(known_lcd_panels);
+
+ if (num_panels <= 0) {
+ print_err("No LCD panels supported by driver!");
+ return -ENODEV;
+ }
+
+ if (fb_get_options(DRIVER_NAME, &options))
+ return -ENODEV;
+ if (!options)
+ return -ENODEV;
+
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ /* Panel option */
+ if (!strncmp(this_opt, "panel:", 6)) {
+ int i;
+ this_opt += 6;
+ for (i = 0; i < num_panels; i++) {
+ if (!strncmp(this_opt, known_lcd_panels[i].name,
+ strlen(this_opt))) {
+ fbdev->panel = &known_lcd_panels[i];
+ fbdev->panel_idx = i;
+ break;
+ }
+ }
+ if (i >= num_panels) {
+ print_warn("Panel '%s' not supported!", this_opt);
+ return -ENODEV;
+ }
+ }
+ /* Unsupported option */
+ else
+ print_warn("Unsupported option \"%s\"", this_opt);
+ }
+
+ print_info("Panel=%s", fbdev->panel->name);
+
+ return 0;
+}
static int __devinit au1100fb_drv_probe(struct platform_device *dev)
{
@@ -465,22 +488,21 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev)
unsigned long page;
u32 sys_clksrc;
- if (!dev)
- return -EINVAL;
-
/* Allocate new device private */
- if (!(fbdev = kzalloc(sizeof(struct au1100fb_device), GFP_KERNEL))) {
+ fbdev = kzalloc(sizeof(struct au1100fb_device), GFP_KERNEL);
+ if (!fbdev) {
print_err("fail to allocate device private record");
return -ENOMEM;
}
- fbdev->panel = &known_lcd_panels[drv_info.panel_idx];
+ if (au1100fb_setup(fbdev))
+ goto failed;
platform_set_drvdata(dev, (void *)fbdev);
/* Allocate region for our registers and map them */
- if (!(regs_res = platform_get_resource(to_platform_device(dev),
- IORESOURCE_MEM, 0))) {
+ regs_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!regs_res) {
print_err("fail to retrieve registers resource");
return -EFAULT;
}
@@ -500,13 +522,11 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev)
print_dbg("Register memory map at %p", fbdev->regs);
print_dbg("phys=0x%08x, size=%d", fbdev->regs_phys, fbdev->regs_len);
-
-
/* Allocate the framebuffer to the maximum screen size * nbr of video buffers */
fbdev->fb_len = fbdev->panel->xres * fbdev->panel->yres *
(fbdev->panel->bpp >> 3) * AU1100FB_NBR_VIDEO_BUFFERS;
- fbdev->fb_mem = dma_alloc_coherent(dev, PAGE_ALIGN(fbdev->fb_len),
+ fbdev->fb_mem = dma_alloc_coherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len),
&fbdev->fb_phys, GFP_KERNEL);
if (!fbdev->fb_mem) {
print_err("fail to allocate frambuffer (size: %dK))",
@@ -525,7 +545,7 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev)
page < PAGE_ALIGN((unsigned long)fbdev->fb_mem + fbdev->fb_len);
page += PAGE_SIZE) {
#if CONFIG_DMA_NONCOHERENT
- SetPageReserved(virt_to_page(CAC_ADDR(page)));
+ SetPageReserved(virt_to_page(CAC_ADDR((void *)page)));
#else
SetPageReserved(virt_to_page(page));
#endif
@@ -578,7 +598,8 @@ failed:
release_mem_region(fbdev->regs_phys, fbdev->regs_len);
}
if (fbdev->fb_mem) {
- dma_free_noncoherent(dev, fbdev->fb_len, fbdev->fb_mem, fbdev->fb_phys);
+ dma_free_noncoherent(&dev->dev, fbdev->fb_len, fbdev->fb_mem,
+ fbdev->fb_phys);
}
if (fbdev->info.cmap.len != 0) {
fb_dealloc_cmap(&fbdev->info.cmap);
@@ -608,7 +629,8 @@ int au1100fb_drv_remove(struct platform_device *dev)
release_mem_region(fbdev->regs_phys, fbdev->regs_len);
- dma_free_coherent(dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem, fbdev->fb_phys);
+ dma_free_coherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem,
+ fbdev->fb_phys);
fb_dealloc_cmap(&fbdev->info.cmap);
kfree(fbdev->info.pseudo_palette);
@@ -675,101 +697,18 @@ static struct platform_driver au1100fb_driver = {
.resume = au1100fb_drv_resume,
};
-/*-------------------------------------------------------------------------*/
-
-/* Kernel driver */
-
-int au1100fb_setup(char *options)
-{
- char* this_opt;
- int num_panels = ARRAY_SIZE(known_lcd_panels);
- char* mode = NULL;
- int panel_idx = 0;
-
- if (num_panels <= 0) {
- print_err("No LCD panels supported by driver!");
- return -EFAULT;
- }
-
- if (options) {
- while ((this_opt = strsep(&options,",")) != NULL) {
- /* Panel option */
- if (!strncmp(this_opt, "panel:", 6)) {
- int i;
- this_opt += 6;
- for (i = 0; i < num_panels; i++) {
- if (!strncmp(this_opt,
- known_lcd_panels[i].name,
- strlen(this_opt))) {
- panel_idx = i;
- break;
- }
- }
- if (i >= num_panels) {
- print_warn("Panel %s not supported!", this_opt);
- }
- }
- if (!strncmp(this_opt, "nocursor", 8)) {
- this_opt += 8;
- nocursor = 1;
- print_info("Cursor disabled");
- }
- /* Mode option (only option that start with digit) */
- else if (isdigit(this_opt[0])) {
- mode = kstrdup(this_opt, GFP_KERNEL);
- if (!mode) {
- print_err("memory allocation failed");
- return -ENOMEM;
- }
- }
- /* Unsupported option */
- else {
- print_warn("Unsupported option \"%s\"", this_opt);
- }
- }
- }
-
- drv_info.panel_idx = panel_idx;
- drv_info.opt_mode = mode;
-
- print_info("Panel=%s Mode=%s",
- known_lcd_panels[drv_info.panel_idx].name,
- drv_info.opt_mode ? drv_info.opt_mode : "default");
-
- return 0;
-}
-
-int __init au1100fb_init(void)
+static int __init au1100fb_load(void)
{
- char* options;
- int ret;
-
- print_info("" DRIVER_DESC "");
-
- memset(&drv_info, 0, sizeof(drv_info));
-
- if (fb_get_options(DRIVER_NAME, &options))
- return -ENODEV;
-
- /* Setup driver with options */
- ret = au1100fb_setup(options);
- if (ret < 0) {
- print_err("Fail to setup driver");
- return ret;
- }
-
return platform_driver_register(&au1100fb_driver);
}
-void __exit au1100fb_cleanup(void)
+static void __exit au1100fb_unload(void)
{
platform_driver_unregister(&au1100fb_driver);
-
- kfree(drv_info.opt_mode);
}
-module_init(au1100fb_init);
-module_exit(au1100fb_cleanup);
+module_init(au1100fb_load);
+module_exit(au1100fb_unload);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/video/au1100fb.h b/drivers/video/au1100fb.h
index 164fe2f..12d9642d 100644
--- a/drivers/video/au1100fb.h
+++ b/drivers/video/au1100fb.h
@@ -108,6 +108,7 @@ struct au1100fb_device {
unsigned char* fb_mem; /* FrameBuffer memory map */
size_t fb_len;
dma_addr_t fb_phys;
+ int panel_idx;
};
/********************************************************************/
@@ -364,11 +365,6 @@ static struct au1100fb_panel known_lcd_panels[] =
},
};
-struct au1100fb_drv_info {
- int panel_idx;
- char *opt_mode;
-};
-
/********************************************************************/
/* Inline helpers */
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
index 5dff32a..7200559 100644
--- a/drivers/video/au1200fb.c
+++ b/drivers/video/au1200fb.c
@@ -46,18 +46,10 @@
#include <asm/mach-au1x00/au1000.h>
#include "au1200fb.h"
-#ifdef CONFIG_PM
-#include <asm/mach-au1x00/au1xxx_pm.h>
-#endif
-
-#ifndef CONFIG_FB_AU1200_DEVS
-#define CONFIG_FB_AU1200_DEVS 4
-#endif
-
#define DRIVER_NAME "au1200fb"
#define DRIVER_DESC "LCD controller driver for AU1200 processors"
-#define DEBUG 1
+#define DEBUG 0
#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
@@ -150,7 +142,7 @@ struct au1200_lcd_iodata_t {
/* Private, per-framebuffer management information (independent of the panel itself) */
struct au1200fb_device {
- struct fb_info fb_info; /* FB driver info record */
+ struct fb_info *fb_info; /* FB driver info record */
int plane;
unsigned char* fb_mem; /* FrameBuffer memory map */
@@ -158,7 +150,6 @@ struct au1200fb_device {
dma_addr_t fb_phys;
};
-static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS];
/********************************************************************/
/* LCD controller restrictions */
@@ -171,10 +162,18 @@ static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS];
/* Default number of visible screen buffer to allocate */
#define AU1200FB_NBR_VIDEO_BUFFERS 1
+/* Default maximum number of fb devices to create */
+#define MAX_DEVICE_COUNT 4
+
+/* Default window configuration entry to use (see windows[]) */
+#define DEFAULT_WINDOW_INDEX 2
+
/********************************************************************/
+static struct fb_info *_au1200fb_infos[MAX_DEVICE_COUNT];
static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR;
-static int window_index = 2; /* default is zero */
+static int device_count = MAX_DEVICE_COUNT;
+static int window_index = DEFAULT_WINDOW_INDEX; /* default is zero */
static int panel_index = 2; /* default is zero */
static struct window_settings *win;
static struct panel_settings *panel;
@@ -205,12 +204,6 @@ struct window_settings {
extern int board_au1200fb_panel_init (void);
extern int board_au1200fb_panel_shutdown (void);
-#ifdef CONFIG_PM
-int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
- au1xxx_request_t request, void *data);
-au1xxx_power_dev_t *LCD_pm_dev;
-#endif
-
/*
* Default window configurations
*/
@@ -652,25 +645,6 @@ static struct panel_settings known_lcd_panels[] =
/********************************************************************/
-#ifdef CONFIG_PM
-static int set_brightness(unsigned int brightness)
-{
- unsigned int hi1, divider;
-
- /* limit brightness pwm duty to >= 30/1600 */
- if (brightness < 30) {
- brightness = 30;
- }
- divider = (lcd->pwmdiv & 0x3FFFF) + 1;
- hi1 = (lcd->pwmhi >> 16) + 1;
- hi1 = (((brightness & 0xFF) + 1) * divider >> 8);
- lcd->pwmhi &= 0xFFFF;
- lcd->pwmhi |= (hi1 << 16);
-
- return brightness;
-}
-#endif /* CONFIG_PM */
-
static int winbpp (unsigned int winctrl1)
{
int bits = 0;
@@ -712,8 +686,8 @@ static int fbinfo2index (struct fb_info *fb_info)
{
int i;
- for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i) {
- if (fb_info == (struct fb_info *)(&_au1200fb_devices[i].fb_info))
+ for (i = 0; i < device_count; ++i) {
+ if (fb_info == _au1200fb_infos[i])
return i;
}
printk("au1200fb: ERROR: fbinfo2index failed!\n");
@@ -962,7 +936,7 @@ static void au1200_setmode(struct au1200fb_device *fbdev)
lcd->window[plane].winctrl2 = ( 0
| LCD_WINCTRL2_CKMODE_00
| LCD_WINCTRL2_DBM
- | LCD_WINCTRL2_BX_N( fbdev->fb_info.fix.line_length)
+ | LCD_WINCTRL2_BX_N(fbdev->fb_info->fix.line_length)
| LCD_WINCTRL2_SCX_1
| LCD_WINCTRL2_SCY_1
) ;
@@ -1050,7 +1024,7 @@ static void au1200fb_update_fbinfo(struct fb_info *fbi)
static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *fbi)
{
- struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
+ struct au1200fb_device *fbdev = fbi->par;
u32 pixclock;
int screen_size, plane;
@@ -1142,7 +1116,7 @@ static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
*/
static int au1200fb_fb_set_par(struct fb_info *fbi)
{
- struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
+ struct au1200fb_device *fbdev = fbi->par;
au1200fb_update_fbinfo(fbi);
au1200_setmode(fbdev);
@@ -1246,11 +1220,7 @@ static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
unsigned int len;
unsigned long start=0, off;
- struct au1200fb_device *fbdev = (struct au1200fb_device *) info;
-
-#ifdef CONFIG_PM
- au1xxx_pm_access(LCD_pm_dev);
-#endif
+ struct au1200fb_device *fbdev = info->par;
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
return -EINVAL;
@@ -1461,10 +1431,6 @@ static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd,
int plane;
int val;
-#ifdef CONFIG_PM
- au1xxx_pm_access(LCD_pm_dev);
-#endif
-
plane = fbinfo2index(info);
print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane);
@@ -1536,9 +1502,11 @@ static struct fb_ops au1200fb_fb_ops = {
.fb_set_par = au1200fb_fb_set_par,
.fb_setcolreg = au1200fb_fb_setcolreg,
.fb_blank = au1200fb_fb_blank,
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
- .fb_imageblit = cfb_imageblit,
+ .fb_fillrect = sys_fillrect,
+ .fb_copyarea = sys_copyarea,
+ .fb_imageblit = sys_imageblit,
+ .fb_read = fb_sys_read,
+ .fb_write = fb_sys_write,
.fb_sync = NULL,
.fb_ioctl = au1200fb_ioctl,
.fb_mmap = au1200fb_fb_mmap,
@@ -1561,10 +1529,9 @@ static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id)
static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
{
- struct fb_info *fbi = &fbdev->fb_info;
+ struct fb_info *fbi = fbdev->fb_info;
int bpp;
- memset(fbi, 0, sizeof(struct fb_info));
fbi->fbops = &au1200fb_fb_ops;
bpp = winbpp(win->w[fbdev->plane].mode_winctrl1);
@@ -1623,24 +1590,36 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
/* AU1200 LCD controller device driver */
-static int au1200fb_drv_probe(struct platform_device *dev)
+static int __devinit au1200fb_drv_probe(struct platform_device *dev)
{
struct au1200fb_device *fbdev;
+ struct fb_info *fbi = NULL;
unsigned long page;
- int bpp, plane, ret;
+ int bpp, plane, ret, irq;
- if (!dev)
- return -EINVAL;
+ /* shut gcc up */
+ ret = 0;
+ fbdev = NULL;
+
+ /* Kickstart the panel */
+ au1200_setpanel(panel);
- for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) {
+ for (plane = 0; plane < device_count; ++plane) {
bpp = winbpp(win->w[plane].mode_winctrl1);
if (win->w[plane].xres == 0)
win->w[plane].xres = panel->Xres;
if (win->w[plane].yres == 0)
win->w[plane].yres = panel->Yres;
- fbdev = &_au1200fb_devices[plane];
- memset(fbdev, 0, sizeof(struct au1200fb_device));
+ fbi = framebuffer_alloc(sizeof(struct au1200fb_device),
+ &dev->dev);
+ if (!fbi)
+ goto failed;
+
+ _au1200fb_infos[plane] = fbi;
+ fbdev = fbi->par;
+ fbdev->fb_info = fbi;
+
fbdev->plane = plane;
/* Allocate the framebuffer to the maximum screen size */
@@ -1673,30 +1652,31 @@ static int au1200fb_drv_probe(struct platform_device *dev)
goto failed;
/* Register new framebuffer */
- if ((ret = register_framebuffer(&fbdev->fb_info)) < 0) {
+ ret = register_framebuffer(fbi);
+ if (ret < 0) {
print_err("cannot register new framebuffer");
goto failed;
}
- au1200fb_fb_set_par(&fbdev->fb_info);
+ au1200fb_fb_set_par(fbi);
#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
if (plane == 0)
- if (fb_prepare_logo(&fbdev->fb_info, FB_ROTATE_UR)) {
+ if (fb_prepare_logo(fbi, FB_ROTATE_UR)) {
/* Start display and show logo on boot */
- fb_set_cmap(&fbdev->fb_info.cmap,
- &fbdev->fb_info);
-
- fb_show_logo(&fbdev->fb_info, FB_ROTATE_UR);
+ fb_set_cmap(&fbi->cmap, fbi);
+ fb_show_logo(fbi, FB_ROTATE_UR);
}
#endif
}
/* Now hook interrupt too */
- if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq,
- IRQF_DISABLED | IRQF_SHARED, "lcd", (void *)dev)) < 0) {
+ irq = platform_get_irq(dev, 0);
+ ret = request_irq(irq, au1200fb_handle_irq,
+ IRQF_SHARED, "lcd", (void *)dev);
+ if (ret) {
print_err("fail to request interrupt line %d (err: %d)",
- AU1200_LCD_INT, ret);
+ irq, ret);
goto failed;
}
@@ -1705,84 +1685,108 @@ static int au1200fb_drv_probe(struct platform_device *dev)
failed:
/* NOTE: This only does the current plane/window that failed; others are still active */
if (fbdev->fb_mem)
- dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len),
+ dma_free_noncoherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len),
fbdev->fb_mem, fbdev->fb_phys);
- if (fbdev->fb_info.cmap.len != 0)
- fb_dealloc_cmap(&fbdev->fb_info.cmap);
- if (fbdev->fb_info.pseudo_palette)
- kfree(fbdev->fb_info.pseudo_palette);
+ if (fbi) {
+ if (fbi->cmap.len != 0)
+ fb_dealloc_cmap(&fbi->cmap);
+ kfree(fbi->pseudo_palette);
+ }
if (plane == 0)
free_irq(AU1200_LCD_INT, (void*)dev);
return ret;
}
-static int au1200fb_drv_remove(struct platform_device *dev)
+static int __devexit au1200fb_drv_remove(struct platform_device *dev)
{
struct au1200fb_device *fbdev;
+ struct fb_info *fbi;
int plane;
- if (!dev)
- return -ENODEV;
-
/* Turn off the panel */
au1200_setpanel(NULL);
- for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane)
- {
- fbdev = &_au1200fb_devices[plane];
+ for (plane = 0; plane < device_count; ++plane) {
+ fbi = _au1200fb_infos[plane];
+ fbdev = fbi->par;
/* Clean up all probe data */
- unregister_framebuffer(&fbdev->fb_info);
+ unregister_framebuffer(fbi);
if (fbdev->fb_mem)
dma_free_noncoherent(&dev->dev,
PAGE_ALIGN(fbdev->fb_len),
fbdev->fb_mem, fbdev->fb_phys);
- if (fbdev->fb_info.cmap.len != 0)
- fb_dealloc_cmap(&fbdev->fb_info.cmap);
- if (fbdev->fb_info.pseudo_palette)
- kfree(fbdev->fb_info.pseudo_palette);
+ if (fbi->cmap.len != 0)
+ fb_dealloc_cmap(&fbi->cmap);
+ kfree(fbi->pseudo_palette);
+
+ framebuffer_release(fbi);
+ _au1200fb_infos[plane] = NULL;
}
- free_irq(AU1200_LCD_INT, (void *)dev);
+ free_irq(platform_get_irq(dev, 0), (void *)dev);
return 0;
}
#ifdef CONFIG_PM
-static int au1200fb_drv_suspend(struct platform_device *dev, u32 state)
+static int au1200fb_drv_suspend(struct device *dev)
{
- /* TODO */
+ au1200_setpanel(NULL);
+
+ lcd->outmask = 0;
+ au_sync();
+
return 0;
}
-static int au1200fb_drv_resume(struct platform_device *dev)
+static int au1200fb_drv_resume(struct device *dev)
{
- /* TODO */
+ struct fb_info *fbi;
+ int i;
+
+ /* Kickstart the panel */
+ au1200_setpanel(panel);
+
+ for (i = 0; i < device_count; i++) {
+ fbi = _au1200fb_infos[i];
+ au1200fb_fb_set_par(fbi);
+ }
+
return 0;
}
+
+static const struct dev_pm_ops au1200fb_pmops = {
+ .suspend = au1200fb_drv_suspend,
+ .resume = au1200fb_drv_resume,
+ .freeze = au1200fb_drv_suspend,
+ .thaw = au1200fb_drv_resume,
+};
+
+#define AU1200FB_PMOPS (&au1200fb_pmops)
+
+#else
+#define AU1200FB_PMOPS NULL
#endif /* CONFIG_PM */
static struct platform_driver au1200fb_driver = {
.driver = {
- .name = "au1200-lcd",
- .owner = THIS_MODULE,
+ .name = "au1200-lcd",
+ .owner = THIS_MODULE,
+ .pm = AU1200FB_PMOPS,
},
.probe = au1200fb_drv_probe,
- .remove = au1200fb_drv_remove,
-#ifdef CONFIG_PM
- .suspend = au1200fb_drv_suspend,
- .resume = au1200fb_drv_resume,
-#endif
+ .remove = __devexit_p(au1200fb_drv_remove),
};
/*-------------------------------------------------------------------------*/
/* Kernel driver */
-static void au1200fb_setup(void)
+static int au1200fb_setup(void)
{
- char* options = NULL;
- char* this_opt;
+ char *options = NULL;
+ char *this_opt, *endptr;
int num_panels = ARRAY_SIZE(known_lcd_panels);
int panel_idx = -1;
@@ -1827,70 +1831,42 @@ static void au1200fb_setup(void)
nohwcursor = 1;
}
- /* Unsupported option */
- else {
- print_warn("Unsupported option \"%s\"", this_opt);
+ else if (strncmp(this_opt, "devices:", 8) == 0) {
+ this_opt += 8;
+ device_count = simple_strtol(this_opt,
+ &endptr, 0);
+ if ((device_count < 0) ||
+ (device_count > MAX_DEVICE_COUNT))
+ device_count = MAX_DEVICE_COUNT;
}
- }
- }
-}
-#ifdef CONFIG_PM
-static int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
- au1xxx_request_t request, void *data) {
- int retval = -1;
- unsigned int d = 0;
- unsigned int brightness = 0;
-
- if (request == AU1XXX_PM_SLEEP) {
- board_au1200fb_panel_shutdown();
- }
- else if (request == AU1XXX_PM_WAKEUP) {
- if(dev->prev_state == SLEEP_STATE)
- {
- int plane;
- au1200_setpanel(panel);
- for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) {
- struct au1200fb_device *fbdev;
- fbdev = &_au1200fb_devices[plane];
- au1200fb_fb_set_par(&fbdev->fb_info);
+ else if (strncmp(this_opt, "wincfg:", 7) == 0) {
+ this_opt += 7;
+ window_index = simple_strtol(this_opt,
+ &endptr, 0);
+ if ((window_index < 0) ||
+ (window_index >= ARRAY_SIZE(windows)))
+ window_index = DEFAULT_WINDOW_INDEX;
}
- }
- d = *((unsigned int*)data);
- if(d <=10) brightness = 26;
- else if(d<=20) brightness = 51;
- else if(d<=30) brightness = 77;
- else if(d<=40) brightness = 102;
- else if(d<=50) brightness = 128;
- else if(d<=60) brightness = 153;
- else if(d<=70) brightness = 179;
- else if(d<=80) brightness = 204;
- else if(d<=90) brightness = 230;
- else brightness = 255;
- set_brightness(brightness);
- } else if (request == AU1XXX_PM_GETSTATUS) {
- return dev->cur_state;
- } else if (request == AU1XXX_PM_ACCESS) {
- if (dev->cur_state != SLEEP_STATE)
- return retval;
- else {
- au1200_setpanel(panel);
+ else if (strncmp(this_opt, "off", 3) == 0)
+ return 1;
+ /* Unsupported option */
+ else {
+ print_warn("Unsupported option \"%s\"", this_opt);
+ }
}
- } else if (request == AU1XXX_PM_IDLE) {
- } else if (request == AU1XXX_PM_CLEANUP) {
}
-
- return retval;
+ return 0;
}
-#endif
static int __init au1200fb_init(void)
{
print_info("" DRIVER_DESC "");
/* Setup driver with options */
- au1200fb_setup();
+ if (au1200fb_setup())
+ return -ENODEV;
/* Point to the panel selected */
panel = &known_lcd_panels[panel_index];
@@ -1899,17 +1875,6 @@ static int __init au1200fb_init(void)
printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
- /* Kickstart the panel, the framebuffers/windows come soon enough */
- au1200_setpanel(panel);
-
- #ifdef CONFIG_PM
- LCD_pm_dev = new_au1xxx_power_device("LCD", &au1200fb_pm_callback, NULL);
- if ( LCD_pm_dev == NULL)
- printk(KERN_INFO "Unable to create a power management device entry for the au1200fb.\n");
- else
- printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n");
- #endif
-
return platform_driver_register(&au1200fb_driver);
}
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c
index 183b6f6..66bc74d 100644
--- a/drivers/video/backlight/adp8860_bl.c
+++ b/drivers/video/backlight/adp8860_bl.c
@@ -7,7 +7,6 @@
*/
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pm.h>
diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c
index d06886a..98e0304 100644
--- a/drivers/video/backlight/adp8870_bl.c
+++ b/drivers/video/backlight/adp8870_bl.c
@@ -7,7 +7,6 @@
*/
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pm.h>
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index 2464b91..56720fb 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -633,7 +633,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
goto out7;
}
- if (request_irq(info->irq, bfin_bf54x_irq_error, IRQF_DISABLED,
+ if (request_irq(info->irq, bfin_bf54x_irq_error, 0,
"PPI ERROR", info) < 0) {
printk(KERN_ERR DRIVER_NAME
": unable to request PPI ERROR IRQ\n");
diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c
index 23b6c4b..c633068 100644
--- a/drivers/video/bfin-lq035q1-fb.c
+++ b/drivers/video/bfin-lq035q1-fb.c
@@ -695,7 +695,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
goto out7;
}
- ret = request_irq(info->irq, bfin_lq035q1_irq_error, IRQF_DISABLED,
+ ret = request_irq(info->irq, bfin_lq035q1_irq_error, 0,
DRIVER_NAME" PPI ERROR", info);
if (ret < 0) {
dev_err(&pdev->dev, "unable to request PPI ERROR IRQ\n");
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c
index d8de29f..d5e1267 100644
--- a/drivers/video/bfin-t350mcqb-fb.c
+++ b/drivers/video/bfin-t350mcqb-fb.c
@@ -529,7 +529,7 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
goto out7;
}
- ret = request_irq(info->irq, bfin_t350mcqb_irq_error, IRQF_DISABLED,
+ ret = request_irq(info->irq, bfin_t350mcqb_irq_error, 0,
"PPI ERROR", info);
if (ret < 0) {
printk(KERN_ERR DRIVER_NAME
diff --git a/drivers/video/bfin_adv7393fb.c b/drivers/video/bfin_adv7393fb.c
index 8486f54..811dd7f 100644
--- a/drivers/video/bfin_adv7393fb.c
+++ b/drivers/video/bfin_adv7393fb.c
@@ -481,7 +481,7 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client,
goto out_4;
}
- if (request_irq(IRQ_PPI_ERROR, ppi_irq_error, IRQF_DISABLED,
+ if (request_irq(IRQ_PPI_ERROR, ppi_irq_error, 0,
"PPI ERROR", fbdev) < 0) {
dev_err(&client->dev, "unable to request PPI ERROR IRQ\n");
ret = -EFAULT;
diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c
index caaa27d..cb09aa1f 100644
--- a/drivers/video/carminefb.c
+++ b/drivers/video/carminefb.c
@@ -32,11 +32,11 @@
#define CARMINEFB_DEFAULT_VIDEO_MODE 1
static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
-module_param(fb_mode, uint, 444);
+module_param(fb_mode, uint, 0444);
MODULE_PARM_DESC(fb_mode, "Initial video mode as integer.");
static char *fb_mode_str;
-module_param(fb_mode_str, charp, 444);
+module_param(fb_mode_str, charp, 0444);
MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters.");
/*
@@ -46,7 +46,7 @@ MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters.");
* 0b010 Display 1
*/
static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1;
-module_param(fb_displays, int, 444);
+module_param(fb_displays, int, 0444);
MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used");
struct carmine_hw {
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index 9075bea5..7b2c40a 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -550,7 +550,7 @@ static void control_set_hardware(struct fb_info_control *p, struct fb_par_contro
/*
- * Parse user speficied options (`video=controlfb:')
+ * Parse user specified options (`video=controlfb:')
*/
static void __init control_setup(char *options)
{
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index fcdac87..55f91d9 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -35,6 +35,9 @@
#define DRIVER_NAME "da8xx_lcdc"
+#define LCD_VERSION_1 1
+#define LCD_VERSION_2 2
+
/* LCD Status Register */
#define LCD_END_OF_FRAME1 BIT(9)
#define LCD_END_OF_FRAME0 BIT(8)
@@ -49,7 +52,9 @@
#define LCD_DMA_BURST_4 0x2
#define LCD_DMA_BURST_8 0x3
#define LCD_DMA_BURST_16 0x4
-#define LCD_END_OF_FRAME_INT_ENA BIT(2)
+#define LCD_V1_END_OF_FRAME_INT_ENA BIT(2)
+#define LCD_V2_END_OF_FRAME0_INT_ENA BIT(8)
+#define LCD_V2_END_OF_FRAME1_INT_ENA BIT(9)
#define LCD_DUAL_FRAME_BUFFER_ENABLE BIT(0)
/* LCD Control Register */
@@ -65,12 +70,18 @@
#define LCD_MONO_8BIT_MODE BIT(9)
#define LCD_RASTER_ORDER BIT(8)
#define LCD_TFT_MODE BIT(7)
-#define LCD_UNDERFLOW_INT_ENA BIT(6)
-#define LCD_PL_ENABLE BIT(4)
+#define LCD_V1_UNDERFLOW_INT_ENA BIT(6)
+#define LCD_V2_UNDERFLOW_INT_ENA BIT(5)
+#define LCD_V1_PL_INT_ENA BIT(4)
+#define LCD_V2_PL_INT_ENA BIT(6)
#define LCD_MONOCHROME_MODE BIT(1)
#define LCD_RASTER_ENABLE BIT(0)
#define LCD_TFT_ALT_ENABLE BIT(23)
#define LCD_STN_565_ENABLE BIT(24)
+#define LCD_V2_DMA_CLK_EN BIT(2)
+#define LCD_V2_LIDD_CLK_EN BIT(1)
+#define LCD_V2_CORE_CLK_EN BIT(0)
+#define LCD_V2_LPP_B10 26
/* LCD Raster Timing 2 Register */
#define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16)
@@ -82,6 +93,7 @@
#define LCD_INVERT_FRAME_CLOCK BIT(20)
/* LCD Block */
+#define LCD_PID_REG 0x0
#define LCD_CTRL_REG 0x4
#define LCD_STAT_REG 0x8
#define LCD_RASTER_CTRL_REG 0x28
@@ -94,6 +106,17 @@
#define LCD_DMA_FRM_BUF_BASE_ADDR_1_REG 0x4C
#define LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG 0x50
+/* Interrupt Registers available only in Version 2 */
+#define LCD_RAW_STAT_REG 0x58
+#define LCD_MASKED_STAT_REG 0x5c
+#define LCD_INT_ENABLE_SET_REG 0x60
+#define LCD_INT_ENABLE_CLR_REG 0x64
+#define LCD_END_OF_INT_IND_REG 0x68
+
+/* Clock registers available only on Version 2 */
+#define LCD_CLK_ENABLE_REG 0x6c
+#define LCD_CLK_RESET_REG 0x70
+
#define LCD_NUM_BUFFERS 2
#define WSI_TIMEOUT 50
@@ -105,6 +128,8 @@
static resource_size_t da8xx_fb_reg_base;
static struct resource *lcdc_regs;
+static unsigned int lcd_revision;
+static irq_handler_t lcdc_irq_handler;
static inline unsigned int lcdc_read(unsigned int addr)
{
@@ -240,6 +265,7 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
u32 end;
u32 reg_ras;
u32 reg_dma;
+ u32 reg_int;
/* init reg to clear PLM (loading mode) fields */
reg_ras = lcdc_read(LCD_RASTER_CTRL_REG);
@@ -252,7 +278,14 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
end = par->dma_end;
reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY);
- reg_dma |= LCD_END_OF_FRAME_INT_ENA;
+ if (lcd_revision == LCD_VERSION_1) {
+ reg_dma |= LCD_V1_END_OF_FRAME_INT_ENA;
+ } else {
+ reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
+ LCD_V2_END_OF_FRAME0_INT_ENA |
+ LCD_V2_END_OF_FRAME1_INT_ENA;
+ lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
+ }
reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE;
lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
@@ -264,7 +297,14 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
end = start + par->palette_sz - 1;
reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);
- reg_ras |= LCD_PL_ENABLE;
+
+ if (lcd_revision == LCD_VERSION_1) {
+ reg_ras |= LCD_V1_PL_INT_ENA;
+ } else {
+ reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
+ LCD_V2_PL_INT_ENA;
+ lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
+ }
lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
@@ -348,6 +388,7 @@ static void lcd_cfg_vertical_sync(int back_porch, int pulse_width,
static int lcd_cfg_display(const struct lcd_ctrl_config *cfg)
{
u32 reg;
+ u32 reg_int;
reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(LCD_TFT_MODE |
LCD_MONO_8BIT_MODE |
@@ -375,7 +416,13 @@ static int lcd_cfg_display(const struct lcd_ctrl_config *cfg)
}
/* enable additional interrupts here */
- reg |= LCD_UNDERFLOW_INT_ENA;
+ if (lcd_revision == LCD_VERSION_1) {
+ reg |= LCD_V1_UNDERFLOW_INT_ENA;
+ } else {
+ reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
+ LCD_V2_UNDERFLOW_INT_ENA;
+ lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
+ }
lcdc_write(reg, LCD_RASTER_CTRL_REG);
@@ -413,18 +460,43 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
/* Set the Panel Width */
/* Pixels per line = (PPL + 1)*16 */
- /*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/
- width &= 0x3f0;
+ if (lcd_revision == LCD_VERSION_1) {
+ /*
+ * 0x3F in bits 4..9 gives max horizontal resolution = 1024
+ * pixels.
+ */
+ width &= 0x3f0;
+ } else {
+ /*
+ * 0x7F in bits 4..10 gives max horizontal resolution = 2048
+ * pixels.
+ */
+ width &= 0x7f0;
+ }
+
reg = lcdc_read(LCD_RASTER_TIMING_0_REG);
reg &= 0xfffffc00;
- reg |= ((width >> 4) - 1) << 4;
+ if (lcd_revision == LCD_VERSION_1) {
+ reg |= ((width >> 4) - 1) << 4;
+ } else {
+ width = (width >> 4) - 1;
+ reg |= ((width & 0x3f) << 4) | ((width & 0x40) >> 3);
+ }
lcdc_write(reg, LCD_RASTER_TIMING_0_REG);
/* Set the Panel Height */
+ /* Set bits 9:0 of Lines Per Pixel */
reg = lcdc_read(LCD_RASTER_TIMING_1_REG);
reg = ((height - 1) & 0x3ff) | (reg & 0xfffffc00);
lcdc_write(reg, LCD_RASTER_TIMING_1_REG);
+ /* Set bit 10 of Lines Per Pixel */
+ if (lcd_revision == LCD_VERSION_2) {
+ reg = lcdc_read(LCD_RASTER_TIMING_2_REG);
+ reg |= ((height - 1) & 0x400) << 16;
+ lcdc_write(reg, LCD_RASTER_TIMING_2_REG);
+ }
+
/* Set the Raster Order of the Frame Buffer */
reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8);
if (raster_order)
@@ -511,6 +583,9 @@ static void lcd_reset(struct da8xx_fb_par *par)
/* DMA has to be disabled */
lcdc_write(0, LCD_DMA_CTRL_REG);
lcdc_write(0, LCD_RASTER_CTRL_REG);
+
+ if (lcd_revision == LCD_VERSION_2)
+ lcdc_write(0, LCD_INT_ENABLE_SET_REG);
}
static void lcd_calc_clk_divider(struct da8xx_fb_par *par)
@@ -523,6 +598,11 @@ static void lcd_calc_clk_divider(struct da8xx_fb_par *par)
/* Configure the LCD clock divisor. */
lcdc_write(LCD_CLK_DIVISOR(div) |
(LCD_RASTER_MODE & 0x1), LCD_CTRL_REG);
+
+ if (lcd_revision == LCD_VERSION_2)
+ lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN |
+ LCD_V2_CORE_CLK_EN, LCD_CLK_ENABLE_REG);
+
}
static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
@@ -583,7 +663,63 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
return 0;
}
-static irqreturn_t lcdc_irq_handler(int irq, void *arg)
+/* IRQ handler for version 2 of LCDC */
+static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
+{
+ struct da8xx_fb_par *par = arg;
+ u32 stat = lcdc_read(LCD_MASKED_STAT_REG);
+ u32 reg_int;
+
+ if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
+ lcd_disable_raster();
+ lcdc_write(stat, LCD_MASKED_STAT_REG);
+ lcd_enable_raster();
+ } else if (stat & LCD_PL_LOAD_DONE) {
+ /*
+ * Must disable raster before changing state of any control bit.
+ * And also must be disabled before clearing the PL loading
+ * interrupt via the following write to the status register. If
+ * this is done after then one gets multiple PL done interrupts.
+ */
+ lcd_disable_raster();
+
+ lcdc_write(stat, LCD_MASKED_STAT_REG);
+
+ /* Disable PL completion inerrupt */
+ reg_int = lcdc_read(LCD_INT_ENABLE_CLR_REG) |
+ (LCD_V2_PL_INT_ENA);
+ lcdc_write(reg_int, LCD_INT_ENABLE_CLR_REG);
+
+ /* Setup and start data loading mode */
+ lcd_blit(LOAD_DATA, par);
+ } else {
+ lcdc_write(stat, LCD_MASKED_STAT_REG);
+
+ if (stat & LCD_END_OF_FRAME0) {
+ lcdc_write(par->dma_start,
+ LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
+ lcdc_write(par->dma_end,
+ LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+ par->vsync_flag = 1;
+ wake_up_interruptible(&par->vsync_wait);
+ }
+
+ if (stat & LCD_END_OF_FRAME1) {
+ lcdc_write(par->dma_start,
+ LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
+ lcdc_write(par->dma_end,
+ LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
+ par->vsync_flag = 1;
+ wake_up_interruptible(&par->vsync_wait);
+ }
+ }
+
+ lcdc_write(0, LCD_END_OF_INT_IND_REG);
+ return IRQ_HANDLED;
+}
+
+/* IRQ handler for version 1 LCDC */
+static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
{
struct da8xx_fb_par *par = arg;
u32 stat = lcdc_read(LCD_STAT_REG);
@@ -606,7 +742,7 @@ static irqreturn_t lcdc_irq_handler(int irq, void *arg)
/* Disable PL completion inerrupt */
reg_ras = lcdc_read(LCD_RASTER_CTRL_REG);
- reg_ras &= ~LCD_PL_ENABLE;
+ reg_ras &= ~LCD_V1_PL_INT_ENA;
lcdc_write(reg_ras, LCD_RASTER_CTRL_REG);
/* Setup and start data loading mode */
@@ -877,8 +1013,8 @@ static int da8xx_pan_display(struct fb_var_screeninfo *var,
start = fix->smem_start +
new_var.yoffset * fix->line_length +
- new_var.xoffset * var->bits_per_pixel / 8;
- end = start + var->yres * fix->line_length - 1;
+ new_var.xoffset * fbi->var.bits_per_pixel / 8;
+ end = start + fbi->var.yres * fix->line_length - 1;
par->dma_start = start;
par->dma_end = end;
}
@@ -945,6 +1081,22 @@ static int __devinit fb_probe(struct platform_device *device)
if (ret)
goto err_clk_put;
+ /* Determine LCD IP Version */
+ switch (lcdc_read(LCD_PID_REG)) {
+ case 0x4C100102:
+ lcd_revision = LCD_VERSION_1;
+ break;
+ case 0x4F200800:
+ lcd_revision = LCD_VERSION_2;
+ break;
+ default:
+ dev_warn(&device->dev, "Unknown PID Reg value 0x%x, "
+ "defaulting to LCD revision 1\n",
+ lcdc_read(LCD_PID_REG));
+ lcd_revision = LCD_VERSION_1;
+ break;
+ }
+
for (i = 0, lcdc_info = known_lcd_panels;
i < ARRAY_SIZE(known_lcd_panels);
i++, lcdc_info++) {
@@ -1085,7 +1237,13 @@ static int __devinit fb_probe(struct platform_device *device)
}
#endif
- ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par);
+ if (lcd_revision == LCD_VERSION_1)
+ lcdc_irq_handler = lcdc_irq_handler_rev01;
+ else
+ lcdc_irq_handler = lcdc_irq_handler_rev02;
+
+ ret = request_irq(par->irq, lcdc_irq_handler, 0,
+ DRIVER_NAME, par);
if (ret)
goto irq_freq;
return 0;
diff --git a/drivers/video/fb-puv3.c b/drivers/video/fb-puv3.c
index 27f2c57..60a787f 100644
--- a/drivers/video/fb-puv3.c
+++ b/drivers/video/fb-puv3.c
@@ -624,8 +624,8 @@ static int unifb_pan_display(struct fb_var_screeninfo *var,
|| var->xoffset)
return -EINVAL;
} else {
- if (var->xoffset + var->xres > info->var.xres_virtual ||
- var->yoffset + var->yres > info->var.yres_virtual)
+ if (var->xoffset + info->var.xres > info->var.xres_virtual ||
+ var->yoffset + info->var.yres > info->var.yres_virtual)
return -EINVAL;
}
info->var.xoffset = var->xoffset;
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index 32814e8..c27e153 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -223,8 +223,7 @@ void fb_deferred_io_cleanup(struct fb_info *info)
int i;
BUG_ON(!fbdefio);
- cancel_delayed_work(&info->deferred_work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&info->deferred_work);
/* clear out the mapping that we setup */
for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) {
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 5aac00e..ad93629 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1738,8 +1738,6 @@ void fb_set_suspend(struct fb_info *info, int state)
{
struct fb_event event;
- if (!lock_fb_info(info))
- return;
event.info = info;
if (state) {
fb_notifier_call_chain(FB_EVENT_SUSPEND, &event);
@@ -1748,7 +1746,6 @@ void fb_set_suspend(struct fb_info *info, int state)
info->state = FBINFO_STATE_RUNNING;
fb_notifier_call_chain(FB_EVENT_RESUME, &event);
}
- unlock_fb_info(info);
}
/**
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 4f57485..cef6557 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -493,7 +493,8 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
return num;
}
-static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
+static int get_std_timing(unsigned char *block, struct fb_videomode *mode,
+ int ver, int rev)
{
int xres, yres = 0, refresh, ratio, i;
@@ -504,7 +505,11 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
ratio = (block[1] & 0xc0) >> 6;
switch (ratio) {
case 0:
- yres = xres;
+ /* in EDID 1.3 the meaning of 0 changed to 16:10 (prior 1:1) */
+ if (ver < 1 || (ver == 1 && rev < 3))
+ yres = xres;
+ else
+ yres = (xres * 10)/16;
break;
case 1:
yres = (xres * 3)/4;
@@ -533,12 +538,12 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
}
static int get_dst_timing(unsigned char *block,
- struct fb_videomode *mode)
+ struct fb_videomode *mode, int ver, int rev)
{
int j, num = 0;
for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE)
- num += get_std_timing(block, &mode[num]);
+ num += get_std_timing(block, &mode[num], ver, rev);
return num;
}
@@ -599,6 +604,10 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
struct fb_videomode *mode, *m;
unsigned char *block;
int num = 0, i, first = 1;
+ int ver, rev;
+
+ ver = edid[EDID_STRUCT_VERSION];
+ rev = edid[EDID_STRUCT_REVISION];
mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
if (mode == NULL)
@@ -632,12 +641,12 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
DPRINTK(" Standard Timings\n");
block = edid + STD_TIMING_DESCRIPTIONS_START;
for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE)
- num += get_std_timing(block, &mode[num]);
+ num += get_std_timing(block, &mode[num], ver, rev);
block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
- num += get_dst_timing(block + 5, &mode[num]);
+ num += get_dst_timing(block + 5, &mode[num], ver, rev);
}
/* Yikes, EDID data is totally useless */
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 04251ce..67afa9c 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -399,9 +399,12 @@ static ssize_t store_fbstate(struct device *device,
state = simple_strtoul(buf, &last, 0);
+ if (!lock_fb_info(fb_info))
+ return -ENODEV;
console_lock();
fb_set_suspend(fb_info, (int)state);
console_unlock();
+ unlock_fb_info(fb_info);
return count;
}
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 0acc7d6..a16beeb 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -30,37 +30,40 @@
#include <linux/clk.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
-
-#include <linux/of_platform.h>
+#include <linux/spinlock.h>
#include <sysdev/fsl_soc.h>
#include <linux/fsl-diu-fb.h>
#include "edid.h"
-/*
- * These parameters give default parameters
- * for video output 1024x768,
- * FIXME - change timing to proper amounts
- * hsync 31.5kHz, vsync 60Hz
- */
-static struct fb_videomode __devinitdata fsl_diu_default_mode = {
- .refresh = 60,
- .xres = 1024,
- .yres = 768,
- .pixclock = 15385,
- .left_margin = 160,
- .right_margin = 24,
- .upper_margin = 29,
- .lower_margin = 3,
- .hsync_len = 136,
- .vsync_len = 6,
- .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- .vmode = FB_VMODE_NONINTERLACED
+#define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */
+ /* 1 for plane 0, 2 for plane 1&2 each */
+
+/* HW cursor parameters */
+#define MAX_CURS 32
+
+/* INT_STATUS/INT_MASK field descriptions */
+#define INT_VSYNC 0x01 /* Vsync interrupt */
+#define INT_VSYNC_WB 0x02 /* Vsync interrupt for write back operation */
+#define INT_UNDRUN 0x04 /* Under run exception interrupt */
+#define INT_PARERR 0x08 /* Display parameters error interrupt */
+#define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */
+
+struct diu_addr {
+ void *vaddr; /* Virtual address */
+ dma_addr_t paddr; /* Physical address */
+ __u32 offset;
};
+/*
+ * List of supported video modes
+ *
+ * The first entry is the default video mode. The remain entries are in
+ * order if increasing resolution and frequency. The 320x240-60 mode is
+ * the initial AOI for the second and third planes.
+ */
static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
{
- .name = "1024x768-60",
.refresh = 60,
.xres = 1024,
.yres = 768,
@@ -75,7 +78,132 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
.vmode = FB_VMODE_NONINTERLACED
},
{
- .name = "1024x768-70",
+ .refresh = 60,
+ .xres = 320,
+ .yres = 240,
+ .pixclock = 79440,
+ .left_margin = 16,
+ .right_margin = 16,
+ .upper_margin = 16,
+ .lower_margin = 5,
+ .hsync_len = 48,
+ .vsync_len = 1,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .refresh = 60,
+ .xres = 640,
+ .yres = 480,
+ .pixclock = 39722,
+ .left_margin = 48,
+ .right_margin = 16,
+ .upper_margin = 33,
+ .lower_margin = 10,
+ .hsync_len = 96,
+ .vsync_len = 2,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .refresh = 72,
+ .xres = 640,
+ .yres = 480,
+ .pixclock = 32052,
+ .left_margin = 128,
+ .right_margin = 24,
+ .upper_margin = 28,
+ .lower_margin = 9,
+ .hsync_len = 40,
+ .vsync_len = 3,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .refresh = 75,
+ .xres = 640,
+ .yres = 480,
+ .pixclock = 31747,
+ .left_margin = 120,
+ .right_margin = 16,
+ .upper_margin = 16,
+ .lower_margin = 1,
+ .hsync_len = 64,
+ .vsync_len = 3,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .refresh = 90,
+ .xres = 640,
+ .yres = 480,
+ .pixclock = 25057,
+ .left_margin = 120,
+ .right_margin = 32,
+ .upper_margin = 14,
+ .lower_margin = 25,
+ .hsync_len = 40,
+ .vsync_len = 14,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .refresh = 100,
+ .xres = 640,
+ .yres = 480,
+ .pixclock = 22272,
+ .left_margin = 48,
+ .right_margin = 32,
+ .upper_margin = 17,
+ .lower_margin = 22,
+ .hsync_len = 128,
+ .vsync_len = 12,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .refresh = 60,
+ .xres = 800,
+ .yres = 480,
+ .pixclock = 33805,
+ .left_margin = 96,
+ .right_margin = 24,
+ .upper_margin = 10,
+ .lower_margin = 3,
+ .hsync_len = 72,
+ .vsync_len = 7,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .refresh = 60,
+ .xres = 800,
+ .yres = 600,
+ .pixclock = 25000,
+ .left_margin = 88,
+ .right_margin = 40,
+ .upper_margin = 23,
+ .lower_margin = 1,
+ .hsync_len = 128,
+ .vsync_len = 4,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .refresh = 60,
+ .xres = 854,
+ .yres = 480,
+ .pixclock = 31518,
+ .left_margin = 104,
+ .right_margin = 16,
+ .upper_margin = 13,
+ .lower_margin = 1,
+ .hsync_len = 88,
+ .vsync_len = 3,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
.refresh = 70,
.xres = 1024,
.yres = 768,
@@ -90,7 +218,6 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
.vmode = FB_VMODE_NONINTERLACED
},
{
- .name = "1024x768-75",
.refresh = 75,
.xres = 1024,
.yres = 768,
@@ -105,7 +232,34 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
.vmode = FB_VMODE_NONINTERLACED
},
{
- .name = "1280x1024-60",
+ .refresh = 60,
+ .xres = 1280,
+ .yres = 480,
+ .pixclock = 18939,
+ .left_margin = 353,
+ .right_margin = 47,
+ .upper_margin = 39,
+ .lower_margin = 4,
+ .hsync_len = 8,
+ .vsync_len = 2,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .refresh = 60,
+ .xres = 1280,
+ .yres = 720,
+ .pixclock = 13426,
+ .left_margin = 192,
+ .right_margin = 64,
+ .upper_margin = 22,
+ .lower_margin = 1,
+ .hsync_len = 136,
+ .vsync_len = 3,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
.refresh = 60,
.xres = 1280,
.yres = 1024,
@@ -120,7 +274,6 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
.vmode = FB_VMODE_NONINTERLACED
},
{
- .name = "1280x1024-70",
.refresh = 70,
.xres = 1280,
.yres = 1024,
@@ -135,7 +288,6 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
.vmode = FB_VMODE_NONINTERLACED
},
{
- .name = "1280x1024-75",
.refresh = 75,
.xres = 1280,
.yres = 1024,
@@ -150,40 +302,25 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
.vmode = FB_VMODE_NONINTERLACED
},
{
- .name = "320x240", /* for AOI only */
.refresh = 60,
- .xres = 320,
- .yres = 240,
- .pixclock = 15385,
- .left_margin = 0,
- .right_margin = 0,
- .upper_margin = 0,
- .lower_margin = 0,
- .hsync_len = 0,
- .vsync_len = 0,
- .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- .vmode = FB_VMODE_NONINTERLACED
- },
- {
- .name = "1280x480-60",
- .refresh = 60,
- .xres = 1280,
- .yres = 480,
- .pixclock = 18939,
- .left_margin = 353,
- .right_margin = 47,
- .upper_margin = 39,
- .lower_margin = 4,
- .hsync_len = 8,
- .vsync_len = 2,
+ .xres = 1920,
+ .yres = 1080,
+ .pixclock = 5787,
+ .left_margin = 328,
+ .right_margin = 120,
+ .upper_margin = 34,
+ .lower_margin = 1,
+ .hsync_len = 208,
+ .vsync_len = 3,
.sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.vmode = FB_VMODE_NONINTERLACED
},
};
-static char *fb_mode = "1024x768-32@60";
+static char *fb_mode;
static unsigned long default_bpp = 32;
-static int monitor_port;
+static enum fsl_diu_monitor_port monitor_port;
+static char *monitor_string;
#if defined(CONFIG_NOT_COHERENT_CACHE)
static u8 *coherence_data;
@@ -201,15 +338,27 @@ struct fsl_diu_data {
void *dummy_aoi_virt;
unsigned int irq;
int fb_enabled;
- int monitor_port;
+ enum fsl_diu_monitor_port monitor_port;
+ struct diu __iomem *diu_reg;
+ spinlock_t reg_lock;
+ struct diu_addr ad;
+ struct diu_addr gamma;
+ struct diu_addr pallete;
+ struct diu_addr cursor;
+};
+
+enum mfb_index {
+ PLANE0 = 0, /* Plane 0, only one AOI that fills the screen */
+ PLANE1_AOI0, /* Plane 1, first AOI */
+ PLANE1_AOI1, /* Plane 1, second AOI */
+ PLANE2_AOI0, /* Plane 2, first AOI */
+ PLANE2_AOI1, /* Plane 2, second AOI */
};
struct mfb_info {
- int index;
- int type;
+ enum mfb_index index;
char *id;
int registered;
- int blank;
unsigned long pseudo_palette[16];
struct diu_ad *ad;
int cursor_reset;
@@ -223,63 +372,82 @@ struct mfb_info {
static struct mfb_info mfb_template[] = {
- { /* AOI 0 for plane 0 */
- .index = 0,
- .type = MFB_TYPE_OUTPUT,
- .id = "Panel0",
- .registered = 0,
- .count = 0,
- .x_aoi_d = 0,
- .y_aoi_d = 0,
+ {
+ .index = PLANE0,
+ .id = "Panel0",
+ .registered = 0,
+ .count = 0,
+ .x_aoi_d = 0,
+ .y_aoi_d = 0,
},
- { /* AOI 0 for plane 1 */
- .index = 1,
- .type = MFB_TYPE_OUTPUT,
- .id = "Panel1 AOI0",
- .registered = 0,
- .g_alpha = 0xff,
- .count = 0,
- .x_aoi_d = 0,
- .y_aoi_d = 0,
+ {
+ .index = PLANE1_AOI0,
+ .id = "Panel1 AOI0",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 0,
+ .y_aoi_d = 0,
},
- { /* AOI 1 for plane 1 */
- .index = 2,
- .type = MFB_TYPE_OUTPUT,
- .id = "Panel1 AOI1",
- .registered = 0,
- .g_alpha = 0xff,
- .count = 0,
- .x_aoi_d = 0,
- .y_aoi_d = 480,
+ {
+ .index = PLANE1_AOI1,
+ .id = "Panel1 AOI1",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 0,
+ .y_aoi_d = 480,
},
- { /* AOI 0 for plane 2 */
- .index = 3,
- .type = MFB_TYPE_OUTPUT,
- .id = "Panel2 AOI0",
- .registered = 0,
- .g_alpha = 0xff,
- .count = 0,
- .x_aoi_d = 640,
- .y_aoi_d = 0,
+ {
+ .index = PLANE2_AOI0,
+ .id = "Panel2 AOI0",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 640,
+ .y_aoi_d = 0,
},
- { /* AOI 1 for plane 2 */
- .index = 4,
- .type = MFB_TYPE_OUTPUT,
- .id = "Panel2 AOI1",
- .registered = 0,
- .g_alpha = 0xff,
- .count = 0,
- .x_aoi_d = 640,
- .y_aoi_d = 480,
+ {
+ .index = PLANE2_AOI1,
+ .id = "Panel2 AOI1",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 640,
+ .y_aoi_d = 480,
},
};
-static struct diu_hw dr = {
- .mode = MFB_MODE1,
- .reg_lock = __SPIN_LOCK_UNLOCKED(diu_hw.reg_lock),
-};
+/**
+ * fsl_diu_name_to_port - convert a port name to a monitor port enum
+ *
+ * Takes the name of a monitor port ("dvi", "lvds", or "dlvds") and returns
+ * the enum fsl_diu_monitor_port that corresponds to that string.
+ *
+ * For compatibility with older versions, a number ("0", "1", or "2") is also
+ * supported.
+ *
+ * If the string is unknown, DVI is assumed.
+ *
+ * If the particular port is not supported by the platform, another port
+ * (platform-specific) is chosen instead.
+ */
+static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s)
+{
+ enum fsl_diu_monitor_port port = FSL_DIU_PORT_DVI;
+ unsigned long val;
-static struct diu_pool pool;
+ if (s) {
+ if (!strict_strtoul(s, 10, &val) && (val <= 2))
+ port = (enum fsl_diu_monitor_port) val;
+ else if (strncmp(s, "lvds", 4) == 0)
+ port = FSL_DIU_PORT_LVDS;
+ else if (strncmp(s, "dlvds", 5) == 0)
+ port = FSL_DIU_PORT_DLVDS;
+ }
+
+ return diu_ops.valid_monitor_port(port);
+}
/**
* fsl_diu_alloc - allocate memory for the DIU
@@ -292,14 +460,9 @@ static void *fsl_diu_alloc(size_t size, phys_addr_t *phys)
{
void *virt;
- pr_debug("size=%zu\n", size);
-
virt = alloc_pages_exact(size, GFP_DMA | __GFP_ZERO);
- if (virt) {
+ if (virt)
*phys = virt_to_phys(virt);
- pr_debug("virt=%p phys=%llx\n", virt,
- (unsigned long long)*phys);
- }
return virt;
}
@@ -313,8 +476,6 @@ static void *fsl_diu_alloc(size_t size, phys_addr_t *phys)
*/
static void fsl_diu_free(void *virt, size_t size)
{
- pr_debug("virt=%p size=%zu\n", virt, size);
-
if (virt && size)
free_pages_exact(virt, size);
}
@@ -330,82 +491,72 @@ void wr_reg_wa(u32 *reg, u32 val)
} while (in_be32(reg) != val);
}
-static int fsl_diu_enable_panel(struct fb_info *info)
+static void fsl_diu_enable_panel(struct fb_info *info)
{
struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
- struct diu *hw = dr.diu_reg;
struct diu_ad *ad = mfbi->ad;
struct fsl_diu_data *machine_data = mfbi->parent;
- int res = 0;
+ struct diu __iomem *hw = machine_data->diu_reg;
- pr_debug("enable_panel index %d\n", mfbi->index);
- if (mfbi->type != MFB_TYPE_OFF) {
- switch (mfbi->index) {
- case 0: /* plane 0 */
- if (hw->desc[0] != ad->paddr)
- wr_reg_wa(&hw->desc[0], ad->paddr);
- break;
- case 1: /* plane 1 AOI 0 */
- cmfbi = machine_data->fsl_diu_info[2]->par;
- if (hw->desc[1] != ad->paddr) { /* AOI0 closed */
- if (cmfbi->count > 0) /* AOI1 open */
- ad->next_ad =
- cpu_to_le32(cmfbi->ad->paddr);
- else
- ad->next_ad = 0;
- wr_reg_wa(&hw->desc[1], ad->paddr);
- }
- break;
- case 3: /* plane 2 AOI 0 */
- cmfbi = machine_data->fsl_diu_info[4]->par;
- if (hw->desc[2] != ad->paddr) { /* AOI0 closed */
- if (cmfbi->count > 0) /* AOI1 open */
- ad->next_ad =
- cpu_to_le32(cmfbi->ad->paddr);
- else
- ad->next_ad = 0;
- wr_reg_wa(&hw->desc[2], ad->paddr);
- }
- break;
- case 2: /* plane 1 AOI 1 */
- pmfbi = machine_data->fsl_diu_info[1]->par;
- ad->next_ad = 0;
- if (hw->desc[1] == machine_data->dummy_ad->paddr)
- wr_reg_wa(&hw->desc[1], ad->paddr);
- else /* AOI0 open */
- pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
- break;
- case 4: /* plane 2 AOI 1 */
- pmfbi = machine_data->fsl_diu_info[3]->par;
- ad->next_ad = 0;
- if (hw->desc[2] == machine_data->dummy_ad->paddr)
- wr_reg_wa(&hw->desc[2], ad->paddr);
- else /* AOI0 was open */
- pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
- break;
- default:
- res = -EINVAL;
- break;
+ switch (mfbi->index) {
+ case PLANE0:
+ if (hw->desc[0] != ad->paddr)
+ wr_reg_wa(&hw->desc[0], ad->paddr);
+ break;
+ case PLANE1_AOI0:
+ cmfbi = machine_data->fsl_diu_info[2]->par;
+ if (hw->desc[1] != ad->paddr) { /* AOI0 closed */
+ if (cmfbi->count > 0) /* AOI1 open */
+ ad->next_ad =
+ cpu_to_le32(cmfbi->ad->paddr);
+ else
+ ad->next_ad = 0;
+ wr_reg_wa(&hw->desc[1], ad->paddr);
}
- } else
- res = -EINVAL;
- return res;
+ break;
+ case PLANE2_AOI0:
+ cmfbi = machine_data->fsl_diu_info[4]->par;
+ if (hw->desc[2] != ad->paddr) { /* AOI0 closed */
+ if (cmfbi->count > 0) /* AOI1 open */
+ ad->next_ad =
+ cpu_to_le32(cmfbi->ad->paddr);
+ else
+ ad->next_ad = 0;
+ wr_reg_wa(&hw->desc[2], ad->paddr);
+ }
+ break;
+ case PLANE1_AOI1:
+ pmfbi = machine_data->fsl_diu_info[1]->par;
+ ad->next_ad = 0;
+ if (hw->desc[1] == machine_data->dummy_ad->paddr)
+ wr_reg_wa(&hw->desc[1], ad->paddr);
+ else /* AOI0 open */
+ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
+ break;
+ case PLANE2_AOI1:
+ pmfbi = machine_data->fsl_diu_info[3]->par;
+ ad->next_ad = 0;
+ if (hw->desc[2] == machine_data->dummy_ad->paddr)
+ wr_reg_wa(&hw->desc[2], ad->paddr);
+ else /* AOI0 was open */
+ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
+ break;
+ }
}
-static int fsl_diu_disable_panel(struct fb_info *info)
+static void fsl_diu_disable_panel(struct fb_info *info)
{
struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
- struct diu *hw = dr.diu_reg;
struct diu_ad *ad = mfbi->ad;
struct fsl_diu_data *machine_data = mfbi->parent;
- int res = 0;
+ struct diu __iomem *hw = machine_data->diu_reg;
switch (mfbi->index) {
- case 0: /* plane 0 */
+ case PLANE0:
if (hw->desc[0] != machine_data->dummy_ad->paddr)
wr_reg_wa(&hw->desc[0], machine_data->dummy_ad->paddr);
break;
- case 1: /* plane 1 AOI 0 */
+ case PLANE1_AOI0:
cmfbi = machine_data->fsl_diu_info[2]->par;
if (cmfbi->count > 0) /* AOI1 is open */
wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr);
@@ -414,7 +565,7 @@ static int fsl_diu_disable_panel(struct fb_info *info)
wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
/* close AOI 0 */
break;
- case 3: /* plane 2 AOI 0 */
+ case PLANE2_AOI0:
cmfbi = machine_data->fsl_diu_info[4]->par;
if (cmfbi->count > 0) /* AOI1 is open */
wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr);
@@ -423,7 +574,7 @@ static int fsl_diu_disable_panel(struct fb_info *info)
wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
/* close AOI 0 */
break;
- case 2: /* plane 1 AOI 1 */
+ case PLANE1_AOI1:
pmfbi = machine_data->fsl_diu_info[1]->par;
if (hw->desc[1] != ad->paddr) {
/* AOI1 is not the first in the chain */
@@ -434,7 +585,7 @@ static int fsl_diu_disable_panel(struct fb_info *info)
wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
/* close AOI 1 */
break;
- case 4: /* plane 2 AOI 1 */
+ case PLANE2_AOI1:
pmfbi = machine_data->fsl_diu_info[3]->par;
if (hw->desc[2] != ad->paddr) {
/* AOI1 is not the first in the chain */
@@ -445,31 +596,26 @@ static int fsl_diu_disable_panel(struct fb_info *info)
wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
/* close AOI 1 */
break;
- default:
- res = -EINVAL;
- break;
}
-
- return res;
}
static void enable_lcdc(struct fb_info *info)
{
- struct diu *hw = dr.diu_reg;
struct mfb_info *mfbi = info->par;
struct fsl_diu_data *machine_data = mfbi->parent;
+ struct diu __iomem *hw = machine_data->diu_reg;
if (!machine_data->fb_enabled) {
- out_be32(&hw->diu_mode, dr.mode);
+ out_be32(&hw->diu_mode, MFB_MODE1);
machine_data->fb_enabled++;
}
}
static void disable_lcdc(struct fb_info *info)
{
- struct diu *hw = dr.diu_reg;
struct mfb_info *mfbi = info->par;
struct fsl_diu_data *machine_data = mfbi->parent;
+ struct diu __iomem *hw = machine_data->diu_reg;
if (machine_data->fb_enabled) {
out_be32(&hw->diu_mode, 0);
@@ -482,7 +628,8 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
{
struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par;
struct fsl_diu_data *machine_data = mfbi->parent;
- int available_height, upper_aoi_bottom, index = mfbi->index;
+ int available_height, upper_aoi_bottom;
+ enum mfb_index index = mfbi->index;
int lower_aoi_is_open, upper_aoi_is_open;
__u32 base_plane_width, base_plane_height, upper_aoi_height;
@@ -494,14 +641,14 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
if (mfbi->y_aoi_d < 0)
mfbi->y_aoi_d = 0;
switch (index) {
- case 0:
+ case PLANE0:
if (mfbi->x_aoi_d != 0)
mfbi->x_aoi_d = 0;
if (mfbi->y_aoi_d != 0)
mfbi->y_aoi_d = 0;
break;
- case 1: /* AOI 0 */
- case 3:
+ case PLANE1_AOI0:
+ case PLANE2_AOI0:
lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par;
lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0;
if (var->xres > base_plane_width)
@@ -518,8 +665,8 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
if ((mfbi->y_aoi_d + var->yres) > available_height)
mfbi->y_aoi_d = available_height - var->yres;
break;
- case 2: /* AOI 1 */
- case 4:
+ case PLANE1_AOI1:
+ case PLANE2_AOI1:
upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par;
upper_aoi_height =
machine_data->fsl_diu_info[index-1]->var.yres;
@@ -555,9 +702,6 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
static int fsl_diu_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
- pr_debug("check_var xres: %d\n", var->xres);
- pr_debug("check_var yres: %d\n", var->yres);
-
if (var->xres_virtual < var->xres)
var->xres_virtual = var->xres;
if (var->yres_virtual < var->yres)
@@ -652,7 +796,7 @@ static void set_fix(struct fb_info *info)
struct fb_var_screeninfo *var = &info->var;
struct mfb_info *mfbi = info->par;
- strncpy(fix->id, mfbi->id, strlen(mfbi->id));
+ strncpy(fix->id, mfbi->id, sizeof(fix->id));
fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
fix->type = FB_TYPE_PACKED_PIXELS;
fix->accel = FB_ACCEL_NONE;
@@ -666,45 +810,37 @@ static void update_lcdc(struct fb_info *info)
struct fb_var_screeninfo *var = &info->var;
struct mfb_info *mfbi = info->par;
struct fsl_diu_data *machine_data = mfbi->parent;
- struct diu *hw;
+ struct diu __iomem *hw;
int i, j;
char __iomem *cursor_base, *gamma_table_base;
u32 temp;
- hw = dr.diu_reg;
-
- if (mfbi->type == MFB_TYPE_OFF) {
- fsl_diu_disable_panel(info);
- return;
- }
+ hw = machine_data->diu_reg;
diu_ops.set_monitor_port(machine_data->monitor_port);
- gamma_table_base = pool.gamma.vaddr;
- cursor_base = pool.cursor.vaddr;
+ gamma_table_base = machine_data->gamma.vaddr;
+ cursor_base = machine_data->cursor.vaddr;
/* Prep for DIU init - gamma table, cursor table */
for (i = 0; i <= 2; i++)
- for (j = 0; j <= 255; j++)
- *gamma_table_base++ = j;
+ for (j = 0; j <= 255; j++)
+ *gamma_table_base++ = j;
- diu_ops.set_gamma_table(machine_data->monitor_port, pool.gamma.vaddr);
+ diu_ops.set_gamma_table(machine_data->monitor_port,
+ machine_data->gamma.vaddr);
- pr_debug("update-lcdc: HW - %p\n Disabling DIU\n", hw);
disable_lcdc(info);
/* Program DIU registers */
- out_be32(&hw->gamma, pool.gamma.paddr);
- out_be32(&hw->cursor, pool.cursor.paddr);
+ out_be32(&hw->gamma, machine_data->gamma.paddr);
+ out_be32(&hw->cursor, machine_data->cursor.paddr);
out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */
out_be32(&hw->bgnd_wb, 0); /* BGND_WB */
out_be32(&hw->disp_size, (var->yres << 16 | var->xres));
/* DISP SIZE */
- pr_debug("DIU xres: %d\n", var->xres);
- pr_debug("DIU yres: %d\n", var->yres);
-
out_be32(&hw->wb_size, 0); /* WB SIZE */
out_be32(&hw->wb_mem_addr, 0); /* WB MEM ADDR */
@@ -721,15 +857,6 @@ static void update_lcdc(struct fb_info *info)
out_be32(&hw->vsyn_para, temp);
- pr_debug("DIU right_margin - %d\n", var->right_margin);
- pr_debug("DIU left_margin - %d\n", var->left_margin);
- pr_debug("DIU hsync_len - %d\n", var->hsync_len);
- pr_debug("DIU upper_margin - %d\n", var->upper_margin);
- pr_debug("DIU lower_margin - %d\n", var->lower_margin);
- pr_debug("DIU vsync_len - %d\n", var->vsync_len);
- pr_debug("DIU HSYNC - 0x%08x\n", hw->hsyn_para);
- pr_debug("DIU VSYNC - 0x%08x\n", hw->vsyn_para);
-
diu_ops.set_pixel_clock(var->pixclock);
out_be32(&hw->syn_pol, 0); /* SYNC SIGNALS POLARITY */
@@ -746,14 +873,9 @@ static int map_video_memory(struct fb_info *info)
phys_addr_t phys;
u32 smem_len = info->fix.line_length * info->var.yres_virtual;
- pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual);
- pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
- pr_debug("info->fix.line_length = %d\n", info->fix.line_length);
- pr_debug("MAP_VIDEO_MEMORY: smem_len = %u\n", smem_len);
-
info->screen_base = fsl_diu_alloc(smem_len, &phys);
if (info->screen_base == NULL) {
- printk(KERN_ERR "Unable to allocate fb memory\n");
+ dev_err(info->dev, "unable to allocate fb memory\n");
return -ENOMEM;
}
mutex_lock(&info->mm_lock);
@@ -762,10 +884,6 @@ static int map_video_memory(struct fb_info *info)
mutex_unlock(&info->mm_lock);
info->screen_size = info->fix.smem_len;
- pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n",
- info->fix.smem_start, info->fix.smem_len);
- pr_debug("screen base %p\n", info->screen_base);
-
return 0;
}
@@ -810,9 +928,9 @@ static int fsl_diu_set_par(struct fb_info *info)
struct mfb_info *mfbi = info->par;
struct fsl_diu_data *machine_data = mfbi->parent;
struct diu_ad *ad = mfbi->ad;
- struct diu *hw;
+ struct diu __iomem *hw;
- hw = dr.diu_reg;
+ hw = machine_data->diu_reg;
set_fix(info);
mfbi->cursor_reset = 1;
@@ -822,18 +940,16 @@ static int fsl_diu_set_par(struct fb_info *info)
if (len != info->fix.smem_len) {
if (info->fix.smem_start)
unmap_video_memory(info);
- pr_debug("SET PAR: smem_len = %d\n", info->fix.smem_len);
/* Memory allocation for framebuffer */
if (map_video_memory(info)) {
- printk(KERN_ERR "Unable to allocate fb memory 1\n");
+ dev_err(info->dev, "unable to allocate fb memory 1\n");
return -ENOMEM;
}
}
- ad->pix_fmt =
- diu_ops.get_pixel_format(var->bits_per_pixel,
- machine_data->monitor_port);
+ ad->pix_fmt = diu_ops.get_pixel_format(machine_data->monitor_port,
+ var->bits_per_pixel);
ad->addr = cpu_to_le32(info->fix.smem_start);
ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) |
var->xres_virtual) | mfbi->g_alpha;
@@ -851,14 +967,14 @@ static int fsl_diu_set_par(struct fb_info *info)
ad->ckmin_g = 255;
ad->ckmin_b = 255;
- if (mfbi->index == 0)
+ if (mfbi->index == PLANE0)
update_lcdc(info);
return 0;
}
static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
{
- return ((val<<width) + 0x7FFF - val)>>16;
+ return ((val << width) + 0x7FFF - val) >> 16;
}
/*
@@ -870,8 +986,9 @@ static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
* pseudo_palette in struct fb_info. For pseudocolor mode we have a limited
* color palette.
*/
-static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp, struct fb_info *info)
+static int fsl_diu_setcolreg(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ unsigned int transp, struct fb_info *info)
{
int ret = 1;
@@ -906,9 +1023,6 @@ static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green,
ret = 0;
}
break;
- case FB_VISUAL_STATIC_PSEUDOCOLOR:
- case FB_VISUAL_PSEUDOCOLOR:
- break;
}
return ret;
@@ -944,37 +1058,6 @@ static int fsl_diu_pan_display(struct fb_var_screeninfo *var,
return 0;
}
-/*
- * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking
- * succeeded, != 0 if un-/blanking failed.
- * blank_mode == 2: suspend vsync
- * blank_mode == 3: suspend hsync
- * blank_mode == 4: powerdown
- */
-static int fsl_diu_blank(int blank_mode, struct fb_info *info)
-{
- struct mfb_info *mfbi = info->par;
-
- mfbi->blank = blank_mode;
-
- switch (blank_mode) {
- case FB_BLANK_VSYNC_SUSPEND:
- case FB_BLANK_HSYNC_SUSPEND:
- /* FIXME: fixes to enable_panel and enable lcdc needed */
- case FB_BLANK_NORMAL:
- /* fsl_diu_disable_panel(info);*/
- break;
- case FB_BLANK_POWERDOWN:
- /* disable_lcdc(info); */
- break;
- case FB_BLANK_UNBLANK:
- /* fsl_diu_enable_panel(info);*/
- break;
- }
-
- return 0;
-}
-
static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
@@ -989,25 +1072,29 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
if (!arg)
return -EINVAL;
switch (cmd) {
+ case MFB_SET_PIXFMT_OLD:
+ dev_warn(info->dev,
+ "MFB_SET_PIXFMT value of 0x%08x is deprecated.\n",
+ MFB_SET_PIXFMT_OLD);
case MFB_SET_PIXFMT:
if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt)))
return -EFAULT;
ad->pix_fmt = pix_fmt;
- pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt);
break;
+ case MFB_GET_PIXFMT_OLD:
+ dev_warn(info->dev,
+ "MFB_GET_PIXFMT value of 0x%08x is deprecated.\n",
+ MFB_GET_PIXFMT_OLD);
case MFB_GET_PIXFMT:
pix_fmt = ad->pix_fmt;
if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt)))
return -EFAULT;
- pr_debug("get pixel format 0x%08x\n", ad->pix_fmt);
break;
case MFB_SET_AOID:
if (copy_from_user(&aoi_d, buf, sizeof(aoi_d)))
return -EFAULT;
mfbi->x_aoi_d = aoi_d.x_aoi_d;
mfbi->y_aoi_d = aoi_d.y_aoi_d;
- pr_debug("set AOI display offset of index %d to (%d,%d)\n",
- mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
fsl_diu_check_var(&info->var, info);
fsl_diu_set_aoi(info);
break;
@@ -1016,14 +1103,11 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
aoi_d.y_aoi_d = mfbi->y_aoi_d;
if (copy_to_user(buf, &aoi_d, sizeof(aoi_d)))
return -EFAULT;
- pr_debug("get AOI display offset of index %d (%d,%d)\n",
- mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
break;
case MFB_GET_ALPHA:
global_alpha = mfbi->g_alpha;
if (copy_to_user(buf, &global_alpha, sizeof(global_alpha)))
return -EFAULT;
- pr_debug("get global alpha of index %d\n", mfbi->index);
break;
case MFB_SET_ALPHA:
/* set panel information */
@@ -1032,7 +1116,6 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) |
(global_alpha & 0xff);
mfbi->g_alpha = global_alpha;
- pr_debug("set global alpha for index %d\n", mfbi->index);
break;
case MFB_SET_CHROMA_KEY:
/* set panel winformation */
@@ -1060,27 +1143,9 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
ad->ckmin_g = ck.green_min;
ad->ckmin_b = ck.blue_min;
}
- pr_debug("set chroma key\n");
break;
- case FBIOGET_GWINFO:
- if (mfbi->type == MFB_TYPE_OFF)
- return -ENODEV;
- /* get graphic window information */
- if (copy_to_user(buf, ad, sizeof(*ad)))
- return -EFAULT;
- break;
- case FBIOGET_HWCINFO:
- pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO);
- break;
- case FBIOPUT_MODEINFO:
- pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO);
- break;
- case FBIOGET_DISPINFO:
- pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO);
- break;
-
default:
- printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd);
+ dev_err(info->dev, "unknown ioctl command (0x%08X)\n", cmd);
return -ENOIOCTLCMD;
}
@@ -1095,22 +1160,18 @@ static int fsl_diu_open(struct fb_info *info, int user)
int res = 0;
/* free boot splash memory on first /dev/fb0 open */
- if (!mfbi->index && diu_ops.release_bootmem)
+ if ((mfbi->index == PLANE0) && diu_ops.release_bootmem)
diu_ops.release_bootmem();
spin_lock(&diu_lock);
mfbi->count++;
if (mfbi->count == 1) {
- pr_debug("open plane index %d\n", mfbi->index);
fsl_diu_check_var(&info->var, info);
res = fsl_diu_set_par(info);
if (res < 0)
mfbi->count--;
- else {
- res = fsl_diu_enable_panel(info);
- if (res < 0)
- mfbi->count--;
- }
+ else
+ fsl_diu_enable_panel(info);
}
spin_unlock(&diu_lock);
@@ -1126,12 +1187,9 @@ static int fsl_diu_release(struct fb_info *info, int user)
spin_lock(&diu_lock);
mfbi->count--;
- if (mfbi->count == 0) {
- pr_debug("release plane index %d\n", mfbi->index);
- res = fsl_diu_disable_panel(info);
- if (res < 0)
- mfbi->count++;
- }
+ if (mfbi->count == 0)
+ fsl_diu_disable_panel(info);
+
spin_unlock(&diu_lock);
return res;
}
@@ -1141,7 +1199,6 @@ static struct fb_ops fsl_diu_ops = {
.fb_check_var = fsl_diu_check_var,
.fb_set_par = fsl_diu_set_par,
.fb_setcolreg = fsl_diu_setcolreg,
- .fb_blank = fsl_diu_blank,
.fb_pan_display = fsl_diu_pan_display,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
@@ -1178,7 +1235,7 @@ static int __devinit install_fb(struct fb_info *info)
if (init_fbinfo(info))
return -EINVAL;
- if (mfbi->index == 0) { /* plane 0 */
+ if (mfbi->index == PLANE0) {
if (mfbi->edid_data) {
/* Now build modedb from EDID */
fb_edid_to_monspecs(mfbi->edid_data, &info->monspecs);
@@ -1192,43 +1249,23 @@ static int __devinit install_fb(struct fb_info *info)
} else {
aoi_mode = init_aoi_mode;
}
- pr_debug("mode used = %s\n", aoi_mode);
- rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize,
- &fsl_diu_default_mode, default_bpp);
- switch (rc) {
- case 1:
- pr_debug("using mode specified in @mode\n");
- break;
- case 2:
- pr_debug("using mode specified in @mode "
- "with ignored refresh rate\n");
- break;
- case 3:
- pr_debug("using mode default mode\n");
- break;
- case 4:
- pr_debug("using mode from list\n");
- break;
- default:
- pr_debug("rc = %d\n", rc);
- pr_debug("failed to find mode\n");
+ rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize, NULL,
+ default_bpp);
+ if (!rc) {
/*
* For plane 0 we continue and look into
* driver's internal modedb.
*/
- if (mfbi->index == 0 && mfbi->edid_data)
+ if ((mfbi->index == PLANE0) && mfbi->edid_data)
has_default_mode = 0;
else
return -EINVAL;
- break;
}
if (!has_default_mode) {
rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
- ARRAY_SIZE(fsl_diu_mode_db),
- &fsl_diu_default_mode,
- default_bpp);
- if (rc > 0 && rc < 5)
+ ARRAY_SIZE(fsl_diu_mode_db), NULL, default_bpp);
+ if (rc)
has_default_mode = 1;
}
@@ -1256,33 +1293,22 @@ static int __devinit install_fb(struct fb_info *info)
fb_videomode_to_var(&info->var, modedb);
}
- pr_debug("xres_virtual %d\n", info->var.xres_virtual);
- pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel);
-
- pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
- pr_debug("info->fix.line_length = %d\n", info->fix.line_length);
-
- if (mfbi->type == MFB_TYPE_OFF)
- mfbi->blank = FB_BLANK_NORMAL;
- else
- mfbi->blank = FB_BLANK_UNBLANK;
-
if (fsl_diu_check_var(&info->var, info)) {
- printk(KERN_ERR "fb_check_var failed");
+ dev_err(info->dev, "fsl_diu_check_var failed\n");
+ unmap_video_memory(info);
fb_dealloc_cmap(&info->cmap);
return -EINVAL;
}
if (register_framebuffer(info) < 0) {
- printk(KERN_ERR "register_framebuffer failed");
+ dev_err(info->dev, "register_framebuffer failed\n");
unmap_video_memory(info);
fb_dealloc_cmap(&info->cmap);
return -EINVAL;
}
mfbi->registered = 1;
- printk(KERN_INFO "fb%d: %s fb device registered successfully.\n",
- info->node, info->fix.id);
+ dev_info(info->dev, "%s registered successfully\n", mfbi->id);
return 0;
}
@@ -1294,7 +1320,7 @@ static void uninstall_fb(struct fb_info *info)
if (!mfbi->registered)
return;
- if (mfbi->index == 0)
+ if (mfbi->index == PLANE0)
kfree(mfbi->edid_data);
unregister_framebuffer(info);
@@ -1307,20 +1333,20 @@ static void uninstall_fb(struct fb_info *info)
static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
{
- struct diu *hw = dr.diu_reg;
+ struct diu __iomem *hw = dev_id;
unsigned int status = in_be32(&hw->int_status);
if (status) {
/* This is the workaround for underrun */
if (status & INT_UNDRUN) {
out_be32(&hw->diu_mode, 0);
- pr_debug("Err: DIU occurs underrun!\n");
udelay(1);
out_be32(&hw->diu_mode, 1);
}
#if defined(CONFIG_NOT_COHERENT_CACHE)
else if (status & INT_VSYNC) {
unsigned int i;
+
for (i = 0; i < coherence_data_size;
i += d_cache_line_size)
__asm__ __volatile__ (
@@ -1333,43 +1359,38 @@ static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
return IRQ_NONE;
}
-static int request_irq_local(int irq)
+static int request_irq_local(struct fsl_diu_data *machine_data)
{
- unsigned long status, ints;
- struct diu *hw;
+ struct diu __iomem *hw = machine_data->diu_reg;
+ u32 ints;
int ret;
- hw = dr.diu_reg;
-
/* Read to clear the status */
- status = in_be32(&hw->int_status);
+ in_be32(&hw->int_status);
- ret = request_irq(irq, fsl_diu_isr, 0, "diu", NULL);
- if (ret)
- pr_info("Request diu IRQ failed.\n");
- else {
+ ret = request_irq(machine_data->irq, fsl_diu_isr, 0, "fsl-diu-fb", hw);
+ if (!ret) {
ints = INT_PARERR | INT_LS_BF_VS;
#if !defined(CONFIG_NOT_COHERENT_CACHE)
ints |= INT_VSYNC;
#endif
- if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3)
- ints |= INT_VSYNC_WB;
/* Read to clear the status */
- status = in_be32(&hw->int_status);
+ in_be32(&hw->int_status);
out_be32(&hw->int_mask, ints);
}
+
return ret;
}
-static void free_irq_local(int irq)
+static void free_irq_local(struct fsl_diu_data *machine_data)
{
- struct diu *hw = dr.diu_reg;
+ struct diu __iomem *hw = machine_data->diu_reg;
/* Disable all LCDC interrupt */
out_be32(&hw->int_mask, 0x1f);
- free_irq(irq, NULL);
+ free_irq(machine_data->irq, NULL);
}
#ifdef CONFIG_PM
@@ -1406,49 +1427,42 @@ static int fsl_diu_resume(struct platform_device *ofdev)
static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size,
u32 bytes_align)
{
- u32 offset, ssize;
- u32 mask;
- dma_addr_t paddr = 0;
+ u32 offset;
+ dma_addr_t mask;
- ssize = size + bytes_align;
- buf->vaddr = dma_alloc_coherent(dev, ssize, &paddr, GFP_DMA |
- __GFP_ZERO);
+ buf->vaddr =
+ dma_alloc_coherent(dev, size + bytes_align, &buf->paddr,
+ GFP_DMA | __GFP_ZERO);
if (!buf->vaddr)
return -ENOMEM;
- buf->paddr = (__u32) paddr;
-
mask = bytes_align - 1;
- offset = (u32)buf->paddr & mask;
+ offset = buf->paddr & mask;
if (offset) {
buf->offset = bytes_align - offset;
- buf->paddr = (u32)buf->paddr + offset;
+ buf->paddr = buf->paddr + offset;
} else
buf->offset = 0;
+
return 0;
}
static void free_buf(struct device *dev, struct diu_addr *buf, u32 size,
u32 bytes_align)
{
- dma_free_coherent(dev, size + bytes_align,
- buf->vaddr, (buf->paddr - buf->offset));
- return;
+ dma_free_coherent(dev, size + bytes_align, buf->vaddr,
+ buf->paddr - buf->offset);
}
static ssize_t store_monitor(struct device *device,
struct device_attribute *attr, const char *buf, size_t count)
{
- int old_monitor_port;
- unsigned long val;
+ enum fsl_diu_monitor_port old_monitor_port;
struct fsl_diu_data *machine_data =
container_of(attr, struct fsl_diu_data, dev_attr);
- if (strict_strtoul(buf, 10, &val))
- return 0;
-
old_monitor_port = machine_data->monitor_port;
- machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val);
+ machine_data->monitor_port = fsl_diu_name_to_port(buf);
if (old_monitor_port != machine_data->monitor_port) {
/* All AOIs need adjust pixel format
@@ -1468,16 +1482,25 @@ static ssize_t show_monitor(struct device *device,
{
struct fsl_diu_data *machine_data =
container_of(attr, struct fsl_diu_data, dev_attr);
- return diu_ops.show_monitor_port(machine_data->monitor_port, buf);
+
+ switch (machine_data->monitor_port) {
+ case FSL_DIU_PORT_DVI:
+ return sprintf(buf, "DVI\n");
+ case FSL_DIU_PORT_LVDS:
+ return sprintf(buf, "Single-link LVDS\n");
+ case FSL_DIU_PORT_DLVDS:
+ return sprintf(buf, "Dual-link LVDS\n");
+ }
+
+ return 0;
}
-static int __devinit fsl_diu_probe(struct platform_device *ofdev)
+static int __devinit fsl_diu_probe(struct platform_device *pdev)
{
- struct device_node *np = ofdev->dev.of_node;
+ struct device_node *np = pdev->dev.of_node;
struct mfb_info *mfbi;
- phys_addr_t dummy_ad_addr;
+ phys_addr_t dummy_ad_addr = 0;
int ret, i, error = 0;
- struct resource res;
struct fsl_diu_data *machine_data;
int diu_mode;
@@ -1485,11 +1508,13 @@ static int __devinit fsl_diu_probe(struct platform_device *ofdev)
if (!machine_data)
return -ENOMEM;
+ spin_lock_init(&machine_data->reg_lock);
+
for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
machine_data->fsl_diu_info[i] =
- framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev);
+ framebuffer_alloc(sizeof(struct mfb_info), &pdev->dev);
if (!machine_data->fsl_diu_info[i]) {
- dev_err(&ofdev->dev, "cannot allocate memory\n");
+ dev_err(&pdev->dev, "cannot allocate memory\n");
ret = -ENOMEM;
goto error2;
}
@@ -1497,7 +1522,7 @@ static int __devinit fsl_diu_probe(struct platform_device *ofdev)
memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
mfbi->parent = machine_data;
- if (mfbi->index == 0) {
+ if (mfbi->index == PLANE0) {
const u8 *prop;
int len;
@@ -1509,60 +1534,49 @@ static int __devinit fsl_diu_probe(struct platform_device *ofdev)
}
}
- ret = of_address_to_resource(np, 0, &res);
- if (ret) {
- dev_err(&ofdev->dev, "could not obtain DIU address\n");
- goto error;
- }
- if (!res.start) {
- dev_err(&ofdev->dev, "invalid DIU address\n");
- goto error;
- }
- dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start);
-
- dr.diu_reg = ioremap(res.start, sizeof(struct diu));
- if (!dr.diu_reg) {
- dev_err(&ofdev->dev, "Err: can't map DIU registers!\n");
+ machine_data->diu_reg = of_iomap(np, 0);
+ if (!machine_data->diu_reg) {
+ dev_err(&pdev->dev, "cannot map DIU registers\n");
ret = -EFAULT;
goto error2;
}
- diu_mode = in_be32(&dr.diu_reg->diu_mode);
- if (diu_mode != MFB_MODE1)
- out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU */
+ diu_mode = in_be32(&machine_data->diu_reg->diu_mode);
+ if (diu_mode == MFB_MODE0)
+ out_be32(&machine_data->diu_reg->diu_mode, 0); /* disable DIU */
/* Get the IRQ of the DIU */
machine_data->irq = irq_of_parse_and_map(np, 0);
if (!machine_data->irq) {
- dev_err(&ofdev->dev, "could not get DIU IRQ\n");
+ dev_err(&pdev->dev, "could not get DIU IRQ\n");
ret = -EINVAL;
goto error;
}
machine_data->monitor_port = monitor_port;
/* Area descriptor memory pool aligns to 64-bit boundary */
- if (allocate_buf(&ofdev->dev, &pool.ad,
+ if (allocate_buf(&pdev->dev, &machine_data->ad,
sizeof(struct diu_ad) * FSL_AOI_NUM, 8))
return -ENOMEM;
/* Get memory for Gamma Table - 32-byte aligned memory */
- if (allocate_buf(&ofdev->dev, &pool.gamma, 768, 32)) {
+ if (allocate_buf(&pdev->dev, &machine_data->gamma, 768, 32)) {
ret = -ENOMEM;
goto error;
}
/* For performance, cursor bitmap buffer aligns to 32-byte boundary */
- if (allocate_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2,
- 32)) {
+ if (allocate_buf(&pdev->dev, &machine_data->cursor,
+ MAX_CURS * MAX_CURS * 2, 32)) {
ret = -ENOMEM;
goto error;
}
i = ARRAY_SIZE(machine_data->fsl_diu_info);
- machine_data->dummy_ad = (struct diu_ad *)
- ((u32)pool.ad.vaddr + pool.ad.offset) + i;
- machine_data->dummy_ad->paddr = pool.ad.paddr +
+ machine_data->dummy_ad = (struct diu_ad *)((u32)machine_data->ad.vaddr +
+ machine_data->ad.offset) + i;
+ machine_data->dummy_ad->paddr = machine_data->ad.paddr +
i * sizeof(struct diu_ad);
machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr);
if (!machine_data->dummy_aoi_virt) {
@@ -1581,30 +1595,29 @@ static int __devinit fsl_diu_probe(struct platform_device *ofdev)
* Let DIU display splash screen if it was pre-initialized
* by the bootloader, set dummy area descriptor otherwise.
*/
- if (diu_mode != MFB_MODE1)
- out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
+ if (diu_mode == MFB_MODE0)
+ out_be32(&machine_data->diu_reg->desc[0],
+ machine_data->dummy_ad->paddr);
- out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr);
- out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr);
+ out_be32(&machine_data->diu_reg->desc[1], machine_data->dummy_ad->paddr);
+ out_be32(&machine_data->diu_reg->desc[2], machine_data->dummy_ad->paddr);
for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
machine_data->fsl_diu_info[i]->fix.smem_start = 0;
mfbi = machine_data->fsl_diu_info[i]->par;
- mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr
- + pool.ad.offset) + i;
- mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad);
+ mfbi->ad = (struct diu_ad *)((u32)machine_data->ad.vaddr
+ + machine_data->ad.offset) + i;
+ mfbi->ad->paddr =
+ machine_data->ad.paddr + i * sizeof(struct diu_ad);
ret = install_fb(machine_data->fsl_diu_info[i]);
if (ret) {
- dev_err(&ofdev->dev,
- "Failed to register framebuffer %d\n",
- i);
+ dev_err(&pdev->dev, "could not register fb %d\n", i);
goto error;
}
}
- if (request_irq_local(machine_data->irq)) {
- dev_err(machine_data->fsl_diu_info[0]->dev,
- "could not request irq for diu.");
+ if (request_irq_local(machine_data)) {
+ dev_err(&pdev->dev, "could not claim irq\n");
goto error;
}
@@ -1616,29 +1629,28 @@ static int __devinit fsl_diu_probe(struct platform_device *ofdev)
error = device_create_file(machine_data->fsl_diu_info[0]->dev,
&machine_data->dev_attr);
if (error) {
- dev_err(machine_data->fsl_diu_info[0]->dev,
- "could not create sysfs %s file\n",
+ dev_err(&pdev->dev, "could not create sysfs file %s\n",
machine_data->dev_attr.attr.name);
}
- dev_set_drvdata(&ofdev->dev, machine_data);
+ dev_set_drvdata(&pdev->dev, machine_data);
return 0;
error:
- for (i = ARRAY_SIZE(machine_data->fsl_diu_info);
- i > 0; i--)
- uninstall_fb(machine_data->fsl_diu_info[i - 1]);
- if (pool.ad.vaddr)
- free_buf(&ofdev->dev, &pool.ad,
+ for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
+ uninstall_fb(machine_data->fsl_diu_info[i]);
+
+ if (machine_data->ad.vaddr)
+ free_buf(&pdev->dev, &machine_data->ad,
sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
- if (pool.gamma.vaddr)
- free_buf(&ofdev->dev, &pool.gamma, 768, 32);
- if (pool.cursor.vaddr)
- free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2,
- 32);
+ if (machine_data->gamma.vaddr)
+ free_buf(&pdev->dev, &machine_data->gamma, 768, 32);
+ if (machine_data->cursor.vaddr)
+ free_buf(&pdev->dev, &machine_data->cursor,
+ MAX_CURS * MAX_CURS * 2, 32);
if (machine_data->dummy_aoi_virt)
fsl_diu_free(machine_data->dummy_aoi_virt, 64);
- iounmap(dr.diu_reg);
+ iounmap(machine_data->diu_reg);
error2:
for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
@@ -1649,28 +1661,27 @@ error2:
return ret;
}
-
-static int fsl_diu_remove(struct platform_device *ofdev)
+static int fsl_diu_remove(struct platform_device *pdev)
{
struct fsl_diu_data *machine_data;
int i;
- machine_data = dev_get_drvdata(&ofdev->dev);
+ machine_data = dev_get_drvdata(&pdev->dev);
disable_lcdc(machine_data->fsl_diu_info[0]);
- free_irq_local(machine_data->irq);
- for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--)
- uninstall_fb(machine_data->fsl_diu_info[i - 1]);
- if (pool.ad.vaddr)
- free_buf(&ofdev->dev, &pool.ad,
+ free_irq_local(machine_data);
+ for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
+ uninstall_fb(machine_data->fsl_diu_info[i]);
+ if (machine_data->ad.vaddr)
+ free_buf(&pdev->dev, &machine_data->ad,
sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
- if (pool.gamma.vaddr)
- free_buf(&ofdev->dev, &pool.gamma, 768, 32);
- if (pool.cursor.vaddr)
- free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2,
- 32);
+ if (machine_data->gamma.vaddr)
+ free_buf(&pdev->dev, &machine_data->gamma, 768, 32);
+ if (machine_data->cursor.vaddr)
+ free_buf(&pdev->dev, &machine_data->cursor,
+ MAX_CURS * MAX_CURS * 2, 32);
if (machine_data->dummy_aoi_virt)
fsl_diu_free(machine_data->dummy_aoi_virt, 64);
- iounmap(dr.diu_reg);
+ iounmap(machine_data->diu_reg);
for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
if (machine_data->fsl_diu_info[i])
framebuffer_release(machine_data->fsl_diu_info[i]);
@@ -1692,8 +1703,7 @@ static int __init fsl_diu_setup(char *options)
if (!*opt)
continue;
if (!strncmp(opt, "monitor=", 8)) {
- if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2))
- monitor_port = val;
+ monitor_port = fsl_diu_name_to_port(opt + 8);
} else if (!strncmp(opt, "bpp=", 4)) {
if (!strict_strtoul(opt + 4, 10, &val))
default_bpp = val;
@@ -1720,7 +1730,7 @@ MODULE_DEVICE_TABLE(of, fsl_diu_match);
static struct platform_driver fsl_diu_driver = {
.driver = {
- .name = "fsl_diu",
+ .name = "fsl-diu-fb",
.owner = THIS_MODULE,
.of_match_table = fsl_diu_match,
},
@@ -1746,48 +1756,54 @@ static int __init fsl_diu_init(void)
if (fb_get_options("fslfb", &option))
return -ENODEV;
fsl_diu_setup(option);
+#else
+ monitor_port = fsl_diu_name_to_port(monitor_string);
#endif
- printk(KERN_INFO "Freescale DIU driver\n");
+ pr_info("Freescale Display Interface Unit (DIU) framebuffer driver\n");
#ifdef CONFIG_NOT_COHERENT_CACHE
np = of_find_node_by_type(NULL, "cpu");
if (!np) {
- printk(KERN_ERR "Err: can't find device node 'cpu'\n");
+ pr_err("fsl-diu-fb: can't find 'cpu' device node\n");
return -ENODEV;
}
prop = of_get_property(np, "d-cache-size", NULL);
if (prop == NULL) {
+ pr_err("fsl-diu-fb: missing 'd-cache-size' property' "
+ "in 'cpu' node\n");
of_node_put(np);
return -ENODEV;
}
- /* Freescale PLRU requires 13/8 times the cache size to do a proper
- displacement flush
+ /*
+ * Freescale PLRU requires 13/8 times the cache size to do a proper
+ * displacement flush
*/
- coherence_data_size = *prop * 13;
+ coherence_data_size = be32_to_cpup(prop) * 13;
coherence_data_size /= 8;
prop = of_get_property(np, "d-cache-line-size", NULL);
if (prop == NULL) {
+ pr_err("fsl-diu-fb: missing 'd-cache-line-size' property' "
+ "in 'cpu' node\n");
of_node_put(np);
return -ENODEV;
}
- d_cache_line_size = *prop;
+ d_cache_line_size = be32_to_cpup(prop);
of_node_put(np);
coherence_data = vmalloc(coherence_data_size);
if (!coherence_data)
return -ENOMEM;
#endif
+
ret = platform_driver_register(&fsl_diu_driver);
if (ret) {
- printk(KERN_ERR
- "fsl-diu: failed to register platform driver\n");
+ pr_err("fsl-diu-fb: failed to register platform driver\n");
#if defined(CONFIG_NOT_COHERENT_CACHE)
vfree(coherence_data);
#endif
- iounmap(dr.diu_reg);
}
return ret;
}
@@ -1811,8 +1827,8 @@ module_param_named(mode, fb_mode, charp, 0);
MODULE_PARM_DESC(mode,
"Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
module_param_named(bpp, default_bpp, ulong, 0);
-MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
-module_param_named(monitor, monitor_port, int, 0);
-MODULE_PARM_DESC(monitor,
- "Specify the monitor port (0, 1 or 2) if supported by the platform");
+MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified in 'mode'");
+module_param_named(monitor, monitor_string, charp, 0);
+MODULE_PARM_DESC(monitor, "Specify the monitor port "
+ "(\"dvi\", \"lvds\", or \"dlvds\") if supported by the platform");
diff --git a/drivers/video/g364fb.c b/drivers/video/g364fb.c
index d662317..223896c 100644
--- a/drivers/video/g364fb.c
+++ b/drivers/video/g364fb.c
@@ -149,10 +149,11 @@ int g364fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
static int g364fb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
- if (var->xoffset || var->yoffset + var->yres > var->yres_virtual)
+ if (var->xoffset ||
+ var->yoffset + info->var.yres > info->var.yres_virtual)
return -EINVAL;
- *(unsigned int *) TOP_REG = var->yoffset * var->xres;
+ *(unsigned int *) TOP_REG = var->yoffset * info->var.xres;
return 0;
}
diff --git a/drivers/video/grvga.c b/drivers/video/grvga.c
new file mode 100644
index 0000000..f37e025
--- /dev/null
+++ b/drivers/video/grvga.c
@@ -0,0 +1,579 @@
+/*
+ * Driver for Aeroflex Gaisler SVGACTRL framebuffer device.
+ *
+ * 2011 (c) Aeroflex Gaisler AB
+ *
+ * Full documentation of the core can be found here:
+ * http://www.gaisler.com/products/grlib/grip.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Contributors: Kristoffer Glembo <kristoffer@gaisler.com>
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/io.h>
+
+struct grvga_regs {
+ u32 status; /* 0x00 */
+ u32 video_length; /* 0x04 */
+ u32 front_porch; /* 0x08 */
+ u32 sync_length; /* 0x0C */
+ u32 line_length; /* 0x10 */
+ u32 fb_pos; /* 0x14 */
+ u32 clk_vector[4]; /* 0x18 */
+ u32 clut; /* 0x20 */
+};
+
+struct grvga_par {
+ struct grvga_regs *regs;
+ u32 color_palette[16]; /* 16 entry pseudo palette used by fbcon in true color mode */
+ int clk_sel;
+ int fb_alloced; /* = 1 if framebuffer is allocated in main memory */
+};
+
+
+static const struct fb_videomode grvga_modedb[] = {
+ {
+ /* 640x480 @ 60 Hz */
+ NULL, 60, 640, 480, 40000, 48, 16, 39, 11, 96, 2,
+ 0, FB_VMODE_NONINTERLACED
+ }, {
+ /* 800x600 @ 60 Hz */
+ NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
+ 0, FB_VMODE_NONINTERLACED
+ }, {
+ /* 800x600 @ 72 Hz */
+ NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
+ 0, FB_VMODE_NONINTERLACED
+ }, {
+ /* 1024x768 @ 60 Hz */
+ NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
+ 0, FB_VMODE_NONINTERLACED
+ }
+ };
+
+static struct fb_fix_screeninfo grvga_fix __initdata = {
+ .id = "AG SVGACTRL",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_PSEUDOCOLOR,
+ .xpanstep = 0,
+ .ypanstep = 1,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+};
+
+static int grvga_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct grvga_par *par = info->par;
+ int i;
+
+ if (!var->xres)
+ var->xres = 1;
+ if (!var->yres)
+ var->yres = 1;
+ if (var->bits_per_pixel <= 8)
+ var->bits_per_pixel = 8;
+ else if (var->bits_per_pixel <= 16)
+ var->bits_per_pixel = 16;
+ else if (var->bits_per_pixel <= 24)
+ var->bits_per_pixel = 24;
+ else if (var->bits_per_pixel <= 32)
+ var->bits_per_pixel = 32;
+ else
+ return -EINVAL;
+
+ var->xres_virtual = var->xres;
+ var->yres_virtual = 2*var->yres;
+
+ if (info->fix.smem_len) {
+ if ((var->yres_virtual*var->xres_virtual*var->bits_per_pixel/8) > info->fix.smem_len)
+ return -ENOMEM;
+ }
+
+ /* Which clocks that are available can be read out in these registers */
+ for (i = 0; i <= 3 ; i++) {
+ if (var->pixclock == par->regs->clk_vector[i])
+ break;
+ }
+ if (i <= 3)
+ par->clk_sel = i;
+ else
+ return -EINVAL;
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ var->red = (struct fb_bitfield) {0, 8, 0}; /* offset, length, msb-right */
+ var->green = (struct fb_bitfield) {0, 8, 0};
+ var->blue = (struct fb_bitfield) {0, 8, 0};
+ var->transp = (struct fb_bitfield) {0, 0, 0};
+ break;
+ case 16:
+ var->red = (struct fb_bitfield) {11, 5, 0};
+ var->green = (struct fb_bitfield) {5, 6, 0};
+ var->blue = (struct fb_bitfield) {0, 5, 0};
+ var->transp = (struct fb_bitfield) {0, 0, 0};
+ break;
+ case 24:
+ case 32:
+ var->red = (struct fb_bitfield) {16, 8, 0};
+ var->green = (struct fb_bitfield) {8, 8, 0};
+ var->blue = (struct fb_bitfield) {0, 8, 0};
+ var->transp = (struct fb_bitfield) {24, 8, 0};
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int grvga_set_par(struct fb_info *info)
+{
+
+ u32 func = 0;
+ struct grvga_par *par = info->par;
+
+ __raw_writel(((info->var.yres - 1) << 16) | (info->var.xres - 1),
+ &par->regs->video_length);
+
+ __raw_writel((info->var.lower_margin << 16) | (info->var.right_margin),
+ &par->regs->front_porch);
+
+ __raw_writel((info->var.vsync_len << 16) | (info->var.hsync_len),
+ &par->regs->sync_length);
+
+ __raw_writel(((info->var.yres + info->var.lower_margin + info->var.upper_margin + info->var.vsync_len - 1) << 16) |
+ (info->var.xres + info->var.right_margin + info->var.left_margin + info->var.hsync_len - 1),
+ &par->regs->line_length);
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ func = 1;
+ break;
+ case 16:
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ func = 2;
+ break;
+ case 24:
+ case 32:
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ func = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ __raw_writel((par->clk_sel << 6) | (func << 4) | 1,
+ &par->regs->status);
+
+ info->fix.line_length = (info->var.xres_virtual*info->var.bits_per_pixel)/8;
+ return 0;
+}
+
+static int grvga_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info)
+{
+ struct grvga_par *par;
+ par = info->par;
+
+ if (regno >= 256) /* Size of CLUT */
+ return -EINVAL;
+
+ if (info->var.grayscale) {
+ /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+ }
+
+
+
+#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
+
+ red = CNVT_TOHW(red, info->var.red.length);
+ green = CNVT_TOHW(green, info->var.green.length);
+ blue = CNVT_TOHW(blue, info->var.blue.length);
+ transp = CNVT_TOHW(transp, info->var.transp.length);
+
+#undef CNVT_TOHW
+
+ /* In PSEUDOCOLOR we use the hardware CLUT */
+ if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
+ __raw_writel((regno << 24) | (red << 16) | (green << 8) | blue,
+ &par->regs->clut);
+
+ /* Truecolor uses the pseudo palette */
+ else if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+ u32 v;
+ if (regno >= 16)
+ return -EINVAL;
+
+
+ v = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset) |
+ (transp << info->var.transp.offset);
+
+ ((u32 *) (info->pseudo_palette))[regno] = v;
+ }
+ return 0;
+}
+
+static int grvga_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct grvga_par *par = info->par;
+ struct fb_fix_screeninfo *fix = &info->fix;
+ u32 base_addr;
+
+ if (var->xoffset != 0)
+ return -EINVAL;
+
+ base_addr = fix->smem_start + (var->yoffset * fix->line_length);
+ base_addr &= ~3UL;
+
+ /* Set framebuffer base address */
+ __raw_writel(base_addr,
+ &par->regs->fb_pos);
+
+ return 0;
+}
+
+static struct fb_ops grvga_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = grvga_check_var,
+ .fb_set_par = grvga_set_par,
+ .fb_setcolreg = grvga_setcolreg,
+ .fb_pan_display = grvga_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit
+};
+
+static int __init grvga_parse_custom(char *options,
+ struct fb_var_screeninfo *screendata)
+{
+ char *this_opt;
+ int count = 0;
+ if (!options || !*options)
+ return -1;
+
+ while ((this_opt = strsep(&options, " ")) != NULL) {
+ if (!*this_opt)
+ continue;
+
+ switch (count) {
+ case 0:
+ screendata->pixclock = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 1:
+ screendata->xres = screendata->xres_virtual = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 2:
+ screendata->right_margin = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 3:
+ screendata->hsync_len = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 4:
+ screendata->left_margin = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 5:
+ screendata->yres = screendata->yres_virtual = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 6:
+ screendata->lower_margin = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 7:
+ screendata->vsync_len = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 8:
+ screendata->upper_margin = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 9:
+ screendata->bits_per_pixel = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ default:
+ return -1;
+ }
+ }
+ screendata->activate = FB_ACTIVATE_NOW;
+ screendata->vmode = FB_VMODE_NONINTERLACED;
+ return 0;
+}
+
+static int __devinit grvga_probe(struct platform_device *dev)
+{
+ struct fb_info *info;
+ int retval = -ENOMEM;
+ unsigned long virtual_start;
+ unsigned long grvga_fix_addr = 0;
+ unsigned long physical_start = 0;
+ unsigned long grvga_mem_size = 0;
+ struct grvga_par *par = NULL;
+ char *options = NULL, *mode_opt = NULL;
+
+ info = framebuffer_alloc(sizeof(struct grvga_par), &dev->dev);
+ if (!info) {
+ dev_err(&dev->dev, "framebuffer_alloc failed\n");
+ return -ENOMEM;
+ }
+
+ /* Expecting: "grvga: modestring, [addr:<framebuffer physical address>], [size:<framebuffer size>]
+ *
+ * If modestring is custom:<custom mode string> we parse the string which then contains all videoparameters
+ * If address is left out, we allocate memory,
+ * if size is left out we only allocate enough to support the given mode.
+ */
+ if (fb_get_options("grvga", &options)) {
+ retval = -ENODEV;
+ goto err;
+ }
+
+ if (!options || !*options)
+ options = "640x480-8@60";
+
+ while (1) {
+ char *this_opt = strsep(&options, ",");
+
+ if (!this_opt)
+ break;
+
+ if (!strncmp(this_opt, "custom", 6)) {
+ if (grvga_parse_custom(this_opt, &info->var) < 0) {
+ dev_err(&dev->dev, "Failed to parse custom mode (%s).\n", this_opt);
+ retval = -EINVAL;
+ goto err1;
+ }
+ } else if (!strncmp(this_opt, "addr", 4))
+ grvga_fix_addr = simple_strtoul(this_opt + 5, NULL, 16);
+ else if (!strncmp(this_opt, "size", 4))
+ grvga_mem_size = simple_strtoul(this_opt + 5, NULL, 0);
+ else
+ mode_opt = this_opt;
+ }
+
+ par = info->par;
+ info->fbops = &grvga_ops;
+ info->fix = grvga_fix;
+ info->pseudo_palette = par->color_palette;
+ info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
+ info->fix.smem_len = grvga_mem_size;
+
+ if (!request_mem_region(dev->resource[0].start, resource_size(&dev->resource[0]), "grlib-svgactrl regs")) {
+ dev_err(&dev->dev, "registers already mapped\n");
+ retval = -EBUSY;
+ goto err;
+ }
+
+ par->regs = of_ioremap(&dev->resource[0], 0,
+ resource_size(&dev->resource[0]),
+ "grlib-svgactrl regs");
+
+ if (!par->regs) {
+ dev_err(&dev->dev, "failed to map registers\n");
+ retval = -ENOMEM;
+ goto err1;
+ }
+
+ retval = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (retval < 0) {
+ dev_err(&dev->dev, "failed to allocate mem with fb_alloc_cmap\n");
+ retval = -ENOMEM;
+ goto err2;
+ }
+
+ if (mode_opt) {
+ retval = fb_find_mode(&info->var, info, mode_opt,
+ grvga_modedb, sizeof(grvga_modedb), &grvga_modedb[0], 8);
+ if (!retval || retval == 4) {
+ retval = -EINVAL;
+ goto err3;
+ }
+ }
+
+ if (!grvga_mem_size)
+ grvga_mem_size = info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel/8;
+
+ if (grvga_fix_addr) {
+ /* Got framebuffer base address from argument list */
+
+ physical_start = grvga_fix_addr;
+
+ if (!request_mem_region(physical_start, grvga_mem_size, dev->name)) {
+ dev_err(&dev->dev, "failed to request memory region\n");
+ retval = -ENOMEM;
+ goto err3;
+ }
+
+ virtual_start = (unsigned long) ioremap(physical_start, grvga_mem_size);
+
+ if (!virtual_start) {
+ dev_err(&dev->dev, "error mapping framebuffer memory\n");
+ retval = -ENOMEM;
+ goto err4;
+ }
+ } else { /* Allocate frambuffer memory */
+
+ unsigned long page;
+
+ virtual_start = (unsigned long) __get_free_pages(GFP_DMA,
+ get_order(grvga_mem_size));
+ if (!virtual_start) {
+ dev_err(&dev->dev,
+ "unable to allocate framebuffer memory (%lu bytes)\n",
+ grvga_mem_size);
+ retval = -ENOMEM;
+ goto err3;
+ }
+
+ physical_start = dma_map_single(&dev->dev, (void *)virtual_start, grvga_mem_size, DMA_TO_DEVICE);
+
+ /* Set page reserved so that mmap will work. This is necessary
+ * since we'll be remapping normal memory.
+ */
+ for (page = virtual_start;
+ page < PAGE_ALIGN(virtual_start + grvga_mem_size);
+ page += PAGE_SIZE) {
+ SetPageReserved(virt_to_page(page));
+ }
+
+ par->fb_alloced = 1;
+ }
+
+ memset((unsigned long *) virtual_start, 0, grvga_mem_size);
+
+ info->screen_base = (char __iomem *) virtual_start;
+ info->fix.smem_start = physical_start;
+ info->fix.smem_len = grvga_mem_size;
+
+ dev_set_drvdata(&dev->dev, info);
+
+ dev_info(&dev->dev,
+ "Aeroflex Gaisler framebuffer device (fb%d), %dx%d-%d, using %luK of video memory @ %p\n",
+ info->node, info->var.xres, info->var.yres, info->var.bits_per_pixel,
+ grvga_mem_size >> 10, info->screen_base);
+
+ retval = register_framebuffer(info);
+ if (retval < 0) {
+ dev_err(&dev->dev, "failed to register framebuffer\n");
+ goto err4;
+ }
+
+ __raw_writel(physical_start, &par->regs->fb_pos);
+ __raw_writel(__raw_readl(&par->regs->status) | 1, /* Enable framebuffer */
+ &par->regs->status);
+
+ return 0;
+
+err4:
+ dev_set_drvdata(&dev->dev, NULL);
+ if (grvga_fix_addr) {
+ release_mem_region(physical_start, grvga_mem_size);
+ iounmap((void *)virtual_start);
+ } else
+ kfree((void *)virtual_start);
+err3:
+ fb_dealloc_cmap(&info->cmap);
+err2:
+ of_iounmap(&dev->resource[0], par->regs,
+ resource_size(&dev->resource[0]));
+err1:
+ release_mem_region(dev->resource[0].start, resource_size(&dev->resource[0]));
+err:
+ framebuffer_release(info);
+
+ return retval;
+}
+
+static int __devexit grvga_remove(struct platform_device *device)
+{
+ struct fb_info *info = dev_get_drvdata(&device->dev);
+ struct grvga_par *par = info->par;
+
+ if (info) {
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+
+ of_iounmap(&device->resource[0], par->regs,
+ resource_size(&device->resource[0]));
+ release_mem_region(device->resource[0].start, resource_size(&device->resource[0]));
+
+ if (!par->fb_alloced) {
+ release_mem_region(info->fix.smem_start, info->fix.smem_len);
+ iounmap(info->screen_base);
+ } else
+ kfree((void *)info->screen_base);
+
+ framebuffer_release(info);
+ dev_set_drvdata(&device->dev, NULL);
+ }
+
+ return 0;
+}
+
+static struct of_device_id svgactrl_of_match[] = {
+ {
+ .name = "GAISLER_SVGACTRL",
+ },
+ {
+ .name = "01_063",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, svgactrl_of_match);
+
+static struct platform_driver grvga_driver = {
+ .driver = {
+ .name = "grlib-svgactrl",
+ .owner = THIS_MODULE,
+ .of_match_table = svgactrl_of_match,
+ },
+ .probe = grvga_probe,
+ .remove = __devexit_p(grvga_remove),
+};
+
+
+static int __init grvga_init(void)
+{
+ return platform_driver_register(&grvga_driver);
+}
+
+static void __exit grvga_exit(void)
+{
+ platform_driver_unregister(&grvga_driver);
+}
+
+module_init(grvga_init);
+module_exit(grvga_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Aeroflex Gaisler");
+MODULE_DESCRIPTION("Aeroflex Gaisler framebuffer device driver");
diff --git a/drivers/video/gxt4500.c b/drivers/video/gxt4500.c
index 896e53d..0fad23f 100644
--- a/drivers/video/gxt4500.c
+++ b/drivers/video/gxt4500.c
@@ -543,8 +543,8 @@ static int gxt4500_pan_display(struct fb_var_screeninfo *var,
if (var->xoffset & 7)
return -EINVAL;
- if (var->xoffset + var->xres > var->xres_virtual ||
- var->yoffset + var->yres > var->yres_virtual)
+ if (var->xoffset + info->var.xres > info->var.xres_virtual ||
+ var->yoffset + info->var.yres > info->var.yres_virtual)
return -EINVAL;
writereg(par, REFRESH_START, (var->xoffset << 16) | var->yoffset);
diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c
index 4052718..4394389 100644
--- a/drivers/video/hgafb.c
+++ b/drivers/video/hgafb.c
@@ -422,8 +422,8 @@ static int hgafb_pan_display(struct fb_var_screeninfo *var,
var->xoffset)
return -EINVAL;
} else {
- if (var->xoffset + var->xres > info->var.xres_virtual
- || var->yoffset + var->yres > info->var.yres_virtual
+ if (var->xoffset + info->var.xres > info->var.xres_virtual
+ || var->yoffset + info->var.yres > info->var.yres_virtual
|| var->yoffset % 8)
return -EINVAL;
}
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
index efb2c10..8149356 100644
--- a/drivers/video/imsttfb.c
+++ b/drivers/video/imsttfb.c
@@ -749,7 +749,7 @@ set_offset (struct fb_var_screeninfo *var, struct fb_info *info)
{
struct imstt_par *par = info->par;
__u32 off = var->yoffset * (info->fix.line_length >> 3)
- + ((var->xoffset * (var->bits_per_pixel >> 3)) >> 3);
+ + ((var->xoffset * (info->var.bits_per_pixel >> 3)) >> 3);
write_reg_le32(par->dc_regs, SSR, off);
}
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 38065cf..fbad61d 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -390,12 +390,12 @@ int intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
xoffset = ROUND_DOWN_TO(var->xoffset, 8);
yoffset = var->yoffset;
- if ((xoffset + var->xres > var->xres_virtual) ||
- (yoffset + var->yres > var->yres_virtual))
+ if ((xoffset + info->var.xres > info->var.xres_virtual) ||
+ (yoffset + info->var.yres > info->var.yres_virtual))
return -EINVAL;
offset = (yoffset * dinfo->pitch) +
- (xoffset * var->bits_per_pixel) / 8;
+ (xoffset * info->var.bits_per_pixel) / 8;
offset += dinfo->fb.offset << 12;
diff --git a/drivers/video/mb862xx/mb862xx-i2c.c b/drivers/video/mb862xx/mb862xx-i2c.c
index b953099..934081d 100644
--- a/drivers/video/mb862xx/mb862xx-i2c.c
+++ b/drivers/video/mb862xx/mb862xx-i2c.c
@@ -23,7 +23,7 @@ static int mb862xx_i2c_wait_event(struct i2c_adapter *adap)
u32 reg;
do {
- udelay(1);
+ udelay(10);
reg = inreg(i2c, GC_I2C_BCR);
if (reg & (I2C_INT | I2C_BER))
break;
diff --git a/drivers/video/mb862xx/mb862xxfbdrv.c b/drivers/video/mb862xx/mb862xxfbdrv.c
index ee1de3e..c16ff1d 100644
--- a/drivers/video/mb862xx/mb862xxfbdrv.c
+++ b/drivers/video/mb862xx/mb862xxfbdrv.c
@@ -278,7 +278,7 @@ static int mb862xxfb_pan(struct fb_var_screeninfo *var,
reg = pack(var->yoffset, var->xoffset);
outreg(disp, GC_L0WY_L0WX, reg);
- reg = pack(var->yres_virtual, var->xres_virtual);
+ reg = pack(info->var.yres_virtual, info->var.xres_virtual);
outreg(disp, GC_L0WH_L0WW, reg);
return 0;
}
@@ -737,7 +737,7 @@ static int __devinit of_platform_mb862xx_probe(struct platform_device *ofdev)
if (mb862xx_gdc_init(par))
goto io_unmap;
- if (request_irq(par->irq, mb862xx_intr, IRQF_DISABLED,
+ if (request_irq(par->irq, mb862xx_intr, 0,
DRV_NAME, (void *)par)) {
dev_err(dev, "Cannot request irq\n");
goto io_unmap;
@@ -1073,7 +1073,7 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev,
if (mb862xx_pci_gdc_init(par))
goto io_unmap;
- if (request_irq(par->irq, mb862xx_intr, IRQF_DISABLED | IRQF_SHARED,
+ if (request_irq(par->irq, mb862xx_intr, IRQF_SHARED,
DRV_NAME, (void *)par)) {
dev_err(dev, "Cannot request irq\n");
goto io_unmap;
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index cb175fe..a9a907c 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -491,55 +491,56 @@ EXPORT_SYMBOL(vesa_modes);
static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
const struct fb_videomode *mode, unsigned int bpp)
{
- int err = 0;
-
- DPRINTK("Trying mode %s %dx%d-%d@%d\n", mode->name ? mode->name : "noname",
- mode->xres, mode->yres, bpp, mode->refresh);
- var->xres = mode->xres;
- var->yres = mode->yres;
- var->xres_virtual = mode->xres;
- var->yres_virtual = mode->yres;
- var->xoffset = 0;
- var->yoffset = 0;
- var->bits_per_pixel = bpp;
- var->activate |= FB_ACTIVATE_TEST;
- var->pixclock = mode->pixclock;
- var->left_margin = mode->left_margin;
- var->right_margin = mode->right_margin;
- var->upper_margin = mode->upper_margin;
- var->lower_margin = mode->lower_margin;
- var->hsync_len = mode->hsync_len;
- var->vsync_len = mode->vsync_len;
- var->sync = mode->sync;
- var->vmode = mode->vmode;
- if (info->fbops->fb_check_var)
- err = info->fbops->fb_check_var(var, info);
- var->activate &= ~FB_ACTIVATE_TEST;
- return err;
+ int err = 0;
+
+ DPRINTK("Trying mode %s %dx%d-%d@%d\n",
+ mode->name ? mode->name : "noname",
+ mode->xres, mode->yres, bpp, mode->refresh);
+ var->xres = mode->xres;
+ var->yres = mode->yres;
+ var->xres_virtual = mode->xres;
+ var->yres_virtual = mode->yres;
+ var->xoffset = 0;
+ var->yoffset = 0;
+ var->bits_per_pixel = bpp;
+ var->activate |= FB_ACTIVATE_TEST;
+ var->pixclock = mode->pixclock;
+ var->left_margin = mode->left_margin;
+ var->right_margin = mode->right_margin;
+ var->upper_margin = mode->upper_margin;
+ var->lower_margin = mode->lower_margin;
+ var->hsync_len = mode->hsync_len;
+ var->vsync_len = mode->vsync_len;
+ var->sync = mode->sync;
+ var->vmode = mode->vmode;
+ if (info->fbops->fb_check_var)
+ err = info->fbops->fb_check_var(var, info);
+ var->activate &= ~FB_ACTIVATE_TEST;
+ return err;
}
/**
- * fb_find_mode - finds a valid video mode
- * @var: frame buffer user defined part of display
- * @info: frame buffer info structure
- * @mode_option: string video mode to find
- * @db: video mode database
- * @dbsize: size of @db
- * @default_mode: default video mode to fall back to
- * @default_bpp: default color depth in bits per pixel
+ * fb_find_mode - finds a valid video mode
+ * @var: frame buffer user defined part of display
+ * @info: frame buffer info structure
+ * @mode_option: string video mode to find
+ * @db: video mode database
+ * @dbsize: size of @db
+ * @default_mode: default video mode to fall back to
+ * @default_bpp: default color depth in bits per pixel
*
- * Finds a suitable video mode, starting with the specified mode
- * in @mode_option with fallback to @default_mode. If
- * @default_mode fails, all modes in the video mode database will
- * be tried.
+ * Finds a suitable video mode, starting with the specified mode
+ * in @mode_option with fallback to @default_mode. If
+ * @default_mode fails, all modes in the video mode database will
+ * be tried.
*
- * Valid mode specifiers for @mode_option:
+ * Valid mode specifiers for @mode_option:
*
- * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or
- * <name>[-<bpp>][@<refresh>]
+ * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or
+ * <name>[-<bpp>][@<refresh>]
*
- * with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
- * <name> a string.
+ * with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
+ * <name> a string.
*
* If 'M' is present after yres (and before refresh/bpp if present),
* the function will compute the timings using VESA(tm) Coordinated
@@ -551,12 +552,12 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
*
* 1024x768MR-8@60m - Reduced blank with margins at 60Hz.
*
- * NOTE: The passed struct @var is _not_ cleared! This allows you
- * to supply values for e.g. the grayscale and accel_flags fields.
+ * NOTE: The passed struct @var is _not_ cleared! This allows you
+ * to supply values for e.g. the grayscale and accel_flags fields.
*
- * Returns zero for failure, 1 if using specified @mode_option,
- * 2 if using specified @mode_option with an ignored refresh rate,
- * 3 if default mode is used, 4 if fall back to any valid mode.
+ * Returns zero for failure, 1 if using specified @mode_option,
+ * 2 if using specified @mode_option with an ignored refresh rate,
+ * 3 if default mode is used, 4 if fall back to any valid mode.
*
*/
@@ -566,198 +567,203 @@ int fb_find_mode(struct fb_var_screeninfo *var,
const struct fb_videomode *default_mode,
unsigned int default_bpp)
{
- int i;
-
- /* Set up defaults */
- if (!db) {
- db = modedb;
- dbsize = ARRAY_SIZE(modedb);
- }
-
- if (!default_mode)
- default_mode = &db[0];
-
- if (!default_bpp)
- default_bpp = 8;
-
- /* Did the user specify a video mode? */
- if (!mode_option)
- mode_option = fb_mode_option;
- if (mode_option) {
- const char *name = mode_option;
- unsigned int namelen = strlen(name);
- int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
- unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
- int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
- u32 best, diff, tdiff;
-
- for (i = namelen-1; i >= 0; i--) {
- switch (name[i]) {
- case '@':
- namelen = i;
- if (!refresh_specified && !bpp_specified &&
- !yres_specified) {
- refresh = simple_strtol(&name[i+1], NULL, 10);
- refresh_specified = 1;
- if (cvt || rb)
- cvt = 0;
- } else
- goto done;
- break;
- case '-':
- namelen = i;
- if (!bpp_specified && !yres_specified) {
- bpp = simple_strtol(&name[i+1], NULL, 10);
- bpp_specified = 1;
- if (cvt || rb)
- cvt = 0;
- } else
- goto done;
- break;
- case 'x':
- if (!yres_specified) {
- yres = simple_strtol(&name[i+1], NULL, 10);
- yres_specified = 1;
- } else
- goto done;
- break;
- case '0' ... '9':
- break;
- case 'M':
- if (!yres_specified)
- cvt = 1;
- break;
- case 'R':
- if (!cvt)
- rb = 1;
- break;
- case 'm':
- if (!cvt)
- margins = 1;
- break;
- case 'i':
- if (!cvt)
- interlace = 1;
- break;
- default:
- goto done;
- }
- }
- if (i < 0 && yres_specified) {
- xres = simple_strtol(name, NULL, 10);
- res_specified = 1;
- }
-done:
- if (cvt) {
- struct fb_videomode cvt_mode;
- int ret;
-
- DPRINTK("CVT mode %dx%d@%dHz%s%s%s\n", xres, yres,
- (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
- "", (margins) ? " with margins" : "", (interlace) ?
- " interlaced" : "");
-
- memset(&cvt_mode, 0, sizeof(cvt_mode));
- cvt_mode.xres = xres;
- cvt_mode.yres = yres;
- cvt_mode.refresh = (refresh) ? refresh : 60;
+ int i;
- if (interlace)
- cvt_mode.vmode |= FB_VMODE_INTERLACED;
- else
- cvt_mode.vmode &= ~FB_VMODE_INTERLACED;
+ /* Set up defaults */
+ if (!db) {
+ db = modedb;
+ dbsize = ARRAY_SIZE(modedb);
+ }
- ret = fb_find_mode_cvt(&cvt_mode, margins, rb);
+ if (!default_mode)
+ default_mode = &db[0];
+
+ if (!default_bpp)
+ default_bpp = 8;
+
+ /* Did the user specify a video mode? */
+ if (!mode_option)
+ mode_option = fb_mode_option;
+ if (mode_option) {
+ const char *name = mode_option;
+ unsigned int namelen = strlen(name);
+ int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
+ unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
+ int yres_specified = 0, cvt = 0, rb = 0, interlace = 0;
+ int margins = 0;
+ u32 best, diff, tdiff;
+
+ for (i = namelen-1; i >= 0; i--) {
+ switch (name[i]) {
+ case '@':
+ namelen = i;
+ if (!refresh_specified && !bpp_specified &&
+ !yres_specified) {
+ refresh = simple_strtol(&name[i+1], NULL,
+ 10);
+ refresh_specified = 1;
+ if (cvt || rb)
+ cvt = 0;
+ } else
+ goto done;
+ break;
+ case '-':
+ namelen = i;
+ if (!bpp_specified && !yres_specified) {
+ bpp = simple_strtol(&name[i+1], NULL,
+ 10);
+ bpp_specified = 1;
+ if (cvt || rb)
+ cvt = 0;
+ } else
+ goto done;
+ break;
+ case 'x':
+ if (!yres_specified) {
+ yres = simple_strtol(&name[i+1], NULL,
+ 10);
+ yres_specified = 1;
+ } else
+ goto done;
+ break;
+ case '0' ... '9':
+ break;
+ case 'M':
+ if (!yres_specified)
+ cvt = 1;
+ break;
+ case 'R':
+ if (!cvt)
+ rb = 1;
+ break;
+ case 'm':
+ if (!cvt)
+ margins = 1;
+ break;
+ case 'i':
+ if (!cvt)
+ interlace = 1;
+ break;
+ default:
+ goto done;
+ }
+ }
+ if (i < 0 && yres_specified) {
+ xres = simple_strtol(name, NULL, 10);
+ res_specified = 1;
+ }
+done:
+ if (cvt) {
+ struct fb_videomode cvt_mode;
+ int ret;
+
+ DPRINTK("CVT mode %dx%d@%dHz%s%s%s\n", xres, yres,
+ (refresh) ? refresh : 60,
+ (rb) ? " reduced blanking" : "",
+ (margins) ? " with margins" : "",
+ (interlace) ? " interlaced" : "");
+
+ memset(&cvt_mode, 0, sizeof(cvt_mode));
+ cvt_mode.xres = xres;
+ cvt_mode.yres = yres;
+ cvt_mode.refresh = (refresh) ? refresh : 60;
+
+ if (interlace)
+ cvt_mode.vmode |= FB_VMODE_INTERLACED;
+ else
+ cvt_mode.vmode &= ~FB_VMODE_INTERLACED;
+
+ ret = fb_find_mode_cvt(&cvt_mode, margins, rb);
+
+ if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) {
+ DPRINTK("modedb CVT: CVT mode ok\n");
+ return 1;
+ }
- if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) {
- DPRINTK("modedb CVT: CVT mode ok\n");
- return 1;
- }
+ DPRINTK("CVT mode invalid, getting mode from database\n");
+ }
- DPRINTK("CVT mode invalid, getting mode from database\n");
- }
+ DPRINTK("Trying specified video mode%s %ix%i\n",
+ refresh_specified ? "" : " (ignoring refresh rate)",
+ xres, yres);
- DPRINTK("Trying specified video mode%s %ix%i\n",
- refresh_specified ? "" : " (ignoring refresh rate)", xres, yres);
-
- if (!refresh_specified) {
- /*
- * If the caller has provided a custom mode database and a
- * valid monspecs structure, we look for the mode with the
- * highest refresh rate. Otherwise we play it safe it and
- * try to find a mode with a refresh rate closest to the
- * standard 60 Hz.
- */
- if (db != modedb &&
- info->monspecs.vfmin && info->monspecs.vfmax &&
- info->monspecs.hfmin && info->monspecs.hfmax &&
- info->monspecs.dclkmax) {
- refresh = 1000;
- } else {
- refresh = 60;
+ if (!refresh_specified) {
+ /*
+ * If the caller has provided a custom mode database and
+ * a valid monspecs structure, we look for the mode with
+ * the highest refresh rate. Otherwise we play it safe
+ * it and try to find a mode with a refresh rate closest
+ * to the standard 60 Hz.
+ */
+ if (db != modedb &&
+ info->monspecs.vfmin && info->monspecs.vfmax &&
+ info->monspecs.hfmin && info->monspecs.hfmax &&
+ info->monspecs.dclkmax) {
+ refresh = 1000;
+ } else {
+ refresh = 60;
+ }
}
- }
- diff = -1;
- best = -1;
- for (i = 0; i < dbsize; i++) {
- if ((name_matches(db[i], name, namelen) ||
- (res_specified && res_matches(db[i], xres, yres))) &&
- !fb_try_mode(var, info, &db[i], bpp)) {
- if (refresh_specified && db[i].refresh == refresh) {
- return 1;
- } else {
+ diff = -1;
+ best = -1;
+ for (i = 0; i < dbsize; i++) {
+ if ((name_matches(db[i], name, namelen) ||
+ (res_specified && res_matches(db[i], xres, yres))) &&
+ !fb_try_mode(var, info, &db[i], bpp)) {
+ if (refresh_specified && db[i].refresh == refresh)
+ return 1;
+
if (abs(db[i].refresh - refresh) < diff) {
diff = abs(db[i].refresh - refresh);
best = i;
}
}
}
- }
- if (best != -1) {
- fb_try_mode(var, info, &db[best], bpp);
- return (refresh_specified) ? 2 : 1;
- }
-
- diff = 2 * (xres + yres);
- best = -1;
- DPRINTK("Trying best-fit modes\n");
- for (i = 0; i < dbsize; i++) {
- DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres);
- if (!fb_try_mode(var, info, &db[i], bpp)) {
- tdiff = abs(db[i].xres - xres) +
- abs(db[i].yres - yres);
-
- /*
- * Penalize modes with resolutions smaller
- * than requested.
- */
- if (xres > db[i].xres || yres > db[i].yres)
- tdiff += xres + yres;
+ if (best != -1) {
+ fb_try_mode(var, info, &db[best], bpp);
+ return (refresh_specified) ? 2 : 1;
+ }
- if (diff > tdiff) {
- diff = tdiff;
- best = i;
+ diff = 2 * (xres + yres);
+ best = -1;
+ DPRINTK("Trying best-fit modes\n");
+ for (i = 0; i < dbsize; i++) {
+ DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres);
+ if (!fb_try_mode(var, info, &db[i], bpp)) {
+ tdiff = abs(db[i].xres - xres) +
+ abs(db[i].yres - yres);
+
+ /*
+ * Penalize modes with resolutions smaller
+ * than requested.
+ */
+ if (xres > db[i].xres || yres > db[i].yres)
+ tdiff += xres + yres;
+
+ if (diff > tdiff) {
+ diff = tdiff;
+ best = i;
+ }
}
}
+ if (best != -1) {
+ fb_try_mode(var, info, &db[best], bpp);
+ return 5;
+ }
}
- if (best != -1) {
- fb_try_mode(var, info, &db[best], bpp);
- return 5;
- }
- }
- DPRINTK("Trying default video mode\n");
- if (!fb_try_mode(var, info, default_mode, default_bpp))
- return 3;
+ DPRINTK("Trying default video mode\n");
+ if (!fb_try_mode(var, info, default_mode, default_bpp))
+ return 3;
- DPRINTK("Trying all modes\n");
- for (i = 0; i < dbsize; i++)
- if (!fb_try_mode(var, info, &db[i], default_bpp))
- return 4;
+ DPRINTK("Trying all modes\n");
+ for (i = 0; i < dbsize; i++)
+ if (!fb_try_mode(var, info, &db[i], default_bpp))
+ return 4;
- DPRINTK("No valid mode found\n");
- return 0;
+ DPRINTK("No valid mode found\n");
+ return 0;
}
/**
diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c
index 178b072..4527cbf 100644
--- a/drivers/video/msm/mddi.c
+++ b/drivers/video/msm/mddi.c
@@ -715,7 +715,7 @@ static int __devinit mddi_probe(struct platform_device *pdev)
mddi->int_enable = 0;
mddi_writel(mddi->int_enable, INTEN);
- ret = request_irq(mddi->irq, mddi_isr, IRQF_DISABLED, "mddi",
+ ret = request_irq(mddi->irq, mddi_isr, 0, "mddi",
&mddi->client_data);
if (ret) {
printk(KERN_ERR "mddi: failed to request enable irq!\n");
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 243d16f..b934477 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -421,10 +421,11 @@ int mdp_probe(struct platform_device *pdev)
clk = clk_get(&pdev->dev, "mdp_clk");
if (IS_ERR(clk)) {
printk(KERN_INFO "mdp: failed to get mdp clk");
- return PTR_ERR(clk);
+ ret = PTR_ERR(clk);
+ goto error_get_clk;
}
- ret = request_irq(mdp->irq, mdp_isr, IRQF_DISABLED, "msm_mdp", mdp);
+ ret = request_irq(mdp->irq, mdp_isr, 0, "msm_mdp", mdp);
if (ret)
goto error_request_irq;
disable_irq(mdp->irq);
@@ -495,6 +496,7 @@ int mdp_probe(struct platform_device *pdev)
error_device_register:
free_irq(mdp->irq, mdp);
error_request_irq:
+error_get_clk:
iounmap(mdp->base);
error_get_irq:
error_ioremap:
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index 7e3a490..e3406ab 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -382,6 +382,9 @@ static void sdc_disable_channel(struct mx3fb_info *mx3_fbi)
uint32_t enabled;
unsigned long flags;
+ if (mx3_fbi->txd == NULL)
+ return;
+
spin_lock_irqsave(&mx3fb->lock, flags);
enabled = sdc_fb_uninit(mx3_fbi);
@@ -986,9 +989,19 @@ static void __blank(int blank, struct fb_info *fbi)
{
struct mx3fb_info *mx3_fbi = fbi->par;
struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;
+ int was_blank = mx3_fbi->blank;
mx3_fbi->blank = blank;
+ /* Attention!
+ * Do not call sdc_disable_channel() for a channel that is disabled
+ * already! This will result in a kernel NULL pointer dereference
+ * (mx3_fbi->txd is NULL). Hide the fact, that all blank modes are
+ * handled equally by this driver.
+ */
+ if (blank > FB_BLANK_UNBLANK && was_blank > FB_BLANK_UNBLANK)
+ return;
+
switch (blank) {
case FB_BLANK_POWERDOWN:
case FB_BLANK_VSYNC_SUSPEND:
@@ -1062,15 +1075,15 @@ static int mx3fb_pan_display(struct fb_var_screeninfo *var,
y_bottom = var->yoffset;
if (!(var->vmode & FB_VMODE_YWRAP))
- y_bottom += var->yres;
+ y_bottom += fbi->var.yres;
if (y_bottom > fbi->var.yres_virtual)
return -EINVAL;
mutex_lock(&mx3_fbi->mutex);
- offset = (var->yoffset * var->xres_virtual + var->xoffset) *
- (var->bits_per_pixel / 8);
+ offset = var->yoffset * fbi->fix.line_length
+ + var->xoffset * (fbi->var.bits_per_pixel / 8);
base = fbi->fix.smem_start + offset;
dev_dbg(fbi->device, "Updating SDC BG buf %d address=0x%08lX\n",
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 0b2f2dd..d837d63 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -39,6 +39,7 @@
* the required value in the imx_fb_videomode structure.
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index 588527a..feea7b1 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -1185,8 +1185,8 @@ static int neofb_pan_display(struct fb_var_screeninfo *var,
DBG("neofb_update_start");
- Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2;
- Base *= (var->bits_per_pixel + 7) / 8;
+ Base = (var->yoffset * info->var.xres_virtual + var->xoffset) >> 2;
+ Base *= (info->var.bits_per_pixel + 7) / 8;
neoUnlock();
diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c
index 0fff597..d1fbbd8 100644
--- a/drivers/video/nuc900fb.c
+++ b/drivers/video/nuc900fb.c
@@ -39,7 +39,6 @@
#include <mach/regs-clock.h>
#include <mach/regs-ldm.h>
#include <mach/fb.h>
-#include <mach/clkdev.h>
#include "nuc900fb.h"
@@ -588,7 +587,7 @@ static int __devinit nuc900fb_probe(struct platform_device *pdev)
fbinfo->flags = FBINFO_FLAG_DEFAULT;
fbinfo->pseudo_palette = &fbi->pseudo_pal;
- ret = request_irq(irq, nuc900fb_irqhandler, IRQF_DISABLED,
+ ret = request_irq(irq, nuc900fb_irqhandler, 0,
pdev->name, fbinfo);
if (ret) {
dev_err(&pdev->dev, "cannot register irq handler %d -err %d\n",
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 7f91002..80c3f6a 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -1034,7 +1034,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
gpio_direction_input(gpio);
r = request_irq(gpio_to_irq(gpio), taal_te_isr,
- IRQF_DISABLED | IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_RISING,
"taal vsync", dssdev);
if (r) {
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index f27ae16..6694923 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -490,7 +490,7 @@ static int platinum_var_to_par(struct fb_var_screeninfo *var,
/*
- * Parse user speficied options (`video=platinumfb:')
+ * Parse user specified options (`video=platinumfb:')
*/
static int __init platinumfb_setup(char *options)
{
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index 27f93aa..dc7bfa9 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -973,8 +973,8 @@ static int pm2fb_pan_display(struct fb_var_screeninfo *var,
{
struct pm2fb_par *p = info->par;
u32 base;
- u32 depth = (var->bits_per_pixel + 7) & ~7;
- u32 xres = (var->xres + 31) & ~31;
+ u32 depth = (info->var.bits_per_pixel + 7) & ~7;
+ u32 xres = (info->var.xres + 31) & ~31;
depth = (depth > 32) ? 32 : depth;
base = to3264(var->yoffset * xres + var->xoffset, depth, 1);
@@ -1773,7 +1773,7 @@ MODULE_DEVICE_TABLE(pci, pm2fb_id_table);
#ifndef MODULE
/**
- * Parse user speficied options.
+ * Parse user specified options.
*
* This is, comma-separated options following `video=pm2fb:'.
*/
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
index 6666f45..6632ee5 100644
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -1147,9 +1147,9 @@ static int pm3fb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct pm3_par *par = info->par;
- const u32 xres = (var->xres + 31) & ~31;
+ const u32 xres = (info->var.xres + 31) & ~31;
- par->base = pm3fb_shift_bpp(var->bits_per_pixel,
+ par->base = pm3fb_shift_bpp(info->var.bits_per_pixel,
(var->yoffset * xres)
+ var->xoffset);
PM3_WAIT(par, 1);
@@ -1525,7 +1525,7 @@ static int __init pm3fb_setup(char *options)
{
char *this_opt;
- /* Parse user speficied options (`video=pm3fb:') */
+ /* Parse user specified options (`video=pm3fb:') */
if (!options || !*options)
return 0;
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 65560a1..213fbbc 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -1082,7 +1082,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
}
retval = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt,
- IRQF_DISABLED, DEVICE_NAME, &dev->core);
+ 0, DEVICE_NAME, &dev->core);
if (retval) {
dev_err(&dev->core, "%s: request_irq failed %d\n", __func__,
retval);
diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c
index 0283c70..1ed8b36 100644
--- a/drivers/video/pxa3xx-gcu.c
+++ b/drivers/video/pxa3xx-gcu.c
@@ -31,8 +31,6 @@
*/
#include <linux/module.h>
-#include <linux/version.h>
-
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/miscdevice.h>
@@ -678,7 +676,7 @@ pxa3xx_gcu_probe(struct platform_device *dev)
}
ret = request_irq(irq, pxa3xx_gcu_handle_irq,
- IRQF_DISABLED, DRV_NAME, priv);
+ 0, DRV_NAME, priv);
if (ret) {
dev_err(&dev->dev, "request_irq failed\n");
ret = -EBUSY;
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 0f4e8c9..e89778f 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -2191,7 +2191,7 @@ static int __devinit pxafb_probe(struct platform_device *dev)
goto failed_free_mem;
}
- ret = request_irq(irq, pxafb_handle_irq, IRQF_DISABLED, "LCD", fbi);
+ ret = request_irq(irq, pxafb_handle_irq, 0, "LCD", fbi);
if (ret) {
dev_err(&dev->dev, "request_irq failed: %d\n", ret);
ret = -EBUSY;
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index 4aecf21..0753b1c 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -81,6 +81,7 @@ struct s3c_fb;
* @palette: Address of palette memory, or 0 if none.
* @has_prtcon: Set if has PRTCON register.
* @has_shadowcon: Set if has SHADOWCON register.
+ * @has_clksel: Set if VIDCON0 register has CLKSEL bit.
*/
struct s3c_fb_variant {
unsigned int is_2443:1;
@@ -98,6 +99,7 @@ struct s3c_fb_variant {
unsigned int has_prtcon:1;
unsigned int has_shadowcon:1;
+ unsigned int has_clksel:1;
};
/**
@@ -186,6 +188,7 @@ struct s3c_fb_vsync {
* @dev: The device that we bound to, for printing, etc.
* @regs_res: The resource we claimed for the IO registers.
* @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
+ * @lcd_clk: The clk (sclk) feeding pixclk.
* @regs: The mapped hardware registers.
* @variant: Variant information for this hardware.
* @enabled: A bitmask of enabled hardware windows.
@@ -200,6 +203,7 @@ struct s3c_fb {
struct device *dev;
struct resource *regs_res;
struct clk *bus_clk;
+ struct clk *lcd_clk;
void __iomem *regs;
struct s3c_fb_variant variant;
@@ -336,10 +340,15 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
*/
static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
{
- unsigned long clk = clk_get_rate(sfb->bus_clk);
+ unsigned long clk;
unsigned long long tmp;
unsigned int result;
+ if (sfb->variant.has_clksel)
+ clk = clk_get_rate(sfb->bus_clk);
+ else
+ clk = clk_get_rate(sfb->lcd_clk);
+
tmp = (unsigned long long)clk;
tmp *= pixclk;
@@ -883,7 +892,7 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
}
}
/* Offset in bytes to the end of the displayed area */
- end_boff = start_boff + var->yres * info->fix.line_length;
+ end_boff = start_boff + info->var.yres * info->fix.line_length;
/* Temporarily turn off per-vsync update from shadow registers until
* both start and end addresses are updated to prevent corruption */
@@ -1354,13 +1363,24 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
clk_enable(sfb->bus_clk);
+ if (!sfb->variant.has_clksel) {
+ sfb->lcd_clk = clk_get(dev, "sclk_fimd");
+ if (IS_ERR(sfb->lcd_clk)) {
+ dev_err(dev, "failed to get lcd clock\n");
+ ret = PTR_ERR(sfb->lcd_clk);
+ goto err_bus_clk;
+ }
+
+ clk_enable(sfb->lcd_clk);
+ }
+
pm_runtime_enable(sfb->dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "failed to find registers\n");
ret = -ENOENT;
- goto err_clk;
+ goto err_lcd_clk;
}
sfb->regs_res = request_mem_region(res->start, resource_size(res),
@@ -1368,7 +1388,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
if (!sfb->regs_res) {
dev_err(dev, "failed to claim register region\n");
ret = -ENOENT;
- goto err_clk;
+ goto err_lcd_clk;
}
sfb->regs = ioremap(res->start, resource_size(res));
@@ -1450,7 +1470,13 @@ err_ioremap:
err_req_region:
release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
-err_clk:
+err_lcd_clk:
+ if (!sfb->variant.has_clksel) {
+ clk_disable(sfb->lcd_clk);
+ clk_put(sfb->lcd_clk);
+ }
+
+err_bus_clk:
clk_disable(sfb->bus_clk);
clk_put(sfb->bus_clk);
@@ -1481,6 +1507,11 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
iounmap(sfb->regs);
+ if (!sfb->variant.has_clksel) {
+ clk_disable(sfb->lcd_clk);
+ clk_put(sfb->lcd_clk);
+ }
+
clk_disable(sfb->bus_clk);
clk_put(sfb->bus_clk);
@@ -1510,6 +1541,9 @@ static int s3c_fb_suspend(struct device *dev)
s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
}
+ if (!sfb->variant.has_clksel)
+ clk_disable(sfb->lcd_clk);
+
clk_disable(sfb->bus_clk);
return 0;
}
@@ -1524,6 +1558,9 @@ static int s3c_fb_resume(struct device *dev)
clk_enable(sfb->bus_clk);
+ if (!sfb->variant.has_clksel)
+ clk_enable(sfb->lcd_clk);
+
/* setup gpio and output polarity controls */
pd->setup_gpio();
writel(pd->vidcon1, sfb->regs + VIDCON1);
@@ -1569,6 +1606,9 @@ static int s3c_fb_runtime_suspend(struct device *dev)
s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
}
+ if (!sfb->variant.has_clksel)
+ clk_disable(sfb->lcd_clk);
+
clk_disable(sfb->bus_clk);
return 0;
}
@@ -1583,6 +1623,9 @@ static int s3c_fb_runtime_resume(struct device *dev)
clk_enable(sfb->bus_clk);
+ if (!sfb->variant.has_clksel)
+ clk_enable(sfb->lcd_clk);
+
/* setup gpio and output polarity controls */
pd->setup_gpio();
writel(pd->vidcon1, sfb->regs + VIDCON1);
@@ -1755,6 +1798,7 @@ static struct s3c_fb_driverdata s3c_fb_data_64xx = {
},
.has_prtcon = 1,
+ .has_clksel = 1,
},
.win[0] = &s3c_fb_data_64xx_wins[0],
.win[1] = &s3c_fb_data_64xx_wins[1],
@@ -1785,6 +1829,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = {
},
.has_prtcon = 1,
+ .has_clksel = 1,
},
.win[0] = &s3c_fb_data_s5p_wins[0],
.win[1] = &s3c_fb_data_s5p_wins[1],
@@ -1815,6 +1860,37 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
},
.has_shadowcon = 1,
+ .has_clksel = 1,
+ },
+ .win[0] = &s3c_fb_data_s5p_wins[0],
+ .win[1] = &s3c_fb_data_s5p_wins[1],
+ .win[2] = &s3c_fb_data_s5p_wins[2],
+ .win[3] = &s3c_fb_data_s5p_wins[3],
+ .win[4] = &s3c_fb_data_s5p_wins[4],
+};
+
+static struct s3c_fb_driverdata s3c_fb_data_exynos4 = {
+ .variant = {
+ .nr_windows = 5,
+ .vidtcon = VIDTCON0,
+ .wincon = WINCON(0),
+ .winmap = WINxMAP(0),
+ .keycon = WKEYCON,
+ .osd = VIDOSD_BASE,
+ .osd_stride = 16,
+ .buf_start = VIDW_BUF_START(0),
+ .buf_size = VIDW_BUF_SIZE(0),
+ .buf_end = VIDW_BUF_END(0),
+
+ .palette = {
+ [0] = 0x2400,
+ [1] = 0x2800,
+ [2] = 0x2c00,
+ [3] = 0x3000,
+ [4] = 0x3400,
+ },
+
+ .has_shadowcon = 1,
},
.win[0] = &s3c_fb_data_s5p_wins[0],
.win[1] = &s3c_fb_data_s5p_wins[1],
@@ -1843,6 +1919,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = {
[0] = 0x400,
[1] = 0x800,
},
+ .has_clksel = 1,
},
.win[0] = &(struct s3c_fb_win_variant) {
.palette_sz = 256,
@@ -1859,6 +1936,30 @@ static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = {
},
};
+static struct s3c_fb_driverdata s3c_fb_data_s5p64x0 = {
+ .variant = {
+ .nr_windows = 3,
+ .vidtcon = VIDTCON0,
+ .wincon = WINCON(0),
+ .winmap = WINxMAP(0),
+ .keycon = WKEYCON,
+ .osd = VIDOSD_BASE,
+ .osd_stride = 16,
+ .buf_start = VIDW_BUF_START(0),
+ .buf_size = VIDW_BUF_SIZE(0),
+ .buf_end = VIDW_BUF_END(0),
+
+ .palette = {
+ [0] = 0x2400,
+ [1] = 0x2800,
+ [2] = 0x2c00,
+ },
+ },
+ .win[0] = &s3c_fb_data_s5p_wins[0],
+ .win[1] = &s3c_fb_data_s5p_wins[1],
+ .win[2] = &s3c_fb_data_s5p_wins[2],
+};
+
static struct platform_device_id s3c_fb_driver_ids[] = {
{
.name = "s3c-fb",
@@ -1870,8 +1971,14 @@ static struct platform_device_id s3c_fb_driver_ids[] = {
.name = "s5pv210-fb",
.driver_data = (unsigned long)&s3c_fb_data_s5pv210,
}, {
+ .name = "exynos4-fb",
+ .driver_data = (unsigned long)&s3c_fb_data_exynos4,
+ }, {
.name = "s3c2443-fb",
.driver_data = (unsigned long)&s3c_fb_data_s3c2443,
+ }, {
+ .name = "s5p64x0-fb",
+ .driver_data = (unsigned long)&s3c_fb_data_s5p64x0,
},
{},
};
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index 0aa1376..ee4c0df 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -767,7 +767,6 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
static int s3c2410fb_cpufreq_transition(struct notifier_block *nb,
unsigned long val, void *data)
{
- struct cpufreq_freqs *freqs = data;
struct s3c2410fb_info *info;
struct fb_info *fbinfo;
long delta_f;
@@ -911,7 +910,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
for (i = 0; i < 256; i++)
info->palette_buffer[i] = PALETTE_BUFF_CLEAR;
- ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);
+ ret = request_irq(irq, s3c2410fb_irq, 0, pdev->name, info);
if (ret) {
dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);
ret = -EBUSY;
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c
index 4ca5d0c..946a949 100644
--- a/drivers/video/s3fb.c
+++ b/drivers/video/s3fb.c
@@ -1019,12 +1019,13 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
unsigned int offset;
/* Calculate the offset */
- if (var->bits_per_pixel == 0) {
- offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2);
+ if (info->var.bits_per_pixel == 0) {
+ offset = (var->yoffset / 16) * (info->var.xres_virtual / 2)
+ + (var->xoffset / 2);
offset = offset >> 2;
} else {
offset = (var->yoffset * info->fix.line_length) +
- (var->xoffset * var->bits_per_pixel / 8);
+ (var->xoffset * info->var.bits_per_pixel / 8);
offset = offset >> 2;
}
@@ -1504,7 +1505,7 @@ static struct pci_driver s3fb_pci_driver = {
.resume = s3_pci_resume,
};
-/* Parse user speficied options */
+/* Parse user specified options */
#ifndef MODULE
static int __init s3fb_setup(char *options)
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index e8b76d6..98d55d0 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -1457,8 +1457,7 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
if (ret)
goto failed;
- ret = request_irq(irq, sa1100fb_handle_irq, IRQF_DISABLED,
- "LCD", fbi);
+ ret = request_irq(irq, sa1100fb_handle_irq, 0, "LCD", fbi);
if (ret) {
printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret);
goto failed;
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index 4de541c..beb4950 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -1477,15 +1477,9 @@ static void savagefb_set_par_int(struct savagefb_par *par, struct savage_reg *r
vgaHWProtect(par, 0);
}
-static void savagefb_update_start(struct savagefb_par *par,
- struct fb_var_screeninfo *var)
+static void savagefb_update_start(struct savagefb_par *par, int base)
{
- int base;
-
- base = ((var->yoffset * var->xres_virtual + (var->xoffset & ~1))
- * ((var->bits_per_pixel+7) / 8)) >> 2;
-
- /* now program the start address registers */
+ /* program the start address registers */
vga_out16(0x3d4, (base & 0x00ff00) | 0x0c, par);
vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d, par);
vga_out8(0x3d4, 0x69, par);
@@ -1550,8 +1544,12 @@ static int savagefb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct savagefb_par *par = info->par;
+ int base;
+
+ base = (var->yoffset * info->fix.line_length
+ + (var->xoffset & ~1) * ((info->var.bits_per_pixel+7) / 8)) >> 2;
- savagefb_update_start(par, var);
+ savagefb_update_start(par, base);
return 0;
}
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index 7d54e2c..647ba98 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -1111,6 +1111,7 @@ static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate,
static void sh_hdmi_edid_work_fn(struct work_struct *work)
{
struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work);
+ struct fb_info *info;
struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
struct sh_mobile_lcdc_chan *ch;
int ret;
@@ -1123,8 +1124,9 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
mutex_lock(&hdmi->mutex);
+ info = hdmi->info;
+
if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) {
- struct fb_info *info = hdmi->info;
unsigned long parent_rate = 0, hdmi_rate;
ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
@@ -1148,42 +1150,45 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
ch = info->par;
- console_lock();
+ if (lock_fb_info(info)) {
+ console_lock();
- /* HDMI plug in */
- if (!sh_hdmi_must_reconfigure(hdmi) &&
- info->state == FBINFO_STATE_RUNNING) {
- /*
- * First activation with the default monitor - just turn
- * on, if we run a resume here, the logo disappears
- */
- if (lock_fb_info(info)) {
+ /* HDMI plug in */
+ if (!sh_hdmi_must_reconfigure(hdmi) &&
+ info->state == FBINFO_STATE_RUNNING) {
+ /*
+ * First activation with the default monitor - just turn
+ * on, if we run a resume here, the logo disappears
+ */
info->var.width = hdmi->var.width;
info->var.height = hdmi->var.height;
sh_hdmi_display_on(hdmi, info);
- unlock_fb_info(info);
+ } else {
+ /* New monitor or have to wake up */
+ fb_set_suspend(info, 0);
}
- } else {
- /* New monitor or have to wake up */
- fb_set_suspend(info, 0);
- }
- console_unlock();
+ console_unlock();
+ unlock_fb_info(info);
+ }
} else {
ret = 0;
- if (!hdmi->info)
+ if (!info)
goto out;
hdmi->monspec.modedb_len = 0;
fb_destroy_modedb(hdmi->monspec.modedb);
hdmi->monspec.modedb = NULL;
- console_lock();
+ if (lock_fb_info(info)) {
+ console_lock();
- /* HDMI disconnect */
- fb_set_suspend(hdmi->info, 1);
+ /* HDMI disconnect */
+ fb_set_suspend(info, 1);
- console_unlock();
+ console_unlock();
+ unlock_fb_info(info);
+ }
}
out:
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index b048417..3a41c01 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -24,39 +24,14 @@
#include <linux/backlight.h>
#include <linux/gpio.h>
#include <video/sh_mobile_lcdc.h>
+#include <video/sh_mobile_meram.h>
#include <linux/atomic.h>
#include "sh_mobile_lcdcfb.h"
-#include "sh_mobile_meram.h"
#define SIDE_B_OFFSET 0x1000
#define MIRROR_OFFSET 0x2000
-/* shared registers */
-#define _LDDCKR 0x410
-#define _LDDCKSTPR 0x414
-#define _LDINTR 0x468
-#define _LDSR 0x46c
-#define _LDCNT1R 0x470
-#define _LDCNT2R 0x474
-#define _LDRCNTR 0x478
-#define _LDDDSR 0x47c
-#define _LDDWD0R 0x800
-#define _LDDRDR 0x840
-#define _LDDWAR 0x900
-#define _LDDRAR 0x904
-
-/* shared registers and their order for context save/restore */
-static int lcdc_shared_regs[] = {
- _LDDCKR,
- _LDDCKSTPR,
- _LDINTR,
- _LDDDSR,
- _LDCNT1R,
- _LDCNT2R,
-};
-#define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs)
-
#define MAX_XRES 1920
#define MAX_YRES 1080
@@ -98,22 +73,6 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {
[LDPMR] = 0x63c,
};
-#define START_LCDC 0x00000001
-#define LCDC_RESET 0x00000100
-#define DISPLAY_BEU 0x00000008
-#define LCDC_ENABLE 0x00000001
-#define LDINTR_FE 0x00000400
-#define LDINTR_VSE 0x00000200
-#define LDINTR_VEE 0x00000100
-#define LDINTR_FS 0x00000004
-#define LDINTR_VSS 0x00000002
-#define LDINTR_VES 0x00000001
-#define LDRCNTR_SRS 0x00020000
-#define LDRCNTR_SRC 0x00010000
-#define LDRCNTR_MRS 0x00000002
-#define LDRCNTR_MRC 0x00000001
-#define LDSR_MRS 0x00000100
-
static const struct fb_videomode default_720p = {
.name = "HDMI 720p",
.xres = 1280,
@@ -141,7 +100,6 @@ struct sh_mobile_lcdc_priv {
unsigned long lddckr;
struct sh_mobile_lcdc_chan ch[2];
struct notifier_block notifier;
- unsigned long saved_shared_regs[NR_SHARED_REGS];
int started;
int forced_bpp; /* 2 channel LCDC must share bpp setting */
struct sh_mobile_meram_info *meram_dev;
@@ -218,33 +176,36 @@ static void lcdc_sys_write_index(void *handle, unsigned long data)
{
struct sh_mobile_lcdc_chan *ch = handle;
- lcdc_write(ch->lcdc, _LDDWD0R, data | 0x10000000);
- lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
- lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0));
- lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
+ lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT);
+ lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
+ lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
+ (lcdc_chan_is_sublcd(ch) ? 2 : 0));
+ lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
}
static void lcdc_sys_write_data(void *handle, unsigned long data)
{
struct sh_mobile_lcdc_chan *ch = handle;
- lcdc_write(ch->lcdc, _LDDWD0R, data | 0x11000000);
- lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
- lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0));
- lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
+ lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT | LDDWDxR_RSW);
+ lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
+ lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
+ (lcdc_chan_is_sublcd(ch) ? 2 : 0));
+ lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
}
static unsigned long lcdc_sys_read_data(void *handle)
{
struct sh_mobile_lcdc_chan *ch = handle;
- lcdc_write(ch->lcdc, _LDDRDR, 0x01000000);
- lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
- lcdc_write(ch->lcdc, _LDDRAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0));
+ lcdc_write(ch->lcdc, _LDDRDR, LDDRDR_RSR);
+ lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
+ lcdc_write(ch->lcdc, _LDDRAR, LDDRAR_RA |
+ (lcdc_chan_is_sublcd(ch) ? 2 : 0));
udelay(1);
- lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
+ lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
- return lcdc_read(ch->lcdc, _LDDRDR) & 0x3ffff;
+ return lcdc_read(ch->lcdc, _LDDRDR) & LDDRDR_DRD_MASK;
}
struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
@@ -256,18 +217,22 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
{
if (atomic_inc_and_test(&priv->hw_usecnt)) {
- pm_runtime_get_sync(priv->dev);
if (priv->dot_clk)
clk_enable(priv->dot_clk);
+ pm_runtime_get_sync(priv->dev);
+ if (priv->meram_dev && priv->meram_dev->pdev)
+ pm_runtime_get_sync(&priv->meram_dev->pdev->dev);
}
}
static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
{
if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {
+ if (priv->meram_dev && priv->meram_dev->pdev)
+ pm_runtime_put_sync(&priv->meram_dev->pdev->dev);
+ pm_runtime_put(priv->dev);
if (priv->dot_clk)
clk_disable(priv->dot_clk);
- pm_runtime_put(priv->dev);
}
}
@@ -319,13 +284,13 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
if (bcfg->start_transfer)
bcfg->start_transfer(bcfg->board_data, ch,
&sh_mobile_lcdc_sys_bus_ops);
- lcdc_write_chan(ch, LDSM2R, 1);
+ lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
} else {
if (bcfg->start_transfer)
bcfg->start_transfer(bcfg->board_data, ch,
&sh_mobile_lcdc_sys_bus_ops);
- lcdc_write_chan(ch, LDSM2R, 1);
+ lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
}
}
@@ -341,22 +306,16 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
{
struct sh_mobile_lcdc_priv *priv = data;
struct sh_mobile_lcdc_chan *ch;
- unsigned long tmp;
unsigned long ldintr;
int is_sub;
int k;
- /* acknowledge interrupt */
- ldintr = tmp = lcdc_read(priv, _LDINTR);
- /*
- * disable further VSYNC End IRQs, preserve all other enabled IRQs,
- * write 0 to bits 0-6 to ack all triggered IRQs.
- */
- tmp &= 0xffffff00 & ~LDINTR_VEE;
- lcdc_write(priv, _LDINTR, tmp);
+ /* Acknowledge interrupts and disable further VSYNC End IRQs. */
+ ldintr = lcdc_read(priv, _LDINTR);
+ lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE);
/* figure out if this interrupt is for main or sub lcd */
- is_sub = (lcdc_read(priv, _LDSR) & (1 << 10)) ? 1 : 0;
+ is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0;
/* wake up channel and disable clocks */
for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
@@ -365,7 +324,7 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
if (!ch->enabled)
continue;
- /* Frame Start */
+ /* Frame End */
if (ldintr & LDINTR_FS) {
if (is_sub == lcdc_chan_is_sublcd(ch)) {
ch->frame_end = 1;
@@ -391,16 +350,17 @@ static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
/* start or stop the lcdc */
if (start)
- lcdc_write(priv, _LDCNT2R, tmp | START_LCDC);
+ lcdc_write(priv, _LDCNT2R, tmp | LDCNT2R_DO);
else
- lcdc_write(priv, _LDCNT2R, tmp & ~START_LCDC);
+ lcdc_write(priv, _LDCNT2R, tmp & ~LDCNT2R_DO);
/* wait until power is applied/stopped on all channels */
for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled)
while (1) {
- tmp = lcdc_read_chan(&priv->ch[k], LDPMR) & 3;
- if (start && tmp == 3)
+ tmp = lcdc_read_chan(&priv->ch[k], LDPMR)
+ & LDPMR_LPS;
+ if (start && tmp == LDPMR_LPS)
break;
if (!start && tmp == 0)
break;
@@ -418,13 +378,13 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
u32 tmp;
tmp = ch->ldmt1r_value;
- tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28;
- tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27;
- tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0;
- tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0;
- tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0;
- tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0;
- tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0;
+ tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL;
+ tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL;
+ tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;
+ tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;
+ tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;
+ tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;
+ tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;
lcdc_write_chan(ch, LDMT1R, tmp);
/* setup SYS bus */
@@ -463,242 +423,239 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
lcdc_write_chan(ch, LDHAJR, tmp);
}
-static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
+/*
+ * __sh_mobile_lcdc_start - Configure and tart the LCDC
+ * @priv: LCDC device
+ *
+ * Configure all enabled channels and start the LCDC device. All external
+ * devices (clocks, MERAM, panels, ...) are not touched by this function.
+ */
+static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
{
struct sh_mobile_lcdc_chan *ch;
- struct sh_mobile_lcdc_board_cfg *board_cfg;
unsigned long tmp;
int bpp = 0;
- unsigned long ldddsr;
- int k, m, ret;
+ int k, m;
- /* enable clocks before accessing the hardware */
- for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
- if (priv->ch[k].enabled) {
- sh_mobile_lcdc_clk_on(priv);
- if (!bpp)
- bpp = priv->ch[k].info->var.bits_per_pixel;
- }
- }
-
- /* reset */
- lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET);
- lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0);
-
- /* enable LCDC channels */
- tmp = lcdc_read(priv, _LDCNT2R);
- tmp |= priv->ch[0].enabled;
- tmp |= priv->ch[1].enabled;
- lcdc_write(priv, _LDCNT2R, tmp);
-
- /* read data from external memory, avoid using the BEU for now */
- lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU);
+ /* Enable LCDC channels. Read data from external memory, avoid using the
+ * BEU for now.
+ */
+ lcdc_write(priv, _LDCNT2R, priv->ch[0].enabled | priv->ch[1].enabled);
- /* stop the lcdc first */
+ /* Stop the LCDC first and disable all interrupts. */
sh_mobile_lcdc_start_stop(priv, 0);
+ lcdc_write(priv, _LDINTR, 0);
- /* configure clocks */
+ /* Configure power supply, dot clocks and start them. */
tmp = priv->lddckr;
for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
ch = &priv->ch[k];
-
- if (!priv->ch[k].enabled)
+ if (!ch->enabled)
continue;
+ if (!bpp)
+ bpp = ch->info->var.bits_per_pixel;
+
+ /* Power supply */
+ lcdc_write_chan(ch, LDPMR, 0);
+
m = ch->cfg.clock_divider;
if (!m)
continue;
- if (m == 1)
- m = 1 << 6;
- tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
-
- /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */
+ /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider
+ * denominator.
+ */
lcdc_write_chan(ch, LDDCKPAT1R, 0);
lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1);
+
+ if (m == 1)
+ m = LDDCKR_MOSEL;
+ tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
}
lcdc_write(priv, _LDDCKR, tmp);
-
- /* start dotclock again */
lcdc_write(priv, _LDDCKSTPR, 0);
lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0);
- /* interrupts are disabled to begin with */
- lcdc_write(priv, _LDINTR, 0);
-
+ /* Setup geometry, format, frame buffer memory and operation mode. */
for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
ch = &priv->ch[k];
-
if (!ch->enabled)
continue;
sh_mobile_lcdc_geometry(ch);
- /* power supply */
- lcdc_write_chan(ch, LDPMR, 0);
-
- board_cfg = &ch->cfg.board_cfg;
- if (board_cfg->setup_sys) {
- ret = board_cfg->setup_sys(board_cfg->board_data,
- ch, &sh_mobile_lcdc_sys_bus_ops);
- if (ret)
- return ret;
- }
- }
-
- /* word and long word swap */
- ldddsr = lcdc_read(priv, _LDDDSR);
- if (priv->ch[0].info->var.nonstd)
- lcdc_write(priv, _LDDDSR, ldddsr | 7);
- else {
- switch (bpp) {
- case 16:
- lcdc_write(priv, _LDDDSR, ldddsr | 6);
- break;
- case 24:
- lcdc_write(priv, _LDDDSR, ldddsr | 7);
- break;
- case 32:
- lcdc_write(priv, _LDDDSR, ldddsr | 4);
- break;
- }
- }
-
- for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
- unsigned long base_addr_y;
- unsigned long base_addr_c = 0;
- int pitch;
- ch = &priv->ch[k];
-
- if (!priv->ch[k].enabled)
- continue;
-
- /* set bpp format in PKF[4:0] */
- tmp = lcdc_read_chan(ch, LDDFR);
- tmp &= ~0x0003031f;
if (ch->info->var.nonstd) {
- tmp |= (ch->info->var.nonstd << 16);
+ tmp = (ch->info->var.nonstd << 16);
switch (ch->info->var.bits_per_pixel) {
case 12:
+ tmp |= LDDFR_YF_420;
break;
case 16:
- tmp |= (0x1 << 8);
+ tmp |= LDDFR_YF_422;
break;
case 24:
- tmp |= (0x2 << 8);
+ default:
+ tmp |= LDDFR_YF_444;
break;
}
} else {
switch (ch->info->var.bits_per_pixel) {
case 16:
- tmp |= 0x03;
+ tmp = LDDFR_PKF_RGB16;
break;
case 24:
- tmp |= 0x0b;
+ tmp = LDDFR_PKF_RGB24;
break;
case 32:
+ default:
+ tmp = LDDFR_PKF_ARGB32;
break;
}
}
+
lcdc_write_chan(ch, LDDFR, tmp);
+ lcdc_write_chan(ch, LDMLSR, ch->pitch);
+ lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
+ if (ch->info->var.nonstd)
+ lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
- base_addr_y = ch->info->fix.smem_start;
- base_addr_c = base_addr_y +
- ch->info->var.xres *
- ch->info->var.yres_virtual;
- pitch = ch->info->fix.line_length;
+ /* When using deferred I/O mode, configure the LCDC for one-shot
+ * operation and enable the frame end interrupt. Otherwise use
+ * continuous read mode.
+ */
+ if (ch->ldmt1r_value & LDMT1R_IFM &&
+ ch->cfg.sys_bus_cfg.deferred_io_msec) {
+ lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);
+ lcdc_write(priv, _LDINTR, LDINTR_FE);
+ } else {
+ lcdc_write_chan(ch, LDSM1R, 0);
+ }
+ }
- /* test if we can enable meram */
- if (ch->cfg.meram_cfg && priv->meram_dev &&
- priv->meram_dev->ops) {
- struct sh_mobile_meram_cfg *cfg;
- struct sh_mobile_meram_info *mdev;
- unsigned long icb_addr_y, icb_addr_c;
- int icb_pitch;
- int pf;
+ /* Word and long word swap. */
+ if (priv->ch[0].info->var.nonstd)
+ tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
+ else {
+ switch (bpp) {
+ case 16:
+ tmp = LDDDSR_LS | LDDDSR_WS;
+ break;
+ case 24:
+ tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
+ break;
+ case 32:
+ default:
+ tmp = LDDDSR_LS;
+ break;
+ }
+ }
+ lcdc_write(priv, _LDDDSR, tmp);
- cfg = ch->cfg.meram_cfg;
- mdev = priv->meram_dev;
- /* we need to de-init configured ICBs before we
- * we can re-initialize them.
- */
- if (ch->meram_enabled)
- mdev->ops->meram_unregister(mdev, cfg);
+ /* Enable the display output. */
+ lcdc_write(priv, _LDCNT1R, LDCNT1R_DE);
+ sh_mobile_lcdc_start_stop(priv, 1);
+ priv->started = 1;
+}
- ch->meram_enabled = 0;
+static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
+{
+ struct sh_mobile_meram_info *mdev = priv->meram_dev;
+ struct sh_mobile_lcdc_board_cfg *board_cfg;
+ struct sh_mobile_lcdc_chan *ch;
+ unsigned long tmp;
+ int ret;
+ int k;
- if (ch->info->var.nonstd) {
- if (ch->info->var.bits_per_pixel == 24)
- pf = SH_MOBILE_MERAM_PF_NV24;
- else
- pf = SH_MOBILE_MERAM_PF_NV;
- } else {
- pf = SH_MOBILE_MERAM_PF_RGB;
- }
+ /* enable clocks before accessing the hardware */
+ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+ if (priv->ch[k].enabled)
+ sh_mobile_lcdc_clk_on(priv);
+ }
- ret = mdev->ops->meram_register(mdev, cfg, pitch,
- ch->info->var.yres,
- pf,
- base_addr_y,
- base_addr_c,
- &icb_addr_y,
- &icb_addr_c,
- &icb_pitch);
- if (!ret) {
- /* set LDSA1R value */
- base_addr_y = icb_addr_y;
- pitch = icb_pitch;
-
- /* set LDSA2R value if required */
- if (base_addr_c)
- base_addr_c = icb_addr_c;
-
- ch->meram_enabled = 1;
- }
- }
+ /* reset */
+ lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LDCNT2R_BR);
+ lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);
- /* point out our frame buffer */
- lcdc_write_chan(ch, LDSA1R, base_addr_y);
- if (ch->info->var.nonstd)
- lcdc_write_chan(ch, LDSA2R, base_addr_c);
+ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+ ch = &priv->ch[k];
- /* set line size */
- lcdc_write_chan(ch, LDMLSR, pitch);
+ if (!ch->enabled)
+ continue;
- /* setup deferred io if SYS bus */
- tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
- if (ch->ldmt1r_value & (1 << 12) && tmp) {
- ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
- ch->defio.delay = msecs_to_jiffies(tmp);
- ch->info->fbdefio = &ch->defio;
- fb_deferred_io_init(ch->info);
+ board_cfg = &ch->cfg.board_cfg;
+ if (board_cfg->setup_sys) {
+ ret = board_cfg->setup_sys(board_cfg->board_data, ch,
+ &sh_mobile_lcdc_sys_bus_ops);
+ if (ret)
+ return ret;
+ }
+ }
- /* one-shot mode */
- lcdc_write_chan(ch, LDSM1R, 1);
+ /* Compute frame buffer base address and pitch for each channel. */
+ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+ struct sh_mobile_meram_cfg *cfg;
+ int pixelformat;
- /* enable "Frame End Interrupt Enable" bit */
- lcdc_write(priv, _LDINTR, LDINTR_FE);
+ ch = &priv->ch[k];
+ if (!ch->enabled)
+ continue;
- } else {
- /* continuous read mode */
- lcdc_write_chan(ch, LDSM1R, 0);
+ ch->base_addr_y = ch->info->fix.smem_start;
+ ch->base_addr_c = ch->base_addr_y
+ + ch->info->var.xres
+ * ch->info->var.yres_virtual;
+ ch->pitch = ch->info->fix.line_length;
+
+ /* Enable MERAM if possible. */
+ cfg = ch->cfg.meram_cfg;
+ if (mdev == NULL || mdev->ops == NULL || cfg == NULL)
+ continue;
+
+ /* we need to de-init configured ICBs before we can
+ * re-initialize them.
+ */
+ if (ch->meram_enabled) {
+ mdev->ops->meram_unregister(mdev, cfg);
+ ch->meram_enabled = 0;
}
+
+ if (!ch->info->var.nonstd)
+ pixelformat = SH_MOBILE_MERAM_PF_RGB;
+ else if (ch->info->var.bits_per_pixel == 24)
+ pixelformat = SH_MOBILE_MERAM_PF_NV24;
+ else
+ pixelformat = SH_MOBILE_MERAM_PF_NV;
+
+ ret = mdev->ops->meram_register(mdev, cfg, ch->pitch,
+ ch->info->var.yres, pixelformat,
+ ch->base_addr_y, ch->base_addr_c,
+ &ch->base_addr_y, &ch->base_addr_c,
+ &ch->pitch);
+ if (!ret)
+ ch->meram_enabled = 1;
}
- /* display output */
- lcdc_write(priv, _LDCNT1R, LCDC_ENABLE);
+ /* Start the LCDC. */
+ __sh_mobile_lcdc_start(priv);
- /* start the lcdc */
- sh_mobile_lcdc_start_stop(priv, 1);
- priv->started = 1;
-
- /* tell the board code to enable the panel */
+ /* Setup deferred I/O, tell the board code to enable the panels, and
+ * turn backlight on.
+ */
for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
ch = &priv->ch[k];
if (!ch->enabled)
continue;
+ tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
+ if (ch->ldmt1r_value & LDMT1R_IFM && tmp) {
+ ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
+ ch->defio.delay = msecs_to_jiffies(tmp);
+ ch->info->fbdefio = &ch->defio;
+ fb_deferred_io_init(ch->info);
+ }
+
board_cfg = &ch->cfg.board_cfg;
if (board_cfg->display_on && try_module_get(board_cfg->owner)) {
board_cfg->display_on(board_cfg->board_data, ch->info);
@@ -776,42 +733,42 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
{
- int ifm, miftyp;
-
- switch (ch->cfg.interface_type) {
- case RGB8: ifm = 0; miftyp = 0; break;
- case RGB9: ifm = 0; miftyp = 4; break;
- case RGB12A: ifm = 0; miftyp = 5; break;
- case RGB12B: ifm = 0; miftyp = 6; break;
- case RGB16: ifm = 0; miftyp = 7; break;
- case RGB18: ifm = 0; miftyp = 10; break;
- case RGB24: ifm = 0; miftyp = 11; break;
- case SYS8A: ifm = 1; miftyp = 0; break;
- case SYS8B: ifm = 1; miftyp = 1; break;
- case SYS8C: ifm = 1; miftyp = 2; break;
- case SYS8D: ifm = 1; miftyp = 3; break;
- case SYS9: ifm = 1; miftyp = 4; break;
- case SYS12: ifm = 1; miftyp = 5; break;
- case SYS16A: ifm = 1; miftyp = 7; break;
- case SYS16B: ifm = 1; miftyp = 8; break;
- case SYS16C: ifm = 1; miftyp = 9; break;
- case SYS18: ifm = 1; miftyp = 10; break;
- case SYS24: ifm = 1; miftyp = 11; break;
- default: goto bad;
+ int interface_type = ch->cfg.interface_type;
+
+ switch (interface_type) {
+ case RGB8:
+ case RGB9:
+ case RGB12A:
+ case RGB12B:
+ case RGB16:
+ case RGB18:
+ case RGB24:
+ case SYS8A:
+ case SYS8B:
+ case SYS8C:
+ case SYS8D:
+ case SYS9:
+ case SYS12:
+ case SYS16A:
+ case SYS16B:
+ case SYS16C:
+ case SYS18:
+ case SYS24:
+ break;
+ default:
+ return -EINVAL;
}
/* SUBLCD only supports SYS interface */
if (lcdc_chan_is_sublcd(ch)) {
- if (ifm == 0)
- goto bad;
- else
- ifm = 0;
+ if (!(interface_type & LDMT1R_IFM))
+ return -EINVAL;
+
+ interface_type &= ~LDMT1R_IFM;
}
- ch->ldmt1r_value = (ifm << 12) | miftyp;
+ ch->ldmt1r_value = interface_type;
return 0;
- bad:
- return -EINVAL;
}
static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
@@ -819,18 +776,24 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
struct sh_mobile_lcdc_priv *priv)
{
char *str;
- int icksel;
switch (clock_source) {
- case LCDC_CLK_BUS: str = "bus_clk"; icksel = 0; break;
- case LCDC_CLK_PERIPHERAL: str = "peripheral_clk"; icksel = 1; break;
- case LCDC_CLK_EXTERNAL: str = NULL; icksel = 2; break;
+ case LCDC_CLK_BUS:
+ str = "bus_clk";
+ priv->lddckr = LDDCKR_ICKSEL_BUS;
+ break;
+ case LCDC_CLK_PERIPHERAL:
+ str = "peripheral_clk";
+ priv->lddckr = LDDCKR_ICKSEL_MIPI;
+ break;
+ case LCDC_CLK_EXTERNAL:
+ str = NULL;
+ priv->lddckr = LDDCKR_ICKSEL_HDMI;
+ break;
default:
return -EINVAL;
}
- priv->lddckr = icksel << 16;
-
if (str) {
priv->dot_clk = clk_get(&pdev->dev, str);
if (IS_ERR(priv->dot_clk)) {
@@ -914,12 +877,12 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
unsigned long base_addr_y, base_addr_c;
unsigned long c_offset;
- if (!var->nonstd)
- new_pan_offset = (var->yoffset * info->fix.line_length) +
- (var->xoffset * (info->var.bits_per_pixel / 8));
+ if (!info->var.nonstd)
+ new_pan_offset = var->yoffset * info->fix.line_length
+ + var->xoffset * (info->var.bits_per_pixel / 8);
else
- new_pan_offset = (var->yoffset * info->fix.line_length) +
- (var->xoffset);
+ new_pan_offset = var->yoffset * info->fix.line_length
+ + var->xoffset;
if (new_pan_offset == ch->pan_offset)
return 0; /* No change, do nothing */
@@ -928,44 +891,40 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
/* Set the source address for the next refresh */
base_addr_y = ch->dma_handle + new_pan_offset;
- if (var->nonstd) {
+ if (info->var.nonstd) {
/* Set y offset */
- c_offset = (var->yoffset *
- info->fix.line_length *
- (info->var.bits_per_pixel - 8)) / 8;
- base_addr_c = ch->dma_handle + var->xres * var->yres_virtual +
- c_offset;
+ c_offset = var->yoffset * info->fix.line_length
+ * (info->var.bits_per_pixel - 8) / 8;
+ base_addr_c = ch->dma_handle
+ + info->var.xres * info->var.yres_virtual
+ + c_offset;
/* Set x offset */
if (info->var.bits_per_pixel == 24)
base_addr_c += 2 * var->xoffset;
else
base_addr_c += var->xoffset;
- } else
- base_addr_c = 0;
+ }
- if (!ch->meram_enabled) {
- lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
- if (base_addr_c)
- lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
- } else {
+ if (ch->meram_enabled) {
struct sh_mobile_meram_cfg *cfg;
struct sh_mobile_meram_info *mdev;
- unsigned long icb_addr_y, icb_addr_c;
int ret;
cfg = ch->cfg.meram_cfg;
mdev = priv->meram_dev;
ret = mdev->ops->meram_update(mdev, cfg,
base_addr_y, base_addr_c,
- &icb_addr_y, &icb_addr_c);
+ &base_addr_y, &base_addr_c);
if (ret)
return ret;
+ }
- lcdc_write_chan_mirror(ch, LDSA1R, icb_addr_y);
- if (icb_addr_c)
- lcdc_write_chan_mirror(ch, LDSA2R, icb_addr_c);
+ ch->base_addr_y = base_addr_y;
+ ch->base_addr_c = base_addr_c;
- }
+ lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
+ if (info->var.nonstd)
+ lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
if (lcdc_chan_is_sublcd(ch))
lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
@@ -985,9 +944,11 @@ static int sh_mobile_wait_for_vsync(struct fb_info *info)
unsigned long ldintr;
int ret;
- /* Enable VSync End interrupt */
+ /* Enable VSync End interrupt and be careful not to acknowledge any
+ * pending interrupt.
+ */
ldintr = lcdc_read(ch->lcdc, _LDINTR);
- ldintr |= LDINTR_VEE;
+ ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
lcdc_write(ch->lcdc, _LDINTR, ldintr);
ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
@@ -1037,11 +998,6 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
/* Couldn't reconfigure, hopefully, can continue as before */
return;
- if (info->var.nonstd)
- info->fix.line_length = mode1.xres;
- else
- info->fix.line_length = mode1.xres * (ch->cfg.bpp / 8);
-
/*
* fb_set_var() calls the notifier change internally, only if
* FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a
@@ -1094,30 +1050,126 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
{
struct sh_mobile_lcdc_chan *ch = info->par;
struct sh_mobile_lcdc_priv *p = ch->lcdc;
+ unsigned int best_dist = (unsigned int)-1;
+ unsigned int best_xres = 0;
+ unsigned int best_yres = 0;
+ unsigned int i;
- if (var->xres > MAX_XRES || var->yres > MAX_YRES ||
- var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) {
- dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %lukHz!\n",
- var->left_margin, var->xres, var->right_margin, var->hsync_len,
- var->upper_margin, var->yres, var->lower_margin, var->vsync_len,
- PICOS2KHZ(var->pixclock));
+ if (var->xres > MAX_XRES || var->yres > MAX_YRES)
return -EINVAL;
+
+ /* If board code provides us with a list of available modes, make sure
+ * we use one of them. Find the mode closest to the requested one. The
+ * distance between two modes is defined as the size of the
+ * non-overlapping parts of the two rectangles.
+ */
+ for (i = 0; i < ch->cfg.num_cfg; ++i) {
+ const struct fb_videomode *mode = &ch->cfg.lcd_cfg[i];
+ unsigned int dist;
+
+ /* We can only round up. */
+ if (var->xres > mode->xres || var->yres > mode->yres)
+ continue;
+
+ dist = var->xres * var->yres + mode->xres * mode->yres
+ - 2 * min(var->xres, mode->xres)
+ * min(var->yres, mode->yres);
+
+ if (dist < best_dist) {
+ best_xres = mode->xres;
+ best_yres = mode->yres;
+ best_dist = dist;
+ }
+ }
+
+ /* If no available mode can be used, return an error. */
+ if (ch->cfg.num_cfg != 0) {
+ if (best_dist == (unsigned int)-1)
+ return -EINVAL;
+
+ var->xres = best_xres;
+ var->yres = best_yres;
}
+ /* Make sure the virtual resolution is at least as big as the visible
+ * resolution.
+ */
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ if (var->bits_per_pixel <= 16) { /* RGB 565 */
+ var->bits_per_pixel = 16;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ } else if (var->bits_per_pixel <= 24) { /* RGB 888 */
+ var->bits_per_pixel = 24;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */
+ var->bits_per_pixel = 32;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ } else
+ return -EINVAL;
+
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
+
+ /* Make sure we don't exceed our allocated memory. */
+ if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
+ info->fix.smem_len)
+ return -EINVAL;
+
/* only accept the forced_bpp for dual channel configurations */
if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel)
return -EINVAL;
- switch (var->bits_per_pixel) {
- case 16: /* PKF[4:0] = 00011 - RGB 565 */
- case 24: /* PKF[4:0] = 01011 - RGB 888 */
- case 32: /* PKF[4:0] = 00000 - RGBA 888 */
- break;
- default:
- return -EINVAL;
+ return 0;
+}
+
+static int sh_mobile_set_par(struct fb_info *info)
+{
+ struct sh_mobile_lcdc_chan *ch = info->par;
+ u32 line_length = info->fix.line_length;
+ int ret;
+
+ sh_mobile_lcdc_stop(ch->lcdc);
+
+ if (info->var.nonstd)
+ info->fix.line_length = info->var.xres;
+ else
+ info->fix.line_length = info->var.xres
+ * info->var.bits_per_pixel / 8;
+
+ ret = sh_mobile_lcdc_start(ch->lcdc);
+ if (ret < 0) {
+ dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);
+ info->fix.line_length = line_length;
}
- return 0;
+ return ret;
}
/*
@@ -1177,6 +1229,7 @@ static struct fb_ops sh_mobile_lcdc_ops = {
.fb_open = sh_mobile_open,
.fb_release = sh_mobile_release,
.fb_check_var = sh_mobile_check_var,
+ .fb_set_par = sh_mobile_set_par,
};
static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev)
@@ -1238,66 +1291,6 @@ static void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev)
backlight_device_unregister(bdev);
}
-static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp,
- int nonstd)
-{
- if (nonstd) {
- switch (bpp) {
- case 12:
- case 16:
- case 24:
- var->bits_per_pixel = bpp;
- var->nonstd = nonstd;
- return 0;
- default:
- return -EINVAL;
- }
- }
-
- switch (bpp) {
- case 16: /* PKF[4:0] = 00011 - RGB 565 */
- var->red.offset = 11;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 6;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
-
- case 24: /* PKF[4:0] = 01011 - RGB 888 */
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
-
- case 32: /* PKF[4:0] = 00000 - RGBA 888 */
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 24;
- var->transp.length = 8;
- break;
- default:
- return -EINVAL;
- }
- var->bits_per_pixel = bpp;
- var->red.msb_right = 0;
- var->green.msb_right = 0;
- var->blue.msb_right = 0;
- var->transp.msb_right = 0;
- return 0;
-}
-
static int sh_mobile_lcdc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -1316,47 +1309,20 @@ static int sh_mobile_lcdc_resume(struct device *dev)
static int sh_mobile_lcdc_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev);
- struct sh_mobile_lcdc_chan *ch;
- int k, n;
-
- /* save per-channel registers */
- for (k = 0; k < ARRAY_SIZE(p->ch); k++) {
- ch = &p->ch[k];
- if (!ch->enabled)
- continue;
- for (n = 0; n < NR_CH_REGS; n++)
- ch->saved_ch_regs[n] = lcdc_read_chan(ch, n);
- }
-
- /* save shared registers */
- for (n = 0; n < NR_SHARED_REGS; n++)
- p->saved_shared_regs[n] = lcdc_read(p, lcdc_shared_regs[n]);
+ struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
/* turn off LCDC hardware */
- lcdc_write(p, _LDCNT1R, 0);
+ lcdc_write(priv, _LDCNT1R, 0);
+
return 0;
}
static int sh_mobile_lcdc_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev);
- struct sh_mobile_lcdc_chan *ch;
- int k, n;
-
- /* restore per-channel registers */
- for (k = 0; k < ARRAY_SIZE(p->ch); k++) {
- ch = &p->ch[k];
- if (!ch->enabled)
- continue;
- for (n = 0; n < NR_CH_REGS; n++)
- lcdc_write_chan(ch, n, ch->saved_ch_regs[n]);
- }
+ struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
- /* restore shared registers */
- for (n = 0; n < NR_SHARED_REGS; n++)
- lcdc_write(p, lcdc_shared_regs[n], p->saved_shared_regs[n]);
+ __sh_mobile_lcdc_start(priv);
return 0;
}
@@ -1408,17 +1374,187 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
return NOTIFY_OK;
}
-static int sh_mobile_lcdc_remove(struct platform_device *pdev);
+static int sh_mobile_lcdc_remove(struct platform_device *pdev)
+{
+ struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
+ struct fb_info *info;
+ int i;
-static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
+ fb_unregister_client(&priv->notifier);
+
+ for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
+ if (priv->ch[i].info && priv->ch[i].info->dev)
+ unregister_framebuffer(priv->ch[i].info);
+
+ sh_mobile_lcdc_stop(priv);
+
+ for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
+ info = priv->ch[i].info;
+
+ if (!info || !info->device)
+ continue;
+
+ if (priv->ch[i].sglist)
+ vfree(priv->ch[i].sglist);
+
+ if (info->screen_base)
+ dma_free_coherent(&pdev->dev, info->fix.smem_len,
+ info->screen_base,
+ priv->ch[i].dma_handle);
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
+ if (priv->ch[i].bl)
+ sh_mobile_lcdc_bl_remove(priv->ch[i].bl);
+ }
+
+ if (priv->dot_clk)
+ clk_put(priv->dot_clk);
+
+ if (priv->dev)
+ pm_runtime_disable(priv->dev);
+
+ if (priv->base)
+ iounmap(priv->base);
+
+ if (priv->irq)
+ free_irq(priv->irq, priv);
+ kfree(priv);
+ return 0;
+}
+
+static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
+ struct device *dev)
{
+ struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
+ const struct fb_videomode *max_mode;
+ const struct fb_videomode *mode;
+ struct fb_var_screeninfo *var;
struct fb_info *info;
- struct sh_mobile_lcdc_priv *priv;
+ unsigned int max_size;
+ int num_cfg;
+ void *buf;
+ int ret;
+ int i;
+
+ mutex_init(&ch->open_lock);
+
+ /* Allocate the frame buffer device. */
+ ch->info = framebuffer_alloc(0, dev);
+ if (!ch->info) {
+ dev_err(dev, "unable to allocate fb_info\n");
+ return -ENOMEM;
+ }
+
+ info = ch->info;
+ info->fbops = &sh_mobile_lcdc_ops;
+ info->par = ch;
+ info->pseudo_palette = &ch->pseudo_palette;
+ info->flags = FBINFO_FLAG_DEFAULT;
+
+ /* Iterate through the modes to validate them and find the highest
+ * resolution.
+ */
+ max_mode = NULL;
+ max_size = 0;
+
+ for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) {
+ unsigned int size = mode->yres * mode->xres;
+
+ /* NV12 buffers must have even number of lines */
+ if ((cfg->nonstd) && cfg->bpp == 12 &&
+ (mode->yres & 0x1)) {
+ dev_err(dev, "yres must be multiple of 2 for YCbCr420 "
+ "mode.\n");
+ return -EINVAL;
+ }
+
+ if (size > max_size) {
+ max_mode = mode;
+ max_size = size;
+ }
+ }
+
+ if (!max_size)
+ max_size = MAX_XRES * MAX_YRES;
+ else
+ dev_dbg(dev, "Found largest videomode %ux%u\n",
+ max_mode->xres, max_mode->yres);
+
+ /* Initialize fixed screen information. Restrict pan to 2 lines steps
+ * for NV12.
+ */
+ info->fix = sh_mobile_lcdc_fix;
+ info->fix.smem_len = max_size * 2 * cfg->bpp / 8;
+ if (cfg->nonstd && cfg->bpp == 12)
+ info->fix.ypanstep = 2;
+
+ /* Create the mode list. */
+ if (cfg->lcd_cfg == NULL) {
+ mode = &default_720p;
+ num_cfg = 1;
+ } else {
+ mode = cfg->lcd_cfg;
+ num_cfg = cfg->num_cfg;
+ }
+
+ fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
+
+ /* Initialize variable screen information using the first mode as
+ * default. The default Y virtual resolution is twice the panel size to
+ * allow for double-buffering.
+ */
+ var = &info->var;
+ fb_videomode_to_var(var, mode);
+ var->bits_per_pixel = cfg->bpp;
+ var->width = cfg->lcd_size_cfg.width;
+ var->height = cfg->lcd_size_cfg.height;
+ var->yres_virtual = var->yres * 2;
+ var->activate = FB_ACTIVATE_NOW;
+
+ ret = sh_mobile_check_var(var, info);
+ if (ret)
+ return ret;
+
+ /* Allocate frame buffer memory and color map. */
+ buf = dma_alloc_coherent(dev, info->fix.smem_len, &ch->dma_handle,
+ GFP_KERNEL);
+ if (!buf) {
+ dev_err(dev, "unable to allocate buffer\n");
+ return -ENOMEM;
+ }
+
+ ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
+ if (ret < 0) {
+ dev_err(dev, "unable to allocate cmap\n");
+ dma_free_coherent(dev, info->fix.smem_len,
+ buf, ch->dma_handle);
+ return ret;
+ }
+
+ info->fix.smem_start = ch->dma_handle;
+ if (var->nonstd)
+ info->fix.line_length = var->xres;
+ else
+ info->fix.line_length = var->xres * (cfg->bpp / 8);
+
+ info->screen_base = buf;
+ info->device = dev;
+ ch->display_var = *var;
+
+ return 0;
+}
+
+static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
+{
struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data;
+ struct sh_mobile_lcdc_priv *priv;
struct resource *res;
+ int num_channels;
int error;
- void *buf;
- int i, j;
+ int i;
if (!pdata) {
dev_err(&pdev->dev, "no platform data defined\n");
@@ -1440,7 +1576,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
- error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED,
+ error = request_irq(i, sh_mobile_lcdc_irq, 0,
dev_name(&pdev->dev), priv);
if (error) {
dev_err(&pdev->dev, "unable to request irq\n");
@@ -1450,9 +1586,8 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
priv->irq = i;
atomic_set(&priv->hw_usecnt, -1);
- j = 0;
- for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) {
- struct sh_mobile_lcdc_chan *ch = priv->ch + j;
+ for (i = 0, num_channels = 0; i < ARRAY_SIZE(pdata->ch); i++) {
+ struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels;
ch->lcdc = priv;
memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i]));
@@ -1472,26 +1607,26 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
switch (pdata->ch[i].chan) {
case LCDC_CHAN_MAINLCD:
- ch->enabled = 1 << 1;
+ ch->enabled = LDCNT2R_ME;
ch->reg_offs = lcdc_offs_mainlcd;
- j++;
+ num_channels++;
break;
case LCDC_CHAN_SUBLCD:
- ch->enabled = 1 << 2;
+ ch->enabled = LDCNT2R_SE;
ch->reg_offs = lcdc_offs_sublcd;
- j++;
+ num_channels++;
break;
}
}
- if (!j) {
+ if (!num_channels) {
dev_err(&pdev->dev, "no channels defined\n");
error = -EINVAL;
goto err1;
}
/* for dual channel LCDC (MAIN + SUB) force shared bpp setting */
- if (j == 2)
+ if (num_channels == 2)
priv->forced_bpp = pdata->ch[0].bpp;
priv->base = ioremap_nocache(res->start, resource_size(res));
@@ -1506,125 +1641,23 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
priv->meram_dev = pdata->meram_dev;
- for (i = 0; i < j; i++) {
- struct fb_var_screeninfo *var;
- const struct fb_videomode *lcd_cfg, *max_cfg = NULL;
+ for (i = 0; i < num_channels; i++) {
struct sh_mobile_lcdc_chan *ch = priv->ch + i;
- struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
- const struct fb_videomode *mode = cfg->lcd_cfg;
- unsigned long max_size = 0;
- int k;
- int num_cfg;
-
- ch->info = framebuffer_alloc(0, &pdev->dev);
- if (!ch->info) {
- dev_err(&pdev->dev, "unable to allocate fb_info\n");
- error = -ENOMEM;
- break;
- }
-
- info = ch->info;
- var = &info->var;
- info->fbops = &sh_mobile_lcdc_ops;
- info->par = ch;
-
- mutex_init(&ch->open_lock);
-
- for (k = 0, lcd_cfg = mode;
- k < cfg->num_cfg && lcd_cfg;
- k++, lcd_cfg++) {
- unsigned long size = lcd_cfg->yres * lcd_cfg->xres;
- /* NV12 buffers must have even number of lines */
- if ((cfg->nonstd) && cfg->bpp == 12 &&
- (lcd_cfg->yres & 0x1)) {
- dev_err(&pdev->dev, "yres must be multiple of 2"
- " for YCbCr420 mode.\n");
- error = -EINVAL;
- goto err1;
- }
-
- if (size > max_size) {
- max_cfg = lcd_cfg;
- max_size = size;
- }
- }
-
- if (!mode)
- max_size = MAX_XRES * MAX_YRES;
- else if (max_cfg)
- dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n",
- max_cfg->xres, max_cfg->yres);
- info->fix = sh_mobile_lcdc_fix;
- info->fix.smem_len = max_size * 2 * cfg->bpp / 8;
-
- /* Only pan in 2 line steps for NV12 */
- if (cfg->nonstd && cfg->bpp == 12)
- info->fix.ypanstep = 2;
-
- if (!mode) {
- mode = &default_720p;
- num_cfg = 1;
- } else {
- num_cfg = cfg->num_cfg;
- }
-
- fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
-
- fb_videomode_to_var(var, mode);
- var->width = cfg->lcd_size_cfg.width;
- var->height = cfg->lcd_size_cfg.height;
- /* Default Y virtual resolution is 2x panel size */
- var->yres_virtual = var->yres * 2;
- var->activate = FB_ACTIVATE_NOW;
-
- error = sh_mobile_lcdc_set_bpp(var, cfg->bpp, cfg->nonstd);
+ error = sh_mobile_lcdc_channel_init(ch, &pdev->dev);
if (error)
- break;
-
- buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len,
- &ch->dma_handle, GFP_KERNEL);
- if (!buf) {
- dev_err(&pdev->dev, "unable to allocate buffer\n");
- error = -ENOMEM;
- break;
- }
-
- info->pseudo_palette = &ch->pseudo_palette;
- info->flags = FBINFO_FLAG_DEFAULT;
-
- error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
- if (error < 0) {
- dev_err(&pdev->dev, "unable to allocate cmap\n");
- dma_free_coherent(&pdev->dev, info->fix.smem_len,
- buf, ch->dma_handle);
- break;
- }
-
- info->fix.smem_start = ch->dma_handle;
- if (var->nonstd)
- info->fix.line_length = var->xres;
- else
- info->fix.line_length = var->xres * (cfg->bpp / 8);
-
- info->screen_base = buf;
- info->device = &pdev->dev;
- ch->display_var = *var;
+ goto err1;
}
- if (error)
- goto err1;
-
error = sh_mobile_lcdc_start(priv);
if (error) {
dev_err(&pdev->dev, "unable to start hardware\n");
goto err1;
}
- for (i = 0; i < j; i++) {
+ for (i = 0; i < num_channels; i++) {
struct sh_mobile_lcdc_chan *ch = priv->ch + i;
-
- info = ch->info;
+ struct fb_info *info = ch->info;
if (info->fbdefio) {
ch->sglist = vmalloc(sizeof(struct scatterlist) *
@@ -1665,57 +1698,6 @@ err1:
return error;
}
-static int sh_mobile_lcdc_remove(struct platform_device *pdev)
-{
- struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
- struct fb_info *info;
- int i;
-
- fb_unregister_client(&priv->notifier);
-
- for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
- if (priv->ch[i].info && priv->ch[i].info->dev)
- unregister_framebuffer(priv->ch[i].info);
-
- sh_mobile_lcdc_stop(priv);
-
- for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
- info = priv->ch[i].info;
-
- if (!info || !info->device)
- continue;
-
- if (priv->ch[i].sglist)
- vfree(priv->ch[i].sglist);
-
- if (info->screen_base)
- dma_free_coherent(&pdev->dev, info->fix.smem_len,
- info->screen_base,
- priv->ch[i].dma_handle);
- fb_dealloc_cmap(&info->cmap);
- framebuffer_release(info);
- }
-
- for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
- if (priv->ch[i].bl)
- sh_mobile_lcdc_bl_remove(priv->ch[i].bl);
- }
-
- if (priv->dot_clk)
- clk_put(priv->dot_clk);
-
- if (priv->dev)
- pm_runtime_disable(priv->dev);
-
- if (priv->base)
- iounmap(priv->base);
-
- if (priv->irq)
- free_irq(priv->irq, priv);
- kfree(priv);
- return 0;
-}
-
static struct platform_driver sh_mobile_lcdc_driver = {
.driver = {
.name = "sh_mobile_lcdc_fb",
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index aeed668..a58a0f3 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -18,6 +18,13 @@ struct sh_mobile_lcdc_priv;
struct fb_info;
struct backlight_device;
+/*
+ * struct sh_mobile_lcdc_chan - LCDC display channel
+ *
+ * @base_addr_y: Frame buffer viewport base address (luma component)
+ * @base_addr_c: Frame buffer viewport base address (chroma component)
+ * @pitch: Frame buffer line pitch
+ */
struct sh_mobile_lcdc_chan {
struct sh_mobile_lcdc_priv *lcdc;
unsigned long *reg_offs;
@@ -25,7 +32,6 @@ struct sh_mobile_lcdc_chan {
unsigned long enabled; /* ME and SE in LDCNT2R */
struct sh_mobile_lcdc_chan_cfg cfg;
u32 pseudo_palette[PALETTE_NR];
- unsigned long saved_ch_regs[NR_CH_REGS];
struct fb_info *info;
struct backlight_device *bl;
dma_addr_t dma_handle;
@@ -40,6 +46,10 @@ struct sh_mobile_lcdc_chan {
int blank_status;
struct mutex open_lock; /* protects the use counter */
int meram_enabled;
+
+ unsigned long base_addr_y;
+ unsigned long base_addr_c;
+ unsigned int pitch;
};
#endif
diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
index cc7d732..4d63490 100644
--- a/drivers/video/sh_mobile_meram.c
+++ b/drivers/video/sh_mobile_meram.c
@@ -12,29 +12,103 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/pm_runtime.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
-
-#include "sh_mobile_meram.h"
+#include <video/sh_mobile_meram.h>
/* meram registers */
-#define MExxCTL 0x0
-#define MExxBSIZE 0x4
-#define MExxMNCF 0x8
-#define MExxSARA 0x10
-#define MExxSARB 0x14
-#define MExxSBSIZE 0x18
-
-#define MERAM_MExxCTL_VAL(ctl, next_icb, addr) \
- ((ctl) | (((next_icb) & 0x1f) << 11) | (((addr) & 0x7ff) << 16))
-#define MERAM_MExxBSIZE_VAL(a, b, c) \
- (((a) << 28) | ((b) << 16) | (c))
-
-#define MEVCR1 0x4
-#define MEACTS 0x10
-#define MEQSEL1 0x40
-#define MEQSEL2 0x44
+#define MEVCR1 0x4
+#define MEVCR1_RST (1 << 31)
+#define MEVCR1_WD (1 << 30)
+#define MEVCR1_AMD1 (1 << 29)
+#define MEVCR1_AMD0 (1 << 28)
+#define MEQSEL1 0x40
+#define MEQSEL2 0x44
+
+#define MExxCTL 0x400
+#define MExxCTL_BV (1 << 31)
+#define MExxCTL_BSZ_SHIFT 28
+#define MExxCTL_MSAR_MASK (0x7ff << MExxCTL_MSAR_SHIFT)
+#define MExxCTL_MSAR_SHIFT 16
+#define MExxCTL_NXT_MASK (0x1f << MExxCTL_NXT_SHIFT)
+#define MExxCTL_NXT_SHIFT 11
+#define MExxCTL_WD1 (1 << 10)
+#define MExxCTL_WD0 (1 << 9)
+#define MExxCTL_WS (1 << 8)
+#define MExxCTL_CB (1 << 7)
+#define MExxCTL_WBF (1 << 6)
+#define MExxCTL_WF (1 << 5)
+#define MExxCTL_RF (1 << 4)
+#define MExxCTL_CM (1 << 3)
+#define MExxCTL_MD_READ (1 << 0)
+#define MExxCTL_MD_WRITE (2 << 0)
+#define MExxCTL_MD_ICB_WB (3 << 0)
+#define MExxCTL_MD_ICB (4 << 0)
+#define MExxCTL_MD_FB (7 << 0)
+#define MExxCTL_MD_MASK (7 << 0)
+#define MExxBSIZE 0x404
+#define MExxBSIZE_RCNT_SHIFT 28
+#define MExxBSIZE_YSZM1_SHIFT 16
+#define MExxBSIZE_XSZM1_SHIFT 0
+#define MExxMNCF 0x408
+#define MExxMNCF_KWBNM_SHIFT 28
+#define MExxMNCF_KRBNM_SHIFT 24
+#define MExxMNCF_BNM_SHIFT 16
+#define MExxMNCF_XBV (1 << 15)
+#define MExxMNCF_CPL_YCBCR444 (1 << 12)
+#define MExxMNCF_CPL_YCBCR420 (2 << 12)
+#define MExxMNCF_CPL_YCBCR422 (3 << 12)
+#define MExxMNCF_CPL_MSK (3 << 12)
+#define MExxMNCF_BL (1 << 2)
+#define MExxMNCF_LNM_SHIFT 0
+#define MExxSARA 0x410
+#define MExxSARB 0x414
+#define MExxSBSIZE 0x418
+#define MExxSBSIZE_HDV (1 << 31)
+#define MExxSBSIZE_HSZ16 (0 << 28)
+#define MExxSBSIZE_HSZ32 (1 << 28)
+#define MExxSBSIZE_HSZ64 (2 << 28)
+#define MExxSBSIZE_HSZ128 (3 << 28)
+#define MExxSBSIZE_SBSIZZ_SHIFT 0
+
+#define MERAM_MExxCTL_VAL(next, addr) \
+ ((((next) << MExxCTL_NXT_SHIFT) & MExxCTL_NXT_MASK) | \
+ (((addr) << MExxCTL_MSAR_SHIFT) & MExxCTL_MSAR_MASK))
+#define MERAM_MExxBSIZE_VAL(rcnt, yszm1, xszm1) \
+ (((rcnt) << MExxBSIZE_RCNT_SHIFT) | \
+ ((yszm1) << MExxBSIZE_YSZM1_SHIFT) | \
+ ((xszm1) << MExxBSIZE_XSZM1_SHIFT))
+
+#define SH_MOBILE_MERAM_ICB_NUM 32
+
+static unsigned long common_regs[] = {
+ MEVCR1,
+ MEQSEL1,
+ MEQSEL2,
+};
+#define CMN_REGS_SIZE ARRAY_SIZE(common_regs)
+
+static unsigned long icb_regs[] = {
+ MExxCTL,
+ MExxBSIZE,
+ MExxMNCF,
+ MExxSARA,
+ MExxSARB,
+ MExxSBSIZE,
+};
+#define ICB_REGS_SIZE ARRAY_SIZE(icb_regs)
+
+struct sh_mobile_meram_priv {
+ void __iomem *base;
+ struct mutex lock;
+ unsigned long used_icb;
+ int used_meram_cache_regions;
+ unsigned long used_meram_cache[SH_MOBILE_MERAM_ICB_NUM];
+ unsigned long cmn_saved_regs[CMN_REGS_SIZE];
+ unsigned long icb_saved_regs[ICB_REGS_SIZE * SH_MOBILE_MERAM_ICB_NUM];
+};
/* settings */
#define MERAM_SEC_LINE 15
@@ -44,8 +118,7 @@
* MERAM/ICB access functions
*/
-#define MERAM_ICB_OFFSET(base, idx, off) \
- ((base) + (0x400 + ((idx) * 0x20) + (off)))
+#define MERAM_ICB_OFFSET(base, idx, off) ((base) + (off) + (idx) * 0x20)
static inline void meram_write_icb(void __iomem *base, int idx, int off,
unsigned long val)
@@ -280,17 +353,18 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
/*
* Set MERAM for framebuffer
*
- * 0x70f: WD = 0x3, WS=0x1, CM=0x1, MD=FB mode
* we also chain the cache_icb and the marker_icb.
* we also split the allocated MERAM buffer between two ICBs.
*/
meram_write_icb(priv->base, icb->cache_icb, MExxCTL,
- MERAM_MExxCTL_VAL(0x70f, icb->marker_icb,
- icb->meram_offset));
+ MERAM_MExxCTL_VAL(icb->marker_icb, icb->meram_offset) |
+ MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
+ MExxCTL_MD_FB);
meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
- MERAM_MExxCTL_VAL(0x70f, icb->cache_icb,
- icb->meram_offset +
- icb->meram_size / 2));
+ MERAM_MExxCTL_VAL(icb->cache_icb, icb->meram_offset +
+ icb->meram_size / 2) |
+ MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
+ MExxCTL_MD_FB);
return 0;
}
@@ -299,8 +373,10 @@ static void meram_deinit(struct sh_mobile_meram_priv *priv,
struct sh_mobile_meram_icb *icb)
{
/* disable ICB */
- meram_write_icb(priv->base, icb->cache_icb, MExxCTL, 0);
- meram_write_icb(priv->base, icb->marker_icb, MExxCTL, 0);
+ meram_write_icb(priv->base, icb->cache_icb, MExxCTL,
+ MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
+ meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
+ MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
icb->cache_unit = 0;
}
@@ -337,24 +413,22 @@ static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
xres, yres, (!pixelformat) ? "yuv" : "rgb",
base_addr_y, base_addr_c);
- mutex_lock(&priv->lock);
-
/* we can't handle wider than 8192px */
if (xres > 8192) {
dev_err(&pdev->dev, "width exceeding the limit (> 8192).");
- error = -EINVAL;
- goto err;
- }
-
- if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) {
- dev_err(&pdev->dev, "no more ICB available.");
- error = -EINVAL;
- goto err;
+ return -EINVAL;
}
/* do we have at least one ICB config? */
if (cfg->icb[0].marker_icb < 0 || cfg->icb[0].cache_icb < 0) {
dev_err(&pdev->dev, "at least one ICB is required.");
+ return -EINVAL;
+ }
+
+ mutex_lock(&priv->lock);
+
+ if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) {
+ dev_err(&pdev->dev, "no more ICB available.");
error = -EINVAL;
goto err;
}
@@ -460,6 +534,57 @@ static int sh_mobile_meram_update(struct sh_mobile_meram_info *pdata,
return 0;
}
+static int sh_mobile_meram_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
+ int k, j;
+
+ for (k = 0; k < CMN_REGS_SIZE; k++)
+ priv->cmn_saved_regs[k] = meram_read_reg(priv->base,
+ common_regs[k]);
+
+ for (j = 0; j < 32; j++) {
+ if (!test_bit(j, &priv->used_icb))
+ continue;
+ for (k = 0; k < ICB_REGS_SIZE; k++) {
+ priv->icb_saved_regs[j * ICB_REGS_SIZE + k] =
+ meram_read_icb(priv->base, j, icb_regs[k]);
+ /* Reset ICB on resume */
+ if (icb_regs[k] == MExxCTL)
+ priv->icb_saved_regs[j * ICB_REGS_SIZE + k] |=
+ MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF;
+ }
+ }
+ return 0;
+}
+
+static int sh_mobile_meram_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
+ int k, j;
+
+ for (j = 0; j < 32; j++) {
+ if (!test_bit(j, &priv->used_icb))
+ continue;
+ for (k = 0; k < ICB_REGS_SIZE; k++) {
+ meram_write_icb(priv->base, j, icb_regs[k],
+ priv->icb_saved_regs[j * ICB_REGS_SIZE + k]);
+ }
+ }
+
+ for (k = 0; k < CMN_REGS_SIZE; k++)
+ meram_write_reg(priv->base, common_regs[k],
+ priv->cmn_saved_regs[k]);
+ return 0;
+}
+
+static const struct dev_pm_ops sh_mobile_meram_dev_pm_ops = {
+ .runtime_suspend = sh_mobile_meram_runtime_suspend,
+ .runtime_resume = sh_mobile_meram_runtime_resume,
+};
+
static struct sh_mobile_meram_ops sh_mobile_meram_ops = {
.module = THIS_MODULE,
.meram_register = sh_mobile_meram_register,
@@ -513,7 +638,9 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
/* initialize ICB addressing mode */
if (pdata->addr_mode == SH_MOBILE_MERAM_MODE1)
- meram_write_reg(priv->base, MEVCR1, 1 << 29);
+ meram_write_reg(priv->base, MEVCR1, MEVCR1_AMD1);
+
+ pm_runtime_enable(&pdev->dev);
dev_info(&pdev->dev, "sh_mobile_meram initialized.");
@@ -530,6 +657,8 @@ static int sh_mobile_meram_remove(struct platform_device *pdev)
{
struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
+ pm_runtime_disable(&pdev->dev);
+
if (priv->base)
iounmap(priv->base);
@@ -544,6 +673,7 @@ static struct platform_driver sh_mobile_meram_driver = {
.driver = {
.name = "sh_mobile_meram",
.owner = THIS_MODULE,
+ .pm = &sh_mobile_meram_dev_pm_ops,
},
.probe = sh_mobile_meram_probe,
.remove = sh_mobile_meram_remove,
diff --git a/drivers/video/sh_mobile_meram.h b/drivers/video/sh_mobile_meram.h
deleted file mode 100644
index 82c54fb..0000000
--- a/drivers/video/sh_mobile_meram.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef __sh_mobile_meram_h__
-#define __sh_mobile_meram_h__
-
-#include <linux/mutex.h>
-#include <video/sh_mobile_meram.h>
-
-/*
- * MERAM private
- */
-
-#define MERAM_ICB_Y 0x1
-#define MERAM_ICB_C 0x2
-
-/* MERAM cache size */
-#define SH_MOBILE_MERAM_ICB_NUM 32
-
-#define SH_MOBILE_MERAM_CACHE_OFFSET(p) ((p) >> 16)
-#define SH_MOBILE_MERAM_CACHE_SIZE(p) ((p) & 0xffff)
-
-struct sh_mobile_meram_priv {
- void __iomem *base;
- struct mutex lock;
- unsigned long used_icb;
- int used_meram_cache_regions;
- unsigned long used_meram_cache[SH_MOBILE_MERAM_ICB_NUM];
-};
-
-int sh_mobile_meram_alloc_icb(const struct sh_mobile_meram_cfg *cfg,
- int xres,
- int yres,
- unsigned int base_addr,
- int yuv_mode,
- int *marker_icb,
- int *out_pitch);
-
-void sh_mobile_meram_free_icb(int marker_icb);
-
-#define SH_MOBILE_MERAM_START(ind, ab) \
- (0xC0000000 | ((ab & 0x1) << 23) | ((ind & 0x1F) << 24))
-
-#endif /* !__sh_mobile_meram_h__ */
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index 7525984..078ca21 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -1333,19 +1333,14 @@ sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
}
static int
-sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
+sisfb_pan_var(struct sis_video_info *ivideo, struct fb_info *info,
+ struct fb_var_screeninfo *var)
{
- if(var->xoffset > (var->xres_virtual - var->xres)) {
- return -EINVAL;
- }
- if(var->yoffset > (var->yres_virtual - var->yres)) {
- return -EINVAL;
- }
-
- ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
+ ivideo->current_base = var->yoffset * info->var.xres_virtual
+ + var->xoffset;
/* calculate base bpp dep. */
- switch(var->bits_per_pixel) {
+ switch (info->var.bits_per_pixel) {
case 32:
break;
case 16:
@@ -1635,20 +1630,15 @@ sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
int err;
- if(var->xoffset > (var->xres_virtual - var->xres))
- return -EINVAL;
-
- if(var->yoffset > (var->yres_virtual - var->yres))
- return -EINVAL;
-
- if(var->vmode & FB_VMODE_YWRAP)
+ if (var->vmode & FB_VMODE_YWRAP)
return -EINVAL;
- if(var->xoffset + info->var.xres > info->var.xres_virtual ||
- var->yoffset + info->var.yres > info->var.yres_virtual)
+ if (var->xoffset + info->var.xres > info->var.xres_virtual ||
+ var->yoffset + info->var.yres > info->var.yres_virtual)
return -EINVAL;
- if((err = sisfb_pan_var(ivideo, var)) < 0)
+ err = sisfb_pan_var(ivideo, info, var);
+ if (err < 0)
return err;
info->var.xoffset = var->xoffset;
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
index 89158bc..30f7a81 100644
--- a/drivers/video/skeletonfb.c
+++ b/drivers/video/skeletonfb.c
@@ -989,7 +989,7 @@ static struct platform_device *xxxfb_device;
*/
int __init xxxfb_setup(char *options)
{
- /* Parse user speficied options (`video=xxxfb:') */
+ /* Parse user specified options (`video=xxxfb:') */
}
#endif /* MODULE */
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
index 6294dca..a78254c 100644
--- a/drivers/video/sm501fb.c
+++ b/drivers/video/sm501fb.c
@@ -582,7 +582,7 @@ static int sm501fb_pan_crt(struct fb_var_screeninfo *var,
{
struct sm501fb_par *par = info->par;
struct sm501fb_info *fbi = par->info;
- unsigned int bytes_pixel = var->bits_per_pixel / 8;
+ unsigned int bytes_pixel = info->var.bits_per_pixel / 8;
unsigned long reg;
unsigned long xoffs;
@@ -614,10 +614,10 @@ static int sm501fb_pan_pnl(struct fb_var_screeninfo *var,
struct sm501fb_info *fbi = par->info;
unsigned long reg;
- reg = var->xoffset | (var->xres_virtual << 16);
+ reg = var->xoffset | (info->var.xres_virtual << 16);
smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH);
- reg = var->yoffset | (var->yres_virtual << 16);
+ reg = var->yoffset | (info->var.yres_virtual << 16);
smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT);
sm501fb_sync_regs(fbi);
diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c
new file mode 100644
index 0000000..aaccffa
--- /dev/null
+++ b/drivers/video/smscufx.c
@@ -0,0 +1,1994 @@
+/*
+ * smscufx.c -- Framebuffer driver for SMSC UFX USB controller
+ *
+ * Copyright (C) 2011 Steve Glendinning <steve.glendinning@smsc.com>
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Based on udlfb, with work from Florian Echtler, Henrik Bjerregaard Pedersen,
+ * and others.
+ *
+ * Works well with Bernie Thompson's X DAMAGE patch to xf86-video-fbdev
+ * available from http://git.plugable.com
+ *
+ * Layout is based on skeletonfb by James Simmons and Geert Uytterhoeven,
+ * usb-skeleton by GregKH.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/uaccess.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "edid.h"
+
+#define check_warn(status, fmt, args...) \
+ ({ if (status < 0) pr_warn(fmt, ##args); })
+
+#define check_warn_return(status, fmt, args...) \
+ ({ if (status < 0) { pr_warn(fmt, ##args); return status; } })
+
+#define check_warn_goto_error(status, fmt, args...) \
+ ({ if (status < 0) { pr_warn(fmt, ##args); goto error; } })
+
+#define all_bits_set(x, bits) (((x) & (bits)) == (bits))
+
+#define USB_VENDOR_REQUEST_WRITE_REGISTER 0xA0
+#define USB_VENDOR_REQUEST_READ_REGISTER 0xA1
+
+/*
+ * TODO: Propose standard fb.h ioctl for reporting damage,
+ * using _IOWR() and one of the existing area structs from fb.h
+ * Consider these ioctls deprecated, but they're still used by the
+ * DisplayLink X server as yet - need both to be modified in tandem
+ * when new ioctl(s) are ready.
+ */
+#define UFX_IOCTL_RETURN_EDID (0xAD)
+#define UFX_IOCTL_REPORT_DAMAGE (0xAA)
+
+/* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */
+#define BULK_SIZE (512)
+#define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE)
+#define WRITES_IN_FLIGHT (4)
+
+#define GET_URB_TIMEOUT (HZ)
+#define FREE_URB_TIMEOUT (HZ*2)
+
+#define BPP 2
+
+#define UFX_DEFIO_WRITE_DELAY 5 /* fb_deferred_io.delay in jiffies */
+#define UFX_DEFIO_WRITE_DISABLE (HZ*60) /* "disable" with long delay */
+
+struct dloarea {
+ int x, y;
+ int w, h;
+};
+
+struct urb_node {
+ struct list_head entry;
+ struct ufx_data *dev;
+ struct delayed_work release_urb_work;
+ struct urb *urb;
+};
+
+struct urb_list {
+ struct list_head list;
+ spinlock_t lock;
+ struct semaphore limit_sem;
+ int available;
+ int count;
+ size_t size;
+};
+
+struct ufx_data {
+ struct usb_device *udev;
+ struct device *gdev; /* &udev->dev */
+ struct fb_info *info;
+ struct urb_list urbs;
+ struct kref kref;
+ int fb_count;
+ bool virtualized; /* true when physical usb device not present */
+ struct delayed_work free_framebuffer_work;
+ atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */
+ atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */
+ u8 *edid; /* null until we read edid from hw or get from sysfs */
+ size_t edid_size;
+ u32 pseudo_palette[256];
+};
+
+static struct fb_fix_screeninfo ufx_fix = {
+ .id = "smscufx",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+};
+
+static const u32 smscufx_info_flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
+ FBINFO_VIRTFB | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT |
+ FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR;
+
+static struct usb_device_id id_table[] = {
+ {USB_DEVICE(0x0424, 0x9d00),},
+ {USB_DEVICE(0x0424, 0x9d01),},
+ {},
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+/* module options */
+static int console; /* Optionally allow fbcon to consume first framebuffer */
+static int fb_defio = true; /* Optionally enable fb_defio mmap support */
+
+/* ufx keeps a list of urbs for efficient bulk transfers */
+static void ufx_urb_completion(struct urb *urb);
+static struct urb *ufx_get_urb(struct ufx_data *dev);
+static int ufx_submit_urb(struct ufx_data *dev, struct urb * urb, size_t len);
+static int ufx_alloc_urb_list(struct ufx_data *dev, int count, size_t size);
+static void ufx_free_urb_list(struct ufx_data *dev);
+
+/* reads a control register */
+static int ufx_reg_read(struct ufx_data *dev, u32 index, u32 *data)
+{
+ u32 *buf = kmalloc(4, GFP_KERNEL);
+ int ret;
+
+ BUG_ON(!dev);
+
+ if (!buf)
+ return -ENOMEM;
+
+ ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+ USB_VENDOR_REQUEST_READ_REGISTER,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 00, index, buf, 4, USB_CTRL_GET_TIMEOUT);
+
+ le32_to_cpus(buf);
+ *data = *buf;
+ kfree(buf);
+
+ if (unlikely(ret < 0))
+ pr_warn("Failed to read register index 0x%08x\n", index);
+
+ return ret;
+}
+
+/* writes a control register */
+static int ufx_reg_write(struct ufx_data *dev, u32 index, u32 data)
+{
+ u32 *buf = kmalloc(4, GFP_KERNEL);
+ int ret;
+
+ BUG_ON(!dev);
+
+ if (!buf)
+ return -ENOMEM;
+
+ *buf = data;
+ cpu_to_le32s(buf);
+
+ ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+ USB_VENDOR_REQUEST_WRITE_REGISTER,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 00, index, buf, 4, USB_CTRL_SET_TIMEOUT);
+
+ kfree(buf);
+
+ if (unlikely(ret < 0))
+ pr_warn("Failed to write register index 0x%08x with value "
+ "0x%08x\n", index, data);
+
+ return ret;
+}
+
+static int ufx_reg_clear_and_set_bits(struct ufx_data *dev, u32 index,
+ u32 bits_to_clear, u32 bits_to_set)
+{
+ u32 data;
+ int status = ufx_reg_read(dev, index, &data);
+ check_warn_return(status, "ufx_reg_clear_and_set_bits error reading "
+ "0x%x", index);
+
+ data &= (~bits_to_clear);
+ data |= bits_to_set;
+
+ status = ufx_reg_write(dev, index, data);
+ check_warn_return(status, "ufx_reg_clear_and_set_bits error writing "
+ "0x%x", index);
+
+ return 0;
+}
+
+static int ufx_reg_set_bits(struct ufx_data *dev, u32 index, u32 bits)
+{
+ return ufx_reg_clear_and_set_bits(dev, index, 0, bits);
+}
+
+static int ufx_reg_clear_bits(struct ufx_data *dev, u32 index, u32 bits)
+{
+ return ufx_reg_clear_and_set_bits(dev, index, bits, 0);
+}
+
+static int ufx_lite_reset(struct ufx_data *dev)
+{
+ int status;
+ u32 value;
+
+ status = ufx_reg_write(dev, 0x3008, 0x00000001);
+ check_warn_return(status, "ufx_lite_reset error writing 0x3008");
+
+ status = ufx_reg_read(dev, 0x3008, &value);
+ check_warn_return(status, "ufx_lite_reset error reading 0x3008");
+
+ return (value == 0) ? 0 : -EIO;
+}
+
+/* If display is unblanked, then blank it */
+static int ufx_blank(struct ufx_data *dev, bool wait)
+{
+ u32 dc_ctrl, dc_sts;
+ int i;
+
+ int status = ufx_reg_read(dev, 0x2004, &dc_sts);
+ check_warn_return(status, "ufx_blank error reading 0x2004");
+
+ status = ufx_reg_read(dev, 0x2000, &dc_ctrl);
+ check_warn_return(status, "ufx_blank error reading 0x2000");
+
+ /* return success if display is already blanked */
+ if ((dc_sts & 0x00000100) || (dc_ctrl & 0x00000100))
+ return 0;
+
+ /* request the DC to blank the display */
+ dc_ctrl |= 0x00000100;
+ status = ufx_reg_write(dev, 0x2000, dc_ctrl);
+ check_warn_return(status, "ufx_blank error writing 0x2000");
+
+ /* return success immediately if we don't have to wait */
+ if (!wait)
+ return 0;
+
+ for (i = 0; i < 250; i++) {
+ status = ufx_reg_read(dev, 0x2004, &dc_sts);
+ check_warn_return(status, "ufx_blank error reading 0x2004");
+
+ if (dc_sts & 0x00000100)
+ return 0;
+ }
+
+ /* timed out waiting for display to blank */
+ return -EIO;
+}
+
+/* If display is blanked, then unblank it */
+static int ufx_unblank(struct ufx_data *dev, bool wait)
+{
+ u32 dc_ctrl, dc_sts;
+ int i;
+
+ int status = ufx_reg_read(dev, 0x2004, &dc_sts);
+ check_warn_return(status, "ufx_unblank error reading 0x2004");
+
+ status = ufx_reg_read(dev, 0x2000, &dc_ctrl);
+ check_warn_return(status, "ufx_unblank error reading 0x2000");
+
+ /* return success if display is already unblanked */
+ if (((dc_sts & 0x00000100) == 0) || ((dc_ctrl & 0x00000100) == 0))
+ return 0;
+
+ /* request the DC to unblank the display */
+ dc_ctrl &= ~0x00000100;
+ status = ufx_reg_write(dev, 0x2000, dc_ctrl);
+ check_warn_return(status, "ufx_unblank error writing 0x2000");
+
+ /* return success immediately if we don't have to wait */
+ if (!wait)
+ return 0;
+
+ for (i = 0; i < 250; i++) {
+ status = ufx_reg_read(dev, 0x2004, &dc_sts);
+ check_warn_return(status, "ufx_unblank error reading 0x2004");
+
+ if ((dc_sts & 0x00000100) == 0)
+ return 0;
+ }
+
+ /* timed out waiting for display to unblank */
+ return -EIO;
+}
+
+/* If display is enabled, then disable it */
+static int ufx_disable(struct ufx_data *dev, bool wait)
+{
+ u32 dc_ctrl, dc_sts;
+ int i;
+
+ int status = ufx_reg_read(dev, 0x2004, &dc_sts);
+ check_warn_return(status, "ufx_disable error reading 0x2004");
+
+ status = ufx_reg_read(dev, 0x2000, &dc_ctrl);
+ check_warn_return(status, "ufx_disable error reading 0x2000");
+
+ /* return success if display is already disabled */
+ if (((dc_sts & 0x00000001) == 0) || ((dc_ctrl & 0x00000001) == 0))
+ return 0;
+
+ /* request the DC to disable the display */
+ dc_ctrl &= ~(0x00000001);
+ status = ufx_reg_write(dev, 0x2000, dc_ctrl);
+ check_warn_return(status, "ufx_disable error writing 0x2000");
+
+ /* return success immediately if we don't have to wait */
+ if (!wait)
+ return 0;
+
+ for (i = 0; i < 250; i++) {
+ status = ufx_reg_read(dev, 0x2004, &dc_sts);
+ check_warn_return(status, "ufx_disable error reading 0x2004");
+
+ if ((dc_sts & 0x00000001) == 0)
+ return 0;
+ }
+
+ /* timed out waiting for display to disable */
+ return -EIO;
+}
+
+/* If display is disabled, then enable it */
+static int ufx_enable(struct ufx_data *dev, bool wait)
+{
+ u32 dc_ctrl, dc_sts;
+ int i;
+
+ int status = ufx_reg_read(dev, 0x2004, &dc_sts);
+ check_warn_return(status, "ufx_enable error reading 0x2004");
+
+ status = ufx_reg_read(dev, 0x2000, &dc_ctrl);
+ check_warn_return(status, "ufx_enable error reading 0x2000");
+
+ /* return success if display is already enabled */
+ if ((dc_sts & 0x00000001) || (dc_ctrl & 0x00000001))
+ return 0;
+
+ /* request the DC to enable the display */
+ dc_ctrl |= 0x00000001;
+ status = ufx_reg_write(dev, 0x2000, dc_ctrl);
+ check_warn_return(status, "ufx_enable error writing 0x2000");
+
+ /* return success immediately if we don't have to wait */
+ if (!wait)
+ return 0;
+
+ for (i = 0; i < 250; i++) {
+ status = ufx_reg_read(dev, 0x2004, &dc_sts);
+ check_warn_return(status, "ufx_enable error reading 0x2004");
+
+ if (dc_sts & 0x00000001)
+ return 0;
+ }
+
+ /* timed out waiting for display to enable */
+ return -EIO;
+}
+
+static int ufx_config_sys_clk(struct ufx_data *dev)
+{
+ int status = ufx_reg_write(dev, 0x700C, 0x8000000F);
+ check_warn_return(status, "error writing 0x700C");
+
+ status = ufx_reg_write(dev, 0x7014, 0x0010024F);
+ check_warn_return(status, "error writing 0x7014");
+
+ status = ufx_reg_write(dev, 0x7010, 0x00000000);
+ check_warn_return(status, "error writing 0x7010");
+
+ status = ufx_reg_clear_bits(dev, 0x700C, 0x0000000A);
+ check_warn_return(status, "error clearing PLL1 bypass in 0x700C");
+ msleep(1);
+
+ status = ufx_reg_clear_bits(dev, 0x700C, 0x80000000);
+ check_warn_return(status, "error clearing output gate in 0x700C");
+
+ return 0;
+}
+
+static int ufx_config_ddr2(struct ufx_data *dev)
+{
+ int status, i = 0;
+ u32 tmp;
+
+ status = ufx_reg_write(dev, 0x0004, 0x001F0F77);
+ check_warn_return(status, "error writing 0x0004");
+
+ status = ufx_reg_write(dev, 0x0008, 0xFFF00000);
+ check_warn_return(status, "error writing 0x0008");
+
+ status = ufx_reg_write(dev, 0x000C, 0x0FFF2222);
+ check_warn_return(status, "error writing 0x000C");
+
+ status = ufx_reg_write(dev, 0x0010, 0x00030814);
+ check_warn_return(status, "error writing 0x0010");
+
+ status = ufx_reg_write(dev, 0x0014, 0x00500019);
+ check_warn_return(status, "error writing 0x0014");
+
+ status = ufx_reg_write(dev, 0x0018, 0x020D0F15);
+ check_warn_return(status, "error writing 0x0018");
+
+ status = ufx_reg_write(dev, 0x001C, 0x02532305);
+ check_warn_return(status, "error writing 0x001C");
+
+ status = ufx_reg_write(dev, 0x0020, 0x0B030905);
+ check_warn_return(status, "error writing 0x0020");
+
+ status = ufx_reg_write(dev, 0x0024, 0x00000827);
+ check_warn_return(status, "error writing 0x0024");
+
+ status = ufx_reg_write(dev, 0x0028, 0x00000000);
+ check_warn_return(status, "error writing 0x0028");
+
+ status = ufx_reg_write(dev, 0x002C, 0x00000042);
+ check_warn_return(status, "error writing 0x002C");
+
+ status = ufx_reg_write(dev, 0x0030, 0x09520000);
+ check_warn_return(status, "error writing 0x0030");
+
+ status = ufx_reg_write(dev, 0x0034, 0x02223314);
+ check_warn_return(status, "error writing 0x0034");
+
+ status = ufx_reg_write(dev, 0x0038, 0x00430043);
+ check_warn_return(status, "error writing 0x0038");
+
+ status = ufx_reg_write(dev, 0x003C, 0xF00F000F);
+ check_warn_return(status, "error writing 0x003C");
+
+ status = ufx_reg_write(dev, 0x0040, 0xF380F00F);
+ check_warn_return(status, "error writing 0x0040");
+
+ status = ufx_reg_write(dev, 0x0044, 0xF00F0496);
+ check_warn_return(status, "error writing 0x0044");
+
+ status = ufx_reg_write(dev, 0x0048, 0x03080406);
+ check_warn_return(status, "error writing 0x0048");
+
+ status = ufx_reg_write(dev, 0x004C, 0x00001000);
+ check_warn_return(status, "error writing 0x004C");
+
+ status = ufx_reg_write(dev, 0x005C, 0x00000007);
+ check_warn_return(status, "error writing 0x005C");
+
+ status = ufx_reg_write(dev, 0x0100, 0x54F00012);
+ check_warn_return(status, "error writing 0x0100");
+
+ status = ufx_reg_write(dev, 0x0104, 0x00004012);
+ check_warn_return(status, "error writing 0x0104");
+
+ status = ufx_reg_write(dev, 0x0118, 0x40404040);
+ check_warn_return(status, "error writing 0x0118");
+
+ status = ufx_reg_write(dev, 0x0000, 0x00000001);
+ check_warn_return(status, "error writing 0x0000");
+
+ while (i++ < 500) {
+ status = ufx_reg_read(dev, 0x0000, &tmp);
+ check_warn_return(status, "error reading 0x0000");
+
+ if (all_bits_set(tmp, 0xC0000000))
+ return 0;
+ }
+
+ pr_err("DDR2 initialisation timed out, reg 0x0000=0x%08x", tmp);
+ return -ETIMEDOUT;
+}
+
+struct pll_values {
+ u32 div_r0;
+ u32 div_f0;
+ u32 div_q0;
+ u32 range0;
+ u32 div_r1;
+ u32 div_f1;
+ u32 div_q1;
+ u32 range1;
+};
+
+static u32 ufx_calc_range(u32 ref_freq)
+{
+ if (ref_freq >= 88000000)
+ return 7;
+
+ if (ref_freq >= 54000000)
+ return 6;
+
+ if (ref_freq >= 34000000)
+ return 5;
+
+ if (ref_freq >= 21000000)
+ return 4;
+
+ if (ref_freq >= 13000000)
+ return 3;
+
+ if (ref_freq >= 8000000)
+ return 2;
+
+ return 1;
+}
+
+/* calculates PLL divider settings for a desired target frequency */
+static void ufx_calc_pll_values(const u32 clk_pixel_pll, struct pll_values *asic_pll)
+{
+ const u32 ref_clk = 25000000;
+ u32 div_r0, div_f0, div_q0, div_r1, div_f1, div_q1;
+ u32 min_error = clk_pixel_pll;
+
+ for (div_r0 = 1; div_r0 <= 32; div_r0++) {
+ u32 ref_freq0 = ref_clk / div_r0;
+ if (ref_freq0 < 5000000)
+ break;
+
+ if (ref_freq0 > 200000000)
+ continue;
+
+ for (div_f0 = 1; div_f0 <= 256; div_f0++) {
+ u32 vco_freq0 = ref_freq0 * div_f0;
+
+ if (vco_freq0 < 350000000)
+ continue;
+
+ if (vco_freq0 > 700000000)
+ break;
+
+ for (div_q0 = 0; div_q0 < 7; div_q0++) {
+ u32 pllout_freq0 = vco_freq0 / (1 << div_q0);
+
+ if (pllout_freq0 < 5000000)
+ break;
+
+ if (pllout_freq0 > 200000000)
+ continue;
+
+ for (div_r1 = 1; div_r1 <= 32; div_r1++) {
+ u32 ref_freq1 = pllout_freq0 / div_r1;
+
+ if (ref_freq1 < 5000000)
+ break;
+
+ for (div_f1 = 1; div_f1 <= 256; div_f1++) {
+ u32 vco_freq1 = ref_freq1 * div_f1;
+
+ if (vco_freq1 < 350000000)
+ continue;
+
+ if (vco_freq1 > 700000000)
+ break;
+
+ for (div_q1 = 0; div_q1 < 7; div_q1++) {
+ u32 pllout_freq1 = vco_freq1 / (1 << div_q1);
+ int error = abs(pllout_freq1 - clk_pixel_pll);
+
+ if (pllout_freq1 < 5000000)
+ break;
+
+ if (pllout_freq1 > 700000000)
+ continue;
+
+ if (error < min_error) {
+ min_error = error;
+
+ /* final returned value is equal to calculated value - 1
+ * because a value of 0 = divide by 1 */
+ asic_pll->div_r0 = div_r0 - 1;
+ asic_pll->div_f0 = div_f0 - 1;
+ asic_pll->div_q0 = div_q0;
+ asic_pll->div_r1 = div_r1 - 1;
+ asic_pll->div_f1 = div_f1 - 1;
+ asic_pll->div_q1 = div_q1;
+
+ asic_pll->range0 = ufx_calc_range(ref_freq0);
+ asic_pll->range1 = ufx_calc_range(ref_freq1);
+
+ if (min_error == 0)
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/* sets analog bit PLL configuration values */
+static int ufx_config_pix_clk(struct ufx_data *dev, u32 pixclock)
+{
+ struct pll_values asic_pll = {0};
+ u32 value, clk_pixel, clk_pixel_pll;
+ int status;
+
+ /* convert pixclock (in ps) to frequency (in Hz) */
+ clk_pixel = PICOS2KHZ(pixclock) * 1000;
+ pr_debug("pixclock %d ps = clk_pixel %d Hz", pixclock, clk_pixel);
+
+ /* clk_pixel = 1/2 clk_pixel_pll */
+ clk_pixel_pll = clk_pixel * 2;
+
+ ufx_calc_pll_values(clk_pixel_pll, &asic_pll);
+
+ /* Keep BYPASS and RESET signals asserted until configured */
+ status = ufx_reg_write(dev, 0x7000, 0x8000000F);
+ check_warn_return(status, "error writing 0x7000");
+
+ value = (asic_pll.div_f1 | (asic_pll.div_r1 << 8) |
+ (asic_pll.div_q1 << 16) | (asic_pll.range1 << 20));
+ status = ufx_reg_write(dev, 0x7008, value);
+ check_warn_return(status, "error writing 0x7008");
+
+ value = (asic_pll.div_f0 | (asic_pll.div_r0 << 8) |
+ (asic_pll.div_q0 << 16) | (asic_pll.range0 << 20));
+ status = ufx_reg_write(dev, 0x7004, value);
+ check_warn_return(status, "error writing 0x7004");
+
+ status = ufx_reg_clear_bits(dev, 0x7000, 0x00000005);
+ check_warn_return(status,
+ "error clearing PLL0 bypass bits in 0x7000");
+ msleep(1);
+
+ status = ufx_reg_clear_bits(dev, 0x7000, 0x0000000A);
+ check_warn_return(status,
+ "error clearing PLL1 bypass bits in 0x7000");
+ msleep(1);
+
+ status = ufx_reg_clear_bits(dev, 0x7000, 0x80000000);
+ check_warn_return(status, "error clearing gate bits in 0x7000");
+
+ return 0;
+}
+
+static int ufx_set_vid_mode(struct ufx_data *dev, struct fb_var_screeninfo *var)
+{
+ u32 temp;
+ u16 h_total, h_active, h_blank_start, h_blank_end, h_sync_start, h_sync_end;
+ u16 v_total, v_active, v_blank_start, v_blank_end, v_sync_start, v_sync_end;
+
+ int status = ufx_reg_write(dev, 0x8028, 0);
+ check_warn_return(status, "ufx_set_vid_mode error disabling RGB pad");
+
+ status = ufx_reg_write(dev, 0x8024, 0);
+ check_warn_return(status, "ufx_set_vid_mode error disabling VDAC");
+
+ /* shut everything down before changing timing */
+ status = ufx_blank(dev, true);
+ check_warn_return(status, "ufx_set_vid_mode error blanking display");
+
+ status = ufx_disable(dev, true);
+ check_warn_return(status, "ufx_set_vid_mode error disabling display");
+
+ status = ufx_config_pix_clk(dev, var->pixclock);
+ check_warn_return(status, "ufx_set_vid_mode error configuring pixclock");
+
+ status = ufx_reg_write(dev, 0x2000, 0x00000104);
+ check_warn_return(status, "ufx_set_vid_mode error writing 0x2000");
+
+ /* set horizontal timings */
+ h_total = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+ h_active = var->xres;
+ h_blank_start = var->xres + var->right_margin;
+ h_blank_end = var->xres + var->right_margin + var->hsync_len;
+ h_sync_start = var->xres + var->right_margin;
+ h_sync_end = var->xres + var->right_margin + var->hsync_len;
+
+ temp = ((h_total - 1) << 16) | (h_active - 1);
+ status = ufx_reg_write(dev, 0x2008, temp);
+ check_warn_return(status, "ufx_set_vid_mode error writing 0x2008");
+
+ temp = ((h_blank_start - 1) << 16) | (h_blank_end - 1);
+ status = ufx_reg_write(dev, 0x200C, temp);
+ check_warn_return(status, "ufx_set_vid_mode error writing 0x200C");
+
+ temp = ((h_sync_start - 1) << 16) | (h_sync_end - 1);
+ status = ufx_reg_write(dev, 0x2010, temp);
+ check_warn_return(status, "ufx_set_vid_mode error writing 0x2010");
+
+ /* set vertical timings */
+ v_total = var->upper_margin + var->yres + var->lower_margin + var->vsync_len;
+ v_active = var->yres;
+ v_blank_start = var->yres + var->lower_margin;
+ v_blank_end = var->yres + var->lower_margin + var->vsync_len;
+ v_sync_start = var->yres + var->lower_margin;
+ v_sync_end = var->yres + var->lower_margin + var->vsync_len;
+
+ temp = ((v_total - 1) << 16) | (v_active - 1);
+ status = ufx_reg_write(dev, 0x2014, temp);
+ check_warn_return(status, "ufx_set_vid_mode error writing 0x2014");
+
+ temp = ((v_blank_start - 1) << 16) | (v_blank_end - 1);
+ status = ufx_reg_write(dev, 0x2018, temp);
+ check_warn_return(status, "ufx_set_vid_mode error writing 0x2018");
+
+ temp = ((v_sync_start - 1) << 16) | (v_sync_end - 1);
+ status = ufx_reg_write(dev, 0x201C, temp);
+ check_warn_return(status, "ufx_set_vid_mode error writing 0x201C");
+
+ status = ufx_reg_write(dev, 0x2020, 0x00000000);
+ check_warn_return(status, "ufx_set_vid_mode error writing 0x2020");
+
+ status = ufx_reg_write(dev, 0x2024, 0x00000000);
+ check_warn_return(status, "ufx_set_vid_mode error writing 0x2024");
+
+ /* Set the frame length register (#pix * 2 bytes/pixel) */
+ temp = var->xres * var->yres * 2;
+ temp = (temp + 7) & (~0x7);
+ status = ufx_reg_write(dev, 0x2028, temp);
+ check_warn_return(status, "ufx_set_vid_mode error writing 0x2028");
+
+ /* enable desired output interface & disable others */
+ status = ufx_reg_write(dev, 0x2040, 0);
+ check_warn_return(status, "ufx_set_vid_mode error writing 0x2040");
+
+ status = ufx_reg_write(dev, 0x2044, 0);
+ check_warn_return(status, "ufx_set_vid_mode error writing 0x2044");
+
+ status = ufx_reg_write(dev, 0x2048, 0);
+ check_warn_return(status, "ufx_set_vid_mode error writing 0x2048");
+
+ /* set the sync polarities & enable bit */
+ temp = 0x00000001;
+ if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+ temp |= 0x00000010;
+
+ if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+ temp |= 0x00000008;
+
+ status = ufx_reg_write(dev, 0x2040, temp);
+ check_warn_return(status, "ufx_set_vid_mode error writing 0x2040");
+
+ /* start everything back up */
+ status = ufx_enable(dev, true);
+ check_warn_return(status, "ufx_set_vid_mode error enabling display");
+
+ /* Unblank the display */
+ status = ufx_unblank(dev, true);
+ check_warn_return(status, "ufx_set_vid_mode error unblanking display");
+
+ /* enable RGB pad */
+ status = ufx_reg_write(dev, 0x8028, 0x00000003);
+ check_warn_return(status, "ufx_set_vid_mode error enabling RGB pad");
+
+ /* enable VDAC */
+ status = ufx_reg_write(dev, 0x8024, 0x00000007);
+ check_warn_return(status, "ufx_set_vid_mode error enabling VDAC");
+
+ return 0;
+}
+
+static int ufx_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ unsigned long start = vma->vm_start;
+ unsigned long size = vma->vm_end - vma->vm_start;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ unsigned long page, pos;
+
+ if (offset + size > info->fix.smem_len)
+ return -EINVAL;
+
+ pos = (unsigned long)info->fix.smem_start + offset;
+
+ pr_debug("mmap() framebuffer addr:%lu size:%lu\n",
+ pos, size);
+
+ while (size > 0) {
+ page = vmalloc_to_pfn((void *)pos);
+ if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+ return -EAGAIN;
+
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+
+ vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
+ return 0;
+}
+
+static void ufx_raw_rect(struct ufx_data *dev, u16 *cmd, int x, int y,
+ int width, int height)
+{
+ size_t packed_line_len = ALIGN((width * 2), 4);
+ size_t packed_rect_len = packed_line_len * height;
+ int line;
+
+ BUG_ON(!dev);
+ BUG_ON(!dev->info);
+
+ /* command word */
+ *((u32 *)&cmd[0]) = cpu_to_le32(0x01);
+
+ /* length word */
+ *((u32 *)&cmd[2]) = cpu_to_le32(packed_rect_len + 16);
+
+ cmd[4] = cpu_to_le16(x);
+ cmd[5] = cpu_to_le16(y);
+ cmd[6] = cpu_to_le16(width);
+ cmd[7] = cpu_to_le16(height);
+
+ /* frame base address */
+ *((u32 *)&cmd[8]) = cpu_to_le32(0);
+
+ /* color mode and horizontal resolution */
+ cmd[10] = cpu_to_le16(0x4000 | dev->info->var.xres);
+
+ /* vertical resolution */
+ cmd[11] = cpu_to_le16(dev->info->var.yres);
+
+ /* packed data */
+ for (line = 0; line < height; line++) {
+ const int line_offset = dev->info->fix.line_length * (y + line);
+ const int byte_offset = line_offset + (x * BPP);
+ memcpy(&cmd[(24 + (packed_line_len * line)) / 2],
+ (char *)dev->info->fix.smem_start + byte_offset, width * BPP);
+ }
+}
+
+int ufx_handle_damage(struct ufx_data *dev, int x, int y,
+ int width, int height)
+{
+ size_t packed_line_len = ALIGN((width * 2), 4);
+ int len, status, urb_lines, start_line = 0;
+
+ if ((width <= 0) || (height <= 0) ||
+ (x + width > dev->info->var.xres) ||
+ (y + height > dev->info->var.yres))
+ return -EINVAL;
+
+ if (!atomic_read(&dev->usb_active))
+ return 0;
+
+ while (start_line < height) {
+ struct urb *urb = ufx_get_urb(dev);
+ if (!urb) {
+ pr_warn("ufx_handle_damage unable to get urb");
+ return 0;
+ }
+
+ /* assume we have enough space to transfer at least one line */
+ BUG_ON(urb->transfer_buffer_length < (24 + (width * 2)));
+
+ /* calculate the maximum number of lines we could fit in */
+ urb_lines = (urb->transfer_buffer_length - 24) / packed_line_len;
+
+ /* but we might not need this many */
+ urb_lines = min(urb_lines, (height - start_line));
+
+ memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
+
+ ufx_raw_rect(dev, urb->transfer_buffer, x, (y + start_line), width, urb_lines);
+ len = 24 + (packed_line_len * urb_lines);
+
+ status = ufx_submit_urb(dev, urb, len);
+ check_warn_return(status, "Error submitting URB");
+
+ start_line += urb_lines;
+ }
+
+ return 0;
+}
+
+/* Path triggered by usermode clients who write to filesystem
+ * e.g. cat filename > /dev/fb1
+ * Not used by X Windows or text-mode console. But useful for testing.
+ * Slow because of extra copy and we must assume all pixels dirty. */
+static ssize_t ufx_ops_write(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t result;
+ struct ufx_data *dev = info->par;
+ u32 offset = (u32) *ppos;
+
+ result = fb_sys_write(info, buf, count, ppos);
+
+ if (result > 0) {
+ int start = max((int)(offset / info->fix.line_length) - 1, 0);
+ int lines = min((u32)((result / info->fix.line_length) + 1),
+ (u32)info->var.yres);
+
+ ufx_handle_damage(dev, 0, start, info->var.xres, lines);
+ }
+
+ return result;
+}
+
+static void ufx_ops_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
+
+ struct ufx_data *dev = info->par;
+
+ sys_copyarea(info, area);
+
+ ufx_handle_damage(dev, area->dx, area->dy,
+ area->width, area->height);
+}
+
+static void ufx_ops_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+{
+ struct ufx_data *dev = info->par;
+
+ sys_imageblit(info, image);
+
+ ufx_handle_damage(dev, image->dx, image->dy,
+ image->width, image->height);
+}
+
+static void ufx_ops_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+{
+ struct ufx_data *dev = info->par;
+
+ sys_fillrect(info, rect);
+
+ ufx_handle_damage(dev, rect->dx, rect->dy, rect->width,
+ rect->height);
+}
+
+/* NOTE: fb_defio.c is holding info->fbdefio.mutex
+ * Touching ANY framebuffer memory that triggers a page fault
+ * in fb_defio will cause a deadlock, when it also tries to
+ * grab the same mutex. */
+static void ufx_dpy_deferred_io(struct fb_info *info,
+ struct list_head *pagelist)
+{
+ struct page *cur;
+ struct fb_deferred_io *fbdefio = info->fbdefio;
+ struct ufx_data *dev = info->par;
+
+ if (!fb_defio)
+ return;
+
+ if (!atomic_read(&dev->usb_active))
+ return;
+
+ /* walk the written page list and render each to device */
+ list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+ /* create a rectangle of full screen width that encloses the
+ * entire dirty framebuffer page */
+ const int x = 0;
+ const int width = dev->info->var.xres;
+ const int y = (cur->index << PAGE_SHIFT) / (width * 2);
+ int height = (PAGE_SIZE / (width * 2)) + 1;
+ height = min(height, (int)(dev->info->var.yres - y));
+
+ BUG_ON(y >= dev->info->var.yres);
+ BUG_ON((y + height) > dev->info->var.yres);
+
+ ufx_handle_damage(dev, x, y, width, height);
+ }
+}
+
+static int ufx_ops_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ struct ufx_data *dev = info->par;
+ struct dloarea *area = NULL;
+
+ if (!atomic_read(&dev->usb_active))
+ return 0;
+
+ /* TODO: Update X server to get this from sysfs instead */
+ if (cmd == UFX_IOCTL_RETURN_EDID) {
+ u8 __user *edid = (u8 __user *)arg;
+ if (copy_to_user(edid, dev->edid, dev->edid_size))
+ return -EFAULT;
+ return 0;
+ }
+
+ /* TODO: Help propose a standard fb.h ioctl to report mmap damage */
+ if (cmd == UFX_IOCTL_REPORT_DAMAGE) {
+ /* If we have a damage-aware client, turn fb_defio "off"
+ * To avoid perf imact of unecessary page fault handling.
+ * Done by resetting the delay for this fb_info to a very
+ * long period. Pages will become writable and stay that way.
+ * Reset to normal value when all clients have closed this fb.
+ */
+ if (info->fbdefio)
+ info->fbdefio->delay = UFX_DEFIO_WRITE_DISABLE;
+
+ area = (struct dloarea *)arg;
+
+ if (area->x < 0)
+ area->x = 0;
+
+ if (area->x > info->var.xres)
+ area->x = info->var.xres;
+
+ if (area->y < 0)
+ area->y = 0;
+
+ if (area->y > info->var.yres)
+ area->y = info->var.yres;
+
+ ufx_handle_damage(dev, area->x, area->y, area->w, area->h);
+ }
+
+ return 0;
+}
+
+/* taken from vesafb */
+static int
+ufx_ops_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp, struct fb_info *info)
+{
+ int err = 0;
+
+ if (regno >= info->cmap.len)
+ return 1;
+
+ if (regno < 16) {
+ if (info->var.red.offset == 10) {
+ /* 1:5:5:5 */
+ ((u32 *) (info->pseudo_palette))[regno] =
+ ((red & 0xf800) >> 1) |
+ ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
+ } else {
+ /* 0:5:6:5 */
+ ((u32 *) (info->pseudo_palette))[regno] =
+ ((red & 0xf800)) |
+ ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+ }
+ }
+
+ return err;
+}
+
+/* It's common for several clients to have framebuffer open simultaneously.
+ * e.g. both fbcon and X. Makes things interesting.
+ * Assumes caller is holding info->lock (for open and release at least) */
+static int ufx_ops_open(struct fb_info *info, int user)
+{
+ struct ufx_data *dev = info->par;
+
+ /* fbcon aggressively connects to first framebuffer it finds,
+ * preventing other clients (X) from working properly. Usually
+ * not what the user wants. Fail by default with option to enable. */
+ if (user == 0 && !console)
+ return -EBUSY;
+
+ /* If the USB device is gone, we don't accept new opens */
+ if (dev->virtualized)
+ return -ENODEV;
+
+ dev->fb_count++;
+
+ kref_get(&dev->kref);
+
+ if (fb_defio && (info->fbdefio == NULL)) {
+ /* enable defio at last moment if not disabled by client */
+
+ struct fb_deferred_io *fbdefio;
+
+ fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
+
+ if (fbdefio) {
+ fbdefio->delay = UFX_DEFIO_WRITE_DELAY;
+ fbdefio->deferred_io = ufx_dpy_deferred_io;
+ }
+
+ info->fbdefio = fbdefio;
+ fb_deferred_io_init(info);
+ }
+
+ pr_debug("open /dev/fb%d user=%d fb_info=%p count=%d",
+ info->node, user, info, dev->fb_count);
+
+ return 0;
+}
+
+/*
+ * Called when all client interfaces to start transactions have been disabled,
+ * and all references to our device instance (ufx_data) are released.
+ * Every transaction must have a reference, so we know are fully spun down
+ */
+static void ufx_free(struct kref *kref)
+{
+ struct ufx_data *dev = container_of(kref, struct ufx_data, kref);
+
+ /* this function will wait for all in-flight urbs to complete */
+ if (dev->urbs.count > 0)
+ ufx_free_urb_list(dev);
+
+ pr_debug("freeing ufx_data %p", dev);
+
+ kfree(dev);
+}
+
+static void ufx_release_urb_work(struct work_struct *work)
+{
+ struct urb_node *unode = container_of(work, struct urb_node,
+ release_urb_work.work);
+
+ up(&unode->dev->urbs.limit_sem);
+}
+
+static void ufx_free_framebuffer_work(struct work_struct *work)
+{
+ struct ufx_data *dev = container_of(work, struct ufx_data,
+ free_framebuffer_work.work);
+ struct fb_info *info = dev->info;
+ int node = info->node;
+
+ unregister_framebuffer(info);
+
+ if (info->cmap.len != 0)
+ fb_dealloc_cmap(&info->cmap);
+ if (info->monspecs.modedb)
+ fb_destroy_modedb(info->monspecs.modedb);
+ if (info->screen_base)
+ vfree(info->screen_base);
+
+ fb_destroy_modelist(&info->modelist);
+
+ dev->info = 0;
+
+ /* Assume info structure is freed after this point */
+ framebuffer_release(info);
+
+ pr_debug("fb_info for /dev/fb%d has been freed", node);
+
+ /* ref taken in probe() as part of registering framebfufer */
+ kref_put(&dev->kref, ufx_free);
+}
+
+/*
+ * Assumes caller is holding info->lock mutex (for open and release at least)
+ */
+static int ufx_ops_release(struct fb_info *info, int user)
+{
+ struct ufx_data *dev = info->par;
+
+ dev->fb_count--;
+
+ /* We can't free fb_info here - fbmem will touch it when we return */
+ if (dev->virtualized && (dev->fb_count == 0))
+ schedule_delayed_work(&dev->free_framebuffer_work, HZ);
+
+ if ((dev->fb_count == 0) && (info->fbdefio)) {
+ fb_deferred_io_cleanup(info);
+ kfree(info->fbdefio);
+ info->fbdefio = NULL;
+ info->fbops->fb_mmap = ufx_ops_mmap;
+ }
+
+ pr_debug("released /dev/fb%d user=%d count=%d",
+ info->node, user, dev->fb_count);
+
+ kref_put(&dev->kref, ufx_free);
+
+ return 0;
+}
+
+/* Check whether a video mode is supported by the chip
+ * We start from monitor's modes, so don't need to filter that here */
+static int ufx_is_valid_mode(struct fb_videomode *mode,
+ struct fb_info *info)
+{
+ if ((mode->xres * mode->yres) > (2048 * 1152)) {
+ pr_debug("%dx%d too many pixels",
+ mode->xres, mode->yres);
+ return 0;
+ }
+
+ if (mode->pixclock < 5000) {
+ pr_debug("%dx%d %dps pixel clock too fast",
+ mode->xres, mode->yres, mode->pixclock);
+ return 0;
+ }
+
+ pr_debug("%dx%d (pixclk %dps %dMHz) valid mode", mode->xres, mode->yres,
+ mode->pixclock, (1000000 / mode->pixclock));
+ return 1;
+}
+
+static void ufx_var_color_format(struct fb_var_screeninfo *var)
+{
+ const struct fb_bitfield red = { 11, 5, 0 };
+ const struct fb_bitfield green = { 5, 6, 0 };
+ const struct fb_bitfield blue = { 0, 5, 0 };
+
+ var->bits_per_pixel = 16;
+ var->red = red;
+ var->green = green;
+ var->blue = blue;
+}
+
+static int ufx_ops_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct fb_videomode mode;
+
+ /* TODO: support dynamically changing framebuffer size */
+ if ((var->xres * var->yres * 2) > info->fix.smem_len)
+ return -EINVAL;
+
+ /* set device-specific elements of var unrelated to mode */
+ ufx_var_color_format(var);
+
+ fb_var_to_videomode(&mode, var);
+
+ if (!ufx_is_valid_mode(&mode, info))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int ufx_ops_set_par(struct fb_info *info)
+{
+ struct ufx_data *dev = info->par;
+ int result;
+ u16 *pix_framebuffer;
+ int i;
+
+ pr_debug("set_par mode %dx%d", info->var.xres, info->var.yres);
+ result = ufx_set_vid_mode(dev, &info->var);
+
+ if ((result == 0) && (dev->fb_count == 0)) {
+ /* paint greenscreen */
+ pix_framebuffer = (u16 *) info->screen_base;
+ for (i = 0; i < info->fix.smem_len / 2; i++)
+ pix_framebuffer[i] = 0x37e6;
+
+ ufx_handle_damage(dev, 0, 0, info->var.xres, info->var.yres);
+ }
+
+ /* re-enable defio if previously disabled by damage tracking */
+ if (info->fbdefio)
+ info->fbdefio->delay = UFX_DEFIO_WRITE_DELAY;
+
+ return result;
+}
+
+/* In order to come back from full DPMS off, we need to set the mode again */
+static int ufx_ops_blank(int blank_mode, struct fb_info *info)
+{
+ struct ufx_data *dev = info->par;
+ ufx_set_vid_mode(dev, &info->var);
+ return 0;
+}
+
+static struct fb_ops ufx_ops = {
+ .owner = THIS_MODULE,
+ .fb_read = fb_sys_read,
+ .fb_write = ufx_ops_write,
+ .fb_setcolreg = ufx_ops_setcolreg,
+ .fb_fillrect = ufx_ops_fillrect,
+ .fb_copyarea = ufx_ops_copyarea,
+ .fb_imageblit = ufx_ops_imageblit,
+ .fb_mmap = ufx_ops_mmap,
+ .fb_ioctl = ufx_ops_ioctl,
+ .fb_open = ufx_ops_open,
+ .fb_release = ufx_ops_release,
+ .fb_blank = ufx_ops_blank,
+ .fb_check_var = ufx_ops_check_var,
+ .fb_set_par = ufx_ops_set_par,
+};
+
+/* Assumes &info->lock held by caller
+ * Assumes no active clients have framebuffer open */
+static int ufx_realloc_framebuffer(struct ufx_data *dev, struct fb_info *info)
+{
+ int retval = -ENOMEM;
+ int old_len = info->fix.smem_len;
+ int new_len;
+ unsigned char *old_fb = info->screen_base;
+ unsigned char *new_fb;
+
+ pr_debug("Reallocating framebuffer. Addresses will change!");
+
+ new_len = info->fix.line_length * info->var.yres;
+
+ if (PAGE_ALIGN(new_len) > old_len) {
+ /*
+ * Alloc system memory for virtual framebuffer
+ */
+ new_fb = vmalloc(new_len);
+ if (!new_fb) {
+ pr_err("Virtual framebuffer alloc failed");
+ goto error;
+ }
+
+ if (info->screen_base) {
+ memcpy(new_fb, old_fb, old_len);
+ vfree(info->screen_base);
+ }
+
+ info->screen_base = new_fb;
+ info->fix.smem_len = PAGE_ALIGN(new_len);
+ info->fix.smem_start = (unsigned long) new_fb;
+ info->flags = smscufx_info_flags;
+ }
+
+ retval = 0;
+
+error:
+ return retval;
+}
+
+/* sets up I2C Controller for 100 Kbps, std. speed, 7-bit addr, master,
+ * restart enabled, but no start byte, enable controller */
+static int ufx_i2c_init(struct ufx_data *dev)
+{
+ u32 tmp;
+
+ /* disable the controller before it can be reprogrammed */
+ int status = ufx_reg_write(dev, 0x106C, 0x00);
+ check_warn_return(status, "failed to disable I2C");
+
+ /* Setup the clock count registers
+ * (12+1) = 13 clks @ 2.5 MHz = 5.2 uS */
+ status = ufx_reg_write(dev, 0x1018, 12);
+ check_warn_return(status, "error writing 0x1018");
+
+ /* (6+8) = 14 clks @ 2.5 MHz = 5.6 uS */
+ status = ufx_reg_write(dev, 0x1014, 6);
+ check_warn_return(status, "error writing 0x1014");
+
+ status = ufx_reg_read(dev, 0x1000, &tmp);
+ check_warn_return(status, "error reading 0x1000");
+
+ /* set speed to std mode */
+ tmp &= ~(0x06);
+ tmp |= 0x02;
+
+ /* 7-bit (not 10-bit) addressing */
+ tmp &= ~(0x10);
+
+ /* enable restart conditions and master mode */
+ tmp |= 0x21;
+
+ status = ufx_reg_write(dev, 0x1000, tmp);
+ check_warn_return(status, "error writing 0x1000");
+
+ /* Set normal tx using target address 0 */
+ status = ufx_reg_clear_and_set_bits(dev, 0x1004, 0xC00, 0x000);
+ check_warn_return(status, "error setting TX mode bits in 0x1004");
+
+ /* Enable the controller */
+ status = ufx_reg_write(dev, 0x106C, 0x01);
+ check_warn_return(status, "failed to enable I2C");
+
+ return 0;
+}
+
+/* sets the I2C port mux and target address */
+static int ufx_i2c_configure(struct ufx_data *dev)
+{
+ int status = ufx_reg_write(dev, 0x106C, 0x00);
+ check_warn_return(status, "failed to disable I2C");
+
+ status = ufx_reg_write(dev, 0x3010, 0x00000000);
+ check_warn_return(status, "failed to write 0x3010");
+
+ /* A0h is std for any EDID, right shifted by one */
+ status = ufx_reg_clear_and_set_bits(dev, 0x1004, 0x3FF, (0xA0 >> 1));
+ check_warn_return(status, "failed to set TAR bits in 0x1004");
+
+ status = ufx_reg_write(dev, 0x106C, 0x01);
+ check_warn_return(status, "failed to enable I2C");
+
+ return 0;
+}
+
+/* wait for BUSY to clear, with a timeout of 50ms with 10ms sleeps. if no
+ * monitor is connected, there is no error except for timeout */
+static int ufx_i2c_wait_busy(struct ufx_data *dev)
+{
+ u32 tmp;
+ int i, status;
+
+ for (i = 0; i < 15; i++) {
+ status = ufx_reg_read(dev, 0x1100, &tmp);
+ check_warn_return(status, "0x1100 read failed");
+
+ /* if BUSY is clear, check for error */
+ if ((tmp & 0x80000000) == 0) {
+ if (tmp & 0x20000000) {
+ pr_warn("I2C read failed, 0x1100=0x%08x", tmp);
+ return -EIO;
+ }
+
+ return 0;
+ }
+
+ /* perform the first 10 retries without delay */
+ if (i >= 10)
+ msleep(10);
+ }
+
+ pr_warn("I2C access timed out, resetting I2C hardware");
+ status = ufx_reg_write(dev, 0x1100, 0x40000000);
+ check_warn_return(status, "0x1100 write failed");
+
+ return -ETIMEDOUT;
+}
+
+/* reads a 128-byte EDID block from the currently selected port and TAR */
+static int ufx_read_edid(struct ufx_data *dev, u8 *edid, int edid_len)
+{
+ int i, j, status;
+ u32 *edid_u32 = (u32 *)edid;
+
+ BUG_ON(edid_len != EDID_LENGTH);
+
+ status = ufx_i2c_configure(dev);
+ if (status < 0) {
+ pr_err("ufx_i2c_configure failed");
+ return status;
+ }
+
+ memset(edid, 0xff, EDID_LENGTH);
+
+ /* Read the 128-byte EDID as 2 bursts of 64 bytes */
+ for (i = 0; i < 2; i++) {
+ u32 temp = 0x28070000 | (63 << 20) | (((u32)(i * 64)) << 8);
+ status = ufx_reg_write(dev, 0x1100, temp);
+ check_warn_return(status, "Failed to write 0x1100");
+
+ temp |= 0x80000000;
+ status = ufx_reg_write(dev, 0x1100, temp);
+ check_warn_return(status, "Failed to write 0x1100");
+
+ status = ufx_i2c_wait_busy(dev);
+ check_warn_return(status, "Timeout waiting for I2C BUSY to clear");
+
+ for (j = 0; j < 16; j++) {
+ u32 data_reg_addr = 0x1110 + (j * 4);
+ status = ufx_reg_read(dev, data_reg_addr, edid_u32++);
+ check_warn_return(status, "Error reading i2c data");
+ }
+ }
+
+ /* all FF's in the first 16 bytes indicates nothing is connected */
+ for (i = 0; i < 16; i++) {
+ if (edid[i] != 0xFF) {
+ pr_debug("edid data read succesfully");
+ return EDID_LENGTH;
+ }
+ }
+
+ pr_warn("edid data contains all 0xff");
+ return -ETIMEDOUT;
+}
+
+/* 1) use sw default
+ * 2) Parse into various fb_info structs
+ * 3) Allocate virtual framebuffer memory to back highest res mode
+ *
+ * Parses EDID into three places used by various parts of fbdev:
+ * fb_var_screeninfo contains the timing of the monitor's preferred mode
+ * fb_info.monspecs is full parsed EDID info, including monspecs.modedb
+ * fb_info.modelist is a linked list of all monitor & VESA modes which work
+ *
+ * If EDID is not readable/valid, then modelist is all VESA modes,
+ * monspecs is NULL, and fb_var_screeninfo is set to safe VESA mode
+ * Returns 0 if successful */
+static int ufx_setup_modes(struct ufx_data *dev, struct fb_info *info,
+ char *default_edid, size_t default_edid_size)
+{
+ const struct fb_videomode *default_vmode = NULL;
+ u8 *edid;
+ int i, result = 0, tries = 3;
+
+ if (info->dev) /* only use mutex if info has been registered */
+ mutex_lock(&info->lock);
+
+ edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
+ if (!edid) {
+ result = -ENOMEM;
+ goto error;
+ }
+
+ fb_destroy_modelist(&info->modelist);
+ memset(&info->monspecs, 0, sizeof(info->monspecs));
+
+ /* Try to (re)read EDID from hardware first
+ * EDID data may return, but not parse as valid
+ * Try again a few times, in case of e.g. analog cable noise */
+ while (tries--) {
+ i = ufx_read_edid(dev, edid, EDID_LENGTH);
+
+ if (i >= EDID_LENGTH)
+ fb_edid_to_monspecs(edid, &info->monspecs);
+
+ if (info->monspecs.modedb_len > 0) {
+ dev->edid = edid;
+ dev->edid_size = i;
+ break;
+ }
+ }
+
+ /* If that fails, use a previously returned EDID if available */
+ if (info->monspecs.modedb_len == 0) {
+ pr_err("Unable to get valid EDID from device/display\n");
+
+ if (dev->edid) {
+ fb_edid_to_monspecs(dev->edid, &info->monspecs);
+ if (info->monspecs.modedb_len > 0)
+ pr_err("Using previously queried EDID\n");
+ }
+ }
+
+ /* If that fails, use the default EDID we were handed */
+ if (info->monspecs.modedb_len == 0) {
+ if (default_edid_size >= EDID_LENGTH) {
+ fb_edid_to_monspecs(default_edid, &info->monspecs);
+ if (info->monspecs.modedb_len > 0) {
+ memcpy(edid, default_edid, default_edid_size);
+ dev->edid = edid;
+ dev->edid_size = default_edid_size;
+ pr_err("Using default/backup EDID\n");
+ }
+ }
+ }
+
+ /* If we've got modes, let's pick a best default mode */
+ if (info->monspecs.modedb_len > 0) {
+
+ for (i = 0; i < info->monspecs.modedb_len; i++) {
+ if (ufx_is_valid_mode(&info->monspecs.modedb[i], info))
+ fb_add_videomode(&info->monspecs.modedb[i],
+ &info->modelist);
+ else /* if we've removed top/best mode */
+ info->monspecs.misc &= ~FB_MISC_1ST_DETAIL;
+ }
+
+ default_vmode = fb_find_best_display(&info->monspecs,
+ &info->modelist);
+ }
+
+ /* If everything else has failed, fall back to safe default mode */
+ if (default_vmode == NULL) {
+
+ struct fb_videomode fb_vmode = {0};
+
+ /* Add the standard VESA modes to our modelist
+ * Since we don't have EDID, there may be modes that
+ * overspec monitor and/or are incorrect aspect ratio, etc.
+ * But at least the user has a chance to choose
+ */
+ for (i = 0; i < VESA_MODEDB_SIZE; i++) {
+ if (ufx_is_valid_mode((struct fb_videomode *)
+ &vesa_modes[i], info))
+ fb_add_videomode(&vesa_modes[i],
+ &info->modelist);
+ }
+
+ /* default to resolution safe for projectors
+ * (since they are most common case without EDID)
+ */
+ fb_vmode.xres = 800;
+ fb_vmode.yres = 600;
+ fb_vmode.refresh = 60;
+ default_vmode = fb_find_nearest_mode(&fb_vmode,
+ &info->modelist);
+ }
+
+ /* If we have good mode and no active clients */
+ if ((default_vmode != NULL) && (dev->fb_count == 0)) {
+
+ fb_videomode_to_var(&info->var, default_vmode);
+ ufx_var_color_format(&info->var);
+
+ /* with mode size info, we can now alloc our framebuffer */
+ memcpy(&info->fix, &ufx_fix, sizeof(ufx_fix));
+ info->fix.line_length = info->var.xres *
+ (info->var.bits_per_pixel / 8);
+
+ result = ufx_realloc_framebuffer(dev, info);
+
+ } else
+ result = -EINVAL;
+
+error:
+ if (edid && (dev->edid != edid))
+ kfree(edid);
+
+ if (info->dev)
+ mutex_unlock(&info->lock);
+
+ return result;
+}
+
+static int ufx_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *usbdev;
+ struct ufx_data *dev;
+ struct fb_info *info = 0;
+ int retval = -ENOMEM;
+ u32 id_rev, fpga_rev;
+
+ /* usb initialization */
+ usbdev = interface_to_usbdev(interface);
+ BUG_ON(!usbdev);
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&usbdev->dev, "ufx_usb_probe: failed alloc of dev struct\n");
+ goto error;
+ }
+
+ /* we need to wait for both usb and fbdev to spin down on disconnect */
+ kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */
+ kref_get(&dev->kref); /* matching kref_put in free_framebuffer_work */
+
+ dev->udev = usbdev;
+ dev->gdev = &usbdev->dev; /* our generic struct device * */
+ usb_set_intfdata(interface, dev);
+
+ dev_dbg(dev->gdev, "%s %s - serial #%s\n",
+ usbdev->manufacturer, usbdev->product, usbdev->serial);
+ dev_dbg(dev->gdev, "vid_%04x&pid_%04x&rev_%04x driver's ufx_data struct at %p\n",
+ usbdev->descriptor.idVendor, usbdev->descriptor.idProduct,
+ usbdev->descriptor.bcdDevice, dev);
+ dev_dbg(dev->gdev, "console enable=%d\n", console);
+ dev_dbg(dev->gdev, "fb_defio enable=%d\n", fb_defio);
+
+ if (!ufx_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
+ retval = -ENOMEM;
+ dev_err(dev->gdev, "ufx_alloc_urb_list failed\n");
+ goto error;
+ }
+
+ /* We don't register a new USB class. Our client interface is fbdev */
+
+ /* allocates framebuffer driver structure, not framebuffer memory */
+ info = framebuffer_alloc(0, &usbdev->dev);
+ if (!info) {
+ retval = -ENOMEM;
+ dev_err(dev->gdev, "framebuffer_alloc failed\n");
+ goto error;
+ }
+
+ dev->info = info;
+ info->par = dev;
+ info->pseudo_palette = dev->pseudo_palette;
+ info->fbops = &ufx_ops;
+
+ retval = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (retval < 0) {
+ dev_err(dev->gdev, "fb_alloc_cmap failed %x\n", retval);
+ goto error;
+ }
+
+ INIT_DELAYED_WORK(&dev->free_framebuffer_work,
+ ufx_free_framebuffer_work);
+
+ INIT_LIST_HEAD(&info->modelist);
+
+ retval = ufx_reg_read(dev, 0x3000, &id_rev);
+ check_warn_goto_error(retval, "error %d reading 0x3000 register from device", retval);
+ dev_dbg(dev->gdev, "ID_REV register value 0x%08x", id_rev);
+
+ retval = ufx_reg_read(dev, 0x3004, &fpga_rev);
+ check_warn_goto_error(retval, "error %d reading 0x3004 register from device", retval);
+ dev_dbg(dev->gdev, "FPGA_REV register value 0x%08x", fpga_rev);
+
+ dev_dbg(dev->gdev, "resetting device");
+ retval = ufx_lite_reset(dev);
+ check_warn_goto_error(retval, "error %d resetting device", retval);
+
+ dev_dbg(dev->gdev, "configuring system clock");
+ retval = ufx_config_sys_clk(dev);
+ check_warn_goto_error(retval, "error %d configuring system clock", retval);
+
+ dev_dbg(dev->gdev, "configuring DDR2 controller");
+ retval = ufx_config_ddr2(dev);
+ check_warn_goto_error(retval, "error %d initialising DDR2 controller", retval);
+
+ dev_dbg(dev->gdev, "configuring I2C controller");
+ retval = ufx_i2c_init(dev);
+ check_warn_goto_error(retval, "error %d initialising I2C controller", retval);
+
+ dev_dbg(dev->gdev, "selecting display mode");
+ retval = ufx_setup_modes(dev, info, NULL, 0);
+ check_warn_goto_error(retval, "unable to find common mode for display and adapter");
+
+ retval = ufx_reg_set_bits(dev, 0x4000, 0x00000001);
+ check_warn_goto_error(retval, "error %d enabling graphics engine", retval);
+
+ /* ready to begin using device */
+ atomic_set(&dev->usb_active, 1);
+
+ dev_dbg(dev->gdev, "checking var");
+ retval = ufx_ops_check_var(&info->var, info);
+ check_warn_goto_error(retval, "error %d ufx_ops_check_var", retval);
+
+ dev_dbg(dev->gdev, "setting par");
+ retval = ufx_ops_set_par(info);
+ check_warn_goto_error(retval, "error %d ufx_ops_set_par", retval);
+
+ dev_dbg(dev->gdev, "registering framebuffer");
+ retval = register_framebuffer(info);
+ check_warn_goto_error(retval, "error %d register_framebuffer", retval);
+
+ dev_info(dev->gdev, "SMSC UDX USB device /dev/fb%d attached. %dx%d resolution."
+ " Using %dK framebuffer memory\n", info->node,
+ info->var.xres, info->var.yres, info->fix.smem_len >> 10);
+
+ return 0;
+
+error:
+ if (dev) {
+ if (info) {
+ if (info->cmap.len != 0)
+ fb_dealloc_cmap(&info->cmap);
+ if (info->monspecs.modedb)
+ fb_destroy_modedb(info->monspecs.modedb);
+ if (info->screen_base)
+ vfree(info->screen_base);
+
+ fb_destroy_modelist(&info->modelist);
+
+ framebuffer_release(info);
+ }
+
+ kref_put(&dev->kref, ufx_free); /* ref for framebuffer */
+ kref_put(&dev->kref, ufx_free); /* last ref from kref_init */
+
+ /* dev has been deallocated. Do not dereference */
+ }
+
+ return retval;
+}
+
+static void ufx_usb_disconnect(struct usb_interface *interface)
+{
+ struct ufx_data *dev;
+ struct fb_info *info;
+
+ dev = usb_get_intfdata(interface);
+ info = dev->info;
+
+ pr_debug("USB disconnect starting\n");
+
+ /* we virtualize until all fb clients release. Then we free */
+ dev->virtualized = true;
+
+ /* When non-active we'll update virtual framebuffer, but no new urbs */
+ atomic_set(&dev->usb_active, 0);
+
+ usb_set_intfdata(interface, NULL);
+
+ /* if clients still have us open, will be freed on last close */
+ if (dev->fb_count == 0)
+ schedule_delayed_work(&dev->free_framebuffer_work, 0);
+
+ /* release reference taken by kref_init in probe() */
+ kref_put(&dev->kref, ufx_free);
+
+ /* consider ufx_data freed */
+}
+
+static struct usb_driver ufx_driver = {
+ .name = "smscufx",
+ .probe = ufx_usb_probe,
+ .disconnect = ufx_usb_disconnect,
+ .id_table = id_table,
+};
+
+static int __init ufx_module_init(void)
+{
+ int res;
+
+ res = usb_register(&ufx_driver);
+ if (res)
+ err("usb_register failed. Error number %d", res);
+
+ return res;
+}
+
+static void __exit ufx_module_exit(void)
+{
+ usb_deregister(&ufx_driver);
+}
+
+module_init(ufx_module_init);
+module_exit(ufx_module_exit);
+
+static void ufx_urb_completion(struct urb *urb)
+{
+ struct urb_node *unode = urb->context;
+ struct ufx_data *dev = unode->dev;
+ unsigned long flags;
+
+ /* sync/async unlink faults aren't errors */
+ if (urb->status) {
+ if (!(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN)) {
+ pr_err("%s - nonzero write bulk status received: %d\n",
+ __func__, urb->status);
+ atomic_set(&dev->lost_pixels, 1);
+ }
+ }
+
+ urb->transfer_buffer_length = dev->urbs.size; /* reset to actual */
+
+ spin_lock_irqsave(&dev->urbs.lock, flags);
+ list_add_tail(&unode->entry, &dev->urbs.list);
+ dev->urbs.available++;
+ spin_unlock_irqrestore(&dev->urbs.lock, flags);
+
+ /* When using fb_defio, we deadlock if up() is called
+ * while another is waiting. So queue to another process */
+ if (fb_defio)
+ schedule_delayed_work(&unode->release_urb_work, 0);
+ else
+ up(&dev->urbs.limit_sem);
+}
+
+static void ufx_free_urb_list(struct ufx_data *dev)
+{
+ int count = dev->urbs.count;
+ struct list_head *node;
+ struct urb_node *unode;
+ struct urb *urb;
+ int ret;
+ unsigned long flags;
+
+ pr_debug("Waiting for completes and freeing all render urbs\n");
+
+ /* keep waiting and freeing, until we've got 'em all */
+ while (count--) {
+ /* Getting interrupted means a leak, but ok at shutdown*/
+ ret = down_interruptible(&dev->urbs.limit_sem);
+ if (ret)
+ break;
+
+ spin_lock_irqsave(&dev->urbs.lock, flags);
+
+ node = dev->urbs.list.next; /* have reserved one with sem */
+ list_del_init(node);
+
+ spin_unlock_irqrestore(&dev->urbs.lock, flags);
+
+ unode = list_entry(node, struct urb_node, entry);
+ urb = unode->urb;
+
+ /* Free each separately allocated piece */
+ usb_free_coherent(urb->dev, dev->urbs.size,
+ urb->transfer_buffer, urb->transfer_dma);
+ usb_free_urb(urb);
+ kfree(node);
+ }
+}
+
+static int ufx_alloc_urb_list(struct ufx_data *dev, int count, size_t size)
+{
+ int i = 0;
+ struct urb *urb;
+ struct urb_node *unode;
+ char *buf;
+
+ spin_lock_init(&dev->urbs.lock);
+
+ dev->urbs.size = size;
+ INIT_LIST_HEAD(&dev->urbs.list);
+
+ while (i < count) {
+ unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL);
+ if (!unode)
+ break;
+ unode->dev = dev;
+
+ INIT_DELAYED_WORK(&unode->release_urb_work,
+ ufx_release_urb_work);
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ kfree(unode);
+ break;
+ }
+ unode->urb = urb;
+
+ buf = usb_alloc_coherent(dev->udev, size, GFP_KERNEL,
+ &urb->transfer_dma);
+ if (!buf) {
+ kfree(unode);
+ usb_free_urb(urb);
+ break;
+ }
+
+ /* urb->transfer_buffer_length set to actual before submit */
+ usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 1),
+ buf, size, ufx_urb_completion, unode);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ list_add_tail(&unode->entry, &dev->urbs.list);
+
+ i++;
+ }
+
+ sema_init(&dev->urbs.limit_sem, i);
+ dev->urbs.count = i;
+ dev->urbs.available = i;
+
+ pr_debug("allocated %d %d byte urbs\n", i, (int) size);
+
+ return i;
+}
+
+static struct urb *ufx_get_urb(struct ufx_data *dev)
+{
+ int ret = 0;
+ struct list_head *entry;
+ struct urb_node *unode;
+ struct urb *urb = NULL;
+ unsigned long flags;
+
+ /* Wait for an in-flight buffer to complete and get re-queued */
+ ret = down_timeout(&dev->urbs.limit_sem, GET_URB_TIMEOUT);
+ if (ret) {
+ atomic_set(&dev->lost_pixels, 1);
+ pr_warn("wait for urb interrupted: %x available: %d\n",
+ ret, dev->urbs.available);
+ goto error;
+ }
+
+ spin_lock_irqsave(&dev->urbs.lock, flags);
+
+ BUG_ON(list_empty(&dev->urbs.list)); /* reserved one with limit_sem */
+ entry = dev->urbs.list.next;
+ list_del_init(entry);
+ dev->urbs.available--;
+
+ spin_unlock_irqrestore(&dev->urbs.lock, flags);
+
+ unode = list_entry(entry, struct urb_node, entry);
+ urb = unode->urb;
+
+error:
+ return urb;
+}
+
+static int ufx_submit_urb(struct ufx_data *dev, struct urb *urb, size_t len)
+{
+ int ret;
+
+ BUG_ON(len > dev->urbs.size);
+
+ urb->transfer_buffer_length = len; /* set to actual payload len */
+ ret = usb_submit_urb(urb, GFP_KERNEL);
+ if (ret) {
+ ufx_urb_completion(urb); /* because no one else will */
+ atomic_set(&dev->lost_pixels, 1);
+ pr_err("usb_submit_urb error %x\n", ret);
+ }
+ return ret;
+}
+
+module_param(console, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
+MODULE_PARM_DESC(console, "Allow fbcon to be used on this display");
+
+module_param(fb_defio, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
+MODULE_PARM_DESC(fb_defio, "Enable fb_defio mmap support");
+
+MODULE_AUTHOR("Steve Glendinning <steve.glendinning@smsc.com>");
+MODULE_DESCRIPTION("SMSC UFX kernel framebuffer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c
index cd1c4dc..8e4a446 100644
--- a/drivers/video/tmiofb.c
+++ b/drivers/video/tmiofb.c
@@ -744,7 +744,7 @@ static int __devinit tmiofb_probe(struct platform_device *dev)
goto err_ioremap_vram;
}
- retval = request_irq(irq, &tmiofb_irq, IRQF_DISABLED,
+ retval = request_irq(irq, &tmiofb_irq, 0,
dev_name(&dev->dev), info);
if (retval)
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
index c6c7756..34cf019 100644
--- a/drivers/video/tridentfb.c
+++ b/drivers/video/tridentfb.c
@@ -987,8 +987,8 @@ static int tridentfb_pan_display(struct fb_var_screeninfo *var,
unsigned int offset;
debug("enter\n");
- offset = (var->xoffset + (var->yoffset * var->xres_virtual))
- * var->bits_per_pixel / 32;
+ offset = (var->xoffset + (var->yoffset * info->var.xres_virtual))
+ * info->var.bits_per_pixel / 32;
set_screen_start(par, offset);
debug("exit\n");
return 0;
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
index 087fc99..3473e75 100644
--- a/drivers/video/udlfb.c
+++ b/drivers/video/udlfb.c
@@ -48,20 +48,30 @@ static const u32 udlfb_info_flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR;
/*
- * There are many DisplayLink-based products, all with unique PIDs. We are able
- * to support all volume ones (circa 2009) with a single driver, so we match
- * globally on VID. TODO: Probe() needs to detect when we might be running
- * "future" chips, and bail on those, so a compatible driver can match.
+ * There are many DisplayLink-based graphics products, all with unique PIDs.
+ * So we match on DisplayLink's VID + Vendor-Defined Interface Class (0xff)
+ * We also require a match on SubClass (0x00) and Protocol (0x00),
+ * which is compatible with all known USB 2.0 era graphics chips and firmware,
+ * but allows DisplayLink to increment those for any future incompatible chips
*/
static struct usb_device_id id_table[] = {
- {.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,},
+ {.idVendor = 0x17e9,
+ .bInterfaceClass = 0xff,
+ .bInterfaceSubClass = 0x00,
+ .bInterfaceProtocol = 0x00,
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
+ USB_DEVICE_ID_MATCH_INT_CLASS |
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS |
+ USB_DEVICE_ID_MATCH_INT_PROTOCOL,
+ },
{},
};
MODULE_DEVICE_TABLE(usb, id_table);
/* module options */
-static int console; /* Optionally allow fbcon to consume first framebuffer */
-static int fb_defio; /* Optionally enable experimental fb_defio mmap support */
+static int console = 1; /* Allow fbcon to open framebuffer */
+static int fb_defio = 1; /* Detect mmap writes using page faults */
+static int shadow = 1; /* Optionally disable shadow framebuffer */
/* dlfb keeps a list of urbs for efficient bulk transfers */
static void dlfb_urb_completion(struct urb *urb);
@@ -94,17 +104,39 @@ static char *dlfb_vidreg_unlock(char *buf)
}
/*
- * On/Off for driving the DisplayLink framebuffer to the display
- * 0x00 H and V sync on
- * 0x01 H and V sync off (screen blank but powered)
- * 0x07 DPMS powerdown (requires modeset to come back)
+ * Map FB_BLANK_* to DisplayLink register
+ * DLReg FB_BLANK_*
+ * ----- -----------------------------
+ * 0x00 FB_BLANK_UNBLANK (0)
+ * 0x01 FB_BLANK (1)
+ * 0x03 FB_BLANK_VSYNC_SUSPEND (2)
+ * 0x05 FB_BLANK_HSYNC_SUSPEND (3)
+ * 0x07 FB_BLANK_POWERDOWN (4) Note: requires modeset to come back
*/
-static char *dlfb_enable_hvsync(char *buf, bool enable)
+static char *dlfb_blanking(char *buf, int fb_blank)
{
- if (enable)
- return dlfb_set_register(buf, 0x1F, 0x00);
- else
- return dlfb_set_register(buf, 0x1F, 0x07);
+ u8 reg;
+
+ switch (fb_blank) {
+ case FB_BLANK_POWERDOWN:
+ reg = 0x07;
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ reg = 0x05;
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ reg = 0x03;
+ break;
+ case FB_BLANK_NORMAL:
+ reg = 0x01;
+ break;
+ default:
+ reg = 0x00;
+ }
+
+ buf = dlfb_set_register(buf, 0x1F, reg);
+
+ return buf;
}
static char *dlfb_set_color_depth(char *buf, u8 selection)
@@ -272,13 +304,15 @@ static int dlfb_set_video_mode(struct dlfb_data *dev,
wrptr = dlfb_set_base8bpp(wrptr, dev->info->fix.smem_len);
wrptr = dlfb_set_vid_cmds(wrptr, var);
- wrptr = dlfb_enable_hvsync(wrptr, true);
+ wrptr = dlfb_blanking(wrptr, FB_BLANK_UNBLANK);
wrptr = dlfb_vidreg_unlock(wrptr);
writesize = wrptr - buf;
retval = dlfb_submit_urb(dev, urb, writesize);
+ dev->blank_mode = FB_BLANK_UNBLANK;
+
return retval;
}
@@ -752,14 +786,13 @@ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
{
struct dlfb_data *dev = info->par;
- struct dloarea *area = NULL;
if (!atomic_read(&dev->usb_active))
return 0;
/* TODO: Update X server to get this from sysfs instead */
if (cmd == DLFB_IOCTL_RETURN_EDID) {
- char *edid = (char *)arg;
+ void __user *edid = (void __user *)arg;
if (copy_to_user(edid, dev->edid, dev->edid_size))
return -EFAULT;
return 0;
@@ -767,6 +800,11 @@ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
/* TODO: Help propose a standard fb.h ioctl to report mmap damage */
if (cmd == DLFB_IOCTL_REPORT_DAMAGE) {
+ struct dloarea area;
+
+ if (copy_from_user(&area, (void __user *)arg,
+ sizeof(struct dloarea)))
+ return -EFAULT;
/*
* If we have a damage-aware client, turn fb_defio "off"
@@ -778,21 +816,19 @@ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
if (info->fbdefio)
info->fbdefio->delay = DL_DEFIO_WRITE_DISABLE;
- area = (struct dloarea *)arg;
+ if (area.x < 0)
+ area.x = 0;
- if (area->x < 0)
- area->x = 0;
+ if (area.x > info->var.xres)
+ area.x = info->var.xres;
- if (area->x > info->var.xres)
- area->x = info->var.xres;
+ if (area.y < 0)
+ area.y = 0;
- if (area->y < 0)
- area->y = 0;
+ if (area.y > info->var.yres)
+ area.y = info->var.yres;
- if (area->y > info->var.yres)
- area->y = info->var.yres;
-
- dlfb_handle_damage(dev, area->x, area->y, area->w, area->h,
+ dlfb_handle_damage(dev, area.x, area.y, area.w, area.h,
info->screen_base);
}
@@ -840,7 +876,7 @@ static int dlfb_ops_open(struct fb_info *info, int user)
* preventing other clients (X) from working properly. Usually
* not what the user wants. Fail by default with option to enable.
*/
- if ((user == 0) & (!console))
+ if ((user == 0) && (!console))
return -EBUSY;
/* If the USB device is gone, we don't accept new opens */
@@ -1039,32 +1075,57 @@ static int dlfb_ops_set_par(struct fb_info *info)
return result;
}
+/* To fonzi the jukebox (e.g. make blanking changes take effect) */
+static char *dlfb_dummy_render(char *buf)
+{
+ *buf++ = 0xAF;
+ *buf++ = 0x6A; /* copy */
+ *buf++ = 0x00; /* from address*/
+ *buf++ = 0x00;
+ *buf++ = 0x00;
+ *buf++ = 0x01; /* one pixel */
+ *buf++ = 0x00; /* to address */
+ *buf++ = 0x00;
+ *buf++ = 0x00;
+ return buf;
+}
+
/*
* In order to come back from full DPMS off, we need to set the mode again
*/
static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
{
struct dlfb_data *dev = info->par;
+ char *bufptr;
+ struct urb *urb;
- if (blank_mode != FB_BLANK_UNBLANK) {
- char *bufptr;
- struct urb *urb;
-
- urb = dlfb_get_urb(dev);
- if (!urb)
- return 0;
+ pr_info("/dev/fb%d FB_BLANK mode %d --> %d\n",
+ info->node, dev->blank_mode, blank_mode);
- bufptr = (char *) urb->transfer_buffer;
- bufptr = dlfb_vidreg_lock(bufptr);
- bufptr = dlfb_enable_hvsync(bufptr, false);
- bufptr = dlfb_vidreg_unlock(bufptr);
+ if ((dev->blank_mode == FB_BLANK_POWERDOWN) &&
+ (blank_mode != FB_BLANK_POWERDOWN)) {
- dlfb_submit_urb(dev, urb, bufptr -
- (char *) urb->transfer_buffer);
- } else {
+ /* returning from powerdown requires a fresh modeset */
dlfb_set_video_mode(dev, &info->var);
}
+ urb = dlfb_get_urb(dev);
+ if (!urb)
+ return 0;
+
+ bufptr = (char *) urb->transfer_buffer;
+ bufptr = dlfb_vidreg_lock(bufptr);
+ bufptr = dlfb_blanking(bufptr, blank_mode);
+ bufptr = dlfb_vidreg_unlock(bufptr);
+
+ /* seems like a render op is needed to have blank change take effect */
+ bufptr = dlfb_dummy_render(bufptr);
+
+ dlfb_submit_urb(dev, urb, bufptr -
+ (char *) urb->transfer_buffer);
+
+ dev->blank_mode = blank_mode;
+
return 0;
}
@@ -1097,7 +1158,7 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dev, struct fb_info *info)
int new_len;
unsigned char *old_fb = info->screen_base;
unsigned char *new_fb;
- unsigned char *new_back;
+ unsigned char *new_back = 0;
pr_warn("Reallocating framebuffer. Addresses will change!\n");
@@ -1129,7 +1190,8 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dev, struct fb_info *info)
* But with imperfect damage info we may send pixels over USB
* that were, in fact, unchanged - wasting limited USB bandwidth
*/
- new_back = vzalloc(new_len);
+ if (shadow)
+ new_back = vzalloc(new_len);
if (!new_back)
pr_info("No shadow/backing buffer allocated\n");
else {
@@ -1430,21 +1492,30 @@ static int dlfb_select_std_channel(struct dlfb_data *dev)
}
static int dlfb_parse_vendor_descriptor(struct dlfb_data *dev,
- struct usb_device *usbdev)
+ struct usb_interface *interface)
{
char *desc;
char *buf;
char *desc_end;
- u8 total_len = 0;
+ int total_len = 0;
buf = kzalloc(MAX_VENDOR_DESCRIPTOR_SIZE, GFP_KERNEL);
if (!buf)
return false;
desc = buf;
- total_len = usb_get_descriptor(usbdev, 0x5f, /* vendor specific */
- 0, desc, MAX_VENDOR_DESCRIPTOR_SIZE);
+ total_len = usb_get_descriptor(interface_to_usbdev(interface),
+ 0x5f, /* vendor specific */
+ 0, desc, MAX_VENDOR_DESCRIPTOR_SIZE);
+
+ /* if not found, look in configuration descriptor */
+ if (total_len < 0) {
+ if (0 == usb_get_extra_descriptor(interface->cur_altsetting,
+ 0x5f, &desc))
+ total_len = (int) desc[0];
+ }
+
if (total_len > 5) {
pr_info("vendor descriptor length:%x data:%02x %02x %02x %02x" \
"%02x %02x %02x %02x %02x %02x %02x\n",
@@ -1485,6 +1556,8 @@ static int dlfb_parse_vendor_descriptor(struct dlfb_data *dev,
}
desc += length;
}
+ } else {
+ pr_info("vendor descriptor not available (%d)\n", total_len);
}
goto success;
@@ -1531,10 +1604,11 @@ static int dlfb_usb_probe(struct usb_interface *interface,
usbdev->descriptor.bcdDevice, dev);
pr_info("console enable=%d\n", console);
pr_info("fb_defio enable=%d\n", fb_defio);
+ pr_info("shadow enable=%d\n", shadow);
dev->sku_pixel_limit = 2048 * 1152; /* default to maximum */
- if (!dlfb_parse_vendor_descriptor(dev, usbdev)) {
+ if (!dlfb_parse_vendor_descriptor(dev, interface)) {
pr_err("firmware not recognized. Assume incompatible device\n");
goto error;
}
@@ -1548,7 +1622,7 @@ static int dlfb_usb_probe(struct usb_interface *interface,
/* We don't register a new USB class. Our client interface is fbdev */
/* allocates framebuffer driver structure, not framebuffer memory */
- info = framebuffer_alloc(0, &usbdev->dev);
+ info = framebuffer_alloc(0, &interface->dev);
if (!info) {
retval = -ENOMEM;
pr_err("framebuffer_alloc failed\n");
@@ -1883,10 +1957,13 @@ static int dlfb_submit_urb(struct dlfb_data *dev, struct urb *urb, size_t len)
}
module_param(console, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
-MODULE_PARM_DESC(console, "Allow fbcon to consume first framebuffer found");
+MODULE_PARM_DESC(console, "Allow fbcon to open framebuffer");
module_param(fb_defio, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
-MODULE_PARM_DESC(fb_defio, "Enable fb_defio mmap support. *Experimental*");
+MODULE_PARM_DESC(fb_defio, "Page fault detection of mmap writes");
+
+module_param(shadow, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
+MODULE_PARM_DESC(shadow, "Shadow vid mem. Disable to save mem but lose perf");
MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, "
"Jaya Kumar <jayakumar.lkml@gmail.com>, "
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
index 6b52bf6..3f5a041 100644
--- a/drivers/video/valkyriefb.c
+++ b/drivers/video/valkyriefb.c
@@ -555,7 +555,7 @@ static int __init valkyrie_init_info(struct fb_info *info,
/*
- * Parse user speficied options (`video=valkyriefb:')
+ * Parse user specified options (`video=valkyriefb:')
*/
int __init valkyriefb_setup(char *options)
{
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index bc67251..bf2f780 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -395,8 +395,8 @@ static int vfb_pan_display(struct fb_var_screeninfo *var,
|| var->xoffset)
return -EINVAL;
} else {
- if (var->xoffset + var->xres > info->var.xres_virtual ||
- var->yoffset + var->yres > info->var.yres_virtual)
+ if (var->xoffset + info->var.xres > info->var.xres_virtual ||
+ var->yoffset + info->var.yres > info->var.yres_virtual)
return -EINVAL;
}
info->var.xoffset = var->xoffset;
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index 305c975..0267acd 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -207,7 +207,7 @@ static void vga16fb_pan_var(struct fb_info *info,
* granularity if someone supports xoffset in bit resolution */
vga_io_r(VGA_IS1_RC); /* reset flip-flop */
vga_io_w(VGA_ATT_IW, VGA_ATC_PEL);
- if (var->bits_per_pixel == 8)
+ if (info->var.bits_per_pixel == 8)
vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1);
else
vga_io_w(VGA_ATT_IW, xoffset & 7);
diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c
index b1f3647..9138e51 100644
--- a/drivers/video/via/dvi.c
+++ b/drivers/video/via/dvi.c
@@ -172,30 +172,20 @@ static int tmds_register_read_bytes(int index, u8 *buff, int buff_len)
}
/* DVI Set Mode */
-void viafb_dvi_set_mode(struct VideoModeTable *mode, int mode_bpp,
- int set_iga)
+void viafb_dvi_set_mode(const struct fb_var_screeninfo *var, int iga)
{
- struct VideoModeTable *rb_mode;
- struct crt_mode_table *pDviTiming;
- unsigned long desirePixelClock, maxPixelClock;
- pDviTiming = mode->crtc;
- desirePixelClock = pDviTiming->refresh_rate
- * pDviTiming->crtc.hor_total * pDviTiming->crtc.ver_total
- / 1000000;
- maxPixelClock = (unsigned long)viaparinfo->
- tmds_setting_info->max_pixel_clock;
-
- DEBUG_MSG(KERN_INFO "\nDVI_set_mode!!\n");
-
- if ((maxPixelClock != 0) && (desirePixelClock > maxPixelClock)) {
- rb_mode = viafb_get_rb_mode(mode->crtc[0].crtc.hor_addr,
- mode->crtc[0].crtc.ver_addr);
- if (rb_mode) {
- mode = rb_mode;
- pDviTiming = rb_mode->crtc;
- }
+ struct fb_var_screeninfo dvi_var = *var;
+ struct crt_mode_table *rb_mode;
+ int maxPixelClock;
+
+ maxPixelClock = viaparinfo->shared->tmds_setting_info.max_pixel_clock;
+ if (maxPixelClock && PICOS2KHZ(var->pixclock) / 1000 > maxPixelClock) {
+ rb_mode = viafb_get_best_rb_mode(var->xres, var->yres, 60);
+ if (rb_mode)
+ viafb_fill_var_timing_info(&dvi_var, rb_mode);
}
- viafb_fill_crtc_timing(pDviTiming, mode, mode_bpp / 8, set_iga);
+
+ viafb_fill_crtc_timing(&dvi_var, iga);
}
/* Sense DVI Connector */
diff --git a/drivers/video/via/dvi.h b/drivers/video/via/dvi.h
index f473dd0..e2116aa 100644
--- a/drivers/video/via/dvi.h
+++ b/drivers/video/via/dvi.h
@@ -59,7 +59,6 @@ void viafb_dvi_enable(void);
bool __devinit viafb_tmds_trasmitter_identify(void);
void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
struct tmds_setting_information *tmds_setting);
-void viafb_dvi_set_mode(struct VideoModeTable *videoMode, int mode_bpp,
- int set_iga);
+void viafb_dvi_set_mode(const struct fb_var_screeninfo *var, int iga);
#endif /* __DVI_H__ */
diff --git a/drivers/video/via/global.c b/drivers/video/via/global.c
index e10d824..3102171 100644
--- a/drivers/video/via/global.c
+++ b/drivers/video/via/global.c
@@ -35,6 +35,8 @@ int viafb_LCD_ON ;
int viafb_LCD2_ON;
int viafb_SAMM_ON;
int viafb_dual_fb;
+unsigned int viafb_second_xres = 640;
+unsigned int viafb_second_yres = 480;
int viafb_hotplug_Xres = 640;
int viafb_hotplug_Yres = 480;
int viafb_hotplug_bpp = 32;
diff --git a/drivers/video/via/global.h b/drivers/video/via/global.h
index ff969dc..275dbbb 100644
--- a/drivers/video/via/global.h
+++ b/drivers/video/via/global.h
@@ -67,6 +67,8 @@ extern int viafb_lcd_dsp_method;
extern int viafb_lcd_mode;
extern int viafb_CRT_ON;
+extern unsigned int viafb_second_xres;
+extern unsigned int viafb_second_yres;
extern int viafb_hotplug_Xres;
extern int viafb_hotplug_Yres;
extern int viafb_hotplug_bpp;
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index 47b1353..d5aaca9 100644
--- a/drivers/video/via/hw.c
+++ b/drivers/video/via/hw.c
@@ -191,67 +191,6 @@ static struct fetch_count fetch_count_reg = {
{IGA2_FETCH_COUNT_REG_NUM, {{CR65, 0, 7}, {CR67, 2, 3} } }
};
-static struct iga1_crtc_timing iga1_crtc_reg = {
- /* IGA1 Horizontal Total */
- {IGA1_HOR_TOTAL_REG_NUM, {{CR00, 0, 7}, {CR36, 3, 3} } },
- /* IGA1 Horizontal Addressable Video */
- {IGA1_HOR_ADDR_REG_NUM, {{CR01, 0, 7} } },
- /* IGA1 Horizontal Blank Start */
- {IGA1_HOR_BLANK_START_REG_NUM, {{CR02, 0, 7} } },
- /* IGA1 Horizontal Blank End */
- {IGA1_HOR_BLANK_END_REG_NUM,
- {{CR03, 0, 4}, {CR05, 7, 7}, {CR33, 5, 5} } },
- /* IGA1 Horizontal Sync Start */
- {IGA1_HOR_SYNC_START_REG_NUM, {{CR04, 0, 7}, {CR33, 4, 4} } },
- /* IGA1 Horizontal Sync End */
- {IGA1_HOR_SYNC_END_REG_NUM, {{CR05, 0, 4} } },
- /* IGA1 Vertical Total */
- {IGA1_VER_TOTAL_REG_NUM,
- {{CR06, 0, 7}, {CR07, 0, 0}, {CR07, 5, 5}, {CR35, 0, 0} } },
- /* IGA1 Vertical Addressable Video */
- {IGA1_VER_ADDR_REG_NUM,
- {{CR12, 0, 7}, {CR07, 1, 1}, {CR07, 6, 6}, {CR35, 2, 2} } },
- /* IGA1 Vertical Blank Start */
- {IGA1_VER_BLANK_START_REG_NUM,
- {{CR15, 0, 7}, {CR07, 3, 3}, {CR09, 5, 5}, {CR35, 3, 3} } },
- /* IGA1 Vertical Blank End */
- {IGA1_VER_BLANK_END_REG_NUM, {{CR16, 0, 7} } },
- /* IGA1 Vertical Sync Start */
- {IGA1_VER_SYNC_START_REG_NUM,
- {{CR10, 0, 7}, {CR07, 2, 2}, {CR07, 7, 7}, {CR35, 1, 1} } },
- /* IGA1 Vertical Sync End */
- {IGA1_VER_SYNC_END_REG_NUM, {{CR11, 0, 3} } }
-};
-
-static struct iga2_crtc_timing iga2_crtc_reg = {
- /* IGA2 Horizontal Total */
- {IGA2_HOR_TOTAL_REG_NUM, {{CR50, 0, 7}, {CR55, 0, 3} } },
- /* IGA2 Horizontal Addressable Video */
- {IGA2_HOR_ADDR_REG_NUM, {{CR51, 0, 7}, {CR55, 4, 6} } },
- /* IGA2 Horizontal Blank Start */
- {IGA2_HOR_BLANK_START_REG_NUM, {{CR52, 0, 7}, {CR54, 0, 2} } },
- /* IGA2 Horizontal Blank End */
- {IGA2_HOR_BLANK_END_REG_NUM,
- {{CR53, 0, 7}, {CR54, 3, 5}, {CR5D, 6, 6} } },
- /* IGA2 Horizontal Sync Start */
- {IGA2_HOR_SYNC_START_REG_NUM,
- {{CR56, 0, 7}, {CR54, 6, 7}, {CR5C, 7, 7}, {CR5D, 7, 7} } },
- /* IGA2 Horizontal Sync End */
- {IGA2_HOR_SYNC_END_REG_NUM, {{CR57, 0, 7}, {CR5C, 6, 6} } },
- /* IGA2 Vertical Total */
- {IGA2_VER_TOTAL_REG_NUM, {{CR58, 0, 7}, {CR5D, 0, 2} } },
- /* IGA2 Vertical Addressable Video */
- {IGA2_VER_ADDR_REG_NUM, {{CR59, 0, 7}, {CR5D, 3, 5} } },
- /* IGA2 Vertical Blank Start */
- {IGA2_VER_BLANK_START_REG_NUM, {{CR5A, 0, 7}, {CR5C, 0, 2} } },
- /* IGA2 Vertical Blank End */
- {IGA2_VER_BLANK_END_REG_NUM, {{CR5B, 0, 7}, {CR5C, 3, 5} } },
- /* IGA2 Vertical Sync Start */
- {IGA2_VER_SYNC_START_REG_NUM, {{CR5E, 0, 7}, {CR5F, 5, 7} } },
- /* IGA2 Vertical Sync End */
- {IGA2_VER_SYNC_END_REG_NUM, {{CR5F, 0, 4} } }
-};
-
static struct rgbLUT palLUT_table[] = {
/* {R,G,B} */
/* Index 0x00~0x03 */
@@ -1528,302 +1467,40 @@ void viafb_set_vclock(u32 clk, int set_iga)
via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */
}
-void viafb_load_crtc_timing(struct display_timing device_timing,
- int set_iga)
+static struct display_timing var_to_timing(const struct fb_var_screeninfo *var)
{
- int i;
- int viafb_load_reg_num = 0;
- int reg_value = 0;
- struct io_register *reg = NULL;
-
- viafb_unlock_crt();
-
- for (i = 0; i < 12; i++) {
- if (set_iga == IGA1) {
- switch (i) {
- case H_TOTAL_INDEX:
- reg_value =
- IGA1_HOR_TOTAL_FORMULA(device_timing.
- hor_total);
- viafb_load_reg_num =
- iga1_crtc_reg.hor_total.reg_num;
- reg = iga1_crtc_reg.hor_total.reg;
- break;
- case H_ADDR_INDEX:
- reg_value =
- IGA1_HOR_ADDR_FORMULA(device_timing.
- hor_addr);
- viafb_load_reg_num =
- iga1_crtc_reg.hor_addr.reg_num;
- reg = iga1_crtc_reg.hor_addr.reg;
- break;
- case H_BLANK_START_INDEX:
- reg_value =
- IGA1_HOR_BLANK_START_FORMULA
- (device_timing.hor_blank_start);
- viafb_load_reg_num =
- iga1_crtc_reg.hor_blank_start.reg_num;
- reg = iga1_crtc_reg.hor_blank_start.reg;
- break;
- case H_BLANK_END_INDEX:
- reg_value =
- IGA1_HOR_BLANK_END_FORMULA
- (device_timing.hor_blank_start,
- device_timing.hor_blank_end);
- viafb_load_reg_num =
- iga1_crtc_reg.hor_blank_end.reg_num;
- reg = iga1_crtc_reg.hor_blank_end.reg;
- break;
- case H_SYNC_START_INDEX:
- reg_value =
- IGA1_HOR_SYNC_START_FORMULA
- (device_timing.hor_sync_start);
- viafb_load_reg_num =
- iga1_crtc_reg.hor_sync_start.reg_num;
- reg = iga1_crtc_reg.hor_sync_start.reg;
- break;
- case H_SYNC_END_INDEX:
- reg_value =
- IGA1_HOR_SYNC_END_FORMULA
- (device_timing.hor_sync_start,
- device_timing.hor_sync_end);
- viafb_load_reg_num =
- iga1_crtc_reg.hor_sync_end.reg_num;
- reg = iga1_crtc_reg.hor_sync_end.reg;
- break;
- case V_TOTAL_INDEX:
- reg_value =
- IGA1_VER_TOTAL_FORMULA(device_timing.
- ver_total);
- viafb_load_reg_num =
- iga1_crtc_reg.ver_total.reg_num;
- reg = iga1_crtc_reg.ver_total.reg;
- break;
- case V_ADDR_INDEX:
- reg_value =
- IGA1_VER_ADDR_FORMULA(device_timing.
- ver_addr);
- viafb_load_reg_num =
- iga1_crtc_reg.ver_addr.reg_num;
- reg = iga1_crtc_reg.ver_addr.reg;
- break;
- case V_BLANK_START_INDEX:
- reg_value =
- IGA1_VER_BLANK_START_FORMULA
- (device_timing.ver_blank_start);
- viafb_load_reg_num =
- iga1_crtc_reg.ver_blank_start.reg_num;
- reg = iga1_crtc_reg.ver_blank_start.reg;
- break;
- case V_BLANK_END_INDEX:
- reg_value =
- IGA1_VER_BLANK_END_FORMULA
- (device_timing.ver_blank_start,
- device_timing.ver_blank_end);
- viafb_load_reg_num =
- iga1_crtc_reg.ver_blank_end.reg_num;
- reg = iga1_crtc_reg.ver_blank_end.reg;
- break;
- case V_SYNC_START_INDEX:
- reg_value =
- IGA1_VER_SYNC_START_FORMULA
- (device_timing.ver_sync_start);
- viafb_load_reg_num =
- iga1_crtc_reg.ver_sync_start.reg_num;
- reg = iga1_crtc_reg.ver_sync_start.reg;
- break;
- case V_SYNC_END_INDEX:
- reg_value =
- IGA1_VER_SYNC_END_FORMULA
- (device_timing.ver_sync_start,
- device_timing.ver_sync_end);
- viafb_load_reg_num =
- iga1_crtc_reg.ver_sync_end.reg_num;
- reg = iga1_crtc_reg.ver_sync_end.reg;
- break;
-
- }
- }
-
- if (set_iga == IGA2) {
- switch (i) {
- case H_TOTAL_INDEX:
- reg_value =
- IGA2_HOR_TOTAL_FORMULA(device_timing.
- hor_total);
- viafb_load_reg_num =
- iga2_crtc_reg.hor_total.reg_num;
- reg = iga2_crtc_reg.hor_total.reg;
- break;
- case H_ADDR_INDEX:
- reg_value =
- IGA2_HOR_ADDR_FORMULA(device_timing.
- hor_addr);
- viafb_load_reg_num =
- iga2_crtc_reg.hor_addr.reg_num;
- reg = iga2_crtc_reg.hor_addr.reg;
- break;
- case H_BLANK_START_INDEX:
- reg_value =
- IGA2_HOR_BLANK_START_FORMULA
- (device_timing.hor_blank_start);
- viafb_load_reg_num =
- iga2_crtc_reg.hor_blank_start.reg_num;
- reg = iga2_crtc_reg.hor_blank_start.reg;
- break;
- case H_BLANK_END_INDEX:
- reg_value =
- IGA2_HOR_BLANK_END_FORMULA
- (device_timing.hor_blank_start,
- device_timing.hor_blank_end);
- viafb_load_reg_num =
- iga2_crtc_reg.hor_blank_end.reg_num;
- reg = iga2_crtc_reg.hor_blank_end.reg;
- break;
- case H_SYNC_START_INDEX:
- reg_value =
- IGA2_HOR_SYNC_START_FORMULA
- (device_timing.hor_sync_start);
- if (UNICHROME_CN700 <=
- viaparinfo->chip_info->gfx_chip_name)
- viafb_load_reg_num =
- iga2_crtc_reg.hor_sync_start.
- reg_num;
- else
- viafb_load_reg_num = 3;
- reg = iga2_crtc_reg.hor_sync_start.reg;
- break;
- case H_SYNC_END_INDEX:
- reg_value =
- IGA2_HOR_SYNC_END_FORMULA
- (device_timing.hor_sync_start,
- device_timing.hor_sync_end);
- viafb_load_reg_num =
- iga2_crtc_reg.hor_sync_end.reg_num;
- reg = iga2_crtc_reg.hor_sync_end.reg;
- break;
- case V_TOTAL_INDEX:
- reg_value =
- IGA2_VER_TOTAL_FORMULA(device_timing.
- ver_total);
- viafb_load_reg_num =
- iga2_crtc_reg.ver_total.reg_num;
- reg = iga2_crtc_reg.ver_total.reg;
- break;
- case V_ADDR_INDEX:
- reg_value =
- IGA2_VER_ADDR_FORMULA(device_timing.
- ver_addr);
- viafb_load_reg_num =
- iga2_crtc_reg.ver_addr.reg_num;
- reg = iga2_crtc_reg.ver_addr.reg;
- break;
- case V_BLANK_START_INDEX:
- reg_value =
- IGA2_VER_BLANK_START_FORMULA
- (device_timing.ver_blank_start);
- viafb_load_reg_num =
- iga2_crtc_reg.ver_blank_start.reg_num;
- reg = iga2_crtc_reg.ver_blank_start.reg;
- break;
- case V_BLANK_END_INDEX:
- reg_value =
- IGA2_VER_BLANK_END_FORMULA
- (device_timing.ver_blank_start,
- device_timing.ver_blank_end);
- viafb_load_reg_num =
- iga2_crtc_reg.ver_blank_end.reg_num;
- reg = iga2_crtc_reg.ver_blank_end.reg;
- break;
- case V_SYNC_START_INDEX:
- reg_value =
- IGA2_VER_SYNC_START_FORMULA
- (device_timing.ver_sync_start);
- viafb_load_reg_num =
- iga2_crtc_reg.ver_sync_start.reg_num;
- reg = iga2_crtc_reg.ver_sync_start.reg;
- break;
- case V_SYNC_END_INDEX:
- reg_value =
- IGA2_VER_SYNC_END_FORMULA
- (device_timing.ver_sync_start,
- device_timing.ver_sync_end);
- viafb_load_reg_num =
- iga2_crtc_reg.ver_sync_end.reg_num;
- reg = iga2_crtc_reg.ver_sync_end.reg;
- break;
-
- }
- }
- viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
- }
-
- viafb_lock_crt();
+ struct display_timing timing;
+
+ timing.hor_addr = var->xres;
+ timing.hor_sync_start = timing.hor_addr + var->right_margin;
+ timing.hor_sync_end = timing.hor_sync_start + var->hsync_len;
+ timing.hor_total = timing.hor_sync_end + var->left_margin;
+ timing.hor_blank_start = timing.hor_addr;
+ timing.hor_blank_end = timing.hor_total;
+ timing.ver_addr = var->yres;
+ timing.ver_sync_start = timing.ver_addr + var->lower_margin;
+ timing.ver_sync_end = timing.ver_sync_start + var->vsync_len;
+ timing.ver_total = timing.ver_sync_end + var->upper_margin;
+ timing.ver_blank_start = timing.ver_addr;
+ timing.ver_blank_end = timing.ver_total;
+ return timing;
}
-void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
- struct VideoModeTable *video_mode, int bpp_byte, int set_iga)
+void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, int iga)
{
- struct display_timing crt_reg;
- int i;
- int index = 0;
- int h_addr, v_addr;
- u32 clock, refresh = viafb_refresh;
-
- if (viafb_SAMM_ON && set_iga == IGA2)
- refresh = viafb_refresh1;
-
- for (i = 0; i < video_mode->mode_array; i++) {
- index = i;
-
- if (crt_table[i].refresh_rate == refresh)
- break;
- }
+ struct display_timing crt_reg = var_to_timing(var);
- crt_reg = crt_table[index].crtc;
+ if (iga == IGA1)
+ via_set_primary_timing(&crt_reg);
+ else if (iga == IGA2)
+ via_set_secondary_timing(&crt_reg);
- /* Mode 640x480 has border, but LCD/DFP didn't have border. */
- /* So we would delete border. */
- if ((viafb_LCD_ON | viafb_DVI_ON)
- && video_mode->crtc[0].crtc.hor_addr == 640
- && video_mode->crtc[0].crtc.ver_addr == 480
- && refresh == 60) {
- /* The border is 8 pixels. */
- crt_reg.hor_blank_start = crt_reg.hor_blank_start - 8;
-
- /* Blanking time should add left and right borders. */
- crt_reg.hor_blank_end = crt_reg.hor_blank_end + 16;
- }
-
- h_addr = crt_reg.hor_addr;
- v_addr = crt_reg.ver_addr;
- if (set_iga == IGA1) {
- viafb_unlock_crt();
- viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
- }
-
- switch (set_iga) {
- case IGA1:
- viafb_load_crtc_timing(crt_reg, IGA1);
- break;
- case IGA2:
- viafb_load_crtc_timing(crt_reg, IGA2);
- break;
- }
-
- viafb_lock_crt();
- viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7);
- viafb_load_fetch_count_reg(h_addr, bpp_byte, set_iga);
-
- /* load FIFO */
- if ((viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266)
- && (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400))
- viafb_load_FIFO_reg(set_iga, h_addr, v_addr);
-
- clock = crt_reg.hor_total * crt_reg.ver_total
- * crt_table[index].refresh_rate;
- viafb_set_vclock(clock, set_iga);
+ viafb_load_fetch_count_reg(var->xres, var->bits_per_pixel / 8, iga);
+ if (viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266
+ && viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400)
+ viafb_load_FIFO_reg(iga, var->xres, var->yres);
+ viafb_set_vclock(PICOS2KHZ(var->pixclock) * 1000, iga);
}
void __devinit viafb_init_chip_info(int chip_type)
@@ -2092,23 +1769,9 @@ static u8 get_sync(struct fb_info *info)
return polarity;
}
-int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
- struct VideoModeTable *vmode_tbl1, int video_bpp1)
+static void hw_init(void)
{
- int i, j;
- int port;
- u32 devices = viaparinfo->shared->iga1_devices
- | viaparinfo->shared->iga2_devices;
- u8 value, index, mask;
- struct crt_mode_table *crt_timing;
- struct crt_mode_table *crt_timing1 = NULL;
-
- device_screen_off();
- crt_timing = vmode_tbl->crtc;
-
- if (viafb_SAMM_ON == 1) {
- crt_timing1 = vmode_tbl1->crtc;
- }
+ int i;
inb(VIAStatus);
outb(0x00, VIAAR);
@@ -2147,9 +1810,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
break;
}
+ /* probably this should go to the scaling code one day */
viafb_write_regx(scaling_parameters, ARRAY_SIZE(scaling_parameters));
- device_off();
- via_set_state(devices, VIA_STATE_OFF);
/* Fill VPIT Parameters */
/* Write Misc Register */
@@ -2175,12 +1837,29 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
inb(VIAStatus);
outb(0x20, VIAAR);
+ load_fix_bit_crtc_reg();
+}
+
+int viafb_setmode(int video_bpp, int video_bpp1)
+{
+ int j;
+ int port;
+ u32 devices = viaparinfo->shared->iga1_devices
+ | viaparinfo->shared->iga2_devices;
+ u8 value, index, mask;
+ struct fb_var_screeninfo var2;
+
+ device_screen_off();
+ device_off();
+ via_set_state(devices, VIA_STATE_OFF);
+
+ hw_init();
+
/* Update Patch Register */
if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266
- || viaparinfo->chip_info->gfx_chip_name == UNICHROME_K400)
- && vmode_tbl->crtc[0].crtc.hor_addr == 1024
- && vmode_tbl->crtc[0].crtc.ver_addr == 768) {
+ || viaparinfo->chip_info->gfx_chip_name == UNICHROME_K400)
+ && viafbinfo->var.xres == 1024 && viafbinfo->var.yres == 768) {
for (j = 0; j < res_patch_table[0].table_length; j++) {
index = res_patch_table[0].io_reg_table[j].index;
port = res_patch_table[0].io_reg_table[j].port;
@@ -2190,7 +1869,6 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
}
}
- load_fix_bit_crtc_reg();
via_set_primary_pitch(viafbinfo->fix.line_length);
via_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length
: viafbinfo->fix.line_length);
@@ -2208,23 +1886,28 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
/* Clear On Screen */
+ if (viafb_dual_fb) {
+ var2 = viafbinfo1->var;
+ } else if (viafb_SAMM_ON) {
+ viafb_fill_var_timing_info(&var2, viafb_get_best_mode(
+ viafb_second_xres, viafb_second_yres, viafb_refresh1));
+ var2.bits_per_pixel = viafbinfo->var.bits_per_pixel;
+ }
+
/* CRT set mode */
if (viafb_CRT_ON) {
- if (viafb_SAMM_ON &&
- viaparinfo->shared->iga2_devices & VIA_CRT) {
- viafb_fill_crtc_timing(crt_timing1, vmode_tbl1,
- video_bpp1 / 8, IGA2);
- } else {
- viafb_fill_crtc_timing(crt_timing, vmode_tbl,
- video_bpp / 8,
+ if (viaparinfo->shared->iga2_devices & VIA_CRT
+ && viafb_SAMM_ON)
+ viafb_fill_crtc_timing(&var2, IGA2);
+ else
+ viafb_fill_crtc_timing(&viafbinfo->var,
(viaparinfo->shared->iga1_devices & VIA_CRT)
? IGA1 : IGA2);
- }
/* Patch if set_hres is not 8 alignment (1366) to viafb_setmode
to 8 alignment (1368),there is several pixels (2 pixels)
on right side of screen. */
- if (vmode_tbl->crtc[0].crtc.hor_addr % 8) {
+ if (viafbinfo->var.xres % 8) {
viafb_unlock_crt();
viafb_write_reg(CR02, VIACR,
viafb_read_reg(VIACR, CR02) - 1);
@@ -2233,31 +1916,20 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
}
if (viafb_DVI_ON) {
- if (viafb_SAMM_ON &&
- (viaparinfo->tmds_setting_info->iga_path == IGA2)) {
- viafb_dvi_set_mode(viafb_get_mode
- (viaparinfo->tmds_setting_info->h_active,
- viaparinfo->tmds_setting_info->
- v_active),
- video_bpp1, viaparinfo->
- tmds_setting_info->iga_path);
- } else {
- viafb_dvi_set_mode(viafb_get_mode
- (viaparinfo->tmds_setting_info->h_active,
- viaparinfo->
- tmds_setting_info->v_active),
- video_bpp, viaparinfo->
- tmds_setting_info->iga_path);
- }
+ if (viaparinfo->shared->tmds_setting_info.iga_path == IGA2
+ && viafb_SAMM_ON)
+ viafb_dvi_set_mode(&var2, IGA2);
+ else
+ viafb_dvi_set_mode(&viafbinfo->var,
+ viaparinfo->tmds_setting_info->iga_path);
}
if (viafb_LCD_ON) {
if (viafb_SAMM_ON &&
(viaparinfo->lvds_setting_info->iga_path == IGA2)) {
viaparinfo->lvds_setting_info->bpp = video_bpp1;
- viafb_lcd_set_mode(crt_timing1, viaparinfo->
- lvds_setting_info,
- &viaparinfo->chip_info->lvds_chip_info);
+ viafb_lcd_set_mode(viaparinfo->lvds_setting_info,
+ &viaparinfo->chip_info->lvds_chip_info);
} else {
/* IGA1 doesn't have LCD scaling, so set it center. */
if (viaparinfo->lvds_setting_info->iga_path == IGA1) {
@@ -2265,18 +1937,16 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
LCD_CENTERING;
}
viaparinfo->lvds_setting_info->bpp = video_bpp;
- viafb_lcd_set_mode(crt_timing, viaparinfo->
- lvds_setting_info,
- &viaparinfo->chip_info->lvds_chip_info);
+ viafb_lcd_set_mode(viaparinfo->lvds_setting_info,
+ &viaparinfo->chip_info->lvds_chip_info);
}
}
if (viafb_LCD2_ON) {
if (viafb_SAMM_ON &&
(viaparinfo->lvds_setting_info2->iga_path == IGA2)) {
viaparinfo->lvds_setting_info2->bpp = video_bpp1;
- viafb_lcd_set_mode(crt_timing1, viaparinfo->
- lvds_setting_info2,
- &viaparinfo->chip_info->lvds_chip_info2);
+ viafb_lcd_set_mode(viaparinfo->lvds_setting_info2,
+ &viaparinfo->chip_info->lvds_chip_info2);
} else {
/* IGA1 doesn't have LCD scaling, so set it center. */
if (viaparinfo->lvds_setting_info2->iga_path == IGA1) {
@@ -2284,9 +1954,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
LCD_CENTERING;
}
viaparinfo->lvds_setting_info2->bpp = video_bpp;
- viafb_lcd_set_mode(crt_timing, viaparinfo->
- lvds_setting_info2,
- &viaparinfo->chip_info->lvds_chip_info2);
+ viafb_lcd_set_mode(viaparinfo->lvds_setting_info2,
+ &viaparinfo->chip_info->lvds_chip_info2);
}
}
@@ -2296,8 +1965,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
/* If set mode normally, save resolution information for hot-plug . */
if (!viafb_hotplug) {
- viafb_hotplug_Xres = vmode_tbl->crtc[0].crtc.hor_addr;
- viafb_hotplug_Yres = vmode_tbl->crtc[0].crtc.ver_addr;
+ viafb_hotplug_Xres = viafbinfo->var.xres;
+ viafb_hotplug_Yres = viafbinfo->var.yres;
viafb_hotplug_bpp = video_bpp;
viafb_hotplug_refresh = viafb_refresh;
@@ -2348,42 +2017,14 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
return 1;
}
-int viafb_get_pixclock(int hres, int vres, int vmode_refresh)
-{
- int i;
- struct crt_mode_table *best;
- struct VideoModeTable *vmode = viafb_get_mode(hres, vres);
-
- if (!vmode)
- return RES_640X480_60HZ_PIXCLOCK;
-
- best = &vmode->crtc[0];
- for (i = 1; i < vmode->mode_array; i++) {
- if (abs(vmode->crtc[i].refresh_rate - vmode_refresh)
- < abs(best->refresh_rate - vmode_refresh))
- best = &vmode->crtc[i];
- }
-
- return 1000000000 / (best->crtc.hor_total * best->crtc.ver_total)
- * 1000 / best->refresh_rate;
-}
-
int viafb_get_refresh(int hres, int vres, u32 long_refresh)
{
- int i;
struct crt_mode_table *best;
- struct VideoModeTable *vmode = viafb_get_mode(hres, vres);
- if (!vmode)
+ best = viafb_get_best_mode(hres, vres, long_refresh);
+ if (!best)
return 60;
- best = &vmode->crtc[0];
- for (i = 1; i < vmode->mode_array; i++) {
- if (abs(vmode->crtc[i].refresh_rate - long_refresh)
- < abs(best->refresh_rate - long_refresh))
- best = &vmode->crtc[i];
- }
-
if (abs(best->refresh_rate - long_refresh) > 3) {
if (hres == 1200 && vres == 900)
return 49; /* OLPC DCON only supports 50 Hz */
@@ -2485,21 +2126,14 @@ void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
}
/*According var's xres, yres fill var's other timing information*/
-void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
- struct VideoModeTable *vmode_tbl)
+void viafb_fill_var_timing_info(struct fb_var_screeninfo *var,
+ struct crt_mode_table *mode)
{
- struct crt_mode_table *crt_timing = NULL;
struct display_timing crt_reg;
- int i = 0, index = 0;
- crt_timing = vmode_tbl->crtc;
- for (i = 0; i < vmode_tbl->mode_array; i++) {
- index = i;
- if (crt_timing[i].refresh_rate == refresh)
- break;
- }
- crt_reg = crt_timing[index].crtc;
- var->pixclock = viafb_get_pixclock(var->xres, var->yres, refresh);
+ crt_reg = mode->crtc;
+ var->pixclock = 1000000000 / (crt_reg.hor_total * crt_reg.ver_total)
+ * 1000 / mode->refresh_rate;
var->left_margin =
crt_reg.hor_total - (crt_reg.hor_sync_start + crt_reg.hor_sync_end);
var->right_margin = crt_reg.hor_sync_start - crt_reg.hor_addr;
@@ -2509,8 +2143,8 @@ void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
var->lower_margin = crt_reg.ver_sync_start - crt_reg.ver_addr;
var->vsync_len = crt_reg.ver_sync_end;
var->sync = 0;
- if (crt_timing[index].h_sync_polarity == POSITIVE)
+ if (mode->h_sync_polarity == POSITIVE)
var->sync |= FB_SYNC_HOR_HIGH_ACT;
- if (crt_timing[index].v_sync_polarity == POSITIVE)
+ if (mode->v_sync_polarity == POSITIVE)
var->sync |= FB_SYNC_VERT_HIGH_ACT;
}
diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h
index c7239eb..4db5b6e 100644
--- a/drivers/video/via/hw.h
+++ b/drivers/video/via/hw.h
@@ -51,40 +51,6 @@
#define VIA_HSYNC_NEGATIVE 0x01
#define VIA_VSYNC_NEGATIVE 0x02
-/***************************************************
-* Definition IGA1 Design Method of CRTC Registers *
-****************************************************/
-#define IGA1_HOR_TOTAL_FORMULA(x) (((x)/8)-5)
-#define IGA1_HOR_ADDR_FORMULA(x) (((x)/8)-1)
-#define IGA1_HOR_BLANK_START_FORMULA(x) (((x)/8)-1)
-#define IGA1_HOR_BLANK_END_FORMULA(x, y) (((x+y)/8)-1)
-#define IGA1_HOR_SYNC_START_FORMULA(x) ((x)/8)
-#define IGA1_HOR_SYNC_END_FORMULA(x, y) ((x+y)/8)
-
-#define IGA1_VER_TOTAL_FORMULA(x) ((x)-2)
-#define IGA1_VER_ADDR_FORMULA(x) ((x)-1)
-#define IGA1_VER_BLANK_START_FORMULA(x) ((x)-1)
-#define IGA1_VER_BLANK_END_FORMULA(x, y) ((x+y)-1)
-#define IGA1_VER_SYNC_START_FORMULA(x) ((x)-1)
-#define IGA1_VER_SYNC_END_FORMULA(x, y) ((x+y)-1)
-
-/***************************************************
-** Definition IGA2 Design Method of CRTC Registers *
-****************************************************/
-#define IGA2_HOR_TOTAL_FORMULA(x) ((x)-1)
-#define IGA2_HOR_ADDR_FORMULA(x) ((x)-1)
-#define IGA2_HOR_BLANK_START_FORMULA(x) ((x)-1)
-#define IGA2_HOR_BLANK_END_FORMULA(x, y) ((x+y)-1)
-#define IGA2_HOR_SYNC_START_FORMULA(x) ((x)-1)
-#define IGA2_HOR_SYNC_END_FORMULA(x, y) ((x+y)-1)
-
-#define IGA2_VER_TOTAL_FORMULA(x) ((x)-1)
-#define IGA2_VER_ADDR_FORMULA(x) ((x)-1)
-#define IGA2_VER_BLANK_START_FORMULA(x) ((x)-1)
-#define IGA2_VER_BLANK_END_FORMULA(x, y) ((x+y)-1)
-#define IGA2_VER_SYNC_START_FORMULA(x) ((x)-1)
-#define IGA2_VER_SYNC_END_FORMULA(x, y) ((x+y)-1)
-
/**********************************************************/
/* Definition IGA2 Design Method of CRTC Shadow Registers */
/**********************************************************/
@@ -97,33 +63,6 @@
#define IGA2_VER_SYNC_START_SHADOW_FORMULA(x) (x)
#define IGA2_VER_SYNC_END_SHADOW_FORMULA(x, y) (x+y)
-/* Define Register Number for IGA1 CRTC Timing */
-
-/* location: {CR00,0,7},{CR36,3,3} */
-#define IGA1_HOR_TOTAL_REG_NUM 2
-/* location: {CR01,0,7} */
-#define IGA1_HOR_ADDR_REG_NUM 1
-/* location: {CR02,0,7} */
-#define IGA1_HOR_BLANK_START_REG_NUM 1
-/* location: {CR03,0,4},{CR05,7,7},{CR33,5,5} */
-#define IGA1_HOR_BLANK_END_REG_NUM 3
-/* location: {CR04,0,7},{CR33,4,4} */
-#define IGA1_HOR_SYNC_START_REG_NUM 2
-/* location: {CR05,0,4} */
-#define IGA1_HOR_SYNC_END_REG_NUM 1
-/* location: {CR06,0,7},{CR07,0,0},{CR07,5,5},{CR35,0,0} */
-#define IGA1_VER_TOTAL_REG_NUM 4
-/* location: {CR12,0,7},{CR07,1,1},{CR07,6,6},{CR35,2,2} */
-#define IGA1_VER_ADDR_REG_NUM 4
-/* location: {CR15,0,7},{CR07,3,3},{CR09,5,5},{CR35,3,3} */
-#define IGA1_VER_BLANK_START_REG_NUM 4
-/* location: {CR16,0,7} */
-#define IGA1_VER_BLANK_END_REG_NUM 1
-/* location: {CR10,0,7},{CR07,2,2},{CR07,7,7},{CR35,1,1} */
-#define IGA1_VER_SYNC_START_REG_NUM 4
-/* location: {CR11,0,3} */
-#define IGA1_VER_SYNC_END_REG_NUM 1
-
/* Define Register Number for IGA2 Shadow CRTC Timing */
/* location: {CR6D,0,7},{CR71,3,3} */
@@ -143,37 +82,6 @@
/* location: {CR76,0,3} */
#define IGA2_SHADOW_VER_SYNC_END_REG_NUM 1
-/* Define Register Number for IGA2 CRTC Timing */
-
-/* location: {CR50,0,7},{CR55,0,3} */
-#define IGA2_HOR_TOTAL_REG_NUM 2
-/* location: {CR51,0,7},{CR55,4,6} */
-#define IGA2_HOR_ADDR_REG_NUM 2
-/* location: {CR52,0,7},{CR54,0,2} */
-#define IGA2_HOR_BLANK_START_REG_NUM 2
-/* location: CLE266: {CR53,0,7},{CR54,3,5} => CLE266's CR5D[6]
-is reserved, so it may have problem to set 1600x1200 on IGA2. */
-/* Others: {CR53,0,7},{CR54,3,5},{CR5D,6,6} */
-#define IGA2_HOR_BLANK_END_REG_NUM 3
-/* location: {CR56,0,7},{CR54,6,7},{CR5C,7,7} */
-/* VT3314 and Later: {CR56,0,7},{CR54,6,7},{CR5C,7,7}, {CR5D,7,7} */
-#define IGA2_HOR_SYNC_START_REG_NUM 4
-
-/* location: {CR57,0,7},{CR5C,6,6} */
-#define IGA2_HOR_SYNC_END_REG_NUM 2
-/* location: {CR58,0,7},{CR5D,0,2} */
-#define IGA2_VER_TOTAL_REG_NUM 2
-/* location: {CR59,0,7},{CR5D,3,5} */
-#define IGA2_VER_ADDR_REG_NUM 2
-/* location: {CR5A,0,7},{CR5C,0,2} */
-#define IGA2_VER_BLANK_START_REG_NUM 2
-/* location: {CR5E,0,7},{CR5C,3,5} */
-#define IGA2_VER_BLANK_END_REG_NUM 2
-/* location: {CR5E,0,7},{CR5F,5,7} */
-#define IGA2_VER_SYNC_START_REG_NUM 2
-/* location: {CR5F,0,4} */
-#define IGA2_VER_SYNC_END_REG_NUM 1
-
/* Define Fetch Count Register*/
/* location: {SR1C,0,7},{SR1D,0,1} */
@@ -446,87 +354,12 @@ is reserved, so it may have problem to set 1600x1200 on IGA2. */
/* location: {CR78,0,7},{CR79,6,7} */
#define LCD_VER_SCALING_FACTOR_REG_NUM_CLE 2
-/************************************************
- ***** Define IGA1 Display Timing *****
- ************************************************/
struct io_register {
u8 io_addr;
u8 start_bit;
u8 end_bit;
};
-/* IGA1 Horizontal Total */
-struct iga1_hor_total {
- int reg_num;
- struct io_register reg[IGA1_HOR_TOTAL_REG_NUM];
-};
-
-/* IGA1 Horizontal Addressable Video */
-struct iga1_hor_addr {
- int reg_num;
- struct io_register reg[IGA1_HOR_ADDR_REG_NUM];
-};
-
-/* IGA1 Horizontal Blank Start */
-struct iga1_hor_blank_start {
- int reg_num;
- struct io_register reg[IGA1_HOR_BLANK_START_REG_NUM];
-};
-
-/* IGA1 Horizontal Blank End */
-struct iga1_hor_blank_end {
- int reg_num;
- struct io_register reg[IGA1_HOR_BLANK_END_REG_NUM];
-};
-
-/* IGA1 Horizontal Sync Start */
-struct iga1_hor_sync_start {
- int reg_num;
- struct io_register reg[IGA1_HOR_SYNC_START_REG_NUM];
-};
-
-/* IGA1 Horizontal Sync End */
-struct iga1_hor_sync_end {
- int reg_num;
- struct io_register reg[IGA1_HOR_SYNC_END_REG_NUM];
-};
-
-/* IGA1 Vertical Total */
-struct iga1_ver_total {
- int reg_num;
- struct io_register reg[IGA1_VER_TOTAL_REG_NUM];
-};
-
-/* IGA1 Vertical Addressable Video */
-struct iga1_ver_addr {
- int reg_num;
- struct io_register reg[IGA1_VER_ADDR_REG_NUM];
-};
-
-/* IGA1 Vertical Blank Start */
-struct iga1_ver_blank_start {
- int reg_num;
- struct io_register reg[IGA1_VER_BLANK_START_REG_NUM];
-};
-
-/* IGA1 Vertical Blank End */
-struct iga1_ver_blank_end {
- int reg_num;
- struct io_register reg[IGA1_VER_BLANK_END_REG_NUM];
-};
-
-/* IGA1 Vertical Sync Start */
-struct iga1_ver_sync_start {
- int reg_num;
- struct io_register reg[IGA1_VER_SYNC_START_REG_NUM];
-};
-
-/* IGA1 Vertical Sync End */
-struct iga1_ver_sync_end {
- int reg_num;
- struct io_register reg[IGA1_VER_SYNC_END_REG_NUM];
-};
-
/*****************************************************
** Define IGA2 Shadow Display Timing ****
*****************************************************/
@@ -579,82 +412,6 @@ struct iga2_shadow_ver_sync_end {
struct io_register reg[IGA2_SHADOW_VER_SYNC_END_REG_NUM];
};
-/*****************************************************
-** Define IGA2 Display Timing ****
-******************************************************/
-
-/* IGA2 Horizontal Total */
-struct iga2_hor_total {
- int reg_num;
- struct io_register reg[IGA2_HOR_TOTAL_REG_NUM];
-};
-
-/* IGA2 Horizontal Addressable Video */
-struct iga2_hor_addr {
- int reg_num;
- struct io_register reg[IGA2_HOR_ADDR_REG_NUM];
-};
-
-/* IGA2 Horizontal Blank Start */
-struct iga2_hor_blank_start {
- int reg_num;
- struct io_register reg[IGA2_HOR_BLANK_START_REG_NUM];
-};
-
-/* IGA2 Horizontal Blank End */
-struct iga2_hor_blank_end {
- int reg_num;
- struct io_register reg[IGA2_HOR_BLANK_END_REG_NUM];
-};
-
-/* IGA2 Horizontal Sync Start */
-struct iga2_hor_sync_start {
- int reg_num;
- struct io_register reg[IGA2_HOR_SYNC_START_REG_NUM];
-};
-
-/* IGA2 Horizontal Sync End */
-struct iga2_hor_sync_end {
- int reg_num;
- struct io_register reg[IGA2_HOR_SYNC_END_REG_NUM];
-};
-
-/* IGA2 Vertical Total */
-struct iga2_ver_total {
- int reg_num;
- struct io_register reg[IGA2_VER_TOTAL_REG_NUM];
-};
-
-/* IGA2 Vertical Addressable Video */
-struct iga2_ver_addr {
- int reg_num;
- struct io_register reg[IGA2_VER_ADDR_REG_NUM];
-};
-
-/* IGA2 Vertical Blank Start */
-struct iga2_ver_blank_start {
- int reg_num;
- struct io_register reg[IGA2_VER_BLANK_START_REG_NUM];
-};
-
-/* IGA2 Vertical Blank End */
-struct iga2_ver_blank_end {
- int reg_num;
- struct io_register reg[IGA2_VER_BLANK_END_REG_NUM];
-};
-
-/* IGA2 Vertical Sync Start */
-struct iga2_ver_sync_start {
- int reg_num;
- struct io_register reg[IGA2_VER_SYNC_START_REG_NUM];
-};
-
-/* IGA2 Vertical Sync End */
-struct iga2_ver_sync_end {
- int reg_num;
- struct io_register reg[IGA2_VER_SYNC_END_REG_NUM];
-};
-
/* IGA1 Fetch Count Register */
struct iga1_fetch_count {
int reg_num;
@@ -817,21 +574,6 @@ struct display_queue_expire_num {
iga2_display_queue_expire_num_reg;
};
-struct iga1_crtc_timing {
- struct iga1_hor_total hor_total;
- struct iga1_hor_addr hor_addr;
- struct iga1_hor_blank_start hor_blank_start;
- struct iga1_hor_blank_end hor_blank_end;
- struct iga1_hor_sync_start hor_sync_start;
- struct iga1_hor_sync_end hor_sync_end;
- struct iga1_ver_total ver_total;
- struct iga1_ver_addr ver_addr;
- struct iga1_ver_blank_start ver_blank_start;
- struct iga1_ver_blank_end ver_blank_end;
- struct iga1_ver_sync_start ver_sync_start;
- struct iga1_ver_sync_end ver_sync_end;
-};
-
struct iga2_shadow_crtc_timing {
struct iga2_shadow_hor_total hor_total_shadow;
struct iga2_shadow_hor_blank_end hor_blank_end_shadow;
@@ -843,21 +585,6 @@ struct iga2_shadow_crtc_timing {
struct iga2_shadow_ver_sync_end ver_sync_end_shadow;
};
-struct iga2_crtc_timing {
- struct iga2_hor_total hor_total;
- struct iga2_hor_addr hor_addr;
- struct iga2_hor_blank_start hor_blank_start;
- struct iga2_hor_blank_end hor_blank_end;
- struct iga2_hor_sync_start hor_sync_start;
- struct iga2_hor_sync_end hor_sync_end;
- struct iga2_ver_total ver_total;
- struct iga2_ver_addr ver_addr;
- struct iga2_ver_blank_start ver_blank_start;
- struct iga2_ver_blank_end ver_blank_end;
- struct iga2_ver_sync_start ver_sync_start;
- struct iga2_ver_sync_end ver_sync_end;
-};
-
/* device ID */
#define CLE266_FUNCTION3 0x3123
#define KM400_FUNCTION3 0x3205
@@ -910,9 +637,7 @@ extern int viafb_LCD_ON;
extern int viafb_DVI_ON;
extern int viafb_hotplug;
-void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
- struct VideoModeTable *video_mode, int bpp_byte, int set_iga);
-
+void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, int iga);
void viafb_set_vclock(u32 CLK, int set_iga);
void viafb_load_reg(int timing_value, int viafb_load_reg_num,
struct io_register *reg,
@@ -932,13 +657,11 @@ void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active);
void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
*p_gfx_dpa_setting);
-int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
- struct VideoModeTable *vmode_tbl1, int video_bpp1);
-void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
- struct VideoModeTable *vmode_tbl);
+int viafb_setmode(int video_bpp, int video_bpp1);
+void viafb_fill_var_timing_info(struct fb_var_screeninfo *var,
+ struct crt_mode_table *mode);
void __devinit viafb_init_chip_info(int chip_type);
void __devinit viafb_init_dac(int set_iga);
-int viafb_get_pixclock(int hres, int vres, int vmode_refresh);
int viafb_get_refresh(int hres, int vres, u32 float_refresh);
void viafb_update_device_setting(int hres, int vres, int bpp, int flag);
diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c
index 6e06981..5f3b4e3 100644
--- a/drivers/video/via/lcd.c
+++ b/drivers/video/via/lcd.c
@@ -548,9 +548,8 @@ static void lcd_patch_skew(struct lvds_setting_information
}
/* LCD Set Mode */
-void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
- struct lvds_setting_information *plvds_setting_info,
- struct lvds_chip_information *plvds_chip_info)
+void viafb_lcd_set_mode(struct lvds_setting_information *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info)
{
int set_iga = plvds_setting_info->iga_path;
int mode_bpp = plvds_setting_info->bpp;
@@ -559,16 +558,15 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
int panel_hres = plvds_setting_info->lcd_panel_hres;
int panel_vres = plvds_setting_info->lcd_panel_vres;
u32 clock;
- struct display_timing mode_crt_reg, panel_crt_reg;
- struct crt_mode_table *panel_crt_table = NULL;
- struct VideoModeTable *vmode_tbl = viafb_get_mode(panel_hres,
- panel_vres);
+ struct display_timing mode_crt_reg, panel_crt_reg, timing;
+ struct crt_mode_table *mode_crt_table, *panel_crt_table;
DEBUG_MSG(KERN_INFO "viafb_lcd_set_mode!!\n");
/* Get mode table */
+ mode_crt_table = viafb_get_best_mode(set_hres, set_vres, 60);
mode_crt_reg = mode_crt_table->crtc;
/* Get panel table Pointer */
- panel_crt_table = vmode_tbl->crtc;
+ panel_crt_table = viafb_get_best_mode(panel_hres, panel_vres, 60);
panel_crt_reg = panel_crt_table->crtc;
DEBUG_MSG(KERN_INFO "bellow viafb_lcd_set_mode!!\n");
if (VT1636_LVDS == plvds_chip_info->lvds_chip_name)
@@ -576,31 +574,28 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
clock = panel_crt_reg.hor_total * panel_crt_reg.ver_total
* panel_crt_table->refresh_rate;
plvds_setting_info->vclk = clock;
- if (set_iga == IGA1) {
- /* IGA1 doesn't have LCD scaling, so set it as centering. */
- viafb_load_crtc_timing(lcd_centering_timging
- (mode_crt_reg, panel_crt_reg), IGA1);
+
+ if (set_iga == IGA2 && (set_hres < panel_hres || set_vres < panel_vres)
+ && plvds_setting_info->display_method == LCD_EXPANDSION) {
+ timing = panel_crt_reg;
+ load_lcd_scaling(set_hres, set_vres, panel_hres, panel_vres);
} else {
- /* Expansion */
- if (plvds_setting_info->display_method == LCD_EXPANDSION
- && (set_hres < panel_hres || set_vres < panel_vres)) {
- /* expansion timing IGA2 loaded panel set timing*/
- viafb_load_crtc_timing(panel_crt_reg, IGA2);
- DEBUG_MSG(KERN_INFO "viafb_load_crtc_timing!!\n");
- load_lcd_scaling(set_hres, set_vres, panel_hres,
- panel_vres);
- DEBUG_MSG(KERN_INFO "load_lcd_scaling!!\n");
- } else { /* Centering */
- /* centering timing IGA2 always loaded panel
- and mode releative timing */
- viafb_load_crtc_timing(lcd_centering_timging
- (mode_crt_reg, panel_crt_reg), IGA2);
- viafb_write_reg_mask(CR79, VIACR, 0x00,
+ timing = lcd_centering_timging(mode_crt_reg, panel_crt_reg);
+ if (set_iga == IGA2)
+ /* disable scaling */
+ via_write_reg_mask(VIACR, 0x79, 0x00,
BIT0 + BIT1 + BIT2);
- /* LCD scaling disabled */
- }
}
+ timing.hor_blank_end += timing.hor_blank_start;
+ timing.hor_sync_end += timing.hor_sync_start;
+ timing.ver_blank_end += timing.ver_blank_start;
+ timing.ver_sync_end += timing.ver_sync_start;
+ if (set_iga == IGA1)
+ via_set_primary_timing(&timing);
+ else if (set_iga == IGA2)
+ via_set_secondary_timing(&timing);
+
/* Fetch count for IGA2 only */
viafb_load_fetch_count_reg(set_hres, mode_bpp / 8, set_iga);
diff --git a/drivers/video/via/lcd.h b/drivers/video/via/lcd.h
index 75f60a6..77ca7b8 100644
--- a/drivers/video/via/lcd.h
+++ b/drivers/video/via/lcd.h
@@ -76,16 +76,13 @@ void __devinit viafb_init_lvds_output_interface(struct lvds_chip_information
*plvds_chip_info,
struct lvds_setting_information
*plvds_setting_info);
-void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
- struct lvds_setting_information *plvds_setting_info,
- struct lvds_chip_information *plvds_chip_info);
+void viafb_lcd_set_mode(struct lvds_setting_information *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info);
bool __devinit viafb_lvds_trasmitter_identify(void);
void viafb_init_lvds_output_interface(struct lvds_chip_information
*plvds_chip_info,
struct lvds_setting_information
*plvds_setting_info);
bool viafb_lcd_get_mobile_state(bool *mobile);
-void viafb_load_crtc_timing(struct display_timing device_timing,
- int set_iga);
#endif /* __LCD_H__ */
diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h
index 61b0bd5..69d882c 100644
--- a/drivers/video/via/share.h
+++ b/drivers/video/via/share.h
@@ -22,6 +22,8 @@
#ifndef __SHARE_H__
#define __SHARE_H__
+#include "via_modesetting.h"
+
/* Define Bit Field */
#define BIT0 0x01
#define BIT1 0x02
@@ -634,10 +636,6 @@
#define V_SYNC_SATRT_SHADOW_INDEX 18
#define V_SYNC_END_SHADOW_INDEX 19
-/* Definition Video Mode Pixel Clock (picoseconds)
-*/
-#define RES_640X480_60HZ_PIXCLOCK 39722
-
/* LCD display method
*/
#define LCD_EXPANDSION 0x00
@@ -648,23 +646,6 @@
#define LCD_OPENLDI 0x00
#define LCD_SPWG 0x01
-/* Define display timing
-*/
-struct display_timing {
- u16 hor_total;
- u16 hor_addr;
- u16 hor_blank_start;
- u16 hor_blank_end;
- u16 hor_sync_start;
- u16 hor_sync_end;
- u16 ver_total;
- u16 ver_addr;
- u16 ver_blank_start;
- u16 ver_blank_end;
- u16 ver_sync_start;
- u16 ver_sync_end;
-};
-
struct crt_mode_table {
int refresh_rate;
int h_sync_polarity;
diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
index eb112b6..dd58b53 100644
--- a/drivers/video/via/via-core.c
+++ b/drivers/video/via/via-core.c
@@ -35,7 +35,7 @@ static struct via_port_cfg adap_configs[] = {
* The OLPC XO-1.5 puts the camera power and reset lines onto
* GPIO 2C.
*/
-static const struct via_port_cfg olpc_adap_configs[] = {
+static struct via_port_cfg olpc_adap_configs[] = {
[VIA_PORT_26] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x26 },
[VIA_PORT_31] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x31 },
[VIA_PORT_25] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x25 },
diff --git a/drivers/video/via/via_modesetting.c b/drivers/video/via/via_modesetting.c
index 3cddcff..0e431ae 100644
--- a/drivers/video/via/via_modesetting.c
+++ b/drivers/video/via/via_modesetting.c
@@ -29,6 +29,110 @@
#include "share.h"
#include "debug.h"
+
+void via_set_primary_timing(const struct display_timing *timing)
+{
+ struct display_timing raw;
+
+ raw.hor_total = timing->hor_total / 8 - 5;
+ raw.hor_addr = timing->hor_addr / 8 - 1;
+ raw.hor_blank_start = timing->hor_blank_start / 8 - 1;
+ raw.hor_blank_end = timing->hor_blank_end / 8 - 1;
+ raw.hor_sync_start = timing->hor_sync_start / 8;
+ raw.hor_sync_end = timing->hor_sync_end / 8;
+ raw.ver_total = timing->ver_total - 2;
+ raw.ver_addr = timing->ver_addr - 1;
+ raw.ver_blank_start = timing->ver_blank_start - 1;
+ raw.ver_blank_end = timing->ver_blank_end - 1;
+ raw.ver_sync_start = timing->ver_sync_start - 1;
+ raw.ver_sync_end = timing->ver_sync_end - 1;
+
+ /* unlock timing registers */
+ via_write_reg_mask(VIACR, 0x11, 0x00, 0x80);
+
+ via_write_reg(VIACR, 0x00, raw.hor_total & 0xFF);
+ via_write_reg(VIACR, 0x01, raw.hor_addr & 0xFF);
+ via_write_reg(VIACR, 0x02, raw.hor_blank_start & 0xFF);
+ via_write_reg_mask(VIACR, 0x03, raw.hor_blank_end & 0x1F, 0x1F);
+ via_write_reg(VIACR, 0x04, raw.hor_sync_start & 0xFF);
+ via_write_reg_mask(VIACR, 0x05, (raw.hor_sync_end & 0x1F)
+ | (raw.hor_blank_end << (7 - 5) & 0x80), 0x9F);
+ via_write_reg(VIACR, 0x06, raw.ver_total & 0xFF);
+ via_write_reg_mask(VIACR, 0x07, (raw.ver_total >> 8 & 0x01)
+ | (raw.ver_addr >> (8 - 1) & 0x02)
+ | (raw.ver_sync_start >> (8 - 2) & 0x04)
+ | (raw.ver_blank_start >> (8 - 3) & 0x08)
+ | (raw.ver_total >> (9 - 5) & 0x20)
+ | (raw.ver_addr >> (9 - 6) & 0x40)
+ | (raw.ver_sync_start >> (9 - 7) & 0x80), 0xEF);
+ via_write_reg_mask(VIACR, 0x09, raw.ver_blank_start >> (9 - 5) & 0x20,
+ 0x20);
+ via_write_reg(VIACR, 0x10, raw.ver_sync_start & 0xFF);
+ via_write_reg_mask(VIACR, 0x11, raw.ver_sync_end & 0x0F, 0x0F);
+ via_write_reg(VIACR, 0x12, raw.ver_addr & 0xFF);
+ via_write_reg(VIACR, 0x15, raw.ver_blank_start & 0xFF);
+ via_write_reg(VIACR, 0x16, raw.ver_blank_end & 0xFF);
+ via_write_reg_mask(VIACR, 0x33, (raw.hor_sync_start >> (8 - 4) & 0x10)
+ | (raw.hor_blank_end >> (6 - 5) & 0x20), 0x30);
+ via_write_reg_mask(VIACR, 0x35, (raw.ver_total >> 10 & 0x01)
+ | (raw.ver_sync_start >> (10 - 1) & 0x02)
+ | (raw.ver_addr >> (10 - 2) & 0x04)
+ | (raw.ver_blank_start >> (10 - 3) & 0x08), 0x0F);
+ via_write_reg_mask(VIACR, 0x36, raw.hor_total >> (8 - 3) & 0x08, 0x08);
+
+ /* lock timing registers */
+ via_write_reg_mask(VIACR, 0x11, 0x80, 0x80);
+
+ /* reset timing control */
+ via_write_reg_mask(VIACR, 0x17, 0x00, 0x80);
+ via_write_reg_mask(VIACR, 0x17, 0x80, 0x80);
+}
+
+void via_set_secondary_timing(const struct display_timing *timing)
+{
+ struct display_timing raw;
+
+ raw.hor_total = timing->hor_total - 1;
+ raw.hor_addr = timing->hor_addr - 1;
+ raw.hor_blank_start = timing->hor_blank_start - 1;
+ raw.hor_blank_end = timing->hor_blank_end - 1;
+ raw.hor_sync_start = timing->hor_sync_start - 1;
+ raw.hor_sync_end = timing->hor_sync_end - 1;
+ raw.ver_total = timing->ver_total - 1;
+ raw.ver_addr = timing->ver_addr - 1;
+ raw.ver_blank_start = timing->ver_blank_start - 1;
+ raw.ver_blank_end = timing->ver_blank_end - 1;
+ raw.ver_sync_start = timing->ver_sync_start - 1;
+ raw.ver_sync_end = timing->ver_sync_end - 1;
+
+ via_write_reg(VIACR, 0x50, raw.hor_total & 0xFF);
+ via_write_reg(VIACR, 0x51, raw.hor_addr & 0xFF);
+ via_write_reg(VIACR, 0x52, raw.hor_blank_start & 0xFF);
+ via_write_reg(VIACR, 0x53, raw.hor_blank_end & 0xFF);
+ via_write_reg(VIACR, 0x54, (raw.hor_blank_start >> 8 & 0x07)
+ | (raw.hor_blank_end >> (8 - 3) & 0x38)
+ | (raw.hor_sync_start >> (8 - 6) & 0xC0));
+ via_write_reg_mask(VIACR, 0x55, (raw.hor_total >> 8 & 0x0F)
+ | (raw.hor_addr >> (8 - 4) & 0x70), 0x7F);
+ via_write_reg(VIACR, 0x56, raw.hor_sync_start & 0xFF);
+ via_write_reg(VIACR, 0x57, raw.hor_sync_end & 0xFF);
+ via_write_reg(VIACR, 0x58, raw.ver_total & 0xFF);
+ via_write_reg(VIACR, 0x59, raw.ver_addr & 0xFF);
+ via_write_reg(VIACR, 0x5A, raw.ver_blank_start & 0xFF);
+ via_write_reg(VIACR, 0x5B, raw.ver_blank_end & 0xFF);
+ via_write_reg(VIACR, 0x5C, (raw.ver_blank_start >> 8 & 0x07)
+ | (raw.ver_blank_end >> (8 - 3) & 0x38)
+ | (raw.hor_sync_end >> (8 - 6) & 0x40)
+ | (raw.hor_sync_start >> (10 - 7) & 0x80));
+ via_write_reg(VIACR, 0x5D, (raw.ver_total >> 8 & 0x07)
+ | (raw.ver_addr >> (8 - 3) & 0x38)
+ | (raw.hor_blank_end >> (11 - 6) & 0x40)
+ | (raw.hor_sync_start >> (11 - 7) & 0x80));
+ via_write_reg(VIACR, 0x5E, raw.ver_sync_start & 0xFF);
+ via_write_reg(VIACR, 0x5F, (raw.ver_sync_end & 0x1F)
+ | (raw.ver_sync_start >> (8 - 5) & 0xE0));
+}
+
void via_set_primary_address(u32 addr)
{
DEBUG_MSG(KERN_DEBUG "via_set_primary_address(0x%08X)\n", addr);
diff --git a/drivers/video/via/via_modesetting.h b/drivers/video/via/via_modesetting.h
index ae35cfd..06e09fe 100644
--- a/drivers/video/via/via_modesetting.h
+++ b/drivers/video/via/via_modesetting.h
@@ -28,6 +28,29 @@
#include <linux/types.h>
+
+#define VIA_PITCH_SIZE (1<<3)
+#define VIA_PITCH_MAX 0x3FF8
+
+
+struct display_timing {
+ u16 hor_total;
+ u16 hor_addr;
+ u16 hor_blank_start;
+ u16 hor_blank_end;
+ u16 hor_sync_start;
+ u16 hor_sync_end;
+ u16 ver_total;
+ u16 ver_addr;
+ u16 ver_blank_start;
+ u16 ver_blank_end;
+ u16 ver_sync_start;
+ u16 ver_sync_end;
+};
+
+
+void via_set_primary_timing(const struct display_timing *timing);
+void via_set_secondary_timing(const struct display_timing *timing);
void via_set_primary_address(u32 addr);
void via_set_secondary_address(u32 addr);
void via_set_primary_pitch(u32 pitch);
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index 53aa443..a13c258 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -38,8 +38,6 @@ static char *viafb_mode1;
static int viafb_bpp = 32;
static int viafb_bpp1 = 32;
-static unsigned int viafb_second_xres = 640;
-static unsigned int viafb_second_yres = 480;
static unsigned int viafb_second_offset;
static int viafb_second_size;
@@ -151,7 +149,8 @@ static void viafb_update_fix(struct fb_info *info)
info->fix.visual =
bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
- info->fix.line_length = (info->var.xres_virtual * bpp / 8 + 7) & ~7;
+ info->fix.line_length = ALIGN(info->var.xres_virtual * bpp / 8,
+ VIA_PITCH_SIZE);
}
static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix,
@@ -200,7 +199,6 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
int depth, refresh;
- struct VideoModeTable *vmode_entry;
struct viafb_par *ppar = info->par;
u32 line;
@@ -210,8 +208,10 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
if (var->vmode & FB_VMODE_INTERLACED || var->vmode & FB_VMODE_DOUBLE)
return -EINVAL;
- vmode_entry = viafb_get_mode(var->xres, var->yres);
- if (!vmode_entry) {
+ /* the refresh rate is not important here, as we only want to know
+ * whether the resolution exists
+ */
+ if (!viafb_get_best_mode(var->xres, var->yres, 60)) {
DEBUG_MSG(KERN_INFO
"viafb: Mode %dx%dx%d not supported!!\n",
var->xres, var->yres, var->bits_per_pixel);
@@ -238,8 +238,12 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
depth = 24;
viafb_fill_var_color_info(var, depth);
- line = (var->xres_virtual * var->bits_per_pixel / 8 + 7) & ~7;
- if (line * var->yres_virtual > ppar->memsize)
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+
+ line = ALIGN(var->xres_virtual * var->bits_per_pixel / 8,
+ VIA_PITCH_SIZE);
+ if (line > VIA_PITCH_MAX || line * var->yres_virtual > ppar->memsize)
return -EINVAL;
/* Based on var passed in to calculate the refresh,
@@ -249,7 +253,8 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
get_var_refresh(var));
/* Adjust var according to our driver's own table */
- viafb_fill_var_timing_info(var, refresh, vmode_entry);
+ viafb_fill_var_timing_info(var,
+ viafb_get_best_mode(var->xres, var->yres, refresh));
if (var->accel_flags & FB_ACCELF_TEXT &&
!ppar->shared->vdev->engine_mmio)
var->accel_flags = 0;
@@ -260,7 +265,6 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
static int viafb_set_par(struct fb_info *info)
{
struct viafb_par *viapar = info->par;
- struct VideoModeTable *vmode_entry, *vmode_entry1 = NULL;
int refresh;
DEBUG_MSG(KERN_INFO "viafb_set_par!\n");
@@ -269,10 +273,7 @@ static int viafb_set_par(struct fb_info *info)
viafb_update_device_setting(viafbinfo->var.xres, viafbinfo->var.yres,
viafbinfo->var.bits_per_pixel, 0);
- vmode_entry = viafb_get_mode(viafbinfo->var.xres, viafbinfo->var.yres);
if (viafb_dual_fb) {
- vmode_entry1 = viafb_get_mode(viafbinfo1->var.xres,
- viafbinfo1->var.yres);
viafb_update_device_setting(viafbinfo1->var.xres,
viafbinfo1->var.yres, viafbinfo1->var.bits_per_pixel,
1);
@@ -280,8 +281,6 @@ static int viafb_set_par(struct fb_info *info)
DEBUG_MSG(KERN_INFO
"viafb_second_xres = %d, viafb_second_yres = %d, bpp = %d\n",
viafb_second_xres, viafb_second_yres, viafb_bpp1);
- vmode_entry1 = viafb_get_mode(viafb_second_xres,
- viafb_second_yres);
viafb_update_device_setting(viafb_second_xres,
viafb_second_yres, viafb_bpp1, 1);
@@ -289,7 +288,8 @@ static int viafb_set_par(struct fb_info *info)
refresh = viafb_get_refresh(info->var.xres, info->var.yres,
get_var_refresh(&info->var));
- if (vmode_entry) {
+ if (viafb_get_best_mode(viafbinfo->var.xres, viafbinfo->var.yres,
+ refresh)) {
if (viafb_dual_fb && viapar->iga_path == IGA2) {
viafb_bpp1 = info->var.bits_per_pixel;
viafb_refresh1 = refresh;
@@ -302,8 +302,7 @@ static int viafb_set_par(struct fb_info *info)
info->flags &= ~FBINFO_HWACCEL_DISABLED;
else
info->flags |= FBINFO_HWACCEL_DISABLED;
- viafb_setmode(vmode_entry, info->var.bits_per_pixel,
- vmode_entry1, viafb_bpp1);
+ viafb_setmode(info->var.bits_per_pixel, viafb_bpp1);
viafb_pan_display(&info->var, info);
}
@@ -348,8 +347,9 @@ static int viafb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct viafb_par *viapar = info->par;
- u32 vram_addr = (var->yoffset * var->xres_virtual + var->xoffset)
- * (var->bits_per_pixel / 8) + viapar->vram_addr;
+ u32 vram_addr = viapar->vram_addr
+ + var->yoffset * info->fix.line_length
+ + var->xoffset * info->var.bits_per_pixel / 8;
DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr);
if (!viafb_dual_fb) {
@@ -1158,7 +1158,8 @@ static ssize_t viafb_dvp0_proc_write(struct file *file,
for (i = 0; i < 3; i++) {
value = strsep(&pbuf, " ");
if (value != NULL) {
- strict_strtoul(value, 0, (unsigned long *)&reg_val);
+ if (kstrtou8(value, 0, &reg_val) < 0)
+ return -EINVAL;
DEBUG_MSG(KERN_INFO "DVP0:reg_val[%l]=:%x\n", i,
reg_val);
switch (i) {
@@ -1228,7 +1229,8 @@ static ssize_t viafb_dvp1_proc_write(struct file *file,
for (i = 0; i < 3; i++) {
value = strsep(&pbuf, " ");
if (value != NULL) {
- strict_strtoul(value, 0, (unsigned long *)&reg_val);
+ if (kstrtou8(value, 0, &reg_val) < 0)
+ return -EINVAL;
switch (i) {
case 0:
viafb_write_reg_mask(CR9B, VIACR,
@@ -1286,7 +1288,8 @@ static ssize_t viafb_dfph_proc_write(struct file *file,
if (copy_from_user(&buf[0], buffer, length))
return -EFAULT;
buf[length - 1] = '\0'; /*Ensure end string */
- strict_strtoul(&buf[0], 0, (unsigned long *)&reg_val);
+ if (kstrtou8(buf, 0, &reg_val) < 0)
+ return -EINVAL;
viafb_write_reg_mask(CR97, VIACR, reg_val, 0x0f);
return count;
}
@@ -1325,7 +1328,8 @@ static ssize_t viafb_dfpl_proc_write(struct file *file,
if (copy_from_user(&buf[0], buffer, length))
return -EFAULT;
buf[length - 1] = '\0'; /*Ensure end string */
- strict_strtoul(&buf[0], 0, (unsigned long *)&reg_val);
+ if (kstrtou8(buf, 0, &reg_val) < 0)
+ return -EINVAL;
viafb_write_reg_mask(CR99, VIACR, reg_val, 0x0f);
return count;
}
@@ -1394,8 +1398,8 @@ static ssize_t viafb_vt1636_proc_write(struct file *file,
for (i = 0; i < 2; i++) {
value = strsep(&pbuf, " ");
if (value != NULL) {
- strict_strtoul(value, 0,
- (unsigned long *)&reg_val.Data);
+ if (kstrtou8(value, 0, &reg_val.Data) < 0)
+ return -EINVAL;
switch (i) {
case 0:
reg_val.Index = 0x08;
@@ -1431,8 +1435,8 @@ static ssize_t viafb_vt1636_proc_write(struct file *file,
for (i = 0; i < 2; i++) {
value = strsep(&pbuf, " ");
if (value != NULL) {
- strict_strtoul(value, 0,
- (unsigned long *)&reg_val.Data);
+ if (kstrtou8(value, 0, &reg_val.Data) < 0)
+ return -EINVAL;
switch (i) {
case 0:
reg_val.Index = 0x08;
@@ -1729,7 +1733,6 @@ static struct viafb_pm_hooks viafb_fb_pm_hooks = {
int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
{
u32 default_xres, default_yres;
- struct VideoModeTable *vmode_entry;
struct fb_var_screeninfo default_var;
int rc;
u32 viafb_par_length;
@@ -1802,7 +1805,6 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
}
parse_mode(viafb_mode, &default_xres, &default_yres);
- vmode_entry = viafb_get_mode(default_xres, default_yres);
if (viafb_SAMM_ON == 1)
parse_mode(viafb_mode1, &viafb_second_xres,
&viafb_second_yres);
@@ -1812,9 +1814,8 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
default_var.xres_virtual = default_xres;
default_var.yres_virtual = default_yres;
default_var.bits_per_pixel = viafb_bpp;
- viafb_fill_var_timing_info(&default_var, viafb_get_refresh(
- default_var.xres, default_var.yres, viafb_refresh),
- viafb_get_mode(default_var.xres, default_var.yres));
+ viafb_fill_var_timing_info(&default_var, viafb_get_best_mode(
+ default_var.xres, default_var.yres, viafb_refresh));
viafb_setup_fixinfo(&viafbinfo->fix, viaparinfo);
viafbinfo->var = default_var;
@@ -1853,9 +1854,8 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
default_var.xres_virtual = viafb_second_xres;
default_var.yres_virtual = viafb_second_yres;
default_var.bits_per_pixel = viafb_bpp1;
- viafb_fill_var_timing_info(&default_var, viafb_get_refresh(
- default_var.xres, default_var.yres, viafb_refresh1),
- viafb_get_mode(default_var.xres, default_var.yres));
+ viafb_fill_var_timing_info(&default_var, viafb_get_best_mode(
+ default_var.xres, default_var.yres, viafb_refresh1));
viafb_setup_fixinfo(&viafbinfo1->fix, viaparinfo1);
viafb_check_var(&default_var, viafbinfo1);
@@ -1950,61 +1950,67 @@ static int __init viafb_setup(void)
if (!*this_opt)
continue;
- if (!strncmp(this_opt, "viafb_mode1=", 12))
+ if (!strncmp(this_opt, "viafb_mode1=", 12)) {
viafb_mode1 = kstrdup(this_opt + 12, GFP_KERNEL);
- else if (!strncmp(this_opt, "viafb_mode=", 11))
+ } else if (!strncmp(this_opt, "viafb_mode=", 11)) {
viafb_mode = kstrdup(this_opt + 11, GFP_KERNEL);
- else if (!strncmp(this_opt, "viafb_bpp1=", 11))
- strict_strtoul(this_opt + 11, 0,
- (unsigned long *)&viafb_bpp1);
- else if (!strncmp(this_opt, "viafb_bpp=", 10))
- strict_strtoul(this_opt + 10, 0,
- (unsigned long *)&viafb_bpp);
- else if (!strncmp(this_opt, "viafb_refresh1=", 15))
- strict_strtoul(this_opt + 15, 0,
- (unsigned long *)&viafb_refresh1);
- else if (!strncmp(this_opt, "viafb_refresh=", 14))
- strict_strtoul(this_opt + 14, 0,
- (unsigned long *)&viafb_refresh);
- else if (!strncmp(this_opt, "viafb_lcd_dsp_method=", 21))
- strict_strtoul(this_opt + 21, 0,
- (unsigned long *)&viafb_lcd_dsp_method);
- else if (!strncmp(this_opt, "viafb_lcd_panel_id=", 19))
- strict_strtoul(this_opt + 19, 0,
- (unsigned long *)&viafb_lcd_panel_id);
- else if (!strncmp(this_opt, "viafb_accel=", 12))
- strict_strtoul(this_opt + 12, 0,
- (unsigned long *)&viafb_accel);
- else if (!strncmp(this_opt, "viafb_SAMM_ON=", 14))
- strict_strtoul(this_opt + 14, 0,
- (unsigned long *)&viafb_SAMM_ON);
- else if (!strncmp(this_opt, "viafb_active_dev=", 17))
+ } else if (!strncmp(this_opt, "viafb_bpp1=", 11)) {
+ if (kstrtouint(this_opt + 11, 0, &viafb_bpp1) < 0)
+ return -EINVAL;
+ } else if (!strncmp(this_opt, "viafb_bpp=", 10)) {
+ if (kstrtouint(this_opt + 10, 0, &viafb_bpp) < 0)
+ return -EINVAL;
+ } else if (!strncmp(this_opt, "viafb_refresh1=", 15)) {
+ if (kstrtoint(this_opt + 15, 0, &viafb_refresh1) < 0)
+ return -EINVAL;
+ } else if (!strncmp(this_opt, "viafb_refresh=", 14)) {
+ if (kstrtoint(this_opt + 14, 0, &viafb_refresh) < 0)
+ return -EINVAL;
+ } else if (!strncmp(this_opt, "viafb_lcd_dsp_method=", 21)) {
+ if (kstrtoint(this_opt + 21, 0,
+ &viafb_lcd_dsp_method) < 0)
+ return -EINVAL;
+ } else if (!strncmp(this_opt, "viafb_lcd_panel_id=", 19)) {
+ if (kstrtoint(this_opt + 19, 0,
+ &viafb_lcd_panel_id) < 0)
+ return -EINVAL;
+ } else if (!strncmp(this_opt, "viafb_accel=", 12)) {
+ if (kstrtoint(this_opt + 12, 0, &viafb_accel) < 0)
+ return -EINVAL;
+ } else if (!strncmp(this_opt, "viafb_SAMM_ON=", 14)) {
+ if (kstrtoint(this_opt + 14, 0, &viafb_SAMM_ON) < 0)
+ return -EINVAL;
+ } else if (!strncmp(this_opt, "viafb_active_dev=", 17)) {
viafb_active_dev = kstrdup(this_opt + 17, GFP_KERNEL);
- else if (!strncmp(this_opt,
- "viafb_display_hardware_layout=", 30))
- strict_strtoul(this_opt + 30, 0,
- (unsigned long *)&viafb_display_hardware_layout);
- else if (!strncmp(this_opt, "viafb_second_size=", 18))
- strict_strtoul(this_opt + 18, 0,
- (unsigned long *)&viafb_second_size);
- else if (!strncmp(this_opt,
- "viafb_platform_epia_dvi=", 24))
- strict_strtoul(this_opt + 24, 0,
- (unsigned long *)&viafb_platform_epia_dvi);
- else if (!strncmp(this_opt,
- "viafb_device_lcd_dualedge=", 26))
- strict_strtoul(this_opt + 26, 0,
- (unsigned long *)&viafb_device_lcd_dualedge);
- else if (!strncmp(this_opt, "viafb_bus_width=", 16))
- strict_strtoul(this_opt + 16, 0,
- (unsigned long *)&viafb_bus_width);
- else if (!strncmp(this_opt, "viafb_lcd_mode=", 15))
- strict_strtoul(this_opt + 15, 0,
- (unsigned long *)&viafb_lcd_mode);
- else if (!strncmp(this_opt, "viafb_lcd_port=", 15))
+ } else if (!strncmp(this_opt,
+ "viafb_display_hardware_layout=", 30)) {
+ if (kstrtoint(this_opt + 30, 0,
+ &viafb_display_hardware_layout) < 0)
+ return -EINVAL;
+ } else if (!strncmp(this_opt, "viafb_second_size=", 18)) {
+ if (kstrtoint(this_opt + 18, 0, &viafb_second_size) < 0)
+ return -EINVAL;
+ } else if (!strncmp(this_opt,
+ "viafb_platform_epia_dvi=", 24)) {
+ if (kstrtoint(this_opt + 24, 0,
+ &viafb_platform_epia_dvi) < 0)
+ return -EINVAL;
+ } else if (!strncmp(this_opt,
+ "viafb_device_lcd_dualedge=", 26)) {
+ if (kstrtoint(this_opt + 26, 0,
+ &viafb_device_lcd_dualedge) < 0)
+ return -EINVAL;
+ } else if (!strncmp(this_opt, "viafb_bus_width=", 16)) {
+ if (kstrtoint(this_opt + 16, 0, &viafb_bus_width) < 0)
+ return -EINVAL;
+ } else if (!strncmp(this_opt, "viafb_lcd_mode=", 15)) {
+ if (kstrtoint(this_opt + 15, 0, &viafb_lcd_mode) < 0)
+ return -EINVAL;
+ } else if (!strncmp(this_opt, "viafb_lcd_port=", 15)) {
viafb_lcd_port = kstrdup(this_opt + 15, GFP_KERNEL);
- else if (!strncmp(this_opt, "viafb_dvi_port=", 15))
+ } else if (!strncmp(this_opt, "viafb_dvi_port=", 15)) {
viafb_dvi_port = kstrdup(this_opt + 15, GFP_KERNEL);
+ }
}
return 0;
}
@@ -2028,9 +2034,9 @@ int __init viafb_init(void)
return r;
#endif
if (parse_mode(viafb_mode, &dummy_x, &dummy_y)
- || !viafb_get_mode(dummy_x, dummy_y)
+ || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh)
|| parse_mode(viafb_mode1, &dummy_x, &dummy_y)
- || !viafb_get_mode(dummy_x, dummy_y)
+ || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh1)
|| viafb_bpp < 0 || viafb_bpp > 32
|| viafb_bpp1 < 0 || viafb_bpp1 > 32
|| parse_active_dev())
diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c
index 58df74e..0911cac 100644
--- a/drivers/video/via/viamode.c
+++ b/drivers/video/via/viamode.c
@@ -281,7 +281,7 @@ static struct crt_mode_table CRTM640x480[] = {
/*r_rate,hsp,vsp */
/*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
{REFRESH_60, M640X480_R60_HSP, M640X480_R60_VSP,
- {800, 640, 648, 144, 656, 96, 525, 480, 480, 45, 490, 2} },
+ {800, 640, 640, 160, 656, 96, 525, 480, 480, 45, 490, 2} },
{REFRESH_75, M640X480_R75_HSP, M640X480_R75_VSP,
{840, 640, 640, 200, 656, 64, 500, 480, 480, 20, 481, 3} },
{REFRESH_85, M640X480_R85_HSP, M640X480_R85_VSP,
@@ -863,26 +863,56 @@ int NUM_TOTAL_CLE266_ModeXregs = ARRAY_SIZE(CLE266_ModeXregs);
int NUM_TOTAL_PATCH_MODE = ARRAY_SIZE(res_patch_table);
-struct VideoModeTable *viafb_get_mode(int hres, int vres)
+static struct VideoModeTable *get_modes(struct VideoModeTable *vmt, int n,
+ int hres, int vres)
{
- u32 i;
- for (i = 0; i < ARRAY_SIZE(viafb_modes); i++)
- if (viafb_modes[i].mode_array &&
- viafb_modes[i].crtc[0].crtc.hor_addr == hres &&
- viafb_modes[i].crtc[0].crtc.ver_addr == vres)
+ int i;
+
+ for (i = 0; i < n; i++)
+ if (vmt[i].mode_array &&
+ vmt[i].crtc[0].crtc.hor_addr == hres &&
+ vmt[i].crtc[0].crtc.ver_addr == vres)
return &viafb_modes[i];
return NULL;
}
-struct VideoModeTable *viafb_get_rb_mode(int hres, int vres)
+static struct crt_mode_table *get_best_mode(struct VideoModeTable *vmt,
+ int refresh)
{
- u32 i;
- for (i = 0; i < ARRAY_SIZE(viafb_rb_modes); i++)
- if (viafb_rb_modes[i].mode_array &&
- viafb_rb_modes[i].crtc[0].crtc.hor_addr == hres &&
- viafb_rb_modes[i].crtc[0].crtc.ver_addr == vres)
- return &viafb_rb_modes[i];
+ struct crt_mode_table *best;
+ int i;
- return NULL;
+ if (!vmt)
+ return NULL;
+
+ best = &vmt->crtc[0];
+ for (i = 1; i < vmt->mode_array; i++) {
+ if (abs(vmt->crtc[i].refresh_rate - refresh)
+ < abs(best->refresh_rate - refresh))
+ best = &vmt->crtc[i];
+ }
+
+ return best;
+}
+
+static struct VideoModeTable *viafb_get_mode(int hres, int vres)
+{
+ return get_modes(viafb_modes, ARRAY_SIZE(viafb_modes), hres, vres);
+}
+
+struct crt_mode_table *viafb_get_best_mode(int hres, int vres, int refresh)
+{
+ return get_best_mode(viafb_get_mode(hres, vres), refresh);
+}
+
+static struct VideoModeTable *viafb_get_rb_mode(int hres, int vres)
+{
+ return get_modes(viafb_rb_modes, ARRAY_SIZE(viafb_rb_modes), hres,
+ vres);
+}
+
+struct crt_mode_table *viafb_get_best_rb_mode(int hres, int vres, int refresh)
+{
+ return get_best_mode(viafb_get_rb_mode(hres, vres), refresh);
}
diff --git a/drivers/video/via/viamode.h b/drivers/video/via/viamode.h
index 3751289..5917a2b 100644
--- a/drivers/video/via/viamode.h
+++ b/drivers/video/via/viamode.h
@@ -60,7 +60,7 @@ extern struct io_reg PM1024x768[];
extern struct patch_table res_patch_table[];
extern struct VPITTable VPIT;
-struct VideoModeTable *viafb_get_mode(int hres, int vres);
-struct VideoModeTable *viafb_get_rb_mode(int hres, int vres);
+struct crt_mode_table *viafb_get_best_mode(int hres, int vres, int refresh);
+struct crt_mode_table *viafb_get_best_rb_mode(int hres, int vres, int refresh);
#endif /* __VIAMODE_H__ */
diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c
index 0e120d6..777c21d 100644
--- a/drivers/video/vt8500lcdfb.c
+++ b/drivers/video/vt8500lcdfb.c
@@ -210,8 +210,8 @@ static int vt8500lcd_pan_display(struct fb_var_screeninfo *var,
struct vt8500lcd_info *fbi = to_vt8500lcd_info(info);
writel((1 << 31)
- | (((var->xres_virtual - var->xres) * pixlen / 4) << 20)
- | (off >> 2), fbi->regbase + 0x20);
+ | (((info->var.xres_virtual - info->var.xres) * pixlen / 4) << 20)
+ | (off >> 2), fbi->regbase + 0x20);
return 0;
}
@@ -355,7 +355,7 @@ static int __devinit vt8500lcd_probe(struct platform_device *pdev)
goto failed_free_palette;
}
- ret = request_irq(irq, vt8500lcd_handle_irq, IRQF_DISABLED, "LCD", fbi);
+ ret = request_irq(irq, vt8500lcd_handle_irq, 0, "LCD", fbi);
if (ret) {
dev_err(&pdev->dev, "request_irq failed: %d\n", ret);
ret = -EBUSY;
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c
index f9b3e3d..4e74d26 100644
--- a/drivers/video/vt8623fb.c
+++ b/drivers/video/vt8623fb.c
@@ -620,13 +620,14 @@ static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *i
unsigned int offset;
/* Calculate the offset */
- if (var->bits_per_pixel == 0) {
- offset = (var->yoffset / 16) * var->xres_virtual + var->xoffset;
+ if (info->var.bits_per_pixel == 0) {
+ offset = (var->yoffset / 16) * info->var.xres_virtual
+ + var->xoffset;
offset = offset >> 3;
} else {
offset = (var->yoffset * info->fix.line_length) +
- (var->xoffset * var->bits_per_pixel / 8);
- offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 1);
+ (var->xoffset * info->var.bits_per_pixel / 8);
+ offset = offset >> ((info->var.bits_per_pixel == 4) ? 2 : 1);
}
/* Set the offset */
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index 77dea01..fcb6cd9 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -23,7 +23,6 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/version.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 410fba4..809cbda 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -494,15 +494,16 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason,
asminline_call(&cmn_regs, cru_rom_addr);
die_nmi_called = 1;
spin_unlock_irqrestore(&rom_lock, rom_pl);
+
+ if (allow_kdump)
+ hpwdt_stop();
+
if (!is_icru) {
if (cmn_regs.u1.ral == 0) {
- printk(KERN_WARNING "hpwdt: An NMI occurred, "
+ panic("An NMI occurred, "
"but unable to determine source.\n");
}
}
-
- if (allow_kdump)
- hpwdt_stop();
panic("An NMI occurred, please see the Integrated "
"Management Log for details.\n");
diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c
index 7d82ada..102aed0 100644
--- a/drivers/watchdog/lantiq_wdt.c
+++ b/drivers/watchdog/lantiq_wdt.c
@@ -51,16 +51,16 @@ static int ltq_wdt_ok_to_close;
static void
ltq_wdt_enable(void)
{
- ltq_wdt_timeout = ltq_wdt_timeout *
+ unsigned long int timeout = ltq_wdt_timeout *
(ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000;
- if (ltq_wdt_timeout > LTQ_MAX_TIMEOUT)
- ltq_wdt_timeout = LTQ_MAX_TIMEOUT;
+ if (timeout > LTQ_MAX_TIMEOUT)
+ timeout = LTQ_MAX_TIMEOUT;
/* write the first password magic */
ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
/* write the second magic plus the configuration and new timeout */
ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV |
- LTQ_WDT_PW2 | ltq_wdt_timeout, ltq_wdt_membase + LTQ_WDT_CR);
+ LTQ_WDT_PW2 | timeout, ltq_wdt_membase + LTQ_WDT_CR);
}
static void
diff --git a/drivers/watchdog/sbc_epx_c3.c b/drivers/watchdog/sbc_epx_c3.c
index 3066a51..eaca366 100644
--- a/drivers/watchdog/sbc_epx_c3.c
+++ b/drivers/watchdog/sbc_epx_c3.c
@@ -173,7 +173,7 @@ static struct notifier_block epx_c3_notifier = {
.notifier_call = epx_c3_notify_sys,
};
-static const char banner[] __initdata = KERN_INFO PFX
+static const char banner[] __initconst = KERN_INFO PFX
"Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n";
static int __init watchdog_init(void)
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index d33520d..1199da0 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -59,7 +59,7 @@ static struct watchdog_device *wdd;
static int watchdog_ping(struct watchdog_device *wddev)
{
- if (test_bit(WDOG_ACTIVE, &wdd->status)) {
+ if (test_bit(WDOG_ACTIVE, &wddev->status)) {
if (wddev->ops->ping)
return wddev->ops->ping(wddev); /* ping the watchdog */
else
@@ -81,12 +81,12 @@ static int watchdog_start(struct watchdog_device *wddev)
{
int err;
- if (!test_bit(WDOG_ACTIVE, &wdd->status)) {
+ if (!test_bit(WDOG_ACTIVE, &wddev->status)) {
err = wddev->ops->start(wddev);
if (err < 0)
return err;
- set_bit(WDOG_ACTIVE, &wdd->status);
+ set_bit(WDOG_ACTIVE, &wddev->status);
}
return 0;
}
@@ -105,18 +105,18 @@ static int watchdog_stop(struct watchdog_device *wddev)
{
int err = -EBUSY;
- if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) {
+ if (test_bit(WDOG_NO_WAY_OUT, &wddev->status)) {
pr_info("%s: nowayout prevents watchdog to be stopped!\n",
- wdd->info->identity);
+ wddev->info->identity);
return err;
}
- if (test_bit(WDOG_ACTIVE, &wdd->status)) {
+ if (test_bit(WDOG_ACTIVE, &wddev->status)) {
err = wddev->ops->stop(wddev);
if (err < 0)
return err;
- clear_bit(WDOG_ACTIVE, &wdd->status);
+ clear_bit(WDOG_ACTIVE, &wddev->status);
}
return 0;
}
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index da70f5c..7523719 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -54,7 +54,7 @@
* This lock protects updates to the following mapping and reference-count
* arrays. The lock does not need to be acquired to read the mapping tables.
*/
-static DEFINE_SPINLOCK(irq_mapping_update_lock);
+static DEFINE_MUTEX(irq_mapping_update_lock);
static LIST_HEAD(xen_irq_list_head);
@@ -631,7 +631,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
int irq = -1;
struct physdev_irq irq_op;
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
irq = find_irq_by_gsi(gsi);
if (irq != -1) {
@@ -684,7 +684,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
handle_edge_irq, name);
out:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
return irq;
}
@@ -710,7 +710,7 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
{
int irq, ret;
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
irq = xen_allocate_irq_dynamic();
if (irq == -1)
@@ -724,10 +724,10 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
if (ret < 0)
goto error_irq;
out:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
return irq;
error_irq:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
xen_free_irq(irq);
return -1;
}
@@ -740,7 +740,7 @@ int xen_destroy_irq(int irq)
struct irq_info *info = info_for_irq(irq);
int rc = -ENOENT;
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
desc = irq_to_desc(irq);
if (!desc)
@@ -766,7 +766,7 @@ int xen_destroy_irq(int irq)
xen_free_irq(irq);
out:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
return rc;
}
@@ -776,7 +776,7 @@ int xen_irq_from_pirq(unsigned pirq)
struct irq_info *info;
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
list_for_each_entry(info, &xen_irq_list_head, list) {
if (info == NULL || info->type != IRQT_PIRQ)
@@ -787,7 +787,7 @@ int xen_irq_from_pirq(unsigned pirq)
}
irq = -1;
out:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
return irq;
}
@@ -802,7 +802,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
{
int irq;
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
irq = evtchn_to_irq[evtchn];
@@ -818,7 +818,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
}
out:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
return irq;
}
@@ -829,7 +829,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
struct evtchn_bind_ipi bind_ipi;
int evtchn, irq;
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
irq = per_cpu(ipi_to_irq, cpu)[ipi];
@@ -853,7 +853,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
}
out:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
return irq;
}
@@ -878,7 +878,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
struct evtchn_bind_virq bind_virq;
int evtchn, irq;
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
irq = per_cpu(virq_to_irq, cpu)[virq];
@@ -903,7 +903,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
}
out:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
return irq;
}
@@ -913,7 +913,7 @@ static void unbind_from_irq(unsigned int irq)
struct evtchn_close close;
int evtchn = evtchn_from_irq(irq);
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
if (VALID_EVTCHN(evtchn)) {
close.port = evtchn;
@@ -943,7 +943,7 @@ static void unbind_from_irq(unsigned int irq)
xen_free_irq(irq);
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
}
int bind_evtchn_to_irqhandler(unsigned int evtchn,
@@ -1279,7 +1279,7 @@ void rebind_evtchn_irq(int evtchn, int irq)
will also be masked. */
disable_irq(irq);
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
/* After resume the irq<->evtchn mappings are all cleared out */
BUG_ON(evtchn_to_irq[evtchn] != -1);
@@ -1289,7 +1289,7 @@ void rebind_evtchn_irq(int evtchn, int irq)
xen_irq_info_evtchn_init(irq, evtchn);
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
/* new event channels are always bound to cpu 0 */
irq_set_affinity(irq, cpumask_of(0));
diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c
index e0c2807..181fa81 100644
--- a/drivers/zorro/zorro.c
+++ b/drivers/zorro/zorro.c
@@ -148,10 +148,10 @@ static int __init amiga_zorro_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, bus);
- /* Register all devices */
pr_info("Zorro: Probing AutoConfig expansion devices: %u device%s\n",
zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s");
+ /* First identify all devices ... */
for (i = 0; i < zorro_num_autocon; i++) {
z = &zorro_autocon[i];
z->id = (z->rom.er_Manufacturer<<16) | (z->rom.er_Product<<8);
@@ -172,6 +172,11 @@ static int __init amiga_zorro_probe(struct platform_device *pdev)
dev_set_name(&z->dev, "%02x", i);
z->dev.parent = &bus->dev;
z->dev.bus = &zorro_bus_type;
+ }
+
+ /* ... then register them */
+ for (i = 0; i < zorro_num_autocon; i++) {
+ z = &zorro_autocon[i];
error = device_register(&z->dev);
if (error) {
dev_err(&bus->dev, "Error registering device %s\n",
OpenPOWER on IntegriCloud