/include/clocksource/

treeRussell King
summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile5
-rw-r--r--drivers/acpi/Kconfig29
-rw-r--r--drivers/acpi/Makefile3
-rw-r--r--drivers/acpi/ac.c3
-rw-r--r--drivers/acpi/acpi_memhotplug.c51
-rw-r--r--drivers/acpi/acpi_pad.c514
-rw-r--r--drivers/acpi/acpica/Makefile4
-rw-r--r--drivers/acpi/acpica/acconfig.h14
-rw-r--r--drivers/acpi/acpica/acdebug.h4
-rw-r--r--drivers/acpi/acpica/acglobal.h37
-rw-r--r--drivers/acpi/acpica/achware.h8
-rw-r--r--drivers/acpi/acpica/acinterp.h4
-rw-r--r--drivers/acpi/acpica/aclocal.h16
-rw-r--r--drivers/acpi/acpica/acmacros.h2
-rw-r--r--drivers/acpi/acpica/acnamesp.h25
-rw-r--r--drivers/acpi/acpica/acobject.h1
-rw-r--r--drivers/acpi/acpica/acparser.h2
-rw-r--r--drivers/acpi/acpica/acpredef.h585
-rw-r--r--drivers/acpi/acpica/acutils.h30
-rw-r--r--drivers/acpi/acpica/amlcode.h1
-rw-r--r--drivers/acpi/acpica/dsfield.c18
-rw-r--r--drivers/acpi/acpica/dsmethod.c15
-rw-r--r--drivers/acpi/acpica/dsmthdat.c8
-rw-r--r--drivers/acpi/acpica/dsobject.c23
-rw-r--r--drivers/acpi/acpica/dswload.c41
-rw-r--r--drivers/acpi/acpica/evgpe.c8
-rw-r--r--drivers/acpi/acpica/evgpeblk.c4
-rw-r--r--drivers/acpi/acpica/evrgnini.c45
-rw-r--r--drivers/acpi/acpica/exconfig.c7
-rw-r--r--drivers/acpi/acpica/exdump.c6
-rw-r--r--drivers/acpi/acpica/exfield.c82
-rw-r--r--drivers/acpi/acpica/exfldio.c7
-rw-r--r--drivers/acpi/acpica/exregion.c35
-rw-r--r--drivers/acpi/acpica/exutils.c53
-rw-r--r--drivers/acpi/acpica/hwgpe.c34
-rw-r--r--drivers/acpi/acpica/hwregs.c206
-rw-r--r--drivers/acpi/acpica/hwsleep.c3
-rw-r--r--drivers/acpi/acpica/hwtimer.c2
-rw-r--r--drivers/acpi/acpica/hwxface.c181
-rw-r--r--drivers/acpi/acpica/nsalloc.c88
-rw-r--r--drivers/acpi/acpica/nsdumpdv.c7
-rw-r--r--drivers/acpi/acpica/nseval.c137
-rw-r--r--drivers/acpi/acpica/nsinit.c15
-rw-r--r--drivers/acpi/acpica/nsload.c3
-rw-r--r--drivers/acpi/acpica/nspredef.c718
-rw-r--r--drivers/acpi/acpica/nsrepair.c203
-rw-r--r--drivers/acpi/acpica/nsutils.c5
-rw-r--r--drivers/acpi/acpica/nsxfeval.c23
-rw-r--r--drivers/acpi/acpica/nsxfname.c237
-rw-r--r--drivers/acpi/acpica/psloop.c119
-rw-r--r--drivers/acpi/acpica/psxface.c4
-rw-r--r--drivers/acpi/acpica/tbfadt.c1
-rw-r--r--drivers/acpi/acpica/tbutils.c82
-rw-r--r--drivers/acpi/acpica/utdelete.c6
-rw-r--r--drivers/acpi/acpica/uteval.c378
-rw-r--r--drivers/acpi/acpica/utglobal.c12
-rw-r--r--drivers/acpi/acpica/utids.c382
-rw-r--r--drivers/acpi/acpica/utinit.c22
-rw-r--r--drivers/acpi/acpica/utmisc.c85
-rw-r--r--drivers/acpi/acpica/utxface.c26
-rw-r--r--drivers/acpi/battery.c22
-rw-r--r--drivers/acpi/blacklist.c19
-rw-r--r--drivers/acpi/bus.c52
-rw-r--r--drivers/acpi/button.c50
-rw-r--r--drivers/acpi/cm_sbs.c2
-rw-r--r--drivers/acpi/container.c13
-rw-r--r--drivers/acpi/debug.c82
-rw-r--r--drivers/acpi/dock.c26
-rw-r--r--drivers/acpi/ec.c318
-rw-r--r--drivers/acpi/event.c2
-rw-r--r--drivers/acpi/fan.c2
-rw-r--r--drivers/acpi/glue.c10
-rw-r--r--drivers/acpi/internal.h22
-rw-r--r--drivers/acpi/numa.c2
-rw-r--r--drivers/acpi/osl.c136
-rw-r--r--drivers/acpi/pci_irq.c2
-rw-r--r--drivers/acpi/pci_link.c2
-rw-r--r--drivers/acpi/pci_root.c30
-rw-r--r--drivers/acpi/pci_slot.c5
-rw-r--r--drivers/acpi/power.c59
-rw-r--r--drivers/acpi/power_meter.c1022
-rw-r--r--drivers/acpi/proc.c4
-rw-r--r--drivers/acpi/processor_core.c241
-rw-r--r--drivers/acpi/processor_idle.c20
-rw-r--r--drivers/acpi/processor_perflib.c5
-rw-r--r--drivers/acpi/processor_thermal.c5
-rw-r--r--drivers/acpi/processor_throttling.c14
-rw-r--r--drivers/acpi/sbs.c2
-rw-r--r--drivers/acpi/sbshc.c2
-rw-r--r--drivers/acpi/scan.c698
-rw-r--r--drivers/acpi/sleep.c52
-rw-r--r--drivers/acpi/system.c2
-rw-r--r--drivers/acpi/tables.c6
-rw-r--r--drivers/acpi/thermal.c2
-rw-r--r--drivers/acpi/utils.c2
-rw-r--r--drivers/acpi/video.c101
-rw-r--r--drivers/acpi/video_detect.c4
-rw-r--r--drivers/acpi/wakeup.c4
-rw-r--r--drivers/amba/bus.c26
-rw-r--r--drivers/ata/Kconfig9
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ahci.c213
-rw-r--r--drivers/ata/libata-acpi.c40
-rw-r--r--drivers/ata/libata-core.c28
-rw-r--r--drivers/ata/libata-eh.c56
-rw-r--r--drivers/ata/libata.h2
-rw-r--r--drivers/ata/pata_ali.c2
-rw-r--r--drivers/ata/pata_amd.c3
-rw-r--r--drivers/ata/pata_atiixp.c2
-rw-r--r--drivers/ata/pata_atp867x.c587
-rw-r--r--drivers/ata/pata_hpt37x.c2
-rw-r--r--drivers/ata/pata_pcmcia.c17
-rw-r--r--drivers/ata/pata_sc1200.c3
-rw-r--r--drivers/ata/pata_via.c2
-rw-r--r--drivers/ata/sata_fsl.c84
-rw-r--r--drivers/ata/sata_mv.c29
-rw-r--r--drivers/ata/sata_nv.c18
-rw-r--r--drivers/ata/sata_promise.c155
-rw-r--r--drivers/ata/sata_via.c1
-rw-r--r--drivers/atm/ambassador.c8
-rw-r--r--drivers/atm/eni.c2
-rw-r--r--drivers/atm/firestream.c2
-rw-r--r--drivers/atm/fore200e.c2
-rw-r--r--drivers/atm/he.c59
-rw-r--r--drivers/atm/horizon.c6
-rw-r--r--drivers/atm/iphase.c2
-rw-r--r--drivers/atm/solos-attrlist.c11
-rw-r--r--drivers/atm/solos-pci.c77
-rw-r--r--drivers/atm/zatm.c2
-rw-r--r--drivers/base/Kconfig25
-rw-r--r--drivers/base/Makefile2
-rw-r--r--drivers/base/base.h13
-rw-r--r--drivers/base/bus.c40
-rw-r--r--drivers/base/class.c87
-rw-r--r--drivers/base/core.c48
-rw-r--r--drivers/base/dd.c42
-rw-r--r--drivers/base/devtmpfs.c375
-rw-r--r--drivers/base/dma-coherent.c176
-rw-r--r--drivers/base/driver.c6
-rw-r--r--drivers/base/init.c1
-rw-r--r--drivers/base/node.c5
-rw-r--r--drivers/base/platform.c98
-rw-r--r--drivers/base/power/Makefile1
-rw-r--r--drivers/base/power/main.c200
-rw-r--r--drivers/base/power/power.h31
-rw-r--r--drivers/base/power/runtime.c1007
-rw-r--r--drivers/block/DAC960.c168
-rw-r--r--drivers/block/amiflop.c2
-rw-r--r--drivers/block/aoe/aoeblk.c5
-rw-r--r--drivers/block/aoe/aoechr.c4
-rw-r--r--drivers/block/aoe/aoecmd.c23
-rw-r--r--drivers/block/ataflop.c2
-rw-r--r--drivers/block/brd.c2
-rw-r--r--drivers/block/cciss.c852
-rw-r--r--drivers/block/cciss.h12
-rw-r--r--drivers/block/cpqarray.c65
-rw-r--r--drivers/block/floppy.c11
-rw-r--r--drivers/block/hd.c2
-rw-r--r--drivers/block/loop.c6
-rw-r--r--drivers/block/mg_disk.c2
-rw-r--r--drivers/block/nbd.c2
-rw-r--r--drivers/block/osdblk.c2
-rw-r--r--drivers/block/paride/pcd.c14
-rw-r--r--drivers/block/paride/pd.c2
-rw-r--r--drivers/block/paride/pf.c2
-rw-r--r--drivers/block/pktcdvd.c10
-rw-r--r--drivers/block/ps3disk.c2
-rw-r--r--drivers/block/ps3vram.c4
-rw-r--r--drivers/block/sunvdc.c2
-rw-r--r--drivers/block/swim.c2
-rw-r--r--drivers/block/swim3.c4
-rw-r--r--drivers/block/sx8.c6
-rw-r--r--drivers/block/ub.c2
-rw-r--r--drivers/block/umem.c3
-rw-r--r--drivers/block/viodasd.c14
-rw-r--r--drivers/block/virtio_blk.c64
-rw-r--r--drivers/block/xd.c2
-rw-r--r--drivers/block/xen-blkfront.c4
-rw-r--r--drivers/block/xsysace.c2
-rw-r--r--drivers/block/z2ram.c3
-rw-r--r--drivers/bluetooth/Kconfig25
-rw-r--r--drivers/bluetooth/Makefile6
-rw-r--r--drivers/bluetooth/bluecard_cs.c16
-rw-r--r--drivers/bluetooth/bt3c_cs.c13
-rw-r--r--drivers/bluetooth/btmrvl_debugfs.c432
-rw-r--r--drivers/bluetooth/btmrvl_drv.h139
-rw-r--r--drivers/bluetooth/btmrvl_main.c624
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c1003
-rw-r--r--drivers/bluetooth/btmrvl_sdio.h108
-rw-r--r--drivers/bluetooth/btuart_cs.c13
-rw-r--r--drivers/bluetooth/btusb.c201
-rw-r--r--drivers/bluetooth/dtl1_cs.c14
-rw-r--r--drivers/bluetooth/hci_bcsp.c3
-rw-r--r--drivers/cdrom/cdrom.c8
-rw-r--r--drivers/cdrom/gdrom.c2
-rw-r--r--drivers/cdrom/viocd.c2
-rw-r--r--drivers/char/Kconfig14
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/agp/Kconfig3
-rw-r--r--drivers/char/agp/agp.h17
-rw-r--r--drivers/char/agp/ali-agp.c4
-rw-r--r--drivers/char/agp/alpha-agp.c2
-rw-r--r--drivers/char/agp/amd-k7-agp.c10
-rw-r--r--drivers/char/agp/amd64-agp.c7
-rw-r--r--drivers/char/agp/ati-agp.c7
-rw-r--r--drivers/char/agp/backend.c36
-rw-r--r--drivers/char/agp/efficeon-agp.c4
-rw-r--r--drivers/char/agp/generic.c20
-rw-r--r--drivers/char/agp/hp-agp.c17
-rw-r--r--drivers/char/agp/i460-agp.c17
-rw-r--r--drivers/char/agp/intel-agp.c226
-rw-r--r--drivers/char/agp/nvidia-agp.c2
-rw-r--r--drivers/char/agp/parisc-agp.c14
-rw-r--r--drivers/char/agp/sgi-agp.c8
-rw-r--r--drivers/char/agp/sworks-agp.c10
-rw-r--r--drivers/char/agp/uninorth-agp.c55
-rw-r--r--drivers/char/apm-emulation.c2
-rw-r--r--drivers/char/applicom.c1
-rw-r--r--drivers/char/bfin-otp.c175
-rw-r--r--drivers/char/cyclades.c2313
-rw-r--r--drivers/char/dtlk.c1
-rw-r--r--drivers/char/epca.c3
-rw-r--r--drivers/char/esp.c7
-rw-r--r--drivers/char/generic_nvram.c27
-rw-r--r--drivers/char/generic_serial.c1
-rw-r--r--drivers/char/genrtc.c1
-rw-r--r--drivers/char/hpet.c21
-rw-r--r--drivers/char/hvc_console.c8
-rw-r--r--drivers/char/hvc_console.h12
-rw-r--r--drivers/char/hvc_iucv.c4
-rw-r--r--drivers/char/hvc_vio.c4
-rw-r--r--drivers/char/hvc_xen.c25
-rw-r--r--drivers/char/hvsi.c3
-rw-r--r--drivers/char/hw_random/Kconfig13
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/core.c2
-rw-r--r--drivers/char/hw_random/octeon-rng.c147
-rw-r--r--drivers/char/hw_random/omap-rng.c4
-rw-r--r--drivers/char/hw_random/virtio-rng.c4
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c1
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c1
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c4
-rw-r--r--drivers/char/isicom.c57
-rw-r--r--drivers/char/istallion.c1
-rw-r--r--drivers/char/keyboard.c2
-rw-r--r--drivers/char/mbcs.c5
-rw-r--r--drivers/char/mem.c95
-rw-r--r--drivers/char/misc.c12
-rw-r--r--drivers/char/mspec.c2
-rw-r--r--drivers/char/mwave/mwavedd.c22
-rw-r--r--drivers/char/mxser.c62
-rw-r--r--drivers/char/n_tty.c79
-rw-r--r--drivers/char/nozomi.c1
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c75
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c52
-rw-r--r--drivers/char/pcmcia/ipwireless/hardware.c8
-rw-r--r--drivers/char/pcmcia/ipwireless/main.c296
-rw-r--r--drivers/char/pcmcia/synclink_cs.c87
-rw-r--r--drivers/char/pty.c54
-rw-r--r--drivers/char/random.c4
-rw-r--r--drivers/char/raw.c6
-rw-r--r--drivers/char/rio/riocmd.c1
-rw-r--r--drivers/char/rio/rioctrl.c3
-rw-r--r--drivers/char/rio/riotty.c1
-rw-r--r--drivers/char/riscom8.c164
-rw-r--r--drivers/char/rtc.c1
-rw-r--r--drivers/char/ser_a2232.c1
-rw-r--r--drivers/char/serial167.c12
-rw-r--r--drivers/char/sonypi.c1
-rw-r--r--drivers/char/stallion.c1
-rw-r--r--drivers/char/synclink.c7
-rw-r--r--drivers/char/synclink_gt.c7
-rw-r--r--drivers/char/synclinkmp.c7
-rw-r--r--drivers/char/sysrq.c4
-rw-r--r--drivers/char/tlclk.c1
-rw-r--r--drivers/char/tpm/tpm.c10
-rw-r--r--drivers/char/tpm/tpm_bios.c4
-rw-r--r--drivers/char/tpm/tpm_tis.c11
-rw-r--r--drivers/char/tty_buffer.c31
-rw-r--r--drivers/char/tty_io.c46
-rw-r--r--drivers/char/tty_ioctl.c4
-rw-r--r--drivers/char/tty_ldisc.c89
-rw-r--r--drivers/char/tty_port.c41
-rw-r--r--drivers/char/uv_mmtimer.c216
-rw-r--r--drivers/char/virtio_console.c4
-rw-r--r--drivers/char/vt.c17
-rw-r--r--drivers/char/vt_ioctl.c484
-rw-r--r--drivers/char/xilinx_hwicap/xilinx_hwicap.c2
-rw-r--r--drivers/connector/cn_proc.c29
-rw-r--r--drivers/connector/cn_queue.c15
-rw-r--r--drivers/connector/connector.c24
-rw-r--r--drivers/cpufreq/cpufreq.c349
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c16
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c158
-rw-r--r--drivers/cpuidle/cpuidle.c7
-rw-r--r--drivers/cpuidle/governors/menu.c271
-rw-r--r--drivers/crypto/padlock-aes.c4
-rw-r--r--drivers/crypto/padlock-sha.c14
-rw-r--r--drivers/dca/dca-core.c124
-rw-r--r--drivers/dma/Kconfig16
-rw-r--r--drivers/dma/Makefile4
-rw-r--r--drivers/dma/at_hdmac.c79
-rw-r--r--drivers/dma/at_hdmac_regs.h1
-rw-r--r--drivers/dma/dmaengine.c104
-rw-r--r--drivers/dma/dmatest.c40
-rw-r--r--drivers/dma/dw_dmac.c65
-rw-r--r--drivers/dma/dw_dmac_regs.h1
-rw-r--r--drivers/dma/fsldma.c288
-rw-r--r--drivers/dma/fsldma.h4
-rw-r--r--drivers/dma/ioat.c202
-rw-r--r--drivers/dma/ioat/Makefile2
-rw-r--r--drivers/dma/ioat/dca.c (renamed from drivers/dma/ioat_dca.c)19
-rw-r--r--drivers/dma/ioat/dma.c1238
-rw-r--r--drivers/dma/ioat/dma.h335
-rw-r--r--drivers/dma/ioat/dma_v2.c873
-rw-r--r--drivers/dma/ioat/dma_v2.h190
-rw-r--r--drivers/dma/ioat/dma_v3.c1253
-rw-r--r--drivers/dma/ioat/hw.h217
-rw-r--r--drivers/dma/ioat/pci.c210
-rw-r--r--drivers/dma/ioat/registers.h (renamed from drivers/dma/ioatdma_registers.h)52
-rw-r--r--drivers/dma/ioat_dma.c1741
-rw-r--r--drivers/dma/ioatdma.h165
-rw-r--r--drivers/dma/ioatdma_hw.h70
-rw-r--r--drivers/dma/iop-adma.c491
-rw-r--r--drivers/dma/iovlock.c10
-rw-r--r--drivers/dma/mv_xor.c7
-rw-r--r--drivers/dma/mv_xor.h4
-rw-r--r--drivers/dma/shdma.c784
-rw-r--r--drivers/dma/shdma.h64
-rw-r--r--drivers/dma/txx9dmac.c39
-rw-r--r--drivers/dma/txx9dmac.h1
-rw-r--r--drivers/edac/Kconfig27
-rw-r--r--drivers/edac/Makefile7
-rw-r--r--drivers/edac/amd64_edac.c607
-rw-r--r--drivers/edac/amd64_edac.h94
-rw-r--r--drivers/edac/amd64_edac_dbg.c2
-rw-r--r--drivers/edac/amd64_edac_err_types.c161
-rw-r--r--drivers/edac/amd64_edac_inj.c49
-rw-r--r--drivers/edac/cpc925_edac.c6
-rw-r--r--drivers/edac/edac_core.h2
-rw-r--r--drivers/edac/edac_device.c5
-rw-r--r--drivers/edac/edac_mc.c4
-rw-r--r--drivers/edac/edac_mce_amd.c455
-rw-r--r--drivers/edac/edac_mce_amd.h69
-rw-r--r--drivers/edac/edac_pci.c4
-rw-r--r--drivers/edac/i3200_edac.c527
-rw-r--r--drivers/edac/i5000_edac.c7
-rw-r--r--drivers/edac/i5400_edac.c89
-rw-r--r--drivers/edac/mpc85xx_edac.c32
-rw-r--r--drivers/edac/mv64x60_edac.c22
-rw-r--r--drivers/firewire/core-card.c13
-rw-r--r--drivers/firewire/core-cdev.c1
-rw-r--r--drivers/firewire/core-device.c2
-rw-r--r--drivers/firewire/core-transaction.c2
-rw-r--r--drivers/firewire/core.h14
-rw-r--r--drivers/firewire/net.c6
-rw-r--r--drivers/firewire/ohci.c45
-rw-r--r--drivers/firewire/sbp2.c55
-rw-r--r--drivers/firmware/dmi-id.c2
-rw-r--r--drivers/firmware/iscsi_ibft.c2
-rw-r--r--drivers/firmware/iscsi_ibft_find.c4
-rw-r--r--drivers/firmware/memmap.c2
-rw-r--r--drivers/gpio/Kconfig42
-rw-r--r--drivers/gpio/Makefile5
-rw-r--r--drivers/gpio/adp5520-gpio.c206
-rw-r--r--drivers/gpio/bt8xxgpio.c7
-rw-r--r--drivers/gpio/gpiolib.c263
-rw-r--r--drivers/gpio/langwell_gpio.c288
-rw-r--r--drivers/gpio/max7301.c1
-rw-r--r--drivers/gpio/mc33880.c196
-rw-r--r--drivers/gpio/mcp23s08.c5
-rw-r--r--drivers/gpio/pca953x.c4
-rw-r--r--drivers/gpio/pcf857x.c4
-rw-r--r--drivers/gpio/twl4030-gpio.c5
-rw-r--r--drivers/gpio/ucb1400_gpio.c125
-rw-r--r--drivers/gpio/wm831x-gpio.c252
-rw-r--r--drivers/gpu/Makefile2
-rw-r--r--drivers/gpu/drm/Kconfig20
-rw-r--r--drivers/gpu/drm/Makefile8
-rw-r--r--drivers/gpu/drm/drm_bufs.c4
-rw-r--r--drivers/gpu/drm/drm_cache.c46
-rw-r--r--drivers/gpu/drm/drm_crtc.c78
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c308
-rw-r--r--drivers/gpu/drm/drm_drv.c4
-rw-r--r--drivers/gpu/drm/drm_edid.c557
-rw-r--r--drivers/gpu/drm/drm_encoder_slave.c116
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c1030
-rw-r--r--drivers/gpu/drm/drm_gem.c26
-rw-r--r--drivers/gpu/drm/drm_irq.c27
-rw-r--r--drivers/gpu/drm/drm_mm.c30
-rw-r--r--drivers/gpu/drm/drm_modes.c434
-rw-r--r--drivers/gpu/drm/drm_proc.c17
-rw-r--r--drivers/gpu/drm/drm_sysfs.c32
-rw-r--r--drivers/gpu/drm/drm_vm.c8
-rw-r--r--drivers/gpu/drm/i915/Makefile3
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c (renamed from drivers/gpu/drm/i915/i915_gem_debugfs.c)101
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c314
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c143
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h191
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c898
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c80
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c133
-rw-r--r--drivers/gpu/drm/i915/i915_opregion.c22
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h208
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c495
-rw-r--r--drivers/gpu/drm/i915/i915_trace.h316
-rw-r--r--drivers/gpu/drm/i915/i915_trace_points.c11
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c19
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c41
-rw-r--r--drivers/gpu/drm/i915/intel_display.c1404
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c4
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h15
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c748
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c28
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c8
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c110
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c825
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c33
-rw-r--r--drivers/gpu/drm/mga/mga_dma.c4
-rw-r--r--drivers/gpu/drm/mga/mga_drv.h1
-rw-r--r--drivers/gpu/drm/mga/mga_state.c4
-rw-r--r--drivers/gpu/drm/mga/mga_ucode.h11645
-rw-r--r--drivers/gpu/drm/mga/mga_warp.c180
-rw-r--r--drivers/gpu/drm/r128/r128_cce.c116
-rw-r--r--drivers/gpu/drm/r128/r128_drv.h8
-rw-r--r--drivers/gpu/drm/r128/r128_state.c36
-rw-r--r--drivers/gpu/drm/radeon/.gitignore3
-rw-r--r--drivers/gpu/drm/radeon/Kconfig1
-rw-r--r--drivers/gpu/drm/radeon/Makefile43
-rw-r--r--drivers/gpu/drm/radeon/atom.c1
-rw-r--r--drivers/gpu/drm/radeon/atombios.h13
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c359
-rw-r--r--drivers/gpu/drm/radeon/avivod.h60
-rw-r--r--drivers/gpu/drm/radeon/mkregtable.c720
-rw-r--r--drivers/gpu/drm/radeon/r100.c1763
-rw-r--r--drivers/gpu/drm/radeon/r100_track.h183
-rw-r--r--drivers/gpu/drm/radeon/r100d.h714
-rw-r--r--drivers/gpu/drm/radeon/r200.c454
-rw-r--r--drivers/gpu/drm/radeon/r300.c981
-rw-r--r--drivers/gpu/drm/radeon/r300d.h306
-rw-r--r--drivers/gpu/drm/radeon/r420.c307
-rw-r--r--drivers/gpu/drm/radeon/r420d.h249
-rw-r--r--drivers/gpu/drm/radeon/r500_reg.h12
-rw-r--r--drivers/gpu/drm/radeon/r520.c283
-rw-r--r--drivers/gpu/drm/radeon/r520d.h187
-rw-r--r--drivers/gpu/drm/radeon/r600.c1853
-rw-r--r--drivers/gpu/drm/radeon/r600_blit.c858
-rw-r--r--drivers/gpu/drm/radeon/r600_blit_kms.c805
-rw-r--r--drivers/gpu/drm/radeon/r600_blit_shaders.c1072
-rw-r--r--drivers/gpu/drm/radeon/r600_blit_shaders.h14
-rw-r--r--drivers/gpu/drm/radeon/r600_cp.c541
-rw-r--r--drivers/gpu/drm/radeon/r600_cs.c801
-rw-r--r--drivers/gpu/drm/radeon/r600_microcode.h23297
-rw-r--r--drivers/gpu/drm/radeon/r600d.h677
-rw-r--r--drivers/gpu/drm/radeon/radeon.h452
-rw-r--r--drivers/gpu/drm/radeon/radeon_agp.c12
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h386
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c394
-rw-r--r--drivers/gpu/drm/radeon/radeon_benchmark.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_bios.c46
-rw-r--r--drivers/gpu/drm/radeon/radeon_clocks.c20
-rw-r--r--drivers/gpu/drm/radeon/radeon_combios.c345
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c710
-rw-r--r--drivers/gpu/drm/radeon/radeon_cp.c151
-rw-r--r--drivers/gpu/drm/radeon/radeon_cs.c104
-rw-r--r--drivers/gpu/drm/radeon/radeon_cursor.c10
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c351
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c168
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c28
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.h216
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c242
-rw-r--r--drivers/gpu/drm/radeon/radeon_family.h97
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c694
-rw-r--r--drivers/gpu/drm/radeon/radeon_fence.c49
-rw-r--r--drivers/gpu/drm/radeon/radeon_gart.c29
-rw-r--r--drivers/gpu/drm/radeon/radeon_ioc32.c15
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq.c18
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c16
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c74
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_crtc.c126
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_encoders.c392
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_tv.c904
-rw-r--r--drivers/gpu/drm/radeon/radeon_microcode.h1844
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h106
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c27
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.h1
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c65
-rw-r--r--drivers/gpu/drm/radeon/radeon_reg.h86
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c143
-rw-r--r--drivers/gpu/drm/radeon/radeon_state.c23
-rw-r--r--drivers/gpu/drm/radeon/radeon_test.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c103
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/r100105
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/r200184
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/r300729
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/rn5030
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/rs600729
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/rv515486
-rw-r--r--drivers/gpu/drm/radeon/rs100d.h (renamed from drivers/gpu/drm/radeon/radeon_share.h)19
-rw-r--r--drivers/gpu/drm/radeon/rs400.c331
-rw-r--r--drivers/gpu/drm/radeon/rs400d.h160
-rw-r--r--drivers/gpu/drm/radeon/rs600.c611
-rw-r--r--drivers/gpu/drm/radeon/rs600d.h470
-rw-r--r--drivers/gpu/drm/radeon/rs690.c360
-rw-r--r--drivers/gpu/drm/radeon/rs690d.h307
-rw-r--r--drivers/gpu/drm/radeon/rs690r.h99
-rw-r--r--drivers/gpu/drm/radeon/rs780.c102
-rw-r--r--drivers/gpu/drm/radeon/rv200d.h (renamed from drivers/gpu/drm/radeon/r300.h)12
-rw-r--r--drivers/gpu/drm/radeon/rv250d.h123
-rw-r--r--drivers/gpu/drm/radeon/rv350d.h52
-rw-r--r--drivers/gpu/drm/radeon/rv515.c884
-rw-r--r--drivers/gpu/drm/radeon/rv515d.h603
-rw-r--r--drivers/gpu/drm/radeon/rv515r.h170
-rw-r--r--drivers/gpu/drm/radeon/rv770.c1059
-rw-r--r--drivers/gpu/drm/radeon/rv770d.h346
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c295
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c4
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_global.c6
-rw-r--r--drivers/gpu/drm/ttm/ttm_memory.c508
-rw-r--r--drivers/gpu/drm/ttm/ttm_module.c58
-rw-r--r--drivers/gpu/drm/ttm/ttm_tt.c105
-rw-r--r--drivers/gpu/vga/Kconfig10
-rw-r--r--drivers/gpu/vga/Makefile1
-rw-r--r--drivers/gpu/vga/vgaarb.c1205
-rw-r--r--drivers/hid/Kconfig36
-rw-r--r--drivers/hid/Makefile6
-rw-r--r--drivers/hid/hid-a4tech.c4
-rw-r--r--drivers/hid/hid-apple.c4
-rw-r--r--drivers/hid/hid-belkin.c4
-rw-r--r--drivers/hid/hid-cherry.c4
-rw-r--r--drivers/hid/hid-chicony.c4
-rw-r--r--drivers/hid/hid-core.c83
-rw-r--r--drivers/hid/hid-cypress.c4
-rw-r--r--drivers/hid/hid-debug.c439
-rw-r--r--drivers/hid/hid-ezkey.c4
-rw-r--r--drivers/hid/hid-gyration.c4
-rw-r--r--drivers/hid/hid-ids.h14
-rw-r--r--drivers/hid/hid-input.c13
-rw-r--r--drivers/hid/hid-kensington.c4
-rw-r--r--drivers/hid/hid-kye.c4
-rw-r--r--drivers/hid/hid-lg.c6
-rw-r--r--drivers/hid/hid-lgff.c6
-rw-r--r--drivers/hid/hid-microsoft.c4
-rw-r--r--drivers/hid/hid-monterey.c4
-rw-r--r--drivers/hid/hid-ntrig.c37
-rw-r--r--drivers/hid/hid-petalynx.c4
-rw-r--r--drivers/hid/hid-pl.c4
-rw-r--r--drivers/hid/hid-samsung.c43
-rw-r--r--drivers/hid/hid-sjoy.c4
-rw-r--r--drivers/hid/hid-sony.c4
-rw-r--r--drivers/hid/hid-sunplus.c4
-rw-r--r--drivers/hid/hid-tmff.c10
-rw-r--r--drivers/hid/hid-topseed.c4
-rw-r--r--drivers/hid/hid-twinhan.c147
-rw-r--r--drivers/hid/hid-wacom.c4
-rw-r--r--drivers/hid/hid-zpff.c4
-rw-r--r--drivers/hid/hidraw.c6
-rw-r--r--drivers/hid/usbhid/hid-core.c28
-rw-r--r--drivers/hid/usbhid/hid-quirks.c2
-rw-r--r--drivers/hid/usbhid/hiddev.c6
-rw-r--r--drivers/hwmon/Kconfig182
-rw-r--r--drivers/hwmon/Makefile12
-rw-r--r--drivers/hwmon/abituguru.c2
-rw-r--r--drivers/hwmon/abituguru3.c79
-rw-r--r--drivers/hwmon/adcxx.c101
-rw-r--r--drivers/hwmon/adm1021.c79
-rw-r--r--drivers/hwmon/adm1031.c40
-rw-r--r--drivers/hwmon/adt7475.c17
-rw-r--r--drivers/hwmon/applesmc.c40
-rw-r--r--drivers/hwmon/asus_atk0110.c339
-rw-r--r--drivers/hwmon/coretemp.c57
-rw-r--r--drivers/hwmon/dme1737.c33
-rw-r--r--drivers/hwmon/f71805f.c2
-rw-r--r--drivers/hwmon/fscher.c680
-rw-r--r--drivers/hwmon/fschmd.c4
-rw-r--r--drivers/hwmon/fscpos.c654
-rw-r--r--drivers/hwmon/hdaps.c3
-rw-r--r--drivers/hwmon/hp_accel.c5
-rw-r--r--drivers/hwmon/hwmon-vid.c10
-rw-r--r--drivers/hwmon/it87.c7
-rw-r--r--drivers/hwmon/lis3lv02d.c9
-rw-r--r--drivers/hwmon/lis3lv02d.h24
-rw-r--r--drivers/hwmon/lis3lv02d_spi.c48
-rw-r--r--drivers/hwmon/lm70.c55
-rw-r--r--drivers/hwmon/lm78.c2
-rw-r--r--drivers/hwmon/lm85.c32
-rw-r--r--drivers/hwmon/ltc4215.c49
-rw-r--r--drivers/hwmon/ltc4245.c134
-rw-r--r--drivers/hwmon/max1111.c1
-rw-r--r--drivers/hwmon/pc87360.c2
-rw-r--r--drivers/hwmon/pc87427.c8
-rw-r--r--drivers/hwmon/s3c-hwmon.c412
-rw-r--r--drivers/hwmon/sht15.c14
-rw-r--r--drivers/hwmon/sis5595.c2
-rw-r--r--drivers/hwmon/smsc47b397.c2
-rw-r--r--drivers/hwmon/smsc47m1.c2
-rw-r--r--drivers/hwmon/tmp421.c347
-rw-r--r--drivers/hwmon/via686a.c2
-rw-r--r--drivers/hwmon/vt1211.c8
-rw-r--r--drivers/hwmon/vt8231.c2
-rw-r--r--drivers/hwmon/w83627ehf.c2
-rw-r--r--drivers/hwmon/w83627hf.c2
-rw-r--r--drivers/hwmon/w83781d.c2
-rw-r--r--drivers/hwmon/wm831x-hwmon.c226
-rw-r--r--drivers/hwmon/wm8350-hwmon.c151
-rw-r--r--drivers/i2c/Kconfig8
-rw-r--r--drivers/i2c/busses/Kconfig23
-rw-r--r--drivers/i2c/busses/Makefile3
-rw-r--r--drivers/i2c/busses/i2c-amd756.c2
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c4
-rw-r--r--drivers/i2c/busses/i2c-i801.c4
-rw-r--r--drivers/i2c/busses/i2c-imx.c89
-rw-r--r--drivers/i2c/busses/i2c-isch.c2
-rw-r--r--drivers/i2c/busses/i2c-mpc.c10
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c4
-rw-r--r--drivers/i2c/busses/i2c-piix4.c17
-rw-r--r--drivers/i2c/busses/i2c-pnx.c16
-rw-r--r--drivers/i2c/busses/i2c-pxa.c25
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c25
-rw-r--r--drivers/i2c/busses/i2c-scmi.c429
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c39
-rw-r--r--drivers/i2c/busses/i2c-sis96x.c2
-rw-r--r--drivers/i2c/busses/i2c-taos-evm.c45
-rw-r--r--drivers/i2c/busses/i2c-viapro.c2
-rw-r--r--drivers/i2c/busses/scx200_acb.c6
-rw-r--r--drivers/i2c/chips/Kconfig48
-rw-r--r--drivers/i2c/chips/Makefile3
-rw-r--r--drivers/i2c/chips/pca9539.c152
-rw-r--r--drivers/i2c/chips/pcf8574.c215
-rw-r--r--drivers/i2c/chips/pcf8575.c198
-rw-r--r--drivers/i2c/chips/tsl2550.c45
-rw-r--r--drivers/i2c/i2c-core.c176
-rw-r--r--drivers/ide/at91_ide.c2
-rw-r--r--drivers/ide/atiixp.c2
-rw-r--r--drivers/ide/cmd64x.c6
-rw-r--r--drivers/ide/ide-acpi.c5
-rw-r--r--drivers/ide/ide-cd.c34
-rw-r--r--drivers/ide/ide-cs.c33
-rw-r--r--drivers/ide/ide-disk_proc.c129
-rw-r--r--drivers/ide/ide-floppy_proc.c30
-rw-r--r--drivers/ide/ide-gd.c2
-rw-r--r--drivers/ide/ide-ioctls.c10
-rw-r--r--drivers/ide/ide-iops.c17
-rw-r--r--drivers/ide/ide-probe.c42
-rw-r--r--drivers/ide/ide-proc.c348
-rw-r--r--drivers/ide/ide-tape.c162
-rw-r--r--drivers/ide/ide-taskfile.c126
-rw-r--r--drivers/ide/palm_bk3710.c2
-rw-r--r--drivers/ide/sis5513.c10
-rw-r--r--drivers/ide/umc8672.c4
-rw-r--r--drivers/idle/i7300_idle.c20
-rw-r--r--drivers/ieee1394/dma.c2
-rw-r--r--drivers/ieee1394/eth1394.c19
-rw-r--r--drivers/ieee1394/raw1394.c5
-rw-r--r--drivers/ieee1394/sbp2.c3
-rw-r--r--drivers/ieee1394/video1394.c1
-rw-r--r--drivers/ieee802154/fakehard.c196
-rw-r--r--drivers/infiniband/core/addr.c2
-rw-r--r--drivers/infiniband/core/iwcm.c3
-rw-r--r--drivers/infiniband/core/mad_rmpp.c17
-rw-r--r--drivers/infiniband/core/ucm.c1
-rw-r--r--drivers/infiniband/core/ucma.c1
-rw-r--r--drivers/infiniband/core/user_mad.c1
-rw-r--r--drivers/infiniband/core/uverbs_main.c1
-rw-r--r--drivers/infiniband/hw/amso1100/c2.c1
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c12
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c1
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_uverbs.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6110.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba7220.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mmap.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_qp.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ruc.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_sysfs.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ud.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_user_pages.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_user_sdma.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs_mcast.c1
-rw-r--r--drivers/infiniband/hw/mthca/mthca_catas.c11
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.c2
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c3
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c1
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c1
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c7
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c2
-rw-r--r--drivers/input/evdev.c1
-rw-r--r--drivers/input/ff-core.c20
-rw-r--r--drivers/input/ff-memless.c26
-rw-r--r--drivers/input/input.c143
-rw-r--r--drivers/input/joydev.c107
-rw-r--r--drivers/input/joystick/xpad.c4
-rw-r--r--drivers/input/keyboard/Kconfig66
-rw-r--r--drivers/input/keyboard/Makefile6
-rw-r--r--drivers/input/keyboard/adp5588-keys.c361
-rw-r--r--drivers/input/keyboard/atkbd.c181
-rw-r--r--drivers/input/keyboard/bf54x-keys.c26
-rw-r--r--drivers/input/keyboard/gpio_keys.c20
-rw-r--r--drivers/input/keyboard/hil_kbd.c607
-rw-r--r--drivers/input/keyboard/hilkbd.c1
-rw-r--r--drivers/input/keyboard/lkkbd.c62
-rw-r--r--drivers/input/keyboard/matrix_keypad.c15
-rw-r--r--drivers/input/keyboard/max7359_keypad.c330
-rw-r--r--drivers/input/keyboard/omap-keypad.c22
-rw-r--r--drivers/input/keyboard/opencores-kbd.c180
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c219
-rw-r--r--drivers/input/keyboard/qt2160.c397
-rw-r--r--drivers/input/keyboard/sh_keysc.c25
-rw-r--r--drivers/input/keyboard/sunkbd.c143
-rw-r--r--drivers/input/keyboard/tosakbd.c18
-rw-r--r--drivers/input/keyboard/twl4030_keypad.c480
-rw-r--r--drivers/input/keyboard/w90p910_keypad.c281
-rw-r--r--drivers/input/misc/Kconfig48
-rw-r--r--drivers/input/misc/Makefile5
-rw-r--r--drivers/input/misc/bfin_rotary.c283
-rw-r--r--drivers/input/misc/cobalt_btns.c2
-rw-r--r--drivers/input/misc/dm355evm_keys.c34
-rw-r--r--drivers/input/misc/hp_sdc_rtc.c2
-rw-r--r--drivers/input/misc/pcap_keys.c144
-rw-r--r--drivers/input/misc/rotary_encoder.c4
-rw-r--r--drivers/input/misc/sparcspkr.c4
-rw-r--r--drivers/input/misc/uinput.c1
-rw-r--r--drivers/input/misc/winbond-cir.c1614
-rw-r--r--drivers/input/misc/wistron_btns.c93
-rw-r--r--drivers/input/misc/wm831x-on.c163
-rw-r--r--drivers/input/mouse/Kconfig16
-rw-r--r--drivers/input/mouse/Makefile2
-rw-r--r--drivers/input/mouse/alps.c20
-rw-r--r--drivers/input/mouse/alps.h4
-rw-r--r--drivers/input/mouse/bcm5974.c31
-rw-r--r--drivers/input/mouse/elantech.c2
-rw-r--r--drivers/input/mouse/elantech.h4
-rw-r--r--drivers/input/mouse/hgpk.c61
-rw-r--r--drivers/input/mouse/hgpk.h6
-rw-r--r--drivers/input/mouse/hil_ptr.c447
-rw-r--r--drivers/input/mouse/lifebook.c11
-rw-r--r--drivers/input/mouse/lifebook.h4
-rw-r--r--drivers/input/mouse/logips2pp.c43
-rw-r--r--drivers/input/mouse/logips2pp.h4
-rw-r--r--drivers/input/mouse/psmouse-base.c115
-rw-r--r--drivers/input/mouse/psmouse.h30
-rw-r--r--drivers/input/mouse/sentelic.c869
-rw-r--r--drivers/input/mouse/sentelic.h98
-rw-r--r--drivers/input/mouse/synaptics.c44
-rw-r--r--drivers/input/mouse/synaptics.h2
-rw-r--r--drivers/input/mouse/synaptics_i2c.c51
-rw-r--r--drivers/input/mouse/touchkit_ps2.c4
-rw-r--r--drivers/input/mouse/touchkit_ps2.h4
-rw-r--r--drivers/input/mouse/trackpoint.c2
-rw-r--r--drivers/input/mouse/trackpoint.h4
-rw-r--r--drivers/input/mouse/vsxxxaa.c8
-rw-r--r--drivers/input/mousedev.c1
-rw-r--r--drivers/input/serio/Kconfig13
-rw-r--r--drivers/input/serio/at32psif.c2
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h103
-rw-r--r--drivers/input/serio/i8042.c319
-rw-r--r--drivers/input/serio/libps2.c42
-rw-r--r--drivers/input/serio/serio.c23
-rw-r--r--drivers/input/serio/serio_raw.c1
-rw-r--r--drivers/input/serio/serport.c1
-rw-r--r--drivers/input/touchscreen/Kconfig42
-rw-r--r--drivers/input/touchscreen/Makefile2
-rw-r--r--drivers/input/touchscreen/ad7877.c1
-rw-r--r--drivers/input/touchscreen/ad7879.c11
-rw-r--r--drivers/input/touchscreen/ads7846.c1
-rw-r--r--drivers/input/touchscreen/atmel_tsadcc.c8
-rw-r--r--drivers/input/touchscreen/eeti_ts.c22
-rw-r--r--drivers/input/touchscreen/h3600_ts_input.c9
-rw-r--r--drivers/input/touchscreen/mainstone-wm97xx.c53
-rw-r--r--drivers/input/touchscreen/mcs5000_ts.c318
-rw-r--r--drivers/input/touchscreen/pcap_ts.c271
-rw-r--r--drivers/input/touchscreen/tsc2007.c264
-rw-r--r--drivers/input/touchscreen/ucb1400_ts.c5
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c81
-rw-r--r--drivers/input/touchscreen/w90p910_ts.c38
-rw-r--r--drivers/input/touchscreen/wacom_w8001.c121
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c9
-rw-r--r--drivers/isdn/Kconfig6
-rw-r--r--drivers/isdn/act2000/capi.c3
-rw-r--r--drivers/isdn/act2000/module.c31
-rw-r--r--drivers/isdn/capi/capi.c2
-rw-r--r--drivers/isdn/capi/capidrv.c27
-rw-r--r--drivers/isdn/capi/capifs.c2
-rw-r--r--drivers/isdn/capi/capiutil.c2
-rw-r--r--drivers/isdn/capi/kcapi.c1
-rw-r--r--drivers/isdn/capi/kcapi_proc.c10
-rw-r--r--drivers/isdn/divert/divert_procfs.c1
-rw-r--r--drivers/isdn/gigaset/asyncdata.c28
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c87
-rw-r--r--drivers/isdn/gigaset/common.c134
-rw-r--r--drivers/isdn/gigaset/ev-layer.c30
-rw-r--r--drivers/isdn/gigaset/i4l.c23
-rw-r--r--drivers/isdn/gigaset/interface.c28
-rw-r--r--drivers/isdn/gigaset/isocdata.c30
-rw-r--r--drivers/isdn/hardware/avm/avm_cs.c4
-rw-r--r--drivers/isdn/hardware/eicon/maintidi.c5
-rw-r--r--drivers/isdn/hardware/eicon/message.c22
-rw-r--r--drivers/isdn/hardware/eicon/os_4bri.c3
-rw-r--r--drivers/isdn/hardware/mISDN/Kconfig52
-rw-r--r--drivers/isdn/hardware/mISDN/Makefile8
-rw-r--r--drivers/isdn/hardware/mISDN/avmfritz.c1152
-rw-r--r--drivers/isdn/hardware/mISDN/hfcmulti.c25
-rw-r--r--drivers/isdn/hardware/mISDN/hfcpci.c16
-rw-r--r--drivers/isdn/hardware/mISDN/hfcsusb.c16
-rw-r--r--drivers/isdn/hardware/mISDN/iohelper.h109
-rw-r--r--drivers/isdn/hardware/mISDN/ipac.h405
-rw-r--r--drivers/isdn/hardware/mISDN/isar.h269
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNinfineon.c1178
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNipac.c1655
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNisar.c1726
-rw-r--r--drivers/isdn/hardware/mISDN/netjet.c1156
-rw-r--r--drivers/isdn/hardware/mISDN/netjet.h58
-rw-r--r--drivers/isdn/hardware/mISDN/speedfax.c526
-rw-r--r--drivers/isdn/hardware/mISDN/w6692.c1440
-rw-r--r--drivers/isdn/hardware/mISDN/w6692.h190
-rw-r--r--drivers/isdn/hisax/Kconfig6
-rw-r--r--drivers/isdn/hisax/Makefile4
-rw-r--r--drivers/isdn/hisax/amd7930_fn.c3
-rw-r--r--drivers/isdn/hisax/arcofi.c1
-rw-r--r--drivers/isdn/hisax/avma1_cs.c28
-rw-r--r--drivers/isdn/hisax/callc.c4
-rw-r--r--drivers/isdn/hisax/diva.c2
-rw-r--r--drivers/isdn/hisax/elsa_cs.c46
-rw-r--r--drivers/isdn/hisax/elsa_ser.c22
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c1
-rw-r--r--drivers/isdn/hisax/hfc_pci.c3
-rw-r--r--drivers/isdn/hisax/hfc_sx.c2
-rw-r--r--drivers/isdn/hisax/hfc_usb.c4
-rw-r--r--drivers/isdn/hisax/hscx_irq.c2
-rw-r--r--drivers/isdn/hisax/icc.c3
-rw-r--r--drivers/isdn/hisax/isac.c2
-rw-r--r--drivers/isdn/hisax/isdnhdlc.h70
-rw-r--r--drivers/isdn/hisax/isdnl1.c12
-rw-r--r--drivers/isdn/hisax/isdnl2.c4
-rw-r--r--drivers/isdn/hisax/isdnl3.c4
-rw-r--r--drivers/isdn/hisax/l3_1tr6.c20
-rw-r--r--drivers/isdn/hisax/l3dss1.c26
-rw-r--r--drivers/isdn/hisax/l3ni1.c26
-rw-r--r--drivers/isdn/hisax/q931.c24
-rw-r--r--drivers/isdn/hisax/sedlbauer_cs.c64
-rw-r--r--drivers/isdn/hisax/st5481.h2
-rw-r--r--drivers/isdn/hisax/st5481_b.c5
-rw-r--r--drivers/isdn/hisax/st5481_d.c2
-rw-r--r--drivers/isdn/hisax/st5481_usb.c11
-rw-r--r--drivers/isdn/hisax/tei.c4
-rw-r--r--drivers/isdn/hisax/teles_cs.c38
-rw-r--r--drivers/isdn/hisax/w6692.c2
-rw-r--r--drivers/isdn/hysdn/hysdn_net.c4
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c1
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c1
-rw-r--r--drivers/isdn/i4l/Kconfig10
-rw-r--r--drivers/isdn/i4l/Makefile1
-rw-r--r--drivers/isdn/i4l/isdn_common.c4
-rw-r--r--drivers/isdn/i4l/isdn_net.c21
-rw-r--r--drivers/isdn/i4l/isdn_net.h6
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c358
-rw-r--r--drivers/isdn/i4l/isdnhdlc.c (renamed from drivers/isdn/hisax/isdnhdlc.c)429
-rw-r--r--drivers/isdn/mISDN/hwchannel.c15
-rw-r--r--drivers/isdn/mISDN/layer2.c2
-rw-r--r--drivers/isdn/mISDN/socket.c2
-rw-r--r--drivers/isdn/mISDN/stack.c2
-rw-r--r--drivers/isdn/pcbit/drv.c1
-rw-r--r--drivers/isdn/pcbit/layer2.c1
-rw-r--r--drivers/isdn/sc/init.c1
-rw-r--r--drivers/leds/Kconfig13
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-clevo-mail.c10
-rw-r--r--drivers/leds/leds-cobalt-qube.c2
-rw-r--r--drivers/leds/leds-cobalt-raq.c4
-rw-r--r--drivers/leds/leds-dac124s085.c1
-rw-r--r--drivers/leds/leds-gpio.c4
-rw-r--r--drivers/leds/leds-pca9532.c15
-rw-r--r--drivers/leds/leds-wm831x-status.c341
-rw-r--r--drivers/leds/ledtrig-gpio.c32
-rw-r--r--drivers/lguest/core.c5
-rw-r--r--drivers/lguest/interrupts_and_traps.c1
-rw-r--r--drivers/lguest/lguest_user.c2
-rw-r--r--drivers/lguest/page_tables.c47
-rw-r--r--drivers/macintosh/macio_asic.c6
-rw-r--r--drivers/macintosh/rack-meter.c2
-rw-r--r--drivers/macintosh/therm_adt746x.c4
-rw-r--r--drivers/macintosh/therm_pm72.c4
-rw-r--r--drivers/macintosh/therm_windtunnel.c4
-rw-r--r--drivers/macintosh/via-pmu-led.c2
-rw-r--r--drivers/macintosh/via-pmu.c40
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c4
-rw-r--r--drivers/macintosh/windfarm_max6690_sensor.c4
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c4
-rw-r--r--drivers/md/Kconfig26
-rw-r--r--drivers/md/Makefile22
-rw-r--r--drivers/md/bitmap.c14
-rw-r--r--drivers/md/dm-exception-store.c38
-rw-r--r--drivers/md/dm-exception-store.h8
-rw-r--r--drivers/md/dm-ioctl.c2
-rw-r--r--drivers/md/dm-log-userspace-base.c2
-rw-r--r--drivers/md/dm-log-userspace-transfer.c6
-rw-r--r--drivers/md/dm-mpath.c42
-rw-r--r--drivers/md/dm-raid1.c2
-rw-r--r--drivers/md/dm-snap-persistent.c16
-rw-r--r--drivers/md/dm-snap.c25
-rw-r--r--drivers/md/dm-stripe.c4
-rw-r--r--drivers/md/dm.c43
-rw-r--r--drivers/md/linear.c5
-rw-r--r--drivers/md/md.c77
-rw-r--r--drivers/md/md.h3
-rw-r--r--drivers/md/multipath.c11
-rw-r--r--drivers/md/raid0.c10
-rw-r--r--drivers/md/raid1.c42
-rw-r--r--drivers/md/raid10.c23
-rw-r--r--drivers/md/raid5.c1668
-rw-r--r--drivers/md/raid5.h42
-rw-r--r--drivers/md/raid6altivec.uc2
-rw-r--r--drivers/md/raid6int.uc2
-rw-r--r--drivers/md/raid6test/Makefile42
-rw-r--r--drivers/md/unroll.awk20
-rw-r--r--drivers/md/unroll.pl24
-rw-r--r--drivers/media/common/ir-functions.c15
-rw-r--r--drivers/media/common/ir-keymaps.c5022
-rw-r--r--drivers/media/common/tuners/tda18271-common.c3
-rw-r--r--drivers/media/common/tuners/tda18271-fe.c111
-rw-r--r--drivers/media/common/tuners/tda18271-maps.c3
-rw-r--r--drivers/media/common/tuners/tda18271-priv.h21
-rw-r--r--drivers/media/common/tuners/tda18271.h17
-rw-r--r--drivers/media/common/tuners/tuner-simple.c6
-rw-r--r--drivers/media/common/tuners/tuner-types.c52
-rw-r--r--drivers/media/dvb/Kconfig17
-rw-r--r--drivers/media/dvb/Makefile2
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c218
-rw-r--r--drivers/media/dvb/bt8xx/dst.c2
-rw-r--r--drivers/media/dvb/dm1105/dm1105.c150
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c234
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.h9
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c9
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c254
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h17
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c3
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c4
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.h6
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig15
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile3
-rw-r--r--drivers/media/dvb/dvb-usb/a800.c70
-rw-r--r--drivers/media/dvb/dvb-usb/af9005-remote.c76
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.c70
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.h460
-rw-r--r--drivers/media/dvb/dvb-usb/anysee.c106
-rw-r--r--drivers/media/dvb/dvb-usb/ce6230.c4
-rw-r--r--drivers/media/dvb/dvb-usb/cinergyT2-core.c74
-rw-r--r--drivers/media/dvb/dvb-usb/cinergyT2-fe.c1
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c270
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c893
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-common.c244
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mc.c10
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c114
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u.c36
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-i2c.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h17
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c73
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h17
-rw-r--r--drivers/media/dvb/dvb-usb/dw2102.c403
-rw-r--r--drivers/media/dvb/dvb-usb/friio-fe.c483
-rw-r--r--drivers/media/dvb/dvb-usb/friio.c525
-rw-r--r--drivers/media/dvb/dvb-usb/friio.h99
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.c70
-rw-r--r--drivers/media/dvb/dvb-usb/nova-t-usb2.c97
-rw-r--r--drivers/media/dvb/dvb-usb/opera1.c55
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x.c6
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.c102
-rw-r--r--drivers/media/dvb/firewire/firedtv-avc.c181
-rw-r--r--drivers/media/dvb/firewire/firedtv-ci.c2
-rw-r--r--drivers/media/dvb/firewire/firedtv-fe.c8
-rw-r--r--drivers/media/dvb/frontends/Kconfig15
-rw-r--r--drivers/media/dvb/frontends/Makefile2
-rw-r--r--drivers/media/dvb/frontends/au8522_decoder.c5
-rw-r--r--drivers/media/dvb/frontends/cx22700.c2
-rw-r--r--drivers/media/dvb/frontends/cx24113.c6
-rw-r--r--drivers/media/dvb/frontends/cx24123.c2
-rw-r--r--drivers/media/dvb/frontends/dib0070.c803
-rw-r--r--drivers/media/dvb/frontends/dib0070.h35
-rw-r--r--drivers/media/dvb/frontends/dib7000p.c40
-rw-r--r--drivers/media/dvb/frontends/dib8000.c2277
-rw-r--r--drivers/media/dvb/frontends/dib8000.h79
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.c95
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.h31
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c75
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h4
-rw-r--r--drivers/media/dvb/frontends/lgdt3304.c2
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx.c484
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx.h11
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx_priv.h12
-rw-r--r--drivers/media/dvb/frontends/mt312.c7
-rw-r--r--drivers/media/dvb/frontends/s921_module.c2
-rw-r--r--drivers/media/dvb/frontends/stb6100.c4
-rw-r--r--drivers/media/dvb/frontends/stv0900_core.c8
-rw-r--r--drivers/media/dvb/frontends/stv0900_sw.c2
-rw-r--r--drivers/media/dvb/frontends/stv6110.c48
-rw-r--r--drivers/media/dvb/frontends/stv6110.h2
-rw-r--r--drivers/media/dvb/frontends/tda10021.c2
-rw-r--r--drivers/media/dvb/frontends/tda8261.c4
-rw-r--r--drivers/media/dvb/frontends/ves1820.c2
-rw-r--r--drivers/media/dvb/frontends/zl10036.c2
-rw-r--r--drivers/media/dvb/frontends/zl10039.c308
-rw-r--r--drivers/media/dvb/frontends/zl10039.h40
-rw-r--r--drivers/media/dvb/frontends/zl10353.c14
-rw-r--r--drivers/media/dvb/pluto2/pluto2.c2
-rw-r--r--drivers/media/dvb/pt1/Kconfig12
-rw-r--r--drivers/media/dvb/pt1/Makefile5
-rw-r--r--drivers/media/dvb/pt1/pt1.c1058
-rw-r--r--drivers/media/dvb/pt1/va1j5jf8007s.c658
-rw-r--r--drivers/media/dvb/pt1/va1j5jf8007s.h (renamed from drivers/staging/meilhaus/me0600_ttli_reg.h)35
-rw-r--r--drivers/media/dvb/pt1/va1j5jf8007t.c468
-rw-r--r--drivers/media/dvb/pt1/va1j5jf8007t.h (renamed from drivers/staging/meilhaus/metempl_sub_reg.h)35
-rw-r--r--drivers/media/dvb/siano/Kconfig2
-rw-r--r--drivers/media/dvb/siano/smscoreapi.c2
-rw-r--r--drivers/media/dvb/siano/smscoreapi.h4
-rw-r--r--drivers/media/dvb/siano/smsusb.c6
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c2
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c6
-rw-r--r--drivers/media/radio/Kconfig59
-rw-r--r--drivers/media/radio/Makefile4
-rw-r--r--drivers/media/radio/radio-cadet.c7
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c2
-rw-r--r--drivers/media/radio/radio-mr800.c2
-rw-r--r--drivers/media/radio/radio-si470x.c1863
-rw-r--r--drivers/media/radio/radio-si4713.c366
-rw-r--r--drivers/media/radio/si470x/Kconfig37
-rw-r--r--drivers/media/radio/si470x/Makefile9
-rw-r--r--drivers/media/radio/si470x/radio-si470x-common.c798
-rw-r--r--drivers/media/radio/si470x/radio-si470x-i2c.c401
-rw-r--r--drivers/media/radio/si470x/radio-si470x-usb.c988
-rw-r--r--drivers/media/radio/si470x/radio-si470x.h225
-rw-r--r--drivers/media/radio/si4713-i2c.c2060
-rw-r--r--drivers/media/radio/si4713-i2c.h237
-rw-r--r--drivers/media/video/Kconfig99
-rw-r--r--drivers/media/video/Makefile6
-rw-r--r--drivers/media/video/adv7180.c202
-rw-r--r--drivers/media/video/adv7343.c1
-rw-r--r--drivers/media/video/au0828/au0828-cards.c4
-rw-r--r--drivers/media/video/au0828/au0828-dvb.c2
-rw-r--r--drivers/media/video/au0828/au0828-i2c.c1
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c45
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c47
-rw-r--r--drivers/media/video/bt8xx/bttv-i2c.c2
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c27
-rw-r--r--drivers/media/video/cafe_ccic.c5
-rw-r--r--drivers/media/video/cpia.c1
-rw-r--r--drivers/media/video/cx18/cx18-cards.c8
-rw-r--r--drivers/media/video/cx18/cx18-cards.h18
-rw-r--r--drivers/media/video/cx18/cx18-driver.c43
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c2
-rw-r--r--drivers/media/video/cx18/cx18-i2c.c73
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c2
-rw-r--r--drivers/media/video/cx18/cx18-streams.c4
-rw-r--r--drivers/media/video/cx231xx/cx231xx-cards.c4
-rw-r--r--drivers/media/video/cx231xx/cx231xx-conf-reg.h8
-rw-r--r--drivers/media/video/cx231xx/cx231xx-i2c.c1
-rw-r--r--drivers/media/video/cx231xx/cx231xx-video.c4
-rw-r--r--drivers/media/video/cx231xx/cx231xx.h2
-rw-r--r--drivers/media/video/cx23885/cimax2.c13
-rw-r--r--drivers/media/video/cx23885/cx23885-417.c57
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c91
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c31
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c59
-rw-r--r--drivers/media/video/cx23885/cx23885-i2c.c1
-rw-r--r--drivers/media/video/cx23885/cx23885-video.c6
-rw-r--r--drivers/media/video/cx23885/cx23885.h16
-rw-r--r--drivers/media/video/cx23885/netup-eeprom.c6
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c15
-rw-r--r--drivers/media/video/cx25840/cx25840-firmware.c48
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c4
-rw-r--r--drivers/media/video/cx88/cx88-cards.c70
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c20
-rw-r--r--drivers/media/video/cx88/cx88-input.c78
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c4
-rw-r--r--drivers/media/video/cx88/cx88-video.c10
-rw-r--r--drivers/media/video/cx88/cx88.h1
-rw-r--r--drivers/media/video/dabusb.c4
-rw-r--r--drivers/media/video/davinci/Makefile17
-rw-r--r--drivers/media/video/davinci/ccdc_hw_device.h110
-rw-r--r--drivers/media/video/davinci/dm355_ccdc.c978
-rw-r--r--drivers/media/video/davinci/dm355_ccdc_regs.h310
-rw-r--r--drivers/media/video/davinci/dm644x_ccdc.c878
-rw-r--r--drivers/media/video/davinci/dm644x_ccdc_regs.h145
-rw-r--r--drivers/media/video/davinci/vpfe_capture.c2124
-rw-r--r--drivers/media/video/davinci/vpif.c296
-rw-r--r--drivers/media/video/davinci/vpif.h642
-rw-r--r--drivers/media/video/davinci/vpif_capture.c2168
-rw-r--r--drivers/media/video/davinci/vpif_capture.h165
-rw-r--r--drivers/media/video/davinci/vpif_display.c1655
-rw-r--r--drivers/media/video/davinci/vpif_display.h175
-rw-r--r--drivers/media/video/davinci/vpss.c301
-rw-r--r--drivers/media/video/em28xx/Kconfig1
-rw-r--r--drivers/media/video/em28xx/Makefile2
-rw-r--r--drivers/media/video/em28xx/em28xx-audio.c5
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c174
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c51
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c19
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c1
-rw-r--r--drivers/media/video/em28xx/em28xx-reg.h16
-rw-r--r--drivers/media/video/em28xx/em28xx-vbi.c142
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c750
-rw-r--r--drivers/media/video/em28xx/em28xx.h34
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c8
-rw-r--r--drivers/media/video/gspca/Kconfig22
-rw-r--r--drivers/media/video/gspca/Makefile3
-rw-r--r--drivers/media/video/gspca/conex.c2
-rw-r--r--drivers/media/video/gspca/etoms.c4
-rw-r--r--drivers/media/video/gspca/gl860/Kconfig8
-rw-r--r--drivers/media/video/gspca/gl860/Makefile10
-rw-r--r--drivers/media/video/gspca/gl860/gl860-mi1320.c537
-rw-r--r--drivers/media/video/gspca/gl860/gl860-mi2020.c937
-rw-r--r--drivers/media/video/gspca/gl860/gl860-ov2640.c505
-rw-r--r--drivers/media/video/gspca/gl860/gl860-ov9655.c337
-rw-r--r--drivers/media/video/gspca/gl860/gl860.c785
-rw-r--r--drivers/media/video/gspca/gl860/gl860.h108
-rw-r--r--drivers/media/video/gspca/gspca.c68
-rw-r--r--drivers/media/video/gspca/gspca.h5
-rw-r--r--drivers/media/video/gspca/jeilinj.c390
-rw-r--r--drivers/media/video/gspca/m5602/m5602_core.c2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov7660.c262
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov7660.h138
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k4aa.c33
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.c4
-rw-r--r--drivers/media/video/gspca/mr97310a.c853
-rw-r--r--drivers/media/video/gspca/ov519.c2
-rw-r--r--drivers/media/video/gspca/pac207.c37
-rw-r--r--drivers/media/video/gspca/pac7311.c2
-rw-r--r--drivers/media/video/gspca/sn9c20x.c235
-rw-r--r--drivers/media/video/gspca/sonixj.c40
-rw-r--r--drivers/media/video/gspca/spca501.c2
-rw-r--r--drivers/media/video/gspca/spca506.c2
-rw-r--r--drivers/media/video/gspca/spca508.c59
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.c26
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c151
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h2
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_st6422.c15
-rw-r--r--drivers/media/video/gspca/sunplus.c386
-rw-r--r--drivers/media/video/gspca/t613.c210
-rw-r--r--drivers/media/video/gspca/tv8532.c2
-rw-r--r--drivers/media/video/gspca/vc032x.c1127
-rw-r--r--drivers/media/video/gspca/zc3xx.c2
-rw-r--r--drivers/media/video/hdpvr/hdpvr-control.c24
-rw-r--r--drivers/media/video/hdpvr/hdpvr-core.c12
-rw-r--r--drivers/media/video/hdpvr/hdpvr-i2c.c1
-rw-r--r--drivers/media/video/hdpvr/hdpvr-video.c6
-rw-r--r--drivers/media/video/ir-kbd-i2c.c64
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.c70
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.h3
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c5
-rw-r--r--drivers/media/video/ivtv/ivtv-gpio.c13
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c20
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c4
-rw-r--r--drivers/media/video/meye.c6
-rw-r--r--drivers/media/video/mt9m001.c435
-rw-r--r--drivers/media/video/mt9m111.c524
-rw-r--r--drivers/media/video/mt9t031.c491
-rw-r--r--drivers/media/video/mt9v022.c434
-rw-r--r--drivers/media/video/mx1_camera.c79
-rw-r--r--drivers/media/video/mx3_camera.c208
-rw-r--r--drivers/media/video/mxb.c14
-rw-r--r--drivers/media/video/ov772x.c381
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-audio.c5
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c10
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c1
-rw-r--r--drivers/media/video/pwc/pwc-if.c78
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c2
-rw-r--r--drivers/media/video/pwc/pwc.h7
-rw-r--r--drivers/media/video/pxa_camera.c361
-rw-r--r--drivers/media/video/s2255drv.c5
-rw-r--r--drivers/media/video/saa6588.c60
-rw-r--r--drivers/media/video/saa7134/Kconfig1
-rw-r--r--drivers/media/video/saa7134/saa6752hs.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c242
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c267
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c10
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c47
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c124
-rw-r--r--drivers/media/video/saa7134/saa7134-ts.c6
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c5
-rw-r--r--drivers/media/video/saa7134/saa7134.h11
-rw-r--r--drivers/media/video/saa7164/Kconfig18
-rw-r--r--drivers/media/video/saa7164/Makefile12
-rw-r--r--drivers/media/video/saa7164/saa7164-api.c600
-rw-r--r--drivers/media/video/saa7164/saa7164-buffer.c155
-rw-r--r--drivers/media/video/saa7164/saa7164-bus.c448
-rw-r--r--drivers/media/video/saa7164/saa7164-cards.c624
-rw-r--r--drivers/media/video/saa7164/saa7164-cmd.c572
-rw-r--r--drivers/media/video/saa7164/saa7164-core.c740
-rw-r--r--drivers/media/video/saa7164/saa7164-dvb.c602
-rw-r--r--drivers/media/video/saa7164/saa7164-fw.c613
-rw-r--r--drivers/media/video/saa7164/saa7164-i2c.c141
-rw-r--r--drivers/media/video/saa7164/saa7164-reg.h166
-rw-r--r--drivers/media/video/saa7164/saa7164-types.h287
-rw-r--r--drivers/media/video/saa7164/saa7164.h400
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c1100
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c8
-rw-r--r--drivers/media/video/sn9c102/sn9c102_devtable.h2
-rw-r--r--drivers/media/video/soc_camera.c750
-rw-r--r--drivers/media/video/soc_camera_platform.c163
-rw-r--r--drivers/media/video/stk-webcam.c3
-rw-r--r--drivers/media/video/stv680.c9
-rw-r--r--drivers/media/video/tuner-core.c16
-rw-r--r--drivers/media/video/tveeprom.c4
-rw-r--r--drivers/media/video/tvp514x.c1030
-rw-r--r--drivers/media/video/tvp514x_regs.h10
-rw-r--r--drivers/media/video/tw9910.c361
-rw-r--r--drivers/media/video/usbvision/usbvision-core.c1
-rw-r--r--drivers/media/video/usbvision/usbvision-i2c.c13
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c1
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c257
-rw-r--r--drivers/media/video/uvc/uvc_driver.c570
-rw-r--r--drivers/media/video/uvc/uvc_isight.c7
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c279
-rw-r--r--drivers/media/video/uvc/uvc_video.c436
-rw-r--r--drivers/media/video/uvc/uvcvideo.h278
-rw-r--r--drivers/media/video/v4l1-compat.c19
-rw-r--r--drivers/media/video/v4l2-common.c185
-rw-r--r--drivers/media/video/v4l2-compat-ioctl32.c67
-rw-r--r--drivers/media/video/v4l2-dev.c154
-rw-r--r--drivers/media/video/v4l2-ioctl.c33
-rw-r--r--drivers/media/video/videobuf-core.c1
-rw-r--r--drivers/media/video/videobuf-dma-contig.c3
-rw-r--r--drivers/media/video/videobuf-dma-sg.c3
-rw-r--r--drivers/media/video/videobuf-vmalloc.c2
-rw-r--r--drivers/media/video/vino.c11
-rw-r--r--drivers/media/video/w9968cf.c5
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c8
-rw-r--r--drivers/media/video/zoran/zoran_card.c11
-rw-r--r--drivers/media/video/zoran/zoran_driver.c2
-rw-r--r--drivers/media/video/zr364xx.c1226
-rw-r--r--drivers/memstick/core/memstick.c2
-rw-r--r--drivers/memstick/core/mspro_block.c2
-rw-r--r--drivers/message/fusion/mptbase.c98
-rw-r--r--drivers/message/fusion/mptbase.h21
-rw-r--r--drivers/message/fusion/mptfc.c19
-rw-r--r--drivers/message/fusion/mptlan.c3
-rw-r--r--drivers/message/fusion/mptsas.c62
-rw-r--r--drivers/message/fusion/mptscsih.c67
-rw-r--r--drivers/message/fusion/mptscsih.h1
-rw-r--r--drivers/message/fusion/mptspi.c21
-rw-r--r--drivers/message/i2o/i2o_block.c2
-rw-r--r--drivers/mfd/Kconfig42
-rw-r--r--drivers/mfd/Makefile6
-rw-r--r--drivers/mfd/ab3100-core.c68
-rw-r--r--drivers/mfd/ab3100-otp.c268
-rw-r--r--drivers/mfd/dm355evm_msp.c12
-rw-r--r--drivers/mfd/ezx-pcap.c106
-rw-r--r--drivers/mfd/mc13783-core.c427
-rw-r--r--drivers/mfd/mfd-core.c2
-rw-r--r--drivers/mfd/pcf50633-adc.c32
-rw-r--r--drivers/mfd/pcf50633-core.c5
-rw-r--r--drivers/mfd/twl4030-core.c114
-rw-r--r--drivers/mfd/twl4030-irq.c2
-rw-r--r--drivers/mfd/twl4030-power.c472
-rw-r--r--drivers/mfd/ucb1400_core.c32
-rw-r--r--drivers/mfd/ucb1x00-core.c1
-rw-r--r--drivers/mfd/wm831x-core.c1549
-rw-r--r--drivers/mfd/wm831x-irq.c560
-rw-r--r--drivers/mfd/wm831x-otp.c83
-rw-r--r--drivers/mfd/wm8350-core.c27
-rw-r--r--drivers/misc/Kconfig13
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/eeprom/at24.c76
-rw-r--r--drivers/misc/eeprom/at25.c2
-rw-r--r--drivers/misc/eeprom/max6875.c29
-rw-r--r--drivers/misc/enclosure.c73
-rw-r--r--drivers/misc/ep93xx_pwm.c384
-rw-r--r--drivers/misc/hpilo.c291
-rw-r--r--drivers/misc/hpilo.h8
-rw-r--r--drivers/misc/ibmasm/command.c1
-rw-r--r--drivers/misc/ibmasm/event.c1
-rw-r--r--drivers/misc/ibmasm/ibmasmfs.c2
-rw-r--r--drivers/misc/ibmasm/r_heartbeat.c1
-rw-r--r--drivers/misc/lkdtm.c2
-rw-r--r--drivers/misc/phantom.c3
-rw-r--r--drivers/misc/sgi-gru/grufile.c5
-rw-r--r--drivers/misc/sgi-gru/grukservices.c2
-rw-r--r--drivers/misc/sgi-gru/gruprocfs.c16
-rw-r--r--drivers/misc/sgi-gru/grutables.h2
-rw-r--r--drivers/misc/sgi-xp/xpc_sn2.c40
-rw-r--r--drivers/misc/sgi-xp/xpc_uv.c5
-rw-r--r--drivers/misc/sgi-xp/xpnet.c5
-rw-r--r--drivers/mmc/card/block.c2
-rw-r--r--drivers/mmc/core/core.c318
-rw-r--r--drivers/mmc/core/core.h8
-rw-r--r--drivers/mmc/core/debugfs.c2
-rw-r--r--drivers/mmc/core/host.c1
-rw-r--r--drivers/mmc/core/host.h2
-rw-r--r--drivers/mmc/core/mmc.c151
-rw-r--r--drivers/mmc/core/mmc_ops.c59
-rw-r--r--drivers/mmc/core/mmc_ops.h1
-rw-r--r--drivers/mmc/core/sd.c77
-rw-r--r--drivers/mmc/core/sdio.c316
-rw-r--r--drivers/mmc/core/sdio_bus.c3
-rw-r--r--drivers/mmc/core/sdio_cis.c72
-rw-r--r--drivers/mmc/core/sdio_io.c2
-rw-r--r--drivers/mmc/host/Kconfig70
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/at91_mci.c1
-rw-r--r--drivers/mmc/host/atmel-mci.c42
-rw-r--r--drivers/mmc/host/mmc_spi.c1
-rw-r--r--drivers/mmc/host/mmci.c184
-rw-r--r--drivers/mmc/host/mmci.h5
-rw-r--r--drivers/mmc/host/msm_sdcc.c1287
-rw-r--r--drivers/mmc/host/msm_sdcc.h238
-rw-r--r--drivers/mmc/host/mxcmmc.c2
-rw-r--r--drivers/mmc/host/omap.c1
-rw-r--r--drivers/mmc/host/omap_hsmmc.c1083
-rw-r--r--drivers/mmc/host/pxamci.c108
-rw-r--r--drivers/mmc/host/s3cmci.c608
-rw-r--r--drivers/mmc/host/s3cmci.h14
-rw-r--r--drivers/mmc/host/sdhci-of.c49
-rw-r--r--drivers/mmc/host/sdhci-pci.c5
-rw-r--r--drivers/mmc/host/sdhci.c54
-rw-r--r--drivers/mmc/host/sdhci.h6
-rw-r--r--drivers/mtd/Kconfig18
-rw-r--r--drivers/mtd/afs.c2
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c2
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c11
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0020.c2
-rwxr-xr-x[-rw-r--r--]drivers/mtd/chips/cfi_util.c4
-rw-r--r--drivers/mtd/chips/jedec_probe.c41
-rw-r--r--drivers/mtd/devices/Kconfig10
-rw-r--r--drivers/mtd/devices/Makefile1
-rw-r--r--drivers/mtd/devices/lart.c6
-rw-r--r--drivers/mtd/devices/m25p80.c142
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c5
-rw-r--r--drivers/mtd/devices/phram.c25
-rw-r--r--drivers/mtd/devices/slram.c4
-rw-r--r--drivers/mtd/devices/sst25l.c513
-rw-r--r--drivers/mtd/ftl.c2
-rwxr-xr-x[-rw-r--r--]drivers/mtd/inftlcore.c2
-rw-r--r--drivers/mtd/maps/Kconfig15
-rw-r--r--drivers/mtd/maps/Makefile1
-rw-r--r--drivers/mtd/maps/bfin-async-flash.c2
-rw-r--r--drivers/mtd/maps/ceiva.c2
-rw-r--r--drivers/mtd/maps/dc21285.c4
-rw-r--r--drivers/mtd/maps/gpio-addr-flash.c310
-rw-r--r--drivers/mtd/maps/ipaq-flash.c2
-rw-r--r--drivers/mtd/maps/ixp2000.c2
-rw-r--r--drivers/mtd/maps/pcmciamtd.c197
-rw-r--r--drivers/mtd/maps/physmap_of.c24
-rw-r--r--drivers/mtd/maps/plat-ram.c2
-rw-r--r--drivers/mtd/maps/pmcmsp-flash.c76
-rw-r--r--drivers/mtd/maps/pxa2xx-flash.c2
-rw-r--r--drivers/mtd/maps/sa1100-flash.c6
-rw-r--r--drivers/mtd/maps/uclinux.c8
-rw-r--r--drivers/mtd/mtd_blkdevs.c21
-rw-r--r--drivers/mtd/mtdblock.c6
-rw-r--r--drivers/mtd/mtdconcat.c6
-rw-r--r--drivers/mtd/mtdcore.c4
-rw-r--r--drivers/mtd/mtdpart.c5
-rw-r--r--drivers/mtd/nand/Kconfig30
-rw-r--r--drivers/mtd/nand/Makefile2
-rw-r--r--drivers/mtd/nand/ams-delta.c8
-rw-r--r--drivers/mtd/nand/atmel_nand.c2
-rw-r--r--drivers/mtd/nand/cafe_nand.c6
-rw-r--r--drivers/mtd/nand/cmx270_nand.c4
-rw-r--r--drivers/mtd/nand/davinci_nand.c45
-rw-r--r--drivers/mtd/nand/fsl_elbc_nand.c3
-rw-r--r--drivers/mtd/nand/mxc_nand.c16
-rw-r--r--drivers/mtd/nand/nand_base.c173
-rw-r--r--drivers/mtd/nand/nand_ecc.c31
-rw-r--r--drivers/mtd/nand/ndfc.c4
-rw-r--r--drivers/mtd/nand/nomadik_nand.c250
-rw-r--r--drivers/mtd/nand/omap2.c347
-rw-r--r--drivers/mtd/nand/orion_nand.c3
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c17
-rw-r--r--drivers/mtd/nand/sh_flctl.c5
-rw-r--r--drivers/mtd/nand/tmio_nand.c17
-rw-r--r--drivers/mtd/nand/ts7250.c5
-rw-r--r--drivers/mtd/nand/txx9ndfmc.c52
-rw-r--r--drivers/mtd/nand/w90p910_nand.c382
-rw-r--r--drivers/mtd/ofpart.c21
-rw-r--r--drivers/mtd/onenand/Kconfig3
-rw-r--r--drivers/mtd/onenand/generic.c24
-rw-r--r--drivers/mtd/onenand/onenand_base.c20
-rw-r--r--drivers/mtd/tests/mtd_oobtest.c2
-rw-r--r--drivers/mtd/tests/mtd_pagetest.c12
-rw-r--r--drivers/mtd/ubi/build.c3
-rw-r--r--drivers/mtd/ubi/debug.c32
-rw-r--r--drivers/mtd/ubi/debug.h2
-rw-r--r--drivers/mtd/ubi/eba.c2
-rw-r--r--drivers/mtd/ubi/io.c49
-rw-r--r--drivers/mtd/ubi/scan.c29
-rw-r--r--drivers/mtd/ubi/scan.h4
-rw-r--r--drivers/mtd/ubi/ubi.h5
-rw-r--r--drivers/net/3c501.c4
-rw-r--r--drivers/net/3c501.h2
-rw-r--r--drivers/net/3c503.c10
-rw-r--r--drivers/net/3c505.c6
-rw-r--r--drivers/net/3c507.c8
-rw-r--r--drivers/net/3c509.c6
-rw-r--r--drivers/net/3c515.c12
-rw-r--r--drivers/net/3c523.c6
-rw-r--r--drivers/net/3c527.c10
-rw-r--r--drivers/net/3c59x.c97
-rw-r--r--drivers/net/7990.c2
-rw-r--r--drivers/net/8139cp.c7
-rw-r--r--drivers/net/8139too.c11
-rw-r--r--drivers/net/82596.c9
-rw-r--r--drivers/net/8390.c2
-rw-r--r--drivers/net/8390.h4
-rw-r--r--drivers/net/8390p.c2
-rw-r--r--drivers/net/Kconfig46
-rw-r--r--drivers/net/Makefile13
-rw-r--r--drivers/net/a2065.c7
-rw-r--r--drivers/net/acenic.c6
-rw-r--r--drivers/net/acenic.h3
-rw-r--r--drivers/net/amd8111e.c8
-rw-r--r--drivers/net/appletalk/cops.c8
-rw-r--r--drivers/net/appletalk/ipddp.c12
-rw-r--r--drivers/net/appletalk/ltpc.c6
-rw-r--r--drivers/net/arcnet/arc-rawmode.c1
-rw-r--r--drivers/net/arcnet/arcnet.c3
-rw-r--r--drivers/net/arcnet/capmode.c1
-rw-r--r--drivers/net/ariadne.c10
-rw-r--r--drivers/net/arm/am79c961a.c2
-rw-r--r--drivers/net/arm/at91_ether.c2
-rw-r--r--drivers/net/arm/ep93xx_eth.c14
-rw-r--r--drivers/net/arm/ether1.c2
-rw-r--r--drivers/net/arm/ether3.c4
-rw-r--r--drivers/net/arm/ixp4xx_eth.c2
-rw-r--r--drivers/net/arm/ks8695net.c3
-rw-r--r--drivers/net/arm/w90p910_ether.c207
-rw-r--r--drivers/net/at1700.c8
-rw-r--r--drivers/net/atarilance.c4
-rw-r--r--drivers/net/atl1c/atl1c_ethtool.c2
-rw-r--r--drivers/net/atl1c/atl1c_main.c17
-rw-r--r--drivers/net/atl1e/atl1e.h9
-rw-r--r--drivers/net/atl1e/atl1e_ethtool.c2
-rw-r--r--drivers/net/atl1e/atl1e_main.c29
-rw-r--r--drivers/net/atlx/atl1.c3
-rw-r--r--drivers/net/atlx/atl2.c9
-rw-r--r--drivers/net/atp.c8
-rw-r--r--drivers/net/au1000_eth.c27
-rw-r--r--drivers/net/b44.c33
-rw-r--r--drivers/net/bcm63xx_enet.c1971
-rw-r--r--drivers/net/bcm63xx_enet.h303
-rw-r--r--drivers/net/benet/Kconfig1
-rw-r--r--drivers/net/benet/be.h68
-rw-r--r--drivers/net/benet/be_cmds.c700
-rw-r--r--drivers/net/benet/be_cmds.h86
-rw-r--r--drivers/net/benet/be_ethtool.c46
-rw-r--r--drivers/net/benet/be_hw.h88
-rw-r--r--drivers/net/benet/be_main.c840
-rw-r--r--drivers/net/bfin_mac.c4
-rw-r--r--drivers/net/bmac.c2
-rw-r--r--drivers/net/bnx2.c112
-rw-r--r--drivers/net/bnx2.h12
-rw-r--r--drivers/net/bnx2x.h128
-rw-r--r--drivers/net/bnx2x_dump.h890
-rw-r--r--drivers/net/bnx2x_fw_defs.h379
-rw-r--r--drivers/net/bnx2x_hsi.h435
-rw-r--r--drivers/net/bnx2x_init.h320
-rw-r--r--drivers/net/bnx2x_init_ops.h419
-rw-r--r--drivers/net/bnx2x_link.c2578
-rw-r--r--drivers/net/bnx2x_link.h63
-rw-r--r--drivers/net/bnx2x_main.c2326
-rw-r--r--drivers/net/bnx2x_reg.h1067
-rw-r--r--drivers/net/bonding/bond_3ad.c103
-rw-r--r--drivers/net/bonding/bond_alb.c99
-rw-r--r--drivers/net/bonding/bond_ipv6.c4
-rw-r--r--drivers/net/bonding/bond_main.c174
-rw-r--r--drivers/net/bonding/bond_sysfs.c65
-rw-r--r--drivers/net/bonding/bonding.h2
-rw-r--r--drivers/net/can/Kconfig41
-rw-r--r--drivers/net/can/Makefile3
-rw-r--r--drivers/net/can/at91_can.c1186
-rw-r--r--drivers/net/can/dev.c42
-rw-r--r--drivers/net/can/sja1000/Kconfig47
-rw-r--r--drivers/net/can/sja1000/Makefile1
-rw-r--r--drivers/net/can/sja1000/ems_pci.c152
-rw-r--r--drivers/net/can/sja1000/sja1000.c12
-rw-r--r--drivers/net/can/sja1000/sja1000_isa.c281
-rw-r--r--drivers/net/can/sja1000/sja1000_of_platform.c1
-rw-r--r--drivers/net/can/usb/Kconfig10
-rw-r--r--drivers/net/can/usb/Makefile7
-rw-r--r--drivers/net/can/usb/ems_usb.c1158
-rw-r--r--drivers/net/can/vcan.c4
-rw-r--r--drivers/net/cassini.c15
-rw-r--r--drivers/net/chelsio/sge.c2
-rw-r--r--drivers/net/chelsio/sge.h2
-rw-r--r--drivers/net/cnic.c92
-rw-r--r--drivers/net/cnic_if.h4
-rw-r--r--drivers/net/cpmac.c44
-rw-r--r--drivers/net/cris/eth_v10.c22
-rw-r--r--drivers/net/cs89x0.c11
-rw-r--r--drivers/net/cxgb3/adapter.h12
-rw-r--r--drivers/net/cxgb3/ael1002.c1193
-rw-r--r--drivers/net/cxgb3/aq100x.c7
-rw-r--r--drivers/net/cxgb3/common.h10
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c99
-rw-r--r--drivers/net/cxgb3/sge.c6
-rw-r--r--drivers/net/cxgb3/t3_hw.c19
-rw-r--r--drivers/net/cxgb3/xgmac.c11
-rw-r--r--drivers/net/davinci_emac.c77
-rw-r--r--drivers/net/de600.c2
-rw-r--r--drivers/net/de620.c2
-rw-r--r--drivers/net/declance.c4
-rw-r--r--drivers/net/defxx.c16
-rw-r--r--drivers/net/depca.c9
-rw-r--r--drivers/net/dl2k.c4
-rw-r--r--drivers/net/dm9000.c134
-rw-r--r--drivers/net/dm9000.h20
-rw-r--r--drivers/net/dnet.c4
-rw-r--r--drivers/net/dummy.c22
-rw-r--r--drivers/net/e100.c49
-rw-r--r--drivers/net/e1000/e1000.h10
-rw-r--r--drivers/net/e1000/e1000_ethtool.c253
-rw-r--r--drivers/net/e1000/e1000_hw.c12958
-rw-r--r--drivers/net/e1000/e1000_hw.h3234
-rw-r--r--drivers/net/e1000/e1000_main.c1307
-rw-r--r--drivers/net/e1000/e1000_param.c22
-rw-r--r--drivers/net/e1000e/82571.c4
-rw-r--r--drivers/net/e1000e/defines.h2
-rw-r--r--drivers/net/e1000e/e1000.h28
-rw-r--r--drivers/net/e1000e/ethtool.c12
-rw-r--r--drivers/net/e1000e/hw.h3
-rw-r--r--drivers/net/e1000e/ich8lan.c630
-rw-r--r--drivers/net/e1000e/netdev.c68
-rw-r--r--drivers/net/e1000e/phy.c540
-rw-r--r--drivers/net/eepro.c10
-rw-r--r--drivers/net/eexpress.c9
-rw-r--r--drivers/net/ehea/ehea_main.c1
-rw-r--r--drivers/net/ehea/ehea_qmr.c2
-rw-r--r--drivers/net/enc28j60.c6
-rw-r--r--drivers/net/enic/enic.h25
-rw-r--r--drivers/net/enic/enic_main.c379
-rw-r--r--drivers/net/enic/enic_res.c33
-rw-r--r--drivers/net/enic/enic_res.h2
-rw-r--r--drivers/net/enic/vnic_dev.c74
-rw-r--r--drivers/net/enic/vnic_dev.h14
-rw-r--r--drivers/net/enic/vnic_devcmd.h20
-rw-r--r--drivers/net/enic/vnic_intr.c5
-rw-r--r--drivers/net/enic/vnic_nic.h7
-rw-r--r--drivers/net/enic/vnic_rq.c27
-rw-r--r--drivers/net/enic/vnic_rq.h19
-rw-r--r--drivers/net/enic/vnic_wq.c20
-rw-r--r--drivers/net/enic/vnic_wq.h4
-rw-r--r--drivers/net/epic100.c9
-rw-r--r--drivers/net/eql.c7
-rw-r--r--drivers/net/eth16i.c8
-rw-r--r--drivers/net/ethoc.c109
-rw-r--r--drivers/net/ewrk3.c7
-rw-r--r--drivers/net/fealnx.c6
-rw-r--r--drivers/net/fec.c56
-rw-r--r--drivers/net/fec_mpc52xx.c6
-rw-r--r--drivers/net/fec_mpc52xx_phy.c1
-rw-r--r--drivers/net/forcedeth.c11
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c1
-rw-r--r--drivers/net/fs_enet/mii-bitbang.c1
-rw-r--r--drivers/net/fs_enet/mii-fec.c38
-rw-r--r--drivers/net/fsl_pq_mdio.c2
-rw-r--r--drivers/net/gianfar.c5
-rw-r--r--drivers/net/gianfar_ethtool.c2
-rw-r--r--drivers/net/hamachi.c9
-rw-r--r--drivers/net/hamradio/6pack.c4
-rw-r--r--drivers/net/hamradio/baycom_epp.c7
-rw-r--r--drivers/net/hamradio/baycom_ser_fdx.c1
-rw-r--r--drivers/net/hamradio/baycom_ser_hdx.c1
-rw-r--r--drivers/net/hamradio/bpqether.c30
-rw-r--r--drivers/net/hamradio/dmascc.c2
-rw-r--r--drivers/net/hamradio/hdlcdrv.c8
-rw-r--r--drivers/net/hamradio/mkiss.c8
-rw-r--r--drivers/net/hamradio/scc.c11
-rw-r--r--drivers/net/hamradio/yam.c5
-rw-r--r--drivers/net/hp100.c20
-rw-r--r--drivers/net/hydra.c4
-rw-r--r--drivers/net/ibm_newemac/core.c34
-rw-r--r--drivers/net/ibm_newemac/emac.h5
-rw-r--r--drivers/net/ibmlana.c2
-rw-r--r--drivers/net/ibmveth.c5
-rw-r--r--drivers/net/ifb.c12
-rw-r--r--drivers/net/igb/e1000_82575.c379
-rw-r--r--drivers/net/igb/e1000_82575.h8
-rw-r--r--drivers/net/igb/e1000_defines.h10
-rw-r--r--drivers/net/igb/e1000_hw.h18
-rw-r--r--drivers/net/igb/e1000_mac.c177
-rw-r--r--drivers/net/igb/e1000_mac.h4
-rw-r--r--drivers/net/igb/e1000_phy.c9
-rw-r--r--drivers/net/igb/e1000_regs.h1
-rw-r--r--drivers/net/igb/igb.h1
-rw-r--r--drivers/net/igb/igb_ethtool.c103
-rw-r--r--drivers/net/igb/igb_main.c284
-rw-r--r--drivers/net/igbvf/ethtool.c30
-rw-r--r--drivers/net/igbvf/netdev.c26
-rw-r--r--drivers/net/ioc3-eth.c2
-rw-r--r--drivers/net/ipg.c5
-rw-r--r--drivers/net/irda/ali-ircc.c24
-rw-r--r--drivers/net/irda/au1k_ir.c4
-rw-r--r--drivers/net/irda/donauboe.c10
-rw-r--r--drivers/net/irda/irda-usb.c8
-rw-r--r--drivers/net/irda/kingsun-sir.c6
-rw-r--r--drivers/net/irda/ks959-sir.c4
-rw-r--r--drivers/net/irda/ksdazzle-sir.c4
-rw-r--r--drivers/net/irda/mcs7780.c4
-rw-r--r--drivers/net/irda/mcs7780.h3
-rw-r--r--drivers/net/irda/nsc-ircc.c22
-rw-r--r--drivers/net/irda/pxaficp_ir.c51
-rw-r--r--drivers/net/irda/sa1100_ir.c11
-rw-r--r--drivers/net/irda/sir_dev.c9
-rw-r--r--drivers/net/irda/smsc-ircc2.c31
-rw-r--r--drivers/net/irda/stir4200.c5
-rw-r--r--drivers/net/irda/toim3232-sir.c1
-rw-r--r--drivers/net/irda/via-ircc.c28
-rw-r--r--drivers/net/irda/vlsi_ir.c9
-rw-r--r--drivers/net/irda/w83977af_ir.c10
-rw-r--r--drivers/net/isa-skeleton.c2
-rw-r--r--drivers/net/iseries_veth.c6
-rw-r--r--drivers/net/ixgb/ixgb_main.c12
-rw-r--r--drivers/net/ixgbe/ixgbe.h51
-rw-r--r--drivers/net/ixgbe/ixgbe_82598.c64
-rw-r--r--drivers/net/ixgbe/ixgbe_82599.c290
-rw-r--r--drivers/net/ixgbe/ixgbe_common.c235
-rw-r--r--drivers/net/ixgbe/ixgbe_common.h1
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_82599.c21
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_nl.c116
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c157
-rw-r--r--drivers/net/ixgbe/ixgbe_fcoe.c166
-rw-r--r--drivers/net/ixgbe/ixgbe_fcoe.h4
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c354
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h52
-rw-r--r--drivers/net/ixp2000/enp2611.c18
-rw-r--r--drivers/net/ixp2000/ixpdev.c15
-rw-r--r--drivers/net/jazzsonic.c10
-rw-r--r--drivers/net/jme.c191
-rw-r--r--drivers/net/jme.h21
-rw-r--r--drivers/net/korina.c46
-rw-r--r--drivers/net/ks8842.c5
-rw-r--r--drivers/net/ks8851.c48
-rw-r--r--drivers/net/ks8851.h1
-rw-r--r--drivers/net/ks8851_mll.c1691
-rw-r--r--drivers/net/lance.c8
-rw-r--r--drivers/net/lib82596.c4
-rw-r--r--drivers/net/lib8390.c5
-rw-r--r--drivers/net/ll_temac_main.c4
-rw-r--r--drivers/net/loopback.c5
-rw-r--r--drivers/net/lp486e.c8
-rw-r--r--drivers/net/mac89x0.c2
-rw-r--r--drivers/net/macb.c6
-rw-r--r--drivers/net/mace.c2
-rw-r--r--drivers/net/macsonic.c117
-rw-r--r--drivers/net/macvlan.c44
-rw-r--r--drivers/net/mdio.c16
-rw-r--r--drivers/net/meth.c6
-rw-r--r--drivers/net/mii.c3
-rw-r--r--drivers/net/mipsnet.c2
-rw-r--r--drivers/net/mlx4/catas.c11
-rw-r--r--drivers/net/mlx4/en_main.c5
-rw-r--r--drivers/net/mlx4/en_netdev.c18
-rw-r--r--drivers/net/mlx4/en_resources.c9
-rw-r--r--drivers/net/mlx4/en_rx.c111
-rw-r--r--drivers/net/mlx4/en_tx.c8
-rw-r--r--drivers/net/mlx4/fw.c5
-rw-r--r--drivers/net/mlx4/main.c2
-rw-r--r--drivers/net/mlx4/mlx4_en.h19
-rw-r--r--drivers/net/mv643xx_eth.c34
-rw-r--r--drivers/net/myri10ge/myri10ge.c99
-rw-r--r--drivers/net/myri_sbus.c2
-rw-r--r--drivers/net/natsemi.c11
-rw-r--r--drivers/net/netx-eth.c2
-rw-r--r--drivers/net/netxen/Makefile9
-rw-r--r--drivers/net/netxen/netxen_nic.h574
-rw-r--r--drivers/net/netxen/netxen_nic_ctx.c116
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c123
-rw-r--r--drivers/net/netxen/netxen_nic_hdr.h128
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c899
-rw-r--r--drivers/net/netxen/netxen_nic_hw.h132
-rw-r--r--drivers/net/netxen/netxen_nic_init.c410
-rw-r--r--drivers/net/netxen/netxen_nic_main.c1470
-rw-r--r--drivers/net/netxen/netxen_nic_niu.c550
-rw-r--r--drivers/net/netxen/netxen_nic_phan_reg.h178
-rw-r--r--drivers/net/ni5010.c2
-rw-r--r--drivers/net/ni52.c13
-rw-r--r--drivers/net/ni65.c8
-rw-r--r--drivers/net/niu.c32
-rw-r--r--drivers/net/ns83820.c4
-rw-r--r--drivers/net/pasemi_mac_ethtool.c3
-rw-r--r--drivers/net/pci-skeleton.c7
-rw-r--r--drivers/net/pcmcia/3c574_cs.c126
-rw-r--r--drivers/net/pcmcia/3c589_cs.c110
-rw-r--r--drivers/net/pcmcia/axnet_cs.c77
-rw-r--r--drivers/net/pcmcia/com20020_cs.c63
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c199
-rw-r--r--drivers/net/pcmcia/ibmtr_cs.c71
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c181
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c124
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c352
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c283
-rw-r--r--drivers/net/pcnet32.c9
-rw-r--r--drivers/net/phy/Kconfig6
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/bcm63xx.c132
-rw-r--r--drivers/net/phy/broadcom.c233
-rw-r--r--drivers/net/phy/marvell.c21
-rw-r--r--drivers/net/phy/mdio-gpio.c5
-rw-r--r--drivers/net/phy/phy.c3
-rw-r--r--drivers/net/plip.c2
-rw-r--r--drivers/net/ppp_generic.c18
-rw-r--r--drivers/net/pppoe.c151
-rw-r--r--drivers/net/pppol2tp.c6
-rw-r--r--drivers/net/ps3_gelic_net.c2
-rw-r--r--drivers/net/ps3_gelic_wireless.c2
-rw-r--r--drivers/net/qla3xxx.c3
-rw-r--r--drivers/net/qlge/qlge.h48
-rw-r--r--drivers/net/qlge/qlge_dbg.c2
-rw-r--r--drivers/net/qlge/qlge_ethtool.c18
-rw-r--r--drivers/net/qlge/qlge_main.c609
-rw-r--r--drivers/net/qlge/qlge_mpi.c130
-rw-r--r--drivers/net/r6040.c35
-rw-r--r--drivers/net/r8169.c1273
-rw-r--r--drivers/net/rionet.c9
-rw-r--r--drivers/net/rrunner.c5
-rw-r--r--drivers/net/rrunner.h3
-rw-r--r--drivers/net/s2io.c3598
-rw-r--r--drivers/net/s2io.h5
-rw-r--r--drivers/net/sb1000.c8
-rw-r--r--drivers/net/sb1250-mac.c4
-rw-r--r--drivers/net/sc92031.c3
-rw-r--r--drivers/net/seeq8005.c10
-rw-r--r--drivers/net/sfc/efx.c31
-rw-r--r--drivers/net/sfc/efx.h5
-rw-r--r--drivers/net/sfc/ethtool.c2
-rw-r--r--drivers/net/sfc/ethtool.h2
-rw-r--r--drivers/net/sfc/falcon_hwdefs.h2
-rw-r--r--drivers/net/sfc/falcon_xmac.c8
-rw-r--r--drivers/net/sfc/net_driver.h7
-rw-r--r--drivers/net/sfc/rx.c9
-rw-r--r--drivers/net/sfc/selftest.c3
-rw-r--r--drivers/net/sfc/sfe4001.c4
-rw-r--r--drivers/net/sfc/tx.c18
-rw-r--r--drivers/net/sfc/tx.h3
-rw-r--r--drivers/net/sfc/xfp_phy.c19
-rw-r--r--drivers/net/sgiseeq.c8
-rw-r--r--drivers/net/sh_eth.c9
-rw-r--r--drivers/net/sh_eth.h3
-rw-r--r--drivers/net/sis190.c3
-rw-r--r--drivers/net/sis900.c10
-rw-r--r--drivers/net/skfp/pcmplc.c2
-rw-r--r--drivers/net/skfp/pmf.c8
-rw-r--r--drivers/net/skfp/skfddi.c11
-rw-r--r--drivers/net/skge.c25
-rw-r--r--drivers/net/skge.h2
-rw-r--r--drivers/net/sky2.c638
-rw-r--r--drivers/net/sky2.h36
-rw-r--r--drivers/net/slip.c105
-rw-r--r--drivers/net/smc911x.c6
-rw-r--r--drivers/net/smc911x.h1
-rw-r--r--drivers/net/smc9194.c14
-rw-r--r--drivers/net/smc91x.c10
-rw-r--r--drivers/net/smc91x.h30
-rw-r--r--drivers/net/smsc911x.c34
-rw-r--r--drivers/net/smsc9420.c18
-rw-r--r--drivers/net/sonic.c4
-rw-r--r--drivers/net/starfire.c6
-rw-r--r--drivers/net/stmmac/Kconfig53
-rw-r--r--drivers/net/stmmac/Makefile4
-rw-r--r--drivers/net/stmmac/common.h330
-rw-r--r--drivers/net/stmmac/descs.h163
-rw-r--r--drivers/net/stmmac/gmac.c693
-rw-r--r--drivers/net/stmmac/gmac.h204
-rw-r--r--drivers/net/stmmac/mac100.c517
-rw-r--r--drivers/net/stmmac/mac100.h116
-rw-r--r--drivers/net/stmmac/stmmac.h98
-rw-r--r--drivers/net/stmmac/stmmac_ethtool.c395
-rw-r--r--drivers/net/stmmac/stmmac_main.c2210
-rw-r--r--drivers/net/stmmac/stmmac_mdio.c217
-rw-r--r--drivers/net/stmmac/stmmac_timer.c140
-rw-r--r--drivers/net/stmmac/stmmac_timer.h42
-rw-r--r--drivers/net/sun3_82586.c4
-rw-r--r--drivers/net/sun3lance.c4
-rw-r--r--drivers/net/sunbmac.c2
-rw-r--r--drivers/net/sundance.c6
-rw-r--r--drivers/net/sungem.c18
-rw-r--r--drivers/net/sunhme.c5
-rw-r--r--drivers/net/sunlance.c2
-rw-r--r--drivers/net/sunqe.c2
-rw-r--r--drivers/net/sunvnet.c1
-rw-r--r--drivers/net/tc35815.c79
-rw-r--r--drivers/net/tehuti.c5
-rw-r--r--drivers/net/tg3.c2430
-rw-r--r--drivers/net/tg3.h225
-rw-r--r--drivers/net/tlan.c12
-rw-r--r--drivers/net/tokenring/3c359.c6
-rw-r--r--drivers/net/tokenring/ibmtr.c20
-rw-r--r--drivers/net/tokenring/lanstreamer.c8
-rw-r--r--drivers/net/tokenring/olympic.c8
-rw-r--r--drivers/net/tokenring/smctr.c44
-rw-r--r--drivers/net/tokenring/tms380tr.c21
-rw-r--r--drivers/net/tulip/de2104x.c5
-rw-r--r--drivers/net/tulip/de4x5.c11
-rw-r--r--drivers/net/tulip/dmfe.c9
-rw-r--r--drivers/net/tulip/tulip_core.c9
-rw-r--r--drivers/net/tulip/uli526x.c10
-rw-r--r--drivers/net/tulip/winbond-840.c8
-rw-r--r--drivers/net/tulip/xircom_cb.c8
-rw-r--r--drivers/net/tun.c58
-rw-r--r--drivers/net/typhoon.c5
-rw-r--r--drivers/net/ucc_geth.c582
-rw-r--r--drivers/net/ucc_geth.h3
-rw-r--r--drivers/net/ucc_geth_ethtool.c48
-rw-r--r--drivers/net/usb/Kconfig2
-rw-r--r--drivers/net/usb/asix.c4
-rw-r--r--drivers/net/usb/catc.c7
-rw-r--r--drivers/net/usb/cdc-phonet.c20
-rw-r--r--drivers/net/usb/cdc_eem.c17
-rw-r--r--drivers/net/usb/cdc_ether.c42
-rw-r--r--drivers/net/usb/dm9601.c6
-rw-r--r--drivers/net/usb/hso.c20
-rw-r--r--drivers/net/usb/kaweth.c27
-rw-r--r--drivers/net/usb/mcs7830.c2
-rw-r--r--drivers/net/usb/pegasus.c20
-rw-r--r--drivers/net/usb/pegasus.h6
-rw-r--r--drivers/net/usb/rndis_host.c57
-rw-r--r--drivers/net/usb/rtl8150.c7
-rw-r--r--drivers/net/usb/smsc95xx.c74
-rw-r--r--drivers/net/usb/usbnet.c100
-rw-r--r--drivers/net/veth.c46
-rw-r--r--drivers/net/via-rhine.c12
-rw-r--r--drivers/net/via-velocity.c3430
-rw-r--r--drivers/net/via-velocity.h6
-rw-r--r--drivers/net/virtio_net.c258
-rw-r--r--drivers/net/vmxnet3/Makefile35
-rw-r--r--drivers/net/vmxnet3/upt1_defs.h96
-rw-r--r--drivers/net/vmxnet3/vmxnet3_defs.h535
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c2574
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c566
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h389
-rw-r--r--drivers/net/vxge/vxge-config.c10
-rw-r--r--drivers/net/vxge/vxge-config.h19
-rw-r--r--drivers/net/vxge/vxge-main.c175
-rw-r--r--drivers/net/vxge/vxge-main.h8
-rw-r--r--drivers/net/vxge/vxge-reg.h9
-rw-r--r--drivers/net/vxge/vxge-traffic.c12
-rw-r--r--drivers/net/vxge/vxge-traffic.h4
-rw-r--r--drivers/net/vxge/vxge-version.h4
-rw-r--r--drivers/net/wan/c101.c1
-rw-r--r--drivers/net/wan/cosa.c9
-rw-r--r--drivers/net/wan/cycx_x25.c11
-rw-r--r--drivers/net/wan/dlci.c42
-rw-r--r--drivers/net/wan/dscc4.c17
-rw-r--r--drivers/net/wan/farsync.c30
-rw-r--r--drivers/net/wan/hd64570.c4
-rw-r--r--drivers/net/wan/hd64572.c4
-rw-r--r--drivers/net/wan/hdlc.c2
-rw-r--r--drivers/net/wan/hdlc_cisco.c18
-rw-r--r--drivers/net/wan/hdlc_fr.c8
-rw-r--r--drivers/net/wan/hdlc_ppp.c1
-rw-r--r--drivers/net/wan/hdlc_raw_eth.c2
-rw-r--r--drivers/net/wan/hdlc_x25.c6
-rw-r--r--drivers/net/wan/hostess_sv11.c3
-rw-r--r--drivers/net/wan/ixp4xx_hss.c95
-rw-r--r--drivers/net/wan/lapbether.c3
-rw-r--r--drivers/net/wan/lmc/lmc_main.c18
-rw-r--r--drivers/net/wan/n2.c1
-rw-r--r--drivers/net/wan/pci200syn.c12
-rw-r--r--drivers/net/wan/sbni.c11
-rw-r--r--drivers/net/wan/sdla.c11
-rw-r--r--drivers/net/wan/sealevel.c3
-rw-r--r--drivers/net/wan/wanxl.c4
-rw-r--r--drivers/net/wan/x25_asy.c13
-rw-r--r--drivers/net/wan/z85230.c9
-rw-r--r--drivers/net/wan/z85230.h3
-rw-r--r--drivers/net/wimax/i2400m/netdev.c12
-rw-r--r--drivers/net/wimax/i2400m/sdio.c17
-rw-r--r--drivers/net/wimax/i2400m/usb.c5
-rw-r--r--drivers/net/wireless/Kconfig95
-rw-r--r--drivers/net/wireless/adm8211.c62
-rw-r--r--drivers/net/wireless/adm8211.h2
-rw-r--r--drivers/net/wireless/airo.c31
-rw-r--r--drivers/net/wireless/airo_cs.c55
-rw-r--r--drivers/net/wireless/arlan-main.c8
-rw-r--r--drivers/net/wireless/arlan-proc.c28
-rw-r--r--drivers/net/wireless/at76c50x-usb.c33
-rw-r--r--drivers/net/wireless/ath/Kconfig19
-rw-r--r--drivers/net/wireless/ath/ar9170/Kconfig4
-rw-r--r--drivers/net/wireless/ath/ar9170/ar9170.h69
-rw-r--r--drivers/net/wireless/ath/ar9170/led.c11
-rw-r--r--drivers/net/wireless/ath/ar9170/mac.c46
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c768
-rw-r--r--drivers/net/wireless/ath/ar9170/phy.c418
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c4
-rw-r--r--drivers/net/wireless/ath/ath.h48
-rw-r--r--drivers/net/wireless/ath/ath5k/Kconfig3
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h45
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c84
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c474
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h29
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c8
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c39
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.h4
-rw-r--r--drivers/net/wireless/ath/ath5k/led.c6
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c57
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c3
-rw-r--r--drivers/net/wireless/ath/ath5k/reg.h14
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c156
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig13
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile6
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c213
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.h25
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h86
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.c340
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.h100
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c237
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h12
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c99
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h56
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c2598
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h284
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c1188
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c1177
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c1389
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c1083
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h127
-rw-r--r--drivers/net/wireless/ath/ath9k/initvals.h2239
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c47
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h9
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c334
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c34
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.c65
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.h32
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c616
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.h29
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c150
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h205
-rw-r--r--drivers/net/wireless/ath/ath9k/virtual.c34
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c193
-rw-r--r--drivers/net/wireless/ath/main.c36
-rw-r--r--drivers/net/wireless/ath/regd.c2
-rw-r--r--drivers/net/wireless/ath/regd.h26
-rw-r--r--drivers/net/wireless/ath/regd_common.h8
-rw-r--r--drivers/net/wireless/atmel.c10
-rw-r--r--drivers/net/wireless/atmel_cs.c51
-rw-r--r--drivers/net/wireless/b43/Kconfig39
-rw-r--r--drivers/net/wireless/b43/Makefile1
-rw-r--r--drivers/net/wireless/b43/b43.h211
-rw-r--r--drivers/net/wireless/b43/debugfs.c68
-rw-r--r--drivers/net/wireless/b43/debugfs.h4
-rw-r--r--drivers/net/wireless/b43/dma.c71
-rw-r--r--drivers/net/wireless/b43/dma.h3
-rw-r--r--drivers/net/wireless/b43/leds.c266
-rw-r--r--drivers/net/wireless/b43/leds.h34
-rw-r--r--drivers/net/wireless/b43/lo.c2
-rw-r--r--drivers/net/wireless/b43/main.c1130
-rw-r--r--drivers/net/wireless/b43/main.h6
-rw-r--r--drivers/net/wireless/b43/pcmcia.c26
-rw-r--r--drivers/net/wireless/b43/phy_a.c48
-rw-r--r--drivers/net/wireless/b43/phy_common.c37
-rw-r--r--drivers/net/wireless/b43/phy_common.h21
-rw-r--r--drivers/net/wireless/b43/phy_g.c66
-rw-r--r--drivers/net/wireless/b43/phy_g.h3
-rw-r--r--drivers/net/wireless/b43/phy_lp.c1814
-rw-r--r--drivers/net/wireless/b43/phy_lp.h58
-rw-r--r--drivers/net/wireless/b43/phy_n.c3
-rw-r--r--drivers/net/wireless/b43/pio.c168
-rw-r--r--drivers/net/wireless/b43/pio.h6
-rw-r--r--drivers/net/wireless/b43/rfkill.c5
-rw-r--r--drivers/net/wireless/b43/sdio.c202
-rw-r--r--drivers/net/wireless/b43/sdio.h45
-rw-r--r--drivers/net/wireless/b43/sysfs.c3
-rw-r--r--drivers/net/wireless/b43/tables_lpphy.c2193
-rw-r--r--drivers/net/wireless/b43/tables_lpphy.h13
-rw-r--r--drivers/net/wireless/b43/wa.c4
-rw-r--r--drivers/net/wireless/b43/xmit.c44
-rw-r--r--drivers/net/wireless/b43/xmit.h3
-rw-r--r--drivers/net/wireless/b43legacy/dma.c22
-rw-r--r--drivers/net/wireless/b43legacy/main.c21
-rw-r--r--drivers/net/wireless/b43legacy/phy.c1
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_80211.h10
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_tx.c53
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c50
-rw-r--r--drivers/net/wireless/hostap/hostap_info.c1
-rw-r--r--drivers/net/wireless/hostap/hostap_ioctl.c1
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c3
-rw-r--r--drivers/net/wireless/ipw2x00/Kconfig6
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c222
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.h16
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c980
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.h16
-rw-r--r--drivers/net/wireless/ipw2x00/libipw.h (renamed from drivers/net/wireless/ipw2x00/ieee80211.h)661
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_geo.c82
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_module.c82
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_rx.c403
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_tx.c78
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_wx.c94
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c99
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h9
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.c26
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c99
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-hw.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c106
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c162
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c143
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c340
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c529
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.c13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h64
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c795
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h106
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h37
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c1163
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h293
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c513
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h124
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hcmd.c66
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c40
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c823
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h115
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c279
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c42
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c60
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c272
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c354
-rw-r--r--drivers/net/wireless/iwmc3200wifi/Kconfig7
-rw-r--r--drivers/net/wireless/iwmc3200wifi/Makefile2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c437
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c197
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h7
-rw-r--r--drivers/net/wireless/iwmc3200wifi/debug.h2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/debugfs.c105
-rw-r--r--drivers/net/wireless/iwmc3200wifi/eeprom.c4
-rw-r--r--drivers/net/wireless/iwmc3200wifi/fw.c67
-rw-r--r--drivers/net/wireless/iwmc3200wifi/hal.c16
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h47
-rw-r--r--drivers/net/wireless/iwmc3200wifi/lmac.h19
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c104
-rw-r--r--drivers/net/wireless/iwmc3200wifi/netdev.c28
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c206
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.c10
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.h3
-rw-r--r--drivers/net/wireless/iwmc3200wifi/umac.h8
-rw-r--r--drivers/net/wireless/iwmc3200wifi/wext.c723
-rw-r--r--drivers/net/wireless/libertas/assoc.c67
-rw-r--r--drivers/net/wireless/libertas/cmd.c1
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c1
-rw-r--r--drivers/net/wireless/libertas/debugfs.c28
-rw-r--r--drivers/net/wireless/libertas/decl.h5
-rw-r--r--drivers/net/wireless/libertas/dev.h3
-rw-r--r--drivers/net/wireless/libertas/ethtool.c19
-rw-r--r--drivers/net/wireless/libertas/if_cs.c114
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c5
-rw-r--r--drivers/net/wireless/libertas/if_spi.c21
-rw-r--r--drivers/net/wireless/libertas/if_usb.c5
-rw-r--r--drivers/net/wireless/libertas/main.c6
-rw-r--r--drivers/net/wireless/libertas/tx.c7
-rw-r--r--drivers/net/wireless/libertas/wext.c4
-rw-r--r--drivers/net/wireless/libertas_tf/main.c40
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c101
-rw-r--r--drivers/net/wireless/mwl8k.c1559
-rw-r--r--drivers/net/wireless/netwave_cs.c103
-rw-r--r--drivers/net/wireless/orinoco/Kconfig1
-rw-r--r--drivers/net/wireless/orinoco/Makefile2
-rw-r--r--drivers/net/wireless/orinoco/airport.c98
-rw-r--r--drivers/net/wireless/orinoco/cfg.c203
-rw-r--r--drivers/net/wireless/orinoco/cfg.h15
-rw-r--r--drivers/net/wireless/orinoco/fw.c41
-rw-r--r--drivers/net/wireless/orinoco/hermes.c2
-rw-r--r--drivers/net/wireless/orinoco/hermes.h2
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.c50
-rw-r--r--drivers/net/wireless/orinoco/hw.c786
-rw-r--r--drivers/net/wireless/orinoco/hw.h16
-rw-r--r--drivers/net/wireless/orinoco/main.c1169
-rw-r--r--drivers/net/wireless/orinoco/main.h3
-rw-r--r--drivers/net/wireless/orinoco/orinoco.h65
-rw-r--r--drivers/net/wireless/orinoco/orinoco_cs.c125
-rw-r--r--drivers/net/wireless/orinoco/orinoco_nortel.c38
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.c38
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.h57
-rw-r--r--drivers/net/wireless/orinoco/orinoco_plx.c38
-rw-r--r--drivers/net/wireless/orinoco/orinoco_tmd.c38
-rw-r--r--drivers/net/wireless/orinoco/scan.c291
-rw-r--r--drivers/net/wireless/orinoco/scan.h21
-rw-r--r--drivers/net/wireless/orinoco/spectrum_cs.c152
-rw-r--r--drivers/net/wireless/orinoco/wext.c1053
-rw-r--r--drivers/net/wireless/p54/Makefile3
-rw-r--r--drivers/net/wireless/p54/eeprom.c753
-rw-r--r--drivers/net/wireless/p54/eeprom.h226
-rw-r--r--drivers/net/wireless/p54/fwio.c716
-rw-r--r--drivers/net/wireless/p54/led.c162
-rw-r--r--drivers/net/wireless/p54/lmac.h558
-rw-r--r--drivers/net/wireless/p54/main.c648
-rw-r--r--drivers/net/wireless/p54/p54.h151
-rw-r--r--drivers/net/wireless/p54/p54common.c2688
-rw-r--r--drivers/net/wireless/p54/p54common.h644
-rw-r--r--drivers/net/wireless/p54/p54pci.c9
-rw-r--r--drivers/net/wireless/p54/p54spi.c55
-rw-r--r--drivers/net/wireless/p54/p54usb.c53
-rw-r--r--drivers/net/wireless/p54/txrx.c869
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c1
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c1
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.c8
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.h2
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c4
-rw-r--r--drivers/net/wireless/prism54/islpci_mgt.c1
-rw-r--r--drivers/net/wireless/ray_cs.c380
-rw-r--r--drivers/net/wireless/rndis_wlan.c2157
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig16
-rw-r--r--drivers/net/wireless/rt2x00/Makefile1
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c15
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c15
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c28
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c49
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.h12
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h60
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c35
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00crypto.c14
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c108
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h70
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00link.c171
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c127
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c123
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h12
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00reg.h4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00rfkill.c127
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c27
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c27
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h4
-rw-r--r--drivers/net/wireless/rtl818x/Makefile2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_dev.c16
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187.h1
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_dev.c47
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_leds.c18
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_rfkill.c64
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_rfkill.h8
-rw-r--r--drivers/net/wireless/rtl818x/rtl818x.h19
-rw-r--r--drivers/net/wireless/strip.c13
-rw-r--r--drivers/net/wireless/wavelan.c5
-rw-r--r--drivers/net/wireless/wavelan.p.h2
-rw-r--r--drivers/net/wireless/wavelan_cs.c41
-rw-r--r--drivers/net/wireless/wavelan_cs.p.h2
-rw-r--r--drivers/net/wireless/wl12xx/Kconfig51
-rw-r--r--drivers/net/wireless/wl12xx/Makefile18
-rw-r--r--drivers/net/wireless/wl12xx/acx.c689
-rw-r--r--drivers/net/wireless/wl12xx/boot.c295
-rw-r--r--drivers/net/wireless/wl12xx/cmd.c353
-rw-r--r--drivers/net/wireless/wl12xx/init.c200
-rw-r--r--drivers/net/wireless/wl12xx/wl1251.c709
-rw-r--r--drivers/net/wireless/wl12xx/wl1251.h467
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.c918
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.h (renamed from drivers/net/wireless/wl12xx/acx.h)345
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_boot.c530
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_boot.h (renamed from drivers/net/wireless/wl12xx/boot.h)13
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.c412
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.h (renamed from drivers/net/wireless/wl12xx/cmd.h)196
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_debugfs.c (renamed from drivers/net/wireless/wl12xx/debugfs.c)60
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_debugfs.h (renamed from drivers/net/wireless/wl12xx/debugfs.h)16
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_event.c (renamed from drivers/net/wireless/wl12xx/event.c)57
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_event.h (renamed from drivers/net/wireless/wl12xx/event.h)12
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_init.c413
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_init.h41
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_io.c196
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_io.h64
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c (renamed from drivers/net/wireless/wl12xx/main.c)891
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_netlink.h (renamed from drivers/net/wireless/wl12xx/init.h)22
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ps.c (renamed from drivers/net/wireless/wl12xx/ps.c)80
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ps.h (renamed from drivers/net/wireless/wl12xx/ps.h)18
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_reg.h644
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.c (renamed from drivers/net/wireless/wl12xx/rx.c)93
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.h (renamed from drivers/net/wireless/wl12xx/rx.h)24
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_sdio.c205
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_spi.c344
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_spi.h61
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.c (renamed from drivers/net/wireless/wl12xx/tx.c)174
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.h (renamed from drivers/net/wireless/wl12xx/tx.h)21
-rw-r--r--drivers/net/wireless/wl12xx/wl1271.h (renamed from drivers/net/wireless/wl12xx/wl12xx.h)210
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_acx.c961
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_acx.h1221
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_boot.c541
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_boot.h72
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.c813
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.h464
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_debugfs.c518
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_debugfs.h33
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.c125
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.h110
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_init.c397
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_init.h115
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c1393
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ps.c142
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ps.h35
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_reg.h (renamed from drivers/net/wireless/wl12xx/reg.h)223
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_rx.c200
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_rx.h121
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_spi.c (renamed from drivers/net/wireless/wl12xx/spi.c)194
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_spi.h (renamed from drivers/net/wireless/wl12xx/spi.h)68
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.c378
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.h130
-rw-r--r--drivers/net/wireless/wl3501_cs.c80
-rw-r--r--drivers/net/wireless/zd1201.c7
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c8
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h6
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c51
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c76
-rw-r--r--drivers/net/xen-netfront.c8
-rw-r--r--drivers/net/xilinx_emaclite.c1037
-rw-r--r--drivers/net/xtsonic.c2
-rw-r--r--drivers/net/yellowfin.c12
-rw-r--r--drivers/net/znet.c17
-rw-r--r--drivers/of/base.c1
-rw-r--r--drivers/of/of_mdio.c13
-rw-r--r--drivers/oprofile/buffer_sync.c3
-rw-r--r--drivers/oprofile/event_buffer.c35
-rw-r--r--drivers/oprofile/oprofilefs.c2
-rw-r--r--drivers/parisc/ccio-dma.c4
-rw-r--r--drivers/parisc/sba_iommu.c4
-rw-r--r--drivers/parport/parport_cs.c38
-rw-r--r--drivers/parport/procfs.c12
-rw-r--r--drivers/pci/Makefile3
-rw-r--r--drivers/pci/dmar.c120
-rw-r--r--drivers/pci/hotplug/Makefile2
-rw-r--r--drivers/pci/hotplug/acpi_pcihp.c117
-rw-r--r--drivers/pci/hotplug/acpiphp.h3
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c187
-rw-r--r--drivers/pci/hotplug/acpiphp_ibm.c11
-rw-r--r--drivers/pci/hotplug/cpqphp.h1
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c3
-rw-r--r--drivers/pci/hotplug/pciehp.h116
-rw-r--r--drivers/pci/hotplug/pciehp_acpi.c24
-rw-r--r--drivers/pci/hotplug/pciehp_core.c136
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c114
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c119
-rw-r--r--drivers/pci/hotplug/pciehp_pci.c160
-rw-r--r--drivers/pci/hotplug/pcihp_slot.c187
-rw-r--r--drivers/pci/hotplug/shpchp.h9
-rw-r--r--drivers/pci/hotplug/shpchp_pci.c62
-rw-r--r--drivers/pci/intel-iommu.c459
-rw-r--r--drivers/pci/intr_remapping.c8
-rw-r--r--drivers/pci/iova.c16
-rw-r--r--drivers/pci/legacy.c34
-rw-r--r--drivers/pci/msi.c283
-rw-r--r--drivers/pci/pci-acpi.c29
-rw-r--r--drivers/pci/pci-driver.c148
-rw-r--r--drivers/pci/pci-stub.c45
-rw-r--r--drivers/pci/pci-sysfs.c37
-rw-r--r--drivers/pci/pci.c125
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/pcie/aer/aer_inject.c25
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c27
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h34
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c107
-rw-r--r--drivers/pci/pcie/aer/aerdrv_errprint.c190
-rw-r--r--drivers/pci/pcie/aspm.c494
-rw-r--r--drivers/pci/pcie/portdrv_core.c6
-rw-r--r--drivers/pci/pcie/portdrv_pci.c4
-rw-r--r--drivers/pci/probe.c33
-rw-r--r--drivers/pci/quirks.c74
-rw-r--r--drivers/pci/search.c31
-rw-r--r--drivers/pci/setup-bus.c22
-rw-r--r--drivers/pci/setup-res.c38
-rw-r--r--drivers/pcmcia/Kconfig46
-rw-r--r--drivers/pcmcia/Makefile12
-rw-r--r--drivers/pcmcia/at91_cf.c2
-rw-r--r--drivers/pcmcia/au1000_generic.c2
-rw-r--r--drivers/pcmcia/au1000_pb1x00.c1
-rw-r--r--drivers/pcmcia/au1000_xxs1500.c1
-rw-r--r--drivers/pcmcia/bcm63xx_pcmcia.c536
-rw-r--r--drivers/pcmcia/bcm63xx_pcmcia.h60
-rw-r--r--drivers/pcmcia/bfin_cf_pcmcia.c2
-rw-r--r--drivers/pcmcia/cardbus.c4
-rw-r--r--drivers/pcmcia/cirrus.h10
-rw-r--r--drivers/pcmcia/cistpl.c91
-rw-r--r--drivers/pcmcia/cs.c136
-rw-r--r--drivers/pcmcia/cs_internal.h45
-rw-r--r--drivers/pcmcia/ds.c199
-rw-r--r--drivers/pcmcia/i82092.c2
-rw-r--r--drivers/pcmcia/i82365.c43
-rw-r--r--drivers/pcmcia/m32r_cfc.c117
-rw-r--r--drivers/pcmcia/m32r_pcc.c63
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c57
-rw-r--r--drivers/pcmcia/o2micro.h20
-rw-r--r--drivers/pcmcia/omap_cf.c2
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c132
-rw-r--r--drivers/pcmcia/pcmcia_resource.c488
-rw-r--r--drivers/pcmcia/pd6729.c74
-rw-r--r--drivers/pcmcia/pd6729.h7
-rw-r--r--drivers/pcmcia/pxa2xx_base.c112
-rw-r--r--drivers/pcmcia/pxa2xx_base.h3
-rw-r--r--drivers/pcmcia/pxa2xx_cm_x255.c2
-rw-r--r--drivers/pcmcia/pxa2xx_cm_x270.c2
-rw-r--r--drivers/pcmcia/pxa2xx_e740.c2
-rw-r--r--drivers/pcmcia/pxa2xx_lubbock.c14
-rw-r--r--drivers/pcmcia/pxa2xx_mainstone.c2
-rw-r--r--drivers/pcmcia/pxa2xx_palmld.c2
-rw-r--r--drivers/pcmcia/pxa2xx_palmtc.c230
-rw-r--r--drivers/pcmcia/pxa2xx_palmtx.c2
-rw-r--r--drivers/pcmcia/pxa2xx_sharpsl.c2
-rw-r--r--drivers/pcmcia/pxa2xx_trizeps4.c4
-rw-r--r--drivers/pcmcia/pxa2xx_viper.c2
-rw-r--r--drivers/pcmcia/rsrc_mgr.c1
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c3
-rw-r--r--drivers/pcmcia/sa1100_assabet.c4
-rw-r--r--drivers/pcmcia/sa1100_badge4.c11
-rw-r--r--drivers/pcmcia/sa1100_cerf.c2
-rw-r--r--drivers/pcmcia/sa1100_generic.c13
-rw-r--r--drivers/pcmcia/sa1100_h3600.c4
-rw-r--r--drivers/pcmcia/sa1100_jornada720.c162
-rw-r--r--drivers/pcmcia/sa1100_neponset.c15
-rw-r--r--drivers/pcmcia/sa1100_shannon.c2
-rw-r--r--drivers/pcmcia/sa1100_simpad.c2
-rw-r--r--drivers/pcmcia/sa1111_generic.c67
-rw-r--r--drivers/pcmcia/sa1111_generic.h17
-rw-r--r--drivers/pcmcia/sa11xx_base.c99
-rw-r--r--drivers/pcmcia/sa11xx_base.h2
-rw-r--r--drivers/pcmcia/soc_common.c230
-rw-r--r--drivers/pcmcia/soc_common.h10
-rw-r--r--drivers/pcmcia/socket_sysfs.c2
-rw-r--r--drivers/pcmcia/tcic.c35
-rw-r--r--drivers/pcmcia/topic.h15
-rw-r--r--drivers/pcmcia/vrc4171_card.c2
-rw-r--r--drivers/pcmcia/yenta_socket.c116
-rw-r--r--drivers/platform/x86/Kconfig10
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/acer-wmi.c2
-rw-r--r--drivers/platform/x86/acerhdf.c131
-rw-r--r--drivers/platform/x86/asus-laptop.c227
-rw-r--r--drivers/platform/x86/eeepc-laptop.c347
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c109
-rw-r--r--drivers/platform/x86/hp-wmi.c17
-rw-r--r--drivers/platform/x86/sony-laptop.c143
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c986
-rw-r--r--drivers/platform/x86/topstar-laptop.c265
-rw-r--r--drivers/platform/x86/wmi.c1
-rw-r--r--drivers/pnp/driver.c10
-rw-r--r--drivers/pnp/pnpacpi/core.c21
-rw-r--r--drivers/power/Kconfig7
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/ds2760_battery.c147
-rw-r--r--drivers/power/olpc_battery.c50
-rw-r--r--drivers/power/power_supply_core.c44
-rw-r--r--drivers/power/power_supply_sysfs.c12
-rw-r--r--drivers/power/wm831x_power.c779
-rw-r--r--drivers/power/wm8350_power.c22
-rw-r--r--drivers/power/wm97xx_battery.c79
-rw-r--r--drivers/pps/kapi.c20
-rw-r--r--drivers/pps/pps.c11
-rw-r--r--drivers/ps3/ps3stor_lib.c65
-rw-r--r--drivers/regulator/Kconfig55
-rw-r--r--drivers/regulator/Makefile9
-rw-r--r--drivers/regulator/ab3100.c700
-rw-r--r--drivers/regulator/core.c312
-rw-r--r--drivers/regulator/da903x.c77
-rw-r--r--drivers/regulator/fixed.c90
-rw-r--r--drivers/regulator/lp3971.c2
-rw-r--r--drivers/regulator/mc13783.c410
-rw-r--r--drivers/regulator/pcap-regulator.c318
-rw-r--r--drivers/regulator/pcf50633-regulator.c98
-rw-r--r--drivers/regulator/tps65023-regulator.c632
-rw-r--r--drivers/regulator/tps6507x-regulator.c714
-rw-r--r--drivers/regulator/userspace-consumer.c45
-rw-r--r--drivers/regulator/virtual.c56
-rw-r--r--drivers/regulator/wm831x-dcdc.c862
-rw-r--r--drivers/regulator/wm831x-isink.c262
-rw-r--r--drivers/regulator/wm831x-ldo.c852
-rw-r--r--drivers/regulator/wm8350-regulator.c2
-rw-r--r--drivers/rtc/Kconfig68
-rw-r--r--drivers/rtc/Makefile19
-rw-r--r--drivers/rtc/interface.c1
-rw-r--r--drivers/rtc/rtc-ab3100.c281
-rw-r--r--drivers/rtc/rtc-at91rm9200.c24
-rw-r--r--drivers/rtc/rtc-bfin.c2
-rw-r--r--drivers/rtc/rtc-coh901331.c322
-rw-r--r--drivers/rtc/rtc-dev.c1
-rw-r--r--drivers/rtc/rtc-ds1302.c69
-rw-r--r--drivers/rtc/rtc-ds1305.c1
-rw-r--r--drivers/rtc/rtc-ds1307.c3
-rw-r--r--drivers/rtc/rtc-ds1390.c1
-rw-r--r--drivers/rtc/rtc-ds3234.c1
-rw-r--r--drivers/rtc/rtc-ep93xx.c14
-rw-r--r--drivers/rtc/rtc-m41t94.c1
-rw-r--r--drivers/rtc/rtc-max6902.c1
-rw-r--r--drivers/rtc/rtc-mxc.c507
-rw-r--r--drivers/rtc/rtc-omap.c2
-rw-r--r--drivers/rtc/rtc-pcap.c224
-rw-r--r--drivers/rtc/rtc-pcf2123.c364
-rw-r--r--drivers/rtc/rtc-pcf50633.c10
-rw-r--r--drivers/rtc/rtc-pxa.c27
-rw-r--r--drivers/rtc/rtc-r9701.c1
-rw-r--r--drivers/rtc/rtc-rs5c348.c1
-rw-r--r--drivers/rtc/rtc-sa1100.c25
-rw-r--r--drivers/rtc/rtc-sh.c97
-rw-r--r--drivers/rtc/rtc-stmp3xxx.c304
-rw-r--r--drivers/rtc/rtc-sysfs.c14
-rw-r--r--drivers/rtc/rtc-v3020.c2
-rw-r--r--drivers/rtc/rtc-vr41xx.c9
-rw-r--r--drivers/rtc/rtc-wm831x.c523
-rw-r--r--drivers/rtc/rtc-x1205.c6
-rw-r--r--drivers/s390/block/dasd.c20
-rw-r--r--drivers/s390/block/dasd_eckd.c28
-rw-r--r--drivers/s390/block/dasd_int.h2
-rw-r--r--drivers/s390/block/dcssblk.c2
-rw-r--r--drivers/s390/block/xpram.c2
-rw-r--r--drivers/s390/char/monreader.c1
-rw-r--r--drivers/s390/char/raw3270.c2
-rw-r--r--drivers/s390/char/sclp_async.c51
-rw-r--r--drivers/s390/char/sclp_quiesce.c48
-rw-r--r--drivers/s390/char/sclp_vt220.c30
-rw-r--r--drivers/s390/char/tape_block.c5
-rw-r--r--drivers/s390/char/zcore.c1
-rw-r--r--drivers/s390/cio/blacklist.c13
-rw-r--r--drivers/s390/cio/chp.c2
-rw-r--r--drivers/s390/cio/css.c254
-rw-r--r--drivers/s390/cio/css.h3
-rw-r--r--drivers/s390/cio/device.c53
-rw-r--r--drivers/s390/cio/device.h2
-rw-r--r--drivers/s390/cio/device_fsm.c35
-rw-r--r--drivers/s390/cio/idset.c22
-rw-r--r--drivers/s390/cio/idset.h2
-rw-r--r--drivers/s390/cio/qdio_debug.c2
-rw-r--r--drivers/s390/cio/qdio_main.c32
-rw-r--r--drivers/s390/cio/qdio_perf.c2
-rw-r--r--drivers/s390/crypto/ap_bus.c40
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c13
-rw-r--r--drivers/s390/net/claw.c2
-rw-r--r--drivers/s390/net/ctcm_main.c11
-rw-r--r--drivers/s390/net/lcs.c8
-rw-r--r--drivers/s390/net/netiucv.c11
-rw-r--r--drivers/s390/net/qeth_core.h10
-rw-r--r--drivers/s390/net/qeth_core_main.c114
-rw-r--r--drivers/s390/net/qeth_core_sys.c2
-rw-r--r--drivers/s390/net/qeth_l2_main.c48
-rw-r--r--drivers/s390/net/qeth_l3_main.c52
-rw-r--r--drivers/s390/net/smsgiucv.c7
-rw-r--r--drivers/s390/scsi/zfcp_aux.c330
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c126
-rw-r--r--drivers/s390/scsi/zfcp_cfdc.c17
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c544
-rw-r--r--drivers/s390/scsi/zfcp_dbf.h175
-rw-r--r--drivers/s390/scsi/zfcp_def.h183
-rw-r--r--drivers/s390/scsi/zfcp_erp.c175
-rw-r--r--drivers/s390/scsi/zfcp_ext.h105
-rw-r--r--drivers/s390/scsi/zfcp_fc.c187
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c668
-rw-r--r--drivers/s390/scsi/zfcp_fsf.h3
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c369
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c75
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c35
-rw-r--r--drivers/sbus/char/jsflash.c2
-rw-r--r--drivers/scsi/Kconfig17
-rw-r--r--drivers/scsi/Makefile3
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_core.c2
-rw-r--r--drivers/scsi/be2iscsi/Kconfig8
-rw-r--r--drivers/scsi/be2iscsi/Makefile8
-rw-r--r--drivers/scsi/be2iscsi/be.h183
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c523
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h877
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c638
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.h75
-rw-r--r--drivers/scsi/be2iscsi/be_main.c3390
-rw-r--r--drivers/scsi/be2iscsi/be_main.h837
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c321
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.h249
-rw-r--r--drivers/scsi/bfa/Makefile15
-rw-r--r--drivers/scsi/bfa/bfa_callback_priv.h57
-rw-r--r--drivers/scsi/bfa/bfa_cb_ioim_macros.h205
-rw-r--r--drivers/scsi/bfa/bfa_cee.c492
-rw-r--r--drivers/scsi/bfa/bfa_core.c402
-rw-r--r--drivers/scsi/bfa/bfa_csdebug.c58
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.c175
-rw-r--r--drivers/scsi/bfa/bfa_fcpim_priv.h188
-rw-r--r--drivers/scsi/bfa/bfa_fcport.c1671
-rw-r--r--drivers/scsi/bfa/bfa_fcs.c182
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c940
-rw-r--r--drivers/scsi/bfa/bfa_fcs_port.c68
-rw-r--r--drivers/scsi/bfa/bfa_fcs_uf.c105
-rw-r--r--drivers/scsi/bfa/bfa_fcxp.c782
-rw-r--r--drivers/scsi/bfa/bfa_fcxp_priv.h138
-rw-r--r--drivers/scsi/bfa/bfa_fwimg_priv.h31
-rw-r--r--drivers/scsi/bfa/bfa_hw_cb.c142
-rw-r--r--drivers/scsi/bfa/bfa_hw_ct.c162
-rw-r--r--drivers/scsi/bfa/bfa_intr.c218
-rw-r--r--drivers/scsi/bfa/bfa_intr_priv.h115
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c2382
-rw-r--r--drivers/scsi/bfa/bfa_ioc.h259
-rw-r--r--drivers/scsi/bfa/bfa_iocfc.c872
-rw-r--r--drivers/scsi/bfa/bfa_iocfc.h168
-rw-r--r--drivers/scsi/bfa/bfa_iocfc_q.c44
-rw-r--r--drivers/scsi/bfa/bfa_ioim.c1311
-rw-r--r--drivers/scsi/bfa/bfa_itnim.c1088
-rw-r--r--drivers/scsi/bfa/bfa_log.c346
-rw-r--r--drivers/scsi/bfa/bfa_log_module.c451
-rw-r--r--drivers/scsi/bfa/bfa_lps.c782
-rw-r--r--drivers/scsi/bfa/bfa_lps_priv.h38
-rw-r--r--drivers/scsi/bfa/bfa_module.c90
-rw-r--r--drivers/scsi/bfa/bfa_modules_priv.h43
-rw-r--r--drivers/scsi/bfa/bfa_os_inc.h222
-rw-r--r--drivers/scsi/bfa/bfa_port.c460
-rw-r--r--drivers/scsi/bfa/bfa_port_priv.h90
-rw-r--r--drivers/scsi/bfa/bfa_priv.h113
-rw-r--r--drivers/scsi/bfa/bfa_rport.c911
-rw-r--r--drivers/scsi/bfa/bfa_rport_priv.h45
-rw-r--r--drivers/scsi/bfa/bfa_sgpg.c231
-rw-r--r--drivers/scsi/bfa/bfa_sgpg_priv.h79
-rw-r--r--drivers/scsi/bfa/bfa_sm.c38
-rw-r--r--drivers/scsi/bfa/bfa_timer.c90
-rw-r--r--drivers/scsi/bfa/bfa_trcmod_priv.h66
-rw-r--r--drivers/scsi/bfa/bfa_tskim.c689
-rw-r--r--drivers/scsi/bfa/bfa_uf.c345
-rw-r--r--drivers/scsi/bfa/bfa_uf_priv.h47
-rw-r--r--drivers/scsi/bfa/bfad.c1182
-rw-r--r--drivers/scsi/bfa/bfad_attr.c649
-rw-r--r--drivers/scsi/bfa/bfad_attr.h65
-rw-r--r--drivers/scsi/bfa/bfad_drv.h295
-rw-r--r--drivers/scsi/bfa/bfad_fwimg.c97
-rw-r--r--drivers/scsi/bfa/bfad_im.c1230
-rw-r--r--drivers/scsi/bfa/bfad_im.h150
-rw-r--r--drivers/scsi/bfa/bfad_im_compat.h46
-rw-r--r--drivers/scsi/bfa/bfad_intr.c214
-rw-r--r--drivers/scsi/bfa/bfad_ipfc.h42
-rw-r--r--drivers/scsi/bfa/bfad_os.c50
-rw-r--r--drivers/scsi/bfa/bfad_tm.h59
-rw-r--r--drivers/scsi/bfa/bfad_trcmod.h52
-rw-r--r--drivers/scsi/bfa/fab.c62
-rw-r--r--drivers/scsi/bfa/fabric.c1278
-rw-r--r--drivers/scsi/bfa/fcbuild.c1449
-rw-r--r--drivers/scsi/bfa/fcbuild.h273
-rw-r--r--drivers/scsi/bfa/fcpim.c844
-rw-r--r--drivers/scsi/bfa/fcptm.c68
-rw-r--r--drivers/scsi/bfa/fcs.h30
-rw-r--r--drivers/scsi/bfa/fcs_auth.h37
-rw-r--r--drivers/scsi/bfa/fcs_fabric.h61
-rw-r--r--drivers/scsi/bfa/fcs_fcpim.h44
-rw-r--r--drivers/scsi/bfa/fcs_fcptm.h45
-rw-r--r--drivers/scsi/bfa/fcs_fcxp.h29
-rw-r--r--drivers/scsi/bfa/fcs_lport.h117
-rw-r--r--drivers/scsi/bfa/fcs_ms.h35
-rw-r--r--drivers/scsi/bfa/fcs_port.h32
-rw-r--r--drivers/scsi/bfa/fcs_rport.h61
-rw-r--r--drivers/scsi/bfa/fcs_trcmod.h56
-rw-r--r--drivers/scsi/bfa/fcs_uf.h32
-rw-r--r--drivers/scsi/bfa/fcs_vport.h39
-rw-r--r--drivers/scsi/bfa/fdmi.c1223
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen.h92
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_adapter.h31
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_audit.h31
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_ethport.h35
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_ioc.h37
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_itnim.h33
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_lport.h51
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_port.h57
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_rport.h37
-rw-r--r--drivers/scsi/bfa/include/bfa.h177
-rw-r--r--drivers/scsi/bfa/include/bfa_fcpim.h159
-rw-r--r--drivers/scsi/bfa/include/bfa_fcptm.h47
-rw-r--r--drivers/scsi/bfa/include/bfa_svc.h324
-rw-r--r--drivers/scsi/bfa/include/bfa_timer.h53
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi.h174
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_boot.h34
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_cbreg.h305
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_cee.h119
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_ctreg.h611
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_fabric.h92
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_fcpim.h301
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_fcxp.h71
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_ioc.h202
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_iocfc.h177
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_lport.h89
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_lps.h96
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_port.h115
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_pport.h184
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_rport.h104
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_uf.h52
-rw-r--r--drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h36
-rw-r--r--drivers/scsi/bfa/include/cna/cee/bfa_cee.h77
-rw-r--r--drivers/scsi/bfa/include/cna/port/bfa_port.h69
-rw-r--r--drivers/scsi/bfa/include/cna/pstats/ethport_defs.h36
-rw-r--r--drivers/scsi/bfa/include/cna/pstats/phyport_defs.h218
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_checksum.h60
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_debug.h44
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_log.h184
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_perf.h34
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_plog.h162
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_q.h81
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_sm.h69
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_trc.h176
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_wc.h68
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_adapter.h82
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_aen.h73
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_audit.h38
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_auth.h112
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_boot.h71
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_cee.h159
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_driver.h40
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_ethport.h98
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_fcpim.h45
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_im_common.h32
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_im_team.h72
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_ioc.h152
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h310
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_ipfc.h70
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_itnim.h126
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_led.h35
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_lport.h68
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_mfg.h58
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_pci.h41
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_pm.h33
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_pom.h56
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_port.h245
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_pport.h383
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_qos.h99
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_rport.h199
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_status.h255
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_tin.h118
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h43
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_types.h30
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_version.h22
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_vf.h74
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_vport.h91
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb.h33
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h76
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_port.h113
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_rport.h80
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_vf.h47
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h47
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs.h73
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_auth.h82
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h112
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h131
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_fdmi.h63
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h226
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h104
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h63
-rw-r--r--drivers/scsi/bfa/include/log/bfa_log_fcs.h28
-rw-r--r--drivers/scsi/bfa/include/log/bfa_log_hal.h30
-rw-r--r--drivers/scsi/bfa/include/log/bfa_log_linux.h44
-rw-r--r--drivers/scsi/bfa/include/log/bfa_log_wdrv.h36
-rw-r--r--drivers/scsi/bfa/include/protocol/ct.h492
-rw-r--r--drivers/scsi/bfa/include/protocol/fc.h1105
-rw-r--r--drivers/scsi/bfa/include/protocol/fc_sp.h224
-rw-r--r--drivers/scsi/bfa/include/protocol/fcp.h186
-rw-r--r--drivers/scsi/bfa/include/protocol/fdmi.h163
-rw-r--r--drivers/scsi/bfa/include/protocol/pcifw.h75
-rw-r--r--drivers/scsi/bfa/include/protocol/scsi.h1648
-rw-r--r--drivers/scsi/bfa/include/protocol/types.h42
-rw-r--r--drivers/scsi/bfa/loop.c422
-rw-r--r--drivers/scsi/bfa/lport_api.c291
-rw-r--r--drivers/scsi/bfa/lport_priv.h82
-rw-r--r--drivers/scsi/bfa/ms.c759
-rw-r--r--drivers/scsi/bfa/n2n.c105
-rw-r--r--drivers/scsi/bfa/ns.c1243
-rw-r--r--drivers/scsi/bfa/plog.c184
-rw-r--r--drivers/scsi/bfa/rport.c2618
-rw-r--r--drivers/scsi/bfa/rport_api.c180
-rw-r--r--drivers/scsi/bfa/rport_ftrs.c375
-rw-r--r--drivers/scsi/bfa/scn.c482
-rw-r--r--drivers/scsi/bfa/vfapi.c292
-rw-r--r--drivers/scsi/bfa/vport.c891
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c4
-rw-r--r--drivers/scsi/bnx2i/bnx2i_init.c100
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c15
-rw-r--r--drivers/scsi/ch.c6
-rw-r--r--drivers/scsi/constants.c95
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_iscsi.c2
-rw-r--r--drivers/scsi/device_handler/scsi_dh.c56
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c2
-rw-r--r--drivers/scsi/device_handler/scsi_dh_emc.c59
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c118
-rw-r--r--drivers/scsi/dpt_i2o.c4
-rw-r--r--drivers/scsi/fcoe/fcoe.c1078
-rw-r--r--drivers/scsi/fcoe/fcoe.h36
-rw-r--r--drivers/scsi/fcoe/libfcoe.c31
-rw-r--r--drivers/scsi/fnic/fnic_fcs.c2
-rw-r--r--drivers/scsi/fnic/fnic_main.c20
-rw-r--r--drivers/scsi/gdth.c2
-rw-r--r--drivers/scsi/hosts.c2
-rw-r--r--drivers/scsi/hptiop.c37
-rw-r--r--drivers/scsi/hptiop.h3
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c1
-rw-r--r--drivers/scsi/ipr.c42
-rw-r--r--drivers/scsi/ipr.h3
-rw-r--r--drivers/scsi/iscsi_tcp.c33
-rw-r--r--drivers/scsi/libfc/fc_disc.c523
-rw-r--r--drivers/scsi/libfc/fc_elsct.c49
-rw-r--r--drivers/scsi/libfc/fc_exch.c515
-rw-r--r--drivers/scsi/libfc/fc_fcp.c31
-rw-r--r--drivers/scsi/libfc/fc_lport.c283
-rw-r--r--drivers/scsi/libfc/fc_rport.c1144
-rw-r--r--drivers/scsi/libiscsi.c207
-rw-r--r--drivers/scsi/libsas/sas_expander.c1
-rw-r--r--drivers/scsi/libsrp.c1
-rw-r--r--drivers/scsi/lpfc/Makefile2
-rw-r--r--drivers/scsi/lpfc/lpfc.h19
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c10
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c904
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h18
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c4
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c259
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h74
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c134
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c93
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c41
-rw-r--r--drivers/scsi/lpfc/lpfc_nl.h20
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c22
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c263
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h5
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c53
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c2
-rw-r--r--drivers/scsi/mpt2sas/Kconfig2
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h103
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h200
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_history.txt334
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_init.h18
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_ioc.h65
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_tool.h134
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c540
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h153
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_config.c926
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c77
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.h2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_debug.h2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c820
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c59
-rw-r--r--drivers/scsi/mvsas/mv_defs.h4
-rw-r--r--drivers/scsi/mvsas/mv_init.c4
-rw-r--r--drivers/scsi/pcmcia/aha152x_stub.c42
-rw-r--r--drivers/scsi/pcmcia/fdomain_stub.c44
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c10
-rw-r--r--drivers/scsi/pcmcia/qlogic_stub.c45
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c42
-rw-r--r--drivers/scsi/pmcraid.c5608
-rw-r--r--drivers/scsi/pmcraid.h1028
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c9
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h39
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h20
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c239
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c206
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c309
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c33
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c141
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c8
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c4
-rw-r--r--drivers/scsi/scsi.c24
-rw-r--r--drivers/scsi/scsi_debug.c139
-rw-r--r--drivers/scsi/scsi_error.c9
-rw-r--r--drivers/scsi/scsi_lib.c7
-rw-r--r--drivers/scsi/scsi_priv.h2
-rw-r--r--drivers/scsi/scsi_scan.c18
-rw-r--r--drivers/scsi/scsi_sysfs.c72
-rw-r--r--drivers/scsi/scsi_transport_fc.c9
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c73
-rw-r--r--drivers/scsi/scsi_transport_sas.c4
-rw-r--r--drivers/scsi/sd.c144
-rw-r--r--drivers/scsi/sd.h9
-rw-r--r--drivers/scsi/sd_dif.c67
-rw-r--r--drivers/scsi/ses.c209
-rw-r--r--drivers/scsi/sg.c63
-rw-r--r--drivers/scsi/sr.c24
-rw-r--r--drivers/scsi/st.c3
-rw-r--r--drivers/scsi/stex.c33
-rw-r--r--drivers/serial/21285.c8
-rw-r--r--drivers/serial/8250.c37
-rw-r--r--drivers/serial/8250.h1
-rw-r--r--drivers/serial/8250_pci.c86
-rw-r--r--drivers/serial/Kconfig30
-rw-r--r--drivers/serial/Makefile2
-rw-r--r--drivers/serial/amba-pl010.c6
-rw-r--r--drivers/serial/amba-pl011.c32
-rw-r--r--drivers/serial/atmel_serial.c16
-rw-r--r--drivers/serial/bcm63xx_uart.c890
-rw-r--r--drivers/serial/bfin_5xx.c24
-rw-r--r--drivers/serial/bfin_sport_uart.c6
-rw-r--r--drivers/serial/clps711x.c4
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c4
-rw-r--r--drivers/serial/crisv10.c1
-rw-r--r--drivers/serial/dz.c6
-rw-r--r--drivers/serial/icom.c74
-rw-r--r--drivers/serial/imx.c81
-rw-r--r--drivers/serial/ioc3_serial.c54
-rw-r--r--drivers/serial/ioc4_serial.c70
-rw-r--r--drivers/serial/ip22zilog.c14
-rw-r--r--drivers/serial/jsm/jsm_neo.c2
-rw-r--r--drivers/serial/jsm/jsm_tty.c20
-rw-r--r--drivers/serial/m32r_sio.c6
-rw-r--r--drivers/serial/max3100.c17
-rw-r--r--drivers/serial/mcf.c4
-rw-r--r--drivers/serial/mpc52xx_uart.c6
-rw-r--r--drivers/serial/mpsc.c4
-rw-r--r--drivers/serial/msm_serial.c6
-rw-r--r--drivers/serial/mux.c4
-rw-r--r--drivers/serial/netx-serial.c6
-rw-r--r--drivers/serial/nwpserial.c4
-rw-r--r--drivers/serial/of_serial.c1
-rw-r--r--drivers/serial/pmac_zilog.c20
-rw-r--r--drivers/serial/pnx8xxx_uart.c8
-rw-r--r--drivers/serial/pxa.c26
-rw-r--r--drivers/serial/sa1100.c10
-rw-r--r--drivers/serial/samsung.c8
-rw-r--r--drivers/serial/sb1250-duart.c6
-rw-r--r--drivers/serial/sc26xx.c10
-rw-r--r--drivers/serial/serial_core.c883
-rw-r--r--drivers/serial/serial_cs.c176
-rw-r--r--drivers/serial/serial_ks8695.c12
-rw-r--r--drivers/serial/serial_lh7a40x.c6
-rw-r--r--drivers/serial/serial_txx9.c43
-rw-r--r--drivers/serial/sh-sci.c20
-rw-r--r--drivers/serial/sh-sci.h17
-rw-r--r--drivers/serial/sn_console.c22
-rw-r--r--drivers/serial/suncore.c37
-rw-r--r--drivers/serial/suncore.h5
-rw-r--r--drivers/serial/sunhv.c10
-rw-r--r--drivers/serial/sunsab.c19
-rw-r--r--drivers/serial/sunsu.c42
-rw-r--r--drivers/serial/sunzilog.c22
-rw-r--r--drivers/serial/timbuart.c10
-rw-r--r--drivers/serial/uartlite.c19
-rw-r--r--drivers/serial/ucc_uart.c4
-rw-r--r--drivers/serial/vr41xx_siu.c6
-rw-r--r--drivers/serial/zs.c6
-rw-r--r--drivers/sfi/Kconfig17
-rw-r--r--drivers/sfi/Makefile3
-rw-r--r--drivers/sfi/sfi_acpi.c175
-rw-r--r--drivers/sfi/sfi_core.c416
-rw-r--r--drivers/sfi/sfi_core.h70
-rw-r--r--drivers/sh/intc.c71
-rw-r--r--drivers/spi/Kconfig23
-rw-r--r--drivers/spi/Makefile2
-rw-r--r--drivers/spi/amba-pl022.c12
-rw-r--r--drivers/spi/omap2_mcspi.c210
-rw-r--r--drivers/spi/omap_uwire.c2
-rw-r--r--drivers/spi/pxa2xx_spi.c32
-rw-r--r--drivers/spi/spi.c85
-rw-r--r--drivers/spi/spi_imx.c2060
-rw-r--r--drivers/spi/spi_ppc4xx.c612
-rw-r--r--drivers/spi/spi_s3c24xx.c159
-rw-r--r--drivers/spi/spi_stmp.c679
-rw-r--r--drivers/spi/spi_txx9.c13
-rw-r--r--drivers/spi/spidev.c3
-rw-r--r--drivers/spi/tle62x0.c1
-rw-r--r--drivers/ssb/Kconfig14
-rw-r--r--drivers/ssb/Makefile1
-rw-r--r--drivers/ssb/driver_chipcommon_pmu.c94
-rw-r--r--drivers/ssb/main.c64
-rw-r--r--drivers/ssb/pci.c56
-rw-r--r--drivers/ssb/pcmcia.c232
-rw-r--r--drivers/ssb/scan.c17
-rw-r--r--drivers/ssb/sdio.c610
-rw-r--r--drivers/ssb/ssb_private.h40
-rw-r--r--drivers/staging/Kconfig40
-rw-r--r--drivers/staging/Makefile23
-rw-r--r--drivers/staging/agnx/Kconfig5
-rw-r--r--drivers/staging/agnx/Makefile8
-rw-r--r--drivers/staging/agnx/TODO22
-rw-r--r--drivers/staging/agnx/agnx.h156
-rw-r--r--drivers/staging/agnx/debug.h416
-rw-r--r--drivers/staging/agnx/pci.c635
-rw-r--r--drivers/staging/agnx/phy.c960
-rw-r--r--drivers/staging/agnx/phy.h409
-rw-r--r--drivers/staging/agnx/rf.c893
-rw-r--r--drivers/staging/agnx/sta.c218
-rw-r--r--drivers/staging/agnx/sta.h222
-rw-r--r--drivers/staging/agnx/table.c168
-rw-r--r--drivers/staging/agnx/table.h10
-rw-r--r--drivers/staging/agnx/xmit.c835
-rw-r--r--drivers/staging/agnx/xmit.h250
-rw-r--r--drivers/staging/altpciechdma/altpciechdma.c2
-rw-r--r--drivers/staging/android/Kconfig1
-rw-r--r--drivers/staging/android/binder.c713
-rw-r--r--drivers/staging/android/lowmemorykiller.c41
-rw-r--r--drivers/staging/android/lowmemorykiller.txt16
-rw-r--r--drivers/staging/asus_oled/asus_oled.c404
-rw-r--r--drivers/staging/at76_usb/Kconfig8
-rw-r--r--drivers/staging/at76_usb/Makefile1
-rw-r--r--drivers/staging/at76_usb/TODO7
-rw-r--r--drivers/staging/at76_usb/at76_usb.c5579
-rw-r--r--drivers/staging/at76_usb/at76_usb.h706
-rw-r--r--drivers/staging/b3dfg/b3dfg.c42
-rw-r--r--drivers/staging/comedi/Kconfig2
-rw-r--r--drivers/staging/comedi/comedi.h1002
-rw-r--r--drivers/staging/comedi/comedi_compat32.c115
-rw-r--r--drivers/staging/comedi/comedi_compat32.h4
-rw-r--r--drivers/staging/comedi/comedi_fops.c280
-rw-r--r--drivers/staging/comedi/comedi_ksyms.c3
-rw-r--r--drivers/staging/comedi/comedidev.h85
-rw-r--r--drivers/staging/comedi/comedilib.h77
-rw-r--r--drivers/staging/comedi/drivers.c184
-rw-r--r--drivers/staging/comedi/drivers/8253.h69
-rw-r--r--drivers/staging/comedi/drivers/8255.c54
-rw-r--r--drivers/staging/comedi/drivers/8255.h16
-rw-r--r--drivers/staging/comedi/drivers/acl7225b.c22
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h3
-rw-r--r--drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h3
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c2
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c93
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7296.c39
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7432.c57
-rw-r--r--drivers/staging/comedi/drivers/adl_pci8164.c126
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9111.c361
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c532
-rw-r--r--drivers/staging/comedi/drivers/adq12b.c371
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c417
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1723.c73
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c306
-rw-r--r--drivers/staging/comedi/drivers/aio_aio12_8.c36
-rw-r--r--drivers/staging/comedi/drivers/aio_iiro_16.c30
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.c314
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc236.c118
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc263.c101
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c260
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c497
-rw-r--r--drivers/staging/comedi/drivers/c6xdigio.c42
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c385
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c671
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c1788
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c218
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidio.c82
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c89
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdda.c61
-rw-r--r--drivers/staging/comedi/drivers/comedi_bond.c56
-rw-r--r--drivers/staging/comedi/drivers/comedi_fc.c14
-rw-r--r--drivers/staging/comedi/drivers/comedi_fc.h4
-rw-r--r--drivers/staging/comedi/drivers/comedi_parport.c29
-rw-r--r--drivers/staging/comedi/drivers/comedi_test.c143
-rw-r--r--drivers/staging/comedi/drivers/contec_pci_dio.c48
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c119
-rw-r--r--drivers/staging/comedi/drivers/das08.c622
-rw-r--r--drivers/staging/comedi/drivers/das08.h3
-rw-r--r--drivers/staging/comedi/drivers/das08_cs.c222
-rw-r--r--drivers/staging/comedi/drivers/das16.c828
-rw-r--r--drivers/staging/comedi/drivers/das16m1.c132
-rw-r--r--drivers/staging/comedi/drivers/das1800.c658
-rw-r--r--drivers/staging/comedi/drivers/das6402.c23
-rw-r--r--drivers/staging/comedi/drivers/das800.c224
-rw-r--r--drivers/staging/comedi/drivers/dmm32at.c144
-rw-r--r--drivers/staging/comedi/drivers/dt2801.c242
-rw-r--r--drivers/staging/comedi/drivers/dt2811.c178
-rw-r--r--drivers/staging/comedi/drivers/dt2814.c16
-rw-r--r--drivers/staging/comedi/drivers/dt2815.c38
-rw-r--r--drivers/staging/comedi/drivers/dt2817.c19
-rw-r--r--drivers/staging/comedi/drivers/dt282x.c264
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c145
-rw-r--r--drivers/staging/comedi/drivers/dt9812.c85
-rw-r--r--drivers/staging/comedi/drivers/fl512.c37
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c236
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.c198
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.h74
-rw-r--r--drivers/staging/comedi/drivers/ii_pci20kc.c127
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c308
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.h40
-rw-r--r--drivers/staging/comedi/drivers/ke_counter.c67
-rw-r--r--drivers/staging/comedi/drivers/me4000.c881
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c219
-rw-r--r--drivers/staging/comedi/drivers/mite.c138
-rw-r--r--drivers/staging/comedi/drivers/mite.h144
-rw-r--r--drivers/staging/comedi/drivers/mpc624.c48
-rw-r--r--drivers/staging/comedi/drivers/mpc8260cpm.c26
-rw-r--r--drivers/staging/comedi/drivers/multiq3.c45
-rw-r--r--drivers/staging/comedi/drivers/ni_6527.c109
-rw-r--r--drivers/staging/comedi/drivers/ni_65xx.c410
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c293
-rw-r--r--drivers/staging/comedi/drivers/ni_670x.c101
-rw-r--r--drivers/staging/comedi/drivers/ni_at_a2150.c93
-rw-r--r--drivers/staging/comedi/drivers/ni_at_ao.c69
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio.c318
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio16d.c128
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_700.c311
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_dio24.c275
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c452
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.h5
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_cs.c289
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c1663
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_cs.c159
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c344
-rw-r--r--drivers/staging/comedi/drivers/ni_pcimio.c2087
-rw-r--r--drivers/staging/comedi/drivers/ni_stc.h64
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.c475
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.h47
-rw-r--r--drivers/staging/comedi/drivers/ni_tio_internal.h58
-rw-r--r--drivers/staging/comedi/drivers/ni_tiocmd.c105
-rw-r--r--drivers/staging/comedi/drivers/pcl711.c107
-rw-r--r--drivers/staging/comedi/drivers/pcl724.c33
-rw-r--r--drivers/staging/comedi/drivers/pcl725.c7
-rw-r--r--drivers/staging/comedi/drivers/pcl726.c59
-rw-r--r--drivers/staging/comedi/drivers/pcl730.c16
-rw-r--r--drivers/staging/comedi/drivers/pcl812.c480
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c220
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c338
-rw-r--r--drivers/staging/comedi/drivers/pcm3724.c28
-rw-r--r--drivers/staging/comedi/drivers/pcm3730.c16
-rw-r--r--drivers/staging/comedi/drivers/pcmad.c19
-rw-r--r--drivers/staging/comedi/drivers/pcmda12.c25
-rw-r--r--drivers/staging/comedi/drivers/pcmmio.c287
-rw-r--r--drivers/staging/comedi/drivers/pcmuio.c228
-rw-r--r--drivers/staging/comedi/drivers/plx9080.h8
-rw-r--r--drivers/staging/comedi/drivers/poc.c104
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c328
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c487
-rw-r--r--drivers/staging/comedi/drivers/rti800.c83
-rw-r--r--drivers/staging/comedi/drivers/rti802.c21
-rw-r--r--drivers/staging/comedi/drivers/s526.c304
-rw-r--r--drivers/staging/comedi/drivers/s626.c1019
-rw-r--r--drivers/staging/comedi/drivers/s626.h16
-rw-r--r--drivers/staging/comedi/drivers/serial2002.c202
-rw-r--r--drivers/staging/comedi/drivers/skel.c82
-rw-r--r--drivers/staging/comedi/drivers/ssv_dnp.c40
-rw-r--r--drivers/staging/comedi/drivers/unioxx5.c106
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c268
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c459
-rw-r--r--drivers/staging/comedi/drivers/vmk80xx.c135
-rw-r--r--drivers/staging/comedi/kcomedilib/data.c12
-rw-r--r--drivers/staging/comedi/kcomedilib/dio.c8
-rw-r--r--drivers/staging/comedi/kcomedilib/get.c55
-rw-r--r--drivers/staging/comedi/kcomedilib/kcomedilib_main.c35
-rw-r--r--drivers/staging/comedi/kcomedilib/ksyms.c4
-rw-r--r--drivers/staging/comedi/proc.c23
-rw-r--r--drivers/staging/comedi/range.c21
-rw-r--r--drivers/staging/cpc-usb/Kconfig4
-rw-r--r--drivers/staging/cpc-usb/Makefile3
-rw-r--r--drivers/staging/cpc-usb/TODO9
-rw-r--r--drivers/staging/cpc-usb/cpc-usb_drv.c1185
-rw-r--r--drivers/staging/cpc-usb/cpc.h440
-rw-r--r--drivers/staging/cpc-usb/cpc_int.h83
-rw-r--r--drivers/staging/cpc-usb/cpcusb.h86
-rw-r--r--drivers/staging/cpc-usb/sja2m16c.h41
-rw-r--r--drivers/staging/cpc-usb/sja2m16c_2.c452
-rw-r--r--drivers/staging/cx25821/Kconfig34
-rw-r--r--drivers/staging/cx25821/Makefile14
-rw-r--r--drivers/staging/cx25821/README6
-rw-r--r--drivers/staging/cx25821/cx25821-alsa.c789
-rw-r--r--drivers/staging/cx25821/cx25821-audio-upstream.c804
-rw-r--r--drivers/staging/cx25821/cx25821-audio-upstream.h57
-rw-r--r--drivers/staging/cx25821/cx25821-audio.h57
-rw-r--r--drivers/staging/cx25821/cx25821-audups11.c434
-rw-r--r--drivers/staging/cx25821/cx25821-biffuncs.h45
-rw-r--r--drivers/staging/cx25821/cx25821-cards.c70
-rw-r--r--drivers/staging/cx25821/cx25821-core.c1551
-rw-r--r--drivers/staging/cx25821/cx25821-gpio.c98
-rw-r--r--drivers/staging/cx25821/cx25821-gpio.h2
-rw-r--r--drivers/staging/cx25821/cx25821-i2c.c419
-rw-r--r--drivers/staging/cx25821/cx25821-medusa-defines.h51
-rw-r--r--drivers/staging/cx25821/cx25821-medusa-reg.h455
-rw-r--r--drivers/staging/cx25821/cx25821-medusa-video.c869
-rw-r--r--drivers/staging/cx25821/cx25821-medusa-video.h49
-rw-r--r--drivers/staging/cx25821/cx25821-reg.h1592
-rw-r--r--drivers/staging/cx25821/cx25821-sram.h261
-rw-r--r--drivers/staging/cx25821/cx25821-video-upstream-ch2.c835
-rw-r--r--drivers/staging/cx25821/cx25821-video-upstream-ch2.h101
-rw-r--r--drivers/staging/cx25821/cx25821-video-upstream.c894
-rw-r--r--drivers/staging/cx25821/cx25821-video-upstream.h109
-rw-r--r--drivers/staging/cx25821/cx25821-video.c1299
-rw-r--r--drivers/staging/cx25821/cx25821-video.h194
-rw-r--r--drivers/staging/cx25821/cx25821-video0.c451
-rw-r--r--drivers/staging/cx25821/cx25821-video1.c451
-rw-r--r--drivers/staging/cx25821/cx25821-video2.c452
-rw-r--r--drivers/staging/cx25821/cx25821-video3.c451
-rw-r--r--drivers/staging/cx25821/cx25821-video4.c450
-rw-r--r--drivers/staging/cx25821/cx25821-video5.c450
-rw-r--r--drivers/staging/cx25821/cx25821-video6.c450
-rw-r--r--drivers/staging/cx25821/cx25821-video7.c449
-rw-r--r--drivers/staging/cx25821/cx25821-videoioctl.c496
-rw-r--r--drivers/staging/cx25821/cx25821-vidups10.c435
-rw-r--r--drivers/staging/cx25821/cx25821-vidups9.c433
-rw-r--r--drivers/staging/cx25821/cx25821.h602
-rw-r--r--drivers/staging/dream/Kconfig12
-rw-r--r--drivers/staging/dream/Makefile4
-rw-r--r--drivers/staging/dream/camera/Kconfig46
-rw-r--r--drivers/staging/dream/camera/Makefile7
-rw-r--r--drivers/staging/dream/camera/msm_camera.c2181
-rw-r--r--drivers/staging/dream/camera/msm_io7x.c291
-rw-r--r--drivers/staging/dream/camera/msm_io8x.c320
-rw-r--r--drivers/staging/dream/camera/msm_v4l2.c797
-rw-r--r--drivers/staging/dream/camera/msm_vfe7x.c701
-rw-r--r--drivers/staging/dream/camera/msm_vfe7x.h255
-rw-r--r--drivers/staging/dream/camera/msm_vfe8x.c756
-rw-r--r--drivers/staging/dream/camera/msm_vfe8x.h895
-rw-r--r--drivers/staging/dream/camera/msm_vfe8x_proc.c4003
-rw-r--r--drivers/staging/dream/camera/msm_vfe8x_proc.h1549
-rw-r--r--drivers/staging/dream/camera/mt9d112.c761
-rw-r--r--drivers/staging/dream/camera/mt9d112.h36
-rw-r--r--drivers/staging/dream/camera/mt9d112_reg.c307
-rw-r--r--drivers/staging/dream/camera/mt9p012.h51
-rw-r--r--drivers/staging/dream/camera/mt9p012_fox.c1305
-rw-r--r--drivers/staging/dream/camera/mt9p012_reg.c573
-rw-r--r--drivers/staging/dream/camera/mt9t013.c1496
-rw-r--r--drivers/staging/dream/camera/mt9t013.h48
-rw-r--r--drivers/staging/dream/camera/mt9t013_reg.c266
-rw-r--r--drivers/staging/dream/camera/s5k3e2fx.c1310
-rw-r--r--drivers/staging/dream/camera/s5k3e2fx.h9
-rw-r--r--drivers/staging/dream/gpio_axis.c180
-rw-r--r--drivers/staging/dream/gpio_event.c224
-rw-r--r--drivers/staging/dream/gpio_input.c343
-rw-r--r--drivers/staging/dream/gpio_matrix.c406
-rw-r--r--drivers/staging/dream/gpio_output.c84
-rw-r--r--drivers/staging/dream/qdsp5/Makefile17
-rw-r--r--drivers/staging/dream/qdsp5/adsp.c1163
-rw-r--r--drivers/staging/dream/qdsp5/adsp.h369
-rw-r--r--drivers/staging/dream/qdsp5/adsp_6210.c283
-rw-r--r--drivers/staging/dream/qdsp5/adsp_6220.c284
-rw-r--r--drivers/staging/dream/qdsp5/adsp_6225.c328
-rw-r--r--drivers/staging/dream/qdsp5/adsp_driver.c641
-rw-r--r--drivers/staging/dream/qdsp5/adsp_info.c121
-rw-r--r--drivers/staging/dream/qdsp5/adsp_jpeg_patch_event.c31
-rw-r--r--drivers/staging/dream/qdsp5/adsp_jpeg_verify_cmd.c182
-rw-r--r--drivers/staging/dream/qdsp5/adsp_lpm_verify_cmd.c65
-rw-r--r--drivers/staging/dream/qdsp5/adsp_vfe_patch_event.c54
-rw-r--r--drivers/staging/dream/qdsp5/adsp_vfe_verify_cmd.c239
-rw-r--r--drivers/staging/dream/qdsp5/adsp_video_verify_cmd.c163
-rw-r--r--drivers/staging/dream/qdsp5/adsp_videoenc_verify_cmd.c235
-rw-r--r--drivers/staging/dream/qdsp5/audio_aac.c1052
-rw-r--r--drivers/staging/dream/qdsp5/audio_amrnb.c873
-rw-r--r--drivers/staging/dream/qdsp5/audio_evrc.c845
-rw-r--r--drivers/staging/dream/qdsp5/audio_in.c967
-rw-r--r--drivers/staging/dream/qdsp5/audio_mp3.c971
-rw-r--r--drivers/staging/dream/qdsp5/audio_out.c851
-rw-r--r--drivers/staging/dream/qdsp5/audio_qcelp.c856
-rw-r--r--drivers/staging/dream/qdsp5/audmgr.c313
-rw-r--r--drivers/staging/dream/qdsp5/audmgr.h215
-rw-r--r--drivers/staging/dream/qdsp5/audmgr_new.h213
-rw-r--r--drivers/staging/dream/qdsp5/audpp.c429
-rw-r--r--drivers/staging/dream/qdsp5/evlog.h133
-rw-r--r--drivers/staging/dream/qdsp5/snd.c279
-rw-r--r--drivers/staging/dream/smd/Kconfig26
-rw-r--r--drivers/staging/dream/smd/Makefile6
-rw-r--r--drivers/staging/dream/smd/rpc_server_dog_keepalive.c68
-rw-r--r--drivers/staging/dream/smd/rpc_server_time_remote.c77
-rw-r--r--drivers/staging/dream/smd/smd.c1330
-rw-r--r--drivers/staging/dream/smd/smd_private.h171
-rw-r--r--drivers/staging/dream/smd/smd_qmi.c860
-rw-r--r--drivers/staging/dream/smd/smd_rpcrouter.c1274
-rw-r--r--drivers/staging/dream/smd/smd_rpcrouter.h195
-rw-r--r--drivers/staging/dream/smd/smd_rpcrouter_device.c376
-rw-r--r--drivers/staging/dream/smd/smd_rpcrouter_servers.c229
-rw-r--r--drivers/staging/dream/smd/smd_tty.c213
-rw-r--r--drivers/staging/dream/synaptics_i2c_rmi.c658
-rw-r--r--drivers/staging/dream/synaptics_i2c_rmi.h53
-rw-r--r--drivers/staging/dst/dcore.c15
-rw-r--r--drivers/staging/dst/export.c2
-rw-r--r--drivers/staging/echo/TODO5
-rw-r--r--drivers/staging/echo/bit_operations.h226
-rw-r--r--drivers/staging/echo/echo.c190
-rw-r--r--drivers/staging/echo/echo.h15
-rw-r--r--drivers/staging/echo/fir.h109
-rw-r--r--drivers/staging/echo/mmx.h281
-rw-r--r--drivers/staging/echo/oslec.h70
-rw-r--r--drivers/staging/epl/Benchmark.h425
-rw-r--r--drivers/staging/epl/Debug.h694
-rw-r--r--drivers/staging/epl/Edrv8139.c1246
-rw-r--r--drivers/staging/epl/EdrvFec.h114
-rw-r--r--drivers/staging/epl/EdrvSim.h89
-rw-r--r--drivers/staging/epl/Epl.h272
-rw-r--r--drivers/staging/epl/EplAmi.h323
-rw-r--r--drivers/staging/epl/EplApiGeneric.c2054
-rw-r--r--drivers/staging/epl/EplApiLinux.h141
-rw-r--r--drivers/staging/epl/EplApiLinuxKernel.c1173
-rw-r--r--drivers/staging/epl/EplApiProcessImage.c328
-rw-r--r--drivers/staging/epl/EplCfg.h196
-rw-r--r--drivers/staging/epl/EplDef.h355
-rw-r--r--drivers/staging/epl/EplDll.h205
-rw-r--r--drivers/staging/epl/EplDllCal.h123
-rw-r--r--drivers/staging/epl/EplDllk.c4052
-rw-r--r--drivers/staging/epl/EplDllkCal.c1260
-rw-r--r--drivers/staging/epl/EplDlluCal.c529
-rw-r--r--drivers/staging/epl/EplErrDef.h294
-rw-r--r--drivers/staging/epl/EplErrorHandlerk.c810
-rw-r--r--drivers/staging/epl/EplEvent.h279
-rw-r--r--drivers/staging/epl/EplEventk.c853
-rw-r--r--drivers/staging/epl/EplEventu.c813
-rw-r--r--drivers/staging/epl/EplFrame.h344
-rw-r--r--drivers/staging/epl/EplIdentu.c486
-rw-r--r--drivers/staging/epl/EplInc.h370
-rw-r--r--drivers/staging/epl/EplInstDef.h363
-rw-r--r--drivers/staging/epl/EplLed.h92
-rw-r--r--drivers/staging/epl/EplNmt.h230
-rw-r--r--drivers/staging/epl/EplNmtCnu.c701
-rw-r--r--drivers/staging/epl/EplNmtMnu.c2828
-rw-r--r--drivers/staging/epl/EplNmtk.c1840
-rw-r--r--drivers/staging/epl/EplNmtkCal.c147
-rw-r--r--drivers/staging/epl/EplNmtu.c706
-rw-r--r--drivers/staging/epl/EplNmtuCal.c158
-rw-r--r--drivers/staging/epl/EplObd.c3192
-rw-r--r--drivers/staging/epl/EplObd.h456
-rw-r--r--drivers/staging/epl/EplObdMacro.h354
-rw-r--r--drivers/staging/epl/EplObdkCal.c146
-rw-r--r--drivers/staging/epl/EplObdu.c506
-rw-r--r--drivers/staging/epl/EplObduCal.c543
-rw-r--r--drivers/staging/epl/EplPdo.h117
-rw-r--r--drivers/staging/epl/EplPdok.c669
-rw-r--r--drivers/staging/epl/EplPdokCal.c266
-rw-r--r--drivers/staging/epl/EplPdou.c565
-rw-r--r--drivers/staging/epl/EplSdo.h241
-rw-r--r--drivers/staging/epl/EplSdoAc.h111
-rw-r--r--drivers/staging/epl/EplSdoAsndu.c483
-rw-r--r--drivers/staging/epl/EplSdoAsySequ.c2522
-rw-r--r--drivers/staging/epl/EplSdoComu.c3345
-rw-r--r--drivers/staging/epl/EplSdoUdpu.c650
-rw-r--r--drivers/staging/epl/EplStatusu.c377
-rw-r--r--drivers/staging/epl/EplTarget.h140
-rw-r--r--drivers/staging/epl/EplTimer.h116
-rw-r--r--drivers/staging/epl/EplTimeruLinuxKernel.c446
-rw-r--r--drivers/staging/epl/EplVersion.h98
-rw-r--r--drivers/staging/epl/Kconfig6
-rw-r--r--drivers/staging/epl/Makefile41
-rw-r--r--drivers/staging/epl/SharedBuff.c1762
-rw-r--r--drivers/staging/epl/SharedBuff.h187
-rw-r--r--drivers/staging/epl/ShbIpc-LinuxKernel.c944
-rw-r--r--drivers/staging/epl/ShbIpc.h99
-rw-r--r--drivers/staging/epl/ShbLinuxKernel.h68
-rw-r--r--drivers/staging/epl/SocketLinuxKernel.c197
-rw-r--r--drivers/staging/epl/SocketLinuxKernel.h105
-rw-r--r--drivers/staging/epl/TimerHighReskX86.c510
-rw-r--r--drivers/staging/epl/VirtualEthernetLinux.c348
-rw-r--r--drivers/staging/epl/amix86.c861
-rw-r--r--drivers/staging/epl/demo_main.c947
-rw-r--r--drivers/staging/epl/edrv.h167
-rw-r--r--drivers/staging/epl/global.h144
-rw-r--r--drivers/staging/epl/kernel/EplDllk.h153
-rw-r--r--drivers/staging/epl/kernel/EplDllkCal.h129
-rw-r--r--drivers/staging/epl/kernel/EplErrorHandlerk.h88
-rw-r--r--drivers/staging/epl/kernel/EplEventk.h96
-rw-r--r--drivers/staging/epl/kernel/EplNmtk.h90
-rw-r--r--drivers/staging/epl/kernel/EplObdk.h156
-rw-r--r--drivers/staging/epl/kernel/EplPdok.h98
-rw-r--r--drivers/staging/epl/kernel/EplPdokCal.h86
-rw-r--r--drivers/staging/epl/kernel/EplTimerHighResk.h96
-rw-r--r--drivers/staging/epl/kernel/EplTimerk.h108
-rw-r--r--drivers/staging/epl/kernel/VirtualEthernet.h84
-rw-r--r--drivers/staging/epl/proc_fs.c410
-rw-r--r--drivers/staging/epl/proc_fs.h89
-rw-r--r--drivers/staging/epl/user/EplCfgMau.h276
-rw-r--r--drivers/staging/epl/user/EplDllu.h96
-rw-r--r--drivers/staging/epl/user/EplDlluCal.h106
-rw-r--r--drivers/staging/epl/user/EplEventu.h96
-rw-r--r--drivers/staging/epl/user/EplIdentu.h94
-rw-r--r--drivers/staging/epl/user/EplLedu.h95
-rw-r--r--drivers/staging/epl/user/EplNmtCnu.h92
-rw-r--r--drivers/staging/epl/user/EplNmtMnu.h117
-rw-r--r--drivers/staging/epl/user/EplNmtu.h139
-rw-r--r--drivers/staging/epl/user/EplNmtuCal.h80
-rw-r--r--drivers/staging/epl/user/EplObdu.h169
-rw-r--r--drivers/staging/epl/user/EplObduCal.h126
-rw-r--r--drivers/staging/epl/user/EplPdou.h96
-rw-r--r--drivers/staging/epl/user/EplSdoAsndu.h96
-rw-r--r--drivers/staging/epl/user/EplSdoAsySequ.h100
-rw-r--r--drivers/staging/epl/user/EplSdoComu.h114
-rw-r--r--drivers/staging/epl/user/EplSdoUdpu.h97
-rw-r--r--drivers/staging/epl/user/EplStatusu.h90
-rw-r--r--drivers/staging/epl/user/EplTimeru.h95
-rw-r--r--drivers/staging/et131x/Makefile3
-rw-r--r--drivers/staging/et131x/et1310_address_map.h2304
-rw-r--r--drivers/staging/et131x/et1310_eeprom.c215
-rw-r--r--drivers/staging/et131x/et1310_eeprom.h22
-rw-r--r--drivers/staging/et131x/et1310_jagcore.c220
-rw-r--r--drivers/staging/et131x/et1310_jagcore.h36
-rw-r--r--drivers/staging/et131x/et1310_mac.c358
-rw-r--r--drivers/staging/et131x/et1310_mac.h8
-rw-r--r--drivers/staging/et131x/et1310_phy.c770
-rw-r--r--drivers/staging/et131x/et1310_phy.h941
-rw-r--r--drivers/staging/et131x/et1310_pm.c96
-rw-r--r--drivers/staging/et131x/et1310_pm.h46
-rw-r--r--drivers/staging/et131x/et1310_rx.c580
-rw-r--r--drivers/staging/et131x/et1310_rx.h198
-rw-r--r--drivers/staging/et131x/et1310_tx.c1067
-rw-r--r--drivers/staging/et131x/et1310_tx.h108
-rw-r--r--drivers/staging/et131x/et131x_adapter.h141
-rw-r--r--drivers/staging/et131x/et131x_config.c325
-rw-r--r--drivers/staging/et131x/et131x_debug.c217
-rw-r--r--drivers/staging/et131x/et131x_debug.h255
-rw-r--r--drivers/staging/et131x/et131x_defs.h28
-rw-r--r--drivers/staging/et131x/et131x_initpci.c726
-rw-r--r--drivers/staging/et131x/et131x_initpci.h6
-rw-r--r--drivers/staging/et131x/et131x_isr.c240
-rw-r--r--drivers/staging/et131x/et131x_isr.h6
-rw-r--r--drivers/staging/et131x/et131x_netdev.c327
-rw-r--r--drivers/staging/et131x/et131x_netdev.h6
-rw-r--r--drivers/staging/et131x/et131x_version.h6
-rw-r--r--drivers/staging/go7007/Kconfig84
-rw-r--r--drivers/staging/go7007/Makefile15
-rw-r--r--drivers/staging/go7007/go7007-driver.c35
-rw-r--r--drivers/staging/go7007/go7007-fw.c3
-rw-r--r--drivers/staging/go7007/go7007-i2c.c12
-rw-r--r--drivers/staging/go7007/go7007-priv.h6
-rw-r--r--drivers/staging/go7007/go7007-usb.c58
-rw-r--r--drivers/staging/go7007/go7007-v4l2.c225
-rw-r--r--drivers/staging/go7007/go7007.txt176
-rw-r--r--drivers/staging/go7007/s2250-board.c107
-rw-r--r--drivers/staging/go7007/s2250-loader.c8
-rw-r--r--drivers/staging/go7007/s2250-loader.h24
-rw-r--r--drivers/staging/go7007/snd-go7007.c2
-rw-r--r--drivers/staging/go7007/wis-tw9903.c3
-rw-r--r--drivers/staging/heci/Kconfig7
-rw-r--r--drivers/staging/heci/Makefile9
-rw-r--r--drivers/staging/heci/TODO6
-rw-r--r--drivers/staging/heci/heci.h175
-rw-r--r--drivers/staging/heci/heci_data_structures.h529
-rw-r--r--drivers/staging/heci/heci_init.c1083
-rw-r--r--drivers/staging/heci/heci_interface.c498
-rw-r--r--drivers/staging/heci/heci_interface.h170
-rw-r--r--drivers/staging/heci/heci_main.c1576
-rw-r--r--drivers/staging/heci/heci_version.h54
-rw-r--r--drivers/staging/heci/interrupt.c1555
-rw-r--r--drivers/staging/heci/io_heci.c872
-rw-r--r--drivers/staging/hv/BlkVsc.c112
-rw-r--r--drivers/staging/hv/Channel.c1007
-rw-r--r--drivers/staging/hv/Channel.h112
-rw-r--r--drivers/staging/hv/ChannelInterface.c152
-rw-r--r--drivers/staging/hv/ChannelInterface.h35
-rw-r--r--drivers/staging/hv/ChannelMgmt.c686
-rw-r--r--drivers/staging/hv/ChannelMgmt.h320
-rw-r--r--drivers/staging/hv/Connection.c341
-rw-r--r--drivers/staging/hv/Hv.c568
-rw-r--r--drivers/staging/hv/Hv.h144
-rw-r--r--drivers/staging/hv/Kconfig32
-rw-r--r--drivers/staging/hv/Makefile11
-rw-r--r--drivers/staging/hv/NetVsc.c1378
-rw-r--r--drivers/staging/hv/NetVsc.h330
-rw-r--r--drivers/staging/hv/NetVscApi.h123
-rw-r--r--drivers/staging/hv/RingBuffer.c606
-rw-r--r--drivers/staging/hv/RingBuffer.h101
-rw-r--r--drivers/staging/hv/RndisFilter.c1000
-rw-r--r--drivers/staging/hv/RndisFilter.h55
-rw-r--r--drivers/staging/hv/StorVsc.c850
-rw-r--r--drivers/staging/hv/StorVscApi.h113
-rw-r--r--drivers/staging/hv/TODO19
-rw-r--r--drivers/staging/hv/VersionInfo.h31
-rw-r--r--drivers/staging/hv/Vmbus.c311
-rw-r--r--drivers/staging/hv/VmbusApi.h175
-rw-r--r--drivers/staging/hv/VmbusChannelInterface.h89
-rw-r--r--drivers/staging/hv/VmbusPacketFormat.h160
-rw-r--r--drivers/staging/hv/VmbusPrivate.h134
-rw-r--r--drivers/staging/hv/blkvsc_drv.c1512
-rw-r--r--drivers/staging/hv/hv_api.h905
-rw-r--r--drivers/staging/hv/logging.h119
-rw-r--r--drivers/staging/hv/netvsc_drv.c619
-rw-r--r--drivers/staging/hv/osd.c157
-rw-r--r--drivers/staging/hv/osd.h70
-rw-r--r--drivers/staging/hv/rndis.h652
-rw-r--r--drivers/staging/hv/storvsc_drv.c1208
-rw-r--r--drivers/staging/hv/vmbus.h77
-rw-r--r--drivers/staging/hv/vmbus_drv.c981
-rw-r--r--drivers/staging/hv/vstorage.h192
-rw-r--r--drivers/staging/iio/Documentation/device.txt49
-rw-r--r--drivers/staging/iio/Documentation/iio_utils.h159
-rw-r--r--drivers/staging/iio/Documentation/lis3l02dqbuffersimple.c171
-rw-r--r--drivers/staging/iio/Documentation/overview.txt62
-rw-r--r--drivers/staging/iio/Documentation/ring.txt61
-rw-r--r--drivers/staging/iio/Documentation/trigger.txt38
-rw-r--r--drivers/staging/iio/Documentation/userspace.txt60
-rw-r--r--drivers/staging/iio/Kconfig48
-rw-r--r--drivers/staging/iio/Makefile16
-rw-r--r--drivers/staging/iio/TODO69
-rw-r--r--drivers/staging/iio/accel/Kconfig27
-rw-r--r--drivers/staging/iio/accel/Makefile11
-rw-r--r--drivers/staging/iio/accel/accel.h167
-rw-r--r--drivers/staging/iio/accel/kxsd9.c395
-rw-r--r--drivers/staging/iio/accel/lis3l02dq.h232
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_core.c926
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_ring.c600
-rw-r--r--drivers/staging/iio/accel/sca3000.h298
-rw-r--r--drivers/staging/iio/accel/sca3000_core.c1509
-rw-r--r--drivers/staging/iio/accel/sca3000_ring.c331
-rw-r--r--drivers/staging/iio/adc/Kconfig13
-rw-r--r--drivers/staging/iio/adc/Makefile8
-rw-r--r--drivers/staging/iio/adc/adc.h13
-rw-r--r--drivers/staging/iio/adc/max1363.h269
-rw-r--r--drivers/staging/iio/adc/max1363_core.c623
-rw-r--r--drivers/staging/iio/adc/max1363_ring.c241
-rw-r--r--drivers/staging/iio/chrdev.h118
-rw-r--r--drivers/staging/iio/iio.h411
-rw-r--r--drivers/staging/iio/industrialio-core.c853
-rw-r--r--drivers/staging/iio/industrialio-ring.c568
-rw-r--r--drivers/staging/iio/industrialio-trigger.c399
-rw-r--r--drivers/staging/iio/light/Kconfig13
-rw-r--r--drivers/staging/iio/light/Makefile5
-rw-r--r--drivers/staging/iio/light/light.h12
-rw-r--r--drivers/staging/iio/light/tsl2561.c272
-rw-r--r--drivers/staging/iio/ring_generic.h283
-rw-r--r--drivers/staging/iio/ring_hw.h22
-rw-r--r--drivers/staging/iio/ring_sw.c433
-rw-r--r--drivers/staging/iio/ring_sw.h189
-rw-r--r--drivers/staging/iio/sysfs.h293
-rw-r--r--drivers/staging/iio/trigger.h151
-rw-r--r--drivers/staging/iio/trigger/Kconfig21
-rw-r--r--drivers/staging/iio/trigger/Makefile5
-rw-r--r--drivers/staging/iio/trigger/iio-trig-gpio.c202
-rw-r--r--drivers/staging/iio/trigger/iio-trig-periodic-rtc.c228
-rw-r--r--drivers/staging/iio/trigger_consumer.h45
-rw-r--r--drivers/staging/line6/capture.c4
-rw-r--r--drivers/staging/line6/driver.c2
-rw-r--r--drivers/staging/line6/pod.c8
-rw-r--r--drivers/staging/me4000/Kconfig10
-rw-r--r--drivers/staging/me4000/Makefile1
-rw-r--r--drivers/staging/me4000/README13
-rw-r--r--drivers/staging/me4000/me4000.c6109
-rw-r--r--drivers/staging/me4000/me4000.h966
-rw-r--r--drivers/staging/me4000/me4000_firmware.h10033
-rw-r--r--drivers/staging/me4000/me4610_firmware.h5409
-rw-r--r--drivers/staging/meilhaus/Kconfig128
-rw-r--r--drivers/staging/meilhaus/Makefile43
-rw-r--r--drivers/staging/meilhaus/TODO10
-rw-r--r--drivers/staging/meilhaus/me0600_device.c213
-rw-r--r--drivers/staging/meilhaus/me0600_device.h97
-rw-r--r--drivers/staging/meilhaus/me0600_dio.c415
-rw-r--r--drivers/staging/meilhaus/me0600_dio.h68
-rw-r--r--drivers/staging/meilhaus/me0600_dio_reg.h41
-rw-r--r--drivers/staging/meilhaus/me0600_ext_irq.c469
-rw-r--r--drivers/staging/meilhaus/me0600_ext_irq.h58
-rw-r--r--drivers/staging/meilhaus/me0600_ext_irq_reg.h18
-rw-r--r--drivers/staging/meilhaus/me0600_optoi.c243
-rw-r--r--drivers/staging/meilhaus/me0600_optoi.h58
-rw-r--r--drivers/staging/meilhaus/me0600_optoi_reg.h35
-rw-r--r--drivers/staging/meilhaus/me0600_relay.c359
-rw-r--r--drivers/staging/meilhaus/me0600_relay.h63
-rw-r--r--drivers/staging/meilhaus/me0600_relay_reg.h36
-rw-r--r--drivers/staging/meilhaus/me0600_ttli.c238
-rw-r--r--drivers/staging/meilhaus/me0600_ttli.h58
-rw-r--r--drivers/staging/meilhaus/me0900_device.c178
-rw-r--r--drivers/staging/meilhaus/me0900_device.h92
-rw-r--r--drivers/staging/meilhaus/me0900_di.c245
-rw-r--r--drivers/staging/meilhaus/me0900_di.h65
-rw-r--r--drivers/staging/meilhaus/me0900_do.c314
-rw-r--r--drivers/staging/meilhaus/me0900_do.h68
-rw-r--r--drivers/staging/meilhaus/me0900_reg.h40
-rw-r--r--drivers/staging/meilhaus/me1000_device.c206
-rw-r--r--drivers/staging/meilhaus/me1000_device.h59
-rw-r--r--drivers/staging/meilhaus/me1000_dio.c438
-rw-r--r--drivers/staging/meilhaus/me1000_dio.h71
-rw-r--r--drivers/staging/meilhaus/me1000_dio_reg.h50
-rw-r--r--drivers/staging/meilhaus/me1400_device.c253
-rw-r--r--drivers/staging/meilhaus/me1400_device.h108
-rw-r--r--drivers/staging/meilhaus/me1400_ext_irq.c507
-rw-r--r--drivers/staging/meilhaus/me1400_ext_irq.h62
-rw-r--r--drivers/staging/meilhaus/me1400_ext_irq_reg.h56
-rw-r--r--drivers/staging/meilhaus/me1600_ao.c1017
-rw-r--r--drivers/staging/meilhaus/me1600_ao.h128
-rw-r--r--drivers/staging/meilhaus/me1600_ao_reg.h66
-rw-r--r--drivers/staging/meilhaus/me1600_device.c259
-rw-r--r--drivers/staging/meilhaus/me1600_device.h101
-rw-r--r--drivers/staging/meilhaus/me4600_ai.c3405
-rw-r--r--drivers/staging/meilhaus/me4600_ai.h175
-rw-r--r--drivers/staging/meilhaus/me4600_ai_reg.h107
-rw-r--r--drivers/staging/meilhaus/me4600_ao.c5974
-rw-r--r--drivers/staging/meilhaus/me4600_ao.h259
-rw-r--r--drivers/staging/meilhaus/me4600_ao_reg.h113
-rw-r--r--drivers/staging/meilhaus/me4600_device.c371
-rw-r--r--drivers/staging/meilhaus/me4600_device.h151
-rw-r--r--drivers/staging/meilhaus/me4600_di.c256
-rw-r--r--drivers/staging/meilhaus/me4600_di.h64
-rw-r--r--drivers/staging/meilhaus/me4600_dio.c510
-rw-r--r--drivers/staging/meilhaus/me4600_dio.h69
-rw-r--r--drivers/staging/meilhaus/me4600_dio_reg.h63
-rw-r--r--drivers/staging/meilhaus/me4600_do.c433
-rw-r--r--drivers/staging/meilhaus/me4600_do.h65
-rw-r--r--drivers/staging/meilhaus/me4600_ext_irq.c457
-rw-r--r--drivers/staging/meilhaus/me4600_ext_irq.h78
-rw-r--r--drivers/staging/meilhaus/me4600_ext_irq_reg.h41
-rw-r--r--drivers/staging/meilhaus/me4600_reg.h46
-rw-r--r--drivers/staging/meilhaus/me6000_ao.c3709
-rw-r--r--drivers/staging/meilhaus/me6000_ao.h195
-rw-r--r--drivers/staging/meilhaus/me6000_ao_reg.h177
-rw-r--r--drivers/staging/meilhaus/me6000_device.c209
-rw-r--r--drivers/staging/meilhaus/me6000_device.h149
-rw-r--r--drivers/staging/meilhaus/me6000_dio.c415
-rw-r--r--drivers/staging/meilhaus/me6000_dio.h68
-rw-r--r--drivers/staging/meilhaus/me6000_dio_reg.h43
-rw-r--r--drivers/staging/meilhaus/me6000_reg.h35
-rw-r--r--drivers/staging/meilhaus/me8100_device.c185
-rw-r--r--drivers/staging/meilhaus/me8100_device.h97
-rw-r--r--drivers/staging/meilhaus/me8100_di.c684
-rw-r--r--drivers/staging/meilhaus/me8100_di.h89
-rw-r--r--drivers/staging/meilhaus/me8100_di_reg.h47
-rw-r--r--drivers/staging/meilhaus/me8100_do.c391
-rw-r--r--drivers/staging/meilhaus/me8100_do.h70
-rw-r--r--drivers/staging/meilhaus/me8100_do_reg.h36
-rw-r--r--drivers/staging/meilhaus/me8100_reg.h41
-rw-r--r--drivers/staging/meilhaus/me8200_device.c192
-rw-r--r--drivers/staging/meilhaus/me8200_device.h97
-rw-r--r--drivers/staging/meilhaus/me8200_di.c832
-rw-r--r--drivers/staging/meilhaus/me8200_di.h92
-rw-r--r--drivers/staging/meilhaus/me8200_di_reg.h75
-rw-r--r--drivers/staging/meilhaus/me8200_dio.c418
-rw-r--r--drivers/staging/meilhaus/me8200_dio.h68
-rw-r--r--drivers/staging/meilhaus/me8200_dio_reg.h43
-rw-r--r--drivers/staging/meilhaus/me8200_do.c591
-rw-r--r--drivers/staging/meilhaus/me8200_do.h75
-rw-r--r--drivers/staging/meilhaus/me8200_do_reg.h40
-rw-r--r--drivers/staging/meilhaus/me8200_reg.h46
-rw-r--r--drivers/staging/meilhaus/me8254.c1176
-rw-r--r--drivers/staging/meilhaus/me8254.h80
-rw-r--r--drivers/staging/meilhaus/me8254_reg.h172
-rw-r--r--drivers/staging/meilhaus/me8255.c462
-rw-r--r--drivers/staging/meilhaus/me8255.h59
-rw-r--r--drivers/staging/meilhaus/me8255_reg.h50
-rw-r--r--drivers/staging/meilhaus/mecirc_buf.h131
-rw-r--r--drivers/staging/meilhaus/mecommon.h26
-rw-r--r--drivers/staging/meilhaus/medebug.h125
-rw-r--r--drivers/staging/meilhaus/medefines.h449
-rw-r--r--drivers/staging/meilhaus/medevice.c1740
-rw-r--r--drivers/staging/meilhaus/medevice.h304
-rw-r--r--drivers/staging/meilhaus/medlist.c127
-rw-r--r--drivers/staging/meilhaus/medlist.h91
-rw-r--r--drivers/staging/meilhaus/medlock.c195
-rw-r--r--drivers/staging/meilhaus/medlock.h76
-rw-r--r--drivers/staging/meilhaus/medriver.h350
-rw-r--r--drivers/staging/meilhaus/medummy.c1264
-rw-r--r--drivers/staging/meilhaus/medummy.h40
-rw-r--r--drivers/staging/meilhaus/meerror.h100
-rw-r--r--drivers/staging/meilhaus/mefirmware.c137
-rw-r--r--drivers/staging/meilhaus/mefirmware.h57
-rw-r--r--drivers/staging/meilhaus/meids.h31
-rw-r--r--drivers/staging/meilhaus/meinternal.h363
-rw-r--r--drivers/staging/meilhaus/meioctl.h515
-rw-r--r--drivers/staging/meilhaus/memain.c2084
-rw-r--r--drivers/staging/meilhaus/memain.h266
-rw-r--r--drivers/staging/meilhaus/meplx_reg.h53
-rw-r--r--drivers/staging/meilhaus/meslist.c173
-rw-r--r--drivers/staging/meilhaus/meslist.h108
-rw-r--r--drivers/staging/meilhaus/meslock.c136
-rw-r--r--drivers/staging/meilhaus/meslock.h73
-rw-r--r--drivers/staging/meilhaus/mesubdevice.c317
-rw-r--r--drivers/staging/meilhaus/mesubdevice.h197
-rw-r--r--drivers/staging/meilhaus/metempl_device.c135
-rw-r--r--drivers/staging/meilhaus/metempl_device.h92
-rw-r--r--drivers/staging/meilhaus/metempl_sub.c149
-rw-r--r--drivers/staging/meilhaus/metempl_sub.h64
-rw-r--r--drivers/staging/meilhaus/metypes.h95
-rw-r--r--drivers/staging/octeon/cvmx-mdio.h2
-rw-r--r--drivers/staging/octeon/ethernet-mdio.c2
-rw-r--r--drivers/staging/octeon/ethernet-mdio.h2
-rw-r--r--drivers/staging/octeon/ethernet-spi.c2
-rw-r--r--drivers/staging/octeon/ethernet.c53
-rw-r--r--drivers/staging/otus/80211core/cagg.c6
-rw-r--r--drivers/staging/otus/80211core/cmm.c4
-rw-r--r--drivers/staging/otus/80211core/performance.c6
-rw-r--r--drivers/staging/otus/Kconfig2
-rw-r--r--drivers/staging/otus/hal/hpmain.c2
-rw-r--r--drivers/staging/otus/ioctl.c25
-rw-r--r--drivers/staging/otus/usbdrv.c22
-rw-r--r--drivers/staging/otus/usbdrv.h4
-rw-r--r--drivers/staging/otus/wrap_buf.c3
-rw-r--r--drivers/staging/otus/wrap_dbg.c3
-rw-r--r--drivers/staging/otus/wrap_ev.c7
-rw-r--r--drivers/staging/otus/wrap_mem.c3
-rw-r--r--drivers/staging/otus/wrap_mis.c3
-rw-r--r--drivers/staging/otus/wrap_pkt.c7
-rw-r--r--drivers/staging/otus/wrap_sec.c3
-rw-r--r--drivers/staging/otus/wrap_usb.c3
-rw-r--r--drivers/staging/otus/wwrap.c8
-rw-r--r--drivers/staging/otus/zdcompat.h10
-rw-r--r--drivers/staging/p9auth/p9auth.c14
-rw-r--r--drivers/staging/panel/panel.c63
-rw-r--r--drivers/staging/pata_rdc/Kconfig6
-rw-r--r--drivers/staging/pata_rdc/Makefile2
-rw-r--r--drivers/staging/pata_rdc/pata_rdc.c955
-rw-r--r--drivers/staging/pata_rdc/pata_rdc.h144
-rw-r--r--drivers/staging/poch/poch.c1
-rw-r--r--drivers/staging/pohmelfs/config.c104
-rw-r--r--drivers/staging/pohmelfs/crypto.c4
-rw-r--r--drivers/staging/pohmelfs/dir.c27
-rw-r--r--drivers/staging/pohmelfs/inode.c15
-rw-r--r--drivers/staging/pohmelfs/net.c20
-rw-r--r--drivers/staging/pohmelfs/netfs.h5
-rw-r--r--drivers/staging/pohmelfs/trans.c3
-rw-r--r--drivers/staging/quatech_usb2/Kconfig15
-rw-r--r--drivers/staging/quatech_usb2/Makefile1
-rw-r--r--drivers/staging/quatech_usb2/TODO8
-rw-r--r--drivers/staging/quatech_usb2/quatech_usb2.c2025
-rw-r--r--drivers/staging/rar/Kconfig17
-rw-r--r--drivers/staging/rar/Makefile2
-rw-r--r--drivers/staging/rar/rar_driver.c444
-rw-r--r--drivers/staging/rar/rar_driver.h99
-rw-r--r--drivers/staging/rspiusb/Kconfig6
-rw-r--r--drivers/staging/rspiusb/Makefile1
-rw-r--r--drivers/staging/rspiusb/TODO22
-rw-r--r--drivers/staging/rspiusb/rspiusb.c923
-rw-r--r--drivers/staging/rspiusb/rspiusb.h33
-rw-r--r--drivers/staging/rt2860/2860_main_dev.c7
-rw-r--r--drivers/staging/rt2860/Kconfig2
-rw-r--r--drivers/staging/rt2860/ap.h453
-rw-r--r--drivers/staging/rt2860/chlist.h5
-rw-r--r--drivers/staging/rt2860/common/action.c11
-rw-r--r--drivers/staging/rt2860/common/ba_action.c19
-rw-r--r--drivers/staging/rt2860/common/cmm_data.c298
-rw-r--r--drivers/staging/rt2860/common/cmm_data_2860.c2
-rw-r--r--drivers/staging/rt2860/common/cmm_info.c26
-rw-r--r--drivers/staging/rt2860/common/cmm_sanity.c184
-rw-r--r--drivers/staging/rt2860/common/cmm_wpa.c806
-rw-r--r--drivers/staging/rt2860/common/eeprom.c55
-rw-r--r--drivers/staging/rt2860/common/mlme.c590
-rw-r--r--drivers/staging/rt2860/common/rtmp_init.c386
-rw-r--r--drivers/staging/rt2860/common/spectrum.c5
-rw-r--r--drivers/staging/rt2860/dfs.h12
-rw-r--r--drivers/staging/rt2860/oid.h170
-rw-r--r--drivers/staging/rt2860/rt2860.h2
-rw-r--r--drivers/staging/rt2860/rt28xx.h22
-rw-r--r--drivers/staging/rt2860/rt_config.h4
-rw-r--r--drivers/staging/rt2860/rt_linux.c20
-rw-r--r--drivers/staging/rt2860/rt_linux.h118
-rw-r--r--drivers/staging/rt2860/rt_main_dev.c65
-rw-r--r--drivers/staging/rt2860/rt_profile.c44
-rw-r--r--drivers/staging/rt2860/rtmp.h721
-rw-r--r--drivers/staging/rt2860/rtmp_ckipmic.h35
-rw-r--r--drivers/staging/rt2860/rtmp_def.h14
-rw-r--r--drivers/staging/rt2860/sta/assoc.c26
-rw-r--r--drivers/staging/rt2860/sta/connect.c15
-rw-r--r--drivers/staging/rt2860/sta/rtmp_data.c15
-rw-r--r--drivers/staging/rt2860/sta/sync.c2
-rw-r--r--drivers/staging/rt2860/sta/wpa.c9
-rw-r--r--drivers/staging/rt2860/sta_ioctl.c3174
-rw-r--r--drivers/staging/rt2860/wpa.h3
-rw-r--r--drivers/staging/rt2870/2870_main_dev.c196
-rw-r--r--drivers/staging/rt2870/Kconfig7
-rw-r--r--drivers/staging/rt2870/Makefile2
-rw-r--r--drivers/staging/rt2870/common/2870_rtmp_init.c63
-rw-r--r--drivers/staging/rt2870/common/cmm_data_2870.c30
-rw-r--r--drivers/staging/rt2870/common/firmware.h558
-rw-r--r--drivers/staging/rt2870/common/rtusb_bulk.c3
-rw-r--r--drivers/staging/rt2870/common/rtusb_io.c81
-rw-r--r--drivers/staging/rt2870/link_list.h1
-rw-r--r--drivers/staging/rt2870/rt2870.h215
-rw-r--r--drivers/staging/rt3070/2870_main_dev.c1
-rw-r--r--drivers/staging/rt3070/Kconfig6
-rw-r--r--drivers/staging/rt3070/Makefile43
-rw-r--r--drivers/staging/rt3070/action.h1
-rw-r--r--drivers/staging/rt3070/aironet.h1
-rw-r--r--drivers/staging/rt3070/ap.h1
-rw-r--r--drivers/staging/rt3070/chlist.h1
-rw-r--r--drivers/staging/rt3070/common/2870_rtmp_init.c1
-rw-r--r--drivers/staging/rt3070/common/action.c1
-rw-r--r--drivers/staging/rt3070/common/ba_action.c1
-rw-r--r--drivers/staging/rt3070/common/cmm_data.c1
-rw-r--r--drivers/staging/rt3070/common/cmm_data_2870.c1
-rw-r--r--drivers/staging/rt3070/common/cmm_info.c1
-rw-r--r--drivers/staging/rt3070/common/cmm_sanity.c1
-rw-r--r--drivers/staging/rt3070/common/cmm_sync.c1
-rw-r--r--drivers/staging/rt3070/common/cmm_wpa.c1
-rw-r--r--drivers/staging/rt3070/common/dfs.c1
-rw-r--r--drivers/staging/rt3070/common/eeprom.c1
-rw-r--r--drivers/staging/rt3070/common/md5.c1
-rw-r--r--drivers/staging/rt3070/common/mlme.c1
-rw-r--r--drivers/staging/rt3070/common/rtmp_init.c1
-rw-r--r--drivers/staging/rt3070/common/rtmp_tkip.c1
-rw-r--r--drivers/staging/rt3070/common/rtmp_wep.c1
-rw-r--r--drivers/staging/rt3070/common/rtusb_bulk.c1
-rw-r--r--drivers/staging/rt3070/common/rtusb_data.c1
-rw-r--r--drivers/staging/rt3070/common/rtusb_io.c1
-rw-r--r--drivers/staging/rt3070/common/spectrum.c1
-rw-r--r--drivers/staging/rt3070/dfs.h1
-rw-r--r--drivers/staging/rt3070/link_list.h1
-rw-r--r--drivers/staging/rt3070/md5.h1
-rw-r--r--drivers/staging/rt3070/mlme.h1
-rw-r--r--drivers/staging/rt3070/oid.h1
-rw-r--r--drivers/staging/rt3070/rt2870.h1
-rw-r--r--drivers/staging/rt3070/rt28xx.h1
-rw-r--r--drivers/staging/rt3070/rt_config.h1
-rw-r--r--drivers/staging/rt3070/rt_linux.c1
-rw-r--r--drivers/staging/rt3070/rt_linux.h1
-rw-r--r--drivers/staging/rt3070/rt_main_dev.c1
-rw-r--r--drivers/staging/rt3070/rt_profile.c1
-rw-r--r--drivers/staging/rt3070/rtmp.h1
-rw-r--r--drivers/staging/rt3070/rtmp_ckipmic.h1
-rw-r--r--drivers/staging/rt3070/rtmp_def.h1
-rw-r--r--drivers/staging/rt3070/rtmp_type.h1
-rw-r--r--drivers/staging/rt3070/spectrum.h1
-rw-r--r--drivers/staging/rt3070/spectrum_def.h1
-rw-r--r--drivers/staging/rt3070/sta/aironet.c1
-rw-r--r--drivers/staging/rt3070/sta/assoc.c1
-rw-r--r--drivers/staging/rt3070/sta/auth.c1
-rw-r--r--drivers/staging/rt3070/sta/auth_rsp.c1
-rw-r--r--drivers/staging/rt3070/sta/connect.c2
-rw-r--r--drivers/staging/rt3070/sta/rtmp_data.c1
-rw-r--r--drivers/staging/rt3070/sta/sanity.c1
-rw-r--r--drivers/staging/rt3070/sta/sync.c1
-rw-r--r--drivers/staging/rt3070/sta/wpa.c1
-rw-r--r--drivers/staging/rt3070/sta_ioctl.c1
-rw-r--r--drivers/staging/rt3070/wpa.h1
-rw-r--r--drivers/staging/rt3090/Kconfig5
-rw-r--r--drivers/staging/rt3090/Makefile80
-rw-r--r--drivers/staging/rt3090/action.h66
-rw-r--r--drivers/staging/rt3090/ap.h512
-rw-r--r--drivers/staging/rt3090/ap_apcli.h276
-rw-r--r--drivers/staging/rt3090/ap_autoChSel.h79
-rw-r--r--drivers/staging/rt3090/ap_autoChSel_cmm.h66
-rw-r--r--drivers/staging/rt3090/ap_cfg.h118
-rw-r--r--drivers/staging/rt3090/ap_ids.h82
-rw-r--r--drivers/staging/rt3090/ap_mbss.h72
-rw-r--r--drivers/staging/rt3090/ap_uapsd.h636
-rw-r--r--drivers/staging/rt3090/ap_wds.h212
-rw-r--r--drivers/staging/rt3090/chips/rt3090.c123
-rw-r--r--drivers/staging/rt3090/chips/rt30xx.c525
-rw-r--r--drivers/staging/rt3090/chips/rt3370.c121
-rw-r--r--drivers/staging/rt3090/chips/rt3390.c122
-rw-r--r--drivers/staging/rt3090/chips/rt33xx.c536
-rw-r--r--drivers/staging/rt3090/chlist.h130
-rw-r--r--drivers/staging/rt3090/common/action.c1057
-rw-r--r--drivers/staging/rt3090/common/ba_action.c1779
-rw-r--r--drivers/staging/rt3090/common/cmm_aes.c1560
-rw-r--r--drivers/staging/rt3090/common/cmm_asic.c2753
-rw-r--r--drivers/staging/rt3090/common/cmm_cfg.c295
-rw-r--r--drivers/staging/rt3090/common/cmm_data.c2763
-rw-r--r--drivers/staging/rt3090/common/cmm_data_pci.c1576
-rw-r--r--drivers/staging/rt3090/common/cmm_info.c3718
-rw-r--r--drivers/staging/rt3090/common/cmm_mac_pci.c1757
-rw-r--r--drivers/staging/rt3090/common/cmm_profile.c2321
-rw-r--r--drivers/staging/rt3090/common/cmm_sanity.c1718
-rw-r--r--drivers/staging/rt3090/common/cmm_sync.c734
-rw-r--r--drivers/staging/rt3090/common/cmm_tkip.c966
-rw-r--r--drivers/staging/rt3090/common/cmm_wep.c500
-rw-r--r--drivers/staging/rt3090/common/cmm_wpa.c3149
-rw-r--r--drivers/staging/rt3090/common/crypt_aes.c1007
-rw-r--r--drivers/staging/rt3090/common/crypt_biginteger.c1119
-rw-r--r--drivers/staging/rt3090/common/crypt_dh.c234
-rw-r--r--drivers/staging/rt3090/common/crypt_hmac.c279
-rw-r--r--drivers/staging/rt3090/common/crypt_md5.c353
-rw-r--r--drivers/staging/rt3090/common/crypt_sha2.c536
-rw-r--r--drivers/staging/rt3090/common/dfs.c481
-rw-r--r--drivers/staging/rt3090/common/ee_efuse.c1548
-rw-r--r--drivers/staging/rt3090/common/ee_prom.c308
-rw-r--r--drivers/staging/rt3090/common/eeprom.c98
-rw-r--r--drivers/staging/rt3090/common/igmp_snoop.c1365
-rw-r--r--drivers/staging/rt3090/common/mlme.c6550
-rw-r--r--drivers/staging/rt3090/common/mlme_ex.c215
-rw-r--r--drivers/staging/rt3090/common/netif_block.c147
-rw-r--r--drivers/staging/rt3090/common/rt_channel.c1287
-rw-r--r--drivers/staging/rt3090/common/rt_rf.c201
-rw-r--r--drivers/staging/rt3090/common/rtmp_init.c3882
-rw-r--r--drivers/staging/rt3090/common/rtmp_mcu.c560
-rw-r--r--drivers/staging/rt3090/common/rtmp_timer.c327
-rw-r--r--drivers/staging/rt3090/common/spectrum.c2221
-rw-r--r--drivers/staging/rt3090/config.mk187
-rw-r--r--drivers/staging/rt3090/crypt_hmac.h81
-rw-r--r--drivers/staging/rt3090/crypt_md5.h78
-rw-r--r--drivers/staging/rt3090/crypt_sha2.h107
-rw-r--r--drivers/staging/rt3090/dfs.h137
-rw-r--r--drivers/staging/rt3090/eeprom.h82
-rw-r--r--drivers/staging/rt3090/firmware.h517
-rw-r--r--drivers/staging/rt3090/igmp_snoop.h152
-rw-r--r--drivers/staging/rt3090/ipv6.h215
-rw-r--r--drivers/staging/rt3090/link_list.h (renamed from drivers/staging/rt2860/link_list.h)1
-rw-r--r--drivers/staging/rt3090/mac_pci.h454
-rw-r--r--drivers/staging/rt3090/mlme.h1360
-rw-r--r--drivers/staging/rt3090/mlme_ex.h83
-rw-r--r--drivers/staging/rt3090/mlme_ex_def.h53
-rw-r--r--drivers/staging/rt3090/netif_block.h56
-rw-r--r--drivers/staging/rt3090/oid.h1144
-rw-r--r--drivers/staging/rt3090/pci_main_dev.c1195
-rw-r--r--drivers/staging/rt3090/rt3090.h77
-rw-r--r--drivers/staging/rt3090/rt30xx.h (renamed from drivers/staging/rt2860/md4.h)30
-rw-r--r--drivers/staging/rt3090/rt3370.h64
-rw-r--r--drivers/staging/rt3090/rt3390.h77
-rw-r--r--drivers/staging/rt3090/rt33xx.h (renamed from drivers/staging/rt2870/md4.h)30
-rw-r--r--drivers/staging/rt3090/rt_ate.c6089
-rw-r--r--drivers/staging/rt3090/rt_ate.h314
-rw-r--r--drivers/staging/rt3090/rt_config.h126
-rw-r--r--drivers/staging/rt3090/rt_linux.c1624
-rw-r--r--drivers/staging/rt3090/rt_linux.h1034
-rw-r--r--drivers/staging/rt3090/rt_main_dev.c897
-rw-r--r--drivers/staging/rt3090/rt_pci_rbus.c989
-rw-r--r--drivers/staging/rt3090/rt_profile.c101
-rw-r--r--drivers/staging/rt3090/rtmp.h6873
-rw-r--r--drivers/staging/rt3090/rtmp_chip.h355
-rw-r--r--drivers/staging/rt3090/rtmp_def.h1650
-rw-r--r--drivers/staging/rt3090/rtmp_dot11.h146
-rw-r--r--drivers/staging/rt3090/rtmp_iface.h81
-rw-r--r--drivers/staging/rt3090/rtmp_mac.h2304
-rw-r--r--drivers/staging/rt3090/rtmp_mcu.h55
-rw-r--r--drivers/staging/rt3090/rtmp_os.h93
-rw-r--r--drivers/staging/rt3090/rtmp_pci.h110
-rw-r--r--drivers/staging/rt3090/rtmp_phy.h631
-rw-r--r--drivers/staging/rt3090/rtmp_timer.h162
-rw-r--r--drivers/staging/rt3090/rtmp_type.h147
-rw-r--r--drivers/staging/rt3090/spectrum.h234
-rw-r--r--drivers/staging/rt3090/spectrum_def.h257
-rw-r--r--drivers/staging/rt3090/sta/assoc.c1673
-rw-r--r--drivers/staging/rt3090/sta/auth.c491
-rw-r--r--drivers/staging/rt3090/sta/auth_rsp.c151
-rw-r--r--drivers/staging/rt3090/sta/connect.c2759
-rw-r--r--drivers/staging/rt3090/sta/dls.c2207
-rw-r--r--drivers/staging/rt3090/sta/rtmp_ckipmic.c579
-rw-r--r--drivers/staging/rt3090/sta/rtmp_data.c2661
-rw-r--r--drivers/staging/rt3090/sta/sanity.c382
-rw-r--r--drivers/staging/rt3090/sta/sync.c1840
-rw-r--r--drivers/staging/rt3090/sta/wpa.c396
-rw-r--r--drivers/staging/rt3090/sta_ioctl.c7557
-rw-r--r--drivers/staging/rt3090/vr_ikans.h71
-rw-r--r--drivers/staging/rt3090/wpa.h447
-rw-r--r--drivers/staging/rtl8187se/Kconfig2
-rw-r--r--drivers/staging/rtl8187se/Makefile16
-rw-r--r--drivers/staging/rtl8187se/TODO14
-rw-r--r--drivers/staging/rtl8187se/ieee80211.h1755
-rw-r--r--drivers/staging/rtl8187se/ieee80211/dot11d.c22
-rw-r--r--drivers/staging/rtl8187se/ieee80211/dot11d.h2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211.h665
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c21
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c88
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c324
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c125
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_module.c92
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c512
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c1045
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c30
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c274
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c146
-rw-r--r--drivers/staging/rtl8187se/ieee80211/internal.h115
-rw-r--r--drivers/staging/rtl8187se/ieee80211/rtl_crypto.h399
-rw-r--r--drivers/staging/rtl8187se/r8180.h24
-rw-r--r--drivers/staging/rtl8187se/r8180_93cx6.h2
-rw-r--r--drivers/staging/rtl8187se/r8180_core.c2958
-rw-r--r--drivers/staging/rtl8187se/r8180_dm.c58
-rw-r--r--drivers/staging/rtl8187se/r8180_dm.h18
-rw-r--r--drivers/staging/rtl8187se/r8180_gct.c296
-rw-r--r--drivers/staging/rtl8187se/r8180_hw.h393
-rw-r--r--drivers/staging/rtl8187se/r8180_max2820.c240
-rw-r--r--drivers/staging/rtl8187se/r8180_max2820.h21
-rw-r--r--drivers/staging/rtl8187se/r8180_pm.c92
-rw-r--r--drivers/staging/rtl8187se/r8180_rtl8225.c933
-rw-r--r--drivers/staging/rtl8187se/r8180_rtl8225.h12
-rw-r--r--drivers/staging/rtl8187se/r8180_rtl8225z2.c1552
-rw-r--r--drivers/staging/rtl8187se/r8180_rtl8255.c1838
-rw-r--r--drivers/staging/rtl8187se/r8180_rtl8255.h19
-rw-r--r--drivers/staging/rtl8187se/r8180_sa2400.c233
-rw-r--r--drivers/staging/rtl8187se/r8180_sa2400.h26
-rw-r--r--drivers/staging/rtl8187se/r8180_wx.c63
-rw-r--r--drivers/staging/rtl8187se/r8180_wx.h2
-rw-r--r--drivers/staging/rtl8187se/r8185b_init.c665
-rw-r--r--drivers/staging/rtl8192e/Kconfig6
-rw-r--r--drivers/staging/rtl8192e/Makefile34
-rw-r--r--drivers/staging/rtl8192e/dot11d.h (renamed from drivers/staging/rtl8192su/dot11d.h)0
-rw-r--r--drivers/staging/rtl8192e/ieee80211.h2687
-rw-r--r--drivers/staging/rtl8192e/ieee80211/dot11d.c239
-rw-r--r--drivers/staging/rtl8192e/ieee80211/dot11d.h (renamed from drivers/staging/rtl8187se/dot11d.h)3
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211.h (renamed from drivers/staging/rtl8192su/ieee80211.h)115
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.c267
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.h (renamed from drivers/staging/rtl8192su/ieee80211_crypt.h)7
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_ccmp.c534
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_tkip.c1031
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_wep.c393
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_module.c426
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c2802
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c3541
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c682
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c933
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c1021
-rw-r--r--drivers/staging/rtl8192e/ieee80211/rtl819x_BA.h69
-rw-r--r--drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c779
-rw-r--r--drivers/staging/rtl8192e/ieee80211/rtl819x_HT.h481
-rw-r--r--drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c1719
-rw-r--r--drivers/staging/rtl8192e/ieee80211/rtl819x_Qos.h748
-rw-r--r--drivers/staging/rtl8192e/ieee80211/rtl819x_TS.h56
-rw-r--r--drivers/staging/rtl8192e/ieee80211/rtl819x_TSProc.c659
-rw-r--r--drivers/staging/rtl8192e/ieee80211/rtl_crypto.h (renamed from drivers/staging/rtl8192su/ieee80211/rtl_crypto.h)0
-rw-r--r--drivers/staging/rtl8192e/ieee80211_crypt.h (renamed from drivers/staging/rtl8187se/ieee80211_crypt.h)0
-rw-r--r--drivers/staging/rtl8192e/r8180_93cx6.c146
-rw-r--r--drivers/staging/rtl8192e/r8180_93cx6.h40
-rw-r--r--drivers/staging/rtl8192e/r8190_rtl8256.c1161
-rw-r--r--drivers/staging/rtl8192e/r8190_rtl8256.h (renamed from drivers/staging/rtl8192su/r8190_rtl8256.h)9
-rw-r--r--drivers/staging/rtl8192e/r8192E.h1516
-rw-r--r--drivers/staging/rtl8192e/r8192E_core.c6463
-rw-r--r--drivers/staging/rtl8192e/r8192E_dm.c3880
-rw-r--r--drivers/staging/rtl8192e/r8192E_dm.h312
-rw-r--r--drivers/staging/rtl8192e/r8192E_hw.h (renamed from drivers/staging/rtl8192su/r8192U_hw.h)437
-rw-r--r--drivers/staging/rtl8192e/r8192E_wx.c1344
-rw-r--r--drivers/staging/rtl8192e/r8192E_wx.h (renamed from drivers/staging/rtl8187se/r8180_gct.h)23
-rw-r--r--drivers/staging/rtl8192e/r8192_pm.c172
-rw-r--r--drivers/staging/rtl8192e/r8192_pm.h (renamed from drivers/staging/rtl8187se/r8180_pm.h)18
-rw-r--r--drivers/staging/rtl8192e/r819xE_cmdpkt.c804
-rw-r--r--drivers/staging/rtl8192e/r819xE_cmdpkt.h207
-rw-r--r--drivers/staging/rtl8192e/r819xE_firmware.c352
-rw-r--r--drivers/staging/rtl8192e/r819xE_phy.c (renamed from drivers/staging/rtl8192su/r819xU_phy.c)2404
-rw-r--r--drivers/staging/rtl8192e/r819xE_phy.h (renamed from drivers/staging/rtl8192su/r819xU_phy.h)61
-rw-r--r--drivers/staging/rtl8192e/r819xE_phyreg.h (renamed from drivers/staging/rtl8192su/r819xU_phyreg.h)7
-rw-r--r--drivers/staging/rtl8192su/Kconfig2
-rw-r--r--drivers/staging/rtl8192su/Makefile39
-rw-r--r--drivers/staging/rtl8192su/TODO17
-rw-r--r--drivers/staging/rtl8192su/ieee80211/EndianFree.h199
-rw-r--r--drivers/staging/rtl8192su/ieee80211/Makefile3
-rw-r--r--drivers/staging/rtl8192su/ieee80211/aes.c469
-rw-r--r--drivers/staging/rtl8192su/ieee80211/api.c246
-rw-r--r--drivers/staging/rtl8192su/ieee80211/arc4.c103
-rw-r--r--drivers/staging/rtl8192su/ieee80211/autoload.c40
-rw-r--r--drivers/staging/rtl8192su/ieee80211/cipher.c299
-rw-r--r--drivers/staging/rtl8192su/ieee80211/compress.c64
-rw-r--r--drivers/staging/rtl8192su/ieee80211/crypto_compat.h90
-rw-r--r--drivers/staging/rtl8192su/ieee80211/digest.c108
-rw-r--r--drivers/staging/rtl8192su/ieee80211/dot11d.c25
-rw-r--r--drivers/staging/rtl8192su/ieee80211/dot11d.h4
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211.h1350
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.c35
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.h7
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_ccmp.c66
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_tkip.c292
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_wep.c126
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_module.c81
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_r8192s.h436
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c253
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c375
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_softmac_wx.c86
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c26
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_wx.c289
-rw-r--r--drivers/staging/rtl8192su/ieee80211/internal.h115
-rw-r--r--drivers/staging/rtl8192su/ieee80211/kmap_types.h20
-rw-r--r--drivers/staging/rtl8192su/ieee80211/michael_mic.c194
-rw-r--r--drivers/staging/rtl8192su/ieee80211/proc.c116
-rw-r--r--drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c49
-rw-r--r--drivers/staging/rtl8192su/ieee80211/rtl819x_HT.h9
-rw-r--r--drivers/staging/rtl8192su/ieee80211/rtl819x_HTProc.c279
-rw-r--r--drivers/staging/rtl8192su/ieee80211/rtl819x_Qos.h168
-rw-r--r--drivers/staging/rtl8192su/ieee80211/rtl819x_TSProc.c34
-rw-r--r--drivers/staging/rtl8192su/ieee80211/scatterwalk.c126
-rw-r--r--drivers/staging/rtl8192su/ieee80211/scatterwalk.h51
-rw-r--r--drivers/staging/rtl8192su/r8180_93cx6.h5
-rw-r--r--drivers/staging/rtl8192su/r8190_rtl8256.c312
-rw-r--r--drivers/staging/rtl8192su/r8192S_Efuse.c113
-rw-r--r--drivers/staging/rtl8192su/r8192S_FwImgDTM.h3797
-rw-r--r--drivers/staging/rtl8192su/r8192S_firmware.c483
-rw-r--r--drivers/staging/rtl8192su/r8192S_firmware.h5
-rw-r--r--drivers/staging/rtl8192su/r8192S_hw.h184
-rw-r--r--drivers/staging/rtl8192su/r8192S_phy.c947
-rw-r--r--drivers/staging/rtl8192su/r8192S_phy.h5
-rw-r--r--drivers/staging/rtl8192su/r8192S_rtl6052.c104
-rw-r--r--drivers/staging/rtl8192su/r8192S_rtl6052.h47
-rw-r--r--drivers/staging/rtl8192su/r8192U.h528
-rw-r--r--drivers/staging/rtl8192su/r8192U_core.c4898
-rw-r--r--drivers/staging/rtl8192su/r8192U_dm.c550
-rw-r--r--drivers/staging/rtl8192su/r8192U_dm.h55
-rw-r--r--drivers/staging/rtl8192su/r8192U_pm.c11
-rw-r--r--drivers/staging/rtl8192su/r8192U_pm.h2
-rw-r--r--drivers/staging/rtl8192su/r8192U_wx.c132
-rw-r--r--drivers/staging/rtl8192su/r8192U_wx.h1
-rw-r--r--drivers/staging/rtl8192su/r819xU_HTType.h9
-rw-r--r--drivers/staging/rtl8192su/r819xU_cmdpkt.c113
-rw-r--r--drivers/staging/rtl8192su/r819xU_cmdpkt.h20
-rw-r--r--drivers/staging/rtl8192su/r819xU_firmware.c707
-rw-r--r--drivers/staging/rtl8192su/r819xU_firmware.h106
-rw-r--r--drivers/staging/rtl8192su/r819xU_firmware_img.c3447
-rw-r--r--drivers/staging/rtl8192su/r819xU_firmware_img.h35
-rw-r--r--drivers/staging/sep/Kconfig10
-rw-r--r--drivers/staging/sep/Makefile2
-rw-r--r--drivers/staging/sep/TODO8
-rw-r--r--drivers/staging/sep/sep_dev.h110
-rw-r--r--drivers/staging/sep/sep_driver.c2708
-rw-r--r--drivers/staging/sep/sep_driver_api.h425
-rw-r--r--drivers/staging/sep/sep_driver_config.h225
-rw-r--r--drivers/staging/sep/sep_driver_hw_defs.h232
-rw-r--r--drivers/staging/serqt_usb2/serqt_usb2.c2
-rw-r--r--drivers/staging/slicoss/slicoss.c4
-rw-r--r--drivers/staging/stlc45xx/Kconfig8
-rw-r--r--drivers/staging/stlc45xx/Makefile1
-rw-r--r--drivers/staging/stlc45xx/stlc45xx.c2592
-rw-r--r--drivers/staging/stlc45xx/stlc45xx.h283
-rw-r--r--drivers/staging/stlc45xx/stlc45xx_lmac.h434
-rw-r--r--drivers/staging/sxg/Kconfig11
-rw-r--r--drivers/staging/sxg/Makefile3
-rw-r--r--drivers/staging/sxg/README12
-rw-r--r--drivers/staging/sxg/sxg.c4543
-rw-r--r--drivers/staging/sxg/sxg.h787
-rw-r--r--drivers/staging/sxg/sxg_ethtool.c328
-rw-r--r--drivers/staging/sxg/sxg_os.h149
-rw-r--r--drivers/staging/sxg/sxgdbg.h184
-rw-r--r--drivers/staging/sxg/sxghif.h1014
-rw-r--r--drivers/staging/sxg/sxghw.h1020
-rw-r--r--drivers/staging/sxg/sxgphycode-1.2.h130
-rw-r--r--drivers/staging/udlfb/udlfb.h2
-rw-r--r--drivers/staging/usbip/Kconfig2
-rw-r--r--drivers/staging/usbip/stub_dev.c16
-rw-r--r--drivers/staging/usbip/stub_main.c8
-rw-r--r--drivers/staging/usbip/stub_rx.c49
-rw-r--r--drivers/staging/usbip/stub_tx.c26
-rw-r--r--drivers/staging/usbip/usbip_common.c226
-rw-r--r--drivers/staging/usbip/usbip_common.h96
-rw-r--r--drivers/staging/usbip/usbip_event.c37
-rw-r--r--drivers/staging/usbip/vhci_hcd.c156
-rw-r--r--drivers/staging/usbip/vhci_rx.c41
-rw-r--r--drivers/staging/usbip/vhci_sysfs.c22
-rw-r--r--drivers/staging/usbip/vhci_tx.c22
-rw-r--r--drivers/staging/vme/Kconfig17
-rw-r--r--drivers/staging/vme/Makefile7
-rw-r--r--drivers/staging/vme/TODO98
-rw-r--r--drivers/staging/vme/bridges/Kconfig13
-rw-r--r--drivers/staging/vme/bridges/Makefile2
-rw-r--r--drivers/staging/vme/bridges/vme_ca91cx42.c1934
-rw-r--r--drivers/staging/vme/bridges/vme_ca91cx42.h505
-rw-r--r--drivers/staging/vme/bridges/vme_tsi148.c2926
-rw-r--r--drivers/staging/vme/bridges/vme_tsi148.h1387
-rw-r--r--drivers/staging/vme/devices/Kconfig8
-rw-r--r--drivers/staging/vme/devices/Makefile5
-rw-r--r--drivers/staging/vme/devices/vme_user.c826
-rw-r--r--drivers/staging/vme/devices/vme_user.h52
-rw-r--r--drivers/staging/vme/vme.c1497
-rw-r--r--drivers/staging/vme/vme.h161
-rw-r--r--drivers/staging/vme/vme_api.txt372
-rw-r--r--drivers/staging/vme/vme_bridge.h261
-rw-r--r--drivers/staging/vt6655/80211hdr.h10
-rw-r--r--drivers/staging/vt6655/80211mgr.c38
-rw-r--r--drivers/staging/vt6655/80211mgr.h13
-rw-r--r--drivers/staging/vt6655/IEEE11h.c47
-rw-r--r--drivers/staging/vt6655/IEEE11h.h16
-rw-r--r--drivers/staging/vt6655/Kconfig2
-rw-r--r--drivers/staging/vt6655/Makefile6
-rw-r--r--drivers/staging/vt6655/Makefile.arm181
-rw-r--r--drivers/staging/vt6655/Makefile.x86209
-rw-r--r--drivers/staging/vt6655/TODO20
-rw-r--r--drivers/staging/vt6655/aes_ccmp.c30
-rw-r--r--drivers/staging/vt6655/aes_ccmp.h2
-rw-r--r--drivers/staging/vt6655/baseband.c61
-rw-r--r--drivers/staging/vt6655/baseband.h35
-rw-r--r--drivers/staging/vt6655/bssdb.c158
-rw-r--r--drivers/staging/vt6655/bssdb.h23
-rw-r--r--drivers/staging/vt6655/card.c80
-rw-r--r--drivers/staging/vt6655/card.h17
-rw-r--r--drivers/staging/vt6655/country.h17
-rw-r--r--drivers/staging/vt6655/datarate.c26
-rw-r--r--drivers/staging/vt6655/desc.h103
-rw-r--r--drivers/staging/vt6655/device.h177
-rw-r--r--drivers/staging/vt6655/device_cfg.h46
-rw-r--r--drivers/staging/vt6655/device_main.c643
-rw-r--r--drivers/staging/vt6655/dpc.c304
-rw-r--r--drivers/staging/vt6655/dpc.h24
-rw-r--r--drivers/staging/vt6655/hostap.c135
-rw-r--r--drivers/staging/vt6655/hostap.h24
-rw-r--r--drivers/staging/vt6655/iocmd.h23
-rw-r--r--drivers/staging/vt6655/ioctl.c101
-rw-r--r--drivers/staging/vt6655/ioctl.h17
-rw-r--r--drivers/staging/vt6655/iowpa.h4
-rw-r--r--drivers/staging/vt6655/iwctl.c314
-rw-r--r--drivers/staging/vt6655/iwctl.h105
-rw-r--r--drivers/staging/vt6655/kcompat.h49
-rw-r--r--drivers/staging/vt6655/key.c153
-rw-r--r--drivers/staging/vt6655/key.h24
-rw-r--r--drivers/staging/vt6655/mac.c145
-rw-r--r--drivers/staging/vt6655/mac.h19
-rw-r--r--drivers/staging/vt6655/mib.c153
-rw-r--r--drivers/staging/vt6655/mib.h35
-rw-r--r--drivers/staging/vt6655/michael.c7
-rw-r--r--drivers/staging/vt6655/michael.h4
-rw-r--r--drivers/staging/vt6655/power.c45
-rw-r--r--drivers/staging/vt6655/power.h3
-rw-r--r--drivers/staging/vt6655/rc4.c7
-rw-r--r--drivers/staging/vt6655/rc4.h6
-rw-r--r--drivers/staging/vt6655/rf.c16
-rw-r--r--drivers/staging/vt6655/rf.h16
-rw-r--r--drivers/staging/vt6655/rxtx.c556
-rw-r--r--drivers/staging/vt6655/rxtx.h10
-rw-r--r--drivers/staging/vt6655/srom.c31
-rw-r--r--drivers/staging/vt6655/srom.h24
-rw-r--r--drivers/staging/vt6655/tcrc.c9
-rw-r--r--drivers/staging/vt6655/tcrc.h18
-rw-r--r--drivers/staging/vt6655/tether.c16
-rw-r--r--drivers/staging/vt6655/tether.h26
-rw-r--r--drivers/staging/vt6655/tkip.c12
-rw-r--r--drivers/staging/vt6655/tkip.h16
-rw-r--r--drivers/staging/vt6655/tmacro.h90
-rw-r--r--drivers/staging/vt6655/tpci.h117
-rw-r--r--drivers/staging/vt6655/ttype.h261
-rw-r--r--drivers/staging/vt6655/upc.h5
-rw-r--r--drivers/staging/vt6655/vntwifi.c33
-rw-r--r--drivers/staging/vt6655/vntwifi.h19
-rw-r--r--drivers/staging/vt6655/wcmd.c137
-rw-r--r--drivers/staging/vt6655/wcmd.h22
-rw-r--r--drivers/staging/vt6655/wctl.c17
-rw-r--r--drivers/staging/vt6655/wctl.h19
-rw-r--r--drivers/staging/vt6655/wmgr.c360
-rw-r--r--drivers/staging/vt6655/wmgr.h33
-rw-r--r--drivers/staging/vt6655/wpa.c71
-rw-r--r--drivers/staging/vt6655/wpa.h14
-rw-r--r--drivers/staging/vt6655/wpa2.c55
-rw-r--r--drivers/staging/vt6655/wpa2.h24
-rw-r--r--drivers/staging/vt6655/wpactl.c102
-rw-r--r--drivers/staging/vt6655/wpactl.h17
-rw-r--r--drivers/staging/vt6655/wroute.c28
-rw-r--r--drivers/staging/vt6655/wroute.h18
-rw-r--r--drivers/staging/vt6656/80211hdr.h353
-rw-r--r--drivers/staging/vt6656/80211mgr.c1026
-rw-r--r--drivers/staging/vt6656/80211mgr.h861
-rw-r--r--drivers/staging/vt6656/Kconfig6
-rw-r--r--drivers/staging/vt6656/Makefile39
-rw-r--r--drivers/staging/vt6656/TODO19
-rw-r--r--drivers/staging/vt6656/aes_ccmp.c402
-rw-r--r--drivers/staging/vt6656/aes_ccmp.h46
-rw-r--r--drivers/staging/vt6656/baseband.c2105
-rw-r--r--drivers/staging/vt6656/baseband.h146
-rw-r--r--drivers/staging/vt6656/bssdb.c1721
-rw-r--r--drivers/staging/vt6656/bssdb.h359
-rw-r--r--drivers/staging/vt6656/card.c1113
-rw-r--r--drivers/staging/vt6656/card.h95
-rw-r--r--drivers/staging/vt6656/channel.c525
-rw-r--r--drivers/staging/vt6656/channel.h57
-rw-r--r--drivers/staging/vt6656/control.c109
-rw-r--r--drivers/staging/vt6656/control.h83
-rw-r--r--drivers/staging/vt6656/country.h163
-rw-r--r--drivers/staging/vt6656/datarate.c499
-rw-r--r--drivers/staging/vt6656/datarate.h110
-rw-r--r--drivers/staging/vt6656/desc.h443
-rw-r--r--drivers/staging/vt6656/device.h939
-rw-r--r--drivers/staging/vt6656/device_cfg.h107
-rw-r--r--drivers/staging/vt6656/dpc.c1616
-rw-r--r--drivers/staging/vt6656/dpc.h70
-rw-r--r--drivers/staging/vt6656/firmware.c876
-rw-r--r--drivers/staging/vt6656/firmware.h60
-rw-r--r--drivers/staging/vt6656/hostap.c868
-rw-r--r--drivers/staging/vt6656/hostap.h70
-rw-r--r--drivers/staging/vt6656/int.c193
-rw-r--r--drivers/staging/vt6656/int.h83
-rw-r--r--drivers/staging/vt6656/iocmd.h475
-rw-r--r--drivers/staging/vt6656/ioctl.c701
-rw-r--r--drivers/staging/vt6656/ioctl.h57
-rw-r--r--drivers/staging/vt6656/iowpa.h158
-rw-r--r--drivers/staging/vt6656/iwctl.c2190
-rw-r--r--drivers/staging/vt6656/iwctl.h229
-rw-r--r--drivers/staging/vt6656/kcompat.h39
-rw-r--r--drivers/staging/vt6656/key.c869
-rw-r--r--drivers/staging/vt6656/key.h177
-rw-r--r--drivers/staging/vt6656/mac.c482
-rw-r--r--drivers/staging/vt6656/mac.h442
-rw-r--r--drivers/staging/vt6656/main_usb.c2195
-rw-r--r--drivers/staging/vt6656/mib.c573
-rw-r--r--drivers/staging/vt6656/mib.h423
-rw-r--r--drivers/staging/vt6656/michael.c181
-rw-r--r--drivers/staging/vt6656/michael.h58
-rw-r--r--drivers/staging/vt6656/power.c424
-rw-r--r--drivers/staging/vt6656/power.h84
-rw-r--r--drivers/staging/vt6656/rc4.c87
-rw-r--r--drivers/staging/vt6656/rc4.h47
-rw-r--r--drivers/staging/vt6656/rf.c1151
-rw-r--r--drivers/staging/vt6656/rf.h100
-rw-r--r--drivers/staging/vt6656/rndis.h162
-rw-r--r--drivers/staging/vt6656/rxtx.c3239
-rw-r--r--drivers/staging/vt6656/rxtx.h694
-rw-r--r--drivers/staging/vt6656/srom.h127
-rw-r--r--drivers/staging/vt6656/tcrc.c198
-rw-r--r--drivers/staging/vt6656/tcrc.h53
-rw-r--r--drivers/staging/vt6656/tether.c109
-rw-r--r--drivers/staging/vt6656/tether.h236
-rw-r--r--drivers/staging/vt6656/tkip.c272
-rw-r--r--drivers/staging/vt6656/tkip.h (renamed from drivers/staging/vt6655/tbit.h)50
-rw-r--r--drivers/staging/vt6656/tmacro.h62
-rw-r--r--drivers/staging/vt6656/ttype.h162
-rw-r--r--drivers/staging/vt6656/upc.h166
-rw-r--r--drivers/staging/vt6656/usbpipe.c841
-rw-r--r--drivers/staging/vt6656/usbpipe.h99
-rw-r--r--drivers/staging/vt6656/vntconfiguration.dat6
-rw-r--r--drivers/staging/vt6656/wcmd.c1354
-rw-r--r--drivers/staging/vt6656/wcmd.h150
-rw-r--r--drivers/staging/vt6656/wctl.c254
-rw-r--r--drivers/staging/vt6656/wctl.h108
-rw-r--r--drivers/staging/vt6656/wmgr.c4949
-rw-r--r--drivers/staging/vt6656/wmgr.h502
-rw-r--r--drivers/staging/vt6656/wpa.c316
-rw-r--r--drivers/staging/vt6656/wpa.h84
-rw-r--r--drivers/staging/vt6656/wpa2.c363
-rw-r--r--drivers/staging/vt6656/wpa2.h (renamed from drivers/staging/vt6655/umem.h)69
-rw-r--r--drivers/staging/vt6656/wpactl.c1008
-rw-r--r--drivers/staging/vt6656/wpactl.h72
-rw-r--r--drivers/staging/winbond/Kconfig2
-rw-r--r--drivers/staging/winbond/core.h4
-rw-r--r--drivers/staging/winbond/localpara.h1
-rw-r--r--drivers/staging/winbond/mds.c22
-rw-r--r--drivers/staging/winbond/mds_f.h6
-rw-r--r--drivers/staging/winbond/mds_s.h17
-rw-r--r--drivers/staging/winbond/mlmetxrx.c2
-rw-r--r--drivers/staging/winbond/mlmetxrx_f.h32
-rw-r--r--drivers/staging/winbond/mto.c26
-rw-r--r--drivers/staging/winbond/mto.h116
-rw-r--r--drivers/staging/winbond/wb35rx.c7
-rw-r--r--drivers/staging/winbond/wb35tx.c4
-rw-r--r--drivers/staging/winbond/wbhal_f.h2
-rw-r--r--drivers/staging/winbond/wbhal_s.h4
-rw-r--r--drivers/staging/winbond/wbusb.c49
-rw-r--r--drivers/staging/wlan-ng/Kconfig2
-rw-r--r--drivers/staging/wlan-ng/hfa384x_usb.c205
-rw-r--r--drivers/staging/wlan-ng/p80211conv.c12
-rw-r--r--drivers/staging/wlan-ng/p80211hdr.h15
-rw-r--r--drivers/staging/wlan-ng/p80211meta.h6
-rw-r--r--drivers/staging/wlan-ng/p80211mgmt.h6
-rw-r--r--drivers/staging/wlan-ng/p80211msg.h6
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.c64
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.h3
-rw-r--r--drivers/staging/wlan-ng/p80211req.c12
-rw-r--r--drivers/staging/wlan-ng/p80211types.h4
-rw-r--r--drivers/staging/wlan-ng/p80211wep.c27
-rw-r--r--drivers/staging/wlan-ng/p80211wext.c77
-rw-r--r--drivers/staging/wlan-ng/prism2fw.c509
-rw-r--r--drivers/staging/wlan-ng/prism2mgmt.c23
-rw-r--r--drivers/staging/wlan-ng/prism2mib.c144
-rw-r--r--drivers/staging/wlan-ng/prism2sta.c153
-rw-r--r--drivers/staging/wlan-ng/prism2usb.c10
-rw-r--r--drivers/telephony/ixj_pcmcia.c36
-rw-r--r--drivers/thermal/Kconfig1
-rw-r--r--drivers/thermal/thermal_sys.c10
-rw-r--r--drivers/uio/Kconfig15
-rw-r--r--drivers/uio/Makefile1
-rw-r--r--drivers/uio/uio.c3
-rw-r--r--drivers/uio/uio_pci_generic.c207
-rw-r--r--drivers/uio/uio_pdrv_genirq.c55
-rw-r--r--drivers/usb/Kconfig4
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/class/cdc-acm.c25
-rw-r--r--drivers/usb/class/cdc-wdm.c32
-rw-r--r--drivers/usb/class/usblp.c4
-rw-r--r--drivers/usb/class/usbtmc.c88
-rw-r--r--drivers/usb/core/config.c2
-rw-r--r--drivers/usb/core/devio.c247
-rw-r--r--drivers/usb/core/driver.c75
-rw-r--r--drivers/usb/core/endpoint.c2
-rw-r--r--drivers/usb/core/file.c8
-rw-r--r--drivers/usb/core/generic.c4
-rw-r--r--drivers/usb/core/hcd.c111
-rw-r--r--drivers/usb/core/hcd.h5
-rw-r--r--drivers/usb/core/hub.c128
-rw-r--r--drivers/usb/core/inode.c3
-rw-r--r--drivers/usb/core/message.c32
-rw-r--r--drivers/usb/core/sysfs.c4
-rw-r--r--drivers/usb/core/usb.c17
-rw-r--r--drivers/usb/core/usb.h11
-rw-r--r--drivers/usb/early/Makefile5
-rw-r--r--drivers/usb/early/ehci-dbgp.c996
-rw-r--r--drivers/usb/gadget/Kconfig60
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/amd5536udc.c105
-rw-r--r--drivers/usb/gadget/at91_udc.c1
-rw-r--r--drivers/usb/gadget/audio.c24
-rw-r--r--drivers/usb/gadget/composite.c2
-rw-r--r--drivers/usb/gadget/dummy_hcd.c5
-rw-r--r--drivers/usb/gadget/ether.c26
-rw-r--r--drivers/usb/gadget/f_audio.c97
-rw-r--r--drivers/usb/gadget/f_eem.c562
-rw-r--r--drivers/usb/gadget/f_loopback.c1
-rw-r--r--drivers/usb/gadget/f_obex.c1
-rw-r--r--drivers/usb/gadget/f_phonet.c93
-rw-r--r--drivers/usb/gadget/f_rndis.c15
-rw-r--r--drivers/usb/gadget/f_sourcesink.c1
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.c4
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c2
-rw-r--r--drivers/usb/gadget/gadget_chips.h8
-rw-r--r--drivers/usb/gadget/gmidi.c8
-rw-r--r--drivers/usb/gadget/imx_udc.c8
-rw-r--r--drivers/usb/gadget/inode.c3
-rw-r--r--drivers/usb/gadget/m66592-udc.c286
-rw-r--r--drivers/usb/gadget/m66592-udc.h90
-rw-r--r--drivers/usb/gadget/printer.c2
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c49
-rw-r--r--drivers/usb/gadget/pxa25x_udc.h1
-rw-r--r--drivers/usb/gadget/r8a66597-udc.c1689
-rw-r--r--drivers/usb/gadget/r8a66597-udc.h275
-rw-r--r--drivers/usb/gadget/rndis.c13
-rw-r--r--drivers/usb/gadget/rndis.h3
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c6
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c3
-rw-r--r--drivers/usb/gadget/u_audio.c11
-rw-r--r--drivers/usb/gadget/u_ether.c97
-rw-r--r--drivers/usb/gadget/u_ether.h12
-rw-r--r--drivers/usb/gadget/u_serial.c1
-rw-r--r--drivers/usb/host/Kconfig25
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-atmel.c230
-rw-r--r--drivers/usb/host/ehci-au1xxx.c29
-rw-r--r--drivers/usb/host/ehci-dbg.c46
-rw-r--r--drivers/usb/host/ehci-hcd.c91
-rw-r--r--drivers/usb/host/ehci-hub.c84
-rw-r--r--drivers/usb/host/ehci-mem.c26
-rw-r--r--drivers/usb/host/ehci-pci.c48
-rw-r--r--drivers/usb/host/ehci-q.c111
-rw-r--r--drivers/usb/host/ehci-sched.c125
-rw-r--r--drivers/usb/host/ehci-w90x900.c181
-rw-r--r--drivers/usb/host/ehci.h18
-rw-r--r--drivers/usb/host/isp1362-hcd.c2909
-rw-r--r--drivers/usb/host/isp1362.h1079
-rw-r--r--drivers/usb/host/isp1760-hcd.c4
-rw-r--r--drivers/usb/host/isp1760-hcd.h2
-rw-r--r--drivers/usb/host/isp1760-if.c21
-rw-r--r--drivers/usb/host/ohci-at91.c2
-rw-r--r--drivers/usb/host/ohci-au1xxx.c27
-rw-r--r--drivers/usb/host/ohci-ep93xx.c1
-rw-r--r--drivers/usb/host/ohci-hcd.c6
-rw-r--r--drivers/usb/host/ohci-pci.c20
-rw-r--r--drivers/usb/host/ohci-pxa27x.c34
-rw-r--r--drivers/usb/host/ohci-q.c20
-rw-r--r--drivers/usb/host/ohci.h9
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c1
-rw-r--r--drivers/usb/host/r8a66597-hcd.c233
-rw-r--r--drivers/usb/host/r8a66597.h440
-rw-r--r--drivers/usb/host/sl811-hcd.c8
-rw-r--r--drivers/usb/host/sl811_cs.c49
-rw-r--r--drivers/usb/host/uhci-hcd.c2
-rw-r--r--drivers/usb/host/uhci-q.c1
-rw-r--r--drivers/usb/host/whci/asl.c35
-rw-r--r--drivers/usb/host/whci/debug.c6
-rw-r--r--drivers/usb/host/whci/hcd.c8
-rw-r--r--drivers/usb/host/whci/pzl.c36
-rw-r--r--drivers/usb/host/whci/qset.c4
-rw-r--r--drivers/usb/host/whci/whci-hc.h1
-rw-r--r--drivers/usb/host/xhci-dbg.c5
-rw-r--r--drivers/usb/host/xhci-hcd.c559
-rw-r--r--drivers/usb/host/xhci-mem.c150
-rw-r--r--drivers/usb/host/xhci-pci.c16
-rw-r--r--drivers/usb/host/xhci-ring.c384
-rw-r--r--drivers/usb/host/xhci.h113
-rw-r--r--drivers/usb/image/microtek.c37
-rw-r--r--drivers/usb/misc/idmouse.c21
-rw-r--r--drivers/usb/misc/iowarrior.c4
-rw-r--r--drivers/usb/misc/ldusb.c6
-rw-r--r--drivers/usb/misc/legousbtower.c10
-rw-r--r--drivers/usb/misc/rio500.c3
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c53
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.h2
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_init.c1
-rw-r--r--drivers/usb/misc/usblcd.c3
-rw-r--r--drivers/usb/misc/usbsevseg.c69
-rw-r--r--drivers/usb/mon/Kconfig4
-rw-r--r--drivers/usb/mon/Makefile2
-rw-r--r--drivers/usb/mon/mon_bin.c25
-rw-r--r--drivers/usb/mon/mon_dma.c95
-rw-r--r--drivers/usb/mon/mon_main.c1
-rw-r--r--drivers/usb/mon/mon_text.c14
-rw-r--r--drivers/usb/mon/usb_mon.h14
-rw-r--r--drivers/usb/musb/Kconfig4
-rw-r--r--drivers/usb/musb/blackfin.c1
-rw-r--r--drivers/usb/musb/cppi_dma.c10
-rw-r--r--drivers/usb/musb/musb_core.c30
-rw-r--r--drivers/usb/musb/musb_core.h7
-rw-r--r--drivers/usb/musb/musb_gadget.c79
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c3
-rw-r--r--drivers/usb/musb/musb_host.c5
-rw-r--r--drivers/usb/musb/musb_regs.h9
-rw-r--r--drivers/usb/otg/isp1301_omap.c23
-rw-r--r--drivers/usb/serial/aircable.c10
-rw-r--r--drivers/usb/serial/ark3116.c73
-rw-r--r--drivers/usb/serial/belkin_sa.c4
-rw-r--r--drivers/usb/serial/ch341.c57
-rw-r--r--drivers/usb/serial/console.c32
-rw-r--r--drivers/usb/serial/cp210x.c34
-rw-r--r--drivers/usb/serial/cyberjack.c4
-rw-r--r--drivers/usb/serial/cypress_m8.c30
-rw-r--r--drivers/usb/serial/cypress_m8.h2
-rw-r--r--drivers/usb/serial/digi_acceleport.c14
-rw-r--r--drivers/usb/serial/empeg.c20
-rw-r--r--drivers/usb/serial/ftdi_sio.c438
-rw-r--r--drivers/usb/serial/ftdi_sio.h10
-rw-r--r--drivers/usb/serial/garmin_gps.c15
-rw-r--r--drivers/usb/serial/generic.c211
-rw-r--r--drivers/usb/serial/io_edgeport.c8
-rw-r--r--drivers/usb/serial/io_ti.c3
-rw-r--r--drivers/usb/serial/ipaq.c18
-rw-r--r--drivers/usb/serial/ipw.c3
-rw-r--r--drivers/usb/serial/ir-usb.c6
-rw-r--r--drivers/usb/serial/iuu_phoenix.c149
-rw-r--r--drivers/usb/serial/keyspan.c3
-rw-r--r--drivers/usb/serial/keyspan.h3
-rw-r--r--drivers/usb/serial/keyspan_pda.c4
-rw-r--r--drivers/usb/serial/kl5kusb105.c14
-rw-r--r--drivers/usb/serial/kobil_sct.c28
-rw-r--r--drivers/usb/serial/mct_u232.c29
-rw-r--r--drivers/usb/serial/mos7720.c123
-rw-r--r--drivers/usb/serial/mos7840.c118
-rw-r--r--drivers/usb/serial/moto_modem.c2
-rw-r--r--drivers/usb/serial/navman.c3
-rw-r--r--drivers/usb/serial/omninet.c6
-rw-r--r--drivers/usb/serial/opticon.c16
-rw-r--r--drivers/usb/serial/option.c163
-rw-r--r--drivers/usb/serial/oti6858.c33
-rw-r--r--drivers/usb/serial/pl2303.c84
-rw-r--r--drivers/usb/serial/pl2303.h4
-rw-r--r--drivers/usb/serial/sierra.c193
-rw-r--r--drivers/usb/serial/spcp8x5.c28
-rw-r--r--drivers/usb/serial/symbolserial.c25
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c6
-rw-r--r--drivers/usb/serial/usb-serial.c414
-rw-r--r--drivers/usb/serial/usb_debug.c5
-rw-r--r--drivers/usb/serial/visor.c34
-rw-r--r--drivers/usb/serial/whiteheat.c21
-rw-r--r--drivers/usb/storage/datafab.c4
-rw-r--r--drivers/usb/storage/initializers.c2
-rw-r--r--drivers/usb/storage/jumpshot.c2
-rw-r--r--drivers/usb/storage/onetouch.c2
-rw-r--r--drivers/usb/storage/transport.c46
-rw-r--r--drivers/usb/storage/unusual_devs.h29
-rw-r--r--drivers/usb/usb-skeleton.c252
-rw-r--r--drivers/usb/wusbcore/security.c41
-rw-r--r--drivers/usb/wusbcore/wa-hc.h2
-rw-r--r--drivers/uwb/hwa-rc.c3
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h3
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/netdev.c2
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/tx.c3
-rw-r--r--drivers/uwb/lc-dev.c2
-rw-r--r--drivers/uwb/lc-rc.c2
-rw-r--r--drivers/uwb/reset.c21
-rw-r--r--drivers/uwb/umc-bus.c2
-rw-r--r--drivers/uwb/uwb-debug.c6
-rw-r--r--drivers/uwb/uwbd.c4
-rw-r--r--drivers/uwb/whc-rc.c4
-rw-r--r--drivers/video/Kconfig60
-rw-r--r--drivers/video/Makefile3
-rw-r--r--drivers/video/atafb.c6
-rw-r--r--drivers/video/atmel_lcdfb.c17
-rw-r--r--drivers/video/aty/atyfb_base.c829
-rw-r--r--drivers/video/au1100fb.c7
-rw-r--r--drivers/video/backlight/Kconfig35
-rw-r--r--drivers/video/backlight/Makefile4
-rw-r--r--drivers/video/backlight/adp5520_bl.c377
-rw-r--r--drivers/video/backlight/adx_bl.c178
-rw-r--r--drivers/video/backlight/backlight.c42
-rw-r--r--drivers/video/backlight/corgi_lcd.c6
-rw-r--r--drivers/video/backlight/da903x_bl.c20
-rw-r--r--drivers/video/backlight/hp680_bl.c2
-rw-r--r--drivers/video/backlight/lcd.c2
-rw-r--r--drivers/video/backlight/lms283gf05.c242
-rw-r--r--drivers/video/backlight/ltv350qv.c1
-rw-r--r--drivers/video/backlight/mbp_nvidia_bl.c36
-rw-r--r--drivers/video/backlight/tdo24m.c1
-rw-r--r--drivers/video/backlight/tosa_lcd.c2
-rw-r--r--drivers/video/backlight/vgg2432a4.c3
-rw-r--r--drivers/video/backlight/wm831x_bl.c250
-rw-r--r--drivers/video/cfbcopyarea.c2
-rw-r--r--drivers/video/console/.gitignore2
-rw-r--r--drivers/video/console/Kconfig9
-rw-r--r--drivers/video/console/Makefile12
-rw-r--r--drivers/video/console/bitblit.c8
-rw-r--r--drivers/video/console/fbcon.c63
-rw-r--r--drivers/video/console/newport_con.c2
-rw-r--r--drivers/video/console/prom.uni11
-rw-r--r--drivers/video/console/promcon.c598
-rw-r--r--drivers/video/console/vgacon.c9
-rw-r--r--drivers/video/da8xx-fb.c892
-rw-r--r--drivers/video/ep93xx-fb.c646
-rw-r--r--drivers/video/fb_defio.c2
-rw-r--r--drivers/video/fbmem.c21
-rw-r--r--drivers/video/gbefb.c2
-rw-r--r--drivers/video/imxfb.c186
-rw-r--r--drivers/video/matrox/g450_pll.c209
-rw-r--r--drivers/video/matrox/g450_pll.h8
-rw-r--r--drivers/video/matrox/i2c-matroxfb.c18
-rw-r--r--drivers/video/matrox/matroxfb_DAC1064.c614
-rw-r--r--drivers/video/matrox/matroxfb_DAC1064.h4
-rw-r--r--drivers/video/matrox/matroxfb_Ti3026.c258
-rw-r--r--drivers/video/matrox/matroxfb_accel.c129
-rw-r--r--drivers/video/matrox/matroxfb_accel.h2
-rw-r--r--drivers/video/matrox/matroxfb_base.c772
-rw-r--r--drivers/video/matrox/matroxfb_base.h80
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.c160
-rw-r--r--drivers/video/matrox/matroxfb_g450.c185
-rw-r--r--drivers/video/matrox/matroxfb_g450.h8
-rw-r--r--drivers/video/matrox/matroxfb_maven.c50
-rw-r--r--drivers/video/matrox/matroxfb_misc.c288
-rw-r--r--drivers/video/matrox/matroxfb_misc.h15
-rw-r--r--drivers/video/msm/Makefile19
-rw-r--r--drivers/video/msm/mddi.c827
-rw-r--r--drivers/video/msm/mddi_client_dummy.c97
-rw-r--r--drivers/video/msm/mddi_client_nt35399.c256
-rw-r--r--drivers/video/msm/mddi_client_toshiba.c284
-rw-r--r--drivers/video/msm/mddi_hw.h305
-rw-r--r--drivers/video/msm/mdp.c520
-rw-r--r--drivers/video/msm/mdp_csc_table.h582
-rw-r--r--drivers/video/msm/mdp_hw.h621
-rw-r--r--drivers/video/msm/mdp_ppp.c730
-rw-r--r--drivers/video/msm/mdp_scale_tables.c766
-rw-r--r--drivers/video/msm/mdp_scale_tables.h38
-rw-r--r--drivers/video/msm/msm_fb.c636
-rw-r--r--drivers/video/omap/Kconfig82
-rw-r--r--drivers/video/omap/Makefile12
-rw-r--r--drivers/video/omap/blizzard.c101
-rw-r--r--drivers/video/omap/dispc.c138
-rw-r--r--drivers/video/omap/dispc.h7
-rw-r--r--drivers/video/omap/hwa742.c2
-rw-r--r--drivers/video/omap/lcd_2430sdp.c202
-rw-r--r--drivers/video/omap/lcd_ams_delta.c137
-rw-r--r--drivers/video/omap/lcd_apollon.c138
-rw-r--r--drivers/video/omap/lcd_h3.c4
-rw-r--r--drivers/video/omap/lcd_h4.c4
-rw-r--r--drivers/video/omap/lcd_inn1510.c4
-rw-r--r--drivers/video/omap/lcd_inn1610.c4
-rw-r--r--drivers/video/omap/lcd_ldp.c200
-rw-r--r--drivers/video/omap/lcd_mipid.c625
-rw-r--r--drivers/video/omap/lcd_omap2evm.c191
-rw-r--r--drivers/video/omap/lcd_omap3beagle.c130
-rw-r--r--drivers/video/omap/lcd_omap3evm.c192
-rw-r--r--drivers/video/omap/lcd_osk.c4
-rw-r--r--drivers/video/omap/lcd_overo.c179
-rw-r--r--drivers/video/omap/lcd_palmte.c4
-rw-r--r--drivers/video/omap/lcd_palmtt.c4
-rw-r--r--drivers/video/omap/lcd_palmz71.c4
-rw-r--r--drivers/video/omap/omapfb_main.c86
-rw-r--r--drivers/video/omap/rfbi.c7
-rw-r--r--drivers/video/platinumfb.c12
-rw-r--r--drivers/video/ps3fb.c2
-rw-r--r--drivers/video/pxafb.c32
-rw-r--r--drivers/video/s3c-fb.c2
-rw-r--r--drivers/video/s3c2410fb.c6
-rw-r--r--drivers/video/sa1100fb.c2
-rw-r--r--drivers/video/savage/savagefb_driver.c20
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c292
-rw-r--r--drivers/video/sis/sis_main.c4
-rw-r--r--drivers/video/sis/vstruct.h2
-rw-r--r--drivers/video/tmiofb.c2
-rw-r--r--drivers/video/uvesafb.c34
-rw-r--r--drivers/video/via/accel.c589
-rw-r--r--drivers/video/via/accel.h13
-rw-r--r--drivers/video/via/chip.h4
-rw-r--r--drivers/video/via/dvi.c6
-rw-r--r--drivers/video/via/global.c3
-rw-r--r--drivers/video/via/global.h2
-rw-r--r--drivers/video/via/hw.c474
-rw-r--r--drivers/video/via/hw.h57
-rw-r--r--drivers/video/via/ioctl.h6
-rw-r--r--drivers/video/via/lcd.c16
-rw-r--r--drivers/video/via/share.h98
-rw-r--r--drivers/video/via/via_i2c.c64
-rw-r--r--drivers/video/via/viafbdev.c1049
-rw-r--r--drivers/video/via/viafbdev.h61
-rw-r--r--drivers/video/via/viamode.c100
-rw-r--r--drivers/video/via/viamode.h141
-rw-r--r--drivers/video/via/vt1636.c4
-rw-r--r--drivers/virtio/virtio_balloon.c4
-rw-r--r--drivers/virtio/virtio_pci.c136
-rw-r--r--drivers/virtio/virtio_ring.c9
-rw-r--r--drivers/vlynq/vlynq.c3
-rw-r--r--drivers/w1/masters/ds2482.c35
-rw-r--r--drivers/w1/w1_netlink.c3
-rw-r--r--drivers/watchdog/Kconfig45
-rw-r--r--drivers/watchdog/Makefile4
-rw-r--r--drivers/watchdog/adx_wdt.c354
-rw-r--r--drivers/watchdog/ar7_wdt.c107
-rw-r--r--drivers/watchdog/booke_wdt.c57
-rw-r--r--drivers/watchdog/coh901327_wdt.c2
-rw-r--r--drivers/watchdog/davinci_wdt.c19
-rw-r--r--drivers/watchdog/iop_wdt.c2
-rw-r--r--drivers/watchdog/nuc900_wdt.c353
-rw-r--r--drivers/watchdog/pnx4008_wdt.c4
-rw-r--r--drivers/watchdog/rc32434_wdt.c4
-rw-r--r--drivers/watchdog/riowd.c2
-rw-r--r--drivers/watchdog/rm9k_wdt.c2
-rw-r--r--drivers/watchdog/sbc_fitpc2_wdt.c267
-rw-r--r--drivers/watchdog/sc1200wdt.c2
-rw-r--r--drivers/watchdog/wdt_pci.c21
-rw-r--r--drivers/watchdog/wm831x_wdt.c441
-rw-r--r--drivers/xen/Makefile3
-rw-r--r--drivers/xen/balloon.c6
-rw-r--r--drivers/xen/events.c13
-rw-r--r--drivers/xen/evtchn.c1
-rw-r--r--drivers/xen/xenfs/xenbus.c1
4558 files changed, 664320 insertions, 367262 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index bc4205d2fc3c..6ee53c7a57a1 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_PARISC) += parisc/
obj-$(CONFIG_RAPIDIO) += rapidio/
obj-y += video/
obj-$(CONFIG_ACPI) += acpi/
+obj-$(CONFIG_SFI) += sfi/
# PnP must come after ACPI since it will eventually need to check if acpi
# was used and do nothing if so
obj-$(CONFIG_PNP) += pnp/
@@ -42,6 +43,8 @@ obj-y += macintosh/
obj-$(CONFIG_IDE) += ide/
obj-$(CONFIG_SCSI) += scsi/
obj-$(CONFIG_ATA) += ata/
+obj-$(CONFIG_MTD) += mtd/
+obj-$(CONFIG_SPI) += spi/
obj-y += net/
obj-$(CONFIG_ATM) += atm/
obj-$(CONFIG_FUSION) += message/
@@ -50,8 +53,6 @@ obj-y += ieee1394/
obj-$(CONFIG_UIO) += uio/
obj-y += cdrom/
obj-y += auxdisplay/
-obj-$(CONFIG_MTD) += mtd/
-obj-$(CONFIG_SPI) += spi/
obj-$(CONFIG_PCCARD) += pcmcia/
obj-$(CONFIG_DIO) += dio/
obj-$(CONFIG_SBUS) += sbus/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 7ec7d88c5999..93d2c7971df6 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -60,7 +60,11 @@ config ACPI_PROCFS
/proc/acpi/fadt (/sys/firmware/acpi/tables/FACP)
/proc/acpi/debug_layer (/sys/module/acpi/parameters/debug_layer)
/proc/acpi/debug_level (/sys/module/acpi/parameters/debug_level)
-
+ /proc/acpi/processor/*/power (/sys/devices/system/cpu/*/cpuidle/*)
+ /proc/acpi/processor/*/performance (/sys/devices/system/cpu/*/
+ cpufreq/*)
+ /proc/acpi/processor/*/throttling (/sys/class/thermal/
+ cooling_device*/*)
This option has no effect on /proc/acpi/ files
and functions which do not yet exist in /sys.
@@ -82,6 +86,17 @@ config ACPI_PROCFS_POWER
Say N to delete power /proc/acpi/ directories that have moved to /sys/
+config ACPI_POWER_METER
+ tristate "ACPI 4.0 power meter"
+ depends on HWMON
+ help
+ This driver exposes ACPI 4.0 power meters as hardware monitoring
+ devices. Say Y (or M) if you have a computer with ACPI 4.0 firmware
+ and a power meter.
+
+ To compile this driver as a module, choose M here:
+ the module will be called power-meter.
+
config ACPI_SYSFS_POWER
bool "Future power /sys interface"
select POWER_SUPPLY
@@ -196,6 +211,18 @@ config ACPI_HOTPLUG_CPU
select ACPI_CONTAINER
default y
+config ACPI_PROCESSOR_AGGREGATOR
+ tristate "Processor Aggregator"
+ depends on ACPI_PROCESSOR
+ depends on EXPERIMENTAL
+ depends on X86
+ help
+ ACPI 4.0 defines processor Aggregator, which enables OS to perform
+ specific processor configuration and control that applies to all
+ processors in the platform. Currently only logical processor idling
+ is defined, which is to reduce power consumption. This driver
+ supports the new device.
+
config ACPI_THERMAL
tristate "Thermal Zone"
depends on ACPI_PROCESSOR
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 03a985be3fe3..7702118509a0 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -56,8 +56,11 @@ obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_SBS) += sbshc.o
obj-$(CONFIG_ACPI_SBS) += sbs.o
+obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o
# processor has its own "processor." module_param namespace
processor-y := processor_core.o processor_throttling.o
processor-y += processor_idle.o processor_thermal.o
processor-$(CONFIG_CPU_FREQ) += processor_perflib.o
+
+obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 0df8fcb687d6..b6ed60b57b0d 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -37,6 +37,8 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#define PREFIX "ACPI: "
+
#define ACPI_AC_CLASS "ac_adapter"
#define ACPI_AC_DEVICE_NAME "AC Adapter"
#define ACPI_AC_FILE_STATE "state"
@@ -243,6 +245,7 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event)
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event,
(u32) ac->state);
+ acpi_notifier_call_chain(device, event, (u32) ac->state);
#ifdef CONFIG_ACPI_SYSFS_POWER
kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
#endif
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 9a62224cc278..28ccdbc05ac8 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -53,7 +53,6 @@ MODULE_LICENSE("GPL");
static int acpi_memory_device_add(struct acpi_device *device);
static int acpi_memory_device_remove(struct acpi_device *device, int type);
-static int acpi_memory_device_start(struct acpi_device *device);
static const struct acpi_device_id memory_device_ids[] = {
{ACPI_MEMORY_DEVICE_HID, 0},
@@ -68,7 +67,6 @@ static struct acpi_driver acpi_memory_device_driver = {
.ops = {
.add = acpi_memory_device_add,
.remove = acpi_memory_device_remove,
- .start = acpi_memory_device_start,
},
};
@@ -431,28 +429,6 @@ static int acpi_memory_device_add(struct acpi_device *device)
printk(KERN_DEBUG "%s \n", acpi_device_name(device));
- return result;
-}
-
-static int acpi_memory_device_remove(struct acpi_device *device, int type)
-{
- struct acpi_memory_device *mem_device = NULL;
-
-
- if (!device || !acpi_driver_data(device))
- return -EINVAL;
-
- mem_device = acpi_driver_data(device);
- kfree(mem_device);
-
- return 0;
-}
-
-static int acpi_memory_device_start (struct acpi_device *device)
-{
- struct acpi_memory_device *mem_device;
- int result = 0;
-
/*
* Early boot code has recognized memory area by EFI/E820.
* If DSDT shows these memory devices on boot, hotplug is not necessary
@@ -462,8 +438,6 @@ static int acpi_memory_device_start (struct acpi_device *device)
if (!acpi_hotmem_initialized)
return 0;
- mem_device = acpi_driver_data(device);
-
if (!acpi_memory_check_device(mem_device)) {
/* call add_memory func */
result = acpi_memory_enable_device(mem_device);
@@ -474,6 +448,20 @@ static int acpi_memory_device_start (struct acpi_device *device)
return result;
}
+static int acpi_memory_device_remove(struct acpi_device *device, int type)
+{
+ struct acpi_memory_device *mem_device = NULL;
+
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+
+ mem_device = acpi_driver_data(device);
+ kfree(mem_device);
+
+ return 0;
+}
+
/*
* Helper function to check for memory device
*/
@@ -481,26 +469,23 @@ static acpi_status is_memory_device(acpi_handle handle)
{
char *hardware_id;
acpi_status status;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_device_info *info;
-
- status = acpi_get_object_info(handle, &buffer);
+ status = acpi_get_object_info(handle, &info);
if (ACPI_FAILURE(status))
return status;
- info = buffer.pointer;
if (!(info->valid & ACPI_VALID_HID)) {
- kfree(buffer.pointer);
+ kfree(info);
return AE_ERROR;
}
- hardware_id = info->hardware_id.value;
+ hardware_id = info->hardware_id.string;
if ((hardware_id == NULL) ||
(strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID)))
status = AE_ERROR;
- kfree(buffer.pointer);
+ kfree(info);
return status;
}
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
new file mode 100644
index 000000000000..0d2cdb86158b
--- /dev/null
+++ b/drivers/acpi/acpi_pad.c
@@ -0,0 +1,514 @@
+/*
+ * acpi_pad.c ACPI Processor Aggregator Driver
+ *
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/cpu.h>
+#include <linux/clockchips.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+#define ACPI_PROCESSOR_AGGREGATOR_CLASS "processor_aggregator"
+#define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator"
+#define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80
+static DEFINE_MUTEX(isolated_cpus_lock);
+
+#define MWAIT_SUBSTATE_MASK (0xf)
+#define MWAIT_CSTATE_MASK (0xf)
+#define MWAIT_SUBSTATE_SIZE (4)
+#define CPUID_MWAIT_LEAF (5)
+#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
+#define CPUID5_ECX_INTERRUPT_BREAK (0x2)
+static unsigned long power_saving_mwait_eax;
+static void power_saving_mwait_init(void)
+{
+ unsigned int eax, ebx, ecx, edx;
+ unsigned int highest_cstate = 0;
+ unsigned int highest_subcstate = 0;
+ int i;
+
+ if (!boot_cpu_has(X86_FEATURE_MWAIT))
+ return;
+ if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
+ return;
+
+ cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
+
+ if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
+ !(ecx & CPUID5_ECX_INTERRUPT_BREAK))
+ return;
+
+ edx >>= MWAIT_SUBSTATE_SIZE;
+ for (i = 0; i < 7 && edx; i++, edx >>= MWAIT_SUBSTATE_SIZE) {
+ if (edx & MWAIT_SUBSTATE_MASK) {
+ highest_cstate = i;
+ highest_subcstate = edx & MWAIT_SUBSTATE_MASK;
+ }
+ }
+ power_saving_mwait_eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
+ (highest_subcstate - 1);
+
+ for_each_online_cpu(i)
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &i);
+
+#if defined(CONFIG_GENERIC_TIME) && defined(CONFIG_X86)
+ switch (boot_cpu_data.x86_vendor) {
+ case X86_VENDOR_AMD:
+ case X86_VENDOR_INTEL:
+ /*
+ * AMD Fam10h TSC will tick in all
+ * C/P/S0/S1 states when this bit is set.
+ */
+ if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
+ return;
+
+ /*FALL THROUGH*/
+ default:
+ /* TSC could halt in idle, so notify users */
+ mark_tsc_unstable("TSC halts in idle");
+ }
+#endif
+}
+
+static unsigned long cpu_weight[NR_CPUS];
+static int tsk_in_cpu[NR_CPUS] = {[0 ... NR_CPUS-1] = -1};
+static DECLARE_BITMAP(pad_busy_cpus_bits, NR_CPUS);
+static void round_robin_cpu(unsigned int tsk_index)
+{
+ struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits);
+ cpumask_var_t tmp;
+ int cpu;
+ unsigned long min_weight = -1, preferred_cpu;
+
+ if (!alloc_cpumask_var(&tmp, GFP_KERNEL))
+ return;
+
+ mutex_lock(&isolated_cpus_lock);
+ cpumask_clear(tmp);
+ for_each_cpu(cpu, pad_busy_cpus)
+ cpumask_or(tmp, tmp, topology_thread_cpumask(cpu));
+ cpumask_andnot(tmp, cpu_online_mask, tmp);
+ /* avoid HT sibilings if possible */
+ if (cpumask_empty(tmp))
+ cpumask_andnot(tmp, cpu_online_mask, pad_busy_cpus);
+ if (cpumask_empty(tmp)) {
+ mutex_unlock(&isolated_cpus_lock);
+ return;
+ }
+ for_each_cpu(cpu, tmp) {
+ if (cpu_weight[cpu] < min_weight) {
+ min_weight = cpu_weight[cpu];
+ preferred_cpu = cpu;
+ }
+ }
+
+ if (tsk_in_cpu[tsk_index] != -1)
+ cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
+ tsk_in_cpu[tsk_index] = preferred_cpu;
+ cpumask_set_cpu(preferred_cpu, pad_busy_cpus);
+ cpu_weight[preferred_cpu]++;
+ mutex_unlock(&isolated_cpus_lock);
+
+ set_cpus_allowed_ptr(current, cpumask_of(preferred_cpu));
+}
+
+static void exit_round_robin(unsigned int tsk_index)
+{
+ struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits);
+ cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
+ tsk_in_cpu[tsk_index] = -1;
+}
+
+static unsigned int idle_pct = 5; /* percentage */
+static unsigned int round_robin_time = 10; /* second */
+static int power_saving_thread(void *data)
+{
+ struct sched_param param = {.sched_priority = 1};
+ int do_sleep;
+ unsigned int tsk_index = (unsigned long)data;
+ u64 last_jiffies = 0;
+
+ sched_setscheduler(current, SCHED_RR, &param);
+
+ while (!kthread_should_stop()) {
+ int cpu;
+ u64 expire_time;
+
+ try_to_freeze();
+
+ /* round robin to cpus */
+ if (last_jiffies + round_robin_time * HZ < jiffies) {
+ last_jiffies = jiffies;
+ round_robin_cpu(tsk_index);
+ }
+
+ do_sleep = 0;
+
+ current_thread_info()->status &= ~TS_POLLING;
+ /*
+ * TS_POLLING-cleared state must be visible before we test
+ * NEED_RESCHED:
+ */
+ smp_mb();
+
+ expire_time = jiffies + HZ * (100 - idle_pct) / 100;
+
+ while (!need_resched()) {
+ local_irq_disable();
+ cpu = smp_processor_id();
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
+ &cpu);
+ stop_critical_timings();
+
+ __monitor((void *)&current_thread_info()->flags, 0, 0);
+ smp_mb();
+ if (!need_resched())
+ __mwait(power_saving_mwait_eax, 1);
+
+ start_critical_timings();
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
+ &cpu);
+ local_irq_enable();
+
+ if (jiffies > expire_time) {
+ do_sleep = 1;
+ break;
+ }
+ }
+
+ current_thread_info()->status |= TS_POLLING;
+
+ /*
+ * current sched_rt has threshold for rt task running time.
+ * When a rt task uses 95% CPU time, the rt thread will be
+ * scheduled out for 5% CPU time to not starve other tasks. But
+ * the mechanism only works when all CPUs have RT task running,
+ * as if one CPU hasn't RT task, RT task from other CPUs will
+ * borrow CPU time from this CPU and cause RT task use > 95%
+ * CPU time. To make 'avoid staration' work, takes a nap here.
+ */
+ if (do_sleep)
+ schedule_timeout_killable(HZ * idle_pct / 100);
+ }
+
+ exit_round_robin(tsk_index);
+ return 0;
+}
+
+static struct task_struct *ps_tsks[NR_CPUS];
+static unsigned int ps_tsk_num;
+static int create_power_saving_task(void)
+{
+ ps_tsks[ps_tsk_num] = kthread_run(power_saving_thread,
+ (void *)(unsigned long)ps_tsk_num,
+ "power_saving/%d", ps_tsk_num);
+ if (ps_tsks[ps_tsk_num]) {
+ ps_tsk_num++;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void destroy_power_saving_task(void)
+{
+ if (ps_tsk_num > 0) {
+ ps_tsk_num--;
+ kthread_stop(ps_tsks[ps_tsk_num]);
+ }
+}
+
+static void set_power_saving_task_num(unsigned int num)
+{
+ if (num > ps_tsk_num) {
+ while (ps_tsk_num < num) {
+ if (create_power_saving_task())
+ return;
+ }
+ } else if (num < ps_tsk_num) {
+ while (ps_tsk_num > num)
+ destroy_power_saving_task();
+ }
+}
+
+static int acpi_pad_idle_cpus(unsigned int num_cpus)
+{
+ get_online_cpus();
+
+ num_cpus = min_t(unsigned int, num_cpus, num_online_cpus());
+ set_power_saving_task_num(num_cpus);
+
+ put_online_cpus();
+ return 0;
+}
+
+static uint32_t acpi_pad_idle_cpus_num(void)
+{
+ return ps_tsk_num;
+}
+
+static ssize_t acpi_pad_rrtime_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned long num;
+ if (strict_strtoul(buf, 0, &num))
+ return -EINVAL;
+ if (num < 1 || num >= 100)
+ return -EINVAL;
+ mutex_lock(&isolated_cpus_lock);
+ round_robin_time = num;
+ mutex_unlock(&isolated_cpus_lock);
+ return count;
+}
+
+static ssize_t acpi_pad_rrtime_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%d", round_robin_time);
+}
+static DEVICE_ATTR(rrtime, S_IRUGO|S_IWUSR,
+ acpi_pad_rrtime_show,
+ acpi_pad_rrtime_store);
+
+static ssize_t acpi_pad_idlepct_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned long num;
+ if (strict_strtoul(buf, 0, &num))
+ return -EINVAL;
+ if (num < 1 || num >= 100)
+ return -EINVAL;
+ mutex_lock(&isolated_cpus_lock);
+ idle_pct = num;
+ mutex_unlock(&isolated_cpus_lock);
+ return count;
+}
+
+static ssize_t acpi_pad_idlepct_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%d", idle_pct);
+}
+static DEVICE_ATTR(idlepct, S_IRUGO|S_IWUSR,
+ acpi_pad_idlepct_show,
+ acpi_pad_idlepct_store);
+
+static ssize_t acpi_pad_idlecpus_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned long num;
+ if (strict_strtoul(buf, 0, &num))
+ return -EINVAL;
+ mutex_lock(&isolated_cpus_lock);
+ acpi_pad_idle_cpus(num);
+ mutex_unlock(&isolated_cpus_lock);
+ return count;
+}
+
+static ssize_t acpi_pad_idlecpus_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return cpumask_scnprintf(buf, PAGE_SIZE,
+ to_cpumask(pad_busy_cpus_bits));
+}
+static DEVICE_ATTR(idlecpus, S_IRUGO|S_IWUSR,
+ acpi_pad_idlecpus_show,
+ acpi_pad_idlecpus_store);
+
+static int acpi_pad_add_sysfs(struct acpi_device *device)
+{
+ int result;
+
+ result = device_create_file(&device->dev, &dev_attr_idlecpus);
+ if (result)
+ return -ENODEV;
+ result = device_create_file(&device->dev, &dev_attr_idlepct);
+ if (result) {
+ device_remove_file(&device->dev, &dev_attr_idlecpus);
+ return -ENODEV;
+ }
+ result = device_create_file(&device->dev, &dev_attr_rrtime);
+ if (result) {
+ device_remove_file(&device->dev, &dev_attr_idlecpus);
+ device_remove_file(&device->dev, &dev_attr_idlepct);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void acpi_pad_remove_sysfs(struct acpi_device *device)
+{
+ device_remove_file(&device->dev, &dev_attr_idlecpus);
+ device_remove_file(&device->dev, &dev_attr_idlepct);
+ device_remove_file(&device->dev, &dev_attr_rrtime);
+}
+
+/* Query firmware how many CPUs should be idle */
+static int acpi_pad_pur(acpi_handle handle, int *num_cpus)
+{
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ acpi_status status;
+ union acpi_object *package;
+ int rev, num, ret = -EINVAL;
+
+ status = acpi_evaluate_object(handle, "_PUR", NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return -EINVAL;
+ package = buffer.pointer;
+ if (package->type != ACPI_TYPE_PACKAGE || package->package.count != 2)
+ goto out;
+ rev = package->package.elements[0].integer.value;
+ num = package->package.elements[1].integer.value;
+ if (rev != 1)
+ goto out;
+ *num_cpus = num;
+ ret = 0;
+out:
+ kfree(buffer.pointer);
+ return ret;
+}
+
+/* Notify firmware how many CPUs are idle */
+static void acpi_pad_ost(acpi_handle handle, int stat,
+ uint32_t idle_cpus)
+{
+ union acpi_object params[3] = {
+ {.type = ACPI_TYPE_INTEGER,},
+ {.type = ACPI_TYPE_INTEGER,},
+ {.type = ACPI_TYPE_BUFFER,},
+ };
+ struct acpi_object_list arg_list = {3, params};
+
+ params[0].integer.value = ACPI_PROCESSOR_AGGREGATOR_NOTIFY;
+ params[1].integer.value = stat;
+ params[2].buffer.length = 4;
+ params[2].buffer.pointer = (void *)&idle_cpus;
+ acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
+}
+
+static void acpi_pad_handle_notify(acpi_handle handle)
+{
+ int num_cpus, ret;
+ uint32_t idle_cpus;
+
+ mutex_lock(&isolated_cpus_lock);
+ if (acpi_pad_pur(handle, &num_cpus)) {
+ mutex_unlock(&isolated_cpus_lock);
+ return;
+ }
+ ret = acpi_pad_idle_cpus(num_cpus);
+ idle_cpus = acpi_pad_idle_cpus_num();
+ if (!ret)
+ acpi_pad_ost(handle, 0, idle_cpus);
+ else
+ acpi_pad_ost(handle, 1, 0);
+ mutex_unlock(&isolated_cpus_lock);
+}
+
+static void acpi_pad_notify(acpi_handle handle, u32 event,
+ void *data)
+{
+ struct acpi_device *device = data;
+
+ switch (event) {
+ case ACPI_PROCESSOR_AGGREGATOR_NOTIFY:
+ acpi_pad_handle_notify(handle);
+ acpi_bus_generate_proc_event(device, event, 0);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ dev_name(&device->dev), event, 0);
+ break;
+ default:
+ printk(KERN_WARNING"Unsupported event [0x%x]\n", event);
+ break;
+ }
+}
+
+static int acpi_pad_add(struct acpi_device *device)
+{
+ acpi_status status;
+
+ strcpy(acpi_device_name(device), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_PROCESSOR_AGGREGATOR_CLASS);
+
+ if (acpi_pad_add_sysfs(device))
+ return -ENODEV;
+
+ status = acpi_install_notify_handler(device->handle,
+ ACPI_DEVICE_NOTIFY, acpi_pad_notify, device);
+ if (ACPI_FAILURE(status)) {
+ acpi_pad_remove_sysfs(device);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int acpi_pad_remove(struct acpi_device *device,
+ int type)
+{
+ mutex_lock(&isolated_cpus_lock);
+ acpi_pad_idle_cpus(0);
+ mutex_unlock(&isolated_cpus_lock);
+
+ acpi_remove_notify_handler(device->handle,
+ ACPI_DEVICE_NOTIFY, acpi_pad_notify);
+ acpi_pad_remove_sysfs(device);
+ return 0;
+}
+
+static const struct acpi_device_id pad_device_ids[] = {
+ {"ACPI000C", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, pad_device_ids);
+
+static struct acpi_driver acpi_pad_driver = {
+ .name = "processor_aggregator",
+ .class = ACPI_PROCESSOR_AGGREGATOR_CLASS,
+ .ids = pad_device_ids,
+ .ops = {
+ .add = acpi_pad_add,
+ .remove = acpi_pad_remove,
+ },
+};
+
+static int __init acpi_pad_init(void)
+{
+ power_saving_mwait_init();
+ if (power_saving_mwait_eax == 0)
+ return -EINVAL;
+
+ return acpi_bus_register_driver(&acpi_pad_driver);
+}
+
+static void __exit acpi_pad_exit(void)
+{
+ acpi_bus_unregister_driver(&acpi_pad_driver);
+}
+
+module_init(acpi_pad_init);
+module_exit(acpi_pad_exit);
+MODULE_AUTHOR("Shaohua Li<shaohua.li@intel.com>");
+MODULE_DESCRIPTION("ACPI Processor Aggregator Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index 72ac28da14e3..e7973bc16846 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -28,7 +28,7 @@ acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o
acpi-y += nsaccess.o nsload.o nssearch.o nsxfeval.o \
nsalloc.o nseval.o nsnames.o nsutils.o nsxfname.o \
nsdump.o nsinit.o nsobject.o nswalk.o nsxfobj.o \
- nsparse.o nspredef.o
+ nsparse.o nspredef.o nsrepair.o
acpi-$(ACPI_FUTURE_USAGE) += nsdumpdv.o
@@ -44,4 +44,4 @@ acpi-y += tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o
acpi-y += utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \
utcopy.o utdelete.o utglobal.o utmath.o utobject.o \
- utstate.o utmutex.o utobject.o utresrc.o utlock.o
+ utstate.o utmutex.o utobject.o utresrc.o utlock.o utids.o
diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h
index e6777fb883d2..a4471e3d3853 100644
--- a/drivers/acpi/acpica/acconfig.h
+++ b/drivers/acpi/acpica/acconfig.h
@@ -103,9 +103,9 @@
#define ACPI_MAX_REFERENCE_COUNT 0x1000
-/* Size of cached memory mapping for system memory operation region */
+/* Default page size for use in mapping memory for operation regions */
-#define ACPI_SYSMEM_REGION_WINDOW_SIZE 4096
+#define ACPI_DEFAULT_PAGE_SIZE 4096 /* Must be power of 2 */
/* owner_id tracking. 8 entries allows for 255 owner_ids */
@@ -183,7 +183,7 @@
/* Operation regions */
-#define ACPI_NUM_PREDEFINED_REGIONS 8
+#define ACPI_NUM_PREDEFINED_REGIONS 9
#define ACPI_USER_REGION_BEGIN 0x80
/* Maximum space_ids for Operation Regions */
@@ -199,9 +199,15 @@
#define ACPI_RSDP_CHECKSUM_LENGTH 20
#define ACPI_RSDP_XCHECKSUM_LENGTH 36
-/* SMBus bidirectional buffer size */
+/* SMBus and IPMI bidirectional buffer size */
#define ACPI_SMBUS_BUFFER_SIZE 34
+#define ACPI_IPMI_BUFFER_SIZE 66
+
+/* _sx_d and _sx_w control methods */
+
+#define ACPI_NUM_sx_d_METHODS 4
+#define ACPI_NUM_sx_w_METHODS 5
/******************************************************************************
*
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 62c59df3b86c..a4fb001d96f1 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -154,10 +154,6 @@ void
acpi_db_display_argument_object(union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state);
-void acpi_db_check_predefined_names(void);
-
-void acpi_db_batch_execute(void);
-
/*
* dbexec - debugger control method execution
*/
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 3d87362d17ed..29ba66d5a790 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -58,6 +58,10 @@
#define ACPI_INIT_GLOBAL(a,b) a
#endif
+#ifdef DEFINE_ACPI_GLOBALS
+
+/* Public globals, available from outside ACPICA subsystem */
+
/*****************************************************************************
*
* Runtime configuration (static defaults that can be overriden at runtime)
@@ -78,7 +82,7 @@
* 5) Allow unresolved references (invalid target name) in package objects
* 6) Enable warning messages for behavior that is not ACPI spec compliant
*/
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE);
+u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE);
/*
* Automatically serialize ALL control methods? Default is FALSE, meaning
@@ -86,27 +90,36 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE);
* Only change this if the ASL code is poorly written and cannot handle
* reentrancy even though methods are marked "NotSerialized".
*/
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_all_methods_serialized, FALSE);
+u8 ACPI_INIT_GLOBAL(acpi_gbl_all_methods_serialized, FALSE);
/*
* Create the predefined _OSI method in the namespace? Default is TRUE
* because ACPI CA is fully compatible with other ACPI implementations.
* Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior.
*/
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE);
+u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE);
/*
* Disable wakeup GPEs during runtime? Default is TRUE because WAKE and
* RUNTIME GPEs should never be shared, and WAKE GPEs should typically only
* be enabled just before going to sleep.
*/
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE);
+u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE);
/*
* Optionally use default values for the ACPI register widths. Set this to
* TRUE to use the defaults, if an FADT contains incorrect widths/lengths.
*/
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE);
+u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE);
+
+/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
+
+struct acpi_table_fadt acpi_gbl_FADT;
+u32 acpi_current_gpe_count;
+u32 acpi_gbl_trace_flags;
+acpi_name acpi_gbl_trace_method_name;
+
+#endif
/*****************************************************************************
*
@@ -114,11 +127,6 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE);
*
****************************************************************************/
-/* Runtime configuration of debug print levels */
-
-extern u32 acpi_dbg_level;
-extern u32 acpi_dbg_layer;
-
/* Procedure nesting level for debug output */
extern u32 acpi_gbl_nesting_level;
@@ -127,10 +135,8 @@ extern u32 acpi_gbl_nesting_level;
ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
ACPI_EXTERN u32 acpi_gbl_original_dbg_layer;
-ACPI_EXTERN acpi_name acpi_gbl_trace_method_name;
ACPI_EXTERN u32 acpi_gbl_trace_dbg_level;
ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
-ACPI_EXTERN u32 acpi_gbl_trace_flags;
/*****************************************************************************
*
@@ -142,10 +148,8 @@ ACPI_EXTERN u32 acpi_gbl_trace_flags;
* acpi_gbl_root_table_list is the master list of ACPI tables found in the
* RSDT/XSDT.
*
- * acpi_gbl_FADT is a local copy of the FADT, converted to a common format.
*/
ACPI_EXTERN struct acpi_internal_rsdt acpi_gbl_root_table_list;
-ACPI_EXTERN struct acpi_table_fadt acpi_gbl_FADT;
ACPI_EXTERN struct acpi_table_facs *acpi_gbl_FACS;
/* These addresses are calculated from the FADT Event Block addresses */
@@ -261,7 +265,8 @@ ACPI_EXTERN u8 acpi_gbl_osi_data;
extern u8 acpi_gbl_shutdown;
extern u32 acpi_gbl_startup_flags;
extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT];
-extern const char *acpi_gbl_highest_dstate_names[4];
+extern const char *acpi_gbl_lowest_dstate_names[ACPI_NUM_sx_w_METHODS];
+extern const char *acpi_gbl_highest_dstate_names[ACPI_NUM_sx_d_METHODS];
extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS];
@@ -290,6 +295,7 @@ extern char const *acpi_gbl_exception_names_ctrl[];
ACPI_EXTERN struct acpi_namespace_node acpi_gbl_root_node_struct;
ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_root_node;
ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_fadt_gpe_device;
+ACPI_EXTERN union acpi_operand_object *acpi_gbl_module_code_list;
extern const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES];
extern const struct acpi_predefined_names
@@ -340,7 +346,6 @@ ACPI_EXTERN struct acpi_fixed_event_handler
ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
ACPI_EXTERN struct acpi_gpe_block_info
*acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
-ACPI_EXTERN u32 acpi_current_gpe_count;
/*****************************************************************************
*
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
index 4afa3d8e0efb..36192f142fbb 100644
--- a/drivers/acpi/acpica/achware.h
+++ b/drivers/acpi/acpica/achware.h
@@ -62,6 +62,14 @@ u32 acpi_hw_get_mode(void);
/*
* hwregs - ACPI Register I/O
*/
+acpi_status
+acpi_hw_validate_register(struct acpi_generic_address *reg,
+ u8 max_bit_width, u64 *address);
+
+acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg);
+
+acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg);
+
struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id);
acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control);
diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h
index e8db7a3143a5..5db9f2916f7c 100644
--- a/drivers/acpi/acpica/acinterp.h
+++ b/drivers/acpi/acpica/acinterp.h
@@ -461,9 +461,9 @@ void acpi_ex_acquire_global_lock(u32 rule);
void acpi_ex_release_global_lock(u32 rule);
-void acpi_ex_eisa_id_to_string(u32 numeric_id, char *out_string);
+void acpi_ex_eisa_id_to_string(char *dest, acpi_integer compressed_id);
-void acpi_ex_unsigned_integer_to_string(acpi_integer value, char *out_string);
+void acpi_ex_integer_to_string(char *dest, acpi_integer value);
/*
* exregion - default op_region handlers
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index ee986edfa0da..81e64f478679 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -369,6 +369,19 @@ union acpi_predefined_info {
struct acpi_package_info3 ret_info3;
};
+/* Data block used during object validation */
+
+struct acpi_predefined_data {
+ char *pathname;
+ const union acpi_predefined_info *predefined;
+ u32 flags;
+ u8 node_flags;
+};
+
+/* Defines for Flags field above */
+
+#define ACPI_OBJECT_REPAIRED 1
+
/*
* Bitmapped return value types
* Note: the actual data types must be contiguous, a loop in nspredef.c
@@ -885,6 +898,9 @@ struct acpi_bit_register_info {
#define ACPI_OSI_WIN_XP_SP2 0x05
#define ACPI_OSI_WINSRV_2003_SP1 0x06
#define ACPI_OSI_WIN_VISTA 0x07
+#define ACPI_OSI_WINSRV_2008 0x08
+#define ACPI_OSI_WIN_VISTA_SP1 0x09
+#define ACPI_OSI_WIN_7 0x0A
#define ACPI_ALWAYS_ILLEGAL 0x00
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index 91ac7d7b4402..3acd9c6760ea 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -340,6 +340,7 @@
*/
#define ACPI_ERROR_NAMESPACE(s, e) acpi_ns_report_error (AE_INFO, s, e);
#define ACPI_ERROR_METHOD(s, n, p, e) acpi_ns_report_method_error (AE_INFO, s, n, p, e);
+#define ACPI_WARN_PREDEFINED(plist) acpi_ut_predefined_warning plist
#else
@@ -347,6 +348,7 @@
#define ACPI_ERROR_NAMESPACE(s, e)
#define ACPI_ERROR_METHOD(s, n, p, e)
+#define ACPI_WARN_PREDEFINED(plist)
#endif /* ACPI_NO_ERROR_MESSAGES */
/*
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index 94cdc2b8cb93..09a2764c734b 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -73,6 +73,14 @@
#define ACPI_NS_WALK_UNLOCK 0x01
#define ACPI_NS_WALK_TEMP_NODES 0x02
+/* Object is not a package element */
+
+#define ACPI_NOT_PACKAGE_ELEMENT ACPI_UINT32_MAX
+
+/* Always emit warning message, not dependent on node flags */
+
+#define ACPI_WARN_ALWAYS 0
+
/*
* nsinit - Namespace initialization
*/
@@ -144,6 +152,8 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name);
void acpi_ns_delete_node(struct acpi_namespace_node *node);
+void acpi_ns_remove_node(struct acpi_namespace_node *node);
+
void
acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_handle);
@@ -186,6 +196,8 @@ acpi_ns_dump_objects(acpi_object_type type,
*/
acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info);
+void acpi_ns_exec_module_code_list(void);
+
/*
* nspredef - Support for predefined/reserved names
*/
@@ -260,6 +272,19 @@ acpi_ns_get_attached_data(struct acpi_namespace_node *node,
acpi_object_handler handler, void **data);
/*
+ * nsrepair - return object repair for predefined methods/objects
+ */
+acpi_status
+acpi_ns_repair_object(struct acpi_predefined_data *data,
+ u32 expected_btypes,
+ u32 package_index,
+ union acpi_operand_object **return_object_ptr);
+
+acpi_status
+acpi_ns_repair_package_list(struct acpi_predefined_data *data,
+ union acpi_operand_object **obj_desc_ptr);
+
+/*
* nssearch - Namespace searching and entry
*/
acpi_status
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index eb6f038b03d9..b39d682a2140 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -98,6 +98,7 @@
#define AOPOBJ_SETUP_COMPLETE 0x10
#define AOPOBJ_SINGLE_DATUM 0x20
#define AOPOBJ_INVALID 0x40 /* Used if host OS won't allow an op_region address */
+#define AOPOBJ_MODULE_LEVEL 0x80
/******************************************************************************
*
diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h
index 23ee0fbf5619..22881e8ce229 100644
--- a/drivers/acpi/acpica/acparser.h
+++ b/drivers/acpi/acpica/acparser.h
@@ -62,6 +62,8 @@
#define ACPI_PARSE_DEFERRED_OP 0x0100
#define ACPI_PARSE_DISASSEMBLE 0x0200
+#define ACPI_PARSE_MODULE_LEVEL 0x0400
+
/******************************************************************************
*
* Parser interfaces
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index 63f656ae3604..57bdaf6ffab1 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -64,8 +64,8 @@
* (Used for _PRW)
*
*
- * 2) PTYPE2 packages contain a variable number of sub-packages. Each of the
- * different types describe the contents of each of the sub-packages.
+ * 2) PTYPE2 packages contain a Variable-length number of sub-packages. Each
+ * of the different types describe the contents of each of the sub-packages.
*
* ACPI_PTYPE2: Each subpackage contains 1 or 2 object types:
* object type
@@ -91,6 +91,9 @@
* ACPI_PTYPE2_MIN: Each subpackage has a variable but minimum length
* (Used for _HPX)
*
+ * ACPI_PTYPE2_REV_FIXED: Revision at start, each subpackage is Fixed-length
+ * (Used for _ART, _FPS)
+ *
*****************************************************************************/
enum acpi_return_package_types {
@@ -101,9 +104,11 @@ enum acpi_return_package_types {
ACPI_PTYPE2_COUNT = 5,
ACPI_PTYPE2_PKG_COUNT = 6,
ACPI_PTYPE2_FIXED = 7,
- ACPI_PTYPE2_MIN = 8
+ ACPI_PTYPE2_MIN = 8,
+ ACPI_PTYPE2_REV_FIXED = 9
};
+#ifdef ACPI_CREATE_PREDEFINED_TABLE
/*
* Predefined method/object information table.
*
@@ -136,239 +141,385 @@ enum acpi_return_package_types {
* is saved here (rather than in a separate table) in order to minimize the
* overall size of the stored data.
*/
-static const union acpi_predefined_info predefined_names[] = {
- {.info = {"_AC0", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_AC1", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_AC2", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_AC3", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_AC4", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_AC5", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_AC6", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_AC7", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_AC8", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_AC9", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_ADR", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_AL0", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_AL1", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_AL2", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_AL3", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_AL4", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_AL5", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_AL6", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_AL7", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_AL8", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_AL9", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_ALC", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_ALI", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_ALP", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_ALR", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 2, 0, 0, 0}}, /* variable (Pkgs) each 2 (Ints) */
- {.info = {"_ALT", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_BBN", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_BCL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Ints) */
- {.info = {"_BCM", 1, 0}},
- {.info = {"_BDN", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_BFS", 1, 0}},
- {.info = {"_BIF", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER,
- 9,
- ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER, 4, 0}}, /* fixed (9 Int),(4 Str) */
- {.info = {"_BLT", 3, 0}},
- {.info = {"_BMC", 1, 0}},
- {.info = {"_BMD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* fixed (5 Int) */
- {.info = {"_BQC", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_BST", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0}}, /* fixed (4 Int) */
- {.info = {"_BTM", 1, ACPI_RTYPE_INTEGER}},
- {.info = {"_BTP", 1, 0}},
- {.info = {"_CBA", 0, ACPI_RTYPE_INTEGER}}, /* see PCI firmware spec 3.0 */
- {.info = {"_CID", 0,
- ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE}},
- {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0, 0, 0, 0}}, /* variable (Ints/Strs) */
- {.info = {"_CRS", 0, ACPI_RTYPE_BUFFER}},
- {.info = {"_CRT", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_CSD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (1 Int(n), n-1 Int) */
- {.info = {"_CST", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_PKG_COUNT,
- ACPI_RTYPE_BUFFER, 1,
- ACPI_RTYPE_INTEGER, 3, 0}}, /* variable (1 Int(n), n Pkg (1 Buf/3 Int) */
- {.info = {"_DCK", 1, ACPI_RTYPE_INTEGER}},
- {.info = {"_DCS", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_DDC", 1, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER}},
- {.info = {"_DDN", 0, ACPI_RTYPE_STRING}},
- {.info = {"_DGS", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_DIS", 0, 0}},
- {.info = {"_DMA", 0, ACPI_RTYPE_BUFFER}},
- {.info = {"_DOD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Ints) */
- {.info = {"_DOS", 1, 0}},
- {.info = {"_DSM", 4, ACPI_RTYPE_ALL}}, /* Must return a type, but it can be of any type */
- {.info = {"_DSS", 1, 0}},
- {.info = {"_DSW", 3, 0}},
- {.info = {"_EC_", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_EDL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_EJ0", 1, 0}},
- {.info = {"_EJ1", 1, 0}},
- {.info = {"_EJ2", 1, 0}},
- {.info = {"_EJ3", 1, 0}},
- {.info = {"_EJ4", 1, 0}},
- {.info = {"_EJD", 0, ACPI_RTYPE_STRING}},
- {.info = {"_FDE", 0, ACPI_RTYPE_BUFFER}},
- {.info = {"_FDI", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16, 0, 0, 0}}, /* fixed (16 Int) */
- {.info = {"_FDM", 1, 0}},
- {.info = {"_FIX", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Ints) */
- {.info = {"_GLK", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_GPD", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_GPE", 0, ACPI_RTYPE_INTEGER}}, /* _GPE method, not _GPE scope */
- {.info = {"_GSB", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_GTF", 0, ACPI_RTYPE_BUFFER}},
- {.info = {"_GTM", 0, ACPI_RTYPE_BUFFER}},
- {.info = {"_GTS", 1, 0}},
- {.info = {"_HID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}},
- {.info = {"_HOT", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_HPP", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0}}, /* fixed (4 Int) */
+static const union acpi_predefined_info predefined_names[] =
+{
+ {{"_AC0", 0, ACPI_RTYPE_INTEGER}},
+ {{"_AC1", 0, ACPI_RTYPE_INTEGER}},
+ {{"_AC2", 0, ACPI_RTYPE_INTEGER}},
+ {{"_AC3", 0, ACPI_RTYPE_INTEGER}},
+ {{"_AC4", 0, ACPI_RTYPE_INTEGER}},
+ {{"_AC5", 0, ACPI_RTYPE_INTEGER}},
+ {{"_AC6", 0, ACPI_RTYPE_INTEGER}},
+ {{"_AC7", 0, ACPI_RTYPE_INTEGER}},
+ {{"_AC8", 0, ACPI_RTYPE_INTEGER}},
+ {{"_AC9", 0, ACPI_RTYPE_INTEGER}},
+ {{"_ADR", 0, ACPI_RTYPE_INTEGER}},
+ {{"_AL0", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_AL1", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_AL2", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_AL3", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_AL4", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_AL5", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_AL6", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_AL7", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_AL8", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_AL9", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_ALC", 0, ACPI_RTYPE_INTEGER}},
+ {{"_ALI", 0, ACPI_RTYPE_INTEGER}},
+ {{"_ALP", 0, ACPI_RTYPE_INTEGER}},
+ {{"_ALR", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each 2 (Ints) */
+ {{{ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 2,0}, 0,0}},
+
+ {{"_ALT", 0, ACPI_RTYPE_INTEGER}},
+ {{"_ART", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(rev), n Pkg (2 Ref/11 Int) */
+ {{{ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_REFERENCE, 2, ACPI_RTYPE_INTEGER},
+ 11, 0}},
+
+ {{"_BBN", 0, ACPI_RTYPE_INTEGER}},
+ {{"_BCL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0}, 0,0}},
+
+ {{"_BCM", 1, 0}},
+ {{"_BCT", 1, ACPI_RTYPE_INTEGER}},
+ {{"_BDN", 0, ACPI_RTYPE_INTEGER}},
+ {{"_BFS", 1, 0}},
+ {{"_BIF", 0, ACPI_RTYPE_PACKAGE} }, /* Fixed-length (9 Int),(4 Str/Buf) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 9,
+ ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER}, 4, 0} },
+
+ {{"_BIX", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (16 Int),(4 Str) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16, ACPI_RTYPE_STRING}, 4,
+ 0}},
+
+ {{"_BLT", 3, 0}},
+ {{"_BMA", 1, ACPI_RTYPE_INTEGER}},
+ {{"_BMC", 1, 0}},
+ {{"_BMD", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (5 Int) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 5,0}, 0,0}},
+
+ {{"_BMS", 1, ACPI_RTYPE_INTEGER}},
+ {{"_BQC", 0, ACPI_RTYPE_INTEGER}},
+ {{"_BST", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0}, 0,0}},
+
+ {{"_BTM", 1, ACPI_RTYPE_INTEGER}},
+ {{"_BTP", 1, 0}},
+ {{"_CBA", 0, ACPI_RTYPE_INTEGER}}, /* See PCI firmware spec 3.0 */
+ {{"_CDM", 0, ACPI_RTYPE_INTEGER}},
+ {{"_CID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints/Strs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0,0}, 0,0}},
+
+ {{"_CRS", 0, ACPI_RTYPE_BUFFER}},
+ {{"_CRT", 0, ACPI_RTYPE_INTEGER}},
+ {{"_CSD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(n), n-1 Int) */
+ {{{ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0,0}, 0,0}},
+
+ {{"_CST", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(n), n Pkg (1 Buf/3 Int) */
+ {{{ACPI_PTYPE2_PKG_COUNT,ACPI_RTYPE_BUFFER, 1, ACPI_RTYPE_INTEGER}, 3,0}},
+
+ {{"_DCK", 1, ACPI_RTYPE_INTEGER}},
+ {{"_DCS", 0, ACPI_RTYPE_INTEGER}},
+ {{"_DDC", 1, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER}},
+ {{"_DDN", 0, ACPI_RTYPE_STRING}},
+ {{"_DGS", 0, ACPI_RTYPE_INTEGER}},
+ {{"_DIS", 0, 0}},
+ {{"_DMA", 0, ACPI_RTYPE_BUFFER}},
+ {{"_DOD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0}, 0,0}},
+
+ {{"_DOS", 1, 0}},
+ {{"_DSM", 4, ACPI_RTYPE_ALL}}, /* Must return a type, but it can be of any type */
+ {{"_DSS", 1, 0}},
+ {{"_DSW", 3, 0}},
+ {{"_DTI", 1, 0}},
+ {{"_EC_", 0, ACPI_RTYPE_INTEGER}},
+ {{"_EDL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs)*/
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_EJ0", 1, 0}},
+ {{"_EJ1", 1, 0}},
+ {{"_EJ2", 1, 0}},
+ {{"_EJ3", 1, 0}},
+ {{"_EJ4", 1, 0}},
+ {{"_EJD", 0, ACPI_RTYPE_STRING}},
+ {{"_FDE", 0, ACPI_RTYPE_BUFFER}},
+ {{"_FDI", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (16 Int) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16,0}, 0,0}},
+
+ {{"_FDM", 1, 0}},
+ {{"_FIF", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0}, 0, 0}},
+
+ {{"_FIX", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0}, 0,0}},
+
+ {{"_FPS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(rev), n Pkg (5 Int) */
+ {{{ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_INTEGER, 5, 0}, 0, 0}},
+
+ {{"_FSL", 1, 0}},
+ {{"_FST", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (3 Int) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0}, 0, 0}},
+
+ {{"_GAI", 0, ACPI_RTYPE_INTEGER}},
+ {{"_GHL", 0, ACPI_RTYPE_INTEGER}},
+ {{"_GLK", 0, ACPI_RTYPE_INTEGER}},
+ {{"_GPD", 0, ACPI_RTYPE_INTEGER}},
+ {{"_GPE", 0, ACPI_RTYPE_INTEGER}}, /* _GPE method, not _GPE scope */
+ {{"_GSB", 0, ACPI_RTYPE_INTEGER}},
+ {{"_GTF", 0, ACPI_RTYPE_BUFFER}},
+ {{"_GTM", 0, ACPI_RTYPE_BUFFER}},
+ {{"_GTS", 1, 0}},
+ {{"_HID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}},
+ {{"_HOT", 0, ACPI_RTYPE_INTEGER}},
+ {{"_HPP", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0}, 0,0}},
/*
- * For _HPX, a single package is returned, containing a variable number of sub-packages.
- * Each sub-package contains a PCI record setting. There are several different type of
- * record settings, of different lengths, but all elements of all settings are Integers.
+ * For _HPX, a single package is returned, containing a Variable-length number
+ * of sub-packages. Each sub-package contains a PCI record setting.
+ * There are several different type of record settings, of different
+ * lengths, but all elements of all settings are Integers.
*/
- {.info = {"_HPX", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_MIN, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* variable (Pkgs) each (var Ints) */
- {.info = {"_IFT", 0, ACPI_RTYPE_INTEGER}}, /* see IPMI spec */
- {.info = {"_INI", 0, 0}},
- {.info = {"_IRC", 0, 0}},
- {.info = {"_LCK", 1, 0}},
- {.info = {"_LID", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_MAT", 0, ACPI_RTYPE_BUFFER}},
- {.info = {"_MLS", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_STRING, 2, 0, 0, 0}}, /* variable (Pkgs) each (2 Str) */
- {.info = {"_MSG", 1, 0}},
- {.info = {"_OFF", 0, 0}},
- {.info = {"_ON_", 0, 0}},
- {.info = {"_OS_", 0, ACPI_RTYPE_STRING}},
- {.info = {"_OSC", 4, ACPI_RTYPE_BUFFER}},
- {.info = {"_OST", 3, 0}},
- {.info = {"_PCL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_PCT", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2, 0, 0, 0}}, /* fixed (2 Buf) */
- {.info = {"_PDC", 1, 0}},
- {.info = {"_PIC", 1, 0}},
- {.info = {"_PLD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_BUFFER, 0, 0, 0, 0}}, /* variable (Bufs) */
- {.info = {"_PPC", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_PPE", 0, ACPI_RTYPE_INTEGER}}, /* see dig64 spec */
- {.info = {"_PR0", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_PR1", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_PR2", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_PRS", 0, ACPI_RTYPE_BUFFER}},
+ {{"_HPX", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (var Ints) */
+ {{{ACPI_PTYPE2_MIN, ACPI_RTYPE_INTEGER, 5,0}, 0,0}},
+
+ {{"_IFT", 0, ACPI_RTYPE_INTEGER}}, /* See IPMI spec */
+ {{"_INI", 0, 0}},
+ {{"_IRC", 0, 0}},
+ {{"_LCK", 1, 0}},
+ {{"_LID", 0, ACPI_RTYPE_INTEGER}},
+ {{"_MAT", 0, ACPI_RTYPE_BUFFER}},
+ {{"_MBM", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (8 Int) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 8, 0}, 0, 0}},
+
+ {{"_MLS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (2 Str) */
+ {{{ACPI_PTYPE2, ACPI_RTYPE_STRING, 2,0}, 0,0}},
+
+ {{"_MSG", 1, 0}},
+ {{"_MSM", 4, ACPI_RTYPE_INTEGER}},
+ {{"_NTT", 0, ACPI_RTYPE_INTEGER}},
+ {{"_OFF", 0, 0}},
+ {{"_ON_", 0, 0}},
+ {{"_OS_", 0, ACPI_RTYPE_STRING}},
+ {{"_OSC", 4, ACPI_RTYPE_BUFFER}},
+ {{"_OST", 3, 0}},
+ {{"_PAI", 1, ACPI_RTYPE_INTEGER}},
+ {{"_PCL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_PCT", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (2 Buf) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2,0}, 0,0}},
+
+ {{"_PDC", 1, 0}},
+ {{"_PDL", 0, ACPI_RTYPE_INTEGER}},
+ {{"_PIC", 1, 0}},
+ {{"_PIF", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (3 Int),(3 Str) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, ACPI_RTYPE_STRING}, 3, 0}},
+
+ {{"_PLD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Bufs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_BUFFER, 0,0}, 0,0}},
+
+ {{"_PMC", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (11 Int),(3 Str) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 11, ACPI_RTYPE_STRING}, 3,
+ 0}},
+
+ {{"_PMD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}},
+
+ {{"_PMM", 0, ACPI_RTYPE_INTEGER}},
+ {{"_PPC", 0, ACPI_RTYPE_INTEGER}},
+ {{"_PPE", 0, ACPI_RTYPE_INTEGER}}, /* See dig64 spec */
+ {{"_PR0", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_PR1", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_PR2", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_PR3", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}},
+
+ {{"_PRL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}},
+
+ {{"_PRS", 0, ACPI_RTYPE_BUFFER}},
/*
- * For _PRT, many BIOSs reverse the 2nd and 3rd Package elements. This bug is so prevalent that there
- * is code in the ACPICA Resource Manager to detect this and switch them back. For now, do not allow
- * and issue a warning. To allow this and eliminate the warning, add the ACPI_RTYPE_REFERENCE
- * type to the 2nd element (index 1) in the statement below.
+ * For _PRT, many BIOSs reverse the 3rd and 4th Package elements (Source
+ * and source_index). This bug is so prevalent that there is code in the
+ * ACPICA Resource Manager to detect this and switch them back. For now,
+ * do not allow and issue a warning. To allow this and eliminate the
+ * warning, add the ACPI_RTYPE_REFERENCE type to the 4th element (index 3)
+ * in the statement below.
*/
- {.info = {"_PRT", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_FIXED, 4,
- ACPI_RTYPE_INTEGER,
- ACPI_RTYPE_INTEGER,
- ACPI_RTYPE_INTEGER | ACPI_RTYPE_REFERENCE, ACPI_RTYPE_INTEGER}}, /* variable (Pkgs) each (4): Int,Int,Int/Ref,Int */
-
- {.info = {"_PRW", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_OPTION, 2,
- ACPI_RTYPE_INTEGER |
- ACPI_RTYPE_PACKAGE,
- ACPI_RTYPE_INTEGER, ACPI_RTYPE_REFERENCE, 0}}, /* variable (Pkgs) each: Pkg/Int,Int,[variable Refs] (Pkg is Ref/Int) */
-
- {.info = {"_PS0", 0, 0}},
- {.info = {"_PS1", 0, 0}},
- {.info = {"_PS2", 0, 0}},
- {.info = {"_PS3", 0, 0}},
- {.info = {"_PSC", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_PSD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Pkgs) each (5 Int) with count */
- {.info = {"_PSL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_PSR", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_PSS", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 6, 0, 0, 0}}, /* variable (Pkgs) each (6 Int) */
- {.info = {"_PSV", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_PSW", 1, 0}},
- {.info = {"_PTC", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2, 0, 0, 0}}, /* fixed (2 Buf) */
- {.info = {"_PTS", 1, 0}},
- {.info = {"_PXM", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_REG", 2, 0}},
- {.info = {"_REV", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_RMV", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_ROM", 2, ACPI_RTYPE_BUFFER}},
- {.info = {"_RTV", 0, ACPI_RTYPE_INTEGER}},
+ {{"_PRT", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (4): Int,Int,Int/Ref,Int */
+ {{{ACPI_PTYPE2_FIXED, 4, ACPI_RTYPE_INTEGER,ACPI_RTYPE_INTEGER},
+ ACPI_RTYPE_INTEGER | ACPI_RTYPE_REFERENCE,
+ ACPI_RTYPE_INTEGER}},
+
+ {{"_PRW", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each: Pkg/Int,Int,[Variable-length Refs] (Pkg is Ref/Int) */
+ {{{ACPI_PTYPE1_OPTION, 2, ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE,
+ ACPI_RTYPE_INTEGER}, ACPI_RTYPE_REFERENCE,0}},
+
+ {{"_PS0", 0, 0}},
+ {{"_PS1", 0, 0}},
+ {{"_PS2", 0, 0}},
+ {{"_PS3", 0, 0}},
+ {{"_PSC", 0, ACPI_RTYPE_INTEGER}},
+ {{"_PSD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (5 Int) with count */
+ {{{ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER,0,0}, 0,0}},
+
+ {{"_PSL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_PSR", 0, ACPI_RTYPE_INTEGER}},
+ {{"_PSS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (6 Int) */
+ {{{ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 6,0}, 0,0}},
+
+ {{"_PSV", 0, ACPI_RTYPE_INTEGER}},
+ {{"_PSW", 1, 0}},
+ {{"_PTC", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (2 Buf) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2,0}, 0,0}},
+
+ {{"_PTP", 2, ACPI_RTYPE_INTEGER}},
+ {{"_PTS", 1, 0}},
+ {{"_PUR", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (2 Int) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2, 0}, 0, 0}},
+
+ {{"_PXM", 0, ACPI_RTYPE_INTEGER}},
+ {{"_REG", 2, 0}},
+ {{"_REV", 0, ACPI_RTYPE_INTEGER}},
+ {{"_RMV", 0, ACPI_RTYPE_INTEGER}},
+ {{"_ROM", 2, ACPI_RTYPE_BUFFER}},
+ {{"_RTV", 0, ACPI_RTYPE_INTEGER}},
/*
- * For _S0_ through _S5_, the ACPI spec defines a return Package containing 1 Integer,
- * but most DSDTs have it wrong - 2,3, or 4 integers. Allow this by making the objects "variable length",
- * but all elements must be Integers.
+ * For _S0_ through _S5_, the ACPI spec defines a return Package
+ * containing 1 Integer, but most DSDTs have it wrong - 2,3, or 4 integers.
+ * Allow this by making the objects "Variable-length length", but all elements
+ * must be Integers.
*/
- {.info = {"_S0_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */
- {.info = {"_S1_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */
- {.info = {"_S2_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */
- {.info = {"_S3_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */
- {.info = {"_S4_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */
- {.info = {"_S5_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */
-
- {.info = {"_S1D", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_S2D", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_S3D", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_S4D", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_S0W", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_S1W", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_S2W", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_S3W", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_S4W", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_SBS", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_SCP", 0x13, 0}}, /* Acpi 1.0 allowed 1 arg. Acpi 3.0 expanded to 3 args. Allow both. */
- /* Note: the 3-arg definition may be removed for ACPI 4.0 */
- {.info = {"_SDD", 1, 0}},
- {.info = {"_SEG", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_SLI", 0, ACPI_RTYPE_BUFFER}},
- {.info = {"_SPD", 1, ACPI_RTYPE_INTEGER}},
- {.info = {"_SRS", 1, 0}},
- {.info = {"_SRV", 0, ACPI_RTYPE_INTEGER}}, /* see IPMI spec */
- {.info = {"_SST", 1, 0}},
- {.info = {"_STA", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_STM", 3, 0}},
- {.info = {"_STR", 0, ACPI_RTYPE_BUFFER}},
- {.info = {"_SUN", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_SWS", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_TC1", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_TC2", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_TMP", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_TPC", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_TPT", 1, 0}},
- {.info = {"_TRT", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_REFERENCE, 2,
- ACPI_RTYPE_INTEGER, 6, 0}}, /* variable (Pkgs) each 2_ref/6_int */
- {.info = {"_TSD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* variable (Pkgs) each 5_int with count */
- {.info = {"_TSP", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_TSS", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* variable (Pkgs) each 5_int */
- {.info = {"_TST", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_TTS", 1, 0}},
- {.info = {"_TZD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
- {.info = {"_TZM", 0, ACPI_RTYPE_REFERENCE}},
- {.info = {"_TZP", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_UID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}},
- {.info = {"_UPC", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0}}, /* fixed (4 Int) */
- {.info = {"_UPD", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_UPP", 0, ACPI_RTYPE_INTEGER}},
- {.info = {"_VPO", 0, ACPI_RTYPE_INTEGER}},
+ {{"_S0_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}},
+
+ {{"_S1_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}},
+
+ {{"_S2_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}},
+
+ {{"_S3_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}},
+
+ {{"_S4_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}},
+
+ {{"_S5_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}},
+
+ {{"_S1D", 0, ACPI_RTYPE_INTEGER}},
+ {{"_S2D", 0, ACPI_RTYPE_INTEGER}},
+ {{"_S3D", 0, ACPI_RTYPE_INTEGER}},
+ {{"_S4D", 0, ACPI_RTYPE_INTEGER}},
+ {{"_S0W", 0, ACPI_RTYPE_INTEGER}},
+ {{"_S1W", 0, ACPI_RTYPE_INTEGER}},
+ {{"_S2W", 0, ACPI_RTYPE_INTEGER}},
+ {{"_S3W", 0, ACPI_RTYPE_INTEGER}},
+ {{"_S4W", 0, ACPI_RTYPE_INTEGER}},
+ {{"_SBS", 0, ACPI_RTYPE_INTEGER}},
+ {{"_SCP", 0x13, 0}}, /* Acpi 1.0 allowed 1 arg. Acpi 3.0 expanded to 3 args. Allow both. */
+ /* Note: the 3-arg definition may be removed for ACPI 4.0 */
+ {{"_SDD", 1, 0}},
+ {{"_SEG", 0, ACPI_RTYPE_INTEGER}},
+ {{"_SHL", 1, ACPI_RTYPE_INTEGER}},
+ {{"_SLI", 0, ACPI_RTYPE_BUFFER}},
+ {{"_SPD", 1, ACPI_RTYPE_INTEGER}},
+ {{"_SRS", 1, 0}},
+ {{"_SRV", 0, ACPI_RTYPE_INTEGER}}, /* See IPMI spec */
+ {{"_SST", 1, 0}},
+ {{"_STA", 0, ACPI_RTYPE_INTEGER}},
+ {{"_STM", 3, 0}},
+ {{"_STP", 2, ACPI_RTYPE_INTEGER}},
+ {{"_STR", 0, ACPI_RTYPE_BUFFER}},
+ {{"_STV", 2, ACPI_RTYPE_INTEGER}},
+ {{"_SUN", 0, ACPI_RTYPE_INTEGER}},
+ {{"_SWS", 0, ACPI_RTYPE_INTEGER}},
+ {{"_TC1", 0, ACPI_RTYPE_INTEGER}},
+ {{"_TC2", 0, ACPI_RTYPE_INTEGER}},
+ {{"_TIP", 1, ACPI_RTYPE_INTEGER}},
+ {{"_TIV", 1, ACPI_RTYPE_INTEGER}},
+ {{"_TMP", 0, ACPI_RTYPE_INTEGER}},
+ {{"_TPC", 0, ACPI_RTYPE_INTEGER}},
+ {{"_TPT", 1, 0}},
+ {{"_TRT", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each 2_ref/6_int */
+ {{{ACPI_PTYPE2, ACPI_RTYPE_REFERENCE, 2, ACPI_RTYPE_INTEGER}, 6, 0}},
+
+ {{"_TSD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each 5_int with count */
+ {{{ACPI_PTYPE2_COUNT,ACPI_RTYPE_INTEGER, 5,0}, 0,0}},
+
+ {{"_TSP", 0, ACPI_RTYPE_INTEGER}},
+ {{"_TSS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each 5_int */
+ {{{ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 5,0}, 0,0}},
+
+ {{"_TST", 0, ACPI_RTYPE_INTEGER}},
+ {{"_TTS", 1, 0}},
+ {{"_TZD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
+
+ {{"_TZM", 0, ACPI_RTYPE_REFERENCE}},
+ {{"_TZP", 0, ACPI_RTYPE_INTEGER}},
+ {{"_UID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}},
+ {{"_UPC", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0}, 0,0}},
+
+ {{"_UPD", 0, ACPI_RTYPE_INTEGER}},
+ {{"_UPP", 0, ACPI_RTYPE_INTEGER}},
+ {{"_VPO", 0, ACPI_RTYPE_INTEGER}},
/* Acpi 1.0 defined _WAK with no return value. Later, it was changed to return a package */
- {.info = {"_WAK", 1, ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE}},
- {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2, 0, 0, 0}}, /* fixed (2 Int), but is optional */
- {.ret_info = {0, 0, 0, 0, 0, 0}} /* Table terminator */
+ {{"_WAK", 1, ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE}},
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2,0}, 0,0}}, /* Fixed-length (2 Int), but is optional */
+
+ {{{0,0,0,0}, 0,0}} /* Table terminator */
};
#if 0
/* Not implemented */
-{
-"_WDG", 0, ACPI_RTYPE_BUFFER}, /* MS Extension */
+ {{"_WDG", 0, ACPI_RTYPE_BUFFER}}, /* MS Extension */
+ {{"_WED", 1, ACPI_RTYPE_PACKAGE}}, /* MS Extension */
-{
-"_WED", 1, ACPI_RTYPE_PACKAGE}, /* MS Extension */
+ /* This is an internally implemented control method, no need to check */
+ {{"_OSI", 1, ACPI_RTYPE_INTEGER}},
- /* This is an internally implemented control method, no need to check */
-{
-"_OSI", 1, ACPI_RTYPE_INTEGER},
+ /* TBD: */
+
+ _PRT - currently ignore reversed entries. attempt to fix here?
+ think about possibly fixing package elements like _BIF, etc.
+#endif
- /* TBD: */
- _PRT - currently ignore reversed entries.attempt to fix here ?
- think about code that attempts to fix package elements like _BIF, etc.
#endif
#endif
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index 897810ba0ccc..863a264b829e 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -324,26 +324,30 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
acpi_status
acpi_ut_evaluate_numeric_object(char *object_name,
struct acpi_namespace_node *device_node,
- acpi_integer * address);
+ acpi_integer *value);
acpi_status
-acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
- struct acpica_device_id *hid);
+acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 *status_flags);
acpi_status
-acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
- struct acpi_compatible_id_list **return_cid_list);
+acpi_ut_execute_power_methods(struct acpi_namespace_node *device_node,
+ const char **method_names,
+ u8 method_count, u8 *out_values);
+/*
+ * utids - device ID support
+ */
acpi_status
-acpi_ut_execute_STA(struct acpi_namespace_node *device_node,
- u32 * status_flags);
+acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
+ struct acpica_device_id **return_id);
acpi_status
acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
- struct acpica_device_id *uid);
+ struct acpica_device_id **return_id);
acpi_status
-acpi_ut_execute_sxds(struct acpi_namespace_node *device_node, u8 * highest);
+acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
+ struct acpica_device_id_list **return_cid_list);
/*
* utlock - reader/writer locks
@@ -445,6 +449,8 @@ acpi_ut_short_divide(acpi_integer in_dividend,
*/
const char *acpi_ut_validate_exception(acpi_status status);
+u8 acpi_ut_is_pci_root_bridge(char *id);
+
u8 acpi_ut_is_aml_table(struct acpi_table_header *table);
acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id);
@@ -469,6 +475,12 @@ u8 acpi_ut_valid_acpi_char(char character, u32 position);
acpi_status
acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer);
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_warning(const char *module_name,
+ u32 line_number,
+ char *pathname,
+ u8 node_flags, const char *format, ...);
+
/* Values for Base above (16=Hex, 10=Decimal) */
#define ACPI_ANY_BASE 0
diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h
index 067f967eb389..4940249f2524 100644
--- a/drivers/acpi/acpica/amlcode.h
+++ b/drivers/acpi/acpica/amlcode.h
@@ -404,6 +404,7 @@ typedef enum {
REGION_SMBUS,
REGION_CMOS,
REGION_PCI_BAR,
+ REGION_IPMI,
REGION_DATA_TABLE, /* Internal use only */
REGION_FIXED_HW = 0x7F
} AML_REGION_TYPES;
diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c
index 53e27bc5a734..54a225e56a64 100644
--- a/drivers/acpi/acpica/dsfield.c
+++ b/drivers/acpi/acpica/dsfield.c
@@ -123,9 +123,12 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
ACPI_NS_ERROR_IF_FOUND;
- /* Mark node temporary if we are executing a method */
-
- if (walk_state->method_node) {
+ /*
+ * Mark node temporary if we are executing a normal control
+ * method. (Don't mark if this is a module-level code method)
+ */
+ if (walk_state->method_node &&
+ !(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) {
flags |= ACPI_NS_TEMPORARY;
}
@@ -456,9 +459,12 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
ACPI_NS_ERROR_IF_FOUND;
- /* Mark node(s) temporary if we are executing a method */
-
- if (walk_state->method_node) {
+ /*
+ * Mark node(s) temporary if we are executing a normal control
+ * method. (Don't mark if this is a module-level code method)
+ */
+ if (walk_state->method_node &&
+ !(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) {
flags |= ACPI_NS_TEMPORARY;
}
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index 14b8b8ed8023..567a4899a018 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -578,10 +578,15 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
}
/*
- * Delete any namespace objects created anywhere within
- * the namespace by the execution of this method
+ * Delete any namespace objects created anywhere within the
+ * namespace by the execution of this method. Unless this method
+ * is a module-level executable code method, in which case we
+ * want make the objects permanent.
*/
- acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id);
+ if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) {
+ acpi_ns_delete_namespace_by_owner(method_desc->method.
+ owner_id);
+ }
}
/* Decrement the thread count on the method */
@@ -622,7 +627,9 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
/* No more threads, we can free the owner_id */
- acpi_ut_release_owner_id(&method_desc->method.owner_id);
+ if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) {
+ acpi_ut_release_owner_id(&method_desc->method.owner_id);
+ }
}
return_VOID;
diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c
index 22b1a3ce2c94..7d077bb2f525 100644
--- a/drivers/acpi/acpica/dsmthdat.c
+++ b/drivers/acpi/acpica/dsmthdat.c
@@ -433,10 +433,10 @@ acpi_ds_method_data_get_value(u8 type,
case ACPI_REFCLASS_LOCAL:
- ACPI_ERROR((AE_INFO,
- "Uninitialized Local[%d] at node %p",
- index, node));
-
+ /*
+ * No error message for this case, will be trapped again later to
+ * detect and ignore cases of Store(local_x,local_x)
+ */
return_ACPI_STATUS(AE_AML_UNINITIALIZED_LOCAL);
default:
diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c
index 02e6caad4a76..507e1f0bbdfd 100644
--- a/drivers/acpi/acpica/dsobject.c
+++ b/drivers/acpi/acpica/dsobject.c
@@ -482,14 +482,27 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
if (arg) {
/*
* num_elements was exhausted, but there are remaining elements in the
- * package_list.
+ * package_list. Truncate the package to num_elements.
*
* Note: technically, this is an error, from ACPI spec: "It is an error
* for NumElements to be less than the number of elements in the
- * PackageList". However, for now, we just print an error message and
- * no exception is returned.
+ * PackageList". However, we just print an error message and
+ * no exception is returned. This provides Windows compatibility. Some
+ * BIOSs will alter the num_elements on the fly, creating this type
+ * of ill-formed package object.
*/
while (arg) {
+ /*
+ * We must delete any package elements that were created earlier
+ * and are not going to be used because of the package truncation.
+ */
+ if (arg->common.node) {
+ acpi_ut_remove_reference(ACPI_CAST_PTR
+ (union
+ acpi_operand_object,
+ arg->common.node));
+ arg->common.node = NULL;
+ }
/* Find out how many elements there really are */
@@ -498,7 +511,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
}
ACPI_WARNING((AE_INFO,
- "Package List length (%X) larger than NumElements count (%X), truncated\n",
+ "Package List length (0x%X) larger than NumElements count (0x%X), truncated\n",
i, element_count));
} else if (i < element_count) {
/*
@@ -506,7 +519,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
* Note: this is not an error, the package is padded out with NULLs.
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Package List length (%X) smaller than NumElements count (%X), padded with null elements\n",
+ "Package List length (0x%X) smaller than NumElements count (0x%X), padded with null elements\n",
i, element_count));
}
diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c
index 3023ceaa8d54..6de3a99d4cd4 100644
--- a/drivers/acpi/acpica/dswload.c
+++ b/drivers/acpi/acpica/dswload.c
@@ -581,21 +581,6 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
if ((!(walk_state->op_info->flags & AML_NSOPCODE) &&
(walk_state->opcode != AML_INT_NAMEPATH_OP)) ||
(!(walk_state->op_info->flags & AML_NAMED))) {
-#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
- if ((walk_state->op_info->class == AML_CLASS_EXECUTE) ||
- (walk_state->op_info->class == AML_CLASS_CONTROL)) {
- ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "Begin/EXEC: %s (fl %8.8X)\n",
- walk_state->op_info->name,
- walk_state->op_info->flags));
-
- /* Executing a type1 or type2 opcode outside of a method */
-
- status =
- acpi_ds_exec_begin_op(walk_state, out_op);
- return_ACPI_STATUS(status);
- }
-#endif
return_ACPI_STATUS(AE_OK);
}
@@ -768,7 +753,13 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
/* Execution mode, node cannot already exist, node is temporary */
- flags |= (ACPI_NS_ERROR_IF_FOUND | ACPI_NS_TEMPORARY);
+ flags |= ACPI_NS_ERROR_IF_FOUND;
+
+ if (!
+ (walk_state->
+ parse_flags & ACPI_PARSE_MODULE_LEVEL)) {
+ flags |= ACPI_NS_TEMPORARY;
+ }
}
/* Add new entry or lookup existing entry */
@@ -851,24 +842,6 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
/* Check if opcode had an associated namespace object */
if (!(walk_state->op_info->flags & AML_NSOBJECT)) {
-#ifndef ACPI_NO_METHOD_EXECUTION
-#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
- /* No namespace object. Executable opcode? */
-
- if ((walk_state->op_info->class == AML_CLASS_EXECUTE) ||
- (walk_state->op_info->class == AML_CLASS_CONTROL)) {
- ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "End/EXEC: %s (fl %8.8X)\n",
- walk_state->op_info->name,
- walk_state->op_info->flags));
-
- /* Executing a type1 or type2 opcode outside of a method */
-
- status = acpi_ds_exec_end_op(walk_state);
- return_ACPI_STATUS(status);
- }
-#endif
-#endif
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index b9d8ee69ca6c..afacf4416c73 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -424,8 +424,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
/* Read the Status Register */
status =
- acpi_read(&status_reg,
- &gpe_register_info->status_address);
+ acpi_hw_read(&status_reg,
+ &gpe_register_info->status_address);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -433,8 +433,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
/* Read the Enable Register */
status =
- acpi_read(&enable_reg,
- &gpe_register_info->enable_address);
+ acpi_hw_read(&enable_reg,
+ &gpe_register_info->enable_address);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index 7b3463639422..a60aaa7635f3 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -843,14 +843,14 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
/* Disable all GPEs within this register */
- status = acpi_write(0x00, &this_register->enable_address);
+ status = acpi_hw_write(0x00, &this_register->enable_address);
if (ACPI_FAILURE(status)) {
goto error_exit;
}
/* Clear any pending GPE events within this register */
- status = acpi_write(0xFF, &this_register->status_address);
+ status = acpi_hw_write(0xFF, &this_register->status_address);
if (ACPI_FAILURE(status)) {
goto error_exit;
}
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index 284a7becbe96..cf29c4953028 100644
--- a/drivers/acpi/acpica/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -50,8 +50,6 @@
ACPI_MODULE_NAME("evrgnini")
/* Local prototypes */
-static u8 acpi_ev_match_pci_root_bridge(char *id);
-
static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node);
/*******************************************************************************
@@ -332,37 +330,6 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
/*******************************************************************************
*
- * FUNCTION: acpi_ev_match_pci_root_bridge
- *
- * PARAMETERS: Id - The HID/CID in string format
- *
- * RETURN: TRUE if the Id is a match for a PCI/PCI-Express Root Bridge
- *
- * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID.
- *
- ******************************************************************************/
-
-static u8 acpi_ev_match_pci_root_bridge(char *id)
-{
-
- /*
- * Check if this is a PCI root.
- * ACPI 3.0+: check for a PCI Express root also.
- */
- if (!(ACPI_STRNCMP(id,
- PCI_ROOT_HID_STRING,
- sizeof(PCI_ROOT_HID_STRING))) ||
- !(ACPI_STRNCMP(id,
- PCI_EXPRESS_ROOT_HID_STRING,
- sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
- return (TRUE);
- }
-
- return (FALSE);
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ev_is_pci_root_bridge
*
* PARAMETERS: Node - Device node being examined
@@ -377,9 +344,10 @@ static u8 acpi_ev_match_pci_root_bridge(char *id)
static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
{
acpi_status status;
- struct acpica_device_id hid;
- struct acpi_compatible_id_list *cid;
+ struct acpica_device_id *hid;
+ struct acpica_device_id_list *cid;
u32 i;
+ u8 match;
/* Get the _HID and check for a PCI Root Bridge */
@@ -388,7 +356,10 @@ static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
return (FALSE);
}
- if (acpi_ev_match_pci_root_bridge(hid.value)) {
+ match = acpi_ut_is_pci_root_bridge(hid->string);
+ ACPI_FREE(hid);
+
+ if (match) {
return (TRUE);
}
@@ -402,7 +373,7 @@ static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
/* Check all _CIDs in the returned list */
for (i = 0; i < cid->count; i++) {
- if (acpi_ev_match_pci_root_bridge(cid->id[i].value)) {
+ if (acpi_ut_is_pci_root_bridge(cid->ids[i].string)) {
ACPI_FREE(cid);
return (TRUE);
}
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c
index 277fd609611a..24afef81af39 100644
--- a/drivers/acpi/acpica/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -110,8 +110,15 @@ acpi_ex_add_table(u32 table_index,
if (ACPI_FAILURE(status)) {
acpi_ut_remove_reference(obj_desc);
*ddb_handle = NULL;
+ return_ACPI_STATUS(status);
}
+ /* Execute any module-level code that was found in the table */
+
+ acpi_ex_exit_interpreter();
+ acpi_ns_exec_module_code_list();
+ acpi_ex_enter_interpreter();
+
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index ec524614e708..de3446372ddc 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -418,9 +418,9 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
case ACPI_EXD_REFERENCE:
acpi_ex_out_string("Class Name",
- (char *)
- acpi_ut_get_reference_name
- (obj_desc));
+ ACPI_CAST_PTR(char,
+ acpi_ut_get_reference_name
+ (obj_desc)));
acpi_ex_dump_reference_obj(obj_desc);
break;
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index 546dcdd86785..0b33d6c887b9 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -72,6 +72,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
union acpi_operand_object *buffer_desc;
acpi_size length;
void *buffer;
+ u32 function;
ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);
@@ -97,13 +98,27 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
}
} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
(obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_SMBUS)) {
+ ACPI_ADR_SPACE_SMBUS
+ || obj_desc->field.region_obj->region.space_id ==
+ ACPI_ADR_SPACE_IPMI)) {
/*
- * This is an SMBus read. We must create a buffer to hold the data
- * and directly access the region handler.
+ * This is an SMBus or IPMI read. We must create a buffer to hold
+ * the data and then directly access the region handler.
+ *
+ * Note: Smbus protocol value is passed in upper 16-bits of Function
*/
- buffer_desc =
- acpi_ut_create_buffer_object(ACPI_SMBUS_BUFFER_SIZE);
+ if (obj_desc->field.region_obj->region.space_id ==
+ ACPI_ADR_SPACE_SMBUS) {
+ length = ACPI_SMBUS_BUFFER_SIZE;
+ function =
+ ACPI_READ | (obj_desc->field.attribute << 16);
+ } else { /* IPMI */
+
+ length = ACPI_IPMI_BUFFER_SIZE;
+ function = ACPI_READ;
+ }
+
+ buffer_desc = acpi_ut_create_buffer_object(length);
if (!buffer_desc) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -112,16 +127,13 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
- /*
- * Perform the read.
- * Note: Smbus protocol value is passed in upper 16-bits of Function
- */
+ /* Call the region handler for the read */
+
status = acpi_ex_access_region(obj_desc, 0,
ACPI_CAST_PTR(acpi_integer,
buffer_desc->
buffer.pointer),
- ACPI_READ | (obj_desc->field.
- attribute << 16));
+ function);
acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
goto exit;
}
@@ -212,6 +224,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
u32 length;
void *buffer;
union acpi_operand_object *buffer_desc;
+ u32 function;
ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);
@@ -234,39 +247,56 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
}
} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
(obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_SMBUS)) {
+ ACPI_ADR_SPACE_SMBUS
+ || obj_desc->field.region_obj->region.space_id ==
+ ACPI_ADR_SPACE_IPMI)) {
/*
- * This is an SMBus write. We will bypass the entire field mechanism
- * and handoff the buffer directly to the handler.
+ * This is an SMBus or IPMI write. We will bypass the entire field
+ * mechanism and handoff the buffer directly to the handler. For
+ * these address spaces, the buffer is bi-directional; on a write,
+ * return data is returned in the same buffer.
+ *
+ * Source must be a buffer of sufficient size:
+ * ACPI_SMBUS_BUFFER_SIZE or ACPI_IPMI_BUFFER_SIZE.
*
- * Source must be a buffer of sufficient size (ACPI_SMBUS_BUFFER_SIZE).
+ * Note: SMBus protocol type is passed in upper 16-bits of Function
*/
if (source_desc->common.type != ACPI_TYPE_BUFFER) {
ACPI_ERROR((AE_INFO,
- "SMBus write requires Buffer, found type %s",
+ "SMBus or IPMI write requires Buffer, found type %s",
acpi_ut_get_object_type_name(source_desc)));
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
- if (source_desc->buffer.length < ACPI_SMBUS_BUFFER_SIZE) {
+ if (obj_desc->field.region_obj->region.space_id ==
+ ACPI_ADR_SPACE_SMBUS) {
+ length = ACPI_SMBUS_BUFFER_SIZE;
+ function =
+ ACPI_WRITE | (obj_desc->field.attribute << 16);
+ } else { /* IPMI */
+
+ length = ACPI_IPMI_BUFFER_SIZE;
+ function = ACPI_WRITE;
+ }
+
+ if (source_desc->buffer.length < length) {
ACPI_ERROR((AE_INFO,
- "SMBus write requires Buffer of length %X, found length %X",
- ACPI_SMBUS_BUFFER_SIZE,
- source_desc->buffer.length));
+ "SMBus or IPMI write requires Buffer of length %X, found length %X",
+ length, source_desc->buffer.length));
return_ACPI_STATUS(AE_AML_BUFFER_LIMIT);
}
- buffer_desc =
- acpi_ut_create_buffer_object(ACPI_SMBUS_BUFFER_SIZE);
+ /* Create the bi-directional buffer */
+
+ buffer_desc = acpi_ut_create_buffer_object(length);
if (!buffer_desc) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
buffer = buffer_desc->buffer.pointer;
- ACPI_MEMCPY(buffer, source_desc->buffer.pointer,
- ACPI_SMBUS_BUFFER_SIZE);
+ ACPI_MEMCPY(buffer, source_desc->buffer.pointer, length);
/* Lock entire transaction if requested */
@@ -275,12 +305,10 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
/*
* Perform the write (returns status and perhaps data in the
* same buffer)
- * Note: SMBus protocol type is passed in upper 16-bits of Function.
*/
status = acpi_ex_access_region(obj_desc, 0,
(acpi_integer *) buffer,
- ACPI_WRITE | (obj_desc->field.
- attribute << 16));
+ function);
acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
*result_desc = buffer_desc;
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c
index 6687be167f5f..d7b3b418fb45 100644
--- a/drivers/acpi/acpica/exfldio.c
+++ b/drivers/acpi/acpica/exfldio.c
@@ -120,12 +120,13 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
}
/*
- * Exit now for SMBus address space, it has a non-linear address space
+ * Exit now for SMBus or IPMI address space, it has a non-linear address space
* and the request cannot be directly validated
*/
- if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) {
+ if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS ||
+ rgn_desc->region.space_id == ACPI_ADR_SPACE_IPMI) {
- /* SMBus has a non-linear address space */
+ /* SMBus or IPMI has a non-linear address space */
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c
index 3a54b737d2da..2bd83ac57c3a 100644
--- a/drivers/acpi/acpica/exregion.c
+++ b/drivers/acpi/acpica/exregion.c
@@ -77,7 +77,8 @@ acpi_ex_system_memory_space_handler(u32 function,
void *logical_addr_ptr = NULL;
struct acpi_mem_space_context *mem_info = region_context;
u32 length;
- acpi_size window_size;
+ acpi_size map_length;
+ acpi_size page_boundary_map_length;
#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
u32 remainder;
#endif
@@ -144,25 +145,39 @@ acpi_ex_system_memory_space_handler(u32 function,
}
/*
- * Don't attempt to map memory beyond the end of the region, and
- * constrain the maximum mapping size to something reasonable.
+ * Attempt to map from the requested address to the end of the region.
+ * However, we will never map more than one page, nor will we cross
+ * a page boundary.
*/
- window_size = (acpi_size)
+ map_length = (acpi_size)
((mem_info->address + mem_info->length) - address);
- if (window_size > ACPI_SYSMEM_REGION_WINDOW_SIZE) {
- window_size = ACPI_SYSMEM_REGION_WINDOW_SIZE;
+ /*
+ * If mapping the entire remaining portion of the region will cross
+ * a page boundary, just map up to the page boundary, do not cross.
+ * On some systems, crossing a page boundary while mapping regions
+ * can cause warnings if the pages have different attributes
+ * due to resource management
+ */
+ page_boundary_map_length =
+ ACPI_ROUND_UP(address, ACPI_DEFAULT_PAGE_SIZE) - address;
+
+ if (!page_boundary_map_length) {
+ page_boundary_map_length = ACPI_DEFAULT_PAGE_SIZE;
+ }
+
+ if (map_length > page_boundary_map_length) {
+ map_length = page_boundary_map_length;
}
/* Create a new mapping starting at the address given */
- mem_info->mapped_logical_address =
- acpi_os_map_memory((acpi_physical_address) address, window_size);
+ mem_info->mapped_logical_address = acpi_os_map_memory((acpi_physical_address) address, map_length);
if (!mem_info->mapped_logical_address) {
ACPI_ERROR((AE_INFO,
"Could not map memory at %8.8X%8.8X, size %X",
ACPI_FORMAT_NATIVE_UINT(address),
- (u32) window_size));
+ (u32) map_length));
mem_info->mapped_length = 0;
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -170,7 +185,7 @@ acpi_ex_system_memory_space_handler(u32 function,
/* Save the physical address and mapping size */
mem_info->mapped_physical_address = address;
- mem_info->mapped_length = window_size;
+ mem_info->mapped_length = map_length;
}
/*
diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c
index 87730e944132..7d41f99f7052 100644
--- a/drivers/acpi/acpica/exutils.c
+++ b/drivers/acpi/acpica/exutils.c
@@ -358,50 +358,67 @@ static u32 acpi_ex_digits_needed(acpi_integer value, u32 base)
*
* FUNCTION: acpi_ex_eisa_id_to_string
*
- * PARAMETERS: numeric_id - EISA ID to be converted
+ * PARAMETERS: compressed_id - EISAID to be converted
* out_string - Where to put the converted string (8 bytes)
*
* RETURN: None
*
- * DESCRIPTION: Convert a numeric EISA ID to string representation
+ * DESCRIPTION: Convert a numeric EISAID to string representation. Return
+ * buffer must be large enough to hold the string. The string
+ * returned is always exactly of length ACPI_EISAID_STRING_SIZE
+ * (includes null terminator). The EISAID is always 32 bits.
*
******************************************************************************/
-void acpi_ex_eisa_id_to_string(u32 numeric_id, char *out_string)
+void acpi_ex_eisa_id_to_string(char *out_string, acpi_integer compressed_id)
{
- u32 eisa_id;
+ u32 swapped_id;
ACPI_FUNCTION_ENTRY();
+ /* The EISAID should be a 32-bit integer */
+
+ if (compressed_id > ACPI_UINT32_MAX) {
+ ACPI_WARNING((AE_INFO,
+ "Expected EISAID is larger than 32 bits: 0x%8.8X%8.8X, truncating",
+ ACPI_FORMAT_UINT64(compressed_id)));
+ }
+
/* Swap ID to big-endian to get contiguous bits */
- eisa_id = acpi_ut_dword_byte_swap(numeric_id);
+ swapped_id = acpi_ut_dword_byte_swap((u32)compressed_id);
- out_string[0] = (char)('@' + (((unsigned long)eisa_id >> 26) & 0x1f));
- out_string[1] = (char)('@' + ((eisa_id >> 21) & 0x1f));
- out_string[2] = (char)('@' + ((eisa_id >> 16) & 0x1f));
- out_string[3] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 12);
- out_string[4] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 8);
- out_string[5] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 4);
- out_string[6] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 0);
+ /* First 3 bytes are uppercase letters. Next 4 bytes are hexadecimal */
+
+ out_string[0] =
+ (char)(0x40 + (((unsigned long)swapped_id >> 26) & 0x1F));
+ out_string[1] = (char)(0x40 + ((swapped_id >> 21) & 0x1F));
+ out_string[2] = (char)(0x40 + ((swapped_id >> 16) & 0x1F));
+ out_string[3] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 12);
+ out_string[4] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 8);
+ out_string[5] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 4);
+ out_string[6] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 0);
out_string[7] = 0;
}
/*******************************************************************************
*
- * FUNCTION: acpi_ex_unsigned_integer_to_string
+ * FUNCTION: acpi_ex_integer_to_string
*
- * PARAMETERS: Value - Value to be converted
- * out_string - Where to put the converted string (8 bytes)
+ * PARAMETERS: out_string - Where to put the converted string. At least
+ * 21 bytes are needed to hold the largest
+ * possible 64-bit integer.
+ * Value - Value to be converted
*
* RETURN: None, string
*
- * DESCRIPTION: Convert a number to string representation. Assumes string
- * buffer is large enough to hold the string.
+ * DESCRIPTION: Convert a 64-bit integer to decimal string representation.
+ * Assumes string buffer is large enough to hold the string. The
+ * largest string is (ACPI_MAX64_DECIMAL_DIGITS + 1).
*
******************************************************************************/
-void acpi_ex_unsigned_integer_to_string(acpi_integer value, char *out_string)
+void acpi_ex_integer_to_string(char *out_string, acpi_integer value)
{
u32 count;
u32 digits_needed;
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index d3b7e37c9eed..c28c41b3180b 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -82,7 +82,7 @@ acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
/* Get current value of the enable register that contains this GPE */
- status = acpi_read(&enable_mask, &gpe_register_info->enable_address);
+ status = acpi_hw_read(&enable_mask, &gpe_register_info->enable_address);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -95,7 +95,7 @@ acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
/* Write the updated enable mask */
- status = acpi_write(enable_mask, &gpe_register_info->enable_address);
+ status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address);
return (status);
}
@@ -130,8 +130,8 @@ acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info * gpe_event_info)
/* Write the entire GPE (runtime) enable register */
- status = acpi_write(gpe_register_info->enable_for_run,
- &gpe_register_info->enable_address);
+ status = acpi_hw_write(gpe_register_info->enable_for_run,
+ &gpe_register_info->enable_address);
return (status);
}
@@ -163,8 +163,8 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
* Write a one to the appropriate bit in the status register to
* clear this GPE.
*/
- status = acpi_write(register_bit,
- &gpe_event_info->register_info->status_address);
+ status = acpi_hw_write(register_bit,
+ &gpe_event_info->register_info->status_address);
return (status);
}
@@ -222,7 +222,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
/* GPE currently active (status bit == 1)? */
- status = acpi_read(&in_byte, &gpe_register_info->status_address);
+ status = acpi_hw_read(&in_byte, &gpe_register_info->status_address);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -266,8 +266,8 @@ acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/* Disable all GPEs in this register */
status =
- acpi_write(0x00,
- &gpe_block->register_info[i].enable_address);
+ acpi_hw_write(0x00,
+ &gpe_block->register_info[i].enable_address);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -303,8 +303,8 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/* Clear status on all GPEs in this register */
status =
- acpi_write(0xFF,
- &gpe_block->register_info[i].status_address);
+ acpi_hw_write(0xFF,
+ &gpe_block->register_info[i].status_address);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -345,9 +345,9 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/* Enable all "runtime" GPEs in this register */
- status = acpi_write(gpe_block->register_info[i].enable_for_run,
- &gpe_block->register_info[i].
- enable_address);
+ status =
+ acpi_hw_write(gpe_block->register_info[i].enable_for_run,
+ &gpe_block->register_info[i].enable_address);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -387,9 +387,9 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/* Enable all "wake" GPEs in this register */
- status = acpi_write(gpe_block->register_info[i].enable_for_wake,
- &gpe_block->register_info[i].
- enable_address);
+ status =
+ acpi_hw_write(gpe_block->register_info[i].enable_for_wake,
+ &gpe_block->register_info[i].enable_address);
if (ACPI_FAILURE(status)) {
return (status);
}
diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index 23d5505cb1f7..15c9ed2be853 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -62,6 +62,184 @@ acpi_hw_write_multiple(u32 value,
struct acpi_generic_address *register_a,
struct acpi_generic_address *register_b);
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_validate_register
+ *
+ * PARAMETERS: Reg - GAS register structure
+ * max_bit_width - Max bit_width supported (32 or 64)
+ * Address - Pointer to where the gas->address
+ * is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
+ * pointer, Address, space_id, bit_width, and bit_offset.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_validate_register(struct acpi_generic_address *reg,
+ u8 max_bit_width, u64 *address)
+{
+
+ /* Must have a valid pointer to a GAS structure */
+
+ if (!reg) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Copy the target address. This handles possible alignment issues.
+ * Address must not be null. A null address also indicates an optional
+ * ACPI register that is not supported, so no error message.
+ */
+ ACPI_MOVE_64_TO_64(address, &reg->address);
+ if (!(*address)) {
+ return (AE_BAD_ADDRESS);
+ }
+
+ /* Validate the space_iD */
+
+ if ((reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
+ (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
+ ACPI_ERROR((AE_INFO,
+ "Unsupported address space: 0x%X", reg->space_id));
+ return (AE_SUPPORT);
+ }
+
+ /* Validate the bit_width */
+
+ if ((reg->bit_width != 8) &&
+ (reg->bit_width != 16) &&
+ (reg->bit_width != 32) && (reg->bit_width != max_bit_width)) {
+ ACPI_ERROR((AE_INFO,
+ "Unsupported register bit width: 0x%X",
+ reg->bit_width));
+ return (AE_SUPPORT);
+ }
+
+ /* Validate the bit_offset. Just a warning for now. */
+
+ if (reg->bit_offset != 0) {
+ ACPI_WARNING((AE_INFO,
+ "Unsupported register bit offset: 0x%X",
+ reg->bit_offset));
+ }
+
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_read
+ *
+ * PARAMETERS: Value - Where the value is returned
+ * Reg - GAS register structure
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max
+ * version of acpi_read, used internally since the overhead of
+ * 64-bit values is not needed.
+ *
+ * LIMITATIONS: <These limitations also apply to acpi_hw_write>
+ * bit_width must be exactly 8, 16, or 32.
+ * space_iD must be system_memory or system_iO.
+ * bit_offset and access_width are currently ignored, as there has
+ * not been a need to implement these.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
+{
+ u64 address;
+ acpi_status status;
+
+ ACPI_FUNCTION_NAME(hw_read);
+
+ /* Validate contents of the GAS register */
+
+ status = acpi_hw_validate_register(reg, 32, &address);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /* Initialize entire 32-bit return value to zero */
+
+ *value = 0;
+
+ /*
+ * Two address spaces supported: Memory or IO. PCI_Config is
+ * not supported here because the GAS structure is insufficient
+ */
+ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+ status = acpi_os_read_memory((acpi_physical_address)
+ address, value, reg->bit_width);
+ } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
+
+ status = acpi_hw_read_port((acpi_io_address)
+ address, value, reg->bit_width);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_IO,
+ "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n",
+ *value, reg->bit_width, ACPI_FORMAT_UINT64(address),
+ acpi_ut_get_region_name(reg->space_id)));
+
+ return (status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_write
+ *
+ * PARAMETERS: Value - Value to be written
+ * Reg - GAS register structure
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max
+ * version of acpi_write, used internally since the overhead of
+ * 64-bit values is not needed.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
+{
+ u64 address;
+ acpi_status status;
+
+ ACPI_FUNCTION_NAME(hw_write);
+
+ /* Validate contents of the GAS register */
+
+ status = acpi_hw_validate_register(reg, 32, &address);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /*
+ * Two address spaces supported: Memory or IO. PCI_Config is
+ * not supported here because the GAS structure is insufficient
+ */
+ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+ status = acpi_os_write_memory((acpi_physical_address)
+ address, value, reg->bit_width);
+ } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
+
+ status = acpi_hw_write_port((acpi_io_address)
+ address, value, reg->bit_width);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_IO,
+ "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
+ value, reg->bit_width, ACPI_FORMAT_UINT64(address),
+ acpi_ut_get_region_name(reg->space_id)));
+
+ return (status);
+}
+
/*******************************************************************************
*
* FUNCTION: acpi_hw_clear_acpi_status
@@ -152,15 +330,16 @@ acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control)
ACPI_FUNCTION_TRACE(hw_write_pm1_control);
- status = acpi_write(pm1a_control, &acpi_gbl_FADT.xpm1a_control_block);
+ status =
+ acpi_hw_write(pm1a_control, &acpi_gbl_FADT.xpm1a_control_block);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
if (acpi_gbl_FADT.xpm1b_control_block.address) {
status =
- acpi_write(pm1b_control,
- &acpi_gbl_FADT.xpm1b_control_block);
+ acpi_hw_write(pm1b_control,
+ &acpi_gbl_FADT.xpm1b_control_block);
}
return_ACPI_STATUS(status);
}
@@ -218,12 +397,13 @@ acpi_hw_register_read(u32 register_id, u32 * return_value)
case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
- status = acpi_read(&value, &acpi_gbl_FADT.xpm2_control_block);
+ status =
+ acpi_hw_read(&value, &acpi_gbl_FADT.xpm2_control_block);
break;
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
- status = acpi_read(&value, &acpi_gbl_FADT.xpm_timer_block);
+ status = acpi_hw_read(&value, &acpi_gbl_FADT.xpm_timer_block);
break;
case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
@@ -340,7 +520,8 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
* as per the ACPI spec.
*/
status =
- acpi_read(&read_value, &acpi_gbl_FADT.xpm2_control_block);
+ acpi_hw_read(&read_value,
+ &acpi_gbl_FADT.xpm2_control_block);
if (ACPI_FAILURE(status)) {
goto exit;
}
@@ -350,12 +531,13 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
ACPI_INSERT_BITS(value, ACPI_PM2_CONTROL_PRESERVED_BITS,
read_value);
- status = acpi_write(value, &acpi_gbl_FADT.xpm2_control_block);
+ status =
+ acpi_hw_write(value, &acpi_gbl_FADT.xpm2_control_block);
break;
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
- status = acpi_write(value, &acpi_gbl_FADT.xpm_timer_block);
+ status = acpi_hw_write(value, &acpi_gbl_FADT.xpm_timer_block);
break;
case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
@@ -401,7 +583,7 @@ acpi_hw_read_multiple(u32 *value,
/* The first register is always required */
- status = acpi_read(&value_a, register_a);
+ status = acpi_hw_read(&value_a, register_a);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -409,7 +591,7 @@ acpi_hw_read_multiple(u32 *value,
/* Second register is optional */
if (register_b->address) {
- status = acpi_read(&value_b, register_b);
+ status = acpi_hw_read(&value_b, register_b);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -452,7 +634,7 @@ acpi_hw_write_multiple(u32 value,
/* The first register is always required */
- status = acpi_write(value, register_a);
+ status = acpi_hw_write(value, register_a);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -470,7 +652,7 @@ acpi_hw_write_multiple(u32 value,
* and writes have no side effects"
*/
if (register_b->address) {
- status = acpi_write(value, register_b);
+ status = acpi_hw_write(value, register_b);
}
return (status);
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index db307a356f08..cc22f9a585b0 100644
--- a/drivers/acpi/acpica/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -45,6 +45,7 @@
#include <acpi/acpi.h>
#include "accommon.h"
#include "actables.h"
+#include <linux/tboot.h>
#define _COMPONENT ACPI_HARDWARE
ACPI_MODULE_NAME("hwsleep")
@@ -342,6 +343,8 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
ACPI_FLUSH_CPU_CACHE();
+ tboot_sleep(sleep_state, pm1a_control, pm1b_control);
+
/* Write #2: Write both SLP_TYP + SLP_EN */
status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c
index b7f522c8f023..6b282e85d039 100644
--- a/drivers/acpi/acpica/hwtimer.c
+++ b/drivers/acpi/acpica/hwtimer.c
@@ -100,7 +100,7 @@ acpi_status acpi_get_timer(u32 * ticks)
}
status =
- acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT.xpm_timer_block);
+ acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c
index 9829979f2bdd..647c7b6e6756 100644
--- a/drivers/acpi/acpica/hwxface.c
+++ b/drivers/acpi/acpica/hwxface.c
@@ -78,9 +78,22 @@ acpi_status acpi_reset(void)
return_ACPI_STATUS(AE_NOT_EXIST);
}
- /* Write the reset value to the reset register */
+ if (reset_reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+ /*
+ * For I/O space, write directly to the OSL. This bypasses the port
+ * validation mechanism, which may block a valid write to the reset
+ * register.
+ */
+ status =
+ acpi_os_write_port((acpi_io_address) reset_reg->address,
+ acpi_gbl_FADT.reset_value,
+ reset_reg->bit_width);
+ } else {
+ /* Write the reset value to the reset register */
+
+ status = acpi_hw_write(acpi_gbl_FADT.reset_value, reset_reg);
+ }
- status = acpi_write(acpi_gbl_FADT.reset_value, reset_reg);
return_ACPI_STATUS(status);
}
@@ -97,67 +110,92 @@ ACPI_EXPORT_SYMBOL(acpi_reset)
*
* DESCRIPTION: Read from either memory or IO space.
*
+ * LIMITATIONS: <These limitations also apply to acpi_write>
+ * bit_width must be exactly 8, 16, 32, or 64.
+ * space_iD must be system_memory or system_iO.
+ * bit_offset and access_width are currently ignored, as there has
+ * not been a need to implement these.
+ *
******************************************************************************/
-acpi_status acpi_read(u32 *value, struct acpi_generic_address *reg)
+acpi_status acpi_read(u64 *return_value, struct acpi_generic_address *reg)
{
+ u32 value;
u32 width;
u64 address;
acpi_status status;
ACPI_FUNCTION_NAME(acpi_read);
- /*
- * Must have a valid pointer to a GAS structure, and a non-zero address
- * within.
- */
- if (!reg) {
+ if (!return_value) {
return (AE_BAD_PARAMETER);
}
- /* Get a local copy of the address. Handles possible alignment issues */
+ /* Validate contents of the GAS register. Allow 64-bit transfers */
- ACPI_MOVE_64_TO_64(&address, &reg->address);
- if (!address) {
- return (AE_BAD_ADDRESS);
+ status = acpi_hw_validate_register(reg, 64, &address);
+ if (ACPI_FAILURE(status)) {
+ return (status);
}
- /* Supported widths are 8/16/32 */
-
width = reg->bit_width;
- if ((width != 8) && (width != 16) && (width != 32)) {
- return (AE_SUPPORT);
+ if (width == 64) {
+ width = 32; /* Break into two 32-bit transfers */
}
- /* Initialize entire 32-bit return value to zero */
+ /* Initialize entire 64-bit return value to zero */
- *value = 0;
+ *return_value = 0;
+ value = 0;
/*
* Two address spaces supported: Memory or IO. PCI_Config is
* not supported here because the GAS structure is insufficient
*/
- switch (reg->space_id) {
- case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+ status = acpi_os_read_memory((acpi_physical_address)
+ address, &value, width);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ *return_value = value;
- status = acpi_os_read_memory((acpi_physical_address) address,
- value, width);
- break;
+ if (reg->bit_width == 64) {
- case ACPI_ADR_SPACE_SYSTEM_IO:
+ /* Read the top 32 bits */
- status =
- acpi_hw_read_port((acpi_io_address) address, value, width);
- break;
+ status = acpi_os_read_memory((acpi_physical_address)
+ (address + 4), &value, 32);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ *return_value |= ((u64)value << 32);
+ }
+ } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
- default:
- ACPI_ERROR((AE_INFO,
- "Unsupported address space: %X", reg->space_id));
- return (AE_BAD_PARAMETER);
+ status = acpi_hw_read_port((acpi_io_address)
+ address, &value, width);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ *return_value = value;
+
+ if (reg->bit_width == 64) {
+
+ /* Read the top 32 bits */
+
+ status = acpi_hw_read_port((acpi_io_address)
+ (address + 4), &value, 32);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ *return_value |= ((u64)value << 32);
+ }
}
ACPI_DEBUG_PRINT((ACPI_DB_IO,
- "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n",
- *value, width, ACPI_FORMAT_UINT64(address),
+ "Read: %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
+ ACPI_FORMAT_UINT64(*return_value), reg->bit_width,
+ ACPI_FORMAT_UINT64(address),
acpi_ut_get_region_name(reg->space_id)));
return (status);
@@ -169,7 +207,7 @@ ACPI_EXPORT_SYMBOL(acpi_read)
*
* FUNCTION: acpi_write
*
- * PARAMETERS: Value - To be written
+ * PARAMETERS: Value - Value to be written
* Reg - GAS register structure
*
* RETURN: Status
@@ -177,7 +215,7 @@ ACPI_EXPORT_SYMBOL(acpi_read)
* DESCRIPTION: Write to either memory or IO space.
*
******************************************************************************/
-acpi_status acpi_write(u32 value, struct acpi_generic_address *reg)
+acpi_status acpi_write(u64 value, struct acpi_generic_address *reg)
{
u32 width;
u64 address;
@@ -185,54 +223,61 @@ acpi_status acpi_write(u32 value, struct acpi_generic_address *reg)
ACPI_FUNCTION_NAME(acpi_write);
- /*
- * Must have a valid pointer to a GAS structure, and a non-zero address
- * within.
- */
- if (!reg) {
- return (AE_BAD_PARAMETER);
- }
-
- /* Get a local copy of the address. Handles possible alignment issues */
+ /* Validate contents of the GAS register. Allow 64-bit transfers */
- ACPI_MOVE_64_TO_64(&address, &reg->address);
- if (!address) {
- return (AE_BAD_ADDRESS);
+ status = acpi_hw_validate_register(reg, 64, &address);
+ if (ACPI_FAILURE(status)) {
+ return (status);
}
- /* Supported widths are 8/16/32 */
-
width = reg->bit_width;
- if ((width != 8) && (width != 16) && (width != 32)) {
- return (AE_SUPPORT);
+ if (width == 64) {
+ width = 32; /* Break into two 32-bit transfers */
}
/*
- * Two address spaces supported: Memory or IO.
- * PCI_Config is not supported here because the GAS struct is insufficient
+ * Two address spaces supported: Memory or IO. PCI_Config is
+ * not supported here because the GAS structure is insufficient
*/
- switch (reg->space_id) {
- case ACPI_ADR_SPACE_SYSTEM_MEMORY:
-
- status = acpi_os_write_memory((acpi_physical_address) address,
- value, width);
- break;
+ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+ status = acpi_os_write_memory((acpi_physical_address)
+ address, ACPI_LODWORD(value),
+ width);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
- case ACPI_ADR_SPACE_SYSTEM_IO:
+ if (reg->bit_width == 64) {
+ status = acpi_os_write_memory((acpi_physical_address)
+ (address + 4),
+ ACPI_HIDWORD(value), 32);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
+ } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
- status = acpi_hw_write_port((acpi_io_address) address, value,
+ status = acpi_hw_write_port((acpi_io_address)
+ address, ACPI_LODWORD(value),
width);
- break;
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
- default:
- ACPI_ERROR((AE_INFO,
- "Unsupported address space: %X", reg->space_id));
- return (AE_BAD_PARAMETER);
+ if (reg->bit_width == 64) {
+ status = acpi_hw_write_port((acpi_io_address)
+ (address + 4),
+ ACPI_HIDWORD(value), 32);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
}
ACPI_DEBUG_PRINT((ACPI_DB_IO,
- "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
- value, width, ACPI_FORMAT_UINT64(address),
+ "Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n",
+ ACPI_FORMAT_UINT64(value), reg->bit_width,
+ ACPI_FORMAT_UINT64(address),
acpi_ut_get_region_name(reg->space_id)));
return (status);
diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c
index efc971ab7d65..8a58a1b85aa0 100644
--- a/drivers/acpi/acpica/nsalloc.c
+++ b/drivers/acpi/acpica/nsalloc.c
@@ -96,17 +96,68 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name)
*
* RETURN: None
*
- * DESCRIPTION: Delete a namespace node
+ * DESCRIPTION: Delete a namespace node. All node deletions must come through
+ * here. Detaches any attached objects, including any attached
+ * data. If a handler is associated with attached data, it is
+ * invoked before the node is deleted.
*
******************************************************************************/
void acpi_ns_delete_node(struct acpi_namespace_node *node)
{
+ union acpi_operand_object *obj_desc;
+
+ ACPI_FUNCTION_NAME(ns_delete_node);
+
+ /* Detach an object if there is one */
+
+ acpi_ns_detach_object(node);
+
+ /*
+ * Delete an attached data object if present (an object that was created
+ * and attached via acpi_attach_data). Note: After any normal object is
+ * detached above, the only possible remaining object is a data object.
+ */
+ obj_desc = node->object;
+ if (obj_desc && (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) {
+
+ /* Invoke the attached data deletion handler if present */
+
+ if (obj_desc->data.handler) {
+ obj_desc->data.handler(node, obj_desc->data.pointer);
+ }
+
+ acpi_ut_remove_reference(obj_desc);
+ }
+
+ /* Now we can delete the node */
+
+ (void)acpi_os_release_object(acpi_gbl_namespace_cache, node);
+
+ ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
+ ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Node %p, Remaining %X\n",
+ node, acpi_gbl_current_node_count));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_remove_node
+ *
+ * PARAMETERS: Node - Node to be removed/deleted
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Remove (unlink) and delete a namespace node
+ *
+ ******************************************************************************/
+
+void acpi_ns_remove_node(struct acpi_namespace_node *node)
+{
struct acpi_namespace_node *parent_node;
struct acpi_namespace_node *prev_node;
struct acpi_namespace_node *next_node;
- ACPI_FUNCTION_TRACE_PTR(ns_delete_node, node);
+ ACPI_FUNCTION_TRACE_PTR(ns_remove_node, node);
parent_node = acpi_ns_get_parent_node(node);
@@ -142,12 +193,9 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node)
}
}
- ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
-
- /* Detach an object if there is one, then delete the node */
+ /* Delete the node and any attached objects */
- acpi_ns_detach_object(node);
- (void)acpi_os_release_object(acpi_gbl_namespace_cache, node);
+ acpi_ns_delete_node(node);
return_VOID;
}
@@ -273,25 +321,11 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node)
parent_node, child_node));
}
- /* Now we can free this child object */
-
- ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
-
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
- "Object %p, Remaining %X\n", child_node,
- acpi_gbl_current_node_count));
-
- /* Detach an object if there is one, then free the child node */
-
- acpi_ns_detach_object(child_node);
-
- /* Now we can delete the node */
-
- (void)acpi_os_release_object(acpi_gbl_namespace_cache,
- child_node);
-
- /* And move on to the next child in the list */
-
+ /*
+ * Delete this child node and move on to the next child in the list.
+ * No need to unlink the node since we are deleting the entire branch.
+ */
+ acpi_ns_delete_node(child_node);
child_node = next_node;
} while (!(flags & ANOBJ_END_OF_PEER_LIST));
@@ -433,7 +467,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
if (deletion_node) {
acpi_ns_delete_children(deletion_node);
- acpi_ns_delete_node(deletion_node);
+ acpi_ns_remove_node(deletion_node);
deletion_node = NULL;
}
diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c
index 41994fe7fbb8..0fe87f1aef16 100644
--- a/drivers/acpi/acpica/nsdumpdv.c
+++ b/drivers/acpi/acpica/nsdumpdv.c
@@ -70,7 +70,6 @@ static acpi_status
acpi_ns_dump_one_device(acpi_handle obj_handle,
u32 level, void *context, void **return_value)
{
- struct acpi_buffer buffer;
struct acpi_device_info *info;
acpi_status status;
u32 i;
@@ -80,17 +79,15 @@ acpi_ns_dump_one_device(acpi_handle obj_handle,
status =
acpi_ns_dump_one_object(obj_handle, level, context, return_value);
- buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
- status = acpi_get_object_info(obj_handle, &buffer);
+ status = acpi_get_object_info(obj_handle, &info);
if (ACPI_SUCCESS(status)) {
- info = buffer.pointer;
for (i = 0; i < level; i++) {
ACPI_DEBUG_PRINT_RAW((ACPI_DB_TABLES, " "));
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_TABLES,
" HID: %s, ADR: %8.8X%8.8X, Status: %X\n",
- info->hardware_id.value,
+ info->hardware_id.string,
ACPI_FORMAT_UINT64(info->address),
info->current_status));
ACPI_FREE(info);
diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c
index 8e7dec1176c9..846d1132feb1 100644
--- a/drivers/acpi/acpica/nseval.c
+++ b/drivers/acpi/acpica/nseval.c
@@ -50,6 +50,11 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nseval")
+/* Local prototypes */
+static void
+acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
+ struct acpi_evaluate_info *info);
+
/*******************************************************************************
*
* FUNCTION: acpi_ns_evaluate
@@ -76,6 +81,7 @@ ACPI_MODULE_NAME("nseval")
* MUTEX: Locks interpreter
*
******************************************************************************/
+
acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
{
acpi_status status;
@@ -276,3 +282,134 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
*/
return_ACPI_STATUS(status);
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_exec_module_code_list
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None. Exceptions during method execution are ignored, since
+ * we cannot abort a table load.
+ *
+ * DESCRIPTION: Execute all elements of the global module-level code list.
+ * Each element is executed as a single control method.
+ *
+ ******************************************************************************/
+
+void acpi_ns_exec_module_code_list(void)
+{
+ union acpi_operand_object *prev;
+ union acpi_operand_object *next;
+ struct acpi_evaluate_info *info;
+ u32 method_count = 0;
+
+ ACPI_FUNCTION_TRACE(ns_exec_module_code_list);
+
+ /* Exit now if the list is empty */
+
+ next = acpi_gbl_module_code_list;
+ if (!next) {
+ return_VOID;
+ }
+
+ /* Allocate the evaluation information block */
+
+ info = ACPI_ALLOCATE(sizeof(struct acpi_evaluate_info));
+ if (!info) {
+ return_VOID;
+ }
+
+ /* Walk the list, executing each "method" */
+
+ while (next) {
+ prev = next;
+ next = next->method.mutex;
+
+ /* Clear the link field and execute the method */
+
+ prev->method.mutex = NULL;
+ acpi_ns_exec_module_code(prev, info);
+ method_count++;
+
+ /* Delete the (temporary) method object */
+
+ acpi_ut_remove_reference(prev);
+ }
+
+ ACPI_INFO((AE_INFO,
+ "Executed %u blocks of module-level executable AML code",
+ method_count));
+
+ ACPI_FREE(info);
+ acpi_gbl_module_code_list = NULL;
+ return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_exec_module_code
+ *
+ * PARAMETERS: method_obj - Object container for the module-level code
+ * Info - Info block for method evaluation
+ *
+ * RETURN: None. Exceptions during method execution are ignored, since
+ * we cannot abort a table load.
+ *
+ * DESCRIPTION: Execute a control method containing a block of module-level
+ * executable AML code. The control method is temporarily
+ * installed to the root node, then evaluated.
+ *
+ ******************************************************************************/
+
+static void
+acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
+ struct acpi_evaluate_info *info)
+{
+ union acpi_operand_object *root_obj;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(ns_exec_module_code);
+
+ /* Initialize the evaluation information block */
+
+ ACPI_MEMSET(info, 0, sizeof(struct acpi_evaluate_info));
+ info->prefix_node = acpi_gbl_root_node;
+
+ /*
+ * Get the currently attached root object. Add a reference, because the
+ * ref count will be decreased when the method object is installed to
+ * the root node.
+ */
+ root_obj = acpi_ns_get_attached_object(acpi_gbl_root_node);
+ acpi_ut_add_reference(root_obj);
+
+ /* Install the method (module-level code) in the root node */
+
+ status = acpi_ns_attach_object(acpi_gbl_root_node, method_obj,
+ ACPI_TYPE_METHOD);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ /* Execute the root node as a control method */
+
+ status = acpi_ns_evaluate(info);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INIT, "Executed module-level code at %p\n",
+ method_obj->method.aml_start));
+
+ /* Detach the temporary method object */
+
+ acpi_ns_detach_object(acpi_gbl_root_node);
+
+ /* Restore the original root object */
+
+ status =
+ acpi_ns_attach_object(acpi_gbl_root_node, root_obj,
+ ACPI_TYPE_DEVICE);
+
+ exit:
+ acpi_ut_remove_reference(root_obj);
+ return_VOID;
+}
diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c
index 2adfcf329e15..1d5b360eb25b 100644
--- a/drivers/acpi/acpica/nsinit.c
+++ b/drivers/acpi/acpica/nsinit.c
@@ -170,6 +170,21 @@ acpi_status acpi_ns_initialize_devices(void)
goto error_exit;
}
+ /*
+ * Execute the "global" _INI method that may appear at the root. This
+ * support is provided for Windows compatibility (Vista+) and is not
+ * part of the ACPI specification.
+ */
+ info.evaluate_info->prefix_node = acpi_gbl_root_node;
+ info.evaluate_info->pathname = METHOD_NAME__INI;
+ info.evaluate_info->parameters = NULL;
+ info.evaluate_info->flags = ACPI_IGNORE_RETURN_VALUE;
+
+ status = acpi_ns_evaluate(info.evaluate_info);
+ if (ACPI_SUCCESS(status)) {
+ info.num_INI++;
+ }
+
/* Walk namespace to execute all _INIs on present devices */
status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c
index dcd7a6adbbbc..a7234e60e985 100644
--- a/drivers/acpi/acpica/nsload.c
+++ b/drivers/acpi/acpica/nsload.c
@@ -270,8 +270,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle)
/* Now delete the starting object, and we are done */
- acpi_ns_delete_node(child_handle);
-
+ acpi_ns_remove_node(child_handle);
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index 7f8e066b12a3..f8427afeebdf 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -42,6 +42,8 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
+#define ACPI_CREATE_PREDEFINED_TABLE
+
#include <acpi/acpi.h>
#include "accommon.h"
#include "acnamesp.h"
@@ -72,30 +74,31 @@ ACPI_MODULE_NAME("nspredef")
******************************************************************************/
/* Local prototypes */
static acpi_status
-acpi_ns_check_package(char *pathname,
- union acpi_operand_object **return_object_ptr,
- const union acpi_predefined_info *predefined);
+acpi_ns_check_package(struct acpi_predefined_data *data,
+ union acpi_operand_object **return_object_ptr);
+
+static acpi_status
+acpi_ns_check_package_list(struct acpi_predefined_data *data,
+ const union acpi_predefined_info *package,
+ union acpi_operand_object **elements, u32 count);
static acpi_status
-acpi_ns_check_package_elements(char *pathname,
+acpi_ns_check_package_elements(struct acpi_predefined_data *data,
union acpi_operand_object **elements,
u8 type1,
u32 count1,
u8 type2, u32 count2, u32 start_index);
static acpi_status
-acpi_ns_check_object_type(char *pathname,
+acpi_ns_check_object_type(struct acpi_predefined_data *data,
union acpi_operand_object **return_object_ptr,
u32 expected_btypes, u32 package_index);
static acpi_status
-acpi_ns_check_reference(char *pathname,
+acpi_ns_check_reference(struct acpi_predefined_data *data,
union acpi_operand_object *return_object);
-static acpi_status
-acpi_ns_repair_object(u32 expected_btypes,
- u32 package_index,
- union acpi_operand_object **return_object_ptr);
+static void acpi_ns_get_expected_types(char *buffer, u32 expected_btypes);
/*
* Names for the types that can be returned by the predefined objects.
@@ -109,13 +112,13 @@ static const char *acpi_rtype_names[] = {
"/Reference",
};
-#define ACPI_NOT_PACKAGE ACPI_UINT32_MAX
-
/*******************************************************************************
*
* FUNCTION: acpi_ns_check_predefined_names
*
* PARAMETERS: Node - Namespace node for the method/object
+ * user_param_count - Number of parameters actually passed
+ * return_status - Status from the object evaluation
* return_object_ptr - Pointer to the object returned from the
* evaluation of a method or object
*
@@ -135,12 +138,13 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
acpi_status status = AE_OK;
const union acpi_predefined_info *predefined;
char *pathname;
+ struct acpi_predefined_data *data;
/* Match the name for this method/object against the predefined list */
predefined = acpi_ns_check_for_predefined_name(node);
- /* Get the full pathname to the object, for use in error messages */
+ /* Get the full pathname to the object, for use in warning messages */
pathname = acpi_ns_get_external_pathname(node);
if (!pathname) {
@@ -158,28 +162,17 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
/* If not a predefined name, we cannot validate the return object */
if (!predefined) {
- goto exit;
- }
-
- /* If the method failed, we cannot validate the return object */
-
- if ((return_status != AE_OK) && (return_status != AE_CTRL_RETURN_VALUE)) {
- goto exit;
+ goto cleanup;
}
/*
- * Only validate the return value on the first successful evaluation of
- * the method. This ensures that any warnings will only be emitted during
- * the very first evaluation of the method/object.
+ * If the method failed or did not actually return an object, we cannot
+ * validate the return object
*/
- if (node->flags & ANOBJ_EVALUATED) {
- goto exit;
+ if ((return_status != AE_OK) && (return_status != AE_CTRL_RETURN_VALUE)) {
+ goto cleanup;
}
- /* Mark the node as having been successfully evaluated */
-
- node->flags |= ANOBJ_EVALUATED;
-
/*
* If there is no return value, check if we require a return value for
* this predefined name. Either one return value is expected, or none,
@@ -190,46 +183,67 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
if (!return_object) {
if ((predefined->info.expected_btypes) &&
(!(predefined->info.expected_btypes & ACPI_RTYPE_NONE))) {
- ACPI_ERROR((AE_INFO,
- "%s: Missing expected return value",
- pathname));
+ ACPI_WARN_PREDEFINED((AE_INFO, pathname,
+ ACPI_WARN_ALWAYS,
+ "Missing expected return value"));
status = AE_AML_NO_RETURN_VALUE;
}
- goto exit;
+ goto cleanup;
}
/*
- * We have a return value, but if one wasn't expected, just exit, this is
- * not a problem
+ * 1) We have a return value, but if one wasn't expected, just exit, this is
+ * not a problem. For example, if the "Implicit Return" feature is
+ * enabled, methods will always return a value.
*
- * For example, if the "Implicit Return" feature is enabled, methods will
- * always return a value
+ * 2) If the return value can be of any type, then we cannot perform any
+ * validation, exit.
*/
- if (!predefined->info.expected_btypes) {
- goto exit;
+ if ((!predefined->info.expected_btypes) ||
+ (predefined->info.expected_btypes == ACPI_RTYPE_ALL)) {
+ goto cleanup;
}
+ /* Create the parameter data block for object validation */
+
+ data = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_predefined_data));
+ if (!data) {
+ goto cleanup;
+ }
+ data->predefined = predefined;
+ data->node_flags = node->flags;
+ data->pathname = pathname;
+
/*
* Check that the type of the return object is what is expected for
* this predefined name
*/
- status = acpi_ns_check_object_type(pathname, return_object_ptr,
+ status = acpi_ns_check_object_type(data, return_object_ptr,
predefined->info.expected_btypes,
- ACPI_NOT_PACKAGE);
+ ACPI_NOT_PACKAGE_ELEMENT);
if (ACPI_FAILURE(status)) {
- goto exit;
+ goto check_validation_status;
}
/* For returned Package objects, check the type of all sub-objects */
if (return_object->common.type == ACPI_TYPE_PACKAGE) {
- status =
- acpi_ns_check_package(pathname, return_object_ptr,
- predefined);
+ status = acpi_ns_check_package(data, return_object_ptr);
+ }
+
+check_validation_status:
+ /*
+ * If the object validation failed or if we successfully repaired one
+ * or more objects, mark the parent node to suppress further warning
+ * messages during the next evaluation of the same method/object.
+ */
+ if (ACPI_FAILURE(status) || (data->flags & ACPI_OBJECT_REPAIRED)) {
+ node->flags |= ANOBJ_EVALUATED;
}
+ ACPI_FREE(data);
- exit:
+cleanup:
ACPI_FREE(pathname);
return (status);
}
@@ -268,64 +282,58 @@ acpi_ns_check_parameter_count(char *pathname,
param_count = node->object->method.param_count;
}
- /* Argument count check for non-predefined methods/objects */
-
if (!predefined) {
/*
+ * Check the parameter count for non-predefined methods/objects.
+ *
* Warning if too few or too many arguments have been passed by the
* caller. An incorrect number of arguments may not cause the method
* to fail. However, the method will fail if there are too few
* arguments and the method attempts to use one of the missing ones.
*/
if (user_param_count < param_count) {
- ACPI_WARNING((AE_INFO,
- "%s: Insufficient arguments - needs %d, found %d",
- pathname, param_count, user_param_count));
+ ACPI_WARN_PREDEFINED((AE_INFO, pathname,
+ ACPI_WARN_ALWAYS,
+ "Insufficient arguments - needs %u, found %u",
+ param_count, user_param_count));
} else if (user_param_count > param_count) {
- ACPI_WARNING((AE_INFO,
- "%s: Excess arguments - needs %d, found %d",
- pathname, param_count, user_param_count));
+ ACPI_WARN_PREDEFINED((AE_INFO, pathname,
+ ACPI_WARN_ALWAYS,
+ "Excess arguments - needs %u, found %u",
+ param_count, user_param_count));
}
return;
}
- /* Allow two different legal argument counts (_SCP, etc.) */
-
+ /*
+ * Validate the user-supplied parameter count.
+ * Allow two different legal argument counts (_SCP, etc.)
+ */
required_params_current = predefined->info.param_count & 0x0F;
required_params_old = predefined->info.param_count >> 4;
if (user_param_count != ACPI_UINT32_MAX) {
-
- /* Validate the user-supplied parameter count */
-
if ((user_param_count != required_params_current) &&
(user_param_count != required_params_old)) {
- ACPI_WARNING((AE_INFO,
- "%s: Parameter count mismatch - "
- "caller passed %d, ACPI requires %d",
- pathname, user_param_count,
- required_params_current));
+ ACPI_WARN_PREDEFINED((AE_INFO, pathname,
+ ACPI_WARN_ALWAYS,
+ "Parameter count mismatch - "
+ "caller passed %u, ACPI requires %u",
+ user_param_count,
+ required_params_current));
}
}
/*
- * Only validate the argument count on the first successful evaluation of
- * the method. This ensures that any warnings will only be emitted during
- * the very first evaluation of the method/object.
- */
- if (node->flags & ANOBJ_EVALUATED) {
- return;
- }
-
- /*
* Check that the ASL-defined parameter count is what is expected for
- * this predefined name.
+ * this predefined name (parameter count as defined by the ACPI
+ * specification)
*/
if ((param_count != required_params_current) &&
(param_count != required_params_old)) {
- ACPI_WARNING((AE_INFO,
- "%s: Parameter count mismatch - ASL declared %d, ACPI requires %d",
- pathname, param_count, required_params_current));
+ ACPI_WARN_PREDEFINED((AE_INFO, pathname, node->flags,
+ "Parameter count mismatch - ASL declared %u, ACPI requires %u",
+ param_count, required_params_current));
}
}
@@ -358,9 +366,6 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
this_name = predefined_names;
while (this_name->info.name[0]) {
if (ACPI_COMPARE_NAME(node->name.ascii, this_name->info.name)) {
-
- /* Return pointer to this table entry */
-
return (this_name);
}
@@ -375,17 +380,16 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
this_name++;
}
- return (NULL);
+ return (NULL); /* Not found */
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_check_package
*
- * PARAMETERS: Pathname - Full pathname to the node (for error msgs)
+ * PARAMETERS: Data - Pointer to validation data structure
* return_object_ptr - Pointer to the object returned from the
* evaluation of a method or object
- * Predefined - Pointer to entry in predefined name table
*
* RETURN: Status
*
@@ -395,30 +399,26 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
******************************************************************************/
static acpi_status
-acpi_ns_check_package(char *pathname,
- union acpi_operand_object **return_object_ptr,
- const union acpi_predefined_info *predefined)
+acpi_ns_check_package(struct acpi_predefined_data *data,
+ union acpi_operand_object **return_object_ptr)
{
union acpi_operand_object *return_object = *return_object_ptr;
const union acpi_predefined_info *package;
- union acpi_operand_object *sub_package;
union acpi_operand_object **elements;
- union acpi_operand_object **sub_elements;
- acpi_status status;
+ acpi_status status = AE_OK;
u32 expected_count;
u32 count;
u32 i;
- u32 j;
ACPI_FUNCTION_NAME(ns_check_package);
/* The package info for this name is in the next table entry */
- package = predefined + 1;
+ package = data->predefined + 1;
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
"%s Validating return Package of Type %X, Count %X\n",
- pathname, package->ret_info.type,
+ data->pathname, package->ret_info.type,
return_object->package.count));
/* Extract package count and elements array */
@@ -429,9 +429,8 @@ acpi_ns_check_package(char *pathname,
/* The package must have at least one element, else invalid */
if (!count) {
- ACPI_WARNING((AE_INFO,
- "%s: Return Package has no elements (empty)",
- pathname));
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Return Package has no elements (empty)"));
return (AE_AML_OPERAND_VALUE);
}
@@ -456,15 +455,16 @@ acpi_ns_check_package(char *pathname,
if (count < expected_count) {
goto package_too_small;
} else if (count > expected_count) {
- ACPI_WARNING((AE_INFO,
- "%s: Return Package is larger than needed - "
- "found %u, expected %u", pathname, count,
- expected_count));
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
+ data->node_flags,
+ "Return Package is larger than needed - "
+ "found %u, expected %u", count,
+ expected_count));
}
/* Validate all elements of the returned package */
- status = acpi_ns_check_package_elements(pathname, elements,
+ status = acpi_ns_check_package_elements(data, elements,
package->ret_info.
object_type1,
package->ret_info.
@@ -473,9 +473,6 @@ acpi_ns_check_package(char *pathname,
object_type2,
package->ret_info.
count2, 0);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
break;
case ACPI_PTYPE1_VAR:
@@ -485,7 +482,7 @@ acpi_ns_check_package(char *pathname,
* elements must be of the same type
*/
for (i = 0; i < count; i++) {
- status = acpi_ns_check_object_type(pathname, elements,
+ status = acpi_ns_check_object_type(data, elements,
package->ret_info.
object_type1, i);
if (ACPI_FAILURE(status)) {
@@ -517,8 +514,7 @@ acpi_ns_check_package(char *pathname,
/* These are the required package elements (0, 1, or 2) */
status =
- acpi_ns_check_object_type(pathname,
- elements,
+ acpi_ns_check_object_type(data, elements,
package->
ret_info3.
object_type[i],
@@ -530,8 +526,7 @@ acpi_ns_check_package(char *pathname,
/* These are the optional package elements */
status =
- acpi_ns_check_object_type(pathname,
- elements,
+ acpi_ns_check_object_type(data, elements,
package->
ret_info3.
tail_object_type,
@@ -544,11 +539,30 @@ acpi_ns_check_package(char *pathname,
}
break;
+ case ACPI_PTYPE2_REV_FIXED:
+
+ /* First element is the (Integer) revision */
+
+ status = acpi_ns_check_object_type(data, elements,
+ ACPI_RTYPE_INTEGER, 0);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ elements++;
+ count--;
+
+ /* Examine the sub-packages */
+
+ status =
+ acpi_ns_check_package_list(data, package, elements, count);
+ break;
+
case ACPI_PTYPE2_PKG_COUNT:
/* First element is the (Integer) count of sub-packages to follow */
- status = acpi_ns_check_object_type(pathname, elements,
+ status = acpi_ns_check_object_type(data, elements,
ACPI_RTYPE_INTEGER, 0);
if (ACPI_FAILURE(status)) {
return (status);
@@ -566,9 +580,11 @@ acpi_ns_check_package(char *pathname,
count = expected_count;
elements++;
- /* Now we can walk the sub-packages */
+ /* Examine the sub-packages */
- /*lint -fallthrough */
+ status =
+ acpi_ns_check_package_list(data, package, elements, count);
+ break;
case ACPI_PTYPE2:
case ACPI_PTYPE2_FIXED:
@@ -576,176 +592,240 @@ acpi_ns_check_package(char *pathname,
case ACPI_PTYPE2_COUNT:
/*
- * These types all return a single package that consists of a variable
- * number of sub-packages
+ * These types all return a single Package that consists of a
+ * variable number of sub-Packages.
+ *
+ * First, ensure that the first element is a sub-Package. If not,
+ * the BIOS may have incorrectly returned the object as a single
+ * package instead of a Package of Packages (a common error if
+ * there is only one entry). We may be able to repair this by
+ * wrapping the returned Package with a new outer Package.
*/
- for (i = 0; i < count; i++) {
- sub_package = *elements;
- sub_elements = sub_package->package.elements;
+ if ((*elements)->common.type != ACPI_TYPE_PACKAGE) {
- /* Each sub-object must be of type Package */
+ /* Create the new outer package and populate it */
status =
- acpi_ns_check_object_type(pathname, &sub_package,
- ACPI_RTYPE_PACKAGE, i);
+ acpi_ns_repair_package_list(data,
+ return_object_ptr);
if (ACPI_FAILURE(status)) {
return (status);
}
- /* Examine the different types of sub-packages */
+ /* Update locals to point to the new package (of 1 element) */
- switch (package->ret_info.type) {
- case ACPI_PTYPE2:
- case ACPI_PTYPE2_PKG_COUNT:
+ return_object = *return_object_ptr;
+ elements = return_object->package.elements;
+ count = 1;
+ }
- /* Each subpackage has a fixed number of elements */
+ /* Examine the sub-packages */
- expected_count =
- package->ret_info.count1 +
- package->ret_info.count2;
- if (sub_package->package.count !=
- expected_count) {
- count = sub_package->package.count;
- goto package_too_small;
- }
+ status =
+ acpi_ns_check_package_list(data, package, elements, count);
+ break;
- status =
- acpi_ns_check_package_elements(pathname,
- sub_elements,
- package->
- ret_info.
- object_type1,
- package->
- ret_info.
- count1,
- package->
- ret_info.
- object_type2,
- package->
- ret_info.
- count2, 0);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- break;
+ default:
- case ACPI_PTYPE2_FIXED:
+ /* Should not get here if predefined info table is correct */
- /* Each sub-package has a fixed length */
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Invalid internal return type in table entry: %X",
+ package->ret_info.type));
- expected_count = package->ret_info2.count;
- if (sub_package->package.count < expected_count) {
- count = sub_package->package.count;
- goto package_too_small;
- }
+ return (AE_AML_INTERNAL);
+ }
- /* Check the type of each sub-package element */
+ return (status);
- for (j = 0; j < expected_count; j++) {
- status =
- acpi_ns_check_object_type(pathname,
- &sub_elements[j],
- package->ret_info2.object_type[j], j);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- }
- break;
+package_too_small:
- case ACPI_PTYPE2_MIN:
+ /* Error exit for the case with an incorrect package count */
- /* Each sub-package has a variable but minimum length */
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Return Package is too small - found %u elements, expected %u",
+ count, expected_count));
- expected_count = package->ret_info.count1;
- if (sub_package->package.count < expected_count) {
- count = sub_package->package.count;
- goto package_too_small;
- }
+ return (AE_AML_OPERAND_VALUE);
+}
- /* Check the type of each sub-package element */
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_check_package_list
+ *
+ * PARAMETERS: Data - Pointer to validation data structure
+ * Package - Pointer to package-specific info for method
+ * Elements - Element list of parent package. All elements
+ * of this list should be of type Package.
+ * Count - Count of subpackages
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Examine a list of subpackages
+ *
+ ******************************************************************************/
- status =
- acpi_ns_check_package_elements(pathname,
- sub_elements,
- package->
- ret_info.
- object_type1,
- sub_package->
- package.
- count, 0, 0,
- 0);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- break;
+static acpi_status
+acpi_ns_check_package_list(struct acpi_predefined_data *data,
+ const union acpi_predefined_info *package,
+ union acpi_operand_object **elements, u32 count)
+{
+ union acpi_operand_object *sub_package;
+ union acpi_operand_object **sub_elements;
+ acpi_status status;
+ u32 expected_count;
+ u32 i;
+ u32 j;
- case ACPI_PTYPE2_COUNT:
+ /* Validate each sub-Package in the parent Package */
- /* First element is the (Integer) count of elements to follow */
+ for (i = 0; i < count; i++) {
+ sub_package = *elements;
+ sub_elements = sub_package->package.elements;
- status =
- acpi_ns_check_object_type(pathname,
- sub_elements,
- ACPI_RTYPE_INTEGER,
- 0);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
+ /* Each sub-object must be of type Package */
- /* Make sure package is large enough for the Count */
+ status = acpi_ns_check_object_type(data, &sub_package,
+ ACPI_RTYPE_PACKAGE, i);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
- expected_count =
- (u32) (*sub_elements)->integer.value;
- if (sub_package->package.count < expected_count) {
- count = sub_package->package.count;
- goto package_too_small;
- }
+ /* Examine the different types of expected sub-packages */
+
+ switch (package->ret_info.type) {
+ case ACPI_PTYPE2:
+ case ACPI_PTYPE2_PKG_COUNT:
+ case ACPI_PTYPE2_REV_FIXED:
+
+ /* Each subpackage has a fixed number of elements */
+
+ expected_count =
+ package->ret_info.count1 + package->ret_info.count2;
+ if (sub_package->package.count < expected_count) {
+ goto package_too_small;
+ }
+
+ status =
+ acpi_ns_check_package_elements(data, sub_elements,
+ package->ret_info.
+ object_type1,
+ package->ret_info.
+ count1,
+ package->ret_info.
+ object_type2,
+ package->ret_info.
+ count2, 0);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ break;
- /* Check the type of each sub-package element */
+ case ACPI_PTYPE2_FIXED:
+ /* Each sub-package has a fixed length */
+
+ expected_count = package->ret_info2.count;
+ if (sub_package->package.count < expected_count) {
+ goto package_too_small;
+ }
+
+ /* Check the type of each sub-package element */
+
+ for (j = 0; j < expected_count; j++) {
status =
- acpi_ns_check_package_elements(pathname,
- (sub_elements
- + 1),
- package->
- ret_info.
- object_type1,
- (expected_count
- - 1), 0, 0,
- 1);
+ acpi_ns_check_object_type(data,
+ &sub_elements[j],
+ package->
+ ret_info2.
+ object_type[j],
+ j);
if (ACPI_FAILURE(status)) {
return (status);
}
- break;
+ }
+ break;
+
+ case ACPI_PTYPE2_MIN:
- default:
- break;
+ /* Each sub-package has a variable but minimum length */
+
+ expected_count = package->ret_info.count1;
+ if (sub_package->package.count < expected_count) {
+ goto package_too_small;
}
- elements++;
- }
- break;
+ /* Check the type of each sub-package element */
- default:
+ status =
+ acpi_ns_check_package_elements(data, sub_elements,
+ package->ret_info.
+ object_type1,
+ sub_package->package.
+ count, 0, 0, 0);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ break;
- /* Should not get here if predefined info table is correct */
+ case ACPI_PTYPE2_COUNT:
+
+ /*
+ * First element is the (Integer) count of elements, including
+ * the count field.
+ */
+ status = acpi_ns_check_object_type(data, sub_elements,
+ ACPI_RTYPE_INTEGER,
+ 0);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
- ACPI_WARNING((AE_INFO,
- "%s: Invalid internal return type in table entry: %X",
- pathname, package->ret_info.type));
+ /*
+ * Make sure package is large enough for the Count and is
+ * is as large as the minimum size
+ */
+ expected_count = (u32)(*sub_elements)->integer.value;
+ if (sub_package->package.count < expected_count) {
+ goto package_too_small;
+ }
+ if (sub_package->package.count <
+ package->ret_info.count1) {
+ expected_count = package->ret_info.count1;
+ goto package_too_small;
+ }
- return (AE_AML_INTERNAL);
+ /* Check the type of each sub-package element */
+
+ status =
+ acpi_ns_check_package_elements(data,
+ (sub_elements + 1),
+ package->ret_info.
+ object_type1,
+ (expected_count - 1),
+ 0, 0, 1);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ break;
+
+ default: /* Should not get here, type was validated by caller */
+
+ return (AE_AML_INTERNAL);
+ }
+
+ elements++;
}
return (AE_OK);
- package_too_small:
+package_too_small:
- /* Error exit for the case with an incorrect package count */
+ /* The sub-package count was smaller than required */
- ACPI_WARNING((AE_INFO, "%s: Return Package is too small - "
- "found %u, expected %u", pathname, count,
- expected_count));
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Return Sub-Package[%u] is too small - found %u elements, expected %u",
+ i, sub_package->package.count, expected_count));
return (AE_AML_OPERAND_VALUE);
}
@@ -754,7 +834,7 @@ acpi_ns_check_package(char *pathname,
*
* FUNCTION: acpi_ns_check_package_elements
*
- * PARAMETERS: Pathname - Full pathname to the node (for error msgs)
+ * PARAMETERS: Data - Pointer to validation data structure
* Elements - Pointer to the package elements array
* Type1 - Object type for first group
* Count1 - Count for first group
@@ -770,7 +850,7 @@ acpi_ns_check_package(char *pathname,
******************************************************************************/
static acpi_status
-acpi_ns_check_package_elements(char *pathname,
+acpi_ns_check_package_elements(struct acpi_predefined_data *data,
union acpi_operand_object **elements,
u8 type1,
u32 count1,
@@ -786,7 +866,7 @@ acpi_ns_check_package_elements(char *pathname,
* The second group can have a count of zero.
*/
for (i = 0; i < count1; i++) {
- status = acpi_ns_check_object_type(pathname, this_element,
+ status = acpi_ns_check_object_type(data, this_element,
type1, i + start_index);
if (ACPI_FAILURE(status)) {
return (status);
@@ -795,7 +875,7 @@ acpi_ns_check_package_elements(char *pathname,
}
for (i = 0; i < count2; i++) {
- status = acpi_ns_check_object_type(pathname, this_element,
+ status = acpi_ns_check_object_type(data, this_element,
type2,
(i + count1 + start_index));
if (ACPI_FAILURE(status)) {
@@ -811,12 +891,13 @@ acpi_ns_check_package_elements(char *pathname,
*
* FUNCTION: acpi_ns_check_object_type
*
- * PARAMETERS: Pathname - Full pathname to the node (for error msgs)
+ * PARAMETERS: Data - Pointer to validation data structure
* return_object_ptr - Pointer to the object returned from the
* evaluation of a method or object
* expected_btypes - Bitmap of expected return type(s)
* package_index - Index of object within parent package (if
- * applicable - ACPI_NOT_PACKAGE otherwise)
+ * applicable - ACPI_NOT_PACKAGE_ELEMENT
+ * otherwise)
*
* RETURN: Status
*
@@ -826,7 +907,7 @@ acpi_ns_check_package_elements(char *pathname,
******************************************************************************/
static acpi_status
-acpi_ns_check_object_type(char *pathname,
+acpi_ns_check_object_type(struct acpi_predefined_data *data,
union acpi_operand_object **return_object_ptr,
u32 expected_btypes, u32 package_index)
{
@@ -834,9 +915,6 @@ acpi_ns_check_object_type(char *pathname,
acpi_status status = AE_OK;
u32 return_btype;
char type_buffer[48]; /* Room for 5 types */
- u32 this_rtype;
- u32 i;
- u32 j;
/*
* If we get a NULL return_object here, it is a NULL package element,
@@ -849,10 +927,11 @@ acpi_ns_check_object_type(char *pathname,
/* A Namespace node should not get here, but make sure */
if (ACPI_GET_DESCRIPTOR_TYPE(return_object) == ACPI_DESC_TYPE_NAMED) {
- ACPI_WARNING((AE_INFO,
- "%s: Invalid return type - Found a Namespace node [%4.4s] type %s",
- pathname, return_object->node.name.ascii,
- acpi_ut_get_type_name(return_object->node.type)));
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Invalid return type - Found a Namespace node [%4.4s] type %s",
+ return_object->node.name.ascii,
+ acpi_ut_get_type_name(return_object->node.
+ type)));
return (AE_AML_OPERAND_TYPE);
}
@@ -897,10 +976,11 @@ acpi_ns_check_object_type(char *pathname,
/* Type mismatch -- attempt repair of the returned object */
- status = acpi_ns_repair_object(expected_btypes, package_index,
+ status = acpi_ns_repair_object(data, expected_btypes,
+ package_index,
return_object_ptr);
if (ACPI_SUCCESS(status)) {
- return (status);
+ return (AE_OK); /* Repair was successful */
}
goto type_error_exit;
}
@@ -908,7 +988,7 @@ acpi_ns_check_object_type(char *pathname,
/* For reference objects, check that the reference type is correct */
if (return_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) {
- status = acpi_ns_check_reference(pathname, return_object);
+ status = acpi_ns_check_reference(data, return_object);
}
return (status);
@@ -917,33 +997,19 @@ acpi_ns_check_object_type(char *pathname,
/* Create a string with all expected types for this predefined object */
- j = 1;
- type_buffer[0] = 0;
- this_rtype = ACPI_RTYPE_INTEGER;
-
- for (i = 0; i < ACPI_NUM_RTYPES; i++) {
-
- /* If one of the expected types, concatenate the name of this type */
-
- if (expected_btypes & this_rtype) {
- ACPI_STRCAT(type_buffer, &acpi_rtype_names[i][j]);
- j = 0; /* Use name separator from now on */
- }
- this_rtype <<= 1; /* Next Rtype */
- }
+ acpi_ns_get_expected_types(type_buffer, expected_btypes);
- if (package_index == ACPI_NOT_PACKAGE) {
- ACPI_WARNING((AE_INFO,
- "%s: Return type mismatch - found %s, expected %s",
- pathname,
- acpi_ut_get_object_type_name(return_object),
- type_buffer));
+ if (package_index == ACPI_NOT_PACKAGE_ELEMENT) {
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Return type mismatch - found %s, expected %s",
+ acpi_ut_get_object_type_name
+ (return_object), type_buffer));
} else {
- ACPI_WARNING((AE_INFO,
- "%s: Return Package type mismatch at index %u - "
- "found %s, expected %s", pathname, package_index,
- acpi_ut_get_object_type_name(return_object),
- type_buffer));
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Return Package type mismatch at index %u - "
+ "found %s, expected %s", package_index,
+ acpi_ut_get_object_type_name
+ (return_object), type_buffer));
}
return (AE_AML_OPERAND_TYPE);
@@ -953,7 +1019,7 @@ acpi_ns_check_object_type(char *pathname,
*
* FUNCTION: acpi_ns_check_reference
*
- * PARAMETERS: Pathname - Full pathname to the node (for error msgs)
+ * PARAMETERS: Data - Pointer to validation data structure
* return_object - Object returned from the evaluation of a
* method or object
*
@@ -966,7 +1032,7 @@ acpi_ns_check_object_type(char *pathname,
******************************************************************************/
static acpi_status
-acpi_ns_check_reference(char *pathname,
+acpi_ns_check_reference(struct acpi_predefined_data *data,
union acpi_operand_object *return_object)
{
@@ -979,94 +1045,46 @@ acpi_ns_check_reference(char *pathname,
return (AE_OK);
}
- ACPI_WARNING((AE_INFO,
- "%s: Return type mismatch - "
- "unexpected reference object type [%s] %2.2X",
- pathname, acpi_ut_get_reference_name(return_object),
- return_object->reference.class));
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Return type mismatch - unexpected reference object type [%s] %2.2X",
+ acpi_ut_get_reference_name(return_object),
+ return_object->reference.class));
return (AE_AML_OPERAND_TYPE);
}
/*******************************************************************************
*
- * FUNCTION: acpi_ns_repair_object
+ * FUNCTION: acpi_ns_get_expected_types
*
- * PARAMETERS: Pathname - Full pathname to the node (for error msgs)
- * package_index - Used to determine if target is in a package
- * return_object_ptr - Pointer to the object returned from the
- * evaluation of a method or object
+ * PARAMETERS: Buffer - Pointer to where the string is returned
+ * expected_btypes - Bitmap of expected return type(s)
*
- * RETURN: Status. AE_OK if repair was successful.
+ * RETURN: Buffer is populated with type names.
*
- * DESCRIPTION: Attempt to repair/convert a return object of a type that was
- * not expected.
+ * DESCRIPTION: Translate the expected types bitmap into a string of ascii
+ * names of expected types, for use in warning messages.
*
******************************************************************************/
-static acpi_status
-acpi_ns_repair_object(u32 expected_btypes,
- u32 package_index,
- union acpi_operand_object **return_object_ptr)
+static void acpi_ns_get_expected_types(char *buffer, u32 expected_btypes)
{
- union acpi_operand_object *return_object = *return_object_ptr;
- union acpi_operand_object *new_object;
- acpi_size length;
-
- switch (return_object->common.type) {
- case ACPI_TYPE_BUFFER:
-
- if (!(expected_btypes & ACPI_RTYPE_STRING)) {
- return (AE_AML_OPERAND_TYPE);
- }
-
- /*
- * Have a Buffer, expected a String, convert. Use a to_string
- * conversion, no transform performed on the buffer data. The best
- * example of this is the _BIF method, where the string data from
- * the battery is often (incorrectly) returned as buffer object(s).
- */
- length = 0;
- while ((length < return_object->buffer.length) &&
- (return_object->buffer.pointer[length])) {
- length++;
- }
-
- /* Allocate a new string object */
-
- new_object = acpi_ut_create_string_object(length);
- if (!new_object) {
- return (AE_NO_MEMORY);
- }
+ u32 this_rtype;
+ u32 i;
+ u32 j;
- /*
- * Copy the raw buffer data with no transform. String is already NULL
- * terminated at Length+1.
- */
- ACPI_MEMCPY(new_object->string.pointer,
- return_object->buffer.pointer, length);
+ j = 1;
+ buffer[0] = 0;
+ this_rtype = ACPI_RTYPE_INTEGER;
- /* Install the new return object */
+ for (i = 0; i < ACPI_NUM_RTYPES; i++) {
- acpi_ut_remove_reference(return_object);
- *return_object_ptr = new_object;
+ /* If one of the expected types, concatenate the name of this type */
- /*
- * If the object is a package element, we need to:
- * 1. Decrement the reference count of the orignal object, it was
- * incremented when building the package
- * 2. Increment the reference count of the new object, it will be
- * decremented when releasing the package
- */
- if (package_index != ACPI_NOT_PACKAGE) {
- acpi_ut_remove_reference(return_object);
- acpi_ut_add_reference(new_object);
+ if (expected_btypes & this_rtype) {
+ ACPI_STRCAT(buffer, &acpi_rtype_names[i][j]);
+ j = 0; /* Use name separator from now on */
}
- return (AE_OK);
-
- default:
- break;
+ this_rtype <<= 1; /* Next Rtype */
}
-
- return (AE_AML_OPERAND_TYPE);
}
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c
new file mode 100644
index 000000000000..db2b2a99c3a8
--- /dev/null
+++ b/drivers/acpi/acpica/nsrepair.c
@@ -0,0 +1,203 @@
+/******************************************************************************
+ *
+ * Module Name: nsrepair - Repair for objects returned by predefined methods
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2009, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acpredef.h"
+
+#define _COMPONENT ACPI_NAMESPACE
+ACPI_MODULE_NAME("nsrepair")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_repair_object
+ *
+ * PARAMETERS: Data - Pointer to validation data structure
+ * expected_btypes - Object types expected
+ * package_index - Index of object within parent package (if
+ * applicable - ACPI_NOT_PACKAGE_ELEMENT
+ * otherwise)
+ * return_object_ptr - Pointer to the object returned from the
+ * evaluation of a method or object
+ *
+ * RETURN: Status. AE_OK if repair was successful.
+ *
+ * DESCRIPTION: Attempt to repair/convert a return object of a type that was
+ * not expected.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_ns_repair_object(struct acpi_predefined_data *data,
+ u32 expected_btypes,
+ u32 package_index,
+ union acpi_operand_object **return_object_ptr)
+{
+ union acpi_operand_object *return_object = *return_object_ptr;
+ union acpi_operand_object *new_object;
+ acpi_size length;
+
+ switch (return_object->common.type) {
+ case ACPI_TYPE_BUFFER:
+
+ /* Does the method/object legally return a string? */
+
+ if (!(expected_btypes & ACPI_RTYPE_STRING)) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ /*
+ * Have a Buffer, expected a String, convert. Use a to_string
+ * conversion, no transform performed on the buffer data. The best
+ * example of this is the _BIF method, where the string data from
+ * the battery is often (incorrectly) returned as buffer object(s).
+ */
+ length = 0;
+ while ((length < return_object->buffer.length) &&
+ (return_object->buffer.pointer[length])) {
+ length++;
+ }
+
+ /* Allocate a new string object */
+
+ new_object = acpi_ut_create_string_object(length);
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ /*
+ * Copy the raw buffer data with no transform. String is already NULL
+ * terminated at Length+1.
+ */
+ ACPI_MEMCPY(new_object->string.pointer,
+ return_object->buffer.pointer, length);
+
+ /*
+ * If the original object is a package element, we need to:
+ * 1. Set the reference count of the new object to match the
+ * reference count of the old object.
+ * 2. Decrement the reference count of the original object.
+ */
+ if (package_index != ACPI_NOT_PACKAGE_ELEMENT) {
+ new_object->common.reference_count =
+ return_object->common.reference_count;
+
+ if (return_object->common.reference_count > 1) {
+ return_object->common.reference_count--;
+ }
+
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
+ data->node_flags,
+ "Converted Buffer to expected String at index %u",
+ package_index));
+ } else {
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
+ data->node_flags,
+ "Converted Buffer to expected String"));
+ }
+
+ /* Delete old object, install the new return object */
+
+ acpi_ut_remove_reference(return_object);
+ *return_object_ptr = new_object;
+ data->flags |= ACPI_OBJECT_REPAIRED;
+ return (AE_OK);
+
+ default:
+ break;
+ }
+
+ return (AE_AML_OPERAND_TYPE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_repair_package_list
+ *
+ * PARAMETERS: Data - Pointer to validation data structure
+ * obj_desc_ptr - Pointer to the object to repair. The new
+ * package object is returned here,
+ * overwriting the old object.
+ *
+ * RETURN: Status, new object in *obj_desc_ptr
+ *
+ * DESCRIPTION: Repair a common problem with objects that are defined to return
+ * a variable-length Package of Packages. If the variable-length
+ * is one, some BIOS code mistakenly simply declares a single
+ * Package instead of a Package with one sub-Package. This
+ * function attempts to repair this error by wrapping a Package
+ * object around the original Package, creating the correct
+ * Package with one sub-Package.
+ *
+ * Names that can be repaired in this manner include:
+ * _ALR, _CSD, _HPX, _MLS, _PRT, _PSS, _TRT, TSS
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_repair_package_list(struct acpi_predefined_data *data,
+ union acpi_operand_object **obj_desc_ptr)
+{
+ union acpi_operand_object *pkg_obj_desc;
+
+ /*
+ * Create the new outer package and populate it. The new package will
+ * have a single element, the lone subpackage.
+ */
+ pkg_obj_desc = acpi_ut_create_package_object(1);
+ if (!pkg_obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ pkg_obj_desc->package.elements[0] = *obj_desc_ptr;
+
+ /* Return the new object in the object pointer */
+
+ *obj_desc_ptr = pkg_obj_desc;
+ data->flags |= ACPI_OBJECT_REPAIRED;
+
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Incorrectly formed Package, attempting repair"));
+
+ return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index 78277ed08339..ea55ab4f9849 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -88,7 +88,8 @@ acpi_ns_report_error(const char *module_name,
/* There is a non-ascii character in the name */
- ACPI_MOVE_32_TO_32(&bad_name, internal_name);
+ ACPI_MOVE_32_TO_32(&bad_name,
+ ACPI_CAST_PTR(u32, internal_name));
acpi_os_printf("[0x%4.4X] (NON-ASCII)", bad_name);
} else {
/* Convert path to external format */
@@ -836,7 +837,7 @@ acpi_ns_get_node(struct acpi_namespace_node *prefix_node,
acpi_status status;
char *internal_path;
- ACPI_FUNCTION_TRACE_PTR(ns_get_node, pathname);
+ ACPI_FUNCTION_TRACE_PTR(ns_get_node, ACPI_CAST_PTR(char, pathname));
if (!pathname) {
*return_node = prefix_node;
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c
index daf4ad37896d..4929dbdbc8f0 100644
--- a/drivers/acpi/acpica/nsxfeval.c
+++ b/drivers/acpi/acpica/nsxfeval.c
@@ -535,10 +535,11 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
acpi_status status;
struct acpi_namespace_node *node;
u32 flags;
- struct acpica_device_id hid;
- struct acpi_compatible_id_list *cid;
+ struct acpica_device_id *hid;
+ struct acpica_device_id_list *cid;
u32 i;
- int found;
+ u8 found;
+ int no_match;
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
@@ -582,10 +583,14 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
return (AE_CTRL_DEPTH);
}
- if (ACPI_STRNCMP(hid.value, info->hid, sizeof(hid.value)) != 0) {
-
- /* Get the list of Compatible IDs */
+ no_match = ACPI_STRCMP(hid->string, info->hid);
+ ACPI_FREE(hid);
+ if (no_match) {
+ /*
+ * HID does not match, attempt match within the
+ * list of Compatible IDs (CIDs)
+ */
status = acpi_ut_execute_CID(node, &cid);
if (status == AE_NOT_FOUND) {
return (AE_OK);
@@ -597,10 +602,8 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
found = 0;
for (i = 0; i < cid->count; i++) {
- if (ACPI_STRNCMP(cid->id[i].value, info->hid,
- sizeof(struct
- acpi_compatible_id)) ==
- 0) {
+ if (ACPI_STRCMP(cid->ids[i].string, info->hid)
+ == 0) {
found = 1;
break;
}
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c
index f23593d6add4..ddc84af6336e 100644
--- a/drivers/acpi/acpica/nsxfname.c
+++ b/drivers/acpi/acpica/nsxfname.c
@@ -51,6 +51,11 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsxfname")
+/* Local prototypes */
+static char *acpi_ns_copy_device_id(struct acpica_device_id *dest,
+ struct acpica_device_id *source,
+ char *string_area);
+
/******************************************************************************
*
* FUNCTION: acpi_get_handle
@@ -68,6 +73,7 @@ ACPI_MODULE_NAME("nsxfname")
* namespace handle.
*
******************************************************************************/
+
acpi_status
acpi_get_handle(acpi_handle parent,
acpi_string pathname, acpi_handle * ret_handle)
@@ -210,10 +216,38 @@ ACPI_EXPORT_SYMBOL(acpi_get_name)
/******************************************************************************
*
+ * FUNCTION: acpi_ns_copy_device_id
+ *
+ * PARAMETERS: Dest - Pointer to the destination DEVICE_ID
+ * Source - Pointer to the source DEVICE_ID
+ * string_area - Pointer to where to copy the dest string
+ *
+ * RETURN: Pointer to the next string area
+ *
+ * DESCRIPTION: Copy a single DEVICE_ID, including the string data.
+ *
+ ******************************************************************************/
+static char *acpi_ns_copy_device_id(struct acpica_device_id *dest,
+ struct acpica_device_id *source,
+ char *string_area)
+{
+ /* Create the destination DEVICE_ID */
+
+ dest->string = string_area;
+ dest->length = source->length;
+
+ /* Copy actual string and return a pointer to the next string area */
+
+ ACPI_MEMCPY(string_area, source->string, source->length);
+ return (string_area + source->length);
+}
+
+/******************************************************************************
+ *
* FUNCTION: acpi_get_object_info
*
- * PARAMETERS: Handle - Object Handle
- * Buffer - Where the info is returned
+ * PARAMETERS: Handle - Object Handle
+ * return_buffer - Where the info is returned
*
* RETURN: Status
*
@@ -221,33 +255,37 @@ ACPI_EXPORT_SYMBOL(acpi_get_name)
* namespace node and possibly by running several standard
* control methods (Such as in the case of a device.)
*
+ * For Device and Processor objects, run the Device _HID, _UID, _CID, _STA,
+ * _ADR, _sx_w, and _sx_d methods.
+ *
+ * Note: Allocates the return buffer, must be freed by the caller.
+ *
******************************************************************************/
+
acpi_status
-acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
+acpi_get_object_info(acpi_handle handle,
+ struct acpi_device_info **return_buffer)
{
- acpi_status status;
struct acpi_namespace_node *node;
struct acpi_device_info *info;
- struct acpi_device_info *return_info;
- struct acpi_compatible_id_list *cid_list = NULL;
- acpi_size size;
+ struct acpica_device_id_list *cid_list = NULL;
+ struct acpica_device_id *hid = NULL;
+ struct acpica_device_id *uid = NULL;
+ char *next_id_string;
+ acpi_object_type type;
+ acpi_name name;
+ u8 param_count = 0;
+ u8 valid = 0;
+ u32 info_size;
+ u32 i;
+ acpi_status status;
/* Parameter validation */
- if (!handle || !buffer) {
+ if (!handle || !return_buffer) {
return (AE_BAD_PARAMETER);
}
- status = acpi_ut_validate_buffer(buffer);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
- info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_device_info));
- if (!info) {
- return (AE_NO_MEMORY);
- }
-
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
goto cleanup;
@@ -256,66 +294,91 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
node = acpi_ns_map_handle_to_node(handle);
if (!node) {
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- status = AE_BAD_PARAMETER;
- goto cleanup;
+ return (AE_BAD_PARAMETER);
}
- /* Init return structure */
-
- size = sizeof(struct acpi_device_info);
+ /* Get the namespace node data while the namespace is locked */
- info->type = node->type;
- info->name = node->name.integer;
- info->valid = 0;
+ info_size = sizeof(struct acpi_device_info);
+ type = node->type;
+ name = node->name.integer;
if (node->type == ACPI_TYPE_METHOD) {
- info->param_count = node->object->method.param_count;
+ param_count = node->object->method.param_count;
}
status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
- goto cleanup;
+ return (status);
}
- /* If not a device, we are all done */
-
- if (info->type == ACPI_TYPE_DEVICE) {
+ if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) {
/*
- * Get extra info for ACPI Devices objects only:
- * Run the Device _HID, _UID, _CID, _STA, _ADR and _sx_d methods.
+ * Get extra info for ACPI Device/Processor objects only:
+ * Run the Device _HID, _UID, and _CID methods.
*
* Note: none of these methods are required, so they may or may
- * not be present for this device. The Info->Valid bitfield is used
- * to indicate which methods were found and ran successfully.
+ * not be present for this device. The Info->Valid bitfield is used
+ * to indicate which methods were found and run successfully.
*/
/* Execute the Device._HID method */
- status = acpi_ut_execute_HID(node, &info->hardware_id);
+ status = acpi_ut_execute_HID(node, &hid);
if (ACPI_SUCCESS(status)) {
- info->valid |= ACPI_VALID_HID;
+ info_size += hid->length;
+ valid |= ACPI_VALID_HID;
}
/* Execute the Device._UID method */
- status = acpi_ut_execute_UID(node, &info->unique_id);
+ status = acpi_ut_execute_UID(node, &uid);
if (ACPI_SUCCESS(status)) {
- info->valid |= ACPI_VALID_UID;
+ info_size += uid->length;
+ valid |= ACPI_VALID_UID;
}
/* Execute the Device._CID method */
status = acpi_ut_execute_CID(node, &cid_list);
if (ACPI_SUCCESS(status)) {
- size += cid_list->size;
- info->valid |= ACPI_VALID_CID;
+
+ /* Add size of CID strings and CID pointer array */
+
+ info_size +=
+ (cid_list->list_size -
+ sizeof(struct acpica_device_id_list));
+ valid |= ACPI_VALID_CID;
}
+ }
+
+ /*
+ * Now that we have the variable-length data, we can allocate the
+ * return buffer
+ */
+ info = ACPI_ALLOCATE_ZEROED(info_size);
+ if (!info) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Get the fixed-length data */
+
+ if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) {
+ /*
+ * Get extra info for ACPI Device/Processor objects only:
+ * Run the _STA, _ADR and, sx_w, and _sx_d methods.
+ *
+ * Note: none of these methods are required, so they may or may
+ * not be present for this device. The Info->Valid bitfield is used
+ * to indicate which methods were found and run successfully.
+ */
/* Execute the Device._STA method */
status = acpi_ut_execute_STA(node, &info->current_status);
if (ACPI_SUCCESS(status)) {
- info->valid |= ACPI_VALID_STA;
+ valid |= ACPI_VALID_STA;
}
/* Execute the Device._ADR method */
@@ -323,36 +386,100 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, node,
&info->address);
if (ACPI_SUCCESS(status)) {
- info->valid |= ACPI_VALID_ADR;
+ valid |= ACPI_VALID_ADR;
+ }
+
+ /* Execute the Device._sx_w methods */
+
+ status = acpi_ut_execute_power_methods(node,
+ acpi_gbl_lowest_dstate_names,
+ ACPI_NUM_sx_w_METHODS,
+ info->lowest_dstates);
+ if (ACPI_SUCCESS(status)) {
+ valid |= ACPI_VALID_SXWS;
}
/* Execute the Device._sx_d methods */
- status = acpi_ut_execute_sxds(node, info->highest_dstates);
+ status = acpi_ut_execute_power_methods(node,
+ acpi_gbl_highest_dstate_names,
+ ACPI_NUM_sx_d_METHODS,
+ info->highest_dstates);
if (ACPI_SUCCESS(status)) {
- info->valid |= ACPI_VALID_SXDS;
+ valid |= ACPI_VALID_SXDS;
}
}
- /* Validate/Allocate/Clear caller buffer */
+ /*
+ * Create a pointer to the string area of the return buffer.
+ * Point to the end of the base struct acpi_device_info structure.
+ */
+ next_id_string = ACPI_CAST_PTR(char, info->compatible_id_list.ids);
+ if (cid_list) {
- status = acpi_ut_initialize_buffer(buffer, size);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
+ /* Point past the CID DEVICE_ID array */
+
+ next_id_string +=
+ ((acpi_size) cid_list->count *
+ sizeof(struct acpica_device_id));
}
- /* Populate the return buffer */
+ /*
+ * Copy the HID, UID, and CIDs to the return buffer. The variable-length
+ * strings are copied to the reserved area at the end of the buffer.
+ *
+ * For HID and CID, check if the ID is a PCI Root Bridge.
+ */
+ if (hid) {
+ next_id_string = acpi_ns_copy_device_id(&info->hardware_id,
+ hid, next_id_string);
+
+ if (acpi_ut_is_pci_root_bridge(hid->string)) {
+ info->flags |= ACPI_PCI_ROOT_BRIDGE;
+ }
+ }
- return_info = buffer->pointer;
- ACPI_MEMCPY(return_info, info, sizeof(struct acpi_device_info));
+ if (uid) {
+ next_id_string = acpi_ns_copy_device_id(&info->unique_id,
+ uid, next_id_string);
+ }
if (cid_list) {
- ACPI_MEMCPY(&return_info->compatibility_id, cid_list,
- cid_list->size);
+ info->compatible_id_list.count = cid_list->count;
+ info->compatible_id_list.list_size = cid_list->list_size;
+
+ /* Copy each CID */
+
+ for (i = 0; i < cid_list->count; i++) {
+ next_id_string =
+ acpi_ns_copy_device_id(&info->compatible_id_list.
+ ids[i], &cid_list->ids[i],
+ next_id_string);
+
+ if (acpi_ut_is_pci_root_bridge(cid_list->ids[i].string)) {
+ info->flags |= ACPI_PCI_ROOT_BRIDGE;
+ }
+ }
}
+ /* Copy the fixed-length data */
+
+ info->info_size = info_size;
+ info->type = type;
+ info->name = name;
+ info->param_count = param_count;
+ info->valid = valid;
+
+ *return_buffer = info;
+ status = AE_OK;
+
cleanup:
- ACPI_FREE(info);
+ if (hid) {
+ ACPI_FREE(hid);
+ }
+ if (uid) {
+ ACPI_FREE(uid);
+ }
if (cid_list) {
ACPI_FREE(cid_list);
}
diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c
index c5f6ce19a401..cd7995b3aed4 100644
--- a/drivers/acpi/acpica/psloop.c
+++ b/drivers/acpi/acpica/psloop.c
@@ -86,6 +86,9 @@ static acpi_status
acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
union acpi_parse_object *op, acpi_status status);
+static void
+acpi_ps_link_module_code(u8 *aml_start, u32 aml_length, acpi_owner_id owner_id);
+
/*******************************************************************************
*
* FUNCTION: acpi_ps_get_aml_opcode
@@ -390,6 +393,7 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
{
acpi_status status = AE_OK;
union acpi_parse_object *arg = NULL;
+ const struct acpi_opcode_info *op_info;
ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state);
@@ -449,13 +453,11 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
INCREMENT_ARG_LIST(walk_state->arg_types);
}
- /* Special processing for certain opcodes */
-
- /* TBD (remove): Temporary mechanism to disable this code if needed */
-
-#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
-
- if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS1) &&
+ /*
+ * Handle executable code at "module-level". This refers to
+ * executable opcodes that appear outside of any control method.
+ */
+ if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS2) &&
((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) {
/*
* We want to skip If/Else/While constructs during Pass1 because we
@@ -469,6 +471,23 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
case AML_ELSE_OP:
case AML_WHILE_OP:
+ /*
+ * Currently supported module-level opcodes are:
+ * IF/ELSE/WHILE. These appear to be the most common,
+ * and easiest to support since they open an AML
+ * package.
+ */
+ if (walk_state->pass_number ==
+ ACPI_IMODE_LOAD_PASS1) {
+ acpi_ps_link_module_code(aml_op_start,
+ walk_state->
+ parser_state.
+ pkg_end -
+ aml_op_start,
+ walk_state->
+ owner_id);
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
"Pass1: Skipping an If/Else/While body\n"));
@@ -480,10 +499,34 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
break;
default:
+ /*
+ * Check for an unsupported executable opcode at module
+ * level. We must be in PASS1, the parent must be a SCOPE,
+ * The opcode class must be EXECUTE, and the opcode must
+ * not be an argument to another opcode.
+ */
+ if ((walk_state->pass_number ==
+ ACPI_IMODE_LOAD_PASS1)
+ && (op->common.parent->common.aml_opcode ==
+ AML_SCOPE_OP)) {
+ op_info =
+ acpi_ps_get_opcode_info(op->common.
+ aml_opcode);
+ if ((op_info->class ==
+ AML_CLASS_EXECUTE) && (!arg)) {
+ ACPI_WARNING((AE_INFO,
+ "Detected an unsupported executable opcode "
+ "at module-level: [0x%.4X] at table offset 0x%.4X",
+ op->common.aml_opcode,
+ (u32)((aml_op_start - walk_state->parser_state.aml_start)
+ + sizeof(struct acpi_table_header))));
+ }
+ }
break;
}
}
-#endif
+
+ /* Special processing for certain opcodes */
switch (op->common.aml_opcode) {
case AML_METHOD_OP:
@@ -553,6 +596,66 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
/*******************************************************************************
*
+ * FUNCTION: acpi_ps_link_module_code
+ *
+ * PARAMETERS: aml_start - Pointer to the AML
+ * aml_length - Length of executable AML
+ * owner_id - owner_id of module level code
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Wrap the module-level code with a method object and link the
+ * object to the global list. Note, the mutex field of the method
+ * object is used to link multiple module-level code objects.
+ *
+ ******************************************************************************/
+
+static void
+acpi_ps_link_module_code(u8 *aml_start, u32 aml_length, acpi_owner_id owner_id)
+{
+ union acpi_operand_object *prev;
+ union acpi_operand_object *next;
+ union acpi_operand_object *method_obj;
+
+ /* Get the tail of the list */
+
+ prev = next = acpi_gbl_module_code_list;
+ while (next) {
+ prev = next;
+ next = next->method.mutex;
+ }
+
+ /*
+ * Insert the module level code into the list. Merge it if it is
+ * adjacent to the previous element.
+ */
+ if (!prev ||
+ ((prev->method.aml_start + prev->method.aml_length) != aml_start)) {
+
+ /* Create, initialize, and link a new temporary method object */
+
+ method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
+ if (!method_obj) {
+ return;
+ }
+
+ method_obj->method.aml_start = aml_start;
+ method_obj->method.aml_length = aml_length;
+ method_obj->method.owner_id = owner_id;
+ method_obj->method.flags |= AOPOBJ_MODULE_LEVEL;
+
+ if (!prev) {
+ acpi_gbl_module_code_list = method_obj;
+ } else {
+ prev->method.mutex = method_obj;
+ }
+ } else {
+ prev->method.aml_length += aml_length;
+ }
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ps_complete_op
*
* PARAMETERS: walk_state - Current state
diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c
index ff06032c0f06..dd9731c29a79 100644
--- a/drivers/acpi/acpica/psxface.c
+++ b/drivers/acpi/acpica/psxface.c
@@ -280,6 +280,10 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
goto cleanup;
}
+ if (info->obj_desc->method.flags & AOPOBJ_MODULE_LEVEL) {
+ walk_state->parse_flags |= ACPI_PARSE_MODULE_LEVEL;
+ }
+
/* Invoke an internal method if necessary */
if (info->obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index 82b02dcb942e..c016335fb759 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -275,7 +275,6 @@ void acpi_tb_parse_fadt(u32 table_index)
void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
{
-
/*
* Check if the FADT is larger than the largest table that we expect
* (the ACPI 2.0/3.0 version). If so, truncate the table, and issue
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index ef7d2c2d8f0b..1f15497f00d1 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -49,6 +49,12 @@
ACPI_MODULE_NAME("tbutils")
/* Local prototypes */
+static void acpi_tb_fix_string(char *string, acpi_size length);
+
+static void
+acpi_tb_cleanup_table_header(struct acpi_table_header *out_header,
+ struct acpi_table_header *header);
+
static acpi_physical_address
acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
@@ -161,6 +167,59 @@ u8 acpi_tb_tables_loaded(void)
/*******************************************************************************
*
+ * FUNCTION: acpi_tb_fix_string
+ *
+ * PARAMETERS: String - String to be repaired
+ * Length - Maximum length
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Replace every non-printable or non-ascii byte in the string
+ * with a question mark '?'.
+ *
+ ******************************************************************************/
+
+static void acpi_tb_fix_string(char *string, acpi_size length)
+{
+
+ while (length && *string) {
+ if (!ACPI_IS_PRINT(*string)) {
+ *string = '?';
+ }
+ string++;
+ length--;
+ }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_cleanup_table_header
+ *
+ * PARAMETERS: out_header - Where the cleaned header is returned
+ * Header - Input ACPI table header
+ *
+ * RETURN: Returns the cleaned header in out_header
+ *
+ * DESCRIPTION: Copy the table header and ensure that all "string" fields in
+ * the header consist of printable characters.
+ *
+ ******************************************************************************/
+
+static void
+acpi_tb_cleanup_table_header(struct acpi_table_header *out_header,
+ struct acpi_table_header *header)
+{
+
+ ACPI_MEMCPY(out_header, header, sizeof(struct acpi_table_header));
+
+ acpi_tb_fix_string(out_header->signature, ACPI_NAME_SIZE);
+ acpi_tb_fix_string(out_header->oem_id, ACPI_OEM_ID_SIZE);
+ acpi_tb_fix_string(out_header->oem_table_id, ACPI_OEM_TABLE_ID_SIZE);
+ acpi_tb_fix_string(out_header->asl_compiler_id, ACPI_NAME_SIZE);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_tb_print_table_header
*
* PARAMETERS: Address - Table physical address
@@ -176,6 +235,7 @@ void
acpi_tb_print_table_header(acpi_physical_address address,
struct acpi_table_header *header)
{
+ struct acpi_table_header local_header;
/*
* The reason that the Address is cast to a void pointer is so that we
@@ -192,6 +252,11 @@ acpi_tb_print_table_header(acpi_physical_address address,
/* RSDP has no common fields */
+ ACPI_MEMCPY(local_header.oem_id,
+ ACPI_CAST_PTR(struct acpi_table_rsdp,
+ header)->oem_id, ACPI_OEM_ID_SIZE);
+ acpi_tb_fix_string(local_header.oem_id, ACPI_OEM_ID_SIZE);
+
ACPI_INFO((AE_INFO, "RSDP %p %05X (v%.2d %6.6s)",
ACPI_CAST_PTR (void, address),
(ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
@@ -200,18 +265,21 @@ acpi_tb_print_table_header(acpi_physical_address address,
header)->length : 20,
ACPI_CAST_PTR(struct acpi_table_rsdp,
header)->revision,
- ACPI_CAST_PTR(struct acpi_table_rsdp,
- header)->oem_id));
+ local_header.oem_id));
} else {
/* Standard ACPI table with full common header */
+ acpi_tb_cleanup_table_header(&local_header, header);
+
ACPI_INFO((AE_INFO,
"%4.4s %p %05X (v%.2d %6.6s %8.8s %08X %4.4s %08X)",
- header->signature, ACPI_CAST_PTR (void, address),
- header->length, header->revision, header->oem_id,
- header->oem_table_id, header->oem_revision,
- header->asl_compiler_id,
- header->asl_compiler_revision));
+ local_header.signature, ACPI_CAST_PTR(void, address),
+ local_header.length, local_header.revision,
+ local_header.oem_id, local_header.oem_table_id,
+ local_header.oem_revision,
+ local_header.asl_compiler_id,
+ local_header.asl_compiler_revision));
+
}
}
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
index bc1710315088..96e26e70c63d 100644
--- a/drivers/acpi/acpica/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -215,6 +215,12 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
"***** Region %p\n", object));
+ /* Invalidate the region address/length via the host OS */
+
+ acpi_os_invalidate_address(object->region.space_id,
+ object->region.address,
+ (acpi_size) object->region.length);
+
second_desc = acpi_ns_get_secondary_object(object);
if (second_desc) {
/*
diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c
index 006b16c26017..5d54e36ab453 100644
--- a/drivers/acpi/acpica/uteval.c
+++ b/drivers/acpi/acpica/uteval.c
@@ -44,19 +44,10 @@
#include <acpi/acpi.h>
#include "accommon.h"
#include "acnamesp.h"
-#include "acinterp.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("uteval")
-/* Local prototypes */
-static void
-acpi_ut_copy_id_string(char *destination, char *source, acpi_size max_length);
-
-static acpi_status
-acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc,
- struct acpi_compatible_id *one_cid);
-
/*
* Strings supported by the _OSI predefined (internal) method.
*
@@ -78,6 +69,9 @@ static struct acpi_interface_info acpi_interfaces_supported[] = {
{"Windows 2001 SP2", ACPI_OSI_WIN_XP_SP2}, /* Windows XP SP2 */
{"Windows 2001.1 SP1", ACPI_OSI_WINSRV_2003_SP1}, /* Windows Server 2003 SP1 - Added 03/2006 */
{"Windows 2006", ACPI_OSI_WIN_VISTA}, /* Windows Vista - Added 03/2006 */
+ {"Windows 2006.1", ACPI_OSI_WINSRV_2008}, /* Windows Server 2008 - Added 09/2009 */
+ {"Windows 2006 SP1", ACPI_OSI_WIN_VISTA_SP1}, /* Windows Vista SP1 - Added 09/2009 */
+ {"Windows 2009", ACPI_OSI_WIN_7}, /* Windows 7 and Server 2008 R2 - Added 09/2009 */
/* Feature Group Strings */
@@ -213,7 +207,7 @@ acpi_status acpi_osi_invalidate(char *interface)
* RETURN: Status
*
* DESCRIPTION: Evaluates a namespace object and verifies the type of the
- * return object. Common code that simplifies accessing objects
+ * return object. Common code that simplifies accessing objects
* that have required return objects of fixed types.
*
* NOTE: Internal function, no parameter validation
@@ -298,7 +292,7 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
if ((acpi_gbl_enable_interpreter_slack) && (!expected_return_btypes)) {
/*
- * We received a return object, but one was not expected. This can
+ * We received a return object, but one was not expected. This can
* happen frequently if the "implicit return" feature is enabled.
* Just delete the return object and return AE_OK.
*/
@@ -340,12 +334,12 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
*
* PARAMETERS: object_name - Object name to be evaluated
* device_node - Node for the device
- * Address - Where the value is returned
+ * Value - Where the value is returned
*
* RETURN: Status
*
* DESCRIPTION: Evaluates a numeric namespace object for a selected device
- * and stores result in *Address.
+ * and stores result in *Value.
*
* NOTE: Internal function, no parameter validation
*
@@ -354,7 +348,7 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
acpi_status
acpi_ut_evaluate_numeric_object(char *object_name,
struct acpi_namespace_node *device_node,
- acpi_integer * address)
+ acpi_integer *value)
{
union acpi_operand_object *obj_desc;
acpi_status status;
@@ -369,295 +363,7 @@ acpi_ut_evaluate_numeric_object(char *object_name,
/* Get the returned Integer */
- *address = obj_desc->integer.value;
-
- /* On exit, we must delete the return object */
-
- acpi_ut_remove_reference(obj_desc);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_copy_id_string
- *
- * PARAMETERS: Destination - Where to copy the string
- * Source - Source string
- * max_length - Length of the destination buffer
- *
- * RETURN: None
- *
- * DESCRIPTION: Copies an ID string for the _HID, _CID, and _UID methods.
- * Performs removal of a leading asterisk if present -- workaround
- * for a known issue on a bunch of machines.
- *
- ******************************************************************************/
-
-static void
-acpi_ut_copy_id_string(char *destination, char *source, acpi_size max_length)
-{
-
- /*
- * Workaround for ID strings that have a leading asterisk. This construct
- * is not allowed by the ACPI specification (ID strings must be
- * alphanumeric), but enough existing machines have this embedded in their
- * ID strings that the following code is useful.
- */
- if (*source == '*') {
- source++;
- }
-
- /* Do the actual copy */
-
- ACPI_STRNCPY(destination, source, max_length);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_execute_HID
- *
- * PARAMETERS: device_node - Node for the device
- * Hid - Where the HID is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Executes the _HID control method that returns the hardware
- * ID of the device.
- *
- * NOTE: Internal function, no parameter validation
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
- struct acpica_device_id *hid)
-{
- union acpi_operand_object *obj_desc;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(ut_execute_HID);
-
- status = acpi_ut_evaluate_object(device_node, METHOD_NAME__HID,
- ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
- &obj_desc);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
-
- /* Convert the Numeric HID to string */
-
- acpi_ex_eisa_id_to_string((u32) obj_desc->integer.value,
- hid->value);
- } else {
- /* Copy the String HID from the returned object */
-
- acpi_ut_copy_id_string(hid->value, obj_desc->string.pointer,
- sizeof(hid->value));
- }
-
- /* On exit, we must delete the return object */
-
- acpi_ut_remove_reference(obj_desc);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_translate_one_cid
- *
- * PARAMETERS: obj_desc - _CID object, must be integer or string
- * one_cid - Where the CID string is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Return a numeric or string _CID value as a string.
- * (Compatible ID)
- *
- * NOTE: Assumes a maximum _CID string length of
- * ACPI_MAX_CID_LENGTH.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc,
- struct acpi_compatible_id *one_cid)
-{
-
- switch (obj_desc->common.type) {
- case ACPI_TYPE_INTEGER:
-
- /* Convert the Numeric CID to string */
-
- acpi_ex_eisa_id_to_string((u32) obj_desc->integer.value,
- one_cid->value);
- return (AE_OK);
-
- case ACPI_TYPE_STRING:
-
- if (obj_desc->string.length > ACPI_MAX_CID_LENGTH) {
- return (AE_AML_STRING_LIMIT);
- }
-
- /* Copy the String CID from the returned object */
-
- acpi_ut_copy_id_string(one_cid->value, obj_desc->string.pointer,
- ACPI_MAX_CID_LENGTH);
- return (AE_OK);
-
- default:
-
- return (AE_TYPE);
- }
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_execute_CID
- *
- * PARAMETERS: device_node - Node for the device
- * return_cid_list - Where the CID list is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Executes the _CID control method that returns one or more
- * compatible hardware IDs for the device.
- *
- * NOTE: Internal function, no parameter validation
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ut_execute_CID(struct acpi_namespace_node * device_node,
- struct acpi_compatible_id_list ** return_cid_list)
-{
- union acpi_operand_object *obj_desc;
- acpi_status status;
- u32 count;
- u32 size;
- struct acpi_compatible_id_list *cid_list;
- u32 i;
-
- ACPI_FUNCTION_TRACE(ut_execute_CID);
-
- /* Evaluate the _CID method for this device */
-
- status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CID,
- ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING
- | ACPI_BTYPE_PACKAGE, &obj_desc);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get the number of _CIDs returned */
-
- count = 1;
- if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
- count = obj_desc->package.count;
- }
-
- /* Allocate a worst-case buffer for the _CIDs */
-
- size = (((count - 1) * sizeof(struct acpi_compatible_id)) +
- sizeof(struct acpi_compatible_id_list));
-
- cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size);
- if (!cid_list) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /* Init CID list */
-
- cid_list->count = count;
- cid_list->size = size;
-
- /*
- * A _CID can return either a single compatible ID or a package of
- * compatible IDs. Each compatible ID can be one of the following:
- * 1) Integer (32 bit compressed EISA ID) or
- * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss")
- */
-
- /* The _CID object can be either a single CID or a package (list) of CIDs */
-
- if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
-
- /* Translate each package element */
-
- for (i = 0; i < count; i++) {
- status =
- acpi_ut_translate_one_cid(obj_desc->package.
- elements[i],
- &cid_list->id[i]);
- if (ACPI_FAILURE(status)) {
- break;
- }
- }
- } else {
- /* Only one CID, translate to a string */
-
- status = acpi_ut_translate_one_cid(obj_desc, cid_list->id);
- }
-
- /* Cleanup on error */
-
- if (ACPI_FAILURE(status)) {
- ACPI_FREE(cid_list);
- } else {
- *return_cid_list = cid_list;
- }
-
- /* On exit, we must delete the _CID return object */
-
- acpi_ut_remove_reference(obj_desc);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_execute_UID
- *
- * PARAMETERS: device_node - Node for the device
- * Uid - Where the UID is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Executes the _UID control method that returns the hardware
- * ID of the device.
- *
- * NOTE: Internal function, no parameter validation
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
- struct acpica_device_id *uid)
-{
- union acpi_operand_object *obj_desc;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(ut_execute_UID);
-
- status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID,
- ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
- &obj_desc);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
-
- /* Convert the Numeric UID to string */
-
- acpi_ex_unsigned_integer_to_string(obj_desc->integer.value,
- uid->value);
- } else {
- /* Copy the String UID from the returned object */
-
- acpi_ut_copy_id_string(uid->value, obj_desc->string.pointer,
- sizeof(uid->value));
- }
+ *value = obj_desc->integer.value;
/* On exit, we must delete the return object */
@@ -716,60 +422,64 @@ acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 * flags)
/*******************************************************************************
*
- * FUNCTION: acpi_ut_execute_Sxds
+ * FUNCTION: acpi_ut_execute_power_methods
*
* PARAMETERS: device_node - Node for the device
- * Flags - Where the status flags are returned
+ * method_names - Array of power method names
+ * method_count - Number of methods to execute
+ * out_values - Where the power method values are returned
*
- * RETURN: Status
+ * RETURN: Status, out_values
*
- * DESCRIPTION: Executes _STA for selected device and stores results in
- * *Flags.
+ * DESCRIPTION: Executes the specified power methods for the device and returns
+ * the result(s).
*
* NOTE: Internal function, no parameter validation
*
- ******************************************************************************/
+******************************************************************************/
acpi_status
-acpi_ut_execute_sxds(struct acpi_namespace_node *device_node, u8 * highest)
+acpi_ut_execute_power_methods(struct acpi_namespace_node *device_node,
+ const char **method_names,
+ u8 method_count, u8 *out_values)
{
union acpi_operand_object *obj_desc;
acpi_status status;
+ acpi_status final_status = AE_NOT_FOUND;
u32 i;
- ACPI_FUNCTION_TRACE(ut_execute_sxds);
+ ACPI_FUNCTION_TRACE(ut_execute_power_methods);
- for (i = 0; i < 4; i++) {
- highest[i] = 0xFF;
+ for (i = 0; i < method_count; i++) {
+ /*
+ * Execute the power method (_sx_d or _sx_w). The only allowable
+ * return type is an Integer.
+ */
status = acpi_ut_evaluate_object(device_node,
ACPI_CAST_PTR(char,
- acpi_gbl_highest_dstate_names
- [i]),
+ method_names[i]),
ACPI_BTYPE_INTEGER, &obj_desc);
- if (ACPI_FAILURE(status)) {
- if (status != AE_NOT_FOUND) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "%s on Device %4.4s, %s\n",
- ACPI_CAST_PTR(char,
- acpi_gbl_highest_dstate_names
- [i]),
- acpi_ut_get_node_name
- (device_node),
- acpi_format_exception
- (status)));
-
- return_ACPI_STATUS(status);
- }
- } else {
- /* Extract the Dstate value */
-
- highest[i] = (u8) obj_desc->integer.value;
+ if (ACPI_SUCCESS(status)) {
+ out_values[i] = (u8)obj_desc->integer.value;
/* Delete the return object */
acpi_ut_remove_reference(obj_desc);
+ final_status = AE_OK; /* At least one value is valid */
+ continue;
}
+
+ out_values[i] = ACPI_UINT8_MAX;
+ if (status == AE_NOT_FOUND) {
+ continue; /* Ignore if not found */
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Failed %s on Device %4.4s, %s\n",
+ ACPI_CAST_PTR(char, method_names[i]),
+ acpi_ut_get_node_name(device_node),
+ acpi_format_exception(status)));
}
- return_ACPI_STATUS(AE_OK);
+ return_ACPI_STATUS(final_status);
}
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index 59e46f257c02..3f2c68f4e959 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -90,7 +90,15 @@ const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = {
"\\_S5_"
};
-const char *acpi_gbl_highest_dstate_names[4] = {
+const char *acpi_gbl_lowest_dstate_names[ACPI_NUM_sx_w_METHODS] = {
+ "_S0W",
+ "_S1W",
+ "_S2W",
+ "_S3W",
+ "_S4W"
+};
+
+const char *acpi_gbl_highest_dstate_names[ACPI_NUM_sx_d_METHODS] = {
"_S1D",
"_S2D",
"_S3D",
@@ -351,6 +359,7 @@ const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = {
"SMBus",
"SystemCMOS",
"PCIBARTarget",
+ "IPMI",
"DataTable"
};
@@ -798,6 +807,7 @@ acpi_status acpi_ut_init_globals(void)
/* Namespace */
+ acpi_gbl_module_code_list = NULL;
acpi_gbl_root_node = NULL;
acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME;
acpi_gbl_root_node_struct.descriptor_type = ACPI_DESC_TYPE_NAMED;
diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c
new file mode 100644
index 000000000000..52eaae404554
--- /dev/null
+++ b/drivers/acpi/acpica/utids.c
@@ -0,0 +1,382 @@
+/******************************************************************************
+ *
+ * Module Name: utids - support for device IDs - HID, UID, CID
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2009, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acinterp.h"
+
+#define _COMPONENT ACPI_UTILITIES
+ACPI_MODULE_NAME("utids")
+
+/* Local prototypes */
+static void acpi_ut_copy_id_string(char *destination, char *source);
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_copy_id_string
+ *
+ * PARAMETERS: Destination - Where to copy the string
+ * Source - Source string
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Copies an ID string for the _HID, _CID, and _UID methods.
+ * Performs removal of a leading asterisk if present -- workaround
+ * for a known issue on a bunch of machines.
+ *
+ ******************************************************************************/
+
+static void acpi_ut_copy_id_string(char *destination, char *source)
+{
+
+ /*
+ * Workaround for ID strings that have a leading asterisk. This construct
+ * is not allowed by the ACPI specification (ID strings must be
+ * alphanumeric), but enough existing machines have this embedded in their
+ * ID strings that the following code is useful.
+ */
+ if (*source == '*') {
+ source++;
+ }
+
+ /* Do the actual copy */
+
+ ACPI_STRCPY(destination, source);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_execute_HID
+ *
+ * PARAMETERS: device_node - Node for the device
+ * return_id - Where the string HID is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Executes the _HID control method that returns the hardware
+ * ID of the device. The HID is either an 32-bit encoded EISAID
+ * Integer or a String. A string is always returned. An EISAID
+ * is converted to a string.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
+ struct acpica_device_id **return_id)
+{
+ union acpi_operand_object *obj_desc;
+ struct acpica_device_id *hid;
+ u32 length;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(ut_execute_HID);
+
+ status = acpi_ut_evaluate_object(device_node, METHOD_NAME__HID,
+ ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
+ &obj_desc);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Get the size of the String to be returned, includes null terminator */
+
+ if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
+ length = ACPI_EISAID_STRING_SIZE;
+ } else {
+ length = obj_desc->string.length + 1;
+ }
+
+ /* Allocate a buffer for the HID */
+
+ hid =
+ ACPI_ALLOCATE_ZEROED(sizeof(struct acpica_device_id) +
+ (acpi_size) length);
+ if (!hid) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Area for the string starts after DEVICE_ID struct */
+
+ hid->string = ACPI_ADD_PTR(char, hid, sizeof(struct acpica_device_id));
+
+ /* Convert EISAID to a string or simply copy existing string */
+
+ if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
+ acpi_ex_eisa_id_to_string(hid->string, obj_desc->integer.value);
+ } else {
+ acpi_ut_copy_id_string(hid->string, obj_desc->string.pointer);
+ }
+
+ hid->length = length;
+ *return_id = hid;
+
+cleanup:
+
+ /* On exit, we must delete the return object */
+
+ acpi_ut_remove_reference(obj_desc);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_execute_UID
+ *
+ * PARAMETERS: device_node - Node for the device
+ * return_id - Where the string UID is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Executes the _UID control method that returns the unique
+ * ID of the device. The UID is either a 64-bit Integer (NOT an
+ * EISAID) or a string. Always returns a string. A 64-bit integer
+ * is converted to a decimal string.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
+ struct acpica_device_id **return_id)
+{
+ union acpi_operand_object *obj_desc;
+ struct acpica_device_id *uid;
+ u32 length;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(ut_execute_UID);
+
+ status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID,
+ ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
+ &obj_desc);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Get the size of the String to be returned, includes null terminator */
+
+ if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
+ length = ACPI_MAX64_DECIMAL_DIGITS + 1;
+ } else {
+ length = obj_desc->string.length + 1;
+ }
+
+ /* Allocate a buffer for the UID */
+
+ uid =
+ ACPI_ALLOCATE_ZEROED(sizeof(struct acpica_device_id) +
+ (acpi_size) length);
+ if (!uid) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Area for the string starts after DEVICE_ID struct */
+
+ uid->string = ACPI_ADD_PTR(char, uid, sizeof(struct acpica_device_id));
+
+ /* Convert an Integer to string, or just copy an existing string */
+
+ if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
+ acpi_ex_integer_to_string(uid->string, obj_desc->integer.value);
+ } else {
+ acpi_ut_copy_id_string(uid->string, obj_desc->string.pointer);
+ }
+
+ uid->length = length;
+ *return_id = uid;
+
+cleanup:
+
+ /* On exit, we must delete the return object */
+
+ acpi_ut_remove_reference(obj_desc);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_execute_CID
+ *
+ * PARAMETERS: device_node - Node for the device
+ * return_cid_list - Where the CID list is returned
+ *
+ * RETURN: Status, list of CID strings
+ *
+ * DESCRIPTION: Executes the _CID control method that returns one or more
+ * compatible hardware IDs for the device.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ * A _CID method can return either a single compatible ID or a package of
+ * compatible IDs. Each compatible ID can be one of the following:
+ * 1) Integer (32 bit compressed EISA ID) or
+ * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss")
+ *
+ * The Integer CIDs are converted to string format by this function.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
+ struct acpica_device_id_list **return_cid_list)
+{
+ union acpi_operand_object **cid_objects;
+ union acpi_operand_object *obj_desc;
+ struct acpica_device_id_list *cid_list;
+ char *next_id_string;
+ u32 string_area_size;
+ u32 length;
+ u32 cid_list_size;
+ acpi_status status;
+ u32 count;
+ u32 i;
+
+ ACPI_FUNCTION_TRACE(ut_execute_CID);
+
+ /* Evaluate the _CID method for this device */
+
+ status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CID,
+ ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING
+ | ACPI_BTYPE_PACKAGE, &obj_desc);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * Get the count and size of the returned _CIDs. _CID can return either
+ * a Package of Integers/Strings or a single Integer or String.
+ * Note: This section also validates that all CID elements are of the
+ * correct type (Integer or String).
+ */
+ if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
+ count = obj_desc->package.count;
+ cid_objects = obj_desc->package.elements;
+ } else { /* Single Integer or String CID */
+
+ count = 1;
+ cid_objects = &obj_desc;
+ }
+
+ string_area_size = 0;
+ for (i = 0; i < count; i++) {
+
+ /* String lengths include null terminator */
+
+ switch (cid_objects[i]->common.type) {
+ case ACPI_TYPE_INTEGER:
+ string_area_size += ACPI_EISAID_STRING_SIZE;
+ break;
+
+ case ACPI_TYPE_STRING:
+ string_area_size += cid_objects[i]->string.length + 1;
+ break;
+
+ default:
+ status = AE_TYPE;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * Now that we know the length of the CIDs, allocate return buffer:
+ * 1) Size of the base structure +
+ * 2) Size of the CID DEVICE_ID array +
+ * 3) Size of the actual CID strings
+ */
+ cid_list_size = sizeof(struct acpica_device_id_list) +
+ ((count - 1) * sizeof(struct acpica_device_id)) + string_area_size;
+
+ cid_list = ACPI_ALLOCATE_ZEROED(cid_list_size);
+ if (!cid_list) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Area for CID strings starts after the CID DEVICE_ID array */
+
+ next_id_string = ACPI_CAST_PTR(char, cid_list->ids) +
+ ((acpi_size) count * sizeof(struct acpica_device_id));
+
+ /* Copy/convert the CIDs to the return buffer */
+
+ for (i = 0; i < count; i++) {
+ if (cid_objects[i]->common.type == ACPI_TYPE_INTEGER) {
+
+ /* Convert the Integer (EISAID) CID to a string */
+
+ acpi_ex_eisa_id_to_string(next_id_string,
+ cid_objects[i]->integer.
+ value);
+ length = ACPI_EISAID_STRING_SIZE;
+ } else { /* ACPI_TYPE_STRING */
+
+ /* Copy the String CID from the returned object */
+
+ acpi_ut_copy_id_string(next_id_string,
+ cid_objects[i]->string.pointer);
+ length = cid_objects[i]->string.length + 1;
+ }
+
+ cid_list->ids[i].string = next_id_string;
+ cid_list->ids[i].length = length;
+ next_id_string += length;
+ }
+
+ /* Finish the CID list */
+
+ cid_list->count = count;
+ cid_list->list_size = cid_list_size;
+ *return_cid_list = cid_list;
+
+cleanup:
+
+ /* On exit, we must delete the _CID return object */
+
+ acpi_ut_remove_reference(obj_desc);
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index a54ca84eb362..9d0919ebf7b0 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -99,33 +99,19 @@ static void acpi_ut_terminate(void)
*
* FUNCTION: acpi_ut_subsystem_shutdown
*
- * PARAMETERS: none
+ * PARAMETERS: None
*
- * RETURN: none
+ * RETURN: None
*
- * DESCRIPTION: Shutdown the various subsystems. Don't delete the mutex
- * objects here -- because the AML debugger may be still running.
+ * DESCRIPTION: Shutdown the various components. Do not delete the mutex
+ * objects here, because the AML debugger may be still running.
*
******************************************************************************/
void acpi_ut_subsystem_shutdown(void)
{
-
ACPI_FUNCTION_TRACE(ut_subsystem_shutdown);
- /* Just exit if subsystem is already shutdown */
-
- if (acpi_gbl_shutdown) {
- ACPI_ERROR((AE_INFO, "ACPI Subsystem is already terminated"));
- return_VOID;
- }
-
- /* Subsystem appears active, go ahead and shut it down */
-
- acpi_gbl_shutdown = TRUE;
- acpi_gbl_startup_flags = 0;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n"));
-
#ifndef ACPI_ASL_COMPILER
/* Close the acpi_event Handling */
diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c
index fbe782348b0b..61f6315fce9f 100644
--- a/drivers/acpi/acpica/utmisc.c
+++ b/drivers/acpi/acpica/utmisc.c
@@ -50,6 +50,11 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utmisc")
+/*
+ * Common suffix for messages
+ */
+#define ACPI_COMMON_MSG_SUFFIX \
+ acpi_os_printf(" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number)
/*******************************************************************************
*
* FUNCTION: acpi_ut_validate_exception
@@ -120,6 +125,34 @@ const char *acpi_ut_validate_exception(acpi_status status)
/*******************************************************************************
*
+ * FUNCTION: acpi_ut_is_pci_root_bridge
+ *
+ * PARAMETERS: Id - The HID/CID in string format
+ *
+ * RETURN: TRUE if the Id is a match for a PCI/PCI-Express Root Bridge
+ *
+ * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID.
+ *
+ ******************************************************************************/
+
+u8 acpi_ut_is_pci_root_bridge(char *id)
+{
+
+ /*
+ * Check if this is a PCI root bridge.
+ * ACPI 3.0+: check for a PCI Express root also.
+ */
+ if (!(ACPI_STRCMP(id,
+ PCI_ROOT_HID_STRING)) ||
+ !(ACPI_STRCMP(id, PCI_EXPRESS_ROOT_HID_STRING))) {
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ut_is_aml_table
*
* PARAMETERS: Table - An ACPI table
@@ -1037,8 +1070,7 @@ acpi_error(const char *module_name, u32 line_number, const char *format, ...)
va_start(args, format);
acpi_os_vprintf(format, args);
- acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name,
- line_number);
+ ACPI_COMMON_MSG_SUFFIX;
va_end(args);
}
@@ -1052,8 +1084,7 @@ acpi_exception(const char *module_name,
va_start(args, format);
acpi_os_vprintf(format, args);
- acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name,
- line_number);
+ ACPI_COMMON_MSG_SUFFIX;
va_end(args);
}
@@ -1066,8 +1097,7 @@ acpi_warning(const char *module_name, u32 line_number, const char *format, ...)
va_start(args, format);
acpi_os_vprintf(format, args);
- acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name,
- line_number);
+ ACPI_COMMON_MSG_SUFFIX;
va_end(args);
}
@@ -1088,3 +1118,46 @@ ACPI_EXPORT_SYMBOL(acpi_error)
ACPI_EXPORT_SYMBOL(acpi_exception)
ACPI_EXPORT_SYMBOL(acpi_warning)
ACPI_EXPORT_SYMBOL(acpi_info)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_predefined_warning
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * Pathname - Full pathname to the node
+ * node_flags - From Namespace node for the method/object
+ * Format - Printf format string + additional args
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Warnings for the predefined validation module. Messages are
+ * only emitted the first time a problem with a particular
+ * method/object is detected. This prevents a flood of error
+ * messages for methods that are repeatedly evaluated.
+ *
+******************************************************************************/
+
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_warning(const char *module_name,
+ u32 line_number,
+ char *pathname,
+ u8 node_flags, const char *format, ...)
+{
+ va_list args;
+
+ /*
+ * Warning messages for this method/object will be disabled after the
+ * first time a validation fails or an object is successfully repaired.
+ */
+ if (node_flags & ANOBJ_EVALUATED) {
+ return;
+ }
+
+ acpi_os_printf("ACPI Warning for %s: ", pathname);
+
+ va_start(args, format);
+ acpi_os_vprintf(format, args);
+ ACPI_COMMON_MSG_SUFFIX;
+ va_end(args);
+}
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index 078a22728c6b..b1f5f680bc78 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -251,6 +251,16 @@ acpi_status acpi_initialize_objects(u32 flags)
}
/*
+ * Execute any module-level code that was detected during the table load
+ * phase. Although illegal since ACPI 2.0, there are many machines that
+ * contain this type of code. Each block of detected executable AML code
+ * outside of any control method is wrapped with a temporary control
+ * method object and placed on a global list. The methods on this list
+ * are executed below.
+ */
+ acpi_ns_exec_module_code_list();
+
+ /*
* Initialize the objects that remain uninitialized. This runs the
* executable AML that may be part of the declaration of these objects:
* operation_regions, buffer_fields, Buffers, and Packages.
@@ -318,7 +328,7 @@ ACPI_EXPORT_SYMBOL(acpi_initialize_objects)
*
* RETURN: Status
*
- * DESCRIPTION: Shutdown the ACPI subsystem. Release all resources.
+ * DESCRIPTION: Shutdown the ACPICA subsystem and release all resources.
*
******************************************************************************/
acpi_status acpi_terminate(void)
@@ -327,6 +337,19 @@ acpi_status acpi_terminate(void)
ACPI_FUNCTION_TRACE(acpi_terminate);
+ /* Just exit if subsystem is already shutdown */
+
+ if (acpi_gbl_shutdown) {
+ ACPI_ERROR((AE_INFO, "ACPI Subsystem is already terminated"));
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Subsystem appears active, go ahead and shut it down */
+
+ acpi_gbl_shutdown = TRUE;
+ acpi_gbl_startup_flags = 0;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n"));
+
/* Terminate the AML Debugger if present */
ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = TRUE);
@@ -353,6 +376,7 @@ acpi_status acpi_terminate(void)
}
ACPI_EXPORT_SYMBOL(acpi_terminate)
+
#ifndef ACPI_ASL_COMPILER
#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 58b4517ce712..3f4602b8f287 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -31,6 +31,7 @@
#include <linux/types.h>
#include <linux/jiffies.h>
#include <linux/async.h>
+#include <linux/dmi.h>
#ifdef CONFIG_ACPI_PROCFS_POWER
#include <linux/proc_fs.h>
@@ -45,6 +46,8 @@
#include <linux/power_supply.h>
#endif
+#define PREFIX "ACPI: "
+
#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
#define ACPI_BATTERY_CLASS "battery"
@@ -85,6 +88,10 @@ static const struct acpi_device_id battery_device_ids[] = {
MODULE_DEVICE_TABLE(acpi, battery_device_ids);
+/* For buggy DSDTs that report negative 16-bit values for either charging
+ * or discharging current and/or report 0 as 65536 due to bad math.
+ */
+#define QUIRK_SIGNED16_CURRENT 0x0001
struct acpi_battery {
struct mutex lock;
@@ -112,6 +119,7 @@ struct acpi_battery {
int state;
int power_unit;
u8 alarm_present;
+ long quirks;
};
#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
@@ -390,6 +398,11 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
state_offsets, ARRAY_SIZE(state_offsets));
battery->update_time = jiffies;
kfree(buffer.pointer);
+
+ if ((battery->quirks & QUIRK_SIGNED16_CURRENT) &&
+ battery->rate_now != -1)
+ battery->rate_now = abs((s16)battery->rate_now);
+
return result;
}
@@ -495,6 +508,14 @@ static void sysfs_remove_battery(struct acpi_battery *battery)
}
#endif
+static void acpi_battery_quirks(struct acpi_battery *battery)
+{
+ battery->quirks = 0;
+ if (dmi_name_in_vendors("Acer") && battery->power_unit) {
+ battery->quirks |= QUIRK_SIGNED16_CURRENT;
+ }
+}
+
static int acpi_battery_update(struct acpi_battery *battery)
{
int result, old_present = acpi_battery_present(battery);
@@ -513,6 +534,7 @@ static int acpi_battery_update(struct acpi_battery *battery)
result = acpi_battery_get_info(battery);
if (result)
return result;
+ acpi_battery_quirks(battery);
acpi_battery_init_alarm(battery);
}
#ifdef CONFIG_ACPI_SYSFS_POWER
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index 0c4ca4d318b3..23e5a0519af5 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -34,6 +34,8 @@
#include <acpi/acpi_bus.h>
#include <linux/dmi.h>
+#include "internal.h"
+
enum acpi_blacklist_predicates {
all_versions,
less_than_or_equal,
@@ -222,6 +224,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
* _OSI(Linux) helps sound
* DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"),
* DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"),
+ * T400, T500
* _OSI(Linux) has Linux specific hooks
* DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"),
* _OSI(Linux) is a NOP:
@@ -252,6 +255,22 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"),
},
},
+ {
+ .callback = dmi_enable_osi_linux,
+ .ident = "Lenovo ThinkPad T400",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T400"),
+ },
+ },
+ {
+ .callback = dmi_enable_osi_linux,
+ .ident = "Lenovo ThinkPad T500",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T500"),
+ },
+ },
{}
};
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 2876fc70c3a9..741191524353 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -38,6 +38,7 @@
#include <linux/pci.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#include <linux/dmi.h>
#include "internal.h"
@@ -93,36 +94,33 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
EXPORT_SYMBOL(acpi_bus_get_device);
-int acpi_bus_get_status(struct acpi_device *device)
+acpi_status acpi_bus_get_status_handle(acpi_handle handle,
+ unsigned long long *sta)
{
- acpi_status status = AE_OK;
- unsigned long long sta = 0;
-
+ acpi_status status;
- if (!device)
- return -EINVAL;
+ status = acpi_evaluate_integer(handle, "_STA", NULL, sta);
+ if (ACPI_SUCCESS(status))
+ return AE_OK;
- /*
- * Evaluate _STA if present.
- */
- if (device->flags.dynamic_status) {
- status =
- acpi_evaluate_integer(device->handle, "_STA", NULL, &sta);
- if (ACPI_FAILURE(status))
- return -ENODEV;
- STRUCT_TO_INT(device->status) = (int)sta;
+ if (status == AE_NOT_FOUND) {
+ *sta = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
+ ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
+ return AE_OK;
}
+ return status;
+}
- /*
- * According to ACPI spec some device can be present and functional
- * even if the parent is not present but functional.
- * In such conditions the child device should not inherit the status
- * from the parent.
- */
- else
- STRUCT_TO_INT(device->status) =
- ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
- ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
+int acpi_bus_get_status(struct acpi_device *device)
+{
+ acpi_status status;
+ unsigned long long sta;
+
+ status = acpi_bus_get_status_handle(device->handle, &sta);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ STRUCT_TO_INT(device->status) = (int) sta;
if (device->status.functional && !device->status.present) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: "
@@ -134,14 +132,12 @@ int acpi_bus_get_status(struct acpi_device *device)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n",
device->pnp.bus_id,
(u32) STRUCT_TO_INT(device->status)));
-
return 0;
}
-
EXPORT_SYMBOL(acpi_bus_get_status);
void acpi_bus_private_data_handler(acpi_handle handle,
- u32 function, void *context)
+ void *context)
{
return;
}
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 9195deba9d94..0c9c6a9a002c 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -33,6 +33,8 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#define PREFIX "ACPI: "
+
#define ACPI_BUTTON_CLASS "button"
#define ACPI_BUTTON_FILE_INFO "info"
#define ACPI_BUTTON_FILE_STATE "state"
@@ -113,6 +115,9 @@ static const struct file_operations acpi_button_state_fops = {
.release = single_release,
};
+static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
+static struct acpi_device *lid_device;
+
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
@@ -229,11 +234,41 @@ static int acpi_button_remove_fs(struct acpi_device *device)
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
+int acpi_lid_notifier_register(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&acpi_lid_notifier, nb);
+}
+EXPORT_SYMBOL(acpi_lid_notifier_register);
+
+int acpi_lid_notifier_unregister(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&acpi_lid_notifier, nb);
+}
+EXPORT_SYMBOL(acpi_lid_notifier_unregister);
+
+int acpi_lid_open(void)
+{
+ acpi_status status;
+ unsigned long long state;
+
+ if (!lid_device)
+ return -ENODEV;
+
+ status = acpi_evaluate_integer(lid_device->handle, "_LID", NULL,
+ &state);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ return !!state;
+}
+EXPORT_SYMBOL(acpi_lid_open);
+
static int acpi_lid_send_state(struct acpi_device *device)
{
struct acpi_button *button = acpi_driver_data(device);
unsigned long long state;
acpi_status status;
+ int ret;
status = acpi_evaluate_integer(device->handle, "_LID", NULL, &state);
if (ACPI_FAILURE(status))
@@ -242,7 +277,12 @@ static int acpi_lid_send_state(struct acpi_device *device)
/* input layer checks if event is redundant */
input_report_switch(button->input, SW_LID, !state);
input_sync(button->input);
- return 0;
+
+ ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device);
+ if (ret == NOTIFY_DONE)
+ ret = blocking_notifier_call_chain(&acpi_lid_notifier, state,
+ device);
+ return ret;
}
static void acpi_button_notify(struct acpi_device *device, u32 event)
@@ -364,8 +404,14 @@ static int acpi_button_add(struct acpi_device *device)
error = input_register_device(input);
if (error)
goto err_remove_fs;
- if (button->type == ACPI_BUTTON_TYPE_LID)
+ if (button->type == ACPI_BUTTON_TYPE_LID) {
acpi_lid_send_state(device);
+ /*
+ * This assumes there's only one lid device, or if there are
+ * more we only care about the last one...
+ */
+ lid_device = device;
+ }
if (device->wakeup.flags.valid) {
/* Button's GPE is run-wake GPE */
diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c
index 332fe4b21708..6c9ee68e46fb 100644
--- a/drivers/acpi/cm_sbs.c
+++ b/drivers/acpi/cm_sbs.c
@@ -28,6 +28,8 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#define PREFIX "ACPI: "
+
ACPI_MODULE_NAME("cm_sbs");
#define ACPI_AC_CLASS "ac_adapter"
#define ACPI_BATTERY_CLASS "battery"
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index fe0cdf83641a..642bb305cb65 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -35,6 +35,8 @@
#include <acpi/acpi_drivers.h>
#include <acpi/container.h>
+#define PREFIX "ACPI: "
+
#define ACPI_CONTAINER_DEVICE_NAME "ACPI container device"
#define ACPI_CONTAINER_CLASS "container"
@@ -200,20 +202,17 @@ container_walk_namespace_cb(acpi_handle handle,
u32 lvl, void *context, void **rv)
{
char *hid = NULL;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_device_info *info;
acpi_status status;
int *action = context;
-
- status = acpi_get_object_info(handle, &buffer);
- if (ACPI_FAILURE(status) || !buffer.pointer) {
+ status = acpi_get_object_info(handle, &info);
+ if (ACPI_FAILURE(status)) {
return AE_OK;
}
- info = buffer.pointer;
if (info->valid & ACPI_VALID_HID)
- hid = info->hardware_id.value;
+ hid = info->hardware_id.string;
if (hid == NULL) {
goto end;
@@ -240,7 +239,7 @@ container_walk_namespace_cb(acpi_handle handle,
}
end:
- kfree(buffer.pointer);
+ kfree(info);
return AE_OK;
}
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c
index a8287be0870e..8a690c3b8e23 100644
--- a/drivers/acpi/debug.c
+++ b/drivers/acpi/debug.c
@@ -3,6 +3,7 @@
*/
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -201,72 +202,54 @@ module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer"
#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level"
-static int
-acpi_system_read_debug(char *page,
- char **start, off_t off, int count, int *eof, void *data)
+static int acpi_system_debug_proc_show(struct seq_file *m, void *v)
{
- char *p = page;
- int size = 0;
unsigned int i;
- if (off != 0)
- goto end;
+ seq_printf(m, "%-25s\tHex SET\n", "Description");
- p += sprintf(p, "%-25s\tHex SET\n", "Description");
-
- switch ((unsigned long)data) {
+ switch ((unsigned long)m->private) {
case 0:
for (i = 0; i < ARRAY_SIZE(acpi_debug_layers); i++) {
- p += sprintf(p, "%-25s\t0x%08lX [%c]\n",
+ seq_printf(m, "%-25s\t0x%08lX [%c]\n",
acpi_debug_layers[i].name,
acpi_debug_layers[i].value,
(acpi_dbg_layer & acpi_debug_layers[i].
value) ? '*' : ' ');
}
- p += sprintf(p, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
+ seq_printf(m, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
ACPI_ALL_DRIVERS,
(acpi_dbg_layer & ACPI_ALL_DRIVERS) ==
ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer &
ACPI_ALL_DRIVERS) ==
0 ? ' ' : '-');
- p += sprintf(p,
+ seq_printf(m,
"--\ndebug_layer = 0x%08X (* = enabled, - = partial)\n",
acpi_dbg_layer);
break;
case 1:
for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) {
- p += sprintf(p, "%-25s\t0x%08lX [%c]\n",
+ seq_printf(m, "%-25s\t0x%08lX [%c]\n",
acpi_debug_levels[i].name,
acpi_debug_levels[i].value,
(acpi_dbg_level & acpi_debug_levels[i].
value) ? '*' : ' ');
}
- p += sprintf(p, "--\ndebug_level = 0x%08X (* = enabled)\n",
+ seq_printf(m, "--\ndebug_level = 0x%08X (* = enabled)\n",
acpi_dbg_level);
break;
- default:
- p += sprintf(p, "Invalid debug option\n");
- break;
}
+ return 0;
+}
- end:
- size = (p - page);
- if (size <= off + count)
- *eof = 1;
- *start = page + off;
- size -= off;
- if (size > count)
- size = count;
- if (size < 0)
- size = 0;
-
- return size;
+static int acpi_system_debug_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_system_debug_proc_show, PDE(inode)->data);
}
-static int
-acpi_system_write_debug(struct file *file,
+static ssize_t acpi_system_debug_proc_write(struct file *file,
const char __user * buffer,
- unsigned long count, void *data)
+ size_t count, loff_t *pos)
{
char debug_string[12] = { '\0' };
@@ -279,7 +262,7 @@ acpi_system_write_debug(struct file *file,
debug_string[count] = '\0';
- switch ((unsigned long)data) {
+ switch ((unsigned long)PDE(file->f_path.dentry->d_inode)->data) {
case 0:
acpi_dbg_layer = simple_strtoul(debug_string, NULL, 0);
break;
@@ -292,6 +275,15 @@ acpi_system_write_debug(struct file *file,
return count;
}
+
+static const struct file_operations acpi_system_debug_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = acpi_system_debug_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = acpi_system_debug_proc_write,
+};
#endif
int __init acpi_debug_init(void)
@@ -303,24 +295,18 @@ int __init acpi_debug_init(void)
/* 'debug_layer' [R/W] */
name = ACPI_SYSTEM_FILE_DEBUG_LAYER;
- entry =
- create_proc_read_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
- acpi_root_dir, acpi_system_read_debug,
- (void *)0);
- if (entry)
- entry->write_proc = acpi_system_write_debug;
- else
+ entry = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_root_dir, &acpi_system_debug_proc_fops,
+ (void *)0);
+ if (!entry)
goto Error;
/* 'debug_level' [R/W] */
name = ACPI_SYSTEM_FILE_DEBUG_LEVEL;
- entry =
- create_proc_read_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
- acpi_root_dir, acpi_system_read_debug,
- (void *)1);
- if (entry)
- entry->write_proc = acpi_system_write_debug;
- else
+ entry = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_root_dir, &acpi_system_debug_proc_fops,
+ (void *)1);
+ if (!entry)
goto Error;
Done:
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index efb959d6c8a9..7338b6a3e049 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -33,6 +33,8 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#define PREFIX "ACPI: "
+
#define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver"
ACPI_MODULE_NAME("dock");
@@ -65,7 +67,7 @@ struct dock_station {
struct list_head dependent_devices;
struct list_head hotplug_devices;
- struct list_head sibiling;
+ struct list_head sibling;
struct platform_device *dock_device;
};
static LIST_HEAD(dock_stations);
@@ -231,18 +233,16 @@ static int is_ata(acpi_handle handle)
static int is_battery(acpi_handle handle)
{
struct acpi_device_info *info;
- struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
int ret = 1;
- if (!ACPI_SUCCESS(acpi_get_object_info(handle, &buffer)))
+ if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info)))
return 0;
- info = buffer.pointer;
if (!(info->valid & ACPI_VALID_HID))
ret = 0;
else
- ret = !strcmp("PNP0C0A", info->hardware_id.value);
+ ret = !strcmp("PNP0C0A", info->hardware_id.string);
- kfree(buffer.pointer);
+ kfree(info);
return ret;
}
@@ -275,7 +275,7 @@ int is_dock_device(acpi_handle handle)
if (is_dock(handle))
return 1;
- list_for_each_entry(dock_station, &dock_stations, sibiling) {
+ list_for_each_entry(dock_station, &dock_stations, sibling) {
if (find_dock_dependent_device(dock_station, handle))
return 1;
}
@@ -619,7 +619,7 @@ register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops,
* make sure this handle is for a device dependent on the dock,
* this would include the dock station itself
*/
- list_for_each_entry(dock_station, &dock_stations, sibiling) {
+ list_for_each_entry(dock_station, &dock_stations, sibling) {
/*
* An ATA bay can be in a dock and itself can be ejected
* seperately, so there are two 'dock stations' which need the
@@ -651,7 +651,7 @@ void unregister_hotplug_dock_device(acpi_handle handle)
if (!dock_station_count)
return;
- list_for_each_entry(dock_station, &dock_stations, sibiling) {
+ list_for_each_entry(dock_station, &dock_stations, sibling) {
dd = find_dock_dependent_device(dock_station, handle);
if (dd)
dock_del_hotplug_device(dock_station, dd);
@@ -787,7 +787,7 @@ static int acpi_dock_notifier_call(struct notifier_block *this,
if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
&& event != ACPI_NOTIFY_EJECT_REQUEST)
return 0;
- list_for_each_entry(dock_station, &dock_stations, sibiling) {
+ list_for_each_entry(dock_station, &dock_stations, sibling) {
if (dock_station->handle == handle) {
struct dock_data *dock_data;
@@ -958,7 +958,7 @@ static int dock_add(acpi_handle handle)
dock_station->last_dock_time = jiffies - HZ;
INIT_LIST_HEAD(&dock_station->dependent_devices);
INIT_LIST_HEAD(&dock_station->hotplug_devices);
- INIT_LIST_HEAD(&dock_station->sibiling);
+ INIT_LIST_HEAD(&dock_station->sibling);
spin_lock_init(&dock_station->dd_lock);
mutex_init(&dock_station->hp_lock);
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
@@ -1044,7 +1044,7 @@ static int dock_add(acpi_handle handle)
add_dock_dependent_device(dock_station, dd);
dock_station_count++;
- list_add(&dock_station->sibiling, &dock_stations);
+ list_add(&dock_station->sibling, &dock_stations);
return 0;
dock_add_err_unregister:
@@ -1149,7 +1149,7 @@ static void __exit dock_exit(void)
struct dock_station *tmp;
unregister_acpi_bus_notifier(&dock_acpi_notifier);
- list_for_each_entry_safe(dock_station, tmp, &dock_stations, sibiling)
+ list_for_each_entry_safe(dock_station, tmp, &dock_stations, sibling)
dock_remove(dock_station);
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 391f331674c7..baef28c1e630 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -42,12 +42,12 @@
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#include <linux/dmi.h>
#define ACPI_EC_CLASS "embedded_controller"
#define ACPI_EC_DEVICE_NAME "Embedded Controller"
#define ACPI_EC_FILE_INFO "info"
-#undef PREFIX
#define PREFIX "ACPI: EC: "
/* EC status register */
@@ -68,15 +68,13 @@ enum ec_command {
#define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
#define ACPI_EC_CDELAY 10 /* Wait 10us before polling EC */
+#define ACPI_EC_MSI_UDELAY 550 /* Wait 550us for MSI EC */
#define ACPI_EC_STORM_THRESHOLD 8 /* number of false interrupts
per one transaction */
enum {
EC_FLAGS_QUERY_PENDING, /* Query is pending */
- EC_FLAGS_GPE_MODE, /* Expect GPE to be sent
- * for status change */
- EC_FLAGS_NO_GPE, /* Don't use GPE mode */
EC_FLAGS_GPE_STORM, /* GPE storm detected */
EC_FLAGS_HANDLERS_INSTALLED /* Handlers for GPE and
* OpReg are installed */
@@ -121,6 +119,8 @@ static struct acpi_ec {
} *boot_ec, *first_ec;
static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
+static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
+static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
/* --------------------------------------------------------------------------
Transaction Management
@@ -170,7 +170,7 @@ static void start_transaction(struct acpi_ec *ec)
acpi_ec_write_cmd(ec, ec->curr->command);
}
-static void gpe_transaction(struct acpi_ec *ec, u8 status)
+static void advance_transaction(struct acpi_ec *ec, u8 status)
{
unsigned long flags;
spin_lock_irqsave(&ec->curr_lock, flags);
@@ -201,29 +201,6 @@ unlock:
spin_unlock_irqrestore(&ec->curr_lock, flags);
}
-static int acpi_ec_wait(struct acpi_ec *ec)
-{
- if (wait_event_timeout(ec->wait, ec_transaction_done(ec),
- msecs_to_jiffies(ACPI_EC_DELAY)))
- return 0;
- /* try restart command if we get any false interrupts */
- if (ec->curr->irq_count &&
- (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) {
- pr_debug(PREFIX "controller reset, restart transaction\n");
- start_transaction(ec);
- if (wait_event_timeout(ec->wait, ec_transaction_done(ec),
- msecs_to_jiffies(ACPI_EC_DELAY)))
- return 0;
- }
- /* missing GPEs, switch back to poll mode */
- if (printk_ratelimit())
- pr_info(PREFIX "missing confirmations, "
- "switch off interrupt mode.\n");
- set_bit(EC_FLAGS_NO_GPE, &ec->flags);
- clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
- return 1;
-}
-
static void acpi_ec_gpe_query(void *ec_cxt);
static int ec_check_sci(struct acpi_ec *ec, u8 state)
@@ -236,43 +213,49 @@ static int ec_check_sci(struct acpi_ec *ec, u8 state)
return 0;
}
-static void ec_delay(void)
-{
- /* EC in MSI notebooks don't tolerate delays other than 550 usec */
- if (EC_FLAGS_MSI)
- udelay(ACPI_EC_DELAY);
- else
- /* Use shortest sleep available */
- msleep(1);
-}
-
static int ec_poll(struct acpi_ec *ec)
{
- unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
- udelay(ACPI_EC_CDELAY);
- while (time_before(jiffies, delay)) {
- gpe_transaction(ec, acpi_ec_read_status(ec));
- ec_delay();
- if (ec_transaction_done(ec))
- return 0;
+ unsigned long flags;
+ int repeat = 2; /* number of command restarts */
+ while (repeat--) {
+ unsigned long delay = jiffies +
+ msecs_to_jiffies(ACPI_EC_DELAY);
+ do {
+ /* don't sleep with disabled interrupts */
+ if (EC_FLAGS_MSI || irqs_disabled()) {
+ udelay(ACPI_EC_MSI_UDELAY);
+ if (ec_transaction_done(ec))
+ return 0;
+ } else {
+ if (wait_event_timeout(ec->wait,
+ ec_transaction_done(ec),
+ msecs_to_jiffies(1)))
+ return 0;
+ }
+ advance_transaction(ec, acpi_ec_read_status(ec));
+ } while (time_before(jiffies, delay));
+ if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
+ break;
+ pr_debug(PREFIX "controller reset, restart transaction\n");
+ spin_lock_irqsave(&ec->curr_lock, flags);
+ start_transaction(ec);
+ spin_unlock_irqrestore(&ec->curr_lock, flags);
}
return -ETIME;
}
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
- struct transaction *t,
- int force_poll)
+ struct transaction *t)
{
unsigned long tmp;
int ret = 0;
pr_debug(PREFIX "transaction start\n");
/* disable GPE during transaction if storm is detected */
if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
- clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
acpi_disable_gpe(NULL, ec->gpe);
}
if (EC_FLAGS_MSI)
- udelay(ACPI_EC_DELAY);
+ udelay(ACPI_EC_MSI_UDELAY);
/* start transaction */
spin_lock_irqsave(&ec->curr_lock, tmp);
/* following two actions should be kept atomic */
@@ -281,11 +264,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
spin_unlock_irqrestore(&ec->curr_lock, tmp);
- /* if we selected poll mode or failed in GPE-mode do a poll loop */
- if (force_poll ||
- !test_bit(EC_FLAGS_GPE_MODE, &ec->flags) ||
- acpi_ec_wait(ec))
- ret = ec_poll(ec);
+ ret = ec_poll(ec);
pr_debug(PREFIX "transaction end\n");
spin_lock_irqsave(&ec->curr_lock, tmp);
ec->curr = NULL;
@@ -295,8 +274,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
ec_check_sci(ec, acpi_ec_read_status(ec));
/* it is safe to enable GPE outside of transaction */
acpi_enable_gpe(NULL, ec->gpe);
- } else if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
- t->irq_count > ACPI_EC_STORM_THRESHOLD) {
+ } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) {
pr_info(PREFIX "GPE storm detected, "
"transactions will use polling mode\n");
set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
@@ -314,16 +292,14 @@ static int ec_wait_ibf0(struct acpi_ec *ec)
{
unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
/* interrupt wait manually if GPE mode is not active */
- unsigned long timeout = test_bit(EC_FLAGS_GPE_MODE, &ec->flags) ?
- msecs_to_jiffies(ACPI_EC_DELAY) : msecs_to_jiffies(1);
while (time_before(jiffies, delay))
- if (wait_event_timeout(ec->wait, ec_check_ibf0(ec), timeout))
+ if (wait_event_timeout(ec->wait, ec_check_ibf0(ec),
+ msecs_to_jiffies(1)))
return 0;
return -ETIME;
}
-static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t,
- int force_poll)
+static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
{
int status;
u32 glk;
@@ -345,7 +321,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t,
status = -ETIME;
goto end;
}
- status = acpi_ec_transaction_unlocked(ec, t, force_poll);
+ status = acpi_ec_transaction_unlocked(ec, t);
end:
if (ec->global_lock)
acpi_release_global_lock(glk);
@@ -354,10 +330,6 @@ unlock:
return status;
}
-/*
- * Note: samsung nv5000 doesn't work with ec burst mode.
- * http://bugzilla.kernel.org/show_bug.cgi?id=4980
- */
static int acpi_ec_burst_enable(struct acpi_ec *ec)
{
u8 d;
@@ -365,7 +337,7 @@ static int acpi_ec_burst_enable(struct acpi_ec *ec)
.wdata = NULL, .rdata = &d,
.wlen = 0, .rlen = 1};
- return acpi_ec_transaction(ec, &t, 0);
+ return acpi_ec_transaction(ec, &t);
}
static int acpi_ec_burst_disable(struct acpi_ec *ec)
@@ -375,7 +347,7 @@ static int acpi_ec_burst_disable(struct acpi_ec *ec)
.wlen = 0, .rlen = 0};
return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ?
- acpi_ec_transaction(ec, &t, 0) : 0;
+ acpi_ec_transaction(ec, &t) : 0;
}
static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
@@ -386,7 +358,7 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
.wdata = &address, .rdata = &d,
.wlen = 1, .rlen = 1};
- result = acpi_ec_transaction(ec, &t, 0);
+ result = acpi_ec_transaction(ec, &t);
*data = d;
return result;
}
@@ -398,7 +370,7 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
.wdata = wdata, .rdata = NULL,
.wlen = 2, .rlen = 0};
- return acpi_ec_transaction(ec, &t, 0);
+ return acpi_ec_transaction(ec, &t);
}
/*
@@ -466,7 +438,7 @@ int ec_transaction(u8 command,
if (!first_ec)
return -ENODEV;
- return acpi_ec_transaction(first_ec, &t, force_poll);
+ return acpi_ec_transaction(first_ec, &t);
}
EXPORT_SYMBOL(ec_transaction);
@@ -487,7 +459,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
* bit to be cleared (and thus clearing the interrupt source).
*/
- result = acpi_ec_transaction(ec, &t, 0);
+ result = acpi_ec_transaction(ec, &t);
if (result)
return result;
@@ -570,28 +542,10 @@ static u32 acpi_ec_gpe_handler(void *data)
pr_debug(PREFIX "~~~> interrupt\n");
status = acpi_ec_read_status(ec);
- if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) {
- gpe_transaction(ec, status);
- if (ec_transaction_done(ec) &&
- (status & ACPI_EC_FLAG_IBF) == 0)
- wake_up(&ec->wait);
- }
-
+ advance_transaction(ec, status);
+ if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0)
+ wake_up(&ec->wait);
ec_check_sci(ec, status);
- if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
- !test_bit(EC_FLAGS_NO_GPE, &ec->flags)) {
- /* this is non-query, must be confirmation */
- if (!test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
- if (printk_ratelimit())
- pr_info(PREFIX "non-query interrupt received,"
- " switching to interrupt mode\n");
- } else {
- /* hush, STORM switches the mode every transaction */
- pr_debug(PREFIX "non-query interrupt received,"
- " switching to interrupt mode\n");
- }
- set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
- }
return ACPI_INTERRUPT_HANDLED;
}
@@ -617,7 +571,8 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
if (bits != 8 && acpi_strict)
return AE_BAD_PARAMETER;
- acpi_ec_burst_enable(ec);
+ if (EC_FLAGS_MSI)
+ acpi_ec_burst_enable(ec);
if (function == ACPI_READ) {
result = acpi_ec_read(ec, address, &temp);
@@ -638,7 +593,8 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
}
}
- acpi_ec_burst_disable(ec);
+ if (EC_FLAGS_MSI)
+ acpi_ec_burst_disable(ec);
switch (result) {
case -EINVAL:
@@ -788,6 +744,42 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
return AE_CTRL_TERMINATE;
}
+static int ec_install_handlers(struct acpi_ec *ec)
+{
+ acpi_status status;
+ if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
+ return 0;
+ status = acpi_install_gpe_handler(NULL, ec->gpe,
+ ACPI_GPE_EDGE_TRIGGERED,
+ &acpi_ec_gpe_handler, ec);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+ acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
+ acpi_enable_gpe(NULL, ec->gpe);
+ status = acpi_install_address_space_handler(ec->handle,
+ ACPI_ADR_SPACE_EC,
+ &acpi_ec_space_handler,
+ NULL, ec);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_NOT_FOUND) {
+ /*
+ * Maybe OS fails in evaluating the _REG object.
+ * The AE_NOT_FOUND error will be ignored and OS
+ * continue to initialize EC.
+ */
+ printk(KERN_ERR "Fail in evaluating the _REG object"
+ " of EC device. Broken bios is suspected.\n");
+ } else {
+ acpi_remove_gpe_handler(NULL, ec->gpe,
+ &acpi_ec_gpe_handler);
+ return -ENODEV;
+ }
+ }
+
+ set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags);
+ return 0;
+}
+
static void ec_remove_handlers(struct acpi_ec *ec)
{
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
@@ -802,9 +794,8 @@ static void ec_remove_handlers(struct acpi_ec *ec)
static int acpi_ec_add(struct acpi_device *device)
{
struct acpi_ec *ec = NULL;
+ int ret;
- if (!device)
- return -EINVAL;
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
@@ -837,9 +828,12 @@ static int acpi_ec_add(struct acpi_device *device)
acpi_ec_add_fs(device);
pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
ec->gpe, ec->command_addr, ec->data_addr);
- pr_info(PREFIX "driver started in %s mode\n",
- (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))?"interrupt":"poll");
- return 0;
+
+ ret = ec_install_handlers(ec);
+
+ /* EC is fully operational, allow queries */
+ clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+ return ret;
}
static int acpi_ec_remove(struct acpi_device *device, int type)
@@ -851,6 +845,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
return -EINVAL;
ec = acpi_driver_data(device);
+ ec_remove_handlers(ec);
mutex_lock(&ec->lock);
list_for_each_entry_safe(handler, tmp, &ec->list, node) {
list_del(&handler->node);
@@ -888,91 +883,60 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context)
return AE_OK;
}
-static int ec_install_handlers(struct acpi_ec *ec)
+int __init acpi_boot_ec_enable(void)
{
- acpi_status status;
- if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
+ if (!boot_ec || test_bit(EC_FLAGS_HANDLERS_INSTALLED, &boot_ec->flags))
+ return 0;
+ if (!ec_install_handlers(boot_ec)) {
+ first_ec = boot_ec;
return 0;
- status = acpi_install_gpe_handler(NULL, ec->gpe,
- ACPI_GPE_EDGE_TRIGGERED,
- &acpi_ec_gpe_handler, ec);
- if (ACPI_FAILURE(status))
- return -ENODEV;
- acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
- acpi_enable_gpe(NULL, ec->gpe);
- status = acpi_install_address_space_handler(ec->handle,
- ACPI_ADR_SPACE_EC,
- &acpi_ec_space_handler,
- NULL, ec);
- if (ACPI_FAILURE(status)) {
- if (status == AE_NOT_FOUND) {
- /*
- * Maybe OS fails in evaluating the _REG object.
- * The AE_NOT_FOUND error will be ignored and OS
- * continue to initialize EC.
- */
- printk(KERN_ERR "Fail in evaluating the _REG object"
- " of EC device. Broken bios is suspected.\n");
- } else {
- acpi_remove_gpe_handler(NULL, ec->gpe,
- &acpi_ec_gpe_handler);
- return -ENODEV;
- }
}
-
- set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags);
- return 0;
+ return -EFAULT;
}
-static int acpi_ec_start(struct acpi_device *device)
-{
- struct acpi_ec *ec;
- int ret = 0;
-
- if (!device)
- return -EINVAL;
-
- ec = acpi_driver_data(device);
-
- if (!ec)
- return -EINVAL;
-
- ret = ec_install_handlers(ec);
+static const struct acpi_device_id ec_device_ids[] = {
+ {"PNP0C09", 0},
+ {"", 0},
+};
- /* EC is fully operational, allow queries */
- clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
- return ret;
+/* Some BIOS do not survive early DSDT scan, skip it */
+static int ec_skip_dsdt_scan(const struct dmi_system_id *id)
+{
+ EC_FLAGS_SKIP_DSDT_SCAN = 1;
+ return 0;
}
-static int acpi_ec_stop(struct acpi_device *device, int type)
+/* ASUStek often supplies us with broken ECDT, validate it */
+static int ec_validate_ecdt(const struct dmi_system_id *id)
{
- struct acpi_ec *ec;
- if (!device)
- return -EINVAL;
- ec = acpi_driver_data(device);
- if (!ec)
- return -EINVAL;
- ec_remove_handlers(ec);
-
+ EC_FLAGS_VALIDATE_ECDT = 1;
return 0;
}
-int __init acpi_boot_ec_enable(void)
+/* MSI EC needs special treatment, enable it */
+static int ec_flag_msi(const struct dmi_system_id *id)
{
- if (!boot_ec || test_bit(EC_FLAGS_HANDLERS_INSTALLED, &boot_ec->flags))
- return 0;
- if (!ec_install_handlers(boot_ec)) {
- first_ec = boot_ec;
- return 0;
- }
- return -EFAULT;
+ EC_FLAGS_MSI = 1;
+ EC_FLAGS_VALIDATE_ECDT = 1;
+ return 0;
}
-static const struct acpi_device_id ec_device_ids[] = {
- {"PNP0C09", 0},
- {"", 0},
+static struct dmi_system_id __initdata ec_dmi_table[] = {
+ {
+ ec_skip_dsdt_scan, "Compal JFL92", {
+ DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
+ DMI_MATCH(DMI_BOARD_NAME, "JFL92") }, NULL},
+ {
+ ec_flag_msi, "MSI hardware", {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Micro-Star"),
+ DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star") }, NULL},
+ {
+ ec_validate_ecdt, "ASUS hardware", {
+ DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL},
+ {},
};
+
int __init acpi_ec_ecdt_probe(void)
{
acpi_status status;
@@ -985,11 +949,7 @@ int __init acpi_ec_ecdt_probe(void)
/*
* Generate a boot ec context
*/
- if (dmi_name_in_vendors("Micro-Star") ||
- dmi_name_in_vendors("Notebook")) {
- pr_info(PREFIX "Enabling special treatment for EC from MSI.\n");
- EC_FLAGS_MSI = 1;
- }
+ dmi_check_system(ec_dmi_table);
status = acpi_get_table(ACPI_SIG_ECDT, 1,
(struct acpi_table_header **)&ecdt_ptr);
if (ACPI_SUCCESS(status)) {
@@ -1000,7 +960,7 @@ int __init acpi_ec_ecdt_probe(void)
boot_ec->handle = ACPI_ROOT_OBJECT;
acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle);
/* Don't trust ECDT, which comes from ASUSTek */
- if (!dmi_name_in_vendors("ASUS") && EC_FLAGS_MSI == 0)
+ if (!EC_FLAGS_VALIDATE_ECDT)
goto install;
saved_ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
if (!saved_ec)
@@ -1008,6 +968,10 @@ int __init acpi_ec_ecdt_probe(void)
memcpy(saved_ec, boot_ec, sizeof(struct acpi_ec));
/* fall through */
}
+
+ if (EC_FLAGS_SKIP_DSDT_SCAN)
+ return -ENODEV;
+
/* This workaround is needed only on some broken machines,
* which require early EC, but fail to provide ECDT */
printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n");
@@ -1054,8 +1018,6 @@ static int acpi_ec_suspend(struct acpi_device *device, pm_message_t state)
{
struct acpi_ec *ec = acpi_driver_data(device);
/* Stop using GPE */
- set_bit(EC_FLAGS_NO_GPE, &ec->flags);
- clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
acpi_disable_gpe(NULL, ec->gpe);
return 0;
}
@@ -1064,8 +1026,6 @@ static int acpi_ec_resume(struct acpi_device *device)
{
struct acpi_ec *ec = acpi_driver_data(device);
/* Enable use of GPE back */
- clear_bit(EC_FLAGS_NO_GPE, &ec->flags);
- set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
acpi_enable_gpe(NULL, ec->gpe);
return 0;
}
@@ -1077,8 +1037,6 @@ static struct acpi_driver acpi_ec_driver = {
.ops = {
.add = acpi_ec_add,
.remove = acpi_ec_remove,
- .start = acpi_ec_start,
- .stop = acpi_ec_stop,
.suspend = acpi_ec_suspend,
.resume = acpi_ec_resume,
},
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index aeb7e5fb4a04..c511071bfd79 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -14,6 +14,8 @@
#include <net/netlink.h>
#include <net/genetlink.h>
+#include "internal.h"
+
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("event");
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 53698ea08371..f419849a0d3f 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -34,6 +34,8 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#define PREFIX "ACPI: "
+
#define ACPI_FAN_CLASS "fan"
#define ACPI_FAN_FILE_STATE "state"
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index a8a5c29958c8..c6645f26224b 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -12,6 +12,8 @@
#include <linux/rwsem.h>
#include <linux/acpi.h>
+#include "internal.h"
+
#define ACPI_GLUE_DEBUG 0
#if ACPI_GLUE_DEBUG
#define DBG(x...) printk(PREFIX x)
@@ -93,15 +95,13 @@ do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv)
{
acpi_status status;
struct acpi_device_info *info;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_find_child *find = context;
- status = acpi_get_object_info(handle, &buffer);
+ status = acpi_get_object_info(handle, &info);
if (ACPI_SUCCESS(status)) {
- info = buffer.pointer;
if (info->address == find->address)
find->handle = handle;
- kfree(buffer.pointer);
+ kfree(info);
}
return AE_OK;
}
@@ -121,7 +121,7 @@ EXPORT_SYMBOL(acpi_get_child);
/* Link ACPI devices with physical devices */
static void acpi_glue_data_handler(acpi_handle handle,
- u32 function, void *context)
+ void *context)
{
/* we provide an empty handler */
}
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 11a69b53004e..074cf8682d52 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -1,4 +1,24 @@
-/* For use by Linux/ACPI infrastructure, not drivers */
+/*
+ * acpi/internal.h
+ * For use by Linux/ACPI infrastructure, not drivers
+ *
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * 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.
+ */
+
+#define PREFIX "ACPI: "
int init_acpi_device_notify(void);
int acpi_scan_init(void);
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index d440ccd27d91..202dd0c976a3 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -30,6 +30,8 @@
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
+#define PREFIX "ACPI: "
+
#define ACPI_NUMA 0x80000000
#define _COMPONENT ACPI_NUMA
ACPI_MODULE_NAME("numa");
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 5691f165a952..7c1c59ea9ec6 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -58,6 +58,7 @@ struct acpi_os_dpc {
acpi_osd_exec_callback function;
void *context;
struct work_struct work;
+ int wait;
};
#ifdef CONFIG_ACPI_CUSTOM_DSDT
@@ -88,6 +89,7 @@ struct acpi_res_list {
char name[5]; /* only can have a length of 4 chars, make use of this
one instead of res->name, no need to kalloc then */
struct list_head resource_list;
+ int count;
};
static LIST_HEAD(resource_list_head);
@@ -191,7 +193,7 @@ acpi_status __init acpi_os_initialize(void)
static void bind_to_cpu0(struct work_struct *work)
{
- set_cpus_allowed(current, cpumask_of_cpu(0));
+ set_cpus_allowed_ptr(current, cpumask_of(0));
kfree(work);
}
@@ -697,31 +699,12 @@ void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */
static void acpi_os_execute_deferred(struct work_struct *work)
{
struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
- if (!dpc) {
- printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
- return;
- }
-
- dpc->function(dpc->context);
- kfree(dpc);
-
- return;
-}
-
-static void acpi_os_execute_hp_deferred(struct work_struct *work)
-{
- struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
- if (!dpc) {
- printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
- return;
- }
- acpi_os_wait_events_complete(NULL);
+ if (dpc->wait)
+ acpi_os_wait_events_complete(NULL);
dpc->function(dpc->context);
kfree(dpc);
-
- return;
}
/*******************************************************************************
@@ -745,15 +728,11 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
acpi_status status = AE_OK;
struct acpi_os_dpc *dpc;
struct workqueue_struct *queue;
- work_func_t func;
int ret;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Scheduling function [%p(%p)] for deferred execution.\n",
function, context));
- if (!function)
- return AE_BAD_PARAMETER;
-
/*
* Allocate/initialize DPC structure. Note that this memory will be
* freed by the callee. The kernel handles the work_struct list in a
@@ -778,8 +757,8 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
*/
queue = hp ? kacpi_hotplug_wq :
(type == OSL_NOTIFY_HANDLER ? kacpi_notify_wq : kacpid_wq);
- func = hp ? acpi_os_execute_hp_deferred : acpi_os_execute_deferred;
- INIT_WORK(&dpc->work, func);
+ dpc->wait = hp ? 1 : 0;
+ INIT_WORK(&dpc->work, acpi_os_execute_deferred);
ret = queue_work(queue, &dpc->work);
if (!ret) {
@@ -1182,7 +1161,13 @@ int acpi_check_resource_conflict(struct resource *res)
res_list_elem->name,
(long long) res_list_elem->start,
(long long) res_list_elem->end);
- printk(KERN_INFO "ACPI: Device needs an ACPI driver\n");
+ if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX)
+ printk(KERN_NOTICE "ACPI: This conflict may"
+ " cause random problems and system"
+ " instability\n");
+ printk(KERN_INFO "ACPI: If an ACPI driver is available"
+ " for this device, you should use it instead of"
+ " the native driver\n");
}
if (acpi_enforce_resources == ENFORCE_RESOURCES_STRICT)
return -EBUSY;
@@ -1358,6 +1343,89 @@ acpi_os_validate_interface (char *interface)
return AE_SUPPORT;
}
+static inline int acpi_res_list_add(struct acpi_res_list *res)
+{
+ struct acpi_res_list *res_list_elem;
+
+ list_for_each_entry(res_list_elem, &resource_list_head,
+ resource_list) {
+
+ if (res->resource_type == res_list_elem->resource_type &&
+ res->start == res_list_elem->start &&
+ res->end == res_list_elem->end) {
+
+ /*
+ * The Region(addr,len) already exist in the list,
+ * just increase the count
+ */
+
+ res_list_elem->count++;
+ return 0;
+ }
+ }
+
+ res->count = 1;
+ list_add(&res->resource_list, &resource_list_head);
+ return 1;
+}
+
+static inline void acpi_res_list_del(struct acpi_res_list *res)
+{
+ struct acpi_res_list *res_list_elem;
+
+ list_for_each_entry(res_list_elem, &resource_list_head,
+ resource_list) {
+
+ if (res->resource_type == res_list_elem->resource_type &&
+ res->start == res_list_elem->start &&
+ res->end == res_list_elem->end) {
+
+ /*
+ * If the res count is decreased to 0,
+ * remove and free it
+ */
+
+ if (--res_list_elem->count == 0) {
+ list_del(&res_list_elem->resource_list);
+ kfree(res_list_elem);
+ }
+ return;
+ }
+ }
+}
+
+acpi_status
+acpi_os_invalidate_address(
+ u8 space_id,
+ acpi_physical_address address,
+ acpi_size length)
+{
+ struct acpi_res_list res;
+
+ switch (space_id) {
+ case ACPI_ADR_SPACE_SYSTEM_IO:
+ case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+ /* Only interference checks against SystemIO and SytemMemory
+ are needed */
+ res.start = address;
+ res.end = address + length - 1;
+ res.resource_type = space_id;
+ spin_lock(&acpi_res_lock);
+ acpi_res_list_del(&res);
+ spin_unlock(&acpi_res_lock);
+ break;
+ case ACPI_ADR_SPACE_PCI_CONFIG:
+ case ACPI_ADR_SPACE_EC:
+ case ACPI_ADR_SPACE_SMBUS:
+ case ACPI_ADR_SPACE_CMOS:
+ case ACPI_ADR_SPACE_PCI_BAR_TARGET:
+ case ACPI_ADR_SPACE_DATA_TABLE:
+ case ACPI_ADR_SPACE_FIXED_HARDWARE:
+ break;
+ }
+ return AE_OK;
+}
+
/******************************************************************************
*
* FUNCTION: acpi_os_validate_address
@@ -1382,6 +1450,7 @@ acpi_os_validate_address (
char *name)
{
struct acpi_res_list *res;
+ int added;
if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
return AE_OK;
@@ -1399,14 +1468,17 @@ acpi_os_validate_address (
res->end = address + length - 1;
res->resource_type = space_id;
spin_lock(&acpi_res_lock);
- list_add(&res->resource_list, &resource_list_head);
+ added = acpi_res_list_add(res);
spin_unlock(&acpi_res_lock);
- pr_debug("Added %s resource: start: 0x%llx, end: 0x%llx, "
- "name: %s\n", (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
+ pr_debug("%s %s resource: start: 0x%llx, end: 0x%llx, "
+ "name: %s\n", added ? "Added" : "Already exist",
+ (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
? "SystemIO" : "System Memory",
(unsigned long long)res->start,
(unsigned long long)res->end,
res->name);
+ if (!added)
+ kfree(res);
break;
case ACPI_ADR_SPACE_PCI_CONFIG:
case ACPI_ADR_SPACE_EC:
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index b794eb88ab90..843699ed93f2 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -40,6 +40,8 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#define PREFIX "ACPI: "
+
#define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_irq");
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 16e0f9d3d17c..394ae89409c2 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -43,6 +43,8 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#define PREFIX "ACPI: "
+
#define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_link");
#define ACPI_PCI_LINK_CLASS "pci_irq_routing"
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 55b5b90c2a44..1af808171d46 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -36,6 +36,8 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#define PREFIX "ACPI: "
+
#define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_root");
#define ACPI_PCI_ROOT_CLASS "pci_bridge"
@@ -61,20 +63,6 @@ static struct acpi_driver acpi_pci_root_driver = {
},
};
-struct acpi_pci_root {
- struct list_head node;
- struct acpi_device *device;
- struct pci_bus *bus;
- u16 segment;
- u8 bus_nr;
-
- u32 osc_support_set; /* _OSC state of support bits */
- u32 osc_control_set; /* _OSC state of control bits */
- u32 osc_control_qry; /* the latest _OSC query result */
-
- u32 osc_queried:1; /* has _OSC control been queried? */
-};
-
static LIST_HEAD(acpi_pci_roots);
static struct acpi_pci_driver *sub_driver;
@@ -317,7 +305,7 @@ static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags)
return status;
}
-static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
+struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
{
struct acpi_pci_root *root;
@@ -327,6 +315,7 @@ static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
}
return NULL;
}
+EXPORT_SYMBOL_GPL(acpi_pci_find_root);
struct acpi_handle_node {
struct list_head node;
@@ -400,6 +389,17 @@ struct pci_dev *acpi_get_pci_dev(acpi_handle handle)
pbus = pdev->subordinate;
pci_dev_put(pdev);
+
+ /*
+ * This function may be called for a non-PCI device that has a
+ * PCI parent (eg. a disk under a PCI SATA controller). In that
+ * case pdev->subordinate will be NULL for the parent.
+ */
+ if (!pbus) {
+ dev_dbg(&pdev->dev, "Not a PCI-to-PCI bridge\n");
+ pdev = NULL;
+ break;
+ }
}
out:
list_for_each_entry_safe(node, tmp, &device_list, node)
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c
index 12158e0d009b..45da2bae36c8 100644
--- a/drivers/acpi/pci_slot.c
+++ b/drivers/acpi/pci_slot.c
@@ -31,6 +31,7 @@
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#include <linux/dmi.h>
static int debug;
static int check_sta_before_sun;
@@ -57,7 +58,7 @@ ACPI_MODULE_NAME("pci_slot");
MY_NAME , ## arg); \
} while (0)
-#define SLOT_NAME_SIZE 20 /* Inspired by #define in acpiphp.h */
+#define SLOT_NAME_SIZE 21 /* Inspired by #define in acpiphp.h */
struct acpi_pci_slot {
acpi_handle root_handle; /* handle of the root bridge */
@@ -149,7 +150,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
}
- snprintf(name, sizeof(name), "%u", (u32)sun);
+ snprintf(name, sizeof(name), "%llu", sun);
pci_slot = pci_create_slot(pci_bus, device, name, NULL);
if (IS_ERR(pci_slot)) {
err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot));
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index d74365d4a6e7..22b297916519 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -43,6 +43,9 @@
#include <linux/seq_file.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#include "sleep.h"
+
+#define PREFIX "ACPI: "
#define _COMPONENT ACPI_POWER_COMPONENT
ACPI_MODULE_NAME("power");
@@ -361,17 +364,15 @@ int acpi_device_sleep_wake(struct acpi_device *dev,
*/
int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
{
- int i, err;
+ int i, err = 0;
if (!dev || !dev->wakeup.flags.valid)
return -EINVAL;
- /*
- * Do not execute the code below twice in a row without calling
- * acpi_disable_wakeup_device_power() in between for the same device
- */
- if (dev->wakeup.flags.prepared)
- return 0;
+ mutex_lock(&acpi_device_lock);
+
+ if (dev->wakeup.prepare_count++)
+ goto out;
/* Open power resource */
for (i = 0; i < dev->wakeup.resources.count; i++) {
@@ -379,7 +380,8 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
if (ret) {
printk(KERN_ERR PREFIX "Transition power state\n");
dev->wakeup.flags.valid = 0;
- return -ENODEV;
+ err = -ENODEV;
+ goto err_out;
}
}
@@ -388,9 +390,13 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
* in arbitrary power state afterwards.
*/
err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);
- if (!err)
- dev->wakeup.flags.prepared = 1;
+ err_out:
+ if (err)
+ dev->wakeup.prepare_count = 0;
+
+ out:
+ mutex_unlock(&acpi_device_lock);
return err;
}
@@ -402,35 +408,42 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
*/
int acpi_disable_wakeup_device_power(struct acpi_device *dev)
{
- int i, ret;
+ int i, err = 0;
if (!dev || !dev->wakeup.flags.valid)
return -EINVAL;
+ mutex_lock(&acpi_device_lock);
+
+ if (--dev->wakeup.prepare_count > 0)
+ goto out;
+
/*
- * Do not execute the code below twice in a row without calling
- * acpi_enable_wakeup_device_power() in between for the same device
+ * Executing the code below even if prepare_count is already zero when
+ * the function is called may be useful, for example for initialisation.
*/
- if (!dev->wakeup.flags.prepared)
- return 0;
+ if (dev->wakeup.prepare_count < 0)
+ dev->wakeup.prepare_count = 0;
- dev->wakeup.flags.prepared = 0;
-
- ret = acpi_device_sleep_wake(dev, 0, 0, 0);
- if (ret)
- return ret;
+ err = acpi_device_sleep_wake(dev, 0, 0, 0);
+ if (err)
+ goto out;
/* Close power resource */
for (i = 0; i < dev->wakeup.resources.count; i++) {
- ret = acpi_power_off_device(dev->wakeup.resources.handles[i], dev);
+ int ret = acpi_power_off_device(
+ dev->wakeup.resources.handles[i], dev);
if (ret) {
printk(KERN_ERR PREFIX "Transition power state\n");
dev->wakeup.flags.valid = 0;
- return -ENODEV;
+ err = -ENODEV;
+ goto out;
}
}
- return ret;
+ out:
+ mutex_unlock(&acpi_device_lock);
+ return err;
}
/* --------------------------------------------------------------------------
diff --git a/drivers/acpi/power_meter.c b/drivers/acpi/power_meter.c
new file mode 100644
index 000000000000..2ef7030a0c28
--- /dev/null
+++ b/drivers/acpi/power_meter.c
@@ -0,0 +1,1022 @@
+/*
+ * A hwmon driver for ACPI 4.0 power meters
+ * Copyright (C) 2009 IBM
+ *
+ * Author: Darrick J. Wong <djwong@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/dmi.h>
+#include <linux/kdev_t.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+
+#define ACPI_POWER_METER_NAME "power_meter"
+ACPI_MODULE_NAME(ACPI_POWER_METER_NAME);
+#define ACPI_POWER_METER_DEVICE_NAME "Power Meter"
+#define ACPI_POWER_METER_CLASS "power_meter_resource"
+
+#define NUM_SENSORS 17
+
+#define POWER_METER_CAN_MEASURE (1 << 0)
+#define POWER_METER_CAN_TRIP (1 << 1)
+#define POWER_METER_CAN_CAP (1 << 2)
+#define POWER_METER_CAN_NOTIFY (1 << 3)
+#define POWER_METER_IS_BATTERY (1 << 8)
+#define UNKNOWN_HYSTERESIS 0xFFFFFFFF
+
+#define METER_NOTIFY_CONFIG 0x80
+#define METER_NOTIFY_TRIP 0x81
+#define METER_NOTIFY_CAP 0x82
+#define METER_NOTIFY_CAPPING 0x83
+#define METER_NOTIFY_INTERVAL 0x84
+
+#define POWER_AVERAGE_NAME "power1_average"
+#define POWER_CAP_NAME "power1_cap"
+#define POWER_AVG_INTERVAL_NAME "power1_average_interval"
+#define POWER_ALARM_NAME "power1_alarm"
+
+static int cap_in_hardware;
+static int force_cap_on;
+
+static int can_cap_in_hardware(void)
+{
+ return force_cap_on || cap_in_hardware;
+}
+
+static struct acpi_device_id power_meter_ids[] = {
+ {"ACPI000D", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, power_meter_ids);
+
+struct acpi_power_meter_capabilities {
+ acpi_integer flags;
+ acpi_integer units;
+ acpi_integer type;
+ acpi_integer accuracy;
+ acpi_integer sampling_time;
+ acpi_integer min_avg_interval;
+ acpi_integer max_avg_interval;
+ acpi_integer hysteresis;
+ acpi_integer configurable_cap;
+ acpi_integer min_cap;
+ acpi_integer max_cap;
+};
+
+struct acpi_power_meter_resource {
+ struct acpi_device *acpi_dev;
+ acpi_bus_id name;
+ struct mutex lock;
+ struct device *hwmon_dev;
+ struct acpi_power_meter_capabilities caps;
+ acpi_string model_number;
+ acpi_string serial_number;
+ acpi_string oem_info;
+ acpi_integer power;
+ acpi_integer cap;
+ acpi_integer avg_interval;
+ int sensors_valid;
+ unsigned long sensors_last_updated;
+ struct sensor_device_attribute sensors[NUM_SENSORS];
+ int num_sensors;
+ int trip[2];
+ int num_domain_devices;
+ struct acpi_device **domain_devices;
+ struct kobject *holders_dir;
+};
+
+struct ro_sensor_template {
+ char *label;
+ ssize_t (*show)(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf);
+ int index;
+};
+
+struct rw_sensor_template {
+ char *label;
+ ssize_t (*show)(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf);
+ ssize_t (*set)(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count);
+ int index;
+};
+
+/* Averaging interval */
+static int update_avg_interval(struct acpi_power_meter_resource *resource)
+{
+ unsigned long long data;
+ acpi_status status;
+
+ status = acpi_evaluate_integer(resource->acpi_dev->handle, "_GAI",
+ NULL, &data);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _GAI"));
+ return -ENODEV;
+ }
+
+ resource->avg_interval = data;
+ return 0;
+}
+
+static ssize_t show_avg_interval(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+
+ mutex_lock(&resource->lock);
+ update_avg_interval(resource);
+ mutex_unlock(&resource->lock);
+
+ return sprintf(buf, "%llu\n", resource->avg_interval);
+}
+
+static ssize_t set_avg_interval(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+ union acpi_object arg0 = { ACPI_TYPE_INTEGER };
+ struct acpi_object_list args = { 1, &arg0 };
+ int res;
+ unsigned long temp;
+ unsigned long long data;
+ acpi_status status;
+
+ res = strict_strtoul(buf, 10, &temp);
+ if (res)
+ return res;
+
+ if (temp > resource->caps.max_avg_interval ||
+ temp < resource->caps.min_avg_interval)
+ return -EINVAL;
+ arg0.integer.value = temp;
+
+ mutex_lock(&resource->lock);
+ status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PAI",
+ &args, &data);
+ if (!ACPI_FAILURE(status))
+ resource->avg_interval = temp;
+ mutex_unlock(&resource->lock);
+
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PAI"));
+ return -EINVAL;
+ }
+
+ /* _PAI returns 0 on success, nonzero otherwise */
+ if (data)
+ return -EINVAL;
+
+ return count;
+}
+
+/* Cap functions */
+static int update_cap(struct acpi_power_meter_resource *resource)
+{
+ unsigned long long data;
+ acpi_status status;
+
+ status = acpi_evaluate_integer(resource->acpi_dev->handle, "_GHL",
+ NULL, &data);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _GHL"));
+ return -ENODEV;
+ }
+
+ resource->cap = data;
+ return 0;
+}
+
+static ssize_t show_cap(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+
+ mutex_lock(&resource->lock);
+ update_cap(resource);
+ mutex_unlock(&resource->lock);
+
+ return sprintf(buf, "%llu\n", resource->cap * 1000);
+}
+
+static ssize_t set_cap(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+ union acpi_object arg0 = { ACPI_TYPE_INTEGER };
+ struct acpi_object_list args = { 1, &arg0 };
+ int res;
+ unsigned long temp;
+ unsigned long long data;
+ acpi_status status;
+
+ res = strict_strtoul(buf, 10, &temp);
+ if (res)
+ return res;
+
+ temp /= 1000;
+ if (temp > resource->caps.max_cap || temp < resource->caps.min_cap)
+ return -EINVAL;
+ arg0.integer.value = temp;
+
+ mutex_lock(&resource->lock);
+ status = acpi_evaluate_integer(resource->acpi_dev->handle, "_SHL",
+ &args, &data);
+ if (!ACPI_FAILURE(status))
+ resource->cap = temp;
+ mutex_unlock(&resource->lock);
+
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SHL"));
+ return -EINVAL;
+ }
+
+ /* _SHL returns 0 on success, nonzero otherwise */
+ if (data)
+ return -EINVAL;
+
+ return count;
+}
+
+/* Power meter trip points */
+static int set_acpi_trip(struct acpi_power_meter_resource *resource)
+{
+ union acpi_object arg_objs[] = {
+ {ACPI_TYPE_INTEGER},
+ {ACPI_TYPE_INTEGER}
+ };
+ struct acpi_object_list args = { 2, arg_objs };
+ unsigned long long data;
+ acpi_status status;
+
+ /* Both trip levels must be set */
+ if (resource->trip[0] < 0 || resource->trip[1] < 0)
+ return 0;
+
+ /* This driver stores min, max; ACPI wants max, min. */
+ arg_objs[0].integer.value = resource->trip[1];
+ arg_objs[1].integer.value = resource->trip[0];
+
+ status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PTP",
+ &args, &data);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTP"));
+ return -EINVAL;
+ }
+
+ /* _PTP returns 0 on success, nonzero otherwise */
+ if (data)
+ return -EINVAL;
+
+ return 0;
+}
+
+static ssize_t set_trip(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+ int res;
+ unsigned long temp;
+
+ res = strict_strtoul(buf, 10, &temp);
+ if (res)
+ return res;
+
+ temp /= 1000;
+ if (temp < 0)
+ return -EINVAL;
+
+ mutex_lock(&resource->lock);
+ resource->trip[attr->index - 7] = temp;
+ res = set_acpi_trip(resource);
+ mutex_unlock(&resource->lock);
+
+ if (res)
+ return res;
+
+ return count;
+}
+
+/* Power meter */
+static int update_meter(struct acpi_power_meter_resource *resource)
+{
+ unsigned long long data;
+ acpi_status status;
+ unsigned long local_jiffies = jiffies;
+
+ if (time_before(local_jiffies, resource->sensors_last_updated +
+ msecs_to_jiffies(resource->caps.sampling_time)) &&
+ resource->sensors_valid)
+ return 0;
+
+ status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PMM",
+ NULL, &data);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMM"));
+ return -ENODEV;
+ }
+
+ resource->power = data;
+ resource->sensors_valid = 1;
+ resource->sensors_last_updated = jiffies;
+ return 0;
+}
+
+static ssize_t show_power(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+
+ mutex_lock(&resource->lock);
+ update_meter(resource);
+ mutex_unlock(&resource->lock);
+
+ return sprintf(buf, "%llu\n", resource->power * 1000);
+}
+
+/* Miscellaneous */
+static ssize_t show_str(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+ acpi_string val;
+
+ switch (attr->index) {
+ case 0:
+ val = resource->model_number;
+ break;
+ case 1:
+ val = resource->serial_number;
+ break;
+ case 2:
+ val = resource->oem_info;
+ break;
+ default:
+ BUG();
+ }
+
+ return sprintf(buf, "%s\n", val);
+}
+
+static ssize_t show_val(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+ acpi_integer val = 0;
+
+ switch (attr->index) {
+ case 0:
+ val = resource->caps.min_avg_interval;
+ break;
+ case 1:
+ val = resource->caps.max_avg_interval;
+ break;
+ case 2:
+ val = resource->caps.min_cap * 1000;
+ break;
+ case 3:
+ val = resource->caps.max_cap * 1000;
+ break;
+ case 4:
+ if (resource->caps.hysteresis == UNKNOWN_HYSTERESIS)
+ return sprintf(buf, "unknown\n");
+
+ val = resource->caps.hysteresis * 1000;
+ break;
+ case 5:
+ if (resource->caps.flags & POWER_METER_IS_BATTERY)
+ val = 1;
+ else
+ val = 0;
+ break;
+ case 6:
+ if (resource->power > resource->cap)
+ val = 1;
+ else
+ val = 0;
+ break;
+ case 7:
+ case 8:
+ if (resource->trip[attr->index - 7] < 0)
+ return sprintf(buf, "unknown\n");
+
+ val = resource->trip[attr->index - 7] * 1000;
+ break;
+ default:
+ BUG();
+ }
+
+ return sprintf(buf, "%llu\n", val);
+}
+
+static ssize_t show_accuracy(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+ unsigned int acc = resource->caps.accuracy;
+
+ return sprintf(buf, "%u.%u%%\n", acc / 1000, acc % 1000);
+}
+
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", ACPI_POWER_METER_NAME);
+}
+
+/* Sensor descriptions. If you add a sensor, update NUM_SENSORS above! */
+static struct ro_sensor_template meter_ro_attrs[] = {
+{POWER_AVERAGE_NAME, show_power, 0},
+{"power1_accuracy", show_accuracy, 0},
+{"power1_average_interval_min", show_val, 0},
+{"power1_average_interval_max", show_val, 1},
+{"power1_is_battery", show_val, 5},
+{NULL, NULL, 0},
+};
+
+static struct rw_sensor_template meter_rw_attrs[] = {
+{POWER_AVG_INTERVAL_NAME, show_avg_interval, set_avg_interval, 0},
+{NULL, NULL, NULL, 0},
+};
+
+static struct ro_sensor_template misc_cap_attrs[] = {
+{"power1_cap_min", show_val, 2},
+{"power1_cap_max", show_val, 3},
+{"power1_cap_hyst", show_val, 4},
+{POWER_ALARM_NAME, show_val, 6},
+{NULL, NULL, 0},
+};
+
+static struct ro_sensor_template ro_cap_attrs[] = {
+{POWER_CAP_NAME, show_cap, 0},
+{NULL, NULL, 0},
+};
+
+static struct rw_sensor_template rw_cap_attrs[] = {
+{POWER_CAP_NAME, show_cap, set_cap, 0},
+{NULL, NULL, NULL, 0},
+};
+
+static struct rw_sensor_template trip_attrs[] = {
+{"power1_average_min", show_val, set_trip, 7},
+{"power1_average_max", show_val, set_trip, 8},
+{NULL, NULL, NULL, 0},
+};
+
+static struct ro_sensor_template misc_attrs[] = {
+{"name", show_name, 0},
+{"power1_model_number", show_str, 0},
+{"power1_oem_info", show_str, 2},
+{"power1_serial_number", show_str, 1},
+{NULL, NULL, 0},
+};
+
+/* Read power domain data */
+static void remove_domain_devices(struct acpi_power_meter_resource *resource)
+{
+ int i;
+
+ if (!resource->num_domain_devices)
+ return;
+
+ for (i = 0; i < resource->num_domain_devices; i++) {
+ struct acpi_device *obj = resource->domain_devices[i];
+ if (!obj)
+ continue;
+
+ sysfs_remove_link(resource->holders_dir,
+ kobject_name(&obj->dev.kobj));
+ put_device(&obj->dev);
+ }
+
+ kfree(resource->domain_devices);
+ kobject_put(resource->holders_dir);
+}
+
+static int read_domain_devices(struct acpi_power_meter_resource *resource)
+{
+ int res = 0;
+ int i;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *pss;
+ acpi_status status;
+
+ status = acpi_evaluate_object(resource->acpi_dev->handle, "_PMD", NULL,
+ &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMD"));
+ return -ENODEV;
+ }
+
+ pss = buffer.pointer;
+ if (!pss ||
+ pss->type != ACPI_TYPE_PACKAGE) {
+ dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME
+ "Invalid _PMD data\n");
+ res = -EFAULT;
+ goto end;
+ }
+
+ if (!pss->package.count)
+ goto end;
+
+ resource->domain_devices = kzalloc(sizeof(struct acpi_device *) *
+ pss->package.count, GFP_KERNEL);
+ if (!resource->domain_devices) {
+ res = -ENOMEM;
+ goto end;
+ }
+
+ resource->holders_dir = kobject_create_and_add("measures",
+ &resource->acpi_dev->dev.kobj);
+ if (!resource->holders_dir) {
+ res = -ENOMEM;
+ goto exit_free;
+ }
+
+ resource->num_domain_devices = pss->package.count;
+
+ for (i = 0; i < pss->package.count; i++) {
+ struct acpi_device *obj;
+ union acpi_object *element = &(pss->package.elements[i]);
+
+ /* Refuse non-references */
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
+ continue;
+
+ /* Create a symlink to domain objects */
+ resource->domain_devices[i] = NULL;
+ status = acpi_bus_get_device(element->reference.handle,
+ &resource->domain_devices[i]);
+ if (ACPI_FAILURE(status))
+ continue;
+
+ obj = resource->domain_devices[i];
+ get_device(&obj->dev);
+
+ res = sysfs_create_link(resource->holders_dir, &obj->dev.kobj,
+ kobject_name(&obj->dev.kobj));
+ if (res) {
+ put_device(&obj->dev);
+ resource->domain_devices[i] = NULL;
+ }
+ }
+
+ res = 0;
+ goto end;
+
+exit_free:
+ kfree(resource->domain_devices);
+end:
+ kfree(buffer.pointer);
+ return res;
+}
+
+/* Registration and deregistration */
+static int register_ro_attrs(struct acpi_power_meter_resource *resource,
+ struct ro_sensor_template *ro)
+{
+ struct device *dev = &resource->acpi_dev->dev;
+ struct sensor_device_attribute *sensors =
+ &resource->sensors[resource->num_sensors];
+ int res = 0;
+
+ while (ro->label) {
+ sensors->dev_attr.attr.name = ro->label;
+ sensors->dev_attr.attr.mode = S_IRUGO;
+ sensors->dev_attr.show = ro->show;
+ sensors->index = ro->index;
+
+ res = device_create_file(dev, &sensors->dev_attr);
+ if (res) {
+ sensors->dev_attr.attr.name = NULL;
+ goto error;
+ }
+ sensors++;
+ resource->num_sensors++;
+ ro++;
+ }
+
+error:
+ return res;
+}
+
+static int register_rw_attrs(struct acpi_power_meter_resource *resource,
+ struct rw_sensor_template *rw)
+{
+ struct device *dev = &resource->acpi_dev->dev;
+ struct sensor_device_attribute *sensors =
+ &resource->sensors[resource->num_sensors];
+ int res = 0;
+
+ while (rw->label) {
+ sensors->dev_attr.attr.name = rw->label;
+ sensors->dev_attr.attr.mode = S_IRUGO | S_IWUSR;
+ sensors->dev_attr.show = rw->show;
+ sensors->dev_attr.store = rw->set;
+ sensors->index = rw->index;
+
+ res = device_create_file(dev, &sensors->dev_attr);
+ if (res) {
+ sensors->dev_attr.attr.name = NULL;
+ goto error;
+ }
+ sensors++;
+ resource->num_sensors++;
+ rw++;
+ }
+
+error:
+ return res;
+}
+
+static void remove_attrs(struct acpi_power_meter_resource *resource)
+{
+ int i;
+
+ for (i = 0; i < resource->num_sensors; i++) {
+ if (!resource->sensors[i].dev_attr.attr.name)
+ continue;
+ device_remove_file(&resource->acpi_dev->dev,
+ &resource->sensors[i].dev_attr);
+ }
+
+ remove_domain_devices(resource);
+
+ resource->num_sensors = 0;
+}
+
+static int setup_attrs(struct acpi_power_meter_resource *resource)
+{
+ int res = 0;
+
+ res = read_domain_devices(resource);
+ if (res)
+ return res;
+
+ if (resource->caps.flags & POWER_METER_CAN_MEASURE) {
+ res = register_ro_attrs(resource, meter_ro_attrs);
+ if (res)
+ goto error;
+ res = register_rw_attrs(resource, meter_rw_attrs);
+ if (res)
+ goto error;
+ }
+
+ if (resource->caps.flags & POWER_METER_CAN_CAP) {
+ if (!can_cap_in_hardware()) {
+ dev_err(&resource->acpi_dev->dev,
+ "Ignoring unsafe software power cap!\n");
+ goto skip_unsafe_cap;
+ }
+
+ if (resource->caps.configurable_cap) {
+ res = register_rw_attrs(resource, rw_cap_attrs);
+ if (res)
+ goto error;
+ } else {
+ res = register_ro_attrs(resource, ro_cap_attrs);
+ if (res)
+ goto error;
+ }
+ res = register_ro_attrs(resource, misc_cap_attrs);
+ if (res)
+ goto error;
+ }
+skip_unsafe_cap:
+
+ if (resource->caps.flags & POWER_METER_CAN_TRIP) {
+ res = register_rw_attrs(resource, trip_attrs);
+ if (res)
+ goto error;
+ }
+
+ res = register_ro_attrs(resource, misc_attrs);
+ if (res)
+ goto error;
+
+ return res;
+error:
+ remove_domain_devices(resource);
+ remove_attrs(resource);
+ return res;
+}
+
+static void free_capabilities(struct acpi_power_meter_resource *resource)
+{
+ acpi_string *str;
+ int i;
+
+ str = &resource->model_number;
+ for (i = 0; i < 3; i++, str++)
+ kfree(*str);
+}
+
+static int read_capabilities(struct acpi_power_meter_resource *resource)
+{
+ int res = 0;
+ int i;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_buffer state = { 0, NULL };
+ struct acpi_buffer format = { sizeof("NNNNNNNNNNN"), "NNNNNNNNNNN" };
+ union acpi_object *pss;
+ acpi_string *str;
+ acpi_status status;
+
+ status = acpi_evaluate_object(resource->acpi_dev->handle, "_PMC", NULL,
+ &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMC"));
+ return -ENODEV;
+ }
+
+ pss = buffer.pointer;
+ if (!pss ||
+ pss->type != ACPI_TYPE_PACKAGE ||
+ pss->package.count != 14) {
+ dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME
+ "Invalid _PMC data\n");
+ res = -EFAULT;
+ goto end;
+ }
+
+ /* Grab all the integer data at once */
+ state.length = sizeof(struct acpi_power_meter_capabilities);
+ state.pointer = &resource->caps;
+
+ status = acpi_extract_package(pss, &format, &state);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Invalid data"));
+ res = -EFAULT;
+ goto end;
+ }
+
+ if (resource->caps.units) {
+ dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME
+ "Unknown units %llu.\n",
+ resource->caps.units);
+ res = -EINVAL;
+ goto end;
+ }
+
+ /* Grab the string data */
+ str = &resource->model_number;
+
+ for (i = 11; i < 14; i++) {
+ union acpi_object *element = &(pss->package.elements[i]);
+
+ if (element->type != ACPI_TYPE_STRING) {
+ res = -EINVAL;
+ goto error;
+ }
+
+ *str = kzalloc(sizeof(u8) * (element->string.length + 1),
+ GFP_KERNEL);
+ if (!*str) {
+ res = -ENOMEM;
+ goto error;
+ }
+
+ strncpy(*str, element->string.pointer, element->string.length);
+ str++;
+ }
+
+ dev_info(&resource->acpi_dev->dev, "Found ACPI power meter.\n");
+ goto end;
+error:
+ str = &resource->model_number;
+ for (i = 0; i < 3; i++, str++)
+ kfree(*str);
+end:
+ kfree(buffer.pointer);
+ return res;
+}
+
+/* Handle ACPI event notifications */
+static void acpi_power_meter_notify(struct acpi_device *device, u32 event)
+{
+ struct acpi_power_meter_resource *resource;
+ int res;
+
+ if (!device || !acpi_driver_data(device))
+ return;
+
+ resource = acpi_driver_data(device);
+
+ mutex_lock(&resource->lock);
+ switch (event) {
+ case METER_NOTIFY_CONFIG:
+ free_capabilities(resource);
+ res = read_capabilities(resource);
+ if (res)
+ break;
+
+ remove_attrs(resource);
+ setup_attrs(resource);
+ break;
+ case METER_NOTIFY_TRIP:
+ sysfs_notify(&device->dev.kobj, NULL, POWER_AVERAGE_NAME);
+ update_meter(resource);
+ break;
+ case METER_NOTIFY_CAP:
+ sysfs_notify(&device->dev.kobj, NULL, POWER_CAP_NAME);
+ update_cap(resource);
+ break;
+ case METER_NOTIFY_INTERVAL:
+ sysfs_notify(&device->dev.kobj, NULL, POWER_AVG_INTERVAL_NAME);
+ update_avg_interval(resource);
+ break;
+ case METER_NOTIFY_CAPPING:
+ sysfs_notify(&device->dev.kobj, NULL, POWER_ALARM_NAME);
+ dev_info(&device->dev, "Capping in progress.\n");
+ break;
+ default:
+ BUG();
+ }
+ mutex_unlock(&resource->lock);
+
+ acpi_bus_generate_netlink_event(ACPI_POWER_METER_CLASS,
+ dev_name(&device->dev), event, 0);
+}
+
+static int acpi_power_meter_add(struct acpi_device *device)
+{
+ int res;
+ struct acpi_power_meter_resource *resource;
+
+ if (!device)
+ return -EINVAL;
+
+ resource = kzalloc(sizeof(struct acpi_power_meter_resource),
+ GFP_KERNEL);
+ if (!resource)
+ return -ENOMEM;
+
+ resource->sensors_valid = 0;
+ resource->acpi_dev = device;
+ mutex_init(&resource->lock);
+ strcpy(acpi_device_name(device), ACPI_POWER_METER_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_POWER_METER_CLASS);
+ device->driver_data = resource;
+
+ free_capabilities(resource);
+ res = read_capabilities(resource);
+ if (res)
+ goto exit_free;
+
+ resource->trip[0] = resource->trip[1] = -1;
+
+ res = setup_attrs(resource);
+ if (res)
+ goto exit_free;
+
+ resource->hwmon_dev = hwmon_device_register(&device->dev);
+ if (IS_ERR(resource->hwmon_dev)) {
+ res = PTR_ERR(resource->hwmon_dev);
+ goto exit_remove;
+ }
+
+ res = 0;
+ goto exit;
+
+exit_remove:
+ remove_attrs(resource);
+exit_free:
+ kfree(resource);
+exit:
+ return res;
+}
+
+static int acpi_power_meter_remove(struct acpi_device *device, int type)
+{
+ struct acpi_power_meter_resource *resource;
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+
+ resource = acpi_driver_data(device);
+ hwmon_device_unregister(resource->hwmon_dev);
+
+ free_capabilities(resource);
+ remove_attrs(resource);
+
+ kfree(resource);
+ return 0;
+}
+
+static int acpi_power_meter_resume(struct acpi_device *device)
+{
+ struct acpi_power_meter_resource *resource;
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+
+ resource = acpi_driver_data(device);
+ free_capabilities(resource);
+ read_capabilities(resource);
+
+ return 0;
+}
+
+static struct acpi_driver acpi_power_meter_driver = {
+ .name = "power_meter",
+ .class = ACPI_POWER_METER_CLASS,
+ .ids = power_meter_ids,
+ .ops = {
+ .add = acpi_power_meter_add,
+ .remove = acpi_power_meter_remove,
+ .resume = acpi_power_meter_resume,
+ .notify = acpi_power_meter_notify,
+ },
+};
+
+/* Module init/exit routines */
+static int __init enable_cap_knobs(const struct dmi_system_id *d)
+{
+ cap_in_hardware = 1;
+ return 0;
+}
+
+static struct dmi_system_id __initdata pm_dmi_table[] = {
+ {
+ enable_cap_knobs, "IBM Active Energy Manager",
+ {
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM")
+ },
+ },
+ {}
+};
+
+static int __init acpi_power_meter_init(void)
+{
+ int result;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ dmi_check_system(pm_dmi_table);
+
+ result = acpi_bus_register_driver(&acpi_power_meter_driver);
+ if (result < 0)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void __exit acpi_power_meter_exit(void)
+{
+ acpi_bus_unregister_driver(&acpi_power_meter_driver);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_DESCRIPTION("ACPI 4.0 power meter driver");
+MODULE_LICENSE("GPL");
+
+module_param(force_cap_on, bool, 0644);
+MODULE_PARM_DESC(force_cap_on, "Enable power cap even it is unsafe to do so.");
+
+module_init(acpi_power_meter_init);
+module_exit(acpi_power_meter_exit);
diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c
index d0d550d22a6d..d0d25e2e1ced 100644
--- a/drivers/acpi/proc.c
+++ b/drivers/acpi/proc.c
@@ -393,11 +393,13 @@ acpi_system_write_wakeup_device(struct file *file,
struct list_head *node, *next;
char strbuf[5];
char str[5] = "";
- int len = count;
+ unsigned int len = count;
struct acpi_device *found_dev = NULL;
if (len > 4)
len = 4;
+ if (len < 0)
+ return -EFAULT;
if (copy_from_user(strbuf, buffer, len))
return -EFAULT;
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 2cc4b3033872..ec742a4e5635 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -59,6 +59,8 @@
#include <acpi/acpi_drivers.h>
#include <acpi/processor.h>
+#define PREFIX "ACPI: "
+
#define ACPI_PROCESSOR_CLASS "processor"
#define ACPI_PROCESSOR_DEVICE_NAME "Processor"
#define ACPI_PROCESSOR_FILE_INFO "info"
@@ -79,9 +81,10 @@ MODULE_DESCRIPTION("ACPI Processor Driver");
MODULE_LICENSE("GPL");
static int acpi_processor_add(struct acpi_device *device);
-static int acpi_processor_start(struct acpi_device *device);
static int acpi_processor_remove(struct acpi_device *device, int type);
+#ifdef CONFIG_ACPI_PROCFS
static int acpi_processor_info_open_fs(struct inode *inode, struct file *file);
+#endif
static void acpi_processor_notify(struct acpi_device *device, u32 event);
static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
static int acpi_processor_handle_eject(struct acpi_processor *pr);
@@ -101,7 +104,6 @@ static struct acpi_driver acpi_processor_driver = {
.ops = {
.add = acpi_processor_add,
.remove = acpi_processor_remove,
- .start = acpi_processor_start,
.suspend = acpi_processor_suspend,
.resume = acpi_processor_resume,
.notify = acpi_processor_notify,
@@ -110,7 +112,7 @@ static struct acpi_driver acpi_processor_driver = {
#define INSTALL_NOTIFY_HANDLER 1
#define UNINSTALL_NOTIFY_HANDLER 2
-
+#ifdef CONFIG_ACPI_PROCFS
static const struct file_operations acpi_processor_info_fops = {
.owner = THIS_MODULE,
.open = acpi_processor_info_open_fs,
@@ -118,6 +120,7 @@ static const struct file_operations acpi_processor_info_fops = {
.llseek = seq_lseek,
.release = single_release,
};
+#endif
DEFINE_PER_CPU(struct acpi_processor *, processors);
struct acpi_processor_errata errata __read_mostly;
@@ -316,6 +319,7 @@ static int acpi_processor_set_pdc(struct acpi_processor *pr)
FS Interface (/proc)
-------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
static struct proc_dir_entry *acpi_processor_dir = NULL;
static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset)
@@ -388,7 +392,6 @@ static int acpi_processor_add_fs(struct acpi_device *device)
return -EIO;
return 0;
}
-
static int acpi_processor_remove_fs(struct acpi_device *device)
{
@@ -405,6 +408,16 @@ static int acpi_processor_remove_fs(struct acpi_device *device)
return 0;
}
+#else
+static inline int acpi_processor_add_fs(struct acpi_device *device)
+{
+ return 0;
+}
+static inline int acpi_processor_remove_fs(struct acpi_device *device)
+{
+ return 0;
+}
+#endif
/* Use the acpiid in MADT to map cpus in case of SMP */
@@ -698,92 +711,6 @@ static int acpi_processor_get_info(struct acpi_device *device)
static DEFINE_PER_CPU(void *, processor_device_array);
-static int __cpuinit acpi_processor_start(struct acpi_device *device)
-{
- int result = 0;
- struct acpi_processor *pr;
- struct sys_device *sysdev;
-
- pr = acpi_driver_data(device);
-
- result = acpi_processor_get_info(device);
- if (result) {
- /* Processor is physically not present */
- return 0;
- }
-
- BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0));
-
- /*
- * Buggy BIOS check
- * ACPI id of processors can be reported wrongly by the BIOS.
- * Don't trust it blindly
- */
- if (per_cpu(processor_device_array, pr->id) != NULL &&
- per_cpu(processor_device_array, pr->id) != device) {
- printk(KERN_WARNING "BIOS reported wrong ACPI id "
- "for the processor\n");
- return -ENODEV;
- }
- per_cpu(processor_device_array, pr->id) = device;
-
- per_cpu(processors, pr->id) = pr;
-
- result = acpi_processor_add_fs(device);
- if (result)
- goto end;
-
- sysdev = get_cpu_sysdev(pr->id);
- if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev"))
- return -EFAULT;
-
- /* _PDC call should be done before doing anything else (if reqd.). */
- arch_acpi_processor_init_pdc(pr);
- acpi_processor_set_pdc(pr);
- arch_acpi_processor_cleanup_pdc(pr);
-
-#ifdef CONFIG_CPU_FREQ
- acpi_processor_ppc_has_changed(pr);
-#endif
- acpi_processor_get_throttling_info(pr);
- acpi_processor_get_limit_info(pr);
-
-
- acpi_processor_power_init(pr, device);
-
- pr->cdev = thermal_cooling_device_register("Processor", device,
- &processor_cooling_ops);
- if (IS_ERR(pr->cdev)) {
- result = PTR_ERR(pr->cdev);
- goto end;
- }
-
- dev_info(&device->dev, "registered as cooling_device%d\n",
- pr->cdev->id);
-
- result = sysfs_create_link(&device->dev.kobj,
- &pr->cdev->device.kobj,
- "thermal_cooling");
- if (result)
- printk(KERN_ERR PREFIX "Create sysfs link\n");
- result = sysfs_create_link(&pr->cdev->device.kobj,
- &device->dev.kobj,
- "device");
- if (result)
- printk(KERN_ERR PREFIX "Create sysfs link\n");
-
- if (pr->flags.throttling) {
- printk(KERN_INFO PREFIX "%s [%s] (supports",
- acpi_device_name(device), acpi_device_bid(device));
- printk(" %d throttling states", pr->throttling.state_count);
- printk(")\n");
- }
-
- end:
-
- return result;
-}
-
static void acpi_processor_notify(struct acpi_device *device, u32 event)
{
struct acpi_processor *pr = acpi_driver_data(device);
@@ -843,13 +770,11 @@ static struct notifier_block acpi_cpu_notifier =
.notifier_call = acpi_cpu_soft_notify,
};
-static int acpi_processor_add(struct acpi_device *device)
+static int __cpuinit acpi_processor_add(struct acpi_device *device)
{
struct acpi_processor *pr = NULL;
-
-
- if (!device)
- return -EINVAL;
+ int result = 0;
+ struct sys_device *sysdev;
pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
if (!pr)
@@ -865,7 +790,93 @@ static int acpi_processor_add(struct acpi_device *device)
strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
device->driver_data = pr;
+ result = acpi_processor_get_info(device);
+ if (result) {
+ /* Processor is physically not present */
+ return 0;
+ }
+
+ BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0));
+
+ /*
+ * Buggy BIOS check
+ * ACPI id of processors can be reported wrongly by the BIOS.
+ * Don't trust it blindly
+ */
+ if (per_cpu(processor_device_array, pr->id) != NULL &&
+ per_cpu(processor_device_array, pr->id) != device) {
+ printk(KERN_WARNING "BIOS reported wrong ACPI id "
+ "for the processor\n");
+ result = -ENODEV;
+ goto err_free_cpumask;
+ }
+ per_cpu(processor_device_array, pr->id) = device;
+
+ per_cpu(processors, pr->id) = pr;
+
+ result = acpi_processor_add_fs(device);
+ if (result)
+ goto err_free_cpumask;
+
+ sysdev = get_cpu_sysdev(pr->id);
+ if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) {
+ result = -EFAULT;
+ goto err_remove_fs;
+ }
+
+ /* _PDC call should be done before doing anything else (if reqd.). */
+ arch_acpi_processor_init_pdc(pr);
+ acpi_processor_set_pdc(pr);
+ arch_acpi_processor_cleanup_pdc(pr);
+
+#ifdef CONFIG_CPU_FREQ
+ acpi_processor_ppc_has_changed(pr);
+#endif
+ acpi_processor_get_throttling_info(pr);
+ acpi_processor_get_limit_info(pr);
+
+
+ acpi_processor_power_init(pr, device);
+
+ pr->cdev = thermal_cooling_device_register("Processor", device,
+ &processor_cooling_ops);
+ if (IS_ERR(pr->cdev)) {
+ result = PTR_ERR(pr->cdev);
+ goto err_power_exit;
+ }
+
+ dev_info(&device->dev, "registered as cooling_device%d\n",
+ pr->cdev->id);
+
+ result = sysfs_create_link(&device->dev.kobj,
+ &pr->cdev->device.kobj,
+ "thermal_cooling");
+ if (result) {
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ goto err_thermal_unregister;
+ }
+ result = sysfs_create_link(&pr->cdev->device.kobj,
+ &device->dev.kobj,
+ "device");
+ if (result) {
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ goto err_remove_sysfs;
+ }
+
return 0;
+
+err_remove_sysfs:
+ sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+err_thermal_unregister:
+ thermal_cooling_device_unregister(pr->cdev);
+err_power_exit:
+ acpi_processor_power_exit(pr, device);
+err_remove_fs:
+ acpi_processor_remove_fs(device);
+err_free_cpumask:
+ free_cpumask_var(pr->throttling.shared_cpu_map);
+
+ return result;
}
static int acpi_processor_remove(struct acpi_device *device, int type)
@@ -942,7 +953,6 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
{
acpi_handle phandle;
struct acpi_device *pdev;
- struct acpi_processor *pr;
if (acpi_get_parent(handle, &phandle)) {
@@ -957,15 +967,6 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
return -ENODEV;
}
- acpi_bus_start(*device);
-
- pr = acpi_driver_data(*device);
- if (!pr)
- return -ENODEV;
-
- if ((pr->id >= 0) && (pr->id < nr_cpu_ids)) {
- kobject_uevent(&(*device)->dev.kobj, KOBJ_ONLINE);
- }
return 0;
}
@@ -995,25 +996,6 @@ static void __ref acpi_processor_hotplug_notify(acpi_handle handle,
"Unable to add the device\n");
break;
}
-
- pr = acpi_driver_data(device);
- if (!pr) {
- printk(KERN_ERR PREFIX "Driver data is NULL\n");
- break;
- }
-
- if (pr->id >= 0 && (pr->id < nr_cpu_ids)) {
- kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
- break;
- }
-
- result = acpi_processor_start(device);
- if ((!result) && ((pr->id >= 0) && (pr->id < nr_cpu_ids))) {
- kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
- } else {
- printk(KERN_ERR PREFIX "Device [%s] failed to start\n",
- acpi_device_bid(device));
- }
break;
case ACPI_NOTIFY_EJECT_REQUEST:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -1030,9 +1012,6 @@ static void __ref acpi_processor_hotplug_notify(acpi_handle handle,
"Driver data is NULL, dropping EJECT\n");
return;
}
-
- if ((pr->id < nr_cpu_ids) && (cpu_present(pr->id)))
- kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -1161,11 +1140,11 @@ static int __init acpi_processor_init(void)
(struct acpi_table_header **)&madt)))
madt = NULL;
#endif
-
+#ifdef CONFIG_ACPI_PROCFS
acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
if (!acpi_processor_dir)
return -ENOMEM;
-
+#endif
/*
* Check whether the system is DMI table. If yes, OSPM
* should not use mwait for CPU-states.
@@ -1193,7 +1172,9 @@ out_cpuidle:
cpuidle_unregister_driver(&acpi_idle_driver);
out_proc:
+#ifdef CONFIG_ACPI_PROCFS
remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+#endif
return result;
}
@@ -1213,7 +1194,9 @@ static void __exit acpi_processor_exit(void)
cpuidle_unregister_driver(&acpi_idle_driver);
+#ifdef CONFIG_ACPI_PROCFS
remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+#endif
return;
}
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 66393d5c4c7c..bbd066e7f854 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -60,6 +60,8 @@
#include <acpi/processor.h>
#include <asm/processor.h>
+#define PREFIX "ACPI: "
+
#define ACPI_PROCESSOR_CLASS "processor"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_idle");
@@ -680,6 +682,7 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr)
return 0;
}
+#ifdef CONFIG_ACPI_PROCFS
static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_processor *pr = seq->private;
@@ -759,7 +762,7 @@ static const struct file_operations acpi_processor_power_fops = {
.llseek = seq_lseek,
.release = single_release,
};
-
+#endif
/**
* acpi_idle_bm_check - checks if bus master activity was detected
@@ -1160,8 +1163,9 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
{
acpi_status status = 0;
static int first_run;
+#ifdef CONFIG_ACPI_PROCFS
struct proc_dir_entry *entry = NULL;
- unsigned int i;
+#endif
if (boot_option_idle_override)
return 0;
@@ -1209,15 +1213,8 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
acpi_processor_setup_cpuidle(pr);
if (cpuidle_register_device(&pr->power.dev))
return -EIO;
-
- printk(KERN_INFO PREFIX "CPU%d (power states:", pr->id);
- for (i = 1; i <= pr->power.count; i++)
- if (pr->power.states[i].valid)
- printk(" C%d[C%d]", i,
- pr->power.states[i].type);
- printk(")\n");
}
-
+#ifdef CONFIG_ACPI_PROCFS
/* 'power' [R] */
entry = proc_create_data(ACPI_PROCESSOR_FILE_POWER,
S_IRUGO, acpi_device_dir(device),
@@ -1225,6 +1222,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
acpi_driver_data(device));
if (!entry)
return -EIO;
+#endif
return 0;
}
@@ -1237,9 +1235,11 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
cpuidle_unregister_device(&pr->power.dev);
pr->flags.power_setup_done = 0;
+#ifdef CONFIG_ACPI_PROCFS
if (acpi_device_dir(device))
remove_proc_entry(ACPI_PROCESSOR_FILE_POWER,
acpi_device_dir(device));
+#endif
return 0;
}
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 60e543d3234e..8ba0ed0b9ddb 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -39,6 +39,8 @@
#include <acpi/acpi_drivers.h>
#include <acpi/processor.h>
+#define PREFIX "ACPI: "
+
#define ACPI_PROCESSOR_CLASS "processor"
#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
@@ -509,7 +511,7 @@ int acpi_processor_preregister_performance(
struct acpi_processor *match_pr;
struct acpi_psd_package *match_pdomain;
- if (!alloc_cpumask_var(&covered_cpus, GFP_KERNEL))
+ if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))
return -ENOMEM;
mutex_lock(&performance_mutex);
@@ -556,7 +558,6 @@ int acpi_processor_preregister_performance(
* Now that we have _PSD data from all CPUs, lets setup P-state
* domain info.
*/
- cpumask_clear(covered_cpus);
for_each_possible_cpu(i) {
pr = per_cpu(processors, i);
if (!pr)
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 31adda1099e0..140c5c5b423c 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -40,6 +40,8 @@
#include <acpi/processor.h>
#include <acpi/acpi_drivers.h>
+#define PREFIX "ACPI: "
+
#define ACPI_PROCESSOR_CLASS "processor"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_thermal");
@@ -438,7 +440,7 @@ struct thermal_cooling_device_ops processor_cooling_ops = {
};
/* /proc interface */
-
+#ifdef CONFIG_ACPI_PROCFS
static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_processor *pr = (struct acpi_processor *)seq->private;
@@ -517,3 +519,4 @@ const struct file_operations acpi_processor_limit_fops = {
.llseek = seq_lseek,
.release = single_release,
};
+#endif
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index ae39797aab55..1c5d7a8b2fdf 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -41,6 +41,8 @@
#include <acpi/acpi_drivers.h>
#include <acpi/processor.h>
+#define PREFIX "ACPI: "
+
#define ACPI_PROCESSOR_CLASS "processor"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_throttling");
@@ -75,7 +77,7 @@ static int acpi_processor_update_tsd_coord(void)
struct acpi_tsd_package *pdomain, *match_pdomain;
struct acpi_processor_throttling *pthrottling, *match_pthrottling;
- if (!alloc_cpumask_var(&covered_cpus, GFP_KERNEL))
+ if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))
return -ENOMEM;
/*
@@ -103,7 +105,6 @@ static int acpi_processor_update_tsd_coord(void)
if (retval)
goto err_ret;
- cpumask_clear(covered_cpus);
for_each_possible_cpu(i) {
pr = per_cpu(processors, i);
if (!pr)
@@ -1132,15 +1133,15 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
int result = 0;
struct acpi_processor_throttling *pthrottling;
+ if (!pr)
+ return -EINVAL;
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
pr->throttling.address,
pr->throttling.duty_offset,
pr->throttling.duty_width));
- if (!pr)
- return -EINVAL;
-
/*
* Evaluate _PTC, _TSS and _TPC
* They must all be present or none of them can be used.
@@ -1216,7 +1217,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
}
/* proc interface */
-
+#ifdef CONFIG_ACPI_PROCFS
static int acpi_processor_throttling_seq_show(struct seq_file *seq,
void *offset)
{
@@ -1324,3 +1325,4 @@ const struct file_operations acpi_processor_throttling_fops = {
.llseek = seq_lseek,
.release = single_release,
};
+#endif
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 4b214b74ebaa..52b9db8afc20 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -46,6 +46,8 @@
#include "sbshc.h"
+#define PREFIX "ACPI: "
+
#define ACPI_SBS_CLASS "sbs"
#define ACPI_AC_CLASS "ac_adapter"
#define ACPI_BATTERY_CLASS "battery"
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index 0619734895b2..d9339806df45 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -15,6 +15,8 @@
#include <linux/interrupt.h>
#include "sbshc.h"
+#define PREFIX "ACPI: "
+
#define ACPI_SMB_HC_CLASS "smbus_host_controller"
#define ACPI_SMB_HC_DEVICE_NAME "ACPI SMBus HC"
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 781435d7e369..14a7481c97d7 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -22,6 +22,8 @@ extern struct acpi_device *acpi_root;
#define ACPI_BUS_HID "LNXSYBUS"
#define ACPI_BUS_DEVICE_NAME "System Bus"
+#define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent)
+
static LIST_HEAD(acpi_device_list);
static LIST_HEAD(acpi_bus_id_list);
DEFINE_MUTEX(acpi_device_lock);
@@ -43,40 +45,19 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
{
int len;
int count;
-
- if (!acpi_dev->flags.hardware_id && !acpi_dev->flags.compatible_ids)
- return -ENODEV;
+ struct acpi_hardware_id *id;
len = snprintf(modalias, size, "acpi:");
size -= len;
- if (acpi_dev->flags.hardware_id) {
- count = snprintf(&modalias[len], size, "%s:",
- acpi_dev->pnp.hardware_id);
+ list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
+ count = snprintf(&modalias[len], size, "%s:", id->id);
if (count < 0 || count >= size)
return -EINVAL;
len += count;
size -= count;
}
- if (acpi_dev->flags.compatible_ids) {
- struct acpi_compatible_id_list *cid_list;
- int i;
-
- cid_list = acpi_dev->pnp.cid_list;
- for (i = 0; i < cid_list->count; i++) {
- count = snprintf(&modalias[len], size, "%s:",
- cid_list->id[i].value);
- if (count < 0 || count >= size) {
- printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size",
- acpi_dev->pnp.device_name, i);
- break;
- }
- len += count;
- size -= count;
- }
- }
-
modalias[len] = '\0';
return len;
}
@@ -183,7 +164,7 @@ static ssize_t
acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
struct acpi_device *acpi_dev = to_acpi_device(dev);
- return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id);
+ return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev));
}
static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
@@ -219,17 +200,13 @@ static int acpi_device_setup_files(struct acpi_device *dev)
goto end;
}
- if (dev->flags.hardware_id) {
- result = device_create_file(&dev->dev, &dev_attr_hid);
- if (result)
- goto end;
- }
+ result = device_create_file(&dev->dev, &dev_attr_hid);
+ if (result)
+ goto end;
- if (dev->flags.hardware_id || dev->flags.compatible_ids) {
- result = device_create_file(&dev->dev, &dev_attr_modalias);
- if (result)
- goto end;
- }
+ result = device_create_file(&dev->dev, &dev_attr_modalias);
+ if (result)
+ goto end;
/*
* If device has _EJ0, 'eject' file is created that is used to trigger
@@ -255,11 +232,8 @@ static void acpi_device_remove_files(struct acpi_device *dev)
if (ACPI_SUCCESS(status))
device_remove_file(&dev->dev, &dev_attr_eject);
- if (dev->flags.hardware_id || dev->flags.compatible_ids)
- device_remove_file(&dev->dev, &dev_attr_modalias);
-
- if (dev->flags.hardware_id)
- device_remove_file(&dev->dev, &dev_attr_hid);
+ device_remove_file(&dev->dev, &dev_attr_modalias);
+ device_remove_file(&dev->dev, &dev_attr_hid);
if (dev->handle)
device_remove_file(&dev->dev, &dev_attr_path);
}
@@ -271,6 +245,7 @@ int acpi_match_device_ids(struct acpi_device *device,
const struct acpi_device_id *ids)
{
const struct acpi_device_id *id;
+ struct acpi_hardware_id *hwid;
/*
* If the device is not present, it is unnecessary to load device
@@ -279,36 +254,30 @@ int acpi_match_device_ids(struct acpi_device *device,
if (!device->status.present)
return -ENODEV;
- if (device->flags.hardware_id) {
- for (id = ids; id->id[0]; id++) {
- if (!strcmp((char*)id->id, device->pnp.hardware_id))
+ for (id = ids; id->id[0]; id++)
+ list_for_each_entry(hwid, &device->pnp.ids, list)
+ if (!strcmp((char *) id->id, hwid->id))
return 0;
- }
- }
-
- if (device->flags.compatible_ids) {
- struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
- int i;
-
- for (id = ids; id->id[0]; id++) {
- /* compare multiple _CID entries against driver ids */
- for (i = 0; i < cid_list->count; i++) {
- if (!strcmp((char*)id->id,
- cid_list->id[i].value))
- return 0;
- }
- }
- }
return -ENOENT;
}
EXPORT_SYMBOL(acpi_match_device_ids);
+static void acpi_free_ids(struct acpi_device *device)
+{
+ struct acpi_hardware_id *id, *tmp;
+
+ list_for_each_entry_safe(id, tmp, &device->pnp.ids, list) {
+ kfree(id->id);
+ kfree(id);
+ }
+}
+
static void acpi_device_release(struct device *dev)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
- kfree(acpi_dev->pnp.cid_list);
+ acpi_free_ids(acpi_dev);
kfree(acpi_dev);
}
@@ -366,22 +335,21 @@ static acpi_status acpi_device_notify_fixed(void *data)
{
struct acpi_device *device = data;
- acpi_device_notify(device->handle, ACPI_FIXED_HARDWARE_EVENT, device);
+ /* Fixed hardware devices have no handles */
+ acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device);
return AE_OK;
}
static int acpi_device_install_notify_handler(struct acpi_device *device)
{
acpi_status status;
- char *hid;
- hid = acpi_device_hid(device);
- if (!strcmp(hid, ACPI_BUTTON_HID_POWERF))
+ if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
status =
acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
acpi_device_notify_fixed,
device);
- else if (!strcmp(hid, ACPI_BUTTON_HID_SLEEPF))
+ else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
status =
acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
acpi_device_notify_fixed,
@@ -399,10 +367,10 @@ static int acpi_device_install_notify_handler(struct acpi_device *device)
static void acpi_device_remove_notify_handler(struct acpi_device *device)
{
- if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF))
+ if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
acpi_device_notify_fixed);
- else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF))
+ else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
acpi_device_notify_fixed);
else
@@ -426,9 +394,6 @@ static int acpi_device_probe(struct device * dev)
if (acpi_drv->ops.notify) {
ret = acpi_device_install_notify_handler(acpi_dev);
if (ret) {
- if (acpi_drv->ops.stop)
- acpi_drv->ops.stop(acpi_dev,
- acpi_dev->removal_type);
if (acpi_drv->ops.remove)
acpi_drv->ops.remove(acpi_dev,
acpi_dev->removal_type);
@@ -452,8 +417,6 @@ static int acpi_device_remove(struct device * dev)
if (acpi_drv) {
if (acpi_drv->ops.notify)
acpi_device_remove_notify_handler(acpi_dev);
- if (acpi_drv->ops.stop)
- acpi_drv->ops.stop(acpi_dev, acpi_dev->removal_type);
if (acpi_drv->ops.remove)
acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
}
@@ -474,12 +437,12 @@ struct bus_type acpi_bus_type = {
.uevent = acpi_device_uevent,
};
-static int acpi_device_register(struct acpi_device *device,
- struct acpi_device *parent)
+static int acpi_device_register(struct acpi_device *device)
{
int result;
struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
int found = 0;
+
/*
* Linkage
* -------
@@ -501,8 +464,9 @@ static int acpi_device_register(struct acpi_device *device,
* If failed, create one and link it into acpi_bus_id_list
*/
list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
- if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "device")) {
- acpi_device_bus_id->instance_no ++;
+ if (!strcmp(acpi_device_bus_id->bus_id,
+ acpi_device_hid(device))) {
+ acpi_device_bus_id->instance_no++;
found = 1;
kfree(new_bus_id);
break;
@@ -510,7 +474,7 @@ static int acpi_device_register(struct acpi_device *device,
}
if (!found) {
acpi_device_bus_id = new_bus_id;
- strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device");
+ strcpy(acpi_device_bus_id->bus_id, acpi_device_hid(device));
acpi_device_bus_id->instance_no = 0;
list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
}
@@ -524,7 +488,7 @@ static int acpi_device_register(struct acpi_device *device,
mutex_unlock(&acpi_device_lock);
if (device->parent)
- device->dev.parent = &parent->dev;
+ device->dev.parent = &device->parent->dev;
device->dev.bus = &acpi_bus_type;
device->dev.release = &acpi_device_release;
result = device_register(&device->dev);
@@ -664,6 +628,33 @@ EXPORT_SYMBOL(acpi_bus_unregister_driver);
/* --------------------------------------------------------------------------
Device Enumeration
-------------------------------------------------------------------------- */
+static struct acpi_device *acpi_bus_get_parent(acpi_handle handle)
+{
+ acpi_status status;
+ int ret;
+ struct acpi_device *device;
+
+ /*
+ * Fixed hardware devices do not appear in the namespace and do not
+ * have handles, but we fabricate acpi_devices for them, so we have
+ * to deal with them specially.
+ */
+ if (handle == NULL)
+ return acpi_root;
+
+ do {
+ status = acpi_get_parent(handle, &handle);
+ if (status == AE_NULL_ENTRY)
+ return NULL;
+ if (ACPI_FAILURE(status))
+ return acpi_root;
+
+ ret = acpi_bus_get_device(handle, &device);
+ if (ret == 0)
+ return device;
+ } while (1);
+}
+
acpi_status
acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
{
@@ -687,7 +678,7 @@ acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
}
EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
-void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
+void acpi_bus_data_handler(acpi_handle handle, void *context)
{
/* TBD */
@@ -781,6 +772,7 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
kfree(buffer.pointer);
device->wakeup.flags.valid = 1;
+ device->wakeup.prepare_count = 0;
/* Call _PSW/_DSW object to disable its ability to wake the sleeping
* system for the ACPI device with the _PRW object.
* The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
@@ -875,11 +867,6 @@ static int acpi_bus_get_flags(struct acpi_device *device)
if (ACPI_SUCCESS(status))
device->flags.dynamic_status = 1;
- /* Presence of _CID indicates 'compatible_ids' */
- status = acpi_get_handle(device->handle, "_CID", &temp);
- if (ACPI_SUCCESS(status))
- device->flags.compatible_ids = 1;
-
/* Presence of _RMV indicates 'removable' */
status = acpi_get_handle(device->handle, "_RMV", &temp);
if (ACPI_SUCCESS(status))
@@ -917,8 +904,7 @@ static int acpi_bus_get_flags(struct acpi_device *device)
return 0;
}
-static void acpi_device_get_busid(struct acpi_device *device,
- acpi_handle handle, int type)
+static void acpi_device_get_busid(struct acpi_device *device)
{
char bus_id[5] = { '?', 0 };
struct acpi_buffer buffer = { sizeof(bus_id), bus_id };
@@ -930,10 +916,12 @@ static void acpi_device_get_busid(struct acpi_device *device,
* The device's Bus ID is simply the object name.
* TBD: Shouldn't this value be unique (within the ACPI namespace)?
*/
- switch (type) {
- case ACPI_BUS_TYPE_SYSTEM:
+ if (ACPI_IS_ROOT_DEVICE(device)) {
strcpy(device->pnp.bus_id, "ACPI");
- break;
+ return;
+ }
+
+ switch (device->device_type) {
case ACPI_BUS_TYPE_POWER_BUTTON:
strcpy(device->pnp.bus_id, "PWRF");
break;
@@ -941,7 +929,7 @@ static void acpi_device_get_busid(struct acpi_device *device,
strcpy(device->pnp.bus_id, "SLPF");
break;
default:
- acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
+ acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer);
/* Clean up trailing underscores (if any) */
for (i = 3; i > 1; i--) {
if (bus_id[i] == '_')
@@ -999,157 +987,134 @@ static int acpi_dock_match(struct acpi_device *device)
return acpi_get_handle(device->handle, "_DCK", &tmp);
}
-static void acpi_device_set_id(struct acpi_device *device,
- struct acpi_device *parent, acpi_handle handle,
- int type)
+char *acpi_device_hid(struct acpi_device *device)
+{
+ struct acpi_hardware_id *hid;
+
+ hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list);
+ return hid->id;
+}
+EXPORT_SYMBOL(acpi_device_hid);
+
+static void acpi_add_id(struct acpi_device *device, const char *dev_id)
+{
+ struct acpi_hardware_id *id;
+
+ id = kmalloc(sizeof(*id), GFP_KERNEL);
+ if (!id)
+ return;
+
+ id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL);
+ if (!id->id) {
+ kfree(id);
+ return;
+ }
+
+ strcpy(id->id, dev_id);
+ list_add_tail(&id->list, &device->pnp.ids);
+}
+
+static void acpi_device_set_id(struct acpi_device *device)
{
- struct acpi_device_info *info;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- char *hid = NULL;
- char *uid = NULL;
- struct acpi_compatible_id_list *cid_list = NULL;
- const char *cid_add = NULL;
acpi_status status;
+ struct acpi_device_info *info;
+ struct acpica_device_id_list *cid_list;
+ int i;
- switch (type) {
+ switch (device->device_type) {
case ACPI_BUS_TYPE_DEVICE:
- status = acpi_get_object_info(handle, &buffer);
+ if (ACPI_IS_ROOT_DEVICE(device)) {
+ acpi_add_id(device, ACPI_SYSTEM_HID);
+ break;
+ } else if (ACPI_IS_ROOT_DEVICE(device->parent)) {
+ /* \_SB_, the only root-level namespace device */
+ acpi_add_id(device, ACPI_BUS_HID);
+ strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
+ strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
+ break;
+ }
+
+ status = acpi_get_object_info(device->handle, &info);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__);
return;
}
- info = buffer.pointer;
if (info->valid & ACPI_VALID_HID)
- hid = info->hardware_id.value;
- if (info->valid & ACPI_VALID_UID)
- uid = info->unique_id.value;
- if (info->valid & ACPI_VALID_CID)
- cid_list = &info->compatibility_id;
+ acpi_add_id(device, info->hardware_id.string);
+ if (info->valid & ACPI_VALID_CID) {
+ cid_list = &info->compatible_id_list;
+ for (i = 0; i < cid_list->count; i++)
+ acpi_add_id(device, cid_list->ids[i].string);
+ }
if (info->valid & ACPI_VALID_ADR) {
device->pnp.bus_address = info->address;
device->flags.bus_address = 1;
}
- /* If we have a video/bay/dock device, add our selfdefined
- HID to the CID list. Like that the video/bay/dock drivers
- will get autoloaded and the device might still match
- against another driver.
- */
+ kfree(info);
+
+ /*
+ * Some devices don't reliably have _HIDs & _CIDs, so add
+ * synthetic HIDs to make sure drivers can find them.
+ */
if (acpi_is_video_device(device))
- cid_add = ACPI_VIDEO_HID;
+ acpi_add_id(device, ACPI_VIDEO_HID);
else if (ACPI_SUCCESS(acpi_bay_match(device)))
- cid_add = ACPI_BAY_HID;
+ acpi_add_id(device, ACPI_BAY_HID);
else if (ACPI_SUCCESS(acpi_dock_match(device)))
- cid_add = ACPI_DOCK_HID;
+ acpi_add_id(device, ACPI_DOCK_HID);
break;
case ACPI_BUS_TYPE_POWER:
- hid = ACPI_POWER_HID;
+ acpi_add_id(device, ACPI_POWER_HID);
break;
case ACPI_BUS_TYPE_PROCESSOR:
- hid = ACPI_PROCESSOR_OBJECT_HID;
- break;
- case ACPI_BUS_TYPE_SYSTEM:
- hid = ACPI_SYSTEM_HID;
+ acpi_add_id(device, ACPI_PROCESSOR_OBJECT_HID);
break;
case ACPI_BUS_TYPE_THERMAL:
- hid = ACPI_THERMAL_HID;
+ acpi_add_id(device, ACPI_THERMAL_HID);
break;
case ACPI_BUS_TYPE_POWER_BUTTON:
- hid = ACPI_BUTTON_HID_POWERF;
+ acpi_add_id(device, ACPI_BUTTON_HID_POWERF);
break;
case ACPI_BUS_TYPE_SLEEP_BUTTON:
- hid = ACPI_BUTTON_HID_SLEEPF;
+ acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF);
break;
}
/*
- * \_SB
- * ----
- * Fix for the system root bus device -- the only root-level device.
+ * We build acpi_devices for some objects that don't have _HID or _CID,
+ * e.g., PCI bridges and slots. Drivers can't bind to these objects,
+ * but we do use them indirectly by traversing the acpi_device tree.
+ * This generic ID isn't useful for driver binding, but it provides
+ * the useful property that "every acpi_device has an ID."
*/
- if (((acpi_handle)parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) {
- hid = ACPI_BUS_HID;
- strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
- strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
- }
-
- if (hid) {
- strcpy(device->pnp.hardware_id, hid);
- device->flags.hardware_id = 1;
- }
- if (uid) {
- strcpy(device->pnp.unique_id, uid);
- device->flags.unique_id = 1;
- }
- if (cid_list || cid_add) {
- struct acpi_compatible_id_list *list;
- int size = 0;
- int count = 0;
-
- if (cid_list) {
- size = cid_list->size;
- } else if (cid_add) {
- size = sizeof(struct acpi_compatible_id_list);
- cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size);
- if (!cid_list) {
- printk(KERN_ERR "Memory allocation error\n");
- kfree(buffer.pointer);
- return;
- } else {
- cid_list->count = 0;
- cid_list->size = size;
- }
- }
- if (cid_add)
- size += sizeof(struct acpi_compatible_id);
- list = kmalloc(size, GFP_KERNEL);
-
- if (list) {
- if (cid_list) {
- memcpy(list, cid_list, cid_list->size);
- count = cid_list->count;
- }
- if (cid_add) {
- strncpy(list->id[count].value, cid_add,
- ACPI_MAX_CID_LENGTH);
- count++;
- device->flags.compatible_ids = 1;
- }
- list->size = size;
- list->count = count;
- device->pnp.cid_list = list;
- } else
- printk(KERN_ERR PREFIX "Memory allocation error\n");
- }
-
- kfree(buffer.pointer);
+ if (list_empty(&device->pnp.ids))
+ acpi_add_id(device, "device");
}
-static int acpi_device_set_context(struct acpi_device *device, int type)
+static int acpi_device_set_context(struct acpi_device *device)
{
- acpi_status status = AE_OK;
- int result = 0;
+ acpi_status status;
+
/*
* Context
* -------
* Attach this 'struct acpi_device' to the ACPI object. This makes
- * resolutions from handle->device very efficient. Note that we need
- * to be careful with fixed-feature devices as they all attach to the
- * root object.
+ * resolutions from handle->device very efficient. Fixed hardware
+ * devices have no handles, so we skip them.
*/
- if (type != ACPI_BUS_TYPE_POWER_BUTTON &&
- type != ACPI_BUS_TYPE_SLEEP_BUTTON) {
- status = acpi_attach_data(device->handle,
- acpi_bus_data_handler, device);
+ if (!device->handle)
+ return 0;
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Error attaching device data\n");
- result = -ENODEV;
- }
- }
- return result;
+ status = acpi_attach_data(device->handle,
+ acpi_bus_data_handler, device);
+ if (ACPI_SUCCESS(status))
+ return 0;
+
+ printk(KERN_ERR PREFIX "Error attaching device data\n");
+ return -ENODEV;
}
static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
@@ -1175,17 +1140,14 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
return 0;
}
-static int
-acpi_add_single_object(struct acpi_device **child,
- struct acpi_device *parent, acpi_handle handle, int type,
- struct acpi_bus_ops *ops)
+static int acpi_add_single_object(struct acpi_device **child,
+ acpi_handle handle, int type,
+ unsigned long long sta,
+ struct acpi_bus_ops *ops)
{
- int result = 0;
- struct acpi_device *device = NULL;
-
-
- if (!child)
- return -EINVAL;
+ int result;
+ struct acpi_device *device;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL);
if (!device) {
@@ -1193,85 +1155,31 @@ acpi_add_single_object(struct acpi_device **child,
return -ENOMEM;
}
+ INIT_LIST_HEAD(&device->pnp.ids);
+ device->device_type = type;
device->handle = handle;
- device->parent = parent;
+ device->parent = acpi_bus_get_parent(handle);
device->bus_ops = *ops; /* workround for not call .start */
+ STRUCT_TO_INT(device->status) = sta;
-
- acpi_device_get_busid(device, handle, type);
+ acpi_device_get_busid(device);
/*
* Flags
* -----
- * Get prior to calling acpi_bus_get_status() so we know whether
- * or not _STA is present. Note that we only look for object
- * handles -- cannot evaluate objects until we know the device is
- * present and properly initialized.
+ * Note that we only look for object handles -- cannot evaluate objects
+ * until we know the device is present and properly initialized.
*/
result = acpi_bus_get_flags(device);
if (result)
goto end;
/*
- * Status
- * ------
- * See if the device is present. We always assume that non-Device
- * and non-Processor objects (e.g. thermal zones, power resources,
- * etc.) are present, functioning, etc. (at least when parent object
- * is present). Note that _STA has a different meaning for some
- * objects (e.g. power resources) so we need to be careful how we use
- * it.
- */
- switch (type) {
- case ACPI_BUS_TYPE_PROCESSOR:
- case ACPI_BUS_TYPE_DEVICE:
- result = acpi_bus_get_status(device);
- if (ACPI_FAILURE(result)) {
- result = -ENODEV;
- goto end;
- }
- /*
- * When the device is neither present nor functional, the
- * device should not be added to Linux ACPI device tree.
- * When the status of the device is not present but functinal,
- * it should be added to Linux ACPI tree. For example : bay
- * device , dock device.
- * In such conditions it is unncessary to check whether it is
- * bay device or dock device.
- */
- if (!device->status.present && !device->status.functional) {
- result = -ENODEV;
- goto end;
- }
- break;
- default:
- STRUCT_TO_INT(device->status) =
- ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
- ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
- break;
- }
-
- /*
* Initialize Device
* -----------------
* TBD: Synch with Core's enumeration/initialization process.
*/
-
- /*
- * Hardware ID, Unique ID, & Bus Address
- * -------------------------------------
- */
- acpi_device_set_id(device, parent, handle, type);
-
- /*
- * The ACPI device is attached to acpi handle before getting
- * the power/wakeup/peformance flags. Otherwise OS can't get
- * the corresponding ACPI device by the acpi handle in the course
- * of getting the power/wakeup/performance flags.
- */
- result = acpi_device_set_context(device, type);
- if (result)
- goto end;
+ acpi_device_set_id(device);
/*
* Power Management
@@ -1303,8 +1211,10 @@ acpi_add_single_object(struct acpi_device **child,
goto end;
}
+ if ((result = acpi_device_set_context(device)))
+ goto end;
- result = acpi_device_register(device, parent);
+ result = acpi_device_register(device);
/*
* Bind _ADR-Based Devices when hot add
@@ -1315,130 +1225,117 @@ acpi_add_single_object(struct acpi_device **child,
}
end:
- if (!result)
+ if (!result) {
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Adding %s [%s] parent %s\n", dev_name(&device->dev),
+ (char *) buffer.pointer,
+ device->parent ? dev_name(&device->parent->dev) :
+ "(null)"));
+ kfree(buffer.pointer);
*child = device;
- else {
- kfree(device->pnp.cid_list);
- kfree(device);
- }
+ } else
+ acpi_device_release(&device->dev);
return result;
}
-static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops)
-{
- acpi_status status = AE_OK;
- struct acpi_device *parent = NULL;
- struct acpi_device *child = NULL;
- acpi_handle phandle = NULL;
- acpi_handle chandle = NULL;
- acpi_object_type type = 0;
- u32 level = 1;
+#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \
+ ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING)
+static int acpi_bus_type_and_status(acpi_handle handle, int *type,
+ unsigned long long *sta)
+{
+ acpi_status status;
+ acpi_object_type acpi_type;
- if (!start)
- return -EINVAL;
-
- parent = start;
- phandle = start->handle;
+ status = acpi_get_type(handle, &acpi_type);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
- /*
- * Parse through the ACPI namespace, identify all 'devices', and
- * create a new 'struct acpi_device' for each.
- */
- while ((level > 0) && parent) {
+ switch (acpi_type) {
+ case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */
+ case ACPI_TYPE_DEVICE:
+ *type = ACPI_BUS_TYPE_DEVICE;
+ status = acpi_bus_get_status_handle(handle, sta);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+ break;
+ case ACPI_TYPE_PROCESSOR:
+ *type = ACPI_BUS_TYPE_PROCESSOR;
+ status = acpi_bus_get_status_handle(handle, sta);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+ break;
+ case ACPI_TYPE_THERMAL:
+ *type = ACPI_BUS_TYPE_THERMAL;
+ *sta = ACPI_STA_DEFAULT;
+ break;
+ case ACPI_TYPE_POWER:
+ *type = ACPI_BUS_TYPE_POWER;
+ *sta = ACPI_STA_DEFAULT;
+ break;
+ default:
+ return -ENODEV;
+ }
- status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
- chandle, &chandle);
+ return 0;
+}
- /*
- * If this scope is exhausted then move our way back up.
- */
- if (ACPI_FAILURE(status)) {
- level--;
- chandle = phandle;
- acpi_get_parent(phandle, &phandle);
- if (parent->parent)
- parent = parent->parent;
- continue;
- }
+static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl,
+ void *context, void **return_value)
+{
+ struct acpi_bus_ops *ops = context;
+ int type;
+ unsigned long long sta;
+ struct acpi_device *device;
+ acpi_status status;
+ int result;
- status = acpi_get_type(chandle, &type);
- if (ACPI_FAILURE(status))
- continue;
+ result = acpi_bus_type_and_status(handle, &type, &sta);
+ if (result)
+ return AE_OK;
- /*
- * If this is a scope object then parse it (depth-first).
- */
- if (type == ACPI_TYPE_LOCAL_SCOPE) {
- level++;
- phandle = chandle;
- chandle = NULL;
- continue;
- }
+ if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
+ !(sta & ACPI_STA_DEVICE_FUNCTIONING))
+ return AE_CTRL_DEPTH;
- /*
- * We're only interested in objects that we consider 'devices'.
- */
- switch (type) {
- case ACPI_TYPE_DEVICE:
- type = ACPI_BUS_TYPE_DEVICE;
- break;
- case ACPI_TYPE_PROCESSOR:
- type = ACPI_BUS_TYPE_PROCESSOR;
- break;
- case ACPI_TYPE_THERMAL:
- type = ACPI_BUS_TYPE_THERMAL;
- break;
- case ACPI_TYPE_POWER:
- type = ACPI_BUS_TYPE_POWER;
- break;
- default:
- continue;
- }
+ /*
+ * We may already have an acpi_device from a previous enumeration. If
+ * so, we needn't add it again, but we may still have to start it.
+ */
+ device = NULL;
+ acpi_bus_get_device(handle, &device);
+ if (ops->acpi_op_add && !device)
+ acpi_add_single_object(&device, handle, type, sta, ops);
- if (ops->acpi_op_add)
- status = acpi_add_single_object(&child, parent,
- chandle, type, ops);
- else
- status = acpi_bus_get_device(chandle, &child);
+ if (!device)
+ return AE_CTRL_DEPTH;
+ if (ops->acpi_op_start && !(ops->acpi_op_add)) {
+ status = acpi_start_single_object(device);
if (ACPI_FAILURE(status))
- continue;
+ return AE_CTRL_DEPTH;
+ }
- if (ops->acpi_op_start && !(ops->acpi_op_add)) {
- status = acpi_start_single_object(child);
- if (ACPI_FAILURE(status))
- continue;
- }
+ if (!*return_value)
+ *return_value = device;
+ return AE_OK;
+}
- /*
- * If the device is present, enabled, and functioning then
- * parse its scope (depth-first). Note that we need to
- * represent absent devices to facilitate PnP notifications
- * -- but only the subtree head (not all of its children,
- * which will be enumerated when the parent is inserted).
- *
- * TBD: Need notifications and other detection mechanisms
- * in place before we can fully implement this.
- */
- /*
- * When the device is not present but functional, it is also
- * necessary to scan the children of this device.
- */
- if (child->status.present || (!child->status.present &&
- child->status.functional)) {
- status = acpi_get_next_object(ACPI_TYPE_ANY, chandle,
- NULL, NULL);
- if (ACPI_SUCCESS(status)) {
- level++;
- phandle = chandle;
- chandle = NULL;
- parent = child;
- }
- }
- }
+static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops,
+ struct acpi_device **child)
+{
+ acpi_status status;
+ void *device = NULL;
+
+ status = acpi_bus_check_add(handle, 0, ops, &device);
+ if (ACPI_SUCCESS(status))
+ acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+ acpi_bus_check_add, ops, &device);
+ if (child)
+ *child = device;
return 0;
}
@@ -1446,36 +1343,25 @@ int
acpi_bus_add(struct acpi_device **child,
struct acpi_device *parent, acpi_handle handle, int type)
{
- int result;
struct acpi_bus_ops ops;
memset(&ops, 0, sizeof(ops));
ops.acpi_op_add = 1;
- result = acpi_add_single_object(child, parent, handle, type, &ops);
- if (!result)
- result = acpi_bus_scan(*child, &ops);
-
- return result;
+ acpi_bus_scan(handle, &ops, child);
+ return 0;
}
EXPORT_SYMBOL(acpi_bus_add);
int acpi_bus_start(struct acpi_device *device)
{
- int result;
struct acpi_bus_ops ops;
+ memset(&ops, 0, sizeof(ops));
+ ops.acpi_op_start = 1;
- if (!device)
- return -EINVAL;
-
- result = acpi_start_single_object(device);
- if (!result) {
- memset(&ops, 0, sizeof(ops));
- ops.acpi_op_start = 1;
- result = acpi_bus_scan(device, &ops);
- }
- return result;
+ acpi_bus_scan(device->handle, &ops, NULL);
+ return 0;
}
EXPORT_SYMBOL(acpi_bus_start);
@@ -1534,15 +1420,12 @@ int acpi_bus_trim(struct acpi_device *start, int rmdevice)
}
EXPORT_SYMBOL_GPL(acpi_bus_trim);
-static int acpi_bus_scan_fixed(struct acpi_device *root)
+static int acpi_bus_scan_fixed(void)
{
int result = 0;
struct acpi_device *device = NULL;
struct acpi_bus_ops ops;
- if (!root)
- return -ENODEV;
-
memset(&ops, 0, sizeof(ops));
ops.acpi_op_add = 1;
ops.acpi_op_start = 1;
@@ -1551,16 +1434,16 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
* Enumerate all fixed-feature devices.
*/
if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) {
- result = acpi_add_single_object(&device, acpi_root,
- NULL,
+ result = acpi_add_single_object(&device, NULL,
ACPI_BUS_TYPE_POWER_BUTTON,
+ ACPI_STA_DEFAULT,
&ops);
}
if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
- result = acpi_add_single_object(&device, acpi_root,
- NULL,
+ result = acpi_add_single_object(&device, NULL,
ACPI_BUS_TYPE_SLEEP_BUTTON,
+ ACPI_STA_DEFAULT,
&ops);
}
@@ -1583,24 +1466,15 @@ int __init acpi_scan_init(void)
}
/*
- * Create the root device in the bus's device tree
- */
- result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT,
- ACPI_BUS_TYPE_SYSTEM, &ops);
- if (result)
- goto Done;
-
- /*
* Enumerate devices in the ACPI namespace.
*/
- result = acpi_bus_scan_fixed(acpi_root);
+ result = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root);
if (!result)
- result = acpi_bus_scan(acpi_root, &ops);
+ result = acpi_bus_scan_fixed();
if (result)
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
-Done:
return result;
}
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 42159a28f433..5f2c379ab7bf 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -405,6 +405,46 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
},
},
{
+ .callback = init_set_sci_en_on_resume,
+ .ident = "Hewlett-Packard HP Pavilion dv3 Notebook PC",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv3 Notebook PC"),
+ },
+ },
+ {
+ .callback = init_set_sci_en_on_resume,
+ .ident = "Hewlett-Packard Pavilion dv4",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4"),
+ },
+ },
+ {
+ .callback = init_set_sci_en_on_resume,
+ .ident = "Hewlett-Packard Pavilion dv7",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv7"),
+ },
+ },
+ {
+ .callback = init_set_sci_en_on_resume,
+ .ident = "Hewlett-Packard Compaq Presario C700 Notebook PC",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Compaq Presario C700 Notebook PC"),
+ },
+ },
+ {
+ .callback = init_set_sci_en_on_resume,
+ .ident = "Hewlett-Packard Compaq Presario CQ40 Notebook PC",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Compaq Presario CQ40 Notebook PC"),
+ },
+ },
+ {
.callback = init_old_suspend_ordering,
.ident = "Panasonic CF51-2L",
.matches = {
@@ -689,19 +729,25 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
{
acpi_handle handle;
struct acpi_device *adev;
+ int error;
- if (!device_may_wakeup(dev))
+ if (!device_can_wakeup(dev))
return -EINVAL;
handle = DEVICE_ACPI_HANDLE(dev);
if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
- printk(KERN_DEBUG "ACPI handle has no context!\n");
+ dev_dbg(dev, "ACPI handle has no context in %s!\n", __func__);
return -ENODEV;
}
- return enable ?
+ error = enable ?
acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) :
acpi_disable_wakeup_device_power(adev);
+ if (!error)
+ dev_info(dev, "wake-up capability %s by ACPI\n",
+ enable ? "enabled" : "disabled");
+
+ return error;
}
#endif
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 9c61ab2177cf..d11282975f35 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -31,6 +31,8 @@
#include <acpi/acpi_drivers.h>
+#define PREFIX "ACPI: "
+
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("system");
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 646d39c031ca..f336bca7c450 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -213,6 +213,9 @@ acpi_table_parse_entries(char *id,
unsigned long table_end;
acpi_size tbl_size;
+ if (acpi_disabled)
+ return -ENODEV;
+
if (!handler)
return -EINVAL;
@@ -277,6 +280,9 @@ int __init acpi_table_parse(char *id, acpi_table_handler handler)
struct acpi_table_header *table = NULL;
acpi_size tbl_size;
+ if (acpi_disabled)
+ return -ENODEV;
+
if (!handler)
return -EINVAL;
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 564ea1424288..65f67815902a 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -47,6 +47,8 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#define PREFIX "ACPI: "
+
#define ACPI_THERMAL_CLASS "thermal_zone"
#define ACPI_THERMAL_DEVICE_NAME "Thermal Zone"
#define ACPI_THERMAL_FILE_STATE "state"
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index f844941089bb..811fec10462b 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -30,6 +30,8 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#include "internal.h"
+
#define _COMPONENT ACPI_BUS_COMPONENT
ACPI_MODULE_NAME("utils");
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 60ea984c84a0..05dff631591c 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -40,10 +40,12 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <asm/uaccess.h>
-
+#include <linux/dmi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#define PREFIX "ACPI: "
+
#define ACPI_VIDEO_CLASS "video"
#define ACPI_VIDEO_BUS_NAME "Video Bus"
#define ACPI_VIDEO_DEVICE_NAME "Video Device"
@@ -198,7 +200,7 @@ struct acpi_video_device {
struct acpi_device *dev;
struct acpi_video_device_brightness *brightness;
struct backlight_device *backlight;
- struct thermal_cooling_device *cdev;
+ struct thermal_cooling_device *cooling_dev;
struct output_device *output_dev;
};
@@ -283,7 +285,7 @@ static int acpi_video_device_brightness_open_fs(struct inode *inode,
struct file *file);
static ssize_t acpi_video_device_write_brightness(struct file *file,
const char __user *buffer, size_t count, loff_t *data);
-static struct file_operations acpi_video_device_brightness_fops = {
+static const struct file_operations acpi_video_device_brightness_fops = {
.owner = THIS_MODULE,
.open = acpi_video_device_brightness_open_fs,
.read = seq_read,
@@ -387,20 +389,20 @@ static struct output_properties acpi_output_properties = {
/* thermal cooling device callbacks */
-static int video_get_max_state(struct thermal_cooling_device *cdev, unsigned
+static int video_get_max_state(struct thermal_cooling_device *cooling_dev, unsigned
long *state)
{
- struct acpi_device *device = cdev->devdata;
+ struct acpi_device *device = cooling_dev->devdata;
struct acpi_video_device *video = acpi_driver_data(device);
*state = video->brightness->count - 3;
return 0;
}
-static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned
+static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsigned
long *state)
{
- struct acpi_device *device = cdev->devdata;
+ struct acpi_device *device = cooling_dev->devdata;
struct acpi_video_device *video = acpi_driver_data(device);
unsigned long long level;
int offset;
@@ -417,9 +419,9 @@ static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned
}
static int
-video_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
+video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long state)
{
- struct acpi_device *device = cdev->devdata;
+ struct acpi_device *device = cooling_dev->devdata;
struct acpi_video_device *video = acpi_driver_data(device);
int level;
@@ -603,6 +605,7 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
unsigned long long *level)
{
acpi_status status = AE_OK;
+ int i;
if (device->cap._BQC || device->cap._BCQ) {
char *buf = device->cap._BQC ? "_BQC" : "_BCQ";
@@ -618,8 +621,15 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
}
*level += bqc_offset_aml_bug_workaround;
- device->brightness->curr = *level;
- return 0;
+ for (i = 2; i < device->brightness->count; i++)
+ if (device->brightness->levels[i] == *level) {
+ device->brightness->curr = *level;
+ return 0;
+ }
+ /* BQC returned an invalid level. Stop using it. */
+ ACPI_WARNING((AE_INFO, "%s returned an invalid level",
+ buf));
+ device->cap._BQC = device->cap._BCQ = 0;
} else {
/* Fixme:
* should we return an error or ignore this failure?
@@ -870,7 +880,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
br->flags._BCM_use_index = br->flags._BCL_use_index;
/* _BQC uses INDEX while _BCL uses VALUE in some laptops */
- br->curr = level_old = max_level;
+ br->curr = level = max_level;
if (!device->cap._BQC)
goto set_level;
@@ -892,15 +902,25 @@ acpi_video_init_brightness(struct acpi_video_device *device)
br->flags._BQC_use_index = (level == max_level ? 0 : 1);
- if (!br->flags._BQC_use_index)
+ if (!br->flags._BQC_use_index) {
+ /*
+ * Set the backlight to the initial state.
+ * On some buggy laptops, _BQC returns an uninitialized value
+ * when invoked for the first time, i.e. level_old is invalid.
+ * set the backlight to max_level in this case
+ */
+ for (i = 2; i < br->count; i++)
+ if (level_old == br->levels[i])
+ level = level_old;
goto set_level;
+ }
if (br->flags._BCL_reversed)
level_old = (br->count - 1) - level_old;
- level_old = br->levels[level_old];
+ level = br->levels[level_old];
set_level:
- result = acpi_video_device_lcd_set_level(device, level_old);
+ result = acpi_video_device_lcd_set_level(device, level);
if (result)
goto out_free_levels;
@@ -934,9 +954,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
{
acpi_handle h_dummy1;
-
- memset(&device->cap, 0, sizeof(device->cap));
-
if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) {
device->cap._ADR = 1;
}
@@ -990,19 +1007,29 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
if (result)
printk(KERN_ERR PREFIX "Create sysfs link\n");
- device->cdev = thermal_cooling_device_register("LCD",
+ device->cooling_dev = thermal_cooling_device_register("LCD",
device->dev, &video_cooling_ops);
- if (IS_ERR(device->cdev))
+ if (IS_ERR(device->cooling_dev)) {
+ /*
+ * Set cooling_dev to NULL so we don't crash trying to
+ * free it.
+ * Also, why the hell we are returning early and
+ * not attempt to register video output if cooling
+ * device registration failed?
+ * -- dtor
+ */
+ device->cooling_dev = NULL;
return;
+ }
dev_info(&device->dev->dev, "registered as cooling_device%d\n",
- device->cdev->id);
+ device->cooling_dev->id);
result = sysfs_create_link(&device->dev->dev.kobj,
- &device->cdev->device.kobj,
+ &device->cooling_dev->device.kobj,
"thermal_cooling");
if (result)
printk(KERN_ERR PREFIX "Create sysfs link\n");
- result = sysfs_create_link(&device->cdev->device.kobj,
+ result = sysfs_create_link(&device->cooling_dev->device.kobj,
&device->dev->dev.kobj, "device");
if (result)
printk(KERN_ERR PREFIX "Create sysfs link\n");
@@ -1039,7 +1066,6 @@ static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
{
acpi_handle h_dummy1;
- memset(&video->cap, 0, sizeof(video->cap));
if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) {
video->cap._DOS = 1;
}
@@ -1083,7 +1109,12 @@ static int acpi_video_bus_check(struct acpi_video_bus *video)
*/
/* Does this device support video switching? */
- if (video->cap._DOS) {
+ if (video->cap._DOS || video->cap._DOD) {
+ if (!video->cap._DOS) {
+ printk(KERN_WARNING FW_BUG
+ "ACPI(%s) defines _DOD but not _DOS\n",
+ acpi_device_bid(video->device));
+ }
video->flags.multihead = 1;
status = 0;
}
@@ -1192,7 +1223,7 @@ acpi_video_device_write_state(struct file *file,
u32 state = 0;
- if (!dev || count + 1 > sizeof str)
+ if (!dev || count >= sizeof(str))
return -EINVAL;
if (copy_from_user(str, buffer, count))
@@ -1249,7 +1280,7 @@ acpi_video_device_write_brightness(struct file *file,
int i;
- if (!dev || !dev->brightness || count + 1 > sizeof str)
+ if (!dev || !dev->brightness || count >= sizeof(str))
return -EINVAL;
if (copy_from_user(str, buffer, count))
@@ -1531,7 +1562,7 @@ acpi_video_bus_write_POST(struct file *file,
unsigned long long opt, options;
- if (!video || count + 1 > sizeof str)
+ if (!video || count >= sizeof(str))
return -EINVAL;
status = acpi_video_bus_POST_options(video, &options);
@@ -1571,7 +1602,7 @@ acpi_video_bus_write_DOS(struct file *file,
unsigned long opt;
- if (!video || count + 1 > sizeof str)
+ if (!video || count >= sizeof(str))
return -EINVAL;
if (copy_from_user(str, buffer, count))
@@ -1960,6 +1991,10 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event)
result = acpi_video_device_lcd_set_level(device, level_next);
+ if (!result)
+ backlight_force_update(device->backlight,
+ BACKLIGHT_UPDATE_HOTKEY);
+
out:
if (result)
printk(KERN_ERR PREFIX "Failed to switch the brightness\n");
@@ -2009,13 +2044,13 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
backlight_device_unregister(device->backlight);
device->backlight = NULL;
}
- if (device->cdev) {
+ if (device->cooling_dev) {
sysfs_remove_link(&device->dev->dev.kobj,
"thermal_cooling");
- sysfs_remove_link(&device->cdev->device.kobj,
+ sysfs_remove_link(&device->cooling_dev->device.kobj,
"device");
- thermal_cooling_device_unregister(device->cdev);
- device->cdev = NULL;
+ thermal_cooling_device_unregister(device->cooling_dev);
+ device->cooling_dev = NULL;
}
video_output_unregister(device->output_dev);
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 7cd2b63435ea..575593a8b4e6 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -38,6 +38,8 @@
#include <linux/dmi.h>
#include <linux/pci.h>
+#define PREFIX "ACPI: "
+
ACPI_MODULE_NAME("video");
#define _COMPONENT ACPI_VIDEO_COMPONENT
@@ -82,7 +84,7 @@ long acpi_is_video_device(struct acpi_device *device)
return 0;
/* Does this device able to support video switching ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) &&
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) ||
ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c
index 88725dcdf8bc..e0ee0c036f5a 100644
--- a/drivers/acpi/wakeup.c
+++ b/drivers/acpi/wakeup.c
@@ -68,7 +68,7 @@ void acpi_enable_wakeup_device(u8 sleep_state)
/* If users want to disable run-wake GPE,
* we only disable it for wake and leave it for runtime
*/
- if ((!dev->wakeup.state.enabled && !dev->wakeup.flags.prepared)
+ if ((!dev->wakeup.state.enabled && !dev->wakeup.prepare_count)
|| sleep_state > (u32) dev->wakeup.sleep_state) {
if (dev->wakeup.flags.run_wake) {
/* set_gpe_type will disable GPE, leave it like that */
@@ -100,7 +100,7 @@ void acpi_disable_wakeup_device(u8 sleep_state)
if (!dev->wakeup.flags.valid)
continue;
- if ((!dev->wakeup.state.enabled && !dev->wakeup.flags.prepared)
+ if ((!dev->wakeup.state.enabled && !dev->wakeup.prepare_count)
|| sleep_state > (u32) dev->wakeup.sleep_state) {
if (dev->wakeup.flags.run_wake) {
acpi_set_gpe_type(dev->wakeup.gpe_device,
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 246650673010..f60b2b6a0931 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -204,6 +204,7 @@ static void amba_device_release(struct device *dev)
int amba_device_register(struct amba_device *dev, struct resource *parent)
{
u32 pid, cid;
+ u32 size;
void __iomem *tmp;
int i, ret;
@@ -229,16 +230,25 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
if (ret)
goto err_out;
- tmp = ioremap(dev->res.start, SZ_4K);
+ /*
+ * Dynamically calculate the size of the resource
+ * and use this for iomap
+ */
+ size = resource_size(&dev->res);
+ tmp = ioremap(dev->res.start, size);
if (!tmp) {
ret = -ENOMEM;
goto err_release;
}
+ /*
+ * Read pid and cid based on size of resource
+ * they are located at end of region
+ */
for (pid = 0, i = 0; i < 4; i++)
- pid |= (readl(tmp + 0xfe0 + 4 * i) & 255) << (i * 8);
+ pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << (i * 8);
for (cid = 0, i = 0; i < 4; i++)
- cid |= (readl(tmp + 0xff0 + 4 * i) & 255) << (i * 8);
+ cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << (i * 8);
iounmap(tmp);
@@ -353,11 +363,14 @@ amba_find_device(const char *busid, struct device *parent, unsigned int id,
int amba_request_regions(struct amba_device *dev, const char *name)
{
int ret = 0;
+ u32 size;
if (!name)
name = dev->dev.driver->name;
- if (!request_mem_region(dev->res.start, SZ_4K, name))
+ size = resource_size(&dev->res);
+
+ if (!request_mem_region(dev->res.start, size, name))
ret = -EBUSY;
return ret;
@@ -371,7 +384,10 @@ int amba_request_regions(struct amba_device *dev, const char *name)
*/
void amba_release_regions(struct amba_device *dev)
{
- release_mem_region(dev->res.start, SZ_4K);
+ u32 size;
+
+ size = resource_size(&dev->res);
+ release_mem_region(dev->res.start, size);
}
EXPORT_SYMBOL(amba_driver_register);
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index ab2fa4eeb364..f2df6e2a224c 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -255,6 +255,15 @@ config PATA_ARTOP
If unsure, say N.
+config PATA_ATP867X
+ tristate "ARTOP/Acard ATP867X PATA support"
+ depends on PCI
+ help
+ This option enables support for ARTOP/Acard ATP867X PATA
+ controllers.
+
+ If unsure, say N.
+
config PATA_AT32
tristate "Atmel AVR32 PATA support (Experimental)"
depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 463eb52236aa..01e126f343b3 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_SATA_FSL) += sata_fsl.o
obj-$(CONFIG_PATA_ALI) += pata_ali.o
obj-$(CONFIG_PATA_AMD) += pata_amd.o
obj-$(CONFIG_PATA_ARTOP) += pata_artop.o
+obj-$(CONFIG_PATA_ATP867X) += pata_atp867x.o
obj-$(CONFIG_PATA_AT32) += pata_at32.o
obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o
obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index d4cd9c203314..a3241a1a710b 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -122,6 +122,7 @@ enum {
HOST_VERSION = 0x10, /* AHCI spec. version compliancy */
HOST_EM_LOC = 0x1c, /* Enclosure Management location */
HOST_EM_CTL = 0x20, /* Enclosure Management Control */
+ HOST_CAP2 = 0x24, /* host capabilities, extended */
/* HOST_CTL bits */
HOST_RESET = (1 << 0), /* reset controller; self-clear */
@@ -129,16 +130,29 @@ enum {
HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
/* HOST_CAP bits */
+ HOST_CAP_SXS = (1 << 5), /* Supports External SATA */
HOST_CAP_EMS = (1 << 6), /* Enclosure Management support */
- HOST_CAP_SSC = (1 << 14), /* Slumber capable */
+ HOST_CAP_CCC = (1 << 7), /* Command Completion Coalescing */
+ HOST_CAP_PART = (1 << 13), /* Partial state capable */
+ HOST_CAP_SSC = (1 << 14), /* Slumber state capable */
+ HOST_CAP_PIO_MULTI = (1 << 15), /* PIO multiple DRQ support */
+ HOST_CAP_FBS = (1 << 16), /* FIS-based switching support */
HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */
+ HOST_CAP_ONLY = (1 << 18), /* Supports AHCI mode only */
HOST_CAP_CLO = (1 << 24), /* Command List Override support */
+ HOST_CAP_LED = (1 << 25), /* Supports activity LED */
HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */
HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
+ HOST_CAP_MPS = (1 << 28), /* Mechanical presence switch */
HOST_CAP_SNTF = (1 << 29), /* SNotification register */
HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
+ /* HOST_CAP2 bits */
+ HOST_CAP2_BOH = (1 << 0), /* BIOS/OS handoff supported */
+ HOST_CAP2_NVMHCI = (1 << 1), /* NVMHCI supported */
+ HOST_CAP2_APST = (1 << 2), /* Automatic partial to slumber */
+
/* registers for each SATA port */
PORT_LST_ADDR = 0x00, /* command list DMA addr */
PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */
@@ -267,8 +281,10 @@ struct ahci_em_priv {
struct ahci_host_priv {
unsigned int flags; /* AHCI_HFLAG_* */
u32 cap; /* cap to use */
+ u32 cap2; /* cap2 to use */
u32 port_map; /* port map to use */
u32 saved_cap; /* saved initial cap */
+ u32 saved_cap2; /* saved initial cap2 */
u32 saved_port_map; /* saved initial port_map */
u32 em_loc; /* enclosure management location */
};
@@ -331,12 +347,15 @@ static void ahci_init_sw_activity(struct ata_link *link);
static ssize_t ahci_show_host_caps(struct device *dev,
struct device_attribute *attr, char *buf);
+static ssize_t ahci_show_host_cap2(struct device *dev,
+ struct device_attribute *attr, char *buf);
static ssize_t ahci_show_host_version(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t ahci_show_port_cmd(struct device *dev,
struct device_attribute *attr, char *buf);
DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
+DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
@@ -345,6 +364,7 @@ static struct device_attribute *ahci_shost_attrs[] = {
&dev_attr_em_message_type,
&dev_attr_em_message,
&dev_attr_ahci_host_caps,
+ &dev_attr_ahci_host_cap2,
&dev_attr_ahci_host_version,
&dev_attr_ahci_port_cmd,
NULL
@@ -447,7 +467,8 @@ static const struct ata_port_info ahci_port_info[] = {
[board_ahci_sb600] =
{
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
- AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255),
+ AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255 |
+ AHCI_HFLAG_32BIT_ONLY),
.flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
@@ -554,7 +575,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
/* AMD */
- { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD SB900 */
+ { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
/* AMD is using RAID class only for ahci controllers */
{ PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
@@ -584,6 +605,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_yesncq }, /* MCP67 */
{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_yesncq }, /* MCP67 */
{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_yesncq }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_yesncq }, /* Linux ID */
{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_yesncq }, /* MCP73 */
{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_yesncq }, /* MCP73 */
{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_yesncq }, /* MCP73 */
@@ -732,6 +754,16 @@ static ssize_t ahci_show_host_caps(struct device *dev,
return sprintf(buf, "%x\n", hpriv->cap);
}
+static ssize_t ahci_show_host_cap2(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
+ return sprintf(buf, "%x\n", hpriv->cap2);
+}
+
static ssize_t ahci_show_host_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -771,7 +803,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
struct ahci_host_priv *hpriv)
{
void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
- u32 cap, port_map;
+ u32 cap, cap2, vers, port_map;
int i;
int mv;
@@ -784,6 +816,14 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
+ /* CAP2 register is only defined for AHCI 1.2 and later */
+ vers = readl(mmio + HOST_VERSION);
+ if ((vers >> 16) > 1 ||
+ ((vers >> 16) == 1 && (vers & 0xFFFF) >= 0x200))
+ hpriv->saved_cap2 = cap2 = readl(mmio + HOST_CAP2);
+ else
+ hpriv->saved_cap2 = cap2 = 0;
+
/* some chips have errata preventing 64bit use */
if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
dev_printk(KERN_INFO, &pdev->dev,
@@ -869,6 +909,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
/* record values to use during operation */
hpriv->cap = cap;
+ hpriv->cap2 = cap2;
hpriv->port_map = port_map;
}
@@ -887,6 +928,8 @@ static void ahci_restore_initial_config(struct ata_host *host)
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
writel(hpriv->saved_cap, mmio + HOST_CAP);
+ if (hpriv->saved_cap2)
+ writel(hpriv->saved_cap2, mmio + HOST_CAP2);
writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
(void) readl(mmio + HOST_PORTS_IMPL); /* flush */
}
@@ -2534,13 +2577,14 @@ static void ahci_print_info(struct ata_host *host)
struct ahci_host_priv *hpriv = host->private_data;
struct pci_dev *pdev = to_pci_dev(host->dev);
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
- u32 vers, cap, impl, speed;
+ u32 vers, cap, cap2, impl, speed;
const char *speed_s;
u16 cc;
const char *scc_s;
vers = readl(mmio + HOST_VERSION);
cap = hpriv->cap;
+ cap2 = hpriv->cap2;
impl = hpriv->port_map;
speed = (cap >> 20) & 0xf;
@@ -2583,25 +2627,29 @@ static void ahci_print_info(struct ata_host *host)
"flags: "
"%s%s%s%s%s%s%s"
"%s%s%s%s%s%s%s"
- "%s\n"
+ "%s%s%s%s%s%s\n"
,
- cap & (1 << 31) ? "64bit " : "",
- cap & (1 << 30) ? "ncq " : "",
- cap & (1 << 29) ? "sntf " : "",
- cap & (1 << 28) ? "ilck " : "",
- cap & (1 << 27) ? "stag " : "",
- cap & (1 << 26) ? "pm " : "",
- cap & (1 << 25) ? "led " : "",
-
- cap & (1 << 24) ? "clo " : "",
- cap & (1 << 19) ? "nz " : "",
- cap & (1 << 18) ? "only " : "",
- cap & (1 << 17) ? "pmp " : "",
- cap & (1 << 15) ? "pio " : "",
- cap & (1 << 14) ? "slum " : "",
- cap & (1 << 13) ? "part " : "",
- cap & (1 << 6) ? "ems ": ""
+ cap & HOST_CAP_64 ? "64bit " : "",
+ cap & HOST_CAP_NCQ ? "ncq " : "",
+ cap & HOST_CAP_SNTF ? "sntf " : "",
+ cap & HOST_CAP_MPS ? "ilck " : "",
+ cap & HOST_CAP_SSS ? "stag " : "",
+ cap & HOST_CAP_ALPM ? "pm " : "",
+ cap & HOST_CAP_LED ? "led " : "",
+ cap & HOST_CAP_CLO ? "clo " : "",
+ cap & HOST_CAP_ONLY ? "only " : "",
+ cap & HOST_CAP_PMP ? "pmp " : "",
+ cap & HOST_CAP_FBS ? "fbs " : "",
+ cap & HOST_CAP_PIO_MULTI ? "pio " : "",
+ cap & HOST_CAP_SSC ? "slum " : "",
+ cap & HOST_CAP_PART ? "part " : "",
+ cap & HOST_CAP_CCC ? "ccc " : "",
+ cap & HOST_CAP_EMS ? "ems " : "",
+ cap & HOST_CAP_SXS ? "sxs " : "",
+ cap2 & HOST_CAP2_APST ? "apst " : "",
+ cap2 & HOST_CAP2_NVMHCI ? "nvmp " : "",
+ cap2 & HOST_CAP2_BOH ? "boh " : ""
);
}
@@ -2650,17 +2698,15 @@ static void ahci_p5wdh_workaround(struct ata_host *host)
}
}
-/*
- * SB600 ahci controller on certain boards can't do 64bit DMA with
- * older BIOS.
- */
-static bool ahci_sb600_32bit_only(struct pci_dev *pdev)
+/* only some SB600 ahci controllers can do 64bit DMA */
+static bool ahci_sb600_enable_64bit(struct pci_dev *pdev)
{
static const struct dmi_system_id sysids[] = {
/*
* The oldest version known to be broken is 0901 and
* working is 1501 which was released on 2007-10-26.
- * Force 32bit DMA on anything older than 1501.
+ * Enable 64bit DMA on 1501 and anything newer.
+ *
* Please read bko#9412 for more info.
*/
{
@@ -2673,46 +2719,57 @@ static bool ahci_sb600_32bit_only(struct pci_dev *pdev)
.driver_data = "20071026", /* yyyymmdd */
},
/*
- * It's yet unknown whether more recent BIOS fixes the
- * problem. Blacklist the whole board for the time
- * being. Please read the following thread for more
- * info.
+ * All BIOS versions for the MSI K9A2 Platinum (MS-7376)
+ * support 64bit DMA.
*
- * http://thread.gmane.org/gmane.linux.ide/42326
+ * BIOS versions earlier than 1.5 had the Manufacturer DMI
+ * fields as "MICRO-STAR INTERANTIONAL CO.,LTD".
+ * This spelling mistake was fixed in BIOS version 1.5, so
+ * 1.5 and later have the Manufacturer as
+ * "MICRO-STAR INTERNATIONAL CO.,LTD".
+ * So try to match on DMI_BOARD_VENDOR of "MICRO-STAR INTER".
+ *
+ * BIOS versions earlier than 1.9 had a Board Product Name
+ * DMI field of "MS-7376". This was changed to be
+ * "K9A2 Platinum (MS-7376)" in version 1.9, but we can still
+ * match on DMI_BOARD_NAME of "MS-7376".
*/
{
- .ident = "Gigabyte GA-MA69VM-S2",
+ .ident = "MSI K9A2 Platinum",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR,
- "Gigabyte Technology Co., Ltd."),
- DMI_MATCH(DMI_BOARD_NAME, "GA-MA69VM-S2"),
+ "MICRO-STAR INTER"),
+ DMI_MATCH(DMI_BOARD_NAME, "MS-7376"),
},
},
{ }
};
const struct dmi_system_id *match;
+ int year, month, date;
+ char buf[9];
match = dmi_first_match(sysids);
if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) ||
!match)
return false;
- if (match->driver_data) {
- int year, month, date;
- char buf[9];
-
- dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
- snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
+ if (!match->driver_data)
+ goto enable_64bit;
- if (strcmp(buf, match->driver_data) >= 0)
- return false;
+ dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
+ snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
+ if (strcmp(buf, match->driver_data) >= 0)
+ goto enable_64bit;
+ else {
dev_printk(KERN_WARNING, &pdev->dev, "%s: BIOS too old, "
"forcing 32bit DMA, update BIOS\n", match->ident);
- } else
- dev_printk(KERN_WARNING, &pdev->dev, "%s: this board can't "
- "do 64bit DMA, forcing 32bit\n", match->ident);
+ return false;
+ }
+enable_64bit:
+ dev_printk(KERN_WARNING, &pdev->dev, "%s: enabling 64bit DMA\n",
+ match->ident);
return true;
}
@@ -2858,6 +2915,55 @@ static bool ahci_broken_online(struct pci_dev *pdev)
return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
}
+#ifdef CONFIG_ATA_ACPI
+static void ahci_gtf_filter_workaround(struct ata_host *host)
+{
+ static const struct dmi_system_id sysids[] = {
+ /*
+ * Aspire 3810T issues a bunch of SATA enable commands
+ * via _GTF including an invalid one and one which is
+ * rejected by the device. Among the successful ones
+ * is FPDMA non-zero offset enable which when enabled
+ * only on the drive side leads to NCQ command
+ * failures. Filter it out.
+ */
+ {
+ .ident = "Aspire 3810T",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3810T"),
+ },
+ .driver_data = (void *)ATA_ACPI_FILTER_FPDMA_OFFSET,
+ },
+ { }
+ };
+ const struct dmi_system_id *dmi = dmi_first_match(sysids);
+ unsigned int filter;
+ int i;
+
+ if (!dmi)
+ return;
+
+ filter = (unsigned long)dmi->driver_data;
+ dev_printk(KERN_INFO, host->dev,
+ "applying extra ACPI _GTF filter 0x%x for %s\n",
+ filter, dmi->ident);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ struct ata_link *link;
+ struct ata_device *dev;
+
+ ata_for_each_link(link, ap, EDGE)
+ ata_for_each_dev(dev, link, ALL)
+ dev->gtf_filter |= filter;
+ }
+}
+#else
+static inline void ahci_gtf_filter_workaround(struct ata_host *host)
+{}
+#endif
+
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
@@ -2926,12 +3032,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
- /* apply sb600 32bit only quirk */
- if (ahci_sb600_32bit_only(pdev))
- hpriv->flags |= AHCI_HFLAG_32BIT_ONLY;
+ /* only some SB600s can do 64bit DMA */
+ if (ahci_sb600_enable_64bit(pdev))
+ hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
- if (!(hpriv->flags & AHCI_HFLAG_NO_MSI))
- pci_enable_msi(pdev);
+ if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
+ pci_intx(pdev, 1);
/* save initial config */
ahci_save_initial_config(pdev, hpriv);
@@ -3023,6 +3129,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* apply workaround for ASUS P5W DH Deluxe mainboard */
ahci_p5wdh_workaround(host);
+ /* apply gtf filter quirk */
+ ahci_gtf_filter_workaround(host);
+
/* initialize adapter */
rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
if (rc)
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 01964b6e6f6b..b0882cddfd4c 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -20,19 +20,9 @@
#include <acpi/acpi_bus.h>
-enum {
- ATA_ACPI_FILTER_SETXFER = 1 << 0,
- ATA_ACPI_FILTER_LOCK = 1 << 1,
- ATA_ACPI_FILTER_DIPM = 1 << 2,
-
- ATA_ACPI_FILTER_DEFAULT = ATA_ACPI_FILTER_SETXFER |
- ATA_ACPI_FILTER_LOCK |
- ATA_ACPI_FILTER_DIPM,
-};
-
-static unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT;
+unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT;
module_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644);
-MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock, 0x4=DIPM)");
+MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock, 0x4=DIPM, 0x8=FPDMA non-zero offset, 0x10=FPDMA DMA Setup FIS auto-activate)");
#define NO_PORT_MULT 0xffff
#define SATA_ADR(root, pmp) (((root) << 16) | (pmp))
@@ -613,10 +603,11 @@ static void ata_acpi_gtf_to_tf(struct ata_device *dev,
tf->command = gtf->tf[6]; /* 0x1f7 */
}
-static int ata_acpi_filter_tf(const struct ata_taskfile *tf,
+static int ata_acpi_filter_tf(struct ata_device *dev,
+ const struct ata_taskfile *tf,
const struct ata_taskfile *ptf)
{
- if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_SETXFER) {
+ if (dev->gtf_filter & ATA_ACPI_FILTER_SETXFER) {
/* libata doesn't use ACPI to configure transfer mode.
* It will only confuse device configuration. Skip.
*/
@@ -625,7 +616,7 @@ static int ata_acpi_filter_tf(const struct ata_taskfile *tf,
return 1;
}
- if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_LOCK) {
+ if (dev->gtf_filter & ATA_ACPI_FILTER_LOCK) {
/* BIOS writers, sorry but we don't wanna lock
* features unless the user explicitly said so.
*/
@@ -647,12 +638,23 @@ static int ata_acpi_filter_tf(const struct ata_taskfile *tf,
return 1;
}
- if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_DIPM) {
+ if (tf->command == ATA_CMD_SET_FEATURES &&
+ tf->feature == SETFEATURES_SATA_ENABLE) {
/* inhibit enabling DIPM */
- if (tf->command == ATA_CMD_SET_FEATURES &&
- tf->feature == SETFEATURES_SATA_ENABLE &&
+ if (dev->gtf_filter & ATA_ACPI_FILTER_DIPM &&
tf->nsect == SATA_DIPM)
return 1;
+
+ /* inhibit FPDMA non-zero offset */
+ if (dev->gtf_filter & ATA_ACPI_FILTER_FPDMA_OFFSET &&
+ (tf->nsect == SATA_FPDMA_OFFSET ||
+ tf->nsect == SATA_FPDMA_IN_ORDER))
+ return 1;
+
+ /* inhibit FPDMA auto activation */
+ if (dev->gtf_filter & ATA_ACPI_FILTER_FPDMA_AA &&
+ tf->nsect == SATA_FPDMA_AA)
+ return 1;
}
return 0;
@@ -704,7 +706,7 @@ static int ata_acpi_run_tf(struct ata_device *dev,
pptf = &ptf;
}
- if (!ata_acpi_filter_tf(&tf, pptf)) {
+ if (!ata_acpi_filter_tf(dev, &tf, pptf)) {
rtf = tf;
err_mask = ata_exec_internal(dev, &rtf, NULL,
DMA_NONE, NULL, 0, 0);
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index df31deac5c82..dc72690ed5db 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4919,10 +4919,11 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
*/
void ata_qc_free(struct ata_queued_cmd *qc)
{
- struct ata_port *ap = qc->ap;
+ struct ata_port *ap;
unsigned int tag;
WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
+ ap = qc->ap;
qc->flags = 0;
tag = qc->tag;
@@ -4934,11 +4935,13 @@ void ata_qc_free(struct ata_queued_cmd *qc)
void __ata_qc_complete(struct ata_queued_cmd *qc)
{
- struct ata_port *ap = qc->ap;
- struct ata_link *link = qc->dev->link;
+ struct ata_port *ap;
+ struct ata_link *link;
WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
WARN_ON_ONCE(!(qc->flags & ATA_QCFLAG_ACTIVE));
+ ap = qc->ap;
+ link = qc->dev->link;
if (likely(qc->flags & ATA_QCFLAG_DMAMAP))
ata_sg_clean(qc);
@@ -5024,20 +5027,22 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
struct ata_device *dev = qc->dev;
struct ata_eh_info *ehi = &dev->link->eh_info;
- WARN_ON_ONCE(ap->pflags & ATA_PFLAG_FROZEN);
-
if (unlikely(qc->err_mask))
qc->flags |= ATA_QCFLAG_FAILED;
if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
- if (!ata_tag_internal(qc->tag)) {
- /* always fill result TF for failed qc */
- fill_result_tf(qc);
+ /* always fill result TF for failed qc */
+ fill_result_tf(qc);
+
+ if (!ata_tag_internal(qc->tag))
ata_qc_schedule_eh(qc);
- return;
- }
+ else
+ __ata_qc_complete(qc);
+ return;
}
+ WARN_ON_ONCE(ap->pflags & ATA_PFLAG_FROZEN);
+
/* read result TF if requested */
if (qc->flags & ATA_QCFLAG_RESULT_TF)
fill_result_tf(qc);
@@ -5591,6 +5596,9 @@ void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
dev->link = link;
dev->devno = dev - link->device;
+#ifdef CONFIG_ATA_ACPI
+ dev->gtf_filter = ata_acpi_gtf_filter;
+#endif
ata_dev_init(dev);
}
}
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index a04488f0de88..bba2ae5df1c2 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2667,14 +2667,14 @@ int ata_eh_reset(struct ata_link *link, int classify,
dev->pio_mode = XFER_PIO_0;
dev->flags &= ~ATA_DFLAG_SLEEPING;
- if (!ata_phys_link_offline(ata_dev_phys_link(dev))) {
- /* apply class override */
- if (lflags & ATA_LFLAG_ASSUME_ATA)
- classes[dev->devno] = ATA_DEV_ATA;
- else if (lflags & ATA_LFLAG_ASSUME_SEMB)
- classes[dev->devno] = ATA_DEV_SEMB_UNSUP;
- } else
- classes[dev->devno] = ATA_DEV_NONE;
+ if (ata_phys_link_offline(ata_dev_phys_link(dev)))
+ continue;
+
+ /* apply class override */
+ if (lflags & ATA_LFLAG_ASSUME_ATA)
+ classes[dev->devno] = ATA_DEV_ATA;
+ else if (lflags & ATA_LFLAG_ASSUME_SEMB)
+ classes[dev->devno] = ATA_DEV_SEMB_UNSUP;
}
/* record current link speed */
@@ -2713,34 +2713,48 @@ int ata_eh_reset(struct ata_link *link, int classify,
ap->pflags &= ~ATA_PFLAG_EH_PENDING;
spin_unlock_irqrestore(link->ap->lock, flags);
- /* Make sure onlineness and classification result correspond.
+ /*
+ * Make sure onlineness and classification result correspond.
* Hotplug could have happened during reset and some
* controllers fail to wait while a drive is spinning up after
* being hotplugged causing misdetection. By cross checking
- * link onlineness and classification result, those conditions
- * can be reliably detected and retried.
+ * link on/offlineness and classification result, those
+ * conditions can be reliably detected and retried.
*/
nr_unknown = 0;
ata_for_each_dev(dev, link, ALL) {
- /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
- if (classes[dev->devno] == ATA_DEV_UNKNOWN) {
- classes[dev->devno] = ATA_DEV_NONE;
- if (ata_phys_link_online(ata_dev_phys_link(dev)))
+ if (ata_phys_link_online(ata_dev_phys_link(dev))) {
+ if (classes[dev->devno] == ATA_DEV_UNKNOWN) {
+ ata_dev_printk(dev, KERN_DEBUG, "link online "
+ "but device misclassifed\n");
+ classes[dev->devno] = ATA_DEV_NONE;
nr_unknown++;
+ }
+ } else if (ata_phys_link_offline(ata_dev_phys_link(dev))) {
+ if (ata_class_enabled(classes[dev->devno]))
+ ata_dev_printk(dev, KERN_DEBUG, "link offline, "
+ "clearing class %d to NONE\n",
+ classes[dev->devno]);
+ classes[dev->devno] = ATA_DEV_NONE;
+ } else if (classes[dev->devno] == ATA_DEV_UNKNOWN) {
+ ata_dev_printk(dev, KERN_DEBUG, "link status unknown, "
+ "clearing UNKNOWN to NONE\n");
+ classes[dev->devno] = ATA_DEV_NONE;
}
}
if (classify && nr_unknown) {
if (try < max_tries) {
ata_link_printk(link, KERN_WARNING, "link online but "
- "device misclassified, retrying\n");
+ "%d devices misclassified, retrying\n",
+ nr_unknown);
failed_link = link;
rc = -EAGAIN;
goto fail;
}
ata_link_printk(link, KERN_WARNING,
- "link online but device misclassified, "
- "device detection might fail\n");
+ "link online but %d devices misclassified, "
+ "device detection might fail\n", nr_unknown);
}
/* reset successful, schedule revalidation */
@@ -2967,12 +2981,14 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
* device detection messages backwards.
*/
ata_for_each_dev(dev, link, ALL) {
- if (!(new_mask & (1 << dev->devno)) ||
- dev->class == ATA_DEV_PMP)
+ if (!(new_mask & (1 << dev->devno)))
continue;
dev->class = ehc->classes[dev->devno];
+ if (dev->class == ATA_DEV_PMP)
+ continue;
+
ehc->i.flags |= ATA_EHI_PRINTINFO;
rc = ata_dev_configure(dev);
ehc->i.flags &= ~ATA_EHI_PRINTINFO;
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index be8e2628f82c..823e63096362 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -118,6 +118,8 @@ extern void ata_lpm_schedule(struct ata_port *ap, enum link_pm);
/* libata-acpi.c */
#ifdef CONFIG_ATA_ACPI
+extern unsigned int ata_acpi_gtf_filter;
+
extern void ata_acpi_associate_sata_port(struct ata_port *ap);
extern void ata_acpi_associate(struct ata_host *host);
extern void ata_acpi_dissociate(struct ata_host *host);
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index fc9c5d6d7d80..1432dc9d0ab8 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -290,7 +290,7 @@ static void ali_warn_atapi_dma(struct ata_device *adev)
if (print_info && adev->class == ATA_DEV_ATAPI && !ali_atapi_dma) {
ata_dev_printk(adev, KERN_WARNING,
- "WARNING: ATAPI DMA disabled for reliablity issues. It can be enabled\n");
+ "WARNING: ATAPI DMA disabled for reliability issues. It can be enabled\n");
ata_dev_printk(adev, KERN_WARNING,
"WARNING: via pata_ali.atapi_dma modparam or corresponding sysfs node.\n");
}
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 33a74f11171c..567f3f72774e 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -307,6 +307,9 @@ static unsigned long nv_mode_filter(struct ata_device *dev,
limit |= ATA_MASK_PIO;
if (!(limit & (ATA_MASK_MWDMA | ATA_MASK_UDMA)))
limit |= ATA_MASK_MWDMA | ATA_MASK_UDMA;
+ /* PIO4, MWDMA2, UDMA2 should always be supported regardless of
+ cable detection result */
+ limit |= ata_pack_xfermask(ATA_PIO4, ATA_MWDMA2, ATA_UDMA2);
ata_port_printk(ap, KERN_DEBUG, "nv_mode_filter: 0x%lx&0x%lx->0x%lx, "
"BIOS=0x%lx (0x%x) ACPI=0x%lx%s\n",
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index aa4b3f6ae771..ae4454d4e955 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -246,7 +246,7 @@ static const struct pci_device_id atiixp[] = {
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), },
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), },
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), },
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_SB900_IDE), },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_HUDSON2_IDE), },
{ },
};
diff --git a/drivers/ata/pata_atp867x.c b/drivers/ata/pata_atp867x.c
new file mode 100644
index 000000000000..6fe7ded40c6a
--- /dev/null
+++ b/drivers/ata/pata_atp867x.c
@@ -0,0 +1,587 @@
+/*
+ * pata_atp867x.c - ARTOP 867X 64bit 4-channel UDMA133 ATA controller driver
+ *
+ * (C) 2009 Google Inc. John(Jung-Ik) Lee <jilee@google.com>
+ *
+ * Per Atp867 data sheet rev 1.2, Acard.
+ * Based in part on early ide code from
+ * 2003-2004 by Eric Uhrhane, Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * TODO:
+ * 1. RAID features [comparison, XOR, striping, mirroring, etc.]
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_atp867x"
+#define DRV_VERSION "0.7.5"
+
+/*
+ * IO Registers
+ * Note that all runtime hot priv ports are cached in ap private_data
+ */
+
+enum {
+ ATP867X_IO_CHANNEL_OFFSET = 0x10,
+
+ /*
+ * IO Register Bitfields
+ */
+
+ ATP867X_IO_PIOSPD_ACTIVE_SHIFT = 4,
+ ATP867X_IO_PIOSPD_RECOVER_SHIFT = 0,
+
+ ATP867X_IO_DMAMODE_MSTR_SHIFT = 0,
+ ATP867X_IO_DMAMODE_MSTR_MASK = 0x07,
+ ATP867X_IO_DMAMODE_SLAVE_SHIFT = 4,
+ ATP867X_IO_DMAMODE_SLAVE_MASK = 0x70,
+
+ ATP867X_IO_DMAMODE_UDMA_6 = 0x07,
+ ATP867X_IO_DMAMODE_UDMA_5 = 0x06,
+ ATP867X_IO_DMAMODE_UDMA_4 = 0x05,
+ ATP867X_IO_DMAMODE_UDMA_3 = 0x04,
+ ATP867X_IO_DMAMODE_UDMA_2 = 0x03,
+ ATP867X_IO_DMAMODE_UDMA_1 = 0x02,
+ ATP867X_IO_DMAMODE_UDMA_0 = 0x01,
+ ATP867X_IO_DMAMODE_DISABLE = 0x00,
+
+ ATP867X_IO_SYS_INFO_66MHZ = 0x04,
+ ATP867X_IO_SYS_INFO_SLOW_UDMA5 = 0x02,
+ ATP867X_IO_SYS_MASK_RESERVED = (~0xf1),
+
+ ATP867X_IO_PORTSPD_VAL = 0x1143,
+ ATP867X_PREREAD_VAL = 0x0200,
+
+ ATP867X_NUM_PORTS = 4,
+ ATP867X_BAR_IOBASE = 0,
+ ATP867X_BAR_ROMBASE = 6,
+};
+
+#define ATP867X_IOBASE(ap) ((ap)->host->iomap[0])
+#define ATP867X_SYS_INFO(ap) (0x3F + ATP867X_IOBASE(ap))
+
+#define ATP867X_IO_PORTBASE(ap, port) (0x00 + ATP867X_IOBASE(ap) + \
+ (port) * ATP867X_IO_CHANNEL_OFFSET)
+#define ATP867X_IO_DMABASE(ap, port) (0x40 + \
+ ATP867X_IO_PORTBASE((ap), (port)))
+
+#define ATP867X_IO_STATUS(ap, port) (0x07 + \
+ ATP867X_IO_PORTBASE((ap), (port)))
+#define ATP867X_IO_ALTSTATUS(ap, port) (0x0E + \
+ ATP867X_IO_PORTBASE((ap), (port)))
+
+/*
+ * hot priv ports
+ */
+#define ATP867X_IO_MSTRPIOSPD(ap, port) (0x08 + \
+ ATP867X_IO_DMABASE((ap), (port)))
+#define ATP867X_IO_SLAVPIOSPD(ap, port) (0x09 + \
+ ATP867X_IO_DMABASE((ap), (port)))
+#define ATP867X_IO_8BPIOSPD(ap, port) (0x0A + \
+ ATP867X_IO_DMABASE((ap), (port)))
+#define ATP867X_IO_DMAMODE(ap, port) (0x0B + \
+ ATP867X_IO_DMABASE((ap), (port)))
+
+#define ATP867X_IO_PORTSPD(ap, port) (0x4A + \
+ ATP867X_IO_PORTBASE((ap), (port)))
+#define ATP867X_IO_PREREAD(ap, port) (0x4C + \
+ ATP867X_IO_PORTBASE((ap), (port)))
+
+struct atp867x_priv {
+ void __iomem *dma_mode;
+ void __iomem *mstr_piospd;
+ void __iomem *slave_piospd;
+ void __iomem *eightb_piospd;
+ int pci66mhz;
+};
+
+static void atp867x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct atp867x_priv *dp = ap->private_data;
+ u8 speed = adev->dma_mode;
+ u8 b;
+ u8 mode = speed - XFER_UDMA_0 + 1;
+
+ /*
+ * Doc 6.6.9: decrease the udma mode value by 1 for safer UDMA speed
+ * on 66MHz bus
+ * rev-A: UDMA_1~4 (5, 6 no change)
+ * rev-B: all UDMA modes
+ * UDMA_0 stays not to disable UDMA
+ */
+ if (dp->pci66mhz && mode > ATP867X_IO_DMAMODE_UDMA_0 &&
+ (pdev->device == PCI_DEVICE_ID_ARTOP_ATP867B ||
+ mode < ATP867X_IO_DMAMODE_UDMA_5))
+ mode--;
+
+ b = ioread8(dp->dma_mode);
+ if (adev->devno & 1) {
+ b = (b & ~ATP867X_IO_DMAMODE_SLAVE_MASK) |
+ (mode << ATP867X_IO_DMAMODE_SLAVE_SHIFT);
+ } else {
+ b = (b & ~ATP867X_IO_DMAMODE_MSTR_MASK) |
+ (mode << ATP867X_IO_DMAMODE_MSTR_SHIFT);
+ }
+ iowrite8(b, dp->dma_mode);
+}
+
+static int atp867x_get_active_clocks_shifted(struct ata_port *ap,
+ unsigned int clk)
+{
+ struct atp867x_priv *dp = ap->private_data;
+ unsigned char clocks = clk;
+
+ /*
+ * Doc 6.6.9: increase the clock value by 1 for safer PIO speed
+ * on 66MHz bus
+ */
+ if (dp->pci66mhz)
+ clocks++;
+
+ switch (clocks) {
+ case 0:
+ clocks = 1;
+ break;
+ case 1 ... 6:
+ break;
+ default:
+ printk(KERN_WARNING "ATP867X: active %dclk is invalid. "
+ "Using 12clk.\n", clk);
+ case 9 ... 12:
+ clocks = 7; /* 12 clk */
+ break;
+ case 7:
+ case 8: /* default 8 clk */
+ clocks = 0;
+ goto active_clock_shift_done;
+ }
+
+active_clock_shift_done:
+ return clocks << ATP867X_IO_PIOSPD_ACTIVE_SHIFT;
+}
+
+static int atp867x_get_recover_clocks_shifted(unsigned int clk)
+{
+ unsigned char clocks = clk;
+
+ switch (clocks) {
+ case 0:
+ clocks = 1;
+ break;
+ case 1 ... 11:
+ break;
+ case 13:
+ case 14:
+ --clocks; /* by the spec */
+ break;
+ case 15:
+ break;
+ default:
+ printk(KERN_WARNING "ATP867X: recover %dclk is invalid. "
+ "Using default 12clk.\n", clk);
+ case 12: /* default 12 clk */
+ clocks = 0;
+ break;
+ }
+
+ return clocks << ATP867X_IO_PIOSPD_RECOVER_SHIFT;
+}
+
+static void atp867x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ata_device *peer = ata_dev_pair(adev);
+ struct atp867x_priv *dp = ap->private_data;
+ u8 speed = adev->pio_mode;
+ struct ata_timing t, p;
+ int T, UT;
+ u8 b;
+
+ T = 1000000000 / 33333;
+ UT = T / 4;
+
+ ata_timing_compute(adev, speed, &t, T, UT);
+ if (peer && peer->pio_mode) {
+ ata_timing_compute(peer, peer->pio_mode, &p, T, UT);
+ ata_timing_merge(&p, &t, &t, ATA_TIMING_8BIT);
+ }
+
+ b = ioread8(dp->dma_mode);
+ if (adev->devno & 1)
+ b = (b & ~ATP867X_IO_DMAMODE_SLAVE_MASK);
+ else
+ b = (b & ~ATP867X_IO_DMAMODE_MSTR_MASK);
+ iowrite8(b, dp->dma_mode);
+
+ b = atp867x_get_active_clocks_shifted(ap, t.active) |
+ atp867x_get_recover_clocks_shifted(t.recover);
+
+ if (adev->devno & 1)
+ iowrite8(b, dp->slave_piospd);
+ else
+ iowrite8(b, dp->mstr_piospd);
+
+ b = atp867x_get_active_clocks_shifted(ap, t.act8b) |
+ atp867x_get_recover_clocks_shifted(t.rec8b);
+
+ iowrite8(b, dp->eightb_piospd);
+}
+
+static int atp867x_cable_override(struct pci_dev *pdev)
+{
+ if (pdev->subsystem_vendor == PCI_VENDOR_ID_ARTOP &&
+ (pdev->subsystem_device == PCI_DEVICE_ID_ARTOP_ATP867A ||
+ pdev->subsystem_device == PCI_DEVICE_ID_ARTOP_ATP867B)) {
+ return 1;
+ }
+ return 0;
+}
+
+static int atp867x_cable_detect(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (atp867x_cable_override(pdev))
+ return ATA_CBL_PATA40_SHORT;
+
+ return ATA_CBL_PATA_UNK;
+}
+
+static struct scsi_host_template atp867x_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations atp867x_ops = {
+ .inherits = &ata_bmdma_port_ops,
+ .cable_detect = atp867x_cable_detect,
+ .set_piomode = atp867x_set_piomode,
+ .set_dmamode = atp867x_set_dmamode,
+};
+
+
+#ifdef ATP867X_DEBUG
+static void atp867x_check_res(struct pci_dev *pdev)
+{
+ int i;
+ unsigned long start, len;
+
+ /* Check the PCI resources for this channel are enabled */
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ start = pci_resource_start(pdev, i);
+ len = pci_resource_len(pdev, i);
+ printk(KERN_DEBUG "ATP867X: resource start:len=%lx:%lx\n",
+ start, len);
+ }
+}
+
+static void atp867x_check_ports(struct ata_port *ap, int port)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ struct atp867x_priv *dp = ap->private_data;
+
+ printk(KERN_DEBUG "ATP867X: port[%d] addresses\n"
+ " cmd_addr =0x%llx, 0x%llx\n"
+ " ctl_addr =0x%llx, 0x%llx\n"
+ " bmdma_addr =0x%llx, 0x%llx\n"
+ " data_addr =0x%llx\n"
+ " error_addr =0x%llx\n"
+ " feature_addr =0x%llx\n"
+ " nsect_addr =0x%llx\n"
+ " lbal_addr =0x%llx\n"
+ " lbam_addr =0x%llx\n"
+ " lbah_addr =0x%llx\n"
+ " device_addr =0x%llx\n"
+ " status_addr =0x%llx\n"
+ " command_addr =0x%llx\n"
+ " dp->dma_mode =0x%llx\n"
+ " dp->mstr_piospd =0x%llx\n"
+ " dp->slave_piospd =0x%llx\n"
+ " dp->eightb_piospd =0x%llx\n"
+ " dp->pci66mhz =0x%lx\n",
+ port,
+ (unsigned long long)ioaddr->cmd_addr,
+ (unsigned long long)ATP867X_IO_PORTBASE(ap, port),
+ (unsigned long long)ioaddr->ctl_addr,
+ (unsigned long long)ATP867X_IO_ALTSTATUS(ap, port),
+ (unsigned long long)ioaddr->bmdma_addr,
+ (unsigned long long)ATP867X_IO_DMABASE(ap, port),
+ (unsigned long long)ioaddr->data_addr,
+ (unsigned long long)ioaddr->error_addr,
+ (unsigned long long)ioaddr->feature_addr,
+ (unsigned long long)ioaddr->nsect_addr,
+ (unsigned long long)ioaddr->lbal_addr,
+ (unsigned long long)ioaddr->lbam_addr,
+ (unsigned long long)ioaddr->lbah_addr,
+ (unsigned long long)ioaddr->device_addr,
+ (unsigned long long)ioaddr->status_addr,
+ (unsigned long long)ioaddr->command_addr,
+ (unsigned long long)dp->dma_mode,
+ (unsigned long long)dp->mstr_piospd,
+ (unsigned long long)dp->slave_piospd,
+ (unsigned long long)dp->eightb_piospd,
+ (unsigned long)dp->pci66mhz);
+}
+#endif
+
+static int atp867x_set_priv(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct atp867x_priv *dp;
+ int port = ap->port_no;
+
+ dp = ap->private_data =
+ devm_kzalloc(&pdev->dev, sizeof(*dp), GFP_KERNEL);
+ if (dp == NULL)
+ return -ENOMEM;
+
+ dp->dma_mode = ATP867X_IO_DMAMODE(ap, port);
+ dp->mstr_piospd = ATP867X_IO_MSTRPIOSPD(ap, port);
+ dp->slave_piospd = ATP867X_IO_SLAVPIOSPD(ap, port);
+ dp->eightb_piospd = ATP867X_IO_8BPIOSPD(ap, port);
+
+ dp->pci66mhz =
+ ioread8(ATP867X_SYS_INFO(ap)) & ATP867X_IO_SYS_INFO_66MHZ;
+
+ return 0;
+}
+
+static void atp867x_fixup(struct ata_host *host)
+{
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ struct ata_port *ap = host->ports[0];
+ int i;
+ u8 v;
+
+ /*
+ * Broken BIOS might not set latency high enough
+ */
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &v);
+ if (v < 0x80) {
+ v = 0x80;
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, v);
+ printk(KERN_DEBUG "ATP867X: set latency timer of device %s"
+ " to %d\n", pci_name(pdev), v);
+ }
+
+ /*
+ * init 8bit io ports speed(0aaarrrr) to 43h and
+ * init udma modes of master/slave to 0/0(11h)
+ */
+ for (i = 0; i < ATP867X_NUM_PORTS; i++)
+ iowrite16(ATP867X_IO_PORTSPD_VAL, ATP867X_IO_PORTSPD(ap, i));
+
+ /*
+ * init PreREAD counts
+ */
+ for (i = 0; i < ATP867X_NUM_PORTS; i++)
+ iowrite16(ATP867X_PREREAD_VAL, ATP867X_IO_PREREAD(ap, i));
+
+ v = ioread8(ATP867X_IOBASE(ap) + 0x28);
+ v &= 0xcf; /* Enable INTA#: bit4=0 means enable */
+ v |= 0xc0; /* Enable PCI burst, MRM & not immediate interrupts */
+ iowrite8(v, ATP867X_IOBASE(ap) + 0x28);
+
+ /*
+ * Turn off the over clocked udma5 mode, only for Rev-B
+ */
+ v = ioread8(ATP867X_SYS_INFO(ap));
+ v &= ATP867X_IO_SYS_MASK_RESERVED;
+ if (pdev->device == PCI_DEVICE_ID_ARTOP_ATP867B)
+ v |= ATP867X_IO_SYS_INFO_SLOW_UDMA5;
+ iowrite8(v, ATP867X_SYS_INFO(ap));
+}
+
+static int atp867x_ata_pci_sff_init_host(struct ata_host *host)
+{
+ struct device *gdev = host->dev;
+ struct pci_dev *pdev = to_pci_dev(gdev);
+ unsigned int mask = 0;
+ int i, rc;
+
+ /*
+ * do not map rombase
+ */
+ rc = pcim_iomap_regions(pdev, 1 << ATP867X_BAR_IOBASE, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
+ host->iomap = pcim_iomap_table(pdev);
+
+#ifdef ATP867X_DEBUG
+ atp867x_check_res(pdev);
+
+ for (i = 0; i < PCI_ROM_RESOURCE; i++)
+ printk(KERN_DEBUG "ATP867X: iomap[%d]=0x%llx\n", i,
+ (unsigned long long)(host->iomap[i]));
+#endif
+
+ /*
+ * request, iomap BARs and init port addresses accordingly
+ */
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ ioaddr->cmd_addr = ATP867X_IO_PORTBASE(ap, i);
+ ioaddr->ctl_addr = ioaddr->altstatus_addr
+ = ATP867X_IO_ALTSTATUS(ap, i);
+ ioaddr->bmdma_addr = ATP867X_IO_DMABASE(ap, i);
+
+ ata_sff_std_ports(ioaddr);
+ rc = atp867x_set_priv(ap);
+ if (rc)
+ return rc;
+
+#ifdef ATP867X_DEBUG
+ atp867x_check_ports(ap, i);
+#endif
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx",
+ (unsigned long)ioaddr->cmd_addr,
+ (unsigned long)ioaddr->ctl_addr);
+ ata_port_desc(ap, "bmdma 0x%lx",
+ (unsigned long)ioaddr->bmdma_addr);
+
+ mask |= 1 << i;
+ }
+
+ if (!mask) {
+ dev_printk(KERN_ERR, gdev, "no available native port\n");
+ return -ENODEV;
+ }
+
+ atp867x_fixup(host);
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ return rc;
+}
+
+static int atp867x_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ static int printed_version;
+ static const struct ata_port_info info_867x = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &atp867x_ops,
+ };
+
+ struct ata_host *host;
+ const struct ata_port_info *ppi[] = { &info_867x, NULL };
+ int rc;
+
+ if (!printed_version++)
+ dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ printk(KERN_INFO "ATP867X: ATP867 ATA UDMA133 controller (rev %02X)",
+ pdev->device);
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, ATP867X_NUM_PORTS);
+ if (!host) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to allocate ATA host\n");
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
+ rc = atp867x_ata_pci_sff_init_host(host);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev, "failed to init host\n");
+ goto err_out;
+ }
+
+ pci_set_master(pdev);
+
+ rc = ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+ IRQF_SHARED, &atp867x_sht);
+ if (rc)
+ dev_printk(KERN_ERR, &pdev->dev, "failed to activate host\n");
+
+err_out:
+ return rc;
+}
+
+#ifdef CONFIG_PM
+static int atp867x_reinit_one(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
+
+ atp867x_fixup(host);
+
+ ata_host_resume(host);
+ return 0;
+}
+#endif
+
+static struct pci_device_id atp867x_pci_tbl[] = {
+ { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP867A), 0 },
+ { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP867B), 0 },
+ { },
+};
+
+static struct pci_driver atp867x_driver = {
+ .name = DRV_NAME,
+ .id_table = atp867x_pci_tbl,
+ .probe = atp867x_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = atp867x_reinit_one,
+#endif
+};
+
+static int __init atp867x_init(void)
+{
+ return pci_register_driver(&atp867x_driver);
+}
+
+static void __exit atp867x_exit(void)
+{
+ pci_unregister_driver(&atp867x_driver);
+}
+
+MODULE_AUTHOR("John(Jung-Ik) Lee, Google Inc.");
+MODULE_DESCRIPTION("low level driver for Artop/Acard 867x ATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, atp867x_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(atp867x_init);
+module_exit(atp867x_exit);
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index 122c786449a9..d0a7df2e5ca7 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -624,7 +624,7 @@ static struct ata_port_operations hpt374_fn1_port_ops = {
};
/**
- * htp37x_clock_slot - Turn timing to PC clock entry
+ * hpt37x_clock_slot - Turn timing to PC clock entry
* @freq: Reported frequency timing
* @base: Base timing
*
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index dc99e26f8e5b..1b392c9e8531 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -177,9 +177,6 @@ static struct ata_port_operations pcmcia_8bit_port_ops = {
.drain_fifo = pcmcia_8bit_drain_fifo,
};
-#define CS_CHECK(fn, ret) \
-do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
-
struct pcmcia_config_check {
unsigned long ctl_base;
@@ -252,7 +249,7 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
struct ata_port *ap;
struct ata_pcmcia_info *info;
struct pcmcia_config_check *stk = NULL;
- int last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM, p;
+ int is_kme = 0, ret = -ENOMEM, p;
unsigned long io_base, ctl_base;
void __iomem *io_addr, *ctl_addr;
int n_ports = 1;
@@ -271,7 +268,6 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
pdev->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
pdev->io.IOAddrLines = 3;
pdev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
- pdev->irq.IRQInfo1 = IRQ_LEVEL_ID;
pdev->conf.Attributes = CONF_ENABLE_IRQ;
pdev->conf.IntType = INT_MEMORY_AND_IO;
@@ -296,8 +292,13 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
}
io_base = pdev->io.BasePort1;
ctl_base = stk->ctl_base;
- CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq));
- CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf));
+ ret = pcmcia_request_irq(pdev, &pdev->irq);
+ if (ret)
+ goto failed;
+
+ ret = pcmcia_request_configuration(pdev, &pdev->conf);
+ if (ret)
+ goto failed;
/* iomap */
ret = -ENOMEM;
@@ -351,8 +352,6 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
kfree(stk);
return 0;
-cs_failed:
- cs_error(pdev, last_fn, last_ret);
failed:
kfree(stk);
info->ndev = 0;
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index f49814d6fd2e..3bbed8322ecf 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -235,8 +235,7 @@ static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
.udma_mask = ATA_UDMA2,
.port_ops = &sc1200_port_ops
};
- /* Can't enable port 2 yet, see top comments */
- const struct ata_port_info *ppi[] = { &info, };
+ const struct ata_port_info *ppi[] = { &info, NULL };
return ata_pci_sff_init_one(dev, ppi, &sc1200_sht, NULL);
}
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index 45657cacec43..88984b803d6d 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -111,7 +111,7 @@ static const struct via_isa_bridge {
{ "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA },
{ "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
- { "vt6415", PCI_DEVICE_ID_VIA_6415, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
+ { "vt6415", PCI_DEVICE_ID_VIA_6415, 0x00, 0xff, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
{ "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index d344db42a002..172b57e6543f 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -707,34 +707,17 @@ static unsigned int sata_fsl_dev_classify(struct ata_port *ap)
return ata_dev_classify(&tf);
}
-static int sata_fsl_prereset(struct ata_link *link, unsigned long deadline)
-{
- /* FIXME: Never skip softreset, sata_fsl_softreset() is
- * combination of soft and hard resets. sata_fsl_softreset()
- * needs to be splitted into soft and hard resets.
- */
- return 0;
-}
-
-static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
+static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
- struct sata_fsl_port_priv *pp = ap->private_data;
struct sata_fsl_host_priv *host_priv = ap->host->private_data;
void __iomem *hcr_base = host_priv->hcr_base;
- int pmp = sata_srst_pmp(link);
u32 temp;
- struct ata_taskfile tf;
- u8 *cfis;
- u32 Serror;
int i = 0;
unsigned long start_jiffies;
- DPRINTK("in xx_softreset\n");
-
- if (pmp != SATA_PMP_CTRL_PORT)
- goto issue_srst;
+ DPRINTK("in xx_hardreset\n");
try_offline_again:
/*
@@ -749,7 +732,7 @@ try_offline_again:
if (temp & ONLINE) {
ata_port_printk(ap, KERN_ERR,
- "Softreset failed, not off-lined %d\n", i);
+ "Hardreset failed, not off-lined %d\n", i);
/*
* Try to offline controller atleast twice
@@ -761,7 +744,7 @@ try_offline_again:
goto try_offline_again;
}
- DPRINTK("softreset, controller off-lined\n");
+ DPRINTK("hardreset, controller off-lined\n");
VPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
VPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
@@ -786,11 +769,11 @@ try_offline_again:
if (!(temp & ONLINE)) {
ata_port_printk(ap, KERN_ERR,
- "Softreset failed, not on-lined\n");
+ "Hardreset failed, not on-lined\n");
goto err;
}
- DPRINTK("softreset, controller off-lined & on-lined\n");
+ DPRINTK("hardreset, controller off-lined & on-lined\n");
VPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
VPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
@@ -806,7 +789,7 @@ try_offline_again:
"No Device OR PHYRDY change,Hstatus = 0x%x\n",
ioread32(hcr_base + HSTATUS));
*class = ATA_DEV_NONE;
- goto out;
+ return 0;
}
/*
@@ -819,11 +802,44 @@ try_offline_again:
if ((temp & 0xFF) != 0x18) {
ata_port_printk(ap, KERN_WARNING, "No Signature Update\n");
*class = ATA_DEV_NONE;
- goto out;
+ goto do_followup_srst;
} else {
ata_port_printk(ap, KERN_INFO,
"Signature Update detected @ %d msecs\n",
jiffies_to_msecs(jiffies - start_jiffies));
+ *class = sata_fsl_dev_classify(ap);
+ return 0;
+ }
+
+do_followup_srst:
+ /*
+ * request libATA to perform follow-up softreset
+ */
+ return -EAGAIN;
+
+err:
+ return -EIO;
+}
+
+static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct sata_fsl_port_priv *pp = ap->private_data;
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ int pmp = sata_srst_pmp(link);
+ u32 temp;
+ struct ata_taskfile tf;
+ u8 *cfis;
+ u32 Serror;
+
+ DPRINTK("in xx_softreset\n");
+
+ if (ata_link_offline(link)) {
+ DPRINTK("PHY reports no device\n");
+ *class = ATA_DEV_NONE;
+ return 0;
}
/*
@@ -834,7 +850,6 @@ try_offline_again:
* reached here, we can send a command to the target device
*/
-issue_srst:
DPRINTK("Sending SRST/device reset\n");
ata_tf_init(link->device, &tf);
@@ -860,6 +875,8 @@ issue_srst:
ioread32(CA + hcr_base), ioread32(CC + hcr_base));
iowrite32(0xFFFF, CC + hcr_base);
+ if (pmp != SATA_PMP_CTRL_PORT)
+ iowrite32(pmp, CQPMP + hcr_base);
iowrite32(1, CQ + hcr_base);
temp = ata_wait_register(CQ + hcr_base, 0x1, 0x1, 1, 5000);
@@ -926,7 +943,6 @@ issue_srst:
VPRINTK("cereg = 0x%x\n", ioread32(hcr_base + CE));
}
-out:
return 0;
err:
@@ -988,18 +1004,6 @@ static void sata_fsl_error_intr(struct ata_port *ap)
ehi->err_mask |= AC_ERR_ATA_BUS;
ehi->action |= ATA_EH_SOFTRESET;
- /*
- * Ignore serror in case of fatal errors as we always want
- * to do a soft-reset of the FSL SATA controller. Analyzing
- * serror may cause libata to schedule a hard-reset action,
- * and hard-reset currently does not do controller
- * offline/online, causing command timeouts and leads to an
- * un-recoverable state, hence make libATA ignore
- * autopsy in case of fatal errors.
- */
-
- ehi->flags |= ATA_EHI_NO_AUTOPSY;
-
freeze = 1;
}
@@ -1267,8 +1271,8 @@ static struct ata_port_operations sata_fsl_ops = {
.freeze = sata_fsl_freeze,
.thaw = sata_fsl_thaw,
- .prereset = sata_fsl_prereset,
.softreset = sata_fsl_softreset,
+ .hardreset = sata_fsl_hardreset,
.pmp_softreset = sata_fsl_softreset,
.error_handler = sata_fsl_error_handler,
.post_internal_cmd = sata_fsl_post_internal_cmd,
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 17f9ff9067a2..6f5093b7c8c5 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -1382,6 +1382,25 @@ static int mv_qc_defer(struct ata_queued_cmd *qc)
*/
if (pp->pp_flags & MV_PP_FLAG_DELAYED_EH)
return ATA_DEFER_PORT;
+
+ /* PIO commands need exclusive link: no other commands [DMA or PIO]
+ * can run concurrently.
+ * set excl_link when we want to send a PIO command in DMA mode
+ * or a non-NCQ command in NCQ mode.
+ * When we receive a command from that link, and there are no
+ * outstanding commands, mark a flag to clear excl_link and let
+ * the command go through.
+ */
+ if (unlikely(ap->excl_link)) {
+ if (link == ap->excl_link) {
+ if (ap->nr_active_links)
+ return ATA_DEFER_PORT;
+ qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+ return 0;
+ } else
+ return ATA_DEFER_PORT;
+ }
+
/*
* If the port is completely idle, then allow the new qc.
*/
@@ -1395,8 +1414,14 @@ static int mv_qc_defer(struct ata_queued_cmd *qc)
* doesn't allow it.
*/
if ((pp->pp_flags & MV_PP_FLAG_EDMA_EN) &&
- (pp->pp_flags & MV_PP_FLAG_NCQ_EN) && ata_is_ncq(qc->tf.protocol))
- return 0;
+ (pp->pp_flags & MV_PP_FLAG_NCQ_EN)) {
+ if (ata_is_ncq(qc->tf.protocol))
+ return 0;
+ else {
+ ap->excl_link = link;
+ return ATA_DEFER_PORT;
+ }
+ }
return ATA_DEFER_PORT;
}
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 86a40582999c..1eb4e020eb5c 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -1594,9 +1594,21 @@ static int nv_hardreset(struct ata_link *link, unsigned int *class,
!ata_dev_enabled(link->device))
sata_link_hardreset(link, sata_deb_timing_hotplug, deadline,
NULL, NULL);
- else if (!(ehc->i.flags & ATA_EHI_QUIET))
- ata_link_printk(link, KERN_INFO,
- "nv: skipping hardreset on occupied port\n");
+ else {
+ const unsigned long *timing = sata_ehc_deb_timing(ehc);
+ int rc;
+
+ if (!(ehc->i.flags & ATA_EHI_QUIET))
+ ata_link_printk(link, KERN_INFO, "nv: skipping "
+ "hardreset on occupied port\n");
+
+ /* make sure the link is online */
+ rc = sata_link_resume(link, timing, deadline);
+ /* whine about phy resume failure but proceed */
+ if (rc && rc != -EOPNOTSUPP)
+ ata_link_printk(link, KERN_WARNING, "failed to resume "
+ "link (errno=%d)\n", rc);
+ }
/* device signature acquisition is unreliable */
return -EAGAIN;
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index b1fd7d62071a..07d8d00b4d34 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -56,6 +56,7 @@ enum {
/* host register offsets (from host->iomap[PDC_MMIO_BAR]) */
PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
PDC_FLASH_CTL = 0x44, /* Flash control register */
+ PDC_PCI_CTL = 0x48, /* PCI control/status reg */
PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */
PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */
PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */
@@ -75,7 +76,17 @@ enum {
PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */
/* per-port SATA register offsets (from ap->ioaddr.scr_addr) */
+ PDC_SATA_ERROR = 0x04,
PDC_PHYMODE4 = 0x14,
+ PDC_LINK_LAYER_ERRORS = 0x6C,
+ PDC_FPDMA_CTLSTAT = 0xD8,
+ PDC_INTERNAL_DEBUG_1 = 0xF8, /* also used for PATA */
+ PDC_INTERNAL_DEBUG_2 = 0xFC, /* also used for PATA */
+
+ /* PDC_FPDMA_CTLSTAT bit definitions */
+ PDC_FPDMA_CTLSTAT_RESET = 1 << 3,
+ PDC_FPDMA_CTLSTAT_DMASETUP_INT_FLAG = 1 << 10,
+ PDC_FPDMA_CTLSTAT_SETDB_INT_FLAG = 1 << 11,
/* PDC_GLOBAL_CTL bit definitions */
PDC_PH_ERR = (1 << 8), /* PCI error while loading packet */
@@ -195,9 +206,12 @@ static struct ata_port_operations pdc_sata_ops = {
.hardreset = pdc_sata_hardreset,
};
-/* First-generation chips need a more restrictive ->check_atapi_dma op */
+/* First-generation chips need a more restrictive ->check_atapi_dma op,
+ and ->freeze/thaw that ignore the hotplug controls. */
static struct ata_port_operations pdc_old_sata_ops = {
.inherits = &pdc_sata_ops,
+ .freeze = pdc_freeze,
+ .thaw = pdc_thaw,
.check_atapi_dma = pdc_old_sata_check_atapi_dma,
};
@@ -356,12 +370,76 @@ static int pdc_sata_port_start(struct ata_port *ap)
return 0;
}
+static void pdc_fpdma_clear_interrupt_flag(struct ata_port *ap)
+{
+ void __iomem *sata_mmio = ap->ioaddr.scr_addr;
+ u32 tmp;
+
+ tmp = readl(sata_mmio + PDC_FPDMA_CTLSTAT);
+ tmp |= PDC_FPDMA_CTLSTAT_DMASETUP_INT_FLAG;
+ tmp |= PDC_FPDMA_CTLSTAT_SETDB_INT_FLAG;
+
+ /* It's not allowed to write to the entire FPDMA_CTLSTAT register
+ when NCQ is running. So do a byte-sized write to bits 10 and 11. */
+ writeb(tmp >> 8, sata_mmio + PDC_FPDMA_CTLSTAT + 1);
+ readb(sata_mmio + PDC_FPDMA_CTLSTAT + 1); /* flush */
+}
+
+static void pdc_fpdma_reset(struct ata_port *ap)
+{
+ void __iomem *sata_mmio = ap->ioaddr.scr_addr;
+ u8 tmp;
+
+ tmp = (u8)readl(sata_mmio + PDC_FPDMA_CTLSTAT);
+ tmp &= 0x7F;
+ tmp |= PDC_FPDMA_CTLSTAT_RESET;
+ writeb(tmp, sata_mmio + PDC_FPDMA_CTLSTAT);
+ readl(sata_mmio + PDC_FPDMA_CTLSTAT); /* flush */
+ udelay(100);
+ tmp &= ~PDC_FPDMA_CTLSTAT_RESET;
+ writeb(tmp, sata_mmio + PDC_FPDMA_CTLSTAT);
+ readl(sata_mmio + PDC_FPDMA_CTLSTAT); /* flush */
+
+ pdc_fpdma_clear_interrupt_flag(ap);
+}
+
+static void pdc_not_at_command_packet_phase(struct ata_port *ap)
+{
+ void __iomem *sata_mmio = ap->ioaddr.scr_addr;
+ unsigned int i;
+ u32 tmp;
+
+ /* check not at ASIC packet command phase */
+ for (i = 0; i < 100; ++i) {
+ writel(0, sata_mmio + PDC_INTERNAL_DEBUG_1);
+ tmp = readl(sata_mmio + PDC_INTERNAL_DEBUG_2);
+ if ((tmp & 0xF) != 1)
+ break;
+ udelay(100);
+ }
+}
+
+static void pdc_clear_internal_debug_record_error_register(struct ata_port *ap)
+{
+ void __iomem *sata_mmio = ap->ioaddr.scr_addr;
+
+ writel(0xffffffff, sata_mmio + PDC_SATA_ERROR);
+ writel(0xffff0000, sata_mmio + PDC_LINK_LAYER_ERRORS);
+}
+
static void pdc_reset_port(struct ata_port *ap)
{
void __iomem *ata_ctlstat_mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT;
unsigned int i;
u32 tmp;
+ if (ap->flags & PDC_FLAG_GEN_II)
+ pdc_not_at_command_packet_phase(ap);
+
+ tmp = readl(ata_ctlstat_mmio);
+ tmp |= PDC_RESET;
+ writel(tmp, ata_ctlstat_mmio);
+
for (i = 11; i > 0; i--) {
tmp = readl(ata_ctlstat_mmio);
if (tmp & PDC_RESET)
@@ -376,6 +454,11 @@ static void pdc_reset_port(struct ata_port *ap)
tmp &= ~PDC_RESET;
writel(tmp, ata_ctlstat_mmio);
readl(ata_ctlstat_mmio); /* flush */
+
+ if (sata_scr_valid(&ap->link) && (ap->flags & PDC_FLAG_GEN_II)) {
+ pdc_fpdma_reset(ap);
+ pdc_clear_internal_debug_record_error_register(ap);
+ }
}
static int pdc_pata_cable_detect(struct ata_port *ap)
@@ -626,11 +709,6 @@ static unsigned int pdc_sata_ata_port_to_ata_no(const struct ata_port *ap)
return pdc_port_no_to_ata_no(i, pdc_is_sataii_tx4(ap->flags));
}
-static unsigned int pdc_sata_hotplug_offset(const struct ata_port *ap)
-{
- return (ap->flags & PDC_FLAG_GEN_II) ? PDC2_SATA_PLUG_CSR : PDC_SATA_PLUG_CSR;
-}
-
static void pdc_freeze(struct ata_port *ap)
{
void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
@@ -647,7 +725,7 @@ static void pdc_sata_freeze(struct ata_port *ap)
{
struct ata_host *host = ap->host;
void __iomem *host_mmio = host->iomap[PDC_MMIO_BAR];
- unsigned int hotplug_offset = pdc_sata_hotplug_offset(ap);
+ unsigned int hotplug_offset = PDC2_SATA_PLUG_CSR;
unsigned int ata_no = pdc_sata_ata_port_to_ata_no(ap);
u32 hotplug_status;
@@ -685,7 +763,7 @@ static void pdc_sata_thaw(struct ata_port *ap)
{
struct ata_host *host = ap->host;
void __iomem *host_mmio = host->iomap[PDC_MMIO_BAR];
- unsigned int hotplug_offset = pdc_sata_hotplug_offset(ap);
+ unsigned int hotplug_offset = PDC2_SATA_PLUG_CSR;
unsigned int ata_no = pdc_sata_ata_port_to_ata_no(ap);
u32 hotplug_status;
@@ -708,11 +786,50 @@ static int pdc_pata_softreset(struct ata_link *link, unsigned int *class,
return ata_sff_softreset(link, class, deadline);
}
+static unsigned int pdc_ata_port_to_ata_no(const struct ata_port *ap)
+{
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
+ void __iomem *host_mmio = ap->host->iomap[PDC_MMIO_BAR];
+
+ /* ata_mmio == host_mmio + 0x200 + ata_no * 0x80 */
+ return (ata_mmio - host_mmio - 0x200) / 0x80;
+}
+
+static void pdc_hard_reset_port(struct ata_port *ap)
+{
+ void __iomem *host_mmio = ap->host->iomap[PDC_MMIO_BAR];
+ void __iomem *pcictl_b1_mmio = host_mmio + PDC_PCI_CTL + 1;
+ unsigned int ata_no = pdc_ata_port_to_ata_no(ap);
+ u8 tmp;
+
+ spin_lock(&ap->host->lock);
+
+ tmp = readb(pcictl_b1_mmio);
+ tmp &= ~(0x10 << ata_no);
+ writeb(tmp, pcictl_b1_mmio);
+ readb(pcictl_b1_mmio); /* flush */
+ udelay(100);
+ tmp |= (0x10 << ata_no);
+ writeb(tmp, pcictl_b1_mmio);
+ readb(pcictl_b1_mmio); /* flush */
+
+ spin_unlock(&ap->host->lock);
+}
+
static int pdc_sata_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ if (link->ap->flags & PDC_FLAG_GEN_II)
+ pdc_not_at_command_packet_phase(link->ap);
+ /* hotplug IRQs should have been masked by pdc_sata_freeze() */
+ pdc_hard_reset_port(link->ap);
pdc_reset_port(link->ap);
- return sata_sff_hardreset(link, class, deadline);
+
+ /* sata_promise can't reliably acquire the first D2H Reg FIS
+ * after hardreset. Do non-waiting hardreset and request
+ * follow-up SRST.
+ */
+ return sata_std_hardreset(link, class, deadline);
}
static void pdc_error_handler(struct ata_port *ap)
@@ -832,14 +949,14 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance)
spin_lock(&host->lock);
/* read and clear hotplug flags for all ports */
- if (host->ports[0]->flags & PDC_FLAG_GEN_II)
+ if (host->ports[0]->flags & PDC_FLAG_GEN_II) {
hotplug_offset = PDC2_SATA_PLUG_CSR;
- else
- hotplug_offset = PDC_SATA_PLUG_CSR;
- hotplug_status = readl(host_mmio + hotplug_offset);
- if (hotplug_status & 0xff)
- writel(hotplug_status | 0xff, host_mmio + hotplug_offset);
- hotplug_status &= 0xff; /* clear uninteresting bits */
+ hotplug_status = readl(host_mmio + hotplug_offset);
+ if (hotplug_status & 0xff)
+ writel(hotplug_status | 0xff, host_mmio + hotplug_offset);
+ hotplug_status &= 0xff; /* clear uninteresting bits */
+ } else
+ hotplug_status = 0;
/* reading should also clear interrupts */
mask = readl(host_mmio + PDC_INT_SEQMASK);
@@ -1034,9 +1151,11 @@ static void pdc_host_init(struct ata_host *host)
tmp = readl(host_mmio + hotplug_offset);
writel(tmp | 0xff, host_mmio + hotplug_offset);
- /* unmask plug/unplug ints */
tmp = readl(host_mmio + hotplug_offset);
- writel(tmp & ~0xff0000, host_mmio + hotplug_offset);
+ if (is_gen2) /* unmask plug/unplug ints */
+ writel(tmp & ~0xff0000, host_mmio + hotplug_offset);
+ else /* mask plug/unplug ints */
+ writel(tmp | 0xff0000, host_mmio + hotplug_offset);
/* don't initialise TBG or SLEW on 2nd generation chips */
if (is_gen2)
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index bdd43c7f432e..02efd9a83d26 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -93,7 +93,6 @@ static const struct pci_device_id svia_pci_tbl[] = {
{ PCI_VDEVICE(VIA, 0x7372), vt6420 },
{ PCI_VDEVICE(VIA, 0x5287), vt8251 }, /* 2 sata chnls (Master/Slave) */
{ PCI_VDEVICE(VIA, 0x9000), vt8251 },
- { PCI_VDEVICE(VIA, 0x9040), vt8251 },
{ } /* terminate list */
};
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 703364b52170..66e181345b3a 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -1306,14 +1306,6 @@ static void amb_close (struct atm_vcc * atm_vcc) {
return;
}
-/********** Set socket options for a VC **********/
-
-// int amb_getsockopt (struct atm_vcc * atm_vcc, int level, int optname, void * optval, int optlen);
-
-/********** Set socket options for a VC **********/
-
-// int amb_setsockopt (struct atm_vcc * atm_vcc, int level, int optname, void * optval, int optlen);
-
/********** Send **********/
static int amb_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 5503bfc8e132..0c3026145443 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -2031,7 +2031,7 @@ static int eni_getsockopt(struct atm_vcc *vcc,int level,int optname,
static int eni_setsockopt(struct atm_vcc *vcc,int level,int optname,
- void __user *optval,int optlen)
+ void __user *optval,unsigned int optlen)
{
return -EINVAL;
}
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index b119640e1ee9..cd5049af47a9 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -1244,7 +1244,7 @@ static int fs_getsockopt(struct atm_vcc *vcc,int level,int optname,
static int fs_setsockopt(struct atm_vcc *vcc,int level,int optname,
- void __user *optval,int optlen)
+ void __user *optval,unsigned int optlen)
{
func_enter ();
func_exit ();
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 10f000dbe448..f766cc46b4c4 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -1795,7 +1795,7 @@ fore200e_getsockopt(struct atm_vcc* vcc, int level, int optname, void __user *op
static int
-fore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void __user *optval, int optlen)
+fore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void __user *optval, unsigned int optlen)
{
/* struct fore200e* fore200e = FORE200E_DEV(vcc->dev); */
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index 2de64065aa1b..70667033a568 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -790,11 +790,15 @@ he_init_group(struct he_dev *he_dev, int group)
he_dev->rbps_base = pci_alloc_consistent(he_dev->pci_dev,
CONFIG_RBPS_SIZE * sizeof(struct he_rbp), &he_dev->rbps_phys);
if (he_dev->rbps_base == NULL) {
- hprintk("failed to alloc rbps\n");
- return -ENOMEM;
+ hprintk("failed to alloc rbps_base\n");
+ goto out_destroy_rbps_pool;
}
memset(he_dev->rbps_base, 0, CONFIG_RBPS_SIZE * sizeof(struct he_rbp));
he_dev->rbps_virt = kmalloc(CONFIG_RBPS_SIZE * sizeof(struct he_virt), GFP_KERNEL);
+ if (he_dev->rbps_virt == NULL) {
+ hprintk("failed to alloc rbps_virt\n");
+ goto out_free_rbps_base;
+ }
for (i = 0; i < CONFIG_RBPS_SIZE; ++i) {
dma_addr_t dma_handle;
@@ -802,7 +806,7 @@ he_init_group(struct he_dev *he_dev, int group)
cpuaddr = pci_pool_alloc(he_dev->rbps_pool, GFP_KERNEL|GFP_DMA, &dma_handle);
if (cpuaddr == NULL)
- return -ENOMEM;
+ goto out_free_rbps_virt;
he_dev->rbps_virt[i].virt = cpuaddr;
he_dev->rbps_base[i].status = RBP_LOANED | RBP_SMALLBUF | (i << RBP_INDEX_OFF);
@@ -827,17 +831,21 @@ he_init_group(struct he_dev *he_dev, int group)
CONFIG_RBPL_BUFSIZE, 8, 0);
if (he_dev->rbpl_pool == NULL) {
hprintk("unable to create rbpl pool\n");
- return -ENOMEM;
+ goto out_free_rbps_virt;
}
he_dev->rbpl_base = pci_alloc_consistent(he_dev->pci_dev,
CONFIG_RBPL_SIZE * sizeof(struct he_rbp), &he_dev->rbpl_phys);
if (he_dev->rbpl_base == NULL) {
- hprintk("failed to alloc rbpl\n");
- return -ENOMEM;
+ hprintk("failed to alloc rbpl_base\n");
+ goto out_destroy_rbpl_pool;
}
memset(he_dev->rbpl_base, 0, CONFIG_RBPL_SIZE * sizeof(struct he_rbp));
he_dev->rbpl_virt = kmalloc(CONFIG_RBPL_SIZE * sizeof(struct he_virt), GFP_KERNEL);
+ if (he_dev->rbpl_virt == NULL) {
+ hprintk("failed to alloc rbpl_virt\n");
+ goto out_free_rbpl_base;
+ }
for (i = 0; i < CONFIG_RBPL_SIZE; ++i) {
dma_addr_t dma_handle;
@@ -845,7 +853,7 @@ he_init_group(struct he_dev *he_dev, int group)
cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &dma_handle);
if (cpuaddr == NULL)
- return -ENOMEM;
+ goto out_free_rbpl_virt;
he_dev->rbpl_virt[i].virt = cpuaddr;
he_dev->rbpl_base[i].status = RBP_LOANED | (i << RBP_INDEX_OFF);
@@ -870,7 +878,7 @@ he_init_group(struct he_dev *he_dev, int group)
CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), &he_dev->rbrq_phys);
if (he_dev->rbrq_base == NULL) {
hprintk("failed to allocate rbrq\n");
- return -ENOMEM;
+ goto out_free_rbpl_virt;
}
memset(he_dev->rbrq_base, 0, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq));
@@ -894,7 +902,7 @@ he_init_group(struct he_dev *he_dev, int group)
CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), &he_dev->tbrq_phys);
if (he_dev->tbrq_base == NULL) {
hprintk("failed to allocate tbrq\n");
- return -ENOMEM;
+ goto out_free_rbpq_base;
}
memset(he_dev->tbrq_base, 0, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq));
@@ -906,6 +914,39 @@ he_init_group(struct he_dev *he_dev, int group)
he_writel(he_dev, CONFIG_TBRQ_THRESH, G0_TBRQ_THRESH + (group * 16));
return 0;
+
+out_free_rbpq_base:
+ pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE *
+ sizeof(struct he_rbrq), he_dev->rbrq_base,
+ he_dev->rbrq_phys);
+ i = CONFIG_RBPL_SIZE;
+out_free_rbpl_virt:
+ while (i--)
+ pci_pool_free(he_dev->rbpl_pool, he_dev->rbpl_virt[i].virt,
+ he_dev->rbpl_base[i].phys);
+ kfree(he_dev->rbpl_virt);
+
+out_free_rbpl_base:
+ pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE *
+ sizeof(struct he_rbp), he_dev->rbpl_base,
+ he_dev->rbpl_phys);
+out_destroy_rbpl_pool:
+ pci_pool_destroy(he_dev->rbpl_pool);
+
+ i = CONFIG_RBPS_SIZE;
+out_free_rbps_virt:
+ while (i--)
+ pci_pool_free(he_dev->rbps_pool, he_dev->rbps_virt[i].virt,
+ he_dev->rbps_base[i].phys);
+ kfree(he_dev->rbps_virt);
+
+out_free_rbps_base:
+ pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE *
+ sizeof(struct he_rbp), he_dev->rbps_base,
+ he_dev->rbps_phys);
+out_destroy_rbps_pool:
+ pci_pool_destroy(he_dev->rbps_pool);
+ return -ENOMEM;
}
static int __devinit
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index 6b969f8c684f..4e49021e67ee 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -641,7 +641,7 @@ static int make_rate (const hrz_dev * dev, u32 c, rounding r,
pre = 1;
break;
case round_nearest:
- pre = (br+(c<<div)/2)/(c<<div);
+ pre = DIV_ROUND_CLOSEST(br, c<<div);
// but p must be non-zero
if (!pre)
pre = 1;
@@ -671,7 +671,7 @@ static int make_rate (const hrz_dev * dev, u32 c, rounding r,
pre = DIV_ROUND_UP(br, c<<div);
break;
case round_nearest:
- pre = (br+(c<<div)/2)/(c<<div);
+ pre = DIV_ROUND_CLOSEST(br, c<<div);
break;
default: /* round_up */
pre = br/(c<<div);
@@ -2590,7 +2590,7 @@ static int hrz_getsockopt (struct atm_vcc * atm_vcc, int level, int optname,
}
static int hrz_setsockopt (struct atm_vcc * atm_vcc, int level, int optname,
- void *optval, int optlen) {
+ void *optval, unsigned int optlen) {
hrz_dev * dev = HRZ_DEV(atm_vcc->dev);
PRINTD (DBG_FLOW|DBG_VCC, "hrz_setsockopt");
switch (level) {
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 78c9736c3579..b2c1b37ab2e4 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -2862,7 +2862,7 @@ static int ia_getsockopt(struct atm_vcc *vcc, int level, int optname,
}
static int ia_setsockopt(struct atm_vcc *vcc, int level, int optname,
- void __user *optval, int optlen)
+ void __user *optval, unsigned int optlen)
{
IF_EVENT(printk(">ia_setsockopt\n");)
return -EINVAL;
diff --git a/drivers/atm/solos-attrlist.c b/drivers/atm/solos-attrlist.c
index efa2808dd94d..1a9332e4efe0 100644
--- a/drivers/atm/solos-attrlist.c
+++ b/drivers/atm/solos-attrlist.c
@@ -25,6 +25,10 @@ SOLOS_ATTR_RO(RSCorrectedErrorsUp)
SOLOS_ATTR_RO(RSUnCorrectedErrorsUp)
SOLOS_ATTR_RO(InterleaveRDn)
SOLOS_ATTR_RO(InterleaveRUp)
+SOLOS_ATTR_RO(BisRDn)
+SOLOS_ATTR_RO(BisRUp)
+SOLOS_ATTR_RO(INPdown)
+SOLOS_ATTR_RO(INPup)
SOLOS_ATTR_RO(ShowtimeStart)
SOLOS_ATTR_RO(ATURVendor)
SOLOS_ATTR_RO(ATUCCountry)
@@ -62,6 +66,13 @@ SOLOS_ATTR_RW(Defaults)
SOLOS_ATTR_RW(LineMode)
SOLOS_ATTR_RW(Profile)
SOLOS_ATTR_RW(DetectNoise)
+SOLOS_ATTR_RW(BisAForceSNRMarginDn)
+SOLOS_ATTR_RW(BisMForceSNRMarginDn)
+SOLOS_ATTR_RW(BisAMaxMargin)
+SOLOS_ATTR_RW(BisMMaxMargin)
+SOLOS_ATTR_RW(AnnexAForceSNRMarginDn)
+SOLOS_ATTR_RW(AnnexAMaxMargin)
+SOLOS_ATTR_RW(AnnexMMaxMargin)
SOLOS_ATTR_RO(SupportedAnnexes)
SOLOS_ATTR_RO(Status)
SOLOS_ATTR_RO(TotalStart)
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 9359613addc5..c5f5186d62a3 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -59,21 +59,29 @@
#define RX_DMA_ADDR(port) (0x30 + (4 * (port)))
#define DATA_RAM_SIZE 32768
-#define BUF_SIZE 4096
+#define BUF_SIZE 2048
+#define OLD_BUF_SIZE 4096 /* For FPGA versions <= 2*/
#define FPGA_PAGE 528 /* FPGA flash page size*/
#define SOLOS_PAGE 512 /* Solos flash page size*/
#define FPGA_BLOCK (FPGA_PAGE * 8) /* FPGA flash block size*/
#define SOLOS_BLOCK (SOLOS_PAGE * 8) /* Solos flash block size*/
-#define RX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2)
-#define TX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2 + BUF_SIZE)
+#define RX_BUF(card, nr) ((card->buffers) + (nr)*(card->buffer_size)*2)
+#define TX_BUF(card, nr) ((card->buffers) + (nr)*(card->buffer_size)*2 + (card->buffer_size))
+#define FLASH_BUF ((card->buffers) + 4*(card->buffer_size)*2)
#define RX_DMA_SIZE 2048
+#define FPGA_VERSION(a,b) (((a) << 8) + (b))
+#define LEGACY_BUFFERS 2
+#define DMA_SUPPORTED 4
+
static int reset = 0;
static int atmdebug = 0;
static int firmware_upgrade = 0;
static int fpga_upgrade = 0;
+static int db_firmware_upgrade = 0;
+static int db_fpga_upgrade = 0;
struct pkt_hdr {
__le16 size;
@@ -116,6 +124,8 @@ struct solos_card {
wait_queue_head_t param_wq;
wait_queue_head_t fw_wq;
int using_dma;
+ int fpga_version;
+ int buffer_size;
};
@@ -136,10 +146,14 @@ MODULE_PARM_DESC(reset, "Reset Solos chips on startup");
MODULE_PARM_DESC(atmdebug, "Print ATM data");
MODULE_PARM_DESC(firmware_upgrade, "Initiate Solos firmware upgrade");
MODULE_PARM_DESC(fpga_upgrade, "Initiate FPGA upgrade");
+MODULE_PARM_DESC(db_firmware_upgrade, "Initiate daughter board Solos firmware upgrade");
+MODULE_PARM_DESC(db_fpga_upgrade, "Initiate daughter board FPGA upgrade");
module_param(reset, int, 0444);
module_param(atmdebug, int, 0644);
module_param(firmware_upgrade, int, 0444);
module_param(fpga_upgrade, int, 0444);
+module_param(db_firmware_upgrade, int, 0444);
+module_param(db_fpga_upgrade, int, 0444);
static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
struct atm_vcc *vcc);
@@ -372,7 +386,7 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb
}
snr = next_string(skb);
- if (!str)
+ if (!snr)
return -EIO;
attn = next_string(skb);
if (!attn)
@@ -517,10 +531,32 @@ static int flash_upgrade(struct solos_card *card, int chip)
if (chip == 0) {
fw_name = "solos-FPGA.bin";
blocksize = FPGA_BLOCK;
- } else {
+ }
+
+ if (chip == 1) {
fw_name = "solos-Firmware.bin";
blocksize = SOLOS_BLOCK;
}
+
+ if (chip == 2){
+ if (card->fpga_version > LEGACY_BUFFERS){
+ fw_name = "solos-db-FPGA.bin";
+ blocksize = FPGA_BLOCK;
+ } else {
+ dev_info(&card->dev->dev, "FPGA version doesn't support daughter board upgrades\n");
+ return -EPERM;
+ }
+ }
+
+ if (chip == 3){
+ if (card->fpga_version > LEGACY_BUFFERS){
+ fw_name = "solos-Firmware.bin";
+ blocksize = SOLOS_BLOCK;
+ } else {
+ dev_info(&card->dev->dev, "FPGA version doesn't support daughter board upgrades\n");
+ return -EPERM;
+ }
+ }
if (request_firmware(&fw, fw_name, &card->dev->dev))
return -ENOENT;
@@ -536,8 +572,10 @@ static int flash_upgrade(struct solos_card *card, int chip)
data32 = ioread32(card->config_regs + FPGA_MODE);
/* Set mode to Chip Erase */
- dev_info(&card->dev->dev, "Set FPGA Flash mode to %s Chip Erase\n",
- chip?"Solos":"FPGA");
+ if(chip == 0 || chip == 2)
+ dev_info(&card->dev->dev, "Set FPGA Flash mode to FPGA Chip Erase\n");
+ if(chip == 1 || chip == 3)
+ dev_info(&card->dev->dev, "Set FPGA Flash mode to Solos Chip Erase\n");
iowrite32((chip * 2), card->config_regs + FLASH_MODE);
@@ -557,7 +595,10 @@ static int flash_upgrade(struct solos_card *card, int chip)
/* Copy block to buffer, swapping each 16 bits */
for(i = 0; i < blocksize; i += 4) {
uint32_t word = swahb32p((uint32_t *)(fw->data + offset + i));
- iowrite32(word, RX_BUF(card, 3) + i);
+ if(card->fpga_version > LEGACY_BUFFERS)
+ iowrite32(word, FLASH_BUF + i);
+ else
+ iowrite32(word, RX_BUF(card, 3) + i);
}
/* Specify block number and then trigger flash write */
@@ -630,6 +671,10 @@ void solos_bh(unsigned long card_arg)
memcpy_fromio(header, RX_BUF(card, port), sizeof(*header));
size = le16_to_cpu(header->size);
+ if (size > (card->buffer_size - sizeof(*header))){
+ dev_warn(&card->dev->dev, "Invalid buffer size\n");
+ continue;
+ }
skb = alloc_skb(size + 1, GFP_ATOMIC);
if (!skb) {
@@ -1094,12 +1139,18 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
fpga_ver = (data32 & 0x0000FFFF);
major_ver = ((data32 & 0xFF000000) >> 24);
minor_ver = ((data32 & 0x00FF0000) >> 16);
+ card->fpga_version = FPGA_VERSION(major_ver,minor_ver);
+ if (card->fpga_version > LEGACY_BUFFERS)
+ card->buffer_size = BUF_SIZE;
+ else
+ card->buffer_size = OLD_BUF_SIZE;
dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n",
major_ver, minor_ver, fpga_ver);
- if (0 && fpga_ver > 27)
+ if (card->fpga_version >= DMA_SUPPORTED){
card->using_dma = 1;
- else {
+ } else {
+ card->using_dma = 0;
/* Set RX empty flag for all ports */
iowrite32(0xF0, card->config_regs + FLAGS_ADDR);
}
@@ -1131,6 +1182,12 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (firmware_upgrade)
flash_upgrade(card, 1);
+ if (db_fpga_upgrade)
+ flash_upgrade(card, 2);
+
+ if (db_firmware_upgrade)
+ flash_upgrade(card, 3);
+
err = atm_init(card);
if (err)
goto out_free_irq;
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index 752b1ba81f7e..2e9635be048c 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -1517,7 +1517,7 @@ static int zatm_getsockopt(struct atm_vcc *vcc,int level,int optname,
static int zatm_setsockopt(struct atm_vcc *vcc,int level,int optname,
- void __user *optval,int optlen)
+ void __user *optval,unsigned int optlen)
{
return -EINVAL;
}
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 8f006f96ff53..ee377270beb9 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -8,6 +8,31 @@ config UEVENT_HELPER_PATH
Path to uevent helper program forked by the kernel for
every uevent.
+config DEVTMPFS
+ bool "Create a kernel maintained /dev tmpfs (EXPERIMENTAL)"
+ depends on HOTPLUG && SHMEM && TMPFS
+ help
+ This creates a tmpfs filesystem, and mounts it at bootup
+ and mounts it at /dev. The kernel driver core creates device
+ nodes for all registered devices in that filesystem. All device
+ nodes are owned by root and have the default mode of 0600.
+ Userspace can add and delete the nodes as needed. This is
+ intended to simplify bootup, and make it possible to delay
+ the initial coldplug at bootup done by udev in userspace.
+ It should also provide a simpler way for rescue systems
+ to bring up a kernel with dynamic major/minor numbers.
+ Meaningful symlinks, permissions and device ownership must
+ still be handled by userspace.
+ If unsure, say N here.
+
+config DEVTMPFS_MOUNT
+ bool "Automount devtmpfs at /dev"
+ depends on DEVTMPFS
+ help
+ This will mount devtmpfs at /dev if the kernel mounts the root
+ filesystem. It will not affect initramfs based mounting.
+ If unsure, say N here.
+
config STANDALONE
bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
default y
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index b5b8ba512b28..c12c7f2f2a6f 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -4,8 +4,10 @@ obj-y := core.o sys.o bus.o dd.o \
driver.o class.o platform.o \
cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o
+obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
obj-y += power/
obj-$(CONFIG_HAS_DMA) += dma-mapping.o
+obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
obj-$(CONFIG_ISA) += isa.o
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
diff --git a/drivers/base/base.h b/drivers/base/base.h
index b528145a078f..2ca7f5b7b824 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -70,6 +70,8 @@ struct class_private {
* @knode_parent - node in sibling list
* @knode_driver - node in driver list
* @knode_bus - node in bus list
+ * @driver_data - private pointer for driver specific info. Will turn into a
+ * list soon.
* @device - pointer back to the struct class that this structure is
* associated with.
*
@@ -80,6 +82,7 @@ struct device_private {
struct klist_node knode_parent;
struct klist_node knode_driver;
struct klist_node knode_bus;
+ void *driver_data;
struct device *device;
};
#define to_device_private_parent(obj) \
@@ -89,6 +92,8 @@ struct device_private {
#define to_device_private_bus(obj) \
container_of(obj, struct device_private, knode_bus)
+extern int device_private_init(struct device *dev);
+
/* initialisation functions */
extern int devices_init(void);
extern int buses_init(void);
@@ -104,7 +109,7 @@ extern int system_bus_init(void);
extern int cpu_dev_init(void);
extern int bus_add_device(struct device *dev);
-extern void bus_attach_device(struct device *dev);
+extern void bus_probe_device(struct device *dev);
extern void bus_remove_device(struct device *dev);
extern int bus_add_driver(struct device_driver *drv);
@@ -134,3 +139,9 @@ static inline void module_add_driver(struct module *mod,
struct device_driver *drv) { }
static inline void module_remove_driver(struct device_driver *drv) { }
#endif
+
+#ifdef CONFIG_DEVTMPFS
+extern int devtmpfs_init(void);
+#else
+static inline int devtmpfs_init(void) { return 0; }
+#endif
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 4b04a15146d7..63c143e54a57 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -459,8 +459,9 @@ static inline void remove_deprecated_bus_links(struct device *dev) { }
* bus_add_device - add device to bus
* @dev: device being added
*
+ * - Add device's bus attributes.
+ * - Create links to device's bus.
* - Add the device to its bus's list of devices.
- * - Create link to device's bus.
*/
int bus_add_device(struct device *dev)
{
@@ -483,6 +484,7 @@ int bus_add_device(struct device *dev)
error = make_deprecated_bus_links(dev);
if (error)
goto out_deprecated;
+ klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
}
return 0;
@@ -498,24 +500,19 @@ out_put:
}
/**
- * bus_attach_device - add device to bus
- * @dev: device tried to attach to a driver
+ * bus_probe_device - probe drivers for a new device
+ * @dev: device to probe
*
- * - Add device to bus's list of devices.
- * - Try to attach to driver.
+ * - Automatically probe for a driver if the bus allows it.
*/
-void bus_attach_device(struct device *dev)
+void bus_probe_device(struct device *dev)
{
struct bus_type *bus = dev->bus;
- int ret = 0;
+ int ret;
- if (bus) {
- if (bus->p->drivers_autoprobe)
- ret = device_attach(dev);
+ if (bus && bus->p->drivers_autoprobe) {
+ ret = device_attach(dev);
WARN_ON(ret < 0);
- if (ret >= 0)
- klist_add_tail(&dev->p->knode_bus,
- &bus->p->klist_devices);
}
}
@@ -692,15 +689,19 @@ int bus_add_driver(struct device_driver *drv)
printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
__func__, drv->name);
}
- error = add_bind_files(drv);
- if (error) {
- /* Ditto */
- printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
- __func__, drv->name);
+
+ if (!drv->suppress_bind_attrs) {
+ error = add_bind_files(drv);
+ if (error) {
+ /* Ditto */
+ printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
+ __func__, drv->name);
+ }
}
kobject_uevent(&priv->kobj, KOBJ_ADD);
return 0;
+
out_unregister:
kfree(drv->p);
drv->p = NULL;
@@ -723,7 +724,8 @@ void bus_remove_driver(struct device_driver *drv)
if (!drv->bus)
return;
- remove_bind_files(drv);
+ if (!drv->suppress_bind_attrs)
+ remove_bind_files(drv);
driver_remove_attrs(drv->bus, drv);
driver_remove_file(drv, &driver_attr_uevent);
klist_remove(&drv->p->knode_bus);
diff --git a/drivers/base/class.c b/drivers/base/class.c
index eb85e4312301..161746deab4b 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -488,6 +488,93 @@ void class_interface_unregister(struct class_interface *class_intf)
class_put(parent);
}
+struct class_compat {
+ struct kobject *kobj;
+};
+
+/**
+ * class_compat_register - register a compatibility class
+ * @name: the name of the class
+ *
+ * Compatibility class are meant as a temporary user-space compatibility
+ * workaround when converting a family of class devices to a bus devices.
+ */
+struct class_compat *class_compat_register(const char *name)
+{
+ struct class_compat *cls;
+
+ cls = kmalloc(sizeof(struct class_compat), GFP_KERNEL);
+ if (!cls)
+ return NULL;
+ cls->kobj = kobject_create_and_add(name, &class_kset->kobj);
+ if (!cls->kobj) {
+ kfree(cls);
+ return NULL;
+ }
+ return cls;
+}
+EXPORT_SYMBOL_GPL(class_compat_register);
+
+/**
+ * class_compat_unregister - unregister a compatibility class
+ * @cls: the class to unregister
+ */
+void class_compat_unregister(struct class_compat *cls)
+{
+ kobject_put(cls->kobj);
+ kfree(cls);
+}
+EXPORT_SYMBOL_GPL(class_compat_unregister);
+
+/**
+ * class_compat_create_link - create a compatibility class device link to
+ * a bus device
+ * @cls: the compatibility class
+ * @dev: the target bus device
+ * @device_link: an optional device to which a "device" link should be created
+ */
+int class_compat_create_link(struct class_compat *cls, struct device *dev,
+ struct device *device_link)
+{
+ int error;
+
+ error = sysfs_create_link(cls->kobj, &dev->kobj, dev_name(dev));
+ if (error)
+ return error;
+
+ /*
+ * Optionally add a "device" link (typically to the parent), as a
+ * class device would have one and we want to provide as much
+ * backwards compatibility as possible.
+ */
+ if (device_link) {
+ error = sysfs_create_link(&dev->kobj, &device_link->kobj,
+ "device");
+ if (error)
+ sysfs_remove_link(cls->kobj, dev_name(dev));
+ }
+
+ return error;
+}
+EXPORT_SYMBOL_GPL(class_compat_create_link);
+
+/**
+ * class_compat_remove_link - remove a compatibility class device link to
+ * a bus device
+ * @cls: the compatibility class
+ * @dev: the target bus device
+ * @device_link: an optional device to which a "device" link was previously
+ * created
+ */
+void class_compat_remove_link(struct class_compat *cls, struct device *dev,
+ struct device *device_link)
+{
+ if (device_link)
+ sysfs_remove_link(&dev->kobj, "device");
+ sysfs_remove_link(cls->kobj, dev_name(dev));
+}
+EXPORT_SYMBOL_GPL(class_compat_remove_link);
+
int __init classes_init(void)
{
class_kset = kset_create_and_add("class", NULL, NULL);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 7ecb1938e590..6bee6af8d8e1 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -166,13 +166,16 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
if (MAJOR(dev->devt)) {
const char *tmp;
const char *name;
+ mode_t mode = 0;
add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
- name = device_get_nodename(dev, &tmp);
+ name = device_get_devnode(dev, &mode, &tmp);
if (name) {
add_uevent_var(env, "DEVNAME=%s", name);
kfree(tmp);
+ if (mode)
+ add_uevent_var(env, "DEVMODE=%#o", mode & 0777);
}
}
@@ -341,7 +344,7 @@ static void device_remove_attributes(struct device *dev,
}
static int device_add_groups(struct device *dev,
- struct attribute_group **groups)
+ const struct attribute_group **groups)
{
int error = 0;
int i;
@@ -361,7 +364,7 @@ static int device_add_groups(struct device *dev,
}
static void device_remove_groups(struct device *dev,
- struct attribute_group **groups)
+ const struct attribute_group **groups)
{
int i;
@@ -843,6 +846,17 @@ static void device_remove_sys_dev_entry(struct device *dev)
}
}
+int device_private_init(struct device *dev)
+{
+ dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);
+ if (!dev->p)
+ return -ENOMEM;
+ dev->p->device = dev;
+ klist_init(&dev->p->klist_children, klist_children_get,
+ klist_children_put);
+ return 0;
+}
+
/**
* device_add - add device to device hierarchy.
* @dev: device.
@@ -868,14 +882,11 @@ int device_add(struct device *dev)
if (!dev)
goto done;
- dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);
if (!dev->p) {
- error = -ENOMEM;
- goto done;
+ error = device_private_init(dev);
+ if (error)
+ goto done;
}
- dev->p->device = dev;
- klist_init(&dev->p->klist_children, klist_children_get,
- klist_children_put);
/*
* for statically allocated devices, which should all be converted
@@ -921,6 +932,8 @@ int device_add(struct device *dev)
error = device_create_sys_dev_entry(dev);
if (error)
goto devtattrError;
+
+ devtmpfs_create_node(dev);
}
error = device_add_class_symlinks(dev);
@@ -945,7 +958,7 @@ int device_add(struct device *dev)
BUS_NOTIFY_ADD_DEVICE, dev);
kobject_uevent(&dev->kobj, KOBJ_ADD);
- bus_attach_device(dev);
+ bus_probe_device(dev);
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);
@@ -1067,6 +1080,7 @@ void device_del(struct device *dev)
if (parent)
klist_del(&dev->p->knode_parent);
if (MAJOR(dev->devt)) {
+ devtmpfs_delete_node(dev);
device_remove_sys_dev_entry(dev);
device_remove_file(dev, &devt_attr);
}
@@ -1137,8 +1151,9 @@ static struct device *next_device(struct klist_iter *i)
}
/**
- * device_get_nodename - path of device node file
+ * device_get_devnode - path of device node file
* @dev: device
+ * @mode: returned file access mode
* @tmp: possibly allocated string
*
* Return the relative path of a possible device node.
@@ -1146,21 +1161,22 @@ static struct device *next_device(struct klist_iter *i)
* a name. This memory is returned in tmp and needs to be
* freed by the caller.
*/
-const char *device_get_nodename(struct device *dev, const char **tmp)
+const char *device_get_devnode(struct device *dev,
+ mode_t *mode, const char **tmp)
{
char *s;
*tmp = NULL;
/* the device type may provide a specific name */
- if (dev->type && dev->type->nodename)
- *tmp = dev->type->nodename(dev);
+ if (dev->type && dev->type->devnode)
+ *tmp = dev->type->devnode(dev, mode);
if (*tmp)
return *tmp;
/* the class may provide a specific name */
- if (dev->class && dev->class->nodename)
- *tmp = dev->class->nodename(dev);
+ if (dev->class && dev->class->devnode)
+ *tmp = dev->class->devnode(dev, mode);
if (*tmp)
return *tmp;
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index f0106875f01d..979d159b5cd1 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -11,8 +11,8 @@
*
* Copyright (c) 2002-5 Patrick Mochel
* Copyright (c) 2002-3 Open Source Development Labs
- * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
- * Copyright (c) 2007 Novell Inc.
+ * Copyright (c) 2007-2009 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (c) 2007-2009 Novell Inc.
*
* This file is released under the GPLv2
*/
@@ -23,6 +23,7 @@
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/async.h>
+#include <linux/pm_runtime.h>
#include "base.h"
#include "power/power.h"
@@ -202,7 +203,10 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
+ pm_runtime_get_noresume(dev);
+ pm_runtime_barrier(dev);
ret = really_probe(dev, drv);
+ pm_runtime_put_sync(dev);
return ret;
}
@@ -245,7 +249,9 @@ int device_attach(struct device *dev)
ret = 0;
}
} else {
+ pm_runtime_get_noresume(dev);
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
+ pm_runtime_put_sync(dev);
}
up(&dev->sem);
return ret;
@@ -306,6 +312,9 @@ static void __device_release_driver(struct device *dev)
drv = dev->driver;
if (drv) {
+ pm_runtime_get_noresume(dev);
+ pm_runtime_barrier(dev);
+
driver_sysfs_remove(dev);
if (dev->bus)
@@ -324,6 +333,8 @@ static void __device_release_driver(struct device *dev)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_UNBOUND_DRIVER,
dev);
+
+ pm_runtime_put_sync(dev);
}
}
@@ -380,3 +391,30 @@ void driver_detach(struct device_driver *drv)
put_device(dev);
}
}
+
+/*
+ * These exports can't be _GPL due to .h files using this within them, and it
+ * might break something that was previously working...
+ */
+void *dev_get_drvdata(const struct device *dev)
+{
+ if (dev && dev->p)
+ return dev->p->driver_data;
+ return NULL;
+}
+EXPORT_SYMBOL(dev_get_drvdata);
+
+void dev_set_drvdata(struct device *dev, void *data)
+{
+ int error;
+
+ if (!dev)
+ return;
+ if (!dev->p) {
+ error = device_private_init(dev);
+ if (error)
+ return;
+ }
+ dev->p->driver_data = data;
+}
+EXPORT_SYMBOL(dev_set_drvdata);
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
new file mode 100644
index 000000000000..a1cb5afe6801
--- /dev/null
+++ b/drivers/base/devtmpfs.c
@@ -0,0 +1,375 @@
+/*
+ * devtmpfs - kernel-maintained tmpfs-based /dev
+ *
+ * Copyright (C) 2009, Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * During bootup, before any driver core device is registered,
+ * devtmpfs, a tmpfs-based filesystem is created. Every driver-core
+ * device which requests a device node, will add a node in this
+ * filesystem.
+ * By default, all devices are named after the the name of the
+ * device, owned by root and have a default mode of 0600. Subsystems
+ * can overwrite the default setting if needed.
+ */
+
+#include <linux/kernel.h>
+#include <linux/syscalls.h>
+#include <linux/mount.h>
+#include <linux/device.h>
+#include <linux/genhd.h>
+#include <linux/namei.h>
+#include <linux/fs.h>
+#include <linux/shmem_fs.h>
+#include <linux/cred.h>
+#include <linux/sched.h>
+#include <linux/init_task.h>
+
+static struct vfsmount *dev_mnt;
+
+#if defined CONFIG_DEVTMPFS_MOUNT
+static int dev_mount = 1;
+#else
+static int dev_mount;
+#endif
+
+static int __init mount_param(char *str)
+{
+ dev_mount = simple_strtoul(str, NULL, 0);
+ return 1;
+}
+__setup("devtmpfs.mount=", mount_param);
+
+static int dev_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data, struct vfsmount *mnt)
+{
+ return get_sb_single(fs_type, flags, data, shmem_fill_super, mnt);
+}
+
+static struct file_system_type dev_fs_type = {
+ .name = "devtmpfs",
+ .get_sb = dev_get_sb,
+ .kill_sb = kill_litter_super,
+};
+
+#ifdef CONFIG_BLOCK
+static inline int is_blockdev(struct device *dev)
+{
+ return dev->class == &block_class;
+}
+#else
+static inline int is_blockdev(struct device *dev) { return 0; }
+#endif
+
+static int dev_mkdir(const char *name, mode_t mode)
+{
+ struct nameidata nd;
+ struct dentry *dentry;
+ int err;
+
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ name, LOOKUP_PARENT, &nd);
+ if (err)
+ return err;
+
+ dentry = lookup_create(&nd, 1);
+ if (!IS_ERR(dentry)) {
+ err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
+ dput(dentry);
+ } else {
+ err = PTR_ERR(dentry);
+ }
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+
+ path_put(&nd.path);
+ return err;
+}
+
+static int create_path(const char *nodepath)
+{
+ char *path;
+ struct nameidata nd;
+ int err = 0;
+
+ path = kstrdup(nodepath, GFP_KERNEL);
+ if (!path)
+ return -ENOMEM;
+
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ path, LOOKUP_PARENT, &nd);
+ if (err == 0) {
+ struct dentry *dentry;
+
+ /* create directory right away */
+ dentry = lookup_create(&nd, 1);
+ if (!IS_ERR(dentry)) {
+ err = vfs_mkdir(nd.path.dentry->d_inode,
+ dentry, 0755);
+ dput(dentry);
+ }
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+
+ path_put(&nd.path);
+ } else if (err == -ENOENT) {
+ char *s;
+
+ /* parent directories do not exist, create them */
+ s = path;
+ while (1) {
+ s = strchr(s, '/');
+ if (!s)
+ break;
+ s[0] = '\0';
+ err = dev_mkdir(path, 0755);
+ if (err && err != -EEXIST)
+ break;
+ s[0] = '/';
+ s++;
+ }
+ }
+
+ kfree(path);
+ return err;
+}
+
+int devtmpfs_create_node(struct device *dev)
+{
+ const char *tmp = NULL;
+ const char *nodename;
+ const struct cred *curr_cred;
+ mode_t mode = 0;
+ struct nameidata nd;
+ struct dentry *dentry;
+ int err;
+
+ if (!dev_mnt)
+ return 0;
+
+ nodename = device_get_devnode(dev, &mode, &tmp);
+ if (!nodename)
+ return -ENOMEM;
+
+ if (mode == 0)
+ mode = 0600;
+ if (is_blockdev(dev))
+ mode |= S_IFBLK;
+ else
+ mode |= S_IFCHR;
+
+ curr_cred = override_creds(&init_cred);
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ nodename, LOOKUP_PARENT, &nd);
+ if (err == -ENOENT) {
+ /* create missing parent directories */
+ create_path(nodename);
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ nodename, LOOKUP_PARENT, &nd);
+ if (err)
+ goto out;
+ }
+
+ dentry = lookup_create(&nd, 0);
+ if (!IS_ERR(dentry)) {
+ int umask;
+
+ umask = sys_umask(0000);
+ err = vfs_mknod(nd.path.dentry->d_inode,
+ dentry, mode, dev->devt);
+ sys_umask(umask);
+ /* mark as kernel created inode */
+ if (!err)
+ dentry->d_inode->i_private = &dev_mnt;
+ dput(dentry);
+ } else {
+ err = PTR_ERR(dentry);
+ }
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+
+ path_put(&nd.path);
+out:
+ kfree(tmp);
+ revert_creds(curr_cred);
+ return err;
+}
+
+static int dev_rmdir(const char *name)
+{
+ struct nameidata nd;
+ struct dentry *dentry;
+ int err;
+
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ name, LOOKUP_PARENT, &nd);
+ if (err)
+ return err;
+
+ mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
+ dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
+ if (!IS_ERR(dentry)) {
+ if (dentry->d_inode)
+ err = vfs_rmdir(nd.path.dentry->d_inode, dentry);
+ else
+ err = -ENOENT;
+ dput(dentry);
+ } else {
+ err = PTR_ERR(dentry);
+ }
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+
+ path_put(&nd.path);
+ return err;
+}
+
+static int delete_path(const char *nodepath)
+{
+ const char *path;
+ int err = 0;
+
+ path = kstrdup(nodepath, GFP_KERNEL);
+ if (!path)
+ return -ENOMEM;
+
+ while (1) {
+ char *base;
+
+ base = strrchr(path, '/');
+ if (!base)
+ break;
+ base[0] = '\0';
+ err = dev_rmdir(path);
+ if (err)
+ break;
+ }
+
+ kfree(path);
+ return err;
+}
+
+static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *stat)
+{
+ /* did we create it */
+ if (inode->i_private != &dev_mnt)
+ return 0;
+
+ /* does the dev_t match */
+ if (is_blockdev(dev)) {
+ if (!S_ISBLK(stat->mode))
+ return 0;
+ } else {
+ if (!S_ISCHR(stat->mode))
+ return 0;
+ }
+ if (stat->rdev != dev->devt)
+ return 0;
+
+ /* ours */
+ return 1;
+}
+
+int devtmpfs_delete_node(struct device *dev)
+{
+ const char *tmp = NULL;
+ const char *nodename;
+ const struct cred *curr_cred;
+ struct nameidata nd;
+ struct dentry *dentry;
+ struct kstat stat;
+ int deleted = 1;
+ int err;
+
+ if (!dev_mnt)
+ return 0;
+
+ nodename = device_get_devnode(dev, NULL, &tmp);
+ if (!nodename)
+ return -ENOMEM;
+
+ curr_cred = override_creds(&init_cred);
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ nodename, LOOKUP_PARENT, &nd);
+ if (err)
+ goto out;
+
+ mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
+ dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
+ if (!IS_ERR(dentry)) {
+ if (dentry->d_inode) {
+ err = vfs_getattr(nd.path.mnt, dentry, &stat);
+ if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
+ err = vfs_unlink(nd.path.dentry->d_inode,
+ dentry);
+ if (!err || err == -ENOENT)
+ deleted = 1;
+ }
+ } else {
+ err = -ENOENT;
+ }
+ dput(dentry);
+ } else {
+ err = PTR_ERR(dentry);
+ }
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+
+ path_put(&nd.path);
+ if (deleted && strchr(nodename, '/'))
+ delete_path(nodename);
+out:
+ kfree(tmp);
+ revert_creds(curr_cred);
+ return err;
+}
+
+/*
+ * If configured, or requested by the commandline, devtmpfs will be
+ * auto-mounted after the kernel mounted the root filesystem.
+ */
+int devtmpfs_mount(const char *mountpoint)
+{
+ struct path path;
+ int err;
+
+ if (!dev_mount)
+ return 0;
+
+ if (!dev_mnt)
+ return 0;
+
+ err = kern_path(mountpoint, LOOKUP_FOLLOW, &path);
+ if (err)
+ return err;
+ err = do_add_mount(dev_mnt, &path, 0, NULL);
+ if (err)
+ printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
+ else
+ printk(KERN_INFO "devtmpfs: mounted\n");
+ path_put(&path);
+ return err;
+}
+
+/*
+ * Create devtmpfs instance, driver-core devices will add their device
+ * nodes here.
+ */
+int __init devtmpfs_init(void)
+{
+ int err;
+ struct vfsmount *mnt;
+
+ err = register_filesystem(&dev_fs_type);
+ if (err) {
+ printk(KERN_ERR "devtmpfs: unable to register devtmpfs "
+ "type %i\n", err);
+ return err;
+ }
+
+ mnt = kern_mount(&dev_fs_type);
+ if (IS_ERR(mnt)) {
+ err = PTR_ERR(mnt);
+ printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err);
+ unregister_filesystem(&dev_fs_type);
+ return err;
+ }
+ dev_mnt = mnt;
+
+ printk(KERN_INFO "devtmpfs: initialized\n");
+ return 0;
+}
diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c
new file mode 100644
index 000000000000..962a3b574f21
--- /dev/null
+++ b/drivers/base/dma-coherent.c
@@ -0,0 +1,176 @@
+/*
+ * Coherent per-device memory handling.
+ * Borrowed from i386
+ */
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+
+struct dma_coherent_mem {
+ void *virt_base;
+ u32 device_base;
+ int size;
+ int flags;
+ unsigned long *bitmap;
+};
+
+int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
+ dma_addr_t device_addr, size_t size, int flags)
+{
+ void __iomem *mem_base = NULL;
+ int pages = size >> PAGE_SHIFT;
+ int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
+
+ if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
+ goto out;
+ if (!size)
+ goto out;
+ if (dev->dma_mem)
+ goto out;
+
+ /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
+
+ mem_base = ioremap(bus_addr, size);
+ if (!mem_base)
+ goto out;
+
+ dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
+ if (!dev->dma_mem)
+ goto out;
+ dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+ if (!dev->dma_mem->bitmap)
+ goto free1_out;
+
+ dev->dma_mem->virt_base = mem_base;
+ dev->dma_mem->device_base = device_addr;
+ dev->dma_mem->size = pages;
+ dev->dma_mem->flags = flags;
+
+ if (flags & DMA_MEMORY_MAP)
+ return DMA_MEMORY_MAP;
+
+ return DMA_MEMORY_IO;
+
+ free1_out:
+ kfree(dev->dma_mem);
+ out:
+ if (mem_base)
+ iounmap(mem_base);
+ return 0;
+}
+EXPORT_SYMBOL(dma_declare_coherent_memory);
+
+void dma_release_declared_memory(struct device *dev)
+{
+ struct dma_coherent_mem *mem = dev->dma_mem;
+
+ if (!mem)
+ return;
+ dev->dma_mem = NULL;
+ iounmap(mem->virt_base);
+ kfree(mem->bitmap);
+ kfree(mem);
+}
+EXPORT_SYMBOL(dma_release_declared_memory);
+
+void *dma_mark_declared_memory_occupied(struct device *dev,
+ dma_addr_t device_addr, size_t size)
+{
+ struct dma_coherent_mem *mem = dev->dma_mem;
+ int pos, err;
+
+ size += device_addr & ~PAGE_MASK;
+
+ if (!mem)
+ return ERR_PTR(-EINVAL);
+
+ pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
+ err = bitmap_allocate_region(mem->bitmap, pos, get_order(size));
+ if (err != 0)
+ return ERR_PTR(err);
+ return mem->virt_base + (pos << PAGE_SHIFT);
+}
+EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
+
+/**
+ * dma_alloc_from_coherent() - try to allocate memory from the per-device coherent area
+ *
+ * @dev: device from which we allocate memory
+ * @size: size of requested memory area
+ * @dma_handle: This will be filled with the correct dma handle
+ * @ret: This pointer will be filled with the virtual address
+ * to allocated area.
+ *
+ * This function should be only called from per-arch dma_alloc_coherent()
+ * to support allocation from per-device coherent memory pools.
+ *
+ * Returns 0 if dma_alloc_coherent should continue with allocating from
+ * generic memory areas, or !0 if dma_alloc_coherent should return @ret.
+ */
+int dma_alloc_from_coherent(struct device *dev, ssize_t size,
+ dma_addr_t *dma_handle, void **ret)
+{
+ struct dma_coherent_mem *mem;
+ int order = get_order(size);
+ int pageno;
+
+ if (!dev)
+ return 0;
+ mem = dev->dma_mem;
+ if (!mem)
+ return 0;
+
+ *ret = NULL;
+
+ if (unlikely(size > (mem->size << PAGE_SHIFT)))
+ goto err;
+
+ pageno = bitmap_find_free_region(mem->bitmap, mem->size, order);
+ if (unlikely(pageno < 0))
+ goto err;
+
+ /*
+ * Memory was found in the per-device area.
+ */
+ *dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
+ *ret = mem->virt_base + (pageno << PAGE_SHIFT);
+ memset(*ret, 0, size);
+
+ return 1;
+
+err:
+ /*
+ * In the case where the allocation can not be satisfied from the
+ * per-device area, try to fall back to generic memory if the
+ * constraints allow it.
+ */
+ return mem->flags & DMA_MEMORY_EXCLUSIVE;
+}
+EXPORT_SYMBOL(dma_alloc_from_coherent);
+
+/**
+ * dma_release_from_coherent() - try to free the memory allocated from per-device coherent memory pool
+ * @dev: device from which the memory was allocated
+ * @order: the order of pages allocated
+ * @vaddr: virtual address of allocated pages
+ *
+ * This checks whether the memory was allocated from the per-device
+ * coherent memory pool and if so, releases that memory.
+ *
+ * Returns 1 if we correctly released the memory, or 0 if
+ * dma_release_coherent() should proceed with releasing memory from
+ * generic pools.
+ */
+int dma_release_from_coherent(struct device *dev, int order, void *vaddr)
+{
+ struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
+
+ if (mem && vaddr >= mem->virt_base && vaddr <
+ (mem->virt_base + (mem->size << PAGE_SHIFT))) {
+ int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
+
+ bitmap_release_region(mem->bitmap, page, order);
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(dma_release_from_coherent);
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 8ae0f63602e0..f367885a7646 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -181,7 +181,7 @@ void put_driver(struct device_driver *drv)
EXPORT_SYMBOL_GPL(put_driver);
static int driver_add_groups(struct device_driver *drv,
- struct attribute_group **groups)
+ const struct attribute_group **groups)
{
int error = 0;
int i;
@@ -201,7 +201,7 @@ static int driver_add_groups(struct device_driver *drv,
}
static void driver_remove_groups(struct device_driver *drv,
- struct attribute_group **groups)
+ const struct attribute_group **groups)
{
int i;
@@ -236,7 +236,7 @@ int driver_register(struct device_driver *drv)
put_driver(other);
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
- return -EEXIST;
+ return -EBUSY;
}
ret = bus_add_driver(drv);
diff --git a/drivers/base/init.c b/drivers/base/init.c
index 7bd9b6a5b01f..c8a934e79421 100644
--- a/drivers/base/init.c
+++ b/drivers/base/init.c
@@ -20,6 +20,7 @@
void __init driver_init(void)
{
/* These are the core pieces */
+ devtmpfs_init();
devices_init();
buses_init();
classes_init();
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 91d4087b4039..1fe5536d404f 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -85,6 +85,8 @@ static ssize_t node_read_meminfo(struct sys_device * dev,
"Node %d FilePages: %8lu kB\n"
"Node %d Mapped: %8lu kB\n"
"Node %d AnonPages: %8lu kB\n"
+ "Node %d Shmem: %8lu kB\n"
+ "Node %d KernelStack: %8lu kB\n"
"Node %d PageTables: %8lu kB\n"
"Node %d NFS_Unstable: %8lu kB\n"
"Node %d Bounce: %8lu kB\n"
@@ -116,6 +118,9 @@ static ssize_t node_read_meminfo(struct sys_device * dev,
nid, K(node_page_state(nid, NR_FILE_PAGES)),
nid, K(node_page_state(nid, NR_FILE_MAPPED)),
nid, K(node_page_state(nid, NR_ANON_PAGES)),
+ nid, K(node_page_state(nid, NR_SHMEM)),
+ nid, node_page_state(nid, NR_KERNEL_STACK) *
+ THREAD_SIZE / 1024,
nid, K(node_page_state(nid, NR_PAGETABLE)),
nid, K(node_page_state(nid, NR_UNSTABLE_NFS)),
nid, K(node_page_state(nid, NR_BOUNCE)),
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 456594bd97bc..4fa954b07ac4 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -10,6 +10,7 @@
* information.
*/
+#include <linux/string.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -17,6 +18,7 @@
#include <linux/bootmem.h>
#include <linux/err.h>
#include <linux/slab.h>
+#include <linux/pm_runtime.h>
#include "base.h"
@@ -212,14 +214,13 @@ EXPORT_SYMBOL_GPL(platform_device_add_resources);
int platform_device_add_data(struct platform_device *pdev, const void *data,
size_t size)
{
- void *d;
+ void *d = kmemdup(data, size, GFP_KERNEL);
- d = kmalloc(size, GFP_KERNEL);
if (d) {
- memcpy(d, data, size);
pdev->dev.platform_data = d;
+ return 0;
}
- return d ? 0 : -ENOMEM;
+ return -ENOMEM;
}
EXPORT_SYMBOL_GPL(platform_device_add_data);
@@ -520,11 +521,15 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv,
{
int retval, code;
+ /* make sure driver won't have bind/unbind attributes */
+ drv->driver.suppress_bind_attrs = true;
+
/* temporary section violation during probe() */
drv->probe = probe;
retval = code = platform_driver_register(drv);
- /* Fixup that section violation, being paranoid about code scanning
+ /*
+ * Fixup that section violation, being paranoid about code scanning
* the list of drivers in order to probe new devices. Check to see
* if the probe was successful, and make sure any forced probes of
* new devices fail.
@@ -625,30 +630,6 @@ static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
return ret;
}
-static int platform_legacy_suspend_late(struct device *dev, pm_message_t mesg)
-{
- struct platform_driver *pdrv = to_platform_driver(dev->driver);
- struct platform_device *pdev = to_platform_device(dev);
- int ret = 0;
-
- if (dev->driver && pdrv->suspend_late)
- ret = pdrv->suspend_late(pdev, mesg);
-
- return ret;
-}
-
-static int platform_legacy_resume_early(struct device *dev)
-{
- struct platform_driver *pdrv = to_platform_driver(dev->driver);
- struct platform_device *pdev = to_platform_device(dev);
- int ret = 0;
-
- if (dev->driver && pdrv->resume_early)
- ret = pdrv->resume_early(pdev);
-
- return ret;
-}
-
static int platform_legacy_resume(struct device *dev)
{
struct platform_driver *pdrv = to_platform_driver(dev->driver);
@@ -680,6 +661,13 @@ static void platform_pm_complete(struct device *dev)
drv->pm->complete(dev);
}
+#else /* !CONFIG_PM_SLEEP */
+
+#define platform_pm_prepare NULL
+#define platform_pm_complete NULL
+
+#endif /* !CONFIG_PM_SLEEP */
+
#ifdef CONFIG_SUSPEND
static int platform_pm_suspend(struct device *dev)
@@ -711,8 +699,6 @@ static int platform_pm_suspend_noirq(struct device *dev)
if (drv->pm) {
if (drv->pm->suspend_noirq)
ret = drv->pm->suspend_noirq(dev);
- } else {
- ret = platform_legacy_suspend_late(dev, PMSG_SUSPEND);
}
return ret;
@@ -747,8 +733,6 @@ static int platform_pm_resume_noirq(struct device *dev)
if (drv->pm) {
if (drv->pm->resume_noirq)
ret = drv->pm->resume_noirq(dev);
- } else {
- ret = platform_legacy_resume_early(dev);
}
return ret;
@@ -794,8 +778,6 @@ static int platform_pm_freeze_noirq(struct device *dev)
if (drv->pm) {
if (drv->pm->freeze_noirq)
ret = drv->pm->freeze_noirq(dev);
- } else {
- ret = platform_legacy_suspend_late(dev, PMSG_FREEZE);
}
return ret;
@@ -830,8 +812,6 @@ static int platform_pm_thaw_noirq(struct device *dev)
if (drv->pm) {
if (drv->pm->thaw_noirq)
ret = drv->pm->thaw_noirq(dev);
- } else {
- ret = platform_legacy_resume_early(dev);
}
return ret;
@@ -866,8 +846,6 @@ static int platform_pm_poweroff_noirq(struct device *dev)
if (drv->pm) {
if (drv->pm->poweroff_noirq)
ret = drv->pm->poweroff_noirq(dev);
- } else {
- ret = platform_legacy_suspend_late(dev, PMSG_HIBERNATE);
}
return ret;
@@ -902,8 +880,6 @@ static int platform_pm_restore_noirq(struct device *dev)
if (drv->pm) {
if (drv->pm->restore_noirq)
ret = drv->pm->restore_noirq(dev);
- } else {
- ret = platform_legacy_resume_early(dev);
}
return ret;
@@ -922,7 +898,32 @@ static int platform_pm_restore_noirq(struct device *dev)
#endif /* !CONFIG_HIBERNATION */
-static struct dev_pm_ops platform_dev_pm_ops = {
+#ifdef CONFIG_PM_RUNTIME
+
+int __weak platform_pm_runtime_suspend(struct device *dev)
+{
+ return -ENOSYS;
+};
+
+int __weak platform_pm_runtime_resume(struct device *dev)
+{
+ return -ENOSYS;
+};
+
+int __weak platform_pm_runtime_idle(struct device *dev)
+{
+ return -ENOSYS;
+};
+
+#else /* !CONFIG_PM_RUNTIME */
+
+#define platform_pm_runtime_suspend NULL
+#define platform_pm_runtime_resume NULL
+#define platform_pm_runtime_idle NULL
+
+#endif /* !CONFIG_PM_RUNTIME */
+
+static const struct dev_pm_ops platform_dev_pm_ops = {
.prepare = platform_pm_prepare,
.complete = platform_pm_complete,
.suspend = platform_pm_suspend,
@@ -937,22 +938,17 @@ static struct dev_pm_ops platform_dev_pm_ops = {
.thaw_noirq = platform_pm_thaw_noirq,
.poweroff_noirq = platform_pm_poweroff_noirq,
.restore_noirq = platform_pm_restore_noirq,
+ .runtime_suspend = platform_pm_runtime_suspend,
+ .runtime_resume = platform_pm_runtime_resume,
+ .runtime_idle = platform_pm_runtime_idle,
};
-#define PLATFORM_PM_OPS_PTR (&platform_dev_pm_ops)
-
-#else /* !CONFIG_PM_SLEEP */
-
-#define PLATFORM_PM_OPS_PTR NULL
-
-#endif /* !CONFIG_PM_SLEEP */
-
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
- .pm = PLATFORM_PM_OPS_PTR,
+ .pm = &platform_dev_pm_ops,
};
EXPORT_SYMBOL_GPL(platform_bus_type);
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 911208b89259..3ce3519e8f30 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_PM) += sysfs.o
obj-$(CONFIG_PM_SLEEP) += main.o
+obj-$(CONFIG_PM_RUNTIME) += runtime.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 58a3e572f2c9..8aa2443182d5 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -21,6 +21,7 @@
#include <linux/kallsyms.h>
#include <linux/mutex.h>
#include <linux/pm.h>
+#include <linux/pm_runtime.h>
#include <linux/resume-trace.h>
#include <linux/rwsem.h>
#include <linux/interrupt.h>
@@ -49,7 +50,17 @@ static DEFINE_MUTEX(dpm_list_mtx);
static bool transition_started;
/**
- * device_pm_lock - lock the list of active devices used by the PM core
+ * device_pm_init - Initialize the PM-related part of a device object.
+ * @dev: Device object being initialized.
+ */
+void device_pm_init(struct device *dev)
+{
+ dev->power.status = DPM_ON;
+ pm_runtime_init(dev);
+}
+
+/**
+ * device_pm_lock - Lock the list of active devices used by the PM core.
*/
void device_pm_lock(void)
{
@@ -57,7 +68,7 @@ void device_pm_lock(void)
}
/**
- * device_pm_unlock - unlock the list of active devices used by the PM core
+ * device_pm_unlock - Unlock the list of active devices used by the PM core.
*/
void device_pm_unlock(void)
{
@@ -65,8 +76,8 @@ void device_pm_unlock(void)
}
/**
- * device_pm_add - add a device to the list of active devices
- * @dev: Device to be added to the list
+ * device_pm_add - Add a device to the PM core's list of active devices.
+ * @dev: Device to add to the list.
*/
void device_pm_add(struct device *dev)
{
@@ -92,10 +103,8 @@ void device_pm_add(struct device *dev)
}
/**
- * device_pm_remove - remove a device from the list of active devices
- * @dev: Device to be removed from the list
- *
- * This function also removes the device's PM-related sysfs attributes.
+ * device_pm_remove - Remove a device from the PM core's list of active devices.
+ * @dev: Device to be removed from the list.
*/
void device_pm_remove(struct device *dev)
{
@@ -105,12 +114,13 @@ void device_pm_remove(struct device *dev)
mutex_lock(&dpm_list_mtx);
list_del_init(&dev->power.entry);
mutex_unlock(&dpm_list_mtx);
+ pm_runtime_remove(dev);
}
/**
- * device_pm_move_before - move device in dpm_list
- * @deva: Device to move in dpm_list
- * @devb: Device @deva should come before
+ * device_pm_move_before - Move device in the PM core's list of active devices.
+ * @deva: Device to move in dpm_list.
+ * @devb: Device @deva should come before.
*/
void device_pm_move_before(struct device *deva, struct device *devb)
{
@@ -124,9 +134,9 @@ void device_pm_move_before(struct device *deva, struct device *devb)
}
/**
- * device_pm_move_after - move device in dpm_list
- * @deva: Device to move in dpm_list
- * @devb: Device @deva should come after
+ * device_pm_move_after - Move device in the PM core's list of active devices.
+ * @deva: Device to move in dpm_list.
+ * @devb: Device @deva should come after.
*/
void device_pm_move_after(struct device *deva, struct device *devb)
{
@@ -140,8 +150,8 @@ void device_pm_move_after(struct device *deva, struct device *devb)
}
/**
- * device_pm_move_last - move device to end of dpm_list
- * @dev: Device to move in dpm_list
+ * device_pm_move_last - Move device to end of the PM core's list of devices.
+ * @dev: Device to move in dpm_list.
*/
void device_pm_move_last(struct device *dev)
{
@@ -152,13 +162,14 @@ void device_pm_move_last(struct device *dev)
}
/**
- * pm_op - execute the PM operation appropiate for given PM event
- * @dev: Device.
- * @ops: PM operations to choose from.
- * @state: PM transition of the system being carried out.
+ * pm_op - Execute the PM operation appropriate for given PM event.
+ * @dev: Device to handle.
+ * @ops: PM operations to choose from.
+ * @state: PM transition of the system being carried out.
*/
-static int pm_op(struct device *dev, struct dev_pm_ops *ops,
- pm_message_t state)
+static int pm_op(struct device *dev,
+ const struct dev_pm_ops *ops,
+ pm_message_t state)
{
int error = 0;
@@ -212,15 +223,16 @@ static int pm_op(struct device *dev, struct dev_pm_ops *ops,
}
/**
- * pm_noirq_op - execute the PM operation appropiate for given PM event
- * @dev: Device.
- * @ops: PM operations to choose from.
- * @state: PM transition of the system being carried out.
+ * pm_noirq_op - Execute the PM operation appropriate for given PM event.
+ * @dev: Device to handle.
+ * @ops: PM operations to choose from.
+ * @state: PM transition of the system being carried out.
*
- * The operation is executed with interrupts disabled by the only remaining
- * functional CPU in the system.
+ * The driver of @dev will not receive interrupts while this function is being
+ * executed.
*/
-static int pm_noirq_op(struct device *dev, struct dev_pm_ops *ops,
+static int pm_noirq_op(struct device *dev,
+ const struct dev_pm_ops *ops,
pm_message_t state)
{
int error = 0;
@@ -315,11 +327,12 @@ static void pm_dev_err(struct device *dev, pm_message_t state, char *info,
/*------------------------- Resume routines -------------------------*/
/**
- * device_resume_noirq - Power on one device (early resume).
- * @dev: Device.
- * @state: PM transition of the system being carried out.
+ * device_resume_noirq - Execute an "early resume" callback for given device.
+ * @dev: Device to handle.
+ * @state: PM transition of the system being carried out.
*
- * Must be called with interrupts disabled.
+ * The driver of @dev will not receive interrupts while this function is being
+ * executed.
*/
static int device_resume_noirq(struct device *dev, pm_message_t state)
{
@@ -341,20 +354,18 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
}
/**
- * dpm_resume_noirq - Power on all regular (non-sysdev) devices.
- * @state: PM transition of the system being carried out.
- *
- * Call the "noirq" resume handlers for all devices marked as
- * DPM_OFF_IRQ and enable device drivers to receive interrupts.
+ * dpm_resume_noirq - Execute "early resume" callbacks for non-sysdev devices.
+ * @state: PM transition of the system being carried out.
*
- * Must be called under dpm_list_mtx. Device drivers should not receive
- * interrupts while it's being executed.
+ * Call the "noirq" resume handlers for all devices marked as DPM_OFF_IRQ and
+ * enable device drivers to receive interrupts.
*/
void dpm_resume_noirq(pm_message_t state)
{
struct device *dev;
mutex_lock(&dpm_list_mtx);
+ transition_started = false;
list_for_each_entry(dev, &dpm_list, power.entry)
if (dev->power.status > DPM_OFF) {
int error;
@@ -370,9 +381,9 @@ void dpm_resume_noirq(pm_message_t state)
EXPORT_SYMBOL_GPL(dpm_resume_noirq);
/**
- * device_resume - Restore state for one device.
- * @dev: Device.
- * @state: PM transition of the system being carried out.
+ * device_resume - Execute "resume" callbacks for given device.
+ * @dev: Device to handle.
+ * @state: PM transition of the system being carried out.
*/
static int device_resume(struct device *dev, pm_message_t state)
{
@@ -421,11 +432,11 @@ static int device_resume(struct device *dev, pm_message_t state)
}
/**
- * dpm_resume - Resume every device.
- * @state: PM transition of the system being carried out.
+ * dpm_resume - Execute "resume" callbacks for non-sysdev devices.
+ * @state: PM transition of the system being carried out.
*
- * Execute the appropriate "resume" callback for all devices the status of
- * which indicates that they are inactive.
+ * Execute the appropriate "resume" callback for all devices whose status
+ * indicates that they are suspended.
*/
static void dpm_resume(pm_message_t state)
{
@@ -433,7 +444,6 @@ static void dpm_resume(pm_message_t state)
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
- transition_started = false;
while (!list_empty(&dpm_list)) {
struct device *dev = to_device(dpm_list.next);
@@ -462,9 +472,9 @@ static void dpm_resume(pm_message_t state)
}
/**
- * device_complete - Complete a PM transition for given device
- * @dev: Device.
- * @state: PM transition of the system being carried out.
+ * device_complete - Complete a PM transition for given device.
+ * @dev: Device to handle.
+ * @state: PM transition of the system being carried out.
*/
static void device_complete(struct device *dev, pm_message_t state)
{
@@ -489,11 +499,11 @@ static void device_complete(struct device *dev, pm_message_t state)
}
/**
- * dpm_complete - Complete a PM transition for all devices.
- * @state: PM transition of the system being carried out.
+ * dpm_complete - Complete a PM transition for all non-sysdev devices.
+ * @state: PM transition of the system being carried out.
*
- * Execute the ->complete() callbacks for all devices that are not marked
- * as DPM_ON.
+ * Execute the ->complete() callbacks for all devices whose PM status is not
+ * DPM_ON (this allows new devices to be registered).
*/
static void dpm_complete(pm_message_t state)
{
@@ -501,6 +511,7 @@ static void dpm_complete(pm_message_t state)
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
+ transition_started = false;
while (!list_empty(&dpm_list)) {
struct device *dev = to_device(dpm_list.prev);
@@ -510,6 +521,7 @@ static void dpm_complete(pm_message_t state)
mutex_unlock(&dpm_list_mtx);
device_complete(dev, state);
+ pm_runtime_put_noidle(dev);
mutex_lock(&dpm_list_mtx);
}
@@ -522,11 +534,11 @@ static void dpm_complete(pm_message_t state)
}
/**
- * dpm_resume_end - Restore state of each device in system.
- * @state: PM transition of the system being carried out.
+ * dpm_resume_end - Execute "resume" callbacks and complete system transition.
+ * @state: PM transition of the system being carried out.
*
- * Resume all the devices, unlock them all, and allow new
- * devices to be registered once again.
+ * Execute "resume" callbacks for all devices and complete the PM transition of
+ * the system.
*/
void dpm_resume_end(pm_message_t state)
{
@@ -540,9 +552,11 @@ EXPORT_SYMBOL_GPL(dpm_resume_end);
/*------------------------- Suspend routines -------------------------*/
/**
- * resume_event - return a PM message representing the resume event
- * corresponding to given sleep state.
- * @sleep_state: PM message representing a sleep state.
+ * resume_event - Return a "resume" message for given "suspend" sleep state.
+ * @sleep_state: PM message representing a sleep state.
+ *
+ * Return a PM message representing the resume event corresponding to given
+ * sleep state.
*/
static pm_message_t resume_event(pm_message_t sleep_state)
{
@@ -559,11 +573,12 @@ static pm_message_t resume_event(pm_message_t sleep_state)
}
/**
- * device_suspend_noirq - Shut down one device (late suspend).
- * @dev: Device.
- * @state: PM transition of the system being carried out.
+ * device_suspend_noirq - Execute a "late suspend" callback for given device.
+ * @dev: Device to handle.
+ * @state: PM transition of the system being carried out.
*
- * This is called with interrupts off and only a single CPU running.
+ * The driver of @dev will not receive interrupts while this function is being
+ * executed.
*/
static int device_suspend_noirq(struct device *dev, pm_message_t state)
{
@@ -580,13 +595,11 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
}
/**
- * dpm_suspend_noirq - Power down all regular (non-sysdev) devices.
- * @state: PM transition of the system being carried out.
+ * dpm_suspend_noirq - Execute "late suspend" callbacks for non-sysdev devices.
+ * @state: PM transition of the system being carried out.
*
- * Prevent device drivers from receiving interrupts and call the "noirq"
- * suspend handlers.
- *
- * Must be called under dpm_list_mtx.
+ * Prevent device drivers from receiving interrupts and call the "noirq" suspend
+ * handlers for all non-sysdev devices.
*/
int dpm_suspend_noirq(pm_message_t state)
{
@@ -611,9 +624,9 @@ int dpm_suspend_noirq(pm_message_t state)
EXPORT_SYMBOL_GPL(dpm_suspend_noirq);
/**
- * device_suspend - Save state of one device.
- * @dev: Device.
- * @state: PM transition of the system being carried out.
+ * device_suspend - Execute "suspend" callbacks for given device.
+ * @dev: Device to handle.
+ * @state: PM transition of the system being carried out.
*/
static int device_suspend(struct device *dev, pm_message_t state)
{
@@ -660,10 +673,8 @@ static int device_suspend(struct device *dev, pm_message_t state)
}
/**
- * dpm_suspend - Suspend every device.
- * @state: PM transition of the system being carried out.
- *
- * Execute the appropriate "suspend" callbacks for all devices.
+ * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.
+ * @state: PM transition of the system being carried out.
*/
static int dpm_suspend(pm_message_t state)
{
@@ -697,9 +708,12 @@ static int dpm_suspend(pm_message_t state)
}
/**
- * device_prepare - Execute the ->prepare() callback(s) for given device.
- * @dev: Device.
- * @state: PM transition of the system being carried out.
+ * device_prepare - Prepare a device for system power transition.
+ * @dev: Device to handle.
+ * @state: PM transition of the system being carried out.
+ *
+ * Execute the ->prepare() callback(s) for given device. No new children of the
+ * device may be registered after this function has returned.
*/
static int device_prepare(struct device *dev, pm_message_t state)
{
@@ -735,10 +749,10 @@ static int device_prepare(struct device *dev, pm_message_t state)
}
/**
- * dpm_prepare - Prepare all devices for a PM transition.
- * @state: PM transition of the system being carried out.
+ * dpm_prepare - Prepare all non-sysdev devices for a system PM transition.
+ * @state: PM transition of the system being carried out.
*
- * Execute the ->prepare() callback for all devices.
+ * Execute the ->prepare() callback(s) for all devices.
*/
static int dpm_prepare(pm_message_t state)
{
@@ -755,7 +769,14 @@ static int dpm_prepare(pm_message_t state)
dev->power.status = DPM_PREPARING;
mutex_unlock(&dpm_list_mtx);
- error = device_prepare(dev, state);
+ pm_runtime_get_noresume(dev);
+ if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) {
+ /* Wake-up requested during system sleep transition. */
+ pm_runtime_put_noidle(dev);
+ error = -EBUSY;
+ } else {
+ error = device_prepare(dev, state);
+ }
mutex_lock(&dpm_list_mtx);
if (error) {
@@ -782,10 +803,11 @@ static int dpm_prepare(pm_message_t state)
}
/**
- * dpm_suspend_start - Save state and stop all devices in system.
- * @state: PM transition of the system being carried out.
+ * dpm_suspend_start - Prepare devices for PM transition and suspend them.
+ * @state: PM transition of the system being carried out.
*
- * Prepare and suspend all devices.
+ * Prepare all non-sysdev devices for system PM transition and execute "suspend"
+ * callbacks for them.
*/
int dpm_suspend_start(pm_message_t state)
{
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index c7cb4fc3735c..b8fa1aa5225a 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -1,7 +1,14 @@
-static inline void device_pm_init(struct device *dev)
-{
- dev->power.status = DPM_ON;
-}
+#ifdef CONFIG_PM_RUNTIME
+
+extern void pm_runtime_init(struct device *dev);
+extern void pm_runtime_remove(struct device *dev);
+
+#else /* !CONFIG_PM_RUNTIME */
+
+static inline void pm_runtime_init(struct device *dev) {}
+static inline void pm_runtime_remove(struct device *dev) {}
+
+#endif /* !CONFIG_PM_RUNTIME */
#ifdef CONFIG_PM_SLEEP
@@ -16,23 +23,33 @@ static inline struct device *to_device(struct list_head *entry)
return container_of(entry, struct device, power.entry);
}
+extern void device_pm_init(struct device *dev);
extern void device_pm_add(struct device *);
extern void device_pm_remove(struct device *);
extern void device_pm_move_before(struct device *, struct device *);
extern void device_pm_move_after(struct device *, struct device *);
extern void device_pm_move_last(struct device *);
-#else /* CONFIG_PM_SLEEP */
+#else /* !CONFIG_PM_SLEEP */
+
+static inline void device_pm_init(struct device *dev)
+{
+ pm_runtime_init(dev);
+}
+
+static inline void device_pm_remove(struct device *dev)
+{
+ pm_runtime_remove(dev);
+}
static inline void device_pm_add(struct device *dev) {}
-static inline void device_pm_remove(struct device *dev) {}
static inline void device_pm_move_before(struct device *deva,
struct device *devb) {}
static inline void device_pm_move_after(struct device *deva,
struct device *devb) {}
static inline void device_pm_move_last(struct device *dev) {}
-#endif
+#endif /* !CONFIG_PM_SLEEP */
#ifdef CONFIG_PM
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
new file mode 100644
index 000000000000..846d89e3d122
--- /dev/null
+++ b/drivers/base/power/runtime.c
@@ -0,0 +1,1007 @@
+/*
+ * drivers/base/power/runtime.c - Helper functions for device run-time PM
+ *
+ * Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/sched.h>
+#include <linux/pm_runtime.h>
+#include <linux/jiffies.h>
+
+static int __pm_runtime_resume(struct device *dev, bool from_wq);
+static int __pm_request_idle(struct device *dev);
+static int __pm_request_resume(struct device *dev);
+
+/**
+ * pm_runtime_deactivate_timer - Deactivate given device's suspend timer.
+ * @dev: Device to handle.
+ */
+static void pm_runtime_deactivate_timer(struct device *dev)
+{
+ if (dev->power.timer_expires > 0) {
+ del_timer(&dev->power.suspend_timer);
+ dev->power.timer_expires = 0;
+ }
+}
+
+/**
+ * pm_runtime_cancel_pending - Deactivate suspend timer and cancel requests.
+ * @dev: Device to handle.
+ */
+static void pm_runtime_cancel_pending(struct device *dev)
+{
+ pm_runtime_deactivate_timer(dev);
+ /*
+ * In case there's a request pending, make sure its work function will
+ * return without doing anything.
+ */
+ dev->power.request = RPM_REQ_NONE;
+}
+
+/**
+ * __pm_runtime_idle - Notify device bus type if the device can be suspended.
+ * @dev: Device to notify the bus type about.
+ *
+ * This function must be called under dev->power.lock with interrupts disabled.
+ */
+static int __pm_runtime_idle(struct device *dev)
+ __releases(&dev->power.lock) __acquires(&dev->power.lock)
+{
+ int retval = 0;
+
+ if (dev->power.runtime_error)
+ retval = -EINVAL;
+ else if (dev->power.idle_notification)
+ retval = -EINPROGRESS;
+ else if (atomic_read(&dev->power.usage_count) > 0
+ || dev->power.disable_depth > 0
+ || dev->power.runtime_status != RPM_ACTIVE)
+ retval = -EAGAIN;
+ else if (!pm_children_suspended(dev))
+ retval = -EBUSY;
+ if (retval)
+ goto out;
+
+ if (dev->power.request_pending) {
+ /*
+ * If an idle notification request is pending, cancel it. Any
+ * other pending request takes precedence over us.
+ */
+ if (dev->power.request == RPM_REQ_IDLE) {
+ dev->power.request = RPM_REQ_NONE;
+ } else if (dev->power.request != RPM_REQ_NONE) {
+ retval = -EAGAIN;
+ goto out;
+ }
+ }
+
+ dev->power.idle_notification = true;
+
+ if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) {
+ spin_unlock_irq(&dev->power.lock);
+
+ dev->bus->pm->runtime_idle(dev);
+
+ spin_lock_irq(&dev->power.lock);
+ }
+
+ dev->power.idle_notification = false;
+ wake_up_all(&dev->power.wait_queue);
+
+ out:
+ return retval;
+}
+
+/**
+ * pm_runtime_idle - Notify device bus type if the device can be suspended.
+ * @dev: Device to notify the bus type about.
+ */
+int pm_runtime_idle(struct device *dev)
+{
+ int retval;
+
+ spin_lock_irq(&dev->power.lock);
+ retval = __pm_runtime_idle(dev);
+ spin_unlock_irq(&dev->power.lock);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_idle);
+
+/**
+ * __pm_runtime_suspend - Carry out run-time suspend of given device.
+ * @dev: Device to suspend.
+ * @from_wq: If set, the function has been called via pm_wq.
+ *
+ * Check if the device can be suspended and run the ->runtime_suspend() callback
+ * provided by its bus type. If another suspend has been started earlier, wait
+ * for it to finish. If an idle notification or suspend request is pending or
+ * scheduled, cancel it.
+ *
+ * This function must be called under dev->power.lock with interrupts disabled.
+ */
+int __pm_runtime_suspend(struct device *dev, bool from_wq)
+ __releases(&dev->power.lock) __acquires(&dev->power.lock)
+{
+ struct device *parent = NULL;
+ bool notify = false;
+ int retval = 0;
+
+ dev_dbg(dev, "__pm_runtime_suspend()%s!\n",
+ from_wq ? " from workqueue" : "");
+
+ repeat:
+ if (dev->power.runtime_error) {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ /* Pending resume requests take precedence over us. */
+ if (dev->power.request_pending
+ && dev->power.request == RPM_REQ_RESUME) {
+ retval = -EAGAIN;
+ goto out;
+ }
+
+ /* Other scheduled or pending requests need to be canceled. */
+ pm_runtime_cancel_pending(dev);
+
+ if (dev->power.runtime_status == RPM_SUSPENDED)
+ retval = 1;
+ else if (dev->power.runtime_status == RPM_RESUMING
+ || dev->power.disable_depth > 0
+ || atomic_read(&dev->power.usage_count) > 0)
+ retval = -EAGAIN;
+ else if (!pm_children_suspended(dev))
+ retval = -EBUSY;
+ if (retval)
+ goto out;
+
+ if (dev->power.runtime_status == RPM_SUSPENDING) {
+ DEFINE_WAIT(wait);
+
+ if (from_wq) {
+ retval = -EINPROGRESS;
+ goto out;
+ }
+
+ /* Wait for the other suspend running in parallel with us. */
+ for (;;) {
+ prepare_to_wait(&dev->power.wait_queue, &wait,
+ TASK_UNINTERRUPTIBLE);
+ if (dev->power.runtime_status != RPM_SUSPENDING)
+ break;
+
+ spin_unlock_irq(&dev->power.lock);
+
+ schedule();
+
+ spin_lock_irq(&dev->power.lock);
+ }
+ finish_wait(&dev->power.wait_queue, &wait);
+ goto repeat;
+ }
+
+ dev->power.runtime_status = RPM_SUSPENDING;
+
+ if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
+ spin_unlock_irq(&dev->power.lock);
+
+ retval = dev->bus->pm->runtime_suspend(dev);
+
+ spin_lock_irq(&dev->power.lock);
+ dev->power.runtime_error = retval;
+ } else {
+ retval = -ENOSYS;
+ }
+
+ if (retval) {
+ dev->power.runtime_status = RPM_ACTIVE;
+ pm_runtime_cancel_pending(dev);
+ dev->power.deferred_resume = false;
+
+ if (retval == -EAGAIN || retval == -EBUSY) {
+ notify = true;
+ dev->power.runtime_error = 0;
+ }
+ } else {
+ dev->power.runtime_status = RPM_SUSPENDED;
+
+ if (dev->parent) {
+ parent = dev->parent;
+ atomic_add_unless(&parent->power.child_count, -1, 0);
+ }
+ }
+ wake_up_all(&dev->power.wait_queue);
+
+ if (dev->power.deferred_resume) {
+ dev->power.deferred_resume = false;
+ __pm_runtime_resume(dev, false);
+ retval = -EAGAIN;
+ goto out;
+ }
+
+ if (notify)
+ __pm_runtime_idle(dev);
+
+ if (parent && !parent->power.ignore_children) {
+ spin_unlock_irq(&dev->power.lock);
+
+ pm_request_idle(parent);
+
+ spin_lock_irq(&dev->power.lock);
+ }
+
+ out:
+ dev_dbg(dev, "__pm_runtime_suspend() returns %d!\n", retval);
+
+ return retval;
+}
+
+/**
+ * pm_runtime_suspend - Carry out run-time suspend of given device.
+ * @dev: Device to suspend.
+ */
+int pm_runtime_suspend(struct device *dev)
+{
+ int retval;
+
+ spin_lock_irq(&dev->power.lock);
+ retval = __pm_runtime_suspend(dev, false);
+ spin_unlock_irq(&dev->power.lock);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_suspend);
+
+/**
+ * __pm_runtime_resume - Carry out run-time resume of given device.
+ * @dev: Device to resume.
+ * @from_wq: If set, the function has been called via pm_wq.
+ *
+ * Check if the device can be woken up and run the ->runtime_resume() callback
+ * provided by its bus type. If another resume has been started earlier, wait
+ * for it to finish. If there's a suspend running in parallel with this
+ * function, wait for it to finish and resume the device. Cancel any scheduled
+ * or pending requests.
+ *
+ * This function must be called under dev->power.lock with interrupts disabled.
+ */
+int __pm_runtime_resume(struct device *dev, bool from_wq)
+ __releases(&dev->power.lock) __acquires(&dev->power.lock)
+{
+ struct device *parent = NULL;
+ int retval = 0;
+
+ dev_dbg(dev, "__pm_runtime_resume()%s!\n",
+ from_wq ? " from workqueue" : "");
+
+ repeat:
+ if (dev->power.runtime_error) {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ pm_runtime_cancel_pending(dev);
+
+ if (dev->power.runtime_status == RPM_ACTIVE)
+ retval = 1;
+ else if (dev->power.disable_depth > 0)
+ retval = -EAGAIN;
+ if (retval)
+ goto out;
+
+ if (dev->power.runtime_status == RPM_RESUMING
+ || dev->power.runtime_status == RPM_SUSPENDING) {
+ DEFINE_WAIT(wait);
+
+ if (from_wq) {
+ if (dev->power.runtime_status == RPM_SUSPENDING)
+ dev->power.deferred_resume = true;
+ retval = -EINPROGRESS;
+ goto out;
+ }
+
+ /* Wait for the operation carried out in parallel with us. */
+ for (;;) {
+ prepare_to_wait(&dev->power.wait_queue, &wait,
+ TASK_UNINTERRUPTIBLE);
+ if (dev->power.runtime_status != RPM_RESUMING
+ && dev->power.runtime_status != RPM_SUSPENDING)
+ break;
+
+ spin_unlock_irq(&dev->power.lock);
+
+ schedule();
+
+ spin_lock_irq(&dev->power.lock);
+ }
+ finish_wait(&dev->power.wait_queue, &wait);
+ goto repeat;
+ }
+
+ if (!parent && dev->parent) {
+ /*
+ * Increment the parent's resume counter and resume it if
+ * necessary.
+ */
+ parent = dev->parent;
+ spin_unlock(&dev->power.lock);
+
+ pm_runtime_get_noresume(parent);
+
+ spin_lock(&parent->power.lock);
+ /*
+ * We can resume if the parent's run-time PM is disabled or it
+ * is set to ignore children.
+ */
+ if (!parent->power.disable_depth
+ && !parent->power.ignore_children) {
+ __pm_runtime_resume(parent, false);
+ if (parent->power.runtime_status != RPM_ACTIVE)
+ retval = -EBUSY;
+ }
+ spin_unlock(&parent->power.lock);
+
+ spin_lock(&dev->power.lock);
+ if (retval)
+ goto out;
+ goto repeat;
+ }
+
+ dev->power.runtime_status = RPM_RESUMING;
+
+ if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) {
+ spin_unlock_irq(&dev->power.lock);
+
+ retval = dev->bus->pm->runtime_resume(dev);
+
+ spin_lock_irq(&dev->power.lock);
+ dev->power.runtime_error = retval;
+ } else {
+ retval = -ENOSYS;
+ }
+
+ if (retval) {
+ dev->power.runtime_status = RPM_SUSPENDED;
+ pm_runtime_cancel_pending(dev);
+ } else {
+ dev->power.runtime_status = RPM_ACTIVE;
+ if (parent)
+ atomic_inc(&parent->power.child_count);
+ }
+ wake_up_all(&dev->power.wait_queue);
+
+ if (!retval)
+ __pm_request_idle(dev);
+
+ out:
+ if (parent) {
+ spin_unlock_irq(&dev->power.lock);
+
+ pm_runtime_put(parent);
+
+ spin_lock_irq(&dev->power.lock);
+ }
+
+ dev_dbg(dev, "__pm_runtime_resume() returns %d!\n", retval);
+
+ return retval;
+}
+
+/**
+ * pm_runtime_resume - Carry out run-time resume of given device.
+ * @dev: Device to suspend.
+ */
+int pm_runtime_resume(struct device *dev)
+{
+ int retval;
+
+ spin_lock_irq(&dev->power.lock);
+ retval = __pm_runtime_resume(dev, false);
+ spin_unlock_irq(&dev->power.lock);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_resume);
+
+/**
+ * pm_runtime_work - Universal run-time PM work function.
+ * @work: Work structure used for scheduling the execution of this function.
+ *
+ * Use @work to get the device object the work is to be done for, determine what
+ * is to be done and execute the appropriate run-time PM function.
+ */
+static void pm_runtime_work(struct work_struct *work)
+{
+ struct device *dev = container_of(work, struct device, power.work);
+ enum rpm_request req;
+
+ spin_lock_irq(&dev->power.lock);
+
+ if (!dev->power.request_pending)
+ goto out;
+
+ req = dev->power.request;
+ dev->power.request = RPM_REQ_NONE;
+ dev->power.request_pending = false;
+
+ switch (req) {
+ case RPM_REQ_NONE:
+ break;
+ case RPM_REQ_IDLE:
+ __pm_runtime_idle(dev);
+ break;
+ case RPM_REQ_SUSPEND:
+ __pm_runtime_suspend(dev, true);
+ break;
+ case RPM_REQ_RESUME:
+ __pm_runtime_resume(dev, true);
+ break;
+ }
+
+ out:
+ spin_unlock_irq(&dev->power.lock);
+}
+
+/**
+ * __pm_request_idle - Submit an idle notification request for given device.
+ * @dev: Device to handle.
+ *
+ * Check if the device's run-time PM status is correct for suspending the device
+ * and queue up a request to run __pm_runtime_idle() for it.
+ *
+ * This function must be called under dev->power.lock with interrupts disabled.
+ */
+static int __pm_request_idle(struct device *dev)
+{
+ int retval = 0;
+
+ if (dev->power.runtime_error)
+ retval = -EINVAL;
+ else if (atomic_read(&dev->power.usage_count) > 0
+ || dev->power.disable_depth > 0
+ || dev->power.runtime_status == RPM_SUSPENDED
+ || dev->power.runtime_status == RPM_SUSPENDING)
+ retval = -EAGAIN;
+ else if (!pm_children_suspended(dev))
+ retval = -EBUSY;
+ if (retval)
+ return retval;
+
+ if (dev->power.request_pending) {
+ /* Any requests other then RPM_REQ_IDLE take precedence. */
+ if (dev->power.request == RPM_REQ_NONE)
+ dev->power.request = RPM_REQ_IDLE;
+ else if (dev->power.request != RPM_REQ_IDLE)
+ retval = -EAGAIN;
+ return retval;
+ }
+
+ dev->power.request = RPM_REQ_IDLE;
+ dev->power.request_pending = true;
+ queue_work(pm_wq, &dev->power.work);
+
+ return retval;
+}
+
+/**
+ * pm_request_idle - Submit an idle notification request for given device.
+ * @dev: Device to handle.
+ */
+int pm_request_idle(struct device *dev)
+{
+ unsigned long flags;
+ int retval;
+
+ spin_lock_irqsave(&dev->power.lock, flags);
+ retval = __pm_request_idle(dev);
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(pm_request_idle);
+
+/**
+ * __pm_request_suspend - Submit a suspend request for given device.
+ * @dev: Device to suspend.
+ *
+ * This function must be called under dev->power.lock with interrupts disabled.
+ */
+static int __pm_request_suspend(struct device *dev)
+{
+ int retval = 0;
+
+ if (dev->power.runtime_error)
+ return -EINVAL;
+
+ if (dev->power.runtime_status == RPM_SUSPENDED)
+ retval = 1;
+ else if (atomic_read(&dev->power.usage_count) > 0
+ || dev->power.disable_depth > 0)
+ retval = -EAGAIN;
+ else if (dev->power.runtime_status == RPM_SUSPENDING)
+ retval = -EINPROGRESS;
+ else if (!pm_children_suspended(dev))
+ retval = -EBUSY;
+ if (retval < 0)
+ return retval;
+
+ pm_runtime_deactivate_timer(dev);
+
+ if (dev->power.request_pending) {
+ /*
+ * Pending resume requests take precedence over us, but we can
+ * overtake any other pending request.
+ */
+ if (dev->power.request == RPM_REQ_RESUME)
+ retval = -EAGAIN;
+ else if (dev->power.request != RPM_REQ_SUSPEND)
+ dev->power.request = retval ?
+ RPM_REQ_NONE : RPM_REQ_SUSPEND;
+ return retval;
+ } else if (retval) {
+ return retval;
+ }
+
+ dev->power.request = RPM_REQ_SUSPEND;
+ dev->power.request_pending = true;
+ queue_work(pm_wq, &dev->power.work);
+
+ return 0;
+}
+
+/**
+ * pm_suspend_timer_fn - Timer function for pm_schedule_suspend().
+ * @data: Device pointer passed by pm_schedule_suspend().
+ *
+ * Check if the time is right and execute __pm_request_suspend() in that case.
+ */
+static void pm_suspend_timer_fn(unsigned long data)
+{
+ struct device *dev = (struct device *)data;
+ unsigned long flags;
+ unsigned long expires;
+
+ spin_lock_irqsave(&dev->power.lock, flags);
+
+ expires = dev->power.timer_expires;
+ /* If 'expire' is after 'jiffies' we've been called too early. */
+ if (expires > 0 && !time_after(expires, jiffies)) {
+ dev->power.timer_expires = 0;
+ __pm_request_suspend(dev);
+ }
+
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+}
+
+/**
+ * pm_schedule_suspend - Set up a timer to submit a suspend request in future.
+ * @dev: Device to suspend.
+ * @delay: Time to wait before submitting a suspend request, in milliseconds.
+ */
+int pm_schedule_suspend(struct device *dev, unsigned int delay)
+{
+ unsigned long flags;
+ int retval = 0;
+
+ spin_lock_irqsave(&dev->power.lock, flags);
+
+ if (dev->power.runtime_error) {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ if (!delay) {
+ retval = __pm_request_suspend(dev);
+ goto out;
+ }
+
+ pm_runtime_deactivate_timer(dev);
+
+ if (dev->power.request_pending) {
+ /*
+ * Pending resume requests take precedence over us, but any
+ * other pending requests have to be canceled.
+ */
+ if (dev->power.request == RPM_REQ_RESUME) {
+ retval = -EAGAIN;
+ goto out;
+ }
+ dev->power.request = RPM_REQ_NONE;
+ }
+
+ if (dev->power.runtime_status == RPM_SUSPENDED)
+ retval = 1;
+ else if (dev->power.runtime_status == RPM_SUSPENDING)
+ retval = -EINPROGRESS;
+ else if (atomic_read(&dev->power.usage_count) > 0
+ || dev->power.disable_depth > 0)
+ retval = -EAGAIN;
+ else if (!pm_children_suspended(dev))
+ retval = -EBUSY;
+ if (retval)
+ goto out;
+
+ dev->power.timer_expires = jiffies + msecs_to_jiffies(delay);
+ mod_timer(&dev->power.suspend_timer, dev->power.timer_expires);
+
+ out:
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(pm_schedule_suspend);
+
+/**
+ * pm_request_resume - Submit a resume request for given device.
+ * @dev: Device to resume.
+ *
+ * This function must be called under dev->power.lock with interrupts disabled.
+ */
+static int __pm_request_resume(struct device *dev)
+{
+ int retval = 0;
+
+ if (dev->power.runtime_error)
+ return -EINVAL;
+
+ if (dev->power.runtime_status == RPM_ACTIVE)
+ retval = 1;
+ else if (dev->power.runtime_status == RPM_RESUMING)
+ retval = -EINPROGRESS;
+ else if (dev->power.disable_depth > 0)
+ retval = -EAGAIN;
+ if (retval < 0)
+ return retval;
+
+ pm_runtime_deactivate_timer(dev);
+
+ if (dev->power.request_pending) {
+ /* If non-resume request is pending, we can overtake it. */
+ dev->power.request = retval ? RPM_REQ_NONE : RPM_REQ_RESUME;
+ return retval;
+ } else if (retval) {
+ return retval;
+ }
+
+ dev->power.request = RPM_REQ_RESUME;
+ dev->power.request_pending = true;
+ queue_work(pm_wq, &dev->power.work);
+
+ return retval;
+}
+
+/**
+ * pm_request_resume - Submit a resume request for given device.
+ * @dev: Device to resume.
+ */
+int pm_request_resume(struct device *dev)
+{
+ unsigned long flags;
+ int retval;
+
+ spin_lock_irqsave(&dev->power.lock, flags);
+ retval = __pm_request_resume(dev);
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(pm_request_resume);
+
+/**
+ * __pm_runtime_get - Reference count a device and wake it up, if necessary.
+ * @dev: Device to handle.
+ * @sync: If set and the device is suspended, resume it synchronously.
+ *
+ * Increment the usage count of the device and if it was zero previously,
+ * resume it or submit a resume request for it, depending on the value of @sync.
+ */
+int __pm_runtime_get(struct device *dev, bool sync)
+{
+ int retval = 1;
+
+ if (atomic_add_return(1, &dev->power.usage_count) == 1)
+ retval = sync ? pm_runtime_resume(dev) : pm_request_resume(dev);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(__pm_runtime_get);
+
+/**
+ * __pm_runtime_put - Decrement the device's usage counter and notify its bus.
+ * @dev: Device to handle.
+ * @sync: If the device's bus type is to be notified, do that synchronously.
+ *
+ * Decrement the usage count of the device and if it reaches zero, carry out a
+ * synchronous idle notification or submit an idle notification request for it,
+ * depending on the value of @sync.
+ */
+int __pm_runtime_put(struct device *dev, bool sync)
+{
+ int retval = 0;
+
+ if (atomic_dec_and_test(&dev->power.usage_count))
+ retval = sync ? pm_runtime_idle(dev) : pm_request_idle(dev);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(__pm_runtime_put);
+
+/**
+ * __pm_runtime_set_status - Set run-time PM status of a device.
+ * @dev: Device to handle.
+ * @status: New run-time PM status of the device.
+ *
+ * If run-time PM of the device is disabled or its power.runtime_error field is
+ * different from zero, the status may be changed either to RPM_ACTIVE, or to
+ * RPM_SUSPENDED, as long as that reflects the actual state of the device.
+ * However, if the device has a parent and the parent is not active, and the
+ * parent's power.ignore_children flag is unset, the device's status cannot be
+ * set to RPM_ACTIVE, so -EBUSY is returned in that case.
+ *
+ * If successful, __pm_runtime_set_status() clears the power.runtime_error field
+ * and the device parent's counter of unsuspended children is modified to
+ * reflect the new status. If the new status is RPM_SUSPENDED, an idle
+ * notification request for the parent is submitted.
+ */
+int __pm_runtime_set_status(struct device *dev, unsigned int status)
+{
+ struct device *parent = dev->parent;
+ unsigned long flags;
+ bool notify_parent = false;
+ int error = 0;
+
+ if (status != RPM_ACTIVE && status != RPM_SUSPENDED)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->power.lock, flags);
+
+ if (!dev->power.runtime_error && !dev->power.disable_depth) {
+ error = -EAGAIN;
+ goto out;
+ }
+
+ if (dev->power.runtime_status == status)
+ goto out_set;
+
+ if (status == RPM_SUSPENDED) {
+ /* It always is possible to set the status to 'suspended'. */
+ if (parent) {
+ atomic_add_unless(&parent->power.child_count, -1, 0);
+ notify_parent = !parent->power.ignore_children;
+ }
+ goto out_set;
+ }
+
+ if (parent) {
+ spin_lock(&parent->power.lock);
+
+ /*
+ * It is invalid to put an active child under a parent that is
+ * not active, has run-time PM enabled and the
+ * 'power.ignore_children' flag unset.
+ */
+ if (!parent->power.disable_depth
+ && !parent->power.ignore_children
+ && parent->power.runtime_status != RPM_ACTIVE) {
+ error = -EBUSY;
+ } else {
+ if (dev->power.runtime_status == RPM_SUSPENDED)
+ atomic_inc(&parent->power.child_count);
+ }
+
+ spin_unlock(&parent->power.lock);
+
+ if (error)
+ goto out;
+ }
+
+ out_set:
+ dev->power.runtime_status = status;
+ dev->power.runtime_error = 0;
+ out:
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+
+ if (notify_parent)
+ pm_request_idle(parent);
+
+ return error;
+}
+EXPORT_SYMBOL_GPL(__pm_runtime_set_status);
+
+/**
+ * __pm_runtime_barrier - Cancel pending requests and wait for completions.
+ * @dev: Device to handle.
+ *
+ * Flush all pending requests for the device from pm_wq and wait for all
+ * run-time PM operations involving the device in progress to complete.
+ *
+ * Should be called under dev->power.lock with interrupts disabled.
+ */
+static void __pm_runtime_barrier(struct device *dev)
+{
+ pm_runtime_deactivate_timer(dev);
+
+ if (dev->power.request_pending) {
+ dev->power.request = RPM_REQ_NONE;
+ spin_unlock_irq(&dev->power.lock);
+
+ cancel_work_sync(&dev->power.work);
+
+ spin_lock_irq(&dev->power.lock);
+ dev->power.request_pending = false;
+ }
+
+ if (dev->power.runtime_status == RPM_SUSPENDING
+ || dev->power.runtime_status == RPM_RESUMING
+ || dev->power.idle_notification) {
+ DEFINE_WAIT(wait);
+
+ /* Suspend, wake-up or idle notification in progress. */
+ for (;;) {
+ prepare_to_wait(&dev->power.wait_queue, &wait,
+ TASK_UNINTERRUPTIBLE);
+ if (dev->power.runtime_status != RPM_SUSPENDING
+ && dev->power.runtime_status != RPM_RESUMING
+ && !dev->power.idle_notification)
+ break;
+ spin_unlock_irq(&dev->power.lock);
+
+ schedule();
+
+ spin_lock_irq(&dev->power.lock);
+ }
+ finish_wait(&dev->power.wait_queue, &wait);
+ }
+}
+
+/**
+ * pm_runtime_barrier - Flush pending requests and wait for completions.
+ * @dev: Device to handle.
+ *
+ * Prevent the device from being suspended by incrementing its usage counter and
+ * if there's a pending resume request for the device, wake the device up.
+ * Next, make sure that all pending requests for the device have been flushed
+ * from pm_wq and wait for all run-time PM operations involving the device in
+ * progress to complete.
+ *
+ * Return value:
+ * 1, if there was a resume request pending and the device had to be woken up,
+ * 0, otherwise
+ */
+int pm_runtime_barrier(struct device *dev)
+{
+ int retval = 0;
+
+ pm_runtime_get_noresume(dev);
+ spin_lock_irq(&dev->power.lock);
+
+ if (dev->power.request_pending
+ && dev->power.request == RPM_REQ_RESUME) {
+ __pm_runtime_resume(dev, false);
+ retval = 1;
+ }
+
+ __pm_runtime_barrier(dev);
+
+ spin_unlock_irq(&dev->power.lock);
+ pm_runtime_put_noidle(dev);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_barrier);
+
+/**
+ * __pm_runtime_disable - Disable run-time PM of a device.
+ * @dev: Device to handle.
+ * @check_resume: If set, check if there's a resume request for the device.
+ *
+ * Increment power.disable_depth for the device and if was zero previously,
+ * cancel all pending run-time PM requests for the device and wait for all
+ * operations in progress to complete. The device can be either active or
+ * suspended after its run-time PM has been disabled.
+ *
+ * If @check_resume is set and there's a resume request pending when
+ * __pm_runtime_disable() is called and power.disable_depth is zero, the
+ * function will wake up the device before disabling its run-time PM.
+ */
+void __pm_runtime_disable(struct device *dev, bool check_resume)
+{
+ spin_lock_irq(&dev->power.lock);
+
+ if (dev->power.disable_depth > 0) {
+ dev->power.disable_depth++;
+ goto out;
+ }
+
+ /*
+ * Wake up the device if there's a resume request pending, because that
+ * means there probably is some I/O to process and disabling run-time PM
+ * shouldn't prevent the device from processing the I/O.
+ */
+ if (check_resume && dev->power.request_pending
+ && dev->power.request == RPM_REQ_RESUME) {
+ /*
+ * Prevent suspends and idle notifications from being carried
+ * out after we have woken up the device.
+ */
+ pm_runtime_get_noresume(dev);
+
+ __pm_runtime_resume(dev, false);
+
+ pm_runtime_put_noidle(dev);
+ }
+
+ if (!dev->power.disable_depth++)
+ __pm_runtime_barrier(dev);
+
+ out:
+ spin_unlock_irq(&dev->power.lock);
+}
+EXPORT_SYMBOL_GPL(__pm_runtime_disable);
+
+/**
+ * pm_runtime_enable - Enable run-time PM of a device.
+ * @dev: Device to handle.
+ */
+void pm_runtime_enable(struct device *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->power.lock, flags);
+
+ if (dev->power.disable_depth > 0)
+ dev->power.disable_depth--;
+ else
+ dev_warn(dev, "Unbalanced %s!\n", __func__);
+
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+}
+EXPORT_SYMBOL_GPL(pm_runtime_enable);
+
+/**
+ * pm_runtime_init - Initialize run-time PM fields in given device object.
+ * @dev: Device object to initialize.
+ */
+void pm_runtime_init(struct device *dev)
+{
+ spin_lock_init(&dev->power.lock);
+
+ dev->power.runtime_status = RPM_SUSPENDED;
+ dev->power.idle_notification = false;
+
+ dev->power.disable_depth = 1;
+ atomic_set(&dev->power.usage_count, 0);
+
+ dev->power.runtime_error = 0;
+
+ atomic_set(&dev->power.child_count, 0);
+ pm_suspend_ignore_children(dev, false);
+
+ dev->power.request_pending = false;
+ dev->power.request = RPM_REQ_NONE;
+ dev->power.deferred_resume = false;
+ INIT_WORK(&dev->power.work, pm_runtime_work);
+
+ dev->power.timer_expires = 0;
+ setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,
+ (unsigned long)dev);
+
+ init_waitqueue_head(&dev->power.wait_queue);
+}
+
+/**
+ * pm_runtime_remove - Prepare for removing a device from device hierarchy.
+ * @dev: Device object being removed from device hierarchy.
+ */
+void pm_runtime_remove(struct device *dev)
+{
+ __pm_runtime_disable(dev, false);
+
+ /* Change the status back to 'suspended' to match the initial status. */
+ if (dev->power.runtime_status == RPM_ACTIVE)
+ pm_runtime_set_suspended(dev);
+}
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 1e6b7c14f697..eb4fa1943944 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -38,6 +38,7 @@
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/reboot.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
@@ -152,7 +153,7 @@ static int DAC960_revalidate_disk(struct gendisk *disk)
return 0;
}
-static struct block_device_operations DAC960_BlockDeviceOperations = {
+static const struct block_device_operations DAC960_BlockDeviceOperations = {
.owner = THIS_MODULE,
.open = DAC960_open,
.getgeo = DAC960_getgeo,
@@ -6422,16 +6423,10 @@ static bool DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller,
return true;
}
-
-/*
- DAC960_ProcReadStatus implements reading /proc/rd/status.
-*/
-
-static int DAC960_ProcReadStatus(char *Page, char **Start, off_t Offset,
- int Count, int *EOF, void *Data)
+static int dac960_proc_show(struct seq_file *m, void *v)
{
unsigned char *StatusMessage = "OK\n";
- int ControllerNumber, BytesAvailable;
+ int ControllerNumber;
for (ControllerNumber = 0;
ControllerNumber < DAC960_ControllerCount;
ControllerNumber++)
@@ -6444,52 +6439,49 @@ static int DAC960_ProcReadStatus(char *Page, char **Start, off_t Offset,
break;
}
}
- BytesAvailable = strlen(StatusMessage) - Offset;
- if (Count >= BytesAvailable)
- {
- Count = BytesAvailable;
- *EOF = true;
- }
- if (Count <= 0) return 0;
- *Start = Page;
- memcpy(Page, &StatusMessage[Offset], Count);
- return Count;
+ seq_puts(m, StatusMessage);
+ return 0;
}
+static int dac960_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dac960_proc_show, NULL);
+}
-/*
- DAC960_ProcReadInitialStatus implements reading /proc/rd/cN/initial_status.
-*/
+static const struct file_operations dac960_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = dac960_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
-static int DAC960_ProcReadInitialStatus(char *Page, char **Start, off_t Offset,
- int Count, int *EOF, void *Data)
+static int dac960_initial_status_proc_show(struct seq_file *m, void *v)
{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
- int BytesAvailable = Controller->InitialStatusLength - Offset;
- if (Count >= BytesAvailable)
- {
- Count = BytesAvailable;
- *EOF = true;
- }
- if (Count <= 0) return 0;
- *Start = Page;
- memcpy(Page, &Controller->CombinedStatusBuffer[Offset], Count);
- return Count;
+ DAC960_Controller_T *Controller = (DAC960_Controller_T *)m->private;
+ seq_printf(m, "%.*s", Controller->InitialStatusLength, Controller->CombinedStatusBuffer);
+ return 0;
}
+static int dac960_initial_status_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dac960_initial_status_proc_show, PDE(inode)->data);
+}
-/*
- DAC960_ProcReadCurrentStatus implements reading /proc/rd/cN/current_status.
-*/
+static const struct file_operations dac960_initial_status_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = dac960_initial_status_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
-static int DAC960_ProcReadCurrentStatus(char *Page, char **Start, off_t Offset,
- int Count, int *EOF, void *Data)
+static int dac960_current_status_proc_show(struct seq_file *m, void *v)
{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
+ DAC960_Controller_T *Controller = (DAC960_Controller_T *) m->private;
unsigned char *StatusMessage =
"No Rebuild or Consistency Check in Progress\n";
int ProgressMessageLength = strlen(StatusMessage);
- int BytesAvailable;
if (jiffies != Controller->LastCurrentStatusTime)
{
Controller->CurrentStatusLength = 0;
@@ -6513,56 +6505,48 @@ static int DAC960_ProcReadCurrentStatus(char *Page, char **Start, off_t Offset,
}
Controller->LastCurrentStatusTime = jiffies;
}
- BytesAvailable = Controller->CurrentStatusLength - Offset;
- if (Count >= BytesAvailable)
- {
- Count = BytesAvailable;
- *EOF = true;
- }
- if (Count <= 0) return 0;
- *Start = Page;
- memcpy(Page, &Controller->CurrentStatusBuffer[Offset], Count);
- return Count;
+ seq_printf(m, "%.*s", Controller->CurrentStatusLength, Controller->CurrentStatusBuffer);
+ return 0;
}
+static int dac960_current_status_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dac960_current_status_proc_show, PDE(inode)->data);
+}
-/*
- DAC960_ProcReadUserCommand implements reading /proc/rd/cN/user_command.
-*/
+static const struct file_operations dac960_current_status_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = dac960_current_status_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
-static int DAC960_ProcReadUserCommand(char *Page, char **Start, off_t Offset,
- int Count, int *EOF, void *Data)
+static int dac960_user_command_proc_show(struct seq_file *m, void *v)
{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
- int BytesAvailable = Controller->UserStatusLength - Offset;
- if (Count >= BytesAvailable)
- {
- Count = BytesAvailable;
- *EOF = true;
- }
- if (Count <= 0) return 0;
- *Start = Page;
- memcpy(Page, &Controller->UserStatusBuffer[Offset], Count);
- return Count;
-}
+ DAC960_Controller_T *Controller = (DAC960_Controller_T *)m->private;
+ seq_printf(m, "%.*s", Controller->UserStatusLength, Controller->UserStatusBuffer);
+ return 0;
+}
-/*
- DAC960_ProcWriteUserCommand implements writing /proc/rd/cN/user_command.
-*/
+static int dac960_user_command_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dac960_user_command_proc_show, PDE(inode)->data);
+}
-static int DAC960_ProcWriteUserCommand(struct file *file,
+static ssize_t dac960_user_command_proc_write(struct file *file,
const char __user *Buffer,
- unsigned long Count, void *Data)
+ size_t Count, loff_t *pos)
{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
+ DAC960_Controller_T *Controller = (DAC960_Controller_T *) PDE(file->f_path.dentry->d_inode)->data;
unsigned char CommandBuffer[80];
int Length;
if (Count > sizeof(CommandBuffer)-1) return -EINVAL;
if (copy_from_user(CommandBuffer, Buffer, Count)) return -EFAULT;
CommandBuffer[Count] = '\0';
Length = strlen(CommandBuffer);
- if (CommandBuffer[Length-1] == '\n')
+ if (Length > 0 && CommandBuffer[Length-1] == '\n')
CommandBuffer[--Length] = '\0';
if (Controller->FirmwareType == DAC960_V1_Controller)
return (DAC960_V1_ExecuteUserCommand(Controller, CommandBuffer)
@@ -6572,6 +6556,14 @@ static int DAC960_ProcWriteUserCommand(struct file *file,
? Count : -EBUSY);
}
+static const struct file_operations dac960_user_command_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = dac960_user_command_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = dac960_user_command_proc_write,
+};
/*
DAC960_CreateProcEntries creates the /proc/rd/... entries for the
@@ -6586,23 +6578,17 @@ static void DAC960_CreateProcEntries(DAC960_Controller_T *Controller)
if (DAC960_ProcDirectoryEntry == NULL) {
DAC960_ProcDirectoryEntry = proc_mkdir("rd", NULL);
- StatusProcEntry = create_proc_read_entry("status", 0,
+ StatusProcEntry = proc_create("status", 0,
DAC960_ProcDirectoryEntry,
- DAC960_ProcReadStatus, NULL);
+ &dac960_proc_fops);
}
sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber);
ControllerProcEntry = proc_mkdir(Controller->ControllerName,
DAC960_ProcDirectoryEntry);
- create_proc_read_entry("initial_status", 0, ControllerProcEntry,
- DAC960_ProcReadInitialStatus, Controller);
- create_proc_read_entry("current_status", 0, ControllerProcEntry,
- DAC960_ProcReadCurrentStatus, Controller);
- UserCommandProcEntry =
- create_proc_read_entry("user_command", S_IWUSR | S_IRUSR,
- ControllerProcEntry, DAC960_ProcReadUserCommand,
- Controller);
- UserCommandProcEntry->write_proc = DAC960_ProcWriteUserCommand;
+ proc_create_data("initial_status", 0, ControllerProcEntry, &dac960_initial_status_proc_fops, Controller);
+ proc_create_data("current_status", 0, ControllerProcEntry, &dac960_current_status_proc_fops, Controller);
+ UserCommandProcEntry = proc_create_data("user_command", S_IWUSR | S_IRUSR, ControllerProcEntry, &dac960_user_command_proc_fops, Controller);
Controller->ControllerProcEntry = ControllerProcEntry;
}
@@ -6653,7 +6639,7 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request,
else ErrorCode = get_user(ControllerNumber,
&UserSpaceControllerInfo->ControllerNumber);
if (ErrorCode != 0)
- break;;
+ break;
ErrorCode = -ENXIO;
if (ControllerNumber < 0 ||
ControllerNumber > DAC960_ControllerCount - 1) {
@@ -6661,7 +6647,7 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request,
}
Controller = DAC960_Controllers[ControllerNumber];
if (Controller == NULL)
- break;;
+ break;
memset(&ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T));
ControllerInfo.ControllerNumber = ControllerNumber;
ControllerInfo.FirmwareType = Controller->FirmwareType;
@@ -7210,7 +7196,7 @@ static struct pci_driver DAC960_pci_driver = {
.remove = DAC960_Remove,
};
-static int DAC960_init_module(void)
+static int __init DAC960_init_module(void)
{
int ret;
@@ -7222,7 +7208,7 @@ static int DAC960_init_module(void)
return ret;
}
-static void DAC960_cleanup_module(void)
+static void __exit DAC960_cleanup_module(void)
{
int i;
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 2f07b7c99a95..055225839024 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1632,7 +1632,7 @@ static int amiga_floppy_change(struct gendisk *disk)
return 0;
}
-static struct block_device_operations floppy_fops = {
+static const struct block_device_operations floppy_fops = {
.owner = THIS_MODULE,
.open = floppy_open,
.release = floppy_release,
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index 95d344971eda..3af97d4da2db 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -172,6 +172,9 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio)
BUG();
bio_endio(bio, -ENXIO);
return 0;
+ } else if (bio_rw_flagged(bio, BIO_RW_BARRIER)) {
+ bio_endio(bio, -EOPNOTSUPP);
+ return 0;
} else if (bio->bi_io_vec == NULL) {
printk(KERN_ERR "aoe: bi_io_vec is NULL\n");
BUG();
@@ -234,7 +237,7 @@ aoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
-static struct block_device_operations aoe_bdops = {
+static const struct block_device_operations aoe_bdops = {
.open = aoeblk_open,
.release = aoeblk_release,
.getgeo = aoeblk_getgeo,
diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
index 19888354188f..62141ec09a22 100644
--- a/drivers/block/aoe/aoechr.c
+++ b/drivers/block/aoe/aoechr.c
@@ -266,7 +266,7 @@ static const struct file_operations aoe_fops = {
.owner = THIS_MODULE,
};
-static char *aoe_nodename(struct device *dev)
+static char *aoe_devnode(struct device *dev, mode_t *mode)
{
return kasprintf(GFP_KERNEL, "etherd/%s", dev_name(dev));
}
@@ -288,7 +288,7 @@ aoechr_init(void)
unregister_chrdev(AOE_MAJOR, "aoechr");
return PTR_ERR(aoe_class);
}
- aoe_class->nodename = aoe_nodename;
+ aoe_class->devnode = aoe_devnode;
for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
device_create(aoe_class, NULL,
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 965ece2c7e4d..13bb69d2abb3 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -735,6 +735,21 @@ diskstats(struct gendisk *disk, struct bio *bio, ulong duration, sector_t sector
part_stat_unlock();
}
+/*
+ * Ensure we don't create aliases in VI caches
+ */
+static inline void
+killalias(struct bio *bio)
+{
+ struct bio_vec *bv;
+ int i;
+
+ if (bio_data_dir(bio) == READ)
+ __bio_for_each_segment(bv, bio, i, 0) {
+ flush_dcache_page(bv->bv_page);
+ }
+}
+
void
aoecmd_ata_rsp(struct sk_buff *skb)
{
@@ -853,8 +868,12 @@ aoecmd_ata_rsp(struct sk_buff *skb)
if (buf && --buf->nframesout == 0 && buf->resid == 0) {
diskstats(d->gd, buf->bio, jiffies - buf->stime, buf->sector);
- n = (buf->flags & BUFFL_FAIL) ? -EIO : 0;
- bio_endio(buf->bio, n);
+ if (buf->flags & BUFFL_FAIL)
+ bio_endio(buf->bio, -EIO);
+ else {
+ killalias(buf->bio);
+ bio_endio(buf->bio, 0);
+ }
mempool_free(buf, d->bufpool);
}
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 3ff02941b3dd..847a9e57570a 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -1856,7 +1856,7 @@ static int floppy_release(struct gendisk *disk, fmode_t mode)
return 0;
}
-static struct block_device_operations floppy_fops = {
+static const struct block_device_operations floppy_fops = {
.owner = THIS_MODULE,
.open = floppy_open,
.release = floppy_release,
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index 4bf8705b3ace..4f688434daf1 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -375,7 +375,7 @@ static int brd_ioctl(struct block_device *bdev, fmode_t mode,
return error;
}
-static struct block_device_operations brd_fops = {
+static const struct block_device_operations brd_fops = {
.owner = THIS_MODULE,
.locked_ioctl = brd_ioctl,
#ifdef CONFIG_BLK_DEV_XIP
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index a52cc7fe45ea..92b126394fa1 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -36,9 +36,11 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/init.h>
+#include <linux/jiffies.h>
#include <linux/hdreg.h>
#include <linux/spinlock.h>
#include <linux/compat.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -66,6 +68,12 @@ MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
MODULE_VERSION("3.6.20");
MODULE_LICENSE("GPL");
+static int cciss_allow_hpsa;
+module_param(cciss_allow_hpsa, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(cciss_allow_hpsa,
+ "Prevent cciss driver from accessing hardware known to be "
+ " supported by the hpsa driver");
+
#include "cciss_cmd.h"
#include "cciss.h"
#include <linux/cciss_ioctl.h>
@@ -99,8 +107,6 @@ static const struct pci_device_id cciss_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324A},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324B},
- {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
{0,}
};
@@ -121,8 +127,6 @@ static struct board_type products[] = {
{0x409D0E11, "Smart Array 6400 EM", &SA5_access},
{0x40910E11, "Smart Array 6i", &SA5_access},
{0x3225103C, "Smart Array P600", &SA5_access},
- {0x3223103C, "Smart Array P800", &SA5_access},
- {0x3234103C, "Smart Array P400", &SA5_access},
{0x3235103C, "Smart Array P400i", &SA5_access},
{0x3211103C, "Smart Array E200i", &SA5_access},
{0x3212103C, "Smart Array E200", &SA5_access},
@@ -130,6 +134,10 @@ static struct board_type products[] = {
{0x3214103C, "Smart Array E200i", &SA5_access},
{0x3215103C, "Smart Array E200i", &SA5_access},
{0x3237103C, "Smart Array E500", &SA5_access},
+/* controllers below this line are also supported by the hpsa driver. */
+#define HPSA_BOUNDARY 0x3223103C
+ {0x3223103C, "Smart Array P800", &SA5_access},
+ {0x3234103C, "Smart Array P400", &SA5_access},
{0x323D103C, "Smart Array P700m", &SA5_access},
{0x3241103C, "Smart Array P212", &SA5_access},
{0x3243103C, "Smart Array P410", &SA5_access},
@@ -138,7 +146,6 @@ static struct board_type products[] = {
{0x3249103C, "Smart Array P812", &SA5_access},
{0x324A103C, "Smart Array P712m", &SA5_access},
{0x324B103C, "Smart Array P711m", &SA5_access},
- {0xFFFF103C, "Unknown Smart Array", &SA5_access},
};
/* How long to wait (in milliseconds) for board to go into simple mode */
@@ -155,6 +162,10 @@ static struct board_type products[] = {
static ctlr_info_t *hba[MAX_CTLR];
+static struct task_struct *cciss_scan_thread;
+static DEFINE_MUTEX(scan_mutex);
+static LIST_HEAD(scan_q);
+
static void do_cciss_request(struct request_queue *q);
static irqreturn_t do_cciss_intr(int irq, void *dev_id);
static int cciss_open(struct block_device *bdev, fmode_t mode);
@@ -164,9 +175,9 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo);
static int cciss_revalidate(struct gendisk *disk);
-static int rebuild_lun_table(ctlr_info_t *h, int first_time);
+static int rebuild_lun_table(ctlr_info_t *h, int first_time, int via_ioctl);
static int deregister_disk(ctlr_info_t *h, int drv_index,
- int clear_all);
+ int clear_all, int via_ioctl);
static void cciss_read_capacity(int ctlr, int logvol, int withirq,
sector_t *total_size, unsigned int *block_size);
@@ -189,8 +200,13 @@ static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c,
static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c);
static void fail_all_cmds(unsigned long ctlr);
+static int add_to_scan_list(struct ctlr_info *h);
static int scan_thread(void *data);
static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c);
+static void cciss_hba_release(struct device *dev);
+static void cciss_device_release(struct device *dev);
+static void cciss_free_gendisk(ctlr_info_t *h, int drv_index);
+static void cciss_free_drive_info(ctlr_info_t *h, int drv_index);
#ifdef CONFIG_PROC_FS
static void cciss_procinit(int i);
@@ -205,7 +221,7 @@ static int cciss_compat_ioctl(struct block_device *, fmode_t,
unsigned, unsigned long);
#endif
-static struct block_device_operations cciss_fops = {
+static const struct block_device_operations cciss_fops = {
.owner = THIS_MODULE,
.open = cciss_open,
.release = cciss_release,
@@ -245,7 +261,10 @@ static inline void removeQ(CommandList_struct *c)
#include "cciss_scsi.c" /* For SCSI tape support */
-#define RAID_UNKNOWN 6
+static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
+ "UNKNOWN"
+};
+#define RAID_UNKNOWN (sizeof(raid_label) / sizeof(raid_label[0])-1)
#ifdef CONFIG_PROC_FS
@@ -255,9 +274,6 @@ static inline void removeQ(CommandList_struct *c)
#define ENG_GIG 1000000000
#define ENG_GIG_FACTOR (ENG_GIG/512)
#define ENGAGE_SCSI "engage scsi"
-static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
- "UNKNOWN"
-};
static struct proc_dir_entry *proc_cciss;
@@ -318,7 +334,7 @@ static int cciss_seq_show(struct seq_file *seq, void *v)
ctlr_info_t *h = seq->private;
unsigned ctlr = h->ctlr;
loff_t *pos = v;
- drive_info_struct *drv = &h->drv[*pos];
+ drive_info_struct *drv = h->drv[*pos];
if (*pos > h->highest_lun)
return 0;
@@ -331,7 +347,7 @@ static int cciss_seq_show(struct seq_file *seq, void *v)
vol_sz_frac *= 100;
sector_div(vol_sz_frac, ENG_GIG_FACTOR);
- if (drv->raid_level > 5)
+ if (drv->raid_level < 0 || drv->raid_level > RAID_UNKNOWN)
drv->raid_level = RAID_UNKNOWN;
seq_printf(seq, "cciss/c%dd%d:"
"\t%4u.%02uGB\tRAID %s\n",
@@ -363,7 +379,7 @@ static void cciss_seq_stop(struct seq_file *seq, void *v)
h->busy_configuring = 0;
}
-static struct seq_operations cciss_seq_ops = {
+static const struct seq_operations cciss_seq_ops = {
.start = cciss_seq_start,
.show = cciss_seq_show,
.next = cciss_seq_next,
@@ -426,7 +442,7 @@ out:
return err;
}
-static struct file_operations cciss_proc_fops = {
+static const struct file_operations cciss_proc_fops = {
.owner = THIS_MODULE,
.open = cciss_seq_open,
.read = seq_read,
@@ -454,9 +470,19 @@ static void __devinit cciss_procinit(int i)
#define to_hba(n) container_of(n, struct ctlr_info, dev)
#define to_drv(n) container_of(n, drive_info_struct, dev)
-static struct device_type cciss_host_type = {
- .name = "cciss_host",
-};
+static ssize_t host_store_rescan(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ctlr_info *h = to_hba(dev);
+
+ add_to_scan_list(h);
+ wake_up_process(cciss_scan_thread);
+ wait_for_completion_interruptible(&h->scan_wait);
+
+ return count;
+}
+static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan);
static ssize_t dev_show_unique_id(struct device *dev,
struct device_attribute *attr,
@@ -486,7 +512,7 @@ static ssize_t dev_show_unique_id(struct device *dev,
sn[8], sn[9], sn[10], sn[11],
sn[12], sn[13], sn[14], sn[15]);
}
-DEVICE_ATTR(unique_id, S_IRUGO, dev_show_unique_id, NULL);
+static DEVICE_ATTR(unique_id, S_IRUGO, dev_show_unique_id, NULL);
static ssize_t dev_show_vendor(struct device *dev,
struct device_attribute *attr,
@@ -510,7 +536,7 @@ static ssize_t dev_show_vendor(struct device *dev,
else
return snprintf(buf, sizeof(vendor) + 1, "%s\n", drv->vendor);
}
-DEVICE_ATTR(vendor, S_IRUGO, dev_show_vendor, NULL);
+static DEVICE_ATTR(vendor, S_IRUGO, dev_show_vendor, NULL);
static ssize_t dev_show_model(struct device *dev,
struct device_attribute *attr,
@@ -534,7 +560,7 @@ static ssize_t dev_show_model(struct device *dev,
else
return snprintf(buf, sizeof(model) + 1, "%s\n", drv->model);
}
-DEVICE_ATTR(model, S_IRUGO, dev_show_model, NULL);
+static DEVICE_ATTR(model, S_IRUGO, dev_show_model, NULL);
static ssize_t dev_show_rev(struct device *dev,
struct device_attribute *attr,
@@ -558,13 +584,103 @@ static ssize_t dev_show_rev(struct device *dev,
else
return snprintf(buf, sizeof(rev) + 1, "%s\n", drv->rev);
}
-DEVICE_ATTR(rev, S_IRUGO, dev_show_rev, NULL);
+static DEVICE_ATTR(rev, S_IRUGO, dev_show_rev, NULL);
+
+static ssize_t cciss_show_lunid(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ drive_info_struct *drv = to_drv(dev);
+ struct ctlr_info *h = to_hba(drv->dev.parent);
+ unsigned long flags;
+ unsigned char lunid[8];
+
+ spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+ if (h->busy_configuring) {
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+ return -EBUSY;
+ }
+ if (!drv->heads) {
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+ return -ENOTTY;
+ }
+ memcpy(lunid, drv->LunID, sizeof(lunid));
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+ return snprintf(buf, 20, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ lunid[0], lunid[1], lunid[2], lunid[3],
+ lunid[4], lunid[5], lunid[6], lunid[7]);
+}
+static DEVICE_ATTR(lunid, S_IRUGO, cciss_show_lunid, NULL);
+
+static ssize_t cciss_show_raid_level(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ drive_info_struct *drv = to_drv(dev);
+ struct ctlr_info *h = to_hba(drv->dev.parent);
+ int raid;
+ unsigned long flags;
+
+ spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+ if (h->busy_configuring) {
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+ return -EBUSY;
+ }
+ raid = drv->raid_level;
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+ if (raid < 0 || raid > RAID_UNKNOWN)
+ raid = RAID_UNKNOWN;
+
+ return snprintf(buf, strlen(raid_label[raid]) + 7, "RAID %s\n",
+ raid_label[raid]);
+}
+static DEVICE_ATTR(raid_level, S_IRUGO, cciss_show_raid_level, NULL);
+
+static ssize_t cciss_show_usage_count(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ drive_info_struct *drv = to_drv(dev);
+ struct ctlr_info *h = to_hba(drv->dev.parent);
+ unsigned long flags;
+ int count;
+
+ spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+ if (h->busy_configuring) {
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+ return -EBUSY;
+ }
+ count = drv->usage_count;
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+ return snprintf(buf, 20, "%d\n", count);
+}
+static DEVICE_ATTR(usage_count, S_IRUGO, cciss_show_usage_count, NULL);
+
+static struct attribute *cciss_host_attrs[] = {
+ &dev_attr_rescan.attr,
+ NULL
+};
+
+static struct attribute_group cciss_host_attr_group = {
+ .attrs = cciss_host_attrs,
+};
+
+static const struct attribute_group *cciss_host_attr_groups[] = {
+ &cciss_host_attr_group,
+ NULL
+};
+
+static struct device_type cciss_host_type = {
+ .name = "cciss_host",
+ .groups = cciss_host_attr_groups,
+ .release = cciss_hba_release,
+};
static struct attribute *cciss_dev_attrs[] = {
&dev_attr_unique_id.attr,
&dev_attr_model.attr,
&dev_attr_vendor.attr,
&dev_attr_rev.attr,
+ &dev_attr_lunid.attr,
+ &dev_attr_raid_level.attr,
+ &dev_attr_usage_count.attr,
NULL
};
@@ -572,7 +688,7 @@ static struct attribute_group cciss_dev_attr_group = {
.attrs = cciss_dev_attrs,
};
-static struct attribute_group *cciss_dev_attr_groups[] = {
+static const struct attribute_group *cciss_dev_attr_groups[] = {
&cciss_dev_attr_group,
NULL
};
@@ -580,12 +696,24 @@ static struct attribute_group *cciss_dev_attr_groups[] = {
static struct device_type cciss_dev_type = {
.name = "cciss_device",
.groups = cciss_dev_attr_groups,
+ .release = cciss_device_release,
};
static struct bus_type cciss_bus_type = {
.name = "cciss",
};
+/*
+ * cciss_hba_release is called when the reference count
+ * of h->dev goes to zero.
+ */
+static void cciss_hba_release(struct device *dev)
+{
+ /*
+ * nothing to do, but need this to avoid a warning
+ * about not having a release handler from lib/kref.c.
+ */
+}
/*
* Initialize sysfs entry for each controller. This sets up and registers
@@ -609,6 +737,16 @@ static int cciss_create_hba_sysfs_entry(struct ctlr_info *h)
static void cciss_destroy_hba_sysfs_entry(struct ctlr_info *h)
{
device_del(&h->dev);
+ put_device(&h->dev); /* final put. */
+}
+
+/* cciss_device_release is called when the reference count
+ * of h->drv[x]dev goes to zero.
+ */
+static void cciss_device_release(struct device *dev)
+{
+ drive_info_struct *drv = to_drv(dev);
+ kfree(drv);
}
/*
@@ -617,24 +755,39 @@ static void cciss_destroy_hba_sysfs_entry(struct ctlr_info *h)
* /sys/bus/pci/devices/<dev/ccis#/. We also create a link from
* /sys/block/cciss!c#d# to this entry.
*/
-static int cciss_create_ld_sysfs_entry(struct ctlr_info *h,
- drive_info_struct *drv,
+static long cciss_create_ld_sysfs_entry(struct ctlr_info *h,
int drv_index)
{
- device_initialize(&drv->dev);
- drv->dev.type = &cciss_dev_type;
- drv->dev.bus = &cciss_bus_type;
- dev_set_name(&drv->dev, "c%dd%d", h->ctlr, drv_index);
- drv->dev.parent = &h->dev;
- return device_add(&drv->dev);
+ struct device *dev;
+
+ if (h->drv[drv_index]->device_initialized)
+ return 0;
+
+ dev = &h->drv[drv_index]->dev;
+ device_initialize(dev);
+ dev->type = &cciss_dev_type;
+ dev->bus = &cciss_bus_type;
+ dev_set_name(dev, "c%dd%d", h->ctlr, drv_index);
+ dev->parent = &h->dev;
+ h->drv[drv_index]->device_initialized = 1;
+ return device_add(dev);
}
/*
* Remove sysfs entries for a logical drive.
*/
-static void cciss_destroy_ld_sysfs_entry(drive_info_struct *drv)
+static void cciss_destroy_ld_sysfs_entry(struct ctlr_info *h, int drv_index,
+ int ctlr_exiting)
{
- device_del(&drv->dev);
+ struct device *dev = &h->drv[drv_index]->dev;
+
+ /* special case for c*d0, we only destroy it on controller exit */
+ if (drv_index == 0 && !ctlr_exiting)
+ return;
+
+ device_del(dev);
+ put_device(dev); /* the "final" put. */
+ h->drv[drv_index] = NULL;
}
/*
@@ -751,7 +904,7 @@ static int cciss_open(struct block_device *bdev, fmode_t mode)
printk(KERN_DEBUG "cciss_open %s\n", bdev->bd_disk->disk_name);
#endif /* CCISS_DEBUG */
- if (host->busy_initializing || drv->busy_configuring)
+ if (drv->busy_configuring)
return -EBUSY;
/*
* Root is allowed to open raw volume zero even if it's not configured
@@ -767,7 +920,8 @@ static int cciss_open(struct block_device *bdev, fmode_t mode)
if (MINOR(bdev->bd_dev) & 0x0f) {
return -ENXIO;
/* if it is, make sure we have a LUN ID */
- } else if (drv->LunID == 0) {
+ } else if (memcmp(drv->LunID, CTLR_LUNID,
+ sizeof(drv->LunID))) {
return -ENXIO;
}
}
@@ -1132,12 +1286,13 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
case CCISS_DEREGDISK:
case CCISS_REGNEWD:
case CCISS_REVALIDVOLS:
- return rebuild_lun_table(host, 0);
+ return rebuild_lun_table(host, 0, 1);
case CCISS_GETLUNINFO:{
LogvolInfo_struct luninfo;
- luninfo.LunID = drv->LunID;
+ memcpy(&luninfo.LunID, drv->LunID,
+ sizeof(luninfo.LunID));
luninfo.num_opens = drv->usage_count;
luninfo.num_parts = 0;
if (copy_to_user(argp, &luninfo,
@@ -1475,7 +1630,10 @@ static void cciss_check_queues(ctlr_info_t *h)
/* make sure the disk has been added and the drive is real
* because this can be called from the middle of init_one.
*/
- if (!(h->drv[curr_queue].queue) || !(h->drv[curr_queue].heads))
+ if (!h->drv[curr_queue])
+ continue;
+ if (!(h->drv[curr_queue]->queue) ||
+ !(h->drv[curr_queue]->heads))
continue;
blk_start_queue(h->gendisk[curr_queue]->queue);
@@ -1532,13 +1690,11 @@ static void cciss_softirq_done(struct request *rq)
spin_unlock_irqrestore(&h->lock, flags);
}
-static void log_unit_to_scsi3addr(ctlr_info_t *h, unsigned char scsi3addr[],
- uint32_t log_unit)
+static inline void log_unit_to_scsi3addr(ctlr_info_t *h,
+ unsigned char scsi3addr[], uint32_t log_unit)
{
- log_unit = h->drv[log_unit].LunID & 0x03fff;
- memset(&scsi3addr[4], 0, 4);
- memcpy(&scsi3addr[0], &log_unit, 4);
- scsi3addr[3] |= 0x40;
+ memcpy(scsi3addr, h->drv[log_unit]->LunID,
+ sizeof(h->drv[log_unit]->LunID));
}
/* This function gets the SCSI vendor, model, and revision of a logical drive
@@ -1615,16 +1771,23 @@ static void cciss_get_serial_no(int ctlr, int logvol, int withirq,
return;
}
-static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
+/*
+ * cciss_add_disk sets up the block device queue for a logical drive
+ */
+static int cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
int drv_index)
{
disk->queue = blk_init_queue(do_cciss_request, &h->lock);
+ if (!disk->queue)
+ goto init_queue_failure;
sprintf(disk->disk_name, "cciss/c%dd%d", h->ctlr, drv_index);
disk->major = h->major;
disk->first_minor = drv_index << NWD_SHIFT;
disk->fops = &cciss_fops;
- disk->private_data = &h->drv[drv_index];
- disk->driverfs_dev = &h->drv[drv_index].dev;
+ if (cciss_create_ld_sysfs_entry(h, drv_index))
+ goto cleanup_queue;
+ disk->private_data = h->drv[drv_index];
+ disk->driverfs_dev = &h->drv[drv_index]->dev;
/* Set up queue information */
blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask);
@@ -1642,14 +1805,21 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
disk->queue->queuedata = h;
blk_queue_logical_block_size(disk->queue,
- h->drv[drv_index].block_size);
+ h->drv[drv_index]->block_size);
/* Make sure all queue data is written out before */
- /* setting h->drv[drv_index].queue, as setting this */
+ /* setting h->drv[drv_index]->queue, as setting this */
/* allows the interrupt handler to start the queue */
wmb();
- h->drv[drv_index].queue = disk->queue;
+ h->drv[drv_index]->queue = disk->queue;
add_disk(disk);
+ return 0;
+
+cleanup_queue:
+ blk_cleanup_queue(disk->queue);
+ disk->queue = NULL;
+init_queue_failure:
+ return -1;
}
/* This function will check the usage_count of the drive to be updated/added.
@@ -1662,7 +1832,8 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
* is also the controller node. Any changes to disk 0 will show up on
* the next reboot.
*/
-static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
+static void cciss_update_drive_info(int ctlr, int drv_index, int first_time,
+ int via_ioctl)
{
ctlr_info_t *h = hba[ctlr];
struct gendisk *disk;
@@ -1672,21 +1843,13 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
unsigned long flags = 0;
int ret = 0;
drive_info_struct *drvinfo;
- int was_only_controller_node;
/* Get information about the disk and modify the driver structure */
inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
- drvinfo = kmalloc(sizeof(*drvinfo), GFP_KERNEL);
+ drvinfo = kzalloc(sizeof(*drvinfo), GFP_KERNEL);
if (inq_buff == NULL || drvinfo == NULL)
goto mem_msg;
- /* See if we're trying to update the "controller node"
- * this will happen the when the first logical drive gets
- * created by ACU.
- */
- was_only_controller_node = (drv_index == 0 &&
- h->drv[0].raid_level == -1);
-
/* testing to see if 16-byte CDBs are already being used */
if (h->cciss_read == CCISS_READ_16) {
cciss_read_capacity_16(h->ctlr, drv_index, 1,
@@ -1719,16 +1882,19 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
drvinfo->model, drvinfo->rev);
cciss_get_serial_no(ctlr, drv_index, 1, drvinfo->serial_no,
sizeof(drvinfo->serial_no));
+ /* Save the lunid in case we deregister the disk, below. */
+ memcpy(drvinfo->LunID, h->drv[drv_index]->LunID,
+ sizeof(drvinfo->LunID));
/* Is it the same disk we already know, and nothing's changed? */
- if (h->drv[drv_index].raid_level != -1 &&
+ if (h->drv[drv_index]->raid_level != -1 &&
((memcmp(drvinfo->serial_no,
- h->drv[drv_index].serial_no, 16) == 0) &&
- drvinfo->block_size == h->drv[drv_index].block_size &&
- drvinfo->nr_blocks == h->drv[drv_index].nr_blocks &&
- drvinfo->heads == h->drv[drv_index].heads &&
- drvinfo->sectors == h->drv[drv_index].sectors &&
- drvinfo->cylinders == h->drv[drv_index].cylinders))
+ h->drv[drv_index]->serial_no, 16) == 0) &&
+ drvinfo->block_size == h->drv[drv_index]->block_size &&
+ drvinfo->nr_blocks == h->drv[drv_index]->nr_blocks &&
+ drvinfo->heads == h->drv[drv_index]->heads &&
+ drvinfo->sectors == h->drv[drv_index]->sectors &&
+ drvinfo->cylinders == h->drv[drv_index]->cylinders))
/* The disk is unchanged, nothing to update */
goto freeret;
@@ -1738,18 +1904,17 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
* If the disk already exists then deregister it before proceeding
* (unless it's the first disk (for the controller node).
*/
- if (h->drv[drv_index].raid_level != -1 && drv_index != 0) {
+ if (h->drv[drv_index]->raid_level != -1 && drv_index != 0) {
printk(KERN_WARNING "disk %d has changed.\n", drv_index);
spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
- h->drv[drv_index].busy_configuring = 1;
+ h->drv[drv_index]->busy_configuring = 1;
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
- /* deregister_disk sets h->drv[drv_index].queue = NULL
+ /* deregister_disk sets h->drv[drv_index]->queue = NULL
* which keeps the interrupt handler from starting
* the queue.
*/
- ret = deregister_disk(h, drv_index, 0);
- h->drv[drv_index].busy_configuring = 0;
+ ret = deregister_disk(h, drv_index, 0, via_ioctl);
}
/* If the disk is in use return */
@@ -1757,22 +1922,31 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
goto freeret;
/* Save the new information from cciss_geometry_inquiry
- * and serial number inquiry.
+ * and serial number inquiry. If the disk was deregistered
+ * above, then h->drv[drv_index] will be NULL.
*/
- h->drv[drv_index].block_size = drvinfo->block_size;
- h->drv[drv_index].nr_blocks = drvinfo->nr_blocks;
- h->drv[drv_index].heads = drvinfo->heads;
- h->drv[drv_index].sectors = drvinfo->sectors;
- h->drv[drv_index].cylinders = drvinfo->cylinders;
- h->drv[drv_index].raid_level = drvinfo->raid_level;
- memcpy(h->drv[drv_index].serial_no, drvinfo->serial_no, 16);
- memcpy(h->drv[drv_index].vendor, drvinfo->vendor, VENDOR_LEN + 1);
- memcpy(h->drv[drv_index].model, drvinfo->model, MODEL_LEN + 1);
- memcpy(h->drv[drv_index].rev, drvinfo->rev, REV_LEN + 1);
+ if (h->drv[drv_index] == NULL) {
+ drvinfo->device_initialized = 0;
+ h->drv[drv_index] = drvinfo;
+ drvinfo = NULL; /* so it won't be freed below. */
+ } else {
+ /* special case for cxd0 */
+ h->drv[drv_index]->block_size = drvinfo->block_size;
+ h->drv[drv_index]->nr_blocks = drvinfo->nr_blocks;
+ h->drv[drv_index]->heads = drvinfo->heads;
+ h->drv[drv_index]->sectors = drvinfo->sectors;
+ h->drv[drv_index]->cylinders = drvinfo->cylinders;
+ h->drv[drv_index]->raid_level = drvinfo->raid_level;
+ memcpy(h->drv[drv_index]->serial_no, drvinfo->serial_no, 16);
+ memcpy(h->drv[drv_index]->vendor, drvinfo->vendor,
+ VENDOR_LEN + 1);
+ memcpy(h->drv[drv_index]->model, drvinfo->model, MODEL_LEN + 1);
+ memcpy(h->drv[drv_index]->rev, drvinfo->rev, REV_LEN + 1);
+ }
++h->num_luns;
disk = h->gendisk[drv_index];
- set_capacity(disk, h->drv[drv_index].nr_blocks);
+ set_capacity(disk, h->drv[drv_index]->nr_blocks);
/* If it's not disk 0 (drv_index != 0)
* or if it was disk 0, but there was previously
@@ -1780,8 +1954,15 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
* (raid_leve == -1) then we want to update the
* logical drive's information.
*/
- if (drv_index || first_time)
- cciss_add_disk(h, disk, drv_index);
+ if (drv_index || first_time) {
+ if (cciss_add_disk(h, disk, drv_index) != 0) {
+ cciss_free_gendisk(h, drv_index);
+ cciss_free_drive_info(h, drv_index);
+ printk(KERN_WARNING "cciss:%d could not update "
+ "disk %d\n", h->ctlr, drv_index);
+ --h->num_luns;
+ }
+ }
freeret:
kfree(inq_buff);
@@ -1793,28 +1974,70 @@ mem_msg:
}
/* This function will find the first index of the controllers drive array
- * that has a -1 for the raid_level and will return that index. This is
- * where new drives will be added. If the index to be returned is greater
- * than the highest_lun index for the controller then highest_lun is set
- * to this new index. If there are no available indexes then -1 is returned.
- * "controller_node" is used to know if this is a real logical drive, or just
- * the controller node, which determines if this counts towards highest_lun.
+ * that has a null drv pointer and allocate the drive info struct and
+ * will return that index This is where new drives will be added.
+ * If the index to be returned is greater than the highest_lun index for
+ * the controller then highest_lun is set * to this new index.
+ * If there are no available indexes or if tha allocation fails, then -1
+ * is returned. * "controller_node" is used to know if this is a real
+ * logical drive, or just the controller node, which determines if this
+ * counts towards highest_lun.
*/
-static int cciss_find_free_drive_index(int ctlr, int controller_node)
+static int cciss_alloc_drive_info(ctlr_info_t *h, int controller_node)
{
int i;
+ drive_info_struct *drv;
+ /* Search for an empty slot for our drive info */
for (i = 0; i < CISS_MAX_LUN; i++) {
- if (hba[ctlr]->drv[i].raid_level == -1) {
- if (i > hba[ctlr]->highest_lun)
- if (!controller_node)
- hba[ctlr]->highest_lun = i;
+
+ /* if not cxd0 case, and it's occupied, skip it. */
+ if (h->drv[i] && i != 0)
+ continue;
+ /*
+ * If it's cxd0 case, and drv is alloc'ed already, and a
+ * disk is configured there, skip it.
+ */
+ if (i == 0 && h->drv[i] && h->drv[i]->raid_level != -1)
+ continue;
+
+ /*
+ * We've found an empty slot. Update highest_lun
+ * provided this isn't just the fake cxd0 controller node.
+ */
+ if (i > h->highest_lun && !controller_node)
+ h->highest_lun = i;
+
+ /* If adding a real disk at cxd0, and it's already alloc'ed */
+ if (i == 0 && h->drv[i] != NULL)
return i;
- }
+
+ /*
+ * Found an empty slot, not already alloc'ed. Allocate it.
+ * Mark it with raid_level == -1, so we know it's new later on.
+ */
+ drv = kzalloc(sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -1;
+ drv->raid_level = -1; /* so we know it's new */
+ h->drv[i] = drv;
+ return i;
}
return -1;
}
+static void cciss_free_drive_info(ctlr_info_t *h, int drv_index)
+{
+ kfree(h->drv[drv_index]);
+ h->drv[drv_index] = NULL;
+}
+
+static void cciss_free_gendisk(ctlr_info_t *h, int drv_index)
+{
+ put_disk(h->gendisk[drv_index]);
+ h->gendisk[drv_index] = NULL;
+}
+
/* cciss_add_gendisk finds a free hba[]->drv structure
* and allocates a gendisk if needed, and sets the lunid
* in the drvinfo structure. It returns the index into
@@ -1824,13 +2047,15 @@ static int cciss_find_free_drive_index(int ctlr, int controller_node)
* a means to talk to the controller in case no logical
* drives have yet been configured.
*/
-static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node)
+static int cciss_add_gendisk(ctlr_info_t *h, unsigned char lunid[],
+ int controller_node)
{
int drv_index;
- drv_index = cciss_find_free_drive_index(h->ctlr, controller_node);
+ drv_index = cciss_alloc_drive_info(h, controller_node);
if (drv_index == -1)
return -1;
+
/*Check if the gendisk needs to be allocated */
if (!h->gendisk[drv_index]) {
h->gendisk[drv_index] =
@@ -1839,23 +2064,24 @@ static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node)
printk(KERN_ERR "cciss%d: could not "
"allocate a new disk %d\n",
h->ctlr, drv_index);
- return -1;
+ goto err_free_drive_info;
}
}
- h->drv[drv_index].LunID = lunid;
- if (cciss_create_ld_sysfs_entry(h, &h->drv[drv_index], drv_index))
+ memcpy(h->drv[drv_index]->LunID, lunid,
+ sizeof(h->drv[drv_index]->LunID));
+ if (cciss_create_ld_sysfs_entry(h, drv_index))
goto err_free_disk;
-
/* Don't need to mark this busy because nobody */
/* else knows about this disk yet to contend */
/* for access to it. */
- h->drv[drv_index].busy_configuring = 0;
+ h->drv[drv_index]->busy_configuring = 0;
wmb();
return drv_index;
err_free_disk:
- put_disk(h->gendisk[drv_index]);
- h->gendisk[drv_index] = NULL;
+ cciss_free_gendisk(h, drv_index);
+err_free_drive_info:
+ cciss_free_drive_info(h, drv_index);
return -1;
}
@@ -1872,21 +2098,25 @@ static void cciss_add_controller_node(ctlr_info_t *h)
if (h->gendisk[0] != NULL) /* already did this? Then bail. */
return;
- drv_index = cciss_add_gendisk(h, 0, 1);
- if (drv_index == -1) {
- printk(KERN_WARNING "cciss%d: could not "
- "add disk 0.\n", h->ctlr);
- return;
- }
- h->drv[drv_index].block_size = 512;
- h->drv[drv_index].nr_blocks = 0;
- h->drv[drv_index].heads = 0;
- h->drv[drv_index].sectors = 0;
- h->drv[drv_index].cylinders = 0;
- h->drv[drv_index].raid_level = -1;
- memset(h->drv[drv_index].serial_no, 0, 16);
+ drv_index = cciss_add_gendisk(h, CTLR_LUNID, 1);
+ if (drv_index == -1)
+ goto error;
+ h->drv[drv_index]->block_size = 512;
+ h->drv[drv_index]->nr_blocks = 0;
+ h->drv[drv_index]->heads = 0;
+ h->drv[drv_index]->sectors = 0;
+ h->drv[drv_index]->cylinders = 0;
+ h->drv[drv_index]->raid_level = -1;
+ memset(h->drv[drv_index]->serial_no, 0, 16);
disk = h->gendisk[drv_index];
- cciss_add_disk(h, disk, drv_index);
+ if (cciss_add_disk(h, disk, drv_index) == 0)
+ return;
+ cciss_free_gendisk(h, drv_index);
+ cciss_free_drive_info(h, drv_index);
+error:
+ printk(KERN_WARNING "cciss%d: could not "
+ "add disk 0.\n", h->ctlr);
+ return;
}
/* This function will add and remove logical drives from the Logical
@@ -1897,7 +2127,8 @@ static void cciss_add_controller_node(ctlr_info_t *h)
* INPUT
* h = The controller to perform the operations on
*/
-static int rebuild_lun_table(ctlr_info_t *h, int first_time)
+static int rebuild_lun_table(ctlr_info_t *h, int first_time,
+ int via_ioctl)
{
int ctlr = h->ctlr;
int num_luns;
@@ -1907,7 +2138,7 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
int i;
int drv_found;
int drv_index = 0;
- __u32 lunid = 0;
+ unsigned char lunid[8] = CTLR_LUNID;
unsigned long flags;
if (!capable(CAP_SYS_RAWIO))
@@ -1960,13 +2191,13 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
drv_found = 0;
/* skip holes in the array from already deleted drives */
- if (h->drv[i].raid_level == -1)
+ if (h->drv[i] == NULL)
continue;
for (j = 0; j < num_luns; j++) {
- memcpy(&lunid, &ld_buff->LUN[j][0], 4);
- lunid = le32_to_cpu(lunid);
- if (h->drv[i].LunID == lunid) {
+ memcpy(lunid, &ld_buff->LUN[j][0], sizeof(lunid));
+ if (memcmp(h->drv[i]->LunID, lunid,
+ sizeof(lunid)) == 0) {
drv_found = 1;
break;
}
@@ -1974,11 +2205,11 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
if (!drv_found) {
/* Deregister it from the OS, it's gone. */
spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
- h->drv[i].busy_configuring = 1;
+ h->drv[i]->busy_configuring = 1;
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
- return_code = deregister_disk(h, i, 1);
- cciss_destroy_ld_sysfs_entry(&h->drv[i]);
- h->drv[i].busy_configuring = 0;
+ return_code = deregister_disk(h, i, 1, via_ioctl);
+ if (h->drv[i] != NULL)
+ h->drv[i]->busy_configuring = 0;
}
}
@@ -1992,17 +2223,16 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
drv_found = 0;
- memcpy(&lunid, &ld_buff->LUN[i][0], 4);
- lunid = le32_to_cpu(lunid);
-
+ memcpy(lunid, &ld_buff->LUN[i][0], sizeof(lunid));
/* Find if the LUN is already in the drive array
* of the driver. If so then update its info
* if not in use. If it does not exist then find
* the first free index and add it.
*/
for (j = 0; j <= h->highest_lun; j++) {
- if (h->drv[j].raid_level != -1 &&
- h->drv[j].LunID == lunid) {
+ if (h->drv[j] != NULL &&
+ memcmp(h->drv[j]->LunID, lunid,
+ sizeof(h->drv[j]->LunID)) == 0) {
drv_index = j;
drv_found = 1;
break;
@@ -2015,7 +2245,8 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
if (drv_index == -1)
goto freeret;
}
- cciss_update_drive_info(ctlr, drv_index, first_time);
+ cciss_update_drive_info(ctlr, drv_index, first_time,
+ via_ioctl);
} /* end for */
freeret:
@@ -2032,6 +2263,25 @@ mem_msg:
goto freeret;
}
+static void cciss_clear_drive_info(drive_info_struct *drive_info)
+{
+ /* zero out the disk size info */
+ drive_info->nr_blocks = 0;
+ drive_info->block_size = 0;
+ drive_info->heads = 0;
+ drive_info->sectors = 0;
+ drive_info->cylinders = 0;
+ drive_info->raid_level = -1;
+ memset(drive_info->serial_no, 0, sizeof(drive_info->serial_no));
+ memset(drive_info->model, 0, sizeof(drive_info->model));
+ memset(drive_info->rev, 0, sizeof(drive_info->rev));
+ memset(drive_info->vendor, 0, sizeof(drive_info->vendor));
+ /*
+ * don't clear the LUNID though, we need to remember which
+ * one this one is.
+ */
+}
+
/* This function will deregister the disk and it's queue from the
* kernel. It must be called with the controller lock held and the
* drv structures busy_configuring flag set. It's parameters are:
@@ -2046,43 +2296,48 @@ mem_msg:
* the disk in preparation for re-adding it. In this case
* the highest_lun should be left unchanged and the LunID
* should not be cleared.
+ * via_ioctl
+ * This indicates whether we've reached this path via ioctl.
+ * This affects the maximum usage count allowed for c0d0 to be messed with.
+ * If this path is reached via ioctl(), then the max_usage_count will
+ * be 1, as the process calling ioctl() has got to have the device open.
+ * If we get here via sysfs, then the max usage count will be zero.
*/
static int deregister_disk(ctlr_info_t *h, int drv_index,
- int clear_all)
+ int clear_all, int via_ioctl)
{
int i;
struct gendisk *disk;
drive_info_struct *drv;
+ int recalculate_highest_lun;
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
- drv = &h->drv[drv_index];
+ drv = h->drv[drv_index];
disk = h->gendisk[drv_index];
/* make sure logical volume is NOT is use */
if (clear_all || (h->gendisk[0] == disk)) {
- if (drv->usage_count > 1)
+ if (drv->usage_count > via_ioctl)
return -EBUSY;
} else if (drv->usage_count > 0)
return -EBUSY;
+ recalculate_highest_lun = (drv == h->drv[h->highest_lun]);
+
/* invalidate the devices and deregister the disk. If it is disk
* zero do not deregister it but just zero out it's values. This
* allows us to delete disk zero but keep the controller registered.
*/
if (h->gendisk[0] != disk) {
struct request_queue *q = disk->queue;
- if (disk->flags & GENHD_FL_UP)
+ if (disk->flags & GENHD_FL_UP) {
+ cciss_destroy_ld_sysfs_entry(h, drv_index, 0);
del_gendisk(disk);
- if (q) {
- blk_cleanup_queue(q);
- /* Set drv->queue to NULL so that we do not try
- * to call blk_start_queue on this queue in the
- * interrupt handler
- */
- drv->queue = NULL;
}
+ if (q)
+ blk_cleanup_queue(q);
/* If clear_all is set then we are deleting the logical
* drive, not just refreshing its info. For drives
* other than disk 0 we will call put_disk. We do not
@@ -2105,34 +2360,20 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,
}
} else {
set_capacity(disk, 0);
+ cciss_clear_drive_info(drv);
}
--h->num_luns;
- /* zero out the disk size info */
- drv->nr_blocks = 0;
- drv->block_size = 0;
- drv->heads = 0;
- drv->sectors = 0;
- drv->cylinders = 0;
- drv->raid_level = -1; /* This can be used as a flag variable to
- * indicate that this element of the drive
- * array is free.
- */
-
- if (clear_all) {
- /* check to see if it was the last disk */
- if (drv == h->drv + h->highest_lun) {
- /* if so, find the new hightest lun */
- int i, newhighest = -1;
- for (i = 0; i <= h->highest_lun; i++) {
- /* if the disk has size > 0, it is available */
- if (h->drv[i].heads)
- newhighest = i;
- }
- h->highest_lun = newhighest;
- }
- drv->LunID = 0;
+ /* if it was the last disk, find the new hightest lun */
+ if (clear_all && recalculate_highest_lun) {
+ int i, newhighest = -1;
+ for (i = 0; i <= h->highest_lun; i++) {
+ /* if the disk has size > 0, it is available */
+ if (h->drv[i] && h->drv[i]->heads)
+ newhighest = i;
+ }
+ h->highest_lun = newhighest;
}
return 0;
}
@@ -2479,8 +2720,6 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
} else { /* Get geometry failed */
printk(KERN_WARNING "cciss: reading geometry failed\n");
}
- printk(KERN_INFO " heads=%d, sectors=%d, cylinders=%d\n\n",
- drv->heads, drv->sectors, drv->cylinders);
}
static void
@@ -2514,9 +2753,6 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
*total_size = 0;
*block_size = BLOCK_SIZE;
}
- if (*total_size != 0)
- printk(KERN_INFO " blocks= %llu block_size= %d\n",
- (unsigned long long)*total_size+1, *block_size);
kfree(buf);
}
@@ -2568,7 +2804,8 @@ static int cciss_revalidate(struct gendisk *disk)
InquiryData_struct *inq_buff = NULL;
for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
- if (h->drv[logvol].LunID == drv->LunID) {
+ if (memcmp(h->drv[logvol]->LunID, drv->LunID,
+ sizeof(drv->LunID)) == 0) {
FOUND = 1;
break;
}
@@ -3053,8 +3290,7 @@ static void do_cciss_request(struct request_queue *q)
/* The first 2 bits are reserved for controller error reporting. */
c->Header.Tag.lower = (c->cmdindex << 3);
c->Header.Tag.lower |= 0x04; /* flag for direct lookup. */
- c->Header.LUN.LogDev.VolId = drv->LunID;
- c->Header.LUN.LogDev.Mode = 1;
+ memcpy(&c->Header.LUN, drv->LunID, sizeof(drv->LunID));
c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
c->Request.Type.Type = TYPE_CMD; // It is a command.
c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -3232,20 +3468,121 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+/**
+ * add_to_scan_list() - add controller to rescan queue
+ * @h: Pointer to the controller.
+ *
+ * Adds the controller to the rescan queue if not already on the queue.
+ *
+ * returns 1 if added to the queue, 0 if skipped (could be on the
+ * queue already, or the controller could be initializing or shutting
+ * down).
+ **/
+static int add_to_scan_list(struct ctlr_info *h)
+{
+ struct ctlr_info *test_h;
+ int found = 0;
+ int ret = 0;
+
+ if (h->busy_initializing)
+ return 0;
+
+ if (!mutex_trylock(&h->busy_shutting_down))
+ return 0;
+
+ mutex_lock(&scan_mutex);
+ list_for_each_entry(test_h, &scan_q, scan_list) {
+ if (test_h == h) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found && !h->busy_scanning) {
+ INIT_COMPLETION(h->scan_wait);
+ list_add_tail(&h->scan_list, &scan_q);
+ ret = 1;
+ }
+ mutex_unlock(&scan_mutex);
+ mutex_unlock(&h->busy_shutting_down);
+
+ return ret;
+}
+
+/**
+ * remove_from_scan_list() - remove controller from rescan queue
+ * @h: Pointer to the controller.
+ *
+ * Removes the controller from the rescan queue if present. Blocks if
+ * the controller is currently conducting a rescan.
+ **/
+static void remove_from_scan_list(struct ctlr_info *h)
+{
+ struct ctlr_info *test_h, *tmp_h;
+ int scanning = 0;
+
+ mutex_lock(&scan_mutex);
+ list_for_each_entry_safe(test_h, tmp_h, &scan_q, scan_list) {
+ if (test_h == h) {
+ list_del(&h->scan_list);
+ complete_all(&h->scan_wait);
+ mutex_unlock(&scan_mutex);
+ return;
+ }
+ }
+ if (&h->busy_scanning)
+ scanning = 0;
+ mutex_unlock(&scan_mutex);
+
+ if (scanning)
+ wait_for_completion(&h->scan_wait);
+}
+
+/**
+ * scan_thread() - kernel thread used to rescan controllers
+ * @data: Ignored.
+ *
+ * A kernel thread used scan for drive topology changes on
+ * controllers. The thread processes only one controller at a time
+ * using a queue. Controllers are added to the queue using
+ * add_to_scan_list() and removed from the queue either after done
+ * processing or using remove_from_scan_list().
+ *
+ * returns 0.
+ **/
static int scan_thread(void *data)
{
- ctlr_info_t *h = data;
- int rc;
- DECLARE_COMPLETION_ONSTACK(wait);
- h->rescan_wait = &wait;
+ struct ctlr_info *h;
- for (;;) {
- rc = wait_for_completion_interruptible(&wait);
+ while (1) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
if (kthread_should_stop())
break;
- if (!rc)
- rebuild_lun_table(h, 0);
+
+ while (1) {
+ mutex_lock(&scan_mutex);
+ if (list_empty(&scan_q)) {
+ mutex_unlock(&scan_mutex);
+ break;
+ }
+
+ h = list_entry(scan_q.next,
+ struct ctlr_info,
+ scan_list);
+ list_del(&h->scan_list);
+ h->busy_scanning = 1;
+ mutex_unlock(&scan_mutex);
+
+ if (h) {
+ rebuild_lun_table(h, 0, 0);
+ complete_all(&h->scan_wait);
+ mutex_lock(&scan_mutex);
+ h->busy_scanning = 0;
+ mutex_unlock(&scan_mutex);
+ }
+ }
}
+
return 0;
}
@@ -3268,8 +3605,8 @@ static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c)
case REPORT_LUNS_CHANGED:
printk(KERN_WARNING "cciss%d: report LUN data "
"changed\n", h->ctlr);
- if (h->rescan_wait)
- complete(h->rescan_wait);
+ add_to_scan_list(h);
+ wake_up_process(cciss_scan_thread);
return 1;
break;
case POWER_OR_RESET:
@@ -3422,7 +3759,27 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
__u64 cfg_offset;
__u32 cfg_base_addr;
__u64 cfg_base_addr_index;
- int i, err;
+ int i, prod_index, err;
+
+ subsystem_vendor_id = pdev->subsystem_vendor;
+ subsystem_device_id = pdev->subsystem_device;
+ board_id = (((__u32) (subsystem_device_id << 16) & 0xffff0000) |
+ subsystem_vendor_id);
+
+ for (i = 0; i < ARRAY_SIZE(products); i++) {
+ /* Stand aside for hpsa driver on request */
+ if (cciss_allow_hpsa && products[i].board_id == HPSA_BOUNDARY)
+ return -ENODEV;
+ if (board_id == products[i].board_id)
+ break;
+ }
+ prod_index = i;
+ if (prod_index == ARRAY_SIZE(products)) {
+ dev_warn(&pdev->dev,
+ "unrecognized board ID: 0x%08lx, ignoring.\n",
+ (unsigned long) board_id);
+ return -ENODEV;
+ }
/* check to see if controller has been disabled */
/* BEFORE trying to enable it */
@@ -3446,11 +3803,6 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
return err;
}
- subsystem_vendor_id = pdev->subsystem_vendor;
- subsystem_device_id = pdev->subsystem_device;
- board_id = (((__u32) (subsystem_device_id << 16) & 0xffff0000) |
- subsystem_vendor_id);
-
#ifdef CCISS_DEBUG
printk("command = %x\n", command);
printk("irq = %x\n", pdev->irq);
@@ -3489,7 +3841,7 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
if (scratchpad == CCISS_FIRMWARE_READY)
break;
set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ / 10); /* wait 100ms */
+ schedule_timeout(msecs_to_jiffies(100)); /* wait 100ms */
}
if (scratchpad != CCISS_FIRMWARE_READY) {
printk(KERN_WARNING "cciss: Board not ready. Timed out.\n");
@@ -3536,14 +3888,9 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
* leave a little room for ioctl calls.
*/
c->max_commands = readl(&(c->cfgtable->CmdsOutMax));
- for (i = 0; i < ARRAY_SIZE(products); i++) {
- if (board_id == products[i].board_id) {
- c->product_name = products[i].product_name;
- c->access = *(products[i].access);
- c->nr_cmds = c->max_commands - 4;
- break;
- }
- }
+ c->product_name = products[prod_index].product_name;
+ c->access = *(products[prod_index].access);
+ c->nr_cmds = c->max_commands - 4;
if ((readb(&c->cfgtable->Signature[0]) != 'C') ||
(readb(&c->cfgtable->Signature[1]) != 'I') ||
(readb(&c->cfgtable->Signature[2]) != 'S') ||
@@ -3552,27 +3899,6 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
err = -ENODEV;
goto err_out_free_res;
}
- /* We didn't find the controller in our list. We know the
- * signature is valid. If it's an HP device let's try to
- * bind to the device and fire it up. Otherwise we bail.
- */
- if (i == ARRAY_SIZE(products)) {
- if (subsystem_vendor_id == PCI_VENDOR_ID_HP) {
- c->product_name = products[i-1].product_name;
- c->access = *(products[i-1].access);
- c->nr_cmds = c->max_commands - 4;
- printk(KERN_WARNING "cciss: This is an unknown "
- "Smart Array controller.\n"
- "cciss: Please update to the latest driver "
- "available from www.hp.com.\n");
- } else {
- printk(KERN_WARNING "cciss: Sorry, I don't know how"
- " to access the Smart Array controller %08lx\n"
- , (unsigned long)board_id);
- err = -ENODEV;
- goto err_out_free_res;
- }
- }
#ifdef CONFIG_X86
{
/* Need to enable prefetch in the SCSI core for 6400 in x86 */
@@ -3615,7 +3941,7 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
break;
/* delay and try again */
set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(10);
+ schedule_timeout(msecs_to_jiffies(1));
}
#ifdef CCISS_DEBUG
@@ -3669,15 +3995,16 @@ Enomem:
return -1;
}
-static void free_hba(int i)
+static void free_hba(int n)
{
- ctlr_info_t *p = hba[i];
- int n;
+ ctlr_info_t *h = hba[n];
+ int i;
- hba[i] = NULL;
- for (n = 0; n < CISS_MAX_LUN; n++)
- put_disk(p->gendisk[n]);
- kfree(p);
+ hba[n] = NULL;
+ for (i = 0; i < h->highest_lun + 1; i++)
+ if (h->gendisk[i] != NULL)
+ put_disk(h->gendisk[i]);
+ kfree(h);
}
/* Send a message CDB to the firmware. */
@@ -3889,7 +4216,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
int j = 0;
int rc;
int dac, return_code;
- InquiryData_struct *inq_buff = NULL;
+ InquiryData_struct *inq_buff;
if (reset_devices) {
/* Reset the controller with a PCI power-cycle */
@@ -3918,14 +4245,17 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
hba[i]->busy_initializing = 1;
INIT_HLIST_HEAD(&hba[i]->cmpQ);
INIT_HLIST_HEAD(&hba[i]->reqQ);
+ mutex_init(&hba[i]->busy_shutting_down);
if (cciss_pci_init(hba[i], pdev) != 0)
- goto clean0;
+ goto clean_no_release_regions;
sprintf(hba[i]->devname, "cciss%d", i);
hba[i]->ctlr = i;
hba[i]->pdev = pdev;
+ init_completion(&hba[i]->scan_wait);
+
if (cciss_create_hba_sysfs_entry(hba[i]))
goto clean0;
@@ -4001,8 +4331,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
hba[i]->num_luns = 0;
hba[i]->highest_lun = -1;
for (j = 0; j < CISS_MAX_LUN; j++) {
- hba[i]->drv[j].raid_level = -1;
- hba[i]->drv[j].queue = NULL;
+ hba[i]->drv[j] = NULL;
hba[i]->gendisk[j] = NULL;
}
@@ -4029,23 +4358,17 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
printk(KERN_WARNING "cciss: unable to determine firmware"
" version of controller\n");
}
+ kfree(inq_buff);
cciss_procinit(i);
hba[i]->cciss_max_sectors = 2048;
+ rebuild_lun_table(hba[i], 1, 0);
hba[i]->busy_initializing = 0;
-
- rebuild_lun_table(hba[i], 1);
- hba[i]->cciss_scan_thread = kthread_run(scan_thread, hba[i],
- "cciss_scan%02d", i);
- if (IS_ERR(hba[i]->cciss_scan_thread))
- return PTR_ERR(hba[i]->cciss_scan_thread);
-
return 1;
clean4:
- kfree(inq_buff);
kfree(hba[i]->cmd_pool_bits);
if (hba[i]->cmd_pool)
pci_free_consistent(hba[i]->pdev,
@@ -4062,18 +4385,14 @@ clean2:
clean1:
cciss_destroy_hba_sysfs_entry(hba[i]);
clean0:
+ pci_release_regions(pdev);
+clean_no_release_regions:
hba[i]->busy_initializing = 0;
- /* cleanup any queues that may have been initialized */
- for (j=0; j <= hba[i]->highest_lun; j++){
- drive_info_struct *drv = &(hba[i]->drv[j]);
- if (drv->queue)
- blk_cleanup_queue(drv->queue);
- }
+
/*
* Deliberately omit pci_disable_device(): it does something nasty to
* Smart Array controllers that pci_enable_device does not undo
*/
- pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
free_hba(i);
return -1;
@@ -4125,8 +4444,9 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
return;
}
- kthread_stop(hba[i]->cciss_scan_thread);
+ mutex_lock(&hba[i]->busy_shutting_down);
+ remove_from_scan_list(hba[i]);
remove_proc_entry(hba[i]->devname, proc_cciss);
unregister_blkdev(hba[i]->major, hba[i]->devname);
@@ -4136,8 +4456,10 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
if (disk) {
struct request_queue *q = disk->queue;
- if (disk->flags & GENHD_FL_UP)
+ if (disk->flags & GENHD_FL_UP) {
+ cciss_destroy_ld_sysfs_entry(hba[i], j, 1);
del_gendisk(disk);
+ }
if (q)
blk_cleanup_queue(q);
}
@@ -4170,6 +4492,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
cciss_destroy_hba_sysfs_entry(hba[i]);
+ mutex_unlock(&hba[i]->busy_shutting_down);
free_hba(i);
}
@@ -4202,15 +4525,25 @@ static int __init cciss_init(void)
if (err)
return err;
+ /* Start the scan thread */
+ cciss_scan_thread = kthread_run(scan_thread, NULL, "cciss_scan");
+ if (IS_ERR(cciss_scan_thread)) {
+ err = PTR_ERR(cciss_scan_thread);
+ goto err_bus_unregister;
+ }
+
/* Register for our PCI devices */
err = pci_register_driver(&cciss_pci_driver);
if (err)
- goto err_bus_register;
+ goto err_thread_stop;
- return 0;
+ return err;
-err_bus_register:
+err_thread_stop:
+ kthread_stop(cciss_scan_thread);
+err_bus_unregister:
bus_unregister(&cciss_bus_type);
+
return err;
}
@@ -4227,6 +4560,7 @@ static void __exit cciss_cleanup(void)
cciss_remove_one(hba[i]->pdev);
}
}
+ kthread_stop(cciss_scan_thread);
remove_proc_entry("driver/cciss", NULL);
bus_unregister(&cciss_bus_type);
}
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
index 06a5db25b298..31524cf42c77 100644
--- a/drivers/block/cciss.h
+++ b/drivers/block/cciss.h
@@ -2,6 +2,7 @@
#define CCISS_H
#include <linux/genhd.h>
+#include <linux/mutex.h>
#include "cciss_cmd.h"
@@ -29,7 +30,7 @@ struct access_method {
};
typedef struct _drive_info_struct
{
- __u32 LunID;
+ unsigned char LunID[8];
int usage_count;
struct request_queue *queue;
sector_t nr_blocks;
@@ -51,6 +52,7 @@ typedef struct _drive_info_struct
char vendor[VENDOR_LEN + 1]; /* SCSI vendor string */
char model[MODEL_LEN + 1]; /* SCSI model string */
char rev[REV_LEN + 1]; /* SCSI revision string */
+ char device_initialized; /* indicates whether dev is initialized */
} drive_info_struct;
struct ctlr_info
@@ -86,7 +88,7 @@ struct ctlr_info
BYTE cciss_read_capacity;
// information about each logical volume
- drive_info_struct drv[CISS_MAX_LUN];
+ drive_info_struct *drv[CISS_MAX_LUN];
struct access_method access;
@@ -108,6 +110,8 @@ struct ctlr_info
int nr_frees;
int busy_configuring;
int busy_initializing;
+ int busy_scanning;
+ struct mutex busy_shutting_down;
/* This element holds the zero based queue number of the last
* queue to be started. It is used for fairness.
@@ -122,8 +126,8 @@ struct ctlr_info
/* and saved for later processing */
#endif
unsigned char alive;
- struct completion *rescan_wait;
- struct task_struct *cciss_scan_thread;
+ struct list_head scan_list;
+ struct completion scan_wait;
struct device dev;
};
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 44fa2018f6b0..6422651ec364 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -32,6 +32,7 @@
#include <linux/blkpg.h>
#include <linux/timer.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/hdreg.h>
#include <linux/spinlock.h>
@@ -177,7 +178,6 @@ static int cpqarray_register_ctlr(int ctlr, struct pci_dev *pdev);
#ifdef CONFIG_PROC_FS
static void ida_procinit(int i);
-static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
#else
static void ida_procinit(int i) {}
#endif
@@ -193,7 +193,7 @@ static inline ctlr_info_t *get_host(struct gendisk *disk)
}
-static struct block_device_operations ida_fops = {
+static const struct block_device_operations ida_fops = {
.owner = THIS_MODULE,
.open = ida_open,
.release = ida_release,
@@ -206,6 +206,7 @@ static struct block_device_operations ida_fops = {
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_array;
+static const struct file_operations ida_proc_fops;
/*
* Get us a file in /proc/array that says something about each controller.
@@ -218,19 +219,16 @@ static void __init ida_procinit(int i)
if (!proc_array) return;
}
- create_proc_read_entry(hba[i]->devname, 0, proc_array,
- ida_proc_get_info, hba[i]);
+ proc_create_data(hba[i]->devname, 0, proc_array, &ida_proc_fops, hba[i]);
}
/*
* Report information about this controller.
*/
-static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+static int ida_proc_show(struct seq_file *m, void *v)
{
- off_t pos = 0;
- off_t len = 0;
- int size, i, ctlr;
- ctlr_info_t *h = (ctlr_info_t*)data;
+ int i, ctlr;
+ ctlr_info_t *h = (ctlr_info_t*)m->private;
drv_info_t *drv;
#ifdef CPQ_PROC_PRINT_QUEUES
cmdlist_t *c;
@@ -238,7 +236,7 @@ static int ida_proc_get_info(char *buffer, char **start, off_t offset, int lengt
#endif
ctlr = h->ctlr;
- size = sprintf(buffer, "%s: Compaq %s Controller\n"
+ seq_printf(m, "%s: Compaq %s Controller\n"
" Board ID: 0x%08lx\n"
" Firmware Revision: %c%c%c%c\n"
" Controller Sig: 0x%08lx\n"
@@ -258,55 +256,54 @@ static int ida_proc_get_info(char *buffer, char **start, off_t offset, int lengt
h->log_drives, h->phys_drives,
h->Qdepth, h->maxQsinceinit);
- pos += size; len += size;
-
- size = sprintf(buffer+len, "Logical Drive Info:\n");
- pos += size; len += size;
+ seq_puts(m, "Logical Drive Info:\n");
for(i=0; i<h->log_drives; i++) {
drv = &h->drv[i];
- size = sprintf(buffer+len, "ida/c%dd%d: blksz=%d nr_blks=%d\n",
+ seq_printf(m, "ida/c%dd%d: blksz=%d nr_blks=%d\n",
ctlr, i, drv->blk_size, drv->nr_blks);
- pos += size; len += size;
}
#ifdef CPQ_PROC_PRINT_QUEUES
spin_lock_irqsave(IDA_LOCK(h->ctlr), flags);
- size = sprintf(buffer+len, "\nCurrent Queues:\n");
- pos += size; len += size;
+ seq_puts(m, "\nCurrent Queues:\n");
c = h->reqQ;
- size = sprintf(buffer+len, "reqQ = %p", c); pos += size; len += size;
+ seq_printf(m, "reqQ = %p", c);
if (c) c=c->next;
while(c && c != h->reqQ) {
- size = sprintf(buffer+len, "->%p", c);
- pos += size; len += size;
+ seq_printf(m, "->%p", c);
c=c->next;
}
c = h->cmpQ;
- size = sprintf(buffer+len, "\ncmpQ = %p", c); pos += size; len += size;
+ seq_printf(m, "\ncmpQ = %p", c);
if (c) c=c->next;
while(c && c != h->cmpQ) {
- size = sprintf(buffer+len, "->%p", c);
- pos += size; len += size;
+ seq_printf(m, "->%p", c);
c=c->next;
}
- size = sprintf(buffer+len, "\n"); pos += size; len += size;
+ seq_putc(m, '\n');
spin_unlock_irqrestore(IDA_LOCK(h->ctlr), flags);
#endif
- size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n",
+ seq_printf(m, "nr_allocs = %d\nnr_frees = %d\n",
h->nr_allocs, h->nr_frees);
- pos += size; len += size;
-
- *eof = 1;
- *start = buffer+offset;
- len -= offset;
- if (len>length)
- len = length;
- return len;
+ return 0;
+}
+
+static int ida_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ida_proc_show, PDE(inode)->data);
}
+
+static const struct file_operations ida_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = ida_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif /* CONFIG_PROC_FS */
module_param_array(eisa, int, NULL, 0);
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 91b753013780..5c01f747571b 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3907,7 +3907,7 @@ static int floppy_revalidate(struct gendisk *disk)
return res;
}
-static struct block_device_operations floppy_fops = {
+static const struct block_device_operations floppy_fops = {
.owner = THIS_MODULE,
.open = floppy_open,
.release = floppy_release,
@@ -4151,7 +4151,7 @@ static void floppy_device_release(struct device *dev)
{
}
-static int floppy_resume(struct platform_device *dev)
+static int floppy_resume(struct device *dev)
{
int fdc;
@@ -4162,10 +4162,15 @@ static int floppy_resume(struct platform_device *dev)
return 0;
}
-static struct platform_driver floppy_driver = {
+static struct dev_pm_ops floppy_pm_ops = {
.resume = floppy_resume,
+ .restore = floppy_resume,
+};
+
+static struct platform_driver floppy_driver = {
.driver = {
.name = "floppy",
+ .pm = &floppy_pm_ops,
},
};
diff --git a/drivers/block/hd.c b/drivers/block/hd.c
index f9d01608cbe2..d5cdce08ffd2 100644
--- a/drivers/block/hd.c
+++ b/drivers/block/hd.c
@@ -692,7 +692,7 @@ static irqreturn_t hd_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static struct block_device_operations hd_fops = {
+static const struct block_device_operations hd_fops = {
.getgeo = hd_getgeo,
};
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 5757188cd1fb..bd112c8c7bcd 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -475,7 +475,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
pos = ((loff_t) bio->bi_sector << 9) + lo->lo_offset;
if (bio_rw(bio) == WRITE) {
- int barrier = bio_barrier(bio);
+ bool barrier = bio_rw_flagged(bio, BIO_RW_BARRIER);
struct file *file = lo->lo_backing_file;
if (barrier) {
@@ -949,7 +949,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
lo->lo_state = Lo_unbound;
/* This is safe: open() is still holding a reference. */
module_put(THIS_MODULE);
- if (max_part > 0)
+ if (max_part > 0 && bdev)
ioctl_by_bdev(bdev, BLKRRPART, 0);
mutex_unlock(&lo->lo_ctl_mutex);
/*
@@ -1438,7 +1438,7 @@ out_unlocked:
return 0;
}
-static struct block_device_operations lo_fops = {
+static const struct block_device_operations lo_fops = {
.owner = THIS_MODULE,
.open = lo_open,
.release = lo_release,
diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c
index 6d7fbaa92248..e0339aaa1815 100644
--- a/drivers/block/mg_disk.c
+++ b/drivers/block/mg_disk.c
@@ -775,7 +775,7 @@ static int mg_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
-static struct block_device_operations mg_disk_ops = {
+static const struct block_device_operations mg_disk_ops = {
.getgeo = mg_getgeo
};
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 5d23ffad7c77..cc923a5b430c 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -722,7 +722,7 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
return error;
}
-static struct block_device_operations nbd_fops =
+static const struct block_device_operations nbd_fops =
{
.owner = THIS_MODULE,
.locked_ioctl = nbd_ioctl,
diff --git a/drivers/block/osdblk.c b/drivers/block/osdblk.c
index 13c1aee6aa3f..a808b1530b3b 100644
--- a/drivers/block/osdblk.c
+++ b/drivers/block/osdblk.c
@@ -125,7 +125,7 @@ static struct class *class_osdblk; /* /sys/class/osdblk */
static DEFINE_MUTEX(ctl_mutex); /* Serialize open/close/setup/teardown */
static LIST_HEAD(osdblkdev_list);
-static struct block_device_operations osdblk_bd_ops = {
+static const struct block_device_operations osdblk_bd_ops = {
.owner = THIS_MODULE,
};
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
index 911dfd98d813..8866ca369d5e 100644
--- a/drivers/block/paride/pcd.c
+++ b/drivers/block/paride/pcd.c
@@ -219,8 +219,6 @@ static int pcd_sector; /* address of next requested sector */
static int pcd_count; /* number of blocks still to do */
static char *pcd_buf; /* buffer for request in progress */
-static int pcd_warned; /* Have we logged a phase warning ? */
-
/* kernel glue structures */
static int pcd_block_open(struct block_device *bdev, fmode_t mode)
@@ -249,7 +247,7 @@ static int pcd_block_media_changed(struct gendisk *disk)
return cdrom_media_changed(&cd->info);
}
-static struct block_device_operations pcd_bdops = {
+static const struct block_device_operations pcd_bdops = {
.owner = THIS_MODULE,
.open = pcd_block_open,
.release = pcd_block_release,
@@ -417,12 +415,10 @@ static int pcd_completion(struct pcd_unit *cd, char *buf, char *fun)
printk
("%s: %s: Unexpected phase %d, d=%d, k=%d\n",
cd->name, fun, p, d, k);
- if ((verbose < 2) && !pcd_warned) {
- pcd_warned = 1;
- printk
- ("%s: WARNING: ATAPI phase errors\n",
- cd->name);
- }
+ if (verbose < 2)
+ printk_once(
+ "%s: WARNING: ATAPI phase errors\n",
+ cd->name);
mdelay(1);
}
if (k++ > PCD_TMO) {
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index bf5955b3d873..569e39e8f114 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -807,7 +807,7 @@ static int pd_revalidate(struct gendisk *p)
return 0;
}
-static struct block_device_operations pd_fops = {
+static const struct block_device_operations pd_fops = {
.owner = THIS_MODULE,
.open = pd_open,
.release = pd_release,
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index 68a90834e993..ea54ea393553 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -262,7 +262,7 @@ static char *pf_buf; /* buffer for request in progress */
/* kernel glue structures */
-static struct block_device_operations pf_fops = {
+static const struct block_device_operations pf_fops = {
.owner = THIS_MODULE,
.open = pf_open,
.release = pf_release,
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 99a506f619b7..2ddf03ae034e 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -92,7 +92,7 @@ static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */
static mempool_t *psd_pool;
static struct class *class_pktcdvd = NULL; /* /sys/class/pktcdvd */
-static struct dentry *pkt_debugfs_root = NULL; /* /debug/pktcdvd */
+static struct dentry *pkt_debugfs_root = NULL; /* /sys/kernel/debug/pktcdvd */
/* forward declaration */
static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev);
@@ -2849,7 +2849,7 @@ static int pkt_media_changed(struct gendisk *disk)
return attached_disk->fops->media_changed(attached_disk);
}
-static struct block_device_operations pktcdvd_ops = {
+static const struct block_device_operations pktcdvd_ops = {
.owner = THIS_MODULE,
.open = pkt_open,
.release = pkt_close,
@@ -2857,7 +2857,7 @@ static struct block_device_operations pktcdvd_ops = {
.media_changed = pkt_media_changed,
};
-static char *pktcdvd_nodename(struct gendisk *gd)
+static char *pktcdvd_devnode(struct gendisk *gd, mode_t *mode)
{
return kasprintf(GFP_KERNEL, "pktcdvd/%s", gd->disk_name);
}
@@ -2914,7 +2914,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
disk->fops = &pktcdvd_ops;
disk->flags = GENHD_FL_REMOVABLE;
strcpy(disk->disk_name, pd->name);
- disk->nodename = pktcdvd_nodename;
+ disk->devnode = pktcdvd_devnode;
disk->private_data = pd;
disk->queue = blk_alloc_queue(GFP_KERNEL);
if (!disk->queue)
@@ -3070,7 +3070,7 @@ static const struct file_operations pkt_ctl_fops = {
static struct miscdevice pkt_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DRIVER_NAME,
- .name = "pktcdvd/control",
+ .nodename = "pktcdvd/control",
.fops = &pkt_ctl_fops
};
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
index 34cbb7f3efa8..03a130dca8ab 100644
--- a/drivers/block/ps3disk.c
+++ b/drivers/block/ps3disk.c
@@ -82,7 +82,7 @@ enum lv1_ata_in_out {
static int ps3disk_major;
-static struct block_device_operations ps3disk_fops = {
+static const struct block_device_operations ps3disk_fops = {
.owner = THIS_MODULE,
};
diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c
index 095f97e60665..3bb7c47c869f 100644
--- a/drivers/block/ps3vram.c
+++ b/drivers/block/ps3vram.c
@@ -13,8 +13,8 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <asm/cell-regs.h>
#include <asm/firmware.h>
-#include <asm/iommu.h>
#include <asm/lv1call.h>
#include <asm/ps3.h>
#include <asm/ps3gpu.h>
@@ -88,7 +88,7 @@ struct ps3vram_priv {
static int ps3vram_major;
-static struct block_device_operations ps3vram_fops = {
+static const struct block_device_operations ps3vram_fops = {
.owner = THIS_MODULE,
};
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index cbfd9c0aef03..411f064760b4 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -103,7 +103,7 @@ static int vdc_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
-static struct block_device_operations vdc_fops = {
+static const struct block_device_operations vdc_fops = {
.owner = THIS_MODULE,
.getgeo = vdc_getgeo,
};
diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index cf7877fb8a7d..8f569e3df890 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -748,7 +748,7 @@ static int floppy_revalidate(struct gendisk *disk)
return !fs->disk_in;
}
-static struct block_device_operations floppy_fops = {
+static const struct block_device_operations floppy_fops = {
.owner = THIS_MODULE,
.open = floppy_open,
.release = floppy_release,
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index 80df93e3cdd0..6380ad8d91bd 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -998,7 +998,7 @@ static int floppy_revalidate(struct gendisk *disk)
return ret;
}
-static struct block_device_operations floppy_fops = {
+static const struct block_device_operations floppy_fops = {
.open = floppy_open,
.release = floppy_release,
.locked_ioctl = floppy_ioctl,
@@ -1062,7 +1062,7 @@ static int swim3_add_device(struct macio_dev *mdev, int index)
goto out_release;
}
fs->swim3_intr = macio_irq(mdev, 0);
- fs->dma_intr = macio_irq(mdev, 1);;
+ fs->dma_intr = macio_irq(mdev, 1);
fs->cur_cyl = -1;
fs->cur_sector = -1;
fs->secpercyl = 36;
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index da403b6a7f43..a7c4184f4a63 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -423,7 +423,7 @@ static struct pci_driver carm_driver = {
.remove = carm_remove_one,
};
-static struct block_device_operations carm_bd_ops = {
+static const struct block_device_operations carm_bd_ops = {
.owner = THIS_MODULE,
.getgeo = carm_bdev_getgeo,
};
@@ -1564,15 +1564,13 @@ static int carm_init_shm(struct carm_host *host)
static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static unsigned int printed_version;
struct carm_host *host;
unsigned int pci_dac;
int rc;
struct request_queue *q;
unsigned int i;
- if (!printed_version++)
- printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+ printk_once(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
rc = pci_enable_device(pdev);
if (rc)
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index cc54473b8e77..c739b203fe91 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -1789,7 +1789,7 @@ static int ub_bd_media_changed(struct gendisk *disk)
return lun->changed;
}
-static struct block_device_operations ub_bd_fops = {
+static const struct block_device_operations ub_bd_fops = {
.owner = THIS_MODULE,
.open = ub_bd_open,
.release = ub_bd_release,
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index 858c34dd032d..ad1ba393801a 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -140,7 +140,6 @@ struct cardinfo {
};
static struct cardinfo cards[MM_MAXCARDS];
-static struct block_device_operations mm_fops;
static struct timer_list battery_timer;
static int num_cards;
@@ -789,7 +788,7 @@ static int mm_check_change(struct gendisk *disk)
return 0;
}
-static struct block_device_operations mm_fops = {
+static const struct block_device_operations mm_fops = {
.owner = THIS_MODULE,
.getgeo = mm_getgeo,
.revalidate_disk = mm_revalidate,
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
index 390d69bb7c48..a8c8b56b275e 100644
--- a/drivers/block/viodasd.c
+++ b/drivers/block/viodasd.c
@@ -219,7 +219,7 @@ static int viodasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
/*
* Our file operations table
*/
-static struct block_device_operations viodasd_fops = {
+static const struct block_device_operations viodasd_fops = {
.owner = THIS_MODULE,
.open = viodasd_open,
.release = viodasd_release,
@@ -416,15 +416,9 @@ retry:
goto retry;
}
if (we.max_disk > (MAX_DISKNO - 1)) {
- static int warned;
-
- if (warned == 0) {
- warned++;
- printk(VIOD_KERN_INFO
- "Only examining the first %d "
- "of %d disks connected\n",
- MAX_DISKNO, we.max_disk + 1);
- }
+ printk_once(VIOD_KERN_INFO
+ "Only examining the first %d of %d disks connected\n",
+ MAX_DISKNO, we.max_disk + 1);
}
/* Send the close event to OS/400. We DON'T expect a response */
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index aa1a3d5a3e2b..51042f0ba7e1 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -91,15 +91,26 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
return false;
vbr->req = req;
- if (blk_fs_request(vbr->req)) {
+ switch (req->cmd_type) {
+ case REQ_TYPE_FS:
vbr->out_hdr.type = 0;
vbr->out_hdr.sector = blk_rq_pos(vbr->req);
vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
- } else if (blk_pc_request(vbr->req)) {
+ break;
+ case REQ_TYPE_BLOCK_PC:
vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD;
vbr->out_hdr.sector = 0;
vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
- } else {
+ break;
+ case REQ_TYPE_LINUX_BLOCK:
+ if (req->cmd[0] == REQ_LB_OP_FLUSH) {
+ vbr->out_hdr.type = VIRTIO_BLK_T_FLUSH;
+ vbr->out_hdr.sector = 0;
+ vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
+ break;
+ }
+ /*FALLTHRU*/
+ default:
/* We don't put anything else in the queue. */
BUG();
}
@@ -139,7 +150,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
}
}
- if (vblk->vq->vq_ops->add_buf(vblk->vq, vblk->sg, out, in, vbr)) {
+ if (vblk->vq->vq_ops->add_buf(vblk->vq, vblk->sg, out, in, vbr) < 0) {
mempool_free(vbr, vblk->pool);
return false;
}
@@ -171,32 +182,10 @@ static void do_virtblk_request(struct request_queue *q)
vblk->vq->vq_ops->kick(vblk->vq);
}
-/* return ATA identify data
- */
-static int virtblk_identify(struct gendisk *disk, void *argp)
+static void virtblk_prepare_flush(struct request_queue *q, struct request *req)
{
- struct virtio_blk *vblk = disk->private_data;
- void *opaque;
- int err = -ENOMEM;
-
- opaque = kmalloc(VIRTIO_BLK_ID_BYTES, GFP_KERNEL);
- if (!opaque)
- goto out;
-
- err = virtio_config_buf(vblk->vdev, VIRTIO_BLK_F_IDENTIFY,
- offsetof(struct virtio_blk_config, identify), opaque,
- VIRTIO_BLK_ID_BYTES);
-
- if (err)
- goto out_kfree;
-
- if (copy_to_user(argp, opaque, VIRTIO_BLK_ID_BYTES))
- err = -EFAULT;
-
-out_kfree:
- kfree(opaque);
-out:
- return err;
+ req->cmd_type = REQ_TYPE_LINUX_BLOCK;
+ req->cmd[0] = REQ_LB_OP_FLUSH;
}
static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
@@ -204,10 +193,6 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
{
struct gendisk *disk = bdev->bd_disk;
struct virtio_blk *vblk = disk->private_data;
- void __user *argp = (void __user *)data;
-
- if (cmd == HDIO_GET_IDENTITY)
- return virtblk_identify(disk, argp);
/*
* Only allow the generic SCSI ioctls if the host can support it.
@@ -215,7 +200,8 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI))
return -ENOTTY;
- return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp);
+ return scsi_cmd_ioctl(disk->queue, disk, mode, cmd,
+ (void __user *)data);
}
/* We provide getgeo only to please some old bootloader/partitioning tools */
@@ -243,7 +229,7 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
return 0;
}
-static struct block_device_operations virtblk_fops = {
+static const struct block_device_operations virtblk_fops = {
.locked_ioctl = virtblk_ioctl,
.owner = THIS_MODULE,
.getgeo = virtblk_getgeo,
@@ -314,7 +300,6 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
}
vblk->disk->queue->queuedata = vblk;
- queue_flag_set_unlocked(QUEUE_FLAG_VIRT, vblk->disk->queue);
if (index < 26) {
sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26);
@@ -337,7 +322,10 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
index++;
/* If barriers are supported, tell block layer that queue is ordered */
- if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
+ if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH))
+ blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_DRAIN_FLUSH,
+ virtblk_prepare_flush);
+ else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
/* If disk is read-only in the host, the guest should obey */
@@ -424,7 +412,7 @@ static struct virtio_device_id id_table[] = {
static unsigned int features[] = {
VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
- VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_IDENTIFY
+ VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH
};
/*
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index ce2429219925..0877d3628fda 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -130,7 +130,7 @@ static struct gendisk *xd_gendisk[2];
static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
-static struct block_device_operations xd_fops = {
+static const struct block_device_operations xd_fops = {
.owner = THIS_MODULE,
.locked_ioctl = xd_ioctl,
.getgeo = xd_getgeo,
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index e53284767f7c..b8578bb3f4c9 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -65,7 +65,7 @@ struct blk_shadow {
unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST];
};
-static struct block_device_operations xlvbd_block_fops;
+static const struct block_device_operations xlvbd_block_fops;
#define BLK_RING_SIZE __RING_SIZE((struct blkif_sring *)0, PAGE_SIZE)
@@ -1039,7 +1039,7 @@ static int blkif_release(struct gendisk *disk, fmode_t mode)
return 0;
}
-static struct block_device_operations xlvbd_block_fops =
+static const struct block_device_operations xlvbd_block_fops =
{
.owner = THIS_MODULE,
.open = blkif_open,
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index b20abe102a2b..e5c5415eb45e 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -941,7 +941,7 @@ static int ace_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
-static struct block_device_operations ace_fops = {
+static const struct block_device_operations ace_fops = {
.owner = THIS_MODULE,
.open = ace_open,
.release = ace_release,
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index b2590409f25e..64f941e0f14b 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -64,7 +64,6 @@ static int current_device = -1;
static DEFINE_SPINLOCK(z2ram_lock);
-static struct block_device_operations z2_fops;
static struct gendisk *z2ram_gendisk;
static void do_z2_request(struct request_queue *q)
@@ -315,7 +314,7 @@ z2_release(struct gendisk *disk, fmode_t mode)
return 0;
}
-static struct block_device_operations z2_fops =
+static const struct block_device_operations z2_fops =
{
.owner = THIS_MODULE,
.open = z2_open,
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 1164837bb781..652367aa6546 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -170,5 +170,30 @@ config BT_HCIVHCI
Say Y here to compile support for virtual HCI devices into the
kernel or say M to compile it as module (hci_vhci).
+config BT_MRVL
+ tristate "Marvell Bluetooth driver support"
+ help
+ The core driver to support Marvell Bluetooth devices.
+
+ This driver is required if you want to support
+ Marvell Bluetooth devices, such as 8688.
+
+ Say Y here to compile Marvell Bluetooth driver
+ into the kernel or say M to compile it as module.
+
+config BT_MRVL_SDIO
+ tristate "Marvell BT-over-SDIO driver"
+ depends on BT_MRVL && MMC
+ select FW_LOADER
+ help
+ The driver for Marvell Bluetooth chipsets with SDIO interface.
+
+ This driver is required if you want to use Marvell Bluetooth
+ devices with SDIO interface. Currently only SD8688 chipset is
+ supported.
+
+ Say Y here to compile support for Marvell BT-over-SDIO driver
+ into the kernel or say M to compile it as module.
+
endmenu
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 16930f93d1ca..b3f57d2d4eb0 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -15,6 +15,12 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
obj-$(CONFIG_BT_HCIBTUSB) += btusb.o
obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o
+obj-$(CONFIG_BT_MRVL) += btmrvl.o
+obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o
+
+btmrvl-y := btmrvl_main.o
+btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
+
hci_uart-y := hci_ldisc.o
hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index b0e569ba730d..2acdc605cb4b 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -867,11 +867,9 @@ static int bluecard_probe(struct pcmcia_device *link)
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
link->io.NumPorts1 = 8;
- link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
- link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
link->irq.Handler = bluecard_interrupt;
- link->irq.Instance = info;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -905,22 +903,16 @@ static int bluecard_config(struct pcmcia_device *link)
break;
}
- if (i != 0) {
- cs_error(link, RequestIO, i);
+ if (i != 0)
goto failed;
- }
i = pcmcia_request_irq(link, &link->irq);
- if (i != 0) {
- cs_error(link, RequestIRQ, i);
+ if (i != 0)
link->irq.AssignedIRQ = 0;
- }
i = pcmcia_request_configuration(link, &link->conf);
- if (i != 0) {
- cs_error(link, RequestConfiguration, i);
+ if (i != 0)
goto failed;
- }
if (bluecard_open(info) != 0)
goto failed;
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index d58e22b9f06a..d814a2755ccb 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -659,11 +659,9 @@ static int bt3c_probe(struct pcmcia_device *link)
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
link->io.NumPorts1 = 8;
- link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
- link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
link->irq.Handler = bt3c_interrupt;
- link->irq.Instance = info;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -740,21 +738,16 @@ static int bt3c_config(struct pcmcia_device *link)
goto found_port;
BT_ERR("No usable port range found");
- cs_error(link, RequestIO, -ENODEV);
goto failed;
found_port:
i = pcmcia_request_irq(link, &link->irq);
- if (i != 0) {
- cs_error(link, RequestIRQ, i);
+ if (i != 0)
link->irq.AssignedIRQ = 0;
- }
i = pcmcia_request_configuration(link, &link->conf);
- if (i != 0) {
- cs_error(link, RequestConfiguration, i);
+ if (i != 0)
goto failed;
- }
if (bt3c_open(info) != 0)
goto failed;
diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c
new file mode 100644
index 000000000000..4617bd12f63b
--- /dev/null
+++ b/drivers/bluetooth/btmrvl_debugfs.c
@@ -0,0 +1,432 @@
+/**
+ * Marvell Bluetooth driver: debugfs related functions
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ **/
+
+#include <linux/debugfs.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "btmrvl_drv.h"
+
+struct btmrvl_debugfs_data {
+ struct dentry *root_dir, *config_dir, *status_dir;
+
+ /* config */
+ struct dentry *drvdbg;
+ struct dentry *psmode;
+ struct dentry *pscmd;
+ struct dentry *hsmode;
+ struct dentry *hscmd;
+ struct dentry *gpiogap;
+ struct dentry *hscfgcmd;
+
+ /* status */
+ struct dentry *curpsmode;
+ struct dentry *hsstate;
+ struct dentry *psstate;
+ struct dentry *txdnldready;
+};
+
+static int btmrvl_open_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t btmrvl_hscfgcmd_write(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ long result, ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ ret = strict_strtol(buf, 10, &result);
+
+ priv->btmrvl_dev.hscfgcmd = result;
+
+ if (priv->btmrvl_dev.hscfgcmd) {
+ btmrvl_prepare_command(priv);
+ wake_up_interruptible(&priv->main_thread.wait_q);
+ }
+
+ return count;
+}
+
+static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
+ priv->btmrvl_dev.hscfgcmd);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_hscfgcmd_fops = {
+ .read = btmrvl_hscfgcmd_read,
+ .write = btmrvl_hscfgcmd_write,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ long result, ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ ret = strict_strtol(buf, 10, &result);
+
+ priv->btmrvl_dev.psmode = result;
+
+ return count;
+}
+
+static ssize_t btmrvl_psmode_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
+ priv->btmrvl_dev.psmode);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_psmode_fops = {
+ .read = btmrvl_psmode_read,
+ .write = btmrvl_psmode_write,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ long result, ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ ret = strict_strtol(buf, 10, &result);
+
+ priv->btmrvl_dev.pscmd = result;
+
+ if (priv->btmrvl_dev.pscmd) {
+ btmrvl_prepare_command(priv);
+ wake_up_interruptible(&priv->main_thread.wait_q);
+ }
+
+ return count;
+
+}
+
+static ssize_t btmrvl_pscmd_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_pscmd_fops = {
+ .read = btmrvl_pscmd_read,
+ .write = btmrvl_pscmd_write,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ long result, ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ ret = strict_strtol(buf, 16, &result);
+
+ priv->btmrvl_dev.gpio_gap = result;
+
+ return count;
+}
+
+static ssize_t btmrvl_gpiogap_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "0x%x\n",
+ priv->btmrvl_dev.gpio_gap);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_gpiogap_fops = {
+ .read = btmrvl_gpiogap_read,
+ .write = btmrvl_gpiogap_write,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = (struct btmrvl_private *) file->private_data;
+ char buf[16];
+ long result, ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ ret = strict_strtol(buf, 10, &result);
+
+ priv->btmrvl_dev.hscmd = result;
+ if (priv->btmrvl_dev.hscmd) {
+ btmrvl_prepare_command(priv);
+ wake_up_interruptible(&priv->main_thread.wait_q);
+ }
+
+ return count;
+}
+
+static ssize_t btmrvl_hscmd_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_hscmd_fops = {
+ .read = btmrvl_hscmd_read,
+ .write = btmrvl_hscmd_write,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ long result, ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ ret = strict_strtol(buf, 10, &result);
+
+ priv->btmrvl_dev.hsmode = result;
+
+ return count;
+}
+
+static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hsmode);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_hsmode_fops = {
+ .read = btmrvl_hsmode_read,
+ .write = btmrvl_hsmode_write,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->psmode);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_curpsmode_fops = {
+ .read = btmrvl_curpsmode_read,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->ps_state);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_psstate_fops = {
+ .read = btmrvl_psstate_read,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->hs_state);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_hsstate_fops = {
+ .read = btmrvl_hsstate_read,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
+ priv->btmrvl_dev.tx_dnld_rdy);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_txdnldready_fops = {
+ .read = btmrvl_txdnldready_read,
+ .open = btmrvl_open_generic,
+};
+
+void btmrvl_debugfs_init(struct hci_dev *hdev)
+{
+ struct btmrvl_private *priv = hdev->driver_data;
+ struct btmrvl_debugfs_data *dbg;
+
+ dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
+ priv->debugfs_data = dbg;
+
+ if (!dbg) {
+ BT_ERR("Can not allocate memory for btmrvl_debugfs_data.");
+ return;
+ }
+
+ dbg->root_dir = debugfs_create_dir("btmrvl", NULL);
+
+ dbg->config_dir = debugfs_create_dir("config", dbg->root_dir);
+
+ dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir,
+ hdev->driver_data, &btmrvl_psmode_fops);
+ dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir,
+ hdev->driver_data, &btmrvl_pscmd_fops);
+ dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir,
+ hdev->driver_data, &btmrvl_gpiogap_fops);
+ dbg->hsmode = debugfs_create_file("hsmode", 0644, dbg->config_dir,
+ hdev->driver_data, &btmrvl_hsmode_fops);
+ dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir,
+ hdev->driver_data, &btmrvl_hscmd_fops);
+ dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
+ hdev->driver_data, &btmrvl_hscfgcmd_fops);
+
+ dbg->status_dir = debugfs_create_dir("status", dbg->root_dir);
+ dbg->curpsmode = debugfs_create_file("curpsmode", 0444,
+ dbg->status_dir,
+ hdev->driver_data,
+ &btmrvl_curpsmode_fops);
+ dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir,
+ hdev->driver_data, &btmrvl_psstate_fops);
+ dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir,
+ hdev->driver_data, &btmrvl_hsstate_fops);
+ dbg->txdnldready = debugfs_create_file("txdnldready", 0444,
+ dbg->status_dir,
+ hdev->driver_data,
+ &btmrvl_txdnldready_fops);
+}
+
+void btmrvl_debugfs_remove(struct hci_dev *hdev)
+{
+ struct btmrvl_private *priv = hdev->driver_data;
+ struct btmrvl_debugfs_data *dbg = priv->debugfs_data;
+
+ if (!dbg)
+ return;
+
+ debugfs_remove(dbg->psmode);
+ debugfs_remove(dbg->pscmd);
+ debugfs_remove(dbg->gpiogap);
+ debugfs_remove(dbg->hsmode);
+ debugfs_remove(dbg->hscmd);
+ debugfs_remove(dbg->hscfgcmd);
+ debugfs_remove(dbg->config_dir);
+
+ debugfs_remove(dbg->curpsmode);
+ debugfs_remove(dbg->psstate);
+ debugfs_remove(dbg->hsstate);
+ debugfs_remove(dbg->txdnldready);
+ debugfs_remove(dbg->status_dir);
+
+ debugfs_remove(dbg->root_dir);
+
+ kfree(dbg);
+}
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
new file mode 100644
index 000000000000..411c7a77082d
--- /dev/null
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -0,0 +1,139 @@
+/*
+ * Marvell Bluetooth driver: global definitions & declarations
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+#include <linux/kthread.h>
+#include <linux/bitops.h>
+#include <net/bluetooth/bluetooth.h>
+
+#define BTM_HEADER_LEN 4
+#define BTM_UPLD_SIZE 2312
+
+/* Time to wait until Host Sleep state change in millisecond */
+#define WAIT_UNTIL_HS_STATE_CHANGED 5000
+/* Time to wait for command response in millisecond */
+#define WAIT_UNTIL_CMD_RESP 5000
+
+struct btmrvl_thread {
+ struct task_struct *task;
+ wait_queue_head_t wait_q;
+ void *priv;
+};
+
+struct btmrvl_device {
+ void *card;
+ struct hci_dev *hcidev;
+
+ u8 tx_dnld_rdy;
+
+ u8 psmode;
+ u8 pscmd;
+ u8 hsmode;
+ u8 hscmd;
+
+ /* Low byte is gap, high byte is GPIO */
+ u16 gpio_gap;
+
+ u8 hscfgcmd;
+ u8 sendcmdflag;
+};
+
+struct btmrvl_adapter {
+ u32 int_count;
+ struct sk_buff_head tx_queue;
+ u8 psmode;
+ u8 ps_state;
+ u8 hs_state;
+ u8 wakeup_tries;
+ wait_queue_head_t cmd_wait_q;
+ u8 cmd_complete;
+};
+
+struct btmrvl_private {
+ struct btmrvl_device btmrvl_dev;
+ struct btmrvl_adapter *adapter;
+ struct btmrvl_thread main_thread;
+ int (*hw_host_to_card) (struct btmrvl_private *priv,
+ u8 *payload, u16 nb);
+ int (*hw_wakeup_firmware) (struct btmrvl_private *priv);
+ spinlock_t driver_lock; /* spinlock used by driver */
+#ifdef CONFIG_DEBUG_FS
+ void *debugfs_data;
+#endif
+};
+
+#define MRVL_VENDOR_PKT 0xFE
+
+/* Bluetooth commands */
+#define BT_CMD_AUTO_SLEEP_MODE 0x23
+#define BT_CMD_HOST_SLEEP_CONFIG 0x59
+#define BT_CMD_HOST_SLEEP_ENABLE 0x5A
+#define BT_CMD_MODULE_CFG_REQ 0x5B
+
+/* Sub-commands: Module Bringup/Shutdown Request */
+#define MODULE_BRINGUP_REQ 0xF1
+#define MODULE_SHUTDOWN_REQ 0xF2
+
+#define BT_EVENT_POWER_STATE 0x20
+
+/* Bluetooth Power States */
+#define BT_PS_ENABLE 0x02
+#define BT_PS_DISABLE 0x03
+#define BT_PS_SLEEP 0x01
+
+#define OGF 0x3F
+
+/* Host Sleep states */
+#define HS_ACTIVATED 0x01
+#define HS_DEACTIVATED 0x00
+
+/* Power Save modes */
+#define PS_SLEEP 0x01
+#define PS_AWAKE 0x00
+
+struct btmrvl_cmd {
+ __le16 ocf_ogf;
+ u8 length;
+ u8 data[4];
+} __attribute__ ((packed));
+
+struct btmrvl_event {
+ u8 ec; /* event counter */
+ u8 length;
+ u8 data[4];
+} __attribute__ ((packed));
+
+/* Prototype of global function */
+
+struct btmrvl_private *btmrvl_add_card(void *card);
+int btmrvl_remove_card(struct btmrvl_private *priv);
+
+void btmrvl_interrupt(struct btmrvl_private *priv);
+
+void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);
+int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb);
+
+int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd);
+int btmrvl_prepare_command(struct btmrvl_private *priv);
+
+#ifdef CONFIG_DEBUG_FS
+void btmrvl_debugfs_init(struct hci_dev *hdev);
+void btmrvl_debugfs_remove(struct hci_dev *hdev);
+#endif
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
new file mode 100644
index 000000000000..e605563b4eaa
--- /dev/null
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -0,0 +1,624 @@
+/**
+ * Marvell Bluetooth driver
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ **/
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "btmrvl_drv.h"
+
+#define VERSION "1.0"
+
+/*
+ * This function is called by interface specific interrupt handler.
+ * It updates Power Save & Host Sleep states, and wakes up the main
+ * thread.
+ */
+void btmrvl_interrupt(struct btmrvl_private *priv)
+{
+ priv->adapter->ps_state = PS_AWAKE;
+
+ priv->adapter->wakeup_tries = 0;
+
+ priv->adapter->int_count++;
+
+ wake_up_interruptible(&priv->main_thread.wait_q);
+}
+EXPORT_SYMBOL_GPL(btmrvl_interrupt);
+
+void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb)
+{
+ struct hci_event_hdr *hdr = (void *) skb->data;
+ struct hci_ev_cmd_complete *ec;
+ u16 opcode, ocf;
+
+ if (hdr->evt == HCI_EV_CMD_COMPLETE) {
+ ec = (void *) (skb->data + HCI_EVENT_HDR_SIZE);
+ opcode = __le16_to_cpu(ec->opcode);
+ ocf = hci_opcode_ocf(opcode);
+ if (ocf == BT_CMD_MODULE_CFG_REQ &&
+ priv->btmrvl_dev.sendcmdflag) {
+ priv->btmrvl_dev.sendcmdflag = false;
+ priv->adapter->cmd_complete = true;
+ wake_up_interruptible(&priv->adapter->cmd_wait_q);
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(btmrvl_check_evtpkt);
+
+int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
+{
+ struct btmrvl_adapter *adapter = priv->adapter;
+ struct btmrvl_event *event;
+ u8 ret = 0;
+
+ event = (struct btmrvl_event *) skb->data;
+ if (event->ec != 0xff) {
+ BT_DBG("Not Marvell Event=%x", event->ec);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ switch (event->data[0]) {
+ case BT_CMD_AUTO_SLEEP_MODE:
+ if (!event->data[2]) {
+ if (event->data[1] == BT_PS_ENABLE)
+ adapter->psmode = 1;
+ else
+ adapter->psmode = 0;
+ BT_DBG("PS Mode:%s",
+ (adapter->psmode) ? "Enable" : "Disable");
+ } else {
+ BT_DBG("PS Mode command failed");
+ }
+ break;
+
+ case BT_CMD_HOST_SLEEP_CONFIG:
+ if (!event->data[3])
+ BT_DBG("gpio=%x, gap=%x", event->data[1],
+ event->data[2]);
+ else
+ BT_DBG("HSCFG command failed");
+ break;
+
+ case BT_CMD_HOST_SLEEP_ENABLE:
+ if (!event->data[1]) {
+ adapter->hs_state = HS_ACTIVATED;
+ if (adapter->psmode)
+ adapter->ps_state = PS_SLEEP;
+ wake_up_interruptible(&adapter->cmd_wait_q);
+ BT_DBG("HS ACTIVATED!");
+ } else {
+ BT_DBG("HS Enable failed");
+ }
+ break;
+
+ case BT_CMD_MODULE_CFG_REQ:
+ if (priv->btmrvl_dev.sendcmdflag &&
+ event->data[1] == MODULE_BRINGUP_REQ) {
+ BT_DBG("EVENT:%s", (event->data[2]) ?
+ "Bring-up failed" : "Bring-up succeed");
+ } else if (priv->btmrvl_dev.sendcmdflag &&
+ event->data[1] == MODULE_SHUTDOWN_REQ) {
+ BT_DBG("EVENT:%s", (event->data[2]) ?
+ "Shutdown failed" : "Shutdown succeed");
+ } else {
+ BT_DBG("BT_CMD_MODULE_CFG_REQ resp for APP");
+ ret = -EINVAL;
+ }
+ break;
+
+ case BT_EVENT_POWER_STATE:
+ if (event->data[1] == BT_PS_SLEEP)
+ adapter->ps_state = PS_SLEEP;
+ BT_DBG("EVENT:%s",
+ (adapter->ps_state) ? "PS_SLEEP" : "PS_AWAKE");
+ break;
+
+ default:
+ BT_DBG("Unknown Event=%d", event->data[0]);
+ ret = -EINVAL;
+ break;
+ }
+
+exit:
+ if (!ret)
+ kfree_skb(skb);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(btmrvl_process_event);
+
+int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd)
+{
+ struct sk_buff *skb;
+ struct btmrvl_cmd *cmd;
+ int ret = 0;
+
+ skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
+ if (skb == NULL) {
+ BT_ERR("No free skb");
+ return -ENOMEM;
+ }
+
+ cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
+ cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_MODULE_CFG_REQ));
+ cmd->length = 1;
+ cmd->data[0] = subcmd;
+
+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+
+ skb->dev = (void *) priv->btmrvl_dev.hcidev;
+ skb_queue_head(&priv->adapter->tx_queue, skb);
+
+ priv->btmrvl_dev.sendcmdflag = true;
+
+ priv->adapter->cmd_complete = false;
+
+ BT_DBG("Queue module cfg Command");
+
+ wake_up_interruptible(&priv->main_thread.wait_q);
+
+ if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q,
+ priv->adapter->cmd_complete,
+ msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) {
+ ret = -ETIMEDOUT;
+ BT_ERR("module_cfg_cmd(%x): timeout: %d",
+ subcmd, priv->btmrvl_dev.sendcmdflag);
+ }
+
+ BT_DBG("module cfg Command done");
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd);
+
+static int btmrvl_enable_hs(struct btmrvl_private *priv)
+{
+ struct sk_buff *skb;
+ struct btmrvl_cmd *cmd;
+ int ret = 0;
+
+ skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
+ if (skb == NULL) {
+ BT_ERR("No free skb");
+ return -ENOMEM;
+ }
+
+ cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
+ cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_ENABLE));
+ cmd->length = 0;
+
+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+
+ skb->dev = (void *) priv->btmrvl_dev.hcidev;
+ skb_queue_head(&priv->adapter->tx_queue, skb);
+
+ BT_DBG("Queue hs enable Command");
+
+ wake_up_interruptible(&priv->main_thread.wait_q);
+
+ if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q,
+ priv->adapter->hs_state,
+ msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED))) {
+ ret = -ETIMEDOUT;
+ BT_ERR("timeout: %d, %d,%d", priv->adapter->hs_state,
+ priv->adapter->ps_state,
+ priv->adapter->wakeup_tries);
+ }
+
+ return ret;
+}
+
+int btmrvl_prepare_command(struct btmrvl_private *priv)
+{
+ struct sk_buff *skb = NULL;
+ struct btmrvl_cmd *cmd;
+ int ret = 0;
+
+ if (priv->btmrvl_dev.hscfgcmd) {
+ priv->btmrvl_dev.hscfgcmd = 0;
+
+ skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
+ if (skb == NULL) {
+ BT_ERR("No free skb");
+ return -ENOMEM;
+ }
+
+ cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
+ cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_CONFIG));
+ cmd->length = 2;
+ cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8;
+ cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff);
+
+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+
+ skb->dev = (void *) priv->btmrvl_dev.hcidev;
+ skb_queue_head(&priv->adapter->tx_queue, skb);
+
+ BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x",
+ cmd->data[0], cmd->data[1]);
+ }
+
+ if (priv->btmrvl_dev.pscmd) {
+ priv->btmrvl_dev.pscmd = 0;
+
+ skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
+ if (skb == NULL) {
+ BT_ERR("No free skb");
+ return -ENOMEM;
+ }
+
+ cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
+ cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_AUTO_SLEEP_MODE));
+ cmd->length = 1;
+
+ if (priv->btmrvl_dev.psmode)
+ cmd->data[0] = BT_PS_ENABLE;
+ else
+ cmd->data[0] = BT_PS_DISABLE;
+
+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+
+ skb->dev = (void *) priv->btmrvl_dev.hcidev;
+ skb_queue_head(&priv->adapter->tx_queue, skb);
+
+ BT_DBG("Queue PSMODE Command:%d", cmd->data[0]);
+ }
+
+ if (priv->btmrvl_dev.hscmd) {
+ priv->btmrvl_dev.hscmd = 0;
+
+ if (priv->btmrvl_dev.hsmode) {
+ ret = btmrvl_enable_hs(priv);
+ } else {
+ ret = priv->hw_wakeup_firmware(priv);
+ priv->adapter->hs_state = HS_DEACTIVATED;
+ }
+ }
+
+ return ret;
+}
+
+static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb)
+{
+ int ret = 0;
+
+ if (!skb || !skb->data)
+ return -EINVAL;
+
+ if (!skb->len || ((skb->len + BTM_HEADER_LEN) > BTM_UPLD_SIZE)) {
+ BT_ERR("Tx Error: Bad skb length %d : %d",
+ skb->len, BTM_UPLD_SIZE);
+ return -EINVAL;
+ }
+
+ if (skb_headroom(skb) < BTM_HEADER_LEN) {
+ struct sk_buff *tmp = skb;
+
+ skb = skb_realloc_headroom(skb, BTM_HEADER_LEN);
+ if (!skb) {
+ BT_ERR("Tx Error: realloc_headroom failed %d",
+ BTM_HEADER_LEN);
+ skb = tmp;
+ return -EINVAL;
+ }
+
+ kfree_skb(tmp);
+ }
+
+ skb_push(skb, BTM_HEADER_LEN);
+
+ /* header type: byte[3]
+ * HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor
+ * header length: byte[2][1][0]
+ */
+
+ skb->data[0] = (skb->len & 0x0000ff);
+ skb->data[1] = (skb->len & 0x00ff00) >> 8;
+ skb->data[2] = (skb->len & 0xff0000) >> 16;
+ skb->data[3] = bt_cb(skb)->pkt_type;
+
+ if (priv->hw_host_to_card)
+ ret = priv->hw_host_to_card(priv, skb->data, skb->len);
+
+ return ret;
+}
+
+static void btmrvl_init_adapter(struct btmrvl_private *priv)
+{
+ skb_queue_head_init(&priv->adapter->tx_queue);
+
+ priv->adapter->ps_state = PS_AWAKE;
+
+ init_waitqueue_head(&priv->adapter->cmd_wait_q);
+}
+
+static void btmrvl_free_adapter(struct btmrvl_private *priv)
+{
+ skb_queue_purge(&priv->adapter->tx_queue);
+
+ kfree(priv->adapter);
+
+ priv->adapter = NULL;
+}
+
+static int btmrvl_ioctl(struct hci_dev *hdev,
+ unsigned int cmd, unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+static void btmrvl_destruct(struct hci_dev *hdev)
+{
+}
+
+static int btmrvl_send_frame(struct sk_buff *skb)
+{
+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+ struct btmrvl_private *priv = NULL;
+
+ BT_DBG("type=%d, len=%d", skb->pkt_type, skb->len);
+
+ if (!hdev || !hdev->driver_data) {
+ BT_ERR("Frame for unknown HCI device");
+ return -ENODEV;
+ }
+
+ priv = (struct btmrvl_private *) hdev->driver_data;
+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+ BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags);
+ print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET,
+ skb->data, skb->len);
+ return -EBUSY;
+ }
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+ hdev->stat.cmd_tx++;
+ break;
+
+ case HCI_ACLDATA_PKT:
+ hdev->stat.acl_tx++;
+ break;
+
+ case HCI_SCODATA_PKT:
+ hdev->stat.sco_tx++;
+ break;
+ }
+
+ skb_queue_tail(&priv->adapter->tx_queue, skb);
+
+ wake_up_interruptible(&priv->main_thread.wait_q);
+
+ return 0;
+}
+
+static int btmrvl_flush(struct hci_dev *hdev)
+{
+ struct btmrvl_private *priv = hdev->driver_data;
+
+ skb_queue_purge(&priv->adapter->tx_queue);
+
+ return 0;
+}
+
+static int btmrvl_close(struct hci_dev *hdev)
+{
+ struct btmrvl_private *priv = hdev->driver_data;
+
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ skb_queue_purge(&priv->adapter->tx_queue);
+
+ return 0;
+}
+
+static int btmrvl_open(struct hci_dev *hdev)
+{
+ set_bit(HCI_RUNNING, &hdev->flags);
+
+ return 0;
+}
+
+/*
+ * This function handles the event generated by firmware, rx data
+ * received from firmware, and tx data sent from kernel.
+ */
+static int btmrvl_service_main_thread(void *data)
+{
+ struct btmrvl_thread *thread = data;
+ struct btmrvl_private *priv = thread->priv;
+ struct btmrvl_adapter *adapter = priv->adapter;
+ wait_queue_t wait;
+ struct sk_buff *skb;
+ ulong flags;
+
+ init_waitqueue_entry(&wait, current);
+
+ current->flags |= PF_NOFREEZE;
+
+ for (;;) {
+ add_wait_queue(&thread->wait_q, &wait);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (adapter->wakeup_tries ||
+ ((!adapter->int_count) &&
+ (!priv->btmrvl_dev.tx_dnld_rdy ||
+ skb_queue_empty(&adapter->tx_queue)))) {
+ BT_DBG("main_thread is sleeping...");
+ schedule();
+ }
+
+ set_current_state(TASK_RUNNING);
+
+ remove_wait_queue(&thread->wait_q, &wait);
+
+ BT_DBG("main_thread woke up");
+
+ if (kthread_should_stop()) {
+ BT_DBG("main_thread: break from main thread");
+ break;
+ }
+
+ spin_lock_irqsave(&priv->driver_lock, flags);
+ if (adapter->int_count) {
+ adapter->int_count = 0;
+ } else if (adapter->ps_state == PS_SLEEP &&
+ !skb_queue_empty(&adapter->tx_queue)) {
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ adapter->wakeup_tries++;
+ priv->hw_wakeup_firmware(priv);
+ continue;
+ }
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ if (adapter->ps_state == PS_SLEEP)
+ continue;
+
+ if (!priv->btmrvl_dev.tx_dnld_rdy)
+ continue;
+
+ skb = skb_dequeue(&adapter->tx_queue);
+ if (skb) {
+ if (btmrvl_tx_pkt(priv, skb))
+ priv->btmrvl_dev.hcidev->stat.err_tx++;
+ else
+ priv->btmrvl_dev.hcidev->stat.byte_tx += skb->len;
+
+ kfree_skb(skb);
+ }
+ }
+
+ return 0;
+}
+
+struct btmrvl_private *btmrvl_add_card(void *card)
+{
+ struct hci_dev *hdev = NULL;
+ struct btmrvl_private *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ BT_ERR("Can not allocate priv");
+ goto err_priv;
+ }
+
+ priv->adapter = kzalloc(sizeof(*priv->adapter), GFP_KERNEL);
+ if (!priv->adapter) {
+ BT_ERR("Allocate buffer for btmrvl_adapter failed!");
+ goto err_adapter;
+ }
+
+ btmrvl_init_adapter(priv);
+
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ BT_ERR("Can not allocate HCI device");
+ goto err_hdev;
+ }
+
+ BT_DBG("Starting kthread...");
+ priv->main_thread.priv = priv;
+ spin_lock_init(&priv->driver_lock);
+
+ init_waitqueue_head(&priv->main_thread.wait_q);
+ priv->main_thread.task = kthread_run(btmrvl_service_main_thread,
+ &priv->main_thread, "btmrvl_main_service");
+
+ priv->btmrvl_dev.hcidev = hdev;
+ priv->btmrvl_dev.card = card;
+
+ hdev->driver_data = priv;
+
+ priv->btmrvl_dev.tx_dnld_rdy = true;
+
+ hdev->type = HCI_SDIO;
+ hdev->open = btmrvl_open;
+ hdev->close = btmrvl_close;
+ hdev->flush = btmrvl_flush;
+ hdev->send = btmrvl_send_frame;
+ hdev->destruct = btmrvl_destruct;
+ hdev->ioctl = btmrvl_ioctl;
+ hdev->owner = THIS_MODULE;
+
+ ret = hci_register_dev(hdev);
+ if (ret < 0) {
+ BT_ERR("Can not register HCI device");
+ goto err_hci_register_dev;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ btmrvl_debugfs_init(hdev);
+#endif
+
+ return priv;
+
+err_hci_register_dev:
+ /* Stop the thread servicing the interrupts */
+ kthread_stop(priv->main_thread.task);
+
+ hci_free_dev(hdev);
+
+err_hdev:
+ btmrvl_free_adapter(priv);
+
+err_adapter:
+ kfree(priv);
+
+err_priv:
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(btmrvl_add_card);
+
+int btmrvl_remove_card(struct btmrvl_private *priv)
+{
+ struct hci_dev *hdev;
+
+ hdev = priv->btmrvl_dev.hcidev;
+
+ wake_up_interruptible(&priv->adapter->cmd_wait_q);
+
+ kthread_stop(priv->main_thread.task);
+
+#ifdef CONFIG_DEBUG_FS
+ btmrvl_debugfs_remove(hdev);
+#endif
+
+ hci_unregister_dev(hdev);
+
+ hci_free_dev(hdev);
+
+ priv->btmrvl_dev.hcidev = NULL;
+
+ btmrvl_free_adapter(priv);
+
+ kfree(priv);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(btmrvl_remove_card);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell Bluetooth driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
new file mode 100644
index 000000000000..5b33b85790f2
--- /dev/null
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -0,0 +1,1003 @@
+/**
+ * Marvell BT-over-SDIO driver: SDIO interface related functions.
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ **/
+
+#include <linux/firmware.h>
+
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "btmrvl_drv.h"
+#include "btmrvl_sdio.h"
+
+#define VERSION "1.0"
+
+/* The btmrvl_sdio_remove() callback function is called
+ * when user removes this module from kernel space or ejects
+ * the card from the slot. The driver handles these 2 cases
+ * differently.
+ * If the user is removing the module, a MODULE_SHUTDOWN_REQ
+ * command is sent to firmware and interrupt will be disabled.
+ * If the card is removed, there is no need to send command
+ * or disable interrupt.
+ *
+ * The variable 'user_rmmod' is used to distinguish these two
+ * scenarios. This flag is initialized as FALSE in case the card
+ * is removed, and will be set to TRUE for module removal when
+ * module_exit function is called.
+ */
+static u8 user_rmmod;
+
+static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {
+ .helper = "sd8688_helper.bin",
+ .firmware = "sd8688.bin",
+};
+
+static const struct sdio_device_id btmrvl_sdio_ids[] = {
+ /* Marvell SD8688 Bluetooth device */
+ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
+ .driver_data = (unsigned long) &btmrvl_sdio_sd6888 },
+
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(sdio, btmrvl_sdio_ids);
+
+static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card)
+{
+ u8 reg;
+ int ret;
+
+ reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret);
+ if (!ret)
+ card->rx_unit = reg;
+
+ return ret;
+}
+
+static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat)
+{
+ u8 fws0, fws1;
+ int ret;
+
+ *dat = 0;
+
+ fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret);
+
+ if (!ret)
+ fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret);
+
+ if (ret)
+ return -EIO;
+
+ *dat = (((u16) fws1) << 8) | fws0;
+
+ return 0;
+}
+
+static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat)
+{
+ u8 reg;
+ int ret;
+
+ reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret);
+ if (!ret)
+ *dat = (u16) reg << card->rx_unit;
+
+ return ret;
+}
+
+static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card,
+ u8 mask)
+{
+ int ret;
+
+ sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret);
+ if (ret) {
+ BT_ERR("Unable to enable the host interrupt!");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card,
+ u8 mask)
+{
+ u8 host_int_mask;
+ int ret;
+
+ host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret);
+ if (ret)
+ return -EIO;
+
+ host_int_mask &= ~mask;
+
+ sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret);
+ if (ret < 0) {
+ BT_ERR("Unable to disable the host interrupt!");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits)
+{
+ unsigned int tries;
+ u8 status;
+ int ret;
+
+ for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) {
+ status = sdio_readb(card->func, CARD_STATUS_REG, &ret);
+ if (ret)
+ goto failed;
+ if ((status & bits) == bits)
+ return ret;
+
+ udelay(1);
+ }
+
+ ret = -ETIMEDOUT;
+
+failed:
+ BT_ERR("FAILED! ret=%d", ret);
+
+ return ret;
+}
+
+static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card,
+ int pollnum)
+{
+ int ret = -ETIMEDOUT;
+ u16 firmwarestat;
+ unsigned int tries;
+
+ /* Wait for firmware to become ready */
+ for (tries = 0; tries < pollnum; tries++) {
+ if (btmrvl_sdio_read_fw_status(card, &firmwarestat) < 0)
+ continue;
+
+ if (firmwarestat == FIRMWARE_READY) {
+ ret = 0;
+ break;
+ } else {
+ msleep(10);
+ }
+ }
+
+ return ret;
+}
+
+static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card)
+{
+ const struct firmware *fw_helper = NULL;
+ const u8 *helper = NULL;
+ int ret;
+ void *tmphlprbuf = NULL;
+ int tmphlprbufsz, hlprblknow, helperlen;
+ u8 *helperbuf;
+ u32 tx_len;
+
+ ret = request_firmware(&fw_helper, card->helper,
+ &card->func->dev);
+ if ((ret < 0) || !fw_helper) {
+ BT_ERR("request_firmware(helper) failed, error code = %d",
+ ret);
+ ret = -ENOENT;
+ goto done;
+ }
+
+ helper = fw_helper->data;
+ helperlen = fw_helper->size;
+
+ BT_DBG("Downloading helper image (%d bytes), block size %d bytes",
+ helperlen, SDIO_BLOCK_SIZE);
+
+ tmphlprbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);
+
+ tmphlprbuf = kmalloc(tmphlprbufsz, GFP_KERNEL);
+ if (!tmphlprbuf) {
+ BT_ERR("Unable to allocate buffer for helper."
+ " Terminating download");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ memset(tmphlprbuf, 0, tmphlprbufsz);
+
+ helperbuf = (u8 *) ALIGN_ADDR(tmphlprbuf, BTSDIO_DMA_ALIGN);
+
+ /* Perform helper data transfer */
+ tx_len = (FIRMWARE_TRANSFER_NBLOCK * SDIO_BLOCK_SIZE)
+ - SDIO_HEADER_LEN;
+ hlprblknow = 0;
+
+ do {
+ ret = btmrvl_sdio_poll_card_status(card,
+ CARD_IO_READY | DN_LD_CARD_RDY);
+ if (ret < 0) {
+ BT_ERR("Helper download poll status timeout @ %d",
+ hlprblknow);
+ goto done;
+ }
+
+ /* Check if there is more data? */
+ if (hlprblknow >= helperlen)
+ break;
+
+ if (helperlen - hlprblknow < tx_len)
+ tx_len = helperlen - hlprblknow;
+
+ /* Little-endian */
+ helperbuf[0] = ((tx_len & 0x000000ff) >> 0);
+ helperbuf[1] = ((tx_len & 0x0000ff00) >> 8);
+ helperbuf[2] = ((tx_len & 0x00ff0000) >> 16);
+ helperbuf[3] = ((tx_len & 0xff000000) >> 24);
+
+ memcpy(&helperbuf[SDIO_HEADER_LEN], &helper[hlprblknow],
+ tx_len);
+
+ /* Now send the data */
+ ret = sdio_writesb(card->func, card->ioport, helperbuf,
+ FIRMWARE_TRANSFER_NBLOCK * SDIO_BLOCK_SIZE);
+ if (ret < 0) {
+ BT_ERR("IO error during helper download @ %d",
+ hlprblknow);
+ goto done;
+ }
+
+ hlprblknow += tx_len;
+ } while (true);
+
+ BT_DBG("Transferring helper image EOF block");
+
+ memset(helperbuf, 0x0, SDIO_BLOCK_SIZE);
+
+ ret = sdio_writesb(card->func, card->ioport, helperbuf,
+ SDIO_BLOCK_SIZE);
+ if (ret < 0) {
+ BT_ERR("IO error in writing helper image EOF block");
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ kfree(tmphlprbuf);
+ if (fw_helper)
+ release_firmware(fw_helper);
+
+ return ret;
+}
+
+static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
+{
+ const struct firmware *fw_firmware = NULL;
+ const u8 *firmware = NULL;
+ int firmwarelen, tmpfwbufsz, ret;
+ unsigned int tries, offset;
+ u8 base0, base1;
+ void *tmpfwbuf = NULL;
+ u8 *fwbuf;
+ u16 len;
+ int txlen = 0, tx_blocks = 0, count = 0;
+
+ ret = request_firmware(&fw_firmware, card->firmware,
+ &card->func->dev);
+ if ((ret < 0) || !fw_firmware) {
+ BT_ERR("request_firmware(firmware) failed, error code = %d",
+ ret);
+ ret = -ENOENT;
+ goto done;
+ }
+
+ firmware = fw_firmware->data;
+ firmwarelen = fw_firmware->size;
+
+ BT_DBG("Downloading FW image (%d bytes)", firmwarelen);
+
+ tmpfwbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);
+ tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL);
+ if (!tmpfwbuf) {
+ BT_ERR("Unable to allocate buffer for firmware."
+ " Terminating download");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ memset(tmpfwbuf, 0, tmpfwbufsz);
+
+ /* Ensure aligned firmware buffer */
+ fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, BTSDIO_DMA_ALIGN);
+
+ /* Perform firmware data transfer */
+ offset = 0;
+ do {
+ ret = btmrvl_sdio_poll_card_status(card,
+ CARD_IO_READY | DN_LD_CARD_RDY);
+ if (ret < 0) {
+ BT_ERR("FW download with helper poll status"
+ " timeout @ %d", offset);
+ goto done;
+ }
+
+ /* Check if there is more data ? */
+ if (offset >= firmwarelen)
+ break;
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ base0 = sdio_readb(card->func,
+ SQ_READ_BASE_ADDRESS_A0_REG, &ret);
+ if (ret) {
+ BT_ERR("BASE0 register read failed:"
+ " base0 = 0x%04X(%d)."
+ " Terminating download",
+ base0, base0);
+ ret = -EIO;
+ goto done;
+ }
+ base1 = sdio_readb(card->func,
+ SQ_READ_BASE_ADDRESS_A1_REG, &ret);
+ if (ret) {
+ BT_ERR("BASE1 register read failed:"
+ " base1 = 0x%04X(%d)."
+ " Terminating download",
+ base1, base1);
+ ret = -EIO;
+ goto done;
+ }
+
+ len = (((u16) base1) << 8) | base0;
+ if (len)
+ break;
+
+ udelay(10);
+ }
+
+ if (!len)
+ break;
+ else if (len > BTM_UPLD_SIZE) {
+ BT_ERR("FW download failure @%d, invalid length %d",
+ offset, len);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ txlen = len;
+
+ if (len & BIT(0)) {
+ count++;
+ if (count > MAX_WRITE_IOMEM_RETRY) {
+ BT_ERR("FW download failure @%d, "
+ "over max retry count", offset);
+ ret = -EIO;
+ goto done;
+ }
+ BT_ERR("FW CRC error indicated by the helper: "
+ "len = 0x%04X, txlen = %d", len, txlen);
+ len &= ~BIT(0);
+ /* Set txlen to 0 so as to resend from same offset */
+ txlen = 0;
+ } else {
+ count = 0;
+
+ /* Last block ? */
+ if (firmwarelen - offset < txlen)
+ txlen = firmwarelen - offset;
+
+ tx_blocks =
+ (txlen + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE;
+
+ memcpy(fwbuf, &firmware[offset], txlen);
+ }
+
+ ret = sdio_writesb(card->func, card->ioport, fwbuf,
+ tx_blocks * SDIO_BLOCK_SIZE);
+
+ if (ret < 0) {
+ BT_ERR("FW download, writesb(%d) failed @%d",
+ count, offset);
+ sdio_writeb(card->func, HOST_CMD53_FIN, CONFIG_REG,
+ &ret);
+ if (ret)
+ BT_ERR("writeb failed (CFG)");
+ }
+
+ offset += txlen;
+ } while (true);
+
+ BT_DBG("FW download over, size %d bytes", offset);
+
+ ret = 0;
+
+done:
+ kfree(tmpfwbuf);
+
+ if (fw_firmware)
+ release_firmware(fw_firmware);
+
+ return ret;
+}
+
+static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
+{
+ u16 buf_len = 0;
+ int ret, buf_block_len, blksz;
+ struct sk_buff *skb = NULL;
+ u32 type;
+ u8 *payload = NULL;
+ struct hci_dev *hdev = priv->btmrvl_dev.hcidev;
+ struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
+
+ if (!card || !card->func) {
+ BT_ERR("card or function is NULL!");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* Read the length of data to be transferred */
+ ret = btmrvl_sdio_read_rx_len(card, &buf_len);
+ if (ret < 0) {
+ BT_ERR("read rx_len failed");
+ ret = -EIO;
+ goto exit;
+ }
+
+ blksz = SDIO_BLOCK_SIZE;
+ buf_block_len = (buf_len + blksz - 1) / blksz;
+
+ if (buf_len <= SDIO_HEADER_LEN
+ || (buf_block_len * blksz) > ALLOC_BUF_SIZE) {
+ BT_ERR("invalid packet length: %d", buf_len);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* Allocate buffer */
+ skb = bt_skb_alloc(buf_block_len * blksz + BTSDIO_DMA_ALIGN,
+ GFP_ATOMIC);
+ if (skb == NULL) {
+ BT_ERR("No free skb");
+ goto exit;
+ }
+
+ if ((unsigned long) skb->data & (BTSDIO_DMA_ALIGN - 1)) {
+ skb_put(skb, (unsigned long) skb->data &
+ (BTSDIO_DMA_ALIGN - 1));
+ skb_pull(skb, (unsigned long) skb->data &
+ (BTSDIO_DMA_ALIGN - 1));
+ }
+
+ payload = skb->data;
+
+ ret = sdio_readsb(card->func, payload, card->ioport,
+ buf_block_len * blksz);
+ if (ret < 0) {
+ BT_ERR("readsb failed: %d", ret);
+ ret = -EIO;
+ goto exit;
+ }
+
+ /* This is SDIO specific header length: byte[2][1][0], type: byte[3]
+ * (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor)
+ */
+
+ buf_len = payload[0];
+ buf_len |= (u16) payload[1] << 8;
+ type = payload[3];
+
+ switch (type) {
+ case HCI_ACLDATA_PKT:
+ case HCI_SCODATA_PKT:
+ case HCI_EVENT_PKT:
+ bt_cb(skb)->pkt_type = type;
+ skb->dev = (void *)hdev;
+ skb_put(skb, buf_len);
+ skb_pull(skb, SDIO_HEADER_LEN);
+
+ if (type == HCI_EVENT_PKT)
+ btmrvl_check_evtpkt(priv, skb);
+
+ hci_recv_frame(skb);
+ hdev->stat.byte_rx += buf_len;
+ break;
+
+ case MRVL_VENDOR_PKT:
+ bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
+ skb->dev = (void *)hdev;
+ skb_put(skb, buf_len);
+ skb_pull(skb, SDIO_HEADER_LEN);
+
+ if (btmrvl_process_event(priv, skb))
+ hci_recv_frame(skb);
+
+ hdev->stat.byte_rx += buf_len;
+ break;
+
+ default:
+ BT_ERR("Unknow packet type:%d", type);
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, payload,
+ blksz * buf_block_len);
+
+ kfree_skb(skb);
+ skb = NULL;
+ break;
+ }
+
+exit:
+ if (ret) {
+ hdev->stat.err_rx++;
+ if (skb)
+ kfree_skb(skb);
+ }
+
+ return ret;
+}
+
+static int btmrvl_sdio_get_int_status(struct btmrvl_private *priv, u8 * ireg)
+{
+ int ret;
+ u8 sdio_ireg = 0;
+ struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
+
+ *ireg = 0;
+
+ sdio_ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
+ if (ret) {
+ BT_ERR("sdio_readb: read int status register failed");
+ ret = -EIO;
+ goto done;
+ }
+
+ if (sdio_ireg != 0) {
+ /*
+ * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+ * Clear the interrupt status register and re-enable the
+ * interrupt.
+ */
+ BT_DBG("sdio_ireg = 0x%x", sdio_ireg);
+
+ sdio_writeb(card->func, ~(sdio_ireg) & (DN_LD_HOST_INT_STATUS |
+ UP_LD_HOST_INT_STATUS),
+ HOST_INTSTATUS_REG, &ret);
+ if (ret) {
+ BT_ERR("sdio_writeb: clear int status register "
+ "failed");
+ ret = -EIO;
+ goto done;
+ }
+ }
+
+ if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
+ if (priv->btmrvl_dev.tx_dnld_rdy)
+ BT_DBG("tx_done already received: "
+ " int_status=0x%x", sdio_ireg);
+ else
+ priv->btmrvl_dev.tx_dnld_rdy = true;
+ }
+
+ if (sdio_ireg & UP_LD_HOST_INT_STATUS)
+ btmrvl_sdio_card_to_host(priv);
+
+ *ireg = sdio_ireg;
+
+ ret = 0;
+
+done:
+ return ret;
+}
+
+static void btmrvl_sdio_interrupt(struct sdio_func *func)
+{
+ struct btmrvl_private *priv;
+ struct hci_dev *hcidev;
+ struct btmrvl_sdio_card *card;
+ u8 ireg = 0;
+
+ card = sdio_get_drvdata(func);
+ if (card && card->priv) {
+ priv = card->priv;
+ hcidev = priv->btmrvl_dev.hcidev;
+
+ if (btmrvl_sdio_get_int_status(priv, &ireg))
+ BT_ERR("reading HOST_INT_STATUS_REG failed");
+ else
+ BT_DBG("HOST_INT_STATUS_REG %#x", ireg);
+
+ btmrvl_interrupt(priv);
+ }
+}
+
+static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
+{
+ struct sdio_func *func;
+ u8 reg;
+ int ret = 0;
+
+ if (!card || !card->func) {
+ BT_ERR("Error: card or function is NULL!");
+ ret = -EINVAL;
+ goto failed;
+ }
+
+ func = card->func;
+
+ sdio_claim_host(func);
+
+ ret = sdio_enable_func(func);
+ if (ret) {
+ BT_ERR("sdio_enable_func() failed: ret=%d", ret);
+ ret = -EIO;
+ goto release_host;
+ }
+
+ ret = sdio_claim_irq(func, btmrvl_sdio_interrupt);
+ if (ret) {
+ BT_ERR("sdio_claim_irq failed: ret=%d", ret);
+ ret = -EIO;
+ goto disable_func;
+ }
+
+ ret = sdio_set_block_size(card->func, SDIO_BLOCK_SIZE);
+ if (ret) {
+ BT_ERR("cannot set SDIO block size");
+ ret = -EIO;
+ goto release_irq;
+ }
+
+ reg = sdio_readb(func, IO_PORT_0_REG, &ret);
+ if (ret < 0) {
+ ret = -EIO;
+ goto release_irq;
+ }
+
+ card->ioport = reg;
+
+ reg = sdio_readb(func, IO_PORT_1_REG, &ret);
+ if (ret < 0) {
+ ret = -EIO;
+ goto release_irq;
+ }
+
+ card->ioport |= (reg << 8);
+
+ reg = sdio_readb(func, IO_PORT_2_REG, &ret);
+ if (ret < 0) {
+ ret = -EIO;
+ goto release_irq;
+ }
+
+ card->ioport |= (reg << 16);
+
+ BT_DBG("SDIO FUNC%d IO port: 0x%x", func->num, card->ioport);
+
+ sdio_set_drvdata(func, card);
+
+ sdio_release_host(func);
+
+ return 0;
+
+release_irq:
+ sdio_release_irq(func);
+
+disable_func:
+ sdio_disable_func(func);
+
+release_host:
+ sdio_release_host(func);
+
+failed:
+ return ret;
+}
+
+static int btmrvl_sdio_unregister_dev(struct btmrvl_sdio_card *card)
+{
+ if (card && card->func) {
+ sdio_claim_host(card->func);
+ sdio_release_irq(card->func);
+ sdio_disable_func(card->func);
+ sdio_release_host(card->func);
+ sdio_set_drvdata(card->func, NULL);
+ }
+
+ return 0;
+}
+
+static int btmrvl_sdio_enable_host_int(struct btmrvl_sdio_card *card)
+{
+ int ret;
+
+ if (!card || !card->func)
+ return -EINVAL;
+
+ sdio_claim_host(card->func);
+
+ ret = btmrvl_sdio_enable_host_int_mask(card, HIM_ENABLE);
+
+ btmrvl_sdio_get_rx_unit(card);
+
+ sdio_release_host(card->func);
+
+ return ret;
+}
+
+static int btmrvl_sdio_disable_host_int(struct btmrvl_sdio_card *card)
+{
+ int ret;
+
+ if (!card || !card->func)
+ return -EINVAL;
+
+ sdio_claim_host(card->func);
+
+ ret = btmrvl_sdio_disable_host_int_mask(card, HIM_DISABLE);
+
+ sdio_release_host(card->func);
+
+ return ret;
+}
+
+static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv,
+ u8 *payload, u16 nb)
+{
+ struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
+ int ret = 0;
+ int buf_block_len;
+ int blksz;
+ int i = 0;
+ u8 *buf = NULL;
+ void *tmpbuf = NULL;
+ int tmpbufsz;
+
+ if (!card || !card->func) {
+ BT_ERR("card or function is NULL!");
+ return -EINVAL;
+ }
+
+ buf = payload;
+ if ((unsigned long) payload & (BTSDIO_DMA_ALIGN - 1)) {
+ tmpbufsz = ALIGN_SZ(nb, BTSDIO_DMA_ALIGN);
+ tmpbuf = kzalloc(tmpbufsz, GFP_KERNEL);
+ if (!tmpbuf)
+ return -ENOMEM;
+ buf = (u8 *) ALIGN_ADDR(tmpbuf, BTSDIO_DMA_ALIGN);
+ memcpy(buf, payload, nb);
+ }
+
+ blksz = SDIO_BLOCK_SIZE;
+ buf_block_len = (nb + blksz - 1) / blksz;
+
+ sdio_claim_host(card->func);
+
+ do {
+ /* Transfer data to card */
+ ret = sdio_writesb(card->func, card->ioport, buf,
+ buf_block_len * blksz);
+ if (ret < 0) {
+ i++;
+ BT_ERR("i=%d writesb failed: %d", i, ret);
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ payload, nb);
+ ret = -EIO;
+ if (i > MAX_WRITE_IOMEM_RETRY)
+ goto exit;
+ }
+ } while (ret);
+
+ priv->btmrvl_dev.tx_dnld_rdy = false;
+
+exit:
+ sdio_release_host(card->func);
+
+ return ret;
+}
+
+static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
+{
+ int ret = 0;
+
+ if (!card || !card->func) {
+ BT_ERR("card or function is NULL!");
+ return -EINVAL;
+ }
+ sdio_claim_host(card->func);
+
+ if (!btmrvl_sdio_verify_fw_download(card, 1)) {
+ BT_DBG("Firmware already downloaded!");
+ goto done;
+ }
+
+ ret = btmrvl_sdio_download_helper(card);
+ if (ret) {
+ BT_ERR("Failed to download helper!");
+ ret = -EIO;
+ goto done;
+ }
+
+ if (btmrvl_sdio_download_fw_w_helper(card)) {
+ BT_ERR("Failed to download firmware!");
+ ret = -EIO;
+ goto done;
+ }
+
+ if (btmrvl_sdio_verify_fw_download(card, MAX_POLL_TRIES)) {
+ BT_ERR("FW failed to be active in time!");
+ ret = -ETIMEDOUT;
+ goto done;
+ }
+
+done:
+ sdio_release_host(card->func);
+
+ return ret;
+}
+
+static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv)
+{
+ struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
+ int ret = 0;
+
+ if (!card || !card->func) {
+ BT_ERR("card or function is NULL!");
+ return -EINVAL;
+ }
+
+ sdio_claim_host(card->func);
+
+ sdio_writeb(card->func, HOST_POWER_UP, CONFIG_REG, &ret);
+
+ sdio_release_host(card->func);
+
+ BT_DBG("wake up firmware");
+
+ return ret;
+}
+
+static int btmrvl_sdio_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ int ret = 0;
+ struct btmrvl_private *priv = NULL;
+ struct btmrvl_sdio_card *card = NULL;
+
+ BT_INFO("vendor=0x%x, device=0x%x, class=%d, fn=%d",
+ id->vendor, id->device, id->class, func->num);
+
+ card = kzalloc(sizeof(*card), GFP_KERNEL);
+ if (!card) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ card->func = func;
+
+ if (id->driver_data) {
+ struct btmrvl_sdio_device *data = (void *) id->driver_data;
+ card->helper = data->helper;
+ card->firmware = data->firmware;
+ }
+
+ if (btmrvl_sdio_register_dev(card) < 0) {
+ BT_ERR("Failed to register BT device!");
+ ret = -ENODEV;
+ goto free_card;
+ }
+
+ /* Disable the interrupts on the card */
+ btmrvl_sdio_disable_host_int(card);
+
+ if (btmrvl_sdio_download_fw(card)) {
+ BT_ERR("Downloading firmware failed!");
+ ret = -ENODEV;
+ goto unreg_dev;
+ }
+
+ msleep(100);
+
+ btmrvl_sdio_enable_host_int(card);
+
+ priv = btmrvl_add_card(card);
+ if (!priv) {
+ BT_ERR("Initializing card failed!");
+ ret = -ENODEV;
+ goto disable_host_int;
+ }
+
+ card->priv = priv;
+
+ /* Initialize the interface specific function pointers */
+ priv->hw_host_to_card = btmrvl_sdio_host_to_card;
+ priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;
+
+ btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
+
+ return 0;
+
+disable_host_int:
+ btmrvl_sdio_disable_host_int(card);
+unreg_dev:
+ btmrvl_sdio_unregister_dev(card);
+free_card:
+ kfree(card);
+done:
+ return ret;
+}
+
+static void btmrvl_sdio_remove(struct sdio_func *func)
+{
+ struct btmrvl_sdio_card *card;
+
+ if (func) {
+ card = sdio_get_drvdata(func);
+ if (card) {
+ /* Send SHUTDOWN command & disable interrupt
+ * if user removes the module.
+ */
+ if (user_rmmod) {
+ btmrvl_send_module_cfg_cmd(card->priv,
+ MODULE_SHUTDOWN_REQ);
+ btmrvl_sdio_disable_host_int(card);
+ }
+ BT_DBG("unregester dev");
+ btmrvl_sdio_unregister_dev(card);
+ btmrvl_remove_card(card->priv);
+ kfree(card);
+ }
+ }
+}
+
+static struct sdio_driver bt_mrvl_sdio = {
+ .name = "btmrvl_sdio",
+ .id_table = btmrvl_sdio_ids,
+ .probe = btmrvl_sdio_probe,
+ .remove = btmrvl_sdio_remove,
+};
+
+static int btmrvl_sdio_init_module(void)
+{
+ if (sdio_register_driver(&bt_mrvl_sdio) != 0) {
+ BT_ERR("SDIO Driver Registration Failed");
+ return -ENODEV;
+ }
+
+ /* Clear the flag in case user removes the card. */
+ user_rmmod = 0;
+
+ return 0;
+}
+
+static void btmrvl_sdio_exit_module(void)
+{
+ /* Set the flag as user is removing this module. */
+ user_rmmod = 1;
+
+ sdio_unregister_driver(&bt_mrvl_sdio);
+}
+
+module_init(btmrvl_sdio_init_module);
+module_exit(btmrvl_sdio_exit_module);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h
new file mode 100644
index 000000000000..27329f107e5a
--- /dev/null
+++ b/drivers/bluetooth/btmrvl_sdio.h
@@ -0,0 +1,108 @@
+/**
+ * Marvell BT-over-SDIO driver: SDIO interface related definitions
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ **/
+
+#define SDIO_HEADER_LEN 4
+
+/* SD block size can not bigger than 64 due to buf size limit in firmware */
+/* define SD block size for data Tx/Rx */
+#define SDIO_BLOCK_SIZE 64
+
+/* Number of blocks for firmware transfer */
+#define FIRMWARE_TRANSFER_NBLOCK 2
+
+/* This is for firmware specific length */
+#define FW_EXTRA_LEN 36
+
+#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
+
+#define MRVDRV_BT_RX_PACKET_BUFFER_SIZE \
+ (HCI_MAX_FRAME_SIZE + FW_EXTRA_LEN)
+
+#define ALLOC_BUF_SIZE (((max_t (int, MRVDRV_BT_RX_PACKET_BUFFER_SIZE, \
+ MRVDRV_SIZE_OF_CMD_BUFFER) + SDIO_HEADER_LEN \
+ + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE) \
+ * SDIO_BLOCK_SIZE)
+
+/* The number of times to try when polling for status */
+#define MAX_POLL_TRIES 100
+
+/* Max retry number of CMD53 write */
+#define MAX_WRITE_IOMEM_RETRY 2
+
+/* Host Control Registers */
+#define IO_PORT_0_REG 0x00
+#define IO_PORT_1_REG 0x01
+#define IO_PORT_2_REG 0x02
+
+#define CONFIG_REG 0x03
+#define HOST_POWER_UP BIT(1)
+#define HOST_CMD53_FIN BIT(2)
+
+#define HOST_INT_MASK_REG 0x04
+#define HIM_DISABLE 0xff
+#define HIM_ENABLE (BIT(0) | BIT(1))
+
+#define HOST_INTSTATUS_REG 0x05
+#define UP_LD_HOST_INT_STATUS BIT(0)
+#define DN_LD_HOST_INT_STATUS BIT(1)
+
+/* Card Control Registers */
+#define SQ_READ_BASE_ADDRESS_A0_REG 0x10
+#define SQ_READ_BASE_ADDRESS_A1_REG 0x11
+
+#define CARD_STATUS_REG 0x20
+#define DN_LD_CARD_RDY BIT(0)
+#define CARD_IO_READY BIT(3)
+
+#define CARD_FW_STATUS0_REG 0x40
+#define CARD_FW_STATUS1_REG 0x41
+#define FIRMWARE_READY 0xfedc
+
+#define CARD_RX_LEN_REG 0x42
+#define CARD_RX_UNIT_REG 0x43
+
+
+struct btmrvl_sdio_card {
+ struct sdio_func *func;
+ u32 ioport;
+ const char *helper;
+ const char *firmware;
+ u8 rx_unit;
+ struct btmrvl_private *priv;
+};
+
+struct btmrvl_sdio_device {
+ const char *helper;
+ const char *firmware;
+};
+
+
+/* Platform specific DMA alignment */
+#define BTSDIO_DMA_ALIGN 8
+
+/* Macros for Data Alignment : size */
+#define ALIGN_SZ(p, a) \
+ (((p) + ((a) - 1)) & ~((a) - 1))
+
+/* Macros for Data Alignment : address */
+#define ALIGN_ADDR(p, a) \
+ ((((unsigned long)(p)) + (((unsigned long)(a)) - 1)) & \
+ ~(((unsigned long)(a)) - 1))
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index efd689a062eb..d339464dc15e 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -588,11 +588,9 @@ static int btuart_probe(struct pcmcia_device *link)
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
link->io.NumPorts1 = 8;
- link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
- link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
link->irq.Handler = btuart_interrupt;
- link->irq.Instance = info;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -669,21 +667,16 @@ static int btuart_config(struct pcmcia_device *link)
goto found_port;
BT_ERR("No usable port range found");
- cs_error(link, RequestIO, -ENODEV);
goto failed;
found_port:
i = pcmcia_request_irq(link, &link->irq);
- if (i != 0) {
- cs_error(link, RequestIRQ, i);
+ if (i != 0)
link->irq.AssignedIRQ = 0;
- }
i = pcmcia_request_configuration(link, &link->conf);
- if (i != 0) {
- cs_error(link, RequestConfiguration, i);
+ if (i != 0)
goto failed;
- }
if (btuart_open(info) != 0)
goto failed;
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index e70c57ee4221..44bc8bbabf54 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -35,7 +35,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
-#define VERSION "0.5"
+#define VERSION "0.6"
static int ignore_dga;
static int ignore_csr;
@@ -145,6 +145,7 @@ static struct usb_device_id blacklist_table[] = {
#define BTUSB_INTR_RUNNING 0
#define BTUSB_BULK_RUNNING 1
#define BTUSB_ISOC_RUNNING 2
+#define BTUSB_SUSPENDING 3
struct btusb_data {
struct hci_dev *hdev;
@@ -157,11 +158,15 @@ struct btusb_data {
unsigned long flags;
struct work_struct work;
+ struct work_struct waker;
struct usb_anchor tx_anchor;
struct usb_anchor intr_anchor;
struct usb_anchor bulk_anchor;
struct usb_anchor isoc_anchor;
+ struct usb_anchor deferred;
+ int tx_in_flight;
+ spinlock_t txlock;
struct usb_endpoint_descriptor *intr_ep;
struct usb_endpoint_descriptor *bulk_tx_ep;
@@ -174,8 +179,23 @@ struct btusb_data {
unsigned int sco_num;
int isoc_altsetting;
int suspend_count;
+ int did_iso_resume:1;
};
+static int inc_tx(struct btusb_data *data)
+{
+ unsigned long flags;
+ int rv;
+
+ spin_lock_irqsave(&data->txlock, flags);
+ rv = test_bit(BTUSB_SUSPENDING, &data->flags);
+ if (!rv)
+ data->tx_in_flight++;
+ spin_unlock_irqrestore(&data->txlock, flags);
+
+ return rv;
+}
+
static void btusb_intr_complete(struct urb *urb)
{
struct hci_dev *hdev = urb->context;
@@ -202,6 +222,7 @@ static void btusb_intr_complete(struct urb *urb)
if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))
return;
+ usb_mark_last_busy(data->udev);
usb_anchor_urb(urb, &data->intr_anchor);
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -301,7 +322,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
struct urb *urb;
unsigned char *buf;
unsigned int pipe;
- int err, size;
+ int err, size = HCI_MAX_FRAME_SIZE;
BT_DBG("%s", hdev->name);
@@ -312,8 +333,6 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
if (!urb)
return -ENOMEM;
- size = le16_to_cpu(data->bulk_rx_ep->wMaxPacketSize);
-
buf = kmalloc(size, mem_flags);
if (!buf) {
usb_free_urb(urb);
@@ -327,6 +346,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
urb->transfer_flags |= URB_FREE_BUFFER;
+ usb_mark_last_busy(data->udev);
usb_anchor_urb(urb, &data->bulk_anchor);
err = usb_submit_urb(urb, mem_flags);
@@ -465,6 +485,33 @@ static void btusb_tx_complete(struct urb *urb)
{
struct sk_buff *skb = urb->context;
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+ struct btusb_data *data = hdev->driver_data;
+
+ BT_DBG("%s urb %p status %d count %d", hdev->name,
+ urb, urb->status, urb->actual_length);
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ goto done;
+
+ if (!urb->status)
+ hdev->stat.byte_tx += urb->transfer_buffer_length;
+ else
+ hdev->stat.err_tx++;
+
+done:
+ spin_lock(&data->txlock);
+ data->tx_in_flight--;
+ spin_unlock(&data->txlock);
+
+ kfree(urb->setup_packet);
+
+ kfree_skb(skb);
+}
+
+static void btusb_isoc_tx_complete(struct urb *urb)
+{
+ struct sk_buff *skb = urb->context;
+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
BT_DBG("%s urb %p status %d count %d", hdev->name,
urb, urb->status, urb->actual_length);
@@ -490,11 +537,17 @@ static int btusb_open(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
+ err = usb_autopm_get_interface(data->intf);
+ if (err < 0)
+ return err;
+
+ data->intf->needs_remote_wakeup = 1;
+
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
- return 0;
+ goto done;
if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
- return 0;
+ goto done;
err = btusb_submit_intr_urb(hdev, GFP_KERNEL);
if (err < 0)
@@ -509,17 +562,28 @@ static int btusb_open(struct hci_dev *hdev)
set_bit(BTUSB_BULK_RUNNING, &data->flags);
btusb_submit_bulk_urb(hdev, GFP_KERNEL);
+done:
+ usb_autopm_put_interface(data->intf);
return 0;
failed:
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
clear_bit(HCI_RUNNING, &hdev->flags);
+ usb_autopm_put_interface(data->intf);
return err;
}
+static void btusb_stop_traffic(struct btusb_data *data)
+{
+ usb_kill_anchored_urbs(&data->intr_anchor);
+ usb_kill_anchored_urbs(&data->bulk_anchor);
+ usb_kill_anchored_urbs(&data->isoc_anchor);
+}
+
static int btusb_close(struct hci_dev *hdev)
{
struct btusb_data *data = hdev->driver_data;
+ int err;
BT_DBG("%s", hdev->name);
@@ -527,16 +591,22 @@ static int btusb_close(struct hci_dev *hdev)
return 0;
cancel_work_sync(&data->work);
+ cancel_work_sync(&data->waker);
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
- usb_kill_anchored_urbs(&data->isoc_anchor);
-
clear_bit(BTUSB_BULK_RUNNING, &data->flags);
- usb_kill_anchored_urbs(&data->bulk_anchor);
-
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
- usb_kill_anchored_urbs(&data->intr_anchor);
+ btusb_stop_traffic(data);
+ err = usb_autopm_get_interface(data->intf);
+ if (err < 0)
+ goto failed;
+
+ data->intf->needs_remote_wakeup = 0;
+ usb_autopm_put_interface(data->intf);
+
+failed:
+ usb_scuttle_anchored_urbs(&data->deferred);
return 0;
}
@@ -622,7 +692,7 @@ static int btusb_send_frame(struct sk_buff *skb)
urb->dev = data->udev;
urb->pipe = pipe;
urb->context = skb;
- urb->complete = btusb_tx_complete;
+ urb->complete = btusb_isoc_tx_complete;
urb->interval = data->isoc_tx_ep->bInterval;
urb->transfer_flags = URB_ISO_ASAP;
@@ -633,12 +703,21 @@ static int btusb_send_frame(struct sk_buff *skb)
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
hdev->stat.sco_tx++;
- break;
+ goto skip_waking;
default:
return -EILSEQ;
}
+ err = inc_tx(data);
+ if (err) {
+ usb_anchor_urb(urb, &data->deferred);
+ schedule_work(&data->waker);
+ err = 0;
+ goto done;
+ }
+
+skip_waking:
usb_anchor_urb(urb, &data->tx_anchor);
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -646,10 +725,13 @@ static int btusb_send_frame(struct sk_buff *skb)
BT_ERR("%s urb %p submission failed", hdev->name, urb);
kfree(urb->setup_packet);
usb_unanchor_urb(urb);
+ } else {
+ usb_mark_last_busy(data->udev);
}
usb_free_urb(urb);
+done:
return err;
}
@@ -721,8 +803,19 @@ static void btusb_work(struct work_struct *work)
{
struct btusb_data *data = container_of(work, struct btusb_data, work);
struct hci_dev *hdev = data->hdev;
+ int err;
if (hdev->conn_hash.sco_num > 0) {
+ if (!data->did_iso_resume) {
+ err = usb_autopm_get_interface(data->isoc);
+ if (err < 0) {
+ clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
+ usb_kill_anchored_urbs(&data->isoc_anchor);
+ return;
+ }
+
+ data->did_iso_resume = 1;
+ }
if (data->isoc_altsetting != 2) {
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
usb_kill_anchored_urbs(&data->isoc_anchor);
@@ -742,9 +835,25 @@ static void btusb_work(struct work_struct *work)
usb_kill_anchored_urbs(&data->isoc_anchor);
__set_isoc_interface(hdev, 0);
+ if (data->did_iso_resume) {
+ data->did_iso_resume = 0;
+ usb_autopm_put_interface(data->isoc);
+ }
}
}
+static void btusb_waker(struct work_struct *work)
+{
+ struct btusb_data *data = container_of(work, struct btusb_data, waker);
+ int err;
+
+ err = usb_autopm_get_interface(data->intf);
+ if (err < 0)
+ return;
+
+ usb_autopm_put_interface(data->intf);
+}
+
static int btusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -814,11 +923,14 @@ static int btusb_probe(struct usb_interface *intf,
spin_lock_init(&data->lock);
INIT_WORK(&data->work, btusb_work);
+ INIT_WORK(&data->waker, btusb_waker);
+ spin_lock_init(&data->txlock);
init_usb_anchor(&data->tx_anchor);
init_usb_anchor(&data->intr_anchor);
init_usb_anchor(&data->bulk_anchor);
init_usb_anchor(&data->isoc_anchor);
+ init_usb_anchor(&data->deferred);
hdev = hci_alloc_dev();
if (!hdev) {
@@ -943,6 +1055,7 @@ static void btusb_disconnect(struct usb_interface *intf)
hci_free_dev(hdev);
}
+#ifdef CONFIG_PM
static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
{
struct btusb_data *data = usb_get_intfdata(intf);
@@ -952,22 +1065,44 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
if (data->suspend_count++)
return 0;
+ spin_lock_irq(&data->txlock);
+ if (!(interface_to_usbdev(intf)->auto_pm && data->tx_in_flight)) {
+ set_bit(BTUSB_SUSPENDING, &data->flags);
+ spin_unlock_irq(&data->txlock);
+ } else {
+ spin_unlock_irq(&data->txlock);
+ data->suspend_count--;
+ return -EBUSY;
+ }
+
cancel_work_sync(&data->work);
+ btusb_stop_traffic(data);
usb_kill_anchored_urbs(&data->tx_anchor);
- usb_kill_anchored_urbs(&data->isoc_anchor);
- usb_kill_anchored_urbs(&data->bulk_anchor);
- usb_kill_anchored_urbs(&data->intr_anchor);
-
return 0;
}
+static void play_deferred(struct btusb_data *data)
+{
+ struct urb *urb;
+ int err;
+
+ while ((urb = usb_get_from_anchor(&data->deferred))) {
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err < 0)
+ break;
+
+ data->tx_in_flight++;
+ }
+ usb_scuttle_anchored_urbs(&data->deferred);
+}
+
static int btusb_resume(struct usb_interface *intf)
{
struct btusb_data *data = usb_get_intfdata(intf);
struct hci_dev *hdev = data->hdev;
- int err;
+ int err = 0;
BT_DBG("intf %p", intf);
@@ -975,13 +1110,13 @@ static int btusb_resume(struct usb_interface *intf)
return 0;
if (!test_bit(HCI_RUNNING, &hdev->flags))
- return 0;
+ goto done;
if (test_bit(BTUSB_INTR_RUNNING, &data->flags)) {
err = btusb_submit_intr_urb(hdev, GFP_NOIO);
if (err < 0) {
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
- return err;
+ goto failed;
}
}
@@ -989,9 +1124,10 @@ static int btusb_resume(struct usb_interface *intf)
err = btusb_submit_bulk_urb(hdev, GFP_NOIO);
if (err < 0) {
clear_bit(BTUSB_BULK_RUNNING, &data->flags);
- return err;
- } else
- btusb_submit_bulk_urb(hdev, GFP_NOIO);
+ goto failed;
+ }
+
+ btusb_submit_bulk_urb(hdev, GFP_NOIO);
}
if (test_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
@@ -1001,16 +1137,35 @@ static int btusb_resume(struct usb_interface *intf)
btusb_submit_isoc_urb(hdev, GFP_NOIO);
}
+ spin_lock_irq(&data->txlock);
+ play_deferred(data);
+ clear_bit(BTUSB_SUSPENDING, &data->flags);
+ spin_unlock_irq(&data->txlock);
+ schedule_work(&data->work);
+
return 0;
+
+failed:
+ usb_scuttle_anchored_urbs(&data->deferred);
+done:
+ spin_lock_irq(&data->txlock);
+ clear_bit(BTUSB_SUSPENDING, &data->flags);
+ spin_unlock_irq(&data->txlock);
+
+ return err;
}
+#endif
static struct usb_driver btusb_driver = {
.name = "btusb",
.probe = btusb_probe,
.disconnect = btusb_disconnect,
+#ifdef CONFIG_PM
.suspend = btusb_suspend,
.resume = btusb_resume,
+#endif
.id_table = btusb_table,
+ .supports_autosuspend = 1,
};
static int __init btusb_init(void)
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 2cc7b3266eaf..4f02a6f3c980 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -573,11 +573,9 @@ static int dtl1_probe(struct pcmcia_device *link)
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
link->io.NumPorts1 = 8;
- link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
- link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
link->irq.Handler = dtl1_interrupt;
- link->irq.Instance = info;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -618,20 +616,16 @@ static int dtl1_config(struct pcmcia_device *link)
/* Look for a generic full-sized window */
link->io.NumPorts1 = 8;
- if (!pcmcia_loop_config(link, dtl1_confcheck, NULL))
+ if (pcmcia_loop_config(link, dtl1_confcheck, NULL) < 0)
goto failed;
i = pcmcia_request_irq(link, &link->irq);
- if (i != 0) {
- cs_error(link, RequestIRQ, i);
+ if (i != 0)
link->irq.AssignedIRQ = 0;
- }
i = pcmcia_request_configuration(link, &link->conf);
- if (i != 0) {
- cs_error(link, RequestConfiguration, i);
+ if (i != 0)
goto failed;
- }
if (dtl1_open(info) != 0)
goto failed;
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 894b2cb11ea6..40aec0fb8596 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -373,8 +373,9 @@ static void bcsp_pkt_cull(struct bcsp_struct *bcsp)
i = 0;
skb_queue_walk_safe(&bcsp->unack, skb, tmp) {
- if (i++ >= pkts_to_be_removed)
+ if (i >= pkts_to_be_removed)
break;
+ i++;
__skb_unlink(skb, &bcsp->unack);
kfree_skb(skb);
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 71d1b9bab70b..614da5b8613a 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -3412,7 +3412,7 @@ static int cdrom_print_info(const char *header, int val, char *info,
return 0;
}
-static int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp,
+static int cdrom_sysctl_info(ctl_table *ctl, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int pos;
@@ -3489,7 +3489,7 @@ static int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp,
goto done;
doit:
mutex_unlock(&cdrom_mutex);
- return proc_dostring(ctl, write, filp, buffer, lenp, ppos);
+ return proc_dostring(ctl, write, buffer, lenp, ppos);
done:
printk(KERN_INFO "cdrom: info buffer too small\n");
goto doit;
@@ -3525,12 +3525,12 @@ static void cdrom_update_settings(void)
mutex_unlock(&cdrom_mutex);
}
-static int cdrom_sysctl_handler(ctl_table *ctl, int write, struct file * filp,
+static int cdrom_sysctl_handler(ctl_table *ctl, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int ret;
- ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
+ ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
if (write) {
diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
index b5621f27c4be..a762283d2a21 100644
--- a/drivers/cdrom/gdrom.c
+++ b/drivers/cdrom/gdrom.c
@@ -512,7 +512,7 @@ static int gdrom_bdops_ioctl(struct block_device *bdev, fmode_t mode,
return cdrom_ioctl(gd.cd_info, bdev, mode, cmd, arg);
}
-static struct block_device_operations gdrom_bdops = {
+static const struct block_device_operations gdrom_bdops = {
.owner = THIS_MODULE,
.open = gdrom_bdops_open,
.release = gdrom_bdops_release,
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index 0fff646cc2f0..57ca69e0ac55 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -177,7 +177,7 @@ static int viocd_blk_media_changed(struct gendisk *disk)
return cdrom_media_changed(&di->viocd_info);
}
-struct block_device_operations viocd_fops = {
+static const struct block_device_operations viocd_fops = {
.owner = THIS_MODULE,
.open = viocd_blk_open,
.release = viocd_blk_release,
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 6a06913b01d3..6aad99ec4e0f 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -323,7 +323,7 @@ config SPECIALIX
config SX
tristate "Specialix SX (and SI) card support"
- depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA)
+ depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA) && BROKEN
help
This is a driver for the SX and SI multiport serial cards.
Please read the file <file:Documentation/serial/sx.txt> for details.
@@ -334,7 +334,7 @@ config SX
config RIO
tristate "Specialix RIO system support"
- depends on SERIAL_NONSTANDARD
+ depends on SERIAL_NONSTANDARD && BROKEN
help
This is a driver for the Specialix RIO, a smart serial card which
drives an outboard box that can support up to 128 ports. Product
@@ -395,7 +395,7 @@ config NOZOMI
config A2232
tristate "Commodore A2232 serial support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP
+ depends on EXPERIMENTAL && ZORRO && BROKEN
---help---
This option supports the 2232 7-port serial card shipped with the
Amiga 2000 and other Zorro-bus machines, dating from 1989. At
@@ -1087,6 +1087,14 @@ config MMTIMER
The mmtimer device allows direct userspace access to the
Altix system timer.
+config UV_MMTIMER
+ tristate "UV_MMTIMER Memory mapped RTC for SGI UV"
+ depends on X86_UV
+ default m
+ help
+ The uv_mmtimer device allows direct userspace access to the
+ UV system timer.
+
source "drivers/char/tpm/Kconfig"
config TELCLOCK
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 66f779ad4f4c..19a79dd79eee 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
obj-$(CONFIG_MSPEC) += mspec.o
obj-$(CONFIG_MMTIMER) += mmtimer.o
+obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o
obj-$(CONFIG_VIOTAPE) += viotape.o
obj-$(CONFIG_HVCS) += hvcs.o
obj-$(CONFIG_IBM_BSR) += bsr.o
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index ccb1fa89de29..2fb3a480f6b0 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -56,9 +56,8 @@ config AGP_AMD
X on AMD Irongate, 761, and 762 chipsets.
config AGP_AMD64
- tristate "AMD Opteron/Athlon64 on-CPU GART support" if !GART_IOMMU
+ tristate "AMD Opteron/Athlon64 on-CPU GART support"
depends on AGP && X86
- default y if GART_IOMMU
help
This option gives you AGP support for the GLX component of
X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs.
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 178e2e9e9f09..870f12cfed93 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -107,7 +107,7 @@ struct agp_bridge_driver {
void (*agp_enable)(struct agp_bridge_data *, u32);
void (*cleanup)(void);
void (*tlb_flush)(struct agp_memory *);
- unsigned long (*mask_memory)(struct agp_bridge_data *, struct page *, int);
+ unsigned long (*mask_memory)(struct agp_bridge_data *, dma_addr_t, int);
void (*cache_flush)(void);
int (*create_gatt_table)(struct agp_bridge_data *);
int (*free_gatt_table)(struct agp_bridge_data *);
@@ -121,12 +121,17 @@ struct agp_bridge_driver {
void (*agp_destroy_pages)(struct agp_memory *);
int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
void (*chipset_flush)(struct agp_bridge_data *);
+
+ int (*agp_map_page)(struct page *page, dma_addr_t *ret);
+ void (*agp_unmap_page)(struct page *page, dma_addr_t dma);
+ int (*agp_map_memory)(struct agp_memory *mem);
+ void (*agp_unmap_memory)(struct agp_memory *mem);
};
struct agp_bridge_data {
const struct agp_version *version;
const struct agp_bridge_driver *driver;
- struct vm_operations_struct *vm_ops;
+ const struct vm_operations_struct *vm_ops;
void *previous_size;
void *current_size;
void *dev_private_data;
@@ -134,7 +139,8 @@ struct agp_bridge_data {
u32 __iomem *gatt_table;
u32 *gatt_table_real;
unsigned long scratch_page;
- unsigned long scratch_page_real;
+ struct page *scratch_page_page;
+ dma_addr_t scratch_page_dma;
unsigned long gart_bus_addr;
unsigned long gatt_bus_addr;
u32 mode;
@@ -291,7 +297,7 @@ int agp_3_5_enable(struct agp_bridge_data *bridge);
void global_cache_flush(void);
void get_agp_version(struct agp_bridge_data *bridge);
unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
- struct page *page, int type);
+ dma_addr_t phys, int type);
int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge,
int type);
struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev);
@@ -312,9 +318,6 @@ void agp3_generic_cleanup(void);
#define AGP_GENERIC_SIZES_ENTRIES 11
extern const struct aper_size_info_16 agp3_generic_sizes[];
-#define virt_to_gart(x) (phys_to_gart(virt_to_phys(x)))
-#define gart_to_virt(x) (phys_to_virt(gart_to_phys(x)))
-
extern int agp_off;
extern int agp_try_unsupported_boot;
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
index 201ef3ffd484..d2ce68f27e4b 100644
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -152,7 +152,7 @@ static struct page *m1541_alloc_page(struct agp_bridge_data *bridge)
pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
- phys_to_gart(page_to_phys(page))) | ALI_CACHE_FLUSH_EN ));
+ page_to_phys(page)) | ALI_CACHE_FLUSH_EN ));
return page;
}
@@ -180,7 +180,7 @@ static void m1541_destroy_page(struct page *page, int flags)
pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
- phys_to_gart(page_to_phys(page))) | ALI_CACHE_FLUSH_EN));
+ page_to_phys(page)) | ALI_CACHE_FLUSH_EN));
}
agp_generic_destroy_page(page, flags);
}
diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c
index 5ea4da8e9954..dd84af4d4f7e 100644
--- a/drivers/char/agp/alpha-agp.c
+++ b/drivers/char/agp/alpha-agp.c
@@ -40,7 +40,7 @@ static struct aper_size_info_fixed alpha_core_agp_sizes[] =
{ 0, 0, 0 }, /* filled in by alpha_core_agp_setup */
};
-struct vm_operations_struct alpha_core_agp_vm_ops = {
+static const struct vm_operations_struct alpha_core_agp_vm_ops = {
.fault = alpha_core_agp_vm_fault,
};
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index ba9bde71eaaf..73dbf40c874d 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -44,7 +44,7 @@ static int amd_create_page_map(struct amd_page_map *page_map)
#ifndef CONFIG_X86
SetPageReserved(virt_to_page(page_map->real));
global_cache_flush();
- page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real),
+ page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real),
PAGE_SIZE);
if (page_map->remapped == NULL) {
ClearPageReserved(virt_to_page(page_map->real));
@@ -160,7 +160,7 @@ static int amd_create_gatt_table(struct agp_bridge_data *bridge)
agp_bridge->gatt_table_real = (u32 *)page_dir.real;
agp_bridge->gatt_table = (u32 __iomem *)page_dir.remapped;
- agp_bridge->gatt_bus_addr = virt_to_gart(page_dir.real);
+ agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real);
/* Get the address for the gart region.
* This is a bus address even on the alpha, b/c its
@@ -173,7 +173,7 @@ static int amd_create_gatt_table(struct agp_bridge_data *bridge)
/* Calculate the agp offset */
for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
- writel(virt_to_gart(amd_irongate_private.gatt_pages[i]->real) | 1,
+ writel(virt_to_phys(amd_irongate_private.gatt_pages[i]->real) | 1,
page_dir.remapped+GET_PAGE_DIR_OFF(addr));
readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr)); /* PCI Posting. */
}
@@ -325,7 +325,9 @@ static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
cur_gatt = GET_GATT(addr);
writel(agp_generic_mask_memory(agp_bridge,
- mem->pages[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
+ page_to_phys(mem->pages[i]),
+ mem->type),
+ cur_gatt+GET_GATT_OFF(addr));
readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */
}
amd_irongate_tlbflush(mem);
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 3bf5dda90f4a..2fb2e6cc322a 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -79,7 +79,8 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
tmp = agp_bridge->driver->mask_memory(agp_bridge,
- mem->pages[i], mask_type);
+ page_to_phys(mem->pages[i]),
+ mask_type);
BUG_ON(tmp & 0xffffff0000000ffcULL);
pte = (tmp & 0x000000ff00000000ULL) >> 28;
@@ -177,7 +178,7 @@ static const struct aper_size_info_32 amd_8151_sizes[7] =
static int amd_8151_configure(void)
{
- unsigned long gatt_bus = virt_to_gart(agp_bridge->gatt_table_real);
+ unsigned long gatt_bus = virt_to_phys(agp_bridge->gatt_table_real);
int i;
/* Configure AGP regs in each x86-64 host bridge. */
@@ -557,7 +558,7 @@ static void __devexit agp_amd64_remove(struct pci_dev *pdev)
{
struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
- release_mem_region(virt_to_gart(bridge->gatt_table_real),
+ release_mem_region(virt_to_phys(bridge->gatt_table_real),
amd64_aperture_sizes[bridge->aperture_size_idx].size);
agp_remove_bridge(bridge);
agp_put_bridge(bridge);
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index 33656e144cc5..3b2ecbe86ebe 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -302,7 +302,8 @@ static int ati_insert_memory(struct agp_memory * mem,
addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
cur_gatt = GET_GATT(addr);
writel(agp_bridge->driver->mask_memory(agp_bridge,
- mem->pages[i], mem->type),
+ page_to_phys(mem->pages[i]),
+ mem->type),
cur_gatt+GET_GATT_OFF(addr));
}
readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */
@@ -359,7 +360,7 @@ static int ati_create_gatt_table(struct agp_bridge_data *bridge)
agp_bridge->gatt_table_real = (u32 *)page_dir.real;
agp_bridge->gatt_table = (u32 __iomem *) page_dir.remapped;
- agp_bridge->gatt_bus_addr = virt_to_gart(page_dir.real);
+ agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real);
/* Write out the size register */
current_size = A_SIZE_LVL2(agp_bridge->current_size);
@@ -389,7 +390,7 @@ static int ati_create_gatt_table(struct agp_bridge_data *bridge)
/* Calculate the agp offset */
for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
- writel(virt_to_gart(ati_generic_private.gatt_pages[i]->real) | 1,
+ writel(virt_to_phys(ati_generic_private.gatt_pages[i]->real) | 1,
page_dir.remapped+GET_PAGE_DIR_OFF(addr));
readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr)); /* PCI Posting. */
}
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index cfa5a649dfe7..a56ca080e108 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -114,9 +114,9 @@ static int agp_find_max(void)
long memory, index, result;
#if PAGE_SHIFT < 20
- memory = num_physpages >> (20 - PAGE_SHIFT);
+ memory = totalram_pages >> (20 - PAGE_SHIFT);
#else
- memory = num_physpages << (PAGE_SHIFT - 20);
+ memory = totalram_pages << (PAGE_SHIFT - 20);
#endif
index = 1;
@@ -149,9 +149,21 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
return -ENOMEM;
}
- bridge->scratch_page_real = phys_to_gart(page_to_phys(page));
- bridge->scratch_page =
- bridge->driver->mask_memory(bridge, page, 0);
+ bridge->scratch_page_page = page;
+ if (bridge->driver->agp_map_page) {
+ if (bridge->driver->agp_map_page(page,
+ &bridge->scratch_page_dma)) {
+ dev_err(&bridge->dev->dev,
+ "unable to dma-map scratch page\n");
+ rc = -ENOMEM;
+ goto err_out_nounmap;
+ }
+ } else {
+ bridge->scratch_page_dma = page_to_phys(page);
+ }
+
+ bridge->scratch_page = bridge->driver->mask_memory(bridge,
+ bridge->scratch_page_dma, 0);
}
size_value = bridge->driver->fetch_size();
@@ -191,8 +203,14 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
return 0;
err_out:
+ if (bridge->driver->needs_scratch_page &&
+ bridge->driver->agp_unmap_page) {
+ bridge->driver->agp_unmap_page(bridge->scratch_page_page,
+ bridge->scratch_page_dma);
+ }
+err_out_nounmap:
if (bridge->driver->needs_scratch_page) {
- void *va = gart_to_virt(bridge->scratch_page_real);
+ void *va = page_address(bridge->scratch_page_page);
bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
@@ -219,7 +237,11 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge)
if (bridge->driver->agp_destroy_page &&
bridge->driver->needs_scratch_page) {
- void *va = gart_to_virt(bridge->scratch_page_real);
+ void *va = page_address(bridge->scratch_page_page);
+
+ if (bridge->driver->agp_unmap_page)
+ bridge->driver->agp_unmap_page(bridge->scratch_page_page,
+ bridge->scratch_page_dma);
bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
index 35d50f2861b6..793f39ea9618 100644
--- a/drivers/char/agp/efficeon-agp.c
+++ b/drivers/char/agp/efficeon-agp.c
@@ -67,7 +67,7 @@ static const struct gatt_mask efficeon_generic_masks[] =
/* This function does the same thing as mask_memory() for this chipset... */
static inline unsigned long efficeon_mask_memory(struct page *page)
{
- unsigned long addr = phys_to_gart(page_to_phys(page));
+ unsigned long addr = page_to_phys(page);
return addr | 0x00000001;
}
@@ -226,7 +226,7 @@ static int efficeon_create_gatt_table(struct agp_bridge_data *bridge)
efficeon_private.l1_table[index] = page;
- value = virt_to_gart((unsigned long *)page) | pati | present | index;
+ value = virt_to_phys((unsigned long *)page) | pati | present | index;
pci_write_config_dword(agp_bridge->dev,
EFFICEON_ATTPAGE, value);
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 1e8b461b91f1..c50543966eb2 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -437,6 +437,12 @@ int agp_bind_memory(struct agp_memory *curr, off_t pg_start)
curr->bridge->driver->cache_flush();
curr->is_flushed = true;
}
+
+ if (curr->bridge->driver->agp_map_memory) {
+ ret_val = curr->bridge->driver->agp_map_memory(curr);
+ if (ret_val)
+ return ret_val;
+ }
ret_val = curr->bridge->driver->insert_memory(curr, pg_start, curr->type);
if (ret_val != 0)
@@ -478,6 +484,9 @@ int agp_unbind_memory(struct agp_memory *curr)
if (ret_val != 0)
return ret_val;
+ if (curr->bridge->driver->agp_unmap_memory)
+ curr->bridge->driver->agp_unmap_memory(curr);
+
curr->is_bound = false;
curr->pg_start = 0;
spin_lock(&curr->bridge->mapped_lock);
@@ -979,7 +988,7 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge)
set_memory_uc((unsigned long)table, 1 << page_order);
bridge->gatt_table = (void *)table;
#else
- bridge->gatt_table = ioremap_nocache(virt_to_gart(table),
+ bridge->gatt_table = ioremap_nocache(virt_to_phys(table),
(PAGE_SIZE * (1 << page_order)));
bridge->driver->cache_flush();
#endif
@@ -992,7 +1001,7 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge)
return -ENOMEM;
}
- bridge->gatt_bus_addr = virt_to_gart(bridge->gatt_table_real);
+ bridge->gatt_bus_addr = virt_to_phys(bridge->gatt_table_real);
/* AK: bogus, should encode addresses > 4GB */
for (i = 0; i < num_entries; i++) {
@@ -1132,7 +1141,9 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
}
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
- writel(bridge->driver->mask_memory(bridge, mem->pages[i], mask_type),
+ writel(bridge->driver->mask_memory(bridge,
+ page_to_phys(mem->pages[i]),
+ mask_type),
bridge->gatt_table+j);
}
readl(bridge->gatt_table+j-1); /* PCI Posting. */
@@ -1347,9 +1358,8 @@ void global_cache_flush(void)
EXPORT_SYMBOL(global_cache_flush);
unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
- struct page *page, int type)
+ dma_addr_t addr, int type)
{
- unsigned long addr = phys_to_gart(page_to_phys(page));
/* memory type is ignored in the generic routine */
if (bridge->driver->masks)
return addr | bridge->driver->masks[0].mask;
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
index 8f3d4c184914..9047b2714653 100644
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -107,7 +107,7 @@ static int __init hp_zx1_ioc_shared(void)
hp->gart_size = HP_ZX1_GART_SIZE;
hp->gatt_entries = hp->gart_size / hp->io_page_size;
- hp->io_pdir = gart_to_virt(readq(hp->ioc_regs+HP_ZX1_PDIR_BASE));
+ hp->io_pdir = phys_to_virt(readq(hp->ioc_regs+HP_ZX1_PDIR_BASE));
hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) {
@@ -246,7 +246,7 @@ hp_zx1_configure (void)
agp_bridge->mode = readl(hp->lba_regs+hp->lba_cap_offset+PCI_AGP_STATUS);
if (hp->io_pdir_owner) {
- writel(virt_to_gart(hp->io_pdir), hp->ioc_regs+HP_ZX1_PDIR_BASE);
+ writel(virt_to_phys(hp->io_pdir), hp->ioc_regs+HP_ZX1_PDIR_BASE);
readl(hp->ioc_regs+HP_ZX1_PDIR_BASE);
writel(hp->io_tlb_ps, hp->ioc_regs+HP_ZX1_TCNFG);
readl(hp->ioc_regs+HP_ZX1_TCNFG);
@@ -394,10 +394,8 @@ hp_zx1_remove_memory (struct agp_memory *mem, off_t pg_start, int type)
}
static unsigned long
-hp_zx1_mask_memory (struct agp_bridge_data *bridge,
- struct page *page, int type)
+hp_zx1_mask_memory (struct agp_bridge_data *bridge, dma_addr_t addr, int type)
{
- unsigned long addr = phys_to_gart(page_to_phys(page));
return HP_ZX1_PDIR_VALID_BIT | addr;
}
@@ -478,7 +476,6 @@ zx1_gart_probe (acpi_handle obj, u32 depth, void *context, void **ret)
{
acpi_handle handle, parent;
acpi_status status;
- struct acpi_buffer buffer;
struct acpi_device_info *info;
u64 lba_hpa, sba_hpa, length;
int match;
@@ -490,13 +487,11 @@ zx1_gart_probe (acpi_handle obj, u32 depth, void *context, void **ret)
/* Look for an enclosing IOC scope and find its CSR space */
handle = obj;
do {
- buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
- status = acpi_get_object_info(handle, &buffer);
+ status = acpi_get_object_info(handle, &info);
if (ACPI_SUCCESS(status)) {
/* TBD check _CID also */
- info = buffer.pointer;
- info->hardware_id.value[sizeof(info->hardware_id)-1] = '\0';
- match = (strcmp(info->hardware_id.value, "HWP0001") == 0);
+ info->hardware_id.string[sizeof(info->hardware_id.length)-1] = '\0';
+ match = (strcmp(info->hardware_id.string, "HWP0001") == 0);
kfree(info);
if (match) {
status = hp_acpi_csr_space(handle, &sba_hpa, &length);
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index 60cc35bb5db7..e763d3312ce7 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -61,7 +61,7 @@
#define WR_FLUSH_GATT(index) RD_GATT(index)
static unsigned long i460_mask_memory (struct agp_bridge_data *bridge,
- unsigned long addr, int type);
+ dma_addr_t addr, int type);
static struct {
void *gatt; /* ioremap'd GATT area */
@@ -325,7 +325,7 @@ static int i460_insert_memory_small_io_page (struct agp_memory *mem,
io_page_size = 1UL << I460_IO_PAGE_SHIFT;
for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
- paddr = phys_to_gart(page_to_phys(mem->pages[i]));
+ paddr = page_to_phys(mem->pages[i]);
for (k = 0; k < I460_IOPAGES_PER_KPAGE; k++, j++, paddr += io_page_size)
WR_GATT(j, i460_mask_memory(agp_bridge, paddr, mem->type));
}
@@ -382,7 +382,7 @@ static int i460_alloc_large_page (struct lp_desc *lp)
return -ENOMEM;
}
- lp->paddr = phys_to_gart(page_to_phys(lp->page));
+ lp->paddr = page_to_phys(lp->page);
lp->refcount = 0;
atomic_add(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp);
return 0;
@@ -546,20 +546,13 @@ static void i460_destroy_page (struct page *page, int flags)
#endif /* I460_LARGE_IO_PAGES */
static unsigned long i460_mask_memory (struct agp_bridge_data *bridge,
- unsigned long addr, int type)
+ dma_addr_t addr, int type)
{
/* Make sure the returned address is a valid GATT entry */
return bridge->driver->masks[0].mask
| (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xfffff000) >> 12);
}
-static unsigned long i460_page_mask_memory(struct agp_bridge_data *bridge,
- struct page *page, int type)
-{
- unsigned long addr = phys_to_gart(page_to_phys(page));
- return i460_mask_memory(bridge, addr, type);
-}
-
const struct agp_bridge_driver intel_i460_driver = {
.owner = THIS_MODULE,
.aperture_sizes = i460_sizes,
@@ -569,7 +562,7 @@ const struct agp_bridge_driver intel_i460_driver = {
.fetch_size = i460_fetch_size,
.cleanup = i460_cleanup,
.tlb_flush = i460_tlb_flush,
- .mask_memory = i460_page_mask_memory,
+ .mask_memory = i460_mask_memory,
.masks = i460_masks,
.agp_enable = agp_generic_enable,
.cache_flush = global_cache_flush,
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index c58557790585..3cb56a049e24 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -10,6 +10,16 @@
#include <linux/agp_backend.h>
#include "agp.h"
+/*
+ * If we have Intel graphics, we're not going to have anything other than
+ * an Intel IOMMU. So make the correct use of the PCI DMA API contingent
+ * on the Intel IOMMU support (CONFIG_DMAR).
+ * Only newer chipsets need to bother with this, of course.
+ */
+#ifdef CONFIG_DMAR
+#define USE_PCI_DMA_API 1
+#endif
+
#define PCI_DEVICE_ID_INTEL_E7221_HB 0x2588
#define PCI_DEVICE_ID_INTEL_E7221_IG 0x258a
#define PCI_DEVICE_ID_INTEL_82946GZ_HB 0x2970
@@ -36,6 +46,8 @@
#define PCI_DEVICE_ID_INTEL_Q35_IG 0x29B2
#define PCI_DEVICE_ID_INTEL_Q33_HB 0x29D0
#define PCI_DEVICE_ID_INTEL_Q33_IG 0x29D2
+#define PCI_DEVICE_ID_INTEL_B43_HB 0x2E40
+#define PCI_DEVICE_ID_INTEL_B43_IG 0x2E42
#define PCI_DEVICE_ID_INTEL_GM45_HB 0x2A40
#define PCI_DEVICE_ID_INTEL_GM45_IG 0x2A42
#define PCI_DEVICE_ID_INTEL_IGD_E_HB 0x2E00
@@ -50,6 +62,7 @@
#define PCI_DEVICE_ID_INTEL_IGDNG_D_IG 0x0042
#define PCI_DEVICE_ID_INTEL_IGDNG_M_HB 0x0044
#define PCI_DEVICE_ID_INTEL_IGDNG_MA_HB 0x0062
+#define PCI_DEVICE_ID_INTEL_IGDNG_MC2_HB 0x006a
#define PCI_DEVICE_ID_INTEL_IGDNG_M_IG 0x0046
/* cover 915 and 945 variants */
@@ -81,9 +94,11 @@
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_B43_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_D_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_M_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_MA_HB)
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_MA_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_MC2_HB)
extern int agp_memory_reserved;
@@ -172,6 +187,123 @@ static struct _intel_private {
int resource_valid;
} intel_private;
+#ifdef USE_PCI_DMA_API
+static int intel_agp_map_page(struct page *page, dma_addr_t *ret)
+{
+ *ret = pci_map_page(intel_private.pcidev, page, 0,
+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(intel_private.pcidev, *ret))
+ return -EINVAL;
+ return 0;
+}
+
+static void intel_agp_unmap_page(struct page *page, dma_addr_t dma)
+{
+ pci_unmap_page(intel_private.pcidev, dma,
+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+}
+
+static void intel_agp_free_sglist(struct agp_memory *mem)
+{
+ struct sg_table st;
+
+ st.sgl = mem->sg_list;
+ st.orig_nents = st.nents = mem->page_count;
+
+ sg_free_table(&st);
+
+ mem->sg_list = NULL;
+ mem->num_sg = 0;
+}
+
+static int intel_agp_map_memory(struct agp_memory *mem)
+{
+ struct sg_table st;
+ struct scatterlist *sg;
+ int i;
+
+ DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
+
+ if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
+ return -ENOMEM;
+
+ mem->sg_list = sg = st.sgl;
+
+ for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg))
+ sg_set_page(sg, mem->pages[i], PAGE_SIZE, 0);
+
+ mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list,
+ mem->page_count, PCI_DMA_BIDIRECTIONAL);
+ if (unlikely(!mem->num_sg)) {
+ intel_agp_free_sglist(mem);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void intel_agp_unmap_memory(struct agp_memory *mem)
+{
+ DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count);
+
+ pci_unmap_sg(intel_private.pcidev, mem->sg_list,
+ mem->page_count, PCI_DMA_BIDIRECTIONAL);
+ intel_agp_free_sglist(mem);
+}
+
+static void intel_agp_insert_sg_entries(struct agp_memory *mem,
+ off_t pg_start, int mask_type)
+{
+ struct scatterlist *sg;
+ int i, j;
+
+ j = pg_start;
+
+ WARN_ON(!mem->num_sg);
+
+ if (mem->num_sg == mem->page_count) {
+ for_each_sg(mem->sg_list, sg, mem->page_count, i) {
+ writel(agp_bridge->driver->mask_memory(agp_bridge,
+ sg_dma_address(sg), mask_type),
+ intel_private.gtt+j);
+ j++;
+ }
+ } else {
+ /* sg may merge pages, but we have to seperate
+ * per-page addr for GTT */
+ unsigned int len, m;
+
+ for_each_sg(mem->sg_list, sg, mem->num_sg, i) {
+ len = sg_dma_len(sg) / PAGE_SIZE;
+ for (m = 0; m < len; m++) {
+ writel(agp_bridge->driver->mask_memory(agp_bridge,
+ sg_dma_address(sg) + m * PAGE_SIZE,
+ mask_type),
+ intel_private.gtt+j);
+ j++;
+ }
+ }
+ }
+ readl(intel_private.gtt+j-1);
+}
+
+#else
+
+static void intel_agp_insert_sg_entries(struct agp_memory *mem,
+ off_t pg_start, int mask_type)
+{
+ int i, j;
+
+ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+ writel(agp_bridge->driver->mask_memory(agp_bridge,
+ page_to_phys(mem->pages[i]), mask_type),
+ intel_private.gtt+j);
+ }
+
+ readl(intel_private.gtt+j-1);
+}
+
+#endif
+
static int intel_i810_fetch_size(void)
{
u32 smram_miscc;
@@ -345,8 +477,7 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
global_cache_flush();
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(agp_bridge->driver->mask_memory(agp_bridge,
- mem->pages[i],
- mask_type),
+ page_to_phys(mem->pages[i]), mask_type),
intel_private.registers+I810_PTE_BASE+(j*4));
}
readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
@@ -463,9 +594,8 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
}
static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge,
- struct page *page, int type)
+ dma_addr_t addr, int type)
{
- unsigned long addr = phys_to_gart(page_to_phys(page));
/* Type checking must be done elsewhere */
return addr | bridge->driver->masks[type].mask;
}
@@ -679,23 +809,39 @@ static void intel_i830_setup_flush(void)
if (!intel_private.i8xx_page)
return;
- /* make page uncached */
- map_page_into_agp(intel_private.i8xx_page);
-
intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
if (!intel_private.i8xx_flush_page)
intel_i830_fini_flush();
}
+static void
+do_wbinvd(void *null)
+{
+ wbinvd();
+}
+
+/* The chipset_flush interface needs to get data that has already been
+ * flushed out of the CPU all the way out to main memory, because the GPU
+ * doesn't snoop those buffers.
+ *
+ * The 8xx series doesn't have the same lovely interface for flushing the
+ * chipset write buffers that the later chips do. According to the 865
+ * specs, it's 64 octwords, or 1KB. So, to get those previous things in
+ * that buffer out, we just fill 1KB and clflush it out, on the assumption
+ * that it'll push whatever was in there out. It appears to work.
+ */
static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
{
unsigned int *pg = intel_private.i8xx_flush_page;
- int i;
- for (i = 0; i < 256; i += 2)
- *(pg + i) = i;
+ memset(pg, 0, 1024);
- wmb();
+ if (cpu_has_clflush) {
+ clflush_cache_range(pg, 1024);
+ } else {
+ if (on_each_cpu(do_wbinvd, NULL, 1) != 0)
+ printk(KERN_ERR "Timed out waiting for cache flush.\n");
+ }
}
/* The intel i830 automatically initializes the agp aperture during POST.
@@ -853,7 +999,7 @@ static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(agp_bridge->driver->mask_memory(agp_bridge,
- mem->pages[i], mask_type),
+ page_to_phys(mem->pages[i]), mask_type),
intel_private.registers+I810_PTE_BASE+(j*4));
}
readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
@@ -1041,7 +1187,7 @@ static void intel_i915_chipset_flush(struct agp_bridge_data *bridge)
static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
int type)
{
- int i, j, num_entries;
+ int num_entries;
void *temp;
int ret = -EINVAL;
int mask_type;
@@ -1065,7 +1211,7 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
if ((pg_start + mem->page_count) > num_entries)
goto out_err;
- /* The i915 can't check the GTT for entries since its read only,
+ /* The i915 can't check the GTT for entries since it's read only;
* depend on the caller to make the correct offset decisions.
*/
@@ -1081,12 +1227,7 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
if (!mem->is_flushed)
global_cache_flush();
- for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
- writel(agp_bridge->driver->mask_memory(agp_bridge,
- mem->pages[i], mask_type), intel_private.gtt+j);
- }
-
- readl(intel_private.gtt+j-1);
+ intel_agp_insert_sg_entries(mem, pg_start, mask_type);
agp_bridge->driver->tlb_flush(mem);
out:
@@ -1198,9 +1339,8 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
* this conditional.
*/
static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
- struct page *page, int type)
+ dma_addr_t addr, int type)
{
- dma_addr_t addr = phys_to_gart(page_to_phys(page));
/* Shift high bits down */
addr |= (addr >> 28) & 0xf0;
@@ -1216,9 +1356,11 @@ static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
case PCI_DEVICE_ID_INTEL_Q45_HB:
case PCI_DEVICE_ID_INTEL_G45_HB:
case PCI_DEVICE_ID_INTEL_G41_HB:
+ case PCI_DEVICE_ID_INTEL_B43_HB:
case PCI_DEVICE_ID_INTEL_IGDNG_D_HB:
case PCI_DEVICE_ID_INTEL_IGDNG_M_HB:
case PCI_DEVICE_ID_INTEL_IGDNG_MA_HB:
+ case PCI_DEVICE_ID_INTEL_IGDNG_MC2_HB:
*gtt_offset = *gtt_size = MB(2);
break;
default:
@@ -2006,6 +2148,12 @@ static const struct agp_bridge_driver intel_915_driver = {
.agp_destroy_pages = agp_generic_destroy_pages,
.agp_type_to_mask_type = intel_i830_type_to_mask_type,
.chipset_flush = intel_i915_chipset_flush,
+#ifdef USE_PCI_DMA_API
+ .agp_map_page = intel_agp_map_page,
+ .agp_unmap_page = intel_agp_unmap_page,
+ .agp_map_memory = intel_agp_map_memory,
+ .agp_unmap_memory = intel_agp_unmap_memory,
+#endif
};
static const struct agp_bridge_driver intel_i965_driver = {
@@ -2034,6 +2182,12 @@ static const struct agp_bridge_driver intel_i965_driver = {
.agp_destroy_pages = agp_generic_destroy_pages,
.agp_type_to_mask_type = intel_i830_type_to_mask_type,
.chipset_flush = intel_i915_chipset_flush,
+#ifdef USE_PCI_DMA_API
+ .agp_map_page = intel_agp_map_page,
+ .agp_unmap_page = intel_agp_unmap_page,
+ .agp_map_memory = intel_agp_map_memory,
+ .agp_unmap_memory = intel_agp_unmap_memory,
+#endif
};
static const struct agp_bridge_driver intel_7505_driver = {
@@ -2088,6 +2242,12 @@ static const struct agp_bridge_driver intel_g33_driver = {
.agp_destroy_pages = agp_generic_destroy_pages,
.agp_type_to_mask_type = intel_i830_type_to_mask_type,
.chipset_flush = intel_i915_chipset_flush,
+#ifdef USE_PCI_DMA_API
+ .agp_map_page = intel_agp_map_page,
+ .agp_unmap_page = intel_agp_unmap_page,
+ .agp_map_memory = intel_agp_map_memory,
+ .agp_unmap_memory = intel_agp_unmap_memory,
+#endif
};
static int find_gmch(u16 device)
@@ -2192,6 +2352,8 @@ static const struct intel_driver_description {
"Q45/Q43", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_G45_HB, PCI_DEVICE_ID_INTEL_G45_IG, 0,
"G45/G43", NULL, &intel_i965_driver },
+ { PCI_DEVICE_ID_INTEL_B43_HB, PCI_DEVICE_ID_INTEL_B43_IG, 0,
+ "B43", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, 0,
"G41", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_IGDNG_D_HB, PCI_DEVICE_ID_INTEL_IGDNG_D_IG, 0,
@@ -2200,6 +2362,8 @@ static const struct intel_driver_description {
"IGDNG/M", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_IGDNG_MA_HB, PCI_DEVICE_ID_INTEL_IGDNG_M_IG, 0,
"IGDNG/MA", NULL, &intel_i965_driver },
+ { PCI_DEVICE_ID_INTEL_IGDNG_MC2_HB, PCI_DEVICE_ID_INTEL_IGDNG_M_IG, 0,
+ "IGDNG/MC2", NULL, &intel_i965_driver },
{ 0, 0, 0, NULL, NULL, NULL }
};
@@ -2291,6 +2455,11 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
&bridge->mode);
}
+ if (bridge->driver->mask_memory == intel_i965_mask_memory)
+ if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(36)))
+ dev_err(&intel_private.pcidev->dev,
+ "set gfx device dma mask 36bit failed!\n");
+
pci_set_drvdata(pdev, bridge);
return agp_add_bridge(bridge);
}
@@ -2313,15 +2482,6 @@ static int agp_intel_resume(struct pci_dev *pdev)
struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
int ret_val;
- pci_restore_state(pdev);
-
- /* We should restore our graphics device's config space,
- * as host bridge (00:00) resumes before graphics device (02:00),
- * then our access to its pci space can work right.
- */
- if (intel_private.pcidev)
- pci_restore_state(intel_private.pcidev);
-
if (bridge->driver == &intel_generic_driver)
intel_configure();
else if (bridge->driver == &intel_850_driver)
@@ -2401,9 +2561,11 @@ static struct pci_device_id agp_intel_pci_table[] = {
ID(PCI_DEVICE_ID_INTEL_Q45_HB),
ID(PCI_DEVICE_ID_INTEL_G45_HB),
ID(PCI_DEVICE_ID_INTEL_G41_HB),
+ ID(PCI_DEVICE_ID_INTEL_B43_HB),
ID(PCI_DEVICE_ID_INTEL_IGDNG_D_HB),
ID(PCI_DEVICE_ID_INTEL_IGDNG_M_HB),
ID(PCI_DEVICE_ID_INTEL_IGDNG_MA_HB),
+ ID(PCI_DEVICE_ID_INTEL_IGDNG_MC2_HB),
{ }
};
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index 263d71dd441c..7e36d2b4f9d4 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -225,7 +225,7 @@ static int nvidia_insert_memory(struct agp_memory *mem, off_t pg_start, int type
}
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(agp_bridge->driver->mask_memory(agp_bridge,
- mem->pages[i], mask_type),
+ page_to_phys(mem->pages[i]), mask_type),
agp_bridge->gatt_table+nvidia_private.pg_offset+j);
}
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index e077701ae3d9..1c129211302d 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -32,7 +32,7 @@
#define AGP8X_MODE (1 << AGP8X_MODE_BIT)
static unsigned long
-parisc_agp_mask_memory(struct agp_bridge_data *bridge, unsigned long addr,
+parisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
int type);
static struct _parisc_agp_info {
@@ -189,20 +189,12 @@ parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
}
static unsigned long
-parisc_agp_mask_memory(struct agp_bridge_data *bridge, unsigned long addr,
+parisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
int type)
{
return SBA_PDIR_VALID_BIT | addr;
}
-static unsigned long
-parisc_agp_page_mask_memory(struct agp_bridge_data *bridge, struct page *page,
- int type)
-{
- unsigned long addr = phys_to_gart(page_to_phys(page));
- return SBA_PDIR_VALID_BIT | addr;
-}
-
static void
parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode)
{
@@ -225,7 +217,7 @@ static const struct agp_bridge_driver parisc_agp_driver = {
.configure = parisc_agp_configure,
.fetch_size = parisc_agp_fetch_size,
.tlb_flush = parisc_agp_tlbflush,
- .mask_memory = parisc_agp_page_mask_memory,
+ .mask_memory = parisc_agp_mask_memory,
.masks = parisc_agp_masks,
.agp_enable = parisc_agp_enable,
.cache_flush = global_cache_flush,
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index d3ea2e4226b5..0d426ae39c85 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -70,10 +70,9 @@ static void sgi_tioca_tlbflush(struct agp_memory *mem)
* entry.
*/
static unsigned long
-sgi_tioca_mask_memory(struct agp_bridge_data *bridge,
- struct page *page, int type)
+sgi_tioca_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
+ int type)
{
- unsigned long addr = phys_to_gart(page_to_phys(page));
return tioca_physpage_to_gart(addr);
}
@@ -190,7 +189,8 @@ static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start,
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
table[j] =
- bridge->driver->mask_memory(bridge, mem->pages[i],
+ bridge->driver->mask_memory(bridge,
+ page_to_phys(mem->pages[i]),
mem->type);
}
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
index b964a2199329..13acaaf64edb 100644
--- a/drivers/char/agp/sworks-agp.c
+++ b/drivers/char/agp/sworks-agp.c
@@ -155,7 +155,7 @@ static int serverworks_create_gatt_table(struct agp_bridge_data *bridge)
/* Create a fake scratch directory */
for (i = 0; i < 1024; i++) {
writel(agp_bridge->scratch_page, serverworks_private.scratch_dir.remapped+i);
- writel(virt_to_gart(serverworks_private.scratch_dir.real) | 1, page_dir.remapped+i);
+ writel(virt_to_phys(serverworks_private.scratch_dir.real) | 1, page_dir.remapped+i);
}
retval = serverworks_create_gatt_pages(value->num_entries / 1024);
@@ -167,7 +167,7 @@ static int serverworks_create_gatt_table(struct agp_bridge_data *bridge)
agp_bridge->gatt_table_real = (u32 *)page_dir.real;
agp_bridge->gatt_table = (u32 __iomem *)page_dir.remapped;
- agp_bridge->gatt_bus_addr = virt_to_gart(page_dir.real);
+ agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real);
/* Get the address for the gart region.
* This is a bus address even on the alpha, b/c its
@@ -179,7 +179,7 @@ static int serverworks_create_gatt_table(struct agp_bridge_data *bridge)
/* Calculate the agp offset */
for (i = 0; i < value->num_entries / 1024; i++)
- writel(virt_to_gart(serverworks_private.gatt_pages[i]->real)|1, page_dir.remapped+i);
+ writel(virt_to_phys(serverworks_private.gatt_pages[i]->real)|1, page_dir.remapped+i);
return 0;
}
@@ -349,7 +349,9 @@ static int serverworks_insert_memory(struct agp_memory *mem,
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
cur_gatt = SVRWRKS_GET_GATT(addr);
- writel(agp_bridge->driver->mask_memory(agp_bridge, mem->pages[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
+ writel(agp_bridge->driver->mask_memory(agp_bridge,
+ page_to_phys(mem->pages[i]), mem->type),
+ cur_gatt+GET_GATT_OFF(addr));
}
serverworks_tlbflush(mem);
return 0;
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index f192c3b9ad41..703959eba45a 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -7,6 +7,7 @@
#include <linux/pagemap.h>
#include <linux/agp_backend.h>
#include <linux/delay.h>
+#include <linux/vmalloc.h>
#include <asm/uninorth.h>
#include <asm/pci-bridge.h>
#include <asm/prom.h>
@@ -27,6 +28,8 @@
static int uninorth_rev;
static int is_u3;
+#define DEFAULT_APERTURE_SIZE 256
+#define DEFAULT_APERTURE_STRING "256"
static char *aperture = NULL;
static int uninorth_fetch_size(void)
@@ -55,7 +58,7 @@ static int uninorth_fetch_size(void)
if (!size) {
for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++)
- if (values[i].size == 32)
+ if (values[i].size == DEFAULT_APERTURE_SIZE)
break;
}
@@ -135,7 +138,7 @@ static int uninorth_configure(void)
if (is_u3) {
pci_write_config_dword(agp_bridge->dev,
UNI_N_CFG_GART_DUMMY_PAGE,
- agp_bridge->scratch_page_real >> 12);
+ page_to_phys(agp_bridge->scratch_page_page) >> 12);
}
return 0;
@@ -179,8 +182,6 @@ static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start,
}
(void)in_le32((volatile u32*)&agp_bridge->gatt_table[pg_start]);
mb();
- flush_dcache_range((unsigned long)&agp_bridge->gatt_table[pg_start],
- (unsigned long)&agp_bridge->gatt_table[pg_start + mem->page_count]);
uninorth_tlbflush(mem);
return 0;
@@ -224,7 +225,6 @@ static int u3_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
(unsigned long)__va(page_to_phys(mem->pages[i]))+0x1000);
}
mb();
- flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]);
uninorth_tlbflush(mem);
return 0;
@@ -243,7 +243,6 @@ int u3_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
for (i = 0; i < mem->page_count; ++i)
gp[i] = 0;
mb();
- flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]);
uninorth_tlbflush(mem);
return 0;
@@ -271,7 +270,7 @@ static void uninorth_agp_enable(struct agp_bridge_data *bridge, u32 mode)
if ((uninorth_rev >= 0x30) && (uninorth_rev <= 0x33)) {
/*
- * We need to to set REQ_DEPTH to 7 for U3 versions 1.0, 2.1,
+ * We need to set REQ_DEPTH to 7 for U3 versions 1.0, 2.1,
* 2.2 and 2.3, Darwin do so.
*/
if ((command >> AGPSTAT_RQ_DEPTH_SHIFT) > 7)
@@ -396,6 +395,7 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
int i;
void *temp;
struct page *page;
+ struct page **pages;
/* We can't handle 2 level gatt's */
if (bridge->driver->size_type == LVL2_APER_SIZE)
@@ -424,21 +424,39 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
if (table == NULL)
return -ENOMEM;
+ pages = kmalloc((1 << page_order) * sizeof(struct page*), GFP_KERNEL);
+ if (pages == NULL)
+ goto enomem;
+
table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
- for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
+ for (page = virt_to_page(table), i = 0; page <= virt_to_page(table_end);
+ page++, i++) {
SetPageReserved(page);
+ pages[i] = page;
+ }
bridge->gatt_table_real = (u32 *) table;
- bridge->gatt_table = (u32 *)table;
- bridge->gatt_bus_addr = virt_to_gart(table);
+ /* Need to clear out any dirty data still sitting in caches */
+ flush_dcache_range((unsigned long)table,
+ (unsigned long)(table_end + PAGE_SIZE));
+ bridge->gatt_table = vmap(pages, (1 << page_order), 0, PAGE_KERNEL_NCG);
+
+ if (bridge->gatt_table == NULL)
+ goto enomem;
+
+ bridge->gatt_bus_addr = virt_to_phys(table);
for (i = 0; i < num_entries; i++)
bridge->gatt_table[i] = 0;
- flush_dcache_range((unsigned long)table, (unsigned long)table_end);
-
return 0;
+
+enomem:
+ kfree(pages);
+ if (table)
+ free_pages((unsigned long)table, page_order);
+ return -ENOMEM;
}
static int uninorth_free_gatt_table(struct agp_bridge_data *bridge)
@@ -456,6 +474,7 @@ static int uninorth_free_gatt_table(struct agp_bridge_data *bridge)
* from the table.
*/
+ vunmap(bridge->gatt_table);
table = (char *) bridge->gatt_table_real;
table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
@@ -474,13 +493,11 @@ void null_cache_flush(void)
/* Setup function */
-static const struct aper_size_info_32 uninorth_sizes[7] =
+static const struct aper_size_info_32 uninorth_sizes[] =
{
-#if 0 /* Not sure uninorth supports that high aperture sizes */
{256, 65536, 6, 64},
{128, 32768, 5, 32},
{64, 16384, 4, 16},
-#endif
{32, 8192, 3, 8},
{16, 4096, 2, 4},
{8, 2048, 1, 2},
@@ -491,7 +508,7 @@ static const struct aper_size_info_32 uninorth_sizes[7] =
* Not sure that u3 supports that high aperture sizes but it
* would strange if it did not :)
*/
-static const struct aper_size_info_32 u3_sizes[8] =
+static const struct aper_size_info_32 u3_sizes[] =
{
{512, 131072, 7, 128},
{256, 65536, 6, 64},
@@ -507,7 +524,7 @@ const struct agp_bridge_driver uninorth_agp_driver = {
.owner = THIS_MODULE,
.aperture_sizes = (void *)uninorth_sizes,
.size_type = U32_APER_SIZE,
- .num_aperture_sizes = 4,
+ .num_aperture_sizes = ARRAY_SIZE(uninorth_sizes),
.configure = uninorth_configure,
.fetch_size = uninorth_fetch_size,
.cleanup = uninorth_cleanup,
@@ -534,7 +551,7 @@ const struct agp_bridge_driver u3_agp_driver = {
.owner = THIS_MODULE,
.aperture_sizes = (void *)u3_sizes,
.size_type = U32_APER_SIZE,
- .num_aperture_sizes = 8,
+ .num_aperture_sizes = ARRAY_SIZE(u3_sizes),
.configure = uninorth_configure,
.fetch_size = uninorth_fetch_size,
.cleanup = uninorth_cleanup,
@@ -717,7 +734,7 @@ module_param(aperture, charp, 0);
MODULE_PARM_DESC(aperture,
"Aperture size, must be power of two between 4MB and an\n"
"\t\tupper limit specific to the UniNorth revision.\n"
- "\t\tDefault: 32M");
+ "\t\tDefault: " DEFAULT_APERTURE_STRING "M");
MODULE_AUTHOR("Ben Herrenschmidt & Paul Mackerras");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index aaca40283be9..4f568cb9af3f 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -393,7 +393,7 @@ static int apm_open(struct inode * inode, struct file * filp)
return as ? 0 : -ENOMEM;
}
-static struct file_operations apm_bios_fops = {
+static const struct file_operations apm_bios_fops = {
.owner = THIS_MODULE,
.read = apm_read,
.poll = apm_poll,
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 73a0765344b6..fe2cb2f5db17 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
diff --git a/drivers/char/bfin-otp.c b/drivers/char/bfin-otp.c
index 0a01329451e4..836d4f0a876f 100644
--- a/drivers/char/bfin-otp.c
+++ b/drivers/char/bfin-otp.c
@@ -1,8 +1,7 @@
/*
* Blackfin On-Chip OTP Memory Interface
- * Supports BF52x/BF54x
*
- * Copyright 2007-2008 Analog Devices Inc.
+ * Copyright 2007-2009 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
@@ -17,8 +16,10 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/types.h>
+#include <mtd/mtd-abi.h>
#include <asm/blackfin.h>
+#include <asm/bfrom.h>
#include <asm/uaccess.h>
#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
@@ -30,39 +31,6 @@
static DEFINE_MUTEX(bfin_otp_lock);
-/* OTP Boot ROM functions */
-#define _BOOTROM_OTP_COMMAND 0xEF000018
-#define _BOOTROM_OTP_READ 0xEF00001A
-#define _BOOTROM_OTP_WRITE 0xEF00001C
-
-static u32 (* const otp_command)(u32 command, u32 value) = (void *)_BOOTROM_OTP_COMMAND;
-static u32 (* const otp_read)(u32 page, u32 flags, u64 *page_content) = (void *)_BOOTROM_OTP_READ;
-static u32 (* const otp_write)(u32 page, u32 flags, u64 *page_content) = (void *)_BOOTROM_OTP_WRITE;
-
-/* otp_command(): defines for "command" */
-#define OTP_INIT 0x00000001
-#define OTP_CLOSE 0x00000002
-
-/* otp_{read,write}(): defines for "flags" */
-#define OTP_LOWER_HALF 0x00000000 /* select upper/lower 64-bit half (bit 0) */
-#define OTP_UPPER_HALF 0x00000001
-#define OTP_NO_ECC 0x00000010 /* do not use ECC */
-#define OTP_LOCK 0x00000020 /* sets page protection bit for page */
-#define OTP_ACCESS_READ 0x00001000
-#define OTP_ACCESS_READWRITE 0x00002000
-
-/* Return values for all functions */
-#define OTP_SUCCESS 0x00000000
-#define OTP_MASTER_ERROR 0x001
-#define OTP_WRITE_ERROR 0x003
-#define OTP_READ_ERROR 0x005
-#define OTP_ACC_VIO_ERROR 0x009
-#define OTP_DATA_MULT_ERROR 0x011
-#define OTP_ECC_MULT_ERROR 0x021
-#define OTP_PREV_WR_ERROR 0x041
-#define OTP_DATA_SB_WARN 0x100
-#define OTP_ECC_SB_WARN 0x200
-
/**
* bfin_otp_read - Read OTP pages
*
@@ -86,9 +54,11 @@ static ssize_t bfin_otp_read(struct file *file, char __user *buff, size_t count,
page = *pos / (sizeof(u64) * 2);
while (bytes_done < count) {
flags = (*pos % (sizeof(u64) * 2) ? OTP_UPPER_HALF : OTP_LOWER_HALF);
- stamp("processing page %i (%s)", page, (flags == OTP_UPPER_HALF ? "upper" : "lower"));
- ret = otp_read(page, flags, &content);
+ stamp("processing page %i (0x%x:%s)", page, flags,
+ (flags & OTP_UPPER_HALF ? "upper" : "lower"));
+ ret = bfrom_OtpRead(page, flags, &content);
if (ret & OTP_MASTER_ERROR) {
+ stamp("error from otp: 0x%x", ret);
bytes_done = -EIO;
break;
}
@@ -96,7 +66,7 @@ static ssize_t bfin_otp_read(struct file *file, char __user *buff, size_t count,
bytes_done = -EFAULT;
break;
}
- if (flags == OTP_UPPER_HALF)
+ if (flags & OTP_UPPER_HALF)
++page;
bytes_done += sizeof(content);
*pos += sizeof(content);
@@ -108,14 +78,53 @@ static ssize_t bfin_otp_read(struct file *file, char __user *buff, size_t count,
}
#ifdef CONFIG_BFIN_OTP_WRITE_ENABLE
+static bool allow_writes;
+
+/**
+ * bfin_otp_init_timing - setup OTP timing parameters
+ *
+ * Required before doing any write operation. Algorithms from HRM.
+ */
+static u32 bfin_otp_init_timing(void)
+{
+ u32 tp1, tp2, tp3, timing;
+
+ tp1 = get_sclk() / 1000000;
+ tp2 = (2 * get_sclk() / 10000000) << 8;
+ tp3 = (0x1401) << 15;
+ timing = tp1 | tp2 | tp3;
+ if (bfrom_OtpCommand(OTP_INIT, timing))
+ return 0;
+
+ return timing;
+}
+
+/**
+ * bfin_otp_deinit_timing - set timings to only allow reads
+ *
+ * Should be called after all writes are done.
+ */
+static void bfin_otp_deinit_timing(u32 timing)
+{
+ /* mask bits [31:15] so that any attempts to write fail */
+ bfrom_OtpCommand(OTP_CLOSE, 0);
+ bfrom_OtpCommand(OTP_INIT, timing & ~(-1 << 15));
+ bfrom_OtpCommand(OTP_CLOSE, 0);
+}
+
/**
- * bfin_otp_write - Write OTP pages
+ * bfin_otp_write - write OTP pages
*
* All writes must be in half page chunks (half page == 64 bits).
*/
static ssize_t bfin_otp_write(struct file *filp, const char __user *buff, size_t count, loff_t *pos)
{
- stampit();
+ ssize_t bytes_done;
+ u32 timing, page, base_flags, flags, ret;
+ u64 content;
+
+ if (!allow_writes)
+ return -EACCES;
if (count % sizeof(u64))
return -EMSGSIZE;
@@ -123,20 +132,96 @@ static ssize_t bfin_otp_write(struct file *filp, const char __user *buff, size_t
if (mutex_lock_interruptible(&bfin_otp_lock))
return -ERESTARTSYS;
- /* need otp_init() documentation before this can be implemented */
+ stampit();
+
+ timing = bfin_otp_init_timing();
+ if (timing == 0) {
+ mutex_unlock(&bfin_otp_lock);
+ return -EIO;
+ }
+
+ base_flags = OTP_CHECK_FOR_PREV_WRITE;
+
+ bytes_done = 0;
+ page = *pos / (sizeof(u64) * 2);
+ while (bytes_done < count) {
+ flags = base_flags | (*pos % (sizeof(u64) * 2) ? OTP_UPPER_HALF : OTP_LOWER_HALF);
+ stamp("processing page %i (0x%x:%s) from %p", page, flags,
+ (flags & OTP_UPPER_HALF ? "upper" : "lower"), buff + bytes_done);
+ if (copy_from_user(&content, buff + bytes_done, sizeof(content))) {
+ bytes_done = -EFAULT;
+ break;
+ }
+ ret = bfrom_OtpWrite(page, flags, &content);
+ if (ret & OTP_MASTER_ERROR) {
+ stamp("error from otp: 0x%x", ret);
+ bytes_done = -EIO;
+ break;
+ }
+ if (flags & OTP_UPPER_HALF)
+ ++page;
+ bytes_done += sizeof(content);
+ *pos += sizeof(content);
+ }
+
+ bfin_otp_deinit_timing(timing);
mutex_unlock(&bfin_otp_lock);
+ return bytes_done;
+}
+
+static long bfin_otp_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
+{
+ stampit();
+
+ switch (cmd) {
+ case OTPLOCK: {
+ u32 timing;
+ int ret = -EIO;
+
+ if (!allow_writes)
+ return -EACCES;
+
+ if (mutex_lock_interruptible(&bfin_otp_lock))
+ return -ERESTARTSYS;
+
+ timing = bfin_otp_init_timing();
+ if (timing) {
+ u32 otp_result = bfrom_OtpWrite(arg, OTP_LOCK, NULL);
+ stamp("locking page %lu resulted in 0x%x", arg, otp_result);
+ if (!(otp_result & OTP_MASTER_ERROR))
+ ret = 0;
+
+ bfin_otp_deinit_timing(timing);
+ }
+
+ mutex_unlock(&bfin_otp_lock);
+
+ return ret;
+ }
+
+ case MEMLOCK:
+ allow_writes = false;
+ return 0;
+
+ case MEMUNLOCK:
+ allow_writes = true;
+ return 0;
+ }
+
return -EINVAL;
}
#else
# define bfin_otp_write NULL
+# define bfin_otp_ioctl NULL
#endif
-static struct file_operations bfin_otp_fops = {
- .owner = THIS_MODULE,
- .read = bfin_otp_read,
- .write = bfin_otp_write,
+static const struct file_operations bfin_otp_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = bfin_otp_ioctl,
+ .read = bfin_otp_read,
+ .write = bfin_otp_write,
};
static struct miscdevice bfin_otp_misc_device = {
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 2dafc2da0648..4254457d3911 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -11,7 +11,7 @@
* Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
* Modified and maintained by Marcio Saito <marcio@cyclades.com>.
*
- * Copyright (C) 2007 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (C) 2007-2009 Jiri Slaby <jirislaby@gmail.com>
*
* Much of the design and some of the code came from serial.c
* which was copyright (C) 1991, 1992 Linus Torvalds. It was
@@ -19,577 +19,9 @@
* and then fixed as suggested by Michael K. Johnson 12/12/92.
* Converted to pci probing and cleaned up by Jiri Slaby.
*
- * This version supports shared IRQ's (only for PCI boards).
- *
- * Prevent users from opening non-existing Z ports.
- *
- * Revision 2.3.2.8 2000/07/06 18:14:16 ivan
- * Fixed the PCI detection function to work properly on Alpha systems.
- * Implemented support for TIOCSERGETLSR ioctl.
- * Implemented full support for non-standard baud rates.
- *
- * Revision 2.3.2.7 2000/06/01 18:26:34 ivan
- * Request PLX I/O region, although driver doesn't use it, to avoid
- * problems with other drivers accessing it.
- * Removed count for on-board buffer characters in cy_chars_in_buffer
- * (Cyclades-Z only).
- *
- * Revision 2.3.2.6 2000/05/05 13:56:05 ivan
- * Driver now reports physical instead of virtual memory addresses.
- * Masks were added to some Cyclades-Z read accesses.
- * Implemented workaround for PLX9050 bug that would cause a system lockup
- * in certain systems, depending on the MMIO addresses allocated to the
- * board.
- * Changed the Tx interrupt programming in the CD1400 chips to boost up
- * performance (Cyclom-Y only).
- * Code is now compliant with the new module interface (module_[init|exit]).
- * Make use of the PCI helper functions to access PCI resources.
- * Did some code "housekeeping".
- *
- * Revision 2.3.2.5 2000/01/19 14:35:33 ivan
- * Fixed bug in cy_set_termios on CRTSCTS flag turnoff.
- *
- * Revision 2.3.2.4 2000/01/17 09:19:40 ivan
- * Fixed SMP locking in Cyclom-Y interrupt handler.
- *
- * Revision 2.3.2.3 1999/12/28 12:11:39 ivan
- * Added a new cyclades_card field called nports to allow the driver to
- * know the exact number of ports found by the Z firmware after its load;
- * RX buffer contention prevention logic on interrupt op mode revisited
- * (Cyclades-Z only);
- * Revisited printk's for Z debug;
- * Driver now makes sure that the constant SERIAL_XMIT_SIZE is defined;
- *
- * Revision 2.3.2.2 1999/10/01 11:27:43 ivan
- * Fixed bug in cyz_poll that would make all ports but port 0
- * unable to transmit/receive data (Cyclades-Z only);
- * Implemented logic to prevent the RX buffer from being stuck with data
- * due to a driver / firmware race condition in interrupt op mode
- * (Cyclades-Z only);
- * Fixed bug in block_til_ready logic that would lead to a system crash;
- * Revisited cy_close spinlock usage;
- *
- * Revision 2.3.2.1 1999/09/28 11:01:22 ivan
- * Revisited CONFIG_PCI conditional compilation for PCI board support;
- * Implemented TIOCGICOUNT and TIOCMIWAIT ioctl support;
- * _Major_ cleanup on the Cyclades-Z interrupt support code / logic;
- * Removed CTS handling from the driver -- this is now completely handled
- * by the firmware (Cyclades-Z only);
- * Flush RX on-board buffers on a port open (Cyclades-Z only);
- * Fixed handling of ASYNC_SPD_* TTY flags;
- * Module unload now unmaps all memory area allocated by ioremap;
- *
- * Revision 2.3.1.1 1999/07/15 16:45:53 ivan
- * Removed CY_PROC conditional compilation;
- * Implemented SMP-awareness for the driver;
- * Implemented a new ISA IRQ autoprobe that uses the irq_probe_[on|off]
- * functions;
- * The driver now accepts memory addresses (maddr=0xMMMMM) and IRQs
- * (irq=NN) as parameters (only for ISA boards);
- * Fixed bug in set_line_char that would prevent the Cyclades-Z
- * ports from being configured at speeds above 115.2Kbps;
- * Fixed bug in cy_set_termios that would prevent XON/XOFF flow control
- * switching from working properly;
- * The driver now only prints IRQ info for the Cyclades-Z if it's
- * configured to work in interrupt mode;
- *
- * Revision 2.2.2.3 1999/06/28 11:13:29 ivan
- * Added support for interrupt mode operation for the Z cards;
- * Removed the driver inactivity control for the Z;
- * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when
- * the Z firmware is not loaded yet;
- * Replaced the "manual" Z Tx flush buffer by a call to a FW command of
- * same functionality;
- * Implemented workaround for IRQ setting loss on the PCI configuration
- * registers after a PCI bridge EEPROM reload (affects PLX9060 only);
- *
- * Revision 2.2.2.2 1999/05/14 17:18:15 ivan
- * /proc entry location changed to /proc/tty/driver/cyclades;
- * Added support to shared IRQ's (only for PCI boards);
- * Added support for Cobalt Qube2 systems;
- * IRQ [de]allocation scheme revisited;
- * BREAK implementation changed in order to make use of the 'break_ctl'
- * TTY facility;
- * Fixed typo in TTY structure field 'driver_name';
- * Included a PCI bridge reset and EEPROM reload in the board
- * initialization code (for both Y and Z series).
- *
- * Revision 2.2.2.1 1999/04/08 16:17:43 ivan
- * Fixed a bug in cy_wait_until_sent that was preventing the port to be
- * closed properly after a SIGINT;
- * Module usage counter scheme revisited;
- * Added support to the upcoming Y PCI boards (i.e., support to additional
- * PCI Device ID's).
- *
- * Revision 2.2.1.10 1999/01/20 16:14:29 ivan
- * Removed all unnecessary page-alignement operations in ioremap calls
- * (ioremap is currently safe for these operations).
- *
- * Revision 2.2.1.9 1998/12/30 18:18:30 ivan
- * Changed access to PLX PCI bridge registers from I/O to MMIO, in
- * order to make PLX9050-based boards work with certain motherboards.
- *
- * Revision 2.2.1.8 1998/11/13 12:46:20 ivan
- * cy_close function now resets (correctly) the tty->closing flag;
- * JIFFIES_DIFF macro fixed.
- *
- * Revision 2.2.1.7 1998/09/03 12:07:28 ivan
- * Fixed bug in cy_close function, which was not informing HW of
- * which port should have the reception disabled before doing so;
- * fixed Cyclom-8YoP hardware detection bug.
- *
- * Revision 2.2.1.6 1998/08/20 17:15:39 ivan
- * Fixed bug in cy_close function, which causes malfunction
- * of one of the first 4 ports when a higher port is closed
- * (Cyclom-Y only).
- *
- * Revision 2.2.1.5 1998/08/10 18:10:28 ivan
- * Fixed Cyclom-4Yo hardware detection bug.
- *
- * Revision 2.2.1.4 1998/08/04 11:02:50 ivan
- * /proc/cyclades implementation with great collaboration of
- * Marc Lewis <marc@blarg.net>;
- * cyy_interrupt was changed to avoid occurrence of kernel oopses
- * during PPP operation.
- *
- * Revision 2.2.1.3 1998/06/01 12:09:10 ivan
- * General code review in order to comply with 2.1 kernel standards;
- * data loss prevention for slow devices revisited (cy_wait_until_sent
- * was created);
- * removed conditional compilation for new/old PCI structure support
- * (now the driver only supports the new PCI structure).
- *
- * Revision 2.2.1.1 1998/03/19 16:43:12 ivan
- * added conditional compilation for new/old PCI structure support;
- * removed kernel series (2.0.x / 2.1.x) conditional compilation.
- *
- * Revision 2.1.1.3 1998/03/16 18:01:12 ivan
- * cleaned up the data loss fix;
- * fixed XON/XOFF handling once more (Cyclades-Z);
- * general review of the driver routines;
- * introduction of a mechanism to prevent data loss with slow
- * printers, by forcing a delay before closing the port.
- *
- * Revision 2.1.1.2 1998/02/17 16:50:00 ivan
- * fixed detection/handling of new CD1400 in Ye boards;
- * fixed XON/XOFF handling (Cyclades-Z);
- * fixed data loss caused by a premature port close;
- * introduction of a flag that holds the CD1400 version ID per port
- * (used by the CYGETCD1400VER new ioctl).
- *
- * Revision 2.1.1.1 1997/12/03 17:31:19 ivan
- * Code review for the module cleanup routine;
- * fixed RTS and DTR status report for new CD1400's in get_modem_info;
- * includes anonymous changes regarding signal_pending.
- *
- * Revision 2.1 1997/11/01 17:42:41 ivan
- * Changes in the driver to support Alpha systems (except 8Zo V_1);
- * BREAK fix for the Cyclades-Z boards;
- * driver inactivity control by FW implemented;
- * introduction of flag that allows driver to take advantage of
- * a special CD1400 feature related to HW flow control;
- * added support for the CD1400 rev. J (Cyclom-Y boards);
- * introduction of ioctls to:
- * - control the rtsdtr_inv flag (Cyclom-Y);
- * - control the rflow flag (Cyclom-Y);
- * - adjust the polling interval (Cyclades-Z);
- *
- * Revision 1.36.4.33 1997/06/27 19:00:00 ivan
- * Fixes related to kernel version conditional
- * compilation.
- *
- * Revision 1.36.4.32 1997/06/14 19:30:00 ivan
- * Compatibility issues between kernels 2.0.x and
- * 2.1.x (mainly related to clear_bit function).
- *
- * Revision 1.36.4.31 1997/06/03 15:30:00 ivan
- * Changes to define the memory window according to the
- * board type.
- *
- * Revision 1.36.4.30 1997/05/16 15:30:00 daniel
- * Changes to support new cycladesZ boards.
- *
- * Revision 1.36.4.29 1997/05/12 11:30:00 daniel
- * Merge of Bentson's and Daniel's version 1.36.4.28.
- * Corrects bug in cy_detect_pci: check if there are more
- * ports than the number of static structs allocated.
- * Warning message during initialization if this driver is
- * used with the new generation of cycladesZ boards. Those
- * will be supported only in next release of the driver.
- * Corrects bug in cy_detect_pci and cy_detect_isa that
- * returned wrong number of VALID boards, when a cyclomY
- * was found with no serial modules connected.
- * Changes to use current (2.1.x) kernel subroutine names
- * and created macros for compilation with 2.0.x kernel,
- * instead of the other way around.
- *
- * Revision 1.36.4.28 1997/05/?? ??:00:00 bentson
- * Change queue_task_irq_off to queue_task_irq.
- * The inline function queue_task_irq_off (tqueue.h)
- * was removed from latest releases of 2.1.x kernel.
- * Use of macro __init to mark the initialization
- * routines, so memory can be reused.
- * Also incorporate implementation of critical region
- * in function cleanup_module() created by anonymous
- * linuxer.
- *
- * Revision 1.36.4.28 1997/04/25 16:00:00 daniel
- * Change to support new firmware that solves DCD problem:
- * application could fail to receive SIGHUP signal when DCD
- * varying too fast.
- *
- * Revision 1.36.4.27 1997/03/26 10:30:00 daniel
- * Changed for support linux versions 2.1.X.
- * Backward compatible with linux versions 2.0.X.
- * Corrected illegal use of filler field in
- * CH_CTRL struct.
- * Deleted some debug messages.
- *
- * Revision 1.36.4.26 1997/02/27 12:00:00 daniel
- * Included check for NULL tty pointer in cyz_poll.
- *
- * Revision 1.36.4.25 1997/02/26 16:28:30 bentson
- * Bill Foster at Blarg! Online services noticed that
- * some of the switch elements of -Z modem control
- * lacked a closing "break;"
- *
- * Revision 1.36.4.24 1997/02/24 11:00:00 daniel
- * Changed low water threshold for buffer xmit_buf
- *
- * Revision 1.36.4.23 1996/12/02 21:50:16 bentson
- * Marcio provided fix to modem status fetch for -Z
- *
- * Revision 1.36.4.22 1996/10/28 22:41:17 bentson
- * improve mapping of -Z control page (thanks to Steve
- * Price <stevep@fa.tdktca.com> for help on this)
- *
- * Revision 1.36.4.21 1996/09/10 17:00:10 bentson
- * shift from CPU-bound to memcopy in cyz_polling operation
- *
- * Revision 1.36.4.20 1996/09/09 18:30:32 Bentson
- * Added support to set and report higher speeds.
- *
- * Revision 1.36.4.19c 1996/08/09 10:00:00 Marcio Saito
- * Some fixes in the HW flow control for the BETA release.
- * Don't try to register the IRQ.
- *
- * Revision 1.36.4.19 1996/08/08 16:23:18 Bentson
- * make sure "cyc" appears in all kernel messages; all soft interrupts
- * handled by same routine; recognize out-of-band reception; comment
- * out some diagnostic messages; leave RTS/CTS flow control to hardware;
- * fix race condition in -Z buffer management; only -Y needs to explicitly
- * flush chars; tidy up some startup messages;
- *
- * Revision 1.36.4.18 1996/07/25 18:57:31 bentson
- * shift MOD_INC_USE_COUNT location to match
- * serial.c; purge some diagnostic messages;
- *
- * Revision 1.36.4.17 1996/07/25 18:01:08 bentson
- * enable modem status messages and fetch & process them; note
- * time of last activity type for each port; set_line_char now
- * supports more than line 0 and treats 0 baud correctly;
- * get_modem_info senses rs_status;
- *
- * Revision 1.36.4.16 1996/07/20 08:43:15 bentson
- * barely works--now's time to turn on
- * more features 'til it breaks
- *
- * Revision 1.36.4.15 1996/07/19 22:30:06 bentson
- * check more -Z board status; shorten boot message
- *
- * Revision 1.36.4.14 1996/07/19 22:20:37 bentson
- * fix reference to ch_ctrl in startup; verify return
- * values from cyz_issue_cmd and cyz_update_channel;
- * more stuff to get modem control correct;
- *
- * Revision 1.36.4.13 1996/07/11 19:53:33 bentson
- * more -Z stuff folded in; re-order changes to put -Z stuff
- * after -Y stuff (to make changes clearer)
- *
- * Revision 1.36.4.12 1996/07/11 15:40:55 bentson
- * Add code to poll Cyclades-Z. Add code to get & set RS-232 control.
- * Add code to send break. Clear firmware ID word at startup (so
- * that other code won't talk to inactive board).
- *
- * Revision 1.36.4.11 1996/07/09 05:28:29 bentson
- * add code for -Z in set_line_char
- *
- * Revision 1.36.4.10 1996/07/08 19:28:37 bentson
- * fold more -Z stuff (or in some cases, error messages)
- * into driver; add text to "don't know what to do" messages.
- *
- * Revision 1.36.4.9 1996/07/08 18:38:38 bentson
- * moved compile-time flags near top of file; cosmetic changes
- * to narrow text (to allow 2-up printing); changed many declarations
- * to "static" to limit external symbols; shuffled code order to
- * coalesce -Y and -Z specific code, also to put internal functions
- * in order of tty_driver structure; added code to recognize -Z
- * ports (and for moment, do nothing or report error); add cy_startup
- * to parse boot command line for extra base addresses for ISA probes;
- *
- * Revision 1.36.4.8 1996/06/25 17:40:19 bentson
- * reorder some code, fix types of some vars (int vs. long),
- * add cy_setup to support user declared ISA addresses
- *
- * Revision 1.36.4.7 1996/06/21 23:06:18 bentson
- * dump ioctl based firmware load (it's now a user level
- * program); ensure uninitialzed ports cannot be used
- *
- * Revision 1.36.4.6 1996/06/20 23:17:19 bentson
- * rename vars and restructure some code
- *
- * Revision 1.36.4.5 1996/06/14 15:09:44 bentson
- * get right status back after boot load
- *
- * Revision 1.36.4.4 1996/06/13 19:51:44 bentson
- * successfully loads firmware
- *
- * Revision 1.36.4.3 1996/06/13 06:08:33 bentson
- * add more of the code for the boot/load ioctls
- *
- * Revision 1.36.4.2 1996/06/11 21:00:51 bentson
- * start to add Z functionality--starting with ioctl
- * for loading firmware
- *
- * Revision 1.36.4.1 1996/06/10 18:03:02 bentson
- * added code to recognize Z/PCI card at initialization; report
- * presence, but card is not initialized (because firmware needs
- * to be loaded)
- *
- * Revision 1.36.3.8 1996/06/07 16:29:00 bentson
- * starting minor number at zero; added missing verify_area
- * as noted by Heiko Eißfeldt <heiko@colossus.escape.de>
- *
- * Revision 1.36.3.7 1996/04/19 21:06:18 bentson
- * remove unneeded boot message & fix CLOCAL hardware flow
- * control (Miquel van Smoorenburg <miquels@Q.cistron.nl>);
- * remove unused diagnostic statements; minor 0 is first;
- *
- * Revision 1.36.3.6 1996/03/13 13:21:17 marcio
- * The kernel function vremap (available only in later 1.3.xx kernels)
- * allows the access to memory addresses above the RAM. This revision
- * of the driver supports PCI boards below 1Mb (device id 0x100) and
- * above 1Mb (device id 0x101).
- *
- * Revision 1.36.3.5 1996/03/07 15:20:17 bentson
- * Some global changes to interrupt handling spilled into
- * this driver--mostly unused arguments in system function
- * calls. Also added change by Marcio Saito which should
- * reduce lost interrupts at startup by fast processors.
- *
- * Revision 1.36.3.4 1995/11/13 20:45:10 bentson
- * Changes by Corey Minyard <minyard@wf-rch.cirr.com> distributed
- * in 1.3.41 kernel to remove a possible race condition, extend
- * some error messages, and let the driver run as a loadable module
- * Change by Alan Wendt <alan@ez0.ezlink.com> to remove a
- * possible race condition.
- * Change by Marcio Saito <marcio@cyclades.com> to fix PCI addressing.
- *
- * Revision 1.36.3.3 1995/11/13 19:44:48 bentson
- * Changes by Linus Torvalds in 1.3.33 kernel distribution
- * required due to reordering of driver initialization.
- * Drivers are now initialized *after* memory management.
- *
- * Revision 1.36.3.2 1995/09/08 22:07:14 bentson
- * remove printk from ISR; fix typo
- *
- * Revision 1.36.3.1 1995/09/01 12:00:42 marcio
- * Minor fixes in the PCI board support. PCI function calls in
- * conditional compilation (CONFIG_PCI). Thanks to Jim Duncan
- * <duncan@okay.com>. "bad serial count" message removed.
- *
- * Revision 1.36.3 1995/08/22 09:19:42 marcio
- * Cyclom-Y/PCI support added. Changes in the cy_init routine and
- * board initialization. Changes in the boot messages. The driver
- * supports up to 4 boards and 64 ports by default.
- *
- * Revision 1.36.1.4 1995/03/29 06:14:14 bentson
- * disambiguate between Cyclom-16Y and Cyclom-32Ye;
- *
- * Revision 1.36.1.3 1995/03/23 22:15:35 bentson
- * add missing break in modem control block in ioctl switch statement
- * (discovered by Michael Edward Chastain <mec@jobe.shell.portal.com>);
- *
- * Revision 1.36.1.2 1995/03/22 19:16:22 bentson
- * make sure CTS flow control is set as soon as possible (thanks
- * to note from David Lambert <lambert@chesapeake.rps.slb.com>);
- *
- * Revision 1.36.1.1 1995/03/13 15:44:43 bentson
- * initialize defaults for receive threshold and stale data timeout;
- * cosmetic changes;
- *
- * Revision 1.36 1995/03/10 23:33:53 bentson
- * added support of chips 4-7 in 32 port Cyclom-Ye;
- * fix cy_interrupt pointer dereference problem
- * (Joe Portman <baron@aa.net>);
- * give better error response if open is attempted on non-existent port
- * (Zachariah Vaum <jchryslr@netcom.com>);
- * correct command timeout (Kenneth Lerman <lerman@@seltd.newnet.com>);
- * conditional compilation for -16Y on systems with fast, noisy bus;
- * comment out diagnostic print function;
- * cleaned up table of base addresses;
- * set receiver time-out period register to correct value,
- * set receive threshold to better default values,
- * set chip timer to more accurate 200 Hz ticking,
- * add code to monitor and modify receive parameters
- * (Rik Faith <faith@cs.unc.edu> Nick Simicich
- * <njs@scifi.emi.net>);
- *
- * Revision 1.35 1994/12/16 13:54:18 steffen
- * additional patch by Marcio Saito for board detection
- * Accidently left out in 1.34
- *
- * Revision 1.34 1994/12/10 12:37:12 steffen
- * This is the corrected version as suggested by Marcio Saito
- *
- * Revision 1.33 1994/12/01 22:41:18 bentson
- * add hooks to support more high speeds directly; add tytso
- * patch regarding CLOCAL wakeups
- *
- * Revision 1.32 1994/11/23 19:50:04 bentson
- * allow direct kernel control of higher signalling rates;
- * look for cards at additional locations
- *
- * Revision 1.31 1994/11/16 04:33:28 bentson
- * ANOTHER fix from Corey Minyard, minyard@wf-rch.cirr.com--
- * a problem in chars_in_buffer has been resolved by some
- * small changes; this should yield smoother output
- *
- * Revision 1.30 1994/11/16 04:28:05 bentson
- * Fix from Corey Minyard, Internet: minyard@metronet.com,
- * UUCP: minyard@wf-rch.cirr.com, WORK: minyardbnr.ca, to
- * cy_hangup that appears to clear up much (all?) of the
- * DTR glitches; also he's added/cleaned-up diagnostic messages
- *
- * Revision 1.29 1994/11/16 04:16:07 bentson
- * add change proposed by Ralph Sims, ralphs@halcyon.com, to
- * operate higher speeds in same way as other serial ports;
- * add more serial ports (for up to two 16-port muxes).
- *
- * Revision 1.28 1994/11/04 00:13:16 root
- * turn off diagnostic messages
- *
- * Revision 1.27 1994/11/03 23:46:37 root
- * bunch of changes to bring driver into greater conformance
- * with the serial.c driver (looking for missed fixes)
- *
- * Revision 1.26 1994/11/03 22:40:36 root
- * automatic interrupt probing fixed.
- *
- * Revision 1.25 1994/11/03 20:17:02 root
- * start to implement auto-irq
- *
- * Revision 1.24 1994/11/03 18:01:55 root
- * still working on modem signals--trying not to drop DTR
- * during the getty/login processes
- *
- * Revision 1.23 1994/11/03 17:51:36 root
- * extend baud rate support; set receive threshold as function
- * of baud rate; fix some problems with RTS/CTS;
- *
- * Revision 1.22 1994/11/02 18:05:35 root
- * changed arguments to udelay to type long to get
- * delays to be of correct duration
- *
- * Revision 1.21 1994/11/02 17:37:30 root
- * employ udelay (after calibrating loops_per_second earlier
- * in init/main.c) instead of using home-grown delay routines
- *
- * Revision 1.20 1994/11/02 03:11:38 root
- * cy_chars_in_buffer forces a return value of 0 to let
- * login work (don't know why it does); some functions
- * that were returning EFAULT, now executes the code;
- * more work on deciding when to disable xmit interrupts;
- *
- * Revision 1.19 1994/11/01 20:10:14 root
- * define routine to start transmission interrupts (by enabling
- * transmit interrupts); directly enable/disable modem interrupts;
- *
- * Revision 1.18 1994/11/01 18:40:45 bentson
- * Don't always enable transmit interrupts in startup; interrupt on
- * TxMpty instead of TxRdy to help characters get out before shutdown;
- * restructure xmit interrupt to check for chars first and quit if
- * none are ready to go; modem status (MXVRx) is upright, _not_ inverted
- * (to my view);
- *
- * Revision 1.17 1994/10/30 04:39:45 bentson
- * rename serial_driver and callout_driver to cy_serial_driver and
- * cy_callout_driver to avoid linkage interference; initialize
- * info->type to PORT_CIRRUS; ruggedize paranoia test; elide ->port
- * from cyclades_port structure; add paranoia check to cy_close;
- *
- * Revision 1.16 1994/10/30 01:14:33 bentson
- * change major numbers; add some _early_ return statements;
- *
- * Revision 1.15 1994/10/29 06:43:15 bentson
- * final tidying up for clean compile; enable some error reporting
- *
- * Revision 1.14 1994/10/28 20:30:22 Bentson
- * lots of changes to drag the driver towards the new tty_io
- * structures and operation. not expected to work, but may
- * compile cleanly.
- *
- * Revision 1.13 1994/07/21 23:08:57 Bentson
- * add some diagnostic cruft; support 24 lines (for testing
- * both -8Y and -16Y cards; be more thorough in servicing all
- * chips during interrupt; add "volatile" a few places to
- * circumvent compiler optimizations; fix base & offset
- * computations in block_til_ready (was causing chip 0 to
- * stop operation)
- *
- * Revision 1.12 1994/07/19 16:42:11 Bentson
- * add some hackery for kernel version 1.1.8; expand
- * error messages; refine timing for delay loops and
- * declare loop params volatile
- *
- * Revision 1.11 1994/06/11 21:53:10 bentson
- * get use of save_car right in transmit interrupt service
- *
- * Revision 1.10.1.1 1994/06/11 21:31:18 bentson
- * add some diagnostic printing; try to fix save_car stuff
- *
- * Revision 1.10 1994/06/11 20:36:08 bentson
- * clean up compiler warnings
- *
- * Revision 1.9 1994/06/11 19:42:46 bentson
- * added a bunch of code to support modem signalling
- *
- * Revision 1.8 1994/06/11 17:57:07 bentson
- * recognize break & parity error
- *
- * Revision 1.7 1994/06/05 05:51:34 bentson
- * Reorder baud table to be monotonic; add cli to CP; discard
- * incoming characters and status if the line isn't open; start to
- * fold code into cy_throttle; start to port get_serial_info,
- * set_serial_info, get_modem_info, set_modem_info, and send_break
- * from serial.c; expand cy_ioctl; relocate and expand config_setup;
- * get flow control characters from tty struct; invalidate ports w/o
- * hardware;
- *
- * Revision 1.6 1994/05/31 18:42:21 bentson
- * add a loop-breaker in the interrupt service routine;
- * note when port is initialized so that it can be shut
- * down under the right conditions; receive works without
- * any obvious errors
- *
- * Revision 1.5 1994/05/30 00:55:02 bentson
- * transmit works without obvious errors
- *
- * Revision 1.4 1994/05/27 18:46:27 bentson
- * incorporated more code from lib_y.c; can now print short
- * strings under interrupt control to port zero; seems to
- * select ports/channels/lines correctly
- *
- * Revision 1.3 1994/05/25 22:12:44 bentson
- * shifting from multi-port on a card to proper multiplexor
- * data structures; added skeletons of most routines
- *
- * Revision 1.2 1994/05/19 13:21:43 bentson
- * start to crib from other sources
- *
*/
-#define CY_VERSION "2.5"
+#define CY_VERSION "2.6"
/* If you need to install more boards than NR_CARDS, change the constant
in the definition below. No other change is necessary to support up to
@@ -648,9 +80,7 @@
#include <linux/firmware.h>
#include <linux/device.h>
-#include <asm/system.h>
#include <linux/io.h>
-#include <asm/irq.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
@@ -660,13 +90,11 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-static void cy_throttle(struct tty_struct *tty);
static void cy_send_xchar(struct tty_struct *tty, char ch);
#ifndef SERIAL_XMIT_SIZE
#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096))
#endif
-#define WAKEUP_CHARS 256
#define STD_COM_FLAGS (0)
@@ -756,25 +184,25 @@ static int cy_next_channel; /* next minor available */
* HI VHI
* 20
*/
-static int baud_table[] = {
+static const int baud_table[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
230400, 0
};
-static char baud_co_25[] = { /* 25 MHz clock option table */
+static const char baud_co_25[] = { /* 25 MHz clock option table */
/* value => 00 01 02 03 04 */
/* divide by 8 32 128 512 2048 */
0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-static char baud_bpr_25[] = { /* 25 MHz baud rate period table */
+static const char baud_bpr_25[] = { /* 25 MHz baud rate period table */
0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
};
-static char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
+static const char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
/* value => 00 01 02 03 04 */
/* divide by 8 32 128 512 2048 */
0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
@@ -782,13 +210,13 @@ static char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
0x00
};
-static char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
+static const char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
0x21
};
-static char baud_cor3[] = { /* receive threshold */
+static const char baud_cor3[] = { /* receive threshold */
0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
0x07
@@ -805,7 +233,7 @@ static char baud_cor3[] = { /* receive threshold */
* cables.
*/
-static char rflow_thr[] = { /* rflow threshold */
+static const char rflow_thr[] = { /* rflow threshold */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
0x0a
@@ -814,7 +242,7 @@ static char rflow_thr[] = { /* rflow threshold */
/* The Cyclom-Ye has placed the sequential chips in non-sequential
* address order. This look-up table overcomes that problem.
*/
-static int cy_chip_offset[] = { 0x0000,
+static const unsigned int cy_chip_offset[] = { 0x0000,
0x0400,
0x0800,
0x0C00,
@@ -827,7 +255,7 @@ static int cy_chip_offset[] = { 0x0000,
/* PCI related definitions */
#ifdef CONFIG_PCI
-static struct pci_device_id cy_pci_dev_id[] __devinitdata = {
+static const struct pci_device_id cy_pci_dev_id[] = {
/* PCI < 1Mb */
{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },
/* PCI > 1Mb */
@@ -850,7 +278,7 @@ MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
#endif
static void cy_start(struct tty_struct *);
-static void set_line_char(struct cyclades_port *);
+static void cy_set_line_char(struct cyclades_port *, struct tty_struct *);
static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
#ifdef CONFIG_ISA
static unsigned detect_isa_irq(void __iomem *);
@@ -869,6 +297,20 @@ static void cyz_rx_restart(unsigned long);
static struct timer_list cyz_rx_full_timer[NR_PORTS];
#endif /* CONFIG_CYZ_INTR */
+static inline void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val)
+{
+ struct cyclades_card *card = port->card;
+
+ cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val);
+}
+
+static inline u8 cyy_readb(struct cyclades_port *port, u32 reg)
+{
+ struct cyclades_card *card = port->card;
+
+ return readb(port->u.cyy.base_addr + (reg << card->bus_index));
+}
+
static inline bool cy_is_Z(struct cyclades_card *card)
{
return card->num_chips == (unsigned int)-1;
@@ -893,7 +335,7 @@ static inline bool cyz_is_loaded(struct cyclades_card *card)
}
static inline int serial_paranoia_check(struct cyclades_port *info,
- char *name, const char *routine)
+ const char *name, const char *routine)
{
#ifdef SERIAL_PARANOIA_CHECK
if (!info) {
@@ -909,7 +351,7 @@ static inline int serial_paranoia_check(struct cyclades_port *info,
}
#endif
return 0;
-} /* serial_paranoia_check */
+}
/***********************************************************/
/********* Start of block of Cyclom-Y specific code ********/
@@ -921,13 +363,14 @@ static inline int serial_paranoia_check(struct cyclades_port *info,
This function is only called from inside spinlock-protected code.
*/
-static int cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index)
+static int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index)
{
+ void __iomem *ccr = base_addr + (CyCCR << index);
unsigned int i;
/* Check to see that the previous command has completed */
for (i = 0; i < 100; i++) {
- if (readb(base_addr + (CyCCR << index)) == 0)
+ if (readb(ccr) == 0)
break;
udelay(10L);
}
@@ -937,10 +380,16 @@ static int cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index)
return -1;
/* Issue the new command */
- cy_writeb(base_addr + (CyCCR << index), cmd);
+ cy_writeb(ccr, cmd);
return 0;
-} /* cyy_issue_cmd */
+}
+
+static inline int cyy_issue_cmd(struct cyclades_port *port, u8 cmd)
+{
+ return __cyy_issue_cmd(port->u.cyy.base_addr, cmd,
+ port->card->bus_index);
+}
#ifdef CONFIG_ISA
/* ISA interrupt detection code */
@@ -960,12 +409,12 @@ static unsigned detect_isa_irq(void __iomem *address)
irqs = probe_irq_on();
/* Wait ... */
- udelay(5000L);
+ msleep(5);
/* Enable the Tx interrupts on the CD1400 */
local_irq_save(flags);
cy_writeb(address + (CyCAR << index), 0);
- cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
+ __cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
cy_writeb(address + (CyCAR << index), 0);
cy_writeb(address + (CySRER << index),
@@ -973,7 +422,7 @@ static unsigned detect_isa_irq(void __iomem *address)
local_irq_restore(flags);
/* Wait ... */
- udelay(5000L);
+ msleep(5);
/* Check which interrupt is in use */
irq = probe_irq_off(irqs);
@@ -999,7 +448,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
struct cyclades_port *info;
struct tty_struct *tty;
int len, index = cinfo->bus_index;
- u8 save_xir, channel, save_car, data, char_count;
+ u8 ivr, save_xir, channel, save_car, data, char_count;
#ifdef CY_DEBUG_INTERRUPTS
printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
@@ -1008,26 +457,25 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
save_xir = readb(base_addr + (CyRIR << index));
channel = save_xir & CyIRChannel;
info = &cinfo->ports[channel + chip * 4];
- save_car = readb(base_addr + (CyCAR << index));
- cy_writeb(base_addr + (CyCAR << index), save_xir);
+ save_car = cyy_readb(info, CyCAR);
+ cyy_writeb(info, CyCAR, save_xir);
+ ivr = cyy_readb(info, CyRIVR) & CyIVRMask;
+ tty = tty_port_tty_get(&info->port);
/* if there is nowhere to put the data, discard it */
- if (info->port.tty == NULL) {
- if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
- CyIVRRxEx) { /* exception */
- data = readb(base_addr + (CyRDSR << index));
+ if (tty == NULL) {
+ if (ivr == CyIVRRxEx) { /* exception */
+ data = cyy_readb(info, CyRDSR);
} else { /* normal character reception */
- char_count = readb(base_addr + (CyRDCR << index));
+ char_count = cyy_readb(info, CyRDCR);
while (char_count--)
- data = readb(base_addr + (CyRDSR << index));
+ data = cyy_readb(info, CyRDSR);
}
goto end;
}
/* there is an open port for this data */
- tty = info->port.tty;
- if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
- CyIVRRxEx) { /* exception */
- data = readb(base_addr + (CyRDSR << index));
+ if (ivr == CyIVRRxEx) { /* exception */
+ data = cyy_readb(info, CyRDSR);
/* For statistics only */
if (data & CyBREAK)
@@ -1041,28 +489,29 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
if (data & info->ignore_status_mask) {
info->icount.rx++;
+ tty_kref_put(tty);
return;
}
if (tty_buffer_request_room(tty, 1)) {
if (data & info->read_status_mask) {
if (data & CyBREAK) {
tty_insert_flip_char(tty,
- readb(base_addr + (CyRDSR <<
- index)), TTY_BREAK);
+ cyy_readb(info, CyRDSR),
+ TTY_BREAK);
info->icount.rx++;
if (info->port.flags & ASYNC_SAK)
do_SAK(tty);
} else if (data & CyFRAME) {
tty_insert_flip_char(tty,
- readb(base_addr + (CyRDSR <<
- index)), TTY_FRAME);
+ cyy_readb(info, CyRDSR),
+ TTY_FRAME);
info->icount.rx++;
info->idle_stats.frame_errs++;
} else if (data & CyPARITY) {
/* Pieces of seven... */
tty_insert_flip_char(tty,
- readb(base_addr + (CyRDSR <<
- index)), TTY_PARITY);
+ cyy_readb(info, CyRDSR),
+ TTY_PARITY);
info->icount.rx++;
info->idle_stats.parity_errs++;
} else if (data & CyOVERRUN) {
@@ -1074,8 +523,8 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
the next incoming character.
*/
tty_insert_flip_char(tty,
- readb(base_addr + (CyRDSR <<
- index)), TTY_FRAME);
+ cyy_readb(info, CyRDSR),
+ TTY_FRAME);
info->icount.rx++;
info->idle_stats.overruns++;
/* These two conditions may imply */
@@ -1099,7 +548,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
}
} else { /* normal character reception */
/* load # chars available from the chip */
- char_count = readb(base_addr + (CyRDCR << index));
+ char_count = cyy_readb(info, CyRDCR);
#ifdef CY_ENABLE_MONITORING
++info->mon.int_count;
@@ -1110,7 +559,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
#endif
len = tty_buffer_request_room(tty, char_count);
while (len--) {
- data = readb(base_addr + (CyRDSR << index));
+ data = cyy_readb(info, CyRDSR);
tty_insert_flip_char(tty, data, TTY_NORMAL);
info->idle_stats.recv_bytes++;
info->icount.rx++;
@@ -1121,16 +570,18 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
info->idle_stats.recv_idle = jiffies;
}
tty_schedule_flip(tty);
+ tty_kref_put(tty);
end:
/* end of service */
- cy_writeb(base_addr + (CyRIR << index), save_xir & 0x3f);
- cy_writeb(base_addr + (CyCAR << index), save_car);
+ cyy_writeb(info, CyRIR, save_xir & 0x3f);
+ cyy_writeb(info, CyCAR, save_car);
}
static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
void __iomem *base_addr)
{
struct cyclades_port *info;
+ struct tty_struct *tty;
int char_count, index = cinfo->bus_index;
u8 save_xir, channel, save_car, outch;
@@ -1154,9 +605,9 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
goto end;
}
info = &cinfo->ports[channel + chip * 4];
- if (info->port.tty == NULL) {
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) & ~CyTxRdy);
+ tty = tty_port_tty_get(&info->port);
+ if (tty == NULL) {
+ cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
goto end;
}
@@ -1165,7 +616,7 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
if (info->x_char) { /* send special char */
outch = info->x_char;
- cy_writeb(base_addr + (CyTDR << index), outch);
+ cyy_writeb(info, CyTDR, outch);
char_count--;
info->icount.tx++;
info->x_char = 0;
@@ -1173,14 +624,14 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
if (info->breakon || info->breakoff) {
if (info->breakon) {
- cy_writeb(base_addr + (CyTDR << index), 0);
- cy_writeb(base_addr + (CyTDR << index), 0x81);
+ cyy_writeb(info, CyTDR, 0);
+ cyy_writeb(info, CyTDR, 0x81);
info->breakon = 0;
char_count -= 2;
}
if (info->breakoff) {
- cy_writeb(base_addr + (CyTDR << index), 0);
- cy_writeb(base_addr + (CyTDR << index), 0x83);
+ cyy_writeb(info, CyTDR, 0);
+ cyy_writeb(info, CyTDR, 0x83);
info->breakoff = 0;
char_count -= 2;
}
@@ -1188,27 +639,23 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
while (char_count-- > 0) {
if (!info->xmit_cnt) {
- if (readb(base_addr + (CySRER << index)) & CyTxMpty) {
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) &
- ~CyTxMpty);
+ if (cyy_readb(info, CySRER) & CyTxMpty) {
+ cyy_writeb(info, CySRER,
+ cyy_readb(info, CySRER) & ~CyTxMpty);
} else {
- cy_writeb(base_addr + (CySRER << index),
- (readb(base_addr + (CySRER << index)) &
- ~CyTxRdy) | CyTxMpty);
+ cyy_writeb(info, CySRER, CyTxMpty |
+ (cyy_readb(info, CySRER) & ~CyTxRdy));
}
goto done;
}
if (info->port.xmit_buf == NULL) {
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) &
- ~CyTxRdy);
+ cyy_writeb(info, CySRER,
+ cyy_readb(info, CySRER) & ~CyTxRdy);
goto done;
}
- if (info->port.tty->stopped || info->port.tty->hw_stopped) {
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) &
- ~CyTxRdy);
+ if (tty->stopped || tty->hw_stopped) {
+ cyy_writeb(info, CySRER,
+ cyy_readb(info, CySRER) & ~CyTxRdy);
goto done;
}
/* Because the Embedded Transmit Commands have been enabled,
@@ -1225,15 +672,15 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
info->xmit_cnt--;
info->xmit_tail = (info->xmit_tail + 1) &
(SERIAL_XMIT_SIZE - 1);
- cy_writeb(base_addr + (CyTDR << index), outch);
+ cyy_writeb(info, CyTDR, outch);
info->icount.tx++;
} else {
if (char_count > 1) {
info->xmit_cnt--;
info->xmit_tail = (info->xmit_tail + 1) &
(SERIAL_XMIT_SIZE - 1);
- cy_writeb(base_addr + (CyTDR << index), outch);
- cy_writeb(base_addr + (CyTDR << index), 0);
+ cyy_writeb(info, CyTDR, outch);
+ cyy_writeb(info, CyTDR, 0);
info->icount.tx++;
char_count--;
}
@@ -1241,17 +688,19 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
}
done:
- tty_wakeup(info->port.tty);
+ tty_wakeup(tty);
+ tty_kref_put(tty);
end:
/* end of service */
- cy_writeb(base_addr + (CyTIR << index), save_xir & 0x3f);
- cy_writeb(base_addr + (CyCAR << index), save_car);
+ cyy_writeb(info, CyTIR, save_xir & 0x3f);
+ cyy_writeb(info, CyCAR, save_car);
}
static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
void __iomem *base_addr)
{
struct cyclades_port *info;
+ struct tty_struct *tty;
int index = cinfo->bus_index;
u8 save_xir, channel, save_car, mdm_change, mdm_status;
@@ -1259,13 +708,14 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
save_xir = readb(base_addr + (CyMIR << index));
channel = save_xir & CyIRChannel;
info = &cinfo->ports[channel + chip * 4];
- save_car = readb(base_addr + (CyCAR << index));
- cy_writeb(base_addr + (CyCAR << index), save_xir);
+ save_car = cyy_readb(info, CyCAR);
+ cyy_writeb(info, CyCAR, save_xir);
- mdm_change = readb(base_addr + (CyMISR << index));
- mdm_status = readb(base_addr + (CyMSVR1 << index));
+ mdm_change = cyy_readb(info, CyMISR);
+ mdm_status = cyy_readb(info, CyMSVR1);
- if (!info->port.tty)
+ tty = tty_port_tty_get(&info->port);
+ if (!tty)
goto end;
if (mdm_change & CyANY_DELTA) {
@@ -1279,35 +729,32 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
if (mdm_change & CyRI)
info->icount.rng++;
- wake_up_interruptible(&info->delta_msr_wait);
+ wake_up_interruptible(&info->port.delta_msr_wait);
}
if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) {
- if (!(mdm_status & CyDCD)) {
- tty_hangup(info->port.tty);
- info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
- }
- wake_up_interruptible(&info->port.open_wait);
+ if (mdm_status & CyDCD)
+ wake_up_interruptible(&info->port.open_wait);
+ else
+ tty_hangup(tty);
}
if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) {
- if (info->port.tty->hw_stopped) {
+ if (tty->hw_stopped) {
if (mdm_status & CyCTS) {
/* cy_start isn't used
because... !!! */
- info->port.tty->hw_stopped = 0;
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) |
- CyTxRdy);
- tty_wakeup(info->port.tty);
+ tty->hw_stopped = 0;
+ cyy_writeb(info, CySRER,
+ cyy_readb(info, CySRER) | CyTxRdy);
+ tty_wakeup(tty);
}
} else {
if (!(mdm_status & CyCTS)) {
/* cy_stop isn't used
because ... !!! */
- info->port.tty->hw_stopped = 1;
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) &
- ~CyTxRdy);
+ tty->hw_stopped = 1;
+ cyy_writeb(info, CySRER,
+ cyy_readb(info, CySRER) & ~CyTxRdy);
}
}
}
@@ -1315,10 +762,11 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
}
if (mdm_change & CyRI) {
}*/
+ tty_kref_put(tty);
end:
/* end of service */
- cy_writeb(base_addr + (CyMIR << index), save_xir & 0x3f);
- cy_writeb(base_addr + (CyCAR << index), save_car);
+ cyy_writeb(info, CyMIR, save_xir & 0x3f);
+ cyy_writeb(info, CyCAR, save_car);
}
/* The real interrupt service routine is called
@@ -1389,6 +837,56 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
} /* cyy_interrupt */
+static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set,
+ unsigned int clear)
+{
+ struct cyclades_card *card = info->card;
+ int channel = info->line - card->first_line;
+ u32 rts, dtr, msvrr, msvrd;
+
+ channel &= 0x03;
+
+ if (info->rtsdtr_inv) {
+ msvrr = CyMSVR2;
+ msvrd = CyMSVR1;
+ rts = CyDTR;
+ dtr = CyRTS;
+ } else {
+ msvrr = CyMSVR1;
+ msvrd = CyMSVR2;
+ rts = CyRTS;
+ dtr = CyDTR;
+ }
+ if (set & TIOCM_RTS) {
+ cyy_writeb(info, CyCAR, channel);
+ cyy_writeb(info, msvrr, rts);
+ }
+ if (clear & TIOCM_RTS) {
+ cyy_writeb(info, CyCAR, channel);
+ cyy_writeb(info, msvrr, ~rts);
+ }
+ if (set & TIOCM_DTR) {
+ cyy_writeb(info, CyCAR, channel);
+ cyy_writeb(info, msvrd, dtr);
+#ifdef CY_DEBUG_DTR
+ printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ cyy_readb(info, CyMSVR1),
+ cyy_readb(info, CyMSVR2));
+#endif
+ }
+ if (clear & TIOCM_DTR) {
+ cyy_writeb(info, CyCAR, channel);
+ cyy_writeb(info, msvrd, ~dtr);
+#ifdef CY_DEBUG_DTR
+ printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ cyy_readb(info, CyMSVR1),
+ cyy_readb(info, CyMSVR2));
+#endif
+ }
+}
+
/***********************************************************/
/********* End of block of Cyclom-Y specific code **********/
/******** Start of block of Cyclades-Z specific code *******/
@@ -1398,15 +896,9 @@ static int
cyz_fetch_msg(struct cyclades_card *cinfo,
__u32 *channel, __u8 *cmd, __u32 *param)
{
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
unsigned long loc_doorbell;
- firm_id = cinfo->base_addr + ID_ADDRESS;
- zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
-
loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
if (loc_doorbell) {
*cmd = (char)(0xff & loc_doorbell);
@@ -1422,19 +914,13 @@ static int
cyz_issue_cmd(struct cyclades_card *cinfo,
__u32 channel, __u8 cmd, __u32 param)
{
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
__u32 __iomem *pci_doorbell;
unsigned int index;
- firm_id = cinfo->base_addr + ID_ADDRESS;
if (!cyz_is_loaded(cinfo))
return -1;
- zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
-
index = 0;
pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
while ((readl(pci_doorbell) & 0xff) != 0) {
@@ -1449,11 +935,10 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
return 0;
} /* cyz_issue_cmd */
-static void cyz_handle_rx(struct cyclades_port *info,
- struct BUF_CTRL __iomem *buf_ctrl)
+static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
{
+ struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
struct cyclades_card *cinfo = info->card;
- struct tty_struct *tty = info->port.tty;
unsigned int char_count;
int len;
#ifdef BLOCKMOVE
@@ -1542,11 +1027,10 @@ static void cyz_handle_rx(struct cyclades_port *info,
}
}
-static void cyz_handle_tx(struct cyclades_port *info,
- struct BUF_CTRL __iomem *buf_ctrl)
+static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
{
+ struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
struct cyclades_card *cinfo = info->card;
- struct tty_struct *tty = info->port.tty;
u8 data;
unsigned int char_count;
#ifdef BLOCKMOVE
@@ -1621,34 +1105,24 @@ ztxdone:
static void cyz_handle_cmd(struct cyclades_card *cinfo)
{
+ struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
struct tty_struct *tty;
struct cyclades_port *info;
- static struct FIRM_ID __iomem *firm_id;
- static struct ZFW_CTRL __iomem *zfw_ctrl;
- static struct BOARD_CTRL __iomem *board_ctrl;
- static struct CH_CTRL __iomem *ch_ctrl;
- static struct BUF_CTRL __iomem *buf_ctrl;
__u32 channel, param, fw_ver;
__u8 cmd;
int special_count;
int delta_count;
- firm_id = cinfo->base_addr + ID_ADDRESS;
- zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
fw_ver = readl(&board_ctrl->fw_version);
while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
special_count = 0;
delta_count = 0;
info = &cinfo->ports[channel];
- tty = info->port.tty;
+ tty = tty_port_tty_get(&info->port);
if (tty == NULL)
continue;
- ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
- buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
-
switch (cmd) {
case C_CM_PR_ERROR:
tty_insert_flip_char(tty, 0, TTY_PARITY);
@@ -1669,15 +1143,12 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
info->icount.dcd++;
delta_count++;
if (info->port.flags & ASYNC_CHECK_CD) {
- if ((fw_ver > 241 ? ((u_long) param) :
- readl(&ch_ctrl->rs_status)) &
- C_RS_DCD) {
+ u32 dcd = fw_ver > 241 ? param :
+ readl(&info->u.cyz.ch_ctrl->rs_status);
+ if (dcd & C_RS_DCD)
wake_up_interruptible(&info->port.open_wait);
- } else {
- tty_hangup(info->port.tty);
- wake_up_interruptible(&info->port.open_wait);
- info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
- }
+ else
+ tty_hangup(tty);
}
break;
case C_CM_MCTS:
@@ -1706,7 +1177,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
"port %ld\n", info->card, channel);
#endif
- cyz_handle_rx(info, buf_ctrl);
+ cyz_handle_rx(info, tty);
break;
case C_CM_TXBEMPTY:
case C_CM_TXLOWWM:
@@ -1716,7 +1187,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
"port %ld\n", info->card, channel);
#endif
- cyz_handle_tx(info, buf_ctrl);
+ cyz_handle_tx(info, tty);
break;
#endif /* CONFIG_CYZ_INTR */
case C_CM_FATAL:
@@ -1726,9 +1197,10 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
break;
}
if (delta_count)
- wake_up_interruptible(&info->delta_msr_wait);
+ wake_up_interruptible(&info->port.delta_msr_wait);
if (special_count)
tty_schedule_flip(tty);
+ tty_kref_put(tty);
}
}
@@ -1774,10 +1246,6 @@ static void cyz_poll(unsigned long arg)
{
struct cyclades_card *cinfo;
struct cyclades_port *info;
- struct tty_struct *tty;
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BUF_CTRL __iomem *buf_ctrl;
unsigned long expires = jiffies + HZ;
unsigned int port, card;
@@ -1789,10 +1257,6 @@ static void cyz_poll(unsigned long arg)
if (!cyz_is_loaded(cinfo))
continue;
- firm_id = cinfo->base_addr + ID_ADDRESS;
- zfw_ctrl = cinfo->base_addr +
- (readl(&firm_id->zfwctrl_addr) & 0xfffff);
-
/* Skip first polling cycle to avoid racing conditions with the FW */
if (!cinfo->intr_enabled) {
cinfo->intr_enabled = 1;
@@ -1802,13 +1266,17 @@ static void cyz_poll(unsigned long arg)
cyz_handle_cmd(cinfo);
for (port = 0; port < cinfo->nports; port++) {
+ struct tty_struct *tty;
+
info = &cinfo->ports[port];
- tty = info->port.tty;
- buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
+ tty = tty_port_tty_get(&info->port);
+ /* OK to pass NULL to the handle functions below.
+ They need to drop the data in that case. */
if (!info->throttle)
- cyz_handle_rx(info, buf_ctrl);
- cyz_handle_tx(info, buf_ctrl);
+ cyz_handle_rx(info, tty);
+ cyz_handle_tx(info, tty);
+ tty_kref_put(tty);
}
/* poll every 'cyz_polling_cycle' period */
expires = jiffies + cyz_polling_cycle;
@@ -1824,13 +1292,12 @@ static void cyz_poll(unsigned long arg)
/* This is called whenever a port becomes active;
interrupts are enabled and DTR & RTS are turned on.
*/
-static int startup(struct cyclades_port *info)
+static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
{
struct cyclades_card *card;
unsigned long flags;
int retval = 0;
- void __iomem *base_addr;
- int chip, channel, index;
+ int channel;
unsigned long page;
card = info->card;
@@ -1842,15 +1309,11 @@ static int startup(struct cyclades_port *info)
spin_lock_irqsave(&card->card_lock, flags);
- if (info->port.flags & ASYNC_INITIALIZED) {
- free_page(page);
+ if (info->port.flags & ASYNC_INITIALIZED)
goto errout;
- }
if (!info->type) {
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
- free_page(page);
+ set_bit(TTY_IO_ERROR, &tty->flags);
goto errout;
}
@@ -1861,96 +1324,53 @@ static int startup(struct cyclades_port *info)
spin_unlock_irqrestore(&card->card_lock, flags);
- set_line_char(info);
+ cy_set_line_char(info, tty);
if (!cy_is_Z(card)) {
- chip = channel >> 2;
channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
-#ifdef CY_DEBUG_OPEN
- printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, "
- "base_addr %p\n",
- card, chip, channel, base_addr);
-#endif
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
+ cyy_writeb(info, CyCAR, channel);
- cy_writeb(base_addr + (CyRTPR << index),
+ cyy_writeb(info, CyRTPR,
(info->default_timeout ? info->default_timeout : 0x02));
/* 10ms rx timeout */
- cyy_issue_cmd(base_addr, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR,
- index);
-
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
- cy_writeb(base_addr + (CyMSVR1 << index), CyRTS);
- cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);
-
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:startup raising DTR\n");
- printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
- readb(base_addr + (CyMSVR1 << index)),
- readb(base_addr + (CyMSVR2 << index)));
-#endif
-
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) | CyRxData);
- info->port.flags |= ASYNC_INITIALIZED;
-
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- info->breakon = info->breakoff = 0;
- memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
- info->idle_stats.in_use =
- info->idle_stats.recv_idle =
- info->idle_stats.xmit_idle = jiffies;
+ cyy_issue_cmd(info, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR);
- spin_unlock_irqrestore(&card->card_lock, flags);
+ cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0);
+ cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData);
} else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
- base_addr = card->base_addr;
-
- firm_id = base_addr + ID_ADDRESS;
if (!cyz_is_loaded(card))
return -ENODEV;
- zfw_ctrl = card->base_addr +
- (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
-
#ifdef CY_DEBUG_OPEN
printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
- "base_addr %p\n", card, channel, base_addr);
+ "base_addr %p\n", card, channel, card->base_addr);
#endif
spin_lock_irqsave(&card->card_lock, flags);
- cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
+ cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
#ifdef Z_WAKE
#ifdef CONFIG_CYZ_INTR
- cy_writel(&ch_ctrl[channel].intr_enable,
+ cy_writel(&ch_ctrl->intr_enable,
C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
#else
- cy_writel(&ch_ctrl[channel].intr_enable,
+ cy_writel(&ch_ctrl->intr_enable,
C_IN_IOCTLW | C_IN_MDCD);
#endif /* CONFIG_CYZ_INTR */
#else
#ifdef CONFIG_CYZ_INTR
- cy_writel(&ch_ctrl[channel].intr_enable,
+ cy_writel(&ch_ctrl->intr_enable,
C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
C_IN_RXNNDT | C_IN_MDCD);
#else
- cy_writel(&ch_ctrl[channel].intr_enable, C_IN_MDCD);
+ cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
#endif /* CONFIG_CYZ_INTR */
#endif /* Z_WAKE */
@@ -1969,32 +1389,22 @@ static int startup(struct cyclades_port *info)
/* set timeout !!! */
/* set RTS and DTR !!! */
- cy_writel(&ch_ctrl[channel].rs_control,
- readl(&ch_ctrl[channel].rs_control) | C_RS_RTS |
- C_RS_DTR);
- retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
- if (retval != 0) {
- printk(KERN_ERR "cyc:startup(3) retval on ttyC%d was "
- "%x\n", info->line, retval);
- }
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:startup raising Z DTR\n");
-#endif
+ tty_port_raise_dtr_rts(&info->port);
/* enable send, recv, modem !!! */
+ }
- info->port.flags |= ASYNC_INITIALIZED;
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- info->breakon = info->breakoff = 0;
- memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
- info->idle_stats.in_use =
- info->idle_stats.recv_idle =
- info->idle_stats.xmit_idle = jiffies;
+ info->port.flags |= ASYNC_INITIALIZED;
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
+ clear_bit(TTY_IO_ERROR, &tty->flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ info->breakon = info->breakoff = 0;
+ memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
+ info->idle_stats.in_use =
+ info->idle_stats.recv_idle =
+ info->idle_stats.xmit_idle = jiffies;
+
+ spin_unlock_irqrestore(&card->card_lock, flags);
#ifdef CY_DEBUG_OPEN
printk(KERN_DEBUG "cyc startup done\n");
@@ -2003,28 +1413,20 @@ static int startup(struct cyclades_port *info)
errout:
spin_unlock_irqrestore(&card->card_lock, flags);
+ free_page(page);
return retval;
} /* startup */
static void start_xmit(struct cyclades_port *info)
{
- struct cyclades_card *card;
+ struct cyclades_card *card = info->card;
unsigned long flags;
- void __iomem *base_addr;
- int chip, channel, index;
+ int channel = info->line - card->first_line;
- card = info->card;
- channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
-
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index), channel);
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) | CyTxRdy);
+ cyy_writeb(info, CyCAR, channel & 0x03);
+ cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
#ifdef CONFIG_CYZ_INTR
@@ -2047,12 +1449,11 @@ static void start_xmit(struct cyclades_port *info)
* This routine shuts down a serial port; interrupts are disabled,
* and DTR is dropped if the hangup on close termio flag is on.
*/
-static void shutdown(struct cyclades_port *info)
+static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
{
struct cyclades_card *card;
unsigned long flags;
- void __iomem *base_addr;
- int chip, channel, index;
+ int channel;
if (!(info->port.flags & ASYNC_INITIALIZED))
return;
@@ -2060,21 +1461,10 @@ static void shutdown(struct cyclades_port *info)
card = info->card;
channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
-
-#ifdef CY_DEBUG_OPEN
- printk(KERN_DEBUG "cyc shutdown Y card %d, chip %d, "
- "channel %d, base_addr %p\n",
- card, chip, channel, base_addr);
-#endif
-
spin_lock_irqsave(&card->card_lock, flags);
/* Clear delta_msr_wait queue to avoid mem leaks. */
- wake_up_interruptible(&info->delta_msr_wait);
+ wake_up_interruptible(&info->port.delta_msr_wait);
if (info->port.xmit_buf) {
unsigned char *temp;
@@ -2082,47 +1472,25 @@ static void shutdown(struct cyclades_port *info)
info->port.xmit_buf = NULL;
free_page((unsigned long)temp);
}
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
- if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
- cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS);
- cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR);
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc shutdown dropping DTR\n");
- printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
- readb(base_addr + (CyMSVR1 << index)),
- readb(base_addr + (CyMSVR2 << index)));
-#endif
- }
- cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index);
+ if (tty->termios->c_cflag & HUPCL)
+ cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
+
+ cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
/* it may be appropriate to clear _XMIT at
some later date (after testing)!!! */
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+ set_bit(TTY_IO_ERROR, &tty->flags);
info->port.flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
- int retval;
-
- base_addr = card->base_addr;
#ifdef CY_DEBUG_OPEN
printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
- "base_addr %p\n", card, channel, base_addr);
+ "base_addr %p\n", card, channel, card->base_addr);
#endif
- firm_id = base_addr + ID_ADDRESS;
if (!cyz_is_loaded(card))
return;
- zfw_ctrl = card->base_addr +
- (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
-
spin_lock_irqsave(&card->card_lock, flags);
if (info->port.xmit_buf) {
@@ -2132,23 +1500,10 @@ static void shutdown(struct cyclades_port *info)
free_page((unsigned long)temp);
}
- if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
- cy_writel(&ch_ctrl[channel].rs_control,
- (__u32)(readl(&ch_ctrl[channel].rs_control) &
- ~(C_RS_RTS | C_RS_DTR)));
- retval = cyz_issue_cmd(info->card, channel,
- C_CM_IOCTLM, 0L);
- if (retval != 0) {
- printk(KERN_ERR"cyc:shutdown retval on ttyC%d "
- "was %x\n", info->line, retval);
- }
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:shutdown dropping Z DTR\n");
-#endif
- }
+ if (tty->termios->c_cflag & HUPCL)
+ tty_port_lower_dtr_rts(&info->port);
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+ set_bit(TTY_IO_ERROR, &tty->flags);
info->port.flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&card->card_lock, flags);
@@ -2165,199 +1520,6 @@ static void shutdown(struct cyclades_port *info)
* ------------------------------------------------------------
*/
-static int
-block_til_ready(struct tty_struct *tty, struct file *filp,
- struct cyclades_port *info)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct cyclades_card *cinfo;
- unsigned long flags;
- int chip, channel, index;
- int retval;
- void __iomem *base_addr;
-
- cinfo = info->card;
- channel = info->line - cinfo->first_line;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
- wait_event_interruptible(info->port.close_wait,
- !(info->port.flags & ASYNC_CLOSING));
- return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
- }
-
- /*
- * If non-blocking mode is set, then make the check up front
- * and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- info->port.flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->port.count is dropped by one, so that
- * cy_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->port.open_wait, &wait);
-#ifdef CY_DEBUG_OPEN
- printk(KERN_DEBUG "cyc block_til_ready before block: ttyC%d, "
- "count = %d\n", info->line, info->port.count);
-#endif
- spin_lock_irqsave(&cinfo->card_lock, flags);
- if (!tty_hung_up_p(filp))
- info->port.count--;
- spin_unlock_irqrestore(&cinfo->card_lock, flags);
-#ifdef CY_DEBUG_COUNT
- printk(KERN_DEBUG "cyc block_til_ready: (%d): decrementing count to "
- "%d\n", current->pid, info->port.count);
-#endif
- info->port.blocked_open++;
-
- if (!cy_is_Z(cinfo)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = cinfo->bus_index;
- base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
-
- while (1) {
- spin_lock_irqsave(&cinfo->card_lock, flags);
- if ((tty->termios->c_cflag & CBAUD)) {
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- cy_writeb(base_addr + (CyMSVR1 << index),
- CyRTS);
- cy_writeb(base_addr + (CyMSVR2 << index),
- CyDTR);
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:block_til_ready raising "
- "DTR\n");
- printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
- readb(base_addr + (CyMSVR1 << index)),
- readb(base_addr + (CyMSVR2 << index)));
-#endif
- }
- spin_unlock_irqrestore(&cinfo->card_lock, flags);
-
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(info->port.flags & ASYNC_INITIALIZED)) {
- retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
- break;
- }
-
- spin_lock_irqsave(&cinfo->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- if (!(info->port.flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
- (readb(base_addr +
- (CyMSVR1 << index)) & CyDCD))) {
- spin_unlock_irqrestore(&cinfo->card_lock, flags);
- break;
- }
- spin_unlock_irqrestore(&cinfo->card_lock, flags);
-
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-#ifdef CY_DEBUG_OPEN
- printk(KERN_DEBUG "cyc block_til_ready blocking: "
- "ttyC%d, count = %d\n",
- info->line, info->port.count);
-#endif
- schedule();
- }
- } else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
-
- base_addr = cinfo->base_addr;
- firm_id = base_addr + ID_ADDRESS;
- if (!cyz_is_loaded(cinfo)) {
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&info->port.open_wait, &wait);
- return -EINVAL;
- }
-
- zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr)
- & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
-
- while (1) {
- if ((tty->termios->c_cflag & CBAUD)) {
- cy_writel(&ch_ctrl[channel].rs_control,
- readl(&ch_ctrl[channel].rs_control) |
- C_RS_RTS | C_RS_DTR);
- retval = cyz_issue_cmd(cinfo,
- channel, C_CM_IOCTLM, 0L);
- if (retval != 0) {
- printk(KERN_ERR "cyc:block_til_ready "
- "retval on ttyC%d was %x\n",
- info->line, retval);
- }
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:block_til_ready raising "
- "Z DTR\n");
-#endif
- }
-
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(info->port.flags & ASYNC_INITIALIZED)) {
- retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
- break;
- }
- if (!(info->port.flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
- (readl(&ch_ctrl[channel].rs_status) &
- C_RS_DCD))) {
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-#ifdef CY_DEBUG_OPEN
- printk(KERN_DEBUG "cyc block_til_ready blocking: "
- "ttyC%d, count = %d\n",
- info->line, info->port.count);
-#endif
- schedule();
- }
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&info->port.open_wait, &wait);
- if (!tty_hung_up_p(filp)) {
- info->port.count++;
-#ifdef CY_DEBUG_COUNT
- printk(KERN_DEBUG "cyc:block_til_ready (%d): incrementing "
- "count to %d\n", current->pid, info->port.count);
-#endif
- }
- info->port.blocked_open--;
-#ifdef CY_DEBUG_OPEN
- printk(KERN_DEBUG "cyc:block_til_ready after blocking: ttyC%d, "
- "count = %d\n", info->line, info->port.count);
-#endif
- if (retval)
- return retval;
- info->port.flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-} /* block_til_ready */
-
/*
* This routine is called whenever a serial port is opened. It
* performs the serial-specific initialization for the tty structure.
@@ -2436,7 +1598,6 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
#endif
tty->driver_data = info;
- info->port.tty = tty;
if (serial_paranoia_check(info, tty->name, "cy_open"))
return -ENODEV;
@@ -2462,11 +1623,11 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
/*
* Start up serial port
*/
- retval = startup(info);
+ retval = cy_startup(info, tty);
if (retval)
return retval;
- retval = block_til_ready(tty, filp, info);
+ retval = tty_port_block_til_ready(&info->port, tty, filp);
if (retval) {
#ifdef CY_DEBUG_OPEN
printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
@@ -2476,6 +1637,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
}
info->throttle = 0;
+ tty_port_tty_set(&info->port, tty);
#ifdef CY_DEBUG_OPEN
printk(KERN_DEBUG "cyc:cy_open done\n");
@@ -2490,8 +1652,6 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
{
struct cyclades_card *card;
struct cyclades_port *info = tty->driver_data;
- void __iomem *base_addr;
- int chip, channel, index;
unsigned long orig_jiffies;
int char_time;
@@ -2535,13 +1695,8 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
timeout, char_time, jiffies);
#endif
card = info->card;
- channel = (info->line) - (card->first_line);
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- while (readb(base_addr + (CySRER << index)) & CyTxRdy) {
+ while (cyy_readb(info, CySRER) & CyTxRdy) {
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies);
#endif
@@ -2595,103 +1750,37 @@ static void cy_flush_buffer(struct tty_struct *tty)
} /* cy_flush_buffer */
-/*
- * This routine is called when a particular tty device is closed.
- */
-static void cy_close(struct tty_struct *tty, struct file *filp)
+static void cy_do_close(struct tty_port *port)
{
- struct cyclades_port *info = tty->driver_data;
+ struct cyclades_port *info = container_of(port, struct cyclades_port,
+ port);
struct cyclades_card *card;
unsigned long flags;
-
-#ifdef CY_DEBUG_OTHER
- printk(KERN_DEBUG "cyc:cy_close ttyC%d\n", info->line);
-#endif
-
- if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
- return;
+ int channel;
card = info->card;
-
- spin_lock_irqsave(&card->card_lock, flags);
- /* If the TTY is being hung up, nothing to do */
- if (tty_hung_up_p(filp)) {
- spin_unlock_irqrestore(&card->card_lock, flags);
- return;
- }
-#ifdef CY_DEBUG_OPEN
- printk(KERN_DEBUG "cyc:cy_close ttyC%d, count = %d\n", info->line,
- info->port.count);
-#endif
- if ((tty->count == 1) && (info->port.count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk(KERN_ERR "cyc:cy_close: bad serial port count; "
- "tty->count is 1, info->port.count is %d\n", info->port.count);
- info->port.count = 1;
- }
-#ifdef CY_DEBUG_COUNT
- printk(KERN_DEBUG "cyc:cy_close at (%d): decrementing count to %d\n",
- current->pid, info->port.count - 1);
-#endif
- if (--info->port.count < 0) {
-#ifdef CY_DEBUG_COUNT
- printk(KERN_DEBUG "cyc:cyc_close setting count to 0\n");
-#endif
- info->port.count = 0;
- }
- if (info->port.count) {
- spin_unlock_irqrestore(&card->card_lock, flags);
- return;
- }
- info->port.flags |= ASYNC_CLOSING;
-
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- spin_unlock_irqrestore(&card->card_lock, flags);
- if (info->port.closing_wait != CY_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, info->port.closing_wait);
-
+ channel = info->line - card->first_line;
spin_lock_irqsave(&card->card_lock, flags);
if (!cy_is_Z(card)) {
- int channel = info->line - card->first_line;
- int index = card->bus_index;
- void __iomem *base_addr = card->base_addr +
- (cy_chip_offset[channel >> 2] << index);
/* Stop accepting input */
- channel &= 0x03;
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) & ~CyRxData);
+ cyy_writeb(info, CyCAR, channel & 0x03);
+ cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
if (info->port.flags & ASYNC_INITIALIZED) {
/* Waiting for on-board buffers to be empty before
closing the port */
spin_unlock_irqrestore(&card->card_lock, flags);
- cy_wait_until_sent(tty, info->timeout);
+ cy_wait_until_sent(port->tty, info->timeout);
spin_lock_irqsave(&card->card_lock, flags);
}
} else {
#ifdef Z_WAKE
/* Waiting for on-board buffers to be empty before closing
the port */
- void __iomem *base_addr = card->base_addr;
- struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS;
- struct ZFW_CTRL __iomem *zfw_ctrl =
- base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl;
- int channel = info->line - card->first_line;
+ struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
int retval;
- if (readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
+ if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
if (retval != 0) {
printk(KERN_DEBUG "cyc:cy_close retval on "
@@ -2703,32 +1792,19 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
}
#endif
}
-
spin_unlock_irqrestore(&card->card_lock, flags);
- shutdown(info);
- cy_flush_buffer(tty);
- tty_ldisc_flush(tty);
- spin_lock_irqsave(&card->card_lock, flags);
-
- tty->closing = 0;
- info->port.tty = NULL;
- if (info->port.blocked_open) {
- spin_unlock_irqrestore(&card->card_lock, flags);
- if (info->port.close_delay) {
- msleep_interruptible(jiffies_to_msecs
- (info->port.close_delay));
- }
- wake_up_interruptible(&info->port.open_wait);
- spin_lock_irqsave(&card->card_lock, flags);
- }
- info->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
- wake_up_interruptible(&info->port.close_wait);
-
-#ifdef CY_DEBUG_OTHER
- printk(KERN_DEBUG "cyc:cy_close done\n");
-#endif
+ cy_shutdown(info, port->tty);
+}
- spin_unlock_irqrestore(&card->card_lock, flags);
+/*
+ * This routine is called when a particular tty device is closed.
+ */
+static void cy_close(struct tty_struct *tty, struct file *filp)
+{
+ struct cyclades_port *info = tty->driver_data;
+ if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
+ return;
+ tty_port_close(&info->port, tty, filp);
} /* cy_close */
/* This routine gets called when tty_write has put something into
@@ -2871,18 +1947,13 @@ static int cy_write_room(struct tty_struct *tty)
static int cy_chars_in_buffer(struct tty_struct *tty)
{
- struct cyclades_card *card;
struct cyclades_port *info = tty->driver_data;
- int channel;
if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
return 0;
- card = info->card;
- channel = (info->line) - (card->first_line);
-
#ifdef Z_EXT_CHARS_IN_BUFFER
- if (!cy_is_Z(card)) {
+ if (!cy_is_Z(info->card)) {
#endif /* Z_EXT_CHARS_IN_BUFFER */
#ifdef CY_DEBUG_IO
printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
@@ -2891,20 +1962,11 @@ static int cy_chars_in_buffer(struct tty_struct *tty)
return info->xmit_cnt;
#ifdef Z_EXT_CHARS_IN_BUFFER
} else {
- static struct FIRM_ID *firm_id;
- static struct ZFW_CTRL *zfw_ctrl;
- static struct CH_CTRL *ch_ctrl;
- static struct BUF_CTRL *buf_ctrl;
+ struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
int char_count;
__u32 tx_put, tx_get, tx_bufsize;
lock_kernel();
- firm_id = card->base_addr + ID_ADDRESS;
- zfw_ctrl = card->base_addr +
- (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
- buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
-
tx_get = readl(&buf_ctrl->tx_get);
tx_put = readl(&buf_ctrl->tx_put);
tx_bufsize = readl(&buf_ctrl->tx_bufsize);
@@ -2957,48 +2019,44 @@ static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
* This routine finds or computes the various line characteristics.
* It used to be called config_setup
*/
-static void set_line_char(struct cyclades_port *info)
+static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
{
struct cyclades_card *card;
unsigned long flags;
- void __iomem *base_addr;
- int chip, channel, index;
+ int channel;
unsigned cflag, iflag;
int baud, baud_rate = 0;
int i;
- if (!info->port.tty || !info->port.tty->termios)
+ if (!tty->termios) /* XXX can this happen at all? */
return;
if (info->line == -1)
return;
- cflag = info->port.tty->termios->c_cflag;
- iflag = info->port.tty->termios->c_iflag;
+ cflag = tty->termios->c_cflag;
+ iflag = tty->termios->c_iflag;
/*
* Set up the tty->alt_speed kludge
*/
- if (info->port.tty) {
- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- info->port.tty->alt_speed = 57600;
- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- info->port.tty->alt_speed = 115200;
- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
- info->port.tty->alt_speed = 230400;
- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
- info->port.tty->alt_speed = 460800;
- }
+ if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ tty->alt_speed = 57600;
+ if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ tty->alt_speed = 115200;
+ if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ tty->alt_speed = 230400;
+ if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ tty->alt_speed = 460800;
card = info->card;
channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
-
- index = card->bus_index;
+ u32 cflags;
/* baud rate */
- baud = tty_get_baud_rate(info->port.tty);
+ baud = tty_get_baud_rate(tty);
if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
ASYNC_SPD_CUST) {
if (info->custom_divisor)
@@ -3107,124 +2165,68 @@ static void set_line_char(struct cyclades_port *info)
cable. Contact Marcio Saito for details.
***********************************************/
- chip = channel >> 2;
channel &= 0x03;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
+ cyy_writeb(info, CyCAR, channel);
/* tx and rx baud rate */
- cy_writeb(base_addr + (CyTCOR << index), info->tco);
- cy_writeb(base_addr + (CyTBPR << index), info->tbpr);
- cy_writeb(base_addr + (CyRCOR << index), info->rco);
- cy_writeb(base_addr + (CyRBPR << index), info->rbpr);
+ cyy_writeb(info, CyTCOR, info->tco);
+ cyy_writeb(info, CyTBPR, info->tbpr);
+ cyy_writeb(info, CyRCOR, info->rco);
+ cyy_writeb(info, CyRBPR, info->rbpr);
/* set line characteristics according configuration */
- cy_writeb(base_addr + (CySCHR1 << index),
- START_CHAR(info->port.tty));
- cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(info->port.tty));
- cy_writeb(base_addr + (CyCOR1 << index), info->cor1);
- cy_writeb(base_addr + (CyCOR2 << index), info->cor2);
- cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
- cy_writeb(base_addr + (CyCOR4 << index), info->cor4);
- cy_writeb(base_addr + (CyCOR5 << index), info->cor5);
+ cyy_writeb(info, CySCHR1, START_CHAR(tty));
+ cyy_writeb(info, CySCHR2, STOP_CHAR(tty));
+ cyy_writeb(info, CyCOR1, info->cor1);
+ cyy_writeb(info, CyCOR2, info->cor2);
+ cyy_writeb(info, CyCOR3, info->cor3);
+ cyy_writeb(info, CyCOR4, info->cor4);
+ cyy_writeb(info, CyCOR5, info->cor5);
- cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
- CyCOR3ch, index);
+ cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
+ CyCOR3ch);
/* !!! Is this needed? */
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
- cy_writeb(base_addr + (CyRTPR << index),
+ cyy_writeb(info, CyCAR, channel);
+ cyy_writeb(info, CyRTPR,
(info->default_timeout ? info->default_timeout : 0x02));
/* 10ms rx timeout */
- if (C_CLOCAL(info->port.tty)) {
- /* without modem intr */
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) | CyMdmCh);
- /* act on 1->0 modem transitions */
- if ((cflag & CRTSCTS) && info->rflow) {
- cy_writeb(base_addr + (CyMCOR1 << index),
- (CyCTS | rflow_thr[i]));
- } else {
- cy_writeb(base_addr + (CyMCOR1 << index),
- CyCTS);
- }
- /* act on 0->1 modem transitions */
- cy_writeb(base_addr + (CyMCOR2 << index), CyCTS);
- } else {
- /* without modem intr */
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr +
- (CySRER << index)) | CyMdmCh);
- /* act on 1->0 modem transitions */
- if ((cflag & CRTSCTS) && info->rflow) {
- cy_writeb(base_addr + (CyMCOR1 << index),
- (CyDSR | CyCTS | CyRI | CyDCD |
- rflow_thr[i]));
- } else {
- cy_writeb(base_addr + (CyMCOR1 << index),
- CyDSR | CyCTS | CyRI | CyDCD);
- }
- /* act on 0->1 modem transitions */
- cy_writeb(base_addr + (CyMCOR2 << index),
- CyDSR | CyCTS | CyRI | CyDCD);
- }
+ cflags = CyCTS;
+ if (!C_CLOCAL(tty))
+ cflags |= CyDSR | CyRI | CyDCD;
+ /* without modem intr */
+ cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh);
+ /* act on 1->0 modem transitions */
+ if ((cflag & CRTSCTS) && info->rflow)
+ cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]);
+ else
+ cyy_writeb(info, CyMCOR1, cflags);
+ /* act on 0->1 modem transitions */
+ cyy_writeb(info, CyMCOR2, cflags);
- if (i == 0) { /* baud rate is zero, turn off line */
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR1 << index),
- ~CyRTS);
- } else {
- cy_writeb(base_addr + (CyMSVR2 << index),
- ~CyDTR);
- }
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:set_line_char dropping DTR\n");
- printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
- readb(base_addr + (CyMSVR1 << index)),
- readb(base_addr + (CyMSVR2 << index)));
-#endif
- } else {
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR1 << index),
- CyRTS);
- } else {
- cy_writeb(base_addr + (CyMSVR2 << index),
- CyDTR);
- }
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:set_line_char raising DTR\n");
- printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
- readb(base_addr + (CyMSVR1 << index)),
- readb(base_addr + (CyMSVR2 << index)));
-#endif
- }
+ if (i == 0) /* baud rate is zero, turn off line */
+ cyy_change_rts_dtr(info, 0, TIOCM_DTR);
+ else
+ cyy_change_rts_dtr(info, TIOCM_DTR, 0);
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+ clear_bit(TTY_IO_ERROR, &tty->flags);
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
__u32 sw_flow;
int retval;
- firm_id = card->base_addr + ID_ADDRESS;
if (!cyz_is_loaded(card))
return;
- zfw_ctrl = card->base_addr +
- (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
-
/* baud rate */
- baud = tty_get_baud_rate(info->port.tty);
+ baud = tty_get_baud_rate(tty);
if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
ASYNC_SPD_CUST) {
if (info->custom_divisor)
@@ -3335,45 +2337,38 @@ static void set_line_char(struct cyclades_port *info)
"was %x\n", info->line, retval);
}
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+ clear_bit(TTY_IO_ERROR, &tty->flags);
}
} /* set_line_char */
-static int
-get_serial_info(struct cyclades_port *info,
+static int cy_get_serial_info(struct cyclades_port *info,
struct serial_struct __user *retinfo)
{
- struct serial_struct tmp;
struct cyclades_card *cinfo = info->card;
-
- if (!retinfo)
- return -EFAULT;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->line;
- tmp.port = (info->card - cy_card) * 0x100 + info->line -
- cinfo->first_line;
- tmp.irq = cinfo->irq;
- tmp.flags = info->port.flags;
- tmp.close_delay = info->port.close_delay;
- tmp.closing_wait = info->port.closing_wait;
- tmp.baud_base = info->baud;
- tmp.custom_divisor = info->custom_divisor;
- tmp.hub6 = 0; /*!!! */
+ struct serial_struct tmp = {
+ .type = info->type,
+ .line = info->line,
+ .port = (info->card - cy_card) * 0x100 + info->line -
+ cinfo->first_line,
+ .irq = cinfo->irq,
+ .flags = info->port.flags,
+ .close_delay = info->port.close_delay,
+ .closing_wait = info->port.closing_wait,
+ .baud_base = info->baud,
+ .custom_divisor = info->custom_divisor,
+ .hub6 = 0, /*!!! */
+ };
return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
-} /* get_serial_info */
+}
static int
-set_serial_info(struct cyclades_port *info,
+cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
- struct cyclades_port old_info;
if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
return -EFAULT;
- old_info = *info;
if (!capable(CAP_SYS_ADMIN)) {
if (new_serial.close_delay != info->port.close_delay ||
@@ -3403,10 +2398,10 @@ set_serial_info(struct cyclades_port *info,
check_and_exit:
if (info->port.flags & ASYNC_INITIALIZED) {
- set_line_char(info);
+ cy_set_line_char(info, tty);
return 0;
} else {
- return startup(info);
+ return cy_startup(info, tty);
}
} /* set_serial_info */
@@ -3422,24 +2417,14 @@ check_and_exit:
*/
static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
{
- struct cyclades_card *card;
- int chip, channel, index;
- unsigned char status;
+ struct cyclades_card *card = info->card;
unsigned int result;
unsigned long flags;
- void __iomem *base_addr;
+ u8 status;
- card = info->card;
- channel = (info->line) - (card->first_line);
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
-
spin_lock_irqsave(&card->card_lock, flags);
- status = readb(base_addr + (CySRER << index)) &
- (CyTxRdy | CyTxMpty);
+ status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
spin_unlock_irqrestore(&card->card_lock, flags);
result = (status ? 0 : TIOCSER_TEMT);
} else {
@@ -3453,34 +2438,23 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
{
struct cyclades_port *info = tty->driver_data;
struct cyclades_card *card;
- int chip, channel, index;
- void __iomem *base_addr;
- unsigned long flags;
- unsigned char status;
- unsigned long lstatus;
- unsigned int result;
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
+ int result;
if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
- lock_kernel();
-
card = info->card;
- channel = info->line - card->first_line;
+
+ lock_kernel();
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
+ unsigned long flags;
+ int channel = info->line - card->first_line;
+ u8 status;
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
- status = readb(base_addr + (CyMSVR1 << index));
- status |= readb(base_addr + (CyMSVR2 << index));
+ cyy_writeb(info, CyCAR, channel & 0x03);
+ status = cyy_readb(info, CyMSVR1);
+ status |= cyy_readb(info, CyMSVR2);
spin_unlock_irqrestore(&card->card_lock, flags);
if (info->rtsdtr_inv) {
@@ -3495,27 +2469,22 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
((status & CyDSR) ? TIOCM_DSR : 0) |
((status & CyCTS) ? TIOCM_CTS : 0);
} else {
- base_addr = card->base_addr;
- firm_id = card->base_addr + ID_ADDRESS;
- if (cyz_is_loaded(card)) {
- zfw_ctrl = card->base_addr +
- (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
- lstatus = readl(&ch_ctrl[channel].rs_status);
- result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
- ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
- ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
- ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
- ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
- ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
- } else {
- result = 0;
- unlock_kernel();
- return -ENODEV;
+ u32 lstatus;
+
+ if (!cyz_is_loaded(card)) {
+ result = -ENODEV;
+ goto end;
}
+ lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
+ result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
+ ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
+ ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
+ ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
+ ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
+ ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
}
+end:
unlock_kernel();
return result;
} /* cy_tiomget */
@@ -3526,150 +2495,53 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
{
struct cyclades_port *info = tty->driver_data;
struct cyclades_card *card;
- int chip, channel, index;
- void __iomem *base_addr;
unsigned long flags;
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
- int retval;
if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
card = info->card;
- channel = (info->line) - (card->first_line);
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
+ spin_lock_irqsave(&card->card_lock, flags);
+ cyy_change_rts_dtr(info, set, clear);
+ spin_unlock_irqrestore(&card->card_lock, flags);
+ } else {
+ struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
+ int retval, channel = info->line - card->first_line;
+ u32 rs;
- if (set & TIOCM_RTS) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR2 << index),
- CyDTR);
- } else {
- cy_writeb(base_addr + (CyMSVR1 << index),
- CyRTS);
- }
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
- if (clear & TIOCM_RTS) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR2 << index),
- ~CyDTR);
- } else {
- cy_writeb(base_addr + (CyMSVR1 << index),
- ~CyRTS);
- }
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
+ if (!cyz_is_loaded(card))
+ return -ENODEV;
+
+ spin_lock_irqsave(&card->card_lock, flags);
+ rs = readl(&ch_ctrl->rs_control);
+ if (set & TIOCM_RTS)
+ rs |= C_RS_RTS;
+ if (clear & TIOCM_RTS)
+ rs &= ~C_RS_RTS;
if (set & TIOCM_DTR) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR1 << index),
- CyRTS);
- } else {
- cy_writeb(base_addr + (CyMSVR2 << index),
- CyDTR);
- }
+ rs |= C_RS_DTR;
#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
- printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
- readb(base_addr + (CyMSVR1 << index)),
- readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
#endif
- spin_unlock_irqrestore(&card->card_lock, flags);
}
if (clear & TIOCM_DTR) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR1 << index),
- ~CyRTS);
- } else {
- cy_writeb(base_addr + (CyMSVR2 << index),
- ~CyDTR);
- }
-
+ rs &= ~C_RS_DTR;
#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
- printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
- readb(base_addr + (CyMSVR1 << index)),
- readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:set_modem_info clearing "
+ "Z DTR\n");
#endif
- spin_unlock_irqrestore(&card->card_lock, flags);
}
- } else {
- base_addr = card->base_addr;
-
- firm_id = card->base_addr + ID_ADDRESS;
- if (cyz_is_loaded(card)) {
- zfw_ctrl = card->base_addr +
- (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
-
- if (set & TIOCM_RTS) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- readl(&ch_ctrl[channel].rs_control) |
- C_RS_RTS);
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
- if (clear & TIOCM_RTS) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- readl(&ch_ctrl[channel].rs_control) &
- ~C_RS_RTS);
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
- if (set & TIOCM_DTR) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- readl(&ch_ctrl[channel].rs_control) |
- C_RS_DTR);
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:set_modem_info raising "
- "Z DTR\n");
-#endif
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
- if (clear & TIOCM_DTR) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- readl(&ch_ctrl[channel].rs_control) &
- ~C_RS_DTR);
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:set_modem_info clearing "
- "Z DTR\n");
-#endif
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
- } else {
- return -ENODEV;
- }
- spin_lock_irqsave(&card->card_lock, flags);
+ cy_writel(&ch_ctrl->rs_control, rs);
retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
+ spin_unlock_irqrestore(&card->card_lock, flags);
if (retval != 0) {
printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
"was %x\n", info->line, retval);
}
- spin_unlock_irqrestore(&card->card_lock, flags);
}
return 0;
-} /* cy_tiocmset */
+}
/*
* cy_break() --- routine which turns the break handling on or off
@@ -3734,41 +2606,18 @@ static int cy_break(struct tty_struct *tty, int break_state)
return retval;
} /* cy_break */
-static int get_mon_info(struct cyclades_port *info,
- struct cyclades_monitor __user *mon)
-{
-
- if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
- return -EFAULT;
- info->mon.int_count = 0;
- info->mon.char_count = 0;
- info->mon.char_max = 0;
- info->mon.char_last = 0;
- return 0;
-} /* get_mon_info */
-
static int set_threshold(struct cyclades_port *info, unsigned long value)
{
- struct cyclades_card *card;
- void __iomem *base_addr;
- int channel, chip, index;
+ struct cyclades_card *card = info->card;
unsigned long flags;
- card = info->card;
- channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr =
- card->base_addr + (cy_chip_offset[chip] << index);
-
info->cor3 &= ~CyREC_FIFO;
info->cor3 |= value & CyREC_FIFO;
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
- cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index);
+ cyy_writeb(info, CyCOR3, info->cor3);
+ cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
spin_unlock_irqrestore(&card->card_lock, flags);
}
return 0;
@@ -3777,55 +2626,23 @@ static int set_threshold(struct cyclades_port *info, unsigned long value)
static int get_threshold(struct cyclades_port *info,
unsigned long __user *value)
{
- struct cyclades_card *card;
- void __iomem *base_addr;
- int channel, chip, index;
- unsigned long tmp;
+ struct cyclades_card *card = info->card;
- card = info->card;
- channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
-
- tmp = readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
+ u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
return put_user(tmp, value);
}
return 0;
} /* get_threshold */
-static int set_default_threshold(struct cyclades_port *info,
- unsigned long value)
-{
- info->default_threshold = value & 0x0f;
- return 0;
-} /* set_default_threshold */
-
-static int get_default_threshold(struct cyclades_port *info,
- unsigned long __user *value)
-{
- return put_user(info->default_threshold, value);
-} /* get_default_threshold */
-
static int set_timeout(struct cyclades_port *info, unsigned long value)
{
- struct cyclades_card *card;
- void __iomem *base_addr;
- int channel, chip, index;
+ struct cyclades_card *card = info->card;
unsigned long flags;
- card = info->card;
- channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
-
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyRTPR << index), value & 0xff);
+ cyy_writeb(info, CyRTPR, value & 0xff);
spin_unlock_irqrestore(&card->card_lock, flags);
}
return 0;
@@ -3834,36 +2651,35 @@ static int set_timeout(struct cyclades_port *info, unsigned long value)
static int get_timeout(struct cyclades_port *info,
unsigned long __user *value)
{
- struct cyclades_card *card;
- void __iomem *base_addr;
- int channel, chip, index;
- unsigned long tmp;
+ struct cyclades_card *card = info->card;
- card = info->card;
- channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
-
- tmp = readb(base_addr + (CyRTPR << index));
+ u8 tmp = cyy_readb(info, CyRTPR);
return put_user(tmp, value);
}
return 0;
} /* get_timeout */
-static int set_default_timeout(struct cyclades_port *info, unsigned long value)
+static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
+ struct cyclades_icount *cprev)
{
- info->default_timeout = value & 0xff;
- return 0;
-} /* set_default_timeout */
+ struct cyclades_icount cnow;
+ unsigned long flags;
+ int ret;
-static int get_default_timeout(struct cyclades_port *info,
- unsigned long __user *value)
-{
- return put_user(info->default_timeout, value);
-} /* get_default_timeout */
+ spin_lock_irqsave(&info->card->card_lock, flags);
+ cnow = info->icount; /* atomic copy */
+ spin_unlock_irqrestore(&info->card->card_lock, flags);
+
+ ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
+
+ *cprev = cnow;
+
+ return ret;
+}
/*
* This routine allows the tty driver to implement device-
@@ -3875,8 +2691,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct cyclades_port *info = tty->driver_data;
- struct cyclades_icount cprev, cnow; /* kernel counter temps */
- struct serial_icounter_struct __user *p_cuser; /* user space */
+ struct cyclades_icount cnow; /* kernel counter temps */
int ret_val = 0;
unsigned long flags;
void __user *argp = (void __user *)arg;
@@ -3892,7 +2707,11 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
switch (cmd) {
case CYGETMON:
- ret_val = get_mon_info(info, argp);
+ if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
+ ret_val = -EFAULT;
+ break;
+ }
+ memset(&info->mon, 0, sizeof(info->mon));
break;
case CYGETTHRESH:
ret_val = get_threshold(info, argp);
@@ -3901,10 +2720,11 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
ret_val = set_threshold(info, arg);
break;
case CYGETDEFTHRESH:
- ret_val = get_default_threshold(info, argp);
+ ret_val = put_user(info->default_threshold,
+ (unsigned long __user *)argp);
break;
case CYSETDEFTHRESH:
- ret_val = set_default_threshold(info, arg);
+ info->default_threshold = arg & 0x0f;
break;
case CYGETTIMEOUT:
ret_val = get_timeout(info, argp);
@@ -3913,21 +2733,20 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
ret_val = set_timeout(info, arg);
break;
case CYGETDEFTIMEOUT:
- ret_val = get_default_timeout(info, argp);
+ ret_val = put_user(info->default_timeout,
+ (unsigned long __user *)argp);
break;
case CYSETDEFTIMEOUT:
- ret_val = set_default_timeout(info, arg);
+ info->default_timeout = arg & 0xff;
break;
case CYSETRFLOW:
info->rflow = (int)arg;
- ret_val = 0;
break;
case CYGETRFLOW:
ret_val = info->rflow;
break;
case CYSETRTSDTR_INV:
info->rtsdtr_inv = (int)arg;
- ret_val = 0;
break;
case CYGETRTSDTR_INV:
ret_val = info->rtsdtr_inv;
@@ -3938,7 +2757,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
#ifndef CONFIG_CYZ_INTR
case CYZSETPOLLCYCLE:
cyz_polling_cycle = (arg * HZ) / 1000;
- ret_val = 0;
break;
case CYZGETPOLLCYCLE:
ret_val = (cyz_polling_cycle * 1000) / HZ;
@@ -3946,16 +2764,15 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
#endif /* CONFIG_CYZ_INTR */
case CYSETWAIT:
info->port.closing_wait = (unsigned short)arg * HZ / 100;
- ret_val = 0;
break;
case CYGETWAIT:
ret_val = info->port.closing_wait / (HZ / 100);
break;
case TIOCGSERIAL:
- ret_val = get_serial_info(info, argp);
+ ret_val = cy_get_serial_info(info, argp);
break;
case TIOCSSERIAL:
- ret_val = set_serial_info(info, argp);
+ ret_val = cy_set_serial_info(info, tty, argp);
break;
case TIOCSERGETLSR: /* Get line status register */
ret_val = get_lsr_info(info, argp);
@@ -3971,17 +2788,8 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
/* note the counters on entry */
cnow = info->icount;
spin_unlock_irqrestore(&info->card->card_lock, flags);
- ret_val = wait_event_interruptible(info->delta_msr_wait, ({
- cprev = cnow;
- spin_lock_irqsave(&info->card->card_lock, flags);
- cnow = info->icount; /* atomic copy */
- spin_unlock_irqrestore(&info->card->card_lock, flags);
-
- ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts));
- }));
+ ret_val = wait_event_interruptible(info->port.delta_msr_wait,
+ cy_cflags_changed(info, arg, &cnow));
break;
/*
@@ -3990,46 +2798,29 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
* NB: both 1->0 and 0->1 transitions are counted except for
* RI where only 0->1 is counted.
*/
- case TIOCGICOUNT:
+ case TIOCGICOUNT: {
+ struct serial_icounter_struct sic = { };
+
spin_lock_irqsave(&info->card->card_lock, flags);
cnow = info->icount;
spin_unlock_irqrestore(&info->card->card_lock, flags);
- p_cuser = argp;
- ret_val = put_user(cnow.cts, &p_cuser->cts);
- if (ret_val)
- break;
- ret_val = put_user(cnow.dsr, &p_cuser->dsr);
- if (ret_val)
- break;
- ret_val = put_user(cnow.rng, &p_cuser->rng);
- if (ret_val)
- break;
- ret_val = put_user(cnow.dcd, &p_cuser->dcd);
- if (ret_val)
- break;
- ret_val = put_user(cnow.rx, &p_cuser->rx);
- if (ret_val)
- break;
- ret_val = put_user(cnow.tx, &p_cuser->tx);
- if (ret_val)
- break;
- ret_val = put_user(cnow.frame, &p_cuser->frame);
- if (ret_val)
- break;
- ret_val = put_user(cnow.overrun, &p_cuser->overrun);
- if (ret_val)
- break;
- ret_val = put_user(cnow.parity, &p_cuser->parity);
- if (ret_val)
- break;
- ret_val = put_user(cnow.brk, &p_cuser->brk);
- if (ret_val)
- break;
- ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
- if (ret_val)
- break;
- ret_val = 0;
+
+ sic.cts = cnow.cts;
+ sic.dsr = cnow.dsr;
+ sic.rng = cnow.rng;
+ sic.dcd = cnow.dcd;
+ sic.rx = cnow.rx;
+ sic.tx = cnow.tx;
+ sic.frame = cnow.frame;
+ sic.overrun = cnow.overrun;
+ sic.parity = cnow.parity;
+ sic.brk = cnow.brk;
+ sic.buf_overrun = cnow.buf_overrun;
+
+ if (copy_to_user(argp, &sic, sizeof(sic)))
+ ret_val = -EFAULT;
break;
+ }
default:
ret_val = -ENOIOCTLCMD;
}
@@ -4055,7 +2846,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
#endif
- set_line_char(info);
+ cy_set_line_char(info, tty);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
@@ -4112,8 +2903,6 @@ static void cy_throttle(struct tty_struct *tty)
struct cyclades_port *info = tty->driver_data;
struct cyclades_card *card;
unsigned long flags;
- void __iomem *base_addr;
- int chip, channel, index;
#ifdef CY_DEBUG_THROTTLE
char buf[64];
@@ -4135,24 +2924,9 @@ static void cy_throttle(struct tty_struct *tty)
}
if (tty->termios->c_cflag & CRTSCTS) {
- channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr +
- (cy_chip_offset[chip] << index);
-
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR2 << index),
- ~CyDTR);
- } else {
- cy_writeb(base_addr + (CyMSVR1 << index),
- ~CyRTS);
- }
+ cyy_change_rts_dtr(info, 0, TIOCM_RTS);
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
info->throttle = 1;
@@ -4170,8 +2944,6 @@ static void cy_unthrottle(struct tty_struct *tty)
struct cyclades_port *info = tty->driver_data;
struct cyclades_card *card;
unsigned long flags;
- void __iomem *base_addr;
- int chip, channel, index;
#ifdef CY_DEBUG_THROTTLE
char buf[64];
@@ -4192,24 +2964,9 @@ static void cy_unthrottle(struct tty_struct *tty)
if (tty->termios->c_cflag & CRTSCTS) {
card = info->card;
- channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr +
- (cy_chip_offset[chip] << index);
-
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR2 << index),
- CyDTR);
- } else {
- cy_writeb(base_addr + (CyMSVR1 << index),
- CyRTS);
- }
+ cyy_change_rts_dtr(info, TIOCM_RTS, 0);
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
info->throttle = 0;
@@ -4224,8 +2981,7 @@ static void cy_stop(struct tty_struct *tty)
{
struct cyclades_card *cinfo;
struct cyclades_port *info = tty->driver_data;
- void __iomem *base_addr;
- int chip, channel, index;
+ int channel;
unsigned long flags;
#ifdef CY_DEBUG_OTHER
@@ -4238,16 +2994,9 @@ static void cy_stop(struct tty_struct *tty)
cinfo = info->card;
channel = info->line - cinfo->first_line;
if (!cy_is_Z(cinfo)) {
- index = cinfo->bus_index;
- chip = channel >> 2;
- channel &= 0x03;
- base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
-
spin_lock_irqsave(&cinfo->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char)(channel & 0x0003)); /* index channel */
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) & ~CyTxRdy);
+ cyy_writeb(info, CyCAR, channel & 0x03);
+ cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
spin_unlock_irqrestore(&cinfo->card_lock, flags);
}
} /* cy_stop */
@@ -4256,8 +3005,7 @@ static void cy_start(struct tty_struct *tty)
{
struct cyclades_card *cinfo;
struct cyclades_port *info = tty->driver_data;
- void __iomem *base_addr;
- int chip, channel, index;
+ int channel;
unsigned long flags;
#ifdef CY_DEBUG_OTHER
@@ -4269,17 +3017,10 @@ static void cy_start(struct tty_struct *tty)
cinfo = info->card;
channel = info->line - cinfo->first_line;
- index = cinfo->bus_index;
if (!cy_is_Z(cinfo)) {
- chip = channel >> 2;
- channel &= 0x03;
- base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
-
spin_lock_irqsave(&cinfo->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) (channel & 0x0003)); /* index channel */
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) | CyTxRdy);
+ cyy_writeb(info, CyCAR, channel & 0x03);
+ cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
spin_unlock_irqrestore(&cinfo->card_lock, flags);
}
} /* cy_start */
@@ -4299,17 +3040,84 @@ static void cy_hangup(struct tty_struct *tty)
return;
cy_flush_buffer(tty);
- shutdown(info);
- info->port.count = 0;
-#ifdef CY_DEBUG_COUNT
- printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n",
- current->pid);
-#endif
- info->port.tty = NULL;
- info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
- wake_up_interruptible(&info->port.open_wait);
+ cy_shutdown(info, tty);
+ tty_port_hangup(&info->port);
} /* cy_hangup */
+static int cyy_carrier_raised(struct tty_port *port)
+{
+ struct cyclades_port *info = container_of(port, struct cyclades_port,
+ port);
+ struct cyclades_card *cinfo = info->card;
+ unsigned long flags;
+ int channel = info->line - cinfo->first_line;
+ u32 cd;
+
+ spin_lock_irqsave(&cinfo->card_lock, flags);
+ cyy_writeb(info, CyCAR, channel & 0x03);
+ cd = cyy_readb(info, CyMSVR1) & CyDCD;
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
+
+ return cd;
+}
+
+static void cyy_dtr_rts(struct tty_port *port, int raise)
+{
+ struct cyclades_port *info = container_of(port, struct cyclades_port,
+ port);
+ struct cyclades_card *cinfo = info->card;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cinfo->card_lock, flags);
+ cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
+ raise ? 0 : TIOCM_RTS | TIOCM_DTR);
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
+}
+
+static int cyz_carrier_raised(struct tty_port *port)
+{
+ struct cyclades_port *info = container_of(port, struct cyclades_port,
+ port);
+
+ return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
+}
+
+static void cyz_dtr_rts(struct tty_port *port, int raise)
+{
+ struct cyclades_port *info = container_of(port, struct cyclades_port,
+ port);
+ struct cyclades_card *cinfo = info->card;
+ struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
+ int ret, channel = info->line - cinfo->first_line;
+ u32 rs;
+
+ rs = readl(&ch_ctrl->rs_control);
+ if (raise)
+ rs |= C_RS_RTS | C_RS_DTR;
+ else
+ rs &= ~(C_RS_RTS | C_RS_DTR);
+ cy_writel(&ch_ctrl->rs_control, rs);
+ ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
+ if (ret != 0)
+ printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
+ __func__, info->line, ret);
+#ifdef CY_DEBUG_DTR
+ printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
+#endif
+}
+
+static const struct tty_port_operations cyy_port_ops = {
+ .carrier_raised = cyy_carrier_raised,
+ .dtr_rts = cyy_dtr_rts,
+ .shutdown = cy_do_close,
+};
+
+static const struct tty_port_operations cyz_port_ops = {
+ .carrier_raised = cyz_carrier_raised,
+ .dtr_rts = cyz_dtr_rts,
+ .shutdown = cy_do_close,
+};
+
/*
* ---------------------------------------------------------------------
* cy_init() and friends
@@ -4321,8 +3129,7 @@ static void cy_hangup(struct tty_struct *tty)
static int __devinit cy_init_card(struct cyclades_card *cinfo)
{
struct cyclades_port *info;
- unsigned int port;
- unsigned short chip_number;
+ unsigned int channel, port;
spin_lock_init(&cinfo->card_lock);
cinfo->intr_enabled = 0;
@@ -4334,9 +3141,9 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
return -ENOMEM;
}
- for (port = cinfo->first_line; port < cinfo->first_line + cinfo->nports;
- port++) {
- info = &cinfo->ports[port - cinfo->first_line];
+ for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
+ channel++, port++) {
+ info = &cinfo->ports[channel];
tty_port_init(&info->port);
info->magic = CYCLADES_MAGIC;
info->card = cinfo;
@@ -4346,10 +3153,19 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
info->port.close_delay = 5 * HZ / 10;
info->port.flags = STD_COM_FLAGS;
init_completion(&info->shutdown_wait);
- init_waitqueue_head(&info->delta_msr_wait);
if (cy_is_Z(cinfo)) {
+ struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
+ struct ZFW_CTRL *zfw_ctrl;
+
+ info->port.ops = &cyz_port_ops;
info->type = PORT_STARTECH;
+
+ zfw_ctrl = cinfo->base_addr +
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
+ info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
+
if (cinfo->hw_ver == ZO_V1)
info->xmit_fifo_size = CYZ_FIFO_SIZE;
else
@@ -4359,17 +3175,20 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
cyz_rx_restart, (unsigned long)info);
#endif
} else {
+ unsigned short chip_number;
int index = cinfo->bus_index;
+
+ info->port.ops = &cyy_port_ops;
info->type = PORT_CIRRUS;
info->xmit_fifo_size = CyMAX_CHAR_FIFO;
info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
info->cor2 = CyETC;
info->cor3 = 0x08; /* _very_ small rcv threshold */
- chip_number = (port - cinfo->first_line) / 4;
- info->chip_rev = readb(cinfo->base_addr +
- (cy_chip_offset[chip_number] << index) +
- (CyGFRCR << index));
+ chip_number = channel / CyPORTS_PER_CHIP;
+ info->u.cyy.base_addr = cinfo->base_addr +
+ (cy_chip_offset[chip_number] << index);
+ info->chip_rev = cyy_readb(info, CyGFRCR);
if (info->chip_rev >= CD1400_REV_J) {
/* It is a CD1400 rev. J or later */
@@ -4535,7 +3354,7 @@ static int __init cy_detect_isa(void)
continue;
}
#ifdef MODULE
- if (isparam && irq[i])
+ if (isparam && i < NR_CARDS && irq[i])
cy_isa_irq = irq[i];
else
#endif
@@ -5060,8 +3879,14 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
}
cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
} else {
+ struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+
+ zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
+
cy_card[card_no].hw_ver = mailbox;
cy_card[card_no].num_chips = (unsigned int)-1;
+ cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
#ifdef CONFIG_CYZ_INTR
/* allocate IRQ only if board has an IRQ */
if (irq != 0 && irq != 255) {
@@ -5191,18 +4016,30 @@ static int cyclades_proc_show(struct seq_file *m, void *v)
for (j = 0; j < cy_card[i].nports; j++) {
info = &cy_card[i].ports[j];
- if (info->port.count)
+ if (info->port.count) {
+ /* XXX is the ldisc num worth this? */
+ struct tty_struct *tty;
+ struct tty_ldisc *ld;
+ int num = 0;
+ tty = tty_port_tty_get(&info->port);
+ if (tty) {
+ ld = tty_ldisc_ref(tty);
+ if (ld) {
+ num = ld->ops->num;
+ tty_ldisc_deref(ld);
+ }
+ tty_kref_put(tty);
+ }
seq_printf(m, "%3d %8lu %10lu %8lu "
- "%10lu %8lu %9lu %6ld\n", info->line,
+ "%10lu %8lu %9lu %6d\n", info->line,
(cur_jifs - info->idle_stats.in_use) /
HZ, info->idle_stats.xmit_bytes,
(cur_jifs - info->idle_stats.xmit_idle)/
HZ, info->idle_stats.recv_bytes,
(cur_jifs - info->idle_stats.recv_idle)/
HZ, info->idle_stats.overruns,
- /* FIXME: double check locking */
- (long)info->port.tty->ldisc->ops->num);
- else
+ num);
+ } else
seq_printf(m, "%3d %8lu %10lu %8lu "
"%10lu %8lu %9lu %6ld\n",
info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c
index 52e06589821d..045c930e6320 100644
--- a/drivers/char/dtlk.c
+++ b/drivers/char/dtlk.c
@@ -56,6 +56,7 @@
#include <linux/errno.h> /* for -EBUSY */
#include <linux/ioport.h> /* for request_region */
#include <linux/delay.h> /* for loops_per_jiffy */
+#include <linux/sched.h>
#include <linux/smp_lock.h> /* cycle_kernel_lock() */
#include <asm/io.h> /* for inb_p, outb_p, inb, outb, etc. */
#include <asm/uaccess.h> /* for get_user, etc. */
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index ff647ca1c489..dde5134713e2 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -30,6 +30,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
+#include <linux/sched.h>
#include <linux/serial.h>
#include <linux/delay.h>
#include <linux/ctype.h>
@@ -2239,7 +2240,7 @@ static void do_softint(struct work_struct *work)
struct channel *ch = container_of(work, struct channel, tqueue);
/* Called in response to a modem change event */
if (ch && ch->magic == EPCA_MAGIC) {
- struct tty_struct *tty = tty_port_tty_get(&ch->port);;
+ struct tty_struct *tty = tty_port_tty_get(&ch->port);
if (tty && tty->driver_data) {
if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index a5c59fc2b0ff..b19d43cd9542 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -572,7 +572,7 @@ static void check_modem_status(struct esp_struct *info)
info->icount.dcd++;
if (status & UART_MSR_DCTS)
info->icount.cts++;
- wake_up_interruptible(&info->delta_msr_wait);
+ wake_up_interruptible(&info->port.delta_msr_wait);
}
if ((info->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
@@ -927,7 +927,7 @@ static void shutdown(struct esp_struct *info)
* clear delta_msr_wait queue to avoid mem leaks: we may free the irq
* here so the queue might never be waken up
*/
- wake_up_interruptible(&info->delta_msr_wait);
+ wake_up_interruptible(&info->port.delta_msr_wait);
wake_up_interruptible(&info->break_wait);
/* stop a DMA transfer on the port being closed */
@@ -1800,7 +1800,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file *file,
spin_unlock_irqrestore(&info->lock, flags);
while (1) {
/* FIXME: convert to new style wakeup */
- interruptible_sleep_on(&info->delta_msr_wait);
+ interruptible_sleep_on(&info->port.delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
@@ -2452,7 +2452,6 @@ static int __init espserial_init(void)
info->config.flow_off = flow_off;
info->config.pio_threshold = pio_threshold;
info->next_port = ports;
- init_waitqueue_head(&info->delta_msr_wait);
init_waitqueue_head(&info->break_wait);
ports = info;
printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ",
diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
index a00869c650d5..ef31738c2cbe 100644
--- a/drivers/char/generic_nvram.c
+++ b/drivers/char/generic_nvram.c
@@ -2,7 +2,7 @@
* Generic /dev/nvram driver for architectures providing some
* "generic" hooks, that is :
*
- * nvram_read_byte, nvram_write_byte, nvram_sync
+ * nvram_read_byte, nvram_write_byte, nvram_sync, nvram_get_size
*
* Note that an additional hook is supported for PowerMac only
* for getting the nvram "partition" informations
@@ -28,6 +28,8 @@
#define NVRAM_SIZE 8192
+static ssize_t nvram_len;
+
static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
{
lock_kernel();
@@ -36,7 +38,7 @@ static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
offset += file->f_pos;
break;
case 2:
- offset += NVRAM_SIZE;
+ offset += nvram_len;
break;
}
if (offset < 0) {
@@ -56,9 +58,9 @@ static ssize_t read_nvram(struct file *file, char __user *buf,
if (!access_ok(VERIFY_WRITE, buf, count))
return -EFAULT;
- if (*ppos >= NVRAM_SIZE)
+ if (*ppos >= nvram_len)
return 0;
- for (i = *ppos; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count)
+ for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count)
if (__put_user(nvram_read_byte(i), p))
return -EFAULT;
*ppos = i;
@@ -74,9 +76,9 @@ static ssize_t write_nvram(struct file *file, const char __user *buf,
if (!access_ok(VERIFY_READ, buf, count))
return -EFAULT;
- if (*ppos >= NVRAM_SIZE)
+ if (*ppos >= nvram_len)
return 0;
- for (i = *ppos; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count) {
+ for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count) {
if (__get_user(c, p))
return -EFAULT;
nvram_write_byte(c, i);
@@ -133,9 +135,20 @@ static struct miscdevice nvram_dev = {
int __init nvram_init(void)
{
+ int ret = 0;
+
printk(KERN_INFO "Generic non-volatile memory driver v%s\n",
NVRAM_VERSION);
- return misc_register(&nvram_dev);
+ ret = misc_register(&nvram_dev);
+ if (ret != 0)
+ goto out;
+
+ nvram_len = nvram_get_size();
+ if (nvram_len < 0)
+ nvram_len = NVRAM_SIZE;
+
+out:
+ return ret;
}
void __exit nvram_cleanup(void)
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 9e4e569dc00d..d400cbd280f2 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/tty.h>
+#include <linux/sched.h>
#include <linux/serial.h>
#include <linux/mm.h>
#include <linux/generic_serial.h>
diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c
index aac0985a572b..31e7c91c2d9d 100644
--- a/drivers/char/genrtc.c
+++ b/drivers/char/genrtc.c
@@ -43,6 +43,7 @@
#define RTC_VERSION "1.07"
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/fcntl.h>
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 4a9f3492b921..70a770ac0138 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -166,9 +166,8 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
unsigned long m, t;
t = devp->hd_ireqfreq;
- m = read_counter(&devp->hd_hpet->hpet_mc);
- write_counter(t + m + devp->hd_hpets->hp_delta,
- &devp->hd_timer->hpet_compare);
+ m = read_counter(&devp->hd_timer->hpet_compare);
+ write_counter(t + m, &devp->hd_timer->hpet_compare);
}
if (devp->hd_flags & HPET_SHARED_IRQ)
@@ -504,21 +503,25 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
g = v | Tn_32MODE_CNF_MASK | Tn_INT_ENB_CNF_MASK;
if (devp->hd_flags & HPET_PERIODIC) {
- write_counter(t, &timer->hpet_compare);
g |= Tn_TYPE_CNF_MASK;
- v |= Tn_TYPE_CNF_MASK;
- writeq(v, &timer->hpet_config);
- v |= Tn_VAL_SET_CNF_MASK;
+ v |= Tn_TYPE_CNF_MASK | Tn_VAL_SET_CNF_MASK;
writeq(v, &timer->hpet_config);
local_irq_save(flags);
- /* NOTE: what we modify here is a hidden accumulator
+ /*
+ * NOTE: First we modify the hidden accumulator
* register supported by periodic-capable comparators.
* We never want to modify the (single) counter; that
- * would affect all the comparators.
+ * would affect all the comparators. The value written
+ * is the counter value when the first interrupt is due.
*/
m = read_counter(&hpet->hpet_mc);
write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
+ /*
+ * Then we modify the comparator, indicating the period
+ * for subsequent interrupt.
+ */
+ write_counter(t, &timer->hpet_compare);
} else {
local_irq_save(flags);
m = read_counter(&hpet->hpet_mc);
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index d97779ef72cb..a632f25f144a 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -516,8 +516,6 @@ static void hvc_set_winsz(struct work_struct *work)
struct winsize ws;
hp = container_of(work, struct hvc_struct, tty_resize);
- if (!hp)
- return;
spin_lock_irqsave(&hp->lock, hvc_flags);
if (!hp->tty) {
@@ -680,7 +678,7 @@ int hvc_poll(struct hvc_struct *hp)
EXPORT_SYMBOL_GPL(hvc_poll);
/**
- * hvc_resize() - Update terminal window size information.
+ * __hvc_resize() - Update terminal window size information.
* @hp: HVC console pointer
* @ws: Terminal window size structure
*
@@ -689,12 +687,12 @@ EXPORT_SYMBOL_GPL(hvc_poll);
*
* Locking: Locking free; the function MUST be called holding hp->lock
*/
-void hvc_resize(struct hvc_struct *hp, struct winsize ws)
+void __hvc_resize(struct hvc_struct *hp, struct winsize ws)
{
hp->ws = ws;
schedule_work(&hp->tty_resize);
}
-EXPORT_SYMBOL_GPL(hvc_resize);
+EXPORT_SYMBOL_GPL(__hvc_resize);
/*
* This kthread is either polling or interrupt driven. This is determined by
diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h
index 3c85d78c975c..10950ca706d8 100644
--- a/drivers/char/hvc_console.h
+++ b/drivers/char/hvc_console.h
@@ -28,6 +28,7 @@
#define HVC_CONSOLE_H
#include <linux/kref.h>
#include <linux/tty.h>
+#include <linux/spinlock.h>
/*
* This is the max number of console adapters that can/will be found as
@@ -88,7 +89,16 @@ int hvc_poll(struct hvc_struct *hp);
void hvc_kick(void);
/* Resize hvc tty terminal window */
-extern void hvc_resize(struct hvc_struct *hp, struct winsize ws);
+extern void __hvc_resize(struct hvc_struct *hp, struct winsize ws);
+
+static inline void hvc_resize(struct hvc_struct *hp, struct winsize ws)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&hp->lock, flags);
+ __hvc_resize(hp, ws);
+ spin_unlock_irqrestore(&hp->lock, flags);
+}
/* default notifier for irq based notification */
extern int notifier_add_irq(struct hvc_struct *hp, int data);
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c
index 0ecac7e532f6..b8a5d654d3d0 100644
--- a/drivers/char/hvc_iucv.c
+++ b/drivers/char/hvc_iucv.c
@@ -273,7 +273,9 @@ static int hvc_iucv_write(struct hvc_iucv_private *priv,
case MSG_TYPE_WINSIZE:
if (rb->mbuf->datalen != sizeof(struct winsize))
break;
- hvc_resize(priv->hvc, *((struct winsize *) rb->mbuf->data));
+ /* The caller must ensure that the hvc is locked, which
+ * is the case when called from hvc_iucv_get_chars() */
+ __hvc_resize(priv->hvc, *((struct winsize *) rb->mbuf->data));
break;
case MSG_TYPE_ERROR: /* ignored ... */
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index c72b994652ac..10be343d6ae7 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -120,7 +120,7 @@ static struct vio_driver hvc_vio_driver = {
}
};
-static int hvc_vio_init(void)
+static int __init hvc_vio_init(void)
{
int rc;
@@ -134,7 +134,7 @@ static int hvc_vio_init(void)
}
module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
-static void hvc_vio_exit(void)
+static void __exit hvc_vio_exit(void)
{
vio_unregister_driver(&hvc_vio_driver);
}
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
index eba999f8598d..a6ee32b599a8 100644
--- a/drivers/char/hvc_xen.c
+++ b/drivers/char/hvc_xen.c
@@ -55,7 +55,7 @@ static inline void notify_daemon(void)
notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
}
-static int write_console(uint32_t vtermno, const char *data, int len)
+static int __write_console(const char *data, int len)
{
struct xencons_interface *intf = xencons_interface();
XENCONS_RING_IDX cons, prod;
@@ -76,6 +76,29 @@ static int write_console(uint32_t vtermno, const char *data, int len)
return sent;
}
+static int write_console(uint32_t vtermno, const char *data, int len)
+{
+ int ret = len;
+
+ /*
+ * Make sure the whole buffer is emitted, polling if
+ * necessary. We don't ever want to rely on the hvc daemon
+ * because the most interesting console output is when the
+ * kernel is crippled.
+ */
+ while (len) {
+ int sent = __write_console(data, len);
+
+ data += sent;
+ len -= sent;
+
+ if (unlikely(len))
+ HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
+ }
+
+ return ret;
+}
+
static int read_console(uint32_t vtermno, char *buf, int len)
{
struct xencons_interface *intf = xencons_interface();
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index 2989056a9e39..793b236c9266 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -1230,11 +1230,12 @@ static struct tty_driver *hvsi_console_device(struct console *console,
static int __init hvsi_console_setup(struct console *console, char *options)
{
- struct hvsi_struct *hp = &hvsi_ports[console->index];
+ struct hvsi_struct *hp;
int ret;
if (console->index < 0 || console->index >= hvsi_count)
return -1;
+ hp = &hvsi_ports[console->index];
/* give the FSP a chance to change the baud rate when we re-open */
hvsi_close_protocol(hp);
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index ce66a70184f7..87060266ef91 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -126,6 +126,19 @@ config HW_RANDOM_OMAP
If unsure, say Y.
+config HW_RANDOM_OCTEON
+ tristate "Octeon Random Number Generator support"
+ depends on HW_RANDOM && CPU_CAVIUM_OCTEON
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on Octeon processors.
+
+ To compile this driver as a module, choose M here: the
+ module will be called octeon-rng.
+
+ If unsure, say Y.
+
config HW_RANDOM_PASEMI
tristate "PA Semi HW Random Number Generator support"
depends on HW_RANDOM && PPC_PASEMI
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index 676828ba8123..5eeb1303f0d0 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
+obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index fc93e2fc7c71..1573aebd54b5 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -153,7 +153,7 @@ static const struct file_operations rng_chrdev_ops = {
static struct miscdevice rng_miscdev = {
.minor = RNG_MISCDEV_MINOR,
.name = RNG_MODULE_NAME,
- .devnode = "hwrng",
+ .nodename = "hwrng",
.fops = &rng_chrdev_ops,
};
diff --git a/drivers/char/hw_random/octeon-rng.c b/drivers/char/hw_random/octeon-rng.c
new file mode 100644
index 000000000000..54b0d9ba65cf
--- /dev/null
+++ b/drivers/char/hw_random/octeon-rng.c
@@ -0,0 +1,147 @@
+/*
+ * Hardware Random Number Generator support for Cavium Networks
+ * Octeon processor family.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Cavium Networks
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+
+#include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-rnm-defs.h>
+
+struct octeon_rng {
+ struct hwrng ops;
+ void __iomem *control_status;
+ void __iomem *result;
+};
+
+static int octeon_rng_init(struct hwrng *rng)
+{
+ union cvmx_rnm_ctl_status ctl;
+ struct octeon_rng *p = container_of(rng, struct octeon_rng, ops);
+
+ ctl.u64 = 0;
+ ctl.s.ent_en = 1; /* Enable the entropy source. */
+ ctl.s.rng_en = 1; /* Enable the RNG hardware. */
+ cvmx_write_csr((u64)p->control_status, ctl.u64);
+ return 0;
+}
+
+static void octeon_rng_cleanup(struct hwrng *rng)
+{
+ union cvmx_rnm_ctl_status ctl;
+ struct octeon_rng *p = container_of(rng, struct octeon_rng, ops);
+
+ ctl.u64 = 0;
+ /* Disable everything. */
+ cvmx_write_csr((u64)p->control_status, ctl.u64);
+}
+
+static int octeon_rng_data_read(struct hwrng *rng, u32 *data)
+{
+ struct octeon_rng *p = container_of(rng, struct octeon_rng, ops);
+
+ *data = cvmx_read64_uint32((u64)p->result);
+ return sizeof(u32);
+}
+
+static int __devinit octeon_rng_probe(struct platform_device *pdev)
+{
+ struct resource *res_ports;
+ struct resource *res_result;
+ struct octeon_rng *rng;
+ int ret;
+ struct hwrng ops = {
+ .name = "octeon",
+ .init = octeon_rng_init,
+ .cleanup = octeon_rng_cleanup,
+ .data_read = octeon_rng_data_read
+ };
+
+ rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
+ if (!rng)
+ return -ENOMEM;
+
+ res_ports = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res_ports)
+ goto err_ports;
+
+ res_result = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res_result)
+ goto err_ports;
+
+
+ rng->control_status = devm_ioremap_nocache(&pdev->dev,
+ res_ports->start,
+ sizeof(u64));
+ if (!rng->control_status)
+ goto err_ports;
+
+ rng->result = devm_ioremap_nocache(&pdev->dev,
+ res_result->start,
+ sizeof(u64));
+ if (!rng->result)
+ goto err_r;
+
+ rng->ops = ops;
+
+ dev_set_drvdata(&pdev->dev, &rng->ops);
+ ret = hwrng_register(&rng->ops);
+ if (ret)
+ goto err;
+
+ dev_info(&pdev->dev, "Octeon Random Number Generator\n");
+
+ return 0;
+err:
+ devm_iounmap(&pdev->dev, rng->control_status);
+err_r:
+ devm_iounmap(&pdev->dev, rng->result);
+err_ports:
+ devm_kfree(&pdev->dev, rng);
+ return -ENOENT;
+}
+
+static int __exit octeon_rng_remove(struct platform_device *pdev)
+{
+ struct hwrng *rng = dev_get_drvdata(&pdev->dev);
+
+ hwrng_unregister(rng);
+
+ return 0;
+}
+
+static struct platform_driver octeon_rng_driver = {
+ .driver = {
+ .name = "octeon_rng",
+ .owner = THIS_MODULE,
+ },
+ .probe = octeon_rng_probe,
+ .remove = __exit_p(octeon_rng_remove),
+};
+
+static int __init octeon_rng_mod_init(void)
+{
+ return platform_driver_register(&octeon_rng_driver);
+}
+
+static void __exit octeon_rng_mod_exit(void)
+{
+ platform_driver_unregister(&octeon_rng_driver);
+}
+
+module_init(octeon_rng_mod_init);
+module_exit(octeon_rng_mod_exit);
+
+MODULE_AUTHOR("David Daney");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index 00dd3de1be51..06aad0831c73 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -116,7 +116,7 @@ static int __devinit omap_rng_probe(struct platform_device *pdev)
if (!res)
return -ENOENT;
- mem = request_mem_region(res->start, res->end - res->start + 1,
+ mem = request_mem_region(res->start, resource_size(res),
pdev->name);
if (mem == NULL) {
ret = -EBUSY;
@@ -124,7 +124,7 @@ static int __devinit omap_rng_probe(struct platform_device *pdev)
}
dev_set_drvdata(&pdev->dev, mem);
- rng_base = ioremap(res->start, res->end - res->start + 1);
+ rng_base = ioremap(res->start, resource_size(res));
if (!rng_base) {
ret = -ENOMEM;
goto err_ioremap;
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index 32216b623248..915157fcff98 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -51,7 +51,7 @@ static void register_buffer(void)
sg_init_one(&sg, random_data+data_left, RANDOM_DATA_SIZE-data_left);
/* There should always be room for one buffer. */
- if (vq->vq_ops->add_buf(vq, &sg, 0, 1, random_data) != 0)
+ if (vq->vq_ops->add_buf(vq, &sg, 0, 1, random_data) < 0)
BUG();
vq->vq_ops->kick(vq);
}
@@ -116,7 +116,7 @@ static int virtrng_probe(struct virtio_device *vdev)
return 0;
}
-static void virtrng_remove(struct virtio_device *vdev)
+static void __devexit virtrng_remove(struct virtio_device *vdev)
{
vdev->config->reset(vdev);
hwrng_unregister(&virtio_hwrng);
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index 41fc11dc921c..65545de3dbf4 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -36,6 +36,7 @@
#include <linux/errno.h>
#include <asm/system.h>
#include <linux/poll.h>
+#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/ipmi.h>
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 09050797c76a..ec5e3f8df648 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -35,6 +35,7 @@
#include <linux/errno.h>
#include <asm/system.h>
#include <linux/poll.h>
+#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/slab.h>
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index a261bd735dfb..2e66b5f773dd 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -691,7 +691,7 @@ static struct ctl_table_header *ipmi_table_header;
/*
* Startup and shutdown functions.
*/
-static int ipmi_poweroff_init(void)
+static int __init ipmi_poweroff_init(void)
{
int rv;
@@ -725,7 +725,7 @@ static int ipmi_poweroff_init(void)
}
#ifdef MODULE
-static __exit void ipmi_poweroff_cleanup(void)
+static void __exit ipmi_poweroff_cleanup(void)
{
int rv;
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 4f1f4cd670da..426bfdd7f3e0 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -846,37 +846,53 @@ static int isicom_carrier_raised(struct tty_port *port)
return (ip->status & ISI_DCD)?1 : 0;
}
-static int isicom_open(struct tty_struct *tty, struct file *filp)
+static struct tty_port *isicom_find_port(struct tty_struct *tty)
{
struct isi_port *port;
struct isi_board *card;
unsigned int board;
- int error, line;
+ int line = tty->index;
- line = tty->index;
if (line < 0 || line > PORT_COUNT-1)
- return -ENODEV;
+ return NULL;
board = BOARD(line);
card = &isi_card[board];
if (!(card->status & FIRMWARE_LOADED))
- return -ENODEV;
+ return NULL;
/* open on a port greater than the port count for the card !!! */
if (line > ((board * 16) + card->port_count - 1))
- return -ENODEV;
+ return NULL;
port = &isi_ports[line];
if (isicom_paranoia_check(port, tty->name, "isicom_open"))
- return -ENODEV;
+ return NULL;
+ return &port->port;
+}
+
+static int isicom_open(struct tty_struct *tty, struct file *filp)
+{
+ struct isi_port *port;
+ struct isi_board *card;
+ struct tty_port *tport;
+ int error = 0;
+
+ tport = isicom_find_port(tty);
+ if (tport == NULL)
+ return -ENODEV;
+ port = container_of(tport, struct isi_port, port);
+ card = &isi_card[BOARD(tty->index)];
isicom_setup_board(card);
/* FIXME: locking on port.count etc */
port->port.count++;
tty->driver_data = port;
tty_port_tty_set(&port->port, tty);
- error = isicom_setup_port(tty);
+ /* FIXME: Locking on Initialized flag */
+ if (!test_bit(ASYNCB_INITIALIZED, &tport->flags))
+ error = isicom_setup_port(tty);
if (error == 0)
error = tty_port_block_til_ready(&port->port, tty, filp);
return error;
@@ -952,19 +968,12 @@ static void isicom_flush_buffer(struct tty_struct *tty)
tty_wakeup(tty);
}
-static void isicom_close(struct tty_struct *tty, struct file *filp)
+static void isicom_close_port(struct tty_port *port)
{
- struct isi_port *ip = tty->driver_data;
- struct tty_port *port = &ip->port;
- struct isi_board *card;
+ struct isi_port *ip = container_of(port, struct isi_port, port);
+ struct isi_board *card = ip->card;
unsigned long flags;
- BUG_ON(!ip);
-
- card = ip->card;
- if (isicom_paranoia_check(ip, tty->name, "isicom_close"))
- return;
-
/* indicate to the card that no more data can be received
on this port */
spin_lock_irqsave(&card->card_lock, flags);
@@ -974,9 +983,19 @@ static void isicom_close(struct tty_struct *tty, struct file *filp)
}
isicom_shutdown_port(ip);
spin_unlock_irqrestore(&card->card_lock, flags);
+}
+
+static void isicom_close(struct tty_struct *tty, struct file *filp)
+{
+ struct isi_port *ip = tty->driver_data;
+ struct tty_port *port = &ip->port;
+ if (isicom_paranoia_check(ip, tty->name, "isicom_close"))
+ return;
+ if (tty_port_close_start(port, tty, filp) == 0)
+ return;
+ isicom_close_port(port);
isicom_flush_buffer(tty);
-
tty_port_close_end(port, tty);
}
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index ab2f3349c5c4..402838f4083e 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -19,6 +19,7 @@
/*****************************************************************************/
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 737be953cc58..950837cf9e9c 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -1249,7 +1249,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
if (keycode >= NR_KEYS)
if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8)
- keysym = K(KT_BRL, keycode - KEY_BRL_DOT1 + 1);
+ keysym = U(K(KT_BRL, keycode - KEY_BRL_DOT1 + 1));
else
return;
else
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
index acd8e9ed474a..87c67b42bc08 100644
--- a/drivers/char/mbcs.c
+++ b/drivers/char/mbcs.c
@@ -15,6 +15,7 @@
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/ioport.h>
+#include <linux/kernel.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
@@ -715,8 +716,8 @@ static ssize_t show_algo(struct device *dev, struct device_attribute *attr, char
*/
debug0 = *(uint64_t *) soft->debug_addr;
- return sprintf(buf, "0x%lx 0x%lx\n",
- (debug0 >> 32), (debug0 & 0xffffffff));
+ return sprintf(buf, "0x%x 0x%x\n",
+ upper_32_bits(debug0), lower_32_bits(debug0));
}
static ssize_t store_algo(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 645237bda682..a074fceb67d3 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -301,7 +301,7 @@ static inline int private_mapping_ok(struct vm_area_struct *vma)
}
#endif
-static struct vm_operations_struct mmap_mem_ops = {
+static const struct vm_operations_struct mmap_mem_ops = {
#ifdef CONFIG_HAVE_IOREMAP_PROT
.access = generic_access_phys
#endif
@@ -690,7 +690,7 @@ static ssize_t read_zero(struct file * file, char __user * buf,
if (chunk > PAGE_SIZE)
chunk = PAGE_SIZE; /* Just for latency reasons */
- unwritten = clear_user(buf, chunk);
+ unwritten = __clear_user(buf, chunk);
written += chunk - unwritten;
if (unwritten)
break;
@@ -864,71 +864,75 @@ static const struct file_operations kmsg_fops = {
.write = kmsg_write,
};
-static const struct {
- unsigned int minor;
- char *name;
- umode_t mode;
- const struct file_operations *fops;
- struct backing_dev_info *dev_info;
-} devlist[] = { /* list of minor devices */
- {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops,
- &directly_mappable_cdev_bdi},
+static const struct memdev {
+ const char *name;
+ mode_t mode;
+ const struct file_operations *fops;
+ struct backing_dev_info *dev_info;
+} devlist[] = {
+ [1] = { "mem", 0, &mem_fops, &directly_mappable_cdev_bdi },
#ifdef CONFIG_DEVKMEM
- {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops,
- &directly_mappable_cdev_bdi},
+ [2] = { "kmem", 0, &kmem_fops, &directly_mappable_cdev_bdi },
#endif
- {3, "null", S_IRUGO | S_IWUGO, &null_fops, NULL},
+ [3] = { "null", 0666, &null_fops, NULL },
#ifdef CONFIG_DEVPORT
- {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops, NULL},
+ [4] = { "port", 0, &port_fops, NULL },
#endif
- {5, "zero", S_IRUGO | S_IWUGO, &zero_fops, &zero_bdi},
- {7, "full", S_IRUGO | S_IWUGO, &full_fops, NULL},
- {8, "random", S_IRUGO | S_IWUSR, &random_fops, NULL},
- {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops, NULL},
- {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops, NULL},
+ [5] = { "zero", 0666, &zero_fops, &zero_bdi },
+ [7] = { "full", 0666, &full_fops, NULL },
+ [8] = { "random", 0666, &random_fops, NULL },
+ [9] = { "urandom", 0666, &urandom_fops, NULL },
+ [11] = { "kmsg", 0, &kmsg_fops, NULL },
#ifdef CONFIG_CRASH_DUMP
- {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops, NULL},
+ [12] = { "oldmem", 0, &oldmem_fops, NULL },
#endif
};
static int memory_open(struct inode *inode, struct file *filp)
{
- int ret = 0;
- int i;
+ int minor;
+ const struct memdev *dev;
+ int ret = -ENXIO;
lock_kernel();
- for (i = 0; i < ARRAY_SIZE(devlist); i++) {
- if (devlist[i].minor == iminor(inode)) {
- filp->f_op = devlist[i].fops;
- if (devlist[i].dev_info) {
- filp->f_mapping->backing_dev_info =
- devlist[i].dev_info;
- }
+ minor = iminor(inode);
+ if (minor >= ARRAY_SIZE(devlist))
+ goto out;
- break;
- }
- }
+ dev = &devlist[minor];
+ if (!dev->fops)
+ goto out;
- if (i == ARRAY_SIZE(devlist))
- ret = -ENXIO;
- else
- if (filp->f_op && filp->f_op->open)
- ret = filp->f_op->open(inode, filp);
+ filp->f_op = dev->fops;
+ if (dev->dev_info)
+ filp->f_mapping->backing_dev_info = dev->dev_info;
+ if (dev->fops->open)
+ ret = dev->fops->open(inode, filp);
+ else
+ ret = 0;
+out:
unlock_kernel();
return ret;
}
static const struct file_operations memory_fops = {
- .open = memory_open, /* just a selector for the real open */
+ .open = memory_open,
};
+static char *mem_devnode(struct device *dev, mode_t *mode)
+{
+ if (mode && devlist[MINOR(dev->devt)].mode)
+ *mode = devlist[MINOR(dev->devt)].mode;
+ return NULL;
+}
+
static struct class *mem_class;
static int __init chr_dev_init(void)
{
- int i;
+ int minor;
int err;
err = bdi_init(&zero_bdi);
@@ -939,10 +943,13 @@ static int __init chr_dev_init(void)
printk("unable to get major %d for memory devs\n", MEM_MAJOR);
mem_class = class_create(THIS_MODULE, "mem");
- for (i = 0; i < ARRAY_SIZE(devlist); i++)
- device_create(mem_class, NULL,
- MKDEV(MEM_MAJOR, devlist[i].minor), NULL,
- devlist[i].name);
+ mem_class->devnode = mem_devnode;
+ for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) {
+ if (!devlist[minor].name)
+ continue;
+ device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor),
+ NULL, devlist[minor].name);
+ }
return 0;
}
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 62c99fa59e2b..07fa612a58d5 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -91,7 +91,7 @@ static int misc_seq_show(struct seq_file *seq, void *v)
}
-static struct seq_operations misc_seq_ops = {
+static const struct seq_operations misc_seq_ops = {
.start = misc_seq_start,
.next = misc_seq_next,
.stop = misc_seq_stop,
@@ -263,12 +263,14 @@ int misc_deregister(struct miscdevice *misc)
EXPORT_SYMBOL(misc_register);
EXPORT_SYMBOL(misc_deregister);
-static char *misc_nodename(struct device *dev)
+static char *misc_devnode(struct device *dev, mode_t *mode)
{
struct miscdevice *c = dev_get_drvdata(dev);
- if (c->devnode)
- return kstrdup(c->devnode, GFP_KERNEL);
+ if (mode && c->mode)
+ *mode = c->mode;
+ if (c->nodename)
+ return kstrdup(c->nodename, GFP_KERNEL);
return NULL;
}
@@ -287,7 +289,7 @@ static int __init misc_init(void)
err = -EIO;
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))
goto fail_printk;
- misc_class->nodename = misc_nodename;
+ misc_class->devnode = misc_devnode;
return 0;
fail_printk:
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index 30f095a8c2d4..1997270bb6f4 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -239,7 +239,7 @@ mspec_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
return VM_FAULT_NOPAGE;
}
-static struct vm_operations_struct mspec_vm_ops = {
+static const struct vm_operations_struct mspec_vm_ops = {
.open = mspec_open,
.close = mspec_close,
.fault = mspec_fault,
diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c
index 94ad2c3bfc4a..a4ec50c95072 100644
--- a/drivers/char/mwave/mwavedd.c
+++ b/drivers/char/mwave/mwavedd.c
@@ -281,12 +281,6 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
case IOCTL_MW_REGISTER_IPC: {
unsigned int ipcnum = (unsigned int) ioarg;
- PRINTK_3(TRACE_MWAVE,
- "mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"
- " ipcnum %x entry usIntCount %x\n",
- ipcnum,
- pDrvData->IPCs[ipcnum].usIntCount);
-
if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::mwave_ioctl:"
@@ -295,6 +289,12 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
ipcnum);
return -EINVAL;
}
+ PRINTK_3(TRACE_MWAVE,
+ "mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"
+ " ipcnum %x entry usIntCount %x\n",
+ ipcnum,
+ pDrvData->IPCs[ipcnum].usIntCount);
+
lock_kernel();
pDrvData->IPCs[ipcnum].bIsHere = FALSE;
pDrvData->IPCs[ipcnum].bIsEnabled = TRUE;
@@ -310,11 +310,6 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
case IOCTL_MW_GET_IPC: {
unsigned int ipcnum = (unsigned int) ioarg;
- PRINTK_3(TRACE_MWAVE,
- "mwavedd::mwave_ioctl IOCTL_MW_GET_IPC"
- " ipcnum %x, usIntCount %x\n",
- ipcnum,
- pDrvData->IPCs[ipcnum].usIntCount);
if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::mwave_ioctl:"
@@ -322,6 +317,11 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
" Invalid ipcnum %x\n", ipcnum);
return -EINVAL;
}
+ PRINTK_3(TRACE_MWAVE,
+ "mwavedd::mwave_ioctl IOCTL_MW_GET_IPC"
+ " ipcnum %x, usIntCount %x\n",
+ ipcnum,
+ pDrvData->IPCs[ipcnum].usIntCount);
lock_kernel();
if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) {
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index dbf8d52f31d0..5e28d39b9e81 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -48,7 +48,7 @@
#include "mxser.h"
-#define MXSER_VERSION "2.0.4" /* 1.12 */
+#define MXSER_VERSION "2.0.5" /* 1.14 */
#define MXSERMAJOR 174
#define MXSER_BOARDS 4 /* Max. boards */
@@ -69,6 +69,7 @@
#define PCI_DEVICE_ID_POS104UL 0x1044
#define PCI_DEVICE_ID_CB108 0x1080
#define PCI_DEVICE_ID_CP102UF 0x1023
+#define PCI_DEVICE_ID_CP112UL 0x1120
#define PCI_DEVICE_ID_CB114 0x1142
#define PCI_DEVICE_ID_CP114UL 0x1143
#define PCI_DEVICE_ID_CB134I 0x1341
@@ -139,7 +140,8 @@ static const struct mxser_cardinfo mxser_cards[] = {
{ "CP-138U series", 8, },
{ "POS-104UL series", 4, },
{ "CP-114UL series", 4, },
-/*30*/ { "CP-102UF series", 2, }
+/*30*/ { "CP-102UF series", 2, },
+ { "CP-112UL series", 2, },
};
/* driver_data correspond to the lines in the structure above
@@ -170,6 +172,7 @@ static struct pci_device_id mxser_pcibrds[] = {
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL), .driver_data = 28 },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL), .driver_data = 29 },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP102UF), .driver_data = 30 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP112UL), .driver_data = 31 },
{ }
};
MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
@@ -258,7 +261,6 @@ struct mxser_port {
struct mxser_mon mon_data;
spinlock_t slock;
- wait_queue_head_t delta_msr_wait;
};
struct mxser_board {
@@ -818,7 +820,7 @@ static void mxser_check_modem_status(struct tty_struct *tty,
if (status & UART_MSR_DCTS)
port->icount.cts++;
port->mon_data.modem_status = status;
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
if ((port->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
if (status & UART_MSR_DCD)
@@ -973,7 +975,7 @@ static void mxser_shutdown(struct tty_struct *tty)
* clear delta_msr_wait queue to avoid mem leaks: we may free the irq
* here so the queue might never be waken up
*/
- wake_up_interruptible(&info->delta_msr_wait);
+ wake_up_interruptible(&info->port.delta_msr_wait);
/*
* Free the IRQ, if necessary
@@ -1073,34 +1075,17 @@ static void mxser_flush_buffer(struct tty_struct *tty)
}
-/*
- * This routine is called when the serial port gets closed. First, we
- * wait for the last remaining data to be sent. Then, we unlink its
- * async structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- */
-static void mxser_close(struct tty_struct *tty, struct file *filp)
+static void mxser_close_port(struct tty_struct *tty, struct tty_port *port)
{
- struct mxser_port *info = tty->driver_data;
- struct tty_port *port = &info->port;
-
+ struct mxser_port *info = container_of(port, struct mxser_port, port);
unsigned long timeout;
-
- if (tty->index == MXSER_PORTS)
- return;
- if (!info)
- return;
-
- if (tty_port_close_start(port, tty, filp) == 0)
- return;
-
/*
* Save the termios structure, since this port may have
* separate termios for callout and dialin.
*
* FIXME: Can this go ?
*/
- if (info->port.flags & ASYNC_NORMAL_ACTIVE)
+ if (port->flags & ASYNC_NORMAL_ACTIVE)
info->normal_termios = *tty->termios;
/*
* At this point we stop accepting input. To do this, we
@@ -1112,7 +1097,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
if (info->board->chip_flag)
info->IER &= ~MOXA_MUST_RECV_ISR;
- if (info->port.flags & ASYNC_INITIALIZED) {
+ if (port->flags & ASYNC_INITIALIZED) {
outb(info->IER, info->ioaddr + UART_IER);
/*
* Before we drop DTR, make sure the UART transmitter
@@ -1127,8 +1112,26 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
}
}
mxser_shutdown(tty);
- mxser_flush_buffer(tty);
+}
+
+/*
+ * This routine is called when the serial port gets closed. First, we
+ * wait for the last remaining data to be sent. Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ */
+static void mxser_close(struct tty_struct *tty, struct file *filp)
+{
+ struct mxser_port *info = tty->driver_data;
+ struct tty_port *port = &info->port;
+
+ if (tty->index == MXSER_PORTS)
+ return;
+ if (tty_port_close_start(port, tty, filp) == 0)
+ return;
+ mxser_close_port(tty, port);
+ mxser_flush_buffer(tty);
/* Right now the tty_port set is done outside of the close_end helper
as we don't yet have everyone using refcounts */
tty_port_close_end(port, tty);
@@ -1761,7 +1764,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
cnow = info->icount; /* note the counters on entry */
spin_unlock_irqrestore(&info->slock, flags);
- return wait_event_interruptible(info->delta_msr_wait,
+ return wait_event_interruptible(info->port.delta_msr_wait,
mxser_cflags_changed(info, arg, &cnow));
/*
* Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
@@ -1803,7 +1806,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
lock_kernel();
len = mxser_chars_in_buffer(tty);
- lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT;
+ lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE;
len += (lsr ? 0 : 1);
unlock_kernel();
@@ -2413,7 +2416,6 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
info->port.close_delay = 5 * HZ / 10;
info->port.closing_wait = 30 * HZ;
info->normal_termios = mxvar_sdriver->init_termios;
- init_waitqueue_head(&info->delta_msr_wait);
memset(&info->mon_data, 0, sizeof(struct mxser_mon));
info->err_shadow = 0;
spin_lock_init(&info->slock);
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 4e28b35024ec..2e50f4dfc79c 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -272,7 +272,8 @@ static inline int is_continuation(unsigned char c, struct tty_struct *tty)
*
* This is a helper function that handles one output character
* (including special characters like TAB, CR, LF, etc.),
- * putting the results in the tty driver's write buffer.
+ * doing OPOST processing and putting the results in the
+ * tty driver's write buffer.
*
* Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY
* and NLDLY. They simply aren't relevant in the world today.
@@ -350,8 +351,9 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
* @c: character (or partial unicode symbol)
* @tty: terminal device
*
- * Perform OPOST processing. Returns -1 when the output device is
- * full and the character must be retried.
+ * Output one character with OPOST processing.
+ * Returns -1 when the output device is full and the character
+ * must be retried.
*
* Locking: output_lock to protect column state and space left
* (also, this is called from n_tty_write under the
@@ -377,8 +379,11 @@ static int process_output(unsigned char c, struct tty_struct *tty)
/**
* process_output_block - block post processor
* @tty: terminal device
- * @inbuf: user buffer
- * @nr: number of bytes
+ * @buf: character buffer
+ * @nr: number of bytes to output
+ *
+ * Output a block of characters with OPOST processing.
+ * Returns the number of characters output.
*
* This path is used to speed up block console writes, among other
* things when processing blocks of output data. It handles only
@@ -571,33 +576,23 @@ static void process_echoes(struct tty_struct *tty)
break;
default:
- if (iscntrl(op)) {
- if (L_ECHOCTL(tty)) {
- /*
- * Ensure there is enough space
- * for the whole ctrl pair.
- */
- if (space < 2) {
- no_space_left = 1;
- break;
- }
- tty_put_char(tty, '^');
- tty_put_char(tty, op ^ 0100);
- tty->column += 2;
- space -= 2;
- } else {
- if (!space) {
- no_space_left = 1;
- break;
- }
- tty_put_char(tty, op);
- space--;
- }
- }
/*
- * If above falls through, this was an
- * undefined op.
+ * If the op is not a special byte code,
+ * it is a ctrl char tagged to be echoed
+ * as "^X" (where X is the letter
+ * representing the control char).
+ * Note that we must ensure there is
+ * enough space for the whole ctrl pair.
+ *
*/
+ if (space < 2) {
+ no_space_left = 1;
+ break;
+ }
+ tty_put_char(tty, '^');
+ tty_put_char(tty, op ^ 0100);
+ tty->column += 2;
+ space -= 2;
cp += 2;
nr -= 2;
}
@@ -605,12 +600,18 @@ static void process_echoes(struct tty_struct *tty)
if (no_space_left)
break;
} else {
- int retval;
-
- retval = do_output_char(c, tty, space);
- if (retval < 0)
- break;
- space -= retval;
+ if (O_OPOST(tty) &&
+ !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
+ int retval = do_output_char(c, tty, space);
+ if (retval < 0)
+ break;
+ space -= retval;
+ } else {
+ if (!space)
+ break;
+ tty_put_char(tty, c);
+ space -= 1;
+ }
cp += 1;
nr -= 1;
}
@@ -798,8 +799,8 @@ static void echo_char_raw(unsigned char c, struct tty_struct *tty)
* Echo user input back onto the screen. This must be called only when
* L_ECHO(tty) is true. Called from the driver receive_buf path.
*
- * This variant tags control characters to be possibly echoed as
- * as "^X" (where X is the letter representing the control char).
+ * This variant tags control characters to be echoed as "^X"
+ * (where X is the letter representing the control char).
*
* Locking: echo_lock to protect the echo buffer
*/
@@ -812,7 +813,7 @@ static void echo_char(unsigned char c, struct tty_struct *tty)
add_echo_byte(ECHO_OP_START, tty);
add_echo_byte(ECHO_OP_START, tty);
} else {
- if (iscntrl(c) && c != '\t')
+ if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t')
add_echo_byte(ECHO_OP_START, tty);
add_echo_byte(c, tty);
}
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
index ec58d8c387ff..d3400b20444f 100644
--- a/drivers/char/nozomi.c
+++ b/drivers/char/nozomi.c
@@ -48,6 +48,7 @@
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
+#include <linux/sched.h>
#include <linux/serial.h>
#include <linux/interrupt.h>
#include <linux/kmod.h>
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 881934c068c8..2db4c0a29b05 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -23,8 +23,6 @@
* All rights reserved. Licensed under dual BSD/GPL license.
*/
-/* #define PCMCIA_DEBUG 6 */
-
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -47,18 +45,17 @@
/* #define ATR_CSUM */
-#ifdef PCMCIA_DEBUG
-#define reader_to_dev(x) (&handle_to_dev(x->p_dev))
-static int pc_debug = PCMCIA_DEBUG;
-module_param(pc_debug, int, 0600);
-#define DEBUGP(n, rdr, x, args...) do { \
- if (pc_debug >= (n)) \
- dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \
- __func__ , ## args); \
+#define reader_to_dev(x) (&x->p_dev->dev)
+
+/* n (debug level) is ignored */
+/* additional debug output may be enabled by re-compiling with
+ * CM4000_DEBUG set */
+/* #define CM4000_DEBUG */
+#define DEBUGP(n, rdr, x, args...) do { \
+ dev_dbg(reader_to_dev(rdr), "%s:" x, \
+ __func__ , ## args); \
} while (0)
-#else
-#define DEBUGP(n, rdr, x, args...)
-#endif
+
static char *version = "cm4000_cs.c v2.4.0gm6 - All bugs added by Harald Welte";
#define T_1SEC (HZ)
@@ -174,14 +171,13 @@ static unsigned char fi_di_table[10][14] = {
/* 9 */ {0x09,0x19,0x29,0x39,0x49,0x59,0x69,0x11,0x11,0x99,0xA9,0xB9,0xC9,0xD9}
};
-#ifndef PCMCIA_DEBUG
+#ifndef CM4000_DEBUG
#define xoutb outb
#define xinb inb
#else
static inline void xoutb(unsigned char val, unsigned short port)
{
- if (pc_debug >= 7)
- printk(KERN_DEBUG "outb(val=%.2x,port=%.4x)\n", val, port);
+ pr_debug("outb(val=%.2x,port=%.4x)\n", val, port);
outb(val, port);
}
static inline unsigned char xinb(unsigned short port)
@@ -189,8 +185,7 @@ static inline unsigned char xinb(unsigned short port)
unsigned char val;
val = inb(port);
- if (pc_debug >= 7)
- printk(KERN_DEBUG "%.2x=inb(%.4x)\n", val, port);
+ pr_debug("%.2x=inb(%.4x)\n", val, port);
return val;
}
@@ -514,12 +509,10 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq)
for (i = 0; i < 4; i++) {
xoutb(i, REG_BUF_ADDR(iobase));
xoutb(dev->pts[i], REG_BUF_DATA(iobase)); /* buf data */
-#ifdef PCMCIA_DEBUG
- if (pc_debug >= 5)
- printk("0x%.2x ", dev->pts[i]);
+#ifdef CM4000_DEBUG
+ pr_debug("0x%.2x ", dev->pts[i]);
}
- if (pc_debug >= 5)
- printk("\n");
+ pr_debug("\n");
#else
}
#endif
@@ -579,14 +572,13 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq)
pts_reply[i] = inb(REG_BUF_DATA(iobase));
}
-#ifdef PCMCIA_DEBUG
+#ifdef CM4000_DEBUG
DEBUGP(2, dev, "PTSreply: ");
for (i = 0; i < num_bytes_read; i++) {
- if (pc_debug >= 5)
- printk("0x%.2x ", pts_reply[i]);
+ pr_debug("0x%.2x ", pts_reply[i]);
}
- printk("\n");
-#endif /* PCMCIA_DEBUG */
+ pr_debug("\n");
+#endif /* CM4000_DEBUG */
DEBUGP(5, dev, "Clear Tactive in Flags1\n");
xoutb(0x20, REG_FLAGS1(iobase));
@@ -655,7 +647,7 @@ static void terminate_monitor(struct cm4000_dev *dev)
DEBUGP(5, dev, "Delete timer\n");
del_timer_sync(&dev->timer);
-#ifdef PCMCIA_DEBUG
+#ifdef CM4000_DEBUG
dev->monitor_running = 0;
#endif
@@ -898,7 +890,7 @@ static void monitor_card(unsigned long p)
DEBUGP(4, dev, "ATR checksum (0x%.2x, should "
"be zero) failed\n", dev->atr_csum);
}
-#ifdef PCMCIA_DEBUG
+#ifdef CM4000_DEBUG
else if (test_bit(IS_BAD_LENGTH, &dev->flags)) {
DEBUGP(4, dev, "ATR length error\n");
} else {
@@ -1017,7 +1009,7 @@ static ssize_t cmm_read(struct file *filp, __user char *buf, size_t count,
}
}
- if (dev->proto == 0 && count > dev->rlen - dev->rpos) {
+ if (dev->proto == 0 && count > dev->rlen - dev->rpos && i) {
DEBUGP(4, dev, "T=0 and count > buffer\n");
dev->rbuf[i] = dev->rbuf[i - 1];
dev->rbuf[i - 1] = dev->procbyte;
@@ -1415,7 +1407,7 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
int size;
int rc;
void __user *argp = (void __user *)arg;
-#ifdef PCMCIA_DEBUG
+#ifdef CM4000_DEBUG
char *ioctl_names[CM_IOC_MAXNR + 1] = {
[_IOC_NR(CM_IOCGSTATUS)] "CM_IOCGSTATUS",
[_IOC_NR(CM_IOCGATR)] "CM_IOCGATR",
@@ -1423,9 +1415,9 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
[_IOC_NR(CM_IOCSPTS)] "CM_IOCSPTS",
[_IOC_NR(CM_IOSDBGLVL)] "CM4000_DBGLVL",
};
-#endif
DEBUGP(3, dev, "cmm_ioctl(device=%d.%d) %s\n", imajor(inode),
iminor(inode), ioctl_names[_IOC_NR(cmd)]);
+#endif
lock_kernel();
rc = -ENODEV;
@@ -1523,7 +1515,7 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
case CM_IOCARDOFF:
-#ifdef PCMCIA_DEBUG
+#ifdef CM4000_DEBUG
DEBUGP(4, dev, "... in CM_IOCARDOFF\n");
if (dev->flags0 & 0x01) {
DEBUGP(4, dev, " Card inserted\n");
@@ -1625,18 +1617,9 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
break;
-#ifdef PCMCIA_DEBUG
- case CM_IOSDBGLVL: /* set debug log level */
- {
- int old_pc_debug = 0;
-
- old_pc_debug = pc_debug;
- if (copy_from_user(&pc_debug, argp, sizeof(int)))
- rc = -EFAULT;
- else if (old_pc_debug != pc_debug)
- DEBUGP(0, dev, "Changed debug log level "
- "to %i\n", pc_debug);
- }
+#ifdef CM4000_DEBUG
+ case CM_IOSDBGLVL:
+ rc = -ENOTTY;
break;
#endif
default:
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index 4f0723b07974..a6a70e476bea 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -17,8 +17,6 @@
* All rights reserved, Dual BSD/GPL Licensed.
*/
-/* #define PCMCIA_DEBUG 6 */
-
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -41,18 +39,16 @@
#include "cm4040_cs.h"
-#ifdef PCMCIA_DEBUG
-#define reader_to_dev(x) (&handle_to_dev(x->p_dev))
-static int pc_debug = PCMCIA_DEBUG;
-module_param(pc_debug, int, 0600);
-#define DEBUGP(n, rdr, x, args...) do { \
- if (pc_debug >= (n)) \
- dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \
- __func__ , ##args); \
+#define reader_to_dev(x) (&x->p_dev->dev)
+
+/* n (debug level) is ignored */
+/* additional debug output may be enabled by re-compiling with
+ * CM4040_DEBUG set */
+/* #define CM4040_DEBUG */
+#define DEBUGP(n, rdr, x, args...) do { \
+ dev_dbg(reader_to_dev(rdr), "%s:" x, \
+ __func__ , ## args); \
} while (0)
-#else
-#define DEBUGP(n, rdr, x, args...)
-#endif
static char *version =
"OMNIKEY CardMan 4040 v1.1.0gm5 - All bugs added by Harald Welte";
@@ -90,14 +86,13 @@ struct reader_dev {
static struct pcmcia_device *dev_table[CM_MAX_DEV];
-#ifndef PCMCIA_DEBUG
+#ifndef CM4040_DEBUG
#define xoutb outb
#define xinb inb
#else
static inline void xoutb(unsigned char val, unsigned short port)
{
- if (pc_debug >= 7)
- printk(KERN_DEBUG "outb(val=%.2x,port=%.4x)\n", val, port);
+ pr_debug("outb(val=%.2x,port=%.4x)\n", val, port);
outb(val, port);
}
@@ -106,8 +101,7 @@ static inline unsigned char xinb(unsigned short port)
unsigned char val;
val = inb(port);
- if (pc_debug >= 7)
- printk(KERN_DEBUG "%.2x=inb(%.4x)\n", val, port);
+ pr_debug("%.2x=inb(%.4x)\n", val, port);
return val;
}
#endif
@@ -260,23 +254,22 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf,
return -EIO;
}
dev->r_buf[i] = xinb(iobase + REG_OFFSET_BULK_IN);
-#ifdef PCMCIA_DEBUG
- if (pc_debug >= 6)
- printk(KERN_DEBUG "%lu:%2x ", i, dev->r_buf[i]);
+#ifdef CM4040_DEBUG
+ pr_debug("%lu:%2x ", i, dev->r_buf[i]);
}
- printk("\n");
+ pr_debug("\n");
#else
}
#endif
bytes_to_read = 5 + le32_to_cpu(*(__le32 *)&dev->r_buf[1]);
- DEBUGP(6, dev, "BytesToRead=%lu\n", bytes_to_read);
+ DEBUGP(6, dev, "BytesToRead=%zu\n", bytes_to_read);
min_bytes_to_read = min(count, bytes_to_read + 5);
min_bytes_to_read = min_t(size_t, min_bytes_to_read, READ_WRITE_BUFFER_SIZE);
- DEBUGP(6, dev, "Min=%lu\n", min_bytes_to_read);
+ DEBUGP(6, dev, "Min=%zu\n", min_bytes_to_read);
for (i = 0; i < (min_bytes_to_read-5); i++) {
rc = wait_for_bulk_in_ready(dev);
@@ -288,11 +281,10 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf,
return -EIO;
}
dev->r_buf[i+5] = xinb(iobase + REG_OFFSET_BULK_IN);
-#ifdef PCMCIA_DEBUG
- if (pc_debug >= 6)
- printk(KERN_DEBUG "%lu:%2x ", i, dev->r_buf[i]);
+#ifdef CM4040_DEBUG
+ pr_debug("%lu:%2x ", i, dev->r_buf[i]);
}
- printk("\n");
+ pr_debug("\n");
#else
}
#endif
@@ -547,7 +539,7 @@ static int cm4040_config_check(struct pcmcia_device *p_dev,
p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK;
rc = pcmcia_request_io(p_dev, &p_dev->io);
- dev_printk(KERN_INFO, &handle_to_dev(p_dev),
+ dev_printk(KERN_INFO, &p_dev->dev,
"pcmcia_request_io returned 0x%x\n", rc);
return rc;
}
@@ -569,7 +561,7 @@ static int reader_config(struct pcmcia_device *link, int devno)
fail_rc = pcmcia_request_configuration(link, &link->conf);
if (fail_rc != 0) {
- dev_printk(KERN_INFO, &handle_to_dev(link),
+ dev_printk(KERN_INFO, &link->dev,
"pcmcia_request_configuration failed 0x%x\n",
fail_rc);
goto cs_release;
diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c
index 4c1820cad712..99cffdab1056 100644
--- a/drivers/char/pcmcia/ipwireless/hardware.c
+++ b/drivers/char/pcmcia/ipwireless/hardware.c
@@ -1213,12 +1213,12 @@ static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq,
irqreturn_t ipwireless_interrupt(int irq, void *dev_id)
{
- struct ipw_hardware *hw = dev_id;
+ struct ipw_dev *ipw = dev_id;
- if (hw->hw_version == HW_VERSION_1)
- return ipwireless_handle_v1_interrupt(irq, hw);
+ if (ipw->hardware->hw_version == HW_VERSION_1)
+ return ipwireless_handle_v1_interrupt(irq, ipw->hardware);
else
- return ipwireless_handle_v2_v3_interrupt(irq, hw);
+ return ipwireless_handle_v2_v3_interrupt(irq, ipw->hardware);
}
static void flush_packets_to_hw(struct ipw_hardware *hw)
diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c
index 5216fce0c62d..dff24dae1485 100644
--- a/drivers/char/pcmcia/ipwireless/main.c
+++ b/drivers/char/pcmcia/ipwireless/main.c
@@ -65,10 +65,7 @@ static void signalled_reboot_work(struct work_struct *work_reboot)
struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev,
work_reboot);
struct pcmcia_device *link = ipw->link;
- int ret = pcmcia_reset_card(link->socket);
-
- if (ret != 0)
- cs_error(link, ResetCard, ret);
+ pcmcia_reset_card(link->socket);
}
static void signalled_reboot_callback(void *callback_data)
@@ -79,208 +76,127 @@ static void signalled_reboot_callback(void *callback_data)
schedule_work(&ipw->work_reboot);
}
-static int config_ipwireless(struct ipw_dev *ipw)
+static int ipwireless_probe(struct pcmcia_device *p_dev,
+ cistpl_cftable_entry_t *cfg,
+ cistpl_cftable_entry_t *dflt,
+ unsigned int vcc,
+ void *priv_data)
{
- struct pcmcia_device *link = ipw->link;
- int ret;
- tuple_t tuple;
- unsigned short buf[64];
- cisparse_t parse;
- unsigned short cor_value;
+ struct ipw_dev *ipw = priv_data;
+ struct resource *io_resource;
memreq_t memreq_attr_memory;
memreq_t memreq_common_memory;
+ int ret;
- ipw->is_v2_card = 0;
-
- tuple.Attributes = 0;
- tuple.TupleData = (cisdata_t *) buf;
- tuple.TupleDataMax = sizeof(buf);
- tuple.TupleOffset = 0;
-
- tuple.DesiredTuple = RETURN_FIRST_TUPLE;
-
- ret = pcmcia_get_first_tuple(link, &tuple);
-
- while (ret == 0) {
- ret = pcmcia_get_tuple_data(link, &tuple);
-
- if (ret != 0) {
- cs_error(link, GetTupleData, ret);
- goto exit0;
- }
- ret = pcmcia_get_next_tuple(link, &tuple);
- }
-
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-
- ret = pcmcia_get_first_tuple(link, &tuple);
-
- if (ret != 0) {
- cs_error(link, GetFirstTuple, ret);
- goto exit0;
- }
-
- ret = pcmcia_get_tuple_data(link, &tuple);
-
- if (ret != 0) {
- cs_error(link, GetTupleData, ret);
- goto exit0;
- }
-
- ret = pcmcia_parse_tuple(&tuple, &parse);
-
- if (ret != 0) {
- cs_error(link, ParseTuple, ret);
- goto exit0;
- }
-
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
- link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
- link->io.IOAddrLines = 16;
-
- link->irq.IRQInfo1 = parse.cftable_entry.irq.IRQInfo1;
+ p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ p_dev->io.BasePort1 = cfg->io.win[0].base;
+ p_dev->io.NumPorts1 = cfg->io.win[0].len;
+ p_dev->io.IOAddrLines = 16;
/* 0x40 causes it to generate level mode interrupts. */
/* 0x04 enables IREQ pin. */
- cor_value = parse.cftable_entry.index | 0x44;
- link->conf.ConfigIndex = cor_value;
+ p_dev->conf.ConfigIndex = cfg->index | 0x44;
+ ret = pcmcia_request_io(p_dev, &p_dev->io);
+ if (ret)
+ return ret;
- /* IRQ and I/O settings */
- tuple.DesiredTuple = CISTPL_CONFIG;
+ io_resource = request_region(p_dev->io.BasePort1, p_dev->io.NumPorts1,
+ IPWIRELESS_PCCARD_NAME);
- ret = pcmcia_get_first_tuple(link, &tuple);
+ if (cfg->mem.nwin == 0)
+ return 0;
- if (ret != 0) {
- cs_error(link, GetFirstTuple, ret);
- goto exit0;
- }
+ ipw->request_common_memory.Attributes =
+ WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;
+ ipw->request_common_memory.Base = cfg->mem.win[0].host_addr;
+ ipw->request_common_memory.Size = cfg->mem.win[0].len;
+ if (ipw->request_common_memory.Size < 0x1000)
+ ipw->request_common_memory.Size = 0x1000;
+ ipw->request_common_memory.AccessSpeed = 0;
- ret = pcmcia_get_tuple_data(link, &tuple);
-
- if (ret != 0) {
- cs_error(link, GetTupleData, ret);
- goto exit0;
- }
+ ret = pcmcia_request_window(p_dev, &ipw->request_common_memory,
+ &ipw->handle_common_memory);
- ret = pcmcia_parse_tuple(&tuple, &parse);
+ if (ret != 0)
+ goto exit1;
- if (ret != 0) {
- cs_error(link, GetTupleData, ret);
- goto exit0;
- }
- link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.ConfigBase = parse.config.base;
- link->conf.Present = parse.config.rmask[0];
- link->conf.IntType = INT_MEMORY_AND_IO;
+ memreq_common_memory.CardOffset = cfg->mem.win[0].card_addr;
+ memreq_common_memory.Page = 0;
- link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
- link->irq.Handler = ipwireless_interrupt;
- link->irq.Instance = ipw->hardware;
+ ret = pcmcia_map_mem_page(p_dev, ipw->handle_common_memory,
+ &memreq_common_memory);
- ret = pcmcia_request_io(link, &link->io);
+ if (ret != 0)
+ goto exit2;
- if (ret != 0) {
- cs_error(link, RequestIO, ret);
- goto exit0;
- }
+ ipw->is_v2_card = cfg->mem.win[0].len == 0x100;
- request_region(link->io.BasePort1, link->io.NumPorts1,
+ ipw->common_memory = ioremap(ipw->request_common_memory.Base,
+ ipw->request_common_memory.Size);
+ request_mem_region(ipw->request_common_memory.Base,
+ ipw->request_common_memory.Size,
IPWIRELESS_PCCARD_NAME);
- /* memory settings */
-
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-
- ret = pcmcia_get_first_tuple(link, &tuple);
-
- if (ret != 0) {
- cs_error(link, GetFirstTuple, ret);
- goto exit1;
- }
-
- ret = pcmcia_get_tuple_data(link, &tuple);
+ ipw->request_attr_memory.Attributes =
+ WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE;
+ ipw->request_attr_memory.Base = 0;
+ ipw->request_attr_memory.Size = 0; /* this used to be 0x1000 */
+ ipw->request_attr_memory.AccessSpeed = 0;
- if (ret != 0) {
- cs_error(link, GetTupleData, ret);
- goto exit1;
- }
-
- ret = pcmcia_parse_tuple(&tuple, &parse);
-
- if (ret != 0) {
- cs_error(link, ParseTuple, ret);
- goto exit1;
- }
+ ret = pcmcia_request_window(p_dev, &ipw->request_attr_memory,
+ &ipw->handle_attr_memory);
- if (parse.cftable_entry.mem.nwin > 0) {
- ipw->request_common_memory.Attributes =
- WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;
- ipw->request_common_memory.Base =
- parse.cftable_entry.mem.win[0].host_addr;
- ipw->request_common_memory.Size = parse.cftable_entry.mem.win[0].len;
- if (ipw->request_common_memory.Size < 0x1000)
- ipw->request_common_memory.Size = 0x1000;
- ipw->request_common_memory.AccessSpeed = 0;
-
- ret = pcmcia_request_window(&link, &ipw->request_common_memory,
- &ipw->handle_common_memory);
+ if (ret != 0)
+ goto exit2;
- if (ret != 0) {
- cs_error(link, RequestWindow, ret);
- goto exit1;
- }
+ memreq_attr_memory.CardOffset = 0;
+ memreq_attr_memory.Page = 0;
- memreq_common_memory.CardOffset =
- parse.cftable_entry.mem.win[0].card_addr;
- memreq_common_memory.Page = 0;
+ ret = pcmcia_map_mem_page(p_dev, ipw->handle_attr_memory,
+ &memreq_attr_memory);
- ret = pcmcia_map_mem_page(ipw->handle_common_memory,
- &memreq_common_memory);
+ if (ret != 0)
+ goto exit3;
- if (ret != 0) {
- cs_error(link, MapMemPage, ret);
- goto exit1;
- }
+ ipw->attr_memory = ioremap(ipw->request_attr_memory.Base,
+ ipw->request_attr_memory.Size);
+ request_mem_region(ipw->request_attr_memory.Base,
+ ipw->request_attr_memory.Size, IPWIRELESS_PCCARD_NAME);
- ipw->is_v2_card =
- parse.cftable_entry.mem.win[0].len == 0x100;
+ return 0;
- ipw->common_memory = ioremap(ipw->request_common_memory.Base,
+exit3:
+ pcmcia_release_window(p_dev, ipw->handle_attr_memory);
+exit2:
+ if (ipw->common_memory) {
+ release_mem_region(ipw->request_common_memory.Base,
ipw->request_common_memory.Size);
- request_mem_region(ipw->request_common_memory.Base,
- ipw->request_common_memory.Size, IPWIRELESS_PCCARD_NAME);
-
- ipw->request_attr_memory.Attributes =
- WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE;
- ipw->request_attr_memory.Base = 0;
- ipw->request_attr_memory.Size = 0; /* this used to be 0x1000 */
- ipw->request_attr_memory.AccessSpeed = 0;
-
- ret = pcmcia_request_window(&link, &ipw->request_attr_memory,
- &ipw->handle_attr_memory);
+ iounmap(ipw->common_memory);
+ pcmcia_release_window(p_dev, ipw->handle_common_memory);
+ } else
+ pcmcia_release_window(p_dev, ipw->handle_common_memory);
+exit1:
+ release_resource(io_resource);
+ pcmcia_disable_device(p_dev);
+ return -1;
+}
- if (ret != 0) {
- cs_error(link, RequestWindow, ret);
- goto exit2;
- }
+static int config_ipwireless(struct ipw_dev *ipw)
+{
+ struct pcmcia_device *link = ipw->link;
+ int ret = 0;
- memreq_attr_memory.CardOffset = 0;
- memreq_attr_memory.Page = 0;
+ ipw->is_v2_card = 0;
- ret = pcmcia_map_mem_page(ipw->handle_attr_memory,
- &memreq_attr_memory);
+ ret = pcmcia_loop_config(link, ipwireless_probe, ipw);
+ if (ret != 0)
+ return ret;
- if (ret != 0) {
- cs_error(link, MapMemPage, ret);
- goto exit2;
- }
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.IntType = INT_MEMORY_AND_IO;
- ipw->attr_memory = ioremap(ipw->request_attr_memory.Base,
- ipw->request_attr_memory.Size);
- request_mem_region(ipw->request_attr_memory.Base, ipw->request_attr_memory.Size,
- IPWIRELESS_PCCARD_NAME);
- }
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
+ link->irq.Handler = ipwireless_interrupt;
INIT_WORK(&ipw->work_reboot, signalled_reboot_work);
@@ -291,10 +207,8 @@ static int config_ipwireless(struct ipw_dev *ipw)
ret = pcmcia_request_irq(link, &link->irq);
- if (ret != 0) {
- cs_error(link, RequestIRQ, ret);
- goto exit3;
- }
+ if (ret != 0)
+ goto exit;
printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n",
ipw->is_v2_card ? "V2/V3" : "V1");
@@ -316,12 +230,12 @@ static int config_ipwireless(struct ipw_dev *ipw)
ipw->network = ipwireless_network_create(ipw->hardware);
if (!ipw->network)
- goto exit3;
+ goto exit;
ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network,
ipw->nodes);
if (!ipw->tty)
- goto exit3;
+ goto exit;
ipwireless_init_hardware_v2_v3(ipw->hardware);
@@ -331,35 +245,27 @@ static int config_ipwireless(struct ipw_dev *ipw)
*/
ret = pcmcia_request_configuration(link, &link->conf);
- if (ret != 0) {
- cs_error(link, RequestConfiguration, ret);
- goto exit4;
- }
+ if (ret != 0)
+ goto exit;
link->dev_node = &ipw->nodes[0];
return 0;
-exit4:
- pcmcia_disable_device(link);
-exit3:
+exit:
if (ipw->attr_memory) {
release_mem_region(ipw->request_attr_memory.Base,
ipw->request_attr_memory.Size);
iounmap(ipw->attr_memory);
- pcmcia_release_window(ipw->handle_attr_memory);
- pcmcia_disable_device(link);
+ pcmcia_release_window(link, ipw->handle_attr_memory);
}
-exit2:
if (ipw->common_memory) {
release_mem_region(ipw->request_common_memory.Base,
ipw->request_common_memory.Size);
iounmap(ipw->common_memory);
- pcmcia_release_window(ipw->handle_common_memory);
+ pcmcia_release_window(link, ipw->handle_common_memory);
}
-exit1:
pcmcia_disable_device(link);
-exit0:
return -1;
}
@@ -378,9 +284,9 @@ static void release_ipwireless(struct ipw_dev *ipw)
iounmap(ipw->attr_memory);
}
if (ipw->common_memory)
- pcmcia_release_window(ipw->handle_common_memory);
+ pcmcia_release_window(ipw->link, ipw->handle_common_memory);
if (ipw->attr_memory)
- pcmcia_release_window(ipw->handle_attr_memory);
+ pcmcia_release_window(ipw->link, ipw->handle_attr_memory);
/* Break the link with Card Services */
pcmcia_disable_device(ipw->link);
@@ -406,7 +312,6 @@ static int ipwireless_attach(struct pcmcia_device *link)
ipw->link = link;
link->priv = ipw;
- link->irq.Instance = ipw;
/* Link this device into our device list. */
link->dev_node = &ipw->nodes[0];
@@ -421,7 +326,6 @@ static int ipwireless_attach(struct pcmcia_device *link)
ret = config_ipwireless(ipw);
if (ret != 0) {
- cs_error(link, RegisterClient, ret);
ipwireless_detach(link);
return ret;
}
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 77b364889224..c31a0d913d37 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -554,7 +554,6 @@ static int mgslpc_probe(struct pcmcia_device *link)
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
- link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = NULL;
link->conf.Attributes = 0;
@@ -572,69 +571,51 @@ static int mgslpc_probe(struct pcmcia_device *link)
/* Card has been inserted.
*/
-#define CS_CHECK(fn, ret) \
-do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+static int mgslpc_ioprobe(struct pcmcia_device *p_dev,
+ cistpl_cftable_entry_t *cfg,
+ cistpl_cftable_entry_t *dflt,
+ unsigned int vcc,
+ void *priv_data)
+{
+ if (cfg->io.nwin > 0) {
+ p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ if (!(cfg->io.flags & CISTPL_IO_8BIT))
+ p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+ if (!(cfg->io.flags & CISTPL_IO_16BIT))
+ p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK;
+ p_dev->io.BasePort1 = cfg->io.win[0].base;
+ p_dev->io.NumPorts1 = cfg->io.win[0].len;
+ return pcmcia_request_io(p_dev, &p_dev->io);
+ }
+ return -ENODEV;
+}
static int mgslpc_config(struct pcmcia_device *link)
{
MGSLPC_INFO *info = link->priv;
- tuple_t tuple;
- cisparse_t parse;
- int last_fn, last_ret;
- u_char buf[64];
- cistpl_cftable_entry_t dflt = { 0 };
- cistpl_cftable_entry_t *cfg;
+ int ret;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("mgslpc_config(0x%p)\n", link);
- tuple.Attributes = 0;
- tuple.TupleData = buf;
- tuple.TupleDataMax = sizeof(buf);
- tuple.TupleOffset = 0;
-
- /* get CIS configuration entry */
-
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
- CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-
- cfg = &(parse.cftable_entry);
- CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
- CS_CHECK(ParseTuple, pcmcia_parse_tuple(&tuple, &parse));
-
- if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
- if (cfg->index == 0)
- goto cs_failed;
-
- link->conf.ConfigIndex = cfg->index;
- link->conf.Attributes |= CONF_ENABLE_IRQ;
-
- /* IO window settings */
- link->io.NumPorts1 = 0;
- if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
- cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(io->flags & CISTPL_IO_8BIT))
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(io->flags & CISTPL_IO_16BIT))
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- link->io.BasePort1 = io->win[0].base;
- link->io.NumPorts1 = io->win[0].len;
- CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
- }
+ ret = pcmcia_loop_config(link, mgslpc_ioprobe, NULL);
+ if (ret != 0)
+ goto failed;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 8;
link->conf.Present = PRESENT_OPTION;
- link->irq.Attributes |= IRQ_HANDLE_PRESENT;
link->irq.Handler = mgslpc_isr;
- link->irq.Instance = info;
- CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
- CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
+ ret = pcmcia_request_irq(link, &link->irq);
+ if (ret)
+ goto failed;
+ ret = pcmcia_request_configuration(link, &link->conf);
+ if (ret)
+ goto failed;
info->io_base = link->io.BasePort1;
info->irq_level = link->irq.AssignedIRQ;
@@ -654,8 +635,7 @@ static int mgslpc_config(struct pcmcia_device *link)
printk("\n");
return 0;
-cs_failed:
- cs_error(link, last_fn, last_ret);
+failed:
mgslpc_release((u_long)link);
return -ENODEV;
}
@@ -4005,10 +3985,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
*
* skb socket buffer containing HDLC frame
* dev pointer to network device structure
- *
- * returns 0 if success, otherwise error code
*/
-static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
MGSLPC_INFO *info = dev_to_port(dev);
unsigned long flags;
@@ -4043,7 +4022,7 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
}
spin_unlock_irqrestore(&info->lock,flags);
- return 0;
+ return NETDEV_TX_OK;
}
/**
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index b33d6688e910..62f282e67638 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -18,6 +18,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/fcntl.h>
+#include <linux/sched.h>
#include <linux/string.h>
#include <linux/major.h>
#include <linux/mm.h>
@@ -120,8 +121,10 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
/* Stuff the data into the input queue of the other end */
c = tty_insert_flip_string(to, buf, c);
/* And shovel */
- tty_flip_buffer_push(to);
- tty_wakeup(tty);
+ if (c) {
+ tty_flip_buffer_push(to);
+ tty_wakeup(tty);
+ }
}
return c;
}
@@ -259,6 +262,9 @@ done:
return 0;
}
+/* Traditional BSD devices */
+#ifdef CONFIG_LEGACY_PTYS
+
static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct tty_struct *o_tty;
@@ -308,24 +314,6 @@ free_mem_out:
return -ENOMEM;
}
-
-static const struct tty_operations pty_ops = {
- .install = pty_install,
- .open = pty_open,
- .close = pty_close,
- .write = pty_write,
- .write_room = pty_write_room,
- .flush_buffer = pty_flush_buffer,
- .chars_in_buffer = pty_chars_in_buffer,
- .unthrottle = pty_unthrottle,
- .set_termios = pty_set_termios,
- .resize = pty_resize
-};
-
-/* Traditional BSD devices */
-#ifdef CONFIG_LEGACY_PTYS
-static struct tty_driver *pty_driver, *pty_slave_driver;
-
static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -339,7 +327,12 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
module_param(legacy_count, int, 0);
-static const struct tty_operations pty_ops_bsd = {
+/*
+ * The master side of a pty can do TIOCSPTLCK and thus
+ * has pty_bsd_ioctl.
+ */
+static const struct tty_operations master_pty_ops_bsd = {
+ .install = pty_install,
.open = pty_open,
.close = pty_close,
.write = pty_write,
@@ -352,8 +345,23 @@ static const struct tty_operations pty_ops_bsd = {
.resize = pty_resize
};
+static const struct tty_operations slave_pty_ops_bsd = {
+ .install = pty_install,
+ .open = pty_open,
+ .close = pty_close,
+ .write = pty_write,
+ .write_room = pty_write_room,
+ .flush_buffer = pty_flush_buffer,
+ .chars_in_buffer = pty_chars_in_buffer,
+ .unthrottle = pty_unthrottle,
+ .set_termios = pty_set_termios,
+ .resize = pty_resize
+};
+
static void __init legacy_pty_init(void)
{
+ struct tty_driver *pty_driver, *pty_slave_driver;
+
if (legacy_count <= 0)
return;
@@ -381,7 +389,7 @@ static void __init legacy_pty_init(void)
pty_driver->init_termios.c_ospeed = 38400;
pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
pty_driver->other = pty_slave_driver;
- tty_set_operations(pty_driver, &pty_ops);
+ tty_set_operations(pty_driver, &master_pty_ops_bsd);
pty_slave_driver->owner = THIS_MODULE;
pty_slave_driver->driver_name = "pty_slave";
@@ -397,7 +405,7 @@ static void __init legacy_pty_init(void)
pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |
TTY_DRIVER_REAL_RAW;
pty_slave_driver->other = pty_driver;
- tty_set_operations(pty_slave_driver, &pty_ops);
+ tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);
if (tty_register_driver(pty_driver))
panic("Couldn't register pty driver");
diff --git a/drivers/char/random.c b/drivers/char/random.c
index d8a9255e1a3f..04b505e5a5e2 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1231,7 +1231,7 @@ static char sysctl_bootid[16];
* as an ASCII string in the standard UUID format. If accesses via the
* sysctl system call, it is returned as 16 bytes of binary data.
*/
-static int proc_do_uuid(ctl_table *table, int write, struct file *filp,
+static int proc_do_uuid(ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
ctl_table fake_table;
@@ -1254,7 +1254,7 @@ static int proc_do_uuid(ctl_table *table, int write, struct file *filp,
fake_table.data = buf;
fake_table.maxlen = sizeof(buf);
- return proc_dostring(&fake_table, write, filp, buffer, lenp, ppos);
+ return proc_dostring(&fake_table, write, buffer, lenp, ppos);
}
static int uuid_strategy(ctl_table *table,
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 05f9d18b9361..64acd05f71c8 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -246,7 +246,7 @@ static const struct file_operations raw_fops = {
.read = do_sync_read,
.aio_read = generic_file_aio_read,
.write = do_sync_write,
- .aio_write = generic_file_aio_write_nolock,
+ .aio_write = blkdev_aio_write,
.open = raw_open,
.release= raw_release,
.ioctl = raw_ioctl,
@@ -261,7 +261,7 @@ static const struct file_operations raw_ctl_fops = {
static struct cdev raw_cdev;
-static char *raw_nodename(struct device *dev)
+static char *raw_devnode(struct device *dev, mode_t *mode)
{
return kasprintf(GFP_KERNEL, "raw/%s", dev_name(dev));
}
@@ -289,7 +289,7 @@ static int __init raw_init(void)
ret = PTR_ERR(raw_class);
goto error_region;
}
- raw_class->nodename = raw_nodename;
+ raw_class->devnode = raw_devnode;
device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl");
return 0;
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c
index 01f2654d5a2e..f121357e5af0 100644
--- a/drivers/char/rio/riocmd.c
+++ b/drivers/char/rio/riocmd.c
@@ -32,6 +32,7 @@
*/
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/tty.h>
diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c
index eecee0f576d2..780506326a73 100644
--- a/drivers/char/rio/rioctrl.c
+++ b/drivers/char/rio/rioctrl.c
@@ -31,6 +31,7 @@
*/
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <asm/io.h>
@@ -873,7 +874,7 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su
/*
** It is important that the product code is an unsigned object!
*/
- if (DownLoad.ProductCode > MAX_PRODUCT) {
+ if (DownLoad.ProductCode >= MAX_PRODUCT) {
rio_dprintk(RIO_DEBUG_CTRL, "RIO_DOWNLOAD: Bad product code %d passed\n", DownLoad.ProductCode);
p->RIOError.Error = NO_SUCH_PRODUCT;
return -ENXIO;
diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c
index 2fb49e89b324..47fab7c33073 100644
--- a/drivers/char/rio/riotty.c
+++ b/drivers/char/rio/riotty.c
@@ -33,6 +33,7 @@
#define __EXPLICIT_DEF_H__
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/tty.h>
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 171711acf5cd..3cfa22d469e0 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -343,7 +343,7 @@ static void rc_receive_exc(struct riscom_board const *bp)
if (port == NULL)
return;
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
#ifdef RC_REPORT_OVERRUN
status = rc_in(bp, CD180_RCSR);
@@ -355,18 +355,18 @@ static void rc_receive_exc(struct riscom_board const *bp)
#endif
ch = rc_in(bp, CD180_RDR);
if (!status)
- return;
+ goto out;
if (status & RCSR_TOUT) {
printk(KERN_WARNING "rc%d: port %d: Receiver timeout. "
"Hardware problems ?\n",
board_No(bp), port_No(port));
- return;
+ goto out;
} else if (status & RCSR_BREAK) {
printk(KERN_INFO "rc%d: port %d: Handling break...\n",
board_No(bp), port_No(port));
flag = TTY_BREAK;
- if (port->port.flags & ASYNC_SAK)
+ if (tty && (port->port.flags & ASYNC_SAK))
do_SAK(tty);
} else if (status & RCSR_PE)
@@ -380,8 +380,12 @@ static void rc_receive_exc(struct riscom_board const *bp)
else
flag = TTY_NORMAL;
- tty_insert_flip_char(tty, ch, flag);
- tty_flip_buffer_push(tty);
+ if (tty) {
+ tty_insert_flip_char(tty, ch, flag);
+ tty_flip_buffer_push(tty);
+ }
+out:
+ tty_kref_put(tty);
}
static void rc_receive(struct riscom_board const *bp)
@@ -394,7 +398,7 @@ static void rc_receive(struct riscom_board const *bp)
if (port == NULL)
return;
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
count = rc_in(bp, CD180_RDCR);
@@ -403,15 +407,14 @@ static void rc_receive(struct riscom_board const *bp)
#endif
while (count--) {
- if (tty_buffer_request_room(tty, 1) == 0) {
- printk(KERN_WARNING "rc%d: port %d: Working around "
- "flip buffer overflow.\n",
- board_No(bp), port_No(port));
- break;
- }
- tty_insert_flip_char(tty, rc_in(bp, CD180_RDR), TTY_NORMAL);
+ u8 ch = rc_in(bp, CD180_RDR);
+ if (tty)
+ tty_insert_flip_char(tty, ch, TTY_NORMAL);
+ }
+ if (tty) {
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
}
- tty_flip_buffer_push(tty);
}
static void rc_transmit(struct riscom_board const *bp)
@@ -424,22 +427,22 @@ static void rc_transmit(struct riscom_board const *bp)
if (port == NULL)
return;
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (port->IER & IER_TXEMPTY) {
/* FIFO drained */
rc_out(bp, CD180_CAR, port_No(port));
port->IER &= ~IER_TXEMPTY;
rc_out(bp, CD180_IER, port->IER);
- return;
+ goto out;
}
if ((port->xmit_cnt <= 0 && !port->break_length)
- || tty->stopped || tty->hw_stopped) {
+ || (tty && (tty->stopped || tty->hw_stopped))) {
rc_out(bp, CD180_CAR, port_No(port));
port->IER &= ~IER_TXRDY;
rc_out(bp, CD180_IER, port->IER);
- return;
+ goto out;
}
if (port->break_length) {
@@ -464,7 +467,7 @@ static void rc_transmit(struct riscom_board const *bp)
rc_out(bp, CD180_CCR, CCR_CORCHG2);
port->break_length = 0;
}
- return;
+ goto out;
}
count = CD180_NFIFO;
@@ -480,8 +483,10 @@ static void rc_transmit(struct riscom_board const *bp)
port->IER &= ~IER_TXRDY;
rc_out(bp, CD180_IER, port->IER);
}
- if (port->xmit_cnt <= port->wakeup_chars)
+ if (tty && port->xmit_cnt <= port->wakeup_chars)
tty_wakeup(tty);
+out:
+ tty_kref_put(tty);
}
static void rc_check_modem(struct riscom_board const *bp)
@@ -494,37 +499,43 @@ static void rc_check_modem(struct riscom_board const *bp)
if (port == NULL)
return;
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
mcr = rc_in(bp, CD180_MCR);
if (mcr & MCR_CDCHG) {
if (rc_in(bp, CD180_MSVR) & MSVR_CD)
wake_up_interruptible(&port->port.open_wait);
- else
+ else if (tty)
tty_hangup(tty);
}
#ifdef RISCOM_BRAIN_DAMAGED_CTS
if (mcr & MCR_CTSCHG) {
if (rc_in(bp, CD180_MSVR) & MSVR_CTS) {
- tty->hw_stopped = 0;
port->IER |= IER_TXRDY;
- if (port->xmit_cnt <= port->wakeup_chars)
- tty_wakeup(tty);
+ if (tty) {
+ tty->hw_stopped = 0;
+ if (port->xmit_cnt <= port->wakeup_chars)
+ tty_wakeup(tty);
+ }
} else {
- tty->hw_stopped = 1;
+ if (tty)
+ tty->hw_stopped = 1;
port->IER &= ~IER_TXRDY;
}
rc_out(bp, CD180_IER, port->IER);
}
if (mcr & MCR_DSRCHG) {
if (rc_in(bp, CD180_MSVR) & MSVR_DSR) {
- tty->hw_stopped = 0;
port->IER |= IER_TXRDY;
- if (port->xmit_cnt <= port->wakeup_chars)
- tty_wakeup(tty);
+ if (tty) {
+ tty->hw_stopped = 0;
+ if (port->xmit_cnt <= port->wakeup_chars)
+ tty_wakeup(tty);
+ }
} else {
- tty->hw_stopped = 1;
+ if (tty)
+ tty->hw_stopped = 1;
port->IER &= ~IER_TXRDY;
}
rc_out(bp, CD180_IER, port->IER);
@@ -533,6 +544,7 @@ static void rc_check_modem(struct riscom_board const *bp)
/* Clear change bits */
rc_out(bp, CD180_MCR, 0);
+ tty_kref_put(tty);
}
/* The main interrupt processing routine */
@@ -632,9 +644,9 @@ static void rc_shutdown_board(struct riscom_board *bp)
* Setting up port characteristics.
* Must be called with disabled interrupts
*/
-static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
+static void rc_change_speed(struct tty_struct *tty, struct riscom_board *bp,
+ struct riscom_port *port)
{
- struct tty_struct *tty = port->port.tty;
unsigned long baud;
long tmp;
unsigned char cor1 = 0, cor3 = 0;
@@ -781,7 +793,8 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
}
/* Must be called with interrupts enabled */
-static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
+static int rc_setup_port(struct tty_struct *tty, struct riscom_board *bp,
+ struct riscom_port *port)
{
unsigned long flags;
@@ -793,11 +806,11 @@ static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
spin_lock_irqsave(&riscom_lock, flags);
- clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
+ clear_bit(TTY_IO_ERROR, &tty->flags);
if (port->port.count == 1)
bp->count++;
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- rc_change_speed(bp, port);
+ rc_change_speed(tty, bp, port);
port->port.flags |= ASYNC_INITIALIZED;
spin_unlock_irqrestore(&riscom_lock, flags);
@@ -898,9 +911,9 @@ static int rc_open(struct tty_struct *tty, struct file *filp)
port->port.count++;
tty->driver_data = port;
- port->port.tty = tty;
+ tty_port_tty_set(&port->port, tty);
- error = rc_setup_port(bp, port);
+ error = rc_setup_port(tty, bp, port);
if (error == 0)
error = tty_port_block_til_ready(&port->port, tty, filp);
return error;
@@ -921,20 +934,12 @@ static void rc_flush_buffer(struct tty_struct *tty)
tty_wakeup(tty);
}
-static void rc_close(struct tty_struct *tty, struct file *filp)
+static void rc_close_port(struct tty_port *port)
{
- struct riscom_port *port = tty->driver_data;
- struct riscom_board *bp;
unsigned long flags;
+ struct riscom_port *rp = container_of(port, struct riscom_port, port);
+ struct riscom_board *bp = port_Board(rp);
unsigned long timeout;
-
- if (!port || rc_paranoia_check(port, tty->name, "close"))
- return;
-
- bp = port_Board(port);
-
- if (tty_port_close_start(&port->port, tty, filp) == 0)
- return;
/*
* At this point we stop accepting input. To do this, we
@@ -944,31 +949,37 @@ static void rc_close(struct tty_struct *tty, struct file *filp)
*/
spin_lock_irqsave(&riscom_lock, flags);
- port->IER &= ~IER_RXD;
- if (port->port.flags & ASYNC_INITIALIZED) {
- port->IER &= ~IER_TXRDY;
- port->IER |= IER_TXEMPTY;
- rc_out(bp, CD180_CAR, port_No(port));
- rc_out(bp, CD180_IER, port->IER);
+ rp->IER &= ~IER_RXD;
+ if (port->flags & ASYNC_INITIALIZED) {
+ rp->IER &= ~IER_TXRDY;
+ rp->IER |= IER_TXEMPTY;
+ rc_out(bp, CD180_CAR, port_No(rp));
+ rc_out(bp, CD180_IER, rp->IER);
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially
* important if there is a transmit FIFO!
*/
timeout = jiffies + HZ;
- while (port->IER & IER_TXEMPTY) {
+ while (rp->IER & IER_TXEMPTY) {
spin_unlock_irqrestore(&riscom_lock, flags);
- msleep_interruptible(jiffies_to_msecs(port->timeout));
+ msleep_interruptible(jiffies_to_msecs(rp->timeout));
spin_lock_irqsave(&riscom_lock, flags);
if (time_after(jiffies, timeout))
break;
}
}
- rc_shutdown_port(tty, bp, port);
- rc_flush_buffer(tty);
+ rc_shutdown_port(port->tty, bp, rp);
spin_unlock_irqrestore(&riscom_lock, flags);
+}
+
+static void rc_close(struct tty_struct *tty, struct file *filp)
+{
+ struct riscom_port *port = tty->driver_data;
- tty_port_close_end(&port->port, tty);
+ if (!port || rc_paranoia_check(port, tty->name, "close"))
+ return;
+ tty_port_close(&port->port, tty, filp);
}
static int rc_write(struct tty_struct *tty,
@@ -1170,7 +1181,7 @@ static int rc_send_break(struct tty_struct *tty, int length)
return 0;
}
-static int rc_set_serial_info(struct riscom_port *port,
+static int rc_set_serial_info(struct tty_struct *tty, struct riscom_port *port,
struct serial_struct __user *newinfo)
{
struct serial_struct tmp;
@@ -1180,17 +1191,6 @@ static int rc_set_serial_info(struct riscom_port *port,
if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
return -EFAULT;
-#if 0
- if ((tmp.irq != bp->irq) ||
- (tmp.port != bp->base) ||
- (tmp.type != PORT_CIRRUS) ||
- (tmp.baud_base != (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC) ||
- (tmp.custom_divisor != 0) ||
- (tmp.xmit_fifo_size != CD180_NFIFO) ||
- (tmp.flags & ~RISCOM_LEGAL_FLAGS))
- return -EINVAL;
-#endif
-
change_speed = ((port->port.flags & ASYNC_SPD_MASK) !=
(tmp.flags & ASYNC_SPD_MASK));
@@ -1212,7 +1212,7 @@ static int rc_set_serial_info(struct riscom_port *port,
unsigned long flags;
spin_lock_irqsave(&riscom_lock, flags);
- rc_change_speed(bp, port);
+ rc_change_speed(tty, bp, port);
spin_unlock_irqrestore(&riscom_lock, flags);
}
return 0;
@@ -1255,7 +1255,7 @@ static int rc_ioctl(struct tty_struct *tty, struct file *filp,
break;
case TIOCSSERIAL:
lock_kernel();
- retval = rc_set_serial_info(port, argp);
+ retval = rc_set_serial_info(tty, port, argp);
unlock_kernel();
break;
default:
@@ -1350,21 +1350,12 @@ static void rc_start(struct tty_struct *tty)
static void rc_hangup(struct tty_struct *tty)
{
struct riscom_port *port = tty->driver_data;
- struct riscom_board *bp;
- unsigned long flags;
if (rc_paranoia_check(port, tty->name, "rc_hangup"))
return;
- bp = port_Board(port);
-
- rc_shutdown_port(tty, bp, port);
- spin_lock_irqsave(&port->port.lock, flags);
- port->port.count = 0;
- port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
- port->port.tty = NULL;
- wake_up_interruptible(&port->port.open_wait);
- spin_unlock_irqrestore(&port->port.lock, flags);
+ rc_shutdown_port(tty, port_Board(port), port);
+ tty_port_hangup(&port->port);
}
static void rc_set_termios(struct tty_struct *tty,
@@ -1377,7 +1368,7 @@ static void rc_set_termios(struct tty_struct *tty,
return;
spin_lock_irqsave(&riscom_lock, flags);
- rc_change_speed(port_Board(port), port);
+ rc_change_speed(tty, port_Board(port), port);
spin_unlock_irqrestore(&riscom_lock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
@@ -1410,6 +1401,7 @@ static const struct tty_operations riscom_ops = {
static const struct tty_port_operations riscom_port_ops = {
.carrier_raised = carrier_raised,
+ .shutdown = rc_close_port,
};
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index e0d0f8b2696b..bc4ab3e54550 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -74,6 +74,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
+#include <linux/sched.h>
#include <linux/sysctl.h>
#include <linux/wait.h>
#include <linux/bcd.h>
diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c
index 33a2b531802e..9610861d1f5f 100644
--- a/drivers/char/ser_a2232.c
+++ b/drivers/char/ser_a2232.c
@@ -89,6 +89,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/errno.h>
+#include <linux/sched.h>
#include <linux/tty.h>
#include <asm/setup.h>
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index 51e7a46787be..452370af95de 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -171,7 +171,6 @@ static int startup(struct cyclades_port *);
static void cy_throttle(struct tty_struct *);
static void cy_unthrottle(struct tty_struct *);
static void config_setup(struct cyclades_port *);
-extern void console_print(const char *);
#ifdef CYCLOM_SHOW_STATUS
static void show_status(int);
#endif
@@ -221,8 +220,7 @@ static inline int serial_paranoia_check(struct cyclades_port *info, char *name,
return 1;
}
- if ((long)info < (long)(&cy_port[0])
- || (long)(&cy_port[NR_PORTS]) < (long)info) {
+ if (info < &cy_port[0] || info >= &cy_port[NR_PORTS]) {
printk("Warning: cyclades_port out of range for (%s) in %s\n",
name, routine);
return 1;
@@ -245,7 +243,7 @@ void SP(char *data)
{
unsigned long flags;
local_irq_save(flags);
- console_print(data);
+ printk(KERN_EMERG "%s", data);
local_irq_restore(flags);
}
@@ -255,7 +253,7 @@ void CP(char data)
unsigned long flags;
local_irq_save(flags);
scrn[0] = data;
- console_print(scrn);
+ printk(KERN_EMERG "%c", scrn);
local_irq_restore(flags);
} /* CP */
@@ -521,15 +519,13 @@ static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id)
panic("TxInt on debug port!!!");
}
#endif
-
- info = &cy_port[channel];
-
/* validate the port number (as configured and open) */
if ((channel < 0) || (NR_PORTS <= channel)) {
base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
base_addr[CyTEOIR] = CyNOTRANS;
return IRQ_HANDLED;
}
+ info = &cy_port[channel];
info->last_active = jiffies;
if (info->tty == 0) {
base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index fd3dced97776..8c262aaf7c26 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -36,6 +36,7 @@
*/
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/input.h>
#include <linux/pci.h>
#include <linux/init.h>
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 53e504f41b20..db6dcfa35ba0 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -27,6 +27,7 @@
/*****************************************************************************/
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 813552f14884..4846b73ef28d 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -7697,10 +7697,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
*
* skb socket buffer containing HDLC frame
* dev pointer to network device structure
- *
- * returns 0 if success, otherwise error code
*/
-static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
struct mgsl_struct *info = dev_to_port(dev);
unsigned long flags;
@@ -7731,7 +7730,7 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
usc_start_transmitter(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
- return 0;
+ return NETDEV_TX_OK;
}
/**
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 91f20a92fddf..8678f0c8699d 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -1497,10 +1497,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
*
* skb socket buffer containing HDLC frame
* dev pointer to network device structure
- *
- * returns 0 if success, otherwise error code
*/
-static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
struct slgt_info *info = dev_to_port(dev);
unsigned long flags;
@@ -1529,7 +1528,7 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
update_tx_timer(info);
spin_unlock_irqrestore(&info->lock,flags);
- return 0;
+ return NETDEV_TX_OK;
}
/**
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index 8d4a2a8a0a70..2b18adc4ee19 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -1608,10 +1608,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
*
* skb socket buffer containing HDLC frame
* dev pointer to network device structure
- *
- * returns 0 if success, otherwise error code
*/
-static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
SLMP_INFO *info = dev_to_port(dev);
unsigned long flags;
@@ -1642,7 +1641,7 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
tx_start(info);
spin_unlock_irqrestore(&info->lock,flags);
- return 0;
+ return NETDEV_TX_OK;
}
/**
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 50eecfe1d724..44203ff599da 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -26,7 +26,7 @@
#include <linux/proc_fs.h>
#include <linux/nmi.h>
#include <linux/quotaops.h>
-#include <linux/perf_counter.h>
+#include <linux/perf_event.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/suspend.h>
@@ -252,7 +252,7 @@ static void sysrq_handle_showregs(int key, struct tty_struct *tty)
struct pt_regs *regs = get_irq_regs();
if (regs)
show_regs(regs);
- perf_counter_print_debug();
+ perf_event_print_debug();
}
static struct sysrq_key_op sysrq_showregs_op = {
.handler = sysrq_handle_showregs,
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c
index 8f2284be68e1..80ea6bcfffdc 100644
--- a/drivers/char/tlclk.c
+++ b/drivers/char/tlclk.c
@@ -32,6 +32,7 @@
#include <linux/kernel.h> /* printk() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index b0603b2e5684..f06bb37defb1 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -31,7 +31,7 @@
enum tpm_const {
TPM_MINOR = 224, /* officially assigned */
- TPM_BUFSIZE = 2048,
+ TPM_BUFSIZE = 4096,
TPM_NUM_DEVICES = 256,
};
@@ -696,8 +696,7 @@ int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
cmd.header.in = pcrread_header;
cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
- BUILD_BUG_ON(cmd.header.in.length > READ_PCR_RESULT_SIZE);
- rc = transmit_cmd(chip, &cmd, cmd.header.in.length,
+ rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
"attempting to read a pcr value");
if (rc == 0)
@@ -742,7 +741,7 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read);
* the module usage count.
*/
#define TPM_ORD_PCR_EXTEND cpu_to_be32(20)
-#define EXTEND_PCR_SIZE 34
+#define EXTEND_PCR_RESULT_SIZE 34
static struct tpm_input_header pcrextend_header = {
.tag = TPM_TAG_RQU_COMMAND,
.length = cpu_to_be32(34),
@@ -760,10 +759,9 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
return -ENODEV;
cmd.header.in = pcrextend_header;
- BUILD_BUG_ON(be32_to_cpu(cmd.header.in.length) > EXTEND_PCR_SIZE);
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
- rc = transmit_cmd(chip, &cmd, cmd.header.in.length,
+ rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
"attempting extend a PCR value");
module_put(chip->dev->driver->owner);
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
index 0c2f55a38b95..bf2170fb1cdd 100644
--- a/drivers/char/tpm/tpm_bios.c
+++ b/drivers/char/tpm/tpm_bios.c
@@ -343,14 +343,14 @@ static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
return 0;
}
-static struct seq_operations tpm_ascii_b_measurments_seqops = {
+static const struct seq_operations tpm_ascii_b_measurments_seqops = {
.start = tpm_bios_measurements_start,
.next = tpm_bios_measurements_next,
.stop = tpm_bios_measurements_stop,
.show = tpm_ascii_bios_measurements_show,
};
-static struct seq_operations tpm_binary_b_measurments_seqops = {
+static const struct seq_operations tpm_binary_b_measurments_seqops = {
.start = tpm_bios_measurements_start,
.next = tpm_bios_measurements_next,
.stop = tpm_bios_measurements_stop,
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 0b73e4ec1add..2405f17b29dd 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -257,6 +257,10 @@ out:
return size;
}
+static int itpm;
+module_param(itpm, bool, 0444);
+MODULE_PARM_DESC(itpm, "Force iTPM workarounds (found on some Lenovo laptops)");
+
/*
* If interrupts are used (signaled by an irq set in the vendor structure)
* tpm.c can skip polling for the data to be available as the interrupt is
@@ -293,7 +297,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
&chip->vendor.int_queue);
status = tpm_tis_status(chip);
- if ((status & TPM_STS_DATA_EXPECT) == 0) {
+ if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
rc = -EIO;
goto out_err;
}
@@ -467,6 +471,10 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
"1.2 TPM (device-id 0x%X, rev-id %d)\n",
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
+ if (itpm)
+ dev_info(dev, "Intel iTPM workaround enabled\n");
+
+
/* Figure out the capabilities */
intfcaps =
ioread32(chip->vendor.iobase +
@@ -629,6 +637,7 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = {
{"", 0}, /* User Specified */
{"", 0} /* Terminator */
};
+MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev)
{
diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c
index 3108991c5c8b..66fa4e10d76b 100644
--- a/drivers/char/tty_buffer.c
+++ b/drivers/char/tty_buffer.c
@@ -402,28 +402,26 @@ static void flush_to_ldisc(struct work_struct *work)
container_of(work, struct tty_struct, buf.work.work);
unsigned long flags;
struct tty_ldisc *disc;
- struct tty_buffer *tbuf, *head;
- char *char_buf;
- unsigned char *flag_buf;
disc = tty_ldisc_ref(tty);
if (disc == NULL) /* !TTY_LDISC */
return;
spin_lock_irqsave(&tty->buf.lock, flags);
- /* So we know a flush is running */
- set_bit(TTY_FLUSHING, &tty->flags);
- head = tty->buf.head;
- if (head != NULL) {
- tty->buf.head = NULL;
- for (;;) {
- int count = head->commit - head->read;
+
+ if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) {
+ struct tty_buffer *head;
+ while ((head = tty->buf.head) != NULL) {
+ int count;
+ char *char_buf;
+ unsigned char *flag_buf;
+
+ count = head->commit - head->read;
if (!count) {
if (head->next == NULL)
break;
- tbuf = head;
- head = head->next;
- tty_buffer_free(tty, tbuf);
+ tty->buf.head = head->next;
+ tty_buffer_free(tty, head);
continue;
}
/* Ldisc or user is trying to flush the buffers
@@ -445,9 +443,9 @@ static void flush_to_ldisc(struct work_struct *work)
flag_buf, count);
spin_lock_irqsave(&tty->buf.lock, flags);
}
- /* Restore the queue head */
- tty->buf.head = head;
+ clear_bit(TTY_FLUSHING, &tty->flags);
}
+
/* We may have a deferred request to flush the input buffer,
if so pull the chain under the lock and empty the queue */
if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
@@ -455,7 +453,6 @@ static void flush_to_ldisc(struct work_struct *work)
clear_bit(TTY_FLUSHPENDING, &tty->flags);
wake_up(&tty->read_wait);
}
- clear_bit(TTY_FLUSHING, &tty->flags);
spin_unlock_irqrestore(&tty->buf.lock, flags);
tty_ldisc_deref(disc);
@@ -471,7 +468,7 @@ static void flush_to_ldisc(struct work_struct *work)
*/
void tty_flush_to_ldisc(struct tty_struct *tty)
{
- flush_to_ldisc(&tty->buf.work.work);
+ flush_delayed_work(&tty->buf.work);
}
/**
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index a3afa0c387cd..59499ee0fe6a 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1184,6 +1184,7 @@ int tty_init_termios(struct tty_struct *tty)
tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
return 0;
}
+EXPORT_SYMBOL_GPL(tty_init_termios);
/**
* tty_driver_install_tty() - install a tty entry in the driver
@@ -1386,16 +1387,19 @@ EXPORT_SYMBOL(tty_shutdown);
* tty_mutex - sometimes only
* takes the file list lock internally when working on the list
* of ttys that the driver keeps.
+ *
+ * This method gets called from a work queue so that the driver private
+ * cleanup ops can sleep (needed for USB at least)
*/
-static void release_one_tty(struct kref *kref)
+static void release_one_tty(struct work_struct *work)
{
- struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
+ struct tty_struct *tty =
+ container_of(work, struct tty_struct, hangup_work);
struct tty_driver *driver = tty->driver;
- if (tty->ops->shutdown)
- tty->ops->shutdown(tty);
- else
- tty_shutdown(tty);
+ if (tty->ops->cleanup)
+ tty->ops->cleanup(tty);
+
tty->magic = 0;
tty_driver_kref_put(driver);
module_put(driver->owner);
@@ -1407,6 +1411,21 @@ static void release_one_tty(struct kref *kref)
free_tty_struct(tty);
}
+static void queue_release_one_tty(struct kref *kref)
+{
+ struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
+
+ if (tty->ops->shutdown)
+ tty->ops->shutdown(tty);
+ else
+ tty_shutdown(tty);
+
+ /* The hangup queue is now free so we can reuse it rather than
+ waste a chunk of memory for each port */
+ INIT_WORK(&tty->hangup_work, release_one_tty);
+ schedule_work(&tty->hangup_work);
+}
+
/**
* tty_kref_put - release a tty kref
* @tty: tty device
@@ -1418,7 +1437,7 @@ static void release_one_tty(struct kref *kref)
void tty_kref_put(struct tty_struct *tty)
{
if (tty)
- kref_put(&tty->kref, release_one_tty);
+ kref_put(&tty->kref, queue_release_one_tty);
}
EXPORT_SYMBOL(tty_kref_put);
@@ -2085,7 +2104,7 @@ static int tioccons(struct file *file)
* the generic functionality existed. This piece of history is preserved
* in the expected tty API of posix OS's.
*
- * Locking: none, the open fle handle ensures it won't go away.
+ * Locking: none, the open file handle ensures it won't go away.
*/
static int fionbio(struct file *file, int __user *p)
@@ -3056,11 +3075,22 @@ void __init console_init(void)
}
}
+static char *tty_devnode(struct device *dev, mode_t *mode)
+{
+ if (!mode)
+ return NULL;
+ if (dev->devt == MKDEV(TTYAUX_MAJOR, 0) ||
+ dev->devt == MKDEV(TTYAUX_MAJOR, 2))
+ *mode = 0666;
+ return NULL;
+}
+
static int __init tty_class_init(void)
{
tty_class = class_create(THIS_MODULE, "tty");
if (IS_ERR(tty_class))
return PTR_ERR(tty_class);
+ tty_class->devnode = tty_devnode;
return 0;
}
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index ad6ba4ed2808..8e67d5c642a4 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -393,9 +393,7 @@ void tty_termios_encode_baud_rate(struct ktermios *termios,
termios->c_cflag |= (BOTHER << IBSHIFT);
#else
if (ifound == -1 || ofound == -1) {
- static int warned;
- if (!warned++)
- printk(KERN_WARNING "tty: Unable to return correct "
+ printk_once(KERN_WARNING "tty: Unable to return correct "
"speed data as your architecture needs updating.\n");
}
#endif
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index e48af9f79219..feb55075819b 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -145,48 +145,33 @@ int tty_unregister_ldisc(int disc)
}
EXPORT_SYMBOL(tty_unregister_ldisc);
-
-/**
- * tty_ldisc_try_get - try and reference an ldisc
- * @disc: ldisc number
- *
- * Attempt to open and lock a line discipline into place. Return
- * the line discipline refcounted or an error.
- */
-
-static struct tty_ldisc *tty_ldisc_try_get(int disc)
+static struct tty_ldisc_ops *get_ldops(int disc)
{
unsigned long flags;
- struct tty_ldisc *ld;
- struct tty_ldisc_ops *ldops;
- int err = -EINVAL;
-
- ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
- if (ld == NULL)
- return ERR_PTR(-ENOMEM);
+ struct tty_ldisc_ops *ldops, *ret;
spin_lock_irqsave(&tty_ldisc_lock, flags);
- ld->ops = NULL;
+ ret = ERR_PTR(-EINVAL);
ldops = tty_ldiscs[disc];
- /* Check the entry is defined */
if (ldops) {
- /* If the module is being unloaded we can't use it */
- if (!try_module_get(ldops->owner))
- err = -EAGAIN;
- else {
- /* lock it */
+ ret = ERR_PTR(-EAGAIN);
+ if (try_module_get(ldops->owner)) {
ldops->refcount++;
- ld->ops = ldops;
- atomic_set(&ld->users, 1);
- err = 0;
+ ret = ldops;
}
}
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- if (err) {
- kfree(ld);
- return ERR_PTR(err);
- }
- return ld;
+ return ret;
+}
+
+static void put_ldops(struct tty_ldisc_ops *ldops)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&tty_ldisc_lock, flags);
+ ldops->refcount--;
+ module_put(ldops->owner);
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
}
/**
@@ -205,14 +190,31 @@ static struct tty_ldisc *tty_ldisc_try_get(int disc)
static struct tty_ldisc *tty_ldisc_get(int disc)
{
struct tty_ldisc *ld;
+ struct tty_ldisc_ops *ldops;
if (disc < N_TTY || disc >= NR_LDISCS)
return ERR_PTR(-EINVAL);
- ld = tty_ldisc_try_get(disc);
- if (IS_ERR(ld)) {
+
+ /*
+ * Get the ldisc ops - we may need to request them to be loaded
+ * dynamically and try again.
+ */
+ ldops = get_ldops(disc);
+ if (IS_ERR(ldops)) {
request_module("tty-ldisc-%d", disc);
- ld = tty_ldisc_try_get(disc);
+ ldops = get_ldops(disc);
+ if (IS_ERR(ldops))
+ return ERR_CAST(ldops);
}
+
+ ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
+ if (ld == NULL) {
+ put_ldops(ldops);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ld->ops = ldops;
+ atomic_set(&ld->users, 1);
return ld;
}
@@ -234,13 +236,13 @@ static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
{
int i = *(loff_t *)v;
- struct tty_ldisc *ld;
+ struct tty_ldisc_ops *ldops;
- ld = tty_ldisc_try_get(i);
- if (IS_ERR(ld))
+ ldops = get_ldops(i);
+ if (IS_ERR(ldops))
return 0;
- seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i);
- put_ldisc(ld);
+ seq_printf(m, "%-10s %2d\n", ldops->name ? ldops->name : "???", i);
+ put_ldops(ldops);
return 0;
}
@@ -516,7 +518,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
static int tty_ldisc_halt(struct tty_struct *tty)
{
clear_bit(TTY_LDISC, &tty->flags);
- return cancel_delayed_work(&tty->buf.work);
+ return cancel_delayed_work_sync(&tty->buf.work);
}
/**
@@ -754,12 +756,9 @@ void tty_ldisc_hangup(struct tty_struct *tty)
* N_TTY.
*/
if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
- /* Make sure the old ldisc is quiescent */
- tty_ldisc_halt(tty);
- flush_scheduled_work();
-
/* Avoid racing set_ldisc or tty_ldisc_release */
mutex_lock(&tty->ldisc_mutex);
+ tty_ldisc_halt(tty);
if (tty->ldisc) { /* Not yet closed */
/* Switch back to N_TTY */
tty_ldisc_reinit(tty);
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
index 9769b1149f76..c63f3d33914a 100644
--- a/drivers/char/tty_port.c
+++ b/drivers/char/tty_port.c
@@ -23,6 +23,7 @@ void tty_port_init(struct tty_port *port)
memset(port, 0, sizeof(*port));
init_waitqueue_head(&port->open_wait);
init_waitqueue_head(&port->close_wait);
+ init_waitqueue_head(&port->delta_msr_wait);
mutex_init(&port->mutex);
spin_lock_init(&port->lock);
port->close_delay = (50 * HZ) / 100;
@@ -96,6 +97,14 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
}
EXPORT_SYMBOL(tty_port_tty_set);
+static void tty_port_shutdown(struct tty_port *port)
+{
+ if (port->ops->shutdown &&
+ test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
+ port->ops->shutdown(port);
+
+}
+
/**
* tty_port_hangup - hangup helper
* @port: tty port
@@ -116,6 +125,8 @@ void tty_port_hangup(struct tty_port *port)
port->tty = NULL;
spin_unlock_irqrestore(&port->lock, flags);
wake_up_interruptible(&port->open_wait);
+ wake_up_interruptible(&port->delta_msr_wait);
+ tty_port_shutdown(port);
}
EXPORT_SYMBOL(tty_port_hangup);
@@ -208,8 +219,14 @@ int tty_port_block_til_ready(struct tty_port *port,
/* if non-blocking mode is set we can pass directly to open unless
the port has just hung up or is in another error state */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
+ if (tty->flags & (1 << TTY_IO_ERROR)) {
+ port->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+ if (filp->f_flags & O_NONBLOCK) {
+ /* Indicate we are open */
+ if (tty->termios->c_cflag & CBAUD)
+ tty_port_raise_dtr_rts(port);
port->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
@@ -296,15 +313,17 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
if (port->count) {
spin_unlock_irqrestore(&port->lock, flags);
+ if (port->ops->drop)
+ port->ops->drop(port);
return 0;
}
- port->flags |= ASYNC_CLOSING;
+ set_bit(ASYNCB_CLOSING, &port->flags);
tty->closing = 1;
spin_unlock_irqrestore(&port->lock, flags);
/* Don't block on a stalled port, just pull the chain */
if (tty->flow_stopped)
tty_driver_flush_buffer(tty);
- if (port->flags & ASYNC_INITIALIZED &&
+ if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, port->closing_wait);
if (port->drain_delay) {
@@ -318,6 +337,9 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
timeout = 2 * HZ;
schedule_timeout_interruptible(timeout);
}
+ /* Don't call port->drop for the last reference. Callers will want
+ to drop the last active reference in ->shutdown() or the tty
+ shutdown path */
return 1;
}
EXPORT_SYMBOL(tty_port_close_start);
@@ -348,3 +370,14 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
spin_unlock_irqrestore(&port->lock, flags);
}
EXPORT_SYMBOL(tty_port_close_end);
+
+void tty_port_close(struct tty_port *port, struct tty_struct *tty,
+ struct file *filp)
+{
+ if (tty_port_close_start(port, tty, filp) == 0)
+ return;
+ tty_port_shutdown(port);
+ tty_port_close_end(port, tty);
+ tty_port_tty_set(port, NULL);
+}
+EXPORT_SYMBOL(tty_port_close);
diff --git a/drivers/char/uv_mmtimer.c b/drivers/char/uv_mmtimer.c
new file mode 100644
index 000000000000..867b67be9f0a
--- /dev/null
+++ b/drivers/char/uv_mmtimer.c
@@ -0,0 +1,216 @@
+/*
+ * Timer device implementation for SGI UV platform.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2009 Silicon Graphics, Inc. All rights reserved.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mmtimer.h>
+#include <linux/miscdevice.h>
+#include <linux/posix-timers.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/math64.h>
+#include <linux/smp_lock.h>
+
+#include <asm/genapic.h>
+#include <asm/uv/uv_hub.h>
+#include <asm/uv/bios.h>
+#include <asm/uv/uv.h>
+
+MODULE_AUTHOR("Dimitri Sivanich <sivanich@sgi.com>");
+MODULE_DESCRIPTION("SGI UV Memory Mapped RTC Timer");
+MODULE_LICENSE("GPL");
+
+/* name of the device, usually in /dev */
+#define UV_MMTIMER_NAME "mmtimer"
+#define UV_MMTIMER_DESC "SGI UV Memory Mapped RTC Timer"
+#define UV_MMTIMER_VERSION "1.0"
+
+static long uv_mmtimer_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg);
+static int uv_mmtimer_mmap(struct file *file, struct vm_area_struct *vma);
+
+/*
+ * Period in femtoseconds (10^-15 s)
+ */
+static unsigned long uv_mmtimer_femtoperiod;
+
+static const struct file_operations uv_mmtimer_fops = {
+ .owner = THIS_MODULE,
+ .mmap = uv_mmtimer_mmap,
+ .unlocked_ioctl = uv_mmtimer_ioctl,
+};
+
+/**
+ * uv_mmtimer_ioctl - ioctl interface for /dev/uv_mmtimer
+ * @file: file structure for the device
+ * @cmd: command to execute
+ * @arg: optional argument to command
+ *
+ * Executes the command specified by @cmd. Returns 0 for success, < 0 for
+ * failure.
+ *
+ * Valid commands:
+ *
+ * %MMTIMER_GETOFFSET - Should return the offset (relative to the start
+ * of the page where the registers are mapped) for the counter in question.
+ *
+ * %MMTIMER_GETRES - Returns the resolution of the clock in femto (10^-15)
+ * seconds
+ *
+ * %MMTIMER_GETFREQ - Copies the frequency of the clock in Hz to the address
+ * specified by @arg
+ *
+ * %MMTIMER_GETBITS - Returns the number of bits in the clock's counter
+ *
+ * %MMTIMER_MMAPAVAIL - Returns 1 if registers can be mmap'd into userspace
+ *
+ * %MMTIMER_GETCOUNTER - Gets the current value in the counter and places it
+ * in the address specified by @arg.
+ */
+static long uv_mmtimer_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case MMTIMER_GETOFFSET: /* offset of the counter */
+ /*
+ * UV RTC register is on its own page
+ */
+ if (PAGE_SIZE <= (1 << 16))
+ ret = ((UV_LOCAL_MMR_BASE | UVH_RTC) & (PAGE_SIZE-1))
+ / 8;
+ else
+ ret = -ENOSYS;
+ break;
+
+ case MMTIMER_GETRES: /* resolution of the clock in 10^-15 s */
+ if (copy_to_user((unsigned long __user *)arg,
+ &uv_mmtimer_femtoperiod, sizeof(unsigned long)))
+ ret = -EFAULT;
+ break;
+
+ case MMTIMER_GETFREQ: /* frequency in Hz */
+ if (copy_to_user((unsigned long __user *)arg,
+ &sn_rtc_cycles_per_second,
+ sizeof(unsigned long)))
+ ret = -EFAULT;
+ break;
+
+ case MMTIMER_GETBITS: /* number of bits in the clock */
+ ret = hweight64(UVH_RTC_REAL_TIME_CLOCK_MASK);
+ break;
+
+ case MMTIMER_MMAPAVAIL: /* can we mmap the clock into userspace? */
+ ret = (PAGE_SIZE <= (1 << 16)) ? 1 : 0;
+ break;
+
+ case MMTIMER_GETCOUNTER:
+ if (copy_to_user((unsigned long __user *)arg,
+ (unsigned long *)uv_local_mmr_address(UVH_RTC),
+ sizeof(unsigned long)))
+ ret = -EFAULT;
+ break;
+ default:
+ ret = -ENOTTY;
+ break;
+ }
+ return ret;
+}
+
+/**
+ * uv_mmtimer_mmap - maps the clock's registers into userspace
+ * @file: file structure for the device
+ * @vma: VMA to map the registers into
+ *
+ * Calls remap_pfn_range() to map the clock's registers into
+ * the calling process' address space.
+ */
+static int uv_mmtimer_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ unsigned long uv_mmtimer_addr;
+
+ if (vma->vm_end - vma->vm_start != PAGE_SIZE)
+ return -EINVAL;
+
+ if (vma->vm_flags & VM_WRITE)
+ return -EPERM;
+
+ if (PAGE_SIZE > (1 << 16))
+ return -ENOSYS;
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ uv_mmtimer_addr = UV_LOCAL_MMR_BASE | UVH_RTC;
+ uv_mmtimer_addr &= ~(PAGE_SIZE - 1);
+ uv_mmtimer_addr &= 0xfffffffffffffffUL;
+
+ if (remap_pfn_range(vma, vma->vm_start, uv_mmtimer_addr >> PAGE_SHIFT,
+ PAGE_SIZE, vma->vm_page_prot)) {
+ printk(KERN_ERR "remap_pfn_range failed in uv_mmtimer_mmap\n");
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static struct miscdevice uv_mmtimer_miscdev = {
+ MISC_DYNAMIC_MINOR,
+ UV_MMTIMER_NAME,
+ &uv_mmtimer_fops
+};
+
+
+/**
+ * uv_mmtimer_init - device initialization routine
+ *
+ * Does initial setup for the uv_mmtimer device.
+ */
+static int __init uv_mmtimer_init(void)
+{
+ if (!is_uv_system()) {
+ printk(KERN_ERR "%s: Hardware unsupported\n", UV_MMTIMER_NAME);
+ return -1;
+ }
+
+ /*
+ * Sanity check the cycles/sec variable
+ */
+ if (sn_rtc_cycles_per_second < 100000) {
+ printk(KERN_ERR "%s: unable to determine clock frequency\n",
+ UV_MMTIMER_NAME);
+ return -1;
+ }
+
+ uv_mmtimer_femtoperiod = ((unsigned long)1E15 +
+ sn_rtc_cycles_per_second / 2) /
+ sn_rtc_cycles_per_second;
+
+ if (misc_register(&uv_mmtimer_miscdev)) {
+ printk(KERN_ERR "%s: failed to register device\n",
+ UV_MMTIMER_NAME);
+ return -1;
+ }
+
+ printk(KERN_INFO "%s: v%s, %ld MHz\n", UV_MMTIMER_DESC,
+ UV_MMTIMER_VERSION,
+ sn_rtc_cycles_per_second/(unsigned long)1E6);
+
+ return 0;
+}
+
+module_init(uv_mmtimer_init);
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index c74dacfa6795..a035ae39a359 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -65,7 +65,7 @@ static int put_chars(u32 vtermno, const char *buf, int count)
/* add_buf wants a token to identify this buffer: we hand it any
* non-NULL pointer, since there's only ever one buffer. */
- if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, (void *)1) == 0) {
+ if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, (void *)1) >= 0) {
/* Tell Host to go! */
out_vq->vq_ops->kick(out_vq);
/* Chill out until it's done with the buffer. */
@@ -85,7 +85,7 @@ static void add_inbuf(void)
sg_init_one(sg, inbuf, PAGE_SIZE);
/* We should always be able to add one buffer to an empty queue. */
- if (in_vq->vq_ops->add_buf(in_vq, sg, 0, 1, inbuf) != 0)
+ if (in_vq->vq_ops->add_buf(in_vq, sg, 0, 1, inbuf) < 0)
BUG();
in_vq->vq_ops->kick(in_vq);
}
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 404f4c1ee431..0c80c68cd047 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -252,7 +252,6 @@ static void notify_update(struct vc_data *vc)
struct vt_notifier_param param = { .vc = vc };
atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, &param);
}
-
/*
* Low-Level Functions
*/
@@ -935,6 +934,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
if (CON_IS_VISIBLE(vc))
update_screen(vc);
+ vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
return err;
}
@@ -2129,11 +2129,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
currcons = vc->vc_num;
if (!vc_cons_allocated(currcons)) {
/* could this happen? */
- static int error = 0;
- if (!error) {
- error = 1;
- printk("con_write: tty %d not allocated\n", currcons+1);
- }
+ printk_once("con_write: tty %d not allocated\n", currcons+1);
release_console_sem();
return 0;
}
@@ -2910,6 +2906,9 @@ static const struct tty_operations con_ops = {
.flush_chars = con_flush_chars,
.chars_in_buffer = con_chars_in_buffer,
.ioctl = vt_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = vt_compat_ioctl,
+#endif
.stop = con_stop,
.start = con_start,
.throttle = con_throttle,
@@ -2948,9 +2947,6 @@ int __init vty_init(const struct file_operations *console_fops)
panic("Couldn't register console driver\n");
kbd_init();
console_map_init();
-#ifdef CONFIG_PROM_CONSOLE
- prom_con_init();
-#endif
#ifdef CONFIG_MDA_CONSOLE
mda_console_init();
#endif
@@ -2958,7 +2954,6 @@ int __init vty_init(const struct file_operations *console_fops)
}
#ifndef VT_SINGLE_DRIVER
-#include <linux/device.h>
static struct class *vtconsole_class;
@@ -3641,6 +3636,7 @@ void do_blank_screen(int entering_gfx)
blank_state = blank_vesa_wait;
mod_timer(&console_timer, jiffies + vesa_off_interval);
}
+ vt_event_post(VT_EVENT_BLANK, vc->vc_num, vc->vc_num);
}
EXPORT_SYMBOL(do_blank_screen);
@@ -3685,6 +3681,7 @@ void do_unblank_screen(int leaving_gfx)
console_blank_hook(0);
set_palette(vc);
set_cursor(vc);
+ vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num);
}
EXPORT_SYMBOL(do_unblank_screen);
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index 95189f288f8c..6aa10284104a 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -16,6 +16,8 @@
#include <linux/tty.h>
#include <linux/timer.h>
#include <linux/kernel.h>
+#include <linux/compat.h>
+#include <linux/module.h>
#include <linux/kd.h>
#include <linux/vt.h>
#include <linux/string.h>
@@ -62,6 +64,133 @@ extern struct tty_driver *console_driver;
static void complete_change_console(struct vc_data *vc);
/*
+ * User space VT_EVENT handlers
+ */
+
+struct vt_event_wait {
+ struct list_head list;
+ struct vt_event event;
+ int done;
+};
+
+static LIST_HEAD(vt_events);
+static DEFINE_SPINLOCK(vt_event_lock);
+static DECLARE_WAIT_QUEUE_HEAD(vt_event_waitqueue);
+
+/**
+ * vt_event_post
+ * @event: the event that occurred
+ * @old: old console
+ * @new: new console
+ *
+ * Post an VT event to interested VT handlers
+ */
+
+void vt_event_post(unsigned int event, unsigned int old, unsigned int new)
+{
+ struct list_head *pos, *head;
+ unsigned long flags;
+ int wake = 0;
+
+ spin_lock_irqsave(&vt_event_lock, flags);
+ head = &vt_events;
+
+ list_for_each(pos, head) {
+ struct vt_event_wait *ve = list_entry(pos,
+ struct vt_event_wait, list);
+ if (!(ve->event.event & event))
+ continue;
+ ve->event.event = event;
+ /* kernel view is consoles 0..n-1, user space view is
+ console 1..n with 0 meaning current, so we must bias */
+ ve->event.oldev = old + 1;
+ ve->event.newev = new + 1;
+ wake = 1;
+ ve->done = 1;
+ }
+ spin_unlock_irqrestore(&vt_event_lock, flags);
+ if (wake)
+ wake_up_interruptible(&vt_event_waitqueue);
+}
+
+/**
+ * vt_event_wait - wait for an event
+ * @vw: our event
+ *
+ * Waits for an event to occur which completes our vt_event_wait
+ * structure. On return the structure has wv->done set to 1 for success
+ * or 0 if some event such as a signal ended the wait.
+ */
+
+static void vt_event_wait(struct vt_event_wait *vw)
+{
+ unsigned long flags;
+ /* Prepare the event */
+ INIT_LIST_HEAD(&vw->list);
+ vw->done = 0;
+ /* Queue our event */
+ spin_lock_irqsave(&vt_event_lock, flags);
+ list_add(&vw->list, &vt_events);
+ spin_unlock_irqrestore(&vt_event_lock, flags);
+ /* Wait for it to pass */
+ wait_event_interruptible(vt_event_waitqueue, vw->done);
+ /* Dequeue it */
+ spin_lock_irqsave(&vt_event_lock, flags);
+ list_del(&vw->list);
+ spin_unlock_irqrestore(&vt_event_lock, flags);
+}
+
+/**
+ * vt_event_wait_ioctl - event ioctl handler
+ * @arg: argument to ioctl
+ *
+ * Implement the VT_WAITEVENT ioctl using the VT event interface
+ */
+
+static int vt_event_wait_ioctl(struct vt_event __user *event)
+{
+ struct vt_event_wait vw;
+
+ if (copy_from_user(&vw.event, event, sizeof(struct vt_event)))
+ return -EFAULT;
+ /* Highest supported event for now */
+ if (vw.event.event & ~VT_MAX_EVENT)
+ return -EINVAL;
+
+ vt_event_wait(&vw);
+ /* If it occurred report it */
+ if (vw.done) {
+ if (copy_to_user(event, &vw.event, sizeof(struct vt_event)))
+ return -EFAULT;
+ return 0;
+ }
+ return -EINTR;
+}
+
+/**
+ * vt_waitactive - active console wait
+ * @event: event code
+ * @n: new console
+ *
+ * Helper for event waits. Used to implement the legacy
+ * event waiting ioctls in terms of events
+ */
+
+int vt_waitactive(int n)
+{
+ struct vt_event_wait vw;
+ do {
+ if (n == fg_console + 1)
+ break;
+ vw.event.event = VT_EVENT_SWITCH;
+ vt_event_wait(&vw);
+ if (vw.done == 0)
+ return -EINTR;
+ } while (vw.event.newev != n);
+ return 0;
+}
+
+/*
* these are the valid i/o ports we're allowed to change. they map all the
* video ports
*/
@@ -360,6 +489,8 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_
return 0;
}
+
+
/*
* We handle the console-specific ioctl's here. We allow the
* capability to modify any console, not just the fg_console.
@@ -842,6 +973,43 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
}
break;
+ case VT_SETACTIVATE:
+ {
+ struct vt_setactivate vsa;
+
+ if (!perm)
+ goto eperm;
+
+ if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg,
+ sizeof(struct vt_setactivate))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES)
+ ret = -ENXIO;
+ else {
+ vsa.console--;
+ acquire_console_sem();
+ ret = vc_allocate(vsa.console);
+ if (ret == 0) {
+ struct vc_data *nvc;
+ /* This is safe providing we don't drop the
+ console sem between vc_allocate and
+ finishing referencing nvc */
+ nvc = vc_cons[vsa.console].d;
+ nvc->vt_mode = vsa.mode;
+ nvc->vt_mode.frsig = 0;
+ put_pid(nvc->vt_pid);
+ nvc->vt_pid = get_pid(task_pid(current));
+ }
+ release_console_sem();
+ if (ret)
+ break;
+ /* Commence switch and lock */
+ set_console(arg);
+ }
+ }
+
/*
* wait until the specified VT has been activated
*/
@@ -851,7 +1019,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (arg == 0 || arg > MAX_NR_CONSOLES)
ret = -ENXIO;
else
- ret = vt_waitactive(arg - 1);
+ ret = vt_waitactive(arg);
break;
/*
@@ -1159,6 +1327,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
ret = put_user(vc->vc_hi_font_mask,
(unsigned short __user *)arg);
break;
+ case VT_WAITEVENT:
+ ret = vt_event_wait_ioctl((struct vt_event __user *)arg);
+ break;
default:
ret = -ENOIOCTLCMD;
}
@@ -1170,54 +1341,6 @@ eperm:
goto out;
}
-/*
- * Sometimes we want to wait until a particular VT has been activated. We
- * do it in a very simple manner. Everybody waits on a single queue and
- * get woken up at once. Those that are satisfied go on with their business,
- * while those not ready go back to sleep. Seems overkill to add a wait
- * to each vt just for this - usually this does nothing!
- */
-static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue);
-
-/*
- * Sleeps until a vt is activated, or the task is interrupted. Returns
- * 0 if activation, -EINTR if interrupted by a signal handler.
- */
-int vt_waitactive(int vt)
-{
- int retval;
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&vt_activate_queue, &wait);
- for (;;) {
- retval = 0;
-
- /*
- * Synchronize with redraw_screen(). By acquiring the console
- * semaphore we make sure that the console switch is completed
- * before we return. If we didn't wait for the semaphore, we
- * could return at a point where fg_console has already been
- * updated, but the console switch hasn't been completed.
- */
- acquire_console_sem();
- set_current_state(TASK_INTERRUPTIBLE);
- if (vt == fg_console) {
- release_console_sem();
- break;
- }
- release_console_sem();
- retval = -ERESTARTNOHAND;
- if (signal_pending(current))
- break;
- schedule();
- }
- remove_wait_queue(&vt_activate_queue, &wait);
- __set_current_state(TASK_RUNNING);
- return retval;
-}
-
-#define vt_wake_waitactive() wake_up(&vt_activate_queue)
-
void reset_vc(struct vc_data *vc)
{
vc->vc_mode = KD_TEXT;
@@ -1256,12 +1379,216 @@ void vc_SAK(struct work_struct *work)
release_console_sem();
}
+#ifdef CONFIG_COMPAT
+
+struct compat_consolefontdesc {
+ unsigned short charcount; /* characters in font (256 or 512) */
+ unsigned short charheight; /* scan lines per character (1-32) */
+ compat_caddr_t chardata; /* font data in expanded form */
+};
+
+static inline int
+compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd,
+ int perm, struct console_font_op *op)
+{
+ struct compat_consolefontdesc cfdarg;
+ int i;
+
+ if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case PIO_FONTX:
+ if (!perm)
+ return -EPERM;
+ op->op = KD_FONT_OP_SET;
+ op->flags = KD_FONT_FLAG_OLD;
+ op->width = 8;
+ op->height = cfdarg.charheight;
+ op->charcount = cfdarg.charcount;
+ op->data = compat_ptr(cfdarg.chardata);
+ return con_font_op(vc_cons[fg_console].d, op);
+ case GIO_FONTX:
+ op->op = KD_FONT_OP_GET;
+ op->flags = KD_FONT_FLAG_OLD;
+ op->width = 8;
+ op->height = cfdarg.charheight;
+ op->charcount = cfdarg.charcount;
+ op->data = compat_ptr(cfdarg.chardata);
+ i = con_font_op(vc_cons[fg_console].d, op);
+ if (i)
+ return i;
+ cfdarg.charheight = op->height;
+ cfdarg.charcount = op->charcount;
+ if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc)))
+ return -EFAULT;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+struct compat_console_font_op {
+ compat_uint_t op; /* operation code KD_FONT_OP_* */
+ compat_uint_t flags; /* KD_FONT_FLAG_* */
+ compat_uint_t width, height; /* font size */
+ compat_uint_t charcount;
+ compat_caddr_t data; /* font data with height fixed to 32 */
+};
+
+static inline int
+compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop,
+ int perm, struct console_font_op *op, struct vc_data *vc)
+{
+ int i;
+
+ if (copy_from_user(op, fontop, sizeof(struct compat_console_font_op)))
+ return -EFAULT;
+ if (!perm && op->op != KD_FONT_OP_GET)
+ return -EPERM;
+ op->data = compat_ptr(((struct compat_console_font_op *)op)->data);
+ op->flags |= KD_FONT_FLAG_OLD;
+ i = con_font_op(vc, op);
+ if (i)
+ return i;
+ ((struct compat_console_font_op *)op)->data = (unsigned long)op->data;
+ if (copy_to_user(fontop, op, sizeof(struct compat_console_font_op)))
+ return -EFAULT;
+ return 0;
+}
+
+struct compat_unimapdesc {
+ unsigned short entry_ct;
+ compat_caddr_t entries;
+};
+
+static inline int
+compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
+ int perm, struct vc_data *vc)
+{
+ struct compat_unimapdesc tmp;
+ struct unipair __user *tmp_entries;
+
+ if (copy_from_user(&tmp, user_ud, sizeof tmp))
+ return -EFAULT;
+ tmp_entries = compat_ptr(tmp.entries);
+ if (tmp_entries)
+ if (!access_ok(VERIFY_WRITE, tmp_entries,
+ tmp.entry_ct*sizeof(struct unipair)))
+ return -EFAULT;
+ switch (cmd) {
+ case PIO_UNIMAP:
+ if (!perm)
+ return -EPERM;
+ return con_set_unimap(vc, tmp.entry_ct, tmp_entries);
+ case GIO_UNIMAP:
+ if (!perm && fg_console != vc->vc_num)
+ return -EPERM;
+ return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries);
+ }
+ return 0;
+}
+
+long vt_compat_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct vc_data *vc = tty->driver_data;
+ struct console_font_op op; /* used in multiple places here */
+ struct kbd_struct *kbd;
+ unsigned int console;
+ void __user *up = (void __user *)arg;
+ int perm;
+ int ret = 0;
+
+ console = vc->vc_num;
+
+ lock_kernel();
+
+ if (!vc_cons_allocated(console)) { /* impossible? */
+ ret = -ENOIOCTLCMD;
+ goto out;
+ }
+
+ /*
+ * To have permissions to do most of the vt ioctls, we either have
+ * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
+ */
+ perm = 0;
+ if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
+ perm = 1;
+
+ kbd = kbd_table + console;
+ switch (cmd) {
+ /*
+ * these need special handlers for incompatible data structures
+ */
+ case PIO_FONTX:
+ case GIO_FONTX:
+ ret = compat_fontx_ioctl(cmd, up, perm, &op);
+ break;
+
+ case KDFONTOP:
+ ret = compat_kdfontop_ioctl(up, perm, &op, vc);
+ break;
+
+ case PIO_UNIMAP:
+ case GIO_UNIMAP:
+ ret = compat_unimap_ioctl(cmd, up, perm, vc);
+ break;
+
+ /*
+ * all these treat 'arg' as an integer
+ */
+ case KIOCSOUND:
+ case KDMKTONE:
+#ifdef CONFIG_X86
+ case KDADDIO:
+ case KDDELIO:
+#endif
+ case KDSETMODE:
+ case KDMAPDISP:
+ case KDUNMAPDISP:
+ case KDSKBMODE:
+ case KDSKBMETA:
+ case KDSKBLED:
+ case KDSETLED:
+ case KDSIGACCEPT:
+ case VT_ACTIVATE:
+ case VT_WAITACTIVE:
+ case VT_RELDISP:
+ case VT_DISALLOCATE:
+ case VT_RESIZE:
+ case VT_RESIZEX:
+ goto fallback;
+
+ /*
+ * the rest has a compatible data structure behind arg,
+ * but we have to convert it to a proper 64 bit pointer.
+ */
+ default:
+ arg = (unsigned long)compat_ptr(arg);
+ goto fallback;
+ }
+out:
+ unlock_kernel();
+ return ret;
+
+fallback:
+ unlock_kernel();
+ return vt_ioctl(tty, file, cmd, arg);
+}
+
+
+#endif /* CONFIG_COMPAT */
+
+
/*
- * Performs the back end of a vt switch
+ * Performs the back end of a vt switch. Called under the console
+ * semaphore.
*/
static void complete_change_console(struct vc_data *vc)
{
unsigned char old_vc_mode;
+ int old = fg_console;
last_console = fg_console;
@@ -1325,7 +1652,7 @@ static void complete_change_console(struct vc_data *vc)
/*
* Wake anyone waiting for their VT to activate
*/
- vt_wake_waitactive();
+ vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num);
return;
}
@@ -1398,3 +1725,58 @@ void change_console(struct vc_data *new_vc)
complete_change_console(new_vc);
}
+
+/* Perform a kernel triggered VT switch for suspend/resume */
+
+static int disable_vt_switch;
+
+int vt_move_to_console(unsigned int vt, int alloc)
+{
+ int prev;
+
+ acquire_console_sem();
+ /* Graphics mode - up to X */
+ if (disable_vt_switch) {
+ release_console_sem();
+ return 0;
+ }
+ prev = fg_console;
+
+ if (alloc && vc_allocate(vt)) {
+ /* we can't have a free VC for now. Too bad,
+ * we don't want to mess the screen for now. */
+ release_console_sem();
+ return -ENOSPC;
+ }
+
+ if (set_console(vt)) {
+ /*
+ * We're unable to switch to the SUSPEND_CONSOLE.
+ * Let the calling function know so it can decide
+ * what to do.
+ */
+ release_console_sem();
+ return -EIO;
+ }
+ release_console_sem();
+ if (vt_waitactive(vt + 1)) {
+ pr_debug("Suspend: Can't switch VCs.");
+ return -EINTR;
+ }
+ return prev;
+}
+
+/*
+ * Normally during a suspend, we allocate a new console and switch to it.
+ * When we resume, we switch back to the original console. This switch
+ * can be slow, so on systems where the framebuffer can handle restoration
+ * of video registers anyways, there's little point in doing the console
+ * switch. This function allows you to disable it by passing it '0'.
+ */
+void pm_set_vt_switch(int do_switch)
+{
+ acquire_console_sem();
+ disable_vt_switch = !do_switch;
+ release_console_sem();
+}
+EXPORT_SYMBOL(pm_set_vt_switch);
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
index f40ab699860f..4846d50199f3 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -559,7 +559,7 @@ static int hwicap_release(struct inode *inode, struct file *file)
return status;
}
-static struct file_operations hwicap_fops = {
+static const struct file_operations hwicap_fops = {
.owner = THIS_MODULE,
.write = hwicap_write,
.read = hwicap_read,
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index c5afc98e2675..60697909ebdb 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -139,6 +139,31 @@ void proc_id_connector(struct task_struct *task, int which_id)
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
}
+void proc_sid_connector(struct task_struct *task)
+{
+ struct cn_msg *msg;
+ struct proc_event *ev;
+ struct timespec ts;
+ __u8 buffer[CN_PROC_MSG_SIZE];
+
+ if (atomic_read(&proc_event_num_listeners) < 1)
+ return;
+
+ msg = (struct cn_msg *)buffer;
+ ev = (struct proc_event *)msg->data;
+ get_seq(&msg->seq, &ev->cpu);
+ ktime_get_ts(&ts); /* get high res monotonic timestamp */
+ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
+ ev->what = PROC_EVENT_SID;
+ ev->event_data.sid.process_pid = task->pid;
+ ev->event_data.sid.process_tgid = task->tgid;
+
+ memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
+ msg->ack = 0; /* not used */
+ msg->len = sizeof(*ev);
+ cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+}
+
void proc_exit_connector(struct task_struct *task)
{
struct cn_msg *msg;
@@ -202,9 +227,9 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
* cn_proc_mcast_ctl
* @data: message sent from userspace via the connector
*/
-static void cn_proc_mcast_ctl(void *data)
+static void cn_proc_mcast_ctl(struct cn_msg *msg,
+ struct netlink_skb_parms *nsp)
{
- struct cn_msg *msg = data;
enum proc_cn_mcast_op *mc_op = NULL;
int err = 0;
diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c
index 408c2af25d50..210338ea222f 100644
--- a/drivers/connector/cn_queue.c
+++ b/drivers/connector/cn_queue.c
@@ -78,16 +78,20 @@ void cn_queue_wrapper(struct work_struct *work)
struct cn_callback_entry *cbq =
container_of(work, struct cn_callback_entry, work);
struct cn_callback_data *d = &cbq->data;
+ struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(d->skb));
+ struct netlink_skb_parms *nsp = &NETLINK_CB(d->skb);
- d->callback(d->callback_priv);
+ d->callback(msg, nsp);
- d->destruct_data(d->ddata);
- d->ddata = NULL;
+ kfree_skb(d->skb);
+ d->skb = NULL;
kfree(d->free);
}
-static struct cn_callback_entry *cn_queue_alloc_callback_entry(char *name, struct cb_id *id, void (*callback)(void *))
+static struct cn_callback_entry *
+cn_queue_alloc_callback_entry(char *name, struct cb_id *id,
+ void (*callback)(struct cn_msg *, struct netlink_skb_parms *))
{
struct cn_callback_entry *cbq;
@@ -120,7 +124,8 @@ int cn_cb_equal(struct cb_id *i1, struct cb_id *i2)
return ((i1->idx == i2->idx) && (i1->val == i2->val));
}
-int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(void *))
+int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id,
+ void (*callback)(struct cn_msg *, struct netlink_skb_parms *))
{
struct cn_callback_entry *cbq, *__cbq;
int found = 0;
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index 08b2500f21ec..f06024668f99 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -129,21 +129,19 @@ EXPORT_SYMBOL_GPL(cn_netlink_send);
/*
* Callback helper - queues work and setup destructor for given data.
*/
-static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), void *data)
+static int cn_call_callback(struct sk_buff *skb)
{
struct cn_callback_entry *__cbq, *__new_cbq;
struct cn_dev *dev = &cdev;
+ struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(skb));
int err = -ENODEV;
spin_lock_bh(&dev->cbdev->queue_lock);
list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) {
if (cn_cb_equal(&__cbq->id.id, &msg->id)) {
if (likely(!work_pending(&__cbq->work) &&
- __cbq->data.ddata == NULL)) {
- __cbq->data.callback_priv = msg;
-
- __cbq->data.ddata = data;
- __cbq->data.destruct_data = destruct_data;
+ __cbq->data.skb == NULL)) {
+ __cbq->data.skb = skb;
if (queue_cn_work(__cbq, &__cbq->work))
err = 0;
@@ -156,10 +154,8 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v
__new_cbq = kzalloc(sizeof(struct cn_callback_entry), GFP_ATOMIC);
if (__new_cbq) {
d = &__new_cbq->data;
- d->callback_priv = msg;
+ d->skb = skb;
d->callback = __cbq->data.callback;
- d->ddata = data;
- d->destruct_data = destruct_data;
d->free = __new_cbq;
__new_cbq->pdev = __cbq->pdev;
@@ -191,7 +187,6 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v
*/
static void cn_rx_skb(struct sk_buff *__skb)
{
- struct cn_msg *msg;
struct nlmsghdr *nlh;
int err;
struct sk_buff *skb;
@@ -208,8 +203,7 @@ static void cn_rx_skb(struct sk_buff *__skb)
return;
}
- msg = NLMSG_DATA(nlh);
- err = cn_call_callback(msg, (void (*)(void *))kfree_skb, skb);
+ err = cn_call_callback(skb);
if (err < 0)
kfree_skb(skb);
}
@@ -269,7 +263,8 @@ static void cn_notify(struct cb_id *id, u32 notify_event)
*
* May sleep.
*/
-int cn_add_callback(struct cb_id *id, char *name, void (*callback)(void *))
+int cn_add_callback(struct cb_id *id, char *name,
+ void (*callback)(struct cn_msg *, struct netlink_skb_parms *))
{
int err;
struct cn_dev *dev = &cdev;
@@ -351,9 +346,8 @@ static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2)
*
* Used for notification of a request's processing.
*/
-static void cn_callback(void *data)
+static void cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
{
- struct cn_msg *msg = data;
struct cn_ctl_msg *ctl;
struct cn_ctl_entry *ent;
u32 size;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 2968ed6a9c49..ff57c40e9b8b 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -41,7 +41,7 @@ static struct cpufreq_driver *cpufreq_driver;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
#ifdef CONFIG_HOTPLUG_CPU
/* This one keeps track of the previously set governor of a removed CPU */
-static DEFINE_PER_CPU(struct cpufreq_governor *, cpufreq_cpu_governor);
+static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
#endif
static DEFINE_SPINLOCK(cpufreq_driver_lock);
@@ -61,6 +61,8 @@ static DEFINE_SPINLOCK(cpufreq_driver_lock);
* are concerned with are online after they get the lock.
* - Governor routines that can be called in cpufreq hotplug path should not
* take this sem as top level hotplug notifier handler takes this.
+ * - Lock should not be held across
+ * __cpufreq_governor(data, CPUFREQ_GOV_STOP);
*/
static DEFINE_PER_CPU(int, policy_cpu);
static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
@@ -686,6 +688,9 @@ static struct attribute *default_attrs[] = {
NULL
};
+struct kobject *cpufreq_global_kobject;
+EXPORT_SYMBOL(cpufreq_global_kobject);
+
#define to_policy(k) container_of(k, struct cpufreq_policy, kobj)
#define to_attr(a) container_of(a, struct freq_attr, attr)
@@ -756,95 +761,25 @@ static struct kobj_type ktype_cpufreq = {
.release = cpufreq_sysfs_release,
};
-
-/**
- * cpufreq_add_dev - add a CPU device
- *
- * Adds the cpufreq interface for a CPU device.
- *
- * The Oracle says: try running cpufreq registration/unregistration concurrently
- * with with cpu hotplugging and all hell will break loose. Tried to clean this
- * mess up, but more thorough testing is needed. - Mathieu
+/*
+ * Returns:
+ * Negative: Failure
+ * 0: Success
+ * Positive: When we have a managed CPU and the sysfs got symlinked
*/
-static int cpufreq_add_dev(struct sys_device *sys_dev)
+int cpufreq_add_dev_policy(unsigned int cpu, struct cpufreq_policy *policy,
+ struct sys_device *sys_dev)
{
- unsigned int cpu = sys_dev->id;
int ret = 0;
- struct cpufreq_policy new_policy;
- struct cpufreq_policy *policy;
- struct freq_attr **drv_attr;
- struct sys_device *cpu_sys_dev;
+#ifdef CONFIG_SMP
unsigned long flags;
unsigned int j;
-
- if (cpu_is_offline(cpu))
- return 0;
-
- cpufreq_debug_disable_ratelimit();
- dprintk("adding CPU %u\n", cpu);
-
-#ifdef CONFIG_SMP
- /* check whether a different CPU already registered this
- * CPU because it is in the same boat. */
- policy = cpufreq_cpu_get(cpu);
- if (unlikely(policy)) {
- cpufreq_cpu_put(policy);
- cpufreq_debug_enable_ratelimit();
- return 0;
- }
-#endif
-
- if (!try_module_get(cpufreq_driver->owner)) {
- ret = -EINVAL;
- goto module_out;
- }
-
- policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
- if (!policy) {
- ret = -ENOMEM;
- goto nomem_out;
- }
- if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) {
- ret = -ENOMEM;
- goto err_free_policy;
- }
- if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) {
- ret = -ENOMEM;
- goto err_free_cpumask;
- }
-
- policy->cpu = cpu;
- cpumask_copy(policy->cpus, cpumask_of(cpu));
-
- /* Initially set CPU itself as the policy_cpu */
- per_cpu(policy_cpu, cpu) = cpu;
- ret = (lock_policy_rwsem_write(cpu) < 0);
- WARN_ON(ret);
-
- init_completion(&policy->kobj_unregister);
- INIT_WORK(&policy->update, handle_update);
-
- /* Set governor before ->init, so that driver could check it */
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
- /* call driver. From then on the cpufreq must be able
- * to accept all calls to ->verify and ->setpolicy for this CPU
- */
- ret = cpufreq_driver->init(policy);
- if (ret) {
- dprintk("initialization failed\n");
- goto err_unlock_policy;
- }
- policy->user_policy.min = policy->min;
- policy->user_policy.max = policy->max;
-
- blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
- CPUFREQ_START, policy);
-
-#ifdef CONFIG_SMP
-
#ifdef CONFIG_HOTPLUG_CPU
- if (per_cpu(cpufreq_cpu_governor, cpu)) {
- policy->governor = per_cpu(cpufreq_cpu_governor, cpu);
+ struct cpufreq_governor *gov;
+
+ gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
+ if (gov) {
+ policy->governor = gov;
dprintk("Restoring governor %s for cpu %d\n",
policy->governor->name, cpu);
}
@@ -872,9 +807,8 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
/* Should not go through policy unlock path */
if (cpufreq_driver->exit)
cpufreq_driver->exit(policy);
- ret = -EBUSY;
cpufreq_cpu_put(managed_policy);
- goto err_free_cpumask;
+ return -EBUSY;
}
spin_lock_irqsave(&cpufreq_driver_lock, flags);
@@ -893,17 +827,62 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
* Call driver->exit() because only the cpu parent of
* the kobj needed to call init().
*/
- goto out_driver_exit; /* call driver->exit() */
+ if (cpufreq_driver->exit)
+ cpufreq_driver->exit(policy);
+
+ if (!ret)
+ return 1;
+ else
+ return ret;
}
}
#endif
- memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
+ return ret;
+}
+
+
+/* symlink affected CPUs */
+int cpufreq_add_dev_symlink(unsigned int cpu, struct cpufreq_policy *policy)
+{
+ unsigned int j;
+ int ret = 0;
+
+ for_each_cpu(j, policy->cpus) {
+ struct cpufreq_policy *managed_policy;
+ struct sys_device *cpu_sys_dev;
+
+ if (j == cpu)
+ continue;
+ if (!cpu_online(j))
+ continue;
+
+ dprintk("CPU %u already managed, adding link\n", j);
+ managed_policy = cpufreq_cpu_get(cpu);
+ cpu_sys_dev = get_cpu_sysdev(j);
+ ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
+ "cpufreq");
+ if (ret) {
+ cpufreq_cpu_put(managed_policy);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+int cpufreq_add_dev_interface(unsigned int cpu, struct cpufreq_policy *policy,
+ struct sys_device *sys_dev)
+{
+ struct cpufreq_policy new_policy;
+ struct freq_attr **drv_attr;
+ unsigned long flags;
+ int ret = 0;
+ unsigned int j;
/* prepare interface data */
- ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj,
- "cpufreq");
+ ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
+ &sys_dev->kobj, "cpufreq");
if (ret)
- goto out_driver_exit;
+ return ret;
/* set up files for this cpu device */
drv_attr = cpufreq_driver->attr;
@@ -926,35 +905,20 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
spin_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu(j, policy->cpus) {
- if (!cpu_online(j))
- continue;
+ if (!cpu_online(j))
+ continue;
per_cpu(cpufreq_cpu_data, j) = policy;
per_cpu(policy_cpu, j) = policy->cpu;
}
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
- /* symlink affected CPUs */
- for_each_cpu(j, policy->cpus) {
- struct cpufreq_policy *managed_policy;
-
- if (j == cpu)
- continue;
- if (!cpu_online(j))
- continue;
-
- dprintk("CPU %u already managed, adding link\n", j);
- managed_policy = cpufreq_cpu_get(cpu);
- cpu_sys_dev = get_cpu_sysdev(j);
- ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
- "cpufreq");
- if (ret) {
- cpufreq_cpu_put(managed_policy);
- goto err_out_unregister;
- }
- }
+ ret = cpufreq_add_dev_symlink(cpu, policy);
+ if (ret)
+ goto err_out_kobj_put;
- policy->governor = NULL; /* to assure that the starting sequence is
- * run in cpufreq_set_policy */
+ memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
+ /* assure that the starting sequence is run in __cpufreq_set_policy */
+ policy->governor = NULL;
/* set default policy */
ret = __cpufreq_set_policy(policy, &new_policy);
@@ -963,8 +927,122 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
if (ret) {
dprintk("setting policy failed\n");
- goto err_out_unregister;
+ if (cpufreq_driver->exit)
+ cpufreq_driver->exit(policy);
+ }
+ return ret;
+
+err_out_kobj_put:
+ kobject_put(&policy->kobj);
+ wait_for_completion(&policy->kobj_unregister);
+ return ret;
+}
+
+
+/**
+ * cpufreq_add_dev - add a CPU device
+ *
+ * Adds the cpufreq interface for a CPU device.
+ *
+ * The Oracle says: try running cpufreq registration/unregistration concurrently
+ * with with cpu hotplugging and all hell will break loose. Tried to clean this
+ * mess up, but more thorough testing is needed. - Mathieu
+ */
+static int cpufreq_add_dev(struct sys_device *sys_dev)
+{
+ unsigned int cpu = sys_dev->id;
+ int ret = 0, found = 0;
+ struct cpufreq_policy *policy;
+ unsigned long flags;
+ unsigned int j;
+#ifdef CONFIG_HOTPLUG_CPU
+ int sibling;
+#endif
+
+ if (cpu_is_offline(cpu))
+ return 0;
+
+ cpufreq_debug_disable_ratelimit();
+ dprintk("adding CPU %u\n", cpu);
+
+#ifdef CONFIG_SMP
+ /* check whether a different CPU already registered this
+ * CPU because it is in the same boat. */
+ policy = cpufreq_cpu_get(cpu);
+ if (unlikely(policy)) {
+ cpufreq_cpu_put(policy);
+ cpufreq_debug_enable_ratelimit();
+ return 0;
}
+#endif
+
+ if (!try_module_get(cpufreq_driver->owner)) {
+ ret = -EINVAL;
+ goto module_out;
+ }
+
+ ret = -ENOMEM;
+ policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
+ if (!policy)
+ goto nomem_out;
+
+ if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
+ goto err_free_policy;
+
+ if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
+ goto err_free_cpumask;
+
+ policy->cpu = cpu;
+ cpumask_copy(policy->cpus, cpumask_of(cpu));
+
+ /* Initially set CPU itself as the policy_cpu */
+ per_cpu(policy_cpu, cpu) = cpu;
+ ret = (lock_policy_rwsem_write(cpu) < 0);
+ WARN_ON(ret);
+
+ init_completion(&policy->kobj_unregister);
+ INIT_WORK(&policy->update, handle_update);
+
+ /* Set governor before ->init, so that driver could check it */
+#ifdef CONFIG_HOTPLUG_CPU
+ for_each_online_cpu(sibling) {
+ struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
+ if (cp && cp->governor &&
+ (cpumask_test_cpu(cpu, cp->related_cpus))) {
+ policy->governor = cp->governor;
+ found = 1;
+ break;
+ }
+ }
+#endif
+ if (!found)
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+ /* call driver. From then on the cpufreq must be able
+ * to accept all calls to ->verify and ->setpolicy for this CPU
+ */
+ ret = cpufreq_driver->init(policy);
+ if (ret) {
+ dprintk("initialization failed\n");
+ goto err_unlock_policy;
+ }
+ policy->user_policy.min = policy->min;
+ policy->user_policy.max = policy->max;
+
+ blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
+ CPUFREQ_START, policy);
+
+ ret = cpufreq_add_dev_policy(cpu, policy, sys_dev);
+ if (ret) {
+ if (ret > 0)
+ /* This is a managed cpu, symlink created,
+ exit with 0 */
+ ret = 0;
+ goto err_unlock_policy;
+ }
+
+ ret = cpufreq_add_dev_interface(cpu, policy, sys_dev);
+ if (ret)
+ goto err_out_unregister;
unlock_policy_rwsem_write(cpu);
@@ -982,14 +1060,9 @@ err_out_unregister:
per_cpu(cpufreq_cpu_data, j) = NULL;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
-err_out_kobj_put:
kobject_put(&policy->kobj);
wait_for_completion(&policy->kobj_unregister);
-out_driver_exit:
- if (cpufreq_driver->exit)
- cpufreq_driver->exit(policy);
-
err_unlock_policy:
unlock_policy_rwsem_write(cpu);
err_free_cpumask:
@@ -1055,7 +1128,8 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
#ifdef CONFIG_SMP
#ifdef CONFIG_HOTPLUG_CPU
- per_cpu(cpufreq_cpu_governor, cpu) = data->governor;
+ strncpy(per_cpu(cpufreq_cpu_governor, cpu), data->governor->name,
+ CPUFREQ_NAME_LEN);
#endif
/* if we have other CPUs still registered, we need to unlink them,
@@ -1079,7 +1153,8 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
continue;
dprintk("removing link for cpu %u\n", j);
#ifdef CONFIG_HOTPLUG_CPU
- per_cpu(cpufreq_cpu_governor, j) = data->governor;
+ strncpy(per_cpu(cpufreq_cpu_governor, j),
+ data->governor->name, CPUFREQ_NAME_LEN);
#endif
cpu_sys_dev = get_cpu_sysdev(j);
sysfs_remove_link(&cpu_sys_dev->kobj, "cpufreq");
@@ -1550,9 +1625,22 @@ EXPORT_SYMBOL_GPL(cpufreq_register_governor);
void cpufreq_unregister_governor(struct cpufreq_governor *governor)
{
+#ifdef CONFIG_HOTPLUG_CPU
+ int cpu;
+#endif
+
if (!governor)
return;
+#ifdef CONFIG_HOTPLUG_CPU
+ for_each_present_cpu(cpu) {
+ if (cpu_online(cpu))
+ continue;
+ if (!strcmp(per_cpu(cpufreq_cpu_governor, cpu), governor->name))
+ strcpy(per_cpu(cpufreq_cpu_governor, cpu), "\0");
+ }
+#endif
+
mutex_lock(&cpufreq_governor_mutex);
list_del(&governor->governor_list);
mutex_unlock(&cpufreq_governor_mutex);
@@ -1653,8 +1741,17 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
dprintk("governor switch\n");
/* end old governor */
- if (data->governor)
+ if (data->governor) {
+ /*
+ * Need to release the rwsem around governor
+ * stop due to lock dependency between
+ * cancel_delayed_work_sync and the read lock
+ * taken in the delayed work handler.
+ */
+ unlock_policy_rwsem_write(data->cpu);
__cpufreq_governor(data, CPUFREQ_GOV_STOP);
+ lock_policy_rwsem_write(data->cpu);
+ }
/* start new governor */
data->governor = policy->governor;
@@ -1884,7 +1981,11 @@ static int __init cpufreq_core_init(void)
per_cpu(policy_cpu, cpu) = -1;
init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
}
+
+ cpufreq_global_kobject = kobject_create_and_add("cpufreq",
+ &cpu_sysdev_class.kset.kobj);
+ BUG_ON(!cpufreq_global_kobject);
+
return 0;
}
-
core_initcall(cpufreq_core_init);
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index bdea7e2f94ba..c7b081b839ff 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -71,7 +71,7 @@ struct cpu_dbs_info_s {
*/
struct mutex timer_mutex;
};
-static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
+static DEFINE_PER_CPU(struct cpu_dbs_info_s, cs_cpu_dbs_info);
static unsigned int dbs_enable; /* number of CPUs using this policy */
@@ -116,9 +116,9 @@ static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
idle_time = cputime64_sub(cur_wall_time, busy_time);
if (wall)
- *wall = cur_wall_time;
+ *wall = (cputime64_t)jiffies_to_usecs(cur_wall_time);
- return idle_time;
+ return (cputime64_t)jiffies_to_usecs(idle_time);;
}
static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
@@ -137,7 +137,7 @@ dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
struct cpufreq_freqs *freq = data;
- struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cpu_dbs_info,
+ struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cs_cpu_dbs_info,
freq->cpu);
struct cpufreq_policy *policy;
@@ -297,7 +297,7 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
/* we need to re-evaluate prev_cpu_idle */
for_each_online_cpu(j) {
struct cpu_dbs_info_s *dbs_info;
- dbs_info = &per_cpu(cpu_dbs_info, j);
+ dbs_info = &per_cpu(cs_cpu_dbs_info, j);
dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
&dbs_info->prev_cpu_wall);
if (dbs_tuners_ins.ignore_nice)
@@ -387,7 +387,7 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
cputime64_t cur_wall_time, cur_idle_time;
unsigned int idle_time, wall_time;
- j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info = &per_cpu(cs_cpu_dbs_info, j);
cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
@@ -521,7 +521,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
unsigned int j;
int rc;
- this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
+ this_dbs_info = &per_cpu(cs_cpu_dbs_info, cpu);
switch (event) {
case CPUFREQ_GOV_START:
@@ -538,7 +538,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
- j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info = &per_cpu(cs_cpu_dbs_info, j);
j_dbs_info->cur_policy = policy;
j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index d6ba14276bb1..4b34ade2332b 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -55,6 +55,18 @@ static unsigned int min_sampling_rate;
#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
static void do_dbs_timer(struct work_struct *work);
+static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
+ unsigned int event);
+
+#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
+static
+#endif
+struct cpufreq_governor cpufreq_gov_ondemand = {
+ .name = "ondemand",
+ .governor = cpufreq_governor_dbs,
+ .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+ .owner = THIS_MODULE,
+};
/* Sampling types */
enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE};
@@ -78,7 +90,7 @@ struct cpu_dbs_info_s {
*/
struct mutex timer_mutex;
};
-static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
+static DEFINE_PER_CPU(struct cpu_dbs_info_s, od_cpu_dbs_info);
static unsigned int dbs_enable; /* number of CPUs using this policy */
@@ -121,9 +133,9 @@ static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
idle_time = cputime64_sub(cur_wall_time, busy_time);
if (wall)
- *wall = cur_wall_time;
+ *wall = (cputime64_t)jiffies_to_usecs(cur_wall_time);
- return idle_time;
+ return (cputime64_t)jiffies_to_usecs(idle_time);
}
static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
@@ -149,7 +161,8 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
unsigned int freq_hi, freq_lo;
unsigned int index = 0;
unsigned int jiffies_total, jiffies_hi, jiffies_lo;
- struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, policy->cpu);
+ struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info,
+ policy->cpu);
if (!dbs_info->freq_table) {
dbs_info->freq_lo = 0;
@@ -192,7 +205,7 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
static void ondemand_powersave_bias_init_cpu(int cpu)
{
- struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu);
+ struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
dbs_info->freq_table = cpufreq_frequency_get_table(cpu);
dbs_info->freq_lo = 0;
}
@@ -206,20 +219,23 @@ static void ondemand_powersave_bias_init(void)
}
/************************** sysfs interface ************************/
-static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
+
+static ssize_t show_sampling_rate_max(struct kobject *kobj,
+ struct attribute *attr, char *buf)
{
printk_once(KERN_INFO "CPUFREQ: ondemand sampling_rate_max "
"sysfs file is deprecated - used by: %s\n", current->comm);
return sprintf(buf, "%u\n", -1U);
}
-static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_sampling_rate_min(struct kobject *kobj,
+ struct attribute *attr, char *buf)
{
return sprintf(buf, "%u\n", min_sampling_rate);
}
#define define_one_ro(_name) \
-static struct freq_attr _name = \
+static struct global_attr _name = \
__ATTR(_name, 0444, show_##_name, NULL)
define_one_ro(sampling_rate_max);
@@ -228,7 +244,7 @@ define_one_ro(sampling_rate_min);
/* cpufreq_ondemand Governor Tunables */
#define show_one(file_name, object) \
static ssize_t show_##file_name \
-(struct cpufreq_policy *unused, char *buf) \
+(struct kobject *kobj, struct attribute *attr, char *buf) \
{ \
return sprintf(buf, "%u\n", dbs_tuners_ins.object); \
}
@@ -237,8 +253,38 @@ show_one(up_threshold, up_threshold);
show_one(ignore_nice_load, ignore_nice);
show_one(powersave_bias, powersave_bias);
-static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
- const char *buf, size_t count)
+/*** delete after deprecation time ***/
+
+#define DEPRECATION_MSG(file_name) \
+ printk_once(KERN_INFO "CPUFREQ: Per core ondemand sysfs " \
+ "interface is deprecated - " #file_name "\n");
+
+#define show_one_old(file_name) \
+static ssize_t show_##file_name##_old \
+(struct cpufreq_policy *unused, char *buf) \
+{ \
+ printk_once(KERN_INFO "CPUFREQ: Per core ondemand sysfs " \
+ "interface is deprecated - " #file_name "\n"); \
+ return show_##file_name(NULL, NULL, buf); \
+}
+show_one_old(sampling_rate);
+show_one_old(up_threshold);
+show_one_old(ignore_nice_load);
+show_one_old(powersave_bias);
+show_one_old(sampling_rate_min);
+show_one_old(sampling_rate_max);
+
+#define define_one_ro_old(object, _name) \
+static struct freq_attr object = \
+__ATTR(_name, 0444, show_##_name##_old, NULL)
+
+define_one_ro_old(sampling_rate_min_old, sampling_rate_min);
+define_one_ro_old(sampling_rate_max_old, sampling_rate_max);
+
+/*** delete after deprecation time ***/
+
+static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
{
unsigned int input;
int ret;
@@ -253,8 +299,8 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
return count;
}
-static ssize_t store_up_threshold(struct cpufreq_policy *unused,
- const char *buf, size_t count)
+static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
{
unsigned int input;
int ret;
@@ -272,8 +318,8 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused,
return count;
}
-static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
- const char *buf, size_t count)
+static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
{
unsigned int input;
int ret;
@@ -297,7 +343,7 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
/* we need to re-evaluate prev_cpu_idle */
for_each_online_cpu(j) {
struct cpu_dbs_info_s *dbs_info;
- dbs_info = &per_cpu(cpu_dbs_info, j);
+ dbs_info = &per_cpu(od_cpu_dbs_info, j);
dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
&dbs_info->prev_cpu_wall);
if (dbs_tuners_ins.ignore_nice)
@@ -309,8 +355,8 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
return count;
}
-static ssize_t store_powersave_bias(struct cpufreq_policy *unused,
- const char *buf, size_t count)
+static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
{
unsigned int input;
int ret;
@@ -331,7 +377,7 @@ static ssize_t store_powersave_bias(struct cpufreq_policy *unused,
}
#define define_one_rw(_name) \
-static struct freq_attr _name = \
+static struct global_attr _name = \
__ATTR(_name, 0644, show_##_name, store_##_name)
define_one_rw(sampling_rate);
@@ -354,6 +400,47 @@ static struct attribute_group dbs_attr_group = {
.name = "ondemand",
};
+/*** delete after deprecation time ***/
+
+#define write_one_old(file_name) \
+static ssize_t store_##file_name##_old \
+(struct cpufreq_policy *unused, const char *buf, size_t count) \
+{ \
+ printk_once(KERN_INFO "CPUFREQ: Per core ondemand sysfs " \
+ "interface is deprecated - " #file_name "\n"); \
+ return store_##file_name(NULL, NULL, buf, count); \
+}
+write_one_old(sampling_rate);
+write_one_old(up_threshold);
+write_one_old(ignore_nice_load);
+write_one_old(powersave_bias);
+
+#define define_one_rw_old(object, _name) \
+static struct freq_attr object = \
+__ATTR(_name, 0644, show_##_name##_old, store_##_name##_old)
+
+define_one_rw_old(sampling_rate_old, sampling_rate);
+define_one_rw_old(up_threshold_old, up_threshold);
+define_one_rw_old(ignore_nice_load_old, ignore_nice_load);
+define_one_rw_old(powersave_bias_old, powersave_bias);
+
+static struct attribute *dbs_attributes_old[] = {
+ &sampling_rate_max_old.attr,
+ &sampling_rate_min_old.attr,
+ &sampling_rate_old.attr,
+ &up_threshold_old.attr,
+ &ignore_nice_load_old.attr,
+ &powersave_bias_old.attr,
+ NULL
+};
+
+static struct attribute_group dbs_attr_group_old = {
+ .attrs = dbs_attributes_old,
+ .name = "ondemand",
+};
+
+/*** delete after deprecation time ***/
+
/************************** sysfs end ************************/
static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
@@ -388,7 +475,7 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
unsigned int load, load_freq;
int freq_avg;
- j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
@@ -535,7 +622,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
unsigned int j;
int rc;
- this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
+ this_dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
switch (event) {
case CPUFREQ_GOV_START:
@@ -544,7 +631,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
mutex_lock(&dbs_mutex);
- rc = sysfs_create_group(&policy->kobj, &dbs_attr_group);
+ rc = sysfs_create_group(&policy->kobj, &dbs_attr_group_old);
if (rc) {
mutex_unlock(&dbs_mutex);
return rc;
@@ -553,7 +640,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
dbs_enable++;
for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
- j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
j_dbs_info->cur_policy = policy;
j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
@@ -565,13 +652,20 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
}
this_dbs_info->cpu = cpu;
ondemand_powersave_bias_init_cpu(cpu);
- mutex_init(&this_dbs_info->timer_mutex);
/*
* Start the timerschedule work, when this governor
* is used for first time
*/
if (dbs_enable == 1) {
unsigned int latency;
+
+ rc = sysfs_create_group(cpufreq_global_kobject,
+ &dbs_attr_group);
+ if (rc) {
+ mutex_unlock(&dbs_mutex);
+ return rc;
+ }
+
/* policy latency is in nS. Convert it to uS first */
latency = policy->cpuinfo.transition_latency / 1000;
if (latency == 0)
@@ -585,6 +679,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
}
mutex_unlock(&dbs_mutex);
+ mutex_init(&this_dbs_info->timer_mutex);
dbs_timer_init(this_dbs_info);
break;
@@ -592,10 +687,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
dbs_timer_exit(this_dbs_info);
mutex_lock(&dbs_mutex);
- sysfs_remove_group(&policy->kobj, &dbs_attr_group);
+ sysfs_remove_group(&policy->kobj, &dbs_attr_group_old);
mutex_destroy(&this_dbs_info->timer_mutex);
dbs_enable--;
mutex_unlock(&dbs_mutex);
+ if (!dbs_enable)
+ sysfs_remove_group(cpufreq_global_kobject,
+ &dbs_attr_group);
break;
@@ -613,16 +711,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return 0;
}
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
-static
-#endif
-struct cpufreq_governor cpufreq_gov_ondemand = {
- .name = "ondemand",
- .governor = cpufreq_governor_dbs,
- .max_transition_latency = TRANSITION_LATENCY_LIMIT,
- .owner = THIS_MODULE,
-};
-
static int __init cpufreq_gov_dbs_init(void)
{
int err;
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 8504a2108557..12fdd3987a36 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -17,6 +17,7 @@
#include <linux/cpuidle.h>
#include <linux/ktime.h>
#include <linux/hrtimer.h>
+#include <trace/events/power.h>
#include "cpuidle.h"
@@ -75,8 +76,11 @@ static void cpuidle_idle_call(void)
#endif
/* ask the governor for the next state */
next_state = cpuidle_curr_governor->select(dev);
- if (need_resched())
+ if (need_resched()) {
+ local_irq_enable();
return;
+ }
+
target_state = &dev->states[next_state];
/* enter the state and update stats */
@@ -91,6 +95,7 @@ static void cpuidle_idle_call(void)
/* give the governor an opportunity to reflect on the outcome */
if (cpuidle_curr_governor->reflect)
cpuidle_curr_governor->reflect(dev);
+ trace_power_end(0);
}
/**
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index f1df59f59a37..68104434ebb5 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -2,8 +2,12 @@
* menu.c - the menu idle governor
*
* Copyright (C) 2006-2007 Adam Belay <abelay@novell.com>
+ * Copyright (C) 2009 Intel Corporation
+ * Author:
+ * Arjan van de Ven <arjan@linux.intel.com>
*
- * This code is licenced under the GPL.
+ * This code is licenced under the GPL version 2 as described
+ * in the COPYING file that acompanies the Linux Kernel.
*/
#include <linux/kernel.h>
@@ -13,22 +17,158 @@
#include <linux/ktime.h>
#include <linux/hrtimer.h>
#include <linux/tick.h>
+#include <linux/sched.h>
-#define BREAK_FUZZ 4 /* 4 us */
-#define PRED_HISTORY_PCT 50
+#define BUCKETS 12
+#define RESOLUTION 1024
+#define DECAY 4
+#define MAX_INTERESTING 50000
+
+/*
+ * Concepts and ideas behind the menu governor
+ *
+ * For the menu governor, there are 3 decision factors for picking a C
+ * state:
+ * 1) Energy break even point
+ * 2) Performance impact
+ * 3) Latency tolerance (from pmqos infrastructure)
+ * These these three factors are treated independently.
+ *
+ * Energy break even point
+ * -----------------------
+ * C state entry and exit have an energy cost, and a certain amount of time in
+ * the C state is required to actually break even on this cost. CPUIDLE
+ * provides us this duration in the "target_residency" field. So all that we
+ * need is a good prediction of how long we'll be idle. Like the traditional
+ * menu governor, we start with the actual known "next timer event" time.
+ *
+ * Since there are other source of wakeups (interrupts for example) than
+ * the next timer event, this estimation is rather optimistic. To get a
+ * more realistic estimate, a correction factor is applied to the estimate,
+ * that is based on historic behavior. For example, if in the past the actual
+ * duration always was 50% of the next timer tick, the correction factor will
+ * be 0.5.
+ *
+ * menu uses a running average for this correction factor, however it uses a
+ * set of factors, not just a single factor. This stems from the realization
+ * that the ratio is dependent on the order of magnitude of the expected
+ * duration; if we expect 500 milliseconds of idle time the likelihood of
+ * getting an interrupt very early is much higher than if we expect 50 micro
+ * seconds of idle time. A second independent factor that has big impact on
+ * the actual factor is if there is (disk) IO outstanding or not.
+ * (as a special twist, we consider every sleep longer than 50 milliseconds
+ * as perfect; there are no power gains for sleeping longer than this)
+ *
+ * For these two reasons we keep an array of 12 independent factors, that gets
+ * indexed based on the magnitude of the expected duration as well as the
+ * "is IO outstanding" property.
+ *
+ * Limiting Performance Impact
+ * ---------------------------
+ * C states, especially those with large exit latencies, can have a real
+ * noticable impact on workloads, which is not acceptable for most sysadmins,
+ * and in addition, less performance has a power price of its own.
+ *
+ * As a general rule of thumb, menu assumes that the following heuristic
+ * holds:
+ * The busier the system, the less impact of C states is acceptable
+ *
+ * This rule-of-thumb is implemented using a performance-multiplier:
+ * If the exit latency times the performance multiplier is longer than
+ * the predicted duration, the C state is not considered a candidate
+ * for selection due to a too high performance impact. So the higher
+ * this multiplier is, the longer we need to be idle to pick a deep C
+ * state, and thus the less likely a busy CPU will hit such a deep
+ * C state.
+ *
+ * Two factors are used in determing this multiplier:
+ * a value of 10 is added for each point of "per cpu load average" we have.
+ * a value of 5 points is added for each process that is waiting for
+ * IO on this CPU.
+ * (these values are experimentally determined)
+ *
+ * The load average factor gives a longer term (few seconds) input to the
+ * decision, while the iowait value gives a cpu local instantanious input.
+ * The iowait factor may look low, but realize that this is also already
+ * represented in the system load average.
+ *
+ */
struct menu_device {
int last_state_idx;
+ int needs_update;
unsigned int expected_us;
- unsigned int predicted_us;
- unsigned int current_predicted_us;
- unsigned int last_measured_us;
- unsigned int elapsed_us;
+ u64 predicted_us;
+ unsigned int measured_us;
+ unsigned int exit_us;
+ unsigned int bucket;
+ u64 correction_factor[BUCKETS];
};
+
+#define LOAD_INT(x) ((x) >> FSHIFT)
+#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
+
+static int get_loadavg(void)
+{
+ unsigned long this = this_cpu_load();
+
+
+ return LOAD_INT(this) * 10 + LOAD_FRAC(this) / 10;
+}
+
+static inline int which_bucket(unsigned int duration)
+{
+ int bucket = 0;
+
+ /*
+ * We keep two groups of stats; one with no
+ * IO pending, one without.
+ * This allows us to calculate
+ * E(duration)|iowait
+ */
+ if (nr_iowait_cpu())
+ bucket = BUCKETS/2;
+
+ if (duration < 10)
+ return bucket;
+ if (duration < 100)
+ return bucket + 1;
+ if (duration < 1000)
+ return bucket + 2;
+ if (duration < 10000)
+ return bucket + 3;
+ if (duration < 100000)
+ return bucket + 4;
+ return bucket + 5;
+}
+
+/*
+ * Return a multiplier for the exit latency that is intended
+ * to take performance requirements into account.
+ * The more performance critical we estimate the system
+ * to be, the higher this multiplier, and thus the higher
+ * the barrier to go to an expensive C state.
+ */
+static inline int performance_multiplier(void)
+{
+ int mult = 1;
+
+ /* for higher loadavg, we are more reluctant */
+
+ mult += 2 * get_loadavg();
+
+ /* for IO wait tasks (per cpu!) we add 5x each */
+ mult += 10 * nr_iowait_cpu();
+
+ return mult;
+}
+
static DEFINE_PER_CPU(struct menu_device, menu_devices);
+static void menu_update(struct cpuidle_device *dev);
+
/**
* menu_select - selects the next idle state to enter
* @dev: the CPU
@@ -38,41 +178,68 @@ static int menu_select(struct cpuidle_device *dev)
struct menu_device *data = &__get_cpu_var(menu_devices);
int latency_req = pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY);
int i;
+ int multiplier;
+
+ data->last_state_idx = 0;
+ data->exit_us = 0;
+
+ if (data->needs_update) {
+ menu_update(dev);
+ data->needs_update = 0;
+ }
/* Special case when user has set very strict latency requirement */
- if (unlikely(latency_req == 0)) {
- data->last_state_idx = 0;
+ if (unlikely(latency_req == 0))
return 0;
- }
- /* determine the expected residency time */
+ /* determine the expected residency time, round up */
data->expected_us =
- (u32) ktime_to_ns(tick_nohz_get_sleep_length()) / 1000;
+ DIV_ROUND_UP((u32)ktime_to_ns(tick_nohz_get_sleep_length()), 1000);
+
+
+ data->bucket = which_bucket(data->expected_us);
+
+ multiplier = performance_multiplier();
+
+ /*
+ * if the correction factor is 0 (eg first time init or cpu hotplug
+ * etc), we actually want to start out with a unity factor.
+ */
+ if (data->correction_factor[data->bucket] == 0)
+ data->correction_factor[data->bucket] = RESOLUTION * DECAY;
+
+ /* Make sure to round up for half microseconds */
+ data->predicted_us = DIV_ROUND_CLOSEST(
+ data->expected_us * data->correction_factor[data->bucket],
+ RESOLUTION * DECAY);
+
+ /*
+ * We want to default to C1 (hlt), not to busy polling
+ * unless the timer is happening really really soon.
+ */
+ if (data->expected_us > 5)
+ data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
- /* Recalculate predicted_us based on prediction_history_pct */
- data->predicted_us *= PRED_HISTORY_PCT;
- data->predicted_us += (100 - PRED_HISTORY_PCT) *
- data->current_predicted_us;
- data->predicted_us /= 100;
/* find the deepest idle state that satisfies our constraints */
- for (i = CPUIDLE_DRIVER_STATE_START + 1; i < dev->state_count; i++) {
+ for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) {
struct cpuidle_state *s = &dev->states[i];
- if (s->target_residency > data->expected_us)
- break;
if (s->target_residency > data->predicted_us)
break;
if (s->exit_latency > latency_req)
break;
+ if (s->exit_latency * multiplier > data->predicted_us)
+ break;
+ data->exit_us = s->exit_latency;
+ data->last_state_idx = i;
}
- data->last_state_idx = i - 1;
- return i - 1;
+ return data->last_state_idx;
}
/**
- * menu_reflect - attempts to guess what happened after entry
+ * menu_reflect - records that data structures need update
* @dev: the CPU
*
* NOTE: it's important to be fast here because this operation will add to
@@ -81,39 +248,63 @@ static int menu_select(struct cpuidle_device *dev)
static void menu_reflect(struct cpuidle_device *dev)
{
struct menu_device *data = &__get_cpu_var(menu_devices);
+ data->needs_update = 1;
+}
+
+/**
+ * menu_update - attempts to guess what happened after entry
+ * @dev: the CPU
+ */
+static void menu_update(struct cpuidle_device *dev)
+{
+ struct menu_device *data = &__get_cpu_var(menu_devices);
int last_idx = data->last_state_idx;
unsigned int last_idle_us = cpuidle_get_last_residency(dev);
struct cpuidle_state *target = &dev->states[last_idx];
unsigned int measured_us;
+ u64 new_factor;
/*
* Ugh, this idle state doesn't support residency measurements, so we
* are basically lost in the dark. As a compromise, assume we slept
- * for one full standard timer tick. However, be aware that this
- * could potentially result in a suboptimal state transition.
+ * for the whole expected time.
*/
if (unlikely(!(target->flags & CPUIDLE_FLAG_TIME_VALID)))
- last_idle_us = USEC_PER_SEC / HZ;
+ last_idle_us = data->expected_us;
+
+
+ measured_us = last_idle_us;
/*
- * measured_us and elapsed_us are the cumulative idle time, since the
- * last time we were woken out of idle by an interrupt.
+ * We correct for the exit latency; we are assuming here that the
+ * exit latency happens after the event that we're interested in.
*/
- if (data->elapsed_us <= data->elapsed_us + last_idle_us)
- measured_us = data->elapsed_us + last_idle_us;
+ if (measured_us > data->exit_us)
+ measured_us -= data->exit_us;
+
+
+ /* update our correction ratio */
+
+ new_factor = data->correction_factor[data->bucket]
+ * (DECAY - 1) / DECAY;
+
+ if (data->expected_us > 0 && data->measured_us < MAX_INTERESTING)
+ new_factor += RESOLUTION * measured_us / data->expected_us;
else
- measured_us = -1;
+ /*
+ * we were idle so long that we count it as a perfect
+ * prediction
+ */
+ new_factor += RESOLUTION;
- /* Predict time until next break event */
- data->current_predicted_us = max(measured_us, data->last_measured_us);
+ /*
+ * We don't want 0 as factor; we always want at least
+ * a tiny bit of estimated time.
+ */
+ if (new_factor == 0)
+ new_factor = 1;
- if (last_idle_us + BREAK_FUZZ <
- data->expected_us - target->exit_latency) {
- data->last_measured_us = measured_us;
- data->elapsed_us = 0;
- } else {
- data->elapsed_us = measured_us;
- }
+ data->correction_factor[data->bucket] = new_factor;
}
/**
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index a9952b1236b0..84c51e177269 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -236,7 +236,7 @@ static inline void ecb_crypt(const u8 *in, u8 *out, u32 *key,
/* Padlock in ECB mode fetches at least ecb_fetch_bytes of data.
* We could avoid some copying here but it's probably not worth it.
*/
- if (unlikely(((unsigned long)in & PAGE_SIZE) + ecb_fetch_bytes > PAGE_SIZE)) {
+ if (unlikely(((unsigned long)in & ~PAGE_MASK) + ecb_fetch_bytes > PAGE_SIZE)) {
ecb_crypt_copy(in, out, key, cword, count);
return;
}
@@ -248,7 +248,7 @@ static inline u8 *cbc_crypt(const u8 *in, u8 *out, u32 *key,
u8 *iv, struct cword *cword, int count)
{
/* Padlock in CBC mode fetches at least cbc_fetch_bytes of data. */
- if (unlikely(((unsigned long)in & PAGE_SIZE) + cbc_fetch_bytes > PAGE_SIZE))
+ if (unlikely(((unsigned long)in & ~PAGE_MASK) + cbc_fetch_bytes > PAGE_SIZE))
return cbc_crypt_copy(in, out, key, iv, cword, count);
return rep_xcrypt_cbc(in, out, key, iv, cword, count);
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
index 76cb6b345e7b..0af80577dc7b 100644
--- a/drivers/crypto/padlock-sha.c
+++ b/drivers/crypto/padlock-sha.c
@@ -24,6 +24,12 @@
#include <asm/i387.h>
#include "padlock.h"
+#ifdef CONFIG_64BIT
+#define STACK_ALIGN 16
+#else
+#define STACK_ALIGN 4
+#endif
+
struct padlock_sha_desc {
struct shash_desc fallback;
};
@@ -64,7 +70,9 @@ static int padlock_sha1_finup(struct shash_desc *desc, const u8 *in,
/* We can't store directly to *out as it may be unaligned. */
/* BTW Don't reduce the buffer size below 128 Bytes!
* PadLock microcode needs it that big. */
- char result[128] __attribute__ ((aligned(PADLOCK_ALIGNMENT)));
+ char buf[128 + PADLOCK_ALIGNMENT - STACK_ALIGN] __attribute__
+ ((aligned(STACK_ALIGN)));
+ char *result = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT);
struct padlock_sha_desc *dctx = shash_desc_ctx(desc);
struct sha1_state state;
unsigned int space;
@@ -128,7 +136,9 @@ static int padlock_sha256_finup(struct shash_desc *desc, const u8 *in,
/* We can't store directly to *out as it may be unaligned. */
/* BTW Don't reduce the buffer size below 128 Bytes!
* PadLock microcode needs it that big. */
- char result[128] __attribute__ ((aligned(PADLOCK_ALIGNMENT)));
+ char buf[128 + PADLOCK_ALIGNMENT - STACK_ALIGN] __attribute__
+ ((aligned(STACK_ALIGN)));
+ char *result = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT);
struct padlock_sha_desc *dctx = shash_desc_ctx(desc);
struct sha256_state state;
unsigned int space;
diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c
index 25b743abfb59..52e6bb70a490 100644
--- a/drivers/dca/dca-core.c
+++ b/drivers/dca/dca-core.c
@@ -28,7 +28,7 @@
#include <linux/device.h>
#include <linux/dca.h>
-#define DCA_VERSION "1.8"
+#define DCA_VERSION "1.12.1"
MODULE_VERSION(DCA_VERSION);
MODULE_LICENSE("GPL");
@@ -36,20 +36,92 @@ MODULE_AUTHOR("Intel Corporation");
static DEFINE_SPINLOCK(dca_lock);
-static LIST_HEAD(dca_providers);
+static LIST_HEAD(dca_domains);
-static struct dca_provider *dca_find_provider_by_dev(struct device *dev)
+static struct pci_bus *dca_pci_rc_from_dev(struct device *dev)
{
- struct dca_provider *dca, *ret = NULL;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct pci_bus *bus = pdev->bus;
- list_for_each_entry(dca, &dca_providers, node) {
- if ((!dev) || (dca->ops->dev_managed(dca, dev))) {
- ret = dca;
- break;
- }
+ while (bus->parent)
+ bus = bus->parent;
+
+ return bus;
+}
+
+static struct dca_domain *dca_allocate_domain(struct pci_bus *rc)
+{
+ struct dca_domain *domain;
+
+ domain = kzalloc(sizeof(*domain), GFP_NOWAIT);
+ if (!domain)
+ return NULL;
+
+ INIT_LIST_HEAD(&domain->dca_providers);
+ domain->pci_rc = rc;
+
+ return domain;
+}
+
+static void dca_free_domain(struct dca_domain *domain)
+{
+ list_del(&domain->node);
+ kfree(domain);
+}
+
+static struct dca_domain *dca_find_domain(struct pci_bus *rc)
+{
+ struct dca_domain *domain;
+
+ list_for_each_entry(domain, &dca_domains, node)
+ if (domain->pci_rc == rc)
+ return domain;
+
+ return NULL;
+}
+
+static struct dca_domain *dca_get_domain(struct device *dev)
+{
+ struct pci_bus *rc;
+ struct dca_domain *domain;
+
+ rc = dca_pci_rc_from_dev(dev);
+ domain = dca_find_domain(rc);
+
+ if (!domain) {
+ domain = dca_allocate_domain(rc);
+ if (domain)
+ list_add(&domain->node, &dca_domains);
+ }
+
+ return domain;
+}
+
+static struct dca_provider *dca_find_provider_by_dev(struct device *dev)
+{
+ struct dca_provider *dca;
+ struct pci_bus *rc;
+ struct dca_domain *domain;
+
+ if (dev) {
+ rc = dca_pci_rc_from_dev(dev);
+ domain = dca_find_domain(rc);
+ if (!domain)
+ return NULL;
+ } else {
+ if (!list_empty(&dca_domains))
+ domain = list_first_entry(&dca_domains,
+ struct dca_domain,
+ node);
+ else
+ return NULL;
}
- return ret;
+ list_for_each_entry(dca, &domain->dca_providers, node)
+ if ((!dev) || (dca->ops->dev_managed(dca, dev)))
+ return dca;
+
+ return NULL;
}
/**
@@ -61,6 +133,8 @@ int dca_add_requester(struct device *dev)
struct dca_provider *dca;
int err, slot = -ENODEV;
unsigned long flags;
+ struct pci_bus *pci_rc;
+ struct dca_domain *domain;
if (!dev)
return -EFAULT;
@@ -74,7 +148,14 @@ int dca_add_requester(struct device *dev)
return -EEXIST;
}
- list_for_each_entry(dca, &dca_providers, node) {
+ pci_rc = dca_pci_rc_from_dev(dev);
+ domain = dca_find_domain(pci_rc);
+ if (!domain) {
+ spin_unlock_irqrestore(&dca_lock, flags);
+ return -ENODEV;
+ }
+
+ list_for_each_entry(dca, &domain->dca_providers, node) {
slot = dca->ops->add_requester(dca, dev);
if (slot >= 0)
break;
@@ -222,13 +303,19 @@ int register_dca_provider(struct dca_provider *dca, struct device *dev)
{
int err;
unsigned long flags;
+ struct dca_domain *domain;
err = dca_sysfs_add_provider(dca, dev);
if (err)
return err;
spin_lock_irqsave(&dca_lock, flags);
- list_add(&dca->node, &dca_providers);
+ domain = dca_get_domain(dev);
+ if (!domain) {
+ spin_unlock_irqrestore(&dca_lock, flags);
+ return -ENODEV;
+ }
+ list_add(&dca->node, &domain->dca_providers);
spin_unlock_irqrestore(&dca_lock, flags);
blocking_notifier_call_chain(&dca_provider_chain,
@@ -241,15 +328,24 @@ EXPORT_SYMBOL_GPL(register_dca_provider);
* unregister_dca_provider - remove a dca provider
* @dca - struct created by alloc_dca_provider()
*/
-void unregister_dca_provider(struct dca_provider *dca)
+void unregister_dca_provider(struct dca_provider *dca, struct device *dev)
{
unsigned long flags;
+ struct pci_bus *pci_rc;
+ struct dca_domain *domain;
blocking_notifier_call_chain(&dca_provider_chain,
DCA_PROVIDER_REMOVE, NULL);
spin_lock_irqsave(&dca_lock, flags);
+
list_del(&dca->node);
+
+ pci_rc = dca_pci_rc_from_dev(dev);
+ domain = dca_find_domain(pci_rc);
+ if (list_empty(&domain->dca_providers))
+ dca_free_domain(domain);
+
spin_unlock_irqrestore(&dca_lock, flags);
dca_sysfs_remove_provider(dca);
@@ -276,7 +372,7 @@ EXPORT_SYMBOL_GPL(dca_unregister_notify);
static int __init dca_init(void)
{
- printk(KERN_ERR "dca service started, version %s\n", DCA_VERSION);
+ pr_info("dca service started, version %s\n", DCA_VERSION);
return dca_sysfs_init();
}
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 81e1020fb514..b401dadad4a8 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -17,11 +17,17 @@ if DMADEVICES
comment "DMA Devices"
+config ASYNC_TX_DISABLE_CHANNEL_SWITCH
+ bool
+
config INTEL_IOATDMA
tristate "Intel I/OAT DMA support"
depends on PCI && X86
select DMA_ENGINE
select DCA
+ select ASYNC_TX_DISABLE_CHANNEL_SWITCH
+ select ASYNC_TX_DISABLE_PQ_VAL_DMA
+ select ASYNC_TX_DISABLE_XOR_VAL_DMA
help
Enable support for the Intel(R) I/OAT DMA engine present
in recent Intel Xeon chipsets.
@@ -97,6 +103,14 @@ config TXX9_DMAC
Support the TXx9 SoC internal DMA controller. This can be
integrated in chips such as the Toshiba TX4927/38/39.
+config SH_DMAE
+ tristate "Renesas SuperH DMAC support"
+ depends on SUPERH && SH_DMA
+ depends on !SH_DMA_API
+ select DMA_ENGINE
+ help
+ Enable support for the Renesas SuperH DMA controllers.
+
config DMA_ENGINE
bool
@@ -116,7 +130,7 @@ config NET_DMA
config ASYNC_TX_DMA
bool "Async_tx: Offload support for the async_tx api"
- depends on DMA_ENGINE && !HIGHMEM64G
+ depends on DMA_ENGINE
help
This allows the async_tx api to take advantage of offload engines for
memcpy, memset, xor, and raid6 p+q operations. If your platform has
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 40e1e0083571..eca71ba78ae9 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -1,8 +1,7 @@
obj-$(CONFIG_DMA_ENGINE) += dmaengine.o
obj-$(CONFIG_NET_DMA) += iovlock.o
obj-$(CONFIG_DMATEST) += dmatest.o
-obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o
-ioatdma-objs := ioat.o ioat_dma.o ioat_dca.o
+obj-$(CONFIG_INTEL_IOATDMA) += ioat/
obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
obj-$(CONFIG_FSL_DMA) += fsldma.o
obj-$(CONFIG_MV_XOR) += mv_xor.o
@@ -10,3 +9,4 @@ obj-$(CONFIG_DW_DMAC) += dw_dmac.o
obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
obj-$(CONFIG_MX3_IPU) += ipu/
obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
+obj-$(CONFIG_SH_DMAE) += shdma.o
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 9a1e5fb412ed..7585c4164bd5 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -87,6 +87,7 @@ static struct at_desc *atc_alloc_descriptor(struct dma_chan *chan,
desc = dma_pool_alloc(atdma->dma_desc_pool, gfp_flags, &phys);
if (desc) {
memset(desc, 0, sizeof(struct at_desc));
+ INIT_LIST_HEAD(&desc->tx_list);
dma_async_tx_descriptor_init(&desc->txd, chan);
/* txd.flags will be overwritten in prep functions */
desc->txd.flags = DMA_CTRL_ACK;
@@ -150,11 +151,11 @@ static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc)
struct at_desc *child;
spin_lock_bh(&atchan->lock);
- list_for_each_entry(child, &desc->txd.tx_list, desc_node)
+ list_for_each_entry(child, &desc->tx_list, desc_node)
dev_vdbg(chan2dev(&atchan->chan_common),
"moving child desc %p to freelist\n",
child);
- list_splice_init(&desc->txd.tx_list, &atchan->free_list);
+ list_splice_init(&desc->tx_list, &atchan->free_list);
dev_vdbg(chan2dev(&atchan->chan_common),
"moving desc %p to freelist\n", desc);
list_add(&desc->desc_node, &atchan->free_list);
@@ -247,30 +248,33 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
param = txd->callback_param;
/* move children to free_list */
- list_splice_init(&txd->tx_list, &atchan->free_list);
+ list_splice_init(&desc->tx_list, &atchan->free_list);
/* move myself to free_list */
list_move(&desc->desc_node, &atchan->free_list);
/* unmap dma addresses */
- if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
- if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE)
- dma_unmap_single(chan2parent(&atchan->chan_common),
- desc->lli.daddr,
- desc->len, DMA_FROM_DEVICE);
- else
- dma_unmap_page(chan2parent(&atchan->chan_common),
- desc->lli.daddr,
- desc->len, DMA_FROM_DEVICE);
- }
- if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
- if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE)
- dma_unmap_single(chan2parent(&atchan->chan_common),
- desc->lli.saddr,
- desc->len, DMA_TO_DEVICE);
- else
- dma_unmap_page(chan2parent(&atchan->chan_common),
- desc->lli.saddr,
- desc->len, DMA_TO_DEVICE);
+ if (!atchan->chan_common.private) {
+ struct device *parent = chan2parent(&atchan->chan_common);
+ if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
+ if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE)
+ dma_unmap_single(parent,
+ desc->lli.daddr,
+ desc->len, DMA_FROM_DEVICE);
+ else
+ dma_unmap_page(parent,
+ desc->lli.daddr,
+ desc->len, DMA_FROM_DEVICE);
+ }
+ if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
+ if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE)
+ dma_unmap_single(parent,
+ desc->lli.saddr,
+ desc->len, DMA_TO_DEVICE);
+ else
+ dma_unmap_page(parent,
+ desc->lli.saddr,
+ desc->len, DMA_TO_DEVICE);
+ }
}
/*
@@ -334,7 +338,7 @@ static void atc_cleanup_descriptors(struct at_dma_chan *atchan)
/* This one is currently in progress */
return;
- list_for_each_entry(child, &desc->txd.tx_list, desc_node)
+ list_for_each_entry(child, &desc->tx_list, desc_node)
if (!(child->lli.ctrla & ATC_DONE))
/* Currently in progress */
return;
@@ -407,7 +411,7 @@ static void atc_handle_error(struct at_dma_chan *atchan)
dev_crit(chan2dev(&atchan->chan_common),
" cookie: %d\n", bad_desc->txd.cookie);
atc_dump_lli(atchan, &bad_desc->lli);
- list_for_each_entry(child, &bad_desc->txd.tx_list, desc_node)
+ list_for_each_entry(child, &bad_desc->tx_list, desc_node)
atc_dump_lli(atchan, &child->lli);
/* Pretend the descriptor completed successfully */
@@ -587,7 +591,7 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
prev->lli.dscr = desc->txd.phys;
/* insert the link descriptor to the LD ring */
list_add_tail(&desc->desc_node,
- &first->txd.tx_list);
+ &first->tx_list);
}
prev = desc;
}
@@ -646,8 +650,6 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
reg_width = atslave->reg_width;
- sg_len = dma_map_sg(chan2parent(chan), sgl, sg_len, direction);
-
ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla;
ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN;
@@ -687,7 +689,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
prev->lli.dscr = desc->txd.phys;
/* insert the link descriptor to the LD ring */
list_add_tail(&desc->desc_node,
- &first->txd.tx_list);
+ &first->tx_list);
}
prev = desc;
total_len += len;
@@ -729,7 +731,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
prev->lli.dscr = desc->txd.phys;
/* insert the link descriptor to the LD ring */
list_add_tail(&desc->desc_node,
- &first->txd.tx_list);
+ &first->tx_list);
}
prev = desc;
total_len += len;
@@ -1166,32 +1168,37 @@ static void at_dma_shutdown(struct platform_device *pdev)
clk_disable(atdma->clk);
}
-static int at_dma_suspend_late(struct platform_device *pdev, pm_message_t mesg)
+static int at_dma_suspend_noirq(struct device *dev)
{
- struct at_dma *atdma = platform_get_drvdata(pdev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct at_dma *atdma = platform_get_drvdata(pdev);
at_dma_off(platform_get_drvdata(pdev));
clk_disable(atdma->clk);
return 0;
}
-static int at_dma_resume_early(struct platform_device *pdev)
+static int at_dma_resume_noirq(struct device *dev)
{
- struct at_dma *atdma = platform_get_drvdata(pdev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct at_dma *atdma = platform_get_drvdata(pdev);
clk_enable(atdma->clk);
dma_writel(atdma, EN, AT_DMA_ENABLE);
return 0;
-
}
+static struct dev_pm_ops at_dma_dev_pm_ops = {
+ .suspend_noirq = at_dma_suspend_noirq,
+ .resume_noirq = at_dma_resume_noirq,
+};
+
static struct platform_driver at_dma_driver = {
.remove = __exit_p(at_dma_remove),
.shutdown = at_dma_shutdown,
- .suspend_late = at_dma_suspend_late,
- .resume_early = at_dma_resume_early,
.driver = {
.name = "at_hdmac",
+ .pm = &at_dma_dev_pm_ops,
},
};
diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
index 4c972afc49ec..495457e3dc4b 100644
--- a/drivers/dma/at_hdmac_regs.h
+++ b/drivers/dma/at_hdmac_regs.h
@@ -165,6 +165,7 @@ struct at_desc {
struct at_lli lli;
/* THEN values for driver housekeeping */
+ struct list_head tx_list;
struct dma_async_tx_descriptor txd;
struct list_head desc_node;
size_t len;
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 5a87384ea4ff..8f99354082ce 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -608,6 +608,50 @@ void dmaengine_put(void)
}
EXPORT_SYMBOL(dmaengine_put);
+static bool device_has_all_tx_types(struct dma_device *device)
+{
+ /* A device that satisfies this test has channels that will never cause
+ * an async_tx channel switch event as all possible operation types can
+ * be handled.
+ */
+ #ifdef CONFIG_ASYNC_TX_DMA
+ if (!dma_has_cap(DMA_INTERRUPT, device->cap_mask))
+ return false;
+ #endif
+
+ #if defined(CONFIG_ASYNC_MEMCPY) || defined(CONFIG_ASYNC_MEMCPY_MODULE)
+ if (!dma_has_cap(DMA_MEMCPY, device->cap_mask))
+ return false;
+ #endif
+
+ #if defined(CONFIG_ASYNC_MEMSET) || defined(CONFIG_ASYNC_MEMSET_MODULE)
+ if (!dma_has_cap(DMA_MEMSET, device->cap_mask))
+ return false;
+ #endif
+
+ #if defined(CONFIG_ASYNC_XOR) || defined(CONFIG_ASYNC_XOR_MODULE)
+ if (!dma_has_cap(DMA_XOR, device->cap_mask))
+ return false;
+
+ #ifndef CONFIG_ASYNC_TX_DISABLE_XOR_VAL_DMA
+ if (!dma_has_cap(DMA_XOR_VAL, device->cap_mask))
+ return false;
+ #endif
+ #endif
+
+ #if defined(CONFIG_ASYNC_PQ) || defined(CONFIG_ASYNC_PQ_MODULE)
+ if (!dma_has_cap(DMA_PQ, device->cap_mask))
+ return false;
+
+ #ifndef CONFIG_ASYNC_TX_DISABLE_PQ_VAL_DMA
+ if (!dma_has_cap(DMA_PQ_VAL, device->cap_mask))
+ return false;
+ #endif
+ #endif
+
+ return true;
+}
+
static int get_dma_id(struct dma_device *device)
{
int rc;
@@ -644,8 +688,12 @@ int dma_async_device_register(struct dma_device *device)
!device->device_prep_dma_memcpy);
BUG_ON(dma_has_cap(DMA_XOR, device->cap_mask) &&
!device->device_prep_dma_xor);
- BUG_ON(dma_has_cap(DMA_ZERO_SUM, device->cap_mask) &&
- !device->device_prep_dma_zero_sum);
+ BUG_ON(dma_has_cap(DMA_XOR_VAL, device->cap_mask) &&
+ !device->device_prep_dma_xor_val);
+ BUG_ON(dma_has_cap(DMA_PQ, device->cap_mask) &&
+ !device->device_prep_dma_pq);
+ BUG_ON(dma_has_cap(DMA_PQ_VAL, device->cap_mask) &&
+ !device->device_prep_dma_pq_val);
BUG_ON(dma_has_cap(DMA_MEMSET, device->cap_mask) &&
!device->device_prep_dma_memset);
BUG_ON(dma_has_cap(DMA_INTERRUPT, device->cap_mask) &&
@@ -661,6 +709,12 @@ int dma_async_device_register(struct dma_device *device)
BUG_ON(!device->device_issue_pending);
BUG_ON(!device->dev);
+ /* note: this only matters in the
+ * CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH=y case
+ */
+ if (device_has_all_tx_types(device))
+ dma_cap_set(DMA_ASYNC_TX, device->cap_mask);
+
idr_ref = kmalloc(sizeof(*idr_ref), GFP_KERNEL);
if (!idr_ref)
return -ENOMEM;
@@ -933,55 +987,29 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx,
{
tx->chan = chan;
spin_lock_init(&tx->lock);
- INIT_LIST_HEAD(&tx->tx_list);
}
EXPORT_SYMBOL(dma_async_tx_descriptor_init);
/* dma_wait_for_async_tx - spin wait for a transaction to complete
* @tx: in-flight transaction to wait on
- *
- * This routine assumes that tx was obtained from a call to async_memcpy,
- * async_xor, async_memset, etc which ensures that tx is "in-flight" (prepped
- * and submitted). Walking the parent chain is only meant to cover for DMA
- * drivers that do not implement the DMA_INTERRUPT capability and may race with
- * the driver's descriptor cleanup routine.
*/
enum dma_status
dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx)
{
- enum dma_status status;
- struct dma_async_tx_descriptor *iter;
- struct dma_async_tx_descriptor *parent;
+ unsigned long dma_sync_wait_timeout = jiffies + msecs_to_jiffies(5000);
if (!tx)
return DMA_SUCCESS;
- WARN_ONCE(tx->parent, "%s: speculatively walking dependency chain for"
- " %s\n", __func__, dma_chan_name(tx->chan));
-
- /* poll through the dependency chain, return when tx is complete */
- do {
- iter = tx;
-
- /* find the root of the unsubmitted dependency chain */
- do {
- parent = iter->parent;
- if (!parent)
- break;
- else
- iter = parent;
- } while (parent);
-
- /* there is a small window for ->parent == NULL and
- * ->cookie == -EBUSY
- */
- while (iter->cookie == -EBUSY)
- cpu_relax();
-
- status = dma_sync_wait(iter->chan, iter->cookie);
- } while (status == DMA_IN_PROGRESS || (iter != tx));
-
- return status;
+ while (tx->cookie == -EBUSY) {
+ if (time_after_eq(jiffies, dma_sync_wait_timeout)) {
+ pr_err("%s timeout waiting for descriptor submission\n",
+ __func__);
+ return DMA_ERROR;
+ }
+ cpu_relax();
+ }
+ return dma_sync_wait(tx->chan, tx->cookie);
}
EXPORT_SYMBOL_GPL(dma_wait_for_async_tx);
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index d93017fc7872..a32a4cf7b1e0 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -48,6 +48,11 @@ module_param(xor_sources, uint, S_IRUGO);
MODULE_PARM_DESC(xor_sources,
"Number of xor source buffers (default: 3)");
+static unsigned int pq_sources = 3;
+module_param(pq_sources, uint, S_IRUGO);
+MODULE_PARM_DESC(pq_sources,
+ "Number of p+q source buffers (default: 3)");
+
/*
* Initialization patterns. All bytes in the source buffer has bit 7
* set, all bytes in the destination buffer has bit 7 cleared.
@@ -232,6 +237,7 @@ static int dmatest_func(void *data)
dma_cookie_t cookie;
enum dma_status status;
enum dma_ctrl_flags flags;
+ u8 pq_coefs[pq_sources];
int ret;
int src_cnt;
int dst_cnt;
@@ -248,6 +254,11 @@ static int dmatest_func(void *data)
else if (thread->type == DMA_XOR) {
src_cnt = xor_sources | 1; /* force odd to ensure dst = src */
dst_cnt = 1;
+ } else if (thread->type == DMA_PQ) {
+ src_cnt = pq_sources | 1; /* force odd to ensure dst = src */
+ dst_cnt = 2;
+ for (i = 0; i < pq_sources; i++)
+ pq_coefs[i] = 1;
} else
goto err_srcs;
@@ -283,6 +294,7 @@ static int dmatest_func(void *data)
dma_addr_t dma_dsts[dst_cnt];
struct completion cmp;
unsigned long tmo = msecs_to_jiffies(3000);
+ u8 align = 0;
total_tests++;
@@ -290,6 +302,18 @@ static int dmatest_func(void *data)
src_off = dmatest_random() % (test_buf_size - len + 1);
dst_off = dmatest_random() % (test_buf_size - len + 1);
+ /* honor alignment restrictions */
+ if (thread->type == DMA_MEMCPY)
+ align = dev->copy_align;
+ else if (thread->type == DMA_XOR)
+ align = dev->xor_align;
+ else if (thread->type == DMA_PQ)
+ align = dev->pq_align;
+
+ len = (len >> align) << align;
+ src_off = (src_off >> align) << align;
+ dst_off = (dst_off >> align) << align;
+
dmatest_init_srcs(thread->srcs, src_off, len);
dmatest_init_dsts(thread->dsts, dst_off, len);
@@ -306,6 +330,7 @@ static int dmatest_func(void *data)
DMA_BIDIRECTIONAL);
}
+
if (thread->type == DMA_MEMCPY)
tx = dev->device_prep_dma_memcpy(chan,
dma_dsts[0] + dst_off,
@@ -316,6 +341,15 @@ static int dmatest_func(void *data)
dma_dsts[0] + dst_off,
dma_srcs, xor_sources,
len, flags);
+ else if (thread->type == DMA_PQ) {
+ dma_addr_t dma_pq[dst_cnt];
+
+ for (i = 0; i < dst_cnt; i++)
+ dma_pq[i] = dma_dsts[i] + dst_off;
+ tx = dev->device_prep_dma_pq(chan, dma_pq, dma_srcs,
+ pq_sources, pq_coefs,
+ len, flags);
+ }
if (!tx) {
for (i = 0; i < src_cnt; i++)
@@ -459,6 +493,8 @@ static int dmatest_add_threads(struct dmatest_chan *dtc, enum dma_transaction_ty
op = "copy";
else if (type == DMA_XOR)
op = "xor";
+ else if (type == DMA_PQ)
+ op = "pq";
else
return -EINVAL;
@@ -514,6 +550,10 @@ static int dmatest_add_channel(struct dma_chan *chan)
cnt = dmatest_add_threads(dtc, DMA_XOR);
thread_count += cnt > 0 ? cnt : 0;
}
+ if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) {
+ cnt = dmatest_add_threads(dtc, DMA_PQ);
+ thread_count += cnt > 0 ?: 0;
+ }
pr_info("dmatest: Started %u threads using %s\n",
thread_count, dma_chan_name(chan));
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 98c9a847bf51..2eea823516a7 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -116,7 +116,7 @@ static void dwc_sync_desc_for_cpu(struct dw_dma_chan *dwc, struct dw_desc *desc)
{
struct dw_desc *child;
- list_for_each_entry(child, &desc->txd.tx_list, desc_node)
+ list_for_each_entry(child, &desc->tx_list, desc_node)
dma_sync_single_for_cpu(chan2parent(&dwc->chan),
child->txd.phys, sizeof(child->lli),
DMA_TO_DEVICE);
@@ -137,11 +137,11 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
dwc_sync_desc_for_cpu(dwc, desc);
spin_lock_bh(&dwc->lock);
- list_for_each_entry(child, &desc->txd.tx_list, desc_node)
+ list_for_each_entry(child, &desc->tx_list, desc_node)
dev_vdbg(chan2dev(&dwc->chan),
"moving child desc %p to freelist\n",
child);
- list_splice_init(&desc->txd.tx_list, &dwc->free_list);
+ list_splice_init(&desc->tx_list, &dwc->free_list);
dev_vdbg(chan2dev(&dwc->chan), "moving desc %p to freelist\n", desc);
list_add(&desc->desc_node, &dwc->free_list);
spin_unlock_bh(&dwc->lock);
@@ -209,19 +209,28 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc)
param = txd->callback_param;
dwc_sync_desc_for_cpu(dwc, desc);
- list_splice_init(&txd->tx_list, &dwc->free_list);
+ list_splice_init(&desc->tx_list, &dwc->free_list);
list_move(&desc->desc_node, &dwc->free_list);
- /*
- * We use dma_unmap_page() regardless of how the buffers were
- * mapped before they were submitted...
- */
- if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP))
- dma_unmap_page(chan2parent(&dwc->chan), desc->lli.dar,
- desc->len, DMA_FROM_DEVICE);
- if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP))
- dma_unmap_page(chan2parent(&dwc->chan), desc->lli.sar,
- desc->len, DMA_TO_DEVICE);
+ if (!dwc->chan.private) {
+ struct device *parent = chan2parent(&dwc->chan);
+ if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
+ if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE)
+ dma_unmap_single(parent, desc->lli.dar,
+ desc->len, DMA_FROM_DEVICE);
+ else
+ dma_unmap_page(parent, desc->lli.dar,
+ desc->len, DMA_FROM_DEVICE);
+ }
+ if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
+ if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE)
+ dma_unmap_single(parent, desc->lli.sar,
+ desc->len, DMA_TO_DEVICE);
+ else
+ dma_unmap_page(parent, desc->lli.sar,
+ desc->len, DMA_TO_DEVICE);
+ }
+ }
/*
* The API requires that no submissions are done from a
@@ -289,7 +298,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
/* This one is currently in progress */
return;
- list_for_each_entry(child, &desc->txd.tx_list, desc_node)
+ list_for_each_entry(child, &desc->tx_list, desc_node)
if (child->lli.llp == llp)
/* Currently in progress */
return;
@@ -356,7 +365,7 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
dev_printk(KERN_CRIT, chan2dev(&dwc->chan),
" cookie: %d\n", bad_desc->txd.cookie);
dwc_dump_lli(dwc, &bad_desc->lli);
- list_for_each_entry(child, &bad_desc->txd.tx_list, desc_node)
+ list_for_each_entry(child, &bad_desc->tx_list, desc_node)
dwc_dump_lli(dwc, &child->lli);
/* Pretend the descriptor completed successfully */
@@ -608,7 +617,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
prev->txd.phys, sizeof(prev->lli),
DMA_TO_DEVICE);
list_add_tail(&desc->desc_node,
- &first->txd.tx_list);
+ &first->tx_list);
}
prev = desc;
}
@@ -658,8 +667,6 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
reg_width = dws->reg_width;
prev = first = NULL;
- sg_len = dma_map_sg(chan2parent(chan), sgl, sg_len, direction);
-
switch (direction) {
case DMA_TO_DEVICE:
ctllo = (DWC_DEFAULT_CTLLO
@@ -700,7 +707,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
sizeof(prev->lli),
DMA_TO_DEVICE);
list_add_tail(&desc->desc_node,
- &first->txd.tx_list);
+ &first->tx_list);
}
prev = desc;
total_len += len;
@@ -746,7 +753,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
sizeof(prev->lli),
DMA_TO_DEVICE);
list_add_tail(&desc->desc_node,
- &first->txd.tx_list);
+ &first->tx_list);
}
prev = desc;
total_len += len;
@@ -902,6 +909,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
break;
}
+ INIT_LIST_HEAD(&desc->tx_list);
dma_async_tx_descriptor_init(&desc->txd, chan);
desc->txd.tx_submit = dwc_tx_submit;
desc->txd.flags = DMA_CTRL_ACK;
@@ -1399,8 +1407,9 @@ static void dw_shutdown(struct platform_device *pdev)
clk_disable(dw->clk);
}
-static int dw_suspend_late(struct platform_device *pdev, pm_message_t mesg)
+static int dw_suspend_noirq(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct dw_dma *dw = platform_get_drvdata(pdev);
dw_dma_off(platform_get_drvdata(pdev));
@@ -1408,23 +1417,27 @@ static int dw_suspend_late(struct platform_device *pdev, pm_message_t mesg)
return 0;
}
-static int dw_resume_early(struct platform_device *pdev)
+static int dw_resume_noirq(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct dw_dma *dw = platform_get_drvdata(pdev);
clk_enable(dw->clk);
dma_writel(dw, CFG, DW_CFG_DMA_EN);
return 0;
-
}
+static struct dev_pm_ops dw_dev_pm_ops = {
+ .suspend_noirq = dw_suspend_noirq,
+ .resume_noirq = dw_resume_noirq,
+};
+
static struct platform_driver dw_driver = {
.remove = __exit_p(dw_remove),
.shutdown = dw_shutdown,
- .suspend_late = dw_suspend_late,
- .resume_early = dw_resume_early,
.driver = {
.name = "dw_dmac",
+ .pm = &dw_dev_pm_ops,
},
};
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 13a580767031..d9a939f67f46 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -217,6 +217,7 @@ struct dw_desc {
/* THEN values for driver housekeeping */
struct list_head desc_node;
+ struct list_head tx_list;
struct dma_async_tx_descriptor txd;
size_t len;
};
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index ef87a8984145..296f9e747fac 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -34,6 +34,7 @@
#include <linux/dmapool.h>
#include <linux/of_platform.h>
+#include <asm/fsldma.h>
#include "fsldma.h"
static void dma_init(struct fsl_dma_chan *fsl_chan)
@@ -280,28 +281,40 @@ static void fsl_chan_set_dest_loop_size(struct fsl_dma_chan *fsl_chan, int size)
}
/**
- * fsl_chan_toggle_ext_pause - Toggle channel external pause status
+ * fsl_chan_set_request_count - Set DMA Request Count for external control
* @fsl_chan : Freescale DMA channel
- * @size : Pause control size, 0 for disable external pause control.
- * The maximum is 1024.
+ * @size : Number of bytes to transfer in a single request
+ *
+ * The Freescale DMA channel can be controlled by the external signal DREQ#.
+ * The DMA request count is how many bytes are allowed to transfer before
+ * pausing the channel, after which a new assertion of DREQ# resumes channel
+ * operation.
*
- * The Freescale DMA channel can be controlled by the external
- * signal DREQ#. The pause control size is how many bytes are allowed
- * to transfer before pausing the channel, after which a new assertion
- * of DREQ# resumes channel operation.
+ * A size of 0 disables external pause control. The maximum size is 1024.
*/
-static void fsl_chan_toggle_ext_pause(struct fsl_dma_chan *fsl_chan, int size)
+static void fsl_chan_set_request_count(struct fsl_dma_chan *fsl_chan, int size)
{
- if (size > 1024)
- return;
+ BUG_ON(size > 1024);
+ DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
+ DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32)
+ | ((__ilog2(size) << 24) & 0x0f000000),
+ 32);
+}
- if (size) {
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32)
- | ((__ilog2(size) << 24) & 0x0f000000),
- 32);
+/**
+ * fsl_chan_toggle_ext_pause - Toggle channel external pause status
+ * @fsl_chan : Freescale DMA channel
+ * @enable : 0 is disabled, 1 is enabled.
+ *
+ * The Freescale DMA channel can be controlled by the external signal DREQ#.
+ * The DMA Request Count feature should be used in addition to this feature
+ * to set the number of bytes to transfer before pausing the channel.
+ */
+static void fsl_chan_toggle_ext_pause(struct fsl_dma_chan *fsl_chan, int enable)
+{
+ if (enable)
fsl_chan->feature |= FSL_DMA_CHAN_PAUSE_EXT;
- } else
+ else
fsl_chan->feature &= ~FSL_DMA_CHAN_PAUSE_EXT;
}
@@ -326,7 +339,8 @@ static void fsl_chan_toggle_ext_start(struct fsl_dma_chan *fsl_chan, int enable)
static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
{
struct fsl_dma_chan *fsl_chan = to_fsl_chan(tx->chan);
- struct fsl_desc_sw *desc;
+ struct fsl_desc_sw *desc = tx_to_fsl_desc(tx);
+ struct fsl_desc_sw *child;
unsigned long flags;
dma_cookie_t cookie;
@@ -334,7 +348,7 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
spin_lock_irqsave(&fsl_chan->desc_lock, flags);
cookie = fsl_chan->common.cookie;
- list_for_each_entry(desc, &tx->tx_list, node) {
+ list_for_each_entry(child, &desc->tx_list, node) {
cookie++;
if (cookie < 0)
cookie = 1;
@@ -343,8 +357,8 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
}
fsl_chan->common.cookie = cookie;
- append_ld_queue(fsl_chan, tx_to_fsl_desc(tx));
- list_splice_init(&tx->tx_list, fsl_chan->ld_queue.prev);
+ append_ld_queue(fsl_chan, desc);
+ list_splice_init(&desc->tx_list, fsl_chan->ld_queue.prev);
spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
@@ -366,6 +380,7 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
desc_sw = dma_pool_alloc(fsl_chan->desc_pool, GFP_ATOMIC, &pdesc);
if (desc_sw) {
memset(desc_sw, 0, sizeof(struct fsl_desc_sw));
+ INIT_LIST_HEAD(&desc_sw->tx_list);
dma_async_tx_descriptor_init(&desc_sw->async_tx,
&fsl_chan->common);
desc_sw->async_tx.tx_submit = fsl_dma_tx_submit;
@@ -455,7 +470,7 @@ fsl_dma_prep_interrupt(struct dma_chan *chan, unsigned long flags)
new->async_tx.flags = flags;
/* Insert the link descriptor to the LD ring */
- list_add_tail(&new->node, &new->async_tx.tx_list);
+ list_add_tail(&new->node, &new->tx_list);
/* Set End-of-link to the last link descriptor of new list*/
set_ld_eol(fsl_chan, new);
@@ -513,7 +528,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
dma_dest += copy;
/* Insert the link descriptor to the LD ring */
- list_add_tail(&new->node, &first->async_tx.tx_list);
+ list_add_tail(&new->node, &first->tx_list);
} while (len);
new->async_tx.flags = flags; /* client is in control of this ack */
@@ -528,7 +543,7 @@ fail:
if (!first)
return NULL;
- list = &first->async_tx.tx_list;
+ list = &first->tx_list;
list_for_each_entry_safe_reverse(new, prev, list, node) {
list_del(&new->node);
dma_pool_free(fsl_chan->desc_pool, new, new->async_tx.phys);
@@ -538,6 +553,229 @@ fail:
}
/**
+ * fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
+ * @chan: DMA channel
+ * @sgl: scatterlist to transfer to/from
+ * @sg_len: number of entries in @scatterlist
+ * @direction: DMA direction
+ * @flags: DMAEngine flags
+ *
+ * Prepare a set of descriptors for a DMA_SLAVE transaction. Following the
+ * DMA_SLAVE API, this gets the device-specific information from the
+ * chan->private variable.
+ */
+static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len,
+ enum dma_data_direction direction, unsigned long flags)
+{
+ struct fsl_dma_chan *fsl_chan;
+ struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL;
+ struct fsl_dma_slave *slave;
+ struct list_head *tx_list;
+ size_t copy;
+
+ int i;
+ struct scatterlist *sg;
+ size_t sg_used;
+ size_t hw_used;
+ struct fsl_dma_hw_addr *hw;
+ dma_addr_t dma_dst, dma_src;
+
+ if (!chan)
+ return NULL;
+
+ if (!chan->private)
+ return NULL;
+
+ fsl_chan = to_fsl_chan(chan);
+ slave = chan->private;
+
+ if (list_empty(&slave->addresses))
+ return NULL;
+
+ hw = list_first_entry(&slave->addresses, struct fsl_dma_hw_addr, entry);
+ hw_used = 0;
+
+ /*
+ * Build the hardware transaction to copy from the scatterlist to
+ * the hardware, or from the hardware to the scatterlist
+ *
+ * If you are copying from the hardware to the scatterlist and it
+ * takes two hardware entries to fill an entire page, then both
+ * hardware entries will be coalesced into the same page
+ *
+ * If you are copying from the scatterlist to the hardware and a
+ * single page can fill two hardware entries, then the data will
+ * be read out of the page into the first hardware entry, and so on
+ */
+ for_each_sg(sgl, sg, sg_len, i) {
+ sg_used = 0;
+
+ /* Loop until the entire scatterlist entry is used */
+ while (sg_used < sg_dma_len(sg)) {
+
+ /*
+ * If we've used up the current hardware address/length
+ * pair, we need to load a new one
+ *
+ * This is done in a while loop so that descriptors with
+ * length == 0 will be skipped
+ */
+ while (hw_used >= hw->length) {
+
+ /*
+ * If the current hardware entry is the last
+ * entry in the list, we're finished
+ */
+ if (list_is_last(&hw->entry, &slave->addresses))
+ goto finished;
+
+ /* Get the next hardware address/length pair */
+ hw = list_entry(hw->entry.next,
+ struct fsl_dma_hw_addr, entry);
+ hw_used = 0;
+ }
+
+ /* Allocate the link descriptor from DMA pool */
+ new = fsl_dma_alloc_descriptor(fsl_chan);
+ if (!new) {
+ dev_err(fsl_chan->dev, "No free memory for "
+ "link descriptor\n");
+ goto fail;
+ }
+#ifdef FSL_DMA_LD_DEBUG
+ dev_dbg(fsl_chan->dev, "new link desc alloc %p\n", new);
+#endif
+
+ /*
+ * Calculate the maximum number of bytes to transfer,
+ * making sure it is less than the DMA controller limit
+ */
+ copy = min_t(size_t, sg_dma_len(sg) - sg_used,
+ hw->length - hw_used);
+ copy = min_t(size_t, copy, FSL_DMA_BCR_MAX_CNT);
+
+ /*
+ * DMA_FROM_DEVICE
+ * from the hardware to the scatterlist
+ *
+ * DMA_TO_DEVICE
+ * from the scatterlist to the hardware
+ */
+ if (direction == DMA_FROM_DEVICE) {
+ dma_src = hw->address + hw_used;
+ dma_dst = sg_dma_address(sg) + sg_used;
+ } else {
+ dma_src = sg_dma_address(sg) + sg_used;
+ dma_dst = hw->address + hw_used;
+ }
+
+ /* Fill in the descriptor */
+ set_desc_cnt(fsl_chan, &new->hw, copy);
+ set_desc_src(fsl_chan, &new->hw, dma_src);
+ set_desc_dest(fsl_chan, &new->hw, dma_dst);
+
+ /*
+ * If this is not the first descriptor, chain the
+ * current descriptor after the previous descriptor
+ */
+ if (!first) {
+ first = new;
+ } else {
+ set_desc_next(fsl_chan, &prev->hw,
+ new->async_tx.phys);
+ }
+
+ new->async_tx.cookie = 0;
+ async_tx_ack(&new->async_tx);
+
+ prev = new;
+ sg_used += copy;
+ hw_used += copy;
+
+ /* Insert the link descriptor into the LD ring */
+ list_add_tail(&new->node, &first->tx_list);
+ }
+ }
+
+finished:
+
+ /* All of the hardware address/length pairs had length == 0 */
+ if (!first || !new)
+ return NULL;
+
+ new->async_tx.flags = flags;
+ new->async_tx.cookie = -EBUSY;
+
+ /* Set End-of-link to the last link descriptor of new list */
+ set_ld_eol(fsl_chan, new);
+
+ /* Enable extra controller features */
+ if (fsl_chan->set_src_loop_size)
+ fsl_chan->set_src_loop_size(fsl_chan, slave->src_loop_size);
+
+ if (fsl_chan->set_dest_loop_size)
+ fsl_chan->set_dest_loop_size(fsl_chan, slave->dst_loop_size);
+
+ if (fsl_chan->toggle_ext_start)
+ fsl_chan->toggle_ext_start(fsl_chan, slave->external_start);
+
+ if (fsl_chan->toggle_ext_pause)
+ fsl_chan->toggle_ext_pause(fsl_chan, slave->external_pause);
+
+ if (fsl_chan->set_request_count)
+ fsl_chan->set_request_count(fsl_chan, slave->request_count);
+
+ return &first->async_tx;
+
+fail:
+ /* If first was not set, then we failed to allocate the very first
+ * descriptor, and we're done */
+ if (!first)
+ return NULL;
+
+ /*
+ * First is set, so all of the descriptors we allocated have been added
+ * to first->tx_list, INCLUDING "first" itself. Therefore we
+ * must traverse the list backwards freeing each descriptor in turn
+ *
+ * We're re-using variables for the loop, oh well
+ */
+ tx_list = &first->tx_list;
+ list_for_each_entry_safe_reverse(new, prev, tx_list, node) {
+ list_del_init(&new->node);
+ dma_pool_free(fsl_chan->desc_pool, new, new->async_tx.phys);
+ }
+
+ return NULL;
+}
+
+static void fsl_dma_device_terminate_all(struct dma_chan *chan)
+{
+ struct fsl_dma_chan *fsl_chan;
+ struct fsl_desc_sw *desc, *tmp;
+ unsigned long flags;
+
+ if (!chan)
+ return;
+
+ fsl_chan = to_fsl_chan(chan);
+
+ /* Halt the DMA engine */
+ dma_halt(fsl_chan);
+
+ spin_lock_irqsave(&fsl_chan->desc_lock, flags);
+
+ /* Remove and free all of the descriptors in the LD queue */
+ list_for_each_entry_safe(desc, tmp, &fsl_chan->ld_queue, node) {
+ list_del(&desc->node);
+ dma_pool_free(fsl_chan->desc_pool, desc, desc->async_tx.phys);
+ }
+
+ spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
+}
+
+/**
* fsl_dma_update_completed_cookie - Update the completed cookie.
* @fsl_chan : Freescale DMA channel
*/
@@ -883,6 +1121,7 @@ static int __devinit fsl_dma_chan_probe(struct fsl_dma_device *fdev,
new_fsl_chan->toggle_ext_start = fsl_chan_toggle_ext_start;
new_fsl_chan->set_src_loop_size = fsl_chan_set_src_loop_size;
new_fsl_chan->set_dest_loop_size = fsl_chan_set_dest_loop_size;
+ new_fsl_chan->set_request_count = fsl_chan_set_request_count;
}
spin_lock_init(&new_fsl_chan->desc_lock);
@@ -962,12 +1201,15 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev,
dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask);
+ dma_cap_set(DMA_SLAVE, fdev->common.cap_mask);
fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources;
fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources;
fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt;
fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy;
fdev->common.device_is_tx_complete = fsl_dma_is_complete;
fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending;
+ fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg;
+ fdev->common.device_terminate_all = fsl_dma_device_terminate_all;
fdev->common.dev = &dev->dev;
fdev->irq = irq_of_parse_and_map(dev->node, 0);
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index dc7f26865797..0df14cbb8ca3 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -90,6 +90,7 @@ struct fsl_dma_ld_hw {
struct fsl_desc_sw {
struct fsl_dma_ld_hw hw;
struct list_head node;
+ struct list_head tx_list;
struct dma_async_tx_descriptor async_tx;
struct list_head *ld;
void *priv;
@@ -143,10 +144,11 @@ struct fsl_dma_chan {
struct tasklet_struct tasklet;
u32 feature;
- void (*toggle_ext_pause)(struct fsl_dma_chan *fsl_chan, int size);
+ void (*toggle_ext_pause)(struct fsl_dma_chan *fsl_chan, int enable);
void (*toggle_ext_start)(struct fsl_dma_chan *fsl_chan, int enable);
void (*set_src_loop_size)(struct fsl_dma_chan *fsl_chan, int size);
void (*set_dest_loop_size)(struct fsl_dma_chan *fsl_chan, int size);
+ void (*set_request_count)(struct fsl_dma_chan *fsl_chan, int size);
};
#define to_fsl_chan(chan) container_of(chan, struct fsl_dma_chan, common)
diff --git a/drivers/dma/ioat.c b/drivers/dma/ioat.c
deleted file mode 100644
index 2225bb6ba3d1..000000000000
--- a/drivers/dma/ioat.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Intel I/OAT DMA Linux driver
- * Copyright(c) 2007 - 2009 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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 "COPYING".
- *
- */
-
-/*
- * This driver supports an Intel I/OAT DMA engine, which does asynchronous
- * copy operations.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/dca.h>
-#include "ioatdma.h"
-#include "ioatdma_registers.h"
-#include "ioatdma_hw.h"
-
-MODULE_VERSION(IOAT_DMA_VERSION);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Intel Corporation");
-
-static struct pci_device_id ioat_pci_tbl[] = {
- /* I/OAT v1 platforms */
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_CNB) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SCNB) },
- { PCI_DEVICE(PCI_VENDOR_ID_UNISYS, PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR) },
-
- /* I/OAT v2 platforms */
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB) },
-
- /* I/OAT v3 platforms */
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG0) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG1) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG2) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG3) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG4) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG5) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG6) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG7) },
- { 0, }
-};
-
-struct ioat_device {
- struct pci_dev *pdev;
- void __iomem *iobase;
- struct ioatdma_device *dma;
- struct dca_provider *dca;
-};
-
-static int __devinit ioat_probe(struct pci_dev *pdev,
- const struct pci_device_id *id);
-static void __devexit ioat_remove(struct pci_dev *pdev);
-
-static int ioat_dca_enabled = 1;
-module_param(ioat_dca_enabled, int, 0644);
-MODULE_PARM_DESC(ioat_dca_enabled, "control support of dca service (default: 1)");
-
-static struct pci_driver ioat_pci_driver = {
- .name = "ioatdma",
- .id_table = ioat_pci_tbl,
- .probe = ioat_probe,
- .remove = __devexit_p(ioat_remove),
-};
-
-static int __devinit ioat_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- void __iomem *iobase;
- struct ioat_device *device;
- unsigned long mmio_start, mmio_len;
- int err;
-
- err = pci_enable_device(pdev);
- if (err)
- goto err_enable_device;
-
- err = pci_request_regions(pdev, ioat_pci_driver.name);
- if (err)
- goto err_request_regions;
-
- err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
- if (err)
- err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (err)
- goto err_set_dma_mask;
-
- 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)
- goto err_set_dma_mask;
-
- mmio_start = pci_resource_start(pdev, 0);
- mmio_len = pci_resource_len(pdev, 0);
- iobase = ioremap(mmio_start, mmio_len);
- if (!iobase) {
- err = -ENOMEM;
- goto err_ioremap;
- }
-
- device = kzalloc(sizeof(*device), GFP_KERNEL);
- if (!device) {
- err = -ENOMEM;
- goto err_kzalloc;
- }
- device->pdev = pdev;
- pci_set_drvdata(pdev, device);
- device->iobase = iobase;
-
- pci_set_master(pdev);
-
- switch (readb(iobase + IOAT_VER_OFFSET)) {
- case IOAT_VER_1_2:
- device->dma = ioat_dma_probe(pdev, iobase);
- if (device->dma && ioat_dca_enabled)
- device->dca = ioat_dca_init(pdev, iobase);
- break;
- case IOAT_VER_2_0:
- device->dma = ioat_dma_probe(pdev, iobase);
- if (device->dma && ioat_dca_enabled)
- device->dca = ioat2_dca_init(pdev, iobase);
- break;
- case IOAT_VER_3_0:
- device->dma = ioat_dma_probe(pdev, iobase);
- if (device->dma && ioat_dca_enabled)
- device->dca = ioat3_dca_init(pdev, iobase);
- break;
- default:
- err = -ENODEV;
- break;
- }
- if (!device->dma)
- err = -ENODEV;
-
- if (err)
- goto err_version;
-
- return 0;
-
-err_version:
- kfree(device);
-err_kzalloc:
- iounmap(iobase);
-err_ioremap:
-err_set_dma_mask:
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-err_request_regions:
-err_enable_device:
- return err;
-}
-
-static void __devexit ioat_remove(struct pci_dev *pdev)
-{
- struct ioat_device *device = pci_get_drvdata(pdev);
-
- dev_err(&pdev->dev, "Removing dma and dca services\n");
- if (device->dca) {
- unregister_dca_provider(device->dca);
- free_dca_provider(device->dca);
- device->dca = NULL;
- }
-
- if (device->dma) {
- ioat_dma_remove(device->dma);
- device->dma = NULL;
- }
-
- kfree(device);
-}
-
-static int __init ioat_init_module(void)
-{
- return pci_register_driver(&ioat_pci_driver);
-}
-module_init(ioat_init_module);
-
-static void __exit ioat_exit_module(void)
-{
- pci_unregister_driver(&ioat_pci_driver);
-}
-module_exit(ioat_exit_module);
diff --git a/drivers/dma/ioat/Makefile b/drivers/dma/ioat/Makefile
new file mode 100644
index 000000000000..8997d3fb9051
--- /dev/null
+++ b/drivers/dma/ioat/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o
+ioatdma-objs := pci.o dma.o dma_v2.o dma_v3.o dca.o
diff --git a/drivers/dma/ioat_dca.c b/drivers/dma/ioat/dca.c
index c012a1e15043..abd9038e06b1 100644
--- a/drivers/dma/ioat_dca.c
+++ b/drivers/dma/ioat/dca.c
@@ -33,8 +33,8 @@
#define cpu_physical_id(cpu) (cpuid_ebx(1) >> 24)
#endif
-#include "ioatdma.h"
-#include "ioatdma_registers.h"
+#include "dma.h"
+#include "registers.h"
/*
* Bit 7 of a tag map entry is the "valid" bit, if it is set then bits 0:6
@@ -98,17 +98,17 @@ static int dca_enabled_in_bios(struct pci_dev *pdev)
cpuid_level_9 = cpuid_eax(9);
res = test_bit(0, &cpuid_level_9);
if (!res)
- dev_err(&pdev->dev, "DCA is disabled in BIOS\n");
+ dev_dbg(&pdev->dev, "DCA is disabled in BIOS\n");
return res;
}
-static int system_has_dca_enabled(struct pci_dev *pdev)
+int system_has_dca_enabled(struct pci_dev *pdev)
{
if (boot_cpu_has(X86_FEATURE_DCA))
return dca_enabled_in_bios(pdev);
- dev_err(&pdev->dev, "boot cpu doesn't have X86_FEATURE_DCA\n");
+ dev_dbg(&pdev->dev, "boot cpu doesn't have X86_FEATURE_DCA\n");
return 0;
}
@@ -242,7 +242,8 @@ static struct dca_ops ioat_dca_ops = {
};
-struct dca_provider *ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase)
+struct dca_provider * __devinit
+ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase)
{
struct dca_provider *dca;
struct ioat_dca_priv *ioatdca;
@@ -407,7 +408,8 @@ static int ioat2_dca_count_dca_slots(void __iomem *iobase, u16 dca_offset)
return slots;
}
-struct dca_provider *ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase)
+struct dca_provider * __devinit
+ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase)
{
struct dca_provider *dca;
struct ioat_dca_priv *ioatdca;
@@ -602,7 +604,8 @@ static int ioat3_dca_count_dca_slots(void *iobase, u16 dca_offset)
return slots;
}
-struct dca_provider *ioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase)
+struct dca_provider * __devinit
+ioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase)
{
struct dca_provider *dca;
struct ioat_dca_priv *ioatdca;
diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
new file mode 100644
index 000000000000..c524d36d3c2e
--- /dev/null
+++ b/drivers/dma/ioat/dma.c
@@ -0,0 +1,1238 @@
+/*
+ * Intel I/OAT DMA Linux driver
+ * Copyright(c) 2004 - 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 "COPYING".
+ *
+ */
+
+/*
+ * This driver supports an Intel I/OAT DMA engine, which does asynchronous
+ * copy operations.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
+#include <linux/i7300_idle.h>
+#include "dma.h"
+#include "registers.h"
+#include "hw.h"
+
+int ioat_pending_level = 4;
+module_param(ioat_pending_level, int, 0644);
+MODULE_PARM_DESC(ioat_pending_level,
+ "high-water mark for pushing ioat descriptors (default: 4)");
+
+/* internal functions */
+static void ioat1_cleanup(struct ioat_dma_chan *ioat);
+static void ioat1_dma_start_null_desc(struct ioat_dma_chan *ioat);
+
+/**
+ * ioat_dma_do_interrupt - handler used for single vector interrupt mode
+ * @irq: interrupt id
+ * @data: interrupt data
+ */
+static irqreturn_t ioat_dma_do_interrupt(int irq, void *data)
+{
+ struct ioatdma_device *instance = data;
+ struct ioat_chan_common *chan;
+ unsigned long attnstatus;
+ int bit;
+ u8 intrctrl;
+
+ intrctrl = readb(instance->reg_base + IOAT_INTRCTRL_OFFSET);
+
+ if (!(intrctrl & IOAT_INTRCTRL_MASTER_INT_EN))
+ return IRQ_NONE;
+
+ if (!(intrctrl & IOAT_INTRCTRL_INT_STATUS)) {
+ writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
+ return IRQ_NONE;
+ }
+
+ attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET);
+ for_each_bit(bit, &attnstatus, BITS_PER_LONG) {
+ chan = ioat_chan_by_index(instance, bit);
+ tasklet_schedule(&chan->cleanup_task);
+ }
+
+ writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
+ return IRQ_HANDLED;
+}
+
+/**
+ * ioat_dma_do_interrupt_msix - handler used for vector-per-channel interrupt mode
+ * @irq: interrupt id
+ * @data: interrupt data
+ */
+static irqreturn_t ioat_dma_do_interrupt_msix(int irq, void *data)
+{
+ struct ioat_chan_common *chan = data;
+
+ tasklet_schedule(&chan->cleanup_task);
+
+ return IRQ_HANDLED;
+}
+
+static void ioat1_cleanup_tasklet(unsigned long data);
+
+/* common channel initialization */
+void ioat_init_channel(struct ioatdma_device *device,
+ struct ioat_chan_common *chan, int idx,
+ void (*timer_fn)(unsigned long),
+ void (*tasklet)(unsigned long),
+ unsigned long ioat)
+{
+ struct dma_device *dma = &device->common;
+
+ chan->device = device;
+ chan->reg_base = device->reg_base + (0x80 * (idx + 1));
+ spin_lock_init(&chan->cleanup_lock);
+ chan->common.device = dma;
+ list_add_tail(&chan->common.device_node, &dma->channels);
+ device->idx[idx] = chan;
+ init_timer(&chan->timer);
+ chan->timer.function = timer_fn;
+ chan->timer.data = ioat;
+ tasklet_init(&chan->cleanup_task, tasklet, ioat);
+ tasklet_disable(&chan->cleanup_task);
+}
+
+static void ioat1_timer_event(unsigned long data);
+
+/**
+ * ioat1_dma_enumerate_channels - find and initialize the device's channels
+ * @device: the device to be enumerated
+ */
+static int ioat1_enumerate_channels(struct ioatdma_device *device)
+{
+ u8 xfercap_scale;
+ u32 xfercap;
+ int i;
+ struct ioat_dma_chan *ioat;
+ struct device *dev = &device->pdev->dev;
+ struct dma_device *dma = &device->common;
+
+ INIT_LIST_HEAD(&dma->channels);
+ dma->chancnt = readb(device->reg_base + IOAT_CHANCNT_OFFSET);
+ dma->chancnt &= 0x1f; /* bits [4:0] valid */
+ if (dma->chancnt > ARRAY_SIZE(device->idx)) {
+ dev_warn(dev, "(%d) exceeds max supported channels (%zu)\n",
+ dma->chancnt, ARRAY_SIZE(device->idx));
+ dma->chancnt = ARRAY_SIZE(device->idx);
+ }
+ xfercap_scale = readb(device->reg_base + IOAT_XFERCAP_OFFSET);
+ xfercap_scale &= 0x1f; /* bits [4:0] valid */
+ xfercap = (xfercap_scale == 0 ? -1 : (1UL << xfercap_scale));
+ dev_dbg(dev, "%s: xfercap = %d\n", __func__, xfercap);
+
+#ifdef CONFIG_I7300_IDLE_IOAT_CHANNEL
+ if (i7300_idle_platform_probe(NULL, NULL, 1) == 0)
+ dma->chancnt--;
+#endif
+ for (i = 0; i < dma->chancnt; i++) {
+ ioat = devm_kzalloc(dev, sizeof(*ioat), GFP_KERNEL);
+ if (!ioat)
+ break;
+
+ ioat_init_channel(device, &ioat->base, i,
+ ioat1_timer_event,
+ ioat1_cleanup_tasklet,
+ (unsigned long) ioat);
+ ioat->xfercap = xfercap;
+ spin_lock_init(&ioat->desc_lock);
+ INIT_LIST_HEAD(&ioat->free_desc);
+ INIT_LIST_HEAD(&ioat->used_desc);
+ }
+ dma->chancnt = i;
+ return i;
+}
+
+/**
+ * ioat_dma_memcpy_issue_pending - push potentially unrecognized appended
+ * descriptors to hw
+ * @chan: DMA channel handle
+ */
+static inline void
+__ioat1_dma_memcpy_issue_pending(struct ioat_dma_chan *ioat)
+{
+ void __iomem *reg_base = ioat->base.reg_base;
+
+ dev_dbg(to_dev(&ioat->base), "%s: pending: %d\n",
+ __func__, ioat->pending);
+ ioat->pending = 0;
+ writeb(IOAT_CHANCMD_APPEND, reg_base + IOAT1_CHANCMD_OFFSET);
+}
+
+static void ioat1_dma_memcpy_issue_pending(struct dma_chan *chan)
+{
+ struct ioat_dma_chan *ioat = to_ioat_chan(chan);
+
+ if (ioat->pending > 0) {
+ spin_lock_bh(&ioat->desc_lock);
+ __ioat1_dma_memcpy_issue_pending(ioat);
+ spin_unlock_bh(&ioat->desc_lock);
+ }
+}
+
+/**
+ * ioat1_reset_channel - restart a channel
+ * @ioat: IOAT DMA channel handle
+ */
+static void ioat1_reset_channel(struct ioat_dma_chan *ioat)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+ void __iomem *reg_base = chan->reg_base;
+ u32 chansts, chanerr;
+
+ dev_warn(to_dev(chan), "reset\n");
+ chanerr = readl(reg_base + IOAT_CHANERR_OFFSET);
+ chansts = *chan->completion & IOAT_CHANSTS_STATUS;
+ if (chanerr) {
+ dev_err(to_dev(chan),
+ "chan%d, CHANSTS = 0x%08x CHANERR = 0x%04x, clearing\n",
+ chan_num(chan), chansts, chanerr);
+ writel(chanerr, reg_base + IOAT_CHANERR_OFFSET);
+ }
+
+ /*
+ * whack it upside the head with a reset
+ * and wait for things to settle out.
+ * force the pending count to a really big negative
+ * to make sure no one forces an issue_pending
+ * while we're waiting.
+ */
+
+ ioat->pending = INT_MIN;
+ writeb(IOAT_CHANCMD_RESET,
+ reg_base + IOAT_CHANCMD_OFFSET(chan->device->version));
+ set_bit(IOAT_RESET_PENDING, &chan->state);
+ mod_timer(&chan->timer, jiffies + RESET_DELAY);
+}
+
+static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct dma_chan *c = tx->chan;
+ struct ioat_dma_chan *ioat = to_ioat_chan(c);
+ struct ioat_desc_sw *desc = tx_to_ioat_desc(tx);
+ struct ioat_chan_common *chan = &ioat->base;
+ struct ioat_desc_sw *first;
+ struct ioat_desc_sw *chain_tail;
+ dma_cookie_t cookie;
+
+ spin_lock_bh(&ioat->desc_lock);
+ /* cookie incr and addition to used_list must be atomic */
+ cookie = c->cookie;
+ cookie++;
+ if (cookie < 0)
+ cookie = 1;
+ c->cookie = cookie;
+ tx->cookie = cookie;
+ dev_dbg(to_dev(&ioat->base), "%s: cookie: %d\n", __func__, cookie);
+
+ /* write address into NextDescriptor field of last desc in chain */
+ first = to_ioat_desc(desc->tx_list.next);
+ chain_tail = to_ioat_desc(ioat->used_desc.prev);
+ /* make descriptor updates globally visible before chaining */
+ wmb();
+ chain_tail->hw->next = first->txd.phys;
+ list_splice_tail_init(&desc->tx_list, &ioat->used_desc);
+ dump_desc_dbg(ioat, chain_tail);
+ dump_desc_dbg(ioat, first);
+
+ if (!test_and_set_bit(IOAT_COMPLETION_PENDING, &chan->state))
+ mod_timer(&chan->timer, jiffies + COMPLETION_TIMEOUT);
+
+ ioat->active += desc->hw->tx_cnt;
+ ioat->pending += desc->hw->tx_cnt;
+ if (ioat->pending >= ioat_pending_level)
+ __ioat1_dma_memcpy_issue_pending(ioat);
+ spin_unlock_bh(&ioat->desc_lock);
+
+ return cookie;
+}
+
+/**
+ * ioat_dma_alloc_descriptor - allocate and return a sw and hw descriptor pair
+ * @ioat: the channel supplying the memory pool for the descriptors
+ * @flags: allocation flags
+ */
+static struct ioat_desc_sw *
+ioat_dma_alloc_descriptor(struct ioat_dma_chan *ioat, gfp_t flags)
+{
+ struct ioat_dma_descriptor *desc;
+ struct ioat_desc_sw *desc_sw;
+ struct ioatdma_device *ioatdma_device;
+ dma_addr_t phys;
+
+ ioatdma_device = ioat->base.device;
+ desc = pci_pool_alloc(ioatdma_device->dma_pool, flags, &phys);
+ if (unlikely(!desc))
+ return NULL;
+
+ desc_sw = kzalloc(sizeof(*desc_sw), flags);
+ if (unlikely(!desc_sw)) {
+ pci_pool_free(ioatdma_device->dma_pool, desc, phys);
+ return NULL;
+ }
+
+ memset(desc, 0, sizeof(*desc));
+
+ INIT_LIST_HEAD(&desc_sw->tx_list);
+ dma_async_tx_descriptor_init(&desc_sw->txd, &ioat->base.common);
+ desc_sw->txd.tx_submit = ioat1_tx_submit;
+ desc_sw->hw = desc;
+ desc_sw->txd.phys = phys;
+ set_desc_id(desc_sw, -1);
+
+ return desc_sw;
+}
+
+static int ioat_initial_desc_count = 256;
+module_param(ioat_initial_desc_count, int, 0644);
+MODULE_PARM_DESC(ioat_initial_desc_count,
+ "ioat1: initial descriptors per channel (default: 256)");
+/**
+ * ioat1_dma_alloc_chan_resources - returns the number of allocated descriptors
+ * @chan: the channel to be filled out
+ */
+static int ioat1_dma_alloc_chan_resources(struct dma_chan *c)
+{
+ struct ioat_dma_chan *ioat = to_ioat_chan(c);
+ struct ioat_chan_common *chan = &ioat->base;
+ struct ioat_desc_sw *desc;
+ u32 chanerr;
+ int i;
+ LIST_HEAD(tmp_list);
+
+ /* have we already been set up? */
+ if (!list_empty(&ioat->free_desc))
+ return ioat->desccount;
+
+ /* Setup register to interrupt and write completion status on error */
+ writew(IOAT_CHANCTRL_RUN, chan->reg_base + IOAT_CHANCTRL_OFFSET);
+
+ chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET);
+ if (chanerr) {
+ dev_err(to_dev(chan), "CHANERR = %x, clearing\n", chanerr);
+ writel(chanerr, chan->reg_base + IOAT_CHANERR_OFFSET);
+ }
+
+ /* Allocate descriptors */
+ for (i = 0; i < ioat_initial_desc_count; i++) {
+ desc = ioat_dma_alloc_descriptor(ioat, GFP_KERNEL);
+ if (!desc) {
+ dev_err(to_dev(chan), "Only %d initial descriptors\n", i);
+ break;
+ }
+ set_desc_id(desc, i);
+ list_add_tail(&desc->node, &tmp_list);
+ }
+ spin_lock_bh(&ioat->desc_lock);
+ ioat->desccount = i;
+ list_splice(&tmp_list, &ioat->free_desc);
+ spin_unlock_bh(&ioat->desc_lock);
+
+ /* allocate a completion writeback area */
+ /* doing 2 32bit writes to mmio since 1 64b write doesn't work */
+ chan->completion = pci_pool_alloc(chan->device->completion_pool,
+ GFP_KERNEL, &chan->completion_dma);
+ memset(chan->completion, 0, sizeof(*chan->completion));
+ writel(((u64) chan->completion_dma) & 0x00000000FFFFFFFF,
+ chan->reg_base + IOAT_CHANCMP_OFFSET_LOW);
+ writel(((u64) chan->completion_dma) >> 32,
+ chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);
+
+ tasklet_enable(&chan->cleanup_task);
+ ioat1_dma_start_null_desc(ioat); /* give chain to dma device */
+ dev_dbg(to_dev(chan), "%s: allocated %d descriptors\n",
+ __func__, ioat->desccount);
+ return ioat->desccount;
+}
+
+/**
+ * ioat1_dma_free_chan_resources - release all the descriptors
+ * @chan: the channel to be cleaned
+ */
+static void ioat1_dma_free_chan_resources(struct dma_chan *c)
+{
+ struct ioat_dma_chan *ioat = to_ioat_chan(c);
+ struct ioat_chan_common *chan = &ioat->base;
+ struct ioatdma_device *ioatdma_device = chan->device;
+ struct ioat_desc_sw *desc, *_desc;
+ int in_use_descs = 0;
+
+ /* Before freeing channel resources first check
+ * if they have been previously allocated for this channel.
+ */
+ if (ioat->desccount == 0)
+ return;
+
+ tasklet_disable(&chan->cleanup_task);
+ del_timer_sync(&chan->timer);
+ ioat1_cleanup(ioat);
+
+ /* Delay 100ms after reset to allow internal DMA logic to quiesce
+ * before removing DMA descriptor resources.
+ */
+ writeb(IOAT_CHANCMD_RESET,
+ chan->reg_base + IOAT_CHANCMD_OFFSET(chan->device->version));
+ mdelay(100);
+
+ spin_lock_bh(&ioat->desc_lock);
+ list_for_each_entry_safe(desc, _desc, &ioat->used_desc, node) {
+ dev_dbg(to_dev(chan), "%s: freeing %d from used list\n",
+ __func__, desc_id(desc));
+ dump_desc_dbg(ioat, desc);
+ in_use_descs++;
+ list_del(&desc->node);
+ pci_pool_free(ioatdma_device->dma_pool, desc->hw,
+ desc->txd.phys);
+ kfree(desc);
+ }
+ list_for_each_entry_safe(desc, _desc,
+ &ioat->free_desc, node) {
+ list_del(&desc->node);
+ pci_pool_free(ioatdma_device->dma_pool, desc->hw,
+ desc->txd.phys);
+ kfree(desc);
+ }
+ spin_unlock_bh(&ioat->desc_lock);
+
+ pci_pool_free(ioatdma_device->completion_pool,
+ chan->completion,
+ chan->completion_dma);
+
+ /* one is ok since we left it on there on purpose */
+ if (in_use_descs > 1)
+ dev_err(to_dev(chan), "Freeing %d in use descriptors!\n",
+ in_use_descs - 1);
+
+ chan->last_completion = 0;
+ chan->completion_dma = 0;
+ ioat->pending = 0;
+ ioat->desccount = 0;
+}
+
+/**
+ * ioat1_dma_get_next_descriptor - return the next available descriptor
+ * @ioat: IOAT DMA channel handle
+ *
+ * Gets the next descriptor from the chain, and must be called with the
+ * channel's desc_lock held. Allocates more descriptors if the channel
+ * has run out.
+ */
+static struct ioat_desc_sw *
+ioat1_dma_get_next_descriptor(struct ioat_dma_chan *ioat)
+{
+ struct ioat_desc_sw *new;
+
+ if (!list_empty(&ioat->free_desc)) {
+ new = to_ioat_desc(ioat->free_desc.next);
+ list_del(&new->node);
+ } else {
+ /* try to get another desc */
+ new = ioat_dma_alloc_descriptor(ioat, GFP_ATOMIC);
+ if (!new) {
+ dev_err(to_dev(&ioat->base), "alloc failed\n");
+ return NULL;
+ }
+ }
+ dev_dbg(to_dev(&ioat->base), "%s: allocated: %d\n",
+ __func__, desc_id(new));
+ prefetch(new->hw);
+ return new;
+}
+
+static struct dma_async_tx_descriptor *
+ioat1_dma_prep_memcpy(struct dma_chan *c, dma_addr_t dma_dest,
+ dma_addr_t dma_src, size_t len, unsigned long flags)
+{
+ struct ioat_dma_chan *ioat = to_ioat_chan(c);
+ struct ioat_desc_sw *desc;
+ size_t copy;
+ LIST_HEAD(chain);
+ dma_addr_t src = dma_src;
+ dma_addr_t dest = dma_dest;
+ size_t total_len = len;
+ struct ioat_dma_descriptor *hw = NULL;
+ int tx_cnt = 0;
+
+ spin_lock_bh(&ioat->desc_lock);
+ desc = ioat1_dma_get_next_descriptor(ioat);
+ do {
+ if (!desc)
+ break;
+
+ tx_cnt++;
+ copy = min_t(size_t, len, ioat->xfercap);
+
+ hw = desc->hw;
+ hw->size = copy;
+ hw->ctl = 0;
+ hw->src_addr = src;
+ hw->dst_addr = dest;
+
+ list_add_tail(&desc->node, &chain);
+
+ len -= copy;
+ dest += copy;
+ src += copy;
+ if (len) {
+ struct ioat_desc_sw *next;
+
+ async_tx_ack(&desc->txd);
+ next = ioat1_dma_get_next_descriptor(ioat);
+ hw->next = next ? next->txd.phys : 0;
+ dump_desc_dbg(ioat, desc);
+ desc = next;
+ } else
+ hw->next = 0;
+ } while (len);
+
+ if (!desc) {
+ struct ioat_chan_common *chan = &ioat->base;
+
+ dev_err(to_dev(chan),
+ "chan%d - get_next_desc failed\n", chan_num(chan));
+ list_splice(&chain, &ioat->free_desc);
+ spin_unlock_bh(&ioat->desc_lock);
+ return NULL;
+ }
+ spin_unlock_bh(&ioat->desc_lock);
+
+ desc->txd.flags = flags;
+ desc->len = total_len;
+ list_splice(&chain, &desc->tx_list);
+ hw->ctl_f.int_en = !!(flags & DMA_PREP_INTERRUPT);
+ hw->ctl_f.compl_write = 1;
+ hw->tx_cnt = tx_cnt;
+ dump_desc_dbg(ioat, desc);
+
+ return &desc->txd;
+}
+
+static void ioat1_cleanup_tasklet(unsigned long data)
+{
+ struct ioat_dma_chan *chan = (void *)data;
+
+ ioat1_cleanup(chan);
+ writew(IOAT_CHANCTRL_RUN, chan->base.reg_base + IOAT_CHANCTRL_OFFSET);
+}
+
+void ioat_dma_unmap(struct ioat_chan_common *chan, enum dma_ctrl_flags flags,
+ size_t len, struct ioat_dma_descriptor *hw)
+{
+ struct pci_dev *pdev = chan->device->pdev;
+ size_t offset = len - hw->size;
+
+ if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP))
+ ioat_unmap(pdev, hw->dst_addr - offset, len,
+ PCI_DMA_FROMDEVICE, flags, 1);
+
+ if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP))
+ ioat_unmap(pdev, hw->src_addr - offset, len,
+ PCI_DMA_TODEVICE, flags, 0);
+}
+
+unsigned long ioat_get_current_completion(struct ioat_chan_common *chan)
+{
+ unsigned long phys_complete;
+ u64 completion;
+
+ completion = *chan->completion;
+ phys_complete = ioat_chansts_to_addr(completion);
+
+ dev_dbg(to_dev(chan), "%s: phys_complete: %#llx\n", __func__,
+ (unsigned long long) phys_complete);
+
+ if (is_ioat_halted(completion)) {
+ u32 chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET);
+ dev_err(to_dev(chan), "Channel halted, chanerr = %x\n",
+ chanerr);
+
+ /* TODO do something to salvage the situation */
+ }
+
+ return phys_complete;
+}
+
+bool ioat_cleanup_preamble(struct ioat_chan_common *chan,
+ unsigned long *phys_complete)
+{
+ *phys_complete = ioat_get_current_completion(chan);
+ if (*phys_complete == chan->last_completion)
+ return false;
+ clear_bit(IOAT_COMPLETION_ACK, &chan->state);
+ mod_timer(&chan->timer, jiffies + COMPLETION_TIMEOUT);
+
+ return true;
+}
+
+static void __cleanup(struct ioat_dma_chan *ioat, unsigned long phys_complete)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+ struct list_head *_desc, *n;
+ struct dma_async_tx_descriptor *tx;
+
+ dev_dbg(to_dev(chan), "%s: phys_complete: %lx\n",
+ __func__, phys_complete);
+ list_for_each_safe(_desc, n, &ioat->used_desc) {
+ struct ioat_desc_sw *desc;
+
+ prefetch(n);
+ desc = list_entry(_desc, typeof(*desc), node);
+ tx = &desc->txd;
+ /*
+ * Incoming DMA requests may use multiple descriptors,
+ * due to exceeding xfercap, perhaps. If so, only the
+ * last one will have a cookie, and require unmapping.
+ */
+ dump_desc_dbg(ioat, desc);
+ if (tx->cookie) {
+ chan->completed_cookie = tx->cookie;
+ tx->cookie = 0;
+ ioat_dma_unmap(chan, tx->flags, desc->len, desc->hw);
+ ioat->active -= desc->hw->tx_cnt;
+ if (tx->callback) {
+ tx->callback(tx->callback_param);
+ tx->callback = NULL;
+ }
+ }
+
+ if (tx->phys != phys_complete) {
+ /*
+ * a completed entry, but not the last, so clean
+ * up if the client is done with the descriptor
+ */
+ if (async_tx_test_ack(tx))
+ list_move_tail(&desc->node, &ioat->free_desc);
+ } else {
+ /*
+ * last used desc. Do not remove, so we can
+ * append from it.
+ */
+
+ /* if nothing else is pending, cancel the
+ * completion timeout
+ */
+ if (n == &ioat->used_desc) {
+ dev_dbg(to_dev(chan),
+ "%s cancel completion timeout\n",
+ __func__);
+ clear_bit(IOAT_COMPLETION_PENDING, &chan->state);
+ }
+
+ /* TODO check status bits? */
+ break;
+ }
+ }
+
+ chan->last_completion = phys_complete;
+}
+
+/**
+ * ioat1_cleanup - cleanup up finished descriptors
+ * @chan: ioat channel to be cleaned up
+ *
+ * To prevent lock contention we defer cleanup when the locks are
+ * contended with a terminal timeout that forces cleanup and catches
+ * completion notification errors.
+ */
+static void ioat1_cleanup(struct ioat_dma_chan *ioat)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+ unsigned long phys_complete;
+
+ prefetch(chan->completion);
+
+ if (!spin_trylock_bh(&chan->cleanup_lock))
+ return;
+
+ if (!ioat_cleanup_preamble(chan, &phys_complete)) {
+ spin_unlock_bh(&chan->cleanup_lock);
+ return;
+ }
+
+ if (!spin_trylock_bh(&ioat->desc_lock)) {
+ spin_unlock_bh(&chan->cleanup_lock);
+ return;
+ }
+
+ __cleanup(ioat, phys_complete);
+
+ spin_unlock_bh(&ioat->desc_lock);
+ spin_unlock_bh(&chan->cleanup_lock);
+}
+
+static void ioat1_timer_event(unsigned long data)
+{
+ struct ioat_dma_chan *ioat = (void *) data;
+ struct ioat_chan_common *chan = &ioat->base;
+
+ dev_dbg(to_dev(chan), "%s: state: %lx\n", __func__, chan->state);
+
+ spin_lock_bh(&chan->cleanup_lock);
+ if (test_and_clear_bit(IOAT_RESET_PENDING, &chan->state)) {
+ struct ioat_desc_sw *desc;
+
+ spin_lock_bh(&ioat->desc_lock);
+
+ /* restart active descriptors */
+ desc = to_ioat_desc(ioat->used_desc.prev);
+ ioat_set_chainaddr(ioat, desc->txd.phys);
+ ioat_start(chan);
+
+ ioat->pending = 0;
+ set_bit(IOAT_COMPLETION_PENDING, &chan->state);
+ mod_timer(&chan->timer, jiffies + COMPLETION_TIMEOUT);
+ spin_unlock_bh(&ioat->desc_lock);
+ } else if (test_bit(IOAT_COMPLETION_PENDING, &chan->state)) {
+ unsigned long phys_complete;
+
+ spin_lock_bh(&ioat->desc_lock);
+ /* if we haven't made progress and we have already
+ * acknowledged a pending completion once, then be more
+ * forceful with a restart
+ */
+ if (ioat_cleanup_preamble(chan, &phys_complete))
+ __cleanup(ioat, phys_complete);
+ else if (test_bit(IOAT_COMPLETION_ACK, &chan->state))
+ ioat1_reset_channel(ioat);
+ else {
+ u64 status = ioat_chansts(chan);
+
+ /* manually update the last completion address */
+ if (ioat_chansts_to_addr(status) != 0)
+ *chan->completion = status;
+
+ set_bit(IOAT_COMPLETION_ACK, &chan->state);
+ mod_timer(&chan->timer, jiffies + COMPLETION_TIMEOUT);
+ }
+ spin_unlock_bh(&ioat->desc_lock);
+ }
+ spin_unlock_bh(&chan->cleanup_lock);
+}
+
+static enum dma_status
+ioat1_dma_is_complete(struct dma_chan *c, dma_cookie_t cookie,
+ dma_cookie_t *done, dma_cookie_t *used)
+{
+ struct ioat_dma_chan *ioat = to_ioat_chan(c);
+
+ if (ioat_is_complete(c, cookie, done, used) == DMA_SUCCESS)
+ return DMA_SUCCESS;
+
+ ioat1_cleanup(ioat);
+
+ return ioat_is_complete(c, cookie, done, used);
+}
+
+static void ioat1_dma_start_null_desc(struct ioat_dma_chan *ioat)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+ struct ioat_desc_sw *desc;
+ struct ioat_dma_descriptor *hw;
+
+ spin_lock_bh(&ioat->desc_lock);
+
+ desc = ioat1_dma_get_next_descriptor(ioat);
+
+ if (!desc) {
+ dev_err(to_dev(chan),
+ "Unable to start null desc - get next desc failed\n");
+ spin_unlock_bh(&ioat->desc_lock);
+ return;
+ }
+
+ hw = desc->hw;
+ hw->ctl = 0;
+ hw->ctl_f.null = 1;
+ hw->ctl_f.int_en = 1;
+ hw->ctl_f.compl_write = 1;
+ /* set size to non-zero value (channel returns error when size is 0) */
+ hw->size = NULL_DESC_BUFFER_SIZE;
+ hw->src_addr = 0;
+ hw->dst_addr = 0;
+ async_tx_ack(&desc->txd);
+ hw->next = 0;
+ list_add_tail(&desc->node, &ioat->used_desc);
+ dump_desc_dbg(ioat, desc);
+
+ ioat_set_chainaddr(ioat, desc->txd.phys);
+ ioat_start(chan);
+ spin_unlock_bh(&ioat->desc_lock);
+}
+
+/*
+ * Perform a IOAT transaction to verify the HW works.
+ */
+#define IOAT_TEST_SIZE 2000
+
+static void __devinit ioat_dma_test_callback(void *dma_async_param)
+{
+ struct completion *cmp = dma_async_param;
+
+ complete(cmp);
+}
+
+/**
+ * ioat_dma_self_test - Perform a IOAT transaction to verify the HW works.
+ * @device: device to be tested
+ */
+int __devinit ioat_dma_self_test(struct ioatdma_device *device)
+{
+ int i;
+ u8 *src;
+ u8 *dest;
+ struct dma_device *dma = &device->common;
+ struct device *dev = &device->pdev->dev;
+ struct dma_chan *dma_chan;
+ struct dma_async_tx_descriptor *tx;
+ dma_addr_t dma_dest, dma_src;
+ dma_cookie_t cookie;
+ int err = 0;
+ struct completion cmp;
+ unsigned long tmo;
+ unsigned long flags;
+
+ src = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, GFP_KERNEL);
+ if (!src)
+ return -ENOMEM;
+ dest = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, GFP_KERNEL);
+ if (!dest) {
+ kfree(src);
+ return -ENOMEM;
+ }
+
+ /* Fill in src buffer */
+ for (i = 0; i < IOAT_TEST_SIZE; i++)
+ src[i] = (u8)i;
+
+ /* Start copy, using first DMA channel */
+ dma_chan = container_of(dma->channels.next, struct dma_chan,
+ device_node);
+ if (dma->device_alloc_chan_resources(dma_chan) < 1) {
+ dev_err(dev, "selftest cannot allocate chan resource\n");
+ err = -ENODEV;
+ goto out;
+ }
+
+ dma_src = dma_map_single(dev, src, IOAT_TEST_SIZE, DMA_TO_DEVICE);
+ dma_dest = dma_map_single(dev, dest, IOAT_TEST_SIZE, DMA_FROM_DEVICE);
+ flags = DMA_COMPL_SRC_UNMAP_SINGLE | DMA_COMPL_DEST_UNMAP_SINGLE |
+ DMA_PREP_INTERRUPT;
+ tx = device->common.device_prep_dma_memcpy(dma_chan, dma_dest, dma_src,
+ IOAT_TEST_SIZE, flags);
+ if (!tx) {
+ dev_err(dev, "Self-test prep failed, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ async_tx_ack(tx);
+ init_completion(&cmp);
+ tx->callback = ioat_dma_test_callback;
+ tx->callback_param = &cmp;
+ cookie = tx->tx_submit(tx);
+ if (cookie < 0) {
+ dev_err(dev, "Self-test setup failed, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+ dma->device_issue_pending(dma_chan);
+
+ tmo = wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000));
+
+ if (tmo == 0 ||
+ dma->device_is_tx_complete(dma_chan, cookie, NULL, NULL)
+ != DMA_SUCCESS) {
+ dev_err(dev, "Self-test copy timed out, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+ if (memcmp(src, dest, IOAT_TEST_SIZE)) {
+ dev_err(dev, "Self-test copy failed compare, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+free_resources:
+ dma->device_free_chan_resources(dma_chan);
+out:
+ kfree(src);
+ kfree(dest);
+ return err;
+}
+
+static char ioat_interrupt_style[32] = "msix";
+module_param_string(ioat_interrupt_style, ioat_interrupt_style,
+ sizeof(ioat_interrupt_style), 0644);
+MODULE_PARM_DESC(ioat_interrupt_style,
+ "set ioat interrupt style: msix (default), "
+ "msix-single-vector, msi, intx)");
+
+/**
+ * ioat_dma_setup_interrupts - setup interrupt handler
+ * @device: ioat device
+ */
+static int ioat_dma_setup_interrupts(struct ioatdma_device *device)
+{
+ struct ioat_chan_common *chan;
+ struct pci_dev *pdev = device->pdev;
+ struct device *dev = &pdev->dev;
+ struct msix_entry *msix;
+ int i, j, msixcnt;
+ int err = -EINVAL;
+ u8 intrctrl = 0;
+
+ if (!strcmp(ioat_interrupt_style, "msix"))
+ goto msix;
+ if (!strcmp(ioat_interrupt_style, "msix-single-vector"))
+ goto msix_single_vector;
+ if (!strcmp(ioat_interrupt_style, "msi"))
+ goto msi;
+ if (!strcmp(ioat_interrupt_style, "intx"))
+ goto intx;
+ dev_err(dev, "invalid ioat_interrupt_style %s\n", ioat_interrupt_style);
+ goto err_no_irq;
+
+msix:
+ /* The number of MSI-X vectors should equal the number of channels */
+ msixcnt = device->common.chancnt;
+ for (i = 0; i < msixcnt; i++)
+ device->msix_entries[i].entry = i;
+
+ err = pci_enable_msix(pdev, device->msix_entries, msixcnt);
+ if (err < 0)
+ goto msi;
+ if (err > 0)
+ goto msix_single_vector;
+
+ for (i = 0; i < msixcnt; i++) {
+ msix = &device->msix_entries[i];
+ chan = ioat_chan_by_index(device, i);
+ err = devm_request_irq(dev, msix->vector,
+ ioat_dma_do_interrupt_msix, 0,
+ "ioat-msix", chan);
+ if (err) {
+ for (j = 0; j < i; j++) {
+ msix = &device->msix_entries[j];
+ chan = ioat_chan_by_index(device, j);
+ devm_free_irq(dev, msix->vector, chan);
+ }
+ goto msix_single_vector;
+ }
+ }
+ intrctrl |= IOAT_INTRCTRL_MSIX_VECTOR_CONTROL;
+ goto done;
+
+msix_single_vector:
+ msix = &device->msix_entries[0];
+ msix->entry = 0;
+ err = pci_enable_msix(pdev, device->msix_entries, 1);
+ if (err)
+ goto msi;
+
+ err = devm_request_irq(dev, msix->vector, ioat_dma_do_interrupt, 0,
+ "ioat-msix", device);
+ if (err) {
+ pci_disable_msix(pdev);
+ goto msi;
+ }
+ goto done;
+
+msi:
+ err = pci_enable_msi(pdev);
+ if (err)
+ goto intx;
+
+ err = devm_request_irq(dev, pdev->irq, ioat_dma_do_interrupt, 0,
+ "ioat-msi", device);
+ if (err) {
+ pci_disable_msi(pdev);
+ goto intx;
+ }
+ goto done;
+
+intx:
+ err = devm_request_irq(dev, pdev->irq, ioat_dma_do_interrupt,
+ IRQF_SHARED, "ioat-intx", device);
+ if (err)
+ goto err_no_irq;
+
+done:
+ if (device->intr_quirk)
+ device->intr_quirk(device);
+ intrctrl |= IOAT_INTRCTRL_MASTER_INT_EN;
+ writeb(intrctrl, device->reg_base + IOAT_INTRCTRL_OFFSET);
+ return 0;
+
+err_no_irq:
+ /* Disable all interrupt generation */
+ writeb(0, device->reg_base + IOAT_INTRCTRL_OFFSET);
+ dev_err(dev, "no usable interrupts\n");
+ return err;
+}
+
+static void ioat_disable_interrupts(struct ioatdma_device *device)
+{
+ /* Disable all interrupt generation */
+ writeb(0, device->reg_base + IOAT_INTRCTRL_OFFSET);
+}
+
+int __devinit ioat_probe(struct ioatdma_device *device)
+{
+ int err = -ENODEV;
+ struct dma_device *dma = &device->common;
+ struct pci_dev *pdev = device->pdev;
+ struct device *dev = &pdev->dev;
+
+ /* DMA coherent memory pool for DMA descriptor allocations */
+ device->dma_pool = pci_pool_create("dma_desc_pool", pdev,
+ sizeof(struct ioat_dma_descriptor),
+ 64, 0);
+ if (!device->dma_pool) {
+ err = -ENOMEM;
+ goto err_dma_pool;
+ }
+
+ device->completion_pool = pci_pool_create("completion_pool", pdev,
+ sizeof(u64), SMP_CACHE_BYTES,
+ SMP_CACHE_BYTES);
+
+ if (!device->completion_pool) {
+ err = -ENOMEM;
+ goto err_completion_pool;
+ }
+
+ device->enumerate_channels(device);
+
+ dma_cap_set(DMA_MEMCPY, dma->cap_mask);
+ dma->dev = &pdev->dev;
+
+ if (!dma->chancnt) {
+ dev_err(dev, "zero channels detected\n");
+ goto err_setup_interrupts;
+ }
+
+ err = ioat_dma_setup_interrupts(device);
+ if (err)
+ goto err_setup_interrupts;
+
+ err = device->self_test(device);
+ if (err)
+ goto err_self_test;
+
+ return 0;
+
+err_self_test:
+ ioat_disable_interrupts(device);
+err_setup_interrupts:
+ pci_pool_destroy(device->completion_pool);
+err_completion_pool:
+ pci_pool_destroy(device->dma_pool);
+err_dma_pool:
+ return err;
+}
+
+int __devinit ioat_register(struct ioatdma_device *device)
+{
+ int err = dma_async_device_register(&device->common);
+
+ if (err) {
+ ioat_disable_interrupts(device);
+ pci_pool_destroy(device->completion_pool);
+ pci_pool_destroy(device->dma_pool);
+ }
+
+ return err;
+}
+
+/* ioat1_intr_quirk - fix up dma ctrl register to enable / disable msi */
+static void ioat1_intr_quirk(struct ioatdma_device *device)
+{
+ struct pci_dev *pdev = device->pdev;
+ u32 dmactrl;
+
+ pci_read_config_dword(pdev, IOAT_PCI_DMACTRL_OFFSET, &dmactrl);
+ if (pdev->msi_enabled)
+ dmactrl |= IOAT_PCI_DMACTRL_MSI_EN;
+ else
+ dmactrl &= ~IOAT_PCI_DMACTRL_MSI_EN;
+ pci_write_config_dword(pdev, IOAT_PCI_DMACTRL_OFFSET, dmactrl);
+}
+
+static ssize_t ring_size_show(struct dma_chan *c, char *page)
+{
+ struct ioat_dma_chan *ioat = to_ioat_chan(c);
+
+ return sprintf(page, "%d\n", ioat->desccount);
+}
+static struct ioat_sysfs_entry ring_size_attr = __ATTR_RO(ring_size);
+
+static ssize_t ring_active_show(struct dma_chan *c, char *page)
+{
+ struct ioat_dma_chan *ioat = to_ioat_chan(c);
+
+ return sprintf(page, "%d\n", ioat->active);
+}
+static struct ioat_sysfs_entry ring_active_attr = __ATTR_RO(ring_active);
+
+static ssize_t cap_show(struct dma_chan *c, char *page)
+{
+ struct dma_device *dma = c->device;
+
+ return sprintf(page, "copy%s%s%s%s%s%s\n",
+ dma_has_cap(DMA_PQ, dma->cap_mask) ? " pq" : "",
+ dma_has_cap(DMA_PQ_VAL, dma->cap_mask) ? " pq_val" : "",
+ dma_has_cap(DMA_XOR, dma->cap_mask) ? " xor" : "",
+ dma_has_cap(DMA_XOR_VAL, dma->cap_mask) ? " xor_val" : "",
+ dma_has_cap(DMA_MEMSET, dma->cap_mask) ? " fill" : "",
+ dma_has_cap(DMA_INTERRUPT, dma->cap_mask) ? " intr" : "");
+
+}
+struct ioat_sysfs_entry ioat_cap_attr = __ATTR_RO(cap);
+
+static ssize_t version_show(struct dma_chan *c, char *page)
+{
+ struct dma_device *dma = c->device;
+ struct ioatdma_device *device = to_ioatdma_device(dma);
+
+ return sprintf(page, "%d.%d\n",
+ device->version >> 4, device->version & 0xf);
+}
+struct ioat_sysfs_entry ioat_version_attr = __ATTR_RO(version);
+
+static struct attribute *ioat1_attrs[] = {
+ &ring_size_attr.attr,
+ &ring_active_attr.attr,
+ &ioat_cap_attr.attr,
+ &ioat_version_attr.attr,
+ NULL,
+};
+
+static ssize_t
+ioat_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
+{
+ struct ioat_sysfs_entry *entry;
+ struct ioat_chan_common *chan;
+
+ entry = container_of(attr, struct ioat_sysfs_entry, attr);
+ chan = container_of(kobj, struct ioat_chan_common, kobj);
+
+ if (!entry->show)
+ return -EIO;
+ return entry->show(&chan->common, page);
+}
+
+struct sysfs_ops ioat_sysfs_ops = {
+ .show = ioat_attr_show,
+};
+
+static struct kobj_type ioat1_ktype = {
+ .sysfs_ops = &ioat_sysfs_ops,
+ .default_attrs = ioat1_attrs,
+};
+
+void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type)
+{
+ struct dma_device *dma = &device->common;
+ struct dma_chan *c;
+
+ list_for_each_entry(c, &dma->channels, device_node) {
+ struct ioat_chan_common *chan = to_chan_common(c);
+ struct kobject *parent = &c->dev->device.kobj;
+ int err;
+
+ err = kobject_init_and_add(&chan->kobj, type, parent, "quickdata");
+ if (err) {
+ dev_warn(to_dev(chan),
+ "sysfs init error (%d), continuing...\n", err);
+ kobject_put(&chan->kobj);
+ set_bit(IOAT_KOBJ_INIT_FAIL, &chan->state);
+ }
+ }
+}
+
+void ioat_kobject_del(struct ioatdma_device *device)
+{
+ struct dma_device *dma = &device->common;
+ struct dma_chan *c;
+
+ list_for_each_entry(c, &dma->channels, device_node) {
+ struct ioat_chan_common *chan = to_chan_common(c);
+
+ if (!test_bit(IOAT_KOBJ_INIT_FAIL, &chan->state)) {
+ kobject_del(&chan->kobj);
+ kobject_put(&chan->kobj);
+ }
+ }
+}
+
+int __devinit ioat1_dma_probe(struct ioatdma_device *device, int dca)
+{
+ struct pci_dev *pdev = device->pdev;
+ struct dma_device *dma;
+ int err;
+
+ device->intr_quirk = ioat1_intr_quirk;
+ device->enumerate_channels = ioat1_enumerate_channels;
+ device->self_test = ioat_dma_self_test;
+ dma = &device->common;
+ dma->device_prep_dma_memcpy = ioat1_dma_prep_memcpy;
+ dma->device_issue_pending = ioat1_dma_memcpy_issue_pending;
+ dma->device_alloc_chan_resources = ioat1_dma_alloc_chan_resources;
+ dma->device_free_chan_resources = ioat1_dma_free_chan_resources;
+ dma->device_is_tx_complete = ioat1_dma_is_complete;
+
+ err = ioat_probe(device);
+ if (err)
+ return err;
+ ioat_set_tcp_copy_break(4096);
+ err = ioat_register(device);
+ if (err)
+ return err;
+ ioat_kobject_add(device, &ioat1_ktype);
+
+ if (dca)
+ device->dca = ioat_dca_init(pdev, device->reg_base);
+
+ return err;
+}
+
+void __devexit ioat_dma_remove(struct ioatdma_device *device)
+{
+ struct dma_device *dma = &device->common;
+
+ ioat_disable_interrupts(device);
+
+ ioat_kobject_del(device);
+
+ dma_async_device_unregister(dma);
+
+ pci_pool_destroy(device->dma_pool);
+ pci_pool_destroy(device->completion_pool);
+
+ INIT_LIST_HEAD(&dma->channels);
+}
diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h
new file mode 100644
index 000000000000..45edde996480
--- /dev/null
+++ b/drivers/dma/ioat/dma.h
@@ -0,0 +1,335 @@
+/*
+ * Copyright(c) 2004 - 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+#ifndef IOATDMA_H
+#define IOATDMA_H
+
+#include <linux/dmaengine.h>
+#include "hw.h"
+#include "registers.h"
+#include <linux/init.h>
+#include <linux/dmapool.h>
+#include <linux/cache.h>
+#include <linux/pci_ids.h>
+#include <net/tcp.h>
+
+#define IOAT_DMA_VERSION "4.00"
+
+#define IOAT_LOW_COMPLETION_MASK 0xffffffc0
+#define IOAT_DMA_DCA_ANY_CPU ~0
+
+#define to_ioatdma_device(dev) container_of(dev, struct ioatdma_device, common)
+#define to_ioat_desc(lh) container_of(lh, struct ioat_desc_sw, node)
+#define tx_to_ioat_desc(tx) container_of(tx, struct ioat_desc_sw, txd)
+#define to_dev(ioat_chan) (&(ioat_chan)->device->pdev->dev)
+
+#define chan_num(ch) ((int)((ch)->reg_base - (ch)->device->reg_base) / 0x80)
+
+/*
+ * workaround for IOAT ver.3.0 null descriptor issue
+ * (channel returns error when size is 0)
+ */
+#define NULL_DESC_BUFFER_SIZE 1
+
+/**
+ * struct ioatdma_device - internal representation of a IOAT device
+ * @pdev: PCI-Express device
+ * @reg_base: MMIO register space base address
+ * @dma_pool: for allocating DMA descriptors
+ * @common: embedded struct dma_device
+ * @version: version of ioatdma device
+ * @msix_entries: irq handlers
+ * @idx: per channel data
+ * @dca: direct cache access context
+ * @intr_quirk: interrupt setup quirk (for ioat_v1 devices)
+ * @enumerate_channels: hw version specific channel enumeration
+ * @cleanup_tasklet: select between the v2 and v3 cleanup routines
+ * @timer_fn: select between the v2 and v3 timer watchdog routines
+ * @self_test: hardware version specific self test for each supported op type
+ *
+ * Note: the v3 cleanup routine supports raid operations
+ */
+struct ioatdma_device {
+ struct pci_dev *pdev;
+ void __iomem *reg_base;
+ struct pci_pool *dma_pool;
+ struct pci_pool *completion_pool;
+ struct dma_device common;
+ u8 version;
+ struct msix_entry msix_entries[4];
+ struct ioat_chan_common *idx[4];
+ struct dca_provider *dca;
+ void (*intr_quirk)(struct ioatdma_device *device);
+ int (*enumerate_channels)(struct ioatdma_device *device);
+ void (*cleanup_tasklet)(unsigned long data);
+ void (*timer_fn)(unsigned long data);
+ int (*self_test)(struct ioatdma_device *device);
+};
+
+struct ioat_chan_common {
+ struct dma_chan common;
+ void __iomem *reg_base;
+ unsigned long last_completion;
+ spinlock_t cleanup_lock;
+ dma_cookie_t completed_cookie;
+ unsigned long state;
+ #define IOAT_COMPLETION_PENDING 0
+ #define IOAT_COMPLETION_ACK 1
+ #define IOAT_RESET_PENDING 2
+ #define IOAT_KOBJ_INIT_FAIL 3
+ struct timer_list timer;
+ #define COMPLETION_TIMEOUT msecs_to_jiffies(100)
+ #define IDLE_TIMEOUT msecs_to_jiffies(2000)
+ #define RESET_DELAY msecs_to_jiffies(100)
+ struct ioatdma_device *device;
+ dma_addr_t completion_dma;
+ u64 *completion;
+ struct tasklet_struct cleanup_task;
+ struct kobject kobj;
+};
+
+struct ioat_sysfs_entry {
+ struct attribute attr;
+ ssize_t (*show)(struct dma_chan *, char *);
+};
+
+/**
+ * struct ioat_dma_chan - internal representation of a DMA channel
+ */
+struct ioat_dma_chan {
+ struct ioat_chan_common base;
+
+ size_t xfercap; /* XFERCAP register value expanded out */
+
+ spinlock_t desc_lock;
+ struct list_head free_desc;
+ struct list_head used_desc;
+
+ int pending;
+ u16 desccount;
+ u16 active;
+};
+
+static inline struct ioat_chan_common *to_chan_common(struct dma_chan *c)
+{
+ return container_of(c, struct ioat_chan_common, common);
+}
+
+static inline struct ioat_dma_chan *to_ioat_chan(struct dma_chan *c)
+{
+ struct ioat_chan_common *chan = to_chan_common(c);
+
+ return container_of(chan, struct ioat_dma_chan, base);
+}
+
+/**
+ * ioat_is_complete - poll the status of an ioat transaction
+ * @c: channel handle
+ * @cookie: transaction identifier
+ * @done: if set, updated with last completed transaction
+ * @used: if set, updated with last used transaction
+ */
+static inline enum dma_status
+ioat_is_complete(struct dma_chan *c, dma_cookie_t cookie,
+ dma_cookie_t *done, dma_cookie_t *used)
+{
+ struct ioat_chan_common *chan = to_chan_common(c);
+ dma_cookie_t last_used;
+ dma_cookie_t last_complete;
+
+ last_used = c->cookie;
+ last_complete = chan->completed_cookie;
+
+ if (done)
+ *done = last_complete;
+ if (used)
+ *used = last_used;
+
+ return dma_async_is_complete(cookie, last_complete, last_used);
+}
+
+/* wrapper around hardware descriptor format + additional software fields */
+
+/**
+ * struct ioat_desc_sw - wrapper around hardware descriptor
+ * @hw: hardware DMA descriptor (for memcpy)
+ * @node: this descriptor will either be on the free list,
+ * or attached to a transaction list (tx_list)
+ * @txd: the generic software descriptor for all engines
+ * @id: identifier for debug
+ */
+struct ioat_desc_sw {
+ struct ioat_dma_descriptor *hw;
+ struct list_head node;
+ size_t len;
+ struct list_head tx_list;
+ struct dma_async_tx_descriptor txd;
+ #ifdef DEBUG
+ int id;
+ #endif
+};
+
+#ifdef DEBUG
+#define set_desc_id(desc, i) ((desc)->id = (i))
+#define desc_id(desc) ((desc)->id)
+#else
+#define set_desc_id(desc, i)
+#define desc_id(desc) (0)
+#endif
+
+static inline void
+__dump_desc_dbg(struct ioat_chan_common *chan, struct ioat_dma_descriptor *hw,
+ struct dma_async_tx_descriptor *tx, int id)
+{
+ struct device *dev = to_dev(chan);
+
+ dev_dbg(dev, "desc[%d]: (%#llx->%#llx) cookie: %d flags: %#x"
+ " ctl: %#x (op: %d int_en: %d compl: %d)\n", id,
+ (unsigned long long) tx->phys,
+ (unsigned long long) hw->next, tx->cookie, tx->flags,
+ hw->ctl, hw->ctl_f.op, hw->ctl_f.int_en, hw->ctl_f.compl_write);
+}
+
+#define dump_desc_dbg(c, d) \
+ ({ if (d) __dump_desc_dbg(&c->base, d->hw, &d->txd, desc_id(d)); 0; })
+
+static inline void ioat_set_tcp_copy_break(unsigned long copybreak)
+{
+ #ifdef CONFIG_NET_DMA
+ sysctl_tcp_dma_copybreak = copybreak;
+ #endif
+}
+
+static inline struct ioat_chan_common *
+ioat_chan_by_index(struct ioatdma_device *device, int index)
+{
+ return device->idx[index];
+}
+
+static inline u64 ioat_chansts(struct ioat_chan_common *chan)
+{
+ u8 ver = chan->device->version;
+ u64 status;
+ u32 status_lo;
+
+ /* We need to read the low address first as this causes the
+ * chipset to latch the upper bits for the subsequent read
+ */
+ status_lo = readl(chan->reg_base + IOAT_CHANSTS_OFFSET_LOW(ver));
+ status = readl(chan->reg_base + IOAT_CHANSTS_OFFSET_HIGH(ver));
+ status <<= 32;
+ status |= status_lo;
+
+ return status;
+}
+
+static inline void ioat_start(struct ioat_chan_common *chan)
+{
+ u8 ver = chan->device->version;
+
+ writeb(IOAT_CHANCMD_START, chan->reg_base + IOAT_CHANCMD_OFFSET(ver));
+}
+
+static inline u64 ioat_chansts_to_addr(u64 status)
+{
+ return status & IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR;
+}
+
+static inline u32 ioat_chanerr(struct ioat_chan_common *chan)
+{
+ return readl(chan->reg_base + IOAT_CHANERR_OFFSET);
+}
+
+static inline void ioat_suspend(struct ioat_chan_common *chan)
+{
+ u8 ver = chan->device->version;
+
+ writeb(IOAT_CHANCMD_SUSPEND, chan->reg_base + IOAT_CHANCMD_OFFSET(ver));
+}
+
+static inline void ioat_set_chainaddr(struct ioat_dma_chan *ioat, u64 addr)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+
+ writel(addr & 0x00000000FFFFFFFF,
+ chan->reg_base + IOAT1_CHAINADDR_OFFSET_LOW);
+ writel(addr >> 32,
+ chan->reg_base + IOAT1_CHAINADDR_OFFSET_HIGH);
+}
+
+static inline bool is_ioat_active(unsigned long status)
+{
+ return ((status & IOAT_CHANSTS_STATUS) == IOAT_CHANSTS_ACTIVE);
+}
+
+static inline bool is_ioat_idle(unsigned long status)
+{
+ return ((status & IOAT_CHANSTS_STATUS) == IOAT_CHANSTS_DONE);
+}
+
+static inline bool is_ioat_halted(unsigned long status)
+{
+ return ((status & IOAT_CHANSTS_STATUS) == IOAT_CHANSTS_HALTED);
+}
+
+static inline bool is_ioat_suspended(unsigned long status)
+{
+ return ((status & IOAT_CHANSTS_STATUS) == IOAT_CHANSTS_SUSPENDED);
+}
+
+/* channel was fatally programmed */
+static inline bool is_ioat_bug(unsigned long err)
+{
+ return !!err;
+}
+
+static inline void ioat_unmap(struct pci_dev *pdev, dma_addr_t addr, size_t len,
+ int direction, enum dma_ctrl_flags flags, bool dst)
+{
+ if ((dst && (flags & DMA_COMPL_DEST_UNMAP_SINGLE)) ||
+ (!dst && (flags & DMA_COMPL_SRC_UNMAP_SINGLE)))
+ pci_unmap_single(pdev, addr, len, direction);
+ else
+ pci_unmap_page(pdev, addr, len, direction);
+}
+
+int __devinit ioat_probe(struct ioatdma_device *device);
+int __devinit ioat_register(struct ioatdma_device *device);
+int __devinit ioat1_dma_probe(struct ioatdma_device *dev, int dca);
+int __devinit ioat_dma_self_test(struct ioatdma_device *device);
+void __devexit ioat_dma_remove(struct ioatdma_device *device);
+struct dca_provider * __devinit ioat_dca_init(struct pci_dev *pdev,
+ void __iomem *iobase);
+unsigned long ioat_get_current_completion(struct ioat_chan_common *chan);
+void ioat_init_channel(struct ioatdma_device *device,
+ struct ioat_chan_common *chan, int idx,
+ void (*timer_fn)(unsigned long),
+ void (*tasklet)(unsigned long),
+ unsigned long ioat);
+void ioat_dma_unmap(struct ioat_chan_common *chan, enum dma_ctrl_flags flags,
+ size_t len, struct ioat_dma_descriptor *hw);
+bool ioat_cleanup_preamble(struct ioat_chan_common *chan,
+ unsigned long *phys_complete);
+void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type);
+void ioat_kobject_del(struct ioatdma_device *device);
+extern struct sysfs_ops ioat_sysfs_ops;
+extern struct ioat_sysfs_entry ioat_version_attr;
+extern struct ioat_sysfs_entry ioat_cap_attr;
+#endif /* IOATDMA_H */
diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c
new file mode 100644
index 000000000000..8f1f7f05deaa
--- /dev/null
+++ b/drivers/dma/ioat/dma_v2.c
@@ -0,0 +1,873 @@
+/*
+ * Intel I/OAT DMA Linux driver
+ * Copyright(c) 2004 - 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 "COPYING".
+ *
+ */
+
+/*
+ * This driver supports an Intel I/OAT DMA engine (versions >= 2), which
+ * does asynchronous data movement and checksumming operations.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
+#include <linux/i7300_idle.h>
+#include "dma.h"
+#include "dma_v2.h"
+#include "registers.h"
+#include "hw.h"
+
+int ioat_ring_alloc_order = 8;
+module_param(ioat_ring_alloc_order, int, 0644);
+MODULE_PARM_DESC(ioat_ring_alloc_order,
+ "ioat2+: allocate 2^n descriptors per channel"
+ " (default: 8 max: 16)");
+static int ioat_ring_max_alloc_order = IOAT_MAX_ORDER;
+module_param(ioat_ring_max_alloc_order, int, 0644);
+MODULE_PARM_DESC(ioat_ring_max_alloc_order,
+ "ioat2+: upper limit for ring size (default: 16)");
+
+void __ioat2_issue_pending(struct ioat2_dma_chan *ioat)
+{
+ void * __iomem reg_base = ioat->base.reg_base;
+
+ ioat->pending = 0;
+ ioat->dmacount += ioat2_ring_pending(ioat);
+ ioat->issued = ioat->head;
+ /* make descriptor updates globally visible before notifying channel */
+ wmb();
+ writew(ioat->dmacount, reg_base + IOAT_CHAN_DMACOUNT_OFFSET);
+ dev_dbg(to_dev(&ioat->base),
+ "%s: head: %#x tail: %#x issued: %#x count: %#x\n",
+ __func__, ioat->head, ioat->tail, ioat->issued, ioat->dmacount);
+}
+
+void ioat2_issue_pending(struct dma_chan *chan)
+{
+ struct ioat2_dma_chan *ioat = to_ioat2_chan(chan);
+
+ spin_lock_bh(&ioat->ring_lock);
+ if (ioat->pending == 1)
+ __ioat2_issue_pending(ioat);
+ spin_unlock_bh(&ioat->ring_lock);
+}
+
+/**
+ * ioat2_update_pending - log pending descriptors
+ * @ioat: ioat2+ channel
+ *
+ * set pending to '1' unless pending is already set to '2', pending == 2
+ * indicates that submission is temporarily blocked due to an in-flight
+ * reset. If we are already above the ioat_pending_level threshold then
+ * just issue pending.
+ *
+ * called with ring_lock held
+ */
+static void ioat2_update_pending(struct ioat2_dma_chan *ioat)
+{
+ if (unlikely(ioat->pending == 2))
+ return;
+ else if (ioat2_ring_pending(ioat) > ioat_pending_level)
+ __ioat2_issue_pending(ioat);
+ else
+ ioat->pending = 1;
+}
+
+static void __ioat2_start_null_desc(struct ioat2_dma_chan *ioat)
+{
+ struct ioat_ring_ent *desc;
+ struct ioat_dma_descriptor *hw;
+ int idx;
+
+ if (ioat2_ring_space(ioat) < 1) {
+ dev_err(to_dev(&ioat->base),
+ "Unable to start null desc - ring full\n");
+ return;
+ }
+
+ dev_dbg(to_dev(&ioat->base), "%s: head: %#x tail: %#x issued: %#x\n",
+ __func__, ioat->head, ioat->tail, ioat->issued);
+ idx = ioat2_desc_alloc(ioat, 1);
+ desc = ioat2_get_ring_ent(ioat, idx);
+
+ hw = desc->hw;
+ hw->ctl = 0;
+ hw->ctl_f.null = 1;
+ hw->ctl_f.int_en = 1;
+ hw->ctl_f.compl_write = 1;
+ /* set size to non-zero value (channel returns error when size is 0) */
+ hw->size = NULL_DESC_BUFFER_SIZE;
+ hw->src_addr = 0;
+ hw->dst_addr = 0;
+ async_tx_ack(&desc->txd);
+ ioat2_set_chainaddr(ioat, desc->txd.phys);
+ dump_desc_dbg(ioat, desc);
+ __ioat2_issue_pending(ioat);
+}
+
+static void ioat2_start_null_desc(struct ioat2_dma_chan *ioat)
+{
+ spin_lock_bh(&ioat->ring_lock);
+ __ioat2_start_null_desc(ioat);
+ spin_unlock_bh(&ioat->ring_lock);
+}
+
+static void __cleanup(struct ioat2_dma_chan *ioat, unsigned long phys_complete)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+ struct dma_async_tx_descriptor *tx;
+ struct ioat_ring_ent *desc;
+ bool seen_current = false;
+ u16 active;
+ int i;
+
+ dev_dbg(to_dev(chan), "%s: head: %#x tail: %#x issued: %#x\n",
+ __func__, ioat->head, ioat->tail, ioat->issued);
+
+ active = ioat2_ring_active(ioat);
+ for (i = 0; i < active && !seen_current; i++) {
+ prefetch(ioat2_get_ring_ent(ioat, ioat->tail + i + 1));
+ desc = ioat2_get_ring_ent(ioat, ioat->tail + i);
+ tx = &desc->txd;
+ dump_desc_dbg(ioat, desc);
+ if (tx->cookie) {
+ ioat_dma_unmap(chan, tx->flags, desc->len, desc->hw);
+ chan->completed_cookie = tx->cookie;
+ tx->cookie = 0;
+ if (tx->callback) {
+ tx->callback(tx->callback_param);
+ tx->callback = NULL;
+ }
+ }
+
+ if (tx->phys == phys_complete)
+ seen_current = true;
+ }
+ ioat->tail += i;
+ BUG_ON(!seen_current); /* no active descs have written a completion? */
+
+ chan->last_completion = phys_complete;
+ if (ioat->head == ioat->tail) {
+ dev_dbg(to_dev(chan), "%s: cancel completion timeout\n",
+ __func__);
+ clear_bit(IOAT_COMPLETION_PENDING, &chan->state);
+ mod_timer(&chan->timer, jiffies + IDLE_TIMEOUT);
+ }
+}
+
+/**
+ * ioat2_cleanup - clean finished descriptors (advance tail pointer)
+ * @chan: ioat channel to be cleaned up
+ */
+static void ioat2_cleanup(struct ioat2_dma_chan *ioat)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+ unsigned long phys_complete;
+
+ prefetch(chan->completion);
+
+ if (!spin_trylock_bh(&chan->cleanup_lock))
+ return;
+
+ if (!ioat_cleanup_preamble(chan, &phys_complete)) {
+ spin_unlock_bh(&chan->cleanup_lock);
+ return;
+ }
+
+ if (!spin_trylock_bh(&ioat->ring_lock)) {
+ spin_unlock_bh(&chan->cleanup_lock);
+ return;
+ }
+
+ __cleanup(ioat, phys_complete);
+
+ spin_unlock_bh(&ioat->ring_lock);
+ spin_unlock_bh(&chan->cleanup_lock);
+}
+
+void ioat2_cleanup_tasklet(unsigned long data)
+{
+ struct ioat2_dma_chan *ioat = (void *) data;
+
+ ioat2_cleanup(ioat);
+ writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
+}
+
+void __ioat2_restart_chan(struct ioat2_dma_chan *ioat)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+
+ /* set the tail to be re-issued */
+ ioat->issued = ioat->tail;
+ ioat->dmacount = 0;
+ set_bit(IOAT_COMPLETION_PENDING, &chan->state);
+ mod_timer(&chan->timer, jiffies + COMPLETION_TIMEOUT);
+
+ dev_dbg(to_dev(chan),
+ "%s: head: %#x tail: %#x issued: %#x count: %#x\n",
+ __func__, ioat->head, ioat->tail, ioat->issued, ioat->dmacount);
+
+ if (ioat2_ring_pending(ioat)) {
+ struct ioat_ring_ent *desc;
+
+ desc = ioat2_get_ring_ent(ioat, ioat->tail);
+ ioat2_set_chainaddr(ioat, desc->txd.phys);
+ __ioat2_issue_pending(ioat);
+ } else
+ __ioat2_start_null_desc(ioat);
+}
+
+static void ioat2_restart_channel(struct ioat2_dma_chan *ioat)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+ unsigned long phys_complete;
+ u32 status;
+
+ status = ioat_chansts(chan);
+ if (is_ioat_active(status) || is_ioat_idle(status))
+ ioat_suspend(chan);
+ while (is_ioat_active(status) || is_ioat_idle(status)) {
+ status = ioat_chansts(chan);
+ cpu_relax();
+ }
+
+ if (ioat_cleanup_preamble(chan, &phys_complete))
+ __cleanup(ioat, phys_complete);
+
+ __ioat2_restart_chan(ioat);
+}
+
+void ioat2_timer_event(unsigned long data)
+{
+ struct ioat2_dma_chan *ioat = (void *) data;
+ struct ioat_chan_common *chan = &ioat->base;
+
+ spin_lock_bh(&chan->cleanup_lock);
+ if (test_bit(IOAT_COMPLETION_PENDING, &chan->state)) {
+ unsigned long phys_complete;
+ u64 status;
+
+ spin_lock_bh(&ioat->ring_lock);
+ status = ioat_chansts(chan);
+
+ /* when halted due to errors check for channel
+ * programming errors before advancing the completion state
+ */
+ if (is_ioat_halted(status)) {
+ u32 chanerr;
+
+ chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET);
+ dev_err(to_dev(chan), "%s: Channel halted (%x)\n",
+ __func__, chanerr);
+ BUG_ON(is_ioat_bug(chanerr));
+ }
+
+ /* if we haven't made progress and we have already
+ * acknowledged a pending completion once, then be more
+ * forceful with a restart
+ */
+ if (ioat_cleanup_preamble(chan, &phys_complete))
+ __cleanup(ioat, phys_complete);
+ else if (test_bit(IOAT_COMPLETION_ACK, &chan->state))
+ ioat2_restart_channel(ioat);
+ else {
+ set_bit(IOAT_COMPLETION_ACK, &chan->state);
+ mod_timer(&chan->timer, jiffies + COMPLETION_TIMEOUT);
+ }
+ spin_unlock_bh(&ioat->ring_lock);
+ } else {
+ u16 active;
+
+ /* if the ring is idle, empty, and oversized try to step
+ * down the size
+ */
+ spin_lock_bh(&ioat->ring_lock);
+ active = ioat2_ring_active(ioat);
+ if (active == 0 && ioat->alloc_order > ioat_get_alloc_order())
+ reshape_ring(ioat, ioat->alloc_order-1);
+ spin_unlock_bh(&ioat->ring_lock);
+
+ /* keep shrinking until we get back to our minimum
+ * default size
+ */
+ if (ioat->alloc_order > ioat_get_alloc_order())
+ mod_timer(&chan->timer, jiffies + IDLE_TIMEOUT);
+ }
+ spin_unlock_bh(&chan->cleanup_lock);
+}
+
+/**
+ * ioat2_enumerate_channels - find and initialize the device's channels
+ * @device: the device to be enumerated
+ */
+int ioat2_enumerate_channels(struct ioatdma_device *device)
+{
+ struct ioat2_dma_chan *ioat;
+ struct device *dev = &device->pdev->dev;
+ struct dma_device *dma = &device->common;
+ u8 xfercap_log;
+ int i;
+
+ INIT_LIST_HEAD(&dma->channels);
+ dma->chancnt = readb(device->reg_base + IOAT_CHANCNT_OFFSET);
+ dma->chancnt &= 0x1f; /* bits [4:0] valid */
+ if (dma->chancnt > ARRAY_SIZE(device->idx)) {
+ dev_warn(dev, "(%d) exceeds max supported channels (%zu)\n",
+ dma->chancnt, ARRAY_SIZE(device->idx));
+ dma->chancnt = ARRAY_SIZE(device->idx);
+ }
+ xfercap_log = readb(device->reg_base + IOAT_XFERCAP_OFFSET);
+ xfercap_log &= 0x1f; /* bits [4:0] valid */
+ if (xfercap_log == 0)
+ return 0;
+ dev_dbg(dev, "%s: xfercap = %d\n", __func__, 1 << xfercap_log);
+
+ /* FIXME which i/oat version is i7300? */
+#ifdef CONFIG_I7300_IDLE_IOAT_CHANNEL
+ if (i7300_idle_platform_probe(NULL, NULL, 1) == 0)
+ dma->chancnt--;
+#endif
+ for (i = 0; i < dma->chancnt; i++) {
+ ioat = devm_kzalloc(dev, sizeof(*ioat), GFP_KERNEL);
+ if (!ioat)
+ break;
+
+ ioat_init_channel(device, &ioat->base, i,
+ device->timer_fn,
+ device->cleanup_tasklet,
+ (unsigned long) ioat);
+ ioat->xfercap_log = xfercap_log;
+ spin_lock_init(&ioat->ring_lock);
+ }
+ dma->chancnt = i;
+ return i;
+}
+
+static dma_cookie_t ioat2_tx_submit_unlock(struct dma_async_tx_descriptor *tx)
+{
+ struct dma_chan *c = tx->chan;
+ struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
+ struct ioat_chan_common *chan = &ioat->base;
+ dma_cookie_t cookie = c->cookie;
+
+ cookie++;
+ if (cookie < 0)
+ cookie = 1;
+ tx->cookie = cookie;
+ c->cookie = cookie;
+ dev_dbg(to_dev(&ioat->base), "%s: cookie: %d\n", __func__, cookie);
+
+ if (!test_and_set_bit(IOAT_COMPLETION_PENDING, &chan->state))
+ mod_timer(&chan->timer, jiffies + COMPLETION_TIMEOUT);
+ ioat2_update_pending(ioat);
+ spin_unlock_bh(&ioat->ring_lock);
+
+ return cookie;
+}
+
+static struct ioat_ring_ent *ioat2_alloc_ring_ent(struct dma_chan *chan, gfp_t flags)
+{
+ struct ioat_dma_descriptor *hw;
+ struct ioat_ring_ent *desc;
+ struct ioatdma_device *dma;
+ dma_addr_t phys;
+
+ dma = to_ioatdma_device(chan->device);
+ hw = pci_pool_alloc(dma->dma_pool, flags, &phys);
+ if (!hw)
+ return NULL;
+ memset(hw, 0, sizeof(*hw));
+
+ desc = kmem_cache_alloc(ioat2_cache, flags);
+ if (!desc) {
+ pci_pool_free(dma->dma_pool, hw, phys);
+ return NULL;
+ }
+ memset(desc, 0, sizeof(*desc));
+
+ dma_async_tx_descriptor_init(&desc->txd, chan);
+ desc->txd.tx_submit = ioat2_tx_submit_unlock;
+ desc->hw = hw;
+ desc->txd.phys = phys;
+ return desc;
+}
+
+static void ioat2_free_ring_ent(struct ioat_ring_ent *desc, struct dma_chan *chan)
+{
+ struct ioatdma_device *dma;
+
+ dma = to_ioatdma_device(chan->device);
+ pci_pool_free(dma->dma_pool, desc->hw, desc->txd.phys);
+ kmem_cache_free(ioat2_cache, desc);
+}
+
+static struct ioat_ring_ent **ioat2_alloc_ring(struct dma_chan *c, int order, gfp_t flags)
+{
+ struct ioat_ring_ent **ring;
+ int descs = 1 << order;
+ int i;
+
+ if (order > ioat_get_max_alloc_order())
+ return NULL;
+
+ /* allocate the array to hold the software ring */
+ ring = kcalloc(descs, sizeof(*ring), flags);
+ if (!ring)
+ return NULL;
+ for (i = 0; i < descs; i++) {
+ ring[i] = ioat2_alloc_ring_ent(c, flags);
+ if (!ring[i]) {
+ while (i--)
+ ioat2_free_ring_ent(ring[i], c);
+ kfree(ring);
+ return NULL;
+ }
+ set_desc_id(ring[i], i);
+ }
+
+ /* link descs */
+ for (i = 0; i < descs-1; i++) {
+ struct ioat_ring_ent *next = ring[i+1];
+ struct ioat_dma_descriptor *hw = ring[i]->hw;
+
+ hw->next = next->txd.phys;
+ }
+ ring[i]->hw->next = ring[0]->txd.phys;
+
+ return ring;
+}
+
+/* ioat2_alloc_chan_resources - allocate/initialize ioat2 descriptor ring
+ * @chan: channel to be initialized
+ */
+int ioat2_alloc_chan_resources(struct dma_chan *c)
+{
+ struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
+ struct ioat_chan_common *chan = &ioat->base;
+ struct ioat_ring_ent **ring;
+ u32 chanerr;
+ int order;
+
+ /* have we already been set up? */
+ if (ioat->ring)
+ return 1 << ioat->alloc_order;
+
+ /* Setup register to interrupt and write completion status on error */
+ writew(IOAT_CHANCTRL_RUN, chan->reg_base + IOAT_CHANCTRL_OFFSET);
+
+ chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET);
+ if (chanerr) {
+ dev_err(to_dev(chan), "CHANERR = %x, clearing\n", chanerr);
+ writel(chanerr, chan->reg_base + IOAT_CHANERR_OFFSET);
+ }
+
+ /* allocate a completion writeback area */
+ /* doing 2 32bit writes to mmio since 1 64b write doesn't work */
+ chan->completion = pci_pool_alloc(chan->device->completion_pool,
+ GFP_KERNEL, &chan->completion_dma);
+ if (!chan->completion)
+ return -ENOMEM;
+
+ memset(chan->completion, 0, sizeof(*chan->completion));
+ writel(((u64) chan->completion_dma) & 0x00000000FFFFFFFF,
+ chan->reg_base + IOAT_CHANCMP_OFFSET_LOW);
+ writel(((u64) chan->completion_dma) >> 32,
+ chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);
+
+ order = ioat_get_alloc_order();
+ ring = ioat2_alloc_ring(c, order, GFP_KERNEL);
+ if (!ring)
+ return -ENOMEM;
+
+ spin_lock_bh(&ioat->ring_lock);
+ ioat->ring = ring;
+ ioat->head = 0;
+ ioat->issued = 0;
+ ioat->tail = 0;
+ ioat->pending = 0;
+ ioat->alloc_order = order;
+ spin_unlock_bh(&ioat->ring_lock);
+
+ tasklet_enable(&chan->cleanup_task);
+ ioat2_start_null_desc(ioat);
+
+ return 1 << ioat->alloc_order;
+}
+
+bool reshape_ring(struct ioat2_dma_chan *ioat, int order)
+{
+ /* reshape differs from normal ring allocation in that we want
+ * to allocate a new software ring while only
+ * extending/truncating the hardware ring
+ */
+ struct ioat_chan_common *chan = &ioat->base;
+ struct dma_chan *c = &chan->common;
+ const u16 curr_size = ioat2_ring_mask(ioat) + 1;
+ const u16 active = ioat2_ring_active(ioat);
+ const u16 new_size = 1 << order;
+ struct ioat_ring_ent **ring;
+ u16 i;
+
+ if (order > ioat_get_max_alloc_order())
+ return false;
+
+ /* double check that we have at least 1 free descriptor */
+ if (active == curr_size)
+ return false;
+
+ /* when shrinking, verify that we can hold the current active
+ * set in the new ring
+ */
+ if (active >= new_size)
+ return false;
+
+ /* allocate the array to hold the software ring */
+ ring = kcalloc(new_size, sizeof(*ring), GFP_NOWAIT);
+ if (!ring)
+ return false;
+
+ /* allocate/trim descriptors as needed */
+ if (new_size > curr_size) {
+ /* copy current descriptors to the new ring */
+ for (i = 0; i < curr_size; i++) {
+ u16 curr_idx = (ioat->tail+i) & (curr_size-1);
+ u16 new_idx = (ioat->tail+i) & (new_size-1);
+
+ ring[new_idx] = ioat->ring[curr_idx];
+ set_desc_id(ring[new_idx], new_idx);
+ }
+
+ /* add new descriptors to the ring */
+ for (i = curr_size; i < new_size; i++) {
+ u16 new_idx = (ioat->tail+i) & (new_size-1);
+
+ ring[new_idx] = ioat2_alloc_ring_ent(c, GFP_NOWAIT);
+ if (!ring[new_idx]) {
+ while (i--) {
+ u16 new_idx = (ioat->tail+i) & (new_size-1);
+
+ ioat2_free_ring_ent(ring[new_idx], c);
+ }
+ kfree(ring);
+ return false;
+ }
+ set_desc_id(ring[new_idx], new_idx);
+ }
+
+ /* hw link new descriptors */
+ for (i = curr_size-1; i < new_size; i++) {
+ u16 new_idx = (ioat->tail+i) & (new_size-1);
+ struct ioat_ring_ent *next = ring[(new_idx+1) & (new_size-1)];
+ struct ioat_dma_descriptor *hw = ring[new_idx]->hw;
+
+ hw->next = next->txd.phys;
+ }
+ } else {
+ struct ioat_dma_descriptor *hw;
+ struct ioat_ring_ent *next;
+
+ /* copy current descriptors to the new ring, dropping the
+ * removed descriptors
+ */
+ for (i = 0; i < new_size; i++) {
+ u16 curr_idx = (ioat->tail+i) & (curr_size-1);
+ u16 new_idx = (ioat->tail+i) & (new_size-1);
+
+ ring[new_idx] = ioat->ring[curr_idx];
+ set_desc_id(ring[new_idx], new_idx);
+ }
+
+ /* free deleted descriptors */
+ for (i = new_size; i < curr_size; i++) {
+ struct ioat_ring_ent *ent;
+
+ ent = ioat2_get_ring_ent(ioat, ioat->tail+i);
+ ioat2_free_ring_ent(ent, c);
+ }
+
+ /* fix up hardware ring */
+ hw = ring[(ioat->tail+new_size-1) & (new_size-1)]->hw;
+ next = ring[(ioat->tail+new_size) & (new_size-1)];
+ hw->next = next->txd.phys;
+ }
+
+ dev_dbg(to_dev(chan), "%s: allocated %d descriptors\n",
+ __func__, new_size);
+
+ kfree(ioat->ring);
+ ioat->ring = ring;
+ ioat->alloc_order = order;
+
+ return true;
+}
+
+/**
+ * ioat2_alloc_and_lock - common descriptor alloc boilerplate for ioat2,3 ops
+ * @idx: gets starting descriptor index on successful allocation
+ * @ioat: ioat2,3 channel (ring) to operate on
+ * @num_descs: allocation length
+ */
+int ioat2_alloc_and_lock(u16 *idx, struct ioat2_dma_chan *ioat, int num_descs)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+
+ spin_lock_bh(&ioat->ring_lock);
+ /* never allow the last descriptor to be consumed, we need at
+ * least one free at all times to allow for on-the-fly ring
+ * resizing.
+ */
+ while (unlikely(ioat2_ring_space(ioat) <= num_descs)) {
+ if (reshape_ring(ioat, ioat->alloc_order + 1) &&
+ ioat2_ring_space(ioat) > num_descs)
+ break;
+
+ if (printk_ratelimit())
+ dev_dbg(to_dev(chan),
+ "%s: ring full! num_descs: %d (%x:%x:%x)\n",
+ __func__, num_descs, ioat->head, ioat->tail,
+ ioat->issued);
+ spin_unlock_bh(&ioat->ring_lock);
+
+ /* progress reclaim in the allocation failure case we
+ * may be called under bh_disabled so we need to trigger
+ * the timer event directly
+ */
+ spin_lock_bh(&chan->cleanup_lock);
+ if (jiffies > chan->timer.expires &&
+ timer_pending(&chan->timer)) {
+ struct ioatdma_device *device = chan->device;
+
+ mod_timer(&chan->timer, jiffies + COMPLETION_TIMEOUT);
+ spin_unlock_bh(&chan->cleanup_lock);
+ device->timer_fn((unsigned long) ioat);
+ } else
+ spin_unlock_bh(&chan->cleanup_lock);
+ return -ENOMEM;
+ }
+
+ dev_dbg(to_dev(chan), "%s: num_descs: %d (%x:%x:%x)\n",
+ __func__, num_descs, ioat->head, ioat->tail, ioat->issued);
+
+ *idx = ioat2_desc_alloc(ioat, num_descs);
+ return 0; /* with ioat->ring_lock held */
+}
+
+struct dma_async_tx_descriptor *
+ioat2_dma_prep_memcpy_lock(struct dma_chan *c, dma_addr_t dma_dest,
+ dma_addr_t dma_src, size_t len, unsigned long flags)
+{
+ struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
+ struct ioat_dma_descriptor *hw;
+ struct ioat_ring_ent *desc;
+ dma_addr_t dst = dma_dest;
+ dma_addr_t src = dma_src;
+ size_t total_len = len;
+ int num_descs;
+ u16 idx;
+ int i;
+
+ num_descs = ioat2_xferlen_to_descs(ioat, len);
+ if (likely(num_descs) &&
+ ioat2_alloc_and_lock(&idx, ioat, num_descs) == 0)
+ /* pass */;
+ else
+ return NULL;
+ i = 0;
+ do {
+ size_t copy = min_t(size_t, len, 1 << ioat->xfercap_log);
+
+ desc = ioat2_get_ring_ent(ioat, idx + i);
+ hw = desc->hw;
+
+ hw->size = copy;
+ hw->ctl = 0;
+ hw->src_addr = src;
+ hw->dst_addr = dst;
+
+ len -= copy;
+ dst += copy;
+ src += copy;
+ dump_desc_dbg(ioat, desc);
+ } while (++i < num_descs);
+
+ desc->txd.flags = flags;
+ desc->len = total_len;
+ hw->ctl_f.int_en = !!(flags & DMA_PREP_INTERRUPT);
+ hw->ctl_f.fence = !!(flags & DMA_PREP_FENCE);
+ hw->ctl_f.compl_write = 1;
+ dump_desc_dbg(ioat, desc);
+ /* we leave the channel locked to ensure in order submission */
+
+ return &desc->txd;
+}
+
+/**
+ * ioat2_free_chan_resources - release all the descriptors
+ * @chan: the channel to be cleaned
+ */
+void ioat2_free_chan_resources(struct dma_chan *c)
+{
+ struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
+ struct ioat_chan_common *chan = &ioat->base;
+ struct ioatdma_device *device = chan->device;
+ struct ioat_ring_ent *desc;
+ const u16 total_descs = 1 << ioat->alloc_order;
+ int descs;
+ int i;
+
+ /* Before freeing channel resources first check
+ * if they have been previously allocated for this channel.
+ */
+ if (!ioat->ring)
+ return;
+
+ tasklet_disable(&chan->cleanup_task);
+ del_timer_sync(&chan->timer);
+ device->cleanup_tasklet((unsigned long) ioat);
+
+ /* Delay 100ms after reset to allow internal DMA logic to quiesce
+ * before removing DMA descriptor resources.
+ */
+ writeb(IOAT_CHANCMD_RESET,
+ chan->reg_base + IOAT_CHANCMD_OFFSET(chan->device->version));
+ mdelay(100);
+
+ spin_lock_bh(&ioat->ring_lock);
+ descs = ioat2_ring_space(ioat);
+ dev_dbg(to_dev(chan), "freeing %d idle descriptors\n", descs);
+ for (i = 0; i < descs; i++) {
+ desc = ioat2_get_ring_ent(ioat, ioat->head + i);
+ ioat2_free_ring_ent(desc, c);
+ }
+
+ if (descs < total_descs)
+ dev_err(to_dev(chan), "Freeing %d in use descriptors!\n",
+ total_descs - descs);
+
+ for (i = 0; i < total_descs - descs; i++) {
+ desc = ioat2_get_ring_ent(ioat, ioat->tail + i);
+ dump_desc_dbg(ioat, desc);
+ ioat2_free_ring_ent(desc, c);
+ }
+
+ kfree(ioat->ring);
+ ioat->ring = NULL;
+ ioat->alloc_order = 0;
+ pci_pool_free(device->completion_pool, chan->completion,
+ chan->completion_dma);
+ spin_unlock_bh(&ioat->ring_lock);
+
+ chan->last_completion = 0;
+ chan->completion_dma = 0;
+ ioat->pending = 0;
+ ioat->dmacount = 0;
+}
+
+enum dma_status
+ioat2_is_complete(struct dma_chan *c, dma_cookie_t cookie,
+ dma_cookie_t *done, dma_cookie_t *used)
+{
+ struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
+ struct ioatdma_device *device = ioat->base.device;
+
+ if (ioat_is_complete(c, cookie, done, used) == DMA_SUCCESS)
+ return DMA_SUCCESS;
+
+ device->cleanup_tasklet((unsigned long) ioat);
+
+ return ioat_is_complete(c, cookie, done, used);
+}
+
+static ssize_t ring_size_show(struct dma_chan *c, char *page)
+{
+ struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
+
+ return sprintf(page, "%d\n", (1 << ioat->alloc_order) & ~1);
+}
+static struct ioat_sysfs_entry ring_size_attr = __ATTR_RO(ring_size);
+
+static ssize_t ring_active_show(struct dma_chan *c, char *page)
+{
+ struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
+
+ /* ...taken outside the lock, no need to be precise */
+ return sprintf(page, "%d\n", ioat2_ring_active(ioat));
+}
+static struct ioat_sysfs_entry ring_active_attr = __ATTR_RO(ring_active);
+
+static struct attribute *ioat2_attrs[] = {
+ &ring_size_attr.attr,
+ &ring_active_attr.attr,
+ &ioat_cap_attr.attr,
+ &ioat_version_attr.attr,
+ NULL,
+};
+
+struct kobj_type ioat2_ktype = {
+ .sysfs_ops = &ioat_sysfs_ops,
+ .default_attrs = ioat2_attrs,
+};
+
+int __devinit ioat2_dma_probe(struct ioatdma_device *device, int dca)
+{
+ struct pci_dev *pdev = device->pdev;
+ struct dma_device *dma;
+ struct dma_chan *c;
+ struct ioat_chan_common *chan;
+ int err;
+
+ device->enumerate_channels = ioat2_enumerate_channels;
+ device->cleanup_tasklet = ioat2_cleanup_tasklet;
+ device->timer_fn = ioat2_timer_event;
+ device->self_test = ioat_dma_self_test;
+ dma = &device->common;
+ dma->device_prep_dma_memcpy = ioat2_dma_prep_memcpy_lock;
+ dma->device_issue_pending = ioat2_issue_pending;
+ dma->device_alloc_chan_resources = ioat2_alloc_chan_resources;
+ dma->device_free_chan_resources = ioat2_free_chan_resources;
+ dma->device_is_tx_complete = ioat2_is_complete;
+
+ err = ioat_probe(device);
+ if (err)
+ return err;
+ ioat_set_tcp_copy_break(2048);
+
+ list_for_each_entry(c, &dma->channels, device_node) {
+ chan = to_chan_common(c);
+ writel(IOAT_DCACTRL_CMPL_WRITE_ENABLE | IOAT_DMA_DCA_ANY_CPU,
+ chan->reg_base + IOAT_DCACTRL_OFFSET);
+ }
+
+ err = ioat_register(device);
+ if (err)
+ return err;
+
+ ioat_kobject_add(device, &ioat2_ktype);
+
+ if (dca)
+ device->dca = ioat2_dca_init(pdev, device->reg_base);
+
+ return err;
+}
diff --git a/drivers/dma/ioat/dma_v2.h b/drivers/dma/ioat/dma_v2.h
new file mode 100644
index 000000000000..1d849ef74d5f
--- /dev/null
+++ b/drivers/dma/ioat/dma_v2.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright(c) 2004 - 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+#ifndef IOATDMA_V2_H
+#define IOATDMA_V2_H
+
+#include <linux/dmaengine.h>
+#include "dma.h"
+#include "hw.h"
+
+
+extern int ioat_pending_level;
+extern int ioat_ring_alloc_order;
+
+/*
+ * workaround for IOAT ver.3.0 null descriptor issue
+ * (channel returns error when size is 0)
+ */
+#define NULL_DESC_BUFFER_SIZE 1
+
+#define IOAT_MAX_ORDER 16
+#define ioat_get_alloc_order() \
+ (min(ioat_ring_alloc_order, IOAT_MAX_ORDER))
+#define ioat_get_max_alloc_order() \
+ (min(ioat_ring_max_alloc_order, IOAT_MAX_ORDER))
+
+/* struct ioat2_dma_chan - ioat v2 / v3 channel attributes
+ * @base: common ioat channel parameters
+ * @xfercap_log; log2 of channel max transfer length (for fast division)
+ * @head: allocated index
+ * @issued: hardware notification point
+ * @tail: cleanup index
+ * @pending: lock free indicator for issued != head
+ * @dmacount: identical to 'head' except for occasionally resetting to zero
+ * @alloc_order: log2 of the number of allocated descriptors
+ * @ring: software ring buffer implementation of hardware ring
+ * @ring_lock: protects ring attributes
+ */
+struct ioat2_dma_chan {
+ struct ioat_chan_common base;
+ size_t xfercap_log;
+ u16 head;
+ u16 issued;
+ u16 tail;
+ u16 dmacount;
+ u16 alloc_order;
+ int pending;
+ struct ioat_ring_ent **ring;
+ spinlock_t ring_lock;
+};
+
+static inline struct ioat2_dma_chan *to_ioat2_chan(struct dma_chan *c)
+{
+ struct ioat_chan_common *chan = to_chan_common(c);
+
+ return container_of(chan, struct ioat2_dma_chan, base);
+}
+
+static inline u16 ioat2_ring_mask(struct ioat2_dma_chan *ioat)
+{
+ return (1 << ioat->alloc_order) - 1;
+}
+
+/* count of descriptors in flight with the engine */
+static inline u16 ioat2_ring_active(struct ioat2_dma_chan *ioat)
+{
+ return (ioat->head - ioat->tail) & ioat2_ring_mask(ioat);
+}
+
+/* count of descriptors pending submission to hardware */
+static inline u16 ioat2_ring_pending(struct ioat2_dma_chan *ioat)
+{
+ return (ioat->head - ioat->issued) & ioat2_ring_mask(ioat);
+}
+
+static inline u16 ioat2_ring_space(struct ioat2_dma_chan *ioat)
+{
+ u16 num_descs = ioat2_ring_mask(ioat) + 1;
+ u16 active = ioat2_ring_active(ioat);
+
+ BUG_ON(active > num_descs);
+
+ return num_descs - active;
+}
+
+/* assumes caller already checked space */
+static inline u16 ioat2_desc_alloc(struct ioat2_dma_chan *ioat, u16 len)
+{
+ ioat->head += len;
+ return ioat->head - len;
+}
+
+static inline u16 ioat2_xferlen_to_descs(struct ioat2_dma_chan *ioat, size_t len)
+{
+ u16 num_descs = len >> ioat->xfercap_log;
+
+ num_descs += !!(len & ((1 << ioat->xfercap_log) - 1));
+ return num_descs;
+}
+
+/**
+ * struct ioat_ring_ent - wrapper around hardware descriptor
+ * @hw: hardware DMA descriptor (for memcpy)
+ * @fill: hardware fill descriptor
+ * @xor: hardware xor descriptor
+ * @xor_ex: hardware xor extension descriptor
+ * @pq: hardware pq descriptor
+ * @pq_ex: hardware pq extension descriptor
+ * @pqu: hardware pq update descriptor
+ * @raw: hardware raw (un-typed) descriptor
+ * @txd: the generic software descriptor for all engines
+ * @len: total transaction length for unmap
+ * @result: asynchronous result of validate operations
+ * @id: identifier for debug
+ */
+
+struct ioat_ring_ent {
+ union {
+ struct ioat_dma_descriptor *hw;
+ struct ioat_fill_descriptor *fill;
+ struct ioat_xor_descriptor *xor;
+ struct ioat_xor_ext_descriptor *xor_ex;
+ struct ioat_pq_descriptor *pq;
+ struct ioat_pq_ext_descriptor *pq_ex;
+ struct ioat_pq_update_descriptor *pqu;
+ struct ioat_raw_descriptor *raw;
+ };
+ size_t len;
+ struct dma_async_tx_descriptor txd;
+ enum sum_check_flags *result;
+ #ifdef DEBUG
+ int id;
+ #endif
+};
+
+static inline struct ioat_ring_ent *
+ioat2_get_ring_ent(struct ioat2_dma_chan *ioat, u16 idx)
+{
+ return ioat->ring[idx & ioat2_ring_mask(ioat)];
+}
+
+static inline void ioat2_set_chainaddr(struct ioat2_dma_chan *ioat, u64 addr)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+
+ writel(addr & 0x00000000FFFFFFFF,
+ chan->reg_base + IOAT2_CHAINADDR_OFFSET_LOW);
+ writel(addr >> 32,
+ chan->reg_base + IOAT2_CHAINADDR_OFFSET_HIGH);
+}
+
+int __devinit ioat2_dma_probe(struct ioatdma_device *dev, int dca);
+int __devinit ioat3_dma_probe(struct ioatdma_device *dev, int dca);
+struct dca_provider * __devinit ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase);
+struct dca_provider * __devinit ioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase);
+int ioat2_alloc_and_lock(u16 *idx, struct ioat2_dma_chan *ioat, int num_descs);
+int ioat2_enumerate_channels(struct ioatdma_device *device);
+struct dma_async_tx_descriptor *
+ioat2_dma_prep_memcpy_lock(struct dma_chan *c, dma_addr_t dma_dest,
+ dma_addr_t dma_src, size_t len, unsigned long flags);
+void ioat2_issue_pending(struct dma_chan *chan);
+int ioat2_alloc_chan_resources(struct dma_chan *c);
+void ioat2_free_chan_resources(struct dma_chan *c);
+enum dma_status ioat2_is_complete(struct dma_chan *c, dma_cookie_t cookie,
+ dma_cookie_t *done, dma_cookie_t *used);
+void __ioat2_restart_chan(struct ioat2_dma_chan *ioat);
+bool reshape_ring(struct ioat2_dma_chan *ioat, int order);
+void __ioat2_issue_pending(struct ioat2_dma_chan *ioat);
+void ioat2_cleanup_tasklet(unsigned long data);
+void ioat2_timer_event(unsigned long data);
+extern struct kobj_type ioat2_ktype;
+extern struct kmem_cache *ioat2_cache;
+#endif /* IOATDMA_V2_H */
diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c
new file mode 100644
index 000000000000..42f6f10fb0cc
--- /dev/null
+++ b/drivers/dma/ioat/dma_v3.c
@@ -0,0 +1,1253 @@
+/*
+ * 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) 2004 - 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 "COPYING".
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2004-2009 Intel Corporation. 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.
+ */
+
+/*
+ * Support routines for v3+ hardware
+ */
+
+#include <linux/pci.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include "registers.h"
+#include "hw.h"
+#include "dma.h"
+#include "dma_v2.h"
+
+/* ioat hardware assumes at least two sources for raid operations */
+#define src_cnt_to_sw(x) ((x) + 2)
+#define src_cnt_to_hw(x) ((x) - 2)
+
+/* provide a lookup table for setting the source address in the base or
+ * extended descriptor of an xor or pq descriptor
+ */
+static const u8 xor_idx_to_desc __read_mostly = 0xd0;
+static const u8 xor_idx_to_field[] __read_mostly = { 1, 4, 5, 6, 7, 0, 1, 2 };
+static const u8 pq_idx_to_desc __read_mostly = 0xf8;
+static const u8 pq_idx_to_field[] __read_mostly = { 1, 4, 5, 0, 1, 2, 4, 5 };
+
+static dma_addr_t xor_get_src(struct ioat_raw_descriptor *descs[2], int idx)
+{
+ struct ioat_raw_descriptor *raw = descs[xor_idx_to_desc >> idx & 1];
+
+ return raw->field[xor_idx_to_field[idx]];
+}
+
+static void xor_set_src(struct ioat_raw_descriptor *descs[2],
+ dma_addr_t addr, u32 offset, int idx)
+{
+ struct ioat_raw_descriptor *raw = descs[xor_idx_to_desc >> idx & 1];
+
+ raw->field[xor_idx_to_field[idx]] = addr + offset;
+}
+
+static dma_addr_t pq_get_src(struct ioat_raw_descriptor *descs[2], int idx)
+{
+ struct ioat_raw_descriptor *raw = descs[pq_idx_to_desc >> idx & 1];
+
+ return raw->field[pq_idx_to_field[idx]];
+}
+
+static void pq_set_src(struct ioat_raw_descriptor *descs[2],
+ dma_addr_t addr, u32 offset, u8 coef, int idx)
+{
+ struct ioat_pq_descriptor *pq = (struct ioat_pq_descriptor *) descs[0];
+ struct ioat_raw_descriptor *raw = descs[pq_idx_to_desc >> idx & 1];
+
+ raw->field[pq_idx_to_field[idx]] = addr + offset;
+ pq->coef[idx] = coef;
+}
+
+static void ioat3_dma_unmap(struct ioat2_dma_chan *ioat,
+ struct ioat_ring_ent *desc, int idx)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+ struct pci_dev *pdev = chan->device->pdev;
+ size_t len = desc->len;
+ size_t offset = len - desc->hw->size;
+ struct dma_async_tx_descriptor *tx = &desc->txd;
+ enum dma_ctrl_flags flags = tx->flags;
+
+ switch (desc->hw->ctl_f.op) {
+ case IOAT_OP_COPY:
+ if (!desc->hw->ctl_f.null) /* skip 'interrupt' ops */
+ ioat_dma_unmap(chan, flags, len, desc->hw);
+ break;
+ case IOAT_OP_FILL: {
+ struct ioat_fill_descriptor *hw = desc->fill;
+
+ if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP))
+ ioat_unmap(pdev, hw->dst_addr - offset, len,
+ PCI_DMA_FROMDEVICE, flags, 1);
+ break;
+ }
+ case IOAT_OP_XOR_VAL:
+ case IOAT_OP_XOR: {
+ struct ioat_xor_descriptor *xor = desc->xor;
+ struct ioat_ring_ent *ext;
+ struct ioat_xor_ext_descriptor *xor_ex = NULL;
+ int src_cnt = src_cnt_to_sw(xor->ctl_f.src_cnt);
+ struct ioat_raw_descriptor *descs[2];
+ int i;
+
+ if (src_cnt > 5) {
+ ext = ioat2_get_ring_ent(ioat, idx + 1);
+ xor_ex = ext->xor_ex;
+ }
+
+ if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
+ descs[0] = (struct ioat_raw_descriptor *) xor;
+ descs[1] = (struct ioat_raw_descriptor *) xor_ex;
+ for (i = 0; i < src_cnt; i++) {
+ dma_addr_t src = xor_get_src(descs, i);
+
+ ioat_unmap(pdev, src - offset, len,
+ PCI_DMA_TODEVICE, flags, 0);
+ }
+
+ /* dest is a source in xor validate operations */
+ if (xor->ctl_f.op == IOAT_OP_XOR_VAL) {
+ ioat_unmap(pdev, xor->dst_addr - offset, len,
+ PCI_DMA_TODEVICE, flags, 1);
+ break;
+ }
+ }
+
+ if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP))
+ ioat_unmap(pdev, xor->dst_addr - offset, len,
+ PCI_DMA_FROMDEVICE, flags, 1);
+ break;
+ }
+ case IOAT_OP_PQ_VAL:
+ case IOAT_OP_PQ: {
+ struct ioat_pq_descriptor *pq = desc->pq;
+ struct ioat_ring_ent *ext;
+ struct ioat_pq_ext_descriptor *pq_ex = NULL;
+ int src_cnt = src_cnt_to_sw(pq->ctl_f.src_cnt);
+ struct ioat_raw_descriptor *descs[2];
+ int i;
+
+ if (src_cnt > 3) {
+ ext = ioat2_get_ring_ent(ioat, idx + 1);
+ pq_ex = ext->pq_ex;
+ }
+
+ /* in the 'continue' case don't unmap the dests as sources */
+ if (dmaf_p_disabled_continue(flags))
+ src_cnt--;
+ else if (dmaf_continue(flags))
+ src_cnt -= 3;
+
+ if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
+ descs[0] = (struct ioat_raw_descriptor *) pq;
+ descs[1] = (struct ioat_raw_descriptor *) pq_ex;
+ for (i = 0; i < src_cnt; i++) {
+ dma_addr_t src = pq_get_src(descs, i);
+
+ ioat_unmap(pdev, src - offset, len,
+ PCI_DMA_TODEVICE, flags, 0);
+ }
+
+ /* the dests are sources in pq validate operations */
+ if (pq->ctl_f.op == IOAT_OP_XOR_VAL) {
+ if (!(flags & DMA_PREP_PQ_DISABLE_P))
+ ioat_unmap(pdev, pq->p_addr - offset,
+ len, PCI_DMA_TODEVICE, flags, 0);
+ if (!(flags & DMA_PREP_PQ_DISABLE_Q))
+ ioat_unmap(pdev, pq->q_addr - offset,
+ len, PCI_DMA_TODEVICE, flags, 0);
+ break;
+ }
+ }
+
+ if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
+ if (!(flags & DMA_PREP_PQ_DISABLE_P))
+ ioat_unmap(pdev, pq->p_addr - offset, len,
+ PCI_DMA_BIDIRECTIONAL, flags, 1);
+ if (!(flags & DMA_PREP_PQ_DISABLE_Q))
+ ioat_unmap(pdev, pq->q_addr - offset, len,
+ PCI_DMA_BIDIRECTIONAL, flags, 1);
+ }
+ break;
+ }
+ default:
+ dev_err(&pdev->dev, "%s: unknown op type: %#x\n",
+ __func__, desc->hw->ctl_f.op);
+ }
+}
+
+static bool desc_has_ext(struct ioat_ring_ent *desc)
+{
+ struct ioat_dma_descriptor *hw = desc->hw;
+
+ if (hw->ctl_f.op == IOAT_OP_XOR ||
+ hw->ctl_f.op == IOAT_OP_XOR_VAL) {
+ struct ioat_xor_descriptor *xor = desc->xor;
+
+ if (src_cnt_to_sw(xor->ctl_f.src_cnt) > 5)
+ return true;
+ } else if (hw->ctl_f.op == IOAT_OP_PQ ||
+ hw->ctl_f.op == IOAT_OP_PQ_VAL) {
+ struct ioat_pq_descriptor *pq = desc->pq;
+
+ if (src_cnt_to_sw(pq->ctl_f.src_cnt) > 3)
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * __cleanup - reclaim used descriptors
+ * @ioat: channel (ring) to clean
+ *
+ * The difference from the dma_v2.c __cleanup() is that this routine
+ * handles extended descriptors and dma-unmapping raid operations.
+ */
+static void __cleanup(struct ioat2_dma_chan *ioat, unsigned long phys_complete)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+ struct ioat_ring_ent *desc;
+ bool seen_current = false;
+ u16 active;
+ int i;
+
+ dev_dbg(to_dev(chan), "%s: head: %#x tail: %#x issued: %#x\n",
+ __func__, ioat->head, ioat->tail, ioat->issued);
+
+ active = ioat2_ring_active(ioat);
+ for (i = 0; i < active && !seen_current; i++) {
+ struct dma_async_tx_descriptor *tx;
+
+ prefetch(ioat2_get_ring_ent(ioat, ioat->tail + i + 1));
+ desc = ioat2_get_ring_ent(ioat, ioat->tail + i);
+ dump_desc_dbg(ioat, desc);
+ tx = &desc->txd;
+ if (tx->cookie) {
+ chan->completed_cookie = tx->cookie;
+ ioat3_dma_unmap(ioat, desc, ioat->tail + i);
+ tx->cookie = 0;
+ if (tx->callback) {
+ tx->callback(tx->callback_param);
+ tx->callback = NULL;
+ }
+ }
+
+ if (tx->phys == phys_complete)
+ seen_current = true;
+
+ /* skip extended descriptors */
+ if (desc_has_ext(desc)) {
+ BUG_ON(i + 1 >= active);
+ i++;
+ }
+ }
+ ioat->tail += i;
+ BUG_ON(!seen_current); /* no active descs have written a completion? */
+ chan->last_completion = phys_complete;
+ if (ioat->head == ioat->tail) {
+ dev_dbg(to_dev(chan), "%s: cancel completion timeout\n",
+ __func__);
+ clear_bit(IOAT_COMPLETION_PENDING, &chan->state);
+ mod_timer(&chan->timer, jiffies + IDLE_TIMEOUT);
+ }
+}
+
+static void ioat3_cleanup(struct ioat2_dma_chan *ioat)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+ unsigned long phys_complete;
+
+ prefetch(chan->completion);
+
+ if (!spin_trylock_bh(&chan->cleanup_lock))
+ return;
+
+ if (!ioat_cleanup_preamble(chan, &phys_complete)) {
+ spin_unlock_bh(&chan->cleanup_lock);
+ return;
+ }
+
+ if (!spin_trylock_bh(&ioat->ring_lock)) {
+ spin_unlock_bh(&chan->cleanup_lock);
+ return;
+ }
+
+ __cleanup(ioat, phys_complete);
+
+ spin_unlock_bh(&ioat->ring_lock);
+ spin_unlock_bh(&chan->cleanup_lock);
+}
+
+static void ioat3_cleanup_tasklet(unsigned long data)
+{
+ struct ioat2_dma_chan *ioat = (void *) data;
+
+ ioat3_cleanup(ioat);
+ writew(IOAT_CHANCTRL_RUN | IOAT3_CHANCTRL_COMPL_DCA_EN,
+ ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
+}
+
+static void ioat3_restart_channel(struct ioat2_dma_chan *ioat)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+ unsigned long phys_complete;
+ u32 status;
+
+ status = ioat_chansts(chan);
+ if (is_ioat_active(status) || is_ioat_idle(status))
+ ioat_suspend(chan);
+ while (is_ioat_active(status) || is_ioat_idle(status)) {
+ status = ioat_chansts(chan);
+ cpu_relax();
+ }
+
+ if (ioat_cleanup_preamble(chan, &phys_complete))
+ __cleanup(ioat, phys_complete);
+
+ __ioat2_restart_chan(ioat);
+}
+
+static void ioat3_timer_event(unsigned long data)
+{
+ struct ioat2_dma_chan *ioat = (void *) data;
+ struct ioat_chan_common *chan = &ioat->base;
+
+ spin_lock_bh(&chan->cleanup_lock);
+ if (test_bit(IOAT_COMPLETION_PENDING, &chan->state)) {
+ unsigned long phys_complete;
+ u64 status;
+
+ spin_lock_bh(&ioat->ring_lock);
+ status = ioat_chansts(chan);
+
+ /* when halted due to errors check for channel
+ * programming errors before advancing the completion state
+ */
+ if (is_ioat_halted(status)) {
+ u32 chanerr;
+
+ chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET);
+ dev_err(to_dev(chan), "%s: Channel halted (%x)\n",
+ __func__, chanerr);
+ BUG_ON(is_ioat_bug(chanerr));
+ }
+
+ /* if we haven't made progress and we have already
+ * acknowledged a pending completion once, then be more
+ * forceful with a restart
+ */
+ if (ioat_cleanup_preamble(chan, &phys_complete))
+ __cleanup(ioat, phys_complete);
+ else if (test_bit(IOAT_COMPLETION_ACK, &chan->state))
+ ioat3_restart_channel(ioat);
+ else {
+ set_bit(IOAT_COMPLETION_ACK, &chan->state);
+ mod_timer(&chan->timer, jiffies + COMPLETION_TIMEOUT);
+ }
+ spin_unlock_bh(&ioat->ring_lock);
+ } else {
+ u16 active;
+
+ /* if the ring is idle, empty, and oversized try to step
+ * down the size
+ */
+ spin_lock_bh(&ioat->ring_lock);
+ active = ioat2_ring_active(ioat);
+ if (active == 0 && ioat->alloc_order > ioat_get_alloc_order())
+ reshape_ring(ioat, ioat->alloc_order-1);
+ spin_unlock_bh(&ioat->ring_lock);
+
+ /* keep shrinking until we get back to our minimum
+ * default size
+ */
+ if (ioat->alloc_order > ioat_get_alloc_order())
+ mod_timer(&chan->timer, jiffies + IDLE_TIMEOUT);
+ }
+ spin_unlock_bh(&chan->cleanup_lock);
+}
+
+static enum dma_status
+ioat3_is_complete(struct dma_chan *c, dma_cookie_t cookie,
+ dma_cookie_t *done, dma_cookie_t *used)
+{
+ struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
+
+ if (ioat_is_complete(c, cookie, done, used) == DMA_SUCCESS)
+ return DMA_SUCCESS;
+
+ ioat3_cleanup(ioat);
+
+ return ioat_is_complete(c, cookie, done, used);
+}
+
+static struct dma_async_tx_descriptor *
+ioat3_prep_memset_lock(struct dma_chan *c, dma_addr_t dest, int value,
+ size_t len, unsigned long flags)
+{
+ struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
+ struct ioat_ring_ent *desc;
+ size_t total_len = len;
+ struct ioat_fill_descriptor *fill;
+ int num_descs;
+ u64 src_data = (0x0101010101010101ULL) * (value & 0xff);
+ u16 idx;
+ int i;
+
+ num_descs = ioat2_xferlen_to_descs(ioat, len);
+ if (likely(num_descs) &&
+ ioat2_alloc_and_lock(&idx, ioat, num_descs) == 0)
+ /* pass */;
+ else
+ return NULL;
+ i = 0;
+ do {
+ size_t xfer_size = min_t(size_t, len, 1 << ioat->xfercap_log);
+
+ desc = ioat2_get_ring_ent(ioat, idx + i);
+ fill = desc->fill;
+
+ fill->size = xfer_size;
+ fill->src_data = src_data;
+ fill->dst_addr = dest;
+ fill->ctl = 0;
+ fill->ctl_f.op = IOAT_OP_FILL;
+
+ len -= xfer_size;
+ dest += xfer_size;
+ dump_desc_dbg(ioat, desc);
+ } while (++i < num_descs);
+
+ desc->txd.flags = flags;
+ desc->len = total_len;
+ fill->ctl_f.int_en = !!(flags & DMA_PREP_INTERRUPT);
+ fill->ctl_f.fence = !!(flags & DMA_PREP_FENCE);
+ fill->ctl_f.compl_write = 1;
+ dump_desc_dbg(ioat, desc);
+
+ /* we leave the channel locked to ensure in order submission */
+ return &desc->txd;
+}
+
+static struct dma_async_tx_descriptor *
+__ioat3_prep_xor_lock(struct dma_chan *c, enum sum_check_flags *result,
+ dma_addr_t dest, dma_addr_t *src, unsigned int src_cnt,
+ size_t len, unsigned long flags)
+{
+ struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
+ struct ioat_ring_ent *compl_desc;
+ struct ioat_ring_ent *desc;
+ struct ioat_ring_ent *ext;
+ size_t total_len = len;
+ struct ioat_xor_descriptor *xor;
+ struct ioat_xor_ext_descriptor *xor_ex = NULL;
+ struct ioat_dma_descriptor *hw;
+ u32 offset = 0;
+ int num_descs;
+ int with_ext;
+ int i;
+ u16 idx;
+ u8 op = result ? IOAT_OP_XOR_VAL : IOAT_OP_XOR;
+
+ BUG_ON(src_cnt < 2);
+
+ num_descs = ioat2_xferlen_to_descs(ioat, len);
+ /* we need 2x the number of descriptors to cover greater than 5
+ * sources
+ */
+ if (src_cnt > 5) {
+ with_ext = 1;
+ num_descs *= 2;
+ } else
+ with_ext = 0;
+
+ /* completion writes from the raid engine may pass completion
+ * writes from the legacy engine, so we need one extra null
+ * (legacy) descriptor to ensure all completion writes arrive in
+ * order.
+ */
+ if (likely(num_descs) &&
+ ioat2_alloc_and_lock(&idx, ioat, num_descs+1) == 0)
+ /* pass */;
+ else
+ return NULL;
+ i = 0;
+ do {
+ struct ioat_raw_descriptor *descs[2];
+ size_t xfer_size = min_t(size_t, len, 1 << ioat->xfercap_log);
+ int s;
+
+ desc = ioat2_get_ring_ent(ioat, idx + i);
+ xor = desc->xor;
+
+ /* save a branch by unconditionally retrieving the
+ * extended descriptor xor_set_src() knows to not write
+ * to it in the single descriptor case
+ */
+ ext = ioat2_get_ring_ent(ioat, idx + i + 1);
+ xor_ex = ext->xor_ex;
+
+ descs[0] = (struct ioat_raw_descriptor *) xor;
+ descs[1] = (struct ioat_raw_descriptor *) xor_ex;
+ for (s = 0; s < src_cnt; s++)
+ xor_set_src(descs, src[s], offset, s);
+ xor->size = xfer_size;
+ xor->dst_addr = dest + offset;
+ xor->ctl = 0;
+ xor->ctl_f.op = op;
+ xor->ctl_f.src_cnt = src_cnt_to_hw(src_cnt);
+
+ len -= xfer_size;
+ offset += xfer_size;
+ dump_desc_dbg(ioat, desc);
+ } while ((i += 1 + with_ext) < num_descs);
+
+ /* last xor descriptor carries the unmap parameters and fence bit */
+ desc->txd.flags = flags;
+ desc->len = total_len;
+ if (result)
+ desc->result = result;
+ xor->ctl_f.fence = !!(flags & DMA_PREP_FENCE);
+
+ /* completion descriptor carries interrupt bit */
+ compl_desc = ioat2_get_ring_ent(ioat, idx + i);
+ compl_desc->txd.flags = flags & DMA_PREP_INTERRUPT;
+ hw = compl_desc->hw;
+ hw->ctl = 0;
+ hw->ctl_f.null = 1;
+ hw->ctl_f.int_en = !!(flags & DMA_PREP_INTERRUPT);
+ hw->ctl_f.compl_write = 1;
+ hw->size = NULL_DESC_BUFFER_SIZE;
+ dump_desc_dbg(ioat, compl_desc);
+
+ /* we leave the channel locked to ensure in order submission */
+ return &compl_desc->txd;
+}
+
+static struct dma_async_tx_descriptor *
+ioat3_prep_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
+ unsigned int src_cnt, size_t len, unsigned long flags)
+{
+ return __ioat3_prep_xor_lock(chan, NULL, dest, src, src_cnt, len, flags);
+}
+
+struct dma_async_tx_descriptor *
+ioat3_prep_xor_val(struct dma_chan *chan, dma_addr_t *src,
+ unsigned int src_cnt, size_t len,
+ enum sum_check_flags *result, unsigned long flags)
+{
+ /* the cleanup routine only sets bits on validate failure, it
+ * does not clear bits on validate success... so clear it here
+ */
+ *result = 0;
+
+ return __ioat3_prep_xor_lock(chan, result, src[0], &src[1],
+ src_cnt - 1, len, flags);
+}
+
+static void
+dump_pq_desc_dbg(struct ioat2_dma_chan *ioat, struct ioat_ring_ent *desc, struct ioat_ring_ent *ext)
+{
+ struct device *dev = to_dev(&ioat->base);
+ struct ioat_pq_descriptor *pq = desc->pq;
+ struct ioat_pq_ext_descriptor *pq_ex = ext ? ext->pq_ex : NULL;
+ struct ioat_raw_descriptor *descs[] = { (void *) pq, (void *) pq_ex };
+ int src_cnt = src_cnt_to_sw(pq->ctl_f.src_cnt);
+ int i;
+
+ dev_dbg(dev, "desc[%d]: (%#llx->%#llx) flags: %#x"
+ " sz: %#x ctl: %#x (op: %d int: %d compl: %d pq: '%s%s' src_cnt: %d)\n",
+ desc_id(desc), (unsigned long long) desc->txd.phys,
+ (unsigned long long) (pq_ex ? pq_ex->next : pq->next),
+ desc->txd.flags, pq->size, pq->ctl, pq->ctl_f.op, pq->ctl_f.int_en,
+ pq->ctl_f.compl_write,
+ pq->ctl_f.p_disable ? "" : "p", pq->ctl_f.q_disable ? "" : "q",
+ pq->ctl_f.src_cnt);
+ for (i = 0; i < src_cnt; i++)
+ dev_dbg(dev, "\tsrc[%d]: %#llx coef: %#x\n", i,
+ (unsigned long long) pq_get_src(descs, i), pq->coef[i]);
+ dev_dbg(dev, "\tP: %#llx\n", pq->p_addr);
+ dev_dbg(dev, "\tQ: %#llx\n", pq->q_addr);
+}
+
+static struct dma_async_tx_descriptor *
+__ioat3_prep_pq_lock(struct dma_chan *c, enum sum_check_flags *result,
+ const dma_addr_t *dst, const dma_addr_t *src,
+ unsigned int src_cnt, const unsigned char *scf,
+ size_t len, unsigned long flags)
+{
+ struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
+ struct ioat_chan_common *chan = &ioat->base;
+ struct ioat_ring_ent *compl_desc;
+ struct ioat_ring_ent *desc;
+ struct ioat_ring_ent *ext;
+ size_t total_len = len;
+ struct ioat_pq_descriptor *pq;
+ struct ioat_pq_ext_descriptor *pq_ex = NULL;
+ struct ioat_dma_descriptor *hw;
+ u32 offset = 0;
+ int num_descs;
+ int with_ext;
+ int i, s;
+ u16 idx;
+ u8 op = result ? IOAT_OP_PQ_VAL : IOAT_OP_PQ;
+
+ dev_dbg(to_dev(chan), "%s\n", __func__);
+ /* the engine requires at least two sources (we provide
+ * at least 1 implied source in the DMA_PREP_CONTINUE case)
+ */
+ BUG_ON(src_cnt + dmaf_continue(flags) < 2);
+
+ num_descs = ioat2_xferlen_to_descs(ioat, len);
+ /* we need 2x the number of descriptors to cover greater than 3
+ * sources
+ */
+ if (src_cnt > 3 || flags & DMA_PREP_CONTINUE) {
+ with_ext = 1;
+ num_descs *= 2;
+ } else
+ with_ext = 0;
+
+ /* completion writes from the raid engine may pass completion
+ * writes from the legacy engine, so we need one extra null
+ * (legacy) descriptor to ensure all completion writes arrive in
+ * order.
+ */
+ if (likely(num_descs) &&
+ ioat2_alloc_and_lock(&idx, ioat, num_descs+1) == 0)
+ /* pass */;
+ else
+ return NULL;
+ i = 0;
+ do {
+ struct ioat_raw_descriptor *descs[2];
+ size_t xfer_size = min_t(size_t, len, 1 << ioat->xfercap_log);
+
+ desc = ioat2_get_ring_ent(ioat, idx + i);
+ pq = desc->pq;
+
+ /* save a branch by unconditionally retrieving the
+ * extended descriptor pq_set_src() knows to not write
+ * to it in the single descriptor case
+ */
+ ext = ioat2_get_ring_ent(ioat, idx + i + with_ext);
+ pq_ex = ext->pq_ex;
+
+ descs[0] = (struct ioat_raw_descriptor *) pq;
+ descs[1] = (struct ioat_raw_descriptor *) pq_ex;
+
+ for (s = 0; s < src_cnt; s++)
+ pq_set_src(descs, src[s], offset, scf[s], s);
+
+ /* see the comment for dma_maxpq in include/linux/dmaengine.h */
+ if (dmaf_p_disabled_continue(flags))
+ pq_set_src(descs, dst[1], offset, 1, s++);
+ else if (dmaf_continue(flags)) {
+ pq_set_src(descs, dst[0], offset, 0, s++);
+ pq_set_src(descs, dst[1], offset, 1, s++);
+ pq_set_src(descs, dst[1], offset, 0, s++);
+ }
+ pq->size = xfer_size;
+ pq->p_addr = dst[0] + offset;
+ pq->q_addr = dst[1] + offset;
+ pq->ctl = 0;
+ pq->ctl_f.op = op;
+ pq->ctl_f.src_cnt = src_cnt_to_hw(s);
+ pq->ctl_f.p_disable = !!(flags & DMA_PREP_PQ_DISABLE_P);
+ pq->ctl_f.q_disable = !!(flags & DMA_PREP_PQ_DISABLE_Q);
+
+ len -= xfer_size;
+ offset += xfer_size;
+ } while ((i += 1 + with_ext) < num_descs);
+
+ /* last pq descriptor carries the unmap parameters and fence bit */
+ desc->txd.flags = flags;
+ desc->len = total_len;
+ if (result)
+ desc->result = result;
+ pq->ctl_f.fence = !!(flags & DMA_PREP_FENCE);
+ dump_pq_desc_dbg(ioat, desc, ext);
+
+ /* completion descriptor carries interrupt bit */
+ compl_desc = ioat2_get_ring_ent(ioat, idx + i);
+ compl_desc->txd.flags = flags & DMA_PREP_INTERRUPT;
+ hw = compl_desc->hw;
+ hw->ctl = 0;
+ hw->ctl_f.null = 1;
+ hw->ctl_f.int_en = !!(flags & DMA_PREP_INTERRUPT);
+ hw->ctl_f.compl_write = 1;
+ hw->size = NULL_DESC_BUFFER_SIZE;
+ dump_desc_dbg(ioat, compl_desc);
+
+ /* we leave the channel locked to ensure in order submission */
+ return &compl_desc->txd;
+}
+
+static struct dma_async_tx_descriptor *
+ioat3_prep_pq(struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src,
+ unsigned int src_cnt, const unsigned char *scf, size_t len,
+ unsigned long flags)
+{
+ /* specify valid address for disabled result */
+ if (flags & DMA_PREP_PQ_DISABLE_P)
+ dst[0] = dst[1];
+ if (flags & DMA_PREP_PQ_DISABLE_Q)
+ dst[1] = dst[0];
+
+ /* handle the single source multiply case from the raid6
+ * recovery path
+ */
+ if ((flags & DMA_PREP_PQ_DISABLE_P) && src_cnt == 1) {
+ dma_addr_t single_source[2];
+ unsigned char single_source_coef[2];
+
+ BUG_ON(flags & DMA_PREP_PQ_DISABLE_Q);
+ single_source[0] = src[0];
+ single_source[1] = src[0];
+ single_source_coef[0] = scf[0];
+ single_source_coef[1] = 0;
+
+ return __ioat3_prep_pq_lock(chan, NULL, dst, single_source, 2,
+ single_source_coef, len, flags);
+ } else
+ return __ioat3_prep_pq_lock(chan, NULL, dst, src, src_cnt, scf,
+ len, flags);
+}
+
+struct dma_async_tx_descriptor *
+ioat3_prep_pq_val(struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src,
+ unsigned int src_cnt, const unsigned char *scf, size_t len,
+ enum sum_check_flags *pqres, unsigned long flags)
+{
+ /* specify valid address for disabled result */
+ if (flags & DMA_PREP_PQ_DISABLE_P)
+ pq[0] = pq[1];
+ if (flags & DMA_PREP_PQ_DISABLE_Q)
+ pq[1] = pq[0];
+
+ /* the cleanup routine only sets bits on validate failure, it
+ * does not clear bits on validate success... so clear it here
+ */
+ *pqres = 0;
+
+ return __ioat3_prep_pq_lock(chan, pqres, pq, src, src_cnt, scf, len,
+ flags);
+}
+
+static struct dma_async_tx_descriptor *
+ioat3_prep_pqxor(struct dma_chan *chan, dma_addr_t dst, dma_addr_t *src,
+ unsigned int src_cnt, size_t len, unsigned long flags)
+{
+ unsigned char scf[src_cnt];
+ dma_addr_t pq[2];
+
+ memset(scf, 0, src_cnt);
+ pq[0] = dst;
+ flags |= DMA_PREP_PQ_DISABLE_Q;
+ pq[1] = dst; /* specify valid address for disabled result */
+
+ return __ioat3_prep_pq_lock(chan, NULL, pq, src, src_cnt, scf, len,
+ flags);
+}
+
+struct dma_async_tx_descriptor *
+ioat3_prep_pqxor_val(struct dma_chan *chan, dma_addr_t *src,
+ unsigned int src_cnt, size_t len,
+ enum sum_check_flags *result, unsigned long flags)
+{
+ unsigned char scf[src_cnt];
+ dma_addr_t pq[2];
+
+ /* the cleanup routine only sets bits on validate failure, it
+ * does not clear bits on validate success... so clear it here
+ */
+ *result = 0;
+
+ memset(scf, 0, src_cnt);
+ pq[0] = src[0];
+ flags |= DMA_PREP_PQ_DISABLE_Q;
+ pq[1] = pq[0]; /* specify valid address for disabled result */
+
+ return __ioat3_prep_pq_lock(chan, result, pq, &src[1], src_cnt - 1, scf,
+ len, flags);
+}
+
+static struct dma_async_tx_descriptor *
+ioat3_prep_interrupt_lock(struct dma_chan *c, unsigned long flags)
+{
+ struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
+ struct ioat_ring_ent *desc;
+ struct ioat_dma_descriptor *hw;
+ u16 idx;
+
+ if (ioat2_alloc_and_lock(&idx, ioat, 1) == 0)
+ desc = ioat2_get_ring_ent(ioat, idx);
+ else
+ return NULL;
+
+ hw = desc->hw;
+ hw->ctl = 0;
+ hw->ctl_f.null = 1;
+ hw->ctl_f.int_en = 1;
+ hw->ctl_f.fence = !!(flags & DMA_PREP_FENCE);
+ hw->ctl_f.compl_write = 1;
+ hw->size = NULL_DESC_BUFFER_SIZE;
+ hw->src_addr = 0;
+ hw->dst_addr = 0;
+
+ desc->txd.flags = flags;
+ desc->len = 1;
+
+ dump_desc_dbg(ioat, desc);
+
+ /* we leave the channel locked to ensure in order submission */
+ return &desc->txd;
+}
+
+static void __devinit ioat3_dma_test_callback(void *dma_async_param)
+{
+ struct completion *cmp = dma_async_param;
+
+ complete(cmp);
+}
+
+#define IOAT_NUM_SRC_TEST 6 /* must be <= 8 */
+static int __devinit ioat_xor_val_self_test(struct ioatdma_device *device)
+{
+ int i, src_idx;
+ struct page *dest;
+ struct page *xor_srcs[IOAT_NUM_SRC_TEST];
+ struct page *xor_val_srcs[IOAT_NUM_SRC_TEST + 1];
+ dma_addr_t dma_srcs[IOAT_NUM_SRC_TEST + 1];
+ dma_addr_t dma_addr, dest_dma;
+ struct dma_async_tx_descriptor *tx;
+ struct dma_chan *dma_chan;
+ dma_cookie_t cookie;
+ u8 cmp_byte = 0;
+ u32 cmp_word;
+ u32 xor_val_result;
+ int err = 0;
+ struct completion cmp;
+ unsigned long tmo;
+ struct device *dev = &device->pdev->dev;
+ struct dma_device *dma = &device->common;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ if (!dma_has_cap(DMA_XOR, dma->cap_mask))
+ return 0;
+
+ for (src_idx = 0; src_idx < IOAT_NUM_SRC_TEST; src_idx++) {
+ xor_srcs[src_idx] = alloc_page(GFP_KERNEL);
+ if (!xor_srcs[src_idx]) {
+ while (src_idx--)
+ __free_page(xor_srcs[src_idx]);
+ return -ENOMEM;
+ }
+ }
+
+ dest = alloc_page(GFP_KERNEL);
+ if (!dest) {
+ while (src_idx--)
+ __free_page(xor_srcs[src_idx]);
+ return -ENOMEM;
+ }
+
+ /* Fill in src buffers */
+ for (src_idx = 0; src_idx < IOAT_NUM_SRC_TEST; src_idx++) {
+ u8 *ptr = page_address(xor_srcs[src_idx]);
+ for (i = 0; i < PAGE_SIZE; i++)
+ ptr[i] = (1 << src_idx);
+ }
+
+ for (src_idx = 0; src_idx < IOAT_NUM_SRC_TEST; src_idx++)
+ cmp_byte ^= (u8) (1 << src_idx);
+
+ cmp_word = (cmp_byte << 24) | (cmp_byte << 16) |
+ (cmp_byte << 8) | cmp_byte;
+
+ memset(page_address(dest), 0, PAGE_SIZE);
+
+ dma_chan = container_of(dma->channels.next, struct dma_chan,
+ device_node);
+ if (dma->device_alloc_chan_resources(dma_chan) < 1) {
+ err = -ENODEV;
+ goto out;
+ }
+
+ /* test xor */
+ dest_dma = dma_map_page(dev, dest, 0, PAGE_SIZE, DMA_FROM_DEVICE);
+ for (i = 0; i < IOAT_NUM_SRC_TEST; i++)
+ dma_srcs[i] = dma_map_page(dev, xor_srcs[i], 0, PAGE_SIZE,
+ DMA_TO_DEVICE);
+ tx = dma->device_prep_dma_xor(dma_chan, dest_dma, dma_srcs,
+ IOAT_NUM_SRC_TEST, PAGE_SIZE,
+ DMA_PREP_INTERRUPT);
+
+ if (!tx) {
+ dev_err(dev, "Self-test xor prep failed\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ async_tx_ack(tx);
+ init_completion(&cmp);
+ tx->callback = ioat3_dma_test_callback;
+ tx->callback_param = &cmp;
+ cookie = tx->tx_submit(tx);
+ if (cookie < 0) {
+ dev_err(dev, "Self-test xor setup failed\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+ dma->device_issue_pending(dma_chan);
+
+ tmo = wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000));
+
+ if (dma->device_is_tx_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) {
+ dev_err(dev, "Self-test xor timed out\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ dma_sync_single_for_cpu(dev, dest_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+ for (i = 0; i < (PAGE_SIZE / sizeof(u32)); i++) {
+ u32 *ptr = page_address(dest);
+ if (ptr[i] != cmp_word) {
+ dev_err(dev, "Self-test xor failed compare\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+ }
+ dma_sync_single_for_device(dev, dest_dma, PAGE_SIZE, DMA_TO_DEVICE);
+
+ /* skip validate if the capability is not present */
+ if (!dma_has_cap(DMA_XOR_VAL, dma_chan->device->cap_mask))
+ goto free_resources;
+
+ /* validate the sources with the destintation page */
+ for (i = 0; i < IOAT_NUM_SRC_TEST; i++)
+ xor_val_srcs[i] = xor_srcs[i];
+ xor_val_srcs[i] = dest;
+
+ xor_val_result = 1;
+
+ for (i = 0; i < IOAT_NUM_SRC_TEST + 1; i++)
+ dma_srcs[i] = dma_map_page(dev, xor_val_srcs[i], 0, PAGE_SIZE,
+ DMA_TO_DEVICE);
+ tx = dma->device_prep_dma_xor_val(dma_chan, dma_srcs,
+ IOAT_NUM_SRC_TEST + 1, PAGE_SIZE,
+ &xor_val_result, DMA_PREP_INTERRUPT);
+ if (!tx) {
+ dev_err(dev, "Self-test zero prep failed\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ async_tx_ack(tx);
+ init_completion(&cmp);
+ tx->callback = ioat3_dma_test_callback;
+ tx->callback_param = &cmp;
+ cookie = tx->tx_submit(tx);
+ if (cookie < 0) {
+ dev_err(dev, "Self-test zero setup failed\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+ dma->device_issue_pending(dma_chan);
+
+ tmo = wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000));
+
+ if (dma->device_is_tx_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) {
+ dev_err(dev, "Self-test validate timed out\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ if (xor_val_result != 0) {
+ dev_err(dev, "Self-test validate failed compare\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ /* skip memset if the capability is not present */
+ if (!dma_has_cap(DMA_MEMSET, dma_chan->device->cap_mask))
+ goto free_resources;
+
+ /* test memset */
+ dma_addr = dma_map_page(dev, dest, 0,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ tx = dma->device_prep_dma_memset(dma_chan, dma_addr, 0, PAGE_SIZE,
+ DMA_PREP_INTERRUPT);
+ if (!tx) {
+ dev_err(dev, "Self-test memset prep failed\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ async_tx_ack(tx);
+ init_completion(&cmp);
+ tx->callback = ioat3_dma_test_callback;
+ tx->callback_param = &cmp;
+ cookie = tx->tx_submit(tx);
+ if (cookie < 0) {
+ dev_err(dev, "Self-test memset setup failed\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+ dma->device_issue_pending(dma_chan);
+
+ tmo = wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000));
+
+ if (dma->device_is_tx_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) {
+ dev_err(dev, "Self-test memset timed out\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ for (i = 0; i < PAGE_SIZE/sizeof(u32); i++) {
+ u32 *ptr = page_address(dest);
+ if (ptr[i]) {
+ dev_err(dev, "Self-test memset failed compare\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+ }
+
+ /* test for non-zero parity sum */
+ xor_val_result = 0;
+ for (i = 0; i < IOAT_NUM_SRC_TEST + 1; i++)
+ dma_srcs[i] = dma_map_page(dev, xor_val_srcs[i], 0, PAGE_SIZE,
+ DMA_TO_DEVICE);
+ tx = dma->device_prep_dma_xor_val(dma_chan, dma_srcs,
+ IOAT_NUM_SRC_TEST + 1, PAGE_SIZE,
+ &xor_val_result, DMA_PREP_INTERRUPT);
+ if (!tx) {
+ dev_err(dev, "Self-test 2nd zero prep failed\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ async_tx_ack(tx);
+ init_completion(&cmp);
+ tx->callback = ioat3_dma_test_callback;
+ tx->callback_param = &cmp;
+ cookie = tx->tx_submit(tx);
+ if (cookie < 0) {
+ dev_err(dev, "Self-test 2nd zero setup failed\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+ dma->device_issue_pending(dma_chan);
+
+ tmo = wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000));
+
+ if (dma->device_is_tx_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) {
+ dev_err(dev, "Self-test 2nd validate timed out\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ if (xor_val_result != SUM_CHECK_P_RESULT) {
+ dev_err(dev, "Self-test validate failed compare\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+free_resources:
+ dma->device_free_chan_resources(dma_chan);
+out:
+ src_idx = IOAT_NUM_SRC_TEST;
+ while (src_idx--)
+ __free_page(xor_srcs[src_idx]);
+ __free_page(dest);
+ return err;
+}
+
+static int __devinit ioat3_dma_self_test(struct ioatdma_device *device)
+{
+ int rc = ioat_dma_self_test(device);
+
+ if (rc)
+ return rc;
+
+ rc = ioat_xor_val_self_test(device);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca)
+{
+ struct pci_dev *pdev = device->pdev;
+ int dca_en = system_has_dca_enabled(pdev);
+ struct dma_device *dma;
+ struct dma_chan *c;
+ struct ioat_chan_common *chan;
+ bool is_raid_device = false;
+ int err;
+ u16 dev_id;
+ u32 cap;
+
+ device->enumerate_channels = ioat2_enumerate_channels;
+ device->self_test = ioat3_dma_self_test;
+ dma = &device->common;
+ dma->device_prep_dma_memcpy = ioat2_dma_prep_memcpy_lock;
+ dma->device_issue_pending = ioat2_issue_pending;
+ dma->device_alloc_chan_resources = ioat2_alloc_chan_resources;
+ dma->device_free_chan_resources = ioat2_free_chan_resources;
+
+ dma_cap_set(DMA_INTERRUPT, dma->cap_mask);
+ dma->device_prep_dma_interrupt = ioat3_prep_interrupt_lock;
+
+ cap = readl(device->reg_base + IOAT_DMA_CAP_OFFSET);
+
+ /* dca is incompatible with raid operations */
+ if (dca_en && (cap & (IOAT_CAP_XOR|IOAT_CAP_PQ)))
+ cap &= ~(IOAT_CAP_XOR|IOAT_CAP_PQ);
+
+ if (cap & IOAT_CAP_XOR) {
+ is_raid_device = true;
+ dma->max_xor = 8;
+ dma->xor_align = 2;
+
+ dma_cap_set(DMA_XOR, dma->cap_mask);
+ dma->device_prep_dma_xor = ioat3_prep_xor;
+
+ dma_cap_set(DMA_XOR_VAL, dma->cap_mask);
+ dma->device_prep_dma_xor_val = ioat3_prep_xor_val;
+ }
+ if (cap & IOAT_CAP_PQ) {
+ is_raid_device = true;
+ dma_set_maxpq(dma, 8, 0);
+ dma->pq_align = 2;
+
+ dma_cap_set(DMA_PQ, dma->cap_mask);
+ dma->device_prep_dma_pq = ioat3_prep_pq;
+
+ dma_cap_set(DMA_PQ_VAL, dma->cap_mask);
+ dma->device_prep_dma_pq_val = ioat3_prep_pq_val;
+
+ if (!(cap & IOAT_CAP_XOR)) {
+ dma->max_xor = 8;
+ dma->xor_align = 2;
+
+ dma_cap_set(DMA_XOR, dma->cap_mask);
+ dma->device_prep_dma_xor = ioat3_prep_pqxor;
+
+ dma_cap_set(DMA_XOR_VAL, dma->cap_mask);
+ dma->device_prep_dma_xor_val = ioat3_prep_pqxor_val;
+ }
+ }
+ if (is_raid_device && (cap & IOAT_CAP_FILL_BLOCK)) {
+ dma_cap_set(DMA_MEMSET, dma->cap_mask);
+ dma->device_prep_dma_memset = ioat3_prep_memset_lock;
+ }
+
+
+ if (is_raid_device) {
+ dma->device_is_tx_complete = ioat3_is_complete;
+ device->cleanup_tasklet = ioat3_cleanup_tasklet;
+ device->timer_fn = ioat3_timer_event;
+ } else {
+ dma->device_is_tx_complete = ioat2_is_complete;
+ device->cleanup_tasklet = ioat2_cleanup_tasklet;
+ device->timer_fn = ioat2_timer_event;
+ }
+
+ #ifdef CONFIG_ASYNC_TX_DISABLE_PQ_VAL_DMA
+ dma_cap_clear(DMA_PQ_VAL, dma->cap_mask);
+ dma->device_prep_dma_pq_val = NULL;
+ #endif
+
+ #ifdef CONFIG_ASYNC_TX_DISABLE_XOR_VAL_DMA
+ dma_cap_clear(DMA_XOR_VAL, dma->cap_mask);
+ dma->device_prep_dma_xor_val = NULL;
+ #endif
+
+ /* -= IOAT ver.3 workarounds =- */
+ /* Write CHANERRMSK_INT with 3E07h to mask out the errors
+ * that can cause stability issues for IOAT ver.3
+ */
+ pci_write_config_dword(pdev, IOAT_PCI_CHANERRMASK_INT_OFFSET, 0x3e07);
+
+ /* Clear DMAUNCERRSTS Cfg-Reg Parity Error status bit
+ * (workaround for spurious config parity error after restart)
+ */
+ pci_read_config_word(pdev, IOAT_PCI_DEVICE_ID_OFFSET, &dev_id);
+ if (dev_id == PCI_DEVICE_ID_INTEL_IOAT_TBG0)
+ pci_write_config_dword(pdev, IOAT_PCI_DMAUNCERRSTS_OFFSET, 0x10);
+
+ err = ioat_probe(device);
+ if (err)
+ return err;
+ ioat_set_tcp_copy_break(262144);
+
+ list_for_each_entry(c, &dma->channels, device_node) {
+ chan = to_chan_common(c);
+ writel(IOAT_DMA_DCA_ANY_CPU,
+ chan->reg_base + IOAT_DCACTRL_OFFSET);
+ }
+
+ err = ioat_register(device);
+ if (err)
+ return err;
+
+ ioat_kobject_add(device, &ioat2_ktype);
+
+ if (dca)
+ device->dca = ioat3_dca_init(pdev, device->reg_base);
+
+ return 0;
+}
diff --git a/drivers/dma/ioat/hw.h b/drivers/dma/ioat/hw.h
new file mode 100644
index 000000000000..60e675455b6a
--- /dev/null
+++ b/drivers/dma/ioat/hw.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright(c) 2004 - 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+#ifndef _IOAT_HW_H_
+#define _IOAT_HW_H_
+
+/* PCI Configuration Space Values */
+#define IOAT_PCI_VID 0x8086
+#define IOAT_MMIO_BAR 0
+
+/* CB device ID's */
+#define IOAT_PCI_DID_5000 0x1A38
+#define IOAT_PCI_DID_CNB 0x360B
+#define IOAT_PCI_DID_SCNB 0x65FF
+#define IOAT_PCI_DID_SNB 0x402F
+
+#define IOAT_PCI_RID 0x00
+#define IOAT_PCI_SVID 0x8086
+#define IOAT_PCI_SID 0x8086
+#define IOAT_VER_1_2 0x12 /* Version 1.2 */
+#define IOAT_VER_2_0 0x20 /* Version 2.0 */
+#define IOAT_VER_3_0 0x30 /* Version 3.0 */
+#define IOAT_VER_3_2 0x32 /* Version 3.2 */
+
+int system_has_dca_enabled(struct pci_dev *pdev);
+
+struct ioat_dma_descriptor {
+ uint32_t size;
+ union {
+ uint32_t ctl;
+ struct {
+ unsigned int int_en:1;
+ unsigned int src_snoop_dis:1;
+ unsigned int dest_snoop_dis:1;
+ unsigned int compl_write:1;
+ unsigned int fence:1;
+ unsigned int null:1;
+ unsigned int src_brk:1;
+ unsigned int dest_brk:1;
+ unsigned int bundle:1;
+ unsigned int dest_dca:1;
+ unsigned int hint:1;
+ unsigned int rsvd2:13;
+ #define IOAT_OP_COPY 0x00
+ unsigned int op:8;
+ } ctl_f;
+ };
+ uint64_t src_addr;
+ uint64_t dst_addr;
+ uint64_t next;
+ uint64_t rsv1;
+ uint64_t rsv2;
+ /* store some driver data in an unused portion of the descriptor */
+ union {
+ uint64_t user1;
+ uint64_t tx_cnt;
+ };
+ uint64_t user2;
+};
+
+struct ioat_fill_descriptor {
+ uint32_t size;
+ union {
+ uint32_t ctl;
+ struct {
+ unsigned int int_en:1;
+ unsigned int rsvd:1;
+ unsigned int dest_snoop_dis:1;
+ unsigned int compl_write:1;
+ unsigned int fence:1;
+ unsigned int rsvd2:2;
+ unsigned int dest_brk:1;
+ unsigned int bundle:1;
+ unsigned int rsvd4:15;
+ #define IOAT_OP_FILL 0x01
+ unsigned int op:8;
+ } ctl_f;
+ };
+ uint64_t src_data;
+ uint64_t dst_addr;
+ uint64_t next;
+ uint64_t rsv1;
+ uint64_t next_dst_addr;
+ uint64_t user1;
+ uint64_t user2;
+};
+
+struct ioat_xor_descriptor {
+ uint32_t size;
+ union {
+ uint32_t ctl;
+ struct {
+ unsigned int int_en:1;
+ unsigned int src_snoop_dis:1;
+ unsigned int dest_snoop_dis:1;
+ unsigned int compl_write:1;
+ unsigned int fence:1;
+ unsigned int src_cnt:3;
+ unsigned int bundle:1;
+ unsigned int dest_dca:1;
+ unsigned int hint:1;
+ unsigned int rsvd:13;
+ #define IOAT_OP_XOR 0x87
+ #define IOAT_OP_XOR_VAL 0x88
+ unsigned int op:8;
+ } ctl_f;
+ };
+ uint64_t src_addr;
+ uint64_t dst_addr;
+ uint64_t next;
+ uint64_t src_addr2;
+ uint64_t src_addr3;
+ uint64_t src_addr4;
+ uint64_t src_addr5;
+};
+
+struct ioat_xor_ext_descriptor {
+ uint64_t src_addr6;
+ uint64_t src_addr7;
+ uint64_t src_addr8;
+ uint64_t next;
+ uint64_t rsvd[4];
+};
+
+struct ioat_pq_descriptor {
+ uint32_t size;
+ union {
+ uint32_t ctl;
+ struct {
+ unsigned int int_en:1;
+ unsigned int src_snoop_dis:1;
+ unsigned int dest_snoop_dis:1;
+ unsigned int compl_write:1;
+ unsigned int fence:1;
+ unsigned int src_cnt:3;
+ unsigned int bundle:1;
+ unsigned int dest_dca:1;
+ unsigned int hint:1;
+ unsigned int p_disable:1;
+ unsigned int q_disable:1;
+ unsigned int rsvd:11;
+ #define IOAT_OP_PQ 0x89
+ #define IOAT_OP_PQ_VAL 0x8a
+ unsigned int op:8;
+ } ctl_f;
+ };
+ uint64_t src_addr;
+ uint64_t p_addr;
+ uint64_t next;
+ uint64_t src_addr2;
+ uint64_t src_addr3;
+ uint8_t coef[8];
+ uint64_t q_addr;
+};
+
+struct ioat_pq_ext_descriptor {
+ uint64_t src_addr4;
+ uint64_t src_addr5;
+ uint64_t src_addr6;
+ uint64_t next;
+ uint64_t src_addr7;
+ uint64_t src_addr8;
+ uint64_t rsvd[2];
+};
+
+struct ioat_pq_update_descriptor {
+ uint32_t size;
+ union {
+ uint32_t ctl;
+ struct {
+ unsigned int int_en:1;
+ unsigned int src_snoop_dis:1;
+ unsigned int dest_snoop_dis:1;
+ unsigned int compl_write:1;
+ unsigned int fence:1;
+ unsigned int src_cnt:3;
+ unsigned int bundle:1;
+ unsigned int dest_dca:1;
+ unsigned int hint:1;
+ unsigned int p_disable:1;
+ unsigned int q_disable:1;
+ unsigned int rsvd:3;
+ unsigned int coef:8;
+ #define IOAT_OP_PQ_UP 0x8b
+ unsigned int op:8;
+ } ctl_f;
+ };
+ uint64_t src_addr;
+ uint64_t p_addr;
+ uint64_t next;
+ uint64_t src_addr2;
+ uint64_t p_src;
+ uint64_t q_src;
+ uint64_t q_addr;
+};
+
+struct ioat_raw_descriptor {
+ uint64_t field[8];
+};
+#endif
diff --git a/drivers/dma/ioat/pci.c b/drivers/dma/ioat/pci.c
new file mode 100644
index 000000000000..d545fae30f37
--- /dev/null
+++ b/drivers/dma/ioat/pci.c
@@ -0,0 +1,210 @@
+/*
+ * Intel I/OAT DMA Linux driver
+ * Copyright(c) 2007 - 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 "COPYING".
+ *
+ */
+
+/*
+ * This driver supports an Intel I/OAT DMA engine, which does asynchronous
+ * copy operations.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/dca.h>
+#include "dma.h"
+#include "dma_v2.h"
+#include "registers.h"
+#include "hw.h"
+
+MODULE_VERSION(IOAT_DMA_VERSION);
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel Corporation");
+
+static struct pci_device_id ioat_pci_tbl[] = {
+ /* I/OAT v1 platforms */
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_CNB) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SCNB) },
+ { PCI_VDEVICE(UNISYS, PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR) },
+
+ /* I/OAT v2 platforms */
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB) },
+
+ /* I/OAT v3 platforms */
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG0) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG1) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG2) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG3) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG4) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG5) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG6) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG7) },
+
+ /* I/OAT v3.2 platforms */
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF0) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF1) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF2) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF3) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF4) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF5) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF6) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF7) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF8) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF9) },
+
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, ioat_pci_tbl);
+
+static int __devinit ioat_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id);
+static void __devexit ioat_remove(struct pci_dev *pdev);
+
+static int ioat_dca_enabled = 1;
+module_param(ioat_dca_enabled, int, 0644);
+MODULE_PARM_DESC(ioat_dca_enabled, "control support of dca service (default: 1)");
+
+struct kmem_cache *ioat2_cache;
+
+#define DRV_NAME "ioatdma"
+
+static struct pci_driver ioat_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = ioat_pci_tbl,
+ .probe = ioat_pci_probe,
+ .remove = __devexit_p(ioat_remove),
+};
+
+static struct ioatdma_device *
+alloc_ioatdma(struct pci_dev *pdev, void __iomem *iobase)
+{
+ struct device *dev = &pdev->dev;
+ struct ioatdma_device *d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
+
+ if (!d)
+ return NULL;
+ d->pdev = pdev;
+ d->reg_base = iobase;
+ return d;
+}
+
+static int __devinit ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ void __iomem * const *iomap;
+ struct device *dev = &pdev->dev;
+ struct ioatdma_device *device;
+ int err;
+
+ err = pcim_enable_device(pdev);
+ if (err)
+ return err;
+
+ err = pcim_iomap_regions(pdev, 1 << IOAT_MMIO_BAR, DRV_NAME);
+ if (err)
+ return err;
+ iomap = pcim_iomap_table(pdev);
+ if (!iomap)
+ return -ENOMEM;
+
+ 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;
+
+ device = devm_kzalloc(dev, sizeof(*device), GFP_KERNEL);
+ if (!device)
+ return -ENOMEM;
+
+ pci_set_master(pdev);
+
+ device = alloc_ioatdma(pdev, iomap[IOAT_MMIO_BAR]);
+ if (!device)
+ return -ENOMEM;
+ pci_set_drvdata(pdev, device);
+
+ device->version = readb(device->reg_base + IOAT_VER_OFFSET);
+ if (device->version == IOAT_VER_1_2)
+ err = ioat1_dma_probe(device, ioat_dca_enabled);
+ else if (device->version == IOAT_VER_2_0)
+ err = ioat2_dma_probe(device, ioat_dca_enabled);
+ else if (device->version >= IOAT_VER_3_0)
+ err = ioat3_dma_probe(device, ioat_dca_enabled);
+ else
+ return -ENODEV;
+
+ if (err) {
+ dev_err(dev, "Intel(R) I/OAT DMA Engine init failed\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __devexit ioat_remove(struct pci_dev *pdev)
+{
+ struct ioatdma_device *device = pci_get_drvdata(pdev);
+
+ if (!device)
+ return;
+
+ dev_err(&pdev->dev, "Removing dma and dca services\n");
+ if (device->dca) {
+ unregister_dca_provider(device->dca, &pdev->dev);
+ free_dca_provider(device->dca);
+ device->dca = NULL;
+ }
+ ioat_dma_remove(device);
+}
+
+static int __init ioat_init_module(void)
+{
+ int err;
+
+ pr_info("%s: Intel(R) QuickData Technology Driver %s\n",
+ DRV_NAME, IOAT_DMA_VERSION);
+
+ ioat2_cache = kmem_cache_create("ioat2", sizeof(struct ioat_ring_ent),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!ioat2_cache)
+ return -ENOMEM;
+
+ err = pci_register_driver(&ioat_pci_driver);
+ if (err)
+ kmem_cache_destroy(ioat2_cache);
+
+ return err;
+}
+module_init(ioat_init_module);
+
+static void __exit ioat_exit_module(void)
+{
+ pci_unregister_driver(&ioat_pci_driver);
+ kmem_cache_destroy(ioat2_cache);
+}
+module_exit(ioat_exit_module);
diff --git a/drivers/dma/ioatdma_registers.h b/drivers/dma/ioat/registers.h
index 49bc277424f8..f015ec196700 100644
--- a/drivers/dma/ioatdma_registers.h
+++ b/drivers/dma/ioat/registers.h
@@ -64,18 +64,35 @@
#define IOAT_DEVICE_STATUS_OFFSET 0x0E /* 16-bit */
#define IOAT_DEVICE_STATUS_DEGRADED_MODE 0x0001
+#define IOAT_DEVICE_MMIO_RESTRICTED 0x0002
+#define IOAT_DEVICE_MEMORY_BYPASS 0x0004
+#define IOAT_DEVICE_ADDRESS_REMAPPING 0x0008
+
+#define IOAT_DMA_CAP_OFFSET 0x10 /* 32-bit */
+#define IOAT_CAP_PAGE_BREAK 0x00000001
+#define IOAT_CAP_CRC 0x00000002
+#define IOAT_CAP_SKIP_MARKER 0x00000004
+#define IOAT_CAP_DCA 0x00000010
+#define IOAT_CAP_CRC_MOVE 0x00000020
+#define IOAT_CAP_FILL_BLOCK 0x00000040
+#define IOAT_CAP_APIC 0x00000080
+#define IOAT_CAP_XOR 0x00000100
+#define IOAT_CAP_PQ 0x00000200
#define IOAT_CHANNEL_MMIO_SIZE 0x80 /* Each Channel MMIO space is this size */
/* DMA Channel Registers */
#define IOAT_CHANCTRL_OFFSET 0x00 /* 16-bit Channel Control Register */
#define IOAT_CHANCTRL_CHANNEL_PRIORITY_MASK 0xF000
+#define IOAT3_CHANCTRL_COMPL_DCA_EN 0x0200
#define IOAT_CHANCTRL_CHANNEL_IN_USE 0x0100
#define IOAT_CHANCTRL_DESCRIPTOR_ADDR_SNOOP_CONTROL 0x0020
#define IOAT_CHANCTRL_ERR_INT_EN 0x0010
#define IOAT_CHANCTRL_ANY_ERR_ABORT_EN 0x0008
#define IOAT_CHANCTRL_ERR_COMPLETION_EN 0x0004
-#define IOAT_CHANCTRL_INT_DISABLE 0x0001
+#define IOAT_CHANCTRL_INT_REARM 0x0001
+#define IOAT_CHANCTRL_RUN (IOAT_CHANCTRL_INT_REARM |\
+ IOAT_CHANCTRL_ANY_ERR_ABORT_EN)
#define IOAT_DMA_COMP_OFFSET 0x02 /* 16-bit DMA channel compatibility */
#define IOAT_DMA_COMP_V1 0x0001 /* Compatibility with DMA version 1 */
@@ -94,14 +111,14 @@
#define IOAT2_CHANSTS_OFFSET_HIGH 0x0C
#define IOAT_CHANSTS_OFFSET_HIGH(ver) ((ver) < IOAT_VER_2_0 \
? IOAT1_CHANSTS_OFFSET_HIGH : IOAT2_CHANSTS_OFFSET_HIGH)
-#define IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR ~0x3F
-#define IOAT_CHANSTS_SOFT_ERR 0x0000000000000010
-#define IOAT_CHANSTS_UNAFFILIATED_ERR 0x0000000000000008
-#define IOAT_CHANSTS_DMA_TRANSFER_STATUS 0x0000000000000007
-#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_ACTIVE 0x0
-#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_DONE 0x1
-#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_SUSPENDED 0x2
-#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_HALTED 0x3
+#define IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR (~0x3fULL)
+#define IOAT_CHANSTS_SOFT_ERR 0x10ULL
+#define IOAT_CHANSTS_UNAFFILIATED_ERR 0x8ULL
+#define IOAT_CHANSTS_STATUS 0x7ULL
+#define IOAT_CHANSTS_ACTIVE 0x0
+#define IOAT_CHANSTS_DONE 0x1
+#define IOAT_CHANSTS_SUSPENDED 0x2
+#define IOAT_CHANSTS_HALTED 0x3
@@ -204,22 +221,27 @@
#define IOAT_CDAR_OFFSET_HIGH 0x24
#define IOAT_CHANERR_OFFSET 0x28 /* 32-bit Channel Error Register */
-#define IOAT_CHANERR_DMA_TRANSFER_SRC_ADDR_ERR 0x0001
-#define IOAT_CHANERR_DMA_TRANSFER_DEST_ADDR_ERR 0x0002
-#define IOAT_CHANERR_NEXT_DESCRIPTOR_ADDR_ERR 0x0004
-#define IOAT_CHANERR_NEXT_DESCRIPTOR_ALIGNMENT_ERR 0x0008
+#define IOAT_CHANERR_SRC_ADDR_ERR 0x0001
+#define IOAT_CHANERR_DEST_ADDR_ERR 0x0002
+#define IOAT_CHANERR_NEXT_ADDR_ERR 0x0004
+#define IOAT_CHANERR_NEXT_DESC_ALIGN_ERR 0x0008
#define IOAT_CHANERR_CHAIN_ADDR_VALUE_ERR 0x0010
#define IOAT_CHANERR_CHANCMD_ERR 0x0020
#define IOAT_CHANERR_CHIPSET_UNCORRECTABLE_DATA_INTEGRITY_ERR 0x0040
#define IOAT_CHANERR_DMA_UNCORRECTABLE_DATA_INTEGRITY_ERR 0x0080
#define IOAT_CHANERR_READ_DATA_ERR 0x0100
#define IOAT_CHANERR_WRITE_DATA_ERR 0x0200
-#define IOAT_CHANERR_DESCRIPTOR_CONTROL_ERR 0x0400
-#define IOAT_CHANERR_DESCRIPTOR_LENGTH_ERR 0x0800
+#define IOAT_CHANERR_CONTROL_ERR 0x0400
+#define IOAT_CHANERR_LENGTH_ERR 0x0800
#define IOAT_CHANERR_COMPLETION_ADDR_ERR 0x1000
#define IOAT_CHANERR_INT_CONFIGURATION_ERR 0x2000
#define IOAT_CHANERR_SOFT_ERR 0x4000
#define IOAT_CHANERR_UNAFFILIATED_ERR 0x8000
+#define IOAT_CHANERR_XOR_P_OR_CRC_ERR 0x10000
+#define IOAT_CHANERR_XOR_Q_ERR 0x20000
+#define IOAT_CHANERR_DESCRIPTOR_COUNT_ERR 0x40000
+
+#define IOAT_CHANERR_HANDLE_MASK (IOAT_CHANERR_XOR_P_OR_CRC_ERR | IOAT_CHANERR_XOR_Q_ERR)
#define IOAT_CHANERR_MASK_OFFSET 0x2C /* 32-bit Channel Error Register */
diff --git a/drivers/dma/ioat_dma.c b/drivers/dma/ioat_dma.c
deleted file mode 100644
index a600fc0f7962..000000000000
--- a/drivers/dma/ioat_dma.c
+++ /dev/null
@@ -1,1741 +0,0 @@
-/*
- * Intel I/OAT DMA Linux driver
- * Copyright(c) 2004 - 2009 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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 "COPYING".
- *
- */
-
-/*
- * This driver supports an Intel I/OAT DMA engine, which does asynchronous
- * copy operations.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/dmaengine.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/workqueue.h>
-#include <linux/i7300_idle.h>
-#include "ioatdma.h"
-#include "ioatdma_registers.h"
-#include "ioatdma_hw.h"
-
-#define to_ioat_chan(chan) container_of(chan, struct ioat_dma_chan, common)
-#define to_ioatdma_device(dev) container_of(dev, struct ioatdma_device, common)
-#define to_ioat_desc(lh) container_of(lh, struct ioat_desc_sw, node)
-#define tx_to_ioat_desc(tx) container_of(tx, struct ioat_desc_sw, async_tx)
-
-#define chan_num(ch) ((int)((ch)->reg_base - (ch)->device->reg_base) / 0x80)
-static int ioat_pending_level = 4;
-module_param(ioat_pending_level, int, 0644);
-MODULE_PARM_DESC(ioat_pending_level,
- "high-water mark for pushing ioat descriptors (default: 4)");
-
-#define RESET_DELAY msecs_to_jiffies(100)
-#define WATCHDOG_DELAY round_jiffies(msecs_to_jiffies(2000))
-static void ioat_dma_chan_reset_part2(struct work_struct *work);
-static void ioat_dma_chan_watchdog(struct work_struct *work);
-
-/*
- * workaround for IOAT ver.3.0 null descriptor issue
- * (channel returns error when size is 0)
- */
-#define NULL_DESC_BUFFER_SIZE 1
-
-/* internal functions */
-static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan);
-static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan);
-
-static struct ioat_desc_sw *
-ioat1_dma_get_next_descriptor(struct ioat_dma_chan *ioat_chan);
-static struct ioat_desc_sw *
-ioat2_dma_get_next_descriptor(struct ioat_dma_chan *ioat_chan);
-
-static inline struct ioat_dma_chan *ioat_lookup_chan_by_index(
- struct ioatdma_device *device,
- int index)
-{
- return device->idx[index];
-}
-
-/**
- * ioat_dma_do_interrupt - handler used for single vector interrupt mode
- * @irq: interrupt id
- * @data: interrupt data
- */
-static irqreturn_t ioat_dma_do_interrupt(int irq, void *data)
-{
- struct ioatdma_device *instance = data;
- struct ioat_dma_chan *ioat_chan;
- unsigned long attnstatus;
- int bit;
- u8 intrctrl;
-
- intrctrl = readb(instance->reg_base + IOAT_INTRCTRL_OFFSET);
-
- if (!(intrctrl & IOAT_INTRCTRL_MASTER_INT_EN))
- return IRQ_NONE;
-
- if (!(intrctrl & IOAT_INTRCTRL_INT_STATUS)) {
- writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
- return IRQ_NONE;
- }
-
- attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET);
- for_each_bit(bit, &attnstatus, BITS_PER_LONG) {
- ioat_chan = ioat_lookup_chan_by_index(instance, bit);
- tasklet_schedule(&ioat_chan->cleanup_task);
- }
-
- writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
- return IRQ_HANDLED;
-}
-
-/**
- * ioat_dma_do_interrupt_msix - handler used for vector-per-channel interrupt mode
- * @irq: interrupt id
- * @data: interrupt data
- */
-static irqreturn_t ioat_dma_do_interrupt_msix(int irq, void *data)
-{
- struct ioat_dma_chan *ioat_chan = data;
-
- tasklet_schedule(&ioat_chan->cleanup_task);
-
- return IRQ_HANDLED;
-}
-
-static void ioat_dma_cleanup_tasklet(unsigned long data);
-
-/**
- * ioat_dma_enumerate_channels - find and initialize the device's channels
- * @device: the device to be enumerated
- */
-static int ioat_dma_enumerate_channels(struct ioatdma_device *device)
-{
- u8 xfercap_scale;
- u32 xfercap;
- int i;
- struct ioat_dma_chan *ioat_chan;
-
- /*
- * IOAT ver.3 workarounds
- */
- if (device->version == IOAT_VER_3_0) {
- u32 chan_err_mask;
- u16 dev_id;
- u32 dmauncerrsts;
-
- /*
- * Write CHANERRMSK_INT with 3E07h to mask out the errors
- * that can cause stability issues for IOAT ver.3
- */
- chan_err_mask = 0x3E07;
- pci_write_config_dword(device->pdev,
- IOAT_PCI_CHANERRMASK_INT_OFFSET,
- chan_err_mask);
-
- /*
- * Clear DMAUNCERRSTS Cfg-Reg Parity Error status bit
- * (workaround for spurious config parity error after restart)
- */
- pci_read_config_word(device->pdev,
- IOAT_PCI_DEVICE_ID_OFFSET,
- &dev_id);
- if (dev_id == PCI_DEVICE_ID_INTEL_IOAT_TBG0) {
- dmauncerrsts = 0x10;
- pci_write_config_dword(device->pdev,
- IOAT_PCI_DMAUNCERRSTS_OFFSET,
- dmauncerrsts);
- }
- }
-
- device->common.chancnt = readb(device->reg_base + IOAT_CHANCNT_OFFSET);
- xfercap_scale = readb(device->reg_base + IOAT_XFERCAP_OFFSET);
- xfercap = (xfercap_scale == 0 ? -1 : (1UL << xfercap_scale));
-
-#ifdef CONFIG_I7300_IDLE_IOAT_CHANNEL
- if (i7300_idle_platform_probe(NULL, NULL, 1) == 0) {
- device->common.chancnt--;
- }
-#endif
- for (i = 0; i < device->common.chancnt; i++) {
- ioat_chan = kzalloc(sizeof(*ioat_chan), GFP_KERNEL);
- if (!ioat_chan) {
- device->common.chancnt = i;
- break;
- }
-
- ioat_chan->device = device;
- ioat_chan->reg_base = device->reg_base + (0x80 * (i + 1));
- ioat_chan->xfercap = xfercap;
- ioat_chan->desccount = 0;
- INIT_DELAYED_WORK(&ioat_chan->work, ioat_dma_chan_reset_part2);
- if (ioat_chan->device->version == IOAT_VER_2_0)
- writel(IOAT_DCACTRL_CMPL_WRITE_ENABLE |
- IOAT_DMA_DCA_ANY_CPU,
- ioat_chan->reg_base + IOAT_DCACTRL_OFFSET);
- else if (ioat_chan->device->version == IOAT_VER_3_0)
- writel(IOAT_DMA_DCA_ANY_CPU,
- ioat_chan->reg_base + IOAT_DCACTRL_OFFSET);
- spin_lock_init(&ioat_chan->cleanup_lock);
- spin_lock_init(&ioat_chan->desc_lock);
- INIT_LIST_HEAD(&ioat_chan->free_desc);
- INIT_LIST_HEAD(&ioat_chan->used_desc);
- /* This should be made common somewhere in dmaengine.c */
- ioat_chan->common.device = &device->common;
- list_add_tail(&ioat_chan->common.device_node,
- &device->common.channels);
- device->idx[i] = ioat_chan;
- tasklet_init(&ioat_chan->cleanup_task,
- ioat_dma_cleanup_tasklet,
- (unsigned long) ioat_chan);
- tasklet_disable(&ioat_chan->cleanup_task);
- }
- return device->common.chancnt;
-}
-
-/**
- * ioat_dma_memcpy_issue_pending - push potentially unrecognized appended
- * descriptors to hw
- * @chan: DMA channel handle
- */
-static inline void __ioat1_dma_memcpy_issue_pending(
- struct ioat_dma_chan *ioat_chan)
-{
- ioat_chan->pending = 0;
- writeb(IOAT_CHANCMD_APPEND, ioat_chan->reg_base + IOAT1_CHANCMD_OFFSET);
-}
-
-static void ioat1_dma_memcpy_issue_pending(struct dma_chan *chan)
-{
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
-
- if (ioat_chan->pending > 0) {
- spin_lock_bh(&ioat_chan->desc_lock);
- __ioat1_dma_memcpy_issue_pending(ioat_chan);
- spin_unlock_bh(&ioat_chan->desc_lock);
- }
-}
-
-static inline void __ioat2_dma_memcpy_issue_pending(
- struct ioat_dma_chan *ioat_chan)
-{
- ioat_chan->pending = 0;
- writew(ioat_chan->dmacount,
- ioat_chan->reg_base + IOAT_CHAN_DMACOUNT_OFFSET);
-}
-
-static void ioat2_dma_memcpy_issue_pending(struct dma_chan *chan)
-{
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
-
- if (ioat_chan->pending > 0) {
- spin_lock_bh(&ioat_chan->desc_lock);
- __ioat2_dma_memcpy_issue_pending(ioat_chan);
- spin_unlock_bh(&ioat_chan->desc_lock);
- }
-}
-
-
-/**
- * ioat_dma_chan_reset_part2 - reinit the channel after a reset
- */
-static void ioat_dma_chan_reset_part2(struct work_struct *work)
-{
- struct ioat_dma_chan *ioat_chan =
- container_of(work, struct ioat_dma_chan, work.work);
- struct ioat_desc_sw *desc;
-
- spin_lock_bh(&ioat_chan->cleanup_lock);
- spin_lock_bh(&ioat_chan->desc_lock);
-
- ioat_chan->completion_virt->low = 0;
- ioat_chan->completion_virt->high = 0;
- ioat_chan->pending = 0;
-
- /*
- * count the descriptors waiting, and be sure to do it
- * right for both the CB1 line and the CB2 ring
- */
- ioat_chan->dmacount = 0;
- if (ioat_chan->used_desc.prev) {
- desc = to_ioat_desc(ioat_chan->used_desc.prev);
- do {
- ioat_chan->dmacount++;
- desc = to_ioat_desc(desc->node.next);
- } while (&desc->node != ioat_chan->used_desc.next);
- }
-
- /*
- * write the new starting descriptor address
- * this puts channel engine into ARMED state
- */
- desc = to_ioat_desc(ioat_chan->used_desc.prev);
- switch (ioat_chan->device->version) {
- case IOAT_VER_1_2:
- writel(((u64) desc->async_tx.phys) & 0x00000000FFFFFFFF,
- ioat_chan->reg_base + IOAT1_CHAINADDR_OFFSET_LOW);
- writel(((u64) desc->async_tx.phys) >> 32,
- ioat_chan->reg_base + IOAT1_CHAINADDR_OFFSET_HIGH);
-
- writeb(IOAT_CHANCMD_START, ioat_chan->reg_base
- + IOAT_CHANCMD_OFFSET(ioat_chan->device->version));
- break;
- case IOAT_VER_2_0:
- writel(((u64) desc->async_tx.phys) & 0x00000000FFFFFFFF,
- ioat_chan->reg_base + IOAT2_CHAINADDR_OFFSET_LOW);
- writel(((u64) desc->async_tx.phys) >> 32,
- ioat_chan->reg_base + IOAT2_CHAINADDR_OFFSET_HIGH);
-
- /* tell the engine to go with what's left to be done */
- writew(ioat_chan->dmacount,
- ioat_chan->reg_base + IOAT_CHAN_DMACOUNT_OFFSET);
-
- break;
- }
- dev_err(&ioat_chan->device->pdev->dev,
- "chan%d reset - %d descs waiting, %d total desc\n",
- chan_num(ioat_chan), ioat_chan->dmacount, ioat_chan->desccount);
-
- spin_unlock_bh(&ioat_chan->desc_lock);
- spin_unlock_bh(&ioat_chan->cleanup_lock);
-}
-
-/**
- * ioat_dma_reset_channel - restart a channel
- * @ioat_chan: IOAT DMA channel handle
- */
-static void ioat_dma_reset_channel(struct ioat_dma_chan *ioat_chan)
-{
- u32 chansts, chanerr;
-
- if (!ioat_chan->used_desc.prev)
- return;
-
- chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
- chansts = (ioat_chan->completion_virt->low
- & IOAT_CHANSTS_DMA_TRANSFER_STATUS);
- if (chanerr) {
- dev_err(&ioat_chan->device->pdev->dev,
- "chan%d, CHANSTS = 0x%08x CHANERR = 0x%04x, clearing\n",
- chan_num(ioat_chan), chansts, chanerr);
- writel(chanerr, ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
- }
-
- /*
- * whack it upside the head with a reset
- * and wait for things to settle out.
- * force the pending count to a really big negative
- * to make sure no one forces an issue_pending
- * while we're waiting.
- */
-
- spin_lock_bh(&ioat_chan->desc_lock);
- ioat_chan->pending = INT_MIN;
- writeb(IOAT_CHANCMD_RESET,
- ioat_chan->reg_base
- + IOAT_CHANCMD_OFFSET(ioat_chan->device->version));
- spin_unlock_bh(&ioat_chan->desc_lock);
-
- /* schedule the 2nd half instead of sleeping a long time */
- schedule_delayed_work(&ioat_chan->work, RESET_DELAY);
-}
-
-/**
- * ioat_dma_chan_watchdog - watch for stuck channels
- */
-static void ioat_dma_chan_watchdog(struct work_struct *work)
-{
- struct ioatdma_device *device =
- container_of(work, struct ioatdma_device, work.work);
- struct ioat_dma_chan *ioat_chan;
- int i;
-
- union {
- u64 full;
- struct {
- u32 low;
- u32 high;
- };
- } completion_hw;
- unsigned long compl_desc_addr_hw;
-
- for (i = 0; i < device->common.chancnt; i++) {
- ioat_chan = ioat_lookup_chan_by_index(device, i);
-
- if (ioat_chan->device->version == IOAT_VER_1_2
- /* have we started processing anything yet */
- && ioat_chan->last_completion
- /* have we completed any since last watchdog cycle? */
- && (ioat_chan->last_completion ==
- ioat_chan->watchdog_completion)
- /* has TCP stuck on one cookie since last watchdog? */
- && (ioat_chan->watchdog_tcp_cookie ==
- ioat_chan->watchdog_last_tcp_cookie)
- && (ioat_chan->watchdog_tcp_cookie !=
- ioat_chan->completed_cookie)
- /* is there something in the chain to be processed? */
- /* CB1 chain always has at least the last one processed */
- && (ioat_chan->used_desc.prev != ioat_chan->used_desc.next)
- && ioat_chan->pending == 0) {
-
- /*
- * check CHANSTS register for completed
- * descriptor address.
- * if it is different than completion writeback,
- * it is not zero
- * and it has changed since the last watchdog
- * we can assume that channel
- * is still working correctly
- * and the problem is in completion writeback.
- * update completion writeback
- * with actual CHANSTS value
- * else
- * try resetting the channel
- */
-
- completion_hw.low = readl(ioat_chan->reg_base +
- IOAT_CHANSTS_OFFSET_LOW(ioat_chan->device->version));
- completion_hw.high = readl(ioat_chan->reg_base +
- IOAT_CHANSTS_OFFSET_HIGH(ioat_chan->device->version));
-#if (BITS_PER_LONG == 64)
- compl_desc_addr_hw =
- completion_hw.full
- & IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR;
-#else
- compl_desc_addr_hw =
- completion_hw.low & IOAT_LOW_COMPLETION_MASK;
-#endif
-
- if ((compl_desc_addr_hw != 0)
- && (compl_desc_addr_hw != ioat_chan->watchdog_completion)
- && (compl_desc_addr_hw != ioat_chan->last_compl_desc_addr_hw)) {
- ioat_chan->last_compl_desc_addr_hw = compl_desc_addr_hw;
- ioat_chan->completion_virt->low = completion_hw.low;
- ioat_chan->completion_virt->high = completion_hw.high;
- } else {
- ioat_dma_reset_channel(ioat_chan);
- ioat_chan->watchdog_completion = 0;
- ioat_chan->last_compl_desc_addr_hw = 0;
- }
-
- /*
- * for version 2.0 if there are descriptors yet to be processed
- * and the last completed hasn't changed since the last watchdog
- * if they haven't hit the pending level
- * issue the pending to push them through
- * else
- * try resetting the channel
- */
- } else if (ioat_chan->device->version == IOAT_VER_2_0
- && ioat_chan->used_desc.prev
- && ioat_chan->last_completion
- && ioat_chan->last_completion == ioat_chan->watchdog_completion) {
-
- if (ioat_chan->pending < ioat_pending_level)
- ioat2_dma_memcpy_issue_pending(&ioat_chan->common);
- else {
- ioat_dma_reset_channel(ioat_chan);
- ioat_chan->watchdog_completion = 0;
- }
- } else {
- ioat_chan->last_compl_desc_addr_hw = 0;
- ioat_chan->watchdog_completion
- = ioat_chan->last_completion;
- }
-
- ioat_chan->watchdog_last_tcp_cookie =
- ioat_chan->watchdog_tcp_cookie;
- }
-
- schedule_delayed_work(&device->work, WATCHDOG_DELAY);
-}
-
-static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx)
-{
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan);
- struct ioat_desc_sw *first = tx_to_ioat_desc(tx);
- struct ioat_desc_sw *prev, *new;
- struct ioat_dma_descriptor *hw;
- dma_cookie_t cookie;
- LIST_HEAD(new_chain);
- u32 copy;
- size_t len;
- dma_addr_t src, dst;
- unsigned long orig_flags;
- unsigned int desc_count = 0;
-
- /* src and dest and len are stored in the initial descriptor */
- len = first->len;
- src = first->src;
- dst = first->dst;
- orig_flags = first->async_tx.flags;
- new = first;
-
- spin_lock_bh(&ioat_chan->desc_lock);
- prev = to_ioat_desc(ioat_chan->used_desc.prev);
- prefetch(prev->hw);
- do {
- copy = min_t(size_t, len, ioat_chan->xfercap);
-
- async_tx_ack(&new->async_tx);
-
- hw = new->hw;
- hw->size = copy;
- hw->ctl = 0;
- hw->src_addr = src;
- hw->dst_addr = dst;
- hw->next = 0;
-
- /* chain together the physical address list for the HW */
- wmb();
- prev->hw->next = (u64) new->async_tx.phys;
-
- len -= copy;
- dst += copy;
- src += copy;
-
- list_add_tail(&new->node, &new_chain);
- desc_count++;
- prev = new;
- } while (len && (new = ioat1_dma_get_next_descriptor(ioat_chan)));
-
- if (!new) {
- dev_err(&ioat_chan->device->pdev->dev,
- "tx submit failed\n");
- spin_unlock_bh(&ioat_chan->desc_lock);
- return -ENOMEM;
- }
-
- hw->ctl = IOAT_DMA_DESCRIPTOR_CTL_CP_STS;
- if (first->async_tx.callback) {
- hw->ctl |= IOAT_DMA_DESCRIPTOR_CTL_INT_GN;
- if (first != new) {
- /* move callback into to last desc */
- new->async_tx.callback = first->async_tx.callback;
- new->async_tx.callback_param
- = first->async_tx.callback_param;
- first->async_tx.callback = NULL;
- first->async_tx.callback_param = NULL;
- }
- }
-
- new->tx_cnt = desc_count;
- new->async_tx.flags = orig_flags; /* client is in control of this ack */
-
- /* store the original values for use in later cleanup */
- if (new != first) {
- new->src = first->src;
- new->dst = first->dst;
- new->len = first->len;
- }
-
- /* cookie incr and addition to used_list must be atomic */
- cookie = ioat_chan->common.cookie;
- cookie++;
- if (cookie < 0)
- cookie = 1;
- ioat_chan->common.cookie = new->async_tx.cookie = cookie;
-
- /* write address into NextDescriptor field of last desc in chain */
- to_ioat_desc(ioat_chan->used_desc.prev)->hw->next =
- first->async_tx.phys;
- list_splice_tail(&new_chain, &ioat_chan->used_desc);
-
- ioat_chan->dmacount += desc_count;
- ioat_chan->pending += desc_count;
- if (ioat_chan->pending >= ioat_pending_level)
- __ioat1_dma_memcpy_issue_pending(ioat_chan);
- spin_unlock_bh(&ioat_chan->desc_lock);
-
- return cookie;
-}
-
-static dma_cookie_t ioat2_tx_submit(struct dma_async_tx_descriptor *tx)
-{
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan);
- struct ioat_desc_sw *first = tx_to_ioat_desc(tx);
- struct ioat_desc_sw *new;
- struct ioat_dma_descriptor *hw;
- dma_cookie_t cookie;
- u32 copy;
- size_t len;
- dma_addr_t src, dst;
- unsigned long orig_flags;
- unsigned int desc_count = 0;
-
- /* src and dest and len are stored in the initial descriptor */
- len = first->len;
- src = first->src;
- dst = first->dst;
- orig_flags = first->async_tx.flags;
- new = first;
-
- /*
- * ioat_chan->desc_lock is still in force in version 2 path
- * it gets unlocked at end of this function
- */
- do {
- copy = min_t(size_t, len, ioat_chan->xfercap);
-
- async_tx_ack(&new->async_tx);
-
- hw = new->hw;
- hw->size = copy;
- hw->ctl = 0;
- hw->src_addr = src;
- hw->dst_addr = dst;
-
- len -= copy;
- dst += copy;
- src += copy;
- desc_count++;
- } while (len && (new = ioat2_dma_get_next_descriptor(ioat_chan)));
-
- if (!new) {
- dev_err(&ioat_chan->device->pdev->dev,
- "tx submit failed\n");
- spin_unlock_bh(&ioat_chan->desc_lock);
- return -ENOMEM;
- }
-
- hw->ctl |= IOAT_DMA_DESCRIPTOR_CTL_CP_STS;
- if (first->async_tx.callback) {
- hw->ctl |= IOAT_DMA_DESCRIPTOR_CTL_INT_GN;
- if (first != new) {
- /* move callback into to last desc */
- new->async_tx.callback = first->async_tx.callback;
- new->async_tx.callback_param
- = first->async_tx.callback_param;
- first->async_tx.callback = NULL;
- first->async_tx.callback_param = NULL;
- }
- }
-
- new->tx_cnt = desc_count;
- new->async_tx.flags = orig_flags; /* client is in control of this ack */
-
- /* store the original values for use in later cleanup */
- if (new != first) {
- new->src = first->src;
- new->dst = first->dst;
- new->len = first->len;
- }
-
- /* cookie incr and addition to used_list must be atomic */
- cookie = ioat_chan->common.cookie;
- cookie++;
- if (cookie < 0)
- cookie = 1;
- ioat_chan->common.cookie = new->async_tx.cookie = cookie;
-
- ioat_chan->dmacount += desc_count;
- ioat_chan->pending += desc_count;
- if (ioat_chan->pending >= ioat_pending_level)
- __ioat2_dma_memcpy_issue_pending(ioat_chan);
- spin_unlock_bh(&ioat_chan->desc_lock);
-
- return cookie;
-}
-
-/**
- * ioat_dma_alloc_descriptor - allocate and return a sw and hw descriptor pair
- * @ioat_chan: the channel supplying the memory pool for the descriptors
- * @flags: allocation flags
- */
-static struct ioat_desc_sw *ioat_dma_alloc_descriptor(
- struct ioat_dma_chan *ioat_chan,
- gfp_t flags)
-{
- struct ioat_dma_descriptor *desc;
- struct ioat_desc_sw *desc_sw;
- struct ioatdma_device *ioatdma_device;
- dma_addr_t phys;
-
- ioatdma_device = to_ioatdma_device(ioat_chan->common.device);
- desc = pci_pool_alloc(ioatdma_device->dma_pool, flags, &phys);
- if (unlikely(!desc))
- return NULL;
-
- desc_sw = kzalloc(sizeof(*desc_sw), flags);
- if (unlikely(!desc_sw)) {
- pci_pool_free(ioatdma_device->dma_pool, desc, phys);
- return NULL;
- }
-
- memset(desc, 0, sizeof(*desc));
- dma_async_tx_descriptor_init(&desc_sw->async_tx, &ioat_chan->common);
- switch (ioat_chan->device->version) {
- case IOAT_VER_1_2:
- desc_sw->async_tx.tx_submit = ioat1_tx_submit;
- break;
- case IOAT_VER_2_0:
- case IOAT_VER_3_0:
- desc_sw->async_tx.tx_submit = ioat2_tx_submit;
- break;
- }
-
- desc_sw->hw = desc;
- desc_sw->async_tx.phys = phys;
-
- return desc_sw;
-}
-
-static int ioat_initial_desc_count = 256;
-module_param(ioat_initial_desc_count, int, 0644);
-MODULE_PARM_DESC(ioat_initial_desc_count,
- "initial descriptors per channel (default: 256)");
-
-/**
- * ioat2_dma_massage_chan_desc - link the descriptors into a circle
- * @ioat_chan: the channel to be massaged
- */
-static void ioat2_dma_massage_chan_desc(struct ioat_dma_chan *ioat_chan)
-{
- struct ioat_desc_sw *desc, *_desc;
-
- /* setup used_desc */
- ioat_chan->used_desc.next = ioat_chan->free_desc.next;
- ioat_chan->used_desc.prev = NULL;
-
- /* pull free_desc out of the circle so that every node is a hw
- * descriptor, but leave it pointing to the list
- */
- ioat_chan->free_desc.prev->next = ioat_chan->free_desc.next;
- ioat_chan->free_desc.next->prev = ioat_chan->free_desc.prev;
-
- /* circle link the hw descriptors */
- desc = to_ioat_desc(ioat_chan->free_desc.next);
- desc->hw->next = to_ioat_desc(desc->node.next)->async_tx.phys;
- list_for_each_entry_safe(desc, _desc, ioat_chan->free_desc.next, node) {
- desc->hw->next = to_ioat_desc(desc->node.next)->async_tx.phys;
- }
-}
-
-/**
- * ioat_dma_alloc_chan_resources - returns the number of allocated descriptors
- * @chan: the channel to be filled out
- */
-static int ioat_dma_alloc_chan_resources(struct dma_chan *chan)
-{
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
- struct ioat_desc_sw *desc;
- u16 chanctrl;
- u32 chanerr;
- int i;
- LIST_HEAD(tmp_list);
-
- /* have we already been set up? */
- if (!list_empty(&ioat_chan->free_desc))
- return ioat_chan->desccount;
-
- /* Setup register to interrupt and write completion status on error */
- chanctrl = IOAT_CHANCTRL_ERR_INT_EN |
- IOAT_CHANCTRL_ANY_ERR_ABORT_EN |
- IOAT_CHANCTRL_ERR_COMPLETION_EN;
- writew(chanctrl, ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET);
-
- chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
- if (chanerr) {
- dev_err(&ioat_chan->device->pdev->dev,
- "CHANERR = %x, clearing\n", chanerr);
- writel(chanerr, ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
- }
-
- /* Allocate descriptors */
- for (i = 0; i < ioat_initial_desc_count; i++) {
- desc = ioat_dma_alloc_descriptor(ioat_chan, GFP_KERNEL);
- if (!desc) {
- dev_err(&ioat_chan->device->pdev->dev,
- "Only %d initial descriptors\n", i);
- break;
- }
- list_add_tail(&desc->node, &tmp_list);
- }
- spin_lock_bh(&ioat_chan->desc_lock);
- ioat_chan->desccount = i;
- list_splice(&tmp_list, &ioat_chan->free_desc);
- if (ioat_chan->device->version != IOAT_VER_1_2)
- ioat2_dma_massage_chan_desc(ioat_chan);
- spin_unlock_bh(&ioat_chan->desc_lock);
-
- /* allocate a completion writeback area */
- /* doing 2 32bit writes to mmio since 1 64b write doesn't work */
- ioat_chan->completion_virt =
- pci_pool_alloc(ioat_chan->device->completion_pool,
- GFP_KERNEL,
- &ioat_chan->completion_addr);
- memset(ioat_chan->completion_virt, 0,
- sizeof(*ioat_chan->completion_virt));
- writel(((u64) ioat_chan->completion_addr) & 0x00000000FFFFFFFF,
- ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_LOW);
- writel(((u64) ioat_chan->completion_addr) >> 32,
- ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);
-
- tasklet_enable(&ioat_chan->cleanup_task);
- ioat_dma_start_null_desc(ioat_chan); /* give chain to dma device */
- return ioat_chan->desccount;
-}
-
-/**
- * ioat_dma_free_chan_resources - release all the descriptors
- * @chan: the channel to be cleaned
- */
-static void ioat_dma_free_chan_resources(struct dma_chan *chan)
-{
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
- struct ioatdma_device *ioatdma_device = to_ioatdma_device(chan->device);
- struct ioat_desc_sw *desc, *_desc;
- int in_use_descs = 0;
-
- /* Before freeing channel resources first check
- * if they have been previously allocated for this channel.
- */
- if (ioat_chan->desccount == 0)
- return;
-
- tasklet_disable(&ioat_chan->cleanup_task);
- ioat_dma_memcpy_cleanup(ioat_chan);
-
- /* Delay 100ms after reset to allow internal DMA logic to quiesce
- * before removing DMA descriptor resources.
- */
- writeb(IOAT_CHANCMD_RESET,
- ioat_chan->reg_base
- + IOAT_CHANCMD_OFFSET(ioat_chan->device->version));
- mdelay(100);
-
- spin_lock_bh(&ioat_chan->desc_lock);
- switch (ioat_chan->device->version) {
- case IOAT_VER_1_2:
- list_for_each_entry_safe(desc, _desc,
- &ioat_chan->used_desc, node) {
- in_use_descs++;
- list_del(&desc->node);
- pci_pool_free(ioatdma_device->dma_pool, desc->hw,
- desc->async_tx.phys);
- kfree(desc);
- }
- list_for_each_entry_safe(desc, _desc,
- &ioat_chan->free_desc, node) {
- list_del(&desc->node);
- pci_pool_free(ioatdma_device->dma_pool, desc->hw,
- desc->async_tx.phys);
- kfree(desc);
- }
- break;
- case IOAT_VER_2_0:
- case IOAT_VER_3_0:
- list_for_each_entry_safe(desc, _desc,
- ioat_chan->free_desc.next, node) {
- list_del(&desc->node);
- pci_pool_free(ioatdma_device->dma_pool, desc->hw,
- desc->async_tx.phys);
- kfree(desc);
- }
- desc = to_ioat_desc(ioat_chan->free_desc.next);
- pci_pool_free(ioatdma_device->dma_pool, desc->hw,
- desc->async_tx.phys);
- kfree(desc);
- INIT_LIST_HEAD(&ioat_chan->free_desc);
- INIT_LIST_HEAD(&ioat_chan->used_desc);
- break;
- }
- spin_unlock_bh(&ioat_chan->desc_lock);
-
- pci_pool_free(ioatdma_device->completion_pool,
- ioat_chan->completion_virt,
- ioat_chan->completion_addr);
-
- /* one is ok since we left it on there on purpose */
- if (in_use_descs > 1)
- dev_err(&ioat_chan->device->pdev->dev,
- "Freeing %d in use descriptors!\n",
- in_use_descs - 1);
-
- ioat_chan->last_completion = ioat_chan->completion_addr = 0;
- ioat_chan->pending = 0;
- ioat_chan->dmacount = 0;
- ioat_chan->desccount = 0;
- ioat_chan->watchdog_completion = 0;
- ioat_chan->last_compl_desc_addr_hw = 0;
- ioat_chan->watchdog_tcp_cookie =
- ioat_chan->watchdog_last_tcp_cookie = 0;
-}
-
-/**
- * ioat_dma_get_next_descriptor - return the next available descriptor
- * @ioat_chan: IOAT DMA channel handle
- *
- * Gets the next descriptor from the chain, and must be called with the
- * channel's desc_lock held. Allocates more descriptors if the channel
- * has run out.
- */
-static struct ioat_desc_sw *
-ioat1_dma_get_next_descriptor(struct ioat_dma_chan *ioat_chan)
-{
- struct ioat_desc_sw *new;
-
- if (!list_empty(&ioat_chan->free_desc)) {
- new = to_ioat_desc(ioat_chan->free_desc.next);
- list_del(&new->node);
- } else {
- /* try to get another desc */
- new = ioat_dma_alloc_descriptor(ioat_chan, GFP_ATOMIC);
- if (!new) {
- dev_err(&ioat_chan->device->pdev->dev,
- "alloc failed\n");
- return NULL;
- }
- }
-
- prefetch(new->hw);
- return new;
-}
-
-static struct ioat_desc_sw *
-ioat2_dma_get_next_descriptor(struct ioat_dma_chan *ioat_chan)
-{
- struct ioat_desc_sw *new;
-
- /*
- * used.prev points to where to start processing
- * used.next points to next free descriptor
- * if used.prev == NULL, there are none waiting to be processed
- * if used.next == used.prev.prev, there is only one free descriptor,
- * and we need to use it to as a noop descriptor before
- * linking in a new set of descriptors, since the device
- * has probably already read the pointer to it
- */
- if (ioat_chan->used_desc.prev &&
- ioat_chan->used_desc.next == ioat_chan->used_desc.prev->prev) {
-
- struct ioat_desc_sw *desc;
- struct ioat_desc_sw *noop_desc;
- int i;
-
- /* set up the noop descriptor */
- noop_desc = to_ioat_desc(ioat_chan->used_desc.next);
- /* set size to non-zero value (channel returns error when size is 0) */
- noop_desc->hw->size = NULL_DESC_BUFFER_SIZE;
- noop_desc->hw->ctl = IOAT_DMA_DESCRIPTOR_NUL;
- noop_desc->hw->src_addr = 0;
- noop_desc->hw->dst_addr = 0;
-
- ioat_chan->used_desc.next = ioat_chan->used_desc.next->next;
- ioat_chan->pending++;
- ioat_chan->dmacount++;
-
- /* try to get a few more descriptors */
- for (i = 16; i; i--) {
- desc = ioat_dma_alloc_descriptor(ioat_chan, GFP_ATOMIC);
- if (!desc) {
- dev_err(&ioat_chan->device->pdev->dev,
- "alloc failed\n");
- break;
- }
- list_add_tail(&desc->node, ioat_chan->used_desc.next);
-
- desc->hw->next
- = to_ioat_desc(desc->node.next)->async_tx.phys;
- to_ioat_desc(desc->node.prev)->hw->next
- = desc->async_tx.phys;
- ioat_chan->desccount++;
- }
-
- ioat_chan->used_desc.next = noop_desc->node.next;
- }
- new = to_ioat_desc(ioat_chan->used_desc.next);
- prefetch(new);
- ioat_chan->used_desc.next = new->node.next;
-
- if (ioat_chan->used_desc.prev == NULL)
- ioat_chan->used_desc.prev = &new->node;
-
- prefetch(new->hw);
- return new;
-}
-
-static struct ioat_desc_sw *ioat_dma_get_next_descriptor(
- struct ioat_dma_chan *ioat_chan)
-{
- if (!ioat_chan)
- return NULL;
-
- switch (ioat_chan->device->version) {
- case IOAT_VER_1_2:
- return ioat1_dma_get_next_descriptor(ioat_chan);
- case IOAT_VER_2_0:
- case IOAT_VER_3_0:
- return ioat2_dma_get_next_descriptor(ioat_chan);
- }
- return NULL;
-}
-
-static struct dma_async_tx_descriptor *ioat1_dma_prep_memcpy(
- struct dma_chan *chan,
- dma_addr_t dma_dest,
- dma_addr_t dma_src,
- size_t len,
- unsigned long flags)
-{
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
- struct ioat_desc_sw *new;
-
- spin_lock_bh(&ioat_chan->desc_lock);
- new = ioat_dma_get_next_descriptor(ioat_chan);
- spin_unlock_bh(&ioat_chan->desc_lock);
-
- if (new) {
- new->len = len;
- new->dst = dma_dest;
- new->src = dma_src;
- new->async_tx.flags = flags;
- return &new->async_tx;
- } else {
- dev_err(&ioat_chan->device->pdev->dev,
- "chan%d - get_next_desc failed: %d descs waiting, %d total desc\n",
- chan_num(ioat_chan), ioat_chan->dmacount, ioat_chan->desccount);
- return NULL;
- }
-}
-
-static struct dma_async_tx_descriptor *ioat2_dma_prep_memcpy(
- struct dma_chan *chan,
- dma_addr_t dma_dest,
- dma_addr_t dma_src,
- size_t len,
- unsigned long flags)
-{
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
- struct ioat_desc_sw *new;
-
- spin_lock_bh(&ioat_chan->desc_lock);
- new = ioat2_dma_get_next_descriptor(ioat_chan);
-
- /*
- * leave ioat_chan->desc_lock set in ioat 2 path
- * it will get unlocked at end of tx_submit
- */
-
- if (new) {
- new->len = len;
- new->dst = dma_dest;
- new->src = dma_src;
- new->async_tx.flags = flags;
- return &new->async_tx;
- } else {
- spin_unlock_bh(&ioat_chan->desc_lock);
- dev_err(&ioat_chan->device->pdev->dev,
- "chan%d - get_next_desc failed: %d descs waiting, %d total desc\n",
- chan_num(ioat_chan), ioat_chan->dmacount, ioat_chan->desccount);
- return NULL;
- }
-}
-
-static void ioat_dma_cleanup_tasklet(unsigned long data)
-{
- struct ioat_dma_chan *chan = (void *)data;
- ioat_dma_memcpy_cleanup(chan);
- writew(IOAT_CHANCTRL_INT_DISABLE,
- chan->reg_base + IOAT_CHANCTRL_OFFSET);
-}
-
-static void
-ioat_dma_unmap(struct ioat_dma_chan *ioat_chan, struct ioat_desc_sw *desc)
-{
- if (!(desc->async_tx.flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
- if (desc->async_tx.flags & DMA_COMPL_DEST_UNMAP_SINGLE)
- pci_unmap_single(ioat_chan->device->pdev,
- pci_unmap_addr(desc, dst),
- pci_unmap_len(desc, len),
- PCI_DMA_FROMDEVICE);
- else
- pci_unmap_page(ioat_chan->device->pdev,
- pci_unmap_addr(desc, dst),
- pci_unmap_len(desc, len),
- PCI_DMA_FROMDEVICE);
- }
-
- if (!(desc->async_tx.flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
- if (desc->async_tx.flags & DMA_COMPL_SRC_UNMAP_SINGLE)
- pci_unmap_single(ioat_chan->device->pdev,
- pci_unmap_addr(desc, src),
- pci_unmap_len(desc, len),
- PCI_DMA_TODEVICE);
- else
- pci_unmap_page(ioat_chan->device->pdev,
- pci_unmap_addr(desc, src),
- pci_unmap_len(desc, len),
- PCI_DMA_TODEVICE);
- }
-}
-
-/**
- * ioat_dma_memcpy_cleanup - cleanup up finished descriptors
- * @chan: ioat channel to be cleaned up
- */
-static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan)
-{
- unsigned long phys_complete;
- struct ioat_desc_sw *desc, *_desc;
- dma_cookie_t cookie = 0;
- unsigned long desc_phys;
- struct ioat_desc_sw *latest_desc;
-
- prefetch(ioat_chan->completion_virt);
-
- if (!spin_trylock_bh(&ioat_chan->cleanup_lock))
- return;
-
- /* The completion writeback can happen at any time,
- so reads by the driver need to be atomic operations
- The descriptor physical addresses are limited to 32-bits
- when the CPU can only do a 32-bit mov */
-
-#if (BITS_PER_LONG == 64)
- phys_complete =
- ioat_chan->completion_virt->full
- & IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR;
-#else
- phys_complete =
- ioat_chan->completion_virt->low & IOAT_LOW_COMPLETION_MASK;
-#endif
-
- if ((ioat_chan->completion_virt->full
-