aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CREDITS2
-rw-r--r--Documentation/Changes43
-rw-r--r--Documentation/CodingStyle4
-rw-r--r--Documentation/cgroups/blkio-controller.txt12
-rw-r--r--Documentation/feature-removal-schedule.txt22
-rw-r--r--Documentation/filesystems/caching/netfs-api.txt16
-rw-r--r--Documentation/hwmon/f71882fg4
-rw-r--r--Documentation/hwmon/k10temp8
-rw-r--r--Documentation/kernel-parameters.txt2
-rw-r--r--Documentation/laptops/thinkpad-acpi.txt5
-rw-r--r--Documentation/networking/ip-sysctl.txt2
-rw-r--r--Documentation/power/runtime_pm.txt26
-rw-r--r--Documentation/spinlocks.txt45
-rw-r--r--MAINTAINERS15
-rw-r--r--Makefile2
-rw-r--r--README42
-rw-r--r--arch/arm/common/dmabounce.c2
-rw-r--r--arch/arm/kernel/perf_event.c6
-rw-r--r--arch/arm/kernel/setup.c2
-rw-r--r--arch/arm/kernel/smp_twd.c2
-rw-r--r--arch/arm/mach-at91/at91cap9.c8
-rw-r--r--arch/arm/mach-at91/at91cap9_devices.c2
-rw-r--r--arch/arm/mach-at91/at91rm9200.c6
-rw-r--r--arch/arm/mach-at91/at91rm9200_devices.c2
-rw-r--r--arch/arm/mach-at91/at91sam9260_devices.c2
-rw-r--r--arch/arm/mach-at91/at91sam9261_devices.c2
-rw-r--r--arch/arm/mach-at91/at91sam9263_devices.c2
-rw-r--r--arch/arm/mach-at91/at91sam9g45.c10
-rw-r--r--arch/arm/mach-at91/at91sam9g45_devices.c2
-rw-r--r--arch/arm/mach-at91/at91sam9rl.c4
-rw-r--r--arch/arm/mach-at91/at91sam9rl_devices.c2
-rw-r--r--arch/arm/mach-at91/board-cap9adk.c2
-rw-r--r--arch/arm/mach-at91/board-sam9260ek.c2
-rw-r--r--arch/arm/mach-at91/board-sam9261ek.c2
-rw-r--r--arch/arm/mach-at91/board-sam9263ek.c2
-rw-r--r--arch/arm/mach-at91/board-sam9g20ek.c2
-rw-r--r--arch/arm/mach-at91/board-sam9m10g45ek.c2
-rw-r--r--arch/arm/mach-at91/include/mach/system_rev.h10
-rw-r--r--arch/arm/mach-davinci/irq.c2
-rw-r--r--arch/arm/mach-ep93xx/core.c4
-rw-r--r--arch/arm/mach-exynos4/cpu.c6
-rw-r--r--arch/arm/mach-exynos4/dev-audio.c2
-rw-r--r--arch/arm/mach-exynos4/headsmp.S2
-rw-r--r--arch/arm/mach-exynos4/mach-smdkv310.c8
-rw-r--r--arch/arm/mach-mmp/pxa168.c2
-rw-r--r--arch/arm/mach-mmp/pxa910.c2
-rw-r--r--arch/arm/mach-omap1/board-ams-delta.c8
-rw-r--r--arch/arm/mach-omap1/gpio15xx.c4
-rw-r--r--arch/arm/mach-omap1/gpio16xx.c10
-rw-r--r--arch/arm/mach-omap1/gpio7xx.c14
-rw-r--r--arch/arm/mach-omap2/board-rx51-peripherals.c2
-rw-r--r--arch/arm/mach-pxa/mfp-pxa2xx.c4
-rw-r--r--arch/arm/mach-pxa/raumfeld.c36
-rw-r--r--arch/arm/mach-s3c2440/mach-mini2440.c2
-rw-r--r--arch/arm/mach-s3c64xx/dev-spi.c2
-rw-r--r--arch/arm/mach-s5p64x0/dev-spi.c4
-rw-r--r--arch/arm/mach-s5pc100/dev-spi.c4
-rw-r--r--arch/arm/mach-s5pv210/dev-spi.c2
-rw-r--r--arch/arm/mach-vt8500/irq.c21
-rw-r--r--arch/arm/mm/cache-l2x0.c19
-rw-r--r--arch/arm/mm/mmu.c5
-rw-r--r--arch/arm/mm/nommu.c4
-rw-r--r--arch/arm/plat-orion/gpio.c2
-rw-r--r--arch/arm/plat-pxa/gpio.c10
-rw-r--r--arch/arm/plat-s3c24xx/dma.c12
-rw-r--r--arch/arm/plat-s5p/irq-gpioint.c2
-rw-r--r--arch/arm/plat-s5p/s5p-time.c4
-rw-r--r--arch/arm/plat-samsung/include/plat/devs.h6
-rw-r--r--arch/arm/plat-samsung/include/plat/s3c64xx-spi.h2
-rw-r--r--arch/arm/plat-samsung/irq-uart.c2
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-memory.c30
-rw-r--r--arch/x86/include/asm/mmzone_32.h2
-rw-r--r--arch/x86/kernel/acpi/realmode/wakeup.S14
-rw-r--r--arch/x86/kernel/acpi/realmode/wakeup.h6
-rw-r--r--arch/x86/kernel/acpi/sleep.c6
-rw-r--r--arch/x86/kernel/reboot.c8
-rw-r--r--arch/x86/mm/init_64.c3
-rw-r--r--arch/x86/oprofile/nmi_int.c14
-rw-r--r--arch/x86/pci/xen.c40
-rw-r--r--arch/x86/platform/efi/efi.c3
-rw-r--r--arch/x86/xen/mmu.c4
-rw-r--r--block/cfq-iosched.c8
-rw-r--r--drivers/base/memory.c1
-rw-r--r--drivers/base/syscore.c8
-rw-r--r--drivers/block/drbd/drbd_actlog.c2
-rw-r--r--drivers/block/drbd/drbd_bitmap.c37
-rw-r--r--drivers/block/drbd/drbd_receiver.c6
-rw-r--r--drivers/block/drbd/drbd_worker.c7
-rw-r--r--drivers/char/agp/intel-agp.h7
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c2
-rw-r--r--drivers/firewire/ohci.c6
-rw-r--r--drivers/gpio/langwell_gpio.c2
-rw-r--r--drivers/gpio/tps65910-gpio.c2
-rw-r--r--drivers/gpu/drm/drm_crtc.c3
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c16
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c45
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c11
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h32
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c80
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c19
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c118
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c17
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c2
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c167
-rw-r--r--drivers/gpu/drm/radeon/evergreen_blit_kms.c9
-rw-r--r--drivers/gpu/drm/radeon/evergreend.h4
-rw-r--r--drivers/gpu/drm/radeon/ni.c1
-rw-r--r--drivers/gpu/drm/radeon/nid.h2
-rw-r--r--drivers/gpu/drm/radeon/r600.c1
-rw-r--r--drivers/gpu/drm/radeon/r600d.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_bios.c21
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_reg.h2
-rw-r--r--drivers/gpu/drm/radeon/rs600.c6
-rw-r--r--drivers/gpu/drm/radeon/rv770.c7
-rw-r--r--drivers/hwmon/Kconfig2
-rw-r--r--drivers/hwmon/adm1275.c16
-rw-r--r--drivers/hwmon/emc6w201.c58
-rw-r--r--drivers/hwmon/f71882fg.c19
-rw-r--r--drivers/hwmon/hwmon-vid.c2
-rw-r--r--drivers/hwmon/lm95241.c22
-rw-r--r--drivers/hwmon/pmbus.c19
-rw-r--r--drivers/hwmon/pmbus_core.c11
-rw-r--r--drivers/hwmon/sch5627.c2
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c8
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c7
-rw-r--r--drivers/i2c/busses/i2c-tegra.c8
-rw-r--r--drivers/infiniband/core/cm.c3
-rw-r--r--drivers/infiniband/core/uverbs_main.c3
-rw-r--r--drivers/input/keyboard/pmic8xxx-keypad.c3
-rw-r--r--drivers/input/misc/pmic8xxx-pwrkey.c3
-rw-r--r--drivers/leds/leds-pca9532.c2
-rw-r--r--drivers/media/rc/fintek-cir.c5
-rw-r--r--drivers/media/rc/imon.c19
-rw-r--r--drivers/media/rc/ir-raw.c4
-rw-r--r--drivers/media/rc/ite-cir.c12
-rw-r--r--drivers/media/rc/ite-cir.h3
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c58
-rw-r--r--drivers/media/rc/lirc_dev.c37
-rw-r--r--drivers/media/rc/mceusb.c80
-rw-r--r--drivers/media/rc/nuvoton-cir.c2
-rw-r--r--drivers/media/rc/nuvoton-cir.h1
-rw-r--r--drivers/media/rc/rc-main.c48
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c2
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c8
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c8
-rw-r--r--drivers/media/video/m5mols/m5mols.h57
-rw-r--r--drivers/media/video/m5mols/m5mols_capture.c22
-rw-r--r--drivers/media/video/m5mols/m5mols_controls.c6
-rw-r--r--drivers/media/video/m5mols/m5mols_core.c144
-rw-r--r--drivers/media/video/m5mols/m5mols_reg.h21
-rw-r--r--drivers/media/video/msp3400-driver.c12
-rw-r--r--drivers/media/video/mx1_camera.c10
-rw-r--r--drivers/media/video/omap/omap_vout.c18
-rw-r--r--drivers/media/video/omap/omap_voutlib.c6
-rw-r--r--drivers/media/video/omap3isp/isp.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c4
-rw-r--r--drivers/media/video/pwc/pwc-ctrl.c2
-rw-r--r--drivers/media/video/pwc/pwc-if.c152
-rw-r--r--drivers/media/video/pwc/pwc.h4
-rw-r--r--drivers/media/video/s5p-fimc/fimc-capture.c21
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.c28
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.h29
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c2
-rw-r--r--drivers/media/video/tuner-core.c229
-rw-r--r--drivers/media/video/uvc/uvc_entity.c34
-rw-r--r--drivers/media/video/uvc/uvc_queue.c2
-rw-r--r--drivers/media/video/uvc/uvc_video.c4
-rw-r--r--drivers/media/video/v4l2-dev.c39
-rw-r--r--drivers/media/video/v4l2-ioctl.c18
-rw-r--r--drivers/media/video/videobuf2-core.c14
-rw-r--r--drivers/media/video/videobuf2-dma-sg.c2
-rw-r--r--drivers/mfd/Kconfig3
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/asic3.c1
-rw-r--r--drivers/mfd/htc-pasic3.c1
-rw-r--r--drivers/mfd/omap-usb-host.c131
-rw-r--r--drivers/mfd/tps65911-comparator.c2
-rw-r--r--drivers/mmc/core/mmc.c77
-rw-r--r--drivers/mmc/host/mmci.c2
-rw-r--r--drivers/mmc/host/mmci.h5
-rw-r--r--drivers/net/natsemi.c6
-rw-r--r--drivers/net/sh_eth.c6
-rw-r--r--drivers/net/slip.c2
-rw-r--r--drivers/net/usb/hso.c7
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c3
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h5
-rw-r--r--drivers/net/wireless/ath/ath5k/desc.c3
-rw-r--r--drivers/net/wireless/ath/ath5k/pci.c7
-rw-r--r--drivers/net/wireless/ath/ath5k/sysfs.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c3
-rw-r--r--drivers/net/wireless/ath/carl9170/usb.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/sw.c1
-rw-r--r--drivers/pci/pci.c2
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/setup-bus.c15
-rw-r--r--drivers/pcmcia/pxa2xx_vpac270.c4
-rw-r--r--drivers/platform/x86/acer-wmi.c47
-rw-r--r--drivers/platform/x86/asus-wmi.c1
-rw-r--r--drivers/platform/x86/compal-laptop.c4
-rw-r--r--drivers/platform/x86/dell-laptop.c30
-rw-r--r--drivers/platform/x86/hp-wmi.c11
-rw-r--r--drivers/platform/x86/intel_oaktrail.c1
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c72
-rw-r--r--drivers/regulator/db8500-prcmu.c14
-rw-r--r--drivers/regulator/max8952.c2
-rw-r--r--drivers/regulator/max8997.c55
-rw-r--r--drivers/scsi/Kconfig13
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/hpsa.c16
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c4
-rw-r--r--drivers/scsi/isci/Makefile8
-rw-r--r--drivers/scsi/isci/firmware/Makefile19
-rw-r--r--drivers/scsi/isci/firmware/README36
-rw-r--r--drivers/scsi/isci/firmware/create_fw.c99
-rw-r--r--drivers/scsi/isci/firmware/create_fw.h77
-rw-r--r--drivers/scsi/isci/host.c2751
-rw-r--r--drivers/scsi/isci/host.h542
-rw-r--r--drivers/scsi/isci/init.c565
-rw-r--r--drivers/scsi/isci/isci.h538
-rw-r--r--drivers/scsi/isci/phy.c1312
-rw-r--r--drivers/scsi/isci/phy.h504
-rw-r--r--drivers/scsi/isci/port.c1757
-rw-r--r--drivers/scsi/isci/port.h306
-rw-r--r--drivers/scsi/isci/port_config.c754
-rw-r--r--drivers/scsi/isci/probe_roms.c243
-rw-r--r--drivers/scsi/isci/probe_roms.h249
-rw-r--r--drivers/scsi/isci/registers.h1934
-rw-r--r--drivers/scsi/isci/remote_device.c1501
-rw-r--r--drivers/scsi/isci/remote_device.h352
-rw-r--r--drivers/scsi/isci/remote_node_context.c627
-rw-r--r--drivers/scsi/isci/remote_node_context.h224
-rw-r--r--drivers/scsi/isci/remote_node_table.c598
-rw-r--r--drivers/scsi/isci/remote_node_table.h188
-rw-r--r--drivers/scsi/isci/request.c3391
-rw-r--r--drivers/scsi/isci/request.h448
-rw-r--r--drivers/scsi/isci/sas.h219
-rw-r--r--drivers/scsi/isci/scu_completion_codes.h283
-rw-r--r--drivers/scsi/isci/scu_event_codes.h336
-rw-r--r--drivers/scsi/isci/scu_remote_node_context.h229
-rw-r--r--drivers/scsi/isci/scu_task_context.h942
-rw-r--r--drivers/scsi/isci/task.c1676
-rw-r--r--drivers/scsi/isci/task.h367
-rw-r--r--drivers/scsi/isci/unsolicited_frame_control.c225
-rw-r--r--drivers/scsi/isci/unsolicited_frame_control.h278
-rw-r--r--drivers/spi/spi_s3c64xx.c4
-rw-r--r--drivers/ssb/driver_pcicore.c18
-rw-r--r--drivers/staging/lirc/lirc_imon.c10
-rw-r--r--drivers/staging/lirc/lirc_serial.c44
-rw-r--r--drivers/staging/lirc/lirc_sir.c11
-rw-r--r--drivers/staging/lirc/lirc_zilog.c4
-rw-r--r--drivers/tty/serial/atmel_serial.c3
-rw-r--r--drivers/usb/core/message.c11
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c36
-rw-r--r--drivers/video/amba-clcd.c2
-rw-r--r--drivers/video/fsl-diu-fb.c16
-rw-r--r--drivers/video/geode/gx1fb_core.c14
-rw-r--r--drivers/video/hecubafb.c3
-rw-r--r--drivers/video/sh_mobile_meram.c2
-rw-r--r--drivers/video/sm501fb.c2
-rw-r--r--drivers/video/udlfb.c8
-rw-r--r--drivers/video/vesafb.c1
-rw-r--r--drivers/w1/masters/ds1wm.c5
-rw-r--r--firmware/Makefile1
-rw-r--r--firmware/isci/isci_firmware.bin.ihex16
-rw-r--r--fs/binfmt_elf_fdpic.c1
-rw-r--r--fs/btrfs/ctree.h5
-rw-r--r--fs/btrfs/inode.c12
-rw-r--r--fs/btrfs/super.c6
-rw-r--r--fs/btrfs/volumes.c3
-rw-r--r--fs/ceph/file.c14
-rw-r--r--fs/cifs/cifsfs.c8
-rw-r--r--fs/cifs/cifsproto.h6
-rw-r--r--fs/cifs/connect.c132
-rw-r--r--fs/cifs/fscache.c1
-rw-r--r--fs/fscache/page.c44
-rw-r--r--fs/hfsplus/super.c2
-rw-r--r--fs/hfsplus/wrapper.c7
-rw-r--r--fs/locks.c30
-rw-r--r--fs/nfs/fscache.c8
-rw-r--r--fs/nfs/nfs4filelayout.c1
-rw-r--r--fs/nfs/nfs4xdr.c2
-rw-r--r--fs/nfs/write.c2
-rw-r--r--fs/xfs/xfs_inode_item.c14
-rw-r--r--fs/xfs/xfs_trans.c4
-rw-r--r--include/linux/drbd_limits.h4
-rw-r--r--include/linux/fscache.h21
-rw-r--r--include/linux/fsl-diu-fb.h6
-rw-r--r--include/linux/irq.h3
-rw-r--r--include/linux/memory.h2
-rw-r--r--include/linux/mfd/ds1wm.h7
-rw-r--r--include/linux/mmc/card.h13
-rw-r--r--include/linux/sched.h2
-rw-r--r--include/media/lirc_dev.h2
-rw-r--r--include/media/m5mols.h4
-rw-r--r--include/media/v4l2-subdev.h10
-rw-r--r--include/net/sctp/command.h1
-rw-r--r--include/net/sctp/ulpevent.h2
-rw-r--r--include/sound/sb16_csp.h9
-rw-r--r--kernel/irq/generic-chip.c18
-rw-r--r--kernel/jump_label.c14
-rw-r--r--kernel/power/snapshot.c6
-rw-r--r--kernel/resource.c116
-rw-r--r--kernel/sched.c9
-rw-r--r--lib/debugobjects.c2
-rw-r--r--mm/memcontrol.c140
-rw-r--r--mm/memory.c1
-rw-r--r--mm/nommu.c9
-rw-r--r--mm/vmscan.c59
-rw-r--r--net/bluetooth/hci_conn.c3
-rw-r--r--net/bluetooth/hidp/core.c18
-rw-r--r--net/bluetooth/hidp/hidp.h1
-rw-r--r--net/bluetooth/l2cap_core.c5
-rw-r--r--net/ceph/osd_client.c10
-rw-r--r--net/ipv4/tcp.c10
-rw-r--r--net/ipv4/udp.c10
-rw-r--r--net/mac80211/scan.c3
-rw-r--r--net/mac80211/wpa.c16
-rw-r--r--net/sctp/outqueue.c20
-rw-r--r--net/sctp/protocol.c11
-rw-r--r--net/sctp/sm_sideeffect.c20
-rw-r--r--net/sctp/sm_statefuns.c32
-rw-r--r--net/sctp/sm_statetable.c2
-rw-r--r--net/sctp/socket.c36
-rw-r--r--net/sctp/ulpevent.c16
-rw-r--r--net/sunrpc/rpcb_clnt.c2
-rw-r--r--net/sunrpc/sched.c27
-rw-r--r--net/wireless/core.c12
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/nl80211.c24
-rw-r--r--net/wireless/scan.c10
-rw-r--r--net/xfrm/xfrm_state.c2
-rwxr-xr-xscripts/depmod.sh10
-rw-r--r--sound/atmel/abdac.c2
-rw-r--r--sound/atmel/ac97c.c2
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pcm.c4
-rw-r--r--sound/pci/hda/hda_eld.c2
-rw-r--r--sound/pci/hda/patch_conexant.c4
-rw-r--r--sound/pci/hda/patch_realtek.c33
-rw-r--r--sound/pci/rme9652/hdspm.c8
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.c13
-rw-r--r--sound/soc/codecs/ak4642.c2
-rw-r--r--sound/soc/codecs/tlv320aic26.c14
-rw-r--r--sound/soc/codecs/tlv320aic3x.c9
-rw-r--r--sound/soc/codecs/wm8731.c29
-rw-r--r--sound/soc/codecs/wm8994.c2
-rw-r--r--sound/soc/soc-core.c5
-rw-r--r--sound/soc/tegra/tegra_i2s.c6
-rw-r--r--sound/spi/at73c213.c2
350 files changed, 26458 insertions, 1786 deletions
diff --git a/CREDITS b/CREDITS
index d78359f5f64..1deb331d96e 100644
--- a/CREDITS
+++ b/CREDITS
@@ -518,7 +518,7 @@ N: Zach Brown
E: zab@zabbo.net
D: maestro pci sound
-M: David Brownell
+N: David Brownell
D: Kernel engineer, mentor, and friend. Maintained USB EHCI and
D: gadget layers, SPI subsystem, GPIO subsystem, and more than a few
D: device drivers. His encouragement also helped many engineers get
diff --git a/Documentation/Changes b/Documentation/Changes
index 5f4828a034e..b1758088527 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -2,13 +2,7 @@ Intro
=====
This document is designed to provide a list of the minimum levels of
-software necessary to run the 2.6 kernels, as well as provide brief
-instructions regarding any other "Gotchas" users may encounter when
-trying life on the Bleeding Edge. If upgrading from a pre-2.4.x
-kernel, please consult the Changes file included with 2.4.x kernels for
-additional information; most of that information will not be repeated
-here. Basically, this document assumes that your system is already
-functional and running at least 2.4.x kernels.
+software necessary to run the 3.0 kernels.
This document is originally based on my "Changes" file for 2.0.x kernels
and therefore owes credit to the same people as that file (Jared Mauch,
@@ -22,11 +16,10 @@ Upgrade to at *least* these software revisions before thinking you've
encountered a bug! If you're unsure what version you're currently
running, the suggested command should tell you.
-Again, keep in mind that this list assumes you are already
-functionally running a Linux 2.4 kernel. Also, not all tools are
-necessary on all systems; obviously, if you don't have any ISDN
-hardware, for example, you probably needn't concern yourself with
-isdn4k-utils.
+Again, keep in mind that this list assumes you are already functionally
+running a Linux kernel. Also, not all tools are necessary on all
+systems; obviously, if you don't have any ISDN hardware, for example,
+you probably needn't concern yourself with isdn4k-utils.
o Gnu C 3.2 # gcc --version
o Gnu make 3.80 # make --version
@@ -114,12 +107,12 @@ Ksymoops
If the unthinkable happens and your kernel oopses, you may need the
ksymoops tool to decode it, but in most cases you don't.
-In the 2.6 kernel it is generally preferred to build the kernel with
-CONFIG_KALLSYMS so that it produces readable dumps that can be used as-is
-(this also produces better output than ksymoops).
-If for some reason your kernel is not build with CONFIG_KALLSYMS and
-you have no way to rebuild and reproduce the Oops with that option, then
-you can still decode that Oops with ksymoops.
+It is generally preferred to build the kernel with CONFIG_KALLSYMS so
+that it produces readable dumps that can be used as-is (this also
+produces better output than ksymoops). If for some reason your kernel
+is not build with CONFIG_KALLSYMS and you have no way to rebuild and
+reproduce the Oops with that option, then you can still decode that Oops
+with ksymoops.
Module-Init-Tools
-----------------
@@ -261,8 +254,8 @@ needs to be recompiled or (preferably) upgraded.
NFS-utils
---------
-In 2.4 and earlier kernels, the nfs server needed to know about any
-client that expected to be able to access files via NFS. This
+In ancient (2.4 and earlier) kernels, the nfs server needed to know
+about any client that expected to be able to access files via NFS. This
information would be given to the kernel by "mountd" when the client
mounted the filesystem, or by "exportfs" at system startup. exportfs
would take information about active clients from /var/lib/nfs/rmtab.
@@ -272,11 +265,11 @@ which is not always easy, particularly when trying to implement
fail-over. Even when the system is working well, rmtab suffers from
getting lots of old entries that never get removed.
-With 2.6 we have the option of having the kernel tell mountd when it
-gets a request from an unknown host, and mountd can give appropriate
-export information to the kernel. This removes the dependency on
-rmtab and means that the kernel only needs to know about currently
-active clients.
+With modern kernels we have the option of having the kernel tell mountd
+when it gets a request from an unknown host, and mountd can give
+appropriate export information to the kernel. This removes the
+dependency on rmtab and means that the kernel only needs to know about
+currently active clients.
To enable this new functionality, you need to:
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
index 58b0bf91783..fa6e25b94a5 100644
--- a/Documentation/CodingStyle
+++ b/Documentation/CodingStyle
@@ -680,8 +680,8 @@ ones already enabled by DEBUG.
Chapter 14: Allocating memory
The kernel provides the following general purpose memory allocators:
-kmalloc(), kzalloc(), kcalloc(), and vmalloc(). Please refer to the API
-documentation for further information about them.
+kmalloc(), kzalloc(), kcalloc(), vmalloc(), and vzalloc(). Please refer to
+the API documentation for further information about them.
The preferred form for passing a size of a struct is the following:
diff --git a/Documentation/cgroups/blkio-controller.txt b/Documentation/cgroups/blkio-controller.txt
index cd45c8ea746..84f0a15fc21 100644
--- a/Documentation/cgroups/blkio-controller.txt
+++ b/Documentation/cgroups/blkio-controller.txt
@@ -77,7 +77,7 @@ Throttling/Upper Limit policy
- Specify a bandwidth rate on particular device for root group. The format
for policy is "<major>:<minor> <byes_per_second>".
- echo "8:16 1048576" > /sys/fs/cgroup/blkio/blkio.read_bps_device
+ echo "8:16 1048576" > /sys/fs/cgroup/blkio/blkio.throttle.read_bps_device
Above will put a limit of 1MB/second on reads happening for root group
on device having major/minor number 8:16.
@@ -90,7 +90,7 @@ Throttling/Upper Limit policy
1024+0 records out
4194304 bytes (4.2 MB) copied, 4.0001 s, 1.0 MB/s
- Limits for writes can be put using blkio.write_bps_device file.
+ Limits for writes can be put using blkio.throttle.write_bps_device file.
Hierarchical Cgroups
====================
@@ -286,28 +286,28 @@ Throttling/Upper limit policy files
specified in bytes per second. Rules are per deivce. Following is
the format.
- echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.read_bps_device
+ echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.throttle.read_bps_device
- blkio.throttle.write_bps_device
- Specifies upper limit on WRITE rate to the device. IO rate is
specified in bytes per second. Rules are per deivce. Following is
the format.
- echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.write_bps_device
+ echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.throttle.write_bps_device
- blkio.throttle.read_iops_device
- Specifies upper limit on READ rate from the device. IO rate is
specified in IO per second. Rules are per deivce. Following is
the format.
- echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.read_iops_device
+ echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.throttle.read_iops_device
- blkio.throttle.write_iops_device
- Specifies upper limit on WRITE rate to the device. IO rate is
specified in io per second. Rules are per deivce. Following is
the format.
- echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.write_iops_device
+ echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.throttle.write_iops_device
Note: If both BW and IOPS rules are specified for a device, then IO is
subjectd to both the constraints.
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 72e238465b0..b1c921c2751 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -583,3 +583,25 @@ Why: Superseded by the UVCIOC_CTRL_QUERY ioctl.
Who: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
----------------------------
+
+What: For VIDIOC_S_FREQUENCY the type field must match the device node's type.
+ If not, return -EINVAL.
+When: 3.2
+Why: It makes no sense to switch the tuner to radio mode by calling
+ VIDIOC_S_FREQUENCY on a video node, or to switch the tuner to tv mode by
+ calling VIDIOC_S_FREQUENCY on a radio node. This is the first step of a
+ move to more consistent handling of tv and radio tuners.
+Who: Hans Verkuil <hans.verkuil@cisco.com>
+
+----------------------------
+
+What: Opening a radio device node will no longer automatically switch the
+ tuner mode from tv to radio.
+When: 3.3
+Why: Just opening a V4L device should not change the state of the hardware
+ like that. It's very unexpected and against the V4L spec. Instead, you
+ switch to radio mode by calling VIDIOC_S_FREQUENCY. This is the second
+ and last step of the move to consistent handling of tv and radio tuners.
+Who: Hans Verkuil <hans.verkuil@cisco.com>
+
+----------------------------
diff --git a/Documentation/filesystems/caching/netfs-api.txt b/Documentation/filesystems/caching/netfs-api.txt
index a167ab876c3..7cc6bf2871e 100644
--- a/Documentation/filesystems/caching/netfs-api.txt
+++ b/Documentation/filesystems/caching/netfs-api.txt
@@ -673,6 +673,22 @@ storage request to complete, or it may attempt to cancel the storage request -
in which case the page will not be stored in the cache this time.
+BULK INODE PAGE UNCACHE
+-----------------------
+
+A convenience routine is provided to perform an uncache on all the pages
+attached to an inode. This assumes that the pages on the inode correspond on a
+1:1 basis with the pages in the cache.
+
+ void fscache_uncache_all_inode_pages(struct fscache_cookie *cookie,
+ struct inode *inode);
+
+This takes the netfs cookie that the pages were cached with and the inode that
+the pages are attached to. This function will wait for pages to finish being
+written to the cache and for the cache to finish with the page generally. No
+error is returned.
+
+
==========================
INDEX AND DATA FILE UPDATE
==========================
diff --git a/Documentation/hwmon/f71882fg b/Documentation/hwmon/f71882fg
index 84d2623810f..de91c0db584 100644
--- a/Documentation/hwmon/f71882fg
+++ b/Documentation/hwmon/f71882fg
@@ -22,6 +22,10 @@ Supported chips:
Prefix: 'f71869'
Addresses scanned: none, address read from Super I/O config space
Datasheet: Available from the Fintek website
+ * Fintek F71869A
+ Prefix: 'f71869a'
+ Addresses scanned: none, address read from Super I/O config space
+ Datasheet: Not public
* Fintek F71882FG and F71883FG
Prefix: 'f71882fg'
Addresses scanned: none, address read from Super I/O config space
diff --git a/Documentation/hwmon/k10temp b/Documentation/hwmon/k10temp
index 0393c89277c..a10f73624ad 100644
--- a/Documentation/hwmon/k10temp
+++ b/Documentation/hwmon/k10temp
@@ -9,8 +9,8 @@ Supported chips:
Socket S1G3: Athlon II, Sempron, Turion II
* AMD Family 11h processors:
Socket S1G2: Athlon (X2), Sempron (X2), Turion X2 (Ultra)
-* AMD Family 12h processors: "Llano"
-* AMD Family 14h processors: "Brazos" (C/E/G-Series)
+* AMD Family 12h processors: "Llano" (E2/A4/A6/A8-Series)
+* AMD Family 14h processors: "Brazos" (C/E/G/Z-Series)
* AMD Family 15h processors: "Bulldozer"
Prefix: 'k10temp'
@@ -20,12 +20,16 @@ Supported chips:
http://support.amd.com/us/Processor_TechDocs/31116.pdf
BIOS and Kernel Developer's Guide (BKDG) for AMD Family 11h Processors:
http://support.amd.com/us/Processor_TechDocs/41256.pdf
+ BIOS and Kernel Developer's Guide (BKDG) for AMD Family 12h Processors:
+ http://support.amd.com/us/Processor_TechDocs/41131.pdf
BIOS and Kernel Developer's Guide (BKDG) for AMD Family 14h Models 00h-0Fh Processors:
http://support.amd.com/us/Processor_TechDocs/43170.pdf
Revision Guide for AMD Family 10h Processors:
http://support.amd.com/us/Processor_TechDocs/41322.pdf
Revision Guide for AMD Family 11h Processors:
http://support.amd.com/us/Processor_TechDocs/41788.pdf
+ Revision Guide for AMD Family 12h Processors:
+ http://support.amd.com/us/Processor_TechDocs/44739.pdf
Revision Guide for AMD Family 14h Models 00h-0Fh Processors:
http://support.amd.com/us/Processor_TechDocs/47534.pdf
AMD Family 11h Processor Power and Thermal Data Sheet for Notebooks:
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index fd248a31821..aa47be71df4 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -2015,6 +2015,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
the default.
off: Turn ECRC off
on: Turn ECRC on.
+ realloc reallocate PCI resources if allocations done by BIOS
+ are erroneous.
pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power
Management.
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index 1565eefd6fd..61815483efa 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -534,6 +534,8 @@ Events that are never propagated by the driver:
0x2404 System is waking up from hibernation to undock
0x2405 System is waking up from hibernation to eject bay
0x5010 Brightness level changed/control event
+0x6000 KEYBOARD: Numlock key pressed
+0x6005 KEYBOARD: Fn key pressed (TO BE VERIFIED)
Events that are propagated by the driver to userspace:
@@ -545,6 +547,8 @@ Events that are propagated by the driver to userspace:
0x3006 Bay hotplug request (hint to power up SATA link when
the optical drive tray is ejected)
0x4003 Undocked (see 0x2x04), can sleep again
+0x4010 Docked into hotplug port replicator (non-ACPI dock)
+0x4011 Undocked from hotplug port replicator (non-ACPI dock)
0x500B Tablet pen inserted into its storage bay
0x500C Tablet pen removed from its storage bay
0x6011 ALARM: battery is too hot
@@ -552,6 +556,7 @@ Events that are propagated by the driver to userspace:
0x6021 ALARM: a sensor is too hot
0x6022 ALARM: a sensor is extremely hot
0x6030 System thermal table changed
+0x6040 Nvidia Optimus/AC adapter related (TO BE VERIFIED)
Battery nearly empty alarms are a last resort attempt to get the
operating system to hibernate or shutdown cleanly (0x2313), or shutdown
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index e3df1191e71..db2a4067013 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -336,7 +336,7 @@ tcp_orphan_retries - INTEGER
when RTO retransmissions remain unacknowledged.
See tcp_retries2 for more details.
- The default value is 7.
+ The default value is 8.
If your machine is a loaded WEB server,
you should think about lowering this value, such sockets
may consume significant resources. Cf. tcp_max_orphans.
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index 22accb3eb40..b24875b1ced 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -501,13 +501,29 @@ helper functions described in Section 4. In that case, pm_runtime_resume()
should be used. Of course, for this purpose the device's run-time PM has to be
enabled earlier by calling pm_runtime_enable().
-If the device bus type's or driver's ->probe() or ->remove() callback runs
+If the device bus type's or driver's ->probe() callback runs
pm_runtime_suspend() or pm_runtime_idle() or their asynchronous counterparts,
they will fail returning -EAGAIN, because the device's usage counter is
-incremented by the core before executing ->probe() and ->remove(). Still, it
-may be desirable to suspend the device as soon as ->probe() or ->remove() has
-finished, so the PM core uses pm_runtime_idle_sync() to invoke the
-subsystem-level idle callback for the device at that time.
+incremented by the driver core before executing ->probe(). Still, it may be
+desirable to suspend the device as soon as ->probe() has finished, so the driver
+core uses pm_runtime_put_sync() to invoke the subsystem-level idle callback for
+the device at that time.
+
+Moreover, the driver core prevents runtime PM callbacks from racing with the bus
+notifier callback in __device_release_driver(), which is necessary, because the
+notifier is used by some subsystems to carry out operations affecting the
+runtime PM functionality. It does so by calling pm_runtime_get_sync() before
+driver_sysfs_remove() and the BUS_NOTIFY_UNBIND_DRIVER notifications. This
+resumes the device if it's in the suspended state and prevents it from
+being suspended again while those routines are being executed.
+
+To allow bus types and drivers to put devices into the suspended state by
+calling pm_runtime_suspend() from their ->remove() routines, the driver core
+executes pm_runtime_put_sync() after running the BUS_NOTIFY_UNBIND_DRIVER
+notifications in __device_release_driver(). This requires bus types and
+drivers to make their ->remove() callbacks avoid races with runtime PM directly,
+but also it allows of more flexibility in the handling of devices during the
+removal of their drivers.
The user space can effectively disallow the driver of the device to power manage
it at run time by changing the value of its /sys/devices/.../power/control
diff --git a/Documentation/spinlocks.txt b/Documentation/spinlocks.txt
index 2e3c64b1a6a..9dbe885ecd8 100644
--- a/Documentation/spinlocks.txt
+++ b/Documentation/spinlocks.txt
@@ -13,18 +13,8 @@ static DEFINE_SPINLOCK(xxx_lock);
The above is always safe. It will disable interrupts _locally_, but the
spinlock itself will guarantee the global lock, so it will guarantee that
there is only one thread-of-control within the region(s) protected by that
-lock. This works well even under UP. The above sequence under UP
-essentially is just the same as doing
-
- unsigned long flags;
-
- save_flags(flags); cli();
- ... critical section ...
- restore_flags(flags);
-
-so the code does _not_ need to worry about UP vs SMP issues: the spinlocks
-work correctly under both (and spinlocks are actually more efficient on
-architectures that allow doing the "save_flags + cli" in one operation).
+lock. This works well even under UP also, so the code does _not_ need to
+worry about UP vs SMP issues: the spinlocks work correctly under both.
NOTE! Implications of spin_locks for memory are further described in:
@@ -36,27 +26,7 @@ The above is usually pretty simple (you usually need and want only one
spinlock for most things - using more than one spinlock can make things a
lot more complex and even slower and is usually worth it only for
sequences that you _know_ need to be split up: avoid it at all cost if you
-aren't sure). HOWEVER, it _does_ mean that if you have some code that does
-
- cli();
- .. critical section ..
- sti();
-
-and another sequence that does
-
- spin_lock_irqsave(flags);
- .. critical section ..
- spin_unlock_irqrestore(flags);
-
-then they are NOT mutually exclusive, and the critical regions can happen
-at the same time on two different CPU's. That's fine per se, but the
-critical regions had better be critical for different things (ie they
-can't stomp on each other).
-
-The above is a problem mainly if you end up mixing code - for example the
-routines in ll_rw_block() tend to use cli/sti to protect the atomicity of
-their actions, and if a driver uses spinlocks instead then you should
-think about issues like the above.
+aren't sure).
This is really the only really hard part about spinlocks: once you start
using spinlocks they tend to expand to areas you might not have noticed
@@ -120,11 +90,10 @@ Lesson 3: spinlocks revisited.
The single spin-lock primitives above are by no means the only ones. They
are the most safe ones, and the ones that work under all circumstances,
-but partly _because_ they are safe they are also fairly slow. They are
-much faster than a generic global cli/sti pair, but slower than they'd
-need to be, because they do have to disable interrupts (which is just a
-single instruction on a x86, but it's an expensive one - and on other
-architectures it can be worse).
+but partly _because_ they are safe they are also fairly slow. They are slower
+than they'd need to be, because they do have to disable interrupts
+(which is just a single instruction on a x86, but it's an expensive one -
+and on other architectures it can be worse).
If you have a case where you have to protect a data structure across
several CPU's and you want to use spinlocks you can potentially use
diff --git a/MAINTAINERS b/MAINTAINERS
index 573cfa3091c..7a9569e06b0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -594,6 +594,16 @@ S: Maintained
F: arch/arm/lib/floppydma.S
F: arch/arm/include/asm/floppy.h
+ARM PMU PROFILING AND DEBUGGING
+M: Will Deacon <will.deacon@arm.com>
+S: Maintained
+F: arch/arm/kernel/perf_event*
+F: arch/arm/oprofile/common.c
+F: arch/arm/kernel/pmu.c
+F: arch/arm/include/asm/pmu.h
+F: arch/arm/kernel/hw_breakpoint.c
+F: arch/arm/include/asm/hw_breakpoint.h
+
ARM PORT
M: Russell King <linux@arm.linux.org.uk>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -2197,7 +2207,7 @@ F: drivers/acpi/dock.c
DOCUMENTATION
M: Randy Dunlap <rdunlap@xenotime.net>
L: linux-doc@vger.kernel.org
-T: quilt oss.oracle.com/~rdunlap/kernel-doc-patches/current/
+T: quilt http://userweb.kernel.org/~rdunlap/kernel-doc-patches/current/
S: Maintained
F: Documentation/
@@ -4982,7 +4992,7 @@ F: drivers/power/power_supply*
PNP SUPPORT
M: Adam Belay <abelay@mit.edu>
-M: Bjorn Helgaas <bjorn.helgaas@hp.com>
+M: Bjorn Helgaas <bhelgaas@google.com>
S: Maintained
F: drivers/pnp/
@@ -6733,6 +6743,7 @@ F: fs/fat/
VIDEOBUF2 FRAMEWORK
M: Pawel Osciak <pawel@osciak.com>
M: Marek Szyprowski <m.szyprowski@samsung.com>
+M: Kyungmin Park <kyungmin.park@samsung.com>
L: linux-media@vger.kernel.org
S: Maintained
F: drivers/media/video/videobuf2-*
diff --git a/Makefile b/Makefile
index dc670467fb8..60d91f76c2f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 0
SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION = -rc7
NAME = Sneaky Weasel
# *DOCUMENTATION*
diff --git a/README b/README
index 8510017a357..0d5a7ddbe3e 100644
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
- Linux kernel release 2.6.xx <http://kernel.org/>
+ Linux kernel release 3.x <http://kernel.org/>
-These are the release notes for Linux version 2.6. Read them carefully,
+These are the release notes for Linux version 3. Read them carefully,
as they tell you what this is all about, explain how to install the
kernel, and what to do if something goes wrong.
@@ -62,10 +62,10 @@ INSTALLING the kernel source:
directory where you have permissions (eg. your home directory) and
unpack it:
- gzip -cd linux-2.6.XX.tar.gz | tar xvf -
+ gzip -cd linux-3.X.tar.gz | tar xvf -
or
- bzip2 -dc linux-2.6.XX.tar.bz2 | tar xvf -
+ bzip2 -dc linux-3.X.tar.bz2 | tar xvf -
Replace "XX" with the version number of the latest kernel.
@@ -75,15 +75,15 @@ INSTALLING the kernel source:
files. They should match the library, and not get messed up by
whatever the kernel-du-jour happens to be.
- - You can also upgrade between 2.6.xx releases by patching. Patches are
+ - You can also upgrade between 3.x releases by patching. Patches are
distributed in the traditional gzip and the newer bzip2 format. To
install by patching, get all the newer patch files, enter the
- top level directory of the kernel source (linux-2.6.xx) and execute:
+ top level directory of the kernel source (linux-3.x) and execute:
- gzip -cd ../patch-2.6.xx.gz | patch -p1
+ gzip -cd ../patch-3.x.gz | patch -p1
or
- bzip2 -dc ../patch-2.6.xx.bz2 | patch -p1
+ bzip2 -dc ../patch-3.x.bz2 | patch -p1
(repeat xx for all versions bigger than the version of your current
source tree, _in_order_) and you should be ok. You may want to remove
@@ -91,9 +91,9 @@ INSTALLING the kernel source:
failed patches (xxx# or xxx.rej). If there are, either you or me has
made a mistake.
- Unlike patches for the 2.6.x kernels, patches for the 2.6.x.y kernels
+ Unlike patches for the 3.x kernels, patches for the 3.x.y kernels
(also known as the -stable kernels) are not incremental but instead apply
- directly to the base 2.6.x kernel. Please read
+ directly to the base 3.x kernel. Please read
Documentation/applying-patches.txt for more information.
Alternatively, the script patch-kernel can be used to automate this
@@ -107,14 +107,14 @@ INSTALLING the kernel source:
an alternative directory can be specified as the second argument.
- If you are upgrading between releases using the stable series patches
- (for example, patch-2.6.xx.y), note that these "dot-releases" are
- not incremental and must be applied to the 2.6.xx base tree. For
- example, if your base kernel is 2.6.12 and you want to apply the
- 2.6.12.3 patch, you do not and indeed must not first apply the
- 2.6.12.1 and 2.6.12.2 patches. Similarly, if you are running kernel
- version 2.6.12.2 and want to jump to 2.6.12.3, you must first
- reverse the 2.6.12.2 patch (that is, patch -R) _before_ applying
- the 2.6.12.3 patch.
+ (for example, patch-3.x.y), note that these "dot-releases" are
+ not incremental and must be applied to the 3.x base tree. For
+ example, if your base kernel is 3.0 and you want to apply the
+ 3.0.3 patch, you do not and indeed must not first apply the
+ 3.0.1 and 3.0.2 patches. Similarly, if you are running kernel
+ version 3.0.2 and want to jump to 3.0.3, you must first
+ reverse the 3.0.2 patch (that is, patch -R) _before_ applying
+ the 3.0.3 patch.
You can read more on this in Documentation/applying-patches.txt
- Make sure you have no stale .o files and dependencies lying around:
@@ -126,7 +126,7 @@ INSTALLING the kernel source:
SOFTWARE REQUIREMENTS
- Compiling and running the 2.6.xx kernels requires up-to-date
+ Compiling and running the 3.x kernels requires up-to-date
versions of various software packages. Consult
Documentation/Changes for the minimum version numbers required
and how to get updates for these packages. Beware that using
@@ -142,11 +142,11 @@ BUILD directory for the kernel:
Using the option "make O=output/dir" allow you to specify an alternate
place for the output files (including .config).
Example:
- kernel source code: /usr/src/linux-2.6.N
+ kernel source code: /usr/src/linux-3.N
build directory: /home/name/build/kernel
To configure and build the kernel use:
- cd /usr/src/linux-2.6.N
+ cd /usr/src/linux-3.N
make O=/home/name/build/kernel menuconfig
make O=/home/name/build/kernel
sudo make O=/home/name/build/kernel modules_install install
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index e5681636626..841df7d21c2 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -255,7 +255,7 @@ static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size,
if (buf == 0) {
dev_err(dev, "%s: unable to map unsafe buffer %p!\n",
__func__, ptr);
- return 0;
+ return ~0;
}
dev_dbg(dev,
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index d53c0abc4dd..2b5b1421596 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -583,7 +583,7 @@ static int armpmu_event_init(struct perf_event *event)
static void armpmu_enable(struct pmu *pmu)
{
/* Enable all of the perf events on hardware. */
- int idx;
+ int idx, enabled = 0;
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
if (!armpmu)
@@ -596,9 +596,11 @@ static void armpmu_enable(struct pmu *pmu)
continue;
armpmu->enable(&event->hw, idx);
+ enabled = 1;
}
- armpmu->start();
+ if (enabled)
+ armpmu->start();
}
static void armpmu_disable(struct pmu *pmu)
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index ed11fb08b05..acbb447ac6b 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -73,6 +73,7 @@ __setup("fpe=", fpe_setup);
#endif
extern void paging_init(struct machine_desc *desc);
+extern void sanity_check_meminfo(void);
extern void reboot_setup(char *str);
unsigned int processor_id;
@@ -900,6 +901,7 @@ void __init setup_arch(char **cmdline_p)
parse_early_param();
+ sanity_check_meminfo();
arm_memblock_init(&meminfo, mdesc);
paging_init(mdesc);
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 60636f499cb..2c277d40cee 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -115,7 +115,7 @@ static void __cpuinit twd_calibrate_rate(void)
twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000,
- (twd_timer_rate / 1000000) % 100);
+ (twd_timer_rate / 10000) % 100);
}
}
diff --git a/arch/arm/mach-at91/at91cap9.c b/arch/arm/mach-at91/at91cap9.c
index 17fae4a42ab..f1013d08bb5 100644
--- a/arch/arm/mach-at91/at91cap9.c
+++ b/arch/arm/mach-at91/at91cap9.c
@@ -223,15 +223,15 @@ static struct clk *periph_clocks[] __initdata = {
};
static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk),
- CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk),
+ CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk),
+ CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk),
CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
- CLKDEV_CON_DEV_ID("ssc", "ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("ssc", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
};
static struct clk_lookup usart_clocks_lookups[] = {
diff --git a/arch/arm/mach-at91/at91cap9_devices.c b/arch/arm/mach-at91/at91cap9_devices.c
index cd850ed6f33..dba0d8d8a4b 100644
--- a/arch/arm/mach-at91/at91cap9_devices.c
+++ b/arch/arm/mach-at91/at91cap9_devices.c
@@ -1220,7 +1220,7 @@ void __init at91_set_serial_console(unsigned portnr)
{
if (portnr < ATMEL_MAX_UART) {
atmel_default_console_device = at91_uarts[portnr];
- at91cap9_set_console_clock(portnr);
+ at91cap9_set_console_clock(at91_uarts[portnr]->id);
}
}
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index b228ce9e21a..83a1a3fee55 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -199,9 +199,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk),
CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
- CLKDEV_CON_DEV_ID("ssc", "ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("ssc", "ssc.1", &ssc1_clk),
- CLKDEV_CON_DEV_ID("ssc", "ssc.2", &ssc2_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
};
static struct clk_lookup usart_clocks_lookups[] = {
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index a0ba475be04..7227755ffec 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -1135,7 +1135,7 @@ void __init at91_set_serial_console(unsigned portnr)
{
if (portnr < ATMEL_MAX_UART) {
atmel_default_console_device = at91_uarts[portnr];
- at91rm9200_set_console_clock(portnr);
+ at91rm9200_set_console_clock(at91_uarts[portnr]->id);
}
}
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 1fdeb9058a7..39f81f47b4b 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -1173,7 +1173,7 @@ void __init at91_set_serial_console(unsigned portnr)
{
if (portnr < ATMEL_MAX_UART) {
atmel_default_console_device = at91_uarts[portnr];
- at91sam9260_set_console_clock(portnr);
+ at91sam9260_set_console_clock(at91_uarts[portnr]->id);
}
}
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 3eb4538fcee..5004bf0a05f 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -1013,7 +1013,7 @@ void __init at91_set_serial_console(unsigned portnr)
{
if (portnr < ATMEL_MAX_UART) {
atmel_default_console_device = at91_uarts[portnr];
- at91sam9261_set_console_clock(portnr);
+ at91sam9261_set_console_clock(at91_uarts[portnr]->id);
}
}
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index ffe081b77ed..a050f41fc86 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -1395,7 +1395,7 @@ void __init at91_set_serial_console(unsigned portnr)
{
if (portnr < ATMEL_MAX_UART) {
atmel_default_console_device = at91_uarts[portnr];
- at91sam9263_set_console_clock(portnr);
+ at91sam9263_set_console_clock(at91_uarts[portnr]->id);
}
}
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index 2bb6ff9af1c..11e214121b2 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -217,11 +217,11 @@ static struct clk *periph_clocks[] __initdata = {
static struct clk_lookup periph_clocks_lookups[] = {
/* One additional fake clock for ohci */
CLKDEV_CON_ID("ohci_clk", &uhphs_clk),
- CLKDEV_CON_DEV_ID("ehci_clk", "atmel-ehci.0", &uhphs_clk),
- CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk),
- CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
+ CLKDEV_CON_DEV_ID("ehci_clk", "atmel-ehci", &uhphs_clk),
+ CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk),
+ CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk),
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk),
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 05674865bc2..600bffb01ed 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -1550,7 +1550,7 @@ void __init at91_set_serial_console(unsigned portnr)
{
if (portnr < ATMEL_MAX_UART) {
atmel_default_console_device = at91_uarts[portnr];
- at91sam9g45_set_console_clock(portnr);
+ at91sam9g45_set_console_clock(at91_uarts[portnr]->id);
}
}
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index 1a40f16b66c..29dff18ed13 100644
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ b/arch/arm/mach-at91/at91sam9rl.c
@@ -191,8 +191,8 @@ static struct clk *periph_clocks[] __initdata = {
};
static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk),
- CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk),
+ CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk),
+ CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk),
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index c296045f2b6..aacb19dc922 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -1168,7 +1168,7 @@ void __init at91_set_serial_console(unsigned portnr)
{
if (portnr < ATMEL_MAX_UART) {
atmel_default_console_device = at91_uarts[portnr];
- at91sam9rl_set_console_clock(portnr);
+ at91sam9rl_set_console_clock(at91_uarts[portnr]->id);
}
}
diff --git a/arch/arm/mach-at91/board-cap9adk.c b/arch/arm/mach-at91/board-cap9adk.c
index 1904fdf8761..cdb65d48325 100644
--- a/arch/arm/mach-at91/board-cap9adk.c
+++ b/arch/arm/mach-at91/board-cap9adk.c
@@ -215,7 +215,7 @@ static void __init cap9adk_add_device_nand(void)
csa = at91_sys_read(AT91_MATRIX_EBICSA);
at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
- cap9adk_nand_data.bus_width_16 = !board_have_nand_8bit();
+ cap9adk_nand_data.bus_width_16 = board_have_nand_16bit();
/* setup bus-width (8 or 16) */
if (cap9adk_nand_data.bus_width_16)
cap9adk_nand_smc_config.mode |= AT91_SMC_DBW_16;
diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
index d600dc12322..5c240743c5b 100644
--- a/arch/arm/mach-at91/board-sam9260ek.c
+++ b/arch/arm/mach-at91/board-sam9260ek.c
@@ -214,7 +214,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
static void __init ek_add_device_nand(void)
{
- ek_nand_data.bus_width_16 = !board_have_nand_8bit();
+ ek_nand_data.bus_width_16 = board_have_nand_16bit();
/* setup bus-width (8 or 16) */
if (ek_nand_data.bus_width_16)
ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index f897f84d43d..b60c22b6e24 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -220,7 +220,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
static void __init ek_add_device_nand(void)
{
- ek_nand_data.bus_width_16 = !board_have_nand_8bit();
+ ek_nand_data.bus_width_16 = board_have_nand_16bit();
/* setup bus-width (8 or 16) */
if (ek_nand_data.bus_width_16)
ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index 605b26f40a4..9bbdc92ea19 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -221,7 +221,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
static void __init ek_add_device_nand(void)
{
- ek_nand_data.bus_width_16 = !board_have_nand_8bit();
+ ek_nand_data.bus_width_16 = board_have_nand_16bit();
/* setup bus-width (8 or 16) */
if (ek_nand_data.bus_width_16)
ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
index 7624cf0d006..1325a50101a 100644
--- a/arch/arm/mach-at91/board-sam9g20ek.c
+++ b/arch/arm/mach-at91/board-sam9g20ek.c
@@ -198,7 +198,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
static void __init ek_add_device_nand(void)
{
- ek_nand_data.bus_width_16 = !board_have_nand_8bit();
+ ek_nand_data.bus_width_16 = board_have_nand_16bit();
/* setup bus-width (8 or 16) */
if (ek_nand_data.bus_width_16)
ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
index 063c95d0e8f..33eaa135f24 100644
--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
+++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
@@ -178,7 +178,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
static void __init ek_add_device_nand(void)
{
- ek_nand_data.bus_width_16 = !board_have_nand_8bit();
+ ek_nand_data.bus_width_16 = board_have_nand_16bit();
/* setup bus-width (8 or 16) */
if (ek_nand_data.bus_width_16)
ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
diff --git a/arch/arm/mach-at91/include/mach/system_rev.h b/arch/arm/mach-at91/include/mach/system_rev.h
index b855ee75f72..8f4866045b4 100644
--- a/arch/arm/mach-at91/include/mach/system_rev.h
+++ b/arch/arm/mach-at91/include/mach/system_rev.h
@@ -13,13 +13,13 @@
* the 16-31 bit are reserved for at91 generic information
*
* bit 31:
- * 0 => nand 16 bit
- * 1 => nand 8 bit
+ * 0 => nand 8 bit
+ * 1 => nand 16 bit
*/
-#define BOARD_HAVE_NAND_8BIT (1 << 31)
-static int inline board_have_nand_8bit(void)
+#define BOARD_HAVE_NAND_16BIT (1 << 31)
+static inline int board_have_nand_16bit(void)
{
- return system_rev & BOARD_HAVE_NAND_8BIT;
+ return system_rev & BOARD_HAVE_NAND_16BIT;
}
#endif /* __ARCH_SYSTEM_REV_H__ */
diff --git a/arch/arm/mach-davinci/irq.c b/arch/arm/mach-davinci/irq.c
index bfe68ec4e1a..d8c1af02593 100644
--- a/arch/arm/mach-davinci/irq.c
+++ b/arch/arm/mach-davinci/irq.c
@@ -53,7 +53,7 @@ davinci_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
gc = irq_alloc_generic_chip("AINTC", 1, irq_start, base, handle_edge_irq);
ct = gc->chip_types;
- ct->chip.irq_ack = irq_gc_ack;
+ ct->chip.irq_ack = irq_gc_ack_set_bit;
ct->chip.irq_mask = irq_gc_mask_clr_bit;
ct->chip.irq_unmask = irq_gc_mask_set_bit;
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 1d4b65fd673..6659a0d137a 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -251,9 +251,9 @@ static void ep93xx_uart_set_mctrl(struct amba_device *dev,
unsigned int mcr;
mcr = 0;
- if (!(mctrl & TIOCM_RTS))
+ if (mctrl & TIOCM_RTS)
mcr |= 2;
- if (!(mctrl & TIOCM_DTR))
+ if (mctrl & TIOCM_DTR)
mcr |= 1;
__raw_writel(mcr, base + EP93XX_UART_MCR_OFFSET);
diff --git a/arch/arm/mach-exynos4/cpu.c b/arch/arm/mach-exynos4/cpu.c
index 9babe4473e8..bfd621460ab 100644
--- a/arch/arm/mach-exynos4/cpu.c
+++ b/arch/arm/mach-exynos4/cpu.c
@@ -23,6 +23,7 @@
#include <plat/sdhci.h>
#include <plat/devs.h>
#include <plat/fimc-core.h>
+#include <plat/iic-core.h>
#include <mach/regs-irq.h>
@@ -132,6 +133,11 @@ void __init exynos4_map_io(void)
s3c_fimc_setname(1, "exynos4-fimc");
s3c_fimc_setname(2, "exynos4-fimc");
s3c_fimc_setname(3, "exynos4-fimc");
+
+ /* The I2C bus controllers are directly compatible with s3c2440 */
+ s3c_i2c0_setname("s3c2440-i2c");
+ s3c_i2c1_setname("s3c2440-i2c");
+ s3c_i2c2_setname("s3c2440-i2c");
}
void __init exynos4_init_clocks(int xtal)
diff --git a/arch/arm/mach-exynos4/dev-audio.c b/arch/arm/mach-exynos4/dev-audio.c
index 1eed5f9f7bd..983069a5323 100644
--- a/arch/arm/mach-exynos4/dev-audio.c
+++ b/arch/arm/mach-exynos4/dev-audio.c
@@ -330,7 +330,7 @@ struct platform_device exynos4_device_ac97 = {
static int exynos4_spdif_cfg_gpio(struct platform_device *pdev)
{
- s3c_gpio_cfgpin_range(EXYNOS4_GPC1(0), 2, S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin_range(EXYNOS4_GPC1(0), 2, S3C_GPIO_SFN(4));
return 0;
}
diff --git a/arch/arm/mach-exynos4/headsmp.S b/arch/arm/mach-exynos4/headsmp.S
index 6c6cfc50c46..3cdeb364754 100644
--- a/arch/arm/mach-exynos4/headsmp.S
+++ b/arch/arm/mach-exynos4/headsmp.S
@@ -13,7 +13,7 @@
#include <linux/linkage.h>
#include <linux/init.h>
- __INIT
+ __CPUINIT
/*
* exynos4 specific entry point for secondary CPUs. This provides
diff --git a/arch/arm/mach-exynos4/mach-smdkv310.c b/arch/arm/mach-exynos4/mach-smdkv310.c
index 152676471b6..edd814110da 100644
--- a/arch/arm/mach-exynos4/mach-smdkv310.c
+++ b/arch/arm/mach-exynos4/mach-smdkv310.c
@@ -78,9 +78,7 @@ static struct s3c2410_uartcfg smdkv310_uartcfgs[] __initdata = {
};
static struct s3c_sdhci_platdata smdkv310_hsmmc0_pdata __initdata = {
- .cd_type = S3C_SDHCI_CD_GPIO,
- .ext_cd_gpio = EXYNOS4_GPK0(2),
- .ext_cd_gpio_invert = 1,
+ .cd_type = S3C_SDHCI_CD_INTERNAL,
.clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
#ifdef CONFIG_EXYNOS4_SDHCI_CH0_8BIT
.max_width = 8,
@@ -96,9 +94,7 @@ static struct s3c_sdhci_platdata smdkv310_hsmmc1_pdata __initdata = {
};
static struct s3c_sdhci_platdata smdkv310_hsmmc2_pdata __initdata = {
- .cd_type = S3C_SDHCI_CD_GPIO,
- .ext_cd_gpio = EXYNOS4_GPK2(2),
- .ext_cd_gpio_invert = 1,
+ .cd_type = S3C_SDHCI_CD_INTERNAL,
.clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
#ifdef CONFIG_EXYNOS4_SDHCI_CH2_8BIT
.max_width = 8,
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index 72b4e763158..ab9f999106c 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -79,7 +79,7 @@ static APBC_CLK(ssp4, PXA168_SSP4, 4, 0);
static APBC_CLK(ssp5, PXA168_SSP5, 4, 0);
static APBC_CLK(keypad, PXA168_KPC, 0, 32000);
-static APMU_CLK(nand, NAND, 0x01db, 208000000);
+static APMU_CLK(nand, NAND, 0x19b, 156000000);
static APMU_CLK(lcd, LCD, 0x7f, 312000000);
/* device and clock bindings */
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index 8f92ccd26ed..1464607aa60 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -110,7 +110,7 @@ static APBC_CLK(pwm2, PXA910_PWM2, 1, 13000000);
static APBC_CLK(pwm3, PXA910_PWM3, 1, 13000000);
static APBC_CLK(pwm4, PXA910_PWM4, 1, 13000000);
-static APMU_CLK(nand, NAND, 0x01db, 208000000);
+static APMU_CLK(nand, NAND, 0x19b, 156000000);
static APMU_CLK(u2o, USB, 0x1b, 480000000);
/* device and clock bindings */
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
index de88c9297b6..f49ce85d244 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -215,7 +215,7 @@ static struct omap_kp_platform_data ams_delta_kp_data __initdata = {
.delay = 9,
};
-static struct platform_device ams_delta_kp_device __initdata = {
+static struct platform_device ams_delta_kp_device = {
.name = "omap-keypad",
.id = -1,
.dev = {
@@ -225,12 +225,12 @@ static struct platform_device ams_delta_kp_device __initdata = {
.resource = ams_delta_kp_resources,
};
-static struct platform_device ams_delta_lcd_device __initdata = {
+static struct platform_device ams_delta_lcd_device = {
.name = "lcd_ams_delta",
.id = -1,
};
-static struct platform_device ams_delta_led_device __initdata = {
+static struct platform_device ams_delta_led_device = {
.name = "ams-delta-led",
.id = -1
};
@@ -267,7 +267,7 @@ static struct soc_camera_link ams_delta_iclink = {
.power = ams_delta_camera_power,
};
-static struct platform_device ams_delta_camera_device __initdata = {
+static struct platform_device ams_delta_camera_device = {
.name = "soc-camera-pdrv",
.id = 0,
.dev = {
diff --git a/arch/arm/mach-omap1/gpio15xx.c b/arch/arm/mach-omap1/gpio15xx.c
index 04c4b04cf54..364137c2042 100644
--- a/arch/arm/mach-omap1/gpio15xx.c
+++ b/arch/arm/mach-omap1/gpio15xx.c
@@ -41,7 +41,7 @@ static struct __initdata omap_gpio_platform_data omap15xx_mpu_gpio_config = {
.bank_stride = 1,
};
-static struct __initdata platform_device omap15xx_mpu_gpio = {
+static struct platform_device omap15xx_mpu_gpio = {
.name = "omap_gpio",
.id = 0,
.dev = {
@@ -70,7 +70,7 @@ static struct __initdata omap_gpio_platform_data omap15xx_gpio_config = {
.bank_width = 16,
};
-static struct __initdata platform_device omap15xx_gpio = {
+static struct platform_device omap15xx_gpio = {
.name = "omap_gpio",
.id = 1,
.dev = {
diff --git a/arch/arm/mach-omap1/gpio16xx.c b/arch/arm/mach-omap1/gpio16xx.c
index 5dd0d4c82b2..293a246e282 100644
--- a/arch/arm/mach-omap1/gpio16xx.c
+++ b/arch/arm/mach-omap1/gpio16xx.c
@@ -44,7 +44,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_mpu_gpio_config = {
.bank_stride = 1,
};
-static struct __initdata platform_device omap16xx_mpu_gpio = {
+static struct platform_device omap16xx_mpu_gpio = {
.name = "omap_gpio",
.id = 0,
.dev = {
@@ -73,7 +73,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio1_config = {
.bank_width = 16,
};
-static struct __initdata platform_device omap16xx_gpio1 = {
+static struct platform_device omap16xx_gpio1 = {
.name = "omap_gpio",
.id = 1,
.dev = {
@@ -102,7 +102,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio2_config = {
.bank_width = 16,
};
-static struct __initdata platform_device omap16xx_gpio2 = {
+static struct platform_device omap16xx_gpio2 = {
.name = "omap_gpio",
.id = 2,
.dev = {
@@ -131,7 +131,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio3_config = {
.bank_width = 16,
};
-static struct __initdata platform_device omap16xx_gpio3 = {
+static struct platform_device omap16xx_gpio3 = {
.name = "omap_gpio",
.id = 3,
.dev = {
@@ -160,7 +160,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio4_config = {
.bank_width = 16,
};
-static struct __initdata platform_device omap16xx_gpio4 = {
+static struct platform_device omap16xx_gpio4 = {
.name = "omap_gpio",
.id = 4,
.dev = {
diff --git a/arch/arm/mach-omap1/gpio7xx.c b/arch/arm/mach-omap1/gpio7xx.c
index 1204c8b871a..c6ad248d63a 100644
--- a/arch/arm/mach-omap1/gpio7xx.c
+++ b/arch/arm/mach-omap1/gpio7xx.c
@@ -46,7 +46,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_mpu_gpio_config = {
.bank_stride = 2,
};
-static struct __initdata platform_device omap7xx_mpu_gpio = {
+static struct platform_device omap7xx_mpu_gpio = {
.name = "omap_gpio",
.id = 0,
.dev = {
@@ -75,7 +75,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio1_config = {
.bank_width = 32,
};
-static struct __initdata platform_device omap7xx_gpio1 = {
+static struct platform_device omap7xx_gpio1 = {
.name = "omap_gpio",
.id = 1,
.dev = {
@@ -104,7 +104,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio2_config = {
.bank_width = 32,
};
-static struct __initdata platform_device omap7xx_gpio2 = {
+static struct platform_device omap7xx_gpio2 = {
.name = "omap_gpio",
.id = 2,
.dev = {
@@ -133,7 +133,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio3_config = {
.bank_width = 32,
};
-static struct __initdata platform_device omap7xx_gpio3 = {
+static struct platform_device omap7xx_gpio3 = {
.name = "omap_gpio",
.id = 3,
.dev = {
@@ -162,7 +162,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio4_config = {
.bank_width = 32,
};
-static struct __initdata platform_device omap7xx_gpio4 = {
+static struct platform_device omap7xx_gpio4 = {
.name = "omap_gpio",
.id = 4,
.dev = {
@@ -191,7 +191,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio5_config = {
.bank_width = 32,
};
-static struct __initdata platform_device omap7xx_gpio5 = {
+static struct platform_device omap7xx_gpio5 = {
.name = "omap_gpio",
.id = 5,
.dev = {
@@ -220,7 +220,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio6_config = {
.bank_width = 32,
};
-static struct __initdata platform_device omap7xx_gpio6 = {
+static struct platform_device omap7xx_gpio6 = {
.name = "omap_gpio",
.id = 6,
.dev = {
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index 990366726c5..88bd6f7705f 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -558,7 +558,7 @@ static struct radio_si4713_platform_data rx51_si4713_data __initdata_or_module =
.subdev_board_info = &rx51_si4713_board_info,
};
-static struct platform_device rx51_si4713_dev __initdata_or_module = {
+static struct platform_device rx51_si4713_dev = {
.name = "radio-si4713",
.id = -1,
.dev = {
diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c
index 87ae3129f4f..b27544bcafc 100644
--- a/arch/arm/mach-pxa/mfp-pxa2xx.c
+++ b/arch/arm/mach-pxa/mfp-pxa2xx.c
@@ -347,9 +347,9 @@ static int pxa2xx_mfp_suspend(void)
if ((gpio_desc[i].config & MFP_LPM_KEEP_OUTPUT) &&
(GPDR(i) & GPIO_bit(i))) {
if (GPLR(i) & GPIO_bit(i))
- PGSR(i) |= GPIO_bit(i);
+ PGSR(gpio_to_bank(i)) |= GPIO_bit(i);
else
- PGSR(i) &= ~GPIO_bit(i);
+ PGSR(gpio_to_bank(i)) &= ~GPIO_bit(i);
}
}
diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
index d130f77b6d1..2f37d43f51b 100644
--- a/arch/arm/mach-pxa/raumfeld.c
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -573,10 +573,10 @@ static struct pxafb_mode_info sharp_lq043t3dx02_mode = {
.xres = 480,
.yres = 272,
.bpp = 16,
- .hsync_len = 4,
+ .hsync_len = 41,
.left_margin = 2,
.right_margin = 1,
- .vsync_len = 1,
+ .vsync_len = 10,
.upper_margin = 3,
.lower_margin = 1,
.sync = 0,
@@ -596,29 +596,31 @@ static void __init raumfeld_lcd_init(void)
{
int ret;
- pxa_set_fb_info(NULL, &raumfeld_sharp_lcd_info);
-
- /* Earlier devices had the backlight regulator controlled
- * via PWM, later versions use another controller for that */
- if ((system_rev & 0xff) < 2) {
- mfp_cfg_t raumfeld_pwm_pin_config = GPIO17_PWM0_OUT;
- pxa3xx_mfp_config(&raumfeld_pwm_pin_config, 1);
- platform_device_register(&raumfeld_pwm_backlight_device);
- } else
- platform_device_register(&raumfeld_lt3593_device);
-
ret = gpio_request(GPIO_TFT_VA_EN, "display VA enable");
if (ret < 0)
pr_warning("Unable to request GPIO_TFT_VA_EN\n");
else
gpio_direction_output(GPIO_TFT_VA_EN, 1);
+ msleep(100);
+
ret = gpio_request(GPIO_DISPLAY_ENABLE, "display enable");
if (ret < 0)
pr_warning("Unable to request GPIO_DISPLAY_ENABLE\n");
else
gpio_direction_output(GPIO_DISPLAY_ENABLE, 1);
+ /* Hardware revision 2 has the backlight regulator controlled
+ * by an LT3593, earlier and later devices use PWM for that. */
+ if ((system_rev & 0xff) == 2) {
+ platform_device_register(&raumfeld_lt3593_device);
+ } else {
+ mfp_cfg_t raumfeld_pwm_pin_config = GPIO17_PWM0_OUT;
+ pxa3xx_mfp_config(&raumfeld_pwm_pin_config, 1);
+ platform_device_register(&raumfeld_pwm_backlight_device);
+ }
+
+ pxa_set_fb_info(NULL, &raumfeld_sharp_lcd_info);
platform_device_register(&pxa3xx_device_gcu);
}
@@ -657,10 +659,10 @@ static struct lis3lv02d_platform_data lis3_pdata = {
#define SPI_AK4104 \
{ \
- .modalias = "ak4104", \
- .max_speed_hz = 10000, \
- .bus_num = 0, \
- .chip_select = 0, \
+ .modalias = "ak4104-codec", \
+ .max_speed_hz = 10000, \
+ .bus_num = 0, \
+ .chip_select = 0, \
.controller_data = (void *) GPIO_SPDIF_CS, \
}
diff --git a/arch/arm/mach-s3c2440/mach-mini2440.c b/arch/arm/mach-s3c2440/mach-mini2440.c
index dd3120df09f..fc2dc0b3d4f 100644
--- a/arch/arm/mach-s3c2440/mach-mini2440.c
+++ b/arch/arm/mach-s3c2440/mach-mini2440.c
@@ -552,7 +552,7 @@ struct mini2440_features_t {
struct platform_device *optional[8];
};
-static void mini2440_parse_features(
+static void __init mini2440_parse_features(
struct mini2440_features_t * features,
const char * features_str )
{
diff --git a/arch/arm/mach-s3c64xx/dev-spi.c b/arch/arm/mach-s3c64xx/dev-spi.c
index 82db072cb83..5e6b42089eb 100644
--- a/arch/arm/mach-s3c64xx/dev-spi.c
+++ b/arch/arm/mach-s3c64xx/dev-spi.c
@@ -88,6 +88,7 @@ static struct s3c64xx_spi_info s3c64xx_spi0_pdata = {
.cfg_gpio = s3c64xx_spi_cfg_gpio,
.fifo_lvl_mask = 0x7f,
.rx_lvl_offset = 13,
+ .tx_st_done = 21,
};
static u64 spi_dmamask = DMA_BIT_MASK(32);
@@ -132,6 +133,7 @@ static struct s3c64xx_spi_info s3c64xx_spi1_pdata = {
.cfg_gpio = s3c64xx_spi_cfg_gpio,
.fifo_lvl_mask = 0x7f,
.rx_lvl_offset = 13,
+ .tx_st_done = 21,
};
struct platform_device s3c64xx_device_spi1 = {
diff --git a/arch/arm/mach-s5p64x0/dev-spi.c b/arch/arm/mach-s5p64x0/dev-spi.c
index e78ee18c76e..ac825e82632 100644
--- a/arch/arm/mach-s5p64x0/dev-spi.c
+++ b/arch/arm/mach-s5p64x0/dev-spi.c
@@ -112,12 +112,14 @@ static struct s3c64xx_spi_info s5p6440_spi0_pdata = {
.cfg_gpio = s5p6440_spi_cfg_gpio,
.fifo_lvl_mask = 0x1ff,
.rx_lvl_offset = 15,
+ .tx_st_done = 25,
};
static struct s3c64xx_spi_info s5p6450_spi0_pdata = {
.cfg_gpio = s5p6450_spi_cfg_gpio,
.fifo_lvl_mask = 0x1ff,
.rx_lvl_offset = 15,
+ .tx_st_done = 25,
};
static u64 spi_dmamask = DMA_BIT_MASK(32);
@@ -160,12 +162,14 @@ static struct s3c64xx_spi_info s5p6440_spi1_pdata = {
.cfg_gpio = s5p6440_spi_cfg_gpio,
.fifo_lvl_mask = 0x7f,
.rx_lvl_offset = 15,
+ .tx_st_done = 25,
};
static struct s3c64xx_spi_info s5p6450_spi1_pdata = {
.cfg_gpio = s5p6450_spi_cfg_gpio,
.fifo_lvl_mask = 0x7f,
.rx_lvl_offset = 15,
+ .tx_st_done = 25,
};
struct platform_device s5p64x0_device_spi1 = {
diff --git a/arch/arm/mach-s5pc100/dev-spi.c b/arch/arm/mach-s5pc100/dev-spi.c
index 57b19794d9b..e5d6c4dceb5 100644
--- a/arch/arm/mach-s5pc100/dev-spi.c
+++ b/arch/arm/mach-s5pc100/dev-spi.c
@@ -15,6 +15,7 @@
#include <mach/dma.h>
#include <mach/map.h>
#include <mach/spi-clocks.h>
+#include <mach/irqs.h>
#include <plat/s3c64xx-spi.h>
#include <plat/gpio-cfg.h>
@@ -90,6 +91,7 @@ static struct s3c64xx_spi_info s5pc100_spi0_pdata = {
.fifo_lvl_mask = 0x7f,
.rx_lvl_offset = 13,
.high_speed = 1,
+ .tx_st_done = 21,
};
static u64 spi_dmamask = DMA_BIT_MASK(32);
@@ -134,6 +136,7 @@ static struct s3c64xx_spi_info s5pc100_spi1_pdata = {
.fifo_lvl_mask = 0x7f,
.rx_lvl_offset = 13,
.high_speed = 1,
+ .tx_st_done = 21,
};
struct platform_device s5pc100_device_spi1 = {
@@ -176,6 +179,7 @@ static struct s3c64xx_spi_info s5pc100_spi2_pdata = {
.fifo_lvl_mask = 0x7f,
.rx_lvl_offset = 13,
.high_speed = 1,
+ .tx_st_done = 21,
};
struct platform_device s5pc100_device_spi2 = {
diff --git a/arch/arm/mach-s5pv210/dev-spi.c b/arch/arm/mach-s5pv210/dev-spi.c
index e3249a47e3b..eaf9a7bff7a 100644
--- a/arch/arm/mach-s5pv210/dev-spi.c
+++ b/arch/arm/mach-s5pv210/dev-spi.c
@@ -85,6 +85,7 @@ static struct s3c64xx_spi_info s5pv210_spi0_pdata = {
.fifo_lvl_mask = 0x1ff,
.rx_lvl_offset = 15,
.high_speed = 1,
+ .tx_st_done = 25,
};
static u64 spi_dmamask = DMA_BIT_MASK(32);
@@ -129,6 +130,7 @@ static struct s3c64xx_spi_info s5pv210_spi1_pdata = {
.fifo_lvl_mask = 0x7f,
.rx_lvl_offset = 15,
.high_speed = 1,
+ .tx_st_done = 25,
};
struct platform_device s5pv210_device_spi1 = {
diff --git a/arch/arm/mach-vt8500/irq.c b/arch/arm/mach-vt8500/irq.c
index 245140c0df1..642de0408f2 100644
--- a/arch/arm/mach-vt8500/irq.c
+++ b/arch/arm/mach-vt8500/irq.c
@@ -39,9 +39,10 @@
static void __iomem *ic_regbase;
static void __iomem *sic_regbase;
-static void vt8500_irq_mask(unsigned int irq)
+static void vt8500_irq_mask(struct irq_data *d)
{
void __iomem *base = ic_regbase;
+ unsigned irq = d->irq;
u8 edge;
if (irq >= 64) {
@@ -64,9 +65,10 @@ static void vt8500_irq_mask(unsigned int irq)
}
}
-static void vt8500_irq_unmask(unsigned int irq)
+static void vt8500_irq_unmask(struct irq_data *d)
{
void __iomem *base = ic_regbase;
+ unsigned irq = d->irq;
u8 dctr;
if (irq >= 64) {
@@ -78,10 +80,11 @@ static void vt8500_irq_unmask(unsigned int irq)
writeb(dctr, base + VT8500_IC_DCTR + irq);
}
-static int vt8500_irq_set_type(unsigned int irq, unsigned int flow_type)
+static int vt8500_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
void __iomem *base = ic_regbase;
- unsigned int orig_irq = irq;
+ unsigned irq = d->irq;
+ unsigned orig_irq = irq;
u8 dctr;
if (irq >= 64) {
@@ -114,11 +117,11 @@ static int vt8500_irq_set_type(unsigned int irq, unsigned int flow_type)
}
static struct irq_chip vt8500_irq_chip = {
- .name = "vt8500",
- .ack = vt8500_irq_mask,
- .mask = vt8500_irq_mask,
- .unmask = vt8500_irq_unmask,
- .set_type = vt8500_irq_set_type,
+ .name = "vt8500",
+ .irq_ack = vt8500_irq_mask,
+ .irq_mask = vt8500_irq_mask,
+ .irq_unmask = vt8500_irq_unmask,
+ .irq_set_type = vt8500_irq_set_type,
};
void __init vt8500_init_irq(void)
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index ef59099a546..44c086710d2 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -120,17 +120,22 @@ static void l2x0_cache_sync(void)
spin_unlock_irqrestore(&l2x0_lock, flags);
}
-static void l2x0_flush_all(void)
+static void __l2x0_flush_all(void)
{
- unsigned long flags;
-
- /* clean all ways */
- spin_lock_irqsave(&l2x0_lock, flags);
debug_writel(0x03);
writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY);
cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask);
cache_sync();
debug_writel(0x00);
+}
+
+static void l2x0_flush_all(void)
+{
+ unsigned long flags;
+
+ /* clean all ways */
+ spin_lock_irqsave(&l2x0_lock, flags);
+ __l2x0_flush_all();
spin_unlock_irqrestore(&l2x0_lock, flags);
}
@@ -266,7 +271,9 @@ static void l2x0_disable(void)
unsigned long flags;
spin_lock_irqsave(&l2x0_lock, flags);
- writel(0, l2x0_base + L2X0_CTRL);
+ __l2x0_flush_all();
+ writel_relaxed(0, l2x0_base + L2X0_CTRL);
+ dsb();
spin_unlock_irqrestore(&l2x0_lock, flags);
}
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 9d9e736c2b4..594d677b92c 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -759,7 +759,7 @@ early_param("vmalloc", early_vmalloc);
static phys_addr_t lowmem_limit __initdata = 0;
-static void __init sanity_check_meminfo(void)
+void __init sanity_check_meminfo(void)
{
int i, j, highmem = 0;
@@ -1032,8 +1032,9 @@ void __init paging_init(struct machine_desc *mdesc)
{
void *zero_page;
+ memblock_set_current_limit(lowmem_limit);
+
build_mem_type_table();
- sanity_check_meminfo();
prepare_page_table();
map_lowmem();
devicemaps_init(mdesc);
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index 687d02319a4..941a98c9e8a 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -27,6 +27,10 @@ void __init arm_mm_memblock_reserve(void)
memblock_reserve(CONFIG_VECTORS_BASE, PAGE_SIZE);
}
+void __init sanity_check_meminfo(void)
+{
+}
+
/*
* paging_init() sets up the page tables, initialises the zone memory
* maps, and sets up the zero page, bad page and bad page tables.
diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c
index 5b4fffab1eb..41ab97ebe4c 100644
--- a/arch/arm/plat-orion/gpio.c
+++ b/arch/arm/plat-orion/gpio.c
@@ -432,7 +432,7 @@ void __init orion_gpio_init(int gpio_base, int ngpio,
ct->regs.mask = ochip->mask_offset + GPIO_EDGE_MASK_OFF;
ct->regs.ack = GPIO_EDGE_CAUSE_OFF;
ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
- ct->chip.irq_ack = irq_gc_ack;
+ ct->chip.irq_ack = irq_gc_ack_clr_bit;
ct->chip.irq_mask = irq_gc_mask_clr_bit;
ct->chip.irq_unmask = irq_gc_mask_set_bit;
ct->chip.irq_set_type = gpio_irq_set_type;
diff --git a/arch/arm/plat-pxa/gpio.c b/arch/arm/plat-pxa/gpio.c
index 48ebb9479b6..a11dc367050 100644
--- a/arch/arm/plat-pxa/gpio.c
+++ b/arch/arm/plat-pxa/gpio.c
@@ -50,7 +50,7 @@ static inline void __iomem *gpio_chip_base(struct gpio_chip *c)
return container_of(c, struct pxa_gpio_chip, chip)->regbase;
}
-static inline struct pxa_gpio_chip *gpio_to_chip(unsigned gpio)
+static inline struct pxa_gpio_chip *gpio_to_pxachip(unsigned gpio)
{
return &pxa_gpio_chips[gpio_to_bank(gpio)];
}
@@ -161,7 +161,7 @@ static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
int gpio = irq_to_gpio(d->irq);
unsigned long gpdr, mask = GPIO_bit(gpio);
- c = gpio_to_chip(gpio);
+ c = gpio_to_pxachip(gpio);
if (type == IRQ_TYPE_PROBE) {
/* Don't mess with enabled GPIOs using preconfigured edges or
@@ -230,7 +230,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
static void pxa_ack_muxed_gpio(struct irq_data *d)
{
int gpio = irq_to_gpio(d->irq);
- struct pxa_gpio_chip *c = gpio_to_chip(gpio);
+ struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
__raw_writel(GPIO_bit(gpio), c->regbase + GEDR_OFFSET);
}
@@ -238,7 +238,7 @@ static void pxa_ack_muxed_gpio(struct irq_data *d)
static void pxa_mask_muxed_gpio(struct irq_data *d)
{
int gpio = irq_to_gpio(d->irq);
- struct pxa_gpio_chip *c = gpio_to_chip(gpio);
+ struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
uint32_t grer, gfer;
c->irq_mask &= ~GPIO_bit(gpio);
@@ -252,7 +252,7 @@ static void pxa_mask_muxed_gpio(struct irq_data *d)
static void pxa_unmask_muxed_gpio(struct irq_data *d)
{
int gpio = irq_to_gpio(d->irq);
- struct pxa_gpio_chip *c = gpio_to_chip(gpio);
+ struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
c->irq_mask |= GPIO_bit(gpio);
update_edge_detect(c);
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index 2abf9660bc6..a79a8ccd25f 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -1027,17 +1027,13 @@ int s3c2410_dma_config(unsigned int channel,
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
unsigned int dcon;
- pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
- __func__, channel, xferunit, dcon);
+ pr_debug("%s: chan=%d, xfer_unit=%d\n", __func__, channel, xferunit);
if (chan == NULL)
return -EINVAL;
- pr_debug("%s: Initial dcon is %08x\n", __func__, dcon);
-
dcon = chan->dcon & dma_sel.dcon_mask;
-
- pr_debug("%s: New dcon is %08x\n", __func__, dcon);
+ pr_debug("%s: dcon is %08x\n", __func__, dcon);
switch (chan->req_ch) {
case DMACH_I2S_IN:
@@ -1235,7 +1231,7 @@ static void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp)
/* restore channel's hardware configuration */
if (!cp->in_use)
- return 0;
+ return;
printk(KERN_INFO "dma%d: restoring configuration\n", cp->number);
@@ -1246,8 +1242,6 @@ static void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp)
if (cp->map != NULL)
dma_sel.select(cp, cp->map);
-
- return 0;
}
static void s3c2410_dma_resume(void)
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c
index 135abda31c9..327ab9f662e 100644
--- a/arch/arm/plat-s5p/irq-gpioint.c
+++ b/arch/arm/plat-s5p/irq-gpioint.c
@@ -152,7 +152,7 @@ static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip)
if (!gc)
return -ENOMEM;
ct = gc->chip_types;
- ct->chip.irq_ack = irq_gc_ack;
+ ct->chip.irq_ack = irq_gc_ack_set_bit;
ct->chip.irq_mask = irq_gc_mask_set_bit;
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
ct->chip.irq_set_type = s5p_gpioint_set_type,
diff --git a/arch/arm/plat-s5p/s5p-time.c b/arch/arm/plat-s5p/s5p-time.c
index 899a8cc011f..612934c48b0 100644
--- a/arch/arm/plat-s5p/s5p-time.c
+++ b/arch/arm/plat-s5p/s5p-time.c
@@ -370,11 +370,11 @@ static void __init s5p_clocksource_init(void)
clock_rate = clk_get_rate(tin_source);
- init_sched_clock(&cd, s5p_update_sched_clock, 32, clock_rate);
-
s5p_time_setup(timer_source.source_id, TCNT_MAX);
s5p_time_start(timer_source.source_id, PERIODIC);
+ init_sched_clock(&cd, s5p_update_sched_clock, 32, clock_rate);
+
if (clocksource_register_hz(&time_clocksource, clock_rate))
panic("%s: can't register clocksource\n", time_clocksource.name);
}
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 4af108ff411..e3b31c26ac3 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -12,6 +12,10 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+
+#ifndef __PLAT_DEVS_H
+#define __PLAT_DEVS_H __FILE__
+
#include <linux/platform_device.h>
struct s3c24xx_uart_resources {
@@ -159,3 +163,5 @@ extern struct platform_device s3c_device_ac97;
*/
extern void *s3c_set_platdata(void *pd, size_t pdsize,
struct platform_device *pdev);
+
+#endif /* __PLAT_DEVS_H */
diff --git a/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h b/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
index 0ffe34a2155..4c16fa3621b 100644
--- a/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
+++ b/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
@@ -39,6 +39,7 @@ struct s3c64xx_spi_csinfo {
* @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6
* @rx_lvl_offset: Depends on tx fifo_lvl field and bus number
* @high_speed: If the controller supports HIGH_SPEED_EN bit
+ * @tx_st_done: Depends on tx fifo_lvl field
*/
struct s3c64xx_spi_info {
int src_clk_nr;
@@ -53,6 +54,7 @@ struct s3c64xx_spi_info {
int fifo_lvl_mask;
int rx_lvl_offset;
int high_speed;
+ int tx_st_done;
};
/**
diff --git a/arch/arm/plat-samsung/irq-uart.c b/arch/arm/plat-samsung/irq-uart.c
index 32582c0958e..0e46588d847 100644
--- a/arch/arm/plat-samsung/irq-uart.c
+++ b/arch/arm/plat-samsung/irq-uart.c
@@ -55,7 +55,7 @@ static void __init s3c_init_uart_irq(struct s3c_uart_irq *uirq)
gc = irq_alloc_generic_chip("s3c-uart", 1, uirq->base_irq, reg_base,
handle_level_irq);
ct = gc->chip_types;
- ct->chip.irq_ack = irq_gc_ack;
+ ct->chip.irq_ack = irq_gc_ack_set_bit;
ct->chip.irq_mask = irq_gc_mask_set_bit;
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
ct->regs.ack = S3C64XX_UINTP;
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index 33867ec4a23..9d6a8effeda 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -12,6 +12,8 @@
#include <linux/of.h>
#include <linux/memblock.h>
#include <linux/vmalloc.h>
+#include <linux/memory.h>
+
#include <asm/firmware.h>
#include <asm/machdep.h>
#include <asm/pSeries_reconfig.h>
@@ -20,24 +22,25 @@
static unsigned long get_memblock_size(void)
{
struct device_node *np;
- unsigned int memblock_size = 0;
+ unsigned int memblock_size = MIN_MEMORY_BLOCK_SIZE;
+ struct resource r;
np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
if (np) {
- const unsigned long *size;
+ const __be64 *size;
size = of_get_property(np, "ibm,lmb-size", NULL);
- memblock_size = size ? *size : 0;
-
+ if (size)
+ memblock_size = be64_to_cpup(size);
of_node_put(np);
- } else {
+ } else if (machine_is(pseries)) {
+ /* This fallback really only applies to pseries */
unsigned int memzero_size = 0;
- const unsigned int *regs;
np = of_find_node_by_path("/memory@0");
if (np) {
- regs = of_get_property(np, "reg", NULL);
- memzero_size = regs ? regs[3] : 0;
+ if (!of_address_to_resource(np, 0, &r))
+ memzero_size = resource_size(&r);
of_node_put(np);
}
@@ -50,16 +53,21 @@ static unsigned long get_memblock_size(void)
sprintf(buf, "/memory@%x", memzero_size);
np = of_find_node_by_path(buf);
if (np) {
- regs = of_get_property(np, "reg", NULL);
- memblock_size = regs ? regs[3] : 0;
+ if (!of_address_to_resource(np, 0, &r))
+ memblock_size = resource_size(&r);
of_node_put(np);
}
}
}
-
return memblock_size;
}
+/* WARNING: This is going to override the generic definition whenever
+ * pseries is built-in regardless of what platform is active at boot
+ * time. This is fine for now as this is the only "option" and it
+ * should work everywhere. If not, we'll have to turn this into a
+ * ppc_md. callback
+ */
unsigned long memory_block_size_bytes(void)
{
return get_memblock_size();
diff --git a/arch/x86/include/asm/mmzone_32.h b/arch/x86/include/asm/mmzone_32.h
index 224e8c5eb30..ffa037f28d3 100644
--- a/arch/x86/include/asm/mmzone_32.h
+++ b/arch/x86/include/asm/mmzone_32.h
@@ -57,6 +57,8 @@ static inline int pfn_valid(int pfn)
return 0;
}
+#define early_pfn_valid(pfn) pfn_valid((pfn))
+
#endif /* CONFIG_DISCONTIGMEM */
#ifdef CONFIG_NEED_MULTIPLE_NODES
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.S b/arch/x86/kernel/acpi/realmode/wakeup.S
index ead21b66311..b4fd836e405 100644
--- a/arch/x86/kernel/acpi/realmode/wakeup.S
+++ b/arch/x86/kernel/acpi/realmode/wakeup.S
@@ -28,6 +28,8 @@ pmode_cr3: .long 0 /* Saved %cr3 */
pmode_cr4: .long 0 /* Saved %cr4 */
pmode_efer: .quad 0 /* Saved EFER */
pmode_gdt: .quad 0
+pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
+pmode_behavior: .long 0 /* Wakeup behavior flags */
realmode_flags: .long 0
real_magic: .long 0
trampoline_segment: .word 0
@@ -91,6 +93,18 @@ wakeup_code:
/* Call the C code */
calll main
+ /* Restore MISC_ENABLE before entering protected mode, in case
+ BIOS decided to clear XD_DISABLE during S3. */
+ movl pmode_behavior, %eax
+ btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax
+ jnc 1f
+
+ movl pmode_misc_en, %eax
+ movl pmode_misc_en + 4, %edx
+ movl $MSR_IA32_MISC_ENABLE, %ecx
+ wrmsr
+1:
+
/* Do any other stuff... */
#ifndef CONFIG_64BIT
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.h b/arch/x86/kernel/acpi/realmode/wakeup.h
index e1828c07e79..97a29e1430e 100644
--- a/arch/x86/kernel/acpi/realmode/wakeup.h
+++ b/arch/x86/kernel/acpi/realmode/wakeup.h
@@ -21,6 +21,9 @@ struct wakeup_header {
u32 pmode_efer_low; /* Protected mode EFER */
u32 pmode_efer_high;
u64 pmode_gdt;
+ u32 pmode_misc_en_low; /* Protected mode MISC_ENABLE */
+ u32 pmode_misc_en_high;
+ u32 pmode_behavior; /* Wakeup routine behavior flags */
u32 realmode_flags;
u32 real_magic;
u16 trampoline_segment; /* segment with trampoline code, 64-bit only */
@@ -39,4 +42,7 @@ extern struct wakeup_header wakeup_header;
#define WAKEUP_HEADER_SIGNATURE 0x51ee1111
#define WAKEUP_END_SIGNATURE 0x65a22c82
+/* Wakeup behavior bits */
+#define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0
+
#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 18a857ba7a2..103b6ab368d 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -77,6 +77,12 @@ int acpi_suspend_lowlevel(void)
header->pmode_cr0 = read_cr0();
header->pmode_cr4 = read_cr4_safe();
+ header->pmode_behavior = 0;
+ if (!rdmsr_safe(MSR_IA32_MISC_ENABLE,
+ &header->pmode_misc_en_low,
+ &header->pmode_misc_en_high))
+ header->pmode_behavior |=
+ (1 << WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE);
header->realmode_flags = acpi_realmode_flags;
header->real_magic = 0x12345678;
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 0c016f72769..4f0d46fefa7 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -294,6 +294,14 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "VersaLogic Menlow board"),
},
},
+ { /* Handle reboot issue on Acer Aspire one */
+ .callback = set_bios_reboot,
+ .ident = "Acer Aspire One A110",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
+ },
+ },
{ }
};
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index d865c4aeec5..bbaaa005bf0 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -28,6 +28,7 @@
#include <linux/poison.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
+#include <linux/memory.h>
#include <linux/memory_hotplug.h>
#include <linux/nmi.h>
#include <linux/gfp.h>
@@ -895,8 +896,6 @@ const char *arch_vma_name(struct vm_area_struct *vma)
}
#ifdef CONFIG_X86_UV
-#define MIN_MEMORY_BLOCK_SIZE (1 << SECTION_SIZE_BITS)
-
unsigned long memory_block_size_bytes(void)
{
if (is_uv_system()) {
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c
index cf9750004a0..68894fdc034 100644
--- a/arch/x86/oprofile/nmi_int.c
+++ b/arch/x86/oprofile/nmi_int.c
@@ -112,8 +112,10 @@ static void nmi_cpu_start(void *dummy)
static int nmi_start(void)
{
get_online_cpus();
- on_each_cpu(nmi_cpu_start, NULL, 1);
ctr_running = 1;
+ /* make ctr_running visible to the nmi handler: */
+ smp_mb();
+ on_each_cpu(nmi_cpu_start, NULL, 1);
put_online_cpus();
return 0;
}
@@ -504,15 +506,18 @@ static int nmi_setup(void)
nmi_enabled = 0;
ctr_running = 0;
- barrier();
+ /* make variables visible to the nmi handler: */
+ smp_mb();
err = register_die_notifier(&profile_exceptions_nb);
if (err)
goto fail;
get_online_cpus();
register_cpu_notifier(&oprofile_cpu_nb);
- on_each_cpu(nmi_cpu_setup, NULL, 1);
nmi_enabled = 1;
+ /* make nmi_enabled visible to the nmi handler: */
+ smp_mb();
+ on_each_cpu(nmi_cpu_setup, NULL, 1);
put_online_cpus();
return 0;
@@ -531,7 +536,8 @@ static void nmi_shutdown(void)
nmi_enabled = 0;
ctr_running = 0;
put_online_cpus();
- barrier();
+ /* make variables visible to the nmi handler: */
+ smp_mb();
unregister_die_notifier(&profile_exceptions_nb);
msrs = &get_cpu_var(cpu_msrs);
model->shutdown(msrs);
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index 8214724ce54..f567965c062 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -327,7 +327,7 @@ int __init pci_xen_hvm_init(void)
}
#ifdef CONFIG_XEN_DOM0
-static int xen_register_pirq(u32 gsi, int triggering)
+static int xen_register_pirq(u32 gsi, int gsi_override, int triggering)
{
int rc, pirq, irq = -1;
struct physdev_map_pirq map_irq;
@@ -344,16 +344,18 @@ static int xen_register_pirq(u32 gsi, int triggering)
shareable = 1;
name = "ioapic-level";
}
-
pirq = xen_allocate_pirq_gsi(gsi);
if (pirq < 0)
goto out;
- irq = xen_bind_pirq_gsi_to_irq(gsi, pirq, shareable, name);
+ if (gsi_override >= 0)
+ irq = xen_bind_pirq_gsi_to_irq(gsi_override, pirq, shareable, name);
+ else
+ irq = xen_bind_pirq_gsi_to_irq(gsi, pirq, shareable, name);
if (irq < 0)
goto out;
- printk(KERN_DEBUG "xen: --> pirq=%d -> irq=%d\n", pirq, irq);
+ printk(KERN_DEBUG "xen: --> pirq=%d -> irq=%d (gsi=%d)\n", pirq, irq, gsi);
map_irq.domid = DOMID_SELF;
map_irq.type = MAP_PIRQ_TYPE_GSI;
@@ -370,7 +372,7 @@ out:
return irq;
}
-static int xen_register_gsi(u32 gsi, int triggering, int polarity)
+static int xen_register_gsi(u32 gsi, int gsi_override, int triggering, int polarity)
{
int rc, irq;
struct physdev_setup_gsi setup_gsi;
@@ -381,7 +383,7 @@ static int xen_register_gsi(u32 gsi, int triggering, int polarity)
printk(KERN_DEBUG "xen: registering gsi %u triggering %d polarity %d\n",
gsi, triggering, polarity);
- irq = xen_register_pirq(gsi, triggering);
+ irq = xen_register_pirq(gsi, gsi_override, triggering);
setup_gsi.gsi = gsi;
setup_gsi.triggering = (triggering == ACPI_EDGE_SENSITIVE ? 0 : 1);
@@ -403,6 +405,8 @@ static __init void xen_setup_acpi_sci(void)
int rc;
int trigger, polarity;
int gsi = acpi_sci_override_gsi;
+ int irq = -1;
+ int gsi_override = -1;
if (!gsi)
return;
@@ -419,7 +423,25 @@ static __init void xen_setup_acpi_sci(void)
printk(KERN_INFO "xen: sci override: global_irq=%d trigger=%d "
"polarity=%d\n", gsi, trigger, polarity);
- gsi = xen_register_gsi(gsi, trigger, polarity);
+ /* Before we bind the GSI to a Linux IRQ, check whether
+ * we need to override it with bus_irq (IRQ) value. Usually for
+ * IRQs below IRQ_LEGACY_IRQ this holds IRQ == GSI, as so:
+ * ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 9 low level)
+ * but there are oddballs where the IRQ != GSI:
+ * ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 20 low level)
+ * which ends up being: gsi_to_irq[9] == 20
+ * (which is what acpi_gsi_to_irq ends up calling when starting the
+ * the ACPI interpreter and keels over since IRQ 9 has not been
+ * setup as we had setup IRQ 20 for it).
+ */
+ /* Check whether the GSI != IRQ */
+ if (acpi_gsi_to_irq(gsi, &irq) == 0) {
+ if (irq >= 0 && irq != gsi)
+ /* Bugger, we MUST have that IRQ. */
+ gsi_override = irq;
+ }
+
+ gsi = xen_register_gsi(gsi, gsi_override, trigger, polarity);
printk(KERN_INFO "xen: acpi sci %d\n", gsi);
return;
@@ -428,7 +450,7 @@ static __init void xen_setup_acpi_sci(void)
static int acpi_register_gsi_xen(struct device *dev, u32 gsi,
int trigger, int polarity)
{
- return xen_register_gsi(gsi, trigger, polarity);
+ return xen_register_gsi(gsi, -1 /* no GSI override */, trigger, polarity);
}
static int __init pci_xen_initial_domain(void)
@@ -467,7 +489,7 @@ void __init xen_setup_pirqs(void)
if (acpi_get_override_irq(irq, &trigger, &polarity) == -1)
continue;
- xen_register_pirq(irq,
+ xen_register_pirq(irq, -1 /* no GSI override */,
trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE);
}
}
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 474356b98ed..899e393d8e7 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -504,9 +504,6 @@ void __init efi_init(void)
x86_platform.set_wallclock = efi_set_rtc_mmss;
#endif
- /* Setup for EFI runtime service */
- reboot_type = BOOT_EFI;
-
#if EFI_DEBUG
print_efi_memmap();
#endif
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 673e968df3c..0ccccb67a99 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -1232,7 +1232,11 @@ static void xen_flush_tlb_others(const struct cpumask *cpus,
{
struct {
struct mmuext_op op;
+#ifdef CONFIG_SMP
DECLARE_BITMAP(mask, num_processors);
+#else
+ DECLARE_BITMAP(mask, NR_CPUS);
+#endif
} *args;
struct multicall_space mcs;
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index f3799432676..ae21919f15e 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -2773,11 +2773,14 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
smp_wmb();
cic->key = cfqd_dead_key(cfqd);
+ rcu_read_lock();
if (rcu_dereference(ioc->ioc_data) == cic) {
+ rcu_read_unlock();
spin_lock(&ioc->lock);
rcu_assign_pointer(ioc->ioc_data, NULL);
spin_unlock(&ioc->lock);
- }
+ } else
+ rcu_read_unlock();
if (cic->cfqq[BLK_RW_ASYNC]) {
cfq_exit_cfqq(cfqd, cic->cfqq[BLK_RW_ASYNC]);
@@ -3084,7 +3087,8 @@ cfq_drop_dead_cic(struct cfq_data *cfqd, struct io_context *ioc,
spin_lock_irqsave(&ioc->lock, flags);
- BUG_ON(ioc->ioc_data == cic);
+ BUG_ON(rcu_dereference_check(ioc->ioc_data,
+ lockdep_is_held(&ioc->lock)) == cic);
radix_tree_delete(&ioc->radix_root, cfqd->cic_index);
hlist_del_rcu(&cic->cic_list);
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 9f9b2359f71..45d7c8fc73b 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -30,7 +30,6 @@
static DEFINE_MUTEX(mem_sysfs_mutex);
#define MEMORY_CLASS_NAME "memory"
-#define MIN_MEMORY_BLOCK_SIZE (1 << SECTION_SIZE_BITS)
static int sections_per_block;
diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c
index c126db3cb7d..e8d11b6630e 100644
--- a/drivers/base/syscore.c
+++ b/drivers/base/syscore.c
@@ -9,6 +9,7 @@
#include <linux/syscore_ops.h>
#include <linux/mutex.h>
#include <linux/module.h>
+#include <linux/interrupt.h>
static LIST_HEAD(syscore_ops_list);
static DEFINE_MUTEX(syscore_ops_lock);
@@ -48,6 +49,13 @@ int syscore_suspend(void)
struct syscore_ops *ops;
int ret = 0;
+ pr_debug("Checking wakeup interrupts\n");
+
+ /* Return error code if there are any wakeup interrupts pending. */
+ ret = check_wakeup_irqs();
+ if (ret)
+ return ret;
+
WARN_ONCE(!irqs_disabled(),
"Interrupts enabled before system core suspend.\n");
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c
index 09ef9a878ef..cf0e63dd97d 100644
--- a/drivers/block/drbd/drbd_actlog.c
+++ b/drivers/block/drbd/drbd_actlog.c
@@ -79,7 +79,7 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
md_io.error = 0;
if ((rw & WRITE) && !test_bit(MD_NO_FUA, &mdev->flags))
- rw |= REQ_FUA;
+ rw |= REQ_FUA | REQ_FLUSH;
rw |= REQ_SYNC;
bio = bio_alloc(GFP_NOIO, 1);
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c
index f440a02dfdb..7b976296b56 100644
--- a/drivers/block/drbd/drbd_bitmap.c
+++ b/drivers/block/drbd/drbd_bitmap.c
@@ -112,9 +112,6 @@ struct drbd_bitmap {
struct task_struct *bm_task;
};
-static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
- unsigned long e, int val, const enum km_type km);
-
#define bm_print_lock_info(m) __bm_print_lock_info(m, __func__)
static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func)
{
@@ -994,6 +991,9 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must
bio_endio(bio, -EIO);
} else {
submit_bio(rw, bio);
+ /* this should not count as user activity and cause the
+ * resync to throttle -- see drbd_rs_should_slow_down(). */
+ atomic_add(len >> 9, &mdev->rs_sect_ev);
}
}
@@ -1256,7 +1256,7 @@ unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_f
* expected to be called for only a few bits (e - s about BITS_PER_LONG).
* Must hold bitmap lock already. */
static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
- unsigned long e, int val, const enum km_type km)
+ unsigned long e, int val)
{
struct drbd_bitmap *b = mdev->bitmap;
unsigned long *p_addr = NULL;
@@ -1274,14 +1274,14 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
unsigned int page_nr = bm_bit_to_page_idx(b, bitnr);
if (page_nr != last_page_nr) {
if (p_addr)
- __bm_unmap(p_addr, km);
+ __bm_unmap(p_addr, KM_IRQ1);
if (c < 0)
bm_set_page_lazy_writeout(b->bm_pages[last_page_nr]);
else if (c > 0)
bm_set_page_need_writeout(b->bm_pages[last_page_nr]);
changed_total += c;
c = 0;
- p_addr = __bm_map_pidx(b, page_nr, km);
+ p_addr = __bm_map_pidx(b, page_nr, KM_IRQ1);
last_page_nr = page_nr;
}
if (val)
@@ -1290,7 +1290,7 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
c -= (0 != __test_and_clear_bit_le(bitnr & BITS_PER_PAGE_MASK, p_addr));
}
if (p_addr)
- __bm_unmap(p_addr, km);
+ __bm_unmap(p_addr, KM_IRQ1);
if (c < 0)
bm_set_page_lazy_writeout(b->bm_pages[last_page_nr]);
else if (c > 0)
@@ -1318,7 +1318,7 @@ static int bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
if ((val ? BM_DONT_SET : BM_DONT_CLEAR) & b->bm_flags)
bm_print_lock_info(mdev);
- c = __bm_change_bits_to(mdev, s, e, val, KM_IRQ1);
+ c = __bm_change_bits_to(mdev, s, e, val);
spin_unlock_irqrestore(&b->bm_lock, flags);
return c;
@@ -1343,16 +1343,17 @@ static inline void bm_set_full_words_within_one_page(struct drbd_bitmap *b,
{
int i;
int bits;
- unsigned long *paddr = kmap_atomic(b->bm_pages[page_nr], KM_USER0);
+ unsigned long *paddr = kmap_atomic(b->bm_pages[page_nr], KM_IRQ1);
for (i = first_word; i < last_word; i++) {
bits = hweight_long(paddr[i]);
paddr[i] = ~0UL;
b->bm_set += BITS_PER_LONG - bits;
}
- kunmap_atomic(paddr, KM_USER0);
+ kunmap_atomic(paddr, KM_IRQ1);
}
-/* Same thing as drbd_bm_set_bits, but without taking the spin_lock_irqsave.
+/* Same thing as drbd_bm_set_bits,
+ * but more efficient for a large bit range.
* You must first drbd_bm_lock().
* Can be called to set the whole bitmap in one go.
* Sets bits from s to e _inclusive_. */
@@ -1366,6 +1367,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
* Do not use memset, because we must account for changes,
* so we need to loop over the words with hweight() anyways.
*/
+ struct drbd_bitmap *b = mdev->bitmap;
unsigned long sl = ALIGN(s,BITS_PER_LONG);
unsigned long el = (e+1) & ~((unsigned long)BITS_PER_LONG-1);
int first_page;
@@ -1376,15 +1378,19 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
if (e - s <= 3*BITS_PER_LONG) {
/* don't bother; el and sl may even be wrong. */
- __bm_change_bits_to(mdev, s, e, 1, KM_USER0);
+ spin_lock_irq(&b->bm_lock);
+ __bm_change_bits_to(mdev, s, e, 1);
+ spin_unlock_irq(&b->bm_lock);
return;
}
/* difference is large enough that we can trust sl and el */
+ spin_lock_irq(&b->bm_lock);
+
/* bits filling the current long */
if (sl)
- __bm_change_bits_to(mdev, s, sl-1, 1, KM_USER0);
+ __bm_change_bits_to(mdev, s, sl-1, 1);
first_page = sl >> (3 + PAGE_SHIFT);
last_page = el >> (3 + PAGE_SHIFT);
@@ -1397,8 +1403,10 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
/* first and full pages, unless first page == last page */
for (page_nr = first_page; page_nr < last_page; page_nr++) {
bm_set_full_words_within_one_page(mdev->bitmap, page_nr, first_word, last_word);
+ spin_unlock_irq(&b->bm_lock);
cond_resched();
first_word = 0;
+ spin_lock_irq(&b->bm_lock);
}
/* last page (respectively only page, for first page == last page) */
@@ -1411,7 +1419,8 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
* it would trigger an assert in __bm_change_bits_to()
*/
if (el <= e)
- __bm_change_bits_to(mdev, el, e, 1, KM_USER0);
+ __bm_change_bits_to(mdev, el, e, 1);
+ spin_unlock_irq(&b->bm_lock);
}
/* returns bit state
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index 25d32c5aa50..43beaca5317 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -4602,6 +4602,11 @@ int drbd_asender(struct drbd_thread *thi)
dev_err(DEV, "meta connection shut down by peer.\n");
goto reconnect;
} else if (rv == -EAGAIN) {
+ /* If the data socket received something meanwhile,
+ * that is good enough: peer is still alive. */
+ if (time_after(mdev->last_received,
+ jiffies - mdev->meta.socket->sk->sk_rcvtimeo))
+ continue;
if (ping_timeout_active) {
dev_err(DEV, "PingAck did not arrive in time.\n");
goto reconnect;
@@ -4637,6 +4642,7 @@ int drbd_asender(struct drbd_thread *thi)
goto reconnect;
}
if (received == expect) {
+ mdev->last_received = jiffies;
D_ASSERT(cmd != NULL);
if (!cmd->process(mdev, h))
goto reconnect;
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
index 4d76b06b6b2..4d3e6f6213b 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -536,12 +536,7 @@ static int w_make_resync_request(struct drbd_conf *mdev,
return 1;
}
- /* starting with drbd 8.3.8, we can handle multi-bio EEs,
- * if it should be necessary */
- max_bio_size =
- mdev->agreed_pro_version < 94 ? queue_max_hw_sectors(mdev->rq_queue) << 9 :
- mdev->agreed_pro_version < 95 ? DRBD_MAX_SIZE_H80_PACKET : DRBD_MAX_BIO_SIZE;
-
+ max_bio_size = queue_max_hw_sectors(mdev->rq_queue) << 9;
number = drbd_rs_number_requests(mdev);
if (number == 0)
goto requeue;
diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h
index 999803ce10d..5da67f165af 100644
--- a/drivers/char/agp/intel-agp.h
+++ b/drivers/char/agp/intel-agp.h
@@ -90,9 +90,10 @@
#define G4x_GMCH_SIZE_MASK (0xf << 8)
#define G4x_GMCH_SIZE_1M (0x1 << 8)
#define G4x_GMCH_SIZE_2M (0x3 << 8)
-#define G4x_GMCH_SIZE_VT_1M (0x9 << 8)
-#define G4x_GMCH_SIZE_VT_1_5M (0xa << 8)
-#define G4x_GMCH_SIZE_VT_2M (0xc << 8)
+#define G4x_GMCH_SIZE_VT_EN (0x8 << 8)
+#define G4x_GMCH_SIZE_VT_1M (G4x_GMCH_SIZE_1M | G4x_GMCH_SIZE_VT_EN)
+#define G4x_GMCH_SIZE_VT_1_5M ((0x2 << 8) | G4x_GMCH_SIZE_VT_EN)
+#define G4x_GMCH_SIZE_VT_2M (G4x_GMCH_SIZE_2M | G4x_GMCH_SIZE_VT_EN)
#define GFX_FLSH_CNTL 0x2170 /* 915+ */
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 4e04e127438..596d5dd32f4 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -759,7 +759,7 @@ static void __exit acpi_cpufreq_exit(void)
cpufreq_unregister_driver(&acpi_cpufreq_driver);
- free_percpu(acpi_perf_data);
+ free_acpi_perf_data();
}
module_param(acpi_pstate_strict, uint, 0644);
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 438e6c83117..ebb897329c1 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -264,6 +264,7 @@ static char ohci_driver_name[] = KBUILD_MODNAME;
#define PCI_DEVICE_ID_AGERE_FW643 0x5901
#define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380
#define PCI_DEVICE_ID_TI_TSB12LV22 0x8009
+#define PCI_VENDOR_ID_PINNACLE_SYSTEMS 0x11bd
#define QUIRK_CYCLE_TIMER 1
#define QUIRK_RESET_PACKET 2
@@ -3190,6 +3191,11 @@ static int __devinit pci_probe(struct pci_dev *dev,
int i, err;
size_t size;
+ if (dev->vendor == PCI_VENDOR_ID_PINNACLE_SYSTEMS) {
+ dev_err(&dev->dev, "Pinnacle MovieBoard is not yet supported\n");
+ return -ENOSYS;
+ }
+
ohci = kzalloc(sizeof(*ohci), GFP_KERNEL);
if (ohci == NULL) {
err = -ENOMEM;
diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c
index bd6571e0097..644ba1255d3 100644
--- a/drivers/gpio/langwell_gpio.c
+++ b/drivers/gpio/langwell_gpio.c
@@ -223,7 +223,7 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
gedr = gpio_reg(&lnw->chip, base, GEDR);
pending = readl(gedr);
while (pending) {
- gpio = __ffs(pending) - 1;
+ gpio = __ffs(pending);
mask = BIT(gpio);
pending &= ~mask;
/* Clear before handling so we can't lose an edge */
diff --git a/drivers/gpio/tps65910-gpio.c b/drivers/gpio/tps65910-gpio.c
index 8d1ddfdd63e..15097ca616d 100644
--- a/drivers/gpio/tps65910-gpio.c
+++ b/drivers/gpio/tps65910-gpio.c
@@ -81,8 +81,10 @@ void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
switch(tps65910_chip_id(tps65910)) {
case TPS65910:
tps65910->gpio.ngpio = 6;
+ break;
case TPS65911:
tps65910->gpio.ngpio = 9;
+ break;
default:
return;
}
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 21058e6ad2b..82db1850666 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -886,9 +886,6 @@ int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
total_objects += dev->mode_config.num_connector;
total_objects += dev->mode_config.num_encoder;
- if (total_objects == 0)
- return -EINVAL;
-
group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
if (!group->id_list)
return -ENOMEM;
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 4d46441cbe2..0a893f7400f 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1207,13 +1207,17 @@ static int i915_context_status(struct seq_file *m, void *unused)
if (ret)
return ret;
- seq_printf(m, "power context ");
- describe_obj(m, dev_priv->pwrctx);
- seq_printf(m, "\n");
+ if (dev_priv->pwrctx) {
+ seq_printf(m, "power context ");
+ describe_obj(m, dev_priv->pwrctx);
+ seq_printf(m, "\n");
+ }
- seq_printf(m, "render context ");
- describe_obj(m, dev_priv->renderctx);
- seq_printf(m, "\n");
+ if (dev_priv->renderctx) {
+ seq_printf(m, "render context ");
+ describe_obj(m, dev_priv->renderctx);
+ seq_printf(m, "\n");
+ }
mutex_unlock(&dev->mode_config.mutex);
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 2b79588541e..296fbd66f0e 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1266,30 +1266,6 @@ static int i915_load_modeset_init(struct drm_device *dev)
intel_modeset_gem_init(dev);
- if (IS_IVYBRIDGE(dev)) {
- /* Share pre & uninstall handlers with ILK/SNB */
- dev->driver->irq_handler = ivybridge_irq_handler;
- dev->driver->irq_preinstall = ironlake_irq_preinstall;
- dev->driver->irq_postinstall = ivybridge_irq_postinstall;
- dev->driver->irq_uninstall = ironlake_irq_uninstall;
- dev->driver->enable_vblank = ivybridge_enable_vblank;
- dev->driver->disable_vblank = ivybridge_disable_vblank;
- } else if (HAS_PCH_SPLIT(dev)) {
- dev->driver->irq_handler = ironlake_irq_handler;
- dev->driver->irq_preinstall = ironlake_irq_preinstall;
- dev->driver->irq_postinstall = ironlake_irq_postinstall;
- dev->driver->irq_uninstall = ironlake_irq_uninstall;
- dev->driver->enable_vblank = ironlake_enable_vblank;
- dev->driver->disable_vblank = ironlake_disable_vblank;
- } else {
- dev->driver->irq_preinstall = i915_driver_irq_preinstall;
- dev->driver->irq_postinstall = i915_driver_irq_postinstall;
- dev->driver->irq_uninstall = i915_driver_irq_uninstall;
- dev->driver->irq_handler = i915_driver_irq_handler;
- dev->driver->enable_vblank = i915_enable_vblank;
- dev->driver->disable_vblank = i915_disable_vblank;
- }
-
ret = drm_irq_install(dev);
if (ret)
goto cleanup_gem;
@@ -1967,7 +1943,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (!dev_priv->mm.gtt) {
DRM_ERROR("Failed to initialize GTT\n");
ret = -ENODEV;
- goto out_iomapfree;
+ goto out_rmmap;
}
agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
@@ -2011,18 +1987,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (dev_priv->wq == NULL) {
DRM_ERROR("Failed to create our workqueue.\n");
ret = -ENOMEM;
- goto out_iomapfree;
+ goto out_mtrrfree;
}
/* enable GEM by default */
dev_priv->has_gem = 1;
- dev->driver->get_vblank_counter = i915_get_vblank_counter;
- dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
- if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev)) {
- dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
- dev->driver->get_vblank_counter = gm45_get_vblank_counter;
- }
+ intel_irq_init(dev);
/* Try to make sure MCHBAR is enabled before poking at it */
intel_setup_mchbar(dev);
@@ -2103,13 +2074,21 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
return 0;
out_gem_unload:
+ if (dev_priv->mm.inactive_shrinker.shrink)
+ unregister_shrinker(&dev_priv->mm.inactive_shrinker);
+
if (dev->pdev->msi_enabled)
pci_disable_msi(dev->pdev);
intel_teardown_gmbus(dev);
intel_teardown_mchbar(dev);
destroy_workqueue(dev_priv->wq);
-out_iomapfree:
+out_mtrrfree:
+ if (dev_priv->mm.gtt_mtrr >= 0) {
+ mtrr_del(dev_priv->mm.gtt_mtrr, dev->agp->base,
+ dev->agp->agp_info.aper_size * 1024 * 1024);
+ dev_priv->mm.gtt_mtrr = -1;
+ }
io_mapping_free(dev_priv->mm.gtt_mapping);
out_rmmap:
pci_iounmap(dev->pdev, dev_priv->regs);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 609358faaa9..eb91e2dd791 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -52,7 +52,7 @@ module_param_named(powersave, i915_powersave, int, 0600);
unsigned int i915_semaphores = 0;
module_param_named(semaphores, i915_semaphores, int, 0600);
-unsigned int i915_enable_rc6 = 1;
+unsigned int i915_enable_rc6 = 0;
module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600);
unsigned int i915_enable_fbc = 0;
@@ -577,6 +577,7 @@ int i915_reset(struct drm_device *dev, u8 flags)
if (get_seconds() - dev_priv->last_gpu_reset < 5) {
DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
} else switch (INTEL_INFO(dev)->gen) {
+ case 7:
case 6:
ret = gen6_do_reset(dev, flags);
/* If reset with a user forcewake, try to restore */
@@ -765,14 +766,6 @@ static struct drm_driver driver = {
.resume = i915_resume,
.device_is_agp = i915_driver_device_is_agp,
- .enable_vblank = i915_enable_vblank,
- .disable_vblank = i915_disable_vblank,
- .get_vblank_timestamp = i915_get_vblank_timestamp,
- .get_scanout_position = i915_get_crtc_scanoutpos,
- .irq_preinstall = i915_driver_irq_preinstall,
- .irq_postinstall = i915_driver_irq_postinstall,
- .irq_uninstall = i915_driver_irq_uninstall,
- .irq_handler = i915_driver_irq_handler,
.reclaim_buffers = drm_core_reclaim_buffers,
.master_create = i915_master_create,
.master_destroy = i915_master_destroy,
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index eddabf68e97..f245c588ae9 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -997,8 +997,6 @@ extern unsigned int i915_enable_fbc;
extern int i915_suspend(struct drm_device *dev, pm_message_t state);
extern int i915_resume(struct drm_device *dev);
-extern void i915_save_display(struct drm_device *dev);
-extern void i915_restore_display(struct drm_device *dev);
extern int i915_master_create(struct drm_device *dev, struct drm_master *master);
extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master);
@@ -1033,33 +1031,12 @@ extern int i915_irq_emit(struct drm_device *dev, void *data,
extern int i915_irq_wait(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
-extern void i915_driver_irq_preinstall(struct drm_device * dev);
-extern int i915_driver_irq_postinstall(struct drm_device *dev);
-extern void i915_driver_irq_uninstall(struct drm_device * dev);
-
-extern irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS);
-extern void ironlake_irq_preinstall(struct drm_device *dev);
-extern int ironlake_irq_postinstall(struct drm_device *dev);
-extern void ironlake_irq_uninstall(struct drm_device *dev);
-
-extern irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS);
-extern void ivybridge_irq_preinstall(struct drm_device *dev);
-extern int ivybridge_irq_postinstall(struct drm_device *dev);
-extern void ivybridge_irq_uninstall(struct drm_device *dev);
+extern void intel_irq_init(struct drm_device *dev);
extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-extern int i915_enable_vblank(struct drm_device *dev, int crtc);
-extern void i915_disable_vblank(struct drm_device *dev, int crtc);
-extern int ironlake_enable_vblank(struct drm_device *dev, int crtc);
-extern void ironlake_disable_vblank(struct drm_device *dev, int crtc);
-extern int ivybridge_enable_vblank(struct drm_device *dev, int crtc);
-extern void ivybridge_disable_vblank(struct drm_device *dev, int crtc);
-extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
-extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc);
extern int i915_vblank_swap(struct drm_device *dev, void *data,
struct drm_file *file_priv);
@@ -1070,13 +1047,6 @@ void
i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
void intel_enable_asle (struct drm_device *dev);
-int i915_get_vblank_timestamp(struct drm_device *dev, int crtc,
- int *max_error,
- struct timeval *vblank_time,
- unsigned flags);
-
-int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
- int *vpos, int *hpos);
#ifdef CONFIG_DEBUG_FS
extern void i915_destroy_error_state(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index ae2b49969b9..3b03f85ea62 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -152,7 +152,7 @@ i915_pipe_enabled(struct drm_device *dev, int pipe)
/* Called from drm generic code, passed a 'crtc', which
* we use as a pipe index
*/
-u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
+static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long high_frame;
@@ -184,7 +184,7 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
return (high1 << 8) | low;
}
-u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
+static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int reg = PIPE_FRMCOUNT_GM45(pipe);
@@ -198,7 +198,7 @@ u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
return I915_READ(reg);
}
-int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
+static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
int *vpos, int *hpos)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -264,7 +264,7 @@ int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
return ret;
}
-int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
+static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
int *max_error,
struct timeval *vblank_time,
unsigned flags)
@@ -462,7 +462,7 @@ static void pch_irq_handler(struct drm_device *dev)
DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n");
}
-irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS)
+static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -550,7 +550,7 @@ done:
return ret;
}
-irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
+static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -1209,7 +1209,7 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe)
}
}
-irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
+static irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -1454,7 +1454,7 @@ int i915_irq_wait(struct drm_device *dev, void *data,
/* Called from drm generic code, passed 'crtc' which
* we use as a pipe index
*/
-int i915_enable_vblank(struct drm_device *dev, int pipe)
+static int i915_enable_vblank(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
@@ -1478,7 +1478,7 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
return 0;
}
-int ironlake_enable_vblank(struct drm_device *dev, int pipe)
+static int ironlake_enable_vblank(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
@@ -1494,7 +1494,7 @@ int ironlake_enable_vblank(struct drm_device *dev, int pipe)
return 0;
}
-int ivybridge_enable_vblank(struct drm_device *dev, int pipe)
+static int ivybridge_enable_vblank(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
@@ -1513,7 +1513,7 @@ int ivybridge_enable_vblank(struct drm_device *dev, int pipe)
/* Called from drm generic code, passed 'crtc' which
* we use as a pipe index
*/
-void i915_disable_vblank(struct drm_device *dev, int pipe)
+static void i915_disable_vblank(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
@@ -1529,7 +1529,7 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
-void ironlake_disable_vblank(struct drm_device *dev, int pipe)
+static void ironlake_disable_vblank(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
@@ -1540,7 +1540,7 @@ void ironlake_disable_vblank(struct drm_device *dev, int pipe)
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
-void ivybridge_disable_vblank(struct drm_device *dev, int pipe)
+static void ivybridge_disable_vblank(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
@@ -1728,7 +1728,7 @@ repeat:
/* drm_dma.h hooks
*/
-void ironlake_irq_preinstall(struct drm_device *dev)
+static void ironlake_irq_preinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -1740,7 +1740,7 @@ void ironlake_irq_preinstall(struct drm_device *dev)
INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work);
I915_WRITE(HWSTAM, 0xeffe);
- if (IS_GEN6(dev)) {
+ if (IS_GEN6(dev) || IS_GEN7(dev)) {
/* Workaround stalls observed on Sandy Bridge GPUs by
* making the blitter command streamer generate a
* write to the Hardware Status Page for
@@ -1769,7 +1769,7 @@ void ironlake_irq_preinstall(struct drm_device *dev)
POSTING_READ(SDEIER);
}
-int ironlake_irq_postinstall(struct drm_device *dev)
+static int ironlake_irq_postinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
/* enable kind of interrupts always enabled */
@@ -1841,7 +1841,7 @@ int ironlake_irq_postinstall(struct drm_device *dev)
return 0;
}
-int ivybridge_irq_postinstall(struct drm_device *dev)
+static int ivybridge_irq_postinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
/* enable kind of interrupts always enabled */
@@ -1891,7 +1891,7 @@ int ivybridge_irq_postinstall(struct drm_device *dev)
return 0;
}
-void i915_driver_irq_preinstall(struct drm_device * dev)
+static void i915_driver_irq_preinstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int pipe;
@@ -1918,7 +1918,7 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
* Must be called after intel_modeset_init or hotplug interrupts won't be
* enabled correctly.
*/
-int i915_driver_irq_postinstall(struct drm_device *dev)
+static int i915_driver_irq_postinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
@@ -1994,7 +1994,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
return 0;
}
-void ironlake_irq_uninstall(struct drm_device *dev)
+static void ironlake_irq_uninstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -2014,7 +2014,7 @@ void ironlake_irq_uninstall(struct drm_device *dev)
I915_WRITE(GTIIR, I915_READ(GTIIR));
}
-void i915_driver_irq_uninstall(struct drm_device * dev)
+static void i915_driver_irq_uninstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int pipe;
@@ -2040,3 +2040,41 @@ void i915_driver_irq_uninstall(struct drm_device * dev)
I915_READ(PIPESTAT(pipe)) & 0x8000ffff);
I915_WRITE(IIR, I915_READ(IIR));
}
+
+void intel_irq_init(struct drm_device *dev)
+{
+ dev->driver->get_vblank_counter = i915_get_vblank_counter;
+ dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
+ if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev)) {
+ dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
+ dev->driver->get_vblank_counter = gm45_get_vblank_counter;
+ }
+
+
+ dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
+ dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
+
+ if (IS_IVYBRIDGE(dev)) {
+ /* Share pre & uninstall handlers with ILK/SNB */
+ dev->driver->irq_handler = ivybridge_irq_handler;
+ dev->driver->irq_preinstall = ironlake_irq_preinstall;
+ dev->driver->irq_postinstall = ivybridge_irq_postinstall;
+ dev->driver->irq_uninstall = ironlake_irq_uninstall;
+ dev->driver->enable_vblank = ivybridge_enable_vblank;
+ dev->driver->disable_vblank = ivybridge_disable_vblank;
+ } else if (HAS_PCH_SPLIT(dev)) {
+ dev->driver->irq_handler = ironlake_irq_handler;
+ dev->driver->irq_preinstall = ironlake_irq_preinstall;
+ dev->driver->irq_postinstall = ironlake_irq_postinstall;
+ dev->driver->irq_uninstall = ironlake_irq_uninstall;
+ dev->driver->enable_vblank = ironlake_enable_vblank;
+ dev->driver->disable_vblank = ironlake_disable_vblank;
+ } else {
+ dev->driver->irq_preinstall = i915_driver_irq_preinstall;
+ dev->driver->irq_postinstall = i915_driver_irq_postinstall;
+ dev->driver->irq_uninstall = i915_driver_irq_uninstall;
+ dev->driver->irq_handler = i915_driver_irq_handler;
+ dev->driver->enable_vblank = i915_enable_vblank;
+ dev->driver->disable_vblank = i915_disable_vblank;
+ }
+}
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index e8152d23d5b..5257cfc34c3 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -597,7 +597,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
return;
}
-void i915_save_display(struct drm_device *dev)
+static void i915_save_display(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -678,7 +678,6 @@ void i915_save_display(struct drm_device *dev)
}
/* VGA state */
- mutex_lock(&dev->struct_mutex);
dev_priv->saveVGA0 = I915_READ(VGA0);
dev_priv->saveVGA1 = I915_READ(VGA1);
dev_priv->saveVGA_PD = I915_READ(VGA_PD);
@@ -688,10 +687,9 @@ void i915_save_display(struct drm_device *dev)
dev_priv->saveVGACNTRL = I915_READ(VGACNTRL);
i915_save_vga(dev);
- mutex_unlock(&dev->struct_mutex);
}
-void i915_restore_display(struct drm_device *dev)
+static void i915_restore_display(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -783,7 +781,6 @@ void i915_restore_display(struct drm_device *dev)
else
I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL);
- mutex_lock(&dev->struct_mutex);
I915_WRITE(VGA0, dev_priv->saveVGA0);
I915_WRITE(VGA1, dev_priv->saveVGA1);
I915_WRITE(VGA_PD, dev_priv->saveVGA_PD);
@@ -791,7 +788,6 @@ void i915_restore_display(struct drm_device *dev)
udelay(150);
i915_restore_vga(dev);
- mutex_unlock(&dev->struct_mutex);
}
int i915_save_state(struct drm_device *dev)
@@ -801,6 +797,8 @@ int i915_save_state(struct drm_device *dev)
pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
+ mutex_lock(&dev->struct_mutex);
+
/* Hardware status page */
dev_priv->saveHWS = I915_READ(HWS_PGA);
@@ -840,6 +838,8 @@ int i915_save_state(struct drm_device *dev)
for (i = 0; i < 3; i++)
dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2));
+ mutex_unlock(&dev->struct_mutex);
+
return 0;
}
@@ -850,6 +850,8 @@ int i915_restore_state(struct drm_device *dev)
pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB);
+ mutex_lock(&dev->struct_mutex);
+
/* Hardware status page */
I915_WRITE(HWS_PGA, dev_priv->saveHWS);
@@ -867,6 +869,7 @@ int i915_restore_state(struct drm_device *dev)
I915_WRITE(IER, dev_priv->saveIER);
I915_WRITE(IMR, dev_priv->saveIMR);
}
+ mutex_unlock(&dev->struct_mutex);
intel_init_clock_gating(dev);
@@ -878,6 +881,8 @@ int i915_restore_state(struct drm_device *dev)
if (IS_GEN6(dev))
gen6_enable_rps(dev_priv);
+ mutex_lock(&dev->struct_mutex);
+
/* Cache mode state */
I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
@@ -891,6 +896,8 @@ int i915_restore_state(struct drm_device *dev)
for (i = 0; i < 3; i++)
I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
+ mutex_unlock(&dev->struct_mutex);
+
intel_i2c_reset(dev);
return 0;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 391b55f1cc7..e2aced6eec4 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -50,7 +50,6 @@ struct intel_dp {
bool has_audio;
int force_audio;
uint32_t color_range;
- int dpms_mode;
uint8_t link_bw;
uint8_t lane_count;
uint8_t dpcd[4];
@@ -138,8 +137,8 @@ intel_dp_max_lane_count(struct intel_dp *intel_dp)
{
int max_lane_count = 4;
- if (intel_dp->dpcd[0] >= 0x11) {
- max_lane_count = intel_dp->dpcd[2] & 0x1f;
+ if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) {
+ max_lane_count = intel_dp->dpcd[DP_MAX_LANE_COUNT] & 0x1f;
switch (max_lane_count) {
case 1: case 2: case 4:
break;
@@ -153,7 +152,7 @@ intel_dp_max_lane_count(struct intel_dp *intel_dp)
static int
intel_dp_max_link_bw(struct intel_dp *intel_dp)
{
- int max_link_bw = intel_dp->dpcd[1];
+ int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
switch (max_link_bw) {
case DP_LINK_BW_1_62:
@@ -774,7 +773,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
/*
* Check for DPCD version > 1.1 and enhanced framing support
*/
- if (intel_dp->dpcd[0] >= 0x11 && (intel_dp->dpcd[2] & DP_ENHANCED_FRAME_CAP)) {
+ if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
+ (intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)) {
intel_dp->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
intel_dp->DP |= DP_ENHANCED_FRAMING;
}
@@ -942,11 +942,44 @@ static void ironlake_edp_pll_off(struct drm_encoder *encoder)
udelay(200);
}
+/* If the sink supports it, try to set the power state appropriately */
+static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
+{
+ int ret, i;
+
+ /* Should have a valid DPCD by this point */
+ if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
+ return;
+
+ if (mode != DRM_MODE_DPMS_ON) {
+ ret = intel_dp_aux_native_write_1(intel_dp, DP_SET_POWER,
+ DP_SET_POWER_D3);
+ if (ret != 1)
+ DRM_DEBUG_DRIVER("failed to write sink power state\n");
+ } else {
+ /*
+ * When turning on, we need to retry for 1ms to give the sink
+ * time to wake up.
+ */
+ for (i = 0; i < 3; i++) {
+ ret = intel_dp_aux_native_write_1(intel_dp,
+ DP_SET_POWER,
+ DP_SET_POWER_D0);
+ if (ret == 1)
+ break;
+ msleep(1);
+ }
+ }
+}
+
static void intel_dp_prepare(struct drm_encoder *encoder)
{
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct drm_device *dev = encoder->dev;
+ /* Wake up the sink first */
+ intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+
if (is_edp(intel_dp)) {
ironlake_edp_backlight_off(dev);
ironlake_edp_panel_off(dev);
@@ -990,6 +1023,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
if (mode != DRM_MODE_DPMS_ON) {
if (is_edp(intel_dp))
ironlake_edp_backlight_off(dev);
+ intel_dp_sink_dpms(intel_dp, mode);
intel_dp_link_down(intel_dp);
if (is_edp(intel_dp))
ironlake_edp_panel_off(dev);
@@ -998,6 +1032,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
} else {
if (is_edp(intel_dp))
ironlake_edp_panel_vdd_on(intel_dp);
+ intel_dp_sink_dpms(intel_dp, mode);
if (!(dp_reg & DP_PORT_EN)) {
intel_dp_start_link_train(intel_dp);
if (is_edp(intel_dp)) {
@@ -1009,7 +1044,31 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
if (is_edp(intel_dp))
ironlake_edp_backlight_on(dev);
}
- intel_dp->dpms_mode = mode;
+}
+
+/*
+ * Native read with retry for link status and receiver capability reads for
+ * cases where the sink may still be asleep.
+ */
+static bool
+intel_dp_aux_native_read_retry(struct intel_dp *intel_dp, uint16_t address,
+ uint8_t *recv, int recv_bytes)
+{
+ int ret, i;
+
+ /*
+ * Sinks are *supposed* to come up within 1ms from an off state,
+ * but we're also supposed to retry 3 times per the spec.
+ */
+ for (i = 0; i < 3; i++) {
+ ret = intel_dp_aux_native_read(intel_dp, address, recv,
+ recv_bytes);
+ if (ret == recv_bytes)
+ return true;
+ msleep(1);
+ }
+
+ return false;
}
/*
@@ -1019,14 +1078,10 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
static bool
intel_dp_get_link_status(struct intel_dp *intel_dp)
{
- int ret;
-
- ret = intel_dp_aux_native_read(intel_dp,
- DP_LANE0_1_STATUS,
- intel_dp->link_status, DP_LINK_STATUS_SIZE);
- if (ret != DP_LINK_STATUS_SIZE)
- return false;
- return true;
+ return intel_dp_aux_native_read_retry(intel_dp,
+ DP_LANE0_1_STATUS,
+ intel_dp->link_status,
+ DP_LINK_STATUS_SIZE);
}
static uint8_t
@@ -1515,6 +1570,8 @@ intel_dp_link_down(struct intel_dp *intel_dp)
static void
intel_dp_check_link_status(struct intel_dp *intel_dp)
{
+ int ret;
+
if (!intel_dp->base.base.crtc)
return;
@@ -1523,6 +1580,15 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
return;
}
+ /* Try to read receiver status if the link appears to be up */
+ ret = intel_dp_aux_native_read(intel_dp,
+ 0x000, intel_dp->dpcd,
+ sizeof (intel_dp->dpcd));
+ if (ret != sizeof(intel_dp->dpcd)) {
+ intel_dp_link_down(intel_dp);
+ return;
+ }
+
if (!intel_channel_eq_ok(intel_dp)) {
intel_dp_start_link_train(intel_dp);
intel_dp_complete_link_train(intel_dp);
@@ -1533,6 +1599,7 @@ static enum drm_connector_status
ironlake_dp_detect(struct intel_dp *intel_dp)
{
enum drm_connector_status status;
+ bool ret;
/* Can't disconnect eDP, but you can close the lid... */
if (is_edp(intel_dp)) {
@@ -1543,13 +1610,11 @@ ironlake_dp_detect(struct intel_dp *intel_dp)
}
status = connector_status_disconnected;
- if (intel_dp_aux_native_read(intel_dp,
- 0x000, intel_dp->dpcd,
- sizeof (intel_dp->dpcd))
- == sizeof(intel_dp->dpcd)) {
- if (intel_dp->dpcd[0] != 0)
- status = connector_status_connected;
- }
+ ret = intel_dp_aux_native_read_retry(intel_dp,
+ 0x000, intel_dp->dpcd,
+ sizeof (intel_dp->dpcd));
+ if (ret && intel_dp->dpcd[DP_DPCD_REV] != 0)
+ status = connector_status_connected;
DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0],
intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]);
return status;
@@ -1586,7 +1651,7 @@ g4x_dp_detect(struct intel_dp *intel_dp)
if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd,
sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd))
{
- if (intel_dp->dpcd[0] != 0)
+ if (intel_dp->dpcd[DP_DPCD_REV] != 0)
status = connector_status_connected;
}
@@ -1790,8 +1855,7 @@ intel_dp_hot_plug(struct intel_encoder *intel_encoder)
{
struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base);
- if (intel_dp->dpms_mode == DRM_MODE_DPMS_ON)
- intel_dp_check_link_status(intel_dp);
+ intel_dp_check_link_status(intel_dp);
}
/* Return which DP Port should be selected for Transcoder DP control */
@@ -1859,7 +1923,6 @@ intel_dp_init(struct drm_device *dev, int output_reg)
return;
intel_dp->output_reg = output_reg;
- intel_dp->dpms_mode = -1;
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
if (!intel_connector) {
@@ -1954,8 +2017,9 @@ intel_dp_init(struct drm_device *dev, int output_reg)
sizeof(intel_dp->dpcd));
ironlake_edp_panel_vdd_off(intel_dp);
if (ret == sizeof(intel_dp->dpcd)) {
- if (intel_dp->dpcd[0] >= 0x11)
- dev_priv->no_aux_handshake = intel_dp->dpcd[3] &
+ if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
+ dev_priv->no_aux_handshake =
+ intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
} else {
/* if this fails, presume the device is a ghost */
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 56a8e2aea19..9e2959bc91c 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -1409,6 +1409,11 @@ void intel_setup_overlay(struct drm_device *dev)
overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL);
if (!overlay)
return;
+
+ mutex_lock(&dev->struct_mutex);
+ if (WARN_ON(dev_priv->overlay))
+ goto out_free;
+
overlay->dev = dev;
reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE);
@@ -1416,8 +1421,6 @@ void intel_setup_overlay(struct drm_device *dev)
goto out_free;
overlay->reg_bo = reg_bo;
- mutex_lock(&dev->struct_mutex);
-
if (OVERLAY_NEEDS_PHYSICAL(dev)) {
ret = i915_gem_attach_phys_object(dev, reg_bo,
I915_GEM_PHYS_OVERLAY_REGS,
@@ -1442,8 +1445,6 @@ void intel_setup_overlay(struct drm_device *dev)
}
}
- mutex_unlock(&dev->struct_mutex);
-
/* init all values */
overlay->color_key = 0x0101fe;
overlay->brightness = -19;
@@ -1452,7 +1453,7 @@ void intel_setup_overlay(struct drm_device *dev)
regs = intel_overlay_map_regs(overlay);
if (!regs)
- goto out_free_bo;
+ goto out_unpin_bo;
memset(regs, 0, sizeof(struct overlay_registers));
update_polyphase_filter(regs);
@@ -1461,15 +1462,17 @@ void intel_setup_overlay(struct drm_device *dev)
intel_overlay_unmap_regs(overlay, regs);
dev_priv->overlay = overlay;
+ mutex_unlock(&dev->struct_mutex);
DRM_INFO("initialized overlay support\n");
return;
out_unpin_bo:
- i915_gem_object_unpin(reg_bo);
+ if (!OVERLAY_NEEDS_PHYSICAL(dev))
+ i915_gem_object_unpin(reg_bo);
out_free_bo:
drm_gem_object_unreference(&reg_bo->base);
- mutex_unlock(&dev->struct_mutex);
out_free:
+ mutex_unlock(&dev->struct_mutex);
kfree(overlay);
return;
}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index c0e0ee63fbf..39ac2b634ae 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -165,7 +165,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring);
int __must_check intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n);
static inline int intel_wait_ring_idle(struct intel_ring_buffer *ring)
{
- return intel_wait_ring_buffer(ring, ring->space - 8);
+ return intel_wait_ring_buffer(ring, ring->size - 8);
}
int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n);
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 144f79a350a..731acea865b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -371,7 +371,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->vram.flags_valid = nv50_vram_flags_valid;
break;
case 0xC0:
- case 0xD0:
engine->instmem.init = nvc0_instmem_init;
engine->instmem.takedown = nvc0_instmem_takedown;
engine->instmem.suspend = nvc0_instmem_suspend;
@@ -923,7 +922,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
dev_priv->card_type = NV_50;
break;
case 0xc0:
- case 0xd0:
dev_priv->card_type = NV_C0;
break;
default:
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 12d2fdc5241..15bd0477a3e 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -985,17 +985,19 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav
{
save->vga_control[0] = RREG32(D1VGA_CONTROL);
save->vga_control[1] = RREG32(D2VGA_CONTROL);
- save->vga_control[2] = RREG32(EVERGREEN_D3VGA_CONTROL);
- save->vga_control[3] = RREG32(EVERGREEN_D4VGA_CONTROL);
- save->vga_control[4] = RREG32(EVERGREEN_D5VGA_CONTROL);
- save->vga_control[5] = RREG32(EVERGREEN_D6VGA_CONTROL);
save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
save->vga_hdp_control = RREG32(VGA_HDP_CONTROL);
save->crtc_control[0] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET);
save->crtc_control[1] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
- if (!(rdev->flags & RADEON_IS_IGP)) {
+ if (rdev->num_crtc >= 4) {
+ save->vga_control[2] = RREG32(EVERGREEN_D3VGA_CONTROL);
+ save->vga_control[3] = RREG32(EVERGREEN_D4VGA_CONTROL);
save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET);
save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET);
+ }
+ if (rdev->num_crtc >= 6) {
+ save->vga_control[4] = RREG32(EVERGREEN_D5VGA_CONTROL);
+ save->vga_control[5] = RREG32(EVERGREEN_D6VGA_CONTROL);
save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET);
save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
}
@@ -1004,35 +1006,45 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav
WREG32(VGA_RENDER_CONTROL, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
- if (!(rdev->flags & RADEON_IS_IGP)) {
+ if (rdev->num_crtc >= 4) {
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
+ }
+ if (rdev->num_crtc >= 6) {
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
}
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
- if (!(rdev->flags & RADEON_IS_IGP)) {
+ if (rdev->num_crtc >= 4) {
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+ }
+ if (rdev->num_crtc >= 6) {
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
}
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
- if (!(rdev->flags & RADEON_IS_IGP)) {
+ if (rdev->num_crtc >= 4) {
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+ }
+ if (rdev->num_crtc >= 6) {
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
}
WREG32(D1VGA_CONTROL, 0);
WREG32(D2VGA_CONTROL, 0);
- WREG32(EVERGREEN_D3VGA_CONTROL, 0);
- WREG32(EVERGREEN_D4VGA_CONTROL, 0);
- WREG32(EVERGREEN_D5VGA_CONTROL, 0);
- WREG32(EVERGREEN_D6VGA_CONTROL, 0);
+ if (rdev->num_crtc >= 4) {
+ WREG32(EVERGREEN_D3VGA_CONTROL, 0);
+ WREG32(EVERGREEN_D4VGA_CONTROL, 0);
+ }
+ if (rdev->num_crtc >= 6) {
+ WREG32(EVERGREEN_D5VGA_CONTROL, 0);
+ WREG32(EVERGREEN_D6VGA_CONTROL, 0);
+ }
}
void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save)
@@ -1055,7 +1067,7 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
- if (!(rdev->flags & RADEON_IS_IGP)) {
+ if (rdev->num_crtc >= 4) {
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET,
@@ -1073,7 +1085,8 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
-
+ }
+ if (rdev->num_crtc >= 6) {
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
@@ -1101,31 +1114,41 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
/* Restore video state */
WREG32(D1VGA_CONTROL, save->vga_control[0]);
WREG32(D2VGA_CONTROL, save->vga_control[1]);
- WREG32(EVERGREEN_D3VGA_CONTROL, save->vga_control[2]);
- WREG32(EVERGREEN_D4VGA_CONTROL, save->vga_control[3]);
- WREG32(EVERGREEN_D5VGA_CONTROL, save->vga_control[4]);
- WREG32(EVERGREEN_D6VGA_CONTROL, save->vga_control[5]);
+ if (rdev->num_crtc >= 4) {
+ WREG32(EVERGREEN_D3VGA_CONTROL, save->vga_control[2]);
+ WREG32(EVERGREEN_D4VGA_CONTROL, save->vga_control[3]);
+ }
+ if (rdev->num_crtc >= 6) {
+ WREG32(EVERGREEN_D5VGA_CONTROL, save->vga_control[4]);
+ WREG32(EVERGREEN_D6VGA_CONTROL, save->vga_control[5]);
+ }
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
- if (!(rdev->flags & RADEON_IS_IGP)) {
+ if (rdev->num_crtc >= 4) {
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
+ }
+ if (rdev->num_crtc >= 6) {
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
}
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, save->crtc_control[0]);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, save->crtc_control[1]);
- if (!(rdev->flags & RADEON_IS_IGP)) {
+ if (rdev->num_crtc >= 4) {
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]);
+ }
+ if (rdev->num_crtc >= 6) {
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]);
}
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
- if (!(rdev->flags & RADEON_IS_IGP)) {
+ if (rdev->num_crtc >= 4) {
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+ }
+ if (rdev->num_crtc >= 6) {
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
}
@@ -1977,7 +2000,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
gb_backend_map = 0x66442200;
break;
case CHIP_JUNIPER:
- gb_backend_map = 0x00006420;
+ gb_backend_map = 0x00002200;
break;
default:
gb_backend_map =
@@ -2248,7 +2271,10 @@ int evergreen_mc_init(struct radeon_device *rdev)
/* Get VRAM informations */
rdev->mc.vram_is_ddr = true;
- tmp = RREG32(MC_ARB_RAMCFG);
+ if (rdev->flags & RADEON_IS_IGP)
+ tmp = RREG32(FUS_MC_ARB_RAMCFG);
+ else
+ tmp = RREG32(MC_ARB_RAMCFG);
if (tmp & CHANSIZE_OVERRIDE) {
chansize = 16;
} else if (tmp & CHANSIZE_MASK) {
@@ -2414,18 +2440,22 @@ void evergreen_disable_interrupt_state(struct radeon_device *rdev)
WREG32(GRBM_INT_CNTL, 0);
WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
- if (!(rdev->flags & RADEON_IS_IGP)) {
+ if (rdev->num_crtc >= 4) {
WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+ }
+ if (rdev->num_crtc >= 6) {
WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
}
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
- if (!(rdev->flags & RADEON_IS_IGP)) {
+ if (rdev->num_crtc >= 4) {
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+ }
+ if (rdev->num_crtc >= 6) {
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
}
@@ -2544,19 +2574,25 @@ int evergreen_irq_set(struct radeon_device *rdev)
WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2);
- if (!(rdev->flags & RADEON_IS_IGP)) {
+ if (rdev->num_crtc >= 4) {
WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3);
WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4);
+ }
+ if (rdev->num_crtc >= 6) {
WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5);
WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6);
}
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, grph1);
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, grph2);
- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, grph3);
- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, grph4);
- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, grph5);
- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, grph6);
+ if (rdev->num_crtc >= 4) {
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, grph3);
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, grph4);
+ }
+ if (rdev->num_crtc >= 6) {
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, grph5);
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, grph6);
+ }
WREG32(DC_HPD1_INT_CONTROL, hpd1);
WREG32(DC_HPD2_INT_CONTROL, hpd2);
@@ -2580,53 +2616,57 @@ static inline void evergreen_irq_ack(struct radeon_device *rdev)
rdev->irq.stat_regs.evergreen.disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5);
rdev->irq.stat_regs.evergreen.d1grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET);
rdev->irq.stat_regs.evergreen.d2grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET);
- rdev->irq.stat_regs.evergreen.d3grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET);
- rdev->irq.stat_regs.evergreen.d4grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET);
- rdev->irq.stat_regs.evergreen.d5grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET);
- rdev->irq.stat_regs.evergreen.d6grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET);
+ if (rdev->num_crtc >= 4) {
+ rdev->irq.stat_regs.evergreen.d3grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET);
+ rdev->irq.stat_regs.evergreen.d4grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET);
+ }
+ if (rdev->num_crtc >= 6) {
+ rdev->irq.stat_regs.evergreen.d5grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET);
+ rdev->irq.stat_regs.evergreen.d6grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET);
+ }
if (rdev->irq.stat_regs.evergreen.d1grph_int & GRPH_PFLIP_INT_OCCURRED)
WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
if (rdev->irq.stat_regs.evergreen.d2grph_int & GRPH_PFLIP_INT_OCCURRED)
WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
- if (rdev->irq.stat_regs.evergreen.d3grph_int & GRPH_PFLIP_INT_OCCURRED)
- WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
- if (rdev->irq.stat_regs.evergreen.d4grph_int & GRPH_PFLIP_INT_OCCURRED)
- WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
- if (rdev->irq.stat_regs.evergreen.d5grph_int & GRPH_PFLIP_INT_OCCURRED)
- WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
- if (rdev->irq.stat_regs.evergreen.d6grph_int & GRPH_PFLIP_INT_OCCURRED)
- WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
-
if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT)
WREG32(VBLANK_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VBLANK_ACK);
if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT)
WREG32(VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VLINE_ACK);
-
if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT)
WREG32(VBLANK_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VBLANK_ACK);
if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT)
WREG32(VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VLINE_ACK);
- if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)
- WREG32(VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK);
- if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)
- WREG32(VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK);
-
- if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)
- WREG32(VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK);
- if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)
- WREG32(VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK);
-
- if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)
- WREG32(VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK);
- if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)
- WREG32(VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK);
-
- if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)
- WREG32(VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK);
- if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)
- WREG32(VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK);
+ if (rdev->num_crtc >= 4) {
+ if (rdev->irq.stat_regs.evergreen.d3grph_int & GRPH_PFLIP_INT_OCCURRED)
+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+ if (rdev->irq.stat_regs.evergreen.d4grph_int & GRPH_PFLIP_INT_OCCURRED)
+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)
+ WREG32(VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK);
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)
+ WREG32(VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK);
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)
+ WREG32(VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK);
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)
+ WREG32(VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK);
+ }
+
+ if (rdev->num_crtc >= 6) {
+ if (rdev->irq.stat_regs.evergreen.d5grph_int & GRPH_PFLIP_INT_OCCURRED)
+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+ if (rdev->irq.stat_regs.evergreen.d6grph_int & GRPH_PFLIP_INT_OCCURRED)
+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)
+ WREG32(VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK);
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)
+ WREG32(VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK);
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)
+ WREG32(VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK);
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)
+ WREG32(VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK);
+ }
if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) {
tmp = RREG32(DC_HPD1_INT_CONTROL);
@@ -3234,6 +3274,7 @@ void evergreen_fini(struct radeon_device *rdev)
r700_cp_fini(rdev);
r600_irq_fini(rdev);
radeon_wb_fini(rdev);
+ radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
evergreen_pcie_gart_fini(rdev);
radeon_gem_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c
index 57f3bc17b87..2eb251858e7 100644
--- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c
+++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c
@@ -252,7 +252,7 @@ draw_auto(struct radeon_device *rdev)
}
-/* emits 36 */
+/* emits 39 */
static void
set_default_state(struct radeon_device *rdev)
{
@@ -531,6 +531,11 @@ set_default_state(struct radeon_device *rdev)
radeon_ring_write(rdev, (SQ_DYN_GPR_CNTL_PS_FLUSH_REQ - PACKET3_SET_CONFIG_REG_START) >> 2);
radeon_ring_write(rdev, 0);
+ /* setup LDS */
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+ radeon_ring_write(rdev, (SQ_LDS_RESOURCE_MGMT - PACKET3_SET_CONFIG_REG_START) >> 2);
+ radeon_ring_write(rdev, 0x10001000);
+
/* SQ config */
radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 11));
radeon_ring_write(rdev, (SQ_CONFIG - PACKET3_SET_CONFIG_REG_START) >> 2);
@@ -773,7 +778,7 @@ int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes)
/* calculate number of loops correctly */
ring_size = num_loops * dwords_per_loop;
/* set default + shaders */
- ring_size += 52; /* shaders + def state */
+ ring_size += 55; /* shaders + def state */
ring_size += 10; /* fence emit for VB IB */
ring_size += 5; /* done copy */
ring_size += 10; /* fence emit for done copy */
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index 1636e344982..b7b2714f0b3 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -466,7 +466,7 @@
#define IH_RB_WPTR_ADDR_LO 0x3e14
#define IH_CNTL 0x3e18
# define ENABLE_INTR (1 << 0)
-# define IH_MC_SWAP(x) ((x) << 2)
+# define IH_MC_SWAP(x) ((x) << 1)
# define IH_MC_SWAP_NONE 0
# define IH_MC_SWAP_16BIT 1
# define IH_MC_SWAP_32BIT 2
@@ -547,7 +547,7 @@
# define LB_D5_VBLANK_INTERRUPT (1 << 3)
# define DC_HPD5_INTERRUPT (1 << 17)
# define DC_HPD5_RX_INTERRUPT (1 << 18)
-#define DISP_INTERRUPT_STATUS_CONTINUE5 0x6050
+#define DISP_INTERRUPT_STATUS_CONTINUE5 0x6150
# define LB_D6_VLINE_INTERRUPT (1 << 2)
# define LB_D6_VBLANK_INTERRUPT (1 << 3)
# define DC_HPD6_INTERRUPT (1 << 17)
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index 16caafeadf5..559dbd41290 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -1581,6 +1581,7 @@ void cayman_fini(struct radeon_device *rdev)
cayman_cp_fini(rdev);
r600_irq_fini(rdev);
radeon_wb_fini(rdev);
+ radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
cayman_pcie_gart_fini(rdev);
radeon_gem_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h
index 9736746da2d..4672869cdb2 100644
--- a/drivers/gpu/drm/radeon/nid.h
+++ b/drivers/gpu/drm/radeon/nid.h
@@ -320,7 +320,7 @@
#define CGTS_USER_TCC_DISABLE 0x914C
#define TCC_DISABLE_MASK 0xFFFF0000
#define TCC_DISABLE_SHIFT 16
-#define CGTS_SM_CTRL_REG 0x915C
+#define CGTS_SM_CTRL_REG 0x9150
#define OVERRIDE (1 << 21)
#define TA_CNTL_AUX 0x9508
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index f79d2ccb675..bc54b26cb32 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -2628,6 +2628,7 @@ void r600_fini(struct radeon_device *rdev)
r600_cp_fini(rdev);
r600_irq_fini(rdev);
radeon_wb_fini(rdev);
+ radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
r600_pcie_gart_fini(rdev);
radeon_agp_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index f140a0d5cb5..0245ae6c204 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -536,7 +536,7 @@
#define IH_RB_WPTR_ADDR_LO 0x3e14
#define IH_CNTL 0x3e18
# define ENABLE_INTR (1 << 0)
-# define IH_MC_SWAP(x) ((x) << 2)
+# define IH_MC_SWAP(x) ((x) << 1)
# define IH_MC_SWAP_NONE 0
# define IH_MC_SWAP_16BIT 1
# define IH_MC_SWAP_32BIT 2
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index 3fc5fa1aefd..229a20f10e2 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -331,7 +331,7 @@ static bool avivo_read_disabled_bios(struct radeon_device *rdev)
seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1);
viph_control = RREG32(RADEON_VIPH_CONTROL);
- bus_cntl = RREG32(RADEON_BUS_CNTL);
+ bus_cntl = RREG32(RV370_BUS_CNTL);
d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
@@ -350,7 +350,7 @@ static bool avivo_read_disabled_bios(struct radeon_device *rdev)
WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
/* enable the rom */
- WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
+ WREG32(RV370_BUS_CNTL, (bus_cntl & ~RV370_BUS_BIOS_DIS_ROM));
/* Disable VGA mode */
WREG32(AVIVO_D1VGA_CONTROL,
@@ -367,7 +367,7 @@ static bool avivo_read_disabled_bios(struct radeon_device *rdev)
/* restore regs */
WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1);
WREG32(RADEON_VIPH_CONTROL, viph_control);
- WREG32(RADEON_BUS_CNTL, bus_cntl);
+ WREG32(RV370_BUS_CNTL, bus_cntl);
WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
@@ -390,7 +390,10 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev)
seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1);
viph_control = RREG32(RADEON_VIPH_CONTROL);
- bus_cntl = RREG32(RADEON_BUS_CNTL);
+ if (rdev->flags & RADEON_IS_PCIE)
+ bus_cntl = RREG32(RV370_BUS_CNTL);
+ else
+ bus_cntl = RREG32(RADEON_BUS_CNTL);
crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL);
crtc2_gen_cntl = 0;
crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
@@ -412,7 +415,10 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev)
WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
/* enable the rom */
- WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
+ if (rdev->flags & RADEON_IS_PCIE)
+ WREG32(RV370_BUS_CNTL, (bus_cntl & ~RV370_BUS_BIOS_DIS_ROM));
+ else
+ WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
/* Turn off mem requests and CRTC for both controllers */
WREG32(RADEON_CRTC_GEN_CNTL,
@@ -439,7 +445,10 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev)
/* restore regs */
WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1);
WREG32(RADEON_VIPH_CONTROL, viph_control);
- WREG32(RADEON_BUS_CNTL, bus_cntl);
+ if (rdev->flags & RADEON_IS_PCIE)
+ WREG32(RV370_BUS_CNTL, bus_cntl);
+ else
+ WREG32(RADEON_BUS_CNTL, bus_cntl);
WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl);
if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index cbfca3a24fd..9792d4ffdc8 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -52,6 +52,12 @@ void radeon_connector_hotplug(struct drm_connector *connector)
struct radeon_device *rdev = dev->dev_private;
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ /* bail if the connector does not have hpd pin, e.g.,
+ * VGA, TV, etc.
+ */
+ if (radeon_connector->hpd.hpd == RADEON_HPD_NONE)
+ return;
+
radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
/* powering up/down the eDP panel generates hpd events which
diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h
index ec93a75369e..bc44a3d35ec 100644
--- a/drivers/gpu/drm/radeon/radeon_reg.h
+++ b/drivers/gpu/drm/radeon/radeon_reg.h
@@ -300,6 +300,8 @@
# define RADEON_BUS_READ_BURST (1 << 30)
#define RADEON_BUS_CNTL1 0x0034
# define RADEON_BUS_WAIT_ON_LOCK_EN (1 << 4)
+#define RV370_BUS_CNTL 0x004c
+# define RV370_BUS_BIOS_DIS_ROM (1 << 2)
/* rv370/rv380, rv410, r423/r430/r480, r5xx */
#define RADEON_MSI_REARM_EN 0x0160
# define RV370_MSI_REARM_EN (1 << 0)
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 6e3b11e5abb..1f5850e473c 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -426,7 +426,7 @@ int rs600_gart_init(struct radeon_device *rdev)
return radeon_gart_table_vram_alloc(rdev);
}
-int rs600_gart_enable(struct radeon_device *rdev)
+static int rs600_gart_enable(struct radeon_device *rdev)
{
u32 tmp;
int r, i;
@@ -440,8 +440,8 @@ int rs600_gart_enable(struct radeon_device *rdev)
return r;
radeon_gart_restore(rdev);
/* Enable bus master */
- tmp = RREG32(R_00004C_BUS_CNTL) & C_00004C_BUS_MASTER_DIS;
- WREG32(R_00004C_BUS_CNTL, tmp);
+ tmp = RREG32(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS;
+ WREG32(RADEON_BUS_CNTL, tmp);
/* FIXME: setup default page */
WREG32_MC(R_000100_MC_PT0_CNTL,
(S_000100_EFFECTIVE_L2_CACHE_SIZE(6) |
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 6f508ffd103..4de51891aa6 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -575,6 +575,12 @@ static void rv770_program_channel_remap(struct radeon_device *rdev)
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);
}
@@ -1362,6 +1368,7 @@ void rv770_fini(struct radeon_device *rdev)
r700_cp_fini(rdev);
r600_irq_fini(rdev);
radeon_wb_fini(rdev);
+ radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
rv770_pcie_gart_fini(rdev);
rv770_vram_scratch_fini(rdev);
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 16db83c83c8..5f888f7e7dc 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -333,7 +333,7 @@ config SENSORS_F71882FG
F71858FG
F71862FG
F71863FG
- F71869F/E
+ F71869F/E/A
F71882FG
F71883FG
F71889FG/ED/A
diff --git a/drivers/hwmon/adm1275.c b/drivers/hwmon/adm1275.c
index c2ee2048ab9..b9b7caf4a1d 100644
--- a/drivers/hwmon/adm1275.c
+++ b/drivers/hwmon/adm1275.c
@@ -32,6 +32,7 @@ static int adm1275_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int config;
+ int ret;
struct pmbus_driver_info *info;
if (!i2c_check_functionality(client->adapter,
@@ -43,8 +44,10 @@ static int adm1275_probe(struct i2c_client *client,
return -ENOMEM;
config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
- if (config < 0)
- return config;
+ if (config < 0) {
+ ret = config;
+ goto err_mem;
+ }
info->pages = 1;
info->direct[PSC_VOLTAGE_IN] = true;
@@ -76,7 +79,14 @@ static int adm1275_probe(struct i2c_client *client,
else
info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
- return pmbus_do_probe(client, id, info);
+ ret = pmbus_do_probe(client, id, info);
+ if (ret)
+ goto err_mem;
+ return 0;
+
+err_mem:
+ kfree(info);
+ return ret;
}
static int adm1275_remove(struct i2c_client *client)
diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c
index e0ef32378ac..0064432f361 100644
--- a/drivers/hwmon/emc6w201.c
+++ b/drivers/hwmon/emc6w201.c
@@ -78,8 +78,9 @@ static u16 emc6w201_read16(struct i2c_client *client, u8 reg)
lsb = i2c_smbus_read_byte_data(client, reg);
msb = i2c_smbus_read_byte_data(client, reg + 1);
- if (lsb < 0 || msb < 0) {
- dev_err(&client->dev, "16-bit read failed at 0x%02x\n", reg);
+ if (unlikely(lsb < 0 || msb < 0)) {
+ dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n",
+ 16, "read", reg);
return 0xFFFF; /* Arbitrary value */
}
@@ -95,10 +96,39 @@ static int emc6w201_write16(struct i2c_client *client, u8 reg, u16 val)
int err;
err = i2c_smbus_write_byte_data(client, reg, val & 0xff);
- if (!err)
+ if (likely(!err))
err = i2c_smbus_write_byte_data(client, reg + 1, val >> 8);
- if (err < 0)
- dev_err(&client->dev, "16-bit write failed at 0x%02x\n", reg);
+ if (unlikely(err < 0))
+ dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n",
+ 16, "write", reg);
+
+ return err;
+}
+
+/* Read 8-bit value from register */
+static u8 emc6w201_read8(struct i2c_client *client, u8 reg)
+{
+ int val;
+
+ val = i2c_smbus_read_byte_data(client, reg);
+ if (unlikely(val < 0)) {
+ dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n",
+ 8, "read", reg);
+ return 0x00; /* Arbitrary value */
+ }
+
+ return val;
+}
+
+/* Write 8-bit value to register */
+static int emc6w201_write8(struct i2c_client *client, u8 reg, u8 val)
+{
+ int err;
+
+ err = i2c_smbus_write_byte_data(client, reg, val);
+ if (unlikely(err < 0))
+ dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n",
+ 8, "write", reg);
return err;
}
@@ -114,25 +144,25 @@ static struct emc6w201_data *emc6w201_update_device(struct device *dev)
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
for (nr = 0; nr < 6; nr++) {
data->in[input][nr] =
- i2c_smbus_read_byte_data(client,
+ emc6w201_read8(client,
EMC6W201_REG_IN(nr));
data->in[min][nr] =
- i2c_smbus_read_byte_data(client,
+ emc6w201_read8(client,
EMC6W201_REG_IN_LOW(nr));
data->in[max][nr] =
- i2c_smbus_read_byte_data(client,
+ emc6w201_read8(client,
EMC6W201_REG_IN_HIGH(nr));
}
for (nr = 0; nr < 6; nr++) {
data->temp[input][nr] =
- i2c_smbus_read_byte_data(client,
+ emc6w201_read8(client,
EMC6W201_REG_TEMP(nr));
data->temp[min][nr] =
- i2c_smbus_read_byte_data(client,
+ emc6w201_read8(client,
EMC6W201_REG_TEMP_LOW(nr));
data->temp[max][nr] =
- i2c_smbus_read_byte_data(client,
+ emc6w201_read8(client,
EMC6W201_REG_TEMP_HIGH(nr));
}
@@ -192,7 +222,7 @@ static ssize_t set_in(struct device *dev, struct device_attribute *devattr,
mutex_lock(&data->update_lock);
data->in[sf][nr] = SENSORS_LIMIT(val, 0, 255);
- err = i2c_smbus_write_byte_data(client, reg, data->in[sf][nr]);
+ err = emc6w201_write8(client, reg, data->in[sf][nr]);
mutex_unlock(&data->update_lock);
return err < 0 ? err : count;
@@ -229,7 +259,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
mutex_lock(&data->update_lock);
data->temp[sf][nr] = SENSORS_LIMIT(val, -127, 128);
- err = i2c_smbus_write_byte_data(client, reg, data->temp[sf][nr]);
+ err = emc6w201_write8(client, reg, data->temp[sf][nr]);
mutex_unlock(&data->update_lock);
return err < 0 ? err : count;
@@ -444,7 +474,7 @@ static int emc6w201_detect(struct i2c_client *client,
/* Check configuration */
config = i2c_smbus_read_byte_data(client, EMC6W201_REG_CONFIG);
- if ((config & 0xF4) != 0x04)
+ if (config < 0 || (config & 0xF4) != 0x04)
return -ENODEV;
if (!(config & 0x01)) {
dev_err(&client->dev, "Monitoring not enabled\n");
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
index a4a94a096c9..2d96ed2bf8e 100644
--- a/drivers/hwmon/f71882fg.c
+++ b/drivers/hwmon/f71882fg.c
@@ -52,6 +52,7 @@
#define SIO_F71858_ID 0x0507 /* Chipset ID */
#define SIO_F71862_ID 0x0601 /* Chipset ID */
#define SIO_F71869_ID 0x0814 /* Chipset ID */
+#define SIO_F71869A_ID 0x1007 /* Chipset ID */
#define SIO_F71882_ID 0x0541 /* Chipset ID */
#define SIO_F71889_ID 0x0723 /* Chipset ID */
#define SIO_F71889E_ID 0x0909 /* Chipset ID */
@@ -108,8 +109,8 @@ static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");
-enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71882fg, f71889fg,
- f71889ed, f71889a, f8000, f81865f };
+enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71869a, f71882fg,
+ f71889fg, f71889ed, f71889a, f8000, f81865f };
static const char *f71882fg_names[] = {
"f71808e",
@@ -117,6 +118,7 @@ static const char *f71882fg_names[] = {
"f71858fg",
"f71862fg",
"f71869", /* Both f71869f and f71869e, reg. compatible and same id */
+ "f71869a",
"f71882fg",
"f71889fg", /* f81801u too, same id */
"f71889ed",
@@ -131,6 +133,7 @@ static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
[f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 },
[f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
[f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ [f71869a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
[f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
[f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
[f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
@@ -145,6 +148,7 @@ static const char f71882fg_has_in1_alarm[] = {
[f71858fg] = 0,
[f71862fg] = 0,
[f71869] = 0,
+ [f71869a] = 0,
[f71882fg] = 1,
[f71889fg] = 1,
[f71889ed] = 1,
@@ -159,6 +163,7 @@ static const char f71882fg_fan_has_beep[] = {
[f71858fg] = 0,
[f71862fg] = 1,
[f71869] = 1,
+ [f71869a] = 1,
[f71882fg] = 1,
[f71889fg] = 1,
[f71889ed] = 1,
@@ -173,6 +178,7 @@ static const char f71882fg_nr_fans[] = {
[f71858fg] = 3,
[f71862fg] = 3,
[f71869] = 3,
+ [f71869a] = 3,
[f71882fg] = 4,
[f71889fg] = 3,
[f71889ed] = 3,
@@ -187,6 +193,7 @@ static const char f71882fg_temp_has_beep[] = {
[f71858fg] = 0,
[f71862fg] = 1,
[f71869] = 1,
+ [f71869a] = 1,
[f71882fg] = 1,
[f71889fg] = 1,
[f71889ed] = 1,
@@ -201,6 +208,7 @@ static const char f71882fg_nr_temps[] = {
[f71858fg] = 3,
[f71862fg] = 3,
[f71869] = 3,
+ [f71869a] = 3,
[f71882fg] = 3,
[f71889fg] = 3,
[f71889ed] = 3,
@@ -2243,6 +2251,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
case f71808e:
case f71808a:
case f71869:
+ case f71869a:
/* These always have signed auto point temps */
data->auto_point_temp_signed = 1;
/* Fall through to select correct fan/pwm reg bank! */
@@ -2305,6 +2314,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
case f71808e:
case f71808a:
case f71869:
+ case f71869a:
case f71889fg:
case f71889ed:
case f71889a:
@@ -2528,6 +2538,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
case SIO_F71869_ID:
sio_data->type = f71869;
break;
+ case SIO_F71869A_ID:
+ sio_data->type = f71869a;
+ break;
case SIO_F71882_ID:
sio_data->type = f71882fg;
break;
@@ -2662,7 +2675,7 @@ static void __exit f71882fg_exit(void)
}
MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
-MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
+MODULE_AUTHOR("Hans Edgington, Hans de Goede <hdegoede@redhat.com>");
MODULE_LICENSE("GPL");
module_init(f71882fg_init);
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
index 2582bfef6cc..c8195a077da 100644
--- a/drivers/hwmon/hwmon-vid.c
+++ b/drivers/hwmon/hwmon-vid.c
@@ -202,7 +202,7 @@ static struct vrm_model vrm_models[] = {
{X86_VENDOR_CENTAUR, 0x6, 0x7, ANY, 85}, /* Eden ESP/Ezra */
{X86_VENDOR_CENTAUR, 0x6, 0x8, 0x7, 85}, /* Ezra T */
- {X86_VENDOR_CENTAUR, 0x6, 0x9, 0x7, 85}, /* Nemiah */
+ {X86_VENDOR_CENTAUR, 0x6, 0x9, 0x7, 85}, /* Nehemiah */
{X86_VENDOR_CENTAUR, 0x6, 0x9, ANY, 17}, /* C3-M, Eden-N */
{X86_VENDOR_CENTAUR, 0x6, 0xA, 0x7, 0}, /* No information */
{X86_VENDOR_CENTAUR, 0x6, 0xA, ANY, 13}, /* C7, Esther */
diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c
index 1a6dfb6df1e..d3b464b74ce 100644
--- a/drivers/hwmon/lm95241.c
+++ b/drivers/hwmon/lm95241.c
@@ -98,11 +98,16 @@ struct lm95241_data {
};
/* Conversions */
-static int TempFromReg(u8 val_h, u8 val_l)
+static int temp_from_reg_signed(u8 val_h, u8 val_l)
{
- if (val_h & 0x80)
- return val_h - 0x100;
- return val_h * 1000 + val_l * 1000 / 256;
+ s16 val_hl = (val_h << 8) | val_l;
+ return val_hl * 1000 / 256;
+}
+
+static int temp_from_reg_unsigned(u8 val_h, u8 val_l)
+{
+ u16 val_hl = (val_h << 8) | val_l;
+ return val_hl * 1000 / 256;
}
static struct lm95241_data *lm95241_update_device(struct device *dev)
@@ -135,10 +140,13 @@ static ssize_t show_input(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct lm95241_data *data = lm95241_update_device(dev);
+ int index = to_sensor_dev_attr(attr)->index;
return snprintf(buf, PAGE_SIZE - 1, "%d\n",
- TempFromReg(data->temp[to_sensor_dev_attr(attr)->index],
- data->temp[to_sensor_dev_attr(attr)->index + 1]));
+ index == 0 || (data->config & (1 << (index / 2))) ?
+ temp_from_reg_signed(data->temp[index], data->temp[index + 1]) :
+ temp_from_reg_unsigned(data->temp[index],
+ data->temp[index + 1]));
}
static ssize_t show_type(struct device *dev, struct device_attribute *attr,
@@ -339,7 +347,7 @@ static int lm95241_detect(struct i2c_client *new_client,
if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID)
== MANUFACTURER_ID)
&& (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID)
- >= DEFAULT_REVISION)) {
+ == DEFAULT_REVISION)) {
name = DEVNAME;
} else {
dev_dbg(&adapter->dev, "LM95241 detection failed at 0x%02x\n",
diff --git a/drivers/hwmon/pmbus.c b/drivers/hwmon/pmbus.c
index 98e2e28899e..9b1f0c37ef7 100644
--- a/drivers/hwmon/pmbus.c
+++ b/drivers/hwmon/pmbus.c
@@ -47,22 +47,29 @@ static void pmbus_find_sensor_groups(struct i2c_client *client,
if (info->func[0]
&& pmbus_check_byte_register(client, 0, PMBUS_STATUS_INPUT))
info->func[0] |= PMBUS_HAVE_STATUS_INPUT;
- if (pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_1)) {
+ if (pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_12) &&
+ pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_1)) {
info->func[0] |= PMBUS_HAVE_FAN12;
if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_12))
info->func[0] |= PMBUS_HAVE_STATUS_FAN12;
}
- if (pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_3)) {
+ if (pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_34) &&
+ pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_3)) {
info->func[0] |= PMBUS_HAVE_FAN34;
if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_34))
info->func[0] |= PMBUS_HAVE_STATUS_FAN34;
}
- if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_1)) {
+ if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_1))
info->func[0] |= PMBUS_HAVE_TEMP;
- if (pmbus_check_byte_register(client, 0,
- PMBUS_STATUS_TEMPERATURE))
+ if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_2))
+ info->func[0] |= PMBUS_HAVE_TEMP2;
+ if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_3))
+ info->func[0] |= PMBUS_HAVE_TEMP3;
+ if (info->func[0] & (PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2
+ | PMBUS_HAVE_TEMP3)
+ && pmbus_check_byte_register(client, 0,
+ PMBUS_STATUS_TEMPERATURE))
info->func[0] |= PMBUS_HAVE_STATUS_TEMP;
- }
/* Sensors detected on all pages */
for (page = 0; page < info->pages; page++) {
diff --git a/drivers/hwmon/pmbus_core.c b/drivers/hwmon/pmbus_core.c
index 354770ed318..744672c1f26 100644
--- a/drivers/hwmon/pmbus_core.c
+++ b/drivers/hwmon/pmbus_core.c
@@ -1430,14 +1430,9 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
- /*
- * Bail out if status register or PMBus revision register
- * does not exist.
- */
- if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0
- || i2c_smbus_read_byte_data(client, PMBUS_REVISION) < 0) {
- dev_err(&client->dev,
- "Status or revision register not found\n");
+ /* Bail out if PMBus status register does not exist. */
+ if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0) {
+ dev_err(&client->dev, "PMBus status register not found\n");
ret = -ENODEV;
goto out_data;
}
diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c
index 020c87273ea..3494a4cce41 100644
--- a/drivers/hwmon/sch5627.c
+++ b/drivers/hwmon/sch5627.c
@@ -887,7 +887,7 @@ static void __exit sch5627_exit(void)
}
MODULE_DESCRIPTION("SMSC SCH5627 Hardware Monitoring Driver");
-MODULE_AUTHOR("Hans de Goede (hdegoede@redhat.com)");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_LICENSE("GPL");
module_init(sch5627_init);
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index 52b545a795f..cbc98aea5b0 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -193,7 +193,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
return;
}
if (twi_int_status & MCOMP) {
- if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+ if ((read_MASTER_CTL(iface) & MEN) == 0 &&
+ (iface->cur_mode == TWI_I2C_MODE_REPEAT ||
+ iface->cur_mode == TWI_I2C_MODE_COMBINED)) {
+ iface->result = -1;
+ write_INT_MASK(iface, 0);
+ write_MASTER_CTL(iface, 0);
+ } else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
if (iface->readNum == 0) {
/* set the read number to 1 and ask for manual
* stop in block combine mode
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 6c00c107ebf..f84a63c6dd9 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -248,12 +248,12 @@ static inline int is_msgend(struct s3c24xx_i2c *i2c)
return i2c->msg_ptr >= i2c->msg->len;
}
-/* i2s_s3c_irq_nextbyte
+/* i2c_s3c_irq_nextbyte
*
* process an interrupt and work out what to do
*/
-static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
+static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
{
unsigned long tmp;
unsigned char byte;
@@ -264,7 +264,6 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
case STATE_IDLE:
dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__);
goto out;
- break;
case STATE_STOP:
dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);
@@ -444,7 +443,7 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
/* pretty much this leaves us with the fact that we've
* transmitted or received whatever byte we last sent */
- i2s_s3c_irq_nextbyte(i2c, status);
+ i2c_s3c_irq_nextbyte(i2c, status);
out:
return IRQ_HANDLED;
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 4d9319665e3..fb3b4f8f815 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -40,8 +40,10 @@
#define I2C_CNFG_NEW_MASTER_FSM (1<<11)
#define I2C_STATUS 0x01C
#define I2C_SL_CNFG 0x020
+#define I2C_SL_CNFG_NACK (1<<1)
#define I2C_SL_CNFG_NEWSL (1<<2)
#define I2C_SL_ADDR1 0x02c
+#define I2C_SL_ADDR2 0x030
#define I2C_TX_FIFO 0x050
#define I2C_RX_FIFO 0x054
#define I2C_PACKET_TRANSFER_STATUS 0x058
@@ -337,7 +339,11 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
if (!i2c_dev->is_dvc) {
u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
- i2c_writel(i2c_dev, sl_cfg | I2C_SL_CNFG_NEWSL, I2C_SL_CNFG);
+ sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL;
+ i2c_writel(i2c_dev, sl_cfg, I2C_SL_CNFG);
+ i2c_writel(i2c_dev, 0xfc, I2C_SL_ADDR1);
+ i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2);
+
}
val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index f62f52fb9ec..fc0f2bd9ca8 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -3641,7 +3641,8 @@ static struct kobj_type cm_port_obj_type = {
static char *cm_devnode(struct device *dev, mode_t *mode)
{
- *mode = 0666;
+ if (mode)
+ *mode = 0666;
return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
}
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index e49a85f8a44..56898b6578a 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -826,7 +826,8 @@ static void ib_uverbs_remove_one(struct ib_device *device)
static char *uverbs_devnode(struct device *dev, mode_t *mode)
{
- *mode = 0666;
+ if (mode)
+ *mode = 0666;
return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
}
diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c
index 40b02ae96f8..6229c3e8e78 100644
--- a/drivers/input/keyboard/pmic8xxx-keypad.c
+++ b/drivers/input/keyboard/pmic8xxx-keypad.c
@@ -520,7 +520,8 @@ static void pmic8xxx_kp_close(struct input_dev *dev)
*/
static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev)
{
- const struct pm8xxx_keypad_platform_data *pdata = mfd_get_data(pdev);
+ const struct pm8xxx_keypad_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
const struct matrix_keymap_data *keymap_data;
struct pmic8xxx_kp *kp;
int rc;
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
index 97e07e786e4..b3cfb9c71e6 100644
--- a/drivers/input/misc/pmic8xxx-pwrkey.c
+++ b/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -90,7 +90,8 @@ static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
unsigned int delay;
u8 pon_cntl;
struct pmic8xxx_pwrkey *pwrkey;
- const struct pm8xxx_pwrkey_platform_data *pdata = mfd_get_data(pdev);
+ const struct pm8xxx_pwrkey_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "power key platform data not supplied\n");
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index d8d3a1e910a..a2c874623e3 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -88,7 +88,7 @@ static const struct pca9532_chip_info pca9532_chip_info_tbl[] = {
static struct i2c_driver pca9532_driver = {
.driver = {
- .name = "pca953x",
+ .name = "leds-pca953x",
},
.probe = pca9532_probe,
.remove = pca9532_remove,
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index 8fa539dde1b..7f7079b12f2 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -597,12 +597,17 @@ static void __devexit fintek_remove(struct pnp_dev *pdev)
static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state)
{
struct fintek_dev *fintek = pnp_get_drvdata(pdev);
+ unsigned long flags;
fit_dbg("%s called", __func__);
+ spin_lock_irqsave(&fintek->fintek_lock, flags);
+
/* disable all CIR interrupts */
fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
+ spin_unlock_irqrestore(&fintek->fintek_lock, flags);
+
fintek_config_mode_enable(fintek);
/* disable cir logical dev */
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 3f3c7071626..6bc35eeb653 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -307,6 +307,14 @@ static const struct {
/* 0xffdc iMON MCE VFD */
{ 0x00010000ffffffeell, KEY_VOLUMEUP },
{ 0x01000000ffffffeell, KEY_VOLUMEDOWN },
+ { 0x00000001ffffffeell, KEY_MUTE },
+ { 0x0000000fffffffeell, KEY_MEDIA },
+ { 0x00000012ffffffeell, KEY_UP },
+ { 0x00000013ffffffeell, KEY_DOWN },
+ { 0x00000014ffffffeell, KEY_LEFT },
+ { 0x00000015ffffffeell, KEY_RIGHT },
+ { 0x00000016ffffffeell, KEY_ENTER },
+ { 0x00000017ffffffeell, KEY_ESC },
/* iMON Knob values */
{ 0x000100ffffffffeell, KEY_VOLUMEUP },
{ 0x010000ffffffffeell, KEY_VOLUMEDOWN },
@@ -1582,16 +1590,16 @@ static void imon_incoming_packet(struct imon_context *ictx,
/* Only panel type events left to process now */
spin_lock_irqsave(&ictx->kc_lock, flags);
+ do_gettimeofday(&t);
/* KEY_MUTE repeats from knob need to be suppressed */
if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) {
- do_gettimeofday(&t);
msec = tv2int(&t, &prev_time);
- prev_time = t;
if (msec < ictx->idev->rep[REP_DELAY]) {
spin_unlock_irqrestore(&ictx->kc_lock, flags);
return;
}
}
+ prev_time = t;
kc = ictx->kc;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
@@ -1603,7 +1611,9 @@ static void imon_incoming_packet(struct imon_context *ictx,
input_report_key(ictx->idev, kc, 0);
input_sync(ictx->idev);
+ spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->last_keycode = kc;
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
return;
@@ -1740,6 +1750,8 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
detected_display_type = IMON_DISPLAY_TYPE_VFD;
break;
/* iMON VFD, MCE IR */
+ case 0x46:
+ case 0x7e:
case 0x9e:
dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR");
detected_display_type = IMON_DISPLAY_TYPE_VFD;
@@ -1755,6 +1767,9 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
dev_info(ictx->dev, "Unknown 0xffdc device, "
"defaulting to VFD and iMON IR");
detected_display_type = IMON_DISPLAY_TYPE_VFD;
+ /* We don't know which one it is, allow user to set the
+ * RC6 one from userspace if OTHER wasn't correct. */
+ allowed_protos |= RC_TYPE_RC6;
break;
}
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index 11c19d8d0ee..423ed45d6c5 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -114,18 +114,20 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
s64 delta; /* ns */
DEFINE_IR_RAW_EVENT(ev);
int rc = 0;
+ int delay;
if (!dev->raw)
return -EINVAL;
now = ktime_get();
delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event));
+ delay = MS_TO_NS(dev->input_dev->rep[REP_DELAY]);
/* Check for a long duration since last event or if we're
* being called for the first time, note that delta can't
* possibly be negative.
*/
- if (delta > IR_MAX_DURATION || !dev->raw->last_type)
+ if (delta > delay || !dev->raw->last_type)
type |= IR_START_EVENT;
else
ev.duration = delta;
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index e716b931cf7..ecd3d028076 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -1347,6 +1347,7 @@ static const struct ite_dev_params ite_dev_descs[] = {
{ /* 0: ITE8704 */
.model = "ITE8704 CIR transceiver",
.io_region_size = IT87_IOREG_LENGTH,
+ .io_rsrc_no = 0,
.hw_tx_capable = true,
.sample_period = (u32) (1000000000ULL / 115200),
.tx_carrier_freq = 38000,
@@ -1371,6 +1372,7 @@ static const struct ite_dev_params ite_dev_descs[] = {
{ /* 1: ITE8713 */
.model = "ITE8713 CIR transceiver",
.io_region_size = IT87_IOREG_LENGTH,
+ .io_rsrc_no = 0,
.hw_tx_capable = true,
.sample_period = (u32) (1000000000ULL / 115200),
.tx_carrier_freq = 38000,
@@ -1395,6 +1397,7 @@ static const struct ite_dev_params ite_dev_descs[] = {
{ /* 2: ITE8708 */
.model = "ITE8708 CIR transceiver",
.io_region_size = IT8708_IOREG_LENGTH,
+ .io_rsrc_no = 0,
.hw_tx_capable = true,
.sample_period = (u32) (1000000000ULL / 115200),
.tx_carrier_freq = 38000,
@@ -1420,6 +1423,7 @@ static const struct ite_dev_params ite_dev_descs[] = {
{ /* 3: ITE8709 */
.model = "ITE8709 CIR transceiver",
.io_region_size = IT8709_IOREG_LENGTH,
+ .io_rsrc_no = 2,
.hw_tx_capable = true,
.sample_period = (u32) (1000000000ULL / 115200),
.tx_carrier_freq = 38000,
@@ -1461,6 +1465,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
struct rc_dev *rdev = NULL;
int ret = -ENOMEM;
int model_no;
+ int io_rsrc_no;
ite_dbg("%s called", __func__);
@@ -1490,10 +1495,11 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
/* get the description for the device */
dev_desc = &ite_dev_descs[model_no];
+ io_rsrc_no = dev_desc->io_rsrc_no;
/* validate pnp resources */
- if (!pnp_port_valid(pdev, 0) ||
- pnp_port_len(pdev, 0) != dev_desc->io_region_size) {
+ if (!pnp_port_valid(pdev, io_rsrc_no) ||
+ pnp_port_len(pdev, io_rsrc_no) != dev_desc->io_region_size) {
dev_err(&pdev->dev, "IR PNP Port not valid!\n");
goto failure;
}
@@ -1504,7 +1510,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
}
/* store resource values */
- itdev->cir_addr = pnp_port_start(pdev, 0);
+ itdev->cir_addr = pnp_port_start(pdev, io_rsrc_no);
itdev->cir_irq = pnp_irq(pdev, 0);
/* initialize spinlocks */
diff --git a/drivers/media/rc/ite-cir.h b/drivers/media/rc/ite-cir.h
index 16a19f5fd71..aa899a0b975 100644
--- a/drivers/media/rc/ite-cir.h
+++ b/drivers/media/rc/ite-cir.h
@@ -57,6 +57,9 @@ struct ite_dev_params {
/* size of the I/O region */
int io_region_size;
+ /* IR pnp I/O resource number */
+ int io_rsrc_no;
+
/* true if the hardware supports transmission */
bool hw_tx_capable;
diff --git a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
index bb10ffe086b..8d558ae6345 100644
--- a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
+++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
@@ -15,43 +15,39 @@
/* Pinnacle PCTV HD 800i mini remote */
static struct rc_map_table pinnacle_pctv_hd[] = {
-
- { 0x0f, KEY_1 },
- { 0x15, KEY_2 },
- { 0x10, KEY_3 },
- { 0x18, KEY_4 },
- { 0x1b, KEY_5 },
- { 0x1e, KEY_6 },
- { 0x11, KEY_7 },
- { 0x21, KEY_8 },
- { 0x12, KEY_9 },
- { 0x27, KEY_0 },
-
- { 0x24, KEY_ZOOM },
- { 0x2a, KEY_SUBTITLE },
-
- { 0x00, KEY_MUTE },
- { 0x01, KEY_ENTER }, /* Pinnacle Logo */
- { 0x39, KEY_POWER },
-
- { 0x03, KEY_VOLUMEUP },
- { 0x09, KEY_VOLUMEDOWN },
- { 0x06, KEY_CHANNELUP },
- { 0x0c, KEY_CHANNELDOWN },
-
- { 0x2d, KEY_REWIND },
- { 0x30, KEY_PLAYPAUSE },
- { 0x33, KEY_FASTFORWARD },
- { 0x3c, KEY_STOP },
- { 0x36, KEY_RECORD },
- { 0x3f, KEY_EPG }, /* Labeled "?" */
+ /* Key codes for the tiny Pinnacle remote*/
+ { 0x0700, KEY_MUTE },
+ { 0x0701, KEY_MENU }, /* Pinnacle logo */
+ { 0x0739, KEY_POWER },
+ { 0x0703, KEY_VOLUMEUP },
+ { 0x0709, KEY_VOLUMEDOWN },
+ { 0x0706, KEY_CHANNELUP },
+ { 0x070c, KEY_CHANNELDOWN },
+ { 0x070f, KEY_1 },
+ { 0x0715, KEY_2 },
+ { 0x0710, KEY_3 },
+ { 0x0718, KEY_4 },
+ { 0x071b, KEY_5 },
+ { 0x071e, KEY_6 },
+ { 0x0711, KEY_7 },
+ { 0x0721, KEY_8 },
+ { 0x0712, KEY_9 },
+ { 0x0727, KEY_0 },
+ { 0x0724, KEY_ZOOM }, /* 'Square' key */
+ { 0x072a, KEY_SUBTITLE }, /* 'T' key */
+ { 0x072d, KEY_REWIND },
+ { 0x0730, KEY_PLAYPAUSE },
+ { 0x0733, KEY_FASTFORWARD },
+ { 0x0736, KEY_RECORD },
+ { 0x073c, KEY_STOP },
+ { 0x073f, KEY_HELP }, /* '?' key */
};
static struct rc_map_list pinnacle_pctv_hd_map = {
.map = {
.scan = pinnacle_pctv_hd,
.size = ARRAY_SIZE(pinnacle_pctv_hd),
- .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_RC5,
.name = RC_MAP_PINNACLE_PCTV_HD,
}
};
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index fd237ab120b..27997a9ceb0 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -55,6 +55,8 @@ struct irctl {
struct lirc_buffer *buf;
unsigned int chunk_size;
+ struct cdev *cdev;
+
struct task_struct *task;
long jiffies_to_wait;
};
@@ -62,7 +64,6 @@ struct irctl {
static DEFINE_MUTEX(lirc_dev_lock);
static struct irctl *irctls[MAX_IRCTL_DEVICES];
-static struct cdev cdevs[MAX_IRCTL_DEVICES];
/* Only used for sysfs but defined to void otherwise */
static struct class *lirc_class;
@@ -167,9 +168,13 @@ static struct file_operations lirc_dev_fops = {
static int lirc_cdev_add(struct irctl *ir)
{
- int retval;
+ int retval = -ENOMEM;
struct lirc_driver *d = &ir->d;
- struct cdev *cdev = &cdevs[d->minor];
+ struct cdev *cdev;
+
+ cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+ if (!cdev)
+ goto err_out;
if (d->fops) {
cdev_init(cdev, d->fops);
@@ -180,12 +185,20 @@ static int lirc_cdev_add(struct irctl *ir)
}
retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
if (retval)
- return retval;
+ goto err_out;
retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
- if (retval)
+ if (retval) {
kobject_put(&cdev->kobj);
+ goto err_out;
+ }
+
+ ir->cdev = cdev;
+
+ return 0;
+err_out:
+ kfree(cdev);
return retval;
}
@@ -214,7 +227,7 @@ int lirc_register_driver(struct lirc_driver *d)
if (MAX_IRCTL_DEVICES <= d->minor) {
dev_err(d->dev, "lirc_dev: lirc_register_driver: "
"\"minor\" must be between 0 and %d (%d)!\n",
- MAX_IRCTL_DEVICES-1, d->minor);
+ MAX_IRCTL_DEVICES - 1, d->minor);
err = -EBADRQC;
goto out;
}
@@ -369,7 +382,7 @@ int lirc_unregister_driver(int minor)
if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between "
- "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES-1);
+ "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES - 1);
return -EBADRQC;
}
@@ -380,7 +393,7 @@ int lirc_unregister_driver(int minor)
return -ENOENT;
}
- cdev = &cdevs[minor];
+ cdev = ir->cdev;
mutex_lock(&lirc_dev_lock);
@@ -410,6 +423,7 @@ int lirc_unregister_driver(int minor)
} else {
lirc_irctl_cleanup(ir);
cdev_del(cdev);
+ kfree(cdev);
kfree(ir);
irctls[minor] = NULL;
}
@@ -453,7 +467,7 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
goto error;
}
- cdev = &cdevs[iminor(inode)];
+ cdev = ir->cdev;
if (try_module_get(cdev->owner)) {
ir->open++;
retval = ir->d.set_use_inc(ir->d.data);
@@ -484,13 +498,15 @@ EXPORT_SYMBOL(lirc_dev_fop_open);
int lirc_dev_fop_close(struct inode *inode, struct file *file)
{
struct irctl *ir = irctls[iminor(inode)];
- struct cdev *cdev = &cdevs[iminor(inode)];
+ struct cdev *cdev;
if (!ir) {
printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
return -EINVAL;
}
+ cdev = ir->cdev;
+
dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor);
WARN_ON(mutex_lock_killable(&lirc_dev_lock));
@@ -503,6 +519,7 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
lirc_irctl_cleanup(ir);
cdev_del(cdev);
irctls[ir->d.minor] = NULL;
+ kfree(cdev);
kfree(ir);
}
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index ad927fcaa02..06dfe0957b5 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -108,6 +108,12 @@ static int debug = 1;
static int debug;
#endif
+#define mce_dbg(dev, fmt, ...) \
+ do { \
+ if (debug) \
+ dev_info(dev, fmt, ## __VA_ARGS__); \
+ } while (0)
+
/* general constants */
#define SEND_FLAG_IN_PROGRESS 1
#define SEND_FLAG_COMPLETE 2
@@ -246,6 +252,9 @@ static struct usb_device_id mceusb_dev_table[] = {
.driver_info = MCE_GEN2_TX_INV },
/* SMK eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_SMK, 0x0338) },
+ /* SMK/I-O Data GV-MC7/RCKIT Receiver */
+ { USB_DEVICE(VENDOR_SMK, 0x0353),
+ .driver_info = MCE_GEN2_NO_TX },
/* Tatung eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_TATUNG, 0x9150) },
/* Shuttle eHome Infrared Transceiver */
@@ -606,12 +615,15 @@ static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
if (ir) {
len = urb->actual_length;
- dev_dbg(ir->dev, "callback called (status=%d len=%d)\n",
+ mce_dbg(ir->dev, "callback called (status=%d len=%d)\n",
urb->status, len);
mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true);
}
+ /* the transfer buffer and urb were allocated in mce_request_packet */
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
}
/* request incoming or send outgoing usb packet - used to initialize remote */
@@ -655,17 +667,17 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
return;
}
- dev_dbg(dev, "receive request called (size=%#x)\n", size);
+ mce_dbg(dev, "receive request called (size=%#x)\n", size);
async_urb->transfer_buffer_length = size;
async_urb->dev = ir->usbdev;
res = usb_submit_urb(async_urb, GFP_ATOMIC);
if (res) {
- dev_dbg(dev, "receive request FAILED! (res=%d)\n", res);
+ mce_dbg(dev, "receive request FAILED! (res=%d)\n", res);
return;
}
- dev_dbg(dev, "receive request complete (res=%d)\n", res);
+ mce_dbg(dev, "receive request complete (res=%d)\n", res);
}
static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
@@ -673,9 +685,9 @@ static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
mce_request_packet(ir, data, size, MCEUSB_TX);
}
-static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size)
+static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size)
{
- mce_request_packet(ir, data, size, MCEUSB_RX);
+ mce_request_packet(ir, NULL, size, MCEUSB_RX);
}
/* Send data out the IR blaster port(s) */
@@ -794,7 +806,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
ir->carrier = carrier;
cmdbuf[2] = MCE_CMD_SIG_END;
cmdbuf[3] = MCE_IRDATA_TRAILER;
- dev_dbg(ir->dev, "%s: disabling carrier "
+ mce_dbg(ir->dev, "%s: disabling carrier "
"modulation\n", __func__);
mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
return carrier;
@@ -806,7 +818,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
ir->carrier = carrier;
cmdbuf[2] = prescaler;
cmdbuf[3] = divisor;
- dev_dbg(ir->dev, "%s: requesting %u HZ "
+ mce_dbg(ir->dev, "%s: requesting %u HZ "
"carrier\n", __func__, carrier);
/* Transmit new carrier to mce device */
@@ -879,7 +891,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
* US_TO_NS(MCE_TIME_UNIT);
- dev_dbg(ir->dev, "Storing %s with duration %d\n",
+ mce_dbg(ir->dev, "Storing %s with duration %d\n",
rawir.pulse ? "pulse" : "space",
rawir.duration);
@@ -911,7 +923,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
if (ir->parser_state != CMD_HEADER && !ir->rem)
ir->parser_state = CMD_HEADER;
}
- dev_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n");
+ mce_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n");
ir_raw_event_handle(ir->rc);
}
@@ -933,7 +945,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
if (ir->send_flags == RECV_FLAG_IN_PROGRESS) {
ir->send_flags = SEND_FLAG_COMPLETE;
- dev_dbg(ir->dev, "setup answer received %d bytes\n",
+ mce_dbg(ir->dev, "setup answer received %d bytes\n",
buf_len);
}
@@ -951,7 +963,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
case -EPIPE:
default:
- dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status);
+ mce_dbg(ir->dev, "Error: urb status = %d\n", urb->status);
break;
}
@@ -961,7 +973,6 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
static void mceusb_gen1_init(struct mceusb_dev *ir)
{
int ret;
- int maxp = ir->len_in;
struct device *dev = ir->dev;
char *data;
@@ -978,8 +989,8 @@ static void mceusb_gen1_init(struct mceusb_dev *ir)
ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0,
data, USB_CTRL_MSG_SZ, HZ * 3);
- dev_dbg(dev, "%s - ret = %d\n", __func__, ret);
- dev_dbg(dev, "%s - data[0] = %d, data[1] = %d\n",
+ mce_dbg(dev, "%s - ret = %d\n", __func__, ret);
+ mce_dbg(dev, "%s - data[0] = %d, data[1] = %d\n",
__func__, data[0], data[1]);
/* set feature: bit rate 38400 bps */
@@ -987,71 +998,56 @@ static void mceusb_gen1_init(struct mceusb_dev *ir)
USB_REQ_SET_FEATURE, USB_TYPE_VENDOR,
0xc04e, 0x0000, NULL, 0, HZ * 3);
- dev_dbg(dev, "%s - ret = %d\n", __func__, ret);
+ mce_dbg(dev, "%s - ret = %d\n", __func__, ret);
/* bRequest 4: set char length to 8 bits */
ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
4, USB_TYPE_VENDOR,
0x0808, 0x0000, NULL, 0, HZ * 3);
- dev_dbg(dev, "%s - retB = %d\n", __func__, ret);
+ mce_dbg(dev, "%s - retB = %d\n", __func__, ret);
/* bRequest 2: set handshaking to use DTR/DSR */
ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
2, USB_TYPE_VENDOR,
0x0000, 0x0100, NULL, 0, HZ * 3);
- dev_dbg(dev, "%s - retC = %d\n", __func__, ret);
+ mce_dbg(dev, "%s - retC = %d\n", __func__, ret);
/* device reset */
mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
- mce_sync_in(ir, NULL, maxp);
/* get hw/sw revision? */
mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
- mce_sync_in(ir, NULL, maxp);
kfree(data);
};
static void mceusb_gen2_init(struct mceusb_dev *ir)
{
- int maxp = ir->len_in;
-
/* device reset */
mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
- mce_sync_in(ir, NULL, maxp);
/* get hw/sw revision? */
mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
- mce_sync_in(ir, NULL, maxp);
/* unknown what the next two actually return... */
mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN));
- mce_sync_in(ir, NULL, maxp);
mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2));
- mce_sync_in(ir, NULL, maxp);
}
static void mceusb_get_parameters(struct mceusb_dev *ir)
{
- int maxp = ir->len_in;
-
/* get the carrier and frequency */
mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ));
- mce_sync_in(ir, NULL, maxp);
- if (!ir->flags.no_tx) {
+ if (!ir->flags.no_tx)
/* get the transmitter bitmask */
mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
- mce_sync_in(ir, NULL, maxp);
- }
/* get receiver timeout value */
mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT));
- mce_sync_in(ir, NULL, maxp);
/* get receiver sensor setting */
mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR));
- mce_sync_in(ir, NULL, maxp);
}
static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
@@ -1122,7 +1118,7 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
bool tx_mask_normal;
int ir_intfnum;
- dev_dbg(&intf->dev, "%s called\n", __func__);
+ mce_dbg(&intf->dev, "%s called\n", __func__);
idesc = intf->cur_altsetting;
@@ -1150,7 +1146,7 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
ep_in = ep;
ep_in->bmAttributes = USB_ENDPOINT_XFER_INT;
ep_in->bInterval = 1;
- dev_dbg(&intf->dev, "acceptable inbound endpoint "
+ mce_dbg(&intf->dev, "acceptable inbound endpoint "
"found\n");
}
@@ -1165,12 +1161,12 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
ep_out = ep;
ep_out->bmAttributes = USB_ENDPOINT_XFER_INT;
ep_out->bInterval = 1;
- dev_dbg(&intf->dev, "acceptable outbound endpoint "
+ mce_dbg(&intf->dev, "acceptable outbound endpoint "
"found\n");
}
}
if (ep_in == NULL) {
- dev_dbg(&intf->dev, "inbound and/or endpoint not found\n");
+ mce_dbg(&intf->dev, "inbound and/or endpoint not found\n");
return -ENODEV;
}
@@ -1215,16 +1211,16 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
if (!ir->rc)
goto rc_dev_fail;
- /* flush buffers on the device */
- mce_sync_in(ir, NULL, maxp);
- mce_sync_in(ir, NULL, maxp);
-
/* wire up inbound data handler */
usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in,
maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval);
ir->urb_in->transfer_dma = ir->dma_in;
ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ /* flush buffers on the device */
+ mce_dbg(&intf->dev, "Flushing receive buffers\n");
+ mce_flush_rx_buffer(ir, maxp);
+
/* initialize device */
if (ir->flags.microsoft_gen1)
mceusb_gen1_init(ir);
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index bf3060ea610..565f24c20d7 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -991,7 +991,6 @@ static int nvt_open(struct rc_dev *dev)
unsigned long flags;
spin_lock_irqsave(&nvt->nvt_lock, flags);
- nvt->in_use = true;
nvt_enable_cir(nvt);
spin_unlock_irqrestore(&nvt->nvt_lock, flags);
@@ -1004,7 +1003,6 @@ static void nvt_close(struct rc_dev *dev)
unsigned long flags;
spin_lock_irqsave(&nvt->nvt_lock, flags);
- nvt->in_use = false;
nvt_disable_cir(nvt);
spin_unlock_irqrestore(&nvt->nvt_lock, flags);
}
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index 379795d61ea..1241fc89a36 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -70,7 +70,6 @@ struct nvt_dev {
struct ir_raw_event rawir;
spinlock_t nvt_lock;
- bool in_use;
/* for rx */
u8 buf[RX_BUF_LEN];
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index f57cd5677ac..3186ac7c2c1 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -522,18 +522,20 @@ EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
/**
* ir_do_keyup() - internal function to signal the release of a keypress
* @dev: the struct rc_dev descriptor of the device
+ * @sync: whether or not to call input_sync
*
* This function is used internally to release a keypress, it must be
* called with keylock held.
*/
-static void ir_do_keyup(struct rc_dev *dev)
+static void ir_do_keyup(struct rc_dev *dev, bool sync)
{
if (!dev->keypressed)
return;
IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
input_report_key(dev->input_dev, dev->last_keycode, 0);
- input_sync(dev->input_dev);
+ if (sync)
+ input_sync(dev->input_dev);
dev->keypressed = false;
}
@@ -549,7 +551,7 @@ void rc_keyup(struct rc_dev *dev)
unsigned long flags;
spin_lock_irqsave(&dev->keylock, flags);
- ir_do_keyup(dev);
+ ir_do_keyup(dev, true);
spin_unlock_irqrestore(&dev->keylock, flags);
}
EXPORT_SYMBOL_GPL(rc_keyup);
@@ -578,7 +580,7 @@ static void ir_timer_keyup(unsigned long cookie)
*/
spin_lock_irqsave(&dev->keylock, flags);
if (time_is_before_eq_jiffies(dev->keyup_jiffies))
- ir_do_keyup(dev);
+ ir_do_keyup(dev, true);
spin_unlock_irqrestore(&dev->keylock, flags);
}
@@ -597,6 +599,7 @@ void rc_repeat(struct rc_dev *dev)
spin_lock_irqsave(&dev->keylock, flags);
input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
+ input_sync(dev->input_dev);
if (!dev->keypressed)
goto out;
@@ -622,29 +625,28 @@ EXPORT_SYMBOL_GPL(rc_repeat);
static void ir_do_keydown(struct rc_dev *dev, int scancode,
u32 keycode, u8 toggle)
{
- input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
-
- /* Repeat event? */
- if (dev->keypressed &&
- dev->last_scancode == scancode &&
- dev->last_toggle == toggle)
- return;
+ bool new_event = !dev->keypressed ||
+ dev->last_scancode != scancode ||
+ dev->last_toggle != toggle;
- /* Release old keypress */
- ir_do_keyup(dev);
+ if (new_event && dev->keypressed)
+ ir_do_keyup(dev, false);
- dev->last_scancode = scancode;
- dev->last_toggle = toggle;
- dev->last_keycode = keycode;
+ input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
- if (keycode == KEY_RESERVED)
- return;
+ if (new_event && keycode != KEY_RESERVED) {
+ /* Register a keypress */
+ dev->keypressed = true;
+ dev->last_scancode = scancode;
+ dev->last_toggle = toggle;
+ dev->last_keycode = keycode;
+
+ IR_dprintk(1, "%s: key down event, "
+ "key 0x%04x, scancode 0x%04x\n",
+ dev->input_name, keycode, scancode);
+ input_report_key(dev->input_dev, keycode, 1);
+ }
- /* Register a keypress */
- dev->keypressed = true;
- IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n",
- dev->input_name, keycode, scancode);
- input_report_key(dev->input_dev, dev->last_keycode, 1);
input_sync(dev->input_dev);
}
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index a97cf2750bd..834a48394bc 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -3474,7 +3474,7 @@ static int radio_s_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
- bttv_call_all(btv, tuner, g_tuner, t);
+ bttv_call_all(btv, tuner, s_tuner, t);
return 0;
}
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 1933d4d11bf..e80134f52ef 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -695,14 +695,10 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
cx18_call_all(cx, tuner, g_tuner, vt);
- if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+ if (vt->type == V4L2_TUNER_RADIO)
strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
- vt->type = V4L2_TUNER_RADIO;
- } else {
+ else
strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
- vt->type = V4L2_TUNER_ANALOG_TV;
- }
-
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index f9e347dae73..120c7d8e089 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -1184,14 +1184,10 @@ static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
ivtv_call_all(itv, tuner, g_tuner, vt);
- if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+ if (vt->type == V4L2_TUNER_RADIO)
strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
- vt->type = V4L2_TUNER_RADIO;
- } else {
+ else
strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name));
- vt->type = V4L2_TUNER_ANALOG_TV;
- }
-
return 0;
}
diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h
index 10b55c85448..89d09a8914f 100644
--- a/drivers/media/video/m5mols/m5mols.h
+++ b/drivers/media/video/m5mols/m5mols.h
@@ -2,10 +2,10 @@
* Header for M-5MOLS 8M Pixel camera sensor with ISP
*
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * Author: HeungJun Kim, riverful.kim@samsung.com
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
*
* Copyright (C) 2009 Samsung Electronics Co., Ltd.
- * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com
+ * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -106,23 +106,23 @@ struct m5mols_capture {
* The each value according to each scenemode is recommended in the documents.
*/
struct m5mols_scenemode {
- u32 metering;
- u32 ev_bias;
- u32 wb_mode;
- u32 wb_preset;
- u32 chroma_en;
- u32 chroma_lvl;
- u32 edge_en;
- u32 edge_lvl;
- u32 af_range;
- u32 fd_mode;
- u32 mcc;
- u32 light;
- u32 flash;
- u32 tone;
- u32 iso;
- u32 capt_mode;
- u32 wdr;
+ u8 metering;
+ u8 ev_bias;
+ u8 wb_mode;
+ u8 wb_preset;
+ u8 chroma_en;
+ u8 chroma_lvl;
+ u8 edge_en;
+ u8 edge_lvl;
+ u8 af_range;
+ u8 fd_mode;
+ u8 mcc;
+ u8 light;
+ u8 flash;
+ u8 tone;
+ u8 iso;
+ u8 capt_mode;
+ u8 wdr;
};
/**
@@ -154,7 +154,6 @@ struct m5mols_version {
u8 str[VERSION_STRING_SIZE];
u8 af;
};
-#define VERSION_SIZE sizeof(struct m5mols_version)
/**
* struct m5mols_info - M-5MOLS driver data structure
@@ -216,9 +215,9 @@ struct m5mols_info {
bool lock_ae;
bool lock_awb;
u8 resolution;
- u32 interrupt;
- u32 mode;
- u32 mode_save;
+ u8 interrupt;
+ u8 mode;
+ u8 mode_save;
int (*set_power)(struct device *dev, int on);
};
@@ -256,9 +255,11 @@ struct m5mols_info {
* +-------+---+----------+-----+------+------+------+------+
* - d[0..3]: according to size1
*/
-int m5mols_read(struct v4l2_subdev *sd, u32 reg_comb, u32 *val);
+int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg_comb, u8 *val);
+int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg_comb, u16 *val);
+int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg_comb, u32 *val);
int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val);
-int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 value);
+int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 value);
/*
* Mode operation of the M-5MOLS
@@ -280,12 +281,12 @@ int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 value);
* The available executing order between each modes are as follows:
* PARAMETER <---> MONITOR <---> CAPTURE
*/
-int m5mols_mode(struct m5mols_info *info, u32 mode);
+int m5mols_mode(struct m5mols_info *info, u8 mode);
-int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg);
+int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg);
int m5mols_sync_controls(struct m5mols_info *info);
int m5mols_start_capture(struct m5mols_info *info);
-int m5mols_do_scenemode(struct m5mols_info *info, u32 mode);
+int m5mols_do_scenemode(struct m5mols_info *info, u8 mode);
int m5mols_lock_3a(struct m5mols_info *info, bool lock);
int m5mols_set_ctrl(struct v4l2_ctrl *ctrl);
diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c
index d71a3903b60..d9471928369 100644
--- a/drivers/media/video/m5mols/m5mols_capture.c
+++ b/drivers/media/video/m5mols/m5mols_capture.c
@@ -2,10 +2,10 @@
* The Capture code for Fujitsu M-5MOLS ISP
*
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * Author: HeungJun Kim, riverful.kim@samsung.com
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
*
* Copyright (C) 2009 Samsung Electronics Co., Ltd.
- * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com
+ * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -58,9 +58,9 @@ static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num,
{
u32 num, den;
- int ret = m5mols_read(sd, addr_num, &num);
+ int ret = m5mols_read_u32(sd, addr_num, &num);
if (!ret)
- ret = m5mols_read(sd, addr_den, &den);
+ ret = m5mols_read_u32(sd, addr_den, &den);
if (ret)
return ret;
*val = den == 0 ? 0 : num / den;
@@ -99,20 +99,20 @@ static int m5mols_capture_info(struct m5mols_info *info)
if (ret)
return ret;
- ret = m5mols_read(sd, EXIF_INFO_ISO, (u32 *)&exif->iso_speed);
+ ret = m5mols_read_u16(sd, EXIF_INFO_ISO, &exif->iso_speed);
if (!ret)
- ret = m5mols_read(sd, EXIF_INFO_FLASH, (u32 *)&exif->flash);
+ ret = m5mols_read_u16(sd, EXIF_INFO_FLASH, &exif->flash);
if (!ret)
- ret = m5mols_read(sd, EXIF_INFO_SDR, (u32 *)&exif->sdr);
+ ret = m5mols_read_u16(sd, EXIF_INFO_SDR, &exif->sdr);
if (!ret)
- ret = m5mols_read(sd, EXIF_INFO_QVAL, (u32 *)&exif->qval);
+ ret = m5mols_read_u16(sd, EXIF_INFO_QVAL, &exif->qval);
if (ret)
return ret;
if (!ret)
- ret = m5mols_read(sd, CAPC_IMAGE_SIZE, &info->cap.main);
+ ret = m5mols_read_u32(sd, CAPC_IMAGE_SIZE, &info->cap.main);
if (!ret)
- ret = m5mols_read(sd, CAPC_THUMB_SIZE, &info->cap.thumb);
+ ret = m5mols_read_u32(sd, CAPC_THUMB_SIZE, &info->cap.thumb);
if (!ret)
info->cap.total = info->cap.main + info->cap.thumb;
@@ -122,7 +122,7 @@ static int m5mols_capture_info(struct m5mols_info *info)
int m5mols_start_capture(struct m5mols_info *info)
{
struct v4l2_subdev *sd = &info->sd;
- u32 resolution = info->resolution;
+ u8 resolution = info->resolution;
int timeout;
int ret;
diff --git a/drivers/media/video/m5mols/m5mols_controls.c b/drivers/media/video/m5mols/m5mols_controls.c
index 817c16fec36..d135d20d09c 100644
--- a/drivers/media/video/m5mols/m5mols_controls.c
+++ b/drivers/media/video/m5mols/m5mols_controls.c
@@ -2,10 +2,10 @@
* Controls for M-5MOLS 8M Pixel camera sensor with ISP
*
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * Author: HeungJun Kim, riverful.kim@samsung.com
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
*
* Copyright (C) 2009 Samsung Electronics Co., Ltd.
- * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com
+ * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -130,7 +130,7 @@ static struct m5mols_scenemode m5mols_default_scenemode[] = {
*
* WARNING: The execution order is important. Do not change the order.
*/
-int m5mols_do_scenemode(struct m5mols_info *info, u32 mode)
+int m5mols_do_scenemode(struct m5mols_info *info, u8 mode)
{
struct v4l2_subdev *sd = &info->sd;
struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode];
diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c
index 76eac26e84a..43c68f51c5c 100644
--- a/drivers/media/video/m5mols/m5mols_core.c
+++ b/drivers/media/video/m5mols/m5mols_core.c
@@ -2,10 +2,10 @@
* Driver for M-5MOLS 8M Pixel camera sensor with ISP
*
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * Author: HeungJun Kim, riverful.kim@samsung.com
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
*
* Copyright (C) 2009 Samsung Electronics Co., Ltd.
- * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com
+ * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -133,13 +133,13 @@ static u32 m5mols_swap_byte(u8 *data, u8 length)
/**
* m5mols_read - I2C read function
* @reg: combination of size, category and command for the I2C packet
+ * @size: desired size of I2C packet
* @val: read value
*/
-int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val)
+static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1];
- u8 size = I2C_SIZE(reg);
u8 category = I2C_CATEGORY(reg);
u8 cmd = I2C_COMMAND(reg);
struct i2c_msg msg[2];
@@ -149,11 +149,6 @@ int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val)
if (!client->adapter)
return -ENODEV;
- if (size != 1 && size != 2 && size != 4) {
- v4l2_err(sd, "Wrong data size\n");
- return -EINVAL;
- }
-
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = 5;
@@ -184,6 +179,52 @@ int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val)
return 0;
}
+int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val)
+{
+ u32 val_32;
+ int ret;
+
+ if (I2C_SIZE(reg) != 1) {
+ v4l2_err(sd, "Wrong data size\n");
+ return -EINVAL;
+ }
+
+ ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32);
+ if (ret)
+ return ret;
+
+ *val = (u8)val_32;
+ return ret;
+}
+
+int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg, u16 *val)
+{
+ u32 val_32;
+ int ret;
+
+ if (I2C_SIZE(reg) != 2) {
+ v4l2_err(sd, "Wrong data size\n");
+ return -EINVAL;
+ }
+
+ ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32);
+ if (ret)
+ return ret;
+
+ *val = (u16)val_32;
+ return ret;
+}
+
+int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val)
+{
+ if (I2C_SIZE(reg) != 4) {
+ v4l2_err(sd, "Wrong data size\n");
+ return -EINVAL;
+ }
+
+ return m5mols_read(sd, I2C_SIZE(reg), reg, val);
+}
+
/**
* m5mols_write - I2C command write function
* @reg: combination of size, category and command for the I2C packet
@@ -231,13 +272,14 @@ int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
return 0;
}
-int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 mask)
+int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 mask)
{
- u32 busy, i;
+ u8 busy;
+ int i;
int ret;
for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) {
- ret = m5mols_read(sd, I2C_REG(category, cmd, 1), &busy);
+ ret = m5mols_read_u8(sd, I2C_REG(category, cmd, 1), &busy);
if (ret < 0)
return ret;
if ((busy & mask) == mask)
@@ -252,14 +294,14 @@ int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 mask)
* Before writing desired interrupt value the INT_FACTOR register should
* be read to clear pending interrupts.
*/
-int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg)
+int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg)
{
struct m5mols_info *info = to_m5mols(sd);
- u32 mask = is_available_af(info) ? REG_INT_AF : 0;
- u32 dummy;
+ u8 mask = is_available_af(info) ? REG_INT_AF : 0;
+ u8 dummy;
int ret;
- ret = m5mols_read(sd, SYSTEM_INT_FACTOR, &dummy);
+ ret = m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &dummy);
if (!ret)
ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask);
return ret;
@@ -271,7 +313,7 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg)
* It always accompanies a little delay changing the M-5MOLS mode, so it is
* needed checking current busy status to guarantee right mode.
*/
-static int m5mols_reg_mode(struct v4l2_subdev *sd, u32 mode)
+static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode)
{
int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode);
@@ -286,16 +328,16 @@ static int m5mols_reg_mode(struct v4l2_subdev *sd, u32 mode)
* can be guaranteed only when the sensor is operating in mode which which
* a command belongs to.
*/
-int m5mols_mode(struct m5mols_info *info, u32 mode)
+int m5mols_mode(struct m5mols_info *info, u8 mode)
{
struct v4l2_subdev *sd = &info->sd;
int ret = -EINVAL;
- u32 reg;
+ u8 reg;
if (mode < REG_PARAMETER && mode > REG_CAPTURE)
return ret;
- ret = m5mols_read(sd, SYSTEM_SYSMODE, &reg);
+ ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, &reg);
if ((!ret && reg == mode) || ret)
return ret;
@@ -344,41 +386,37 @@ int m5mols_mode(struct m5mols_info *info, u32 mode)
static int m5mols_get_version(struct v4l2_subdev *sd)
{
struct m5mols_info *info = to_m5mols(sd);
- union {
- struct m5mols_version ver;
- u8 bytes[VERSION_SIZE];
- } version;
- u32 *value;
- u8 cmd = CAT0_VER_CUSTOMER;
+ struct m5mols_version *ver = &info->ver;
+ u8 *str = ver->str;
+ int i;
int ret;
- do {
- value = (u32 *)&version.bytes[cmd];
- ret = m5mols_read(sd, SYSTEM_CMD(cmd), value);
- if (ret)
- return ret;
- } while (cmd++ != CAT0_VER_AWB);
+ ret = m5mols_read_u8(sd, SYSTEM_VER_CUSTOMER, &ver->customer);
+ if (!ret)
+ ret = m5mols_read_u8(sd, SYSTEM_VER_PROJECT, &ver->project);
+ if (!ret)
+ ret = m5mols_read_u16(sd, SYSTEM_VER_FIRMWARE, &ver->fw);
+ if (!ret)
+ ret = m5mols_read_u16(sd, SYSTEM_VER_HARDWARE, &ver->hw);
+ if (!ret)
+ ret = m5mols_read_u16(sd, SYSTEM_VER_PARAMETER, &ver->param);
+ if (!ret)
+ ret = m5mols_read_u16(sd, SYSTEM_VER_AWB, &ver->awb);
+ if (!ret)
+ ret = m5mols_read_u8(sd, AF_VERSION, &ver->af);
+ if (ret)
+ return ret;
- do {
- value = (u32 *)&version.bytes[cmd];
- ret = m5mols_read(sd, SYSTEM_VER_STRING, value);
+ for (i = 0; i < VERSION_STRING_SIZE; i++) {
+ ret = m5mols_read_u8(sd, SYSTEM_VER_STRING, &str[i]);
if (ret)
return ret;
- if (cmd >= VERSION_SIZE - 1)
- return -EINVAL;
- } while (version.bytes[cmd++]);
-
- value = (u32 *)&version.bytes[cmd];
- ret = m5mols_read(sd, AF_VERSION, value);
- if (ret)
- return ret;
+ }
- /* store version information swapped for being readable */
- info->ver = version.ver;
- info->ver.fw = be16_to_cpu(info->ver.fw);
- info->ver.hw = be16_to_cpu(info->ver.hw);
- info->ver.param = be16_to_cpu(info->ver.param);
- info->ver.awb = be16_to_cpu(info->ver.awb);
+ ver->fw = be16_to_cpu(ver->fw);
+ ver->hw = be16_to_cpu(ver->hw);
+ ver->param = be16_to_cpu(ver->param);
+ ver->awb = be16_to_cpu(ver->awb);
v4l2_info(sd, "Manufacturer\t[%s]\n",
is_manufacturer(info, REG_SAMSUNG_ELECTRO) ?
@@ -722,7 +760,7 @@ static int m5mols_init_controls(struct m5mols_info *info)
int ret;
/* Determine value's range & step of controls for various FW version */
- ret = m5mols_read(sd, AE_MAX_GAIN_MON, (u32 *)&max_exposure);
+ ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &max_exposure);
if (!ret)
step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
if (ret)
@@ -842,18 +880,18 @@ static void m5mols_irq_work(struct work_struct *work)
struct m5mols_info *info =
container_of(work, struct m5mols_info, work_irq);
struct v4l2_subdev *sd = &info->sd;
- u32 reg;
+ u8 reg;
int ret;
if (!is_powered(info) ||
- m5mols_read(sd, SYSTEM_INT_FACTOR, &info->interrupt))
+ m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &info->interrupt))
return;
switch (info->interrupt & REG_INT_MASK) {
case REG_INT_AF:
if (!is_available_af(info))
break;
- ret = m5mols_read(sd, AF_STATUS, &reg);
+ ret = m5mols_read_u8(sd, AF_STATUS, &reg);
v4l2_dbg(2, m5mols_debug, sd, "AF %s\n",
reg == REG_AF_FAIL ? "Failed" :
reg == REG_AF_SUCCESS ? "Success" :
diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h
index b83e36fc6ac..c755bd6edfe 100644
--- a/drivers/media/video/m5mols/m5mols_reg.h
+++ b/drivers/media/video/m5mols/m5mols_reg.h
@@ -2,10 +2,10 @@
* Register map for M-5MOLS 8M Pixel camera sensor with ISP
*
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * Author: HeungJun Kim, riverful.kim@samsung.com
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
*
* Copyright (C) 2009 Samsung Electronics Co., Ltd.
- * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com
+ * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -56,13 +56,24 @@
* more specific contents, see definition if file m5mols.h.
*/
#define CAT0_VER_CUSTOMER 0x00 /* customer version */
-#define CAT0_VER_AWB 0x09 /* Auto WB version */
+#define CAT0_VER_PROJECT 0x01 /* project version */
+#define CAT0_VER_FIRMWARE 0x02 /* Firmware version */
+#define CAT0_VER_HARDWARE 0x04 /* Hardware version */
+#define CAT0_VER_PARAMETER 0x06 /* Parameter version */
+#define CAT0_VER_AWB 0x08 /* Auto WB version */
#define CAT0_VER_STRING 0x0a /* string including M-5MOLS */
#define CAT0_SYSMODE 0x0b /* SYSTEM mode register */
#define CAT0_STATUS 0x0c /* SYSTEM mode status register */
#define CAT0_INT_FACTOR 0x10 /* interrupt pending register */
#define CAT0_INT_ENABLE 0x11 /* interrupt enable register */
+#define SYSTEM_VER_CUSTOMER I2C_REG(CAT_SYSTEM, CAT0_VER_CUSTOMER, 1)
+#define SYSTEM_VER_PROJECT I2C_REG(CAT_SYSTEM, CAT0_VER_PROJECT, 1)
+#define SYSTEM_VER_FIRMWARE I2C_REG(CAT_SYSTEM, CAT0_VER_FIRMWARE, 2)
+#define SYSTEM_VER_HARDWARE I2C_REG(CAT_SYSTEM, CAT0_VER_HARDWARE, 2)
+#define SYSTEM_VER_PARAMETER I2C_REG(CAT_SYSTEM, CAT0_VER_PARAMETER, 2)
+#define SYSTEM_VER_AWB I2C_REG(CAT_SYSTEM, CAT0_VER_AWB, 2)
+
#define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1)
#define REG_SYSINIT 0x00 /* SYSTEM mode */
#define REG_PARAMETER 0x01 /* PARAMETER mode */
@@ -382,8 +393,8 @@
#define REG_CAP_START_MAIN 0x01
#define REG_CAP_START_THUMB 0x03
-#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 1)
-#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 1)
+#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 4)
+#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 4)
/*
* Category F - Flash
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index de5d481b032..c43c81f5f97 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -480,12 +480,14 @@ static int msp_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
struct msp_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (state->radio)
+ if (vt->type != V4L2_TUNER_ANALOG_TV)
return 0;
- if (state->opmode == OPMODE_AUTOSELECT)
- msp_detect_stereo(client);
- vt->audmode = state->audmode;
- vt->rxsubchans = state->rxsubchans;
+ if (!state->radio) {
+ if (state->opmode == OPMODE_AUTOSELECT)
+ msp_detect_stereo(client);
+ vt->rxsubchans = state->rxsubchans;
+ }
+ vt->audmode = state->audmode;
vt->capability |= V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
return 0;
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c
index bc0c23a1009..63f8a0cc33d 100644
--- a/drivers/media/video/mx1_camera.c
+++ b/drivers/media/video/mx1_camera.c
@@ -444,12 +444,9 @@ static int mx1_camera_add_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct mx1_camera_dev *pcdev = ici->priv;
- int ret;
- if (pcdev->icd) {
- ret = -EBUSY;
- goto ebusy;
- }
+ if (pcdev->icd)
+ return -EBUSY;
dev_info(icd->dev.parent, "MX1 Camera driver attached to camera %d\n",
icd->devnum);
@@ -458,8 +455,7 @@ static int mx1_camera_add_device(struct soc_camera_device *icd)
pcdev->icd = icd;
-ebusy:
- return ret;
+ return 0;
}
static void mx1_camera_remove_device(struct soc_camera_device *icd)
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
index 4ada9be1d43..4d07c584440 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/video/omap/omap_vout.c
@@ -982,6 +982,14 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
startindex = (vout->vid == OMAP_VIDEO1) ?
video1_numbuffers : video2_numbuffers;
+ /* Check the size of the buffer */
+ if (*size > vout->buffer_size) {
+ v4l2_err(&vout->vid_dev->v4l2_dev,
+ "buffer allocation mismatch [%u] [%u]\n",
+ *size, vout->buffer_size);
+ return -ENOMEM;
+ }
+
for (i = startindex; i < *count; i++) {
vout->buffer_size = *size;
@@ -1228,6 +1236,14 @@ static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma)
(vma->vm_pgoff << PAGE_SHIFT));
return -EINVAL;
}
+ /* Check the size of the buffer */
+ if (size > vout->buffer_size) {
+ v4l2_err(&vout->vid_dev->v4l2_dev,
+ "insufficient memory [%lu] [%u]\n",
+ size, vout->buffer_size);
+ return -ENOMEM;
+ }
+
q->bufs[i]->baddr = vma->vm_start;
vma->vm_flags |= VM_RESERVED;
@@ -2391,7 +2407,7 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev)
/* Register the Video device with V4L2
*/
vfd = vout->vfd;
- if (video_register_device(vfd, VFL_TYPE_GRABBER, k + 1) < 0) {
+ if (video_register_device(vfd, VFL_TYPE_GRABBER, -1) < 0) {
dev_err(&pdev->dev, ": Could not register "
"Video for Linux device\n");
vfd->minor = -1;
diff --git a/drivers/media/video/omap/omap_voutlib.c b/drivers/media/video/omap/omap_voutlib.c
index 2aa6a76c5e5..8ae74817a11 100644
--- a/drivers/media/video/omap/omap_voutlib.c
+++ b/drivers/media/video/omap/omap_voutlib.c
@@ -193,7 +193,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix,
return -EINVAL;
if (cpu_is_omap24xx()) {
- if (crop->height != win->w.height) {
+ if (try_crop.height != win->w.height) {
/* If we're resizing vertically, we can't support a
* crop width wider than 768 pixels.
*/
@@ -202,7 +202,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix,
}
}
/* vertical resizing */
- vresize = (1024 * crop->height) / win->w.height;
+ vresize = (1024 * try_crop.height) / win->w.height;
if (cpu_is_omap24xx() && (vresize > 2048))
vresize = 2048;
else if (cpu_is_omap34xx() && (vresize > 4096))
@@ -221,7 +221,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix,
try_crop.height = 2;
}
/* horizontal resizing */
- hresize = (1024 * crop->width) / win->w.width;
+ hresize = (1024 * try_crop.width) / win->w.width;
if (cpu_is_omap24xx() && (hresize > 2048))
hresize = 2048;
else if (cpu_is_omap34xx() && (hresize > 4096))
diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c
index c9fd04ee70a..94b6ed89e19 100644
--- a/drivers/media/video/omap3isp/isp.c
+++ b/drivers/media/video/omap3isp/isp.c
@@ -1748,7 +1748,7 @@ static int isp_register_entities(struct isp_device *isp)
goto done;
/* Register external entities */
- for (subdevs = pdata->subdevs; subdevs->subdevs; ++subdevs) {
+ for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) {
struct v4l2_subdev *sensor;
struct media_entity *input;
unsigned int flags;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 9d0dd08f57f..e98d3821279 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -3046,6 +3046,8 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw)
if (hdw->input_dirty || hdw->audiomode_dirty || hdw->force_dirty) {
struct v4l2_tuner vt;
memset(&vt, 0, sizeof(vt));
+ vt.type = (hdw->input_val == PVR2_CVAL_INPUT_RADIO) ?
+ V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
vt.audmode = hdw->audiomode_val;
v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, s_tuner, &vt);
}
@@ -5171,6 +5173,8 @@ void pvr2_hdw_status_poll(struct pvr2_hdw *hdw)
{
struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
memset(vtp, 0, sizeof(*vtp));
+ vtp->type = (hdw->input_val == PVR2_CVAL_INPUT_RADIO) ?
+ V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
hdw->tuner_signal_stale = 0;
/* Note: There apparently is no replacement for VIDIOC_CROPCAP
using v4l2-subdev - therefore we can't support that AT ALL right
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index 1593f8deb81..760b4de13ad 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -1414,7 +1414,7 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{
ARG_DEF(struct pwc_probe, probe)
- strcpy(ARGR(probe).name, pdev->vdev->name);
+ strcpy(ARGR(probe).name, pdev->vdev.name);
ARGR(probe).type = pdev->type;
ARG_OUT(probe)
break;
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 356cd42b593..b0bde5a87c8 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -40,7 +40,7 @@
Oh yes, convention: to disctinguish between all the various pointers to
device-structures, I use these names for the pointer variables:
udev: struct usb_device *
- vdev: struct video_device *
+ vdev: struct video_device (member of pwc_dev)
pdev: struct pwc_devive *
*/
@@ -152,6 +152,7 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos);
static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
+static void pwc_video_release(struct video_device *vfd);
static const struct v4l2_file_operations pwc_fops = {
.owner = THIS_MODULE,
@@ -164,42 +165,12 @@ static const struct v4l2_file_operations pwc_fops = {
};
static struct video_device pwc_template = {
.name = "Philips Webcam", /* Filled in later */
- .release = video_device_release,
+ .release = pwc_video_release,
.fops = &pwc_fops,
+ .ioctl_ops = &pwc_ioctl_ops,
};
/***************************************************************************/
-
-/* Okay, this is some magic that I worked out and the reasoning behind it...
-
- The biggest problem with any USB device is of course: "what to do
- when the user unplugs the device while it is in use by an application?"
- We have several options:
- 1) Curse them with the 7 plagues when they do (requires divine intervention)
- 2) Tell them not to (won't work: they'll do it anyway)
- 3) Oops the kernel (this will have a negative effect on a user's uptime)
- 4) Do something sensible.
-
- Of course, we go for option 4.
-
- It happens that this device will be linked to two times, once from
- usb_device and once from the video_device in their respective 'private'
- pointers. This is done when the device is probed() and all initialization
- succeeded. The pwc_device struct links back to both structures.
-
- When a device is unplugged while in use it will be removed from the
- list of known USB devices; I also de-register it as a V4L device, but
- unfortunately I can't free the memory since the struct is still in use
- by the file descriptor. This free-ing is then deferend until the first
- opportunity. Crude, but it works.
-
- A small 'advantage' is that if a user unplugs the cam and plugs it back
- in, it should get assigned the same video device minor, but unfortunately
- it's non-trivial to re-link the cam back to the video device... (that
- would surely be magic! :))
-*/
-
-/***************************************************************************/
/* Private functions */
/* Here we want the physical address of the memory.
@@ -1016,16 +987,15 @@ static ssize_t show_snapshot_button_status(struct device *class_dev,
static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
NULL);
-static int pwc_create_sysfs_files(struct video_device *vdev)
+static int pwc_create_sysfs_files(struct pwc_device *pdev)
{
- struct pwc_device *pdev = video_get_drvdata(vdev);
int rc;
- rc = device_create_file(&vdev->dev, &dev_attr_button);
+ rc = device_create_file(&pdev->vdev.dev, &dev_attr_button);
if (rc)
goto err;
if (pdev->features & FEATURE_MOTOR_PANTILT) {
- rc = device_create_file(&vdev->dev, &dev_attr_pan_tilt);
+ rc = device_create_file(&pdev->vdev.dev, &dev_attr_pan_tilt);
if (rc)
goto err_button;
}
@@ -1033,19 +1003,17 @@ static int pwc_create_sysfs_files(struct video_device *vdev)
return 0;
err_button:
- device_remove_file(&vdev->dev, &dev_attr_button);
+ device_remove_file(&pdev->vdev.dev, &dev_attr_button);
err:
PWC_ERROR("Could not create sysfs files.\n");
return rc;
}
-static void pwc_remove_sysfs_files(struct video_device *vdev)
+static void pwc_remove_sysfs_files(struct pwc_device *pdev)
{
- struct pwc_device *pdev = video_get_drvdata(vdev);
-
if (pdev->features & FEATURE_MOTOR_PANTILT)
- device_remove_file(&vdev->dev, &dev_attr_pan_tilt);
- device_remove_file(&vdev->dev, &dev_attr_button);
+ device_remove_file(&pdev->vdev.dev, &dev_attr_pan_tilt);
+ device_remove_file(&pdev->vdev.dev, &dev_attr_button);
}
#ifdef CONFIG_USB_PWC_DEBUG
@@ -1106,7 +1074,7 @@ static int pwc_video_open(struct file *file)
if (ret >= 0)
{
PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
- pdev->vdev->name,
+ pdev->vdev.name,
pwc_sensor_type_to_string(i), i);
}
}
@@ -1180,16 +1148,15 @@ static int pwc_video_open(struct file *file)
return 0;
}
-
-static void pwc_cleanup(struct pwc_device *pdev)
+static void pwc_video_release(struct video_device *vfd)
{
- pwc_remove_sysfs_files(pdev->vdev);
- video_unregister_device(pdev->vdev);
+ struct pwc_device *pdev = container_of(vfd, struct pwc_device, vdev);
+ int hint;
-#ifdef CONFIG_USB_PWC_INPUT_EVDEV
- if (pdev->button_dev)
- input_unregister_device(pdev->button_dev);
-#endif
+ /* search device_hint[] table if we occupy a slot, by any chance */
+ for (hint = 0; hint < MAX_DEV_HINTS; hint++)
+ if (device_hint[hint].pdev == pdev)
+ device_hint[hint].pdev = NULL;
kfree(pdev);
}
@@ -1199,7 +1166,7 @@ static int pwc_video_close(struct file *file)
{
struct video_device *vdev = file->private_data;
struct pwc_device *pdev;
- int i, hint;
+ int i;
PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
@@ -1234,12 +1201,6 @@ static int pwc_video_close(struct file *file)
}
pdev->vopen--;
PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
- } else {
- pwc_cleanup(pdev);
- /* search device_hint[] table if we occupy a slot, by any chance */
- for (hint = 0; hint < MAX_DEV_HINTS; hint++)
- if (device_hint[hint].pdev == pdev)
- device_hint[hint].pdev = NULL;
}
return 0;
@@ -1715,19 +1676,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
init_waitqueue_head(&pdev->frameq);
pdev->vcompression = pwc_preferred_compression;
- /* Allocate video_device structure */
- pdev->vdev = video_device_alloc();
- if (!pdev->vdev) {
- PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
- rc = -ENOMEM;
- goto err_free_mem;
- }
- memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
- pdev->vdev->parent = &intf->dev;
- pdev->vdev->lock = &pdev->modlock;
- pdev->vdev->ioctl_ops = &pwc_ioctl_ops;
- strcpy(pdev->vdev->name, name);
- video_set_drvdata(pdev->vdev, pdev);
+ /* Init video_device structure */
+ memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template));
+ pdev->vdev.parent = &intf->dev;
+ pdev->vdev.lock = &pdev->modlock;
+ strcpy(pdev->vdev.name, name);
+ video_set_drvdata(&pdev->vdev, pdev);
pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
@@ -1746,8 +1700,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
}
}
- pdev->vdev->release = video_device_release;
-
/* occupy slot */
if (hint < MAX_DEV_HINTS)
device_hint[hint].pdev = pdev;
@@ -1759,16 +1711,16 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pwc_set_leds(pdev, 0, 0);
pwc_camera_power(pdev, 0);
- rc = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
+ rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr);
if (rc < 0) {
PWC_ERROR("Failed to register as video device (%d).\n", rc);
- goto err_video_release;
+ goto err_free_mem;
}
- rc = pwc_create_sysfs_files(pdev->vdev);
+ rc = pwc_create_sysfs_files(pdev);
if (rc)
goto err_video_unreg;
- PWC_INFO("Registered as %s.\n", video_device_node_name(pdev->vdev));
+ PWC_INFO("Registered as %s.\n", video_device_node_name(&pdev->vdev));
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
/* register webcam snapshot button input device */
@@ -1776,7 +1728,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
if (!pdev->button_dev) {
PWC_ERROR("Err, insufficient memory for webcam snapshot button device.");
rc = -ENOMEM;
- pwc_remove_sysfs_files(pdev->vdev);
+ pwc_remove_sysfs_files(pdev);
goto err_video_unreg;
}
@@ -1794,7 +1746,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
if (rc) {
input_free_device(pdev->button_dev);
pdev->button_dev = NULL;
- pwc_remove_sysfs_files(pdev->vdev);
+ pwc_remove_sysfs_files(pdev);
goto err_video_unreg;
}
#endif
@@ -1804,10 +1756,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
err_video_unreg:
if (hint < MAX_DEV_HINTS)
device_hint[hint].pdev = NULL;
- video_unregister_device(pdev->vdev);
- pdev->vdev = NULL; /* So we don't try to release it below */
-err_video_release:
- video_device_release(pdev->vdev);
+ video_unregister_device(&pdev->vdev);
err_free_mem:
kfree(pdev);
return rc;
@@ -1816,10 +1765,8 @@ err_free_mem:
/* The user yanked out the cable... */
static void usb_pwc_disconnect(struct usb_interface *intf)
{
- struct pwc_device *pdev;
- int hint;
+ struct pwc_device *pdev = usb_get_intfdata(intf);
- pdev = usb_get_intfdata (intf);
mutex_lock(&pdev->modlock);
usb_set_intfdata (intf, NULL);
if (pdev == NULL) {
@@ -1836,30 +1783,25 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
}
/* We got unplugged; this is signalled by an EPIPE error code */
- if (pdev->vopen) {
- PWC_INFO("Disconnected while webcam is in use!\n");
- pdev->error_status = EPIPE;
- }
+ pdev->error_status = EPIPE;
+ pdev->unplugged = 1;
/* Alert waiting processes */
wake_up_interruptible(&pdev->frameq);
- /* Wait until device is closed */
- if (pdev->vopen) {
- pdev->unplugged = 1;
- pwc_iso_stop(pdev);
- } else {
- /* Device is closed, so we can safely unregister it */
- PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
-disconnect_out:
- /* search device_hint[] table if we occupy a slot, by any chance */
- for (hint = 0; hint < MAX_DEV_HINTS; hint++)
- if (device_hint[hint].pdev == pdev)
- device_hint[hint].pdev = NULL;
- }
+ /* No need to keep the urbs around after disconnection */
+ pwc_isoc_cleanup(pdev);
+disconnect_out:
mutex_unlock(&pdev->modlock);
- pwc_cleanup(pdev);
+
+ pwc_remove_sysfs_files(pdev);
+ video_unregister_device(&pdev->vdev);
+
+#ifdef CONFIG_USB_PWC_INPUT_EVDEV
+ if (pdev->button_dev)
+ input_unregister_device(pdev->button_dev);
+#endif
}
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index e947766337d..083f8b15df7 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -162,9 +162,9 @@ struct pwc_imgbuf
struct pwc_device
{
- struct video_device *vdev;
+ struct video_device vdev;
- /* Pointer to our usb_device */
+ /* Pointer to our usb_device, may be NULL after unplug */
struct usb_device *udev;
int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index d142b40ea64..81b4a826ee5 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -1,7 +1,7 @@
/*
- * Samsung S5P SoC series camera interface (camera capture) driver
+ * Samsung S5P/EXYNOS4 SoC series camera interface (camera capture) driver
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd
+ * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd.
* Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -262,12 +262,7 @@ static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane)
{
if (!fr || plane >= fr->fmt->memplanes)
return 0;
-
- dbg("%s: w: %d. h: %d. depth[%d]: %d",
- __func__, fr->width, fr->height, plane, fr->fmt->depth[plane]);
-
return fr->f_width * fr->f_height * fr->fmt->depth[plane] / 8;
-
}
static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
@@ -283,24 +278,14 @@ static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
*num_planes = fmt->memplanes;
- dbg("%s, buffer count=%d, plane count=%d",
- __func__, *num_buffers, *num_planes);
-
for (i = 0; i < fmt->memplanes; i++) {
sizes[i] = get_plane_size(&ctx->d_frame, i);
- dbg("plane: %u, plane_size: %lu", i, sizes[i]);
allocators[i] = ctx->fimc_dev->alloc_ctx;
}
return 0;
}
-static int buffer_init(struct vb2_buffer *vb)
-{
- /* TODO: */
- return 0;
-}
-
static int buffer_prepare(struct vb2_buffer *vb)
{
struct vb2_queue *vq = vb->vb2_queue;
@@ -380,7 +365,6 @@ static struct vb2_ops fimc_capture_qops = {
.queue_setup = queue_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
- .buf_init = buffer_init,
.wait_prepare = fimc_unlock,
.wait_finish = fimc_lock,
.start_streaming = start_streaming,
@@ -903,6 +887,7 @@ err_vd_reg:
err_v4l2_reg:
v4l2_device_unregister(v4l2_dev);
err_info:
+ kfree(ctx);
dev_err(&fimc->pdev->dev, "failed to install\n");
return ret;
}
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index dc91a8511af..bdf19ada917 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -1,9 +1,8 @@
/*
- * S5P camera interface (video postprocessor) driver
+ * Samsung S5P/EXYNOS4 SoC series camera interface (video postprocessor) driver
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd
- *
- * Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
+ * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
@@ -42,7 +41,6 @@ static struct fimc_fmt fimc_formats[] = {
.color = S5P_FIMC_RGB565,
.memplanes = 1,
.colplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_BE,
.flags = FMT_FLAGS_M2M,
}, {
.name = "BGR666",
@@ -232,11 +230,7 @@ static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
return 0;
}
}
-
*shift = 0, *ratio = 1;
-
- dbg("s: %d, t: %d, shift: %d, ratio: %d",
- src, tar, *shift, *ratio);
return 0;
}
@@ -268,10 +262,8 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx)
err("invalid source size: %d x %d", sx, sy);
return -EINVAL;
}
-
sc->real_width = sx;
sc->real_height = sy;
- dbg("sx= %d, sy= %d, tx= %d, ty= %d", sx, sy, tx, ty);
ret = fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor);
if (ret)
@@ -711,22 +703,18 @@ static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
f = ctx_get_frame(ctx, vq->type);
if (IS_ERR(f))
return PTR_ERR(f);
-
/*
* Return number of non-contigous planes (plane buffers)
* depending on the configured color format.
*/
- if (f->fmt)
- *num_planes = f->fmt->memplanes;
+ if (!f->fmt)
+ return -EINVAL;
+ *num_planes = f->fmt->memplanes;
for (i = 0; i < f->fmt->memplanes; i++) {
- sizes[i] = (f->width * f->height * f->fmt->depth[i]) >> 3;
+ sizes[i] = (f->f_width * f->f_height * f->fmt->depth[i]) / 8;
allocators[i] = ctx->fimc_dev->alloc_ctx;
}
-
- if (*num_buffers == 0)
- *num_buffers = 1;
-
return 0;
}
@@ -852,7 +840,7 @@ struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask)
for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
fmt = &fimc_formats[i];
- if (fmt->fourcc == f->fmt.pix.pixelformat &&
+ if (fmt->fourcc == f->fmt.pix_mp.pixelformat &&
(fmt->flags & mask))
break;
}
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h
index 3beb1e5320c..1f70772daaf 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.h
+++ b/drivers/media/video/s5p-fimc/fimc-core.h
@@ -1,7 +1,5 @@
/*
- * Copyright (c) 2010 Samsung Electronics
- *
- * Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -135,9 +133,10 @@ enum fimc_color_fmt {
* @name: format description
* @fourcc: the fourcc code for this format, 0 if not applicable
* @color: the corresponding fimc_color_fmt
- * @depth: per plane driver's private 'number of bits per pixel'
* @memplanes: number of physically non-contiguous data planes
* @colplanes: number of physically contiguous data planes
+ * @depth: per plane driver's private 'number of bits per pixel'
+ * @flags: flags indicating which operation mode format applies to
*/
struct fimc_fmt {
enum v4l2_mbus_pixelcode mbus_code;
@@ -171,7 +170,7 @@ struct fimc_dma_offset {
};
/**
- * struct fimc_effect - the configuration data for the "Arbitrary" image effect
+ * struct fimc_effect - color effect information
* @type: effect type
* @pat_cb: cr value when type is "arbitrary"
* @pat_cr: cr value when type is "arbitrary"
@@ -184,7 +183,6 @@ struct fimc_effect {
/**
* struct fimc_scaler - the configuration data for FIMC inetrnal scaler
- *
* @scaleup_h: flag indicating scaling up horizontally
* @scaleup_v: flag indicating scaling up vertically
* @copy_mode: flag indicating transparent DMA transfer (no scaling
@@ -220,7 +218,6 @@ struct fimc_scaler {
/**
* struct fimc_addr - the FIMC physical address set for DMA
- *
* @y: luminance plane physical address
* @cb: Cb plane physical address
* @cr: Cr plane physical address
@@ -234,6 +231,7 @@ struct fimc_addr {
/**
* struct fimc_vid_buffer - the driver's video buffer
* @vb: v4l videobuf buffer
+ * @list: linked list structure for buffer queue
* @paddr: precalculated physical address set
* @index: buffer index for the output DMA engine
*/
@@ -254,11 +252,10 @@ struct fimc_vid_buffer {
* @offs_v: image vertical pixel offset
* @width: image pixel width
* @height: image pixel weight
- * @paddr: image frame buffer physical addresses
- * @buf_cnt: number of buffers depending on a color format
* @payload: image size in bytes (w x h x bpp)
- * @color: color format
+ * @paddr: image frame buffer physical addresses
* @dma_offset: DMA offset in bytes
+ * @fmt: fimc color format pointer
*/
struct fimc_frame {
u32 f_width;
@@ -390,21 +387,22 @@ struct fimc_ctx;
/**
* struct fimc_dev - abstraction for FIMC entity
- *
* @slock: the spinlock protecting this data structure
* @lock: the mutex protecting this data structure
* @pdev: pointer to the FIMC platform device
* @pdata: pointer to the device platform data
+ * @variant: the IP variant information
* @id: FIMC device index (0..FIMC_MAX_DEVS)
* @num_clocks: the number of clocks managed by this device instance
- * @clock[]: the clocks required for FIMC operation
+ * @clock: clocks required for FIMC operation
* @regs: the mapped hardware registers
* @regs_res: the resource claimed for IO registers
- * @irq: interrupt number of the FIMC subdevice
- * @irq_queue:
+ * @irq: FIMC interrupt number
+ * @irq_queue: interrupt handler waitqueue
* @m2m: memory-to-memory V4L2 device information
* @vid_cap: camera capture device information
* @state: flags used to synchronize m2m and capture mode operation
+ * @alloc_ctx: videobuf2 memory allocator context
*/
struct fimc_dev {
spinlock_t slock;
@@ -427,8 +425,7 @@ struct fimc_dev {
/**
* fimc_ctx - the device context data
- *
- * @lock: mutex protecting this data structure
+ * @slock: spinlock protecting this data structure
* @s_frame: source frame properties
* @d_frame: destination frame properties
* @out_order_1p: output 1-plane YCBCR order
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index ff6c0e97563..d4ee24bf692 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -963,7 +963,7 @@ static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
* to work with other protocols.
*/
if (!ir->active) {
- timeout = jiffies + jiffies_to_msecs(15);
+ timeout = jiffies + msecs_to_jiffies(15);
mod_timer(&ir->timer, timeout);
ir->active = true;
}
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 9363ed91a4c..cfa9f7efe93 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -724,19 +724,15 @@ static inline int check_mode(struct tuner *t, enum v4l2_tuner_type mode)
}
/**
- * set_mode_freq - Switch tuner to other mode.
- * @client: struct i2c_client pointer
+ * set_mode - Switch tuner to other mode.
* @t: a pointer to the module's internal struct_tuner
* @mode: enum v4l2_type (radio or TV)
- * @freq: frequency to set (0 means to use the previous one)
*
* If tuner doesn't support the needed mode (radio or TV), prints a
* debug message and returns -EINVAL, changing its state to standby.
- * Otherwise, changes the state and sets frequency to the last value, if
- * the tuner can sleep or if it supports both Radio and TV.
+ * Otherwise, changes the mode and returns 0.
*/
-static int set_mode_freq(struct i2c_client *client, struct tuner *t,
- enum v4l2_tuner_type mode, unsigned int freq)
+static int set_mode(struct tuner *t, enum v4l2_tuner_type mode)
{
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
@@ -752,17 +748,27 @@ static int set_mode_freq(struct i2c_client *client, struct tuner *t,
t->mode = mode;
tuner_dbg("Changing to mode %d\n", mode);
}
+ return 0;
+}
+
+/**
+ * set_freq - Set the tuner to the desired frequency.
+ * @t: a pointer to the module's internal struct_tuner
+ * @freq: frequency to set (0 means to use the current frequency)
+ */
+static void set_freq(struct tuner *t, unsigned int freq)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
+
if (t->mode == V4L2_TUNER_RADIO) {
- if (freq)
- t->radio_freq = freq;
- set_radio_freq(client, t->radio_freq);
+ if (!freq)
+ freq = t->radio_freq;
+ set_radio_freq(client, freq);
} else {
- if (freq)
- t->tv_freq = freq;
- set_tv_freq(client, t->tv_freq);
+ if (!freq)
+ freq = t->tv_freq;
+ set_tv_freq(client, freq);
}
-
- return 0;
}
/*
@@ -817,7 +823,8 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
/**
* tuner_fixup_std - force a given video standard variant
*
- * @t: tuner internal struct
+ * @t: tuner internal struct
+ * @std: TV standard
*
* A few devices or drivers have problem to detect some standard variations.
* On other operational systems, the drivers generally have a per-country
@@ -827,57 +834,39 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
* to distinguish all video standard variations, a modprobe parameter can
* be used to force a video standard match.
*/
-static int tuner_fixup_std(struct tuner *t)
+static v4l2_std_id tuner_fixup_std(struct tuner *t, v4l2_std_id std)
{
- if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
+ if (pal[0] != '-' && (std & V4L2_STD_PAL) == V4L2_STD_PAL) {
switch (pal[0]) {
case '6':
- tuner_dbg("insmod fixup: PAL => PAL-60\n");
- t->std = V4L2_STD_PAL_60;
- break;
+ return V4L2_STD_PAL_60;
case 'b':
case 'B':
case 'g':
case 'G':
- tuner_dbg("insmod fixup: PAL => PAL-BG\n");
- t->std = V4L2_STD_PAL_BG;
- break;
+ return V4L2_STD_PAL_BG;
case 'i':
case 'I':
- tuner_dbg("insmod fixup: PAL => PAL-I\n");
- t->std = V4L2_STD_PAL_I;
- break;
+ return V4L2_STD_PAL_I;
case 'd':
case 'D':
case 'k':
case 'K':
- tuner_dbg("insmod fixup: PAL => PAL-DK\n");
- t->std = V4L2_STD_PAL_DK;
- break;
+ return V4L2_STD_PAL_DK;
case 'M':
case 'm':
- tuner_dbg("insmod fixup: PAL => PAL-M\n");
- t->std = V4L2_STD_PAL_M;
- break;
+ return V4L2_STD_PAL_M;
case 'N':
case 'n':
- if (pal[1] == 'c' || pal[1] == 'C') {
- tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
- t->std = V4L2_STD_PAL_Nc;
- } else {
- tuner_dbg("insmod fixup: PAL => PAL-N\n");
- t->std = V4L2_STD_PAL_N;
- }
- break;
- case '-':
- /* default parameter, do nothing */
- break;
+ if (pal[1] == 'c' || pal[1] == 'C')
+ return V4L2_STD_PAL_Nc;
+ return V4L2_STD_PAL_N;
default:
tuner_warn("pal= argument not recognised\n");
break;
}
}
- if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
+ if (secam[0] != '-' && (std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
switch (secam[0]) {
case 'b':
case 'B':
@@ -885,63 +874,42 @@ static int tuner_fixup_std(struct tuner *t)
case 'G':
case 'h':
case 'H':
- tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
- t->std = V4L2_STD_SECAM_B |
- V4L2_STD_SECAM_G |
- V4L2_STD_SECAM_H;
- break;
+ return V4L2_STD_SECAM_B |
+ V4L2_STD_SECAM_G |
+ V4L2_STD_SECAM_H;
case 'd':
case 'D':
case 'k':
case 'K':
- tuner_dbg("insmod fixup: SECAM => SECAM-DK\n");
- t->std = V4L2_STD_SECAM_DK;
- break;
+ return V4L2_STD_SECAM_DK;
case 'l':
case 'L':
- if ((secam[1] == 'C') || (secam[1] == 'c')) {
- tuner_dbg("insmod fixup: SECAM => SECAM-L'\n");
- t->std = V4L2_STD_SECAM_LC;
- } else {
- tuner_dbg("insmod fixup: SECAM => SECAM-L\n");
- t->std = V4L2_STD_SECAM_L;
- }
- break;
- case '-':
- /* default parameter, do nothing */
- break;
+ if ((secam[1] == 'C') || (secam[1] == 'c'))
+ return V4L2_STD_SECAM_LC;
+ return V4L2_STD_SECAM_L;
default:
tuner_warn("secam= argument not recognised\n");
break;
}
}
- if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
+ if (ntsc[0] != '-' && (std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
switch (ntsc[0]) {
case 'm':
case 'M':
- tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
- t->std = V4L2_STD_NTSC_M;
- break;
+ return V4L2_STD_NTSC_M;
case 'j':
case 'J':
- tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
- t->std = V4L2_STD_NTSC_M_JP;
- break;
+ return V4L2_STD_NTSC_M_JP;
case 'k':
case 'K':
- tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
- t->std = V4L2_STD_NTSC_M_KR;
- break;
- case '-':
- /* default parameter, do nothing */
- break;
+ return V4L2_STD_NTSC_M_KR;
default:
tuner_info("ntsc= argument not recognised\n");
break;
}
}
- return 0;
+ return std;
}
/*
@@ -1058,10 +1026,9 @@ static void tuner_status(struct dvb_frontend *fe)
static int tuner_s_radio(struct v4l2_subdev *sd)
{
struct tuner *t = to_tuner(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (set_mode_freq(client, t, V4L2_TUNER_RADIO, 0) == -EINVAL)
- return 0;
+ if (set_mode(t, V4L2_TUNER_RADIO) == 0)
+ set_freq(t, 0);
return 0;
}
@@ -1072,16 +1039,20 @@ static int tuner_s_radio(struct v4l2_subdev *sd)
/**
* tuner_s_power - controls the power state of the tuner
* @sd: pointer to struct v4l2_subdev
- * @on: a zero value puts the tuner to sleep
+ * @on: a zero value puts the tuner to sleep, non-zero wakes it up
*/
static int tuner_s_power(struct v4l2_subdev *sd, int on)
{
struct tuner *t = to_tuner(sd);
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
- /* FIXME: Why this function don't wake the tuner if on != 0 ? */
- if (on)
+ if (on) {
+ if (t->standby && set_mode(t, t->mode) == 0) {
+ tuner_dbg("Waking up tuner\n");
+ set_freq(t, 0);
+ }
return 0;
+ }
tuner_dbg("Putting tuner to sleep\n");
t->standby = true;
@@ -1093,28 +1064,36 @@ static int tuner_s_power(struct v4l2_subdev *sd, int on)
static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
struct tuner *t = to_tuner(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (set_mode_freq(client, t, V4L2_TUNER_ANALOG_TV, 0) == -EINVAL)
+ if (set_mode(t, V4L2_TUNER_ANALOG_TV))
return 0;
- t->std = std;
- tuner_fixup_std(t);
-
+ t->std = tuner_fixup_std(t, std);
+ if (t->std != std)
+ tuner_dbg("Fixup standard %llx to %llx\n", std, t->std);
+ set_freq(t, 0);
return 0;
}
static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
{
struct tuner *t = to_tuner(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (set_mode_freq(client, t, f->type, f->frequency) == -EINVAL)
- return 0;
+ if (set_mode(t, f->type) == 0)
+ set_freq(t, f->frequency);
return 0;
}
+/**
+ * tuner_g_frequency - Get the tuned frequency for the tuner
+ * @sd: pointer to struct v4l2_subdev
+ * @f: pointer to struct v4l2_frequency
+ *
+ * At return, the structure f will be filled with tuner frequency
+ * if the tuner matches the f->type.
+ * Note: f->type should be initialized before calling it.
+ * This is done by either video_ioctl2 or by the bridge driver.
+ */
static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
{
struct tuner *t = to_tuner(sd);
@@ -1122,8 +1101,7 @@ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
if (check_mode(t, f->type) == -EINVAL)
return 0;
- f->type = t->mode;
- if (fe_tuner_ops->get_frequency && !t->standby) {
+ if (f->type == t->mode && fe_tuner_ops->get_frequency && !t->standby) {
u32 abs_freq;
fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
@@ -1131,12 +1109,22 @@ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
DIV_ROUND_CLOSEST(abs_freq * 2, 125) :
DIV_ROUND_CLOSEST(abs_freq, 62500);
} else {
- f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
+ f->frequency = (V4L2_TUNER_RADIO == f->type) ?
t->radio_freq : t->tv_freq;
}
return 0;
}
+/**
+ * tuner_g_tuner - Fill in tuner information
+ * @sd: pointer to struct v4l2_subdev
+ * @vt: pointer to struct v4l2_tuner
+ *
+ * At return, the structure vt will be filled with tuner information
+ * if the tuner matches vt->type.
+ * Note: vt->type should be initialized before calling it.
+ * This is done by either video_ioctl2 or by the bridge driver.
+ */
static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
{
struct tuner *t = to_tuner(sd);
@@ -1145,48 +1133,58 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
if (check_mode(t, vt->type) == -EINVAL)
return 0;
- vt->type = t->mode;
- if (analog_ops->get_afc)
+ if (vt->type == t->mode && analog_ops->get_afc)
vt->afc = analog_ops->get_afc(&t->fe);
- if (t->mode == V4L2_TUNER_ANALOG_TV)
+ if (vt->type == V4L2_TUNER_ANALOG_TV)
vt->capability |= V4L2_TUNER_CAP_NORM;
- if (t->mode != V4L2_TUNER_RADIO) {
+ if (vt->type != V4L2_TUNER_RADIO) {
vt->rangelow = tv_range[0] * 16;
vt->rangehigh = tv_range[1] * 16;
return 0;
}
/* radio mode */
- vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- if (fe_tuner_ops->get_status) {
- u32 tuner_status;
-
- fe_tuner_ops->get_status(&t->fe, &tuner_status);
- vt->rxsubchans =
- (tuner_status & TUNER_STATUS_STEREO) ?
- V4L2_TUNER_SUB_STEREO :
- V4L2_TUNER_SUB_MONO;
+ if (vt->type == t->mode) {
+ vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ if (fe_tuner_ops->get_status) {
+ u32 tuner_status;
+
+ fe_tuner_ops->get_status(&t->fe, &tuner_status);
+ vt->rxsubchans =
+ (tuner_status & TUNER_STATUS_STEREO) ?
+ V4L2_TUNER_SUB_STEREO :
+ V4L2_TUNER_SUB_MONO;
+ }
+ if (analog_ops->has_signal)
+ vt->signal = analog_ops->has_signal(&t->fe);
+ vt->audmode = t->audmode;
}
- if (analog_ops->has_signal)
- vt->signal = analog_ops->has_signal(&t->fe);
vt->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
- vt->audmode = t->audmode;
vt->rangelow = radio_range[0] * 16000;
vt->rangehigh = radio_range[1] * 16000;
return 0;
}
+/**
+ * tuner_s_tuner - Set the tuner's audio mode
+ * @sd: pointer to struct v4l2_subdev
+ * @vt: pointer to struct v4l2_tuner
+ *
+ * Sets the audio mode if the tuner matches vt->type.
+ * Note: vt->type should be initialized before calling it.
+ * This is done by either video_ioctl2 or by the bridge driver.
+ */
static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
{
struct tuner *t = to_tuner(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (set_mode_freq(client, t, vt->type, 0) == -EINVAL)
+ if (set_mode(t, vt->type))
return 0;
if (t->mode == V4L2_TUNER_RADIO)
t->audmode = vt->audmode;
+ set_freq(t, 0);
return 0;
}
@@ -1221,7 +1219,8 @@ static int tuner_resume(struct i2c_client *c)
tuner_dbg("resume\n");
if (!t->standby)
- set_mode_freq(c, t, t->type, 0);
+ if (set_mode(t, t->mode) == 0)
+ set_freq(t, 0);
return 0;
}
diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/video/uvc/uvc_entity.c
index c3ab0c813be..48fea373c25 100644
--- a/drivers/media/video/uvc/uvc_entity.c
+++ b/drivers/media/video/uvc/uvc_entity.c
@@ -27,14 +27,20 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain,
struct uvc_entity *entity)
{
const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
- struct uvc_entity *remote;
+ struct media_entity *sink;
unsigned int i;
- u8 remote_pad;
- int ret = 0;
+ int ret;
+
+ sink = (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING)
+ ? (entity->vdev ? &entity->vdev->entity : NULL)
+ : &entity->subdev.entity;
+ if (sink == NULL)
+ return 0;
for (i = 0; i < entity->num_pads; ++i) {
struct media_entity *source;
- struct media_entity *sink;
+ struct uvc_entity *remote;
+ u8 remote_pad;
if (!(entity->pads[i].flags & MEDIA_PAD_FL_SINK))
continue;
@@ -43,10 +49,11 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain,
if (remote == NULL)
return -EINVAL;
- source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING)
- ? &remote->vdev->entity : &remote->subdev.entity;
- sink = (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING)
- ? &entity->vdev->entity : &entity->subdev.entity;
+ source = (UVC_ENTITY_TYPE(remote) != UVC_TT_STREAMING)
+ ? (remote->vdev ? &remote->vdev->entity : NULL)
+ : &remote->subdev.entity;
+ if (source == NULL)
+ continue;
remote_pad = remote->num_pads - 1;
ret = media_entity_create_link(source, remote_pad,
@@ -55,11 +62,10 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain,
return ret;
}
- if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING)
- ret = v4l2_device_register_subdev(&chain->dev->vdev,
- &entity->subdev);
+ if (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING)
+ return 0;
- return ret;
+ return v4l2_device_register_subdev(&chain->dev->vdev, &entity->subdev);
}
static struct v4l2_subdev_ops uvc_subdev_ops = {
@@ -84,9 +90,11 @@ static int uvc_mc_init_entity(struct uvc_entity *entity)
ret = media_entity_init(&entity->subdev.entity,
entity->num_pads, entity->pads, 0);
- } else
+ } else if (entity->vdev != NULL) {
ret = media_entity_init(&entity->vdev->entity,
entity->num_pads, entity->pads, 0);
+ } else
+ ret = 0;
return ret;
}
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index 109a06384a8..f90ce9fce53 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -104,6 +104,8 @@ static int __uvc_free_buffers(struct uvc_video_queue *queue)
}
if (queue->count) {
+ uvc_queue_cancel(queue, 0);
+ INIT_LIST_HEAD(&queue->mainqueue);
vfree(queue->mem);
queue->count = 0;
}
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index fc766b9f24c..49994793cc7 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -1255,8 +1255,10 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable)
/* Commit the streaming parameters. */
ret = uvc_commit_video(stream, &stream->ctrl);
- if (ret < 0)
+ if (ret < 0) {
+ uvc_queue_enable(&stream->queue, 0);
return ret;
+ }
return uvc_init_video(stream, GFP_KERNEL);
}
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 19d5ae29378..06f14008b34 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -167,6 +167,12 @@ static void v4l2_device_release(struct device *cd)
mutex_unlock(&videodev_lock);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
+ vdev->vfl_type != VFL_TYPE_SUBDEV)
+ media_device_unregister_entity(&vdev->entity);
+#endif
+
/* Release video_device and perform other
cleanups as needed. */
vdev->release(vdev);
@@ -389,9 +395,6 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
static int v4l2_open(struct inode *inode, struct file *filp)
{
struct video_device *vdev;
-#if defined(CONFIG_MEDIA_CONTROLLER)
- struct media_entity *entity = NULL;
-#endif
int ret = 0;
/* Check if the video device is available */
@@ -405,17 +408,6 @@ static int v4l2_open(struct inode *inode, struct file *filp)
/* and increase the device refcount */
video_get(vdev);
mutex_unlock(&videodev_lock);
-#if defined(CONFIG_MEDIA_CONTROLLER)
- if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
- vdev->vfl_type != VFL_TYPE_SUBDEV) {
- entity = media_entity_get(&vdev->entity);
- if (!entity) {
- ret = -EBUSY;
- video_put(vdev);
- return ret;
- }
- }
-#endif
if (vdev->fops->open) {
if (vdev->lock && mutex_lock_interruptible(vdev->lock)) {
ret = -ERESTARTSYS;
@@ -431,14 +423,8 @@ static int v4l2_open(struct inode *inode, struct file *filp)
err:
/* decrease the refcount in case of an error */
- if (ret) {
-#if defined(CONFIG_MEDIA_CONTROLLER)
- if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
- vdev->vfl_type != VFL_TYPE_SUBDEV)
- media_entity_put(entity);
-#endif
+ if (ret)
video_put(vdev);
- }
return ret;
}
@@ -455,11 +441,6 @@ static int v4l2_release(struct inode *inode, struct file *filp)
if (vdev->lock)
mutex_unlock(vdev->lock);
}
-#if defined(CONFIG_MEDIA_CONTROLLER)
- if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
- vdev->vfl_type != VFL_TYPE_SUBDEV)
- media_entity_put(&vdev->entity);
-#endif
/* decrease the refcount unconditionally since the release()
return value is ignored. */
video_put(vdev);
@@ -754,12 +735,6 @@ void video_unregister_device(struct video_device *vdev)
if (!vdev || !video_is_registered(vdev))
return;
-#if defined(CONFIG_MEDIA_CONTROLLER)
- if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
- vdev->vfl_type != VFL_TYPE_SUBDEV)
- media_device_unregister_entity(&vdev->entity);
-#endif
-
mutex_lock(&videodev_lock);
/* This must be in a critical section to prevent a race with v4l2_open.
* Once this bit has been cleared video_get may never be called again.
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 506edcc2dde..69e8c6ffcc4 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -1822,6 +1822,8 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_g_tuner)
break;
+ p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
+ V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
ret = ops->vidioc_g_tuner(file, fh, p);
if (!ret)
dbgarg(cmd, "index=%d, name=%s, type=%d, "
@@ -1840,6 +1842,8 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_s_tuner)
break;
+ p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
+ V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
dbgarg(cmd, "index=%d, name=%s, type=%d, "
"capability=0x%x, rangelow=%d, "
"rangehigh=%d, signal=%d, afc=%d, "
@@ -1858,6 +1862,8 @@ static long __video_do_ioctl(struct file *file,
if (!ops->vidioc_g_frequency)
break;
+ p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
+ V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
ret = ops->vidioc_g_frequency(file, fh, p);
if (!ret)
dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
@@ -1940,13 +1946,19 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_S_HW_FREQ_SEEK:
{
struct v4l2_hw_freq_seek *p = arg;
+ enum v4l2_tuner_type type;
if (!ops->vidioc_s_hw_freq_seek)
break;
+ type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
+ V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
dbgarg(cmd,
- "tuner=%d, type=%d, seek_upward=%d, wrap_around=%d\n",
- p->tuner, p->type, p->seek_upward, p->wrap_around);
- ret = ops->vidioc_s_hw_freq_seek(file, fh, p);
+ "tuner=%u, type=%u, seek_upward=%u, wrap_around=%u, spacing=%u\n",
+ p->tuner, p->type, p->seek_upward, p->wrap_around, p->spacing);
+ if (p->type != type)
+ ret = -EINVAL;
+ else
+ ret = ops->vidioc_s_hw_freq_seek(file, fh, p);
break;
}
case VIDIOC_ENUM_FRAMESIZES:
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index 6ba1461d51e..3015e600094 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -492,13 +492,6 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
return -EINVAL;
}
- /*
- * If the same number of buffers and memory access method is requested
- * then return immediately.
- */
- if (q->memory == req->memory && req->count == q->num_buffers)
- return 0;
-
if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) {
/*
* We already have buffers allocated, so first check if they
@@ -539,9 +532,9 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
/* Finally, allocate buffers and video memory */
ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes,
plane_sizes);
- if (ret < 0) {
- dprintk(1, "Memory allocation failed with error: %d\n", ret);
- return ret;
+ if (ret == 0) {
+ dprintk(1, "Memory allocation failed\n");
+ return -ENOMEM;
}
/*
@@ -1196,6 +1189,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
* has not already dequeued before initiating cancel.
*/
INIT_LIST_HEAD(&q->done_list);
+ atomic_set(&q->queued_count, 0);
wake_up_all(&q->done_wq);
/*
diff --git a/drivers/media/video/videobuf2-dma-sg.c b/drivers/media/video/videobuf2-dma-sg.c
index b2d9485aac7..10a20d9509d 100644
--- a/drivers/media/video/videobuf2-dma-sg.c
+++ b/drivers/media/video/videobuf2-dma-sg.c
@@ -62,7 +62,7 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size)
goto fail_pages_array_alloc;
for (i = 0; i < buf->sg_desc.num_pages; ++i) {
- buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN);
if (NULL == buf->pages[i])
goto fail_pages_alloc;
sg_set_page(&buf->sg_desc.sglist[i],
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 0f09c057e79..6ca938a6bf9 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -728,6 +728,9 @@ config MFD_TPS65910
if you say yes here you get support for the TPS65910 series of
Power Management chips.
+config TPS65911_COMPARATOR
+ tristate
+
endif # MFD_SUPPORT
menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index efe3cc33ed9..d7d47d2a4c7 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -94,3 +94,4 @@ obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o
obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
obj-$(CONFIG_MFD_TPS65910) += tps65910.o tps65910-irq.o
+obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index c27fd1fc3b8..c71ae09430c 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -619,6 +619,7 @@ static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk)
/* MFD cells (SPI, PWM, LED, DS1WM, MMC) */
static struct ds1wm_driver_data ds1wm_pdata = {
.active_high = 1,
+ .reset_recover_delay = 1,
};
static struct resource ds1wm_resources[] = {
diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c
index 2808bd125d1..04c7093d649 100644
--- a/drivers/mfd/htc-pasic3.c
+++ b/drivers/mfd/htc-pasic3.c
@@ -99,6 +99,7 @@ static int ds1wm_disable(struct platform_device *pdev)
static struct ds1wm_driver_data ds1wm_pdata = {
.active_high = 0,
+ .reset_recover_delay = 1,
};
static struct resource ds1wm_resources[] __initdata = {
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 855219526cc..1717144fe7f 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -26,7 +26,6 @@
#include <linux/spinlock.h>
#include <linux/gpio.h>
#include <plat/usb.h>
-#include <linux/pm_runtime.h>
#define USBHS_DRIVER_NAME "usbhs-omap"
#define OMAP_EHCI_DEVICE "ehci-omap"
@@ -147,6 +146,9 @@
struct usbhs_hcd_omap {
+ struct clk *usbhost_ick;
+ struct clk *usbhost_hs_fck;
+ struct clk *usbhost_fs_fck;
struct clk *xclk60mhsp1_ck;
struct clk *xclk60mhsp2_ck;
struct clk *utmi_p1_fck;
@@ -156,6 +158,8 @@ struct usbhs_hcd_omap {
struct clk *usbhost_p2_fck;
struct clk *usbtll_p2_fck;
struct clk *init_60m_fclk;
+ struct clk *usbtll_fck;
+ struct clk *usbtll_ick;
void __iomem *uhh_base;
void __iomem *tll_base;
@@ -349,13 +353,46 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev)
omap->platdata.ehci_data = pdata->ehci_data;
omap->platdata.ohci_data = pdata->ohci_data;
- pm_runtime_enable(&pdev->dev);
+ omap->usbhost_ick = clk_get(dev, "usbhost_ick");
+ if (IS_ERR(omap->usbhost_ick)) {
+ ret = PTR_ERR(omap->usbhost_ick);
+ dev_err(dev, "usbhost_ick failed error:%d\n", ret);
+ goto err_end;
+ }
+
+ omap->usbhost_hs_fck = clk_get(dev, "hs_fck");
+ if (IS_ERR(omap->usbhost_hs_fck)) {
+ ret = PTR_ERR(omap->usbhost_hs_fck);
+ dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret);
+ goto err_usbhost_ick;
+ }
+
+ omap->usbhost_fs_fck = clk_get(dev, "fs_fck");
+ if (IS_ERR(omap->usbhost_fs_fck)) {
+ ret = PTR_ERR(omap->usbhost_fs_fck);
+ dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret);
+ goto err_usbhost_hs_fck;
+ }
+
+ omap->usbtll_fck = clk_get(dev, "usbtll_fck");
+ if (IS_ERR(omap->usbtll_fck)) {
+ ret = PTR_ERR(omap->usbtll_fck);
+ dev_err(dev, "usbtll_fck failed error:%d\n", ret);
+ goto err_usbhost_fs_fck;
+ }
+
+ omap->usbtll_ick = clk_get(dev, "usbtll_ick");
+ if (IS_ERR(omap->usbtll_ick)) {
+ ret = PTR_ERR(omap->usbtll_ick);
+ dev_err(dev, "usbtll_ick failed error:%d\n", ret);
+ goto err_usbtll_fck;
+ }
omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
if (IS_ERR(omap->utmi_p1_fck)) {
ret = PTR_ERR(omap->utmi_p1_fck);
dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
- goto err_end;
+ goto err_usbtll_ick;
}
omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
@@ -485,8 +522,22 @@ err_xclk60mhsp1_ck:
err_utmi_p1_fck:
clk_put(omap->utmi_p1_fck);
+err_usbtll_ick:
+ clk_put(omap->usbtll_ick);
+
+err_usbtll_fck:
+ clk_put(omap->usbtll_fck);
+
+err_usbhost_fs_fck:
+ clk_put(omap->usbhost_fs_fck);
+
+err_usbhost_hs_fck:
+ clk_put(omap->usbhost_hs_fck);
+
+err_usbhost_ick:
+ clk_put(omap->usbhost_ick);
+
err_end:
- pm_runtime_disable(&pdev->dev);
kfree(omap);
end_probe:
@@ -520,7 +571,11 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev)
clk_put(omap->utmi_p2_fck);
clk_put(omap->xclk60mhsp1_ck);
clk_put(omap->utmi_p1_fck);
- pm_runtime_disable(&pdev->dev);
+ clk_put(omap->usbtll_ick);
+ clk_put(omap->usbtll_fck);
+ clk_put(omap->usbhost_fs_fck);
+ clk_put(omap->usbhost_hs_fck);
+ clk_put(omap->usbhost_ick);
kfree(omap);
return 0;
@@ -640,6 +695,7 @@ static int usbhs_enable(struct device *dev)
struct usbhs_omap_platform_data *pdata = &omap->platdata;
unsigned long flags = 0;
int ret = 0;
+ unsigned long timeout;
unsigned reg;
dev_dbg(dev, "starting TI HSUSB Controller\n");
@@ -652,7 +708,11 @@ static int usbhs_enable(struct device *dev)
if (omap->count > 0)
goto end_count;
- pm_runtime_get_sync(dev);
+ clk_enable(omap->usbhost_ick);
+ clk_enable(omap->usbhost_hs_fck);
+ clk_enable(omap->usbhost_fs_fck);
+ clk_enable(omap->usbtll_fck);
+ clk_enable(omap->usbtll_ick);
if (pdata->ehci_data->phy_reset) {
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) {
@@ -676,6 +736,50 @@ static int usbhs_enable(struct device *dev)
omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
+ /* perform TLL soft reset, and wait until reset is complete */
+ usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
+ OMAP_USBTLL_SYSCONFIG_SOFTRESET);
+
+ /* Wait for TLL reset to complete */
+ timeout = jiffies + msecs_to_jiffies(1000);
+ while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
+ & OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
+ cpu_relax();
+
+ if (time_after(jiffies, timeout)) {
+ dev_dbg(dev, "operation timed out\n");
+ ret = -EINVAL;
+ goto err_tll;
+ }
+ }
+
+ dev_dbg(dev, "TLL RESET DONE\n");
+
+ /* (1<<3) = no idle mode only for initial debugging */
+ usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
+ OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
+ OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
+ OMAP_USBTLL_SYSCONFIG_AUTOIDLE);
+
+ /* Put UHH in NoIdle/NoStandby mode */
+ reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG);
+ if (is_omap_usbhs_rev1(omap)) {
+ reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
+ | OMAP_UHH_SYSCONFIG_SIDLEMODE
+ | OMAP_UHH_SYSCONFIG_CACTIVITY
+ | OMAP_UHH_SYSCONFIG_MIDLEMODE);
+ reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;
+
+
+ } else if (is_omap_usbhs_rev2(omap)) {
+ reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR;
+ reg |= OMAP4_UHH_SYSCONFIG_NOIDLE;
+ reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR;
+ reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY;
+ }
+
+ usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
+
reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
/* setup ULPI bypass and burst configurations */
reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
@@ -815,8 +919,6 @@ end_count:
return 0;
err_tll:
- pm_runtime_put_sync(dev);
- spin_unlock_irqrestore(&omap->lock, flags);
if (pdata->ehci_data->phy_reset) {
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
gpio_free(pdata->ehci_data->reset_gpio_port[0]);
@@ -824,6 +926,13 @@ err_tll:
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
gpio_free(pdata->ehci_data->reset_gpio_port[1]);
}
+
+ clk_disable(omap->usbtll_ick);
+ clk_disable(omap->usbtll_fck);
+ clk_disable(omap->usbhost_fs_fck);
+ clk_disable(omap->usbhost_hs_fck);
+ clk_disable(omap->usbhost_ick);
+ spin_unlock_irqrestore(&omap->lock, flags);
return ret;
}
@@ -896,7 +1005,11 @@ static void usbhs_disable(struct device *dev)
clk_disable(omap->utmi_p1_fck);
}
- pm_runtime_put_sync(dev);
+ clk_disable(omap->usbtll_ick);
+ clk_disable(omap->usbtll_fck);
+ clk_disable(omap->usbhost_fs_fck);
+ clk_disable(omap->usbhost_hs_fck);
+ clk_disable(omap->usbhost_ick);
/* The gpio_free migh sleep; so unlock the spinlock */
spin_unlock_irqrestore(&omap->lock, flags);
diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c
index 3d2dc56a3d4..283ac675975 100644
--- a/drivers/mfd/tps65911-comparator.c
+++ b/drivers/mfd/tps65911-comparator.c
@@ -125,7 +125,7 @@ static DEVICE_ATTR(comp2_threshold, S_IRUGO, comp_threshold_show, NULL);
static __devinit int tps65911_comparator_probe(struct platform_device *pdev)
{
struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
- struct tps65910_platform_data *pdata = dev_get_platdata(tps65910->dev);
+ struct tps65910_board *pdata = dev_get_platdata(tps65910->dev);
int ret;
ret = comp_threshold_set(tps65910, COMP1, pdata->vmbch_threshold);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 2a7e43bc796..aa7d1d79b8c 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -247,12 +247,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
return 0;
/* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
+ card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE];
if (card->csd.structure == 3) {
- int ext_csd_struct = ext_csd[EXT_CSD_STRUCTURE];
- if (ext_csd_struct > 2) {
+ if (card->ext_csd.raw_ext_csd_structure > 2) {
printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
"version %d\n", mmc_hostname(card->host),
- ext_csd_struct);
+ card->ext_csd.raw_ext_csd_structure);
err = -EINVAL;
goto out;
}
@@ -266,6 +266,10 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
goto out;
}
+ card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0];
+ card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1];
+ card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2];
+ card->ext_csd.raw_sectors[3] = ext_csd[EXT_CSD_SEC_CNT + 3];
if (card->ext_csd.rev >= 2) {
card->ext_csd.sectors =
ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
@@ -277,7 +281,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512)
mmc_card_set_blockaddr(card);
}
-
+ card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
EXT_CSD_CARD_TYPE_26:
@@ -307,6 +311,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
mmc_hostname(card->host));
}
+ card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT];
+ card->ext_csd.raw_erase_timeout_mult =
+ ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
+ card->ext_csd.raw_hc_erase_grp_size =
+ ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
if (card->ext_csd.rev >= 3) {
u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG];
@@ -334,6 +343,16 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
}
+ card->ext_csd.raw_hc_erase_gap_size =
+ ext_csd[EXT_CSD_PARTITION_ATTRIBUTE];
+ card->ext_csd.raw_sec_trim_mult =
+ ext_csd[EXT_CSD_SEC_TRIM_MULT];
+ card->ext_csd.raw_sec_erase_mult =
+ ext_csd[EXT_CSD_SEC_ERASE_MULT];
+ card->ext_csd.raw_sec_feature_support =
+ ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
+ card->ext_csd.raw_trim_mult =
+ ext_csd[EXT_CSD_TRIM_MULT];
if (card->ext_csd.rev >= 4) {
/*
* Enhanced area feature support -- check whether the eMMC
@@ -341,7 +360,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
* area offset and size to user by adding sysfs interface.
*/
if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
- (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
+ (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
u8 hc_erase_grp_sz =
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
u8 hc_wp_grp_sz =
@@ -401,17 +420,17 @@ static inline void mmc_free_ext_csd(u8 *ext_csd)
}
-static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,
- unsigned bus_width)
+static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
{
u8 *bw_ext_csd;
int err;
+ if (bus_width == MMC_BUS_WIDTH_1)
+ return 0;
+
err = mmc_get_ext_csd(card, &bw_ext_csd);
- if (err)
- return err;
- if ((ext_csd == NULL || bw_ext_csd == NULL)) {
+ if (err || bw_ext_csd == NULL) {
if (bus_width != MMC_BUS_WIDTH_1)
err = -EINVAL;
goto out;
@@ -421,35 +440,40 @@ static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,
goto out;
/* only compare read only fields */
- err = (!(ext_csd[EXT_CSD_PARTITION_SUPPORT] ==
+ err = (!(card->ext_csd.raw_partition_support ==
bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
- (ext_csd[EXT_CSD_ERASED_MEM_CONT] ==
+ (card->ext_csd.raw_erased_mem_count ==
bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
- (ext_csd[EXT_CSD_REV] ==
+ (card->ext_csd.rev ==
bw_ext_csd[EXT_CSD_REV]) &&
- (ext_csd[EXT_CSD_STRUCTURE] ==
+ (card->ext_csd.raw_ext_csd_structure ==
bw_ext_csd[EXT_CSD_STRUCTURE]) &&
- (ext_csd[EXT_CSD_CARD_TYPE] ==
+ (card->ext_csd.raw_card_type ==
bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
- (ext_csd[EXT_CSD_S_A_TIMEOUT] ==
+ (card->ext_csd.raw_s_a_timeout ==
bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
- (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] ==
+ (card->ext_csd.raw_hc_erase_gap_size ==
bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
- (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] ==
+ (card->ext_csd.raw_erase_timeout_mult ==
bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
- (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] ==
+ (card->ext_csd.raw_hc_erase_grp_size ==
bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
- (ext_csd[EXT_CSD_SEC_TRIM_MULT] ==
+ (card->ext_csd.raw_sec_trim_mult ==
bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
- (ext_csd[EXT_CSD_SEC_ERASE_MULT] ==
+ (card->ext_csd.raw_sec_erase_mult ==
bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
- (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] ==
+ (card->ext_csd.raw_sec_feature_support ==
bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
- (ext_csd[EXT_CSD_TRIM_MULT] ==
+ (card->ext_csd.raw_trim_mult ==
bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
- memcmp(&ext_csd[EXT_CSD_SEC_CNT],
- &bw_ext_csd[EXT_CSD_SEC_CNT],
- 4) != 0);
+ (card->ext_csd.raw_sectors[0] ==
+ bw_ext_csd[EXT_CSD_SEC_CNT + 0]) &&
+ (card->ext_csd.raw_sectors[1] ==
+ bw_ext_csd[EXT_CSD_SEC_CNT + 1]) &&
+ (card->ext_csd.raw_sectors[2] ==
+ bw_ext_csd[EXT_CSD_SEC_CNT + 2]) &&
+ (card->ext_csd.raw_sectors[3] ==
+ bw_ext_csd[EXT_CSD_SEC_CNT + 3]));
if (err)
err = -EINVAL;
@@ -770,7 +794,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
*/
if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
err = mmc_compare_ext_csds(card,
- ext_csd,
bus_width);
else
err = mmc_bus_test(card, bus_width);
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 7721de942c6..fe140724a02 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -582,6 +582,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
data->error = -EILSEQ;
} else if (status & MCI_DATATIMEOUT) {
data->error = -ETIMEDOUT;
+ } else if (status & MCI_STARTBITERR) {
+ data->error = -ECOMM;
} else if (status & MCI_TXUNDERRUN) {
data->error = -EIO;
} else if (status & MCI_RXOVERRUN) {
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index bb32e21c09d..2164e8c6476 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -86,6 +86,7 @@
#define MCI_CMDRESPEND (1 << 6)
#define MCI_CMDSENT (1 << 7)
#define MCI_DATAEND (1 << 8)
+#define MCI_STARTBITERR (1 << 9)
#define MCI_DATABLOCKEND (1 << 10)
#define MCI_CMDACTIVE (1 << 11)
#define MCI_TXACTIVE (1 << 12)
@@ -112,6 +113,7 @@
#define MCI_CMDRESPENDCLR (1 << 6)
#define MCI_CMDSENTCLR (1 << 7)
#define MCI_DATAENDCLR (1 << 8)
+#define MCI_STARTBITERRCLR (1 << 9)
#define MCI_DATABLOCKENDCLR (1 << 10)
/* Extended status bits for the ST Micro variants */
#define MCI_ST_SDIOITC (1 << 22)
@@ -127,6 +129,7 @@
#define MCI_CMDRESPENDMASK (1 << 6)
#define MCI_CMDSENTMASK (1 << 7)
#define MCI_DATAENDMASK (1 << 8)
+#define MCI_STARTBITERRMASK (1 << 9)
#define MCI_DATABLOCKENDMASK (1 << 10)
#define MCI_CMDACTIVEMASK (1 << 11)
#define MCI_TXACTIVEMASK (1 << 12)
@@ -150,7 +153,7 @@
#define MCI_IRQENABLE \
(MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \
MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \
- MCI_CMDRESPENDMASK|MCI_CMDSENTMASK)
+ MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_STARTBITERRMASK)
/* These interrupts are directed to IRQ1 when two IRQ lines are available */
#define MCI_IRQ1MASK \
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 8f8b65af9ed..60f46bc2bf6 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -140,7 +140,7 @@ MODULE_LICENSE("GPL");
module_param(mtu, int, 0);
module_param(debug, int, 0);
module_param(rx_copybreak, int, 0);
-module_param(dspcfg_workaround, int, 1);
+module_param(dspcfg_workaround, int, 0);
module_param_array(options, int, NULL, 0);
module_param_array(full_duplex, int, NULL, 0);
MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)");
@@ -2028,8 +2028,8 @@ static void drain_rx(struct net_device *dev)
np->rx_ring[i].cmd_status = 0;
np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
if (np->rx_skbuff[i]) {
- pci_unmap_single(np->pci_dev,
- np->rx_dma[i], buflen,
+ pci_unmap_single(np->pci_dev, np->rx_dma[i],
+ buflen + NATSEMI_PADDING,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(np->rx_skbuff[i]);
}
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 3da168a859c..ad35c210b83 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -139,6 +139,8 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
.tpauser = 1,
.hw_swap = 1,
.no_ade = 1,
+ .rpadir = 1,
+ .rpadir_value = 2 << 16,
};
#define SH_GIGA_ETH_BASE 0xfee00000
@@ -1185,8 +1187,8 @@ static void sh_eth_adjust_link(struct net_device *ndev)
mdp->cd->set_rate(ndev);
}
if (mdp->link == PHY_DOWN) {
- sh_eth_write(ndev, (sh_eth_read(ndev, ECMR) & ~ECMR_TXF)
- | ECMR_DM, ECMR);
+ sh_eth_write(ndev,
+ (sh_eth_read(ndev, ECMR) & ~ECMR_TXF), ECMR);
new_state = 1;
mdp->link = phydev->link;
}
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 11c9ab3b1e1..8befe697bd7 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -182,11 +182,11 @@ static int sl_alloc_bufs(struct slip *sl, int mtu)
#ifdef SL_INCLUDE_CSLIP
cbuff = xchg(&sl->cbuff, cbuff);
slcomp = xchg(&sl->slcomp, slcomp);
+#endif
#ifdef CONFIG_SLIP_MODE_SLIP6
sl->xdata = 0;
sl->xbits = 0;
#endif
-#endif
spin_unlock_bh(&sl->lock);
err = 0;
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 387ca43f26f..304fe78ff60 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -2421,10 +2421,8 @@ static void hso_free_net_device(struct hso_device *hso_dev)
remove_net_device(hso_net->parent);
- if (hso_net->net) {
+ if (hso_net->net)
unregister_netdev(hso_net->net);
- free_netdev(hso_net->net);
- }
/* start freeing */
for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) {
@@ -2436,6 +2434,9 @@ static void hso_free_net_device(struct hso_device *hso_dev)
kfree(hso_net->mux_bulk_tx_buf);
hso_net->mux_bulk_tx_buf = NULL;
+ if (hso_net->net)
+ free_netdev(hso_net->net);
+
kfree(hso_dev);
}
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index fabcded7c6a..009277e1084 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -2897,6 +2897,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
else
#endif
num_rx_queues = 1;
+ num_rx_queues = rounddown_pow_of_two(num_rx_queues);
if (enable_mq)
num_tx_queues = min(VMXNET3_DEVICE_MAX_TX_QUEUES,
@@ -2904,6 +2905,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
else
num_tx_queues = 1;
+ num_tx_queues = rounddown_pow_of_two(num_tx_queues);
netdev = alloc_etherdev_mq(sizeof(struct vmxnet3_adapter),
max(num_tx_queues, num_rx_queues));
printk(KERN_INFO "# of Tx queues : %d, # of Rx queues : %d\n",
@@ -3088,6 +3090,7 @@ vmxnet3_remove_device(struct pci_dev *pdev)
else
#endif
num_rx_queues = 1;
+ num_rx_queues = rounddown_pow_of_two(num_rx_queues);
cancel_work_sync(&adapter->work);
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index a9cb3fabb17..b18eac1dcca 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -56,6 +56,7 @@
#include <linux/if_vlan.h>
#include <linux/if_arp.h>
#include <linux/inetdevice.h>
+#include <linux/log2.h>
#include "vmxnet3_defs.h"
@@ -69,10 +70,10 @@
/*
* Version numbers
*/
-#define VMXNET3_DRIVER_VERSION_STRING "1.1.14.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING "1.1.18.0-k"
/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM 0x01010E00
+#define VMXNET3_DRIVER_VERSION_NUM 0x01011200
#if defined(CONFIG_PCI_MSI)
/* RSS only makes sense if MSI-X is supported. */
diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c
index 62172d58572..f82383b3ed3 100644
--- a/drivers/net/wireless/ath/ath5k/desc.c
+++ b/drivers/net/wireless/ath/ath5k/desc.c
@@ -107,10 +107,13 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
case AR5K_PKT_TYPE_BEACON:
case AR5K_PKT_TYPE_PROBE_RESP:
frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY;
+ break;
case AR5K_PKT_TYPE_PIFS:
frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS;
+ break;
default:
frame_type = type;
+ break;
}
tx_ctl->tx_control_0 |=
diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c
index 296c316a834..f2c0c236392 100644
--- a/drivers/net/wireless/ath/ath5k/pci.c
+++ b/drivers/net/wireless/ath/ath5k/pci.c
@@ -297,7 +297,9 @@ ath5k_pci_remove(struct pci_dev *pdev)
#ifdef CONFIG_PM_SLEEP
static int ath5k_pci_suspend(struct device *dev)
{
- struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev));
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+ struct ath5k_softc *sc = hw->priv;
ath5k_led_off(sc);
return 0;
@@ -306,7 +308,8 @@ static int ath5k_pci_suspend(struct device *dev)
static int ath5k_pci_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
- struct ath5k_softc *sc = pci_get_drvdata(pdev);
+ struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+ struct ath5k_softc *sc = hw->priv;
/*
* Suspend/Resume resets the PCI configuration space, so we have to
diff --git a/drivers/net/wireless/ath/ath5k/sysfs.c b/drivers/net/wireless/ath/ath5k/sysfs.c
index 929c68cdf8a..a073cdce1f1 100644
--- a/drivers/net/wireless/ath/ath5k/sysfs.c
+++ b/drivers/net/wireless/ath/ath5k/sysfs.c
@@ -10,7 +10,8 @@ static ssize_t ath5k_attr_show_##name(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
- struct ath5k_softc *sc = dev_get_drvdata(dev); \
+ struct ieee80211_hw *hw = dev_get_drvdata(dev); \
+ struct ath5k_softc *sc = hw->priv; \
return snprintf(buf, PAGE_SIZE, "%d\n", get); \
} \
\
@@ -18,7 +19,8 @@ static ssize_t ath5k_attr_store_##name(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
- struct ath5k_softc *sc = dev_get_drvdata(dev); \
+ struct ieee80211_hw *hw = dev_get_drvdata(dev); \
+ struct ath5k_softc *sc = hw->priv; \
int val; \
\
val = (int)simple_strtoul(buf, NULL, 10); \
@@ -33,7 +35,8 @@ static ssize_t ath5k_attr_show_##name(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
- struct ath5k_softc *sc = dev_get_drvdata(dev); \
+ struct ieee80211_hw *hw = dev_get_drvdata(dev); \
+ struct ath5k_softc *sc = hw->priv; \
return snprintf(buf, PAGE_SIZE, "%d\n", get); \
} \
static DEVICE_ATTR(name, S_IRUGO, ath5k_attr_show_##name, NULL)
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 52dadfc3884..6eb58b16ab0 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -662,7 +662,8 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
* TODO - this could be improved to be dependent on the rate.
* The hardware can keep up at lower rates, but not higher rates
*/
- if (fi->keyix != ATH9K_TXKEYIX_INVALID)
+ if ((fi->keyix != ATH9K_TXKEYIX_INVALID) &&
+ !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA))
ndelim += ATH_AGGR_ENCRYPTDELIM;
/*
diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c
index 2fb53d06751..333b69ef2ae 100644
--- a/drivers/net/wireless/ath/carl9170/usb.c
+++ b/drivers/net/wireless/ath/carl9170/usb.c
@@ -112,6 +112,8 @@ static struct usb_device_id carl9170_usb_ids[] = {
{ USB_DEVICE(0x04bb, 0x093f) },
/* NEC WL300NU-G */
{ USB_DEVICE(0x0409, 0x0249) },
+ /* NEC WL300NU-AG */
+ { USB_DEVICE(0x0409, 0x02b4) },
/* AVM FRITZ!WLAN USB Stick N */
{ USB_DEVICE(0x057c, 0x8401) },
/* AVM FRITZ!WLAN USB Stick N 2.4 */
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index 092e342c19d..942f7a3969a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -298,6 +298,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
{RTL_USB_DEVICE(0x06f8, 0xe033, rtl92cu_hal_cfg)}, /*Hercules - Edimax*/
{RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/
{RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/
+ {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/
{RTL_USB_DEVICE(0x0Df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
{RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/
/* HP - Lite-On ,8188CUS Slim Combo */
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2c5b9b99127..692671b1166 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3483,6 +3483,8 @@ static int __init pci_setup(char *str)
pci_no_msi();
} else if (!strcmp(str, "noaer")) {
pci_no_aer();
+ } else if (!strncmp(str, "realloc", 7)) {
+ pci_realloc();
} else if (!strcmp(str, "nodomains")) {
pci_no_domains();
} else if (!strncmp(str, "cbiosize=", 9)) {
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 731e20265ac..3a39bf1f1e2 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -146,6 +146,8 @@ static inline void pci_no_msi(void) { }
static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
#endif
+extern void pci_realloc(void);
+
static inline int pci_no_d1d2(struct pci_dev *dev)
{
unsigned int parent_dstates = 0;
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 1e9e5a5b8c8..9995842e45b 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -47,6 +47,13 @@ struct resource_list_x {
(head)->next = NULL; \
} while (0)
+int pci_realloc_enable = 0;
+#define pci_realloc_enabled() pci_realloc_enable
+void pci_realloc(void)
+{
+ pci_realloc_enable = 1;
+}
+
/**
* add_to_list() - add a new resource tracker to the list
* @head: Head of the list
@@ -1025,6 +1032,7 @@ static int __init pci_get_max_depth(void)
return depth;
}
+
/*
* first try will not touch pci bridge res
* second and later try will clear small leaf bridge res
@@ -1068,6 +1076,13 @@ again:
/* any device complain? */
if (!head.next)
goto enable_and_dump;
+
+ /* don't realloc if asked to do so */
+ if (!pci_realloc_enabled()) {
+ free_list(resource_list_x, &head);
+ goto enable_and_dump;
+ }
+
failed_type = 0;
for (list = head.next; list;) {
failed_type |= list->flags;
diff --git a/drivers/pcmcia/pxa2xx_vpac270.c b/drivers/pcmcia/pxa2xx_vpac270.c
index 712baab3c83..e956f659089 100644
--- a/drivers/pcmcia/pxa2xx_vpac270.c
+++ b/drivers/pcmcia/pxa2xx_vpac270.c
@@ -76,10 +76,10 @@ static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
static void vpac270_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
{
if (skt->nr == 0)
- gpio_request_array(vpac270_pcmcia_gpios,
+ gpio_free_array(vpac270_pcmcia_gpios,
ARRAY_SIZE(vpac270_pcmcia_gpios));
else
- gpio_request_array(vpac270_cf_gpios,
+ gpio_free_array(vpac270_cf_gpios,
ARRAY_SIZE(vpac270_cf_gpios));
}
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 005417bd429..e1c4938b301 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -1156,9 +1156,9 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
struct wmid3_gds_input_param params = {
.function_num = 0x1,
.hotkey_number = 0x01,
- .devices = ACER_WMID3_GDS_WIRELESS &
- ACER_WMID3_GDS_THREEG &
- ACER_WMID3_GDS_WIMAX &
+ .devices = ACER_WMID3_GDS_WIRELESS |
+ ACER_WMID3_GDS_THREEG |
+ ACER_WMID3_GDS_WIMAX |
ACER_WMID3_GDS_BLUETOOTH,
};
struct acpi_buffer input = {
@@ -1445,6 +1445,8 @@ static void acer_wmi_notify(u32 value, void *context)
union acpi_object *obj;
struct event_return_value return_value;
acpi_status status;
+ u16 device_state;
+ const struct key_entry *key;
status = wmi_get_event_data(value, &response);
if (status != AE_OK) {
@@ -1472,23 +1474,32 @@ static void acer_wmi_notify(u32 value, void *context)
switch (return_value.function) {
case WMID_HOTKEY_EVENT:
- if (return_value.device_state) {
- u16 device_state = return_value.device_state;
- pr_debug("device state: 0x%x\n", device_state);
- if (has_cap(ACER_CAP_WIRELESS))
- rfkill_set_sw_state(wireless_rfkill,
- !(device_state & ACER_WMID3_GDS_WIRELESS));
- if (has_cap(ACER_CAP_BLUETOOTH))
- rfkill_set_sw_state(bluetooth_rfkill,
- !(device_state & ACER_WMID3_GDS_BLUETOOTH));
- if (has_cap(ACER_CAP_THREEG))
- rfkill_set_sw_state(threeg_rfkill,
- !(device_state & ACER_WMID3_GDS_THREEG));
- }
- if (!sparse_keymap_report_event(acer_wmi_input_dev,
- return_value.key_num, 1, true))
+ device_state = return_value.device_state;
+ pr_debug("device state: 0x%x\n", device_state);
+
+ key = sparse_keymap_entry_from_scancode(acer_wmi_input_dev,
+ return_value.key_num);
+ if (!key) {
pr_warn("Unknown key number - 0x%x\n",
return_value.key_num);
+ } else {
+ switch (key->keycode) {
+ case KEY_WLAN:
+ case KEY_BLUETOOTH:
+ if (has_cap(ACER_CAP_WIRELESS))
+ rfkill_set_sw_state(wireless_rfkill,
+ !(device_state & ACER_WMID3_GDS_WIRELESS));
+ if (has_cap(ACER_CAP_THREEG))
+ rfkill_set_sw_state(threeg_rfkill,
+ !(device_state & ACER_WMID3_GDS_THREEG));
+ if (has_cap(ACER_CAP_BLUETOOTH))
+ rfkill_set_sw_state(bluetooth_rfkill,
+ !(device_state & ACER_WMID3_GDS_BLUETOOTH));
+ break;
+ }
+ sparse_keymap_report_entry(acer_wmi_input_dev, key,
+ 1, true);
+ }
break;
default:
pr_warn("Unknown function number - %d - %d\n",
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 00460cb9587..3c7857c71a2 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -1025,6 +1025,7 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus)
return power;
memset(&props, 0, sizeof(struct backlight_properties));
+ props.type = BACKLIGHT_PLATFORM;
props.max_brightness = max;
bd = backlight_device_register(asus->driver->name,
&asus->platform_device->dev, asus,
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index 3f204fde1b0..8877b836d27 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -1030,8 +1030,10 @@ static int __devinit compal_probe(struct platform_device *pdev)
initialize_fan_control_data(data);
err = sysfs_create_group(&pdev->dev.kobj, &compal_attribute_group);
- if (err)
+ if (err) {
+ kfree(data);
return err;
+ }
data->hwmon_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->hwmon_dev)) {
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index d3841de6a8c..e39ab1d3ed8 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -292,12 +292,9 @@ static int dell_rfkill_set(void *data, bool blocked)
dell_send_request(buffer, 17, 11);
/* If the hardware switch controls this radio, and the hardware
- switch is disabled, don't allow changing the software state.
- If the hardware switch is reported as not supported, always
- fire the SMI to toggle the killswitch. */
+ switch is disabled, don't allow changing the software state */
if ((hwswitch_state & BIT(hwswitch_bit)) &&
- !(buffer->output[1] & BIT(16)) &&
- (buffer->output[1] & BIT(0))) {
+ !(buffer->output[1] & BIT(16))) {
ret = -EINVAL;
goto out;
}
@@ -403,23 +400,6 @@ static const struct file_operations dell_debugfs_fops = {
static void dell_update_rfkill(struct work_struct *ignored)
{
- int status;
-
- get_buffer();
- dell_send_request(buffer, 17, 11);
- status = buffer->output[1];
- release_buffer();
-
- /* if hardware rfkill is not supported, set it explicitly */
- if (!(status & BIT(0))) {
- if (wifi_rfkill)
- dell_rfkill_set((void *)1, !((status & BIT(17)) >> 17));
- if (bluetooth_rfkill)
- dell_rfkill_set((void *)2, !((status & BIT(18)) >> 18));
- if (wwan_rfkill)
- dell_rfkill_set((void *)3, !((status & BIT(19)) >> 19));
- }
-
if (wifi_rfkill)
dell_rfkill_query(wifi_rfkill, (void *)1);
if (bluetooth_rfkill)
@@ -560,11 +540,11 @@ static int dell_get_intensity(struct backlight_device *bd)
else
dell_send_request(buffer, 0, 1);
+ ret = buffer->output[1];
+
out:
release_buffer();
- if (ret)
- return ret;
- return buffer->output[1];
+ return ret;
}
static const struct backlight_ops dell_ops = {
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index f94017bcdd6..e2faa3cbb79 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -207,6 +207,7 @@ static int hp_wmi_perform_query(int query, int write, void *buffer,
};
struct acpi_buffer input = { sizeof(struct bios_args), &args };
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ u32 rc;
if (WARN_ON(insize > sizeof(args.data)))
return -EINVAL;
@@ -224,13 +225,13 @@ static int hp_wmi_perform_query(int query, int write, void *buffer,
}
bios_return = (struct bios_return *)obj->buffer.pointer;
+ rc = bios_return->return_code;
- if (bios_return->return_code) {
- if (bios_return->return_code != HPWMI_RET_UNKNOWN_CMDTYPE)
- pr_warn("query 0x%x returned error 0x%x\n",
- query, bios_return->return_code);
+ if (rc) {
+ if (rc != HPWMI_RET_UNKNOWN_CMDTYPE)
+ pr_warn("query 0x%x returned error 0x%x\n", query, rc);
kfree(obj);
- return bios_return->return_code;
+ return rc;
}
if (!outsize) {
diff --git a/drivers/platform/x86/intel_oaktrail.c b/drivers/platform/x86/intel_oaktrail.c
index e936364a609..7f88c7923fc 100644
--- a/drivers/platform/x86/intel_oaktrail.c
+++ b/drivers/platform/x86/intel_oaktrail.c
@@ -250,6 +250,7 @@ static int oaktrail_backlight_init(void)
struct backlight_properties props;
memset(&props, 0, sizeof(struct backlight_properties));
+ props.type = BACKLIGHT_PLATFORM;
props.max_brightness = OT_EC_BL_BRIGHTNESS_MAX;
bd = backlight_device_register(DRIVER_NAME,
&oaktrail_device->dev, NULL,
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 77f6e707a2a..26c5b117df2 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -184,6 +184,10 @@ enum tpacpi_hkey_event_t {
/* Misc bay events */
TP_HKEY_EV_OPTDRV_EJ = 0x3006, /* opt. drive tray ejected */
+ TP_HKEY_EV_HOTPLUG_DOCK = 0x4010, /* docked into hotplug dock
+ or port replicator */
+ TP_HKEY_EV_HOTPLUG_UNDOCK = 0x4011, /* undocked from hotplug
+ dock or port replicator */
/* User-interface events */
TP_HKEY_EV_LID_CLOSE = 0x5001, /* laptop lid closed */
@@ -194,6 +198,10 @@ enum tpacpi_hkey_event_t {
TP_HKEY_EV_PEN_REMOVED = 0x500c, /* tablet pen removed */
TP_HKEY_EV_BRGHT_CHANGED = 0x5010, /* backlight control event */
+ /* Key-related user-interface events */
+ TP_HKEY_EV_KEY_NUMLOCK = 0x6000, /* NumLock key pressed */
+ TP_HKEY_EV_KEY_FN = 0x6005, /* Fn key pressed? E420 */
+
/* Thermal events */
TP_HKEY_EV_ALARM_BAT_HOT = 0x6011, /* battery too hot */
TP_HKEY_EV_ALARM_BAT_XHOT = 0x6012, /* battery critically hot */
@@ -201,6 +209,10 @@ enum tpacpi_hkey_event_t {
TP_HKEY_EV_ALARM_SENSOR_XHOT = 0x6022, /* sensor critically hot */
TP_HKEY_EV_THM_TABLE_CHANGED = 0x6030, /* thermal table changed */
+ TP_HKEY_EV_UNK_6040 = 0x6040, /* Related to AC change?
+ some sort of APM hint,
+ W520 */
+
/* Misc */
TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */
};
@@ -3513,6 +3525,34 @@ static bool hotkey_notify_wakeup(const u32 hkey,
return true;
}
+static bool hotkey_notify_dockevent(const u32 hkey,
+ bool *send_acpi_ev,
+ bool *ignore_acpi_ev)
+{
+ /* 0x4000-0x4FFF: dock-related events */
+ *send_acpi_ev = true;
+ *ignore_acpi_ev = false;
+
+ switch (hkey) {
+ case TP_HKEY_EV_UNDOCK_ACK:
+ /* ACPI undock operation completed after wakeup */
+ hotkey_autosleep_ack = 1;
+ pr_info("undocked\n");
+ hotkey_wakeup_hotunplug_complete_notify_change();
+ return true;
+
+ case TP_HKEY_EV_HOTPLUG_DOCK: /* docked to port replicator */
+ pr_info("docked into hotplug port replicator\n");
+ return true;
+ case TP_HKEY_EV_HOTPLUG_UNDOCK: /* undocked from port replicator */
+ pr_info("undocked from hotplug port replicator\n");
+ return true;
+
+ default:
+ return false;
+ }
+}
+
static bool hotkey_notify_usrevent(const u32 hkey,
bool *send_acpi_ev,
bool *ignore_acpi_ev)
@@ -3547,13 +3587,13 @@ static bool hotkey_notify_usrevent(const u32 hkey,
static void thermal_dump_all_sensors(void);
-static bool hotkey_notify_thermal(const u32 hkey,
+static bool hotkey_notify_6xxx(const u32 hkey,
bool *send_acpi_ev,
bool *ignore_acpi_ev)
{
bool known = true;
- /* 0x6000-0x6FFF: thermal alarms */
+ /* 0x6000-0x6FFF: thermal alarms/notices and keyboard events */
*send_acpi_ev = true;
*ignore_acpi_ev = false;
@@ -3582,8 +3622,17 @@ static bool hotkey_notify_thermal(const u32 hkey,
"a sensor reports something is extremely hot!\n");
/* recommended action: immediate sleep/hibernate */
break;
+
+ case TP_HKEY_EV_KEY_NUMLOCK:
+ case TP_HKEY_EV_KEY_FN:
+ /* key press events, we just ignore them as long as the EC
+ * is still reporting them in the normal keyboard stream */
+ *send_acpi_ev = false;
+ *ignore_acpi_ev = true;
+ return true;
+
default:
- pr_alert("THERMAL ALERT: unknown thermal alarm received\n");
+ pr_warn("unknown possible thermal alarm or keyboard event received\n");
known = false;
}
@@ -3652,15 +3701,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
}
break;
case 4:
- /* 0x4000-0x4FFF: dock-related wakeups */
- if (hkey == TP_HKEY_EV_UNDOCK_ACK) {
- hotkey_autosleep_ack = 1;
- pr_info("undocked\n");
- hotkey_wakeup_hotunplug_complete_notify_change();
- known_ev = true;
- } else {
- known_ev = false;
- }
+ /* 0x4000-0x4FFF: dock-related events */
+ known_ev = hotkey_notify_dockevent(hkey, &send_acpi_ev,
+ &ignore_acpi_ev);
break;
case 5:
/* 0x5000-0x5FFF: human interface helpers */
@@ -3668,8 +3711,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
&ignore_acpi_ev);
break;
case 6:
- /* 0x6000-0x6FFF: thermal alarms */
- known_ev = hotkey_notify_thermal(hkey, &send_acpi_ev,
+ /* 0x6000-0x6FFF: thermal alarms/notices and
+ * keyboard events */
+ known_ev = hotkey_notify_6xxx(hkey, &send_acpi_ev,
&ignore_acpi_ev);
break;
case 7:
diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c
index e5f7b8fe51f..2bb8f451cc0 100644
--- a/drivers/regulator/db8500-prcmu.c
+++ b/drivers/regulator/db8500-prcmu.c
@@ -266,7 +266,7 @@ static struct regulator_ops db8500_regulator_switch_ops = {
* Regulator information
*/
static struct db8500_regulator_info
- db8500_regulator_info[DB8500_NUM_REGULATORS] = {
+db8500_regulator_info[DB8500_NUM_REGULATORS] = {
[DB8500_REGULATOR_VAPE] = {
.desc = {
.name = "db8500-vape",
@@ -492,11 +492,9 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev)
info->desc.name, err);
/* if failing, unregister all earlier regulators */
- i--;
- while (i >= 0) {
+ while (--i >= 0) {
info = &db8500_regulator_info[i];
regulator_unregister(info->rdev);
- i--;
}
return err;
}
@@ -536,13 +534,7 @@ static struct platform_driver db8500_regulator_driver = {
static int __init db8500_regulator_init(void)
{
- int ret;
-
- ret = platform_driver_register(&db8500_regulator_driver);
- if (ret < 0)
- return -ENODEV;
-
- return 0;
+ return platform_driver_register(&db8500_regulator_driver);
}
static void __exit db8500_regulator_exit(void)
diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c
index daff7fd0e95..486ed8141fc 100644
--- a/drivers/regulator/max8952.c
+++ b/drivers/regulator/max8952.c
@@ -139,7 +139,7 @@ static int max8952_set_voltage(struct regulator_dev *rdev,
s8 vid = -1, i;
if (!gpio_is_valid(max8952->pdata->gpio_vid0) ||
- !gpio_is_valid(max8952->pdata->gpio_vid0)) {
+ !gpio_is_valid(max8952->pdata->gpio_vid1)) {
/* DVS not supported */
return -EPERM;
}
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
index 10d5a1d9768..ad6628ca94f 100644
--- a/drivers/regulator/max8997.c
+++ b/drivers/regulator/max8997.c
@@ -39,25 +39,28 @@ struct max8997_data {
struct regulator_dev **rdev;
int ramp_delay; /* in mV/us */
+ bool buck1_gpiodvs;
+ bool buck2_gpiodvs;
+ bool buck5_gpiodvs;
u8 buck1_vol[8];
u8 buck2_vol[8];
u8 buck5_vol[8];
+ int buck125_gpios[3];
int buck125_gpioindex;
+ bool ignore_gpiodvs_side_effect;
u8 saved_states[MAX8997_REG_MAX];
};
static inline void max8997_set_gpio(struct max8997_data *max8997)
{
- struct max8997_platform_data *pdata =
- dev_get_platdata(max8997->iodev->dev);
int set3 = (max8997->buck125_gpioindex) & 0x1;
int set2 = ((max8997->buck125_gpioindex) >> 1) & 0x1;
int set1 = ((max8997->buck125_gpioindex) >> 2) & 0x1;
- gpio_set_value(pdata->buck125_gpios[0], set1);
- gpio_set_value(pdata->buck125_gpios[1], set2);
- gpio_set_value(pdata->buck125_gpios[2], set3);
+ gpio_set_value(max8997->buck125_gpios[0], set1);
+ gpio_set_value(max8997->buck125_gpios[1], set2);
+ gpio_set_value(max8997->buck125_gpios[2], set3);
}
struct voltage_map_desc {
@@ -380,8 +383,6 @@ static int max8997_get_voltage_register(struct regulator_dev *rdev,
static int max8997_get_voltage(struct regulator_dev *rdev)
{
struct max8997_data *max8997 = rdev_get_drvdata(rdev);
- struct max8997_platform_data *pdata =
- dev_get_platdata(max8997->iodev->dev);
struct i2c_client *i2c = max8997->iodev->i2c;
int reg, shift, mask, ret;
int rid = max8997_get_rid(rdev);
@@ -391,9 +392,9 @@ static int max8997_get_voltage(struct regulator_dev *rdev)
if (ret)
return ret;
- if ((rid == MAX8997_BUCK1 && pdata->buck1_gpiodvs) ||
- (rid == MAX8997_BUCK2 && pdata->buck2_gpiodvs) ||
- (rid == MAX8997_BUCK5 && pdata->buck5_gpiodvs))
+ if ((rid == MAX8997_BUCK1 && max8997->buck1_gpiodvs) ||
+ (rid == MAX8997_BUCK2 && max8997->buck2_gpiodvs) ||
+ (rid == MAX8997_BUCK5 && max8997->buck5_gpiodvs))
reg += max8997->buck125_gpioindex;
ret = max8997_read_reg(i2c, reg, &val);
@@ -543,7 +544,8 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev,
rid == MAX8997_BUCK4 || rid == MAX8997_BUCK5) {
/* If the voltage is increasing */
if (org < i)
- udelay(desc->step * (i - org) / max8997->ramp_delay);
+ udelay(DIV_ROUND_UP(desc->step * (i - org),
+ max8997->ramp_delay));
}
return ret;
@@ -561,8 +563,6 @@ static int max8997_assess_side_effect(struct regulator_dev *rdev,
u8 new_val, int *best)
{
struct max8997_data *max8997 = rdev_get_drvdata(rdev);
- struct max8997_platform_data *pdata =
- dev_get_platdata(max8997->iodev->dev);
int rid = max8997_get_rid(rdev);
u8 *buckx_val[3];
bool buckx_gpiodvs[3];
@@ -589,9 +589,9 @@ static int max8997_assess_side_effect(struct regulator_dev *rdev,
buckx_val[0] = max8997->buck1_vol;
buckx_val[1] = max8997->buck2_vol;
buckx_val[2] = max8997->buck5_vol;
- buckx_gpiodvs[0] = pdata->buck1_gpiodvs;
- buckx_gpiodvs[1] = pdata->buck2_gpiodvs;
- buckx_gpiodvs[2] = pdata->buck5_gpiodvs;
+ buckx_gpiodvs[0] = max8997->buck1_gpiodvs;
+ buckx_gpiodvs[1] = max8997->buck2_gpiodvs;
+ buckx_gpiodvs[2] = max8997->buck5_gpiodvs;
for (i = 0; i < 8; i++) {
int others;
@@ -640,8 +640,6 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev,
int min_uV, int max_uV, unsigned *selector)
{
struct max8997_data *max8997 = rdev_get_drvdata(rdev);
- struct max8997_platform_data *pdata =
- dev_get_platdata(max8997->iodev->dev);
int rid = max8997_get_rid(rdev);
const struct voltage_map_desc *desc;
int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg;
@@ -653,15 +651,15 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev,
switch (rid) {
case MAX8997_BUCK1:
- if (pdata->buck1_gpiodvs)
+ if (max8997->buck1_gpiodvs)
gpio_dvs_mode = true;
break;
case MAX8997_BUCK2:
- if (pdata->buck2_gpiodvs)
+ if (max8997->buck2_gpiodvs)
gpio_dvs_mode = true;
break;
case MAX8997_BUCK5:
- if (pdata->buck5_gpiodvs)
+ if (max8997->buck5_gpiodvs)
gpio_dvs_mode = true;
break;
}
@@ -695,7 +693,7 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev,
new_idx = tmp_idx;
new_val = tmp_val;
- if (pdata->ignore_gpiodvs_side_effect == false)
+ if (max8997->ignore_gpiodvs_side_effect == false)
return -EINVAL;
dev_warn(&rdev->dev, "MAX8997 GPIO-DVS Side Effect Warning: GPIO SET:"
@@ -993,6 +991,11 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
i2c = max8997->iodev->i2c;
max8997->buck125_gpioindex = pdata->buck125_default_idx;
+ max8997->buck1_gpiodvs = pdata->buck1_gpiodvs;
+ max8997->buck2_gpiodvs = pdata->buck2_gpiodvs;
+ max8997->buck5_gpiodvs = pdata->buck5_gpiodvs;
+ memcpy(max8997->buck125_gpios, pdata->buck125_gpios, sizeof(int) * 3);
+ max8997->ignore_gpiodvs_side_effect = pdata->ignore_gpiodvs_side_effect;
for (i = 0; i < 8; i++) {
max8997->buck1_vol[i] = ret =
@@ -1124,6 +1127,10 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
0x3f);
}
+ /* Misc Settings */
+ max8997->ramp_delay = 10; /* set 10mV/us, which is the default */
+ max8997_write_reg(i2c, MAX8997_REG_BUCKRAMP, (0xf << 4) | 0x9);
+
for (i = 0; i < pdata->num_regulators; i++) {
const struct voltage_map_desc *desc;
int id = pdata->regulators[i].id;
@@ -1148,10 +1155,6 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
}
}
- /* Misc Settings */
- max8997->ramp_delay = 10; /* set 10mV/us, which is the default */
- max8997_write_reg(i2c, MAX8997_REG_BUCKRAMP, (0xf << 4) | 0x9);
-
return 0;
err:
for (i = 0; i < max8997->num_regulators; i++)
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 4a1f029c4fe..8d9dae89f06 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -830,6 +830,19 @@ config SCSI_GDTH
To compile this driver as a module, choose M here: the
module will be called gdth.
+config SCSI_ISCI
+ tristate "Intel(R) C600 Series Chipset SAS Controller"
+ depends on PCI && SCSI
+ depends on X86
+ # (temporary): known alpha quality driver
+ depends on EXPERIMENTAL
+ select SCSI_SAS_LIBSAS
+ ---help---
+ This driver supports the 6Gb/s SAS capabilities of the storage
+ control unit found in the Intel(R) C600 series chipset.
+
+ The experimental tag will be removed after the driver exits alpha
+
config SCSI_GENERIC_NCR5380
tristate "Generic NCR5380/53c400 SCSI PIO support"
depends on ISA && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 7ad0b8a79ae..3c08f5352b2 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -73,6 +73,7 @@ obj-$(CONFIG_SCSI_AACRAID) += aacraid/
obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o
obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/
obj-$(CONFIG_SCSI_PM8001) += pm8001/
+obj-$(CONFIG_SCSI_ISCI) += isci/
obj-$(CONFIG_SCSI_IPS) += ips.o
obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o
obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index c6c0434d803..6bba23a2630 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1037,6 +1037,7 @@ static void complete_scsi_command(struct CommandList *cp)
unsigned char sense_key;
unsigned char asc; /* additional sense code */
unsigned char ascq; /* additional sense code qualifier */
+ unsigned long sense_data_size;
ei = cp->err_info;
cmd = (struct scsi_cmnd *) cp->scsi_cmd;
@@ -1051,10 +1052,14 @@ static void complete_scsi_command(struct CommandList *cp)
cmd->result |= ei->ScsiStatus;
/* copy the sense data whether we need to or not. */
- memcpy(cmd->sense_buffer, ei->SenseInfo,
- ei->SenseLen > SCSI_SENSE_BUFFERSIZE ?
- SCSI_SENSE_BUFFERSIZE :
- ei->SenseLen);
+ if (SCSI_SENSE_BUFFERSIZE < sizeof(ei->SenseInfo))
+ sense_data_size = SCSI_SENSE_BUFFERSIZE;
+ else
+ sense_data_size = sizeof(ei->SenseInfo);
+ if (ei->SenseLen < sense_data_size)
+ sense_data_size = ei->SenseLen;
+
+ memcpy(cmd->sense_buffer, ei->SenseInfo, sense_data_size);
scsi_set_resid(cmd, ei->ResidualCnt);
if (ei->CommandStatus == 0) {
@@ -2580,7 +2585,8 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
c->SG[0].Ext = 0; /* we are not chaining*/
}
hpsa_scsi_do_simple_cmd_core(h, c);
- hpsa_pci_unmap(h->pdev, c, 1, PCI_DMA_BIDIRECTIONAL);
+ if (iocommand.buf_size > 0)
+ hpsa_pci_unmap(h->pdev, c, 1, PCI_DMA_BIDIRECTIONAL);
check_ioctl_unit_attention(h, c);
/* Copy the error information out */
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index b7650613b8c..bdfa223a7db 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -4306,8 +4306,8 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
spin_lock_irqsave(vhost->host->host_lock, flags);
if (rc == H_CLOSED)
vio_enable_interrupts(to_vio_dev(vhost->dev));
- else if (rc || (rc = ibmvfc_send_crq_init(vhost)) ||
- (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) {
+ if (rc || (rc = ibmvfc_send_crq_init(vhost)) ||
+ (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) {
ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
dev_err(vhost->dev, "Error after reset (rc=%d)\n", rc);
}
diff --git a/drivers/scsi/isci/Makefile b/drivers/scsi/isci/Makefile
new file mode 100644
index 00000000000..3359e10e0d8
--- /dev/null
+++ b/drivers/scsi/isci/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_SCSI_ISCI) += isci.o
+isci-objs := init.o phy.o request.o \
+ remote_device.o port.o \
+ host.o task.o probe_roms.o \
+ remote_node_context.o \
+ remote_node_table.o \
+ unsolicited_frame_control.o \
+ port_config.o \
diff --git a/drivers/scsi/isci/firmware/Makefile b/drivers/scsi/isci/firmware/Makefile
new file mode 100644
index 00000000000..5f54461cabc
--- /dev/null
+++ b/drivers/scsi/isci/firmware/Makefile
@@ -0,0 +1,19 @@
+# Makefile for create_fw
+#
+CC=gcc
+CFLAGS=-c -Wall -O2 -g
+LDFLAGS=
+SOURCES=create_fw.c
+OBJECTS=$(SOURCES:.cpp=.o)
+EXECUTABLE=create_fw
+
+all: $(SOURCES) $(EXECUTABLE)
+
+$(EXECUTABLE): $(OBJECTS)
+ $(CC) $(LDFLAGS) $(OBJECTS) -o $@
+
+.c.o:
+ $(CC) $(CFLAGS) $< -O $@
+
+clean:
+ rm -f *.o $(EXECUTABLE)
diff --git a/drivers/scsi/isci/firmware/README b/drivers/scsi/isci/firmware/README
new file mode 100644
index 00000000000..8056d2bd233
--- /dev/null
+++ b/drivers/scsi/isci/firmware/README
@@ -0,0 +1,36 @@
+This defines the temporary binary blow we are to pass to the SCU
+driver to emulate the binary firmware that we will eventually be
+able to access via NVRAM on the SCU controller.
+
+The current size of the binary blob is expected to be 149 bytes or larger
+
+Header Types:
+0x1: Phy Masks
+0x2: Phy Gens
+0x3: SAS Addrs
+0xff: End of Data
+
+ID string - u8[12]: "#SCU MAGIC#\0"
+Version - u8: 1
+SubVersion - u8: 0
+
+Header Type - u8: 0x1
+Size - u8: 8
+Phy Mask - u32[8]
+
+Header Type - u8: 0x2
+Size - u8: 8
+Phy Gen - u32[8]
+
+Header Type - u8: 0x3
+Size - u8: 8
+Sas Addr - u64[8]
+
+Header Type - u8: 0xf
+
+
+==============================================================================
+
+Place isci_firmware.bin in /lib/firmware
+Be sure to recreate the initramfs image to include the firmware.
+
diff --git a/drivers/scsi/isci/firmware/create_fw.c b/drivers/scsi/isci/firmware/create_fw.c
new file mode 100644
index 00000000000..c7a2887a7e9
--- /dev/null
+++ b/drivers/scsi/isci/firmware/create_fw.c
@@ -0,0 +1,99 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <asm/types.h>
+#include <strings.h>
+#include <stdint.h>
+
+#include "create_fw.h"
+#include "../probe_roms.h"
+
+int write_blob(struct isci_orom *isci_orom)
+{
+ FILE *fd;
+ int err;
+ size_t count;
+
+ fd = fopen(blob_name, "w+");
+ if (!fd) {
+ perror("Open file for write failed");
+ fclose(fd);
+ return -EIO;
+ }
+
+ count = fwrite(isci_orom, sizeof(struct isci_orom), 1, fd);
+ if (count != 1) {
+ perror("Write data failed");
+ fclose(fd);
+ return -EIO;
+ }
+
+ fclose(fd);
+
+ return 0;
+}
+
+void set_binary_values(struct isci_orom *isci_orom)
+{
+ int ctrl_idx, phy_idx, port_idx;
+
+ /* setting OROM signature */
+ strncpy(isci_orom->hdr.signature, sig, strlen(sig));
+ isci_orom->hdr.version = version;
+ isci_orom->hdr.total_block_length = sizeof(struct isci_orom);
+ isci_orom->hdr.hdr_length = sizeof(struct sci_bios_oem_param_block_hdr);
+ isci_orom->hdr.num_elements = num_elements;
+
+ for (ctrl_idx = 0; ctrl_idx < 2; ctrl_idx++) {
+ isci_orom->ctrl[ctrl_idx].controller.mode_type = mode_type;
+ isci_orom->ctrl[ctrl_idx].controller.max_concurrent_dev_spin_up =
+ max_num_concurrent_dev_spin_up;
+ isci_orom->ctrl[ctrl_idx].controller.do_enable_ssc =
+ enable_ssc;
+
+ for (port_idx = 0; port_idx < 4; port_idx++)
+ isci_orom->ctrl[ctrl_idx].ports[port_idx].phy_mask =
+ phy_mask[ctrl_idx][port_idx];
+
+ for (phy_idx = 0; phy_idx < 4; phy_idx++) {
+ isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.high =
+ (__u32)(sas_addr[ctrl_idx][phy_idx] >> 32);
+ isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.low =
+ (__u32)(sas_addr[ctrl_idx][phy_idx]);
+
+ isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control0 =
+ afe_tx_amp_control0;
+ isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control1 =
+ afe_tx_amp_control1;
+ isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control2 =
+ afe_tx_amp_control2;
+ isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control3 =
+ afe_tx_amp_control3;
+ }
+ }
+}
+
+int main(void)
+{
+ int err;
+ struct isci_orom *isci_orom;
+
+ isci_orom = malloc(sizeof(struct isci_orom));
+ memset(isci_orom, 0, sizeof(struct isci_orom));
+
+ set_binary_values(isci_orom);
+
+ err = write_blob(isci_orom);
+ if (err < 0) {
+ free(isci_orom);
+ return err;
+ }
+
+ free(isci_orom);
+ return 0;
+}
diff --git a/drivers/scsi/isci/firmware/create_fw.h b/drivers/scsi/isci/firmware/create_fw.h
new file mode 100644
index 00000000000..5f298828d22
--- /dev/null
+++ b/drivers/scsi/isci/firmware/create_fw.h
@@ -0,0 +1,77 @@
+#ifndef _CREATE_FW_H_
+#define _CREATE_FW_H_
+#include "../probe_roms.h"
+
+
+/* we are configuring for 2 SCUs */
+static const int num_elements = 2;
+
+/*
+ * For all defined arrays:
+ * elements 0-3 are for SCU0, ports 0-3
+ * elements 4-7 are for SCU1, ports 0-3
+ *
+ * valid configurations for one SCU are:
+ * P0 P1 P2 P3
+ * ----------------
+ * 0xF,0x0,0x0,0x0 # 1 x4 port
+ * 0x3,0x0,0x4,0x8 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are each x1
+ * # ports
+ * 0x1,0x2,0xC,0x0 # Phys 0 and 1 are each x1 ports, phy 2 and phy 3 are a x2
+ * # port
+ * 0x3,0x0,0xC,0x0 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are a x2 port
+ * 0x1,0x2,0x4,0x8 # Each phy is a x1 port (this is the default configuration)
+ *
+ * if there is a port/phy on which you do not wish to override the default
+ * values, use the value assigned to UNINIT_PARAM (255).
+ */
+
+/* discovery mode type (port auto config mode by default ) */
+
+/*
+ * if there is a port/phy on which you do not wish to override the default
+ * values, use the value "0000000000000000". SAS address of zero's is
+ * considered invalid and will not be used.
+ */
+#ifdef MPC
+static const int mode_type = SCIC_PORT_MANUAL_CONFIGURATION_MODE;
+static const __u8 phy_mask[2][4] = { {1, 2, 4, 8},
+ {1, 2, 4, 8} };
+static const unsigned long long sas_addr[2][4] = { { 0x5FCFFFFFF0000001ULL,
+ 0x5FCFFFFFF0000002ULL,
+ 0x5FCFFFFFF0000003ULL,
+ 0x5FCFFFFFF0000004ULL },
+ { 0x5FCFFFFFF0000005ULL,
+ 0x5FCFFFFFF0000006ULL,
+ 0x5FCFFFFFF0000007ULL,
+ 0x5FCFFFFFF0000008ULL } };
+#else /* APC (default) */
+static const int mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
+static const __u8 phy_mask[2][4];
+static const unsigned long long sas_addr[2][4] = { { 0x5FCFFFFF00000001ULL,
+ 0x5FCFFFFF00000001ULL,
+ 0x5FCFFFFF00000001ULL,
+ 0x5FCFFFFF00000001ULL },
+ { 0x5FCFFFFF00000002ULL,
+ 0x5FCFFFFF00000002ULL,
+ 0x5FCFFFFF00000002ULL,
+ 0x5FCFFFFF00000002ULL } };
+#endif
+
+/* Maximum number of concurrent device spin up */
+static const int max_num_concurrent_dev_spin_up = 1;
+
+/* enable of ssc operation */
+static const int enable_ssc;
+
+/* AFE_TX_AMP_CONTROL */
+static const unsigned int afe_tx_amp_control0 = 0x000bdd08;
+static const unsigned int afe_tx_amp_control1 = 0x000ffc00;
+static const unsigned int afe_tx_amp_control2 = 0x000b7c09;
+static const unsigned int afe_tx_amp_control3 = 0x000afc6e;
+
+static const char blob_name[] = "isci_firmware.bin";
+static const char sig[] = "ISCUOEMB";
+static const unsigned char version = 0x10;
+
+#endif
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
new file mode 100644
index 00000000000..26072f1e985
--- /dev/null
+++ b/drivers/scsi/isci/host.c
@@ -0,0 +1,2751 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <linux/circ_buf.h>
+#include <linux/device.h>
+#include <scsi/sas.h>
+#include "host.h"
+#include "isci.h"
+#include "port.h"
+#include "host.h"
+#include "probe_roms.h"
+#include "remote_device.h"
+#include "request.h"
+#include "scu_completion_codes.h"
+#include "scu_event_codes.h"
+#include "registers.h"
+#include "scu_remote_node_context.h"
+#include "scu_task_context.h"
+
+#define SCU_CONTEXT_RAM_INIT_STALL_TIME 200
+
+#define smu_max_ports(dcc_value) \
+ (\
+ (((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_MASK) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT) + 1 \
+ )
+
+#define smu_max_task_contexts(dcc_value) \
+ (\
+ (((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_MASK) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_SHIFT) + 1 \
+ )
+
+#define smu_max_rncs(dcc_value) \
+ (\
+ (((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_MASK) \
+ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT) + 1 \
+ )
+
+#define SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT 100
+
+/**
+ *
+ *
+ * The number of milliseconds to wait while a given phy is consuming power
+ * before allowing another set of phys to consume power. Ultimately, this will
+ * be specified by OEM parameter.
+ */
+#define SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL 500
+
+/**
+ * NORMALIZE_PUT_POINTER() -
+ *
+ * This macro will normalize the completion queue put pointer so its value can
+ * be used as an array inde
+ */
+#define NORMALIZE_PUT_POINTER(x) \
+ ((x) & SMU_COMPLETION_QUEUE_PUT_POINTER_MASK)
+
+
+/**
+ * NORMALIZE_EVENT_POINTER() -
+ *
+ * This macro will normalize the completion queue event entry so its value can
+ * be used as an index.
+ */
+#define NORMALIZE_EVENT_POINTER(x) \
+ (\
+ ((x) & SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_MASK) \
+ >> SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_SHIFT \
+ )
+
+/**
+ * NORMALIZE_GET_POINTER() -
+ *
+ * This macro will normalize the completion queue get pointer so its value can
+ * be used as an index into an array
+ */
+#define NORMALIZE_GET_POINTER(x) \
+ ((x) & SMU_COMPLETION_QUEUE_GET_POINTER_MASK)
+
+/**
+ * NORMALIZE_GET_POINTER_CYCLE_BIT() -
+ *
+ * This macro will normalize the completion queue cycle pointer so it matches
+ * the completion queue cycle bit
+ */
+#define NORMALIZE_GET_POINTER_CYCLE_BIT(x) \
+ ((SMU_CQGR_CYCLE_BIT & (x)) << (31 - SMU_COMPLETION_QUEUE_GET_CYCLE_BIT_SHIFT))
+
+/**
+ * COMPLETION_QUEUE_CYCLE_BIT() -
+ *
+ * This macro will return the cycle bit of the completion queue entry
+ */
+#define COMPLETION_QUEUE_CYCLE_BIT(x) ((x) & 0x80000000)
+
+/* Init the state machine and call the state entry function (if any) */
+void sci_init_sm(struct sci_base_state_machine *sm,
+ const struct sci_base_state *state_table, u32 initial_state)
+{
+ sci_state_transition_t handler;
+
+ sm->initial_state_id = initial_state;
+ sm->previous_state_id = initial_state;
+ sm->current_state_id = initial_state;
+ sm->state_table = state_table;
+
+ handler = sm->state_table[initial_state].enter_state;
+ if (handler)
+ handler(sm);
+}
+
+/* Call the state exit fn, update the current state, call the state entry fn */
+void sci_change_state(struct sci_base_state_machine *sm, u32 next_state)
+{
+ sci_state_transition_t handler;
+
+ handler = sm->state_table[sm->current_state_id].exit_state;
+ if (handler)
+ handler(sm);
+
+ sm->previous_state_id = sm->current_state_id;
+ sm->current_state_id = next_state;
+
+ handler = sm->state_table[sm->current_state_id].enter_state;
+ if (handler)
+ handler(sm);
+}
+
+static bool sci_controller_completion_queue_has_entries(struct isci_host *ihost)
+{
+ u32 get_value = ihost->completion_queue_get;
+ u32 get_index = get_value & SMU_COMPLETION_QUEUE_GET_POINTER_MASK;
+
+ if (NORMALIZE_GET_POINTER_CYCLE_BIT(get_value) ==
+ COMPLETION_QUEUE_CYCLE_BIT(ihost->completion_queue[get_index]))
+ return true;
+
+ return false;
+}
+
+static bool sci_controller_isr(struct isci_host *ihost)
+{
+ if (sci_controller_completion_queue_has_entries(ihost)) {
+ return true;
+ } else {
+ /*
+ * we have a spurious interrupt it could be that we have already
+ * emptied the completion queue from a previous interrupt */
+ writel(SMU_ISR_COMPLETION, &ihost->smu_registers->interrupt_status);
+
+ /*
+ * There is a race in the hardware that could cause us not to be notified
+ * of an interrupt completion if we do not take this step. We will mask
+ * then unmask the interrupts so if there is another interrupt pending
+ * the clearing of the interrupt source we get the next interrupt message. */
+ writel(0xFF000000, &ihost->smu_registers->interrupt_mask);
+ writel(0, &ihost->smu_registers->interrupt_mask);
+ }
+
+ return false;
+}
+
+irqreturn_t isci_msix_isr(int vec, void *data)
+{
+ struct isci_host *ihost = data;
+
+ if (sci_controller_isr(ihost))
+ tasklet_schedule(&ihost->completion_tasklet);
+
+ return IRQ_HANDLED;
+}
+
+static bool sci_controller_error_isr(struct isci_host *ihost)
+{
+ u32 interrupt_status;
+
+ interrupt_status =
+ readl(&ihost->smu_registers->interrupt_status);
+ interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
+
+ if (interrupt_status != 0) {
+ /*
+ * There is an error interrupt pending so let it through and handle
+ * in the callback */
+ return true;
+ }
+
+ /*
+ * There is a race in the hardware that could cause us not to be notified
+ * of an interrupt completion if we do not take this step. We will mask
+ * then unmask the error interrupts so if there was another interrupt
+ * pending we will be notified.
+ * Could we write the value of (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND)? */
+ writel(0xff, &ihost->smu_registers->interrupt_mask);
+ writel(0, &ihost->smu_registers->interrupt_mask);
+
+ return false;
+}
+
+static void sci_controller_task_completion(struct isci_host *ihost, u32 ent)
+{
+ u32 index = SCU_GET_COMPLETION_INDEX(ent);
+ struct isci_request *ireq = ihost->reqs[index];
+
+ /* Make sure that we really want to process this IO request */
+ if (test_bit(IREQ_ACTIVE, &ireq->flags) &&
+ ireq->io_tag != SCI_CONTROLLER_INVALID_IO_TAG &&
+ ISCI_TAG_SEQ(ireq->io_tag) == ihost->io_request_sequence[index])
+ /* Yep this is a valid io request pass it along to the
+ * io request handler
+ */
+ sci_io_request_tc_completion(ireq, ent);
+}
+
+static void sci_controller_sdma_completion(struct isci_host *ihost, u32 ent)
+{
+ u32 index;
+ struct isci_request *ireq;
+ struct isci_remote_device *idev;
+
+ index = SCU_GET_COMPLETION_INDEX(ent);
+
+ switch (scu_get_command_request_type(ent)) {
+ case SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC:
+ case SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_TC:
+ ireq = ihost->reqs[index];
+ dev_warn(&ihost->pdev->dev, "%s: %x for io request %p\n",
+ __func__, ent, ireq);
+ /* @todo For a post TC operation we need to fail the IO
+ * request
+ */
+ break;
+ case SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_RNC:
+ case SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC:
+ case SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_RNC:
+ idev = ihost->device_table[index];
+ dev_warn(&ihost->pdev->dev, "%s: %x for device %p\n",
+ __func__, ent, idev);
+ /* @todo For a port RNC operation we need to fail the
+ * device
+ */
+ break;
+ default:
+ dev_warn(&ihost->pdev->dev, "%s: unknown completion type %x\n",
+ __func__, ent);
+ break;
+ }
+}
+
+static void sci_controller_unsolicited_frame(struct isci_host *ihost, u32 ent)
+{
+ u32 index;
+ u32 frame_index;
+
+ struct scu_unsolicited_frame_header *frame_header;
+ struct isci_phy *iphy;
+ struct isci_remote_device *idev;
+
+ enum sci_status result = SCI_FAILURE;
+
+ frame_index = SCU_GET_FRAME_INDEX(ent);
+
+ frame_header = ihost->uf_control.buffers.array[frame_index].header;
+ ihost->uf_control.buffers.array[frame_index].state = UNSOLICITED_FRAME_IN_USE;
+
+ if (SCU_GET_FRAME_ERROR(ent)) {
+ /*
+ * / @todo If the IAF frame or SIGNATURE FIS frame has an error will
+ * / this cause a problem? We expect the phy initialization will
+ * / fail if there is an error in the frame. */
+ sci_controller_release_frame(ihost, frame_index);
+ return;
+ }
+
+ if (frame_header->is_address_frame) {
+ index = SCU_GET_PROTOCOL_ENGINE_INDEX(ent);
+ iphy = &ihost->phys[index];
+ result = sci_phy_frame_handler(iphy, frame_index);
+ } else {
+
+ index = SCU_GET_COMPLETION_INDEX(ent);
+
+ if (index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) {
+ /*
+ * This is a signature fis or a frame from a direct attached SATA
+ * device that has not yet been created. In either case forwared
+ * the frame to the PE and let it take care of the frame data. */
+ index = SCU_GET_PROTOCOL_ENGINE_INDEX(ent);
+ iphy = &ihost->phys[index];
+ result = sci_phy_frame_handler(iphy, frame_index);
+ } else {
+ if (index < ihost->remote_node_entries)
+ idev = ihost->device_table[index];
+ else
+ idev = NULL;
+
+ if (idev != NULL)
+ result = sci_remote_device_frame_handler(idev, frame_index);
+ else
+ sci_controller_release_frame(ihost, frame_index);
+ }
+ }
+
+ if (result != SCI_SUCCESS) {
+ /*
+ * / @todo Is there any reason to report some additional error message
+ * / when we get this failure notifiction? */
+ }
+}
+
+static void sci_controller_event_completion(struct isci_host *ihost, u32 ent)
+{
+ struct isci_remote_device *idev;
+ struct isci_request *ireq;
+ struct isci_phy *iphy;
+ u32 index;
+
+ index = SCU_GET_COMPLETION_INDEX(ent);
+
+ switch (scu_get_event_type(ent)) {
+ case SCU_EVENT_TYPE_SMU_COMMAND_ERROR:
+ /* / @todo The driver did something wrong and we need to fix the condtion. */
+ dev_err(&ihost->pdev->dev,
+ "%s: SCIC Controller 0x%p received SMU command error "
+ "0x%x\n",
+ __func__,
+ ihost,
+ ent);
+ break;
+
+ case SCU_EVENT_TYPE_SMU_PCQ_ERROR:
+ case SCU_EVENT_TYPE_SMU_ERROR:
+ case SCU_EVENT_TYPE_FATAL_MEMORY_ERROR:
+ /*
+ * / @todo This is a hardware failure and its likely that we want to
+ * / reset the controller. */
+ dev_err(&ihost->pdev->dev,
+ "%s: SCIC Controller 0x%p received fatal controller "
+ "event 0x%x\n",
+ __func__,
+ ihost,
+ ent);
+ break;
+
+ case SCU_EVENT_TYPE_TRANSPORT_ERROR:
+ ireq = ihost->reqs[index];
+ sci_io_request_event_handler(ireq, ent);
+ break;
+
+ case SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT:
+ switch (scu_get_event_specifier(ent)) {
+ case SCU_EVENT_SPECIFIC_SMP_RESPONSE_NO_PE:
+ case SCU_EVENT_SPECIFIC_TASK_TIMEOUT:
+ ireq = ihost->reqs[index];
+ if (ireq != NULL)
+ sci_io_request_event_handler(ireq, ent);
+ else
+ dev_warn(&ihost->pdev->dev,
+ "%s: SCIC Controller 0x%p received "
+ "event 0x%x for io request object "
+ "that doesnt exist.\n",
+ __func__,
+ ihost,
+ ent);
+
+ break;
+
+ case SCU_EVENT_SPECIFIC_IT_NEXUS_TIMEOUT:
+ idev = ihost->device_table[index];
+ if (idev != NULL)
+ sci_remote_device_event_handler(idev, ent);
+ else
+ dev_warn(&ihost->pdev->dev,
+ "%s: SCIC Controller 0x%p received "
+ "event 0x%x for remote device object "
+ "that doesnt exist.\n",
+ __func__,
+ ihost,
+ ent);
+
+ break;
+ }
+ break;
+
+ case SCU_EVENT_TYPE_BROADCAST_CHANGE:
+ /*
+ * direct the broadcast change event to the phy first and then let
+ * the phy redirect the broadcast change to the port object */
+ case SCU_EVENT_TYPE_ERR_CNT_EVENT:
+ /*
+ * direct error counter event to the phy object since that is where
+ * we get the event notification. This is a type 4 event. */
+ case SCU_EVENT_TYPE_OSSP_EVENT:
+ index = SCU_GET_PROTOCOL_ENGINE_INDEX(ent);
+ iphy = &ihost->phys[index];
+ sci_phy_event_handler(iphy, ent);
+ break;
+
+ case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
+ case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
+ case SCU_EVENT_TYPE_RNC_OPS_MISC:
+ if (index < ihost->remote_node_entries) {
+ idev = ihost->device_table[index];
+
+ if (idev != NULL)
+ sci_remote_device_event_handler(idev, ent);
+ } else
+ dev_err(&ihost->pdev->dev,
+ "%s: SCIC Controller 0x%p received event 0x%x "
+ "for remote device object 0x%0x that doesnt "
+ "exist.\n",
+ __func__,
+ ihost,
+ ent,
+ index);
+
+ break;
+
+ default:
+ dev_warn(&ihost->pdev->dev,
+ "%s: SCIC Controller received unknown event code %x\n",
+ __func__,
+ ent);
+ break;
+ }
+}
+
+static void sci_controller_process_completions(struct isci_host *ihost)
+{
+ u32 completion_count = 0;
+ u32 ent;
+ u32 get_index;
+ u32 get_cycle;
+ u32 event_get;
+ u32 event_cycle;
+
+ dev_dbg(&ihost->pdev->dev,
+ "%s: completion queue begining get:0x%08x\n",
+ __func__,
+ ihost->completion_queue_get);
+
+ /* Get the component parts of the completion queue */
+ get_index = NORMALIZE_GET_POINTER(ihost->completion_queue_get);
+ get_cycle = SMU_CQGR_CYCLE_BIT & ihost->completion_queue_get;
+
+ event_get = NORMALIZE_EVENT_POINTER(ihost->completion_queue_get);
+ event_cycle = SMU_CQGR_EVENT_CYCLE_BIT & ihost->completion_queue_get;
+
+ while (
+ NORMALIZE_GET_POINTER_CYCLE_BIT(get_cycle)
+ == COMPLETION_QUEUE_CYCLE_BIT(ihost->completion_queue[get_index])
+ ) {
+ completion_count++;
+
+ ent = ihost->completion_queue[get_index];
+
+ /* increment the get pointer and check for rollover to toggle the cycle bit */
+ get_cycle ^= ((get_index+1) & SCU_MAX_COMPLETION_QUEUE_ENTRIES) <<
+ (SMU_COMPLETION_QUEUE_GET_CYCLE_BIT_SHIFT - SCU_MAX_COMPLETION_QUEUE_SHIFT);
+ get_index = (get_index+1) & (SCU_MAX_COMPLETION_QUEUE_ENTRIES-1);
+
+ dev_dbg(&ihost->pdev->dev,
+ "%s: completion queue entry:0x%08x\n",
+ __func__,
+ ent);
+
+ switch (SCU_GET_COMPLETION_TYPE(ent)) {
+ case SCU_COMPLETION_TYPE_TASK:
+ sci_controller_task_completion(ihost, ent);
+ break;
+
+ case SCU_COMPLETION_TYPE_SDMA:
+ sci_controller_sdma_completion(ihost, ent);
+ break;
+
+ case SCU_COMPLETION_TYPE_UFI:
+ sci_controller_unsolicited_frame(ihost, ent);
+ break;
+
+ case SCU_COMPLETION_TYPE_EVENT:
+ 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);
+ event_get = (event_get+1) & (SCU_MAX_EVENTS-1);
+
+ sci_controller_event_completion(ihost, ent);
+ break;
+ }
+ default:
+ dev_warn(&ihost->pdev->dev,
+ "%s: SCIC Controller received unknown "
+ "completion type %x\n",
+ __func__,
+ ent);
+ break;
+ }
+ }
+
+ /* Update the get register if we completed one or more entries */
+ if (completion_count > 0) {
+ ihost->completion_queue_get =
+ SMU_CQGR_GEN_BIT(ENABLE) |
+ SMU_CQGR_GEN_BIT(EVENT_ENABLE) |
+ event_cycle |
+ SMU_CQGR_GEN_VAL(EVENT_POINTER, event_get) |
+ get_cycle |
+ SMU_CQGR_GEN_VAL(POINTER, get_index);
+
+ writel(ihost->completion_queue_get,
+ &ihost->smu_registers->completion_queue_get);
+
+ }
+
+ dev_dbg(&ihost->pdev->dev,
+ "%s: completion queue ending get:0x%08x\n",
+ __func__,
+ ihost->completion_queue_get);
+
+}
+
+static void sci_controller_error_handler(struct isci_host *ihost)
+{
+ u32 interrupt_status;
+
+ interrupt_status =
+ readl(&ihost->smu_registers->interrupt_status);
+
+ if ((interrupt_status & SMU_ISR_QUEUE_SUSPEND) &&
+ sci_controller_completion_queue_has_entries(ihost)) {
+
+ sci_controller_process_completions(ihost);
+ writel(SMU_ISR_QUEUE_SUSPEND, &ihost->smu_registers->interrupt_status);
+ } else {
+ dev_err(&ihost->pdev->dev, "%s: status: %#x\n", __func__,
+ interrupt_status);
+
+ sci_change_state(&ihost->sm, SCIC_FAILED);
+
+ return;
+ }
+
+ /* If we dont process any completions I am not sure that we want to do this.
+ * We are in the middle of a hardware fault and should probably be reset.
+ */
+ writel(0, &ihost->smu_registers->interrupt_mask);
+}
+
+irqreturn_t isci_intx_isr(int vec, void *data)
+{
+ irqreturn_t ret = IRQ_NONE;
+ struct isci_host *ihost = data;
+
+ if (sci_controller_isr(ihost)) {
+ writel(SMU_ISR_COMPLETION, &ihost->smu_registers->interrupt_status);
+ tasklet_schedule(&ihost->completion_tasklet);
+ ret = IRQ_HANDLED;
+ } else if (sci_controller_error_isr(ihost)) {
+ spin_lock(&ihost->scic_lock);
+ sci_controller_error_handler(ihost);
+ spin_unlock(&ihost->scic_lock);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+irqreturn_t isci_error_isr(int vec, void *data)
+{
+ struct isci_host *ihost = data;
+
+ if (sci_controller_error_isr(ihost))
+ sci_controller_error_handler(ihost);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * isci_host_start_complete() - This function is called by the core library,
+ * through the ISCI Module, to indicate controller start status.
+ * @isci_host: This parameter specifies the ISCI host object
+ * @completion_status: This parameter specifies the completion status from the
+ * core library.
+ *
+ */
+static void isci_host_start_complete(struct isci_host *ihost, enum sci_status completion_status)
+{
+ if (completion_status != SCI_SUCCESS)
+ dev_info(&ihost->pdev->dev,
+ "controller start timed out, continuing...\n");
+ isci_host_change_state(ihost, isci_ready);
+ clear_bit(IHOST_START_PENDING, &ihost->flags);
+ wake_up(&ihost->eventq);
+}
+
+int isci_host_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+ struct isci_host *ihost = SHOST_TO_SAS_HA(shost)->lldd_ha;
+
+ if (test_bit(IHOST_START_PENDING, &ihost->flags))
+ return 0;
+
+ /* todo: use sas_flush_discovery once it is upstream */
+ scsi_flush_work(shost);
+
+ scsi_flush_work(shost);
+
+ dev_dbg(&ihost->pdev->dev,
+ "%s: ihost->status = %d, time = %ld\n",
+ __func__, isci_host_get_state(ihost), time);
+
+ return 1;
+
+}
+
+/**
+ * sci_controller_get_suggested_start_timeout() - This method returns the
+ * suggested sci_controller_start() timeout amount. The user is free to
+ * use any timeout value, but this method provides the suggested minimum
+ * start timeout value. The returned value is based upon empirical
+ * information determined as a result of interoperability testing.
+ * @controller: the handle to the controller object for which to return the
+ * suggested start timeout.
+ *
+ * This method returns the number of milliseconds for the suggested start
+ * operation timeout.
+ */
+static u32 sci_controller_get_suggested_start_timeout(struct isci_host *ihost)
+{
+ /* Validate the user supplied parameters. */
+ if (!ihost)
+ return 0;
+
+ /*
+ * The suggested minimum timeout value for a controller start operation:
+ *
+ * Signature FIS Timeout
+ * + Phy Start Timeout
+ * + Number of Phy Spin Up Intervals
+ * ---------------------------------
+ * Number of milliseconds for the controller start operation.
+ *
+ * NOTE: The number of phy spin up intervals will be equivalent
+ * to the number of phys divided by the number phys allowed
+ * per interval - 1 (once OEM parameters are supported).
+ * Currently we assume only 1 phy per interval. */
+
+ return SCIC_SDS_SIGNATURE_FIS_TIMEOUT
+ + SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT
+ + ((SCI_MAX_PHYS - 1) * SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL);
+}
+
+static void sci_controller_enable_interrupts(struct isci_host *ihost)
+{
+ BUG_ON(ihost->smu_registers == NULL);
+ writel(0, &ihost->smu_registers->interrupt_mask);
+}
+
+void sci_controller_disable_interrupts(struct isci_host *ihost)
+{
+ BUG_ON(ihost->smu_registers == NULL);
+ writel(0xffffffff, &ihost->smu_registers->interrupt_mask);
+}
+
+static void sci_controller_enable_port_task_scheduler(struct isci_host *ihost)
+{
+ u32 port_task_scheduler_value;
+
+ port_task_scheduler_value =
+ readl(&ihost->scu_registers->peg0.ptsg.control);
+ port_task_scheduler_value |=
+ (SCU_PTSGCR_GEN_BIT(ETM_ENABLE) |
+ SCU_PTSGCR_GEN_BIT(PTSG_ENABLE));
+ writel(port_task_scheduler_value,
+ &ihost->scu_registers->peg0.ptsg.control);
+}
+
+static void sci_controller_assign_task_entries(struct isci_host *ihost)
+{
+ u32 task_assignment;
+
+ /*
+ * Assign all the TCs to function 0
+ * TODO: Do we actually need to read this register to write it back?
+ */
+
+ task_assignment =
+ readl(&ihost->smu_registers->task_context_assignment[0]);
+
+ task_assignment |= (SMU_TCA_GEN_VAL(STARTING, 0)) |
+ (SMU_TCA_GEN_VAL(ENDING, ihost->task_context_entries - 1)) |
+ (SMU_TCA_GEN_BIT(RANGE_CHECK_ENABLE));
+
+ writel(task_assignment,
+ &ihost->smu_registers->task_context_assignment[0]);
+
+}
+
+static void sci_controller_initialize_completion_queue(struct isci_host *ihost)
+{
+ u32 index;
+ u32 completion_queue_control_value;
+ u32 completion_queue_get_value;
+ u32 completion_queue_put_value;
+
+ ihost->completion_queue_get = 0;
+
+ completion_queue_control_value =
+ (SMU_CQC_QUEUE_LIMIT_SET(SCU_MAX_COMPLETION_QUEUE_ENTRIES - 1) |
+ SMU_CQC_EVENT_LIMIT_SET(SCU_MAX_EVENTS - 1));
+
+ writel(completion_queue_control_value,
+ &ihost->smu_registers->completion_queue_control);
+
+
+ /* Set the completion queue get pointer and enable the queue */
+ completion_queue_get_value = (
+ (SMU_CQGR_GEN_VAL(POINTER, 0))
+ | (SMU_CQGR_GEN_VAL(EVENT_POINTER, 0))
+ | (SMU_CQGR_GEN_BIT(ENABLE))
+ | (SMU_CQGR_GEN_BIT(EVENT_ENABLE))
+ );
+
+ writel(completion_queue_get_value,
+ &ihost->smu_registers->completion_queue_get);
+
+ /* Set the completion queue put pointer */
+ completion_queue_put_value = (
+ (SMU_CQPR_GEN_VAL(POINTER, 0))
+ | (SMU_CQPR_GEN_VAL(EVENT_POINTER, 0))
+ );
+
+ writel(completion_queue_put_value,
+ &ihost->smu_registers->completion_queue_put);
+
+ /* Initialize the cycle bit of the completion queue entries */
+ for (index = 0; index < SCU_MAX_COMPLETION_QUEUE_ENTRIES; index++) {
+ /*
+ * If get.cycle_bit != completion_queue.cycle_bit
+ * its not a valid completion queue entry
+ * so at system start all entries are invalid */
+ ihost->completion_queue[index] = 0x80000000;
+ }
+}
+
+static void sci_controller_initialize_unsolicited_frame_queue(struct isci_host *ihost)
+{
+ u32 frame_queue_control_value;
+ u32 frame_queue_get_value;
+ u32 frame_queue_put_value;
+
+ /* Write the queue size */
+ frame_queue_control_value =
+ SCU_UFQC_GEN_VAL(QUEUE_SIZE, SCU_MAX_UNSOLICITED_FRAMES);
+
+ writel(frame_queue_control_value,
+ &ihost->scu_registers->sdma.unsolicited_frame_queue_control);
+
+ /* Setup the get pointer for the unsolicited frame queue */
+ frame_queue_get_value = (
+ SCU_UFQGP_GEN_VAL(POINTER, 0)
+ | SCU_UFQGP_GEN_BIT(ENABLE_BIT)
+ );
+
+ writel(frame_queue_get_value,
+ &ihost->scu_registers->sdma.unsolicited_frame_get_pointer);
+ /* Setup the put pointer for the unsolicited frame queue */
+ frame_queue_put_value = SCU_UFQPP_GEN_VAL(POINTER, 0);
+ writel(frame_queue_put_value,
+ &ihost->scu_registers->sdma.unsolicited_frame_put_pointer);
+}
+
+static void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status)
+{
+ if (ihost->sm.current_state_id == SCIC_STARTING) {
+ /*
+ * We move into the ready state, because some of the phys/ports
+ * may be up and operational.
+ */
+ sci_change_state(&ihost->sm, SCIC_READY);
+
+ isci_host_start_complete(ihost, status);
+ }
+}
+
+static bool is_phy_starting(struct isci_phy *iphy)
+{
+ enum sci_phy_states state;
+
+ state = iphy->sm.current_state_id;
+ switch (state) {
+ case SCI_PHY_STARTING:
+ case SCI_PHY_SUB_INITIAL:
+ case SCI_PHY_SUB_AWAIT_SAS_SPEED_EN:
+ case SCI_PHY_SUB_AWAIT_IAF_UF:
+ case SCI_PHY_SUB_AWAIT_SAS_POWER:
+ case SCI_PHY_SUB_AWAIT_SATA_POWER:
+ case SCI_PHY_SUB_AWAIT_SATA_PHY_EN:
+ case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN:
+ case SCI_PHY_SUB_AWAIT_SIG_FIS_UF:
+ case SCI_PHY_SUB_FINAL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * sci_controller_start_next_phy - start phy
+ * @scic: controller
+ *
+ * If all the phys have been started, then attempt to transition the
+ * controller to the READY state and inform the user
+ * (sci_cb_controller_start_complete()).
+ */
+static enum sci_status sci_controller_start_next_phy(struct isci_host *ihost)
+{
+ struct sci_oem_params *oem = &ihost->oem_parameters;
+ struct isci_phy *iphy;
+ enum sci_status status;
+
+ status = SCI_SUCCESS;
+
+ if (ihost->phy_startup_timer_pending)
+ return status;
+
+ if (ihost->next_phy_to_start >= SCI_MAX_PHYS) {
+ bool is_controller_start_complete = true;
+ u32 state;
+ u8 index;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ iphy = &ihost->phys[index];
+ state = iphy->sm.current_state_id;
+
+ if (!phy_get_non_dummy_port(iphy))
+ continue;
+
+ /* The controller start operation is complete iff:
+ * - all links have been given an opportunity to start
+ * - have no indication of a connected device
+ * - have an indication of a connected device and it has
+ * finished the link training process.
+ */
+ if ((iphy->is_in_link_training == false && state == SCI_PHY_INITIAL) ||
+ (iphy->is_in_link_training == false && state == SCI_PHY_STOPPED) ||
+ (iphy->is_in_link_training == true && is_phy_starting(iphy))) {
+ is_controller_start_complete = false;
+ break;
+ }
+ }
+
+ /*
+ * The controller has successfully finished the start process.
+ * Inform the SCI Core user and transition to the READY state. */
+ if (is_controller_start_complete == true) {
+ sci_controller_transition_to_ready(ihost, SCI_SUCCESS);
+ sci_del_timer(&ihost->phy_timer);
+ ihost->phy_startup_timer_pending = false;
+ }
+ } else {
+ iphy = &ihost->phys[ihost->next_phy_to_start];
+
+ if (oem->controller.mode_type == SCIC_PORT_MANUAL_CONFIGURATION_MODE) {
+ if (phy_get_non_dummy_port(iphy) == NULL) {
+ ihost->next_phy_to_start++;
+
+ /* Caution recursion ahead be forwarned
+ *
+ * The PHY was never added to a PORT in MPC mode
+ * so start the next phy in sequence This phy
+ * will never go link up and will not draw power
+ * the OEM parameters either configured the phy
+ * incorrectly for the PORT or it was never
+ * assigned to a PORT
+ */
+ return sci_controller_start_next_phy(ihost);
+ }
+ }
+
+ status = sci_phy_start(iphy);
+
+ if (status == SCI_SUCCESS) {
+ sci_mod_timer(&ihost->phy_timer,
+ SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT);
+ ihost->phy_startup_timer_pending = true;
+ } else {
+ dev_warn(&ihost->pdev->dev,
+ "%s: Controller stop operation failed "
+ "to stop phy %d because of status "
+ "%d.\n",
+ __func__,
+ ihost->phys[ihost->next_phy_to_start].phy_index,
+ status);
+ }
+
+ ihost->next_phy_to_start++;
+ }
+
+ return status;
+}
+
+static void phy_startup_timeout(unsigned long data)
+{
+ struct sci_timer *tmr = (struct sci_timer *)data;
+ struct isci_host *ihost = container_of(tmr, typeof(*ihost), phy_timer);
+ unsigned long flags;
+ enum sci_status status;
+
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+
+ if (tmr->cancel)
+ goto done;
+
+ ihost->phy_startup_timer_pending = false;
+
+ do {
+ status = sci_controller_start_next_phy(ihost);
+ } while (status != SCI_SUCCESS);
+
+done:
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+}
+
+static u16 isci_tci_active(struct isci_host *ihost)
+{
+ return CIRC_CNT(ihost->tci_head, ihost->tci_tail, SCI_MAX_IO_REQUESTS);
+}
+
+static enum sci_status sci_controller_start(struct isci_host *ihost,
+ u32 timeout)
+{
+ enum sci_status result;
+ u16 index;
+
+ if (ihost->sm.current_state_id != SCIC_INITIALIZED) {
+ dev_warn(&ihost->pdev->dev,
+ "SCIC Controller start operation requested in "
+ "invalid state\n");
+ return SCI_FAILURE_INVALID_STATE;
+ }
+
+ /* Build the TCi free pool */
+ BUILD_BUG_ON(SCI_MAX_IO_REQUESTS > 1 << sizeof(ihost->tci_pool[0]) * 8);
+ ihost->tci_head = 0;
+ ihost->tci_tail = 0;
+ for (index = 0; index < ihost->task_context_entries; index++)
+ isci_tci_free(ihost, index);
+
+ /* Build the RNi free pool */
+ sci_remote_node_table_initialize(&ihost->available_remote_nodes,
+ ihost->remote_node_entries);
+
+ /*
+ * Before anything else lets make sure we will not be
+ * interrupted by the hardware.
+ */
+ sci_controller_disable_interrupts(ihost);
+
+ /* Enable the port task scheduler */
+ sci_controller_enable_port_task_scheduler(ihost);
+
+ /* Assign all the task entries to ihost physical function */
+ sci_controller_assign_task_entries(ihost);
+
+ /* Now initialize the completion queue */
+ sci_controller_initialize_completion_queue(ihost);
+
+ /* Initialize the unsolicited frame queue for use */
+ sci_controller_initialize_unsolicited_frame_queue(ihost);
+
+ /* Start all of the ports on this controller */
+ for (index = 0; index < ihost->logical_port_entries; index++) {
+ struct isci_port *iport = &ihost->ports[index];
+
+ result = sci_port_start(iport);
+ if (result)
+ return result;
+ }
+
+ sci_controller_start_next_phy(ihost);
+
+ sci_mod_timer(&ihost->timer, timeout);
+
+ sci_change_state(&ihost->sm, SCIC_STARTING);
+
+ return SCI_SUCCESS;
+}
+
+void isci_host_scan_start(struct Scsi_Host *shost)
+{
+ struct isci_host *ihost = SHOST_TO_SAS_HA(shost)->lldd_ha;
+ unsigned long tmo = sci_controller_get_suggested_start_timeout(ihost);
+
+ set_bit(IHOST_START_PENDING, &ihost->flags);
+
+ spin_lock_irq(&ihost->scic_lock);
+ sci_controller_start(ihost, tmo);
+ sci_controller_enable_interrupts(ihost);
+ spin_unlock_irq(&ihost->scic_lock);
+}
+
+static void isci_host_stop_complete(struct isci_host *ihost, enum sci_status completion_status)
+{
+ isci_host_change_state(ihost, isci_stopped);
+ sci_controller_disable_interrupts(ihost);
+ clear_bit(IHOST_STOP_PENDING, &ihost->flags);
+ wake_up(&ihost->eventq);
+}
+
+static void sci_controller_completion_handler(struct isci_host *ihost)
+{
+ /* Empty out the completion queue */
+ if (sci_controller_completion_queue_has_entries(ihost))
+ sci_controller_process_completions(ihost);
+
+ /* Clear the interrupt and enable all interrupts again */
+ writel(SMU_ISR_COMPLETION, &ihost->smu_registers->interrupt_status);
+ /* Could we write the value of SMU_ISR_COMPLETION? */
+ writel(0xFF000000, &ihost->smu_registers->interrupt_mask);
+ writel(0, &ihost->smu_registers->interrupt_mask);
+}
+
+/**
+ * isci_host_completion_routine() - This function is the delayed service
+ * routine that calls the sci core library's completion handler. It's
+ * scheduled as a tasklet from the interrupt service routine when interrupts
+ * in use, or set as the timeout function in polled mode.
+ * @data: This parameter specifies the ISCI host object
+ *
+ */
+static void isci_host_completion_routine(unsigned long data)
+{
+ struct isci_host *ihost = (struct isci_host *)data;
+ struct list_head completed_request_list;
+ struct list_head errored_request_list;
+ struct list_head *current_position;
+ struct list_head *next_position;
+ struct isci_request *request;
+ struct isci_request *next_request;
+ struct sas_task *task;
+
+ INIT_LIST_HEAD(&completed_request_list);
+ INIT_LIST_HEAD(&errored_request_list);
+
+ spin_lock_irq(&ihost->scic_lock);
+
+ sci_controller_completion_handler(ihost);
+
+ /* Take the lists of completed I/Os from the host. */
+
+ list_splice_init(&ihost->requests_to_complete,
+ &completed_request_list);
+
+ /* Take the list of errored I/Os from the host. */
+ list_splice_init(&ihost->requests_to_errorback,
+ &errored_request_list);
+
+ spin_unlock_irq(&ihost->scic_lock);
+
+ /* Process any completions in the lists. */
+ list_for_each_safe(current_position, next_position,
+ &completed_request_list) {
+
+ request = list_entry(current_position, struct isci_request,
+ completed_node);
+ task = isci_request_access_task(request);
+
+ /* Normal notification (task_done) */
+ dev_dbg(&ihost->pdev->dev,
+ "%s: Normal - request/task = %p/%p\n",
+ __func__,
+ request,
+ task);
+
+ /* Return the task to libsas */
+ if (task != NULL) {
+
+ task->lldd_task = NULL;
+ if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+
+ /* If the task is already in the abort path,
+ * the task_done callback cannot be called.
+ */
+ task->task_done(task);
+ }
+ }
+
+ spin_lock_irq(&ihost->scic_lock);
+ isci_free_tag(ihost, request->io_tag);
+ spin_unlock_irq(&ihost->scic_lock);
+ }
+ list_for_each_entry_safe(request, next_request, &errored_request_list,
+ completed_node) {
+
+ task = isci_request_access_task(request);
+
+ /* Use sas_task_abort */
+ dev_warn(&ihost->pdev->dev,
+ "%s: Error - request/task = %p/%p\n",
+ __func__,
+ request,
+ task);
+
+ if (task != NULL) {
+
+ /* Put the task into the abort path if it's not there
+ * already.
+ */
+ if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED))
+ sas_task_abort(task);
+
+ } else {
+ /* This is a case where the request has completed with a
+ * status such that it needed further target servicing,
+ * but the sas_task reference has already been removed
+ * from the request. Since it was errored, it was not
+ * being aborted, so there is nothing to do except free
+ * it.
+ */
+
+ spin_lock_irq(&ihost->scic_lock);
+ /* Remove the request from the remote device's list
+ * of pending requests.
+ */
+ list_del_init(&request->dev_node);
+ isci_free_tag(ihost, request->io_tag);
+ spin_unlock_irq(&ihost->scic_lock);
+ }
+ }
+
+}
+
+/**
+ * sci_controller_stop() - This method will stop an individual controller
+ * object.This method will invoke the associated user callback upon
+ * completion. The completion callback is called when the following
+ * conditions are met: -# the method return status is SCI_SUCCESS. -# the
+ * controller has been quiesced. This method will ensure that all IO
+ * requests are quiesced, phys are stopped, and all additional operation by
+ * the hardware is halted.
+ * @controller: the handle to the controller object to stop.
+ * @timeout: This parameter specifies the number of milliseconds in which the
+ * stop operation should complete.
+ *
+ * The controller must be in the STARTED or STOPPED state. Indicate if the
+ * controller stop method succeeded or failed in some way. SCI_SUCCESS if the
+ * stop operation successfully began. SCI_WARNING_ALREADY_IN_STATE if the
+ * controller is already in the STOPPED state. SCI_FAILURE_INVALID_STATE if the
+ * controller is not either in the STARTED or STOPPED states.
+ */
+static enum sci_status sci_controller_stop(struct isci_host *ihost, u32 timeout)
+{
+ if (ihost->sm.current_state_id != SCIC_READY) {
+ dev_warn(&ihost->pdev->dev,
+ "SCIC Controller stop operation requested in "
+ "invalid state\n");
+ return SCI_FAILURE_INVALID_STATE;
+ }
+
+ sci_mod_timer(&ihost->timer, timeout);
+ sci_change_state(&ihost->sm, SCIC_STOPPING);
+ return SCI_SUCCESS;
+}
+
+/**
+ * sci_controller_reset() - This method will reset the supplied core
+ * controller regardless of the state of said controller. This operation is
+ * considered destructive. In other words, all current operations are wiped
+ * out. No IO completions for outstanding devices occur. Outstanding IO
+ * requests are not aborted or completed at the actual remote device.
+ * @controller: the handle to the controller object to reset.
+ *
+ * Indicate if the controller reset method succeeded or failed in some way.
+ * SCI_SUCCESS if the reset operation successfully started. SCI_FATAL_ERROR if
+ * the controller reset operation is unable to complete.
+ */
+static enum sci_status sci_controller_reset(struct isci_host *ihost)
+{
+ switch (ihost->sm.current_state_id) {
+ case SCIC_RESET:
+ case SCIC_READY:
+ case SCIC_STOPPED:
+ case SCIC_FAILED:
+ /*
+ * The reset operation is not a graceful cleanup, just
+ * perform the state transition.
+ */
+ sci_change_state(&ihost->sm, SCIC_RESETTING);
+ return SCI_SUCCESS;
+ default:
+ dev_warn(&ihost->pdev->dev,
+ "SCIC Controller reset operation requested in "
+ "invalid state\n");
+ return SCI_FAILURE_INVALID_STATE;
+ }
+}
+
+void isci_host_deinit(struct isci_host *ihost)
+{
+ int i;
+
+ isci_host_change_state(ihost, isci_stopping);
+ for (i = 0; i < SCI_MAX_PORTS; i++) {
+ struct isci_port *iport = &ihost->ports[i];
+ struct isci_remote_device *idev, *d;
+
+ list_for_each_entry_safe(idev, d, &iport->remote_dev_list, node) {
+ if (test_bit(IDEV_ALLOCATED, &idev->flags))
+ isci_remote_device_stop(ihost, idev);
+ }
+ }
+
+ set_bit(IHOST_STOP_PENDING, &ihost->flags);
+
+ spin_lock_irq(&ihost->scic_lock);
+ sci_controller_stop(ihost, SCIC_CONTROLLER_STOP_TIMEOUT);
+ spin_unlock_irq(&ihost->scic_lock);
+
+ wait_for_stop(ihost);
+ sci_controller_reset(ihost);
+
+ /* Cancel any/all outstanding port timers */
+ for (i = 0; i < ihost->logical_port_entries; i++) {
+ struct isci_port *iport = &ihost->ports[i];
+ del_timer_sync(&iport->timer.timer);
+ }
+
+ /* Cancel any/all outstanding phy timers */
+ for (i = 0; i < SCI_MAX_PHYS; i++) {
+ struct isci_phy *iphy = &ihost->phys[i];
+ del_timer_sync(&iphy->sata_timer.timer);
+ }
+
+ del_timer_sync(&ihost->port_agent.timer.timer);
+
+ del_timer_sync(&ihost->power_control.timer.timer);
+
+ del_timer_sync(&ihost->timer.timer);
+
+ del_timer_sync(&ihost->phy_timer.timer);
+}
+
+static void __iomem *scu_base(struct isci_host *isci_host)
+{
+ struct pci_dev *pdev = isci_host->pdev;
+ int id = isci_host->id;
+
+ return pcim_iomap_table(pdev)[SCI_SCU_BAR * 2] + SCI_SCU_BAR_SIZE * id;
+}
+
+static void __iomem *smu_base(struct isci_host *isci_host)
+{
+ struct pci_dev *pdev = isci_host->pdev;
+ int id = isci_host->id;
+
+ return pcim_iomap_table(pdev)[SCI_SMU_BAR * 2] + SCI_SMU_BAR_SIZE * id;
+}
+
+static void isci_user_parameters_get(struct sci_user_parameters *u)
+{
+ int i;
+
+ for (i = 0; i < SCI_MAX_PHYS; i++) {
+ struct sci_phy_user_params *u_phy = &u->phys[i];
+
+ u_phy->max_speed_generation = phy_gen;
+
+ /* we are not exporting these for now */
+ u_phy->align_insertion_frequency = 0x7f;
+ u_phy->in_connection_align_insertion_frequency = 0xff;
+ u_phy->notify_enable_spin_up_insertion_frequency = 0x33;
+ }
+
+ u->stp_inactivity_timeout = stp_inactive_to;
+ u->ssp_inactivity_timeout = ssp_inactive_to;
+ u->stp_max_occupancy_timeout = stp_max_occ_to;
+ u->ssp_max_occupancy_timeout = ssp_max_occ_to;
+ u->no_outbound_task_timeout = no_outbound_task_to;
+ u->max_number_concurrent_device_spin_up = max_concurr_spinup;
+}
+
+static void sci_controller_initial_state_enter(struct sci_base_state_machine *sm)
+{
+ struct isci_host *ihost = container_of(sm, typeof(*ihost), sm);
+
+ sci_change_state(&ihost->sm, SCIC_RESET);
+}
+
+static inline void sci_controller_starting_state_exit(struct sci_base_state_machine *sm)
+{
+ struct isci_host *ihost = container_of(sm, typeof(*ihost), sm);
+
+ sci_del_timer(&ihost->timer);
+}
+
+#define INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_LOWER_BOUND_NS 853
+#define INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_UPPER_BOUND_NS 1280
+#define INTERRUPT_COALESCE_TIMEOUT_MAX_US 2700000
+#define INTERRUPT_COALESCE_NUMBER_MAX 256
+#define INTERRUPT_COALESCE_TIMEOUT_ENCODE_MIN 7
+#define INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX 28
+
+/**
+ * sci_controller_set_interrupt_coalescence() - This method allows the user to
+ * configure the interrupt coalescence.
+ * @controller: This parameter represents the handle to the controller object
+ * for which its interrupt coalesce register is overridden.
+ * @coalesce_number: Used to control the number of entries in the Completion
+ * Queue before an interrupt is generated. If the number of entries exceed
+ * this number, an interrupt will be generated. The valid range of the input
+ * is [0, 256]. A setting of 0 results in coalescing being disabled.
+ * @coalesce_timeout: Timeout value in microseconds. The valid range of the
+ * input is [0, 2700000] . A setting of 0 is allowed and results in no
+ * interrupt coalescing timeout.
+ *
+ * Indicate if the user successfully set the interrupt coalesce parameters.
+ * SCI_SUCCESS The user successfully updated the interrutp coalescence.
+ * SCI_FAILURE_INVALID_PARAMETER_VALUE The user input value is out of range.
+ */
+static enum sci_status
+sci_controller_set_interrupt_coalescence(struct isci_host *ihost,
+ u32 coalesce_number,
+ u32 coalesce_timeout)
+{
+ u8 timeout_encode = 0;
+ u32 min = 0;
+ u32 max = 0;
+
+ /* Check if the input parameters fall in the range. */
+ if (coalesce_number > INTERRUPT_COALESCE_NUMBER_MAX)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ /*
+ * Defined encoding for interrupt coalescing timeout:
+ * Value Min Max Units
+ * ----- --- --- -----
+ * 0 - - Disabled
+ * 1 13.3 20.0 ns
+ * 2 26.7 40.0
+ * 3 53.3 80.0
+ * 4 106.7 160.0
+ * 5 213.3 320.0
+ * 6 426.7 640.0
+ * 7 853.3 1280.0
+ * 8 1.7 2.6 us
+ * 9 3.4 5.1
+ * 10 6.8 10.2
+ * 11 13.7 20.5
+ * 12 27.3 41.0
+ * 13 54.6 81.9
+ * 14 109.2 163.8
+ * 15 218.5 327.7
+ * 16 436.9 655.4
+ * 17 873.8 1310.7
+ * 18 1.7 2.6 ms
+ * 19 3.5 5.2
+ * 20 7.0 10.5
+ * 21 14.0 21.0
+ * 22 28.0 41.9
+ * 23 55.9 83.9
+ * 24 111.8 167.8
+ * 25 223.7 335.5
+ * 26 447.4 671.1
+ * 27 894.8 1342.2
+ * 28 1.8 2.7 s
+ * Others Undefined */
+
+ /*
+ * Use the table above to decide the encode of interrupt coalescing timeout
+ * value for register writing. */
+ if (coalesce_timeout == 0)
+ timeout_encode = 0;
+ else{
+ /* make the timeout value in unit of (10 ns). */
+ coalesce_timeout = coalesce_timeout * 100;
+ min = INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_LOWER_BOUND_NS / 10;
+ max = INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_UPPER_BOUND_NS / 10;
+
+ /* get the encode of timeout for register writing. */
+ for (timeout_encode = INTERRUPT_COALESCE_TIMEOUT_ENCODE_MIN;
+ timeout_encode <= INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX;
+ timeout_encode++) {
+ if (min <= coalesce_timeout && max > coalesce_timeout)
+ break;
+ else if (coalesce_timeout >= max && coalesce_timeout < min * 2
+ && coalesce_timeout <= INTERRUPT_COALESCE_TIMEOUT_MAX_US * 100) {
+ if ((coalesce_timeout - max) < (2 * min - coalesce_timeout))
+ break;
+ else{
+ timeout_encode++;
+ break;
+ }
+ } else {
+ max = max * 2;
+ min = min * 2;
+ }
+ }
+
+ if (timeout_encode == INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX + 1)
+ /* the value is out of range. */
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+
+ writel(SMU_ICC_GEN_VAL(NUMBER, coalesce_number) |
+ SMU_ICC_GEN_VAL(TIMER, timeout_encode),
+ &ihost->smu_registers->interrupt_coalesce_control);
+
+
+ ihost->interrupt_coalesce_number = (u16)coalesce_number;
+ ihost->interrupt_coalesce_timeout = coalesce_timeout / 100;
+
+ return SCI_SUCCESS;
+}
+
+
+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);
+}
+
+static void sci_controller_ready_state_exit(struct sci_base_state_machine *sm)
+{
+ struct isci_host *ihost = container_of(sm, typeof(*ihost), sm);
+
+ /* disable interrupt coalescence. */
+ sci_controller_set_interrupt_coalescence(ihost, 0, 0);
+}
+
+static enum sci_status sci_controller_stop_phys(struct isci_host *ihost)
+{
+ u32 index;
+ enum sci_status status;
+ enum sci_status phy_status;
+
+ status = SCI_SUCCESS;
+
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ phy_status = sci_phy_stop(&ihost->phys[index]);
+
+ if (phy_status != SCI_SUCCESS &&
+ phy_status != SCI_FAILURE_INVALID_STATE) {
+ status = SCI_FAILURE;
+
+ dev_warn(&ihost->pdev->dev,
+ "%s: Controller stop operation failed to stop "
+ "phy %d because of status %d.\n",
+ __func__,
+ ihost->phys[index].phy_index, phy_status);
+ }
+ }
+
+ return status;
+}
+
+static enum sci_status sci_controller_stop_ports(struct isci_host *ihost)
+{
+ u32 index;
+ enum sci_status port_status;
+ enum sci_status status = SCI_SUCCESS;
+
+ for (index = 0; index < ihost->logical_port_entries; index++) {
+ struct isci_port *iport = &ihost->ports[index];
+
+ port_status = sci_port_stop(iport);
+
+ if ((port_status != SCI_SUCCESS) &&
+ (port_status != SCI_FAILURE_INVALID_STATE)) {
+ status = SCI_FAILURE;
+
+ dev_warn(&ihost->pdev->dev,
+ "%s: Controller stop operation failed to "
+ "stop port %d because of status %d.\n",
+ __func__,
+ iport->logical_port_index,
+ port_status);
+ }
+ }
+
+ return status;
+}
+
+static enum sci_status sci_controller_stop_devices(struct isci_host *ihost)
+{
+ u32 index;
+ enum sci_status status;
+ enum sci_status device_status;
+
+ status = SCI_SUCCESS;
+
+ for (index = 0; index < ihost->remote_node_entries; index++) {
+ if (ihost->device_table[index] != NULL) {
+ /* / @todo What timeout value do we want to provide to this request? */
+ device_status = sci_remote_device_stop(ihost->device_table[index], 0);
+
+ if ((device_status != SCI_SUCCESS) &&
+ (device_status != SCI_FAILURE_INVALID_STATE)) {
+ dev_warn(&ihost->pdev->dev,
+ "%s: Controller stop operation failed "
+ "to stop device 0x%p because of "
+ "status %d.\n",
+ __func__,
+ ihost->device_table[index], device_status);
+ }
+ }
+ }
+
+ return status;
+}
+
+static void sci_controller_stopping_state_enter(struct sci_base_state_machine *sm)
+{
+ struct isci_host *ihost = container_of(sm, typeof(*ihost), sm);
+
+ /* Stop all of the components for this controller */
+ sci_controller_stop_phys(ihost);
+ sci_controller_stop_ports(ihost);
+ sci_controller_stop_devices(ihost);
+}
+
+static void sci_controller_stopping_state_exit(struct sci_base_state_machine *sm)
+{
+ struct isci_host *ihost = container_of(sm, typeof(*ihost), sm);
+
+ sci_del_timer(&ihost->timer);
+}
+
+static void sci_controller_reset_hardware(struct isci_host *ihost)
+{
+ /* Disable interrupts so we dont take any spurious interrupts */
+ sci_controller_disable_interrupts(ihost);
+
+ /* Reset the SCU */
+ writel(0xFFFFFFFF, &ihost->smu_registers->soft_reset_control);
+
+ /* Delay for 1ms to before clearing the CQP and UFQPR. */
+ udelay(1000);
+
+ /* The write to the CQGR clears the CQP */
+ writel(0x00000000, &ihost->smu_registers->completion_queue_get);
+
+ /* The write to the UFQGP clears the UFQPR */
+ writel(0, &ihost->scu_registers->sdma.unsolicited_frame_get_pointer);
+}
+
+static void sci_controller_resetting_state_enter(struct sci_base_state_machine *sm)
+{
+ struct isci_host *ihost = container_of(sm, typeof(*ihost), sm);
+
+ sci_controller_reset_hardware(ihost);
+ sci_change_state(&ihost->sm, SCIC_RESET);
+}
+
+static const struct sci_base_state sci_controller_state_table[] = {
+ [SCIC_INITIAL] = {
+ .enter_state = sci_controller_initial_state_enter,
+ },
+ [SCIC_RESET] = {},
+ [SCIC_INITIALIZING] = {},
+ [SCIC_INITIALIZED] = {},
+ [SCIC_STARTING] = {
+ .exit_state = sci_controller_starting_state_exit,
+ },
+ [SCIC_READY] = {
+ .enter_state = sci_controller_ready_state_enter,
+ .exit_state = sci_controller_ready_state_exit,
+ },
+ [SCIC_RESETTING] = {
+ .enter_state = sci_controller_resetting_state_enter,
+ },
+ [SCIC_STOPPING] = {
+ .enter_state = sci_controller_stopping_state_enter,
+ .exit_state = sci_controller_stopping_state_exit,
+ },
+ [SCIC_STOPPED] = {},
+ [SCIC_FAILED] = {}
+};
+
+static void sci_controller_set_default_config_parameters(struct isci_host *ihost)
+{
+ /* these defaults are overridden by the platform / firmware */
+ u16 index;
+
+ /* Default to APC mode. */
+ ihost->oem_parameters.controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
+
+ /* Default to APC mode. */
+ ihost->oem_parameters.controller.max_concurrent_dev_spin_up = 1;
+
+ /* Default to no SSC operation. */
+ ihost->oem_parameters.controller.do_enable_ssc = false;
+
+ /* Initialize all of the port parameter information to narrow ports. */
+ for (index = 0; index < SCI_MAX_PORTS; index++) {
+ ihost->oem_parameters.ports[index].phy_mask = 0;
+ }
+
+ /* Initialize all of the phy parameter information. */
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ /* Default to 6G (i.e. Gen 3) for now. */
+ ihost->user_parameters.phys[index].max_speed_generation = 3;
+
+ /* the frequencies cannot be 0 */
+ ihost->user_parameters.phys[index].align_insertion_frequency = 0x7f;
+ ihost->user_parameters.phys[index].in_connection_align_insertion_frequency = 0xff;
+ ihost->user_parameters.phys[index].notify_enable_spin_up_insertion_frequency = 0x33;
+
+ /*
+ * Previous Vitesse based expanders had a arbitration issue that
+ * is worked around by having the upper 32-bits of SAS address
+ * with a value greater then the Vitesse company identifier.
+ * Hence, usage of 0x5FCFFFFF. */
+ ihost->oem_parameters.phys[index].sas_address.low = 0x1 + ihost->id;
+ ihost->oem_parameters.phys[index].sas_address.high = 0x5FCFFFFF;
+ }
+
+ ihost->user_parameters.stp_inactivity_timeout = 5;
+ ihost->user_parameters.ssp_inactivity_timeout = 5;
+ ihost->user_parameters.stp_max_occupancy_timeout = 5;
+ ihost->user_parameters.ssp_max_occupancy_timeout = 20;
+ ihost->user_parameters.no_outbound_task_timeout = 20;
+}
+
+static void controller_timeout(unsigned long data)
+{
+ struct sci_timer *tmr = (struct sci_timer *)data;
+ struct isci_host *ihost = container_of(tmr, typeof(*ihost), timer);
+ struct sci_base_state_machine *sm = &ihost->sm;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+
+ if (tmr->cancel)
+ goto done;
+
+ if (sm->current_state_id == SCIC_STARTING)
+ sci_controller_transition_to_ready(ihost, SCI_FAILURE_TIMEOUT);
+ else if (sm->current_state_id == SCIC_STOPPING) {
+ sci_change_state(sm, SCIC_FAILED);
+ isci_host_stop_complete(ihost, SCI_FAILURE_TIMEOUT);
+ } else /* / @todo Now what do we want to do in this case? */
+ dev_err(&ihost->pdev->dev,
+ "%s: Controller timer fired when controller was not "
+ "in a state being timed.\n",
+ __func__);
+
+done:
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+}
+
+static enum sci_status sci_controller_construct(struct isci_host *ihost,
+ void __iomem *scu_base,
+ void __iomem *smu_base)
+{
+ u8 i;
+
+ sci_init_sm(&ihost->sm, sci_controller_state_table, SCIC_INITIAL);
+
+ ihost->scu_registers = scu_base;
+ ihost->smu_registers = smu_base;
+
+ sci_port_configuration_agent_construct(&ihost->port_agent);
+
+ /* Construct the ports for this controller */
+ for (i = 0; i < SCI_MAX_PORTS; i++)
+ sci_port_construct(&ihost->ports[i], i, ihost);
+ sci_port_construct(&ihost->ports[i], SCIC_SDS_DUMMY_PORT, ihost);
+
+ /* Construct the phys for this controller */
+ for (i = 0; i < SCI_MAX_PHYS; i++) {
+ /* Add all the PHYs to the dummy port */
+ sci_phy_construct(&ihost->phys[i],
+ &ihost->ports[SCI_MAX_PORTS], i);
+ }
+
+ ihost->invalid_phy_mask = 0;
+
+ sci_init_timer(&ihost->timer, controller_timeout);
+
+ /* Initialize the User and OEM parameters to default values. */
+ sci_controller_set_default_config_parameters(ihost);
+
+ return sci_controller_reset(ihost);
+}
+
+int sci_oem_parameters_validate(struct sci_oem_params *oem)
+{
+ int i;
+
+ for (i = 0; i < SCI_MAX_PORTS; i++)
+ if (oem->ports[i].phy_mask > SCIC_SDS_PARM_PHY_MASK_MAX)
+ return -EINVAL;
+
+ for (i = 0; i < SCI_MAX_PHYS; i++)
+ if (oem->phys[i].sas_address.high == 0 &&
+ oem->phys[i].sas_address.low == 0)
+ return -EINVAL;
+
+ if (oem->controller.mode_type == SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE) {
+ for (i = 0; i < SCI_MAX_PHYS; i++)
+ if (oem->ports[i].phy_mask != 0)
+ return -EINVAL;
+ } else if (oem->controller.mode_type == SCIC_PORT_MANUAL_CONFIGURATION_MODE) {
+ u8 phy_mask = 0;
+
+ for (i = 0; i < SCI_MAX_PHYS; i++)
+ phy_mask |= oem->ports[i].phy_mask;
+
+ if (phy_mask == 0)
+ return -EINVAL;
+ } else
+ return -EINVAL;
+
+ if (oem->controller.max_concurrent_dev_spin_up > MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT)
+ return -EINVAL;
+
+ return 0;
+}
+
+static enum sci_status sci_oem_parameters_set(struct isci_host *ihost)
+{
+ u32 state = ihost->sm.current_state_id;
+
+ if (state == SCIC_RESET ||
+ state == SCIC_INITIALIZING ||
+ state == SCIC_INITIALIZED) {
+
+ if (sci_oem_parameters_validate(&ihost->oem_parameters))
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+static void power_control_timeout(unsigned long data)
+{
+ struct sci_timer *tmr = (struct sci_timer *)data;
+ struct isci_host *ihost = container_of(tmr, typeof(*ihost), power_control.timer);
+ struct isci_phy *iphy;
+ unsigned long flags;
+ u8 i;
+
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+
+ if (tmr->cancel)
+ goto done;
+
+ ihost->power_control.phys_granted_power = 0;
+
+ if (ihost->power_control.phys_waiting == 0) {
+ ihost->power_control.timer_started = false;
+ goto done;
+ }
+
+ for (i = 0; i < SCI_MAX_PHYS; i++) {
+
+ if (ihost->power_control.phys_waiting == 0)
+ break;
+
+ iphy = ihost->power_control.requesters[i];
+ if (iphy == NULL)
+ continue;
+
+ if (ihost->power_control.phys_granted_power >=
+ ihost->oem_parameters.controller.max_concurrent_dev_spin_up)
+ break;
+
+ ihost->power_control.requesters[i] = NULL;
+ ihost->power_control.phys_waiting--;
+ ihost->power_control.phys_granted_power++;
+ sci_phy_consume_power_handler(iphy);
+ }
+
+ /*
+ * It doesn't matter if the power list is empty, we need to start the
+ * timer in case another phy becomes ready.
+ */
+ sci_mod_timer(tmr, SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL);
+ ihost->power_control.timer_started = true;
+
+done:
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+}
+
+void sci_controller_power_control_queue_insert(struct isci_host *ihost,
+ struct isci_phy *iphy)
+{
+ BUG_ON(iphy == NULL);
+
+ if (ihost->power_control.phys_granted_power <
+ ihost->oem_parameters.controller.max_concurrent_dev_spin_up) {
+ ihost->power_control.phys_granted_power++;
+ sci_phy_consume_power_handler(iphy);
+
+ /*
+ * stop and start the power_control timer. When the timer fires, the
+ * no_of_phys_granted_power will be set to 0
+ */
+ if (ihost->power_control.timer_started)
+ sci_del_timer(&ihost->power_control.timer);
+
+ sci_mod_timer(&ihost->power_control.timer,
+ SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL);
+ ihost->power_control.timer_started = true;
+
+ } else {
+ /* Add the phy in the waiting list */
+ ihost->power_control.requesters[iphy->phy_index] = iphy;
+ ihost->power_control.phys_waiting++;
+ }
+}
+
+void sci_controller_power_control_queue_remove(struct isci_host *ihost,
+ struct isci_phy *iphy)
+{
+ BUG_ON(iphy == NULL);
+
+ if (ihost->power_control.requesters[iphy->phy_index])
+ ihost->power_control.phys_waiting--;
+
+ ihost->power_control.requesters[iphy->phy_index] = NULL;
+}
+
+#define AFE_REGISTER_WRITE_DELAY 10
+
+/* Initialize the AFE for this phy index. We need to read the AFE setup from
+ * the OEM parameters
+ */
+static void sci_controller_afe_initialization(struct isci_host *ihost)
+{
+ const struct sci_oem_params *oem = &ihost->oem_parameters;
+ struct pci_dev *pdev = ihost->pdev;
+ u32 afe_status;
+ u32 phy_id;
+
+ /* Clear DFX Status registers */
+ writel(0x0081000f, &ihost->scu_registers->afe.afe_dfx_master_control0);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+
+ if (is_b0(pdev)) {
+ /* PM Rx Equalization Save, PM SPhy Rx Acknowledgement
+ * Timer, PM Stagger Timer */
+ writel(0x0007BFFF, &ihost->scu_registers->afe.afe_pmsn_master_control2);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ /* Configure bias currents to normal */
+ if (is_a2(pdev))
+ writel(0x00005A00, &ihost->scu_registers->afe.afe_bias_control);
+ else if (is_b0(pdev) || is_c0(pdev))
+ writel(0x00005F00, &ihost->scu_registers->afe.afe_bias_control);
+
+ udelay(AFE_REGISTER_WRITE_DELAY);
+
+ /* Enable PLL */
+ if (is_b0(pdev) || is_c0(pdev))
+ writel(0x80040A08, &ihost->scu_registers->afe.afe_pll_control0);
+ else
+ writel(0x80040908, &ihost->scu_registers->afe.afe_pll_control0);
+
+ udelay(AFE_REGISTER_WRITE_DELAY);
+
+ /* Wait for the PLL to lock */
+ do {
+ afe_status = readl(&ihost->scu_registers->afe.afe_common_block_status);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+ } while ((afe_status & 0x00001000) == 0);
+
+ if (is_a2(pdev)) {
+ /* Shorten SAS SNW lock time (RxLock timer value from 76 us to 50 us) */
+ writel(0x7bcc96ad, &ihost->scu_registers->afe.afe_pmsn_master_control0);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++) {
+ const struct sci_phy_oem_params *oem_phy = &oem->phys[phy_id];
+
+ if (is_b0(pdev)) {
+ /* Configure transmitter SSC parameters */
+ writel(0x00030000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_ssc_control);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+ } else if (is_c0(pdev)) {
+ /* Configure transmitter SSC parameters */
+ writel(0x0003000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_ssc_control);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+
+ /*
+ * All defaults, except the Receive Word Alignament/Comma Detect
+ * Enable....(0xe800) */
+ writel(0x00004500, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control0);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+ } else {
+ /*
+ * All defaults, except the Receive Word Alignament/Comma Detect
+ * Enable....(0xe800) */
+ writel(0x00004512, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control0);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+
+ writel(0x0050100F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control1);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ /*
+ * Power up TX and RX out from power down (PWRDNTX and PWRDNRX)
+ * & increase TX int & ext bias 20%....(0xe85c) */
+ if (is_a2(pdev))
+ writel(0x000003F0, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control);
+ else if (is_b0(pdev)) {
+ /* Power down TX and RX (PWRDNTX and PWRDNRX) */
+ writel(0x000003D7, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+
+ /*
+ * Power up TX and RX out from power down (PWRDNTX and PWRDNRX)
+ * & increase TX int & ext bias 20%....(0xe85c) */
+ writel(0x000003D4, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control);
+ } else {
+ writel(0x000001E7, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+
+ /*
+ * Power up TX and RX out from power down (PWRDNTX and PWRDNRX)
+ * & increase TX int & ext bias 20%....(0xe85c) */
+ writel(0x000001E4, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control);
+ }
+ udelay(AFE_REGISTER_WRITE_DELAY);
+
+ if (is_a2(pdev)) {
+ /* Enable TX equalization (0xe824) */
+ writel(0x00040000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_control);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ /*
+ * RDPI=0x0(RX Power On), RXOOBDETPDNC=0x0, TPD=0x0(TX Power On),
+ * RDD=0x0(RX Detect Enabled) ....(0xe800) */
+ writel(0x00004100, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control0);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+
+ /* Leave DFE/FFE on */
+ if (is_a2(pdev))
+ writel(0x3F11103F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control0);
+ else if (is_b0(pdev)) {
+ writel(0x3F11103F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control0);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+ /* Enable TX equalization (0xe824) */
+ writel(0x00040000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_control);
+ } else {
+ writel(0x0140DF0F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control1);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+
+ writel(0x3F6F103F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control0);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+
+ /* Enable TX equalization (0xe824) */
+ writel(0x00040000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_control);
+ }
+
+ udelay(AFE_REGISTER_WRITE_DELAY);
+
+ writel(oem_phy->afe_tx_amp_control0,
+ &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control0);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+
+ writel(oem_phy->afe_tx_amp_control1,
+ &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control1);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+
+ writel(oem_phy->afe_tx_amp_control2,
+ &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control2);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+
+ writel(oem_phy->afe_tx_amp_control3,
+ &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control3);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+ }
+
+ /* Transfer control to the PEs */
+ writel(0x00010f00, &ihost->scu_registers->afe.afe_dfx_master_control0);
+ udelay(AFE_REGISTER_WRITE_DELAY);
+}
+
+static void sci_controller_initialize_power_control(struct isci_host *ihost)
+{
+ sci_init_timer(&ihost->power_control.timer, power_control_timeout);
+
+ memset(ihost->power_control.requesters, 0,
+ sizeof(ihost->power_control.requesters));
+
+ ihost->power_control.phys_waiting = 0;
+ ihost->power_control.phys_granted_power = 0;
+}
+
+static enum sci_status sci_controller_initialize(struct isci_host *ihost)
+{
+ struct sci_base_state_machine *sm = &ihost->sm;
+ enum sci_status result = SCI_FAILURE;
+ unsigned long i, state, val;
+
+ if (ihost->sm.current_state_id != SCIC_RESET) {
+ dev_warn(&ihost->pdev->dev,
+ "SCIC Controller initialize operation requested "
+ "in invalid state\n");
+ return SCI_FAILURE_INVALID_STATE;
+ }
+
+ sci_change_state(sm, SCIC_INITIALIZING);
+
+ sci_init_timer(&ihost->phy_timer, phy_startup_timeout);
+
+ ihost->next_phy_to_start = 0;
+ ihost->phy_startup_timer_pending = false;
+
+ sci_controller_initialize_power_control(ihost);
+
+ /*
+ * There is nothing to do here for B0 since we do not have to
+ * program the AFE registers.
+ * / @todo The AFE settings are supposed to be correct for the B0 but
+ * / presently they seem to be wrong. */
+ sci_controller_afe_initialization(ihost);
+
+
+ /* Take the hardware out of reset */
+ writel(0, &ihost->smu_registers->soft_reset_control);
+
+ /*
+ * / @todo Provide meaningfull error code for hardware failure
+ * result = SCI_FAILURE_CONTROLLER_HARDWARE; */
+ for (i = 100; i >= 1; i--) {
+ u32 status;
+
+ /* Loop until the hardware reports success */
+ udelay(SCU_CONTEXT_RAM_INIT_STALL_TIME);
+ status = readl(&ihost->smu_registers->control_status);
+
+ if ((status & SCU_RAM_INIT_COMPLETED) == SCU_RAM_INIT_COMPLETED)
+ break;
+ }
+ if (i == 0)
+ goto out;
+
+ /*
+ * Determine what are the actaul device capacities that the
+ * hardware will support */
+ val = readl(&ihost->smu_registers->device_context_capacity);
+
+ /* Record the smaller of the two capacity values */
+ ihost->logical_port_entries = min(smu_max_ports(val), SCI_MAX_PORTS);
+ ihost->task_context_entries = min(smu_max_task_contexts(val), SCI_MAX_IO_REQUESTS);
+ ihost->remote_node_entries = min(smu_max_rncs(val), SCI_MAX_REMOTE_DEVICES);
+
+ /*
+ * Make all PEs that are unassigned match up with the
+ * logical ports
+ */
+ for (i = 0; i < ihost->logical_port_entries; i++) {
+ struct scu_port_task_scheduler_group_registers __iomem
+ *ptsg = &ihost->scu_registers->peg0.ptsg;
+
+ writel(i, &ptsg->protocol_engine[i]);
+ }
+
+ /* Initialize hardware PCI Relaxed ordering in DMA engines */
+ val = readl(&ihost->scu_registers->sdma.pdma_configuration);
+ val |= SCU_PDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
+ writel(val, &ihost->scu_registers->sdma.pdma_configuration);
+
+ val = readl(&ihost->scu_registers->sdma.cdma_configuration);
+ val |= SCU_CDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
+ writel(val, &ihost->scu_registers->sdma.cdma_configuration);
+
+ /*
+ * Initialize the PHYs before the PORTs because the PHY registers
+ * are accessed during the port initialization.
+ */
+ for (i = 0; i < SCI_MAX_PHYS; i++) {
+ result = sci_phy_initialize(&ihost->phys[i],
+ &ihost->scu_registers->peg0.pe[i].tl,
+ &ihost->scu_registers->peg0.pe[i].ll);
+ if (result != SCI_SUCCESS)
+ goto out;
+ }
+
+ for (i = 0; i < ihost->logical_port_entries; i++) {
+ struct isci_port *iport = &ihost->ports[i];
+
+ iport->port_task_scheduler_registers = &ihost->scu_registers->peg0.ptsg.port[i];
+ iport->port_pe_configuration_register = &ihost->scu_registers->peg0.ptsg.protocol_engine[0];
+ iport->viit_registers = &ihost->scu_registers->peg0.viit[i];
+ }
+
+ result = sci_port_configuration_agent_initialize(ihost, &ihost->port_agent);
+
+ out:
+ /* Advance the controller state machine */
+ if (result == SCI_SUCCESS)
+ state = SCIC_INITIALIZED;
+ else
+ state = SCIC_FAILED;
+ sci_change_state(sm, state);
+
+ return result;
+}
+
+static enum sci_status sci_user_parameters_set(struct isci_host *ihost,
+ struct sci_user_parameters *sci_parms)
+{
+ u32 state = ihost->sm.current_state_id;
+
+ if (state == SCIC_RESET ||
+ state == SCIC_INITIALIZING ||
+ state == SCIC_INITIALIZED) {
+ u16 index;
+
+ /*
+ * Validate the user parameters. If they are not legal, then
+ * return a failure.
+ */
+ for (index = 0; index < SCI_MAX_PHYS; index++) {
+ struct sci_phy_user_params *user_phy;
+
+ user_phy = &sci_parms->phys[index];
+
+ if (!((user_phy->max_speed_generation <=
+ SCIC_SDS_PARM_MAX_SPEED) &&
+ (user_phy->max_speed_generation >
+ SCIC_SDS_PARM_NO_SPEED)))
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ if (user_phy->in_connection_align_insertion_frequency <
+ 3)
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ if ((user_phy->in_connection_align_insertion_frequency <
+ 3) ||
+ (user_phy->align_insertion_frequency == 0) ||
+ (user_phy->
+ notify_enable_spin_up_insertion_frequency ==
+ 0))
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+ }
+
+ if ((sci_parms->stp_inactivity_timeout == 0) ||
+ (sci_parms->ssp_inactivity_timeout == 0) ||
+ (sci_parms->stp_max_occupancy_timeout == 0) ||
+ (sci_parms->ssp_max_occupancy_timeout == 0) ||
+ (sci_parms->no_outbound_task_timeout == 0))
+ return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+ memcpy(&ihost->user_parameters, sci_parms, sizeof(*sci_parms));
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INVALID_STATE;
+}
+
+static int sci_controller_mem_init(struct isci_host *ihost)
+{
+ struct device *dev = &ihost->pdev->dev;
+ dma_addr_t dma;
+ size_t size;
+ int err;
+
+ size = SCU_MAX_COMPLETION_QUEUE_ENTRIES * sizeof(u32);
+ ihost->completion_queue = dmam_alloc_coherent(dev, size, &dma, GFP_KERNEL);
+ if (!ihost->completion_queue)
+ return -ENOMEM;
+
+ writel(lower_32_bits(dma), &ihost->smu_registers->completion_queue_lower);
+ writel(upper_32_bits(dma), &ihost->smu_registers->completion_queue_upper);
+
+ size = ihost->remote_node_entries * sizeof(union scu_remote_node_context);
+ ihost->remote_node_context_table = dmam_alloc_coherent(dev, size, &dma,
+ GFP_KERNEL);
+ if (!ihost->remote_node_context_table)
+ return -ENOMEM;
+
+ writel(lower_32_bits(dma), &ihost->smu_registers->remote_node_context_lower);
+ writel(upper_32_bits(dma), &ihost->smu_registers->remote_node_context_upper);
+
+ size = ihost->task_context_entries * sizeof(struct scu_task_context),
+ ihost->task_context_table = dmam_alloc_coherent(dev, size, &dma, GFP_KERNEL);
+ if (!ihost->task_context_table)
+ return -ENOMEM;
+
+ ihost->task_context_dma = dma;
+ writel(lower_32_bits(dma), &ihost->smu_registers->host_task_table_lower);
+ writel(upper_32_bits(dma), &ihost->smu_registers->host_task_table_upper);
+
+ err = sci_unsolicited_frame_control_construct(ihost);
+ if (err)
+ return err;
+
+ /*
+ * Inform the silicon as to the location of the UF headers and
+ * address table.
+ */
+ writel(lower_32_bits(ihost->uf_control.headers.physical_address),
+ &ihost->scu_registers->sdma.uf_header_base_address_lower);
+ writel(upper_32_bits(ihost->uf_control.headers.physical_address),
+ &ihost->scu_registers->sdma.uf_header_base_address_upper);
+
+ writel(lower_32_bits(ihost->uf_control.address_table.physical_address),
+ &ihost->scu_registers->sdma.uf_address_table_lower);
+ writel(upper_32_bits(ihost->uf_control.address_table.physical_address),
+ &ihost->scu_registers->sdma.uf_address_table_upper);
+
+ return 0;
+}
+
+int isci_host_init(struct isci_host *ihost)
+{
+ int err = 0, i;
+ enum sci_status status;
+ struct sci_user_parameters sci_user_params;
+ struct isci_pci_info *pci_info = to_pci_info(ihost->pdev);
+
+ spin_lock_init(&ihost->state_lock);
+ spin_lock_init(&ihost->scic_lock);
+ init_waitqueue_head(&ihost->eventq);
+
+ isci_host_change_state(ihost, isci_starting);
+
+ status = sci_controller_construct(ihost, scu_base(ihost),
+ smu_base(ihost));
+
+ if (status != SCI_SUCCESS) {
+ dev_err(&ihost->pdev->dev,
+ "%s: sci_controller_construct failed - status = %x\n",
+ __func__,
+ status);
+ return -ENODEV;
+ }
+
+ ihost->sas_ha.dev = &ihost->pdev->dev;
+ ihost->sas_ha.lldd_ha = ihost;
+
+ /*
+ * grab initial values stored in the controller object for OEM and USER
+ * parameters
+ */
+ isci_user_parameters_get(&sci_user_params);
+ status = sci_user_parameters_set(ihost, &sci_user_params);
+ if (status != SCI_SUCCESS) {
+ dev_warn(&ihost->pdev->dev,
+ "%s: sci_user_parameters_set failed\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ /* grab any OEM parameters specified in orom */
+ if (pci_info->orom) {
+ status = isci_parse_oem_parameters(&ihost->oem_parameters,
+ pci_info->orom,
+ ihost->id);
+ if (status != SCI_SUCCESS) {
+ dev_warn(&ihost->pdev->dev,
+ "parsing firmware oem parameters failed\n");
+ return -EINVAL;
+ }
+ }
+
+ status = sci_oem_parameters_set(ihost);
+ if (status != SCI_SUCCESS) {
+ dev_warn(&ihost->pdev->dev,
+ "%s: sci_oem_parameters_set failed\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ tasklet_init(&ihost->completion_tasklet,
+ isci_host_completion_routine, (unsigned long)ihost);
+
+ INIT_LIST_HEAD(&ihost->requests_to_complete);
+ INIT_LIST_HEAD(&ihost->requests_to_errorback);
+
+ spin_lock_irq(&ihost->scic_lock);
+ status = sci_controller_initialize(ihost);
+ spin_unlock_irq(&ihost->scic_lock);
+ if (status != SCI_SUCCESS) {
+ dev_warn(&ihost->pdev->dev,
+ "%s: sci_controller_initialize failed -"
+ " status = 0x%x\n",
+ __func__, status);
+ return -ENODEV;
+ }
+
+ err = sci_controller_mem_init(ihost);
+ if (err)
+ return err;
+
+ for (i = 0; i < SCI_MAX_PORTS; i++)
+ isci_port_init(&ihost->ports[i], ihost, i);
+
+ for (i = 0; i < SCI_MAX_PHYS; i++)
+ isci_phy_init(&ihost->phys[i], ihost, i);
+
+ for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) {
+ struct isci_remote_device *idev = &ihost->devices[i];
+
+ INIT_LIST_HEAD(&idev->reqs_in_process);
+ INIT_LIST_HEAD(&idev->node);
+ }
+
+ for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) {
+ struct isci_request *ireq;
+ dma_addr_t dma;
+
+ ireq = dmam_alloc_coherent(&ihost->pdev->dev,
+ sizeof(struct isci_request), &dma,
+ GFP_KERNEL);
+ if (!ireq)
+ return -ENOMEM;
+
+ ireq->tc = &ihost->task_context_table[i];
+ ireq->owning_controller = ihost;
+ spin_lock_init(&ireq->state_lock);
+ ireq->request_daddr = dma;
+ ireq->isci_host = ihost;
+ ihost->reqs[i] = ireq;
+ }
+
+ return 0;
+}
+
+void sci_controller_link_up(struct isci_host *ihost, struct isci_port *iport,
+ struct isci_phy *iphy)
+{
+ switch (ihost->sm.current_state_id) {
+ case SCIC_STARTING:
+ sci_del_timer(&ihost->phy_timer);
+ ihost->phy_startup_timer_pending = false;
+ ihost->port_agent.link_up_handler(ihost, &ihost->port_agent,
+ iport, iphy);
+ sci_controller_start_next_phy(ihost);
+ break;
+ case SCIC_READY:
+ ihost->port_agent.link_up_handler(ihost, &ihost->port_agent,
+ iport, iphy);
+ break;
+ default:
+ dev_dbg(&ihost->pdev->dev,
+ "%s: SCIC Controller linkup event from phy %d in "
+ "unexpected state %d\n", __func__, iphy->phy_index,
+ ihost->sm.current_state_id);
+ }
+}
+
+void sci_controller_link_down(struct isci_host *ihost, struct isci_port *iport,
+ struct isci_phy *iphy)
+{
+ switch (ihost->sm.current_state_id) {
+ case SCIC_STARTING:
+ case SCIC_READY:
+ ihost->port_agent.link_down_handler(ihost, &ihost->port_agent,
+ iport, iphy);
+ break;
+ default:
+ dev_dbg(&ihost->pdev->dev,
+ "%s: SCIC Controller linkdown event from phy %d in "
+ "unexpected state %d\n",
+ __func__,
+ iphy->phy_index,
+ ihost->sm.current_state_id);
+ }
+}
+
+static bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost)
+{
+ u32 index;
+
+ for (index = 0; index < ihost->remote_node_entries; index++) {
+ if ((ihost->device_table[index] != NULL) &&
+ (ihost->device_table[index]->sm.current_state_id == SCI_DEV_STOPPING))
+ return true;
+ }
+
+ return false;
+}
+
+void sci_controller_remote_device_stopped(struct isci_host *ihost,
+ struct isci_remote_device *idev)
+{
+ if (ihost->sm.current_state_id != SCIC_STOPPING) {
+ dev_dbg(&ihost->pdev->dev,
+ "SCIC Controller 0x%p remote device stopped event "
+ "from device 0x%p in unexpected state %d\n",
+ ihost, idev,
+ ihost->sm.current_state_id);
+ return;
+ }
+
+ if (!sci_controller_has_remote_devices_stopping(ihost))
+ sci_change_state(&ihost->sm, SCIC_STOPPED);
+}
+
+void sci_controller_post_request(struct isci_host *ihost, u32 request)
+{
+ dev_dbg(&ihost->pdev->dev, "%s[%d]: %#x\n",
+ __func__, ihost->id, request);
+
+ writel(request, &ihost->smu_registers->post_context_port);
+}
+
+struct isci_request *sci_request_by_tag(struct isci_host *ihost, u16 io_tag)
+{
+ u16 task_index;
+ u16 task_sequence;
+
+ task_index = ISCI_TAG_TCI(io_tag);
+
+ if (task_index < ihost->task_context_entries) {
+ struct isci_request *ireq = ihost->reqs[task_index];
+
+ if (test_bit(IREQ_ACTIVE, &ireq->flags)) {
+ task_sequence = ISCI_TAG_SEQ(io_tag);
+
+ if (task_sequence == ihost->io_request_sequence[task_index])
+ return ireq;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * This method allocates remote node index and the reserves the remote node
+ * context space for use. This method can fail if there are no more remote
+ * node index available.
+ * @scic: This is the controller object which contains the set of
+ * free remote node ids
+ * @sci_dev: This is the device object which is requesting the a remote node
+ * id
+ * @node_id: This is the remote node id that is assinged to the device if one
+ * is available
+ *
+ * enum sci_status SCI_FAILURE_OUT_OF_RESOURCES if there are no available remote
+ * node index available.
+ */
+enum sci_status sci_controller_allocate_remote_node_context(struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ u16 *node_id)
+{
+ u16 node_index;
+ u32 remote_node_count = sci_remote_device_node_count(idev);
+
+ node_index = sci_remote_node_table_allocate_remote_node(
+ &ihost->available_remote_nodes, remote_node_count
+ );
+
+ if (node_index != SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) {
+ ihost->device_table[node_index] = idev;
+
+ *node_id = node_index;
+
+ return SCI_SUCCESS;
+ }
+
+ return SCI_FAILURE_INSUFFICIENT_RESOURCES;
+}
+
+void sci_controller_free_remote_node_context(struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ u16 node_id)
+{
+ u32 remote_node_count = sci_remote_device_node_count(idev);
+
+ if (ihost->device_table[node_id] == idev) {
+ ihost->device_table[node_id] = NULL;
+
+ sci_remote_node_table_release_remote_node_index(
+ &ihost->available_remote_nodes, remote_node_count, node_id
+ );
+ }
+}
+
+void sci_controller_copy_sata_response(void *response_buffer,
+ void *frame_header,
+ void *frame_buffer)
+{
+ /* XXX type safety? */
+ memcpy(response_buffer, frame_header, sizeof(u32));
+
+ memcpy(response_buffer + sizeof(u32),
+ frame_buffer,
+ sizeof(struct dev_to_host_fis) - sizeof(u32));
+}
+
+void sci_controller_release_frame(struct isci_host *ihost, u32 frame_index)
+{
+ if (sci_unsolicited_frame_control_release_frame(&ihost->uf_control, frame_index))
+ writel(ihost->uf_control.get,
+ &ihost->scu_registers->sdma.unsolicited_frame_get_pointer);
+}
+
+void isci_tci_free(struct isci_host *ihost, u16 tci)
+{
+ u16 tail = ihost->tci_tail & (SCI_MAX_IO_REQUESTS-1);
+
+ ihost->tci_pool[tail] = tci;
+ ihost->tci_tail = tail + 1;
+}
+
+static u16 isci_tci_alloc(struct isci_host *ihost)
+{
+ u16 head = ihost->tci_head & (SCI_MAX_IO_REQUESTS-1);
+ u16 tci = ihost->tci_pool[head];
+
+ ihost->tci_head = head + 1;
+ return tci;
+}
+
+static u16 isci_tci_space(struct isci_host *ihost)
+{
+ return CIRC_SPACE(ihost->tci_head, ihost->tci_tail, SCI_MAX_IO_REQUESTS);
+}
+
+u16 isci_alloc_tag(struct isci_host *ihost)
+{
+ if (isci_tci_space(ihost)) {
+ u16 tci = isci_tci_alloc(ihost);
+ u8 seq = ihost->io_request_sequence[tci];
+
+ return ISCI_TAG(seq, tci);
+ }
+
+ return SCI_CONTROLLER_INVALID_IO_TAG;
+}
+
+enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag)
+{
+ u16 tci = ISCI_TAG_TCI(io_tag);
+ u16 seq = ISCI_TAG_SEQ(io_tag);
+
+ /* prevent tail from passing head */
+ if (isci_tci_active(ihost) == 0)
+ return SCI_FAILURE_INVALID_IO_TAG;
+
+ if (seq == ihost->io_request_sequence[tci]) {
+ ihost->io_request_sequence[tci] = (seq+1) & (SCI_MAX_SEQ-1);
+
+ isci_tci_free(ihost, tci);
+
+ return SCI_SUCCESS;
+ }
+ return SCI_FAILURE_INVALID_IO_TAG;
+}
+
+enum sci_status sci_controller_start_io(struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ struct isci_request *ireq)
+{
+ enum sci_status status;
+
+ if (ihost->sm.current_state_id != SCIC_READY) {
+ dev_warn(&ihost->pdev->dev, "invalid state to start I/O");
+ return SCI_FAILURE_INVALID_STATE;
+ }
+
+ status = sci_remote_device_start_io(ihost, idev, ireq);
+ if (status != SCI_SUCCESS)
+ return status;
+
+ set_bit(IREQ_ACTIVE, &ireq->flags);
+ sci_controller_post_request(ihost, ireq->post_context);
+ return SCI_SUCCESS;
+}
+
+enum sci_status sci_controller_terminate_request(struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ struct isci_request *ireq)
+{
+ /* terminate an ongoing (i.e. started) core IO request. This does not
+ * abort the IO request at the target, but rather removes the IO
+ * request from the host controller.
+ */
+ enum sci_status status;
+
+ if (ihost->sm.current_state_id != SCIC_READY) {
+ dev_warn(&ihost->pdev->dev,
+ "invalid state to terminate request\n");
+ return SCI_FAILURE_INVALID_STATE;
+ }
+
+ status = sci_io_request_terminate(ireq);
+ if (status != SCI_SUCCESS)
+ return status;
+
+ /*
+ * Utilize the original post context command and or in the POST_TC_ABORT
+ * request sub-type.
+ */
+ sci_controller_post_request(ihost,
+ ireq->post_context | SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT);
+ return SCI_SUCCESS;
+}
+
+/**
+ * sci_controller_complete_io() - This method will perform core specific
+ * completion operations for an IO request. After this method is invoked,
+ * the user should consider the IO request as invalid until it is properly
+ * reused (i.e. re-constructed).
+ * @ihost: The handle to the controller object for which to complete the
+ * IO request.
+ * @idev: The handle to the remote device object for which to complete
+ * the IO request.
+ * @ireq: the handle to the io request object to complete.
+ */
+enum sci_status sci_controller_complete_io(struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ struct isci_request *ireq)
+{
+ enum sci_status status;
+ u16 index;
+
+ switch (ihost->sm.current_state_id) {
+ case SCIC_STOPPING:
+ /* XXX: Implement this function */
+ return SCI_FAILURE;
+ case SCIC_READY:
+ status = sci_remote_device_complete_io(ihost, idev, ireq);
+ if (status != SCI_SUCCESS)
+ return status;
+
+ index = ISCI_TAG_TCI(ireq->io_tag);
+ clear_bit(IREQ_ACTIVE, &ireq->flags);
+ return SCI_SUCCESS;
+ default:
+ dev_warn(&ihost->pdev->dev, "invalid state to complete I/O");
+ return SCI_FAILURE_INVALID_STATE;
+ }
+
+}
+
+enum sci_status sci_controller_continue_io(struct isci_request *ireq)
+{
+ struct isci_host *ihost = ireq->owning_controller;
+
+ if (ihost->sm.current_state_id != SCIC_READY) {
+ dev_warn(&ihost->pdev->dev, "invalid state to continue I/O");
+ return SCI_FAILURE_INVALID_STATE;
+ }
+
+ set_bit(IREQ_ACTIVE, &ireq->flags);
+ sci_controller_post_request(ihost, ireq->post_context);
+ return SCI_SUCCESS;
+}
+
+/**
+ * sci_controller_start_task() - This method is called by the SCIC user to
+ * send/start a framework task management request.
+ * @controller: the handle to the controller object for which to start the task
+ * management request.
+ * @remote_device: the handle to the remote device object for which to start
+ * the task management request.
+ * @task_request: the handle to the task request object to start.
+ */
+enum sci_task_status sci_controller_start_task(struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ struct isci_request *ireq)
+{
+ enum sci_status status;
+
+ if (ihost->sm.current_state_id != SCIC_READY) {
+ dev_warn(&ihost->pdev->dev,
+ "%s: SCIC Controller starting task from invalid "
+ "state\n",
+ __func__);
+ return SCI_TASK_FAILURE_INVALID_STATE;
+ }
+
+ status = sci_remote_device_start_task(ihost, idev, ireq);
+ switch (status) {
+ case SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS:
+ set_bit(IREQ_ACTIVE, &ireq->flags);
+
+ /*
+ * We will let framework know this task request started successfully,
+ * although core is still woring on starting the request (to post tc when
+ * RNC is resumed.)
+ */
+ return SCI_SUCCESS;
+ case SCI_SUCCESS:
+ set_bit(IREQ_ACTIVE, &ireq->flags);
+ sci_controller_post_request(ihost, ireq->post_context);
+ break;
+ default:
+ break;
+ }
+
+ return status;
+}
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
new file mode 100644
index 00000000000..062101a39f7
--- /dev/null
+++ b/drivers/scsi/isci/host.h
@@ -0,0 +1,542 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _SCI_HOST_H_
+#define _SCI_HOST_H_
+
+#include "remote_device.h"
+#include "phy.h"
+#include "isci.h"
+#include "remote_node_table.h"
+#include "registers.h"
+#include "unsolicited_frame_control.h"
+#include "probe_roms.h"
+
+struct isci_request;
+struct scu_task_context;
+
+
+/**
+ * struct sci_power_control -
+ *
+ * This structure defines the fields for managing power control for direct
+ * attached disk devices.
+ */
+struct sci_power_control {
+ /**
+ * This field is set when the power control timer is running and cleared when
+ * it is not.
+ */
+ bool timer_started;
+
+ /**
+ * Timer to control when the directed attached disks can consume power.
+ */
+ struct sci_timer timer;
+
+ /**
+ * This field is used to keep track of how many phys are put into the
+ * requesters field.
+ */
+ u8 phys_waiting;
+
+ /**
+ * This field is used to keep track of how many phys have been granted to consume power
+ */
+ u8 phys_granted_power;
+
+ /**
+ * This field is an array of phys that we are waiting on. The phys are direct
+ * mapped into requesters via struct sci_phy.phy_index
+ */
+ struct isci_phy *requesters[SCI_MAX_PHYS];
+
+};
+
+struct sci_port_configuration_agent;
+typedef void (*port_config_fn)(struct isci_host *,
+ struct sci_port_configuration_agent *,
+ struct isci_port *, struct isci_phy *);
+
+struct sci_port_configuration_agent {
+ u16 phy_configured_mask;
+ u16 phy_ready_mask;
+ struct {
+ u8 min_index;
+ u8 max_index;
+ } phy_valid_port_range[SCI_MAX_PHYS];
+ bool timer_pending;
+ port_config_fn link_up_handler;
+ port_config_fn link_down_handler;
+ struct sci_timer timer;
+};
+
+/**
+ * isci_host - primary host/controller object
+ * @timer: timeout start/stop operations
+ * @device_table: rni (hw remote node index) to remote device lookup table
+ * @available_remote_nodes: rni allocator
+ * @power_control: manage device spin up
+ * @io_request_sequence: generation number for tci's (task contexts)
+ * @task_context_table: hw task context table
+ * @remote_node_context_table: hw remote node context table
+ * @completion_queue: hw-producer driver-consumer communication ring
+ * @completion_queue_get: tracks the driver 'head' of the ring to notify hw
+ * @logical_port_entries: min({driver|silicon}-supported-port-count)
+ * @remote_node_entries: min({driver|silicon}-supported-node-count)
+ * @task_context_entries: min({driver|silicon}-supported-task-count)
+ * @phy_timer: phy startup timer
+ * @invalid_phy_mask: if an invalid_link_up notification is reported a bit for
+ * the phy index is set so further notifications are not
+ * made. Once the phy reports link up and is made part of a
+ * port then this bit is cleared.
+
+ */
+struct isci_host {
+ struct sci_base_state_machine sm;
+ /* XXX can we time this externally */
+ struct sci_timer timer;
+ /* XXX drop reference module params directly */
+ struct sci_user_parameters user_parameters;
+ /* XXX no need to be a union */
+ struct sci_oem_params oem_parameters;
+ struct sci_port_configuration_agent port_agent;
+ struct isci_remote_device *device_table[SCI_MAX_REMOTE_DEVICES];
+ struct sci_remote_node_table available_remote_nodes;
+ struct sci_power_control power_control;
+ u8 io_request_sequence[SCI_MAX_IO_REQUESTS];
+ struct scu_task_context *task_context_table;
+ dma_addr_t task_context_dma;
+ union scu_remote_node_context *remote_node_context_table;
+ u32 *completion_queue;
+ u32 completion_queue_get;
+ u32 logical_port_entries;
+ u32 remote_node_entries;
+ u32 task_context_entries;
+ struct sci_unsolicited_frame_control uf_control;
+
+ /* phy startup */
+ struct sci_timer phy_timer;
+ /* XXX kill */
+ bool phy_startup_timer_pending;
+ u32 next_phy_to_start;
+ /* XXX convert to unsigned long and use bitops */
+ u8 invalid_phy_mask;
+
+ /* TODO attempt dynamic interrupt coalescing scheme */
+ u16 interrupt_coalesce_number;
+ u32 interrupt_coalesce_timeout;
+ struct smu_registers __iomem *smu_registers;
+ struct scu_registers __iomem *scu_registers;
+
+ u16 tci_head;
+ u16 tci_tail;
+ u16 tci_pool[SCI_MAX_IO_REQUESTS];
+
+ int id; /* unique within a given pci device */
+ struct isci_phy phys[SCI_MAX_PHYS];
+ struct isci_port ports[SCI_MAX_PORTS + 1]; /* includes dummy port */
+ struct sas_ha_struct sas_ha;
+
+ spinlock_t state_lock;
+ struct pci_dev *pdev;
+ enum isci_status status;
+ #define IHOST_START_PENDING 0
+ #define IHOST_STOP_PENDING 1
+ unsigned long flags;
+ wait_queue_head_t eventq;
+ struct Scsi_Host *shost;
+ struct tasklet_struct completion_tasklet;
+ struct list_head requests_to_complete;
+ struct list_head requests_to_errorback;
+ spinlock_t scic_lock;
+ struct isci_request *reqs[SCI_MAX_IO_REQUESTS];
+ struct isci_remote_device devices[SCI_MAX_REMOTE_DEVICES];
+};
+
+/**
+ * enum sci_controller_states - This enumeration depicts all the states
+ * for the common controller state machine.
+ */
+enum sci_controller_states {
+ /**
+ * Simply the initial state for the base controller state machine.
+ */
+ SCIC_INITIAL = 0,
+
+ /**
+ * This state indicates that the controller is reset. The memory for
+ * the controller is in it's initial state, but the controller requires
+ * initialization.
+ * This state is entered from the INITIAL state.
+ * This state is entered from the RESETTING state.
+ */
+ SCIC_RESET,
+
+ /**
+ * This state is typically an action state that indicates the controller
+ * is in the process of initialization. In this state no new IO operations
+ * are permitted.
+ * This state is entered from the RESET state.
+ */
+ SCIC_INITIALIZING,
+
+ /**
+ * This state indicates that the controller has been successfully
+ * initialized. In this state no new IO operations are permitted.
+ * This state is entered from the INITIALIZING state.
+ */
+ SCIC_INITIALIZED,
+
+ /**
+ * This state indicates the the controller is in the process of becoming
+ * ready (i.e. starting). In this state no new IO operations are permitted.
+ * This state is entered from the INITIALIZED state.
+ */
+ SCIC_STARTING,
+
+ /**
+ * This state indicates the controller is now ready. Thus, the user
+ * is able to perform IO operations on the controller.
+ * This state is entered from the STARTING state.
+ */
+ SCIC_READY,
+
+ /**
+ * This state is typically an action state that indicates the controller
+ * is in the process of resetting. Thus, the user is unable to perform
+ * IO operations on the controller. A reset is considered destructive in
+ * most cases.
+ * This state is entered from the READY state.
+ * This state is entered from the FAILED state.
+ * This state is entered from the STOPPED state.
+ */
+ SCIC_RESETTING,
+
+ /**
+ * This state indicates that the controller is in the process of stopping.
+ * In this state no new IO operations are permitted, but existing IO
+ * operations are allowed to complete.
+ * This state is entered from the READY state.
+ */
+ SCIC_STOPPING,
+
+ /**
+ * This state indicates that the controller has successfully been stopped.
+ * In this state no new IO operations are permitted.
+ * This state is entered from the STOPPING state.
+ */
+ SCIC_STOPPED,
+
+ /**
+ * This state indicates that the controller could not successfully be
+ * initialized. In this state no new IO operations are permitted.
+ * This state is entered from the INITIALIZING state.
+ * This state is entered from the STARTING state.
+ * This state is entered from the STOPPING state.
+ * This state is entered from the RESETTING state.
+ */
+ SCIC_FAILED,
+};
+
+/**
+ * struct isci_pci_info - This class represents the pci function containing the
+ * controllers. Depending on PCI SKU, there could be up to 2 controllers in
+ * the PCI function.
+ */
+#define SCI_MAX_MSIX_INT (SCI_NUM_MSI_X_INT*SCI_MAX_CONTROLLERS)
+
+struct isci_pci_info {
+ struct msix_entry msix_entries[SCI_MAX_MSIX_INT];
+ struct isci_host *hosts[SCI_MAX_CONTROLLERS];
+ struct isci_orom *orom;
+};
+
+static inline struct isci_pci_info *to_pci_info(struct pci_dev *pdev)
+{
+ return pci_get_drvdata(pdev);
+}
+
+#define for_each_isci_host(id, ihost, pdev) \
+ for (id = 0, ihost = to_pci_info(pdev)->hosts[id]; \
+ id < ARRAY_SIZE(to_pci_info(pdev)->hosts) && ihost; \
+ ihost = to_pci_info(pdev)->hosts[++id])
+
+static inline enum isci_status isci_host_get_state(struct isci_host *isci_host)
+{
+ return isci_host->status;
+}
+
+static inline void isci_host_change_state(struct isci_host *isci_host,
+ enum isci_status status)
+{
+ unsigned long flags;
+
+ dev_dbg(&isci_host->pdev->dev,
+ "%s: isci_host = %p, state = 0x%x",
+ __func__,
+ isci_host,
+ status);
+ spin_lock_irqsave(&isci_host->state_lock, flags);
+ isci_host->status = status;
+ spin_unlock_irqrestore(&isci_host->state_lock, flags);
+
+}
+
+static inline void wait_for_start(struct isci_host *ihost)
+{
+ wait_event(ihost->eventq, !test_bit(IHOST_START_PENDING, &ihost->flags));
+}
+
+static inline void wait_for_stop(struct isci_host *ihost)
+{
+ wait_event(ihost->eventq, !test_bit(IHOST_STOP_PENDING, &ihost->flags));
+}
+
+static inline void wait_for_device_start(struct isci_host *ihost, struct isci_remote_device *idev)
+{
+ wait_event(ihost->eventq, !test_bit(IDEV_START_PENDING, &idev->flags));
+}
+
+static inline void wait_for_device_stop(struct isci_host *ihost, struct isci_remote_device *idev)
+{
+ wait_event(ihost->eventq, !test_bit(IDEV_STOP_PENDING, &idev->flags));
+}
+
+static inline struct isci_host *dev_to_ihost(struct domain_device *dev)
+{
+ return dev->port->ha->lldd_ha;
+}
+
+/* we always use protocol engine group zero */
+#define ISCI_PEG 0
+
+/* see sci_controller_io_tag_allocate|free for how seq and tci are built */
+#define ISCI_TAG(seq, tci) (((u16) (seq)) << 12 | tci)
+
+/* these are returned by the hardware, so sanitize them */
+#define ISCI_TAG_SEQ(tag) (((tag) >> 12) & (SCI_MAX_SEQ-1))
+#define ISCI_TAG_TCI(tag) ((tag) & (SCI_MAX_IO_REQUESTS-1))
+
+/* expander attached sata devices require 3 rnc slots */
+static inline int sci_remote_device_node_count(struct isci_remote_device *idev)
+{
+ struct domain_device *dev = idev->domain_dev;
+
+ if ((dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) &&
+ !idev->is_direct_attached)
+ return SCU_STP_REMOTE_NODE_COUNT;
+ return SCU_SSP_REMOTE_NODE_COUNT;
+}
+
+/**
+ * sci_controller_clear_invalid_phy() -
+ *
+ * This macro will clear the bit in the invalid phy mask for this controller
+ * object. This is used to control messages reported for invalid link up
+ * notifications.
+ */
+#define sci_controller_clear_invalid_phy(controller, phy) \
+ ((controller)->invalid_phy_mask &= ~(1 << (phy)->phy_index))
+
+static inline struct device *sciphy_to_dev(struct isci_phy *iphy)
+{
+
+ if (!iphy || !iphy->isci_port || !iphy->isci_port->isci_host)
+ return NULL;
+
+ return &iphy->isci_port->isci_host->pdev->dev;
+}
+
+static inline struct device *sciport_to_dev(struct isci_port *iport)
+{
+
+ if (!iport || !iport->isci_host)
+ return NULL;
+
+ return &iport->isci_host->pdev->dev;
+}
+
+static inline struct device *scirdev_to_dev(struct isci_remote_device *idev)
+{
+ if (!idev || !idev->isci_port || !idev->isci_port->isci_host)
+ return NULL;
+
+ return &idev->isci_port->isci_host->pdev->dev;
+}
+
+static inline bool is_a2(struct pci_dev *pdev)
+{
+ if (pdev->revision < 4)
+ return true;
+ return false;
+}
+
+static inline bool is_b0(struct pci_dev *pdev)
+{
+ if (pdev->revision == 4)
+ return true;
+ return false;
+}
+
+static inline bool is_c0(struct pci_dev *pdev)
+{
+ if (pdev->revision >= 5)
+ return true;
+ return false;
+}
+
+void sci_controller_post_request(struct isci_host *ihost,
+ u32 request);
+void sci_controller_release_frame(struct isci_host *ihost,
+ u32 frame_index);
+void sci_controller_copy_sata_response(void *response_buffer,
+ void *frame_header,
+ void *frame_buffer);
+enum sci_status sci_controller_allocate_remote_node_context(struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ u16 *node_id);
+void sci_controller_free_remote_node_context(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ u16 node_id);
+
+struct isci_request *sci_request_by_tag(struct isci_host *ihost,
+ u16 io_tag);
+
+void sci_controller_power_control_queue_insert(
+ struct isci_host *ihost,
+ struct isci_phy *iphy);
+
+void sci_controller_power_control_queue_remove(
+ struct isci_host *ihost,
+ struct isci_phy *iphy);
+
+void sci_controller_link_up(
+ struct isci_host *ihost,
+ struct isci_port *iport,
+ struct isci_phy *iphy);
+
+void sci_controller_link_down(
+ struct isci_host *ihost,
+ struct isci_port *iport,
+ struct isci_phy *iphy);
+
+void sci_controller_remote_device_stopped(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev);
+
+void sci_controller_copy_task_context(
+ struct isci_host *ihost,
+ struct isci_request *ireq);
+
+void sci_controller_register_setup(struct isci_host *ihost);
+
+enum sci_status sci_controller_continue_io(struct isci_request *ireq);
+int isci_host_scan_finished(struct Scsi_Host *, unsigned long);
+void isci_host_scan_start(struct Scsi_Host *);
+u16 isci_alloc_tag(struct isci_host *ihost);
+enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag);
+void isci_tci_free(struct isci_host *ihost, u16 tci);
+
+int isci_host_init(struct isci_host *);
+
+void isci_host_init_controller_names(
+ struct isci_host *isci_host,
+ unsigned int controller_idx);
+
+void isci_host_deinit(
+ struct isci_host *);
+
+void isci_host_port_link_up(
+ struct isci_host *,
+ struct isci_port *,
+ struct isci_phy *);
+int isci_host_dev_found(struct domain_device *);
+
+void isci_host_remote_device_start_complete(
+ struct isci_host *,
+ struct isci_remote_device *,
+ enum sci_status);
+
+void sci_controller_disable_interrupts(
+ struct isci_host *ihost);
+
+enum sci_status sci_controller_start_io(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ struct isci_request *ireq);
+
+enum sci_task_status sci_controller_start_task(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ struct isci_request *ireq);
+
+enum sci_status sci_controller_terminate_request(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ struct isci_request *ireq);
+
+enum sci_status sci_controller_complete_io(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ struct isci_request *ireq);
+
+void sci_port_configuration_agent_construct(
+ struct sci_port_configuration_agent *port_agent);
+
+enum sci_status sci_port_configuration_agent_initialize(
+ struct isci_host *ihost,
+ struct sci_port_configuration_agent *port_agent);
+#endif
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
new file mode 100644
index 00000000000..61e0d09e2b5
--- /dev/null
+++ b/drivers/scsi/isci/init.c
@@ -0,0 +1,565 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/efi.h>
+#include <asm/string.h>
+#include "isci.h"
+#include "task.h"
+#include "probe_roms.h"
+
+static struct scsi_transport_template *isci_transport_template;
+
+static DEFINE_PCI_DEVICE_TABLE(isci_id_table) = {
+ { PCI_VDEVICE(INTEL, 0x1D61),},
+ { PCI_VDEVICE(INTEL, 0x1D63),},
+ { PCI_VDEVICE(INTEL, 0x1D65),},
+ { PCI_VDEVICE(INTEL, 0x1D67),},
+ { PCI_VDEVICE(INTEL, 0x1D69),},
+ { PCI_VDEVICE(INTEL, 0x1D6B),},
+ { PCI_VDEVICE(INTEL, 0x1D60),},
+ { PCI_VDEVICE(INTEL, 0x1D62),},
+ { PCI_VDEVICE(INTEL, 0x1D64),},
+ { PCI_VDEVICE(INTEL, 0x1D66),},
+ { PCI_VDEVICE(INTEL, 0x1D68),},
+ { PCI_VDEVICE(INTEL, 0x1D6A),},
+ {}
+};
+
+MODULE_DEVICE_TABLE(pci, isci_id_table);
+
+/* linux isci specific settings */
+
+unsigned char no_outbound_task_to = 20;
+module_param(no_outbound_task_to, byte, 0);
+MODULE_PARM_DESC(no_outbound_task_to, "No Outbound Task Timeout (1us incr)");
+
+u16 ssp_max_occ_to = 20;
+module_param(ssp_max_occ_to, ushort, 0);
+MODULE_PARM_DESC(ssp_max_occ_to, "SSP Max occupancy timeout (100us incr)");
+
+u16 stp_max_occ_to = 5;
+module_param(stp_max_occ_to, ushort, 0);
+MODULE_PARM_DESC(stp_max_occ_to, "STP Max occupancy timeout (100us incr)");
+
+u16 ssp_inactive_to = 5;
+module_param(ssp_inactive_to, ushort, 0);
+MODULE_PARM_DESC(ssp_inactive_to, "SSP inactivity timeout (100us incr)");
+
+u16 stp_inactive_to = 5;
+module_param(stp_inactive_to, ushort, 0);
+MODULE_PARM_DESC(stp_inactive_to, "STP inactivity timeout (100us incr)");
+
+unsigned char phy_gen = 3;
+module_param(phy_gen, byte, 0);
+MODULE_PARM_DESC(phy_gen, "PHY generation (1: 1.5Gbps 2: 3.0Gbps 3: 6.0Gbps)");
+
+unsigned char max_concurr_spinup = 1;
+module_param(max_concurr_spinup, byte, 0);
+MODULE_PARM_DESC(max_concurr_spinup, "Max concurrent device spinup");
+
+static struct scsi_host_template isci_sht = {
+
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .proc_name = DRV_NAME,
+ .queuecommand = sas_queuecommand,
+ .target_alloc = sas_target_alloc,
+ .slave_configure = sas_slave_configure,
+ .slave_destroy = sas_slave_destroy,
+ .scan_finished = isci_host_scan_finished,
+ .scan_start = isci_host_scan_start,
+ .change_queue_depth = sas_change_queue_depth,
+ .change_queue_type = sas_change_queue_type,
+ .bios_param = sas_bios_param,
+ .can_queue = ISCI_CAN_QUEUE_VAL,
+ .cmd_per_lun = 1,
+ .this_id = -1,
+ .sg_tablesize = SG_ALL,
+ .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
+ .eh_bus_reset_handler = isci_bus_reset_handler,
+ .slave_alloc = sas_slave_alloc,
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
+};
+
+static struct sas_domain_function_template isci_transport_ops = {
+
+ /* The class calls these to notify the LLDD of an event. */
+ .lldd_port_formed = isci_port_formed,
+ .lldd_port_deformed = isci_port_deformed,
+
+ /* The class calls these when a device is found or gone. */
+ .lldd_dev_found = isci_remote_device_found,
+ .lldd_dev_gone = isci_remote_device_gone,
+
+ .lldd_execute_task = isci_task_execute_task,
+ /* Task Management Functions. Must be called from process context. */
+ .lldd_abort_task = isci_task_abort_task,
+ .lldd_abort_task_set = isci_task_abort_task_set,
+ .lldd_clear_aca = isci_task_clear_aca,
+ .lldd_clear_task_set = isci_task_clear_task_set,
+ .lldd_I_T_nexus_reset = isci_task_I_T_nexus_reset,
+ .lldd_lu_reset = isci_task_lu_reset,
+ .lldd_query_task = isci_task_query_task,
+
+ /* Port and Adapter management */
+ .lldd_clear_nexus_port = isci_task_clear_nexus_port,
+ .lldd_clear_nexus_ha = isci_task_clear_nexus_ha,
+
+ /* Phy management */
+ .lldd_control_phy = isci_phy_control,
+};
+
+
+/******************************************************************************
+* P R O T E C T E D M E T H O D S
+******************************************************************************/
+
+
+
+/**
+ * isci_register_sas_ha() - This method initializes various lldd
+ * specific members of the sas_ha struct and calls the libsas
+ * sas_register_ha() function.
+ * @isci_host: This parameter specifies the lldd specific wrapper for the
+ * libsas sas_ha struct.
+ *
+ * This method returns an error code indicating sucess or failure. The user
+ * should check for possible memory allocation error return otherwise, a zero
+ * indicates success.
+ */
+static int isci_register_sas_ha(struct isci_host *isci_host)
+{
+ int i;
+ struct sas_ha_struct *sas_ha = &(isci_host->sas_ha);
+ struct asd_sas_phy **sas_phys;
+ struct asd_sas_port **sas_ports;
+
+ sas_phys = devm_kzalloc(&isci_host->pdev->dev,
+ SCI_MAX_PHYS * sizeof(void *),
+ GFP_KERNEL);
+ if (!sas_phys)
+ return -ENOMEM;
+
+ sas_ports = devm_kzalloc(&isci_host->pdev->dev,
+ SCI_MAX_PORTS * sizeof(void *),
+ GFP_KERNEL);
+ if (!sas_ports)
+ return -ENOMEM;
+
+ /*----------------- Libsas Initialization Stuff----------------------
+ * Set various fields in the sas_ha struct:
+ */
+
+ sas_ha->sas_ha_name = DRV_NAME;
+ sas_ha->lldd_module = THIS_MODULE;
+ sas_ha->sas_addr = &isci_host->phys[0].sas_addr[0];
+
+ /* set the array of phy and port structs. */
+ for (i = 0; i < SCI_MAX_PHYS; i++) {
+ sas_phys[i] = &isci_host->phys[i].sas_phy;
+ sas_ports[i] = &isci_host->ports[i].sas_port;
+ }
+
+ sas_ha->sas_phy = sas_phys;
+ sas_ha->sas_port = sas_ports;
+ sas_ha->num_phys = SCI_MAX_PHYS;
+
+ sas_ha->lldd_queue_size = ISCI_CAN_QUEUE_VAL;
+ sas_ha->lldd_max_execute_num = 1;
+ sas_ha->strict_wide_ports = 1;
+
+ sas_register_ha(sas_ha);
+
+ 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;
+
+ if (!isci_host)
+ return;
+
+ shost = isci_host->shost;
+ device_remove_file(&shost->shost_dev, &dev_attr_isci_id);
+
+ sas_unregister_ha(&isci_host->sas_ha);
+
+ sas_remove_host(isci_host->shost);
+ scsi_remove_host(isci_host->shost);
+ scsi_host_put(isci_host->shost);
+}
+
+static int __devinit isci_pci_init(struct pci_dev *pdev)
+{
+ int err, bar_num, bar_mask = 0;
+ void __iomem * const *iomap;
+
+ err = pcim_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev,
+ "failed enable PCI device %s!\n",
+ pci_name(pdev));
+ return err;
+ }
+
+ for (bar_num = 0; bar_num < SCI_PCI_BAR_COUNT; bar_num++)
+ bar_mask |= 1 << (bar_num * 2);
+
+ err = pcim_iomap_regions(pdev, bar_mask, DRV_NAME);
+ if (err)
+ return err;
+
+ iomap = pcim_iomap_table(pdev);
+ if (!iomap)
+ return -ENOMEM;
+
+ pci_set_master(pdev);
+
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (err) {
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err)
+ return err;
+ }
+
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (err) {
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int num_controllers(struct pci_dev *pdev)
+{
+ /* bar size alone can tell us if we are running with a dual controller
+ * part, no need to trust revision ids that might be under broken firmware
+ * control
+ */
+ resource_size_t scu_bar_size = pci_resource_len(pdev, SCI_SCU_BAR*2);
+ resource_size_t smu_bar_size = pci_resource_len(pdev, SCI_SMU_BAR*2);
+
+ if (scu_bar_size >= SCI_SCU_BAR_SIZE*SCI_MAX_CONTROLLERS &&
+ smu_bar_size >= SCI_SMU_BAR_SIZE*SCI_MAX_CONTROLLERS)
+ return SCI_MAX_CONTROLLERS;
+ else
+ return 1;
+}
+
+static int isci_setup_interrupts(struct pci_dev *pdev)
+{
+ int err, i, num_msix;
+ struct isci_host *ihost;
+ struct isci_pci_info *pci_info = to_pci_info(pdev);
+
+ /*
+ * Determine the number of vectors associated with this
+ * PCI function.
+ */
+ num_msix = num_controllers(pdev) * SCI_NUM_MSI_X_INT;
+
+ for (i = 0; i < num_msix; i++)
+ pci_info->msix_entries[i].entry = i;
+
+ err = pci_enable_msix(pdev, pci_info->msix_entries, num_msix);
+ if (err)
+ goto intx;
+
+ for (i = 0; i < num_msix; i++) {
+ int id = i / SCI_NUM_MSI_X_INT;
+ struct msix_entry *msix = &pci_info->msix_entries[i];
+ irq_handler_t isr;
+
+ ihost = pci_info->hosts[id];
+ /* odd numbered vectors are error interrupts */
+ if (i & 1)
+ isr = isci_error_isr;
+ else
+ isr = isci_msix_isr;
+
+ err = devm_request_irq(&pdev->dev, msix->vector, isr, 0,
+ DRV_NAME"-msix", ihost);
+ if (!err)
+ continue;
+
+ dev_info(&pdev->dev, "msix setup failed falling back to intx\n");
+ while (i--) {
+ id = i / SCI_NUM_MSI_X_INT;
+ ihost = pci_info->hosts[id];
+ msix = &pci_info->msix_entries[i];
+ devm_free_irq(&pdev->dev, msix->vector, ihost);
+ }
+ pci_disable_msix(pdev);
+ goto intx;
+ }
+ return 0;
+
+ intx:
+ for_each_isci_host(i, ihost, pdev) {
+ err = devm_request_irq(&pdev->dev, pdev->irq, isci_intx_isr,
+ IRQF_SHARED, DRV_NAME"-intx", ihost);
+ if (err)
+ break;
+ }
+ return err;
+}
+
+static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
+{
+ struct isci_host *isci_host;
+ struct Scsi_Host *shost;
+ int err;
+
+ isci_host = devm_kzalloc(&pdev->dev, sizeof(*isci_host), GFP_KERNEL);
+ if (!isci_host)
+ return NULL;
+
+ isci_host->pdev = pdev;
+ isci_host->id = id;
+
+ shost = scsi_host_alloc(&isci_sht, sizeof(void *));
+ if (!shost)
+ return NULL;
+ isci_host->shost = shost;
+
+ err = isci_host_init(isci_host);
+ if (err)
+ goto err_shost;
+
+ SHOST_TO_SAS_HA(shost) = &isci_host->sas_ha;
+ isci_host->sas_ha.core.shost = shost;
+ shost->transportt = isci_transport_template;
+
+ shost->max_id = ~0;
+ shost->max_lun = ~0;
+ shost->max_cmd_len = MAX_COMMAND_SIZE;
+
+ err = scsi_add_host(shost, &pdev->dev);
+ if (err)
+ goto err_shost;
+
+ err = isci_register_sas_ha(isci_host);
+ 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:
+ scsi_host_put(shost);
+
+ return NULL;
+}
+
+static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct isci_pci_info *pci_info;
+ int err, i;
+ struct isci_host *isci_host;
+ const struct firmware *fw = NULL;
+ struct isci_orom *orom = NULL;
+ char *source = "(platform)";
+
+ dev_info(&pdev->dev, "driver configured for rev: %d silicon\n",
+ pdev->revision);
+
+ pci_info = devm_kzalloc(&pdev->dev, sizeof(*pci_info), GFP_KERNEL);
+ if (!pci_info)
+ return -ENOMEM;
+ pci_set_drvdata(pdev, pci_info);
+
+ if (efi_enabled)
+ orom = isci_get_efi_var(pdev);
+
+ if (!orom)
+ orom = isci_request_oprom(pdev);
+
+ for (i = 0; orom && i < ARRAY_SIZE(orom->ctrl); i++) {
+ if (sci_oem_parameters_validate(&orom->ctrl[i])) {
+ dev_warn(&pdev->dev,
+ "[%d]: invalid oem parameters detected, falling back to firmware\n", i);
+ devm_kfree(&pdev->dev, orom);
+ orom = NULL;
+ break;
+ }
+ }
+
+ if (!orom) {
+ source = "(firmware)";
+ orom = isci_request_firmware(pdev, fw);
+ if (!orom) {
+ /* TODO convert this to WARN_TAINT_ONCE once the
+ * orom/efi parameter support is widely available
+ */
+ dev_warn(&pdev->dev,
+ "Loading user firmware failed, using default "
+ "values\n");
+ dev_warn(&pdev->dev,
+ "Default OEM configuration being used: 4 "
+ "narrow ports, and default SAS Addresses\n");
+ }
+ }
+
+ if (orom)
+ dev_info(&pdev->dev,
+ "OEM SAS parameters (version: %u.%u) loaded %s\n",
+ (orom->hdr.version & 0xf0) >> 4,
+ (orom->hdr.version & 0xf), source);
+
+ pci_info->orom = orom;
+
+ err = isci_pci_init(pdev);
+ if (err)
+ return err;
+
+ for (i = 0; i < num_controllers(pdev); i++) {
+ struct isci_host *h = isci_host_alloc(pdev, i);
+
+ if (!h) {
+ err = -ENOMEM;
+ goto err_host_alloc;
+ }
+ pci_info->hosts[i] = h;
+ }
+
+ err = isci_setup_interrupts(pdev);
+ if (err)
+ goto err_host_alloc;
+
+ for_each_isci_host(i, isci_host, pdev)
+ scsi_scan_host(isci_host->shost);
+
+ return 0;
+
+ err_host_alloc:
+ for_each_isci_host(i, isci_host, pdev)
+ isci_unregister(isci_host);
+ return err;
+}
+
+static void __devexit isci_pci_remove(struct pci_dev *pdev)
+{
+ struct isci_host *ihost;
+ int i;
+
+ for_each_isci_host(i, ihost, pdev) {
+ isci_unregister(ihost);
+ isci_host_deinit(ihost);
+ sci_controller_disable_interrupts(ihost);
+ }
+}
+
+static struct pci_driver isci_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = isci_id_table,
+ .probe = isci_pci_probe,
+ .remove = __devexit_p(isci_pci_remove),
+};
+
+static __init int isci_init(void)
+{
+ int err;
+
+ pr_info("%s: Intel(R) C600 SAS Controller Driver\n", DRV_NAME);
+
+ isci_transport_template = sas_domain_attach_transport(&isci_transport_ops);
+ if (!isci_transport_template)
+ return -ENOMEM;
+
+ err = pci_register_driver(&isci_pci_driver);
+ if (err)
+ sas_release_transport(isci_transport_template);
+
+ return err;
+}
+
+static __exit void isci_exit(void)
+{
+ pci_unregister_driver(&isci_pci_driver);
+ sas_release_transport(isci_transport_template);
+}
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_FIRMWARE(ISCI_FW_NAME);
+module_init(isci_init);
+module_exit(isci_exit);
diff --git a/drivers/scsi/isci/isci.h b/drivers/scsi/isci/isci.h
new file mode 100644
index 00000000000..d1de63312e7
--- /dev/null
+++ b/drivers/scsi/isci/isci.h
@@ -0,0 +1,538 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ISCI_H__
+#define __ISCI_H__
+
+#include <linux/interrupt.h>
+#include <linux/types.h>
+
+#define DRV_NAME "isci"
+#define SCI_PCI_BAR_COUNT 2
+#define SCI_NUM_MSI_X_INT 2
+#define SCI_SMU_BAR 0
+#define SCI_SMU_BAR_SIZE (16*1024)
+#define SCI_SCU_BAR 1
+#define SCI_SCU_BAR_SIZE (4*1024*1024)
+#define SCI_IO_SPACE_BAR0 2
+#define SCI_IO_SPACE_BAR1 3
+#define ISCI_CAN_QUEUE_VAL 250 /* < SCI_MAX_IO_REQUESTS ? */
+#define SCIC_CONTROLLER_STOP_TIMEOUT 5000
+
+#define SCI_CONTROLLER_INVALID_IO_TAG 0xFFFF
+
+#define SCI_MAX_PHYS (4UL)
+#define SCI_MAX_PORTS SCI_MAX_PHYS
+#define SCI_MAX_SMP_PHYS (384) /* not silicon constrained */
+#define SCI_MAX_REMOTE_DEVICES (256UL)
+#define SCI_MAX_IO_REQUESTS (256UL)
+#define SCI_MAX_SEQ (16)
+#define SCI_MAX_MSIX_MESSAGES (2)
+#define SCI_MAX_SCATTER_GATHER_ELEMENTS 130 /* not silicon constrained */
+#define SCI_MAX_CONTROLLERS 2
+#define SCI_MAX_DOMAINS SCI_MAX_PORTS
+
+#define SCU_MAX_CRITICAL_NOTIFICATIONS (384)
+#define SCU_MAX_EVENTS_SHIFT (7)
+#define SCU_MAX_EVENTS (1 << SCU_MAX_EVENTS_SHIFT)
+#define SCU_MAX_UNSOLICITED_FRAMES (128)
+#define SCU_MAX_COMPLETION_QUEUE_SCRATCH (128)
+#define SCU_MAX_COMPLETION_QUEUE_ENTRIES (SCU_MAX_CRITICAL_NOTIFICATIONS \
+ + SCU_MAX_EVENTS \
+ + SCU_MAX_UNSOLICITED_FRAMES \
+ + SCI_MAX_IO_REQUESTS \
+ + SCU_MAX_COMPLETION_QUEUE_SCRATCH)
+#define SCU_MAX_COMPLETION_QUEUE_SHIFT (ilog2(SCU_MAX_COMPLETION_QUEUE_ENTRIES))
+
+#define SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES (4096)
+#define SCU_UNSOLICITED_FRAME_BUFFER_SIZE (1024)
+#define SCU_INVALID_FRAME_INDEX (0xFFFF)
+
+#define SCU_IO_REQUEST_MAX_SGE_SIZE (0x00FFFFFF)
+#define SCU_IO_REQUEST_MAX_TRANSFER_LENGTH (0x00FFFFFF)
+
+static inline void check_sizes(void)
+{
+ BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_EVENTS);
+ BUILD_BUG_ON(SCU_MAX_UNSOLICITED_FRAMES <= 8);
+ BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_UNSOLICITED_FRAMES);
+ BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_COMPLETION_QUEUE_ENTRIES);
+ BUILD_BUG_ON(SCU_MAX_UNSOLICITED_FRAMES > SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES);
+ BUILD_BUG_ON_NOT_POWER_OF_2(SCI_MAX_IO_REQUESTS);
+ BUILD_BUG_ON_NOT_POWER_OF_2(SCI_MAX_SEQ);
+}
+
+/**
+ * enum sci_status - This is the general return status enumeration for non-IO,
+ * non-task management related SCI interface methods.
+ *
+ *
+ */
+enum sci_status {
+ /**
+ * This member indicates successful completion.
+ */
+ SCI_SUCCESS = 0,
+
+ /**
+ * This value indicates that the calling method completed successfully,
+ * but that the IO may have completed before having it's start method
+ * invoked. This occurs during SAT translation for requests that do
+ * not require an IO to the target or for any other requests that may
+ * be completed without having to submit IO.
+ */
+ SCI_SUCCESS_IO_COMPLETE_BEFORE_START,
+
+ /**
+ * This Value indicates that the SCU hardware returned an early response
+ * because the io request specified more data than is returned by the
+ * target device (mode pages, inquiry data, etc.). The completion routine
+ * will handle this case to get the actual number of bytes transferred.
+ */
+ SCI_SUCCESS_IO_DONE_EARLY,
+
+ /**
+ * This member indicates that the object for which a state change is
+ * being requested is already in said state.
+ */
+ SCI_WARNING_ALREADY_IN_STATE,
+
+ /**
+ * This member indicates interrupt coalescence timer may cause SAS
+ * specification compliance issues (i.e. SMP target mode response
+ * frames must be returned within 1.9 milliseconds).
+ */
+ SCI_WARNING_TIMER_CONFLICT,
+
+ /**
+ * This field indicates a sequence of action is not completed yet. Mostly,
+ * this status is used when multiple ATA commands are needed in a SATI translation.
+ */
+ SCI_WARNING_SEQUENCE_INCOMPLETE,
+
+ /**
+ * This member indicates that there was a general failure.
+ */
+ SCI_FAILURE,
+
+ /**
+ * This member indicates that the SCI implementation is unable to complete
+ * an operation due to a critical flaw the prevents any further operation
+ * (i.e. an invalid pointer).
+ */
+ SCI_FATAL_ERROR,
+
+ /**
+ * This member indicates the calling function failed, because the state
+ * of the controller is in a state that prevents successful completion.
+ */
+ SCI_FAILURE_INVALID_STATE,
+
+ /**
+ * This member indicates the calling function failed, because there is
+ * insufficient resources/memory to complete the request.
+ */
+ SCI_FAILURE_INSUFFICIENT_RESOURCES,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * controller object required for the operation can't be located.
+ */
+ SCI_FAILURE_CONTROLLER_NOT_FOUND,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * discovered controller type is not supported by the library.
+ */
+ SCI_FAILURE_UNSUPPORTED_CONTROLLER_TYPE,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * requested initialization data version isn't supported.
+ */
+ SCI_FAILURE_UNSUPPORTED_INIT_DATA_VERSION,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * requested configuration of SAS Phys into SAS Ports is not supported.
+ */
+ SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * requested protocol is not supported by the remote device, port,
+ * or controller.
+ */
+ SCI_FAILURE_UNSUPPORTED_PROTOCOL,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * requested information type is not supported by the SCI implementation.
+ */
+ SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * device already exists.
+ */
+ SCI_FAILURE_DEVICE_EXISTS,
+
+ /**
+ * This member indicates the calling function failed, because adding
+ * a phy to the object is not possible.
+ */
+ SCI_FAILURE_ADDING_PHY_UNSUPPORTED,
+
+ /**
+ * This member indicates the calling function failed, because the
+ * requested information type is not supported by the SCI implementation.
+ */
+ SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD,
+
+ /**
+ * This member indicates the calling function failed, because the SCI
+ * implementation does not support the supplied time limit.
+ */
+ SCI_FAILURE_UNSUPPORTED_TIME_LIMIT,
+
+ /**
+ * This member indicates the calling method failed, because the SCI
+ * implementation does not contain the specified Phy.
+ */
+ SCI_FAILURE_INVALID_PHY,
+
+ /**
+ * This member indicates the calling method failed, because the SCI
+ * implementation does not contain the specified Port.
+ */
+ SCI_FAILURE_INVALID_PORT,
+
+ /**
+ * This member indicates the calling method was partly successful
+ * The port was reset but not all phys in port are operational
+ */
+ SCI_FAILURE_RESET_PORT_PARTIAL_SUCCESS,
+
+ /**
+ * This member indicates that calling method failed
+ * The port reset did not complete because none of the phys are operational
+ */
+ SCI_FAILURE_RESET_PORT_FAILURE,
+
+ /**
+ * This member indicates the calling method failed, because the SCI
+ * implementation does not contain the specified remote device.
+ */
+ SCI_FAILURE_INVALID_REMOTE_DEVICE,
+
+ /**
+ * This member indicates the calling method failed, because the remote
+ * device is in a bad state and requires a reset.
+ */
+ SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED,
+
+ /**
+ * This member indicates the calling method failed, because the SCI
+ * implementation does not contain or support the specified IO tag.
+ */
+ SCI_FAILURE_INVALID_IO_TAG,
+
+ /**
+ * This member indicates that the operation failed and the user should
+ * check the response data associated with the IO.
+ */
+ SCI_FAILURE_IO_RESPONSE_VALID,
+
+ /**
+ * This member indicates that the operation failed, the failure is
+ * controller implementation specific, and the response data associated
+ * with the request is not valid. You can query for the controller
+ * specific error information via sci_controller_get_request_status()
+ */
+ SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR,
+
+ /**
+ * This member indicated that the operation failed because the
+ * user requested this IO to be terminated.
+ */
+ SCI_FAILURE_IO_TERMINATED,
+
+ /**
+ * This member indicates that the operation failed and the associated
+ * request requires a SCSI abort task to be sent to the target.
+ */
+ SCI_FAILURE_IO_REQUIRES_SCSI_ABORT,
+
+ /**
+ * This member indicates that the operation failed because the supplied
+ * device could not be located.
+ */
+ SCI_FAILURE_DEVICE_NOT_FOUND,
+
+ /**
+ * This member indicates that the operation failed because the
+ * objects association is required and is not correctly set.
+ */
+ SCI_FAILURE_INVALID_ASSOCIATION,
+
+ /**
+ * This member indicates that the operation failed, because a timeout
+ * occurred.
+ */
+ SCI_FAILURE_TIMEOUT,
+
+ /**
+ * This member indicates that the operation failed, because the user
+ * specified a value that is either invalid or not supported.
+ */
+ SCI_FAILURE_INVALID_PARAMETER_VALUE,
+
+ /**
+ * This value indicates that the operation failed, because the number
+ * of messages (MSI-X) is not supported.
+ */
+ SCI_FAILURE_UNSUPPORTED_MESSAGE_COUNT,
+
+ /**
+ * This value indicates that the method failed due to a lack of
+ * available NCQ tags.
+ */
+ SCI_FAILURE_NO_NCQ_TAG_AVAILABLE,
+
+ /**
+ * This value indicates that a protocol violation has occurred on the
+ * link.
+ */
+ SCI_FAILURE_PROTOCOL_VIOLATION,
+
+ /**
+ * This value indicates a failure condition that retry may help to clear.
+ */
+ SCI_FAILURE_RETRY_REQUIRED,
+
+ /**
+ * This field indicates the retry limit was reached when a retry is attempted
+ */
+ SCI_FAILURE_RETRY_LIMIT_REACHED,
+
+ /**
+ * This member indicates the calling method was partly successful.
+ * Mostly, this status is used when a LUN_RESET issued to an expander attached
+ * STP device in READY NCQ substate needs to have RNC suspended/resumed
+ * before posting TC.
+ */
+ SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS,
+
+ /**
+ * This field indicates an illegal phy connection based on the routing attribute
+ * of both expander phy attached to each other.
+ */
+ SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION,
+
+ /**
+ * This field indicates a CONFIG ROUTE INFO command has a response with function result
+ * INDEX DOES NOT EXIST, usually means exceeding max route index.
+ */
+ SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX,
+
+ /**
+ * This value indicates that an unsupported PCI device ID has been
+ * specified. This indicates that attempts to invoke
+ * sci_library_allocate_controller() will fail.
+ */
+ SCI_FAILURE_UNSUPPORTED_PCI_DEVICE_ID
+
+};
+
+/**
+ * enum sci_io_status - This enumeration depicts all of the possible IO
+ * completion status values. Each value in this enumeration maps directly
+ * to a value in the enum sci_status enumeration. Please refer to that
+ * enumeration for detailed comments concerning what the status represents.
+ *
+ * Add the API to retrieve the SCU status from the core. Check to see that the
+ * following status are properly handled: - SCI_IO_FAILURE_UNSUPPORTED_PROTOCOL
+ * - SCI_IO_FAILURE_INVALID_IO_TAG
+ */
+enum sci_io_status {
+ SCI_IO_SUCCESS = SCI_SUCCESS,
+ SCI_IO_FAILURE = SCI_FAILURE,
+ SCI_IO_SUCCESS_COMPLETE_BEFORE_START = SCI_SUCCESS_IO_COMPLETE_BEFORE_START,
+ SCI_IO_SUCCESS_IO_DONE_EARLY = SCI_SUCCESS_IO_DONE_EARLY,
+ SCI_IO_FAILURE_INVALID_STATE = SCI_FAILURE_INVALID_STATE,
+ SCI_IO_FAILURE_INSUFFICIENT_RESOURCES = SCI_FAILURE_INSUFFICIENT_RESOURCES,
+ SCI_IO_FAILURE_UNSUPPORTED_PROTOCOL = SCI_FAILURE_UNSUPPORTED_PROTOCOL,
+ SCI_IO_FAILURE_RESPONSE_VALID = SCI_FAILURE_IO_RESPONSE_VALID,
+ SCI_IO_FAILURE_CONTROLLER_SPECIFIC_ERR = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR,
+ SCI_IO_FAILURE_TERMINATED = SCI_FAILURE_IO_TERMINATED,
+ SCI_IO_FAILURE_REQUIRES_SCSI_ABORT = SCI_FAILURE_IO_REQUIRES_SCSI_ABORT,
+ SCI_IO_FAILURE_INVALID_PARAMETER_VALUE = SCI_FAILURE_INVALID_PARAMETER_VALUE,
+ SCI_IO_FAILURE_NO_NCQ_TAG_AVAILABLE = SCI_FAILURE_NO_NCQ_TAG_AVAILABLE,
+ SCI_IO_FAILURE_PROTOCOL_VIOLATION = SCI_FAILURE_PROTOCOL_VIOLATION,
+
+ SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED,
+
+ SCI_IO_FAILURE_RETRY_REQUIRED = SCI_FAILURE_RETRY_REQUIRED,
+ SCI_IO_FAILURE_RETRY_LIMIT_REACHED = SCI_FAILURE_RETRY_LIMIT_REACHED,
+ SCI_IO_FAILURE_INVALID_REMOTE_DEVICE = SCI_FAILURE_INVALID_REMOTE_DEVICE
+};
+
+/**
+ * enum sci_task_status - This enumeration depicts all of the possible task
+ * completion status values. Each value in this enumeration maps directly
+ * to a value in the enum sci_status enumeration. Please refer to that
+ * enumeration for detailed comments concerning what the status represents.
+ *
+ * Check to see that the following status are properly handled:
+ */
+enum sci_task_status {
+ SCI_TASK_SUCCESS = SCI_SUCCESS,
+ SCI_TASK_FAILURE = SCI_FAILURE,
+ SCI_TASK_FAILURE_INVALID_STATE = SCI_FAILURE_INVALID_STATE,
+ SCI_TASK_FAILURE_INSUFFICIENT_RESOURCES = SCI_FAILURE_INSUFFICIENT_RESOURCES,
+ SCI_TASK_FAILURE_UNSUPPORTED_PROTOCOL = SCI_FAILURE_UNSUPPORTED_PROTOCOL,
+ SCI_TASK_FAILURE_INVALID_TAG = SCI_FAILURE_INVALID_IO_TAG,
+ SCI_TASK_FAILURE_RESPONSE_VALID = SCI_FAILURE_IO_RESPONSE_VALID,
+ SCI_TASK_FAILURE_CONTROLLER_SPECIFIC_ERR = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR,
+ SCI_TASK_FAILURE_TERMINATED = SCI_FAILURE_IO_TERMINATED,
+ SCI_TASK_FAILURE_INVALID_PARAMETER_VALUE = SCI_FAILURE_INVALID_PARAMETER_VALUE,
+
+ SCI_TASK_FAILURE_REMOTE_DEVICE_RESET_REQUIRED = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED,
+ SCI_TASK_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS = SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS
+
+};
+
+/**
+ * sci_swab32_cpy - convert between scsi and scu-hardware byte format
+ * @dest: receive the 4-byte endian swapped version of src
+ * @src: word aligned source buffer
+ *
+ * scu hardware handles SSP/SMP control, response, and unidentified
+ * frames in "big endian dword" order. Regardless of host endian this
+ * is always a swab32()-per-dword conversion of the standard definition,
+ * i.e. single byte fields swapped and multi-byte fields in little-
+ * endian
+ */
+static inline void sci_swab32_cpy(void *_dest, void *_src, ssize_t word_cnt)
+{
+ u32 *dest = _dest, *src = _src;
+
+ while (--word_cnt >= 0)
+ dest[word_cnt] = swab32(src[word_cnt]);
+}
+
+extern unsigned char no_outbound_task_to;
+extern u16 ssp_max_occ_to;
+extern u16 stp_max_occ_to;
+extern u16 ssp_inactive_to;
+extern u16 stp_inactive_to;
+extern unsigned char phy_gen;
+extern unsigned char max_concurr_spinup;
+
+irqreturn_t isci_msix_isr(int vec, void *data);
+irqreturn_t isci_intx_isr(int vec, void *data);
+irqreturn_t isci_error_isr(int vec, void *data);
+
+/*
+ * Each timer is associated with a cancellation flag that is set when
+ * del_timer() is called and checked in the timer callback function. This
+ * is needed since del_timer_sync() cannot be called with sci_lock held.
+ * For deinit however, del_timer_sync() is used without holding the lock.
+ */
+struct sci_timer {
+ struct timer_list timer;
+ bool cancel;
+};
+
+static inline
+void sci_init_timer(struct sci_timer *tmr, void (*fn)(unsigned long))
+{
+ tmr->timer.function = fn;
+ tmr->timer.data = (unsigned long) tmr;
+ tmr->cancel = 0;
+ init_timer(&tmr->timer);
+}
+
+static inline void sci_mod_timer(struct sci_timer *tmr, unsigned long msec)
+{
+ tmr->cancel = 0;
+ mod_timer(&tmr->timer, jiffies + msecs_to_jiffies(msec));
+}
+
+static inline void sci_del_timer(struct sci_timer *tmr)
+{
+ tmr->cancel = 1;
+ del_timer(&tmr->timer);
+}
+
+struct sci_base_state_machine {
+ const struct sci_base_state *state_table;
+ u32 initial_state_id;
+ u32 current_state_id;
+ u32 previous_state_id;
+};
+
+typedef void (*sci_state_transition_t)(struct sci_base_state_machine *sm);
+
+struct sci_base_state {
+ sci_state_transition_t enter_state; /* Called on state entry */
+ sci_state_transition_t exit_state; /* Called on state exit */
+};
+
+extern void sci_init_sm(struct sci_base_state_machine *sm,
+ const struct sci_base_state *state_table,
+ u32 initial_state);
+extern void sci_change_state(struct sci_base_state_machine *sm, u32 next_state);
+#endif /* __ISCI_H__ */
diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c
new file mode 100644
index 00000000000..79313a7a235
--- /dev/null
+++ b/drivers/scsi/isci/phy.c
@@ -0,0 +1,1312 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "isci.h"
+#include "host.h"
+#include "phy.h"
+#include "scu_event_codes.h"
+#include "probe_roms.h"
+
+/* Maximum arbitration wait time in micro-seconds */
+#define SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME (700)
+
+enum sas_linkrate sci_phy_linkrate(struct isci_phy *iphy)
+{
+ return iphy->max_negotiated_speed;
+}
+
+static enum sci_status
+sci_phy_transport_layer_initialization(struct isci_phy *iphy,
+ struct scu_transport_layer_registers __iomem *reg)
+{
+ u32 tl_control;
+
+ iphy->transport_layer_registers = reg;
+
+ writel(SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX,
+ &iphy->transport_layer_registers->stp_rni);
+
+ /*
+ * Hardware team recommends that we enable the STP prefetch for all
+ * transports
+ */
+ tl_control = readl(&iphy->transport_layer_registers->control);
+ tl_control |= SCU_TLCR_GEN_BIT(STP_WRITE_DATA_PREFETCH);
+ writel(tl_control, &iphy->transport_layer_registers->control);
+
+ return SCI_SUCCESS;
+}
+
+static enum sci_status
+sci_phy_link_layer_initialization(struct isci_phy *iphy,
+ struct scu_link_layer_registers __iomem *reg)
+{
+ struct isci_host *ihost = iphy->owning_port->owning_controller;
+ int phy_idx = iphy->phy_index;
+ struct sci_phy_user_params *phy_user = &ihost->user_parameters.phys[phy_idx];
+ struct sci_phy_oem_params *phy_oem =
+ &ihost->oem_parameters.phys[phy_idx];
+ u32 phy_configuration;
+ struct sci_phy_cap phy_cap;
+ u32 parity_check = 0;
+ u32 parity_count = 0;
+ u32 llctl, link_rate;
+ u32 clksm_value = 0;
+
+ iphy->link_layer_registers = reg;
+
+ /* Set our IDENTIFY frame data */
+ #define SCI_END_DEVICE 0x01
+
+ writel(SCU_SAS_TIID_GEN_BIT(SMP_INITIATOR) |
+ SCU_SAS_TIID_GEN_BIT(SSP_INITIATOR) |
+ SCU_SAS_TIID_GEN_BIT(STP_INITIATOR) |
+ SCU_SAS_TIID_GEN_BIT(DA_SATA_HOST) |
+ SCU_SAS_TIID_GEN_VAL(DEVICE_TYPE, SCI_END_DEVICE),
+ &iphy->link_layer_registers->transmit_identification);
+
+ /* Write the device SAS Address */
+ writel(0xFEDCBA98,
+ &iphy->link_layer_registers->sas_device_name_high);
+ writel(phy_idx, &iphy->link_layer_registers->sas_device_name_low);
+
+ /* Write the source SAS Address */
+ writel(phy_oem->sas_address.high,
+ &iphy->link_layer_registers->source_sas_address_high);
+ writel(phy_oem->sas_address.low,
+ &iphy->link_layer_registers->source_sas_address_low);
+
+ /* Clear and Set the PHY Identifier */
+ writel(0, &iphy->link_layer_registers->identify_frame_phy_id);
+ writel(SCU_SAS_TIPID_GEN_VALUE(ID, phy_idx),
+ &iphy->link_layer_registers->identify_frame_phy_id);
+
+ /* Change the initial state of the phy configuration register */
+ phy_configuration =
+ readl(&iphy->link_layer_registers->phy_configuration);
+
+ /* Hold OOB state machine in reset */
+ phy_configuration |= SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
+ writel(phy_configuration,
+ &iphy->link_layer_registers->phy_configuration);
+
+ /* Configure the SNW capabilities */
+ phy_cap.all = 0;
+ phy_cap.start = 1;
+ phy_cap.gen3_no_ssc = 1;
+ phy_cap.gen2_no_ssc = 1;
+ phy_cap.gen1_no_ssc = 1;
+ if (ihost->oem_parameters.controller.do_enable_ssc == true) {
+ phy_cap.gen3_ssc = 1;
+ phy_cap.gen2_ssc = 1;
+ phy_cap.gen1_ssc = 1;
+ }
+
+ /*
+ * The SAS specification indicates that the phy_capabilities that
+ * are transmitted shall have an even parity. Calculate the parity. */
+ parity_check = phy_cap.all;
+ while (parity_check != 0) {
+ if (parity_check & 0x1)
+ parity_count++;
+ parity_check >>= 1;
+ }
+
+ /*
+ * If parity indicates there are an odd number of bits set, then
+ * set the parity bit to 1 in the phy capabilities. */
+ if ((parity_count % 2) != 0)
+ phy_cap.parity = 1;
+
+ writel(phy_cap.all, &iphy->link_layer_registers->phy_capabilities);
+
+ /* Set the enable spinup period but disable the ability to send
+ * notify enable spinup
+ */
+ writel(SCU_ENSPINUP_GEN_VAL(COUNT,
+ phy_user->notify_enable_spin_up_insertion_frequency),
+ &iphy->link_layer_registers->notify_enable_spinup_control);
+
+ /* Write the ALIGN Insertion Ferequency for connected phy and
+ * inpendent of connected state
+ */
+ clksm_value = SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL(CONNECTED,
+ phy_user->in_connection_align_insertion_frequency);
+
+ clksm_value |= SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL(GENERAL,
+ phy_user->align_insertion_frequency);
+
+ writel(clksm_value, &iphy->link_layer_registers->clock_skew_management);
+
+ /* @todo Provide a way to write this register correctly */
+ writel(0x02108421,
+ &iphy->link_layer_registers->afe_lookup_table_control);
+
+ llctl = SCU_SAS_LLCTL_GEN_VAL(NO_OUTBOUND_TASK_TIMEOUT,
+ (u8)ihost->user_parameters.no_outbound_task_timeout);
+
+ switch (phy_user->max_speed_generation) {
+ case SCIC_SDS_PARM_GEN3_SPEED:
+ link_rate = SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN3;
+ break;
+ case SCIC_SDS_PARM_GEN2_SPEED:
+ link_rate = SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN2;
+ break;
+ default:
+ link_rate = SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1;
+ break;
+ }
+ llctl |= SCU_SAS_LLCTL_GEN_VAL(MAX_LINK_RATE, link_rate);
+ writel(llctl, &iphy->link_layer_registers->link_layer_control);
+
+ 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
+ * many breaks. This time value will guarantee that the initiator PHY will
+ * generate the break.
+ */
+ writel(SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME,
+ &iphy->link_layer_registers->maximum_arbitration_wait_timer_timeout);
+ }
+
+ /* Disable link layer hang detection, rely on the OS timeout for I/O timeouts. */
+ writel(0, &iphy->link_layer_registers->link_layer_hang_detection_timeout);
+
+ /* We can exit the initial state to the stopped state */
+ sci_change_state(&iphy->sm, SCI_PHY_STOPPED);
+
+ return SCI_SUCCESS;
+}
+
+static void phy_sata_timeout(unsigned long data)
+{
+ struct sci_timer *tmr = (struct sci_timer *)data;
+ struct isci_phy *iphy = container_of(tmr, typeof(*iphy), sata_timer);
+ struct isci_host *ihost = iphy->owning_port->owning_controller;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+
+ if (tmr->cancel)
+ goto done;
+
+ dev_dbg(sciphy_to_dev(iphy),
+ "%s: SCIC SDS Phy 0x%p did not receive signature fis before "
+ "timeout.\n",
+ __func__,
+ iphy);
+
+ sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+done:
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+}
+
+/**
+ * This method returns the port currently containing this phy. If the phy is
+ * currently contained by the dummy port, then the phy is considered to not
+ * be part of a port.
+ * @sci_phy: This parameter specifies the phy for which to retrieve the
+ * containing port.
+ *
+ * This method returns a handle to a port that contains the supplied phy.
+ * NULL This value is returned if the phy is not part of a real
+ * port (i.e. it's contained in the dummy port). !NULL All other
+ * values indicate a handle/pointer to the port containing the phy.
+ */
+struct isci_port *phy_get_non_dummy_port(struct isci_phy *iphy)
+{
+ struct isci_port *iport = iphy->owning_port;
+
+ if (iport->physical_port_index == SCIC_SDS_DUMMY_PORT)
+ return NULL;
+
+ return iphy->owning_port;
+}
+
+/**
+ * This method will assign a port to the phy object.
+ * @out]: iphy This parameter specifies the phy for which to assign a port
+ * object.
+ *
+ *
+ */
+void sci_phy_set_port(
+ struct isci_phy *iphy,
+ struct isci_port *iport)
+{
+ iphy->owning_port = iport;
+
+ if (iphy->bcn_received_while_port_unassigned) {
+ iphy->bcn_received_while_port_unassigned = false;
+ sci_port_broadcast_change_received(iphy->owning_port, iphy);
+ }
+}
+
+enum sci_status sci_phy_initialize(struct isci_phy *iphy,
+ struct scu_transport_layer_registers __iomem *tl,
+ struct scu_link_layer_registers __iomem *ll)
+{
+ /* Perfrom the initialization of the TL hardware */
+ sci_phy_transport_layer_initialization(iphy, tl);
+
+ /* Perofrm the initialization of the PE hardware */
+ sci_phy_link_layer_initialization(iphy, ll);
+
+ /* There is nothing that needs to be done in this state just
+ * transition to the stopped state
+ */
+ sci_change_state(&iphy->sm, SCI_PHY_STOPPED);
+
+ return SCI_SUCCESS;
+}
+
+/**
+ * This method assigns the direct attached device ID for this phy.
+ *
+ * @iphy The phy for which the direct attached device id is to
+ * be assigned.
+ * @device_id The direct attached device ID to assign to the phy.
+ * This will either be the RNi for the device or an invalid RNi if there
+ * is no current device assigned to the phy.
+ */
+void sci_phy_setup_transport(struct isci_phy *iphy, u32 device_id)
+{
+ u32 tl_control;
+
+ writel(device_id, &iphy->transport_layer_registers->stp_rni);
+
+ /*
+ * The read should guarantee that the first write gets posted
+ * before the next write
+ */
+ tl_control = readl(&iphy->transport_layer_registers->control);
+ tl_control |= SCU_TLCR_GEN_BIT(CLEAR_TCI_NCQ_MAPPING_TABLE);
+ writel(tl_control, &iphy->transport_layer_registers->control);
+}
+
+static void sci_phy_suspend(struct isci_phy *iphy)
+{
+ u32 scu_sas_pcfg_value;
+
+ scu_sas_pcfg_value =
+ readl(&iphy->link_layer_registers->phy_configuration);
+ scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE);
+ writel(scu_sas_pcfg_value,
+ &iphy->link_layer_registers->phy_configuration);
+
+ sci_phy_setup_transport(iphy, SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX);
+}
+
+void sci_phy_resume(struct isci_phy *iphy)
+{
+ u32 scu_sas_pcfg_value;
+
+ scu_sas_pcfg_value =
+ readl(&iphy->link_layer_registers->phy_configuration);
+ scu_sas_pcfg_value &= ~SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE);
+ writel(scu_sas_pcfg_value,
+ &iphy->link_layer_registers->phy_configuration);
+}
+
+void sci_phy_get_sas_address(struct isci_phy *iphy, struct sci_sas_address *sas)
+{
+ sas->high = readl(&iphy->link_layer_registers->source_sas_address_high);
+ sas->low = readl(&iphy->link_layer_registers->source_sas_address_low);
+}
+
+void sci_phy_get_attached_sas_address(struct isci_phy *iphy, struct sci_sas_address *sas)
+{
+ struct sas_identify_frame *iaf;
+
+ iaf = &iphy->frame_rcvd.iaf;
+ memcpy(sas, iaf->sas_addr, SAS_ADDR_SIZE);
+}
+
+void sci_phy_get_protocols(struct isci_phy *iphy, struct sci_phy_proto *proto)
+{
+ proto->all = readl(&iphy->link_layer_registers->transmit_identification);
+}
+
+enum sci_status sci_phy_start(struct isci_phy *iphy)
+{
+ enum sci_phy_states state = iphy->sm.current_state_id;
+
+ if (state != SCI_PHY_STOPPED) {
+ dev_dbg(sciphy_to_dev(iphy),
+ "%s: in wrong state: %d\n", __func__, state);
+ return SCI_FAILURE_INVALID_STATE;
+ }
+
+ sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+ return SCI_SUCCESS;
+}
+
+enum sci_status sci_phy_stop(struct isci_phy *iphy)
+{
+ enum sci_phy_states state = iphy->sm.current_state_id;
+
+ switch (state) {
+ case SCI_PHY_SUB_INITIAL:
+ case SCI_PHY_SUB_AWAIT_OSSP_EN:
+ case SCI_PHY_SUB_AWAIT_SAS_SPEED_EN:
+ case SCI_PHY_SUB_AWAIT_SAS_POWER:
+ case SCI_PHY_SUB_AWAIT_SATA_POWER:
+ case SCI_PHY_SUB_AWAIT_SATA_PHY_EN:
+ case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN:
+ case SCI_PHY_SUB_AWAIT_SIG_FIS_UF:
+ case SCI_PHY_SUB_FINAL:
+ case SCI_PHY_READY:
+ break;
+ default:
+ dev_dbg(sciphy_to_dev(iphy),
+ "%s: in wrong state: %d\n", __func__, state);
+ return SCI_FAILURE_INVALID_STATE;
+ }
+
+ sci_change_state(&iphy->sm, SCI_PHY_STOPPED);
+ return SCI_SUCCESS;
+}
+
+enum sci_status sci_phy_reset(struct isci_phy *iphy)
+{
+ enum sci_phy_states state = iphy->sm.current_state_id;
+
+ if (state != SCI_PHY_READY) {
+ dev_dbg(sciphy_to_dev(iphy),
+ "%s: in wrong state: %d\n", __func__, state);
+ return SCI_FAILURE_INVALID_STATE;
+ }
+
+ sci_change_state(&iphy->sm, SCI_PHY_RESETTING);
+ return SCI_SUCCESS;
+}
+
+enum sci_status sci_phy_consume_power_handler(struct isci_phy *iphy)
+{
+ enum sci_phy_states state = iphy->sm.current_state_id;
+
+ switch (state) {
+ case SCI_PHY_SUB_AWAIT_SAS_POWER: {
+ u32 enable_spinup;
+
+ enable_spinup = readl(&iphy->link_layer_registers->notify_enable_spinup_control);
+ enable_spinup |= SCU_ENSPINUP_GEN_BIT(ENABLE);
+ writel(enable_spinup, &iphy->link_layer_registers->notify_enable_spinup_control);
+
+ /* Change state to the final state this substate machine has run to completion */
+ sci_change_state(&iphy->sm, SCI_PHY_SUB_FINAL);
+
+ return SCI_SUCCESS;
+ }
+ case SCI_PHY_SUB_AWAIT_SATA_POWER: {
+ u32 scu_sas_pcfg_value;
+
+ /* Release the spinup hold state and reset the OOB state machine */
+ scu_sas_pcfg_value =
+ readl(&iphy->link_layer_registers->phy_configuration);
+ scu_sas_pcfg_value &=
+ ~(SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD) | SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE));
+ scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
+ writel(scu_sas_pcfg_value,
+ &iphy->link_layer_registers->phy_configuration);
+
+ /* Now restart the OOB operation */
+ scu_sas_pcfg_value &= ~SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
+ scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE);
+ writel(scu_sas_pcfg_value,
+ &iphy->link_layer_registers->phy_configuration);
+
+ /* Change state to the final state this substate machine has run to completion */
+ sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_PHY_EN);
+
+ return SCI_SUCCESS;
+ }
+ default:
+ dev_dbg(sciphy_to_dev(iphy),
+ "%s: in wrong state: %d\n", __func__, state);
+ return SCI_FAILURE_INVALID_STATE;
+ }
+}
+
+static void sci_phy_start_sas_link_training(struct isci_phy *iphy)
+{
+ /* continue the link training for the phy as if it were a SAS PHY
+ * instead of a SATA PHY. This is done because the completion queue had a SAS
+ * PHY DETECTED event when the state machine was expecting a SATA PHY event.
+ */
+ u32 phy_control;
+
+ phy_control = readl(&iphy->link_layer_registers->phy_configuration);
+ phy_control |= SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD);
+ writel(phy_control,
+ &iphy->link_layer_registers->phy_configuration);
+
+ sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SAS_SPEED_EN);
+
+ iphy->protocol = SCIC_SDS_PHY_PROTOCOL_SAS;
+}
+
+static void sci_phy_start_sata_link_training(struct isci_phy *iphy)
+{
+ /* This method continues the link training for the phy as if it were a SATA PHY
+ * instead of a SAS PHY. This is done because the completion queue had a SATA
+ * SPINUP HOLD event when the state machine was expecting a SAS PHY event. none
+ */
+ sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_POWER);
+
+ iphy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA;
+}
+
+/**
+ * sci_phy_complete_link_training - perform processing common to
+ * all protocols upon completion of link training.
+ * @sci_phy: This parameter specifies the phy object for which link training
+ * has completed.
+ * @max_link_rate: This parameter specifies the maximum link rate to be
+ * associated with this phy.
+ * @next_state: This parameter specifies the next state for the phy's starting
+ * sub-state machine.
+ *
+ */
+static void sci_phy_complete_link_training(struct isci_phy *iphy,
+ enum sas_linkrate max_link_rate,
+ u32 next_state)
+{
+ iphy->max_negotiated_speed = max_link_rate;
+
+ sci_change_state(&iphy->sm, next_state);
+}
+
+enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
+{
+ enum sci_phy_states state = iphy->sm.current_state_id;
+
+ switch (state) {
+ case SCI_PHY_SUB_AWAIT_OSSP_EN:
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_SAS_PHY_DETECTED:
+ sci_phy_start_sas_link_training(iphy);
+ iphy->is_in_link_training = true;
+ break;
+ case SCU_EVENT_SATA_SPINUP_HOLD:
+ sci_phy_start_sata_link_training(iphy);
+ iphy->is_in_link_training = true;
+ break;
+ default:
+ dev_dbg(sciphy_to_dev(iphy),
+ "%s: PHY starting substate machine received "
+ "unexpected event_code %x\n",
+ __func__,
+ event_code);
+ return SCI_FAILURE;
+ }
+ return SCI_SUCCESS;
+ case SCI_PHY_SUB_AWAIT_SAS_SPEED_EN:
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_SAS_PHY_DETECTED:
+ /*
+ * Why is this being reported again by the controller?
+ * We would re-enter this state so just stay here */
+ break;
+ case SCU_EVENT_SAS_15:
+ case SCU_EVENT_SAS_15_SSC:
+ sci_phy_complete_link_training(iphy, SAS_LINK_RATE_1_5_GBPS,
+ SCI_PHY_SUB_AWAIT_IAF_UF);
+ break;
+ case SCU_EVENT_SAS_30:
+ case SCU_EVENT_SAS_30_SSC:
+ sci_phy_complete_link_training(iphy, SAS_LINK_RATE_3_0_GBPS,
+ SCI_PHY_SUB_AWAIT_IAF_UF);
+ break;
+ case SCU_EVENT_SAS_60:
+ case SCU_EVENT_SAS_60_SSC:
+ sci_phy_complete_link_training(iphy, SAS_LINK_RATE_6_0_GBPS,
+ SCI_PHY_SUB_AWAIT_IAF_UF);
+ break;
+ case SCU_EVENT_SATA_SPINUP_HOLD:
+ /*
+ * We were doing SAS PHY link training and received a SATA PHY event
+ * continue OOB/SN as if this were a SATA PHY */
+ sci_phy_start_sata_link_training(iphy);
+ break;
+ case SCU_EVENT_LINK_FAILURE:
+ /* Link failure change state back to the starting state */
+ sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+ break;
+ default:
+ dev_warn(sciphy_to_dev(iphy),
+ "%s: PHY starting substate machine received "
+ "unexpected event_code %x\n",
+ __func__, event_code);
+
+ return SCI_FAILURE;
+ break;
+ }
+ return SCI_SUCCESS;
+ case SCI_PHY_SUB_AWAIT_IAF_UF:
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_SAS_PHY_DETECTED:
+ /* Backup the state machine */
+ sci_phy_start_sas_link_training(iphy);
+ break;
+ case SCU_EVENT_SATA_SPINUP_HOLD:
+ /* We were doing SAS PHY link training and received a
+ * SATA PHY event continue OOB/SN as if this were a
+ * SATA PHY
+ */
+ sci_phy_start_sata_link_training(iphy);
+ break;
+ case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT:
+ case SCU_EVENT_LINK_FAILURE:
+ case SCU_EVENT_HARD_RESET_RECEIVED:
+ /* Start the oob/sn state machine over again */
+ sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+ break;
+ default:
+ dev_warn(sciphy_to_dev(iphy),
+ "%s: PHY starting substate machine received "
+ "unexpected event_code %x\n",
+ __func__, event_code);
+ return SCI_FAILURE;
+ }
+ return SCI_SUCCESS;
+ case SCI_PHY_SUB_AWAIT_SAS_POWER:
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_LINK_FAILURE:
+ /* Link failure change state back to the starting state */
+ sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+ break;
+ default:
+ dev_warn(sciphy_to_dev(iphy),
+ "%s: PHY starting substate machine received unexpected "
+ "event_code %x\n",
+ __func__,
+ event_code);
+ return SCI_FAILURE;
+ }
+ return SCI_SUCCESS;
+ case SCI_PHY_SUB_AWAIT_SATA_POWER:
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_LINK_FAILURE:
+ /* Link failure change state back to the starting state */
+ sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+ break;
+ case SCU_EVENT_SATA_SPINUP_HOLD:
+ /* These events are received every 10ms and are
+ * expected while in this state
+ */
+ break;
+
+ case SCU_EVENT_SAS_PHY_DETECTED:
+ /* There has been a change in the phy type before OOB/SN for the
+ * SATA finished start down the SAS link traning path.
+ */
+ sci_phy_start_sas_link_training(iphy);
+ break;
+
+ default:
+ dev_warn(sciphy_to_dev(iphy),
+ "%s: PHY starting substate machine received "
+ "unexpected event_code %x\n",
+ __func__, event_code);
+
+ return SCI_FAILURE;
+ }
+ return SCI_SUCCESS;
+ case SCI_PHY_SUB_AWAIT_SATA_PHY_EN:
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_LINK_FAILURE:
+ /* Link failure change state back to the starting state */
+ sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+ break;
+ case SCU_EVENT_SATA_SPINUP_HOLD:
+ /* These events might be received since we dont know how many may be in
+ * the completion queue while waiting for power
+ */
+ break;
+ case SCU_EVENT_SATA_PHY_DETECTED:
+ iphy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA;
+
+ /* We have received the SATA PHY notification change state */
+ sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_SPEED_EN);
+ break;
+ case SCU_EVENT_SAS_PHY_DETECTED:
+ /* There has been a change in the phy type before OOB/SN for the
+ * SATA finished start down the SAS link traning path.
+ */
+ sci_phy_start_sas_link_training(iphy);
+ break;
+ default:
+ dev_warn(sciphy_to_dev(iphy),
+ "%s: PHY starting substate machine received "
+ "unexpected event_code %x\n",
+ __func__,
+ event_code);
+
+ return SCI_FAILURE;;
+ }
+ return SCI_SUCCESS;
+ case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN:
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_SATA_PHY_DETECTED:
+ /*
+ * The hardware reports multiple SATA PHY detected events
+ * ignore the extras */
+ break;
+ case SCU_EVENT_SATA_15:
+ case SCU_EVENT_SATA_15_SSC:
+ sci_phy_complete_link_training(iphy, SAS_LINK_RATE_1_5_GBPS,
+ SCI_PHY_SUB_AWAIT_SIG_FIS_UF);
+ break;
+ case SCU_EVENT_SATA_30:
+ case SCU_EVENT_SATA_30_SSC:
+ sci_phy_complete_link_training(iphy, SAS_LINK_RATE_3_0_GBPS,
+ SCI_PHY_SUB_AWAIT_SIG_FIS_UF);
+ break;
+ case SCU_EVENT_SATA_60:
+ case SCU_EVENT_SATA_60_SSC:
+ sci_phy_complete_link_training(iphy, SAS_LINK_RATE_6_0_GBPS,
+ SCI_PHY_SUB_AWAIT_SIG_FIS_UF);
+ break;
+ case SCU_EVENT_LINK_FAILURE:
+ /* Link failure change state back to the starting state */
+ sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+ break;
+ case SCU_EVENT_SAS_PHY_DETECTED:
+ /*
+ * There has been a change in the phy type before OOB/SN for the
+ * SATA finished start down the SAS link traning path. */
+ sci_phy_start_sas_link_training(iphy);
+ break;
+ default:
+ dev_warn(sciphy_to_dev(iphy),
+ "%s: PHY starting substate machine received "
+ "unexpected event_code %x\n",
+ __func__, event_code);
+
+ return SCI_FAILURE;
+ }
+
+ return SCI_SUCCESS;
+ case SCI_PHY_SUB_AWAIT_SIG_FIS_UF:
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_SATA_PHY_DETECTED:
+ /* Backup the state machine */
+ sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_SPEED_EN);
+ break;
+
+ case SCU_EVENT_LINK_FAILURE:
+ /* Link failure change state back to the starting state */
+ sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+ break;
+
+ default:
+ dev_warn(sciphy_to_dev(iphy),
+ "%s: PHY starting substate machine received "
+ "unexpected event_code %x\n",
+ __func__,
+ event_code);
+
+ return SCI_FAILURE;
+ }
+ return SCI_SUCCESS;
+ case SCI_PHY_READY:
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_LINK_FAILURE:
+ /* Link failure change state back to the starting state */
+ sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+ break;
+ case SCU_EVENT_BROADCAST_CHANGE:
+ /* Broadcast change received. Notify the port. */
+ if (phy_get_non_dummy_port(iphy) != NULL)
+ sci_port_broadcast_change_received(iphy->owning_port, iphy);
+ else
+ iphy->bcn_received_while_port_unassigned = true;
+ break;
+ default:
+ dev_warn(sciphy_to_dev(iphy),
+ "%sP SCIC PHY 0x%p ready state machine received "
+ "unexpected event_code %x\n",
+ __func__, iphy, event_code);
+ return SCI_FAILURE_INVALID_STATE;
+ }
+ return SCI_SUCCESS;
+ case SCI_PHY_RESETTING:
+ switch (scu_get_event_code(event_code)) {
+ case SCU_EVENT_HARD_RESET_TRANSMITTED:
+ /* Link failure change state back to the starting state */
+ sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+ break;
+ default:
+ dev_warn(sciphy_to_dev(iphy),
+ "%s: SCIC PHY 0x%p resetting state machine received "
+ "unexpected event_code %x\n",
+ __func__, iphy, event_code);
+
+ return SCI_FAILURE_INVALID_STATE;
+ break;
+ }
+ return SCI_SUCCESS;
+ default:
+ dev_dbg(sciphy_to_dev(iphy),
+ "%s: in wrong state: %d\n", __func__, state);
+ return SCI_FAILURE_INVALID_STATE;
+ }
+}
+
+enum sci_status sci_phy_frame_handler(struct isci_phy *iphy, u32 frame_index)
+{
+ enum sci_phy_states state = iphy->sm.current_state_id;
+ struct isci_host *ihost = iphy->owning_port->owning_controller;
+ enum sci_status result;
+ unsigned long flags;
+
+ switch (state) {
+ case SCI_PHY_SUB_AWAIT_IAF_UF: {
+ u32 *frame_words;
+ struct sas_identify_frame iaf;
+
+ result = sci_unsolicited_frame_control_get_header(&ihost->uf_control,
+ frame_index,
+ (void **)&frame_words);
+
+ if (result != SCI_SUCCESS)
+ return result;
+
+ sci_swab32_cpy(&iaf, frame_words, sizeof(iaf) / sizeof(u32));
+ if (iaf.frame_type == 0) {
+ u32 state;
+
+ spin_lock_irqsave(&iphy->sas_phy.frame_rcvd_lock, flags);
+ memcpy(&iphy->frame_rcvd.iaf, &iaf, sizeof(iaf));
+ spin_unlock_irqrestore(&iphy->sas_phy.frame_rcvd_lock, flags);
+ if (iaf.smp_tport) {
+ /* We got the IAF for an expander PHY go to the final
+ * state since there are no power requirements for
+ * expander phys.
+ */
+ state = SCI_PHY_SUB_FINAL;
+ } else {
+ /* We got the IAF we can now go to the await spinup
+ * semaphore state
+ */
+ state = SCI_PHY_SUB_AWAIT_SAS_POWER;
+ }
+ sci_change_state(&iphy->sm, state);
+ result = SCI_SUCCESS;
+ } else
+ dev_warn(sciphy_to_dev(iphy),
+ "%s: PHY starting substate machine received "
+ "unexpected frame id %x\n",
+ __func__, frame_index);
+
+ sci_controller_release_frame(ihost, frame_index);
+ return result;
+ }
+ case SCI_PHY_SUB_AWAIT_SIG_FIS_UF: {
+ struct dev_to_host_fis *frame_header;
+ u32 *fis_frame_data;
+
+ result = sci_unsolicited_frame_control_get_header(&ihost->uf_control,
+ frame_index,
+ (void **)&frame_header);
+
+ if (result != SCI_SUCCESS)
+ return result;
+
+ if ((frame_header->fis_type == FIS_REGD2H) &&
+ !(frame_header->status & ATA_BUSY)) {
+ sci_unsolicited_frame_control_get_buffer(&ihost->uf_control,
+ frame_index,
+ (void **)&fis_frame_data);
+
+ spin_lock_irqsave(&iphy->sas_phy.frame_rcvd_lock, flags);
+ sci_controller_copy_sata_response(&iphy->frame_rcvd.fis,
+ frame_header,
+ fis_frame_data);
+ spin_unlock_irqrestore(&iphy->sas_phy.frame_rcvd_lock, flags);
+
+ /* got IAF we can now go to the await spinup semaphore state */
+ sci_change_state(&iphy->sm, SCI_PHY_SUB_FINAL);
+
+ result = SCI_SUCCESS;
+ } else
+ dev_warn(sciphy_to_dev(iphy),
+ "%s: PHY starting substate machine received "
+ "unexpected frame id %x\n",
+ __func__, frame_index);
+
+ /* Regardless of the result we are done with this frame with it */
+ sci_controller_release_frame(ihost, frame_index);
+
+ return result;
+ }
+ default:
+ dev_dbg(sciphy_to_dev(iphy),
+ "%s: in wrong state: %d\n", __func__, state);
+ return SCI_FAILURE_INVALID_STATE;
+ }
+
+}
+
+static void sci_phy_starting_initial_substate_enter(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+
+ /* This is just an temporary state go off to the starting state */
+ sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_OSSP_EN);
+}
+
+static void sci_phy_starting_await_sas_power_substate_enter(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+ struct isci_host *ihost = iphy->owning_port->owning_controller;
+
+ sci_controller_power_control_queue_insert(ihost, iphy);
+}
+
+static void sci_phy_starting_await_sas_power_substate_exit(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+ struct isci_host *ihost = iphy->owning_port->owning_controller;
+
+ sci_controller_power_control_queue_remove(ihost, iphy);
+}
+
+static void sci_phy_starting_await_sata_power_substate_enter(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+ struct isci_host *ihost = iphy->owning_port->owning_controller;
+
+ sci_controller_power_control_queue_insert(ihost, iphy);
+}
+
+static void sci_phy_starting_await_sata_power_substate_exit(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+ struct isci_host *ihost = iphy->owning_port->owning_controller;
+
+ sci_controller_power_control_queue_remove(ihost, iphy);
+}
+
+static void sci_phy_starting_await_sata_phy_substate_enter(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+
+ sci_mod_timer(&iphy->sata_timer, SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT);
+}
+
+static void sci_phy_starting_await_sata_phy_substate_exit(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+
+ sci_del_timer(&iphy->sata_timer);
+}
+
+static void sci_phy_starting_await_sata_speed_substate_enter(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+
+ sci_mod_timer(&iphy->sata_timer, SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT);
+}
+
+static void sci_phy_starting_await_sata_speed_substate_exit(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+
+ sci_del_timer(&iphy->sata_timer);
+}
+
+static void sci_phy_starting_await_sig_fis_uf_substate_enter(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+
+ if (sci_port_link_detected(iphy->owning_port, iphy)) {
+
+ /*
+ * Clear the PE suspend condition so we can actually
+ * receive SIG FIS
+ * The hardware will not respond to the XRDY until the PE
+ * suspend condition is cleared.
+ */
+ sci_phy_resume(iphy);
+
+ sci_mod_timer(&iphy->sata_timer,
+ SCIC_SDS_SIGNATURE_FIS_TIMEOUT);
+ } else
+ iphy->is_in_link_training = false;
+}
+
+static void sci_phy_starting_await_sig_fis_uf_substate_exit(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+
+ sci_del_timer(&iphy->sata_timer);
+}
+
+static void sci_phy_starting_final_substate_enter(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+
+ /* State machine has run to completion so exit out and change
+ * the base state machine to the ready state
+ */
+ sci_change_state(&iphy->sm, SCI_PHY_READY);
+}
+
+/**
+ *
+ * @sci_phy: This is the struct isci_phy object to stop.
+ *
+ * This method will stop the struct isci_phy object. This does not reset the
+ * protocol engine it just suspends it and places it in a state where it will
+ * not cause the end device to power up. none
+ */
+static void scu_link_layer_stop_protocol_engine(
+ struct isci_phy *iphy)
+{
+ u32 scu_sas_pcfg_value;
+ u32 enable_spinup_value;
+
+ /* Suspend the protocol engine and place it in a sata spinup hold state */
+ scu_sas_pcfg_value =
+ readl(&iphy->link_layer_registers->phy_configuration);
+ scu_sas_pcfg_value |=
+ (SCU_SAS_PCFG_GEN_BIT(OOB_RESET) |
+ SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE) |
+ SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD));
+ writel(scu_sas_pcfg_value,
+ &iphy->link_layer_registers->phy_configuration);
+
+ /* Disable the notify enable spinup primitives */
+ enable_spinup_value = readl(&iphy->link_layer_registers->notify_enable_spinup_control);
+ enable_spinup_value &= ~SCU_ENSPINUP_GEN_BIT(ENABLE);
+ writel(enable_spinup_value, &iphy->link_layer_registers->notify_enable_spinup_control);
+}
+
+/**
+ *
+ *
+ * This method will start the OOB/SN state machine for this struct isci_phy object.
+ */
+static void scu_link_layer_start_oob(
+ struct isci_phy *iphy)
+{
+ u32 scu_sas_pcfg_value;
+
+ scu_sas_pcfg_value =
+ readl(&iphy->link_layer_registers->phy_configuration);
+ scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE);
+ scu_sas_pcfg_value &=
+ ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) |
+ SCU_SAS_PCFG_GEN_BIT(HARD_RESET));
+ writel(scu_sas_pcfg_value,
+ &iphy->link_layer_registers->phy_configuration);
+}
+
+/**
+ *
+ *
+ * This method will transmit a hard reset request on the specified phy. The SCU
+ * hardware requires that we reset the OOB state machine and set the hard reset
+ * bit in the phy configuration register. We then must start OOB over with the
+ * hard reset bit set.
+ */
+static void scu_link_layer_tx_hard_reset(
+ struct isci_phy *iphy)
+{
+ u32 phy_configuration_value;
+
+ /*
+ * SAS Phys must wait for the HARD_RESET_TX event notification to transition
+ * to the starting state. */
+ phy_configuration_value =
+ readl(&iphy->link_layer_registers->phy_configuration);
+ phy_configuration_value |=
+ (SCU_SAS_PCFG_GEN_BIT(HARD_RESET) |
+ SCU_SAS_PCFG_GEN_BIT(OOB_RESET));
+ writel(phy_configuration_value,
+ &iphy->link_layer_registers->phy_configuration);
+
+ /* Now take the OOB state machine out of reset */
+ phy_configuration_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE);
+ phy_configuration_value &= ~SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
+ writel(phy_configuration_value,
+ &iphy->link_layer_registers->phy_configuration);
+}
+
+static void sci_phy_stopped_state_enter(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+ struct isci_port *iport = iphy->owning_port;
+ struct isci_host *ihost = iport->owning_controller;
+
+ /*
+ * @todo We need to get to the controller to place this PE in a
+ * reset state
+ */
+ sci_del_timer(&iphy->sata_timer);
+
+ scu_link_layer_stop_protocol_engine(iphy);
+
+ if (iphy->sm.previous_state_id != SCI_PHY_INITIAL)
+ sci_controller_link_down(ihost, phy_get_non_dummy_port(iphy), iphy);
+}
+
+static void sci_phy_starting_state_enter(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+ struct isci_port *iport = iphy->owning_port;
+ struct isci_host *ihost = iport->owning_controller;
+
+ scu_link_layer_stop_protocol_engine(iphy);
+ scu_link_layer_start_oob(iphy);
+
+ /* We don't know what kind of phy we are going to be just yet */
+ iphy->protocol = SCIC_SDS_PHY_PROTOCOL_UNKNOWN;
+ iphy->bcn_received_while_port_unassigned = false;
+
+ if (iphy->sm.previous_state_id == SCI_PHY_READY)
+ sci_controller_link_down(ihost, phy_get_non_dummy_port(iphy), iphy);
+
+ sci_change_state(&iphy->sm, SCI_PHY_SUB_INITIAL);
+}
+
+static void sci_phy_ready_state_enter(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+ struct isci_port *iport = iphy->owning_port;
+ struct isci_host *ihost = iport->owning_controller;
+
+ sci_controller_link_up(ihost, phy_get_non_dummy_port(iphy), iphy);
+}
+
+static void sci_phy_ready_state_exit(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+
+ sci_phy_suspend(iphy);
+}
+
+static void sci_phy_resetting_state_enter(struct sci_base_state_machine *sm)
+{
+ struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm);
+
+ /* The phy is being reset, therefore deactivate it from the port. In
+ * the resetting state we don't notify the user regarding link up and
+ * link down notifications
+ */
+ sci_port_deactivate_phy(iphy->owning_port, iphy, false);
+
+ if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) {
+ scu_link_layer_tx_hard_reset(iphy);
+ } else {
+ /* The SCU does not need to have a discrete reset state so
+ * just go back to the starting state.
+ */
+ sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+ }
+}
+
+static const struct sci_base_state sci_phy_state_table[] = {
+ [SCI_PHY_INITIAL] = { },
+ [SCI_PHY_STOPPED] = {
+ .enter_state = sci_phy_stopped_state_enter,
+ },
+ [SCI_PHY_STARTING] = {
+ .enter_state = sci_phy_starting_state_enter,
+ },
+ [SCI_PHY_SUB_INITIAL] = {
+ .enter_state = sci_phy_starting_initial_substate_enter,
+ },
+ [SCI_PHY_SUB_AWAIT_OSSP_EN] = { },
+ [SCI_PHY_SUB_AWAIT_SAS_SPEED_EN] = { },
+ [SCI_PHY_SUB_AWAIT_IAF_UF] = { },
+ [SCI_PHY_SUB_AWAIT_SAS_POWER] = {
+ .enter_state = sci_phy_starting_await_sas_power_substate_enter,
+ .exit_state = sci_phy_starting_await_sas_power_substate_exit,
+ },
+ [SCI_PHY_SUB_AWAIT_SATA_POWER] = {
+ .enter_state = sci_phy_starting_await_sata_power_substate_enter,
+ .exit_state = sci_phy_starting_await_sata_power_substate_exit
+ },
+ [SCI_PHY_SUB_AWAIT_SATA_PHY_EN] = {
+ .enter_state = sci_phy_starting_await_sata_phy_substate_enter,
+ .exit_state = sci_phy_starting_await_sata_phy_substate_exit
+ },
+ [SCI_PHY_SUB_AWAIT_SATA_SPEED_EN] = {
+ .enter_state = sci_phy_starting_await_sata_speed_substate_enter,
+ .exit_state = sci_phy_starting_await_sata_speed_substate_exit
+ },
+ [SCI_PHY_SUB_AWAIT_SIG_FIS_UF] = {
+ .enter_state = sci_phy_starting_await_sig_fis_uf_substate_enter,
+ .exit_state = sci_phy_starting_await_sig_fis_uf_substate_exit
+ },
+ [SCI_PHY_SUB_FINAL] = {
+ .enter_state = sci_phy_starting_final_substate_enter,
+ },
+ [SCI_PHY_READY] = {
+ .enter_state = sci_phy_ready_state_enter,
+ .exit_state = sci_phy_ready_state_exit,
+ },
+ [SCI_PHY_RESETTING] = {
+ .enter_state = sci_phy_resetting_state_enter,
+ },
+ [SCI_PHY_FINAL] = { },
+};
+
+void sci_phy_construct(struct isci_phy *iphy,
+ struct isci_port *iport, u8 phy_index)
+{
+ sci_init_sm(&iphy->sm, sci_phy_state_table, SCI_PHY_INITIAL);
+
+ /* Copy the rest of the input data to our locals */
+ iphy->owning_port = iport;
+ iphy->phy_index = phy_index;
+ iphy->bcn_received_while_port_unassigned = false;
+ iphy->protocol = SCIC_SDS_PHY_PROTOCOL_UNKNOW