diff options
-rw-r--r-- | Documentation/crypto/async-tx-api.txt | 96 | ||||
-rw-r--r-- | Documentation/dmaengine.txt | 1 | ||||
-rw-r--r-- | Documentation/kernel-parameters.txt | 46 | ||||
-rw-r--r-- | Documentation/powerpc/dts-bindings/4xx/ndfc.txt | 39 | ||||
-rw-r--r-- | arch/arm/mach-pxa/corgi.c | 54 | ||||
-rw-r--r-- | arch/arm/mach-pxa/poodle.c | 51 | ||||
-rw-r--r-- | arch/arm/mach-pxa/spitz.c | 77 | ||||
-rw-r--r-- | arch/avr32/mach-at32ap/at32ap700x.c | 15 | ||||
-rw-r--r-- | arch/ia64/include/asm/acpi-ext.h | 1 | ||||
-rw-r--r-- | arch/ia64/include/asm/sn/acpi.h | 2 | ||||
-rw-r--r-- | arch/ia64/kernel/acpi.c | 1 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/io_acpi_init.c | 103 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/io_common.c | 5 | ||||
-rw-r--r-- | arch/parisc/Makefile | 2 | ||||
-rw-r--r-- | arch/parisc/include/asm/Kbuild | 1 | ||||
-rw-r--r-- | arch/parisc/include/asm/byteorder.h | 77 | ||||
-rw-r--r-- | arch/parisc/include/asm/checksum.h | 2 | ||||
-rw-r--r-- | arch/parisc/include/asm/io.h | 12 | ||||
-rw-r--r-- | arch/parisc/include/asm/mmu_context.h | 13 | ||||
-rw-r--r-- | arch/parisc/include/asm/processor.h | 4 | ||||
-rw-r--r-- | arch/parisc/include/asm/swab.h | 66 | ||||
-rw-r--r-- | arch/parisc/include/asm/uaccess.h | 2 | ||||
-rw-r--r-- | arch/parisc/kernel/drivers.c | 40 | ||||
-rw-r--r-- | arch/parisc/kernel/hpmc.S | 8 | ||||
-rw-r--r-- | arch/parisc/kernel/irq.c | 11 | ||||
-rw-r--r-- | arch/parisc/kernel/pdc_cons.c | 2 | ||||
-rw-r--r-- | arch/parisc/kernel/perf.c | 4 | ||||
-rw-r--r-- | arch/parisc/kernel/processor.c | 68 | ||||
-rw-r--r-- | arch/parisc/kernel/setup.c | 11 | ||||
-rw-r--r-- | arch/parisc/kernel/smp.c | 32 | ||||
-rw-r--r-- | arch/parisc/kernel/time.c | 4 | ||||
-rw-r--r-- | arch/parisc/kernel/topology.c | 4 | ||||
-rw-r--r-- | arch/parisc/kernel/traps.c | 9 | ||||
-rw-r--r-- | arch/parisc/kernel/unwind.c | 2 | ||||
-rw-r--r-- | arch/parisc/lib/iomap.c | 2 | ||||
-rw-r--r-- | arch/parisc/lib/memcpy.c | 2 | ||||
-rw-r--r-- | arch/parisc/mm/fault.c | 58 | ||||
-rw-r--r-- | arch/powerpc/include/asm/cell-pmu.h | 2 | ||||
-rw-r--r-- | arch/powerpc/include/asm/oprofile_impl.h | 6 | ||||
-rw-r--r-- | arch/powerpc/oprofile/cell/pr_util.h | 11 | ||||
-rw-r--r-- | arch/powerpc/oprofile/cell/spu_profiler.c | 56 | ||||
-rw-r--r-- | arch/powerpc/oprofile/common.c | 22 | ||||
-rw-r--r-- | arch/powerpc/oprofile/op_model_cell.c | 748 | ||||
-rw-r--r-- | arch/x86/include/asm/bitops.h | 2 | ||||
-rw-r--r-- | arch/x86/kernel/acpi/boot.c | 17 | ||||
-rw-r--r-- | arch/x86/kernel/acpi/cstate.c | 4 | ||||
-rw-r--r-- | arch/x86/kernel/acpi/sleep.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/e820.c | 21 | ||||
-rw-r--r-- | arch/x86/kernel/early-quirks.c | 22 | ||||
-rw-r--r-- | arch/x86/oprofile/op_model_amd.c | 149 | ||||
-rw-r--r-- | crypto/async_tx/async_tx.c | 350 | ||||
-rw-r--r-- | drivers/Kconfig | 2 | ||||
-rw-r--r-- | drivers/Makefile | 1 | ||||
-rw-r--r-- | drivers/acpi/Kconfig | 84 | ||||
-rw-r--r-- | drivers/acpi/Makefile | 25 | ||||
-rw-r--r-- | drivers/acpi/acpica/Makefile | 44 | ||||
-rw-r--r-- | drivers/acpi/acpica/accommon.h | 63 | ||||
-rw-r--r-- | drivers/acpi/acpica/acconfig.h (renamed from include/acpi/acconfig.h) | 8 | ||||
-rw-r--r-- | drivers/acpi/acpica/acdebug.h (renamed from include/acpi/acdebug.h) | 0 | ||||
-rw-r--r-- | drivers/acpi/acpica/acdispat.h (renamed from include/acpi/acdispat.h) | 0 | ||||
-rw-r--r-- | drivers/acpi/acpica/acevents.h (renamed from include/acpi/acevents.h) | 6 | ||||
-rw-r--r-- | drivers/acpi/acpica/acglobal.h (renamed from include/acpi/acglobal.h) | 9 | ||||
-rw-r--r-- | drivers/acpi/acpica/achware.h (renamed from include/acpi/achware.h) | 22 | ||||
-rw-r--r-- | drivers/acpi/acpica/acinterp.h (renamed from include/acpi/acinterp.h) | 0 | ||||
-rw-r--r-- | drivers/acpi/acpica/aclocal.h (renamed from include/acpi/aclocal.h) | 86 | ||||
-rw-r--r-- | drivers/acpi/acpica/acmacros.h (renamed from include/acpi/acmacros.h) | 122 | ||||
-rw-r--r-- | drivers/acpi/acpica/acnamesp.h (renamed from include/acpi/acnamesp.h) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/acobject.h (renamed from include/acpi/acobject.h) | 0 | ||||
-rw-r--r-- | drivers/acpi/acpica/acopcode.h (renamed from include/acpi/acopcode.h) | 0 | ||||
-rw-r--r-- | drivers/acpi/acpica/acparser.h (renamed from include/acpi/acparser.h) | 0 | ||||
-rw-r--r-- | drivers/acpi/acpica/acpredef.h (renamed from include/acpi/acpredef.h) | 0 | ||||
-rw-r--r-- | drivers/acpi/acpica/acresrc.h (renamed from include/acpi/acresrc.h) | 0 | ||||
-rw-r--r-- | drivers/acpi/acpica/acstruct.h (renamed from include/acpi/acstruct.h) | 0 | ||||
-rw-r--r-- | drivers/acpi/acpica/actables.h (renamed from include/acpi/actables.h) | 2 | ||||
-rw-r--r-- | drivers/acpi/acpica/acutils.h (renamed from include/acpi/acutils.h) | 36 | ||||
-rw-r--r-- | drivers/acpi/acpica/amlcode.h (renamed from include/acpi/amlcode.h) | 0 | ||||
-rw-r--r-- | drivers/acpi/acpica/amlresrc.h (renamed from include/acpi/amlresrc.h) | 0 | ||||
-rw-r--r-- | drivers/acpi/acpica/dsfield.c (renamed from drivers/acpi/dispatcher/dsfield.c) | 11 | ||||
-rw-r--r-- | drivers/acpi/acpica/dsinit.c (renamed from drivers/acpi/dispatcher/dsinit.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/dsmethod.c (renamed from drivers/acpi/dispatcher/dsmethod.c) | 14 | ||||
-rw-r--r-- | drivers/acpi/acpica/dsmthdat.c (renamed from drivers/acpi/dispatcher/dsmthdat.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/dsobject.c (renamed from drivers/acpi/dispatcher/dsobject.c) | 11 | ||||
-rw-r--r-- | drivers/acpi/acpica/dsopcode.c (renamed from drivers/acpi/dispatcher/dsopcode.c) | 66 | ||||
-rw-r--r-- | drivers/acpi/acpica/dsutils.c (renamed from drivers/acpi/dispatcher/dsutils.c) | 13 | ||||
-rw-r--r-- | drivers/acpi/acpica/dswexec.c (renamed from drivers/acpi/dispatcher/dswexec.c) | 13 | ||||
-rw-r--r-- | drivers/acpi/acpica/dswload.c (renamed from drivers/acpi/dispatcher/dswload.c) | 13 | ||||
-rw-r--r-- | drivers/acpi/acpica/dswscope.c (renamed from drivers/acpi/dispatcher/dswscope.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/dswstate.c (renamed from drivers/acpi/dispatcher/dswstate.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/evevent.c (renamed from drivers/acpi/events/evevent.c) | 17 | ||||
-rw-r--r-- | drivers/acpi/acpica/evgpe.c (renamed from drivers/acpi/events/evgpe.c) | 53 | ||||
-rw-r--r-- | drivers/acpi/acpica/evgpeblk.c (renamed from drivers/acpi/events/evgpeblk.c) | 82 | ||||
-rw-r--r-- | drivers/acpi/acpica/evmisc.c (renamed from drivers/acpi/events/evmisc.c) | 62 | ||||
-rw-r--r-- | drivers/acpi/acpica/evregion.c (renamed from drivers/acpi/events/evregion.c) | 140 | ||||
-rw-r--r-- | drivers/acpi/acpica/evrgnini.c (renamed from drivers/acpi/events/evrgnini.c) | 46 | ||||
-rw-r--r-- | drivers/acpi/acpica/evsci.c (renamed from drivers/acpi/events/evsci.c) | 13 | ||||
-rw-r--r-- | drivers/acpi/acpica/evxface.c (renamed from drivers/acpi/events/evxface.c) | 9 | ||||
-rw-r--r-- | drivers/acpi/acpica/evxfevnt.c (renamed from drivers/acpi/events/evxfevnt.c) | 170 | ||||
-rw-r--r-- | drivers/acpi/acpica/evxfregn.c (renamed from drivers/acpi/events/evxfregn.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/exconfig.c (renamed from drivers/acpi/executer/exconfig.c) | 9 | ||||
-rw-r--r-- | drivers/acpi/acpica/exconvrt.c (renamed from drivers/acpi/executer/exconvrt.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/excreate.c (renamed from drivers/acpi/executer/excreate.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/exdump.c (renamed from drivers/acpi/executer/exdump.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/exfield.c (renamed from drivers/acpi/executer/exfield.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/exfldio.c (renamed from drivers/acpi/executer/exfldio.c) | 20 | ||||
-rw-r--r-- | drivers/acpi/acpica/exmisc.c (renamed from drivers/acpi/executer/exmisc.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/exmutex.c (renamed from drivers/acpi/executer/exmutex.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/exnames.c (renamed from drivers/acpi/executer/exnames.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/exoparg1.c (renamed from drivers/acpi/executer/exoparg1.c) | 11 | ||||
-rw-r--r-- | drivers/acpi/acpica/exoparg2.c (renamed from drivers/acpi/executer/exoparg2.c) | 9 | ||||
-rw-r--r-- | drivers/acpi/acpica/exoparg3.c (renamed from drivers/acpi/executer/exoparg3.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/exoparg6.c (renamed from drivers/acpi/executer/exoparg6.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/exprep.c (renamed from drivers/acpi/executer/exprep.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/exregion.c (renamed from drivers/acpi/executer/exregion.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/exresnte.c (renamed from drivers/acpi/executer/exresnte.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/exresolv.c (renamed from drivers/acpi/executer/exresolv.c) | 9 | ||||
-rw-r--r-- | drivers/acpi/acpica/exresop.c (renamed from drivers/acpi/executer/exresop.c) | 9 | ||||
-rw-r--r-- | drivers/acpi/acpica/exstore.c (renamed from drivers/acpi/executer/exstore.c) | 9 | ||||
-rw-r--r-- | drivers/acpi/acpica/exstoren.c (renamed from drivers/acpi/executer/exstoren.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/exstorob.c (renamed from drivers/acpi/executer/exstorob.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/exsystem.c (renamed from drivers/acpi/executer/exsystem.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/exutils.c (renamed from drivers/acpi/executer/exutils.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/hwacpi.c (renamed from drivers/acpi/hardware/hwacpi.c) | 1 | ||||
-rw-r--r-- | drivers/acpi/acpica/hwgpe.c (renamed from drivers/acpi/hardware/hwgpe.c) | 78 | ||||
-rw-r--r-- | drivers/acpi/acpica/hwregs.c | 353 | ||||
-rw-r--r-- | drivers/acpi/acpica/hwsleep.c (renamed from drivers/acpi/hardware/hwsleep.c) | 76 | ||||
-rw-r--r-- | drivers/acpi/acpica/hwtimer.c (renamed from drivers/acpi/hardware/hwtimer.c) | 1 | ||||
-rw-r--r-- | drivers/acpi/acpica/hwxface.c (renamed from drivers/acpi/hardware/hwregs.c) | 744 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsaccess.c (renamed from drivers/acpi/namespace/nsaccess.c) | 18 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsalloc.c (renamed from drivers/acpi/namespace/nsalloc.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsdump.c (renamed from drivers/acpi/namespace/nsdump.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsdumpdv.c (renamed from drivers/acpi/namespace/nsdumpdv.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/nseval.c (renamed from drivers/acpi/namespace/nseval.c) | 77 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsinit.c (renamed from drivers/acpi/namespace/nsinit.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsload.c (renamed from drivers/acpi/namespace/nsload.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsnames.c (renamed from drivers/acpi/namespace/nsnames.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsobject.c (renamed from drivers/acpi/namespace/nsobject.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsparse.c (renamed from drivers/acpi/namespace/nsparse.c) | 9 | ||||
-rw-r--r-- | drivers/acpi/acpica/nspredef.c (renamed from drivers/acpi/namespace/nspredef.c) | 261 | ||||
-rw-r--r-- | drivers/acpi/acpica/nssearch.c (renamed from drivers/acpi/namespace/nssearch.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsutils.c (renamed from drivers/acpi/namespace/nsutils.c) | 15 | ||||
-rw-r--r-- | drivers/acpi/acpica/nswalk.c (renamed from drivers/acpi/namespace/nswalk.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsxfeval.c (renamed from drivers/acpi/namespace/nsxfeval.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsxfname.c (renamed from drivers/acpi/namespace/nsxfname.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsxfobj.c (renamed from drivers/acpi/namespace/nsxfobj.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/psargs.c (renamed from drivers/acpi/parser/psargs.c) | 9 | ||||
-rw-r--r-- | drivers/acpi/acpica/psloop.c (renamed from drivers/acpi/parser/psloop.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/psopcode.c (renamed from drivers/acpi/parser/psopcode.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/psparse.c (renamed from drivers/acpi/parser/psparse.c) | 23 | ||||
-rw-r--r-- | drivers/acpi/acpica/psscope.c (renamed from drivers/acpi/parser/psscope.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/pstree.c (renamed from drivers/acpi/parser/pstree.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/psutils.c (renamed from drivers/acpi/parser/psutils.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/pswalk.c (renamed from drivers/acpi/parser/pswalk.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/psxface.c (renamed from drivers/acpi/parser/psxface.c) | 40 | ||||
-rw-r--r-- | drivers/acpi/acpica/rsaddr.c (renamed from drivers/acpi/resources/rsaddr.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/rscalc.c (renamed from drivers/acpi/resources/rscalc.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/rscreate.c (renamed from drivers/acpi/resources/rscreate.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/rsdump.c (renamed from drivers/acpi/resources/rsdump.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/rsinfo.c (renamed from drivers/acpi/resources/rsinfo.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/rsio.c (renamed from drivers/acpi/resources/rsio.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/rsirq.c (renamed from drivers/acpi/resources/rsirq.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/rslist.c (renamed from drivers/acpi/resources/rslist.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/rsmemory.c (renamed from drivers/acpi/resources/rsmemory.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/rsmisc.c (renamed from drivers/acpi/resources/rsmisc.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/rsutils.c (renamed from drivers/acpi/resources/rsutils.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/rsxface.c (renamed from drivers/acpi/resources/rsxface.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/tbfadt.c (renamed from drivers/acpi/tables/tbfadt.c) | 252 | ||||
-rw-r--r-- | drivers/acpi/acpica/tbfind.c (renamed from drivers/acpi/tables/tbfind.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/tbinstal.c (renamed from drivers/acpi/tables/tbinstal.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/tbutils.c (renamed from drivers/acpi/tables/tbutils.c) | 30 | ||||
-rw-r--r-- | drivers/acpi/acpica/tbxface.c (renamed from drivers/acpi/tables/tbxface.c) | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/tbxfroot.c (renamed from drivers/acpi/tables/tbxfroot.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/utalloc.c (renamed from drivers/acpi/utilities/utalloc.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/utcopy.c (renamed from drivers/acpi/utilities/utcopy.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/utdebug.c (renamed from drivers/acpi/utilities/utdebug.c) | 95 | ||||
-rw-r--r-- | drivers/acpi/acpica/utdelete.c (renamed from drivers/acpi/utilities/utdelete.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/uteval.c (renamed from drivers/acpi/utilities/uteval.c) | 11 | ||||
-rw-r--r-- | drivers/acpi/acpica/utglobal.c (renamed from drivers/acpi/utilities/utglobal.c) | 12 | ||||
-rw-r--r-- | drivers/acpi/acpica/utinit.c (renamed from drivers/acpi/utilities/utinit.c) | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/utmath.c (renamed from drivers/acpi/utilities/utmath.c) | 1 | ||||
-rw-r--r-- | drivers/acpi/acpica/utmisc.c (renamed from drivers/acpi/utilities/utmisc.c) | 23 | ||||
-rw-r--r-- | drivers/acpi/acpica/utmutex.c (renamed from drivers/acpi/utilities/utmutex.c) | 1 | ||||
-rw-r--r-- | drivers/acpi/acpica/utobject.c (renamed from drivers/acpi/utilities/utobject.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/utresrc.c (renamed from drivers/acpi/utilities/utresrc.c) | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/utstate.c (renamed from drivers/acpi/utilities/utstate.c) | 1 | ||||
-rw-r--r-- | drivers/acpi/acpica/utxface.c (renamed from drivers/acpi/utilities/utxface.c) | 18 | ||||
-rw-r--r-- | drivers/acpi/battery.c | 5 | ||||
-rw-r--r-- | drivers/acpi/cm_sbs.c | 3 | ||||
-rw-r--r-- | drivers/acpi/debug.c | 1 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/Makefile | 9 | ||||
-rw-r--r-- | drivers/acpi/ec.c | 57 | ||||
-rw-r--r-- | drivers/acpi/events/Makefile | 9 | ||||
-rw-r--r-- | drivers/acpi/executer/Makefile | 10 | ||||
-rw-r--r-- | drivers/acpi/hardware/Makefile | 9 | ||||
-rw-r--r-- | drivers/acpi/main.c (renamed from drivers/acpi/sleep/main.c) | 79 | ||||
-rw-r--r-- | drivers/acpi/namespace/Makefile | 12 | ||||
-rw-r--r-- | drivers/acpi/numa.c | 1 | ||||
-rw-r--r-- | drivers/acpi/osl.c | 4 | ||||
-rw-r--r-- | drivers/acpi/parser/Makefile | 8 | ||||
-rw-r--r-- | drivers/acpi/pci_bind.c | 90 | ||||
-rw-r--r-- | drivers/acpi/pci_irq.c | 472 | ||||
-rw-r--r-- | drivers/acpi/pci_link.c | 6 | ||||
-rw-r--r-- | drivers/acpi/power.c | 6 | ||||
-rw-r--r-- | drivers/acpi/proc.c (renamed from drivers/acpi/sleep/proc.c) | 65 | ||||
-rw-r--r-- | drivers/acpi/reboot.c | 2 | ||||
-rw-r--r-- | drivers/acpi/resources/Makefile | 10 | ||||
-rw-r--r-- | drivers/acpi/sbshc.c | 1 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 1 | ||||
-rw-r--r-- | drivers/acpi/sleep.h (renamed from drivers/acpi/sleep/sleep.h) | 0 | ||||
-rw-r--r-- | drivers/acpi/sleep/Makefile | 5 | ||||
-rw-r--r-- | drivers/acpi/system.c | 63 | ||||
-rw-r--r-- | drivers/acpi/tables/Makefile | 7 | ||||
-rw-r--r-- | drivers/acpi/utilities/Makefile | 9 | ||||
-rw-r--r-- | drivers/acpi/utilities/utcache.c | 314 | ||||
-rw-r--r-- | drivers/acpi/video.c | 20 | ||||
-rw-r--r-- | drivers/acpi/video_detect.c | 4 | ||||
-rw-r--r-- | drivers/acpi/wakeup.c (renamed from drivers/acpi/sleep/wakeup.c) | 6 | ||||
-rw-r--r-- | drivers/ata/libata-acpi.c | 6 | ||||
-rw-r--r-- | drivers/ata/libata-core.c | 16 | ||||
-rw-r--r-- | drivers/ata/libata-sff.c | 24 | ||||
-rw-r--r-- | drivers/ata/pata_acpi.c | 6 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_bios.c | 2 | ||||
-rw-r--r-- | drivers/cpuidle/governors/menu.c | 10 | ||||
-rw-r--r-- | drivers/dca/dca-core.c | 2 | ||||
-rw-r--r-- | drivers/dma/Kconfig | 2 | ||||
-rw-r--r-- | drivers/dma/dmaengine.c | 778 | ||||
-rw-r--r-- | drivers/dma/dmatest.c | 129 | ||||
-rw-r--r-- | drivers/dma/dw_dmac.c | 119 | ||||
-rw-r--r-- | drivers/dma/fsldma.c | 5 | ||||
-rw-r--r-- | drivers/dma/ioat.c | 92 | ||||
-rw-r--r-- | drivers/dma/ioat_dma.c | 18 | ||||
-rw-r--r-- | drivers/dma/iop-adma.c | 30 | ||||
-rw-r--r-- | drivers/dma/mv_xor.c | 11 | ||||
-rw-r--r-- | drivers/ide/ide-acpi.c | 6 | ||||
-rw-r--r-- | drivers/misc/Kconfig | 284 | ||||
-rw-r--r-- | drivers/misc/Makefile | 13 | ||||
-rw-r--r-- | drivers/mmc/host/atmel-mci.c | 103 | ||||
-rw-r--r-- | drivers/mtd/Kconfig | 10 | ||||
-rw-r--r-- | drivers/mtd/Makefile | 2 | ||||
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0001.c | 12 | ||||
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0002.c | 18 | ||||
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0020.c | 14 | ||||
-rw-r--r-- | drivers/mtd/chips/fwh_lock.h | 4 | ||||
-rw-r--r-- | drivers/mtd/devices/lart.c | 6 | ||||
-rw-r--r-- | drivers/mtd/devices/m25p80.c | 41 | ||||
-rw-r--r-- | drivers/mtd/devices/mtd_dataflash.c | 24 | ||||
-rw-r--r-- | drivers/mtd/ftl.c | 100 | ||||
-rw-r--r-- | drivers/mtd/inftlcore.c | 2 | ||||
-rw-r--r-- | drivers/mtd/inftlmount.c | 4 | ||||
-rw-r--r-- | drivers/mtd/lpddr/Kconfig | 22 | ||||
-rw-r--r-- | drivers/mtd/lpddr/Makefile | 6 | ||||
-rw-r--r-- | drivers/mtd/lpddr/lpddr_cmds.c | 796 | ||||
-rw-r--r-- | drivers/mtd/lpddr/qinfo_probe.c | 255 | ||||
-rw-r--r-- | drivers/mtd/maps/Kconfig | 21 | ||||
-rw-r--r-- | drivers/mtd/maps/alchemy-flash.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/amd76xrom.c | 4 | ||||
-rw-r--r-- | drivers/mtd/maps/cfi_flagadm.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/ck804xrom.c | 4 | ||||
-rw-r--r-- | drivers/mtd/maps/dbox2-flash.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/edb7312.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/esb2rom.c | 4 | ||||
-rw-r--r-- | drivers/mtd/maps/fortunet.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/h720x-flash.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/ichxrom.c | 4 | ||||
-rw-r--r-- | drivers/mtd/maps/impa7.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/ipaq-flash.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/mbx860.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/nettel.c | 9 | ||||
-rw-r--r-- | drivers/mtd/maps/octagon-5066.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/physmap.c | 41 | ||||
-rw-r--r-- | drivers/mtd/maps/pmcmsp-flash.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/redwood.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/rpxlite.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/sbc8240.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/scb2_flash.c | 8 | ||||
-rw-r--r-- | drivers/mtd/maps/sharpsl-flash.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/tqm8xxl.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/uclinux.c | 4 | ||||
-rw-r--r-- | drivers/mtd/maps/vmax301.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/wr_sbc82xx_flash.c | 2 | ||||
-rw-r--r-- | drivers/mtd/mtdchar.c | 6 | ||||
-rw-r--r-- | drivers/mtd/mtdconcat.c | 35 | ||||
-rw-r--r-- | drivers/mtd/mtdcore.c | 16 | ||||
-rw-r--r-- | drivers/mtd/mtdoops.c | 9 | ||||
-rw-r--r-- | drivers/mtd/mtdpart.c | 34 | ||||
-rw-r--r-- | drivers/mtd/nand/Kconfig | 7 | ||||
-rw-r--r-- | drivers/mtd/nand/alauda.c | 6 | ||||
-rw-r--r-- | drivers/mtd/nand/cafe_nand.c | 7 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_elbc_nand.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 25 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 31 | ||||
-rw-r--r-- | drivers/mtd/nand/nandsim.c | 339 | ||||
-rw-r--r-- | drivers/mtd/nand/ndfc.c | 269 | ||||
-rw-r--r-- | drivers/mtd/nand/pxa3xx_nand.c | 6 | ||||
-rw-r--r-- | drivers/mtd/nand/sharpsl.c | 247 | ||||
-rw-r--r-- | drivers/mtd/nftlcore.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nftlmount.c | 4 | ||||
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 8 | ||||
-rw-r--r-- | drivers/mtd/rfd_ftl.c | 29 | ||||
-rw-r--r-- | drivers/mtd/ssfdc.c | 7 | ||||
-rw-r--r-- | drivers/mtd/tests/Makefile | 7 | ||||
-rw-r--r-- | drivers/mtd/tests/mtd_oobtest.c | 742 | ||||
-rw-r--r-- | drivers/mtd/tests/mtd_pagetest.c | 632 | ||||
-rw-r--r-- | drivers/mtd/tests/mtd_readtest.c | 253 | ||||
-rw-r--r-- | drivers/mtd/tests/mtd_speedtest.c | 502 | ||||
-rw-r--r-- | drivers/mtd/tests/mtd_stresstest.c | 330 | ||||
-rw-r--r-- | drivers/mtd/tests/mtd_subpagetest.c | 525 | ||||
-rw-r--r-- | drivers/mtd/tests/mtd_torturetest.c | 530 | ||||
-rw-r--r-- | drivers/mtd/ubi/build.c | 2 | ||||
-rw-r--r-- | drivers/mtd/ubi/gluebi.c | 17 | ||||
-rw-r--r-- | drivers/oprofile/buffer_sync.c | 188 | ||||
-rw-r--r-- | drivers/oprofile/cpu_buffer.c | 316 | ||||
-rw-r--r-- | drivers/oprofile/cpu_buffer.h | 89 | ||||
-rw-r--r-- | drivers/oprofile/event_buffer.c | 4 | ||||
-rw-r--r-- | drivers/oprofile/oprof.c | 4 | ||||
-rw-r--r-- | drivers/oprofile/oprof.h | 8 | ||||
-rw-r--r-- | drivers/oprofile/oprofile_files.c | 27 | ||||
-rw-r--r-- | drivers/parisc/asp.c | 3 | ||||
-rw-r--r-- | drivers/parisc/ccio-dma.c | 4 | ||||
-rw-r--r-- | drivers/parisc/dino.c | 4 | ||||
-rw-r--r-- | drivers/parisc/hppb.c | 2 | ||||
-rw-r--r-- | drivers/parisc/lasi.c | 5 | ||||
-rw-r--r-- | drivers/parisc/lba_pci.c | 2 | ||||
-rw-r--r-- | drivers/parisc/sba_iommu.c | 9 | ||||
-rw-r--r-- | drivers/parisc/wax.c | 3 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpi_pcihp.c | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 1 | ||||
-rw-r--r-- | drivers/pci/pci-acpi.c | 2 | ||||
-rw-r--r-- | drivers/platform/Kconfig | 5 | ||||
-rw-r--r-- | drivers/platform/Makefile | 5 | ||||
-rw-r--r-- | drivers/platform/x86/Kconfig | 375 | ||||
-rw-r--r-- | drivers/platform/x86/Makefile | 19 | ||||
-rw-r--r-- | drivers/platform/x86/acer-wmi.c (renamed from drivers/misc/acer-wmi.c) | 0 | ||||
-rw-r--r-- | drivers/platform/x86/asus-laptop.c (renamed from drivers/misc/asus-laptop.c) | 0 | ||||
-rw-r--r-- | drivers/platform/x86/asus_acpi.c (renamed from drivers/acpi/asus_acpi.c) | 0 | ||||
-rw-r--r-- | drivers/platform/x86/compal-laptop.c (renamed from drivers/misc/compal-laptop.c) | 0 | ||||
-rw-r--r-- | drivers/platform/x86/eeepc-laptop.c (renamed from drivers/misc/eeepc-laptop.c) | 0 | ||||
-rw-r--r-- | drivers/platform/x86/fujitsu-laptop.c (renamed from drivers/misc/fujitsu-laptop.c) | 419 | ||||
-rw-r--r-- | drivers/platform/x86/hp-wmi.c (renamed from drivers/misc/hp-wmi.c) | 0 | ||||
-rw-r--r-- | drivers/platform/x86/intel_menlow.c (renamed from drivers/misc/intel_menlow.c) | 0 | ||||
-rw-r--r-- | drivers/platform/x86/msi-laptop.c (renamed from drivers/misc/msi-laptop.c) | 0 | ||||
-rw-r--r-- | drivers/platform/x86/panasonic-laptop.c (renamed from drivers/misc/panasonic-laptop.c) | 22 | ||||
-rw-r--r-- | drivers/platform/x86/sony-laptop.c (renamed from drivers/misc/sony-laptop.c) | 15 | ||||
-rw-r--r-- | drivers/platform/x86/tc1100-wmi.c (renamed from drivers/misc/tc1100-wmi.c) | 1 | ||||
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c (renamed from drivers/misc/thinkpad_acpi.c) | 1 | ||||
-rw-r--r-- | drivers/platform/x86/toshiba_acpi.c (renamed from drivers/acpi/toshiba_acpi.c) | 0 | ||||
-rw-r--r-- | drivers/platform/x86/wmi.c (renamed from drivers/acpi/wmi.c) | 0 | ||||
-rw-r--r-- | drivers/pnp/pnpacpi/core.c | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-parisc.c | 3 | ||||
-rw-r--r-- | fs/jffs2/compr_rubin.c | 120 | ||||
-rw-r--r-- | fs/jffs2/erase.c | 5 | ||||
-rw-r--r-- | include/acpi/acdisasm.h | 445 | ||||
-rw-r--r-- | include/acpi/acexcep.h | 6 | ||||
-rw-r--r-- | include/acpi/acoutput.h | 103 | ||||
-rw-r--r-- | include/acpi/acpi.h | 31 | ||||
-rw-r--r-- | include/acpi/acpiosxf.h | 13 | ||||
-rw-r--r-- | include/acpi/acpixf.h | 100 | ||||
-rw-r--r-- | include/acpi/acrestyp.h | 405 | ||||
-rw-r--r-- | include/acpi/actbl.h | 25 | ||||
-rw-r--r-- | include/acpi/actbl1.h | 2 | ||||
-rw-r--r-- | include/acpi/actypes.h | 557 | ||||
-rw-r--r-- | include/acpi/platform/acenv.h | 45 | ||||
-rw-r--r-- | include/acpi/platform/aclinux.h | 4 | ||||
-rw-r--r-- | include/linux/acpi.h | 17 | ||||
-rw-r--r-- | include/linux/async_tx.h | 17 | ||||
-rw-r--r-- | include/linux/atmel-mci.h | 6 | ||||
-rw-r--r-- | include/linux/dmaengine.h | 181 | ||||
-rw-r--r-- | include/linux/dw_dmac.h | 31 | ||||
-rw-r--r-- | include/linux/mtd/cfi.h | 1 | ||||
-rw-r--r-- | include/linux/mtd/ftl.h | 38 | ||||
-rw-r--r-- | include/linux/mtd/map.h | 1 | ||||
-rw-r--r-- | include/linux/mtd/mtd.h | 75 | ||||
-rw-r--r-- | include/linux/mtd/nand.h | 7 | ||||
-rw-r--r-- | include/linux/mtd/partitions.h | 6 | ||||
-rw-r--r-- | include/linux/mtd/pfow.h | 159 | ||||
-rw-r--r-- | include/linux/mtd/physmap.h | 1 | ||||
-rw-r--r-- | include/linux/mtd/qinfo.h | 91 | ||||
-rw-r--r-- | include/linux/mtd/sharpsl.h | 20 | ||||
-rw-r--r-- | include/linux/netdevice.h | 3 | ||||
-rw-r--r-- | include/linux/oprofile.h | 18 | ||||
-rw-r--r-- | include/linux/pci_hotplug.h | 1 | ||||
-rw-r--r-- | include/linux/suspend.h | 13 | ||||
-rw-r--r-- | include/net/netdma.h | 11 | ||||
-rw-r--r-- | kernel/cred.c | 2 | ||||
-rw-r--r-- | kernel/power/disk.c | 6 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 370 | ||||
-rw-r--r-- | kernel/power/swsusp.c | 122 | ||||
-rw-r--r-- | kernel/trace/ring_buffer.c | 8 | ||||
-rw-r--r-- | net/core/dev.c | 149 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 5 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 2 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 2 |
392 files changed, 12961 insertions, 6922 deletions
diff --git a/Documentation/crypto/async-tx-api.txt b/Documentation/crypto/async-tx-api.txt index c1e9545c59bd..9f59fcbf5d82 100644 --- a/Documentation/crypto/async-tx-api.txt +++ b/Documentation/crypto/async-tx-api.txt @@ -13,9 +13,9 @@ 3.6 Constraints 3.7 Example -4 DRIVER DEVELOPER NOTES +4 DMAENGINE DRIVER DEVELOPER NOTES 4.1 Conformance points -4.2 "My application needs finer control of hardware channels" +4.2 "My application needs exclusive control of hardware channels" 5 SOURCE @@ -150,6 +150,7 @@ ops_run_* and ops_complete_* routines in drivers/md/raid5.c for more implementation examples. 4 DRIVER DEVELOPMENT NOTES + 4.1 Conformance points: There are a few conformance points required in dmaengine drivers to accommodate assumptions made by applications using the async_tx API: @@ -158,58 +159,49 @@ accommodate assumptions made by applications using the async_tx API: 3/ Use async_tx_run_dependencies() in the descriptor clean up path to handle submission of dependent operations -4.2 "My application needs finer control of hardware channels" -This requirement seems to arise from cases where a DMA engine driver is -trying to support device-to-memory DMA. The dmaengine and async_tx -implementations were designed for offloading memory-to-memory -operations; however, there are some capabilities of the dmaengine layer -that can be used for platform-specific channel management. -Platform-specific constraints can be handled by registering the -application as a 'dma_client' and implementing a 'dma_event_callback' to -apply a filter to the available channels in the system. Before showing -how to implement a custom dma_event callback some background of -dmaengine's client support is required. - -The following routines in dmaengine support multiple clients requesting -use of a channel: -- dma_async_client_register(struct dma_client *client) -- dma_async_client_chan_request(struct dma_client *client) - -dma_async_client_register takes a pointer to an initialized dma_client -structure. It expects that the 'event_callback' and 'cap_mask' fields -are already initialized. - -dma_async_client_chan_request triggers dmaengine to notify the client of -all channels that satisfy the capability mask. It is up to the client's -event_callback routine to track how many channels the client needs and -how many it is currently using. The dma_event_callback routine returns a -dma_state_client code to let dmaengine know the status of the -allocation. - -Below is the example of how to extend this functionality for -platform-specific filtering of the available channels beyond the -standard capability mask: - -static enum dma_state_client -my_dma_client_callback(struct dma_client *client, - struct dma_chan *chan, enum dma_state state) -{ - struct dma_device *dma_dev; - struct my_platform_specific_dma *plat_dma_dev; - - dma_dev = chan->device; - plat_dma_dev = container_of(dma_dev, - struct my_platform_specific_dma, - dma_dev); - - if (!plat_dma_dev->platform_specific_capability) - return DMA_DUP; - - . . . -} +4.2 "My application needs exclusive control of hardware channels" +Primarily this requirement arises from cases where a DMA engine driver +is being used to support device-to-memory operations. A channel that is +performing these operations cannot, for many platform specific reasons, +be shared. For these cases the dma_request_channel() interface is +provided. + +The interface is: +struct dma_chan *dma_request_channel(dma_cap_mask_t mask, + dma_filter_fn filter_fn, + void *filter_param); + +Where dma_filter_fn is defined as: +typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param); + +When the optional 'filter_fn' parameter is set to NULL +dma_request_channel simply returns the first channel that satisfies the +capability mask. Otherwise, when the mask parameter is insufficient for +specifying the necessary channel, the filter_fn routine can be used to +disposition the available channels in the system. The filter_fn routine +is called once for each free channel in the system. Upon seeing a +suitable channel filter_fn returns DMA_ACK which flags that channel to +be the return value from dma_request_channel. A channel allocated via +this interface is exclusive to the caller, until dma_release_channel() +is called. + +The DMA_PRIVATE capability flag is used to tag dma devices that should +not be used by the general-purpose allocator. It can be set at +initialization time if it is known that a channel will always be +private. Alternatively, it is set when dma_request_channel() finds an +unused "public" channel. + +A couple caveats to note when implementing a driver and consumer: +1/ Once a channel has been privately allocated it will no longer be + considered by the general-purpose allocator even after a call to + dma_release_channel(). +2/ Since capabilities are specified at the device level a dma_device + with multiple channels will either have all channels public, or all + channels private. 5 SOURCE -include/linux/dmaengine.h: core header file for DMA drivers and clients + +include/linux/dmaengine.h: core header file for DMA drivers and api users drivers/dma/dmaengine.c: offload engine channel management routines drivers/dma/: location for offload engine drivers include/linux/async_tx.h: core header file for the async_tx api diff --git a/Documentation/dmaengine.txt b/Documentation/dmaengine.txt new file mode 100644 index 000000000000..0c1c2f63c0a9 --- /dev/null +++ b/Documentation/dmaengine.txt @@ -0,0 +1 @@ +See Documentation/crypto/async-tx-api.txt diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index fb849020aea9..fcc48bf722a8 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -141,6 +141,7 @@ and is between 256 and 4096 characters. It is defined in the file ht -- run only enough ACPI to enable Hyper Threading strict -- Be less tolerant of platforms that are not strictly ACPI specification compliant. + rsdt -- prefer RSDT over (default) XSDT See also Documentation/power/pm.txt, pci=noacpi @@ -151,16 +152,20 @@ and is between 256 and 4096 characters. It is defined in the file default: 0 acpi_sleep= [HW,ACPI] Sleep options - Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering } - See Documentation/power/video.txt for s3_bios and s3_mode. + Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, + old_ordering, s4_nonvs } + See Documentation/power/video.txt for information on + s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep as soon as the kernel's real-mode entry point is called. s4_nohwsig prevents ACPI hardware signature from being used during resume from hibernation. old_ordering causes the ACPI 1.0 ordering of the _PTS - control method, wrt putting devices into low power - states, to be enforced (the ACPI 2.0 ordering of _PTS is - used by default). + control method, with respect to putting devices into + low power states, to be enforced (the ACPI 2.0 ordering + of _PTS is used by default). + s4_nonvs prevents the kernel from saving/restoring the + ACPI NVS memory during hibernation. acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode Format: { level | edge | high | low } @@ -195,7 +200,7 @@ and is between 256 and 4096 characters. It is defined in the file acpi_skip_timer_override [HW,ACPI] Recognize and ignore IRQ0/pin2 Interrupt Override. For broken nForce2 BIOS resulting in XT-PIC timer. - acpi_use_timer_override [HW,ACPI} + acpi_use_timer_override [HW,ACPI] Use timer override. For some broken Nvidia NF5 boards that require a timer override, but don't have HPET @@ -878,17 +883,19 @@ and is between 256 and 4096 characters. It is defined in the file See Documentation/ide/ide.txt. idle= [X86] - Format: idle=poll or idle=mwait, idle=halt, idle=nomwait - Poll forces a polling idle loop that can slightly improves the performance - of waking up a idle CPU, but will use a lot of power and make the system - run hot. Not recommended. - idle=mwait. On systems which support MONITOR/MWAIT but the kernel chose - to not use it because it doesn't save as much power as a normal idle - loop use the MONITOR/MWAIT idle loop anyways. Performance should be the same - as idle=poll. - idle=halt. Halt is forced to be used for CPU idle. + Format: idle=poll, idle=mwait, idle=halt, idle=nomwait + Poll forces a polling idle loop that can slightly + improve the performance of waking up a idle CPU, but + will use a lot of power and make the system run hot. + Not recommended. + idle=mwait: On systems which support MONITOR/MWAIT but + the kernel chose to not use it because it doesn't save + as much power as a normal idle loop, use the + MONITOR/MWAIT idle loop anyways. Performance should be + the same as idle=poll. + idle=halt: Halt is forced to be used for CPU idle. In such case C2/C3 won't be used again. - idle=nomwait. Disable mwait for CPU C-states + idle=nomwait: Disable mwait for CPU C-states ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem Claim all unknown PCI IDE storage controllers. @@ -1074,8 +1081,8 @@ and is between 256 and 4096 characters. It is defined in the file lapic [X86-32,APIC] Enable the local APIC even if BIOS disabled it. - lapic_timer_c2_ok [X86-32,x86-64,APIC] trust the local apic timer in - C2 power state. + lapic_timer_c2_ok [X86-32,x86-64,APIC] trust the local apic timer + in C2 power state. libata.dma= [LIBATA] DMA control libata.dma=0 Disable all PATA and SATA DMA @@ -2303,7 +2310,8 @@ and is between 256 and 4096 characters. It is defined in the file thermal.psv= [HW,ACPI] -1: disable all passive trip points - <degrees C>: override all passive trip points to this value + <degrees C>: override all passive trip points to this + value thermal.tzp= [HW,ACPI] Specify global default ACPI thermal zone polling rate diff --git a/Documentation/powerpc/dts-bindings/4xx/ndfc.txt b/Documentation/powerpc/dts-bindings/4xx/ndfc.txt new file mode 100644 index 000000000000..869f0b5f16e8 --- /dev/null +++ b/Documentation/powerpc/dts-bindings/4xx/ndfc.txt @@ -0,0 +1,39 @@ +AMCC NDFC (NanD Flash Controller) + +Required properties: +- compatible : "ibm,ndfc". +- reg : should specify chip select and size used for the chip (0x2000). + +Optional properties: +- ccr : NDFC config and control register value (default 0). +- bank-settings : NDFC bank configuration register value (default 0). + +Notes: +- partition(s) - follows the OF MTD standard for partitions + +Example: + +ndfc@1,0 { + compatible = "ibm,ndfc"; + reg = <0x00000001 0x00000000 0x00002000>; + ccr = <0x00001000>; + bank-settings = <0x80002222>; + #address-cells = <1>; + #size-cells = <1>; + + nand { + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "kernel"; + reg = <0x00000000 0x00200000>; + }; + partition@200000 { + label = "root"; + reg = <0x00200000 0x03E00000>; + }; + }; +}; + + diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index c5e28a46b292..a8d91b6c136b 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -27,6 +27,7 @@ #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> #include <linux/spi/corgi_lcd.h> +#include <linux/mtd/sharpsl.h> #include <video/w100fb.h> #include <asm/setup.h> @@ -542,6 +543,55 @@ err_free_1: static inline void corgi_init_spi(void) {} #endif +static struct mtd_partition sharpsl_nand_partitions[] = { + { + .name = "System Area", + .offset = 0, + .size = 7 * 1024 * 1024, + }, + { + .name = "Root Filesystem", + .offset = 7 * 1024 * 1024, + .size = 25 * 1024 * 1024, + }, + { + .name = "Home Filesystem", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; + +static struct nand_bbt_descr sharpsl_bbt = { + .options = 0, + .offs = 4, + .len = 2, + .pattern = scan_ff_pattern +}; + +static struct sharpsl_nand_platform_data sharpsl_nand_platform_data = { + .badblock_pattern = &sharpsl_bbt, + .partitions = sharpsl_nand_partitions, + .nr_partitions = ARRAY_SIZE(sharpsl_nand_partitions), +}; + +static struct resource sharpsl_nand_resources[] = { + { + .start = 0x0C000000, + .end = 0x0C000FFF, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device sharpsl_nand_device = { + .name = "sharpsl-nand", + .id = -1, + .resource = sharpsl_nand_resources, + .num_resources = ARRAY_SIZE(sharpsl_nand_resources), + .dev.platform_data = &sharpsl_nand_platform_data, +}; + static struct mtd_partition sharpsl_rom_parts[] = { { .name ="Boot PROM Filesystem", @@ -577,6 +627,7 @@ static struct platform_device *devices[] __initdata = { &corgifb_device, &corgikbd_device, &corgiled_device, + &sharpsl_nand_device, &sharpsl_rom_device, }; @@ -617,6 +668,9 @@ static void __init corgi_init(void) platform_scoop_config = &corgi_pcmcia_config; + if (machine_is_husky()) + sharpsl_nand_partitions[1].size = 53 * 1024 * 1024; + platform_add_devices(devices, ARRAY_SIZE(devices)); } diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index ae88855bf974..f9093beba752 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -24,6 +24,7 @@ #include <linux/gpio.h> #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> +#include <linux/mtd/sharpsl.h> #include <mach/hardware.h> #include <asm/mach-types.h> @@ -414,6 +415,55 @@ static struct pxafb_mach_info poodle_fb_info = { .lcd_conn = LCD_COLOR_TFT_16BPP, }; +static struct mtd_partition sharpsl_nand_partitions[] = { + { + .name = "System Area", + .offset = 0, + .size = 7 * 1024 * 1024, + }, + { + .name = "Root Filesystem", + .offset = 7 * 1024 * 1024, + .size = 22 * 1024 * 1024, + }, + { + .name = "Home Filesystem", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; + +static struct nand_bbt_descr sharpsl_bbt = { + .options = 0, + .offs = 4, + .len = 2, + .pattern = scan_ff_pattern +}; + +static struct sharpsl_nand_platform_data sharpsl_nand_platform_data = { + .badblock_pattern = &sharpsl_bbt, + .partitions = sharpsl_nand_partitions, + .nr_partitions = ARRAY_SIZE(sharpsl_nand_partitions), +}; + +static struct resource sharpsl_nand_resources[] = { + { + .start = 0x0C000000, + .end = 0x0C000FFF, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device sharpsl_nand_device = { + .name = "sharpsl-nand", + .id = -1, + .resource = sharpsl_nand_resources, + .num_resources = ARRAY_SIZE(sharpsl_nand_resources), + .dev.platform_data = &sharpsl_nand_platform_data, +}; + static struct mtd_partition sharpsl_rom_parts[] = { { .name ="Boot PROM Filesystem", @@ -447,6 +497,7 @@ static struct platform_device sharpsl_rom_device = { static struct platform_device *devices[] __initdata = { &poodle_locomo_device, &poodle_scoop_device, + &sharpsl_nand_device, &sharpsl_rom_device, }; diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 7299d87a1cb3..6d447c9ce8ab 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -31,6 +31,7 @@ #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> #include <linux/spi/corgi_lcd.h> +#include <linux/mtd/sharpsl.h> #include <asm/setup.h> #include <asm/memory.h> @@ -613,6 +614,54 @@ static struct pxafb_mach_info spitz_pxafb_info = { .lcd_conn = LCD_COLOR_TFT_16BPP | LCD_ALTERNATE_MAPPING, }; +static struct mtd_partition sharpsl_nand_partitions[] = { + { + .name = "System Area", + .offset = 0, + .size = 7 * 1024 * 1024, + }, + { + .name = "Root Filesystem", + .offset = 7 * 1024 * 1024, + }, + { + .name = "Home Filesystem", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; + +static struct nand_bbt_descr sharpsl_bbt = { + .options = 0, + .offs = 4, + .len = 2, + .pattern = scan_ff_pattern +}; + +static struct sharpsl_nand_platform_data sharpsl_nand_platform_data = { + .badblock_pattern = &sharpsl_bbt, + .partitions = sharpsl_nand_partitions, + .nr_partitions = ARRAY_SIZE(sharpsl_nand_partitions), +}; + +static struct resource sharpsl_nand_resources[] = { + { + .start = 0x0C000000, + .end = 0x0C000FFF, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device sharpsl_nand_device = { + .name = "sharpsl-nand", + .id = -1, + .resource = sharpsl_nand_resources, + .num_resources = ARRAY_SIZE(sharpsl_nand_resources), + .dev.platform_data = &sharpsl_nand_platform_data, +}; + static struct mtd_partition sharpsl_rom_parts[] = { { @@ -648,6 +697,7 @@ static struct platform_device *devices[] __initdata = { &spitzscoop_device, &spitzkbd_device, &spitzled_device, + &sharpsl_nand_device, &sharpsl_rom_device, }; @@ -671,6 +721,14 @@ static void __init common_init(void) pm_power_off = spitz_poweroff; arm_pm_restart = spitz_restart; + if (machine_is_spitz()) { + sharpsl_nand_partitions[1].size = 5 * 1024 * 1024; + } else if (machine_is_akita()) { + sharpsl_nand_partitions[1].size = 58 * 1024 * 1024; + } else if (machine_is_borzoi()) { + sharpsl_nand_partitions[1].size = 32 * 1024 * 1024; + } + PMCR = 0x00; /* Stop 3.6MHz and drive HIGH to PCMCIA and CS */ @@ -715,10 +773,29 @@ static struct i2c_board_info akita_i2c_board_info[] = { }, }; +static struct nand_bbt_descr sharpsl_akita_bbt = { + .options = 0, + .offs = 4, + .len = 1, + .pattern = scan_ff_pattern +}; + +static struct nand_ecclayout akita_oobinfo = { + .eccbytes = 24, + .eccpos = { + 0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11, + 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23, + 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37}, + .oobfree = {{0x08, 0x09}} +}; + static void __init akita_init(void) { spitz_ficp_platform_data.transceiver_mode = akita_irda_transceiver_mode; + sharpsl_nand_platform_data.badblock_pattern = &sharpsl_akita_bbt; + sharpsl_nand_platform_data.ecc_layout = &akita_oobinfo; + /* We just pretend the second element of the array doesn't exist */ spitz_pcmcia_config.num_devs = 1; platform_scoop_config = &spitz_pcmcia_config; diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c index ea7bc1e8562b..3fbfd1e32a9e 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c @@ -1305,7 +1305,7 @@ struct platform_device *__init at32_add_device_mci(unsigned int id, struct mci_platform_data *data) { struct platform_device *pdev; - struct dw_dma_slave *dws; + struct dw_dma_slave *dws = &data->dma_slave; u32 pioa_mask; u32 piob_mask; @@ -1324,22 +1324,13 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data) ARRAY_SIZE(atmel_mci0_resource))) goto fail; - if (data->dma_slave) - dws = kmemdup(to_dw_dma_slave(data->dma_slave), - sizeof(struct dw_dma_slave), GFP_KERNEL); - else - dws = kzalloc(sizeof(struct dw_dma_slave), GFP_KERNEL); - - dws->slave.dev = &pdev->dev; - dws->slave.dma_dev = &dw_dmac0_device.dev; - dws->slave.reg_width = DMA_SLAVE_WIDTH_32BIT; + dws->dma_dev = &dw_dmac0_device.dev; + dws->reg_width = DW_DMA_SLAVE_WIDTH_32BIT; dws->cfg_hi = (DWC_CFGH_SRC_PER(0) | DWC_CFGH_DST_PER(1)); dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL); - data->dma_slave = &dws->slave; - if (platform_device_add_data(pdev, data, sizeof(struct mci_platform_data))) goto fail; diff --git a/arch/ia64/include/asm/acpi-ext.h b/arch/ia64/include/asm/acpi-ext.h index 734d137dda6e..7f8362b379eb 100644 --- a/arch/ia64/include/asm/acpi-ext.h +++ b/arch/ia64/include/asm/acpi-ext.h @@ -14,7 +14,6 @@ #define _ASM_IA64_ACPI_EXT_H #include <linux/types.h> -#include <acpi/actypes.h> extern acpi_status hp_acpi_csr_space (acpi_handle, u64 *base, u64 *length); diff --git a/arch/ia64/include/asm/sn/acpi.h b/arch/ia64/include/asm/sn/acpi.h index 9ce2801cbd57..fd480db25565 100644 --- a/arch/ia64/include/asm/sn/acpi.h +++ b/arch/ia64/include/asm/sn/acpi.h @@ -9,8 +9,6 @@ #ifndef _ASM_IA64_SN_ACPI_H #define _ASM_IA64_SN_ACPI_H -#include "acpi/acglobal.h" - extern int sn_acpi_rev; #define SN_ACPI_BASE_SUPPORT() (sn_acpi_rev >= 0x20101) diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 0553648b7595..d541671caf4a 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -65,6 +65,7 @@ EXPORT_SYMBOL(pm_idle); void (*pm_power_off) (void); EXPORT_SYMBOL(pm_power_off); +u32 acpi_rsdt_forced; unsigned int acpi_cpei_override; unsigned int acpi_cpei_phys_cpuid; diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c index bc610a6c7851..c5a214026a77 100644 --- a/arch/ia64/sn/kernel/io_acpi_init.c +++ b/arch/ia64/sn/kernel/io_acpi_init.c @@ -13,7 +13,6 @@ #include <asm/sn/sn_sal.h> #include "xtalk/hubdev.h" #include <linux/acpi.h> -#include <acpi/acnamesp.h> /* @@ -64,6 +63,7 @@ static acpi_status __init sn_acpi_hubdev_init(acpi_handle handle, u32 depth, void *context, void **ret) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; u64 addr; struct hubdev_info *hubdev; struct hubdev_info *hubdev_ptr; @@ -77,11 +77,12 @@ sn_acpi_hubdev_init(acpi_handle handle, u32 depth, void *context, void **ret) status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS, &sn_uuid, &buffer); if (ACPI_FAILURE(status)) { + acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); printk(KERN_ERR "sn_acpi_hubdev_init: acpi_get_vendor_resource() " - "(0x%x) failed for: ", status); - acpi_ns_print_node_pathname(handle, NULL); - printk("\n"); + "(0x%x) failed for: %s\n", status, + (char *)name_buffer.pointer); + kfree(name_buffer.pointer); return AE_OK; /* Continue walking namespace */ } @@ -89,11 +90,12 @@ sn_acpi_hubdev_init(acpi_handle handle, u32 depth, void *context, void **ret) vendor = &resource->data.vendor_typed; if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) != sizeof(struct hubdev_info *)) { + acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); printk(KERN_ERR - "sn_acpi_hubdev_init: Invalid vendor data length: %d for: ", - vendor->byte_length); - acpi_ns_print_node_pathname(handle, NULL); - printk("\n"); + "sn_acpi_hubdev_init: Invalid vendor data length: " + "%d for: %s\n", + vendor->byte_length, (char *)name_buffer.pointer); + kfree(name_buffer.pointer); goto exit; } @@ -120,6 +122,7 @@ sn_get_bussoft_ptr(struct pci_bus *bus) { u64 addr; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; acpi_handle handle; struct pcibus_bussoft *prom_bussoft_ptr; struct acpi_resource *resource; @@ -131,11 +134,11 @@ sn_get_bussoft_ptr(struct pci_bus *bus) status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS, &sn_uuid, &buffer); if (ACPI_FAILURE(status)) { + acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); printk(KERN_ERR "%s: " - "acpi_get_vendor_resource() failed (0x%x) for: ", - __func__, status); - acpi_ns_print_node_pathname(handle, NULL); - printk("\n"); + "acpi_get_vendor_resource() failed (0x%x) for: %s\n", + __func__, status, (char *)name_buffer.pointer); + kfree(name_buffer.pointer); return NULL; } resource = buffer.pointer; @@ -168,6 +171,7 @@ sn_extract_device_info(acpi_handle handle, struct pcidev_info **pcidev_info, { u64 addr; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct sn_irq_info *irq_info, *irq_info_prom; struct pcidev_info *pcidev_ptr, *pcidev_prom_ptr; struct acpi_resource *resource; @@ -182,11 +186,11 @@ sn_extract_device_info(acpi_handle handle, struct pcidev_info **pcidev_info, status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS, &sn_uuid, &buffer); if (ACPI_FAILURE(status)) { + acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); printk(KERN_ERR - "%s: acpi_get_vendor_resource() failed (0x%x) for: ", - __func__, status); - acpi_ns_print_node_pathname(handle, NULL); - printk("\n"); + "%s: acpi_get_vendor_resource() failed (0x%x) for: %s\n", + __func__, status, (char *)name_buffer.pointer); + kfree(name_buffer.pointer); return 1; } @@ -194,11 +198,12 @@ sn_extract_device_info(acpi_handle handle, struct pcidev_info **pcidev_info, vendor = &resource->data.vendor_typed; if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) != sizeof(struct pci_devdev_info *)) { + acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); printk(KERN_ERR - "%s: Invalid vendor data length: %d for: ", - __func__, vendor->byte_length); - acpi_ns_print_node_pathname(handle, NULL); - printk("\n"); + "%s: Invalid vendor data length: %d for: %s\n", + __func__, vendor->byte_length, + (char *)name_buffer.pointer); + kfree(name_buffer.pointer); ret = 1; goto exit; } @@ -239,6 +244,9 @@ get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle) acpi_handle parent; int slot; acpi_status status; + struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + acpi_get_name(device_handle, ACPI_FULL_PATHNAME, &name_buffer); /* * Do an upward search to find the root bus device, and @@ -249,9 +257,8 @@ get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle) status = acpi_get_parent(child, &parent); if (ACPI_FAILURE(status)) { printk(KERN_ERR "%s: acpi_get_parent() failed " - "(0x%x) for: ", __func__, status); - acpi_ns_print_node_pathname(child, NULL); - printk("\n"); + "(0x%x) for: %s\n", __func__, status, + (char *)name_buffer.pointer); panic("%s: Unable to find host devfn\n", __func__); } if (parent == rootbus_handle) @@ -259,22 +266,20 @@ get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle) child = parent; } if (!child) { - printk(KERN_ERR "%s: Unable to find root bus for: ", - __func__); - acpi_ns_print_node_pathname(device_handle, NULL); - printk("\n"); + printk(KERN_ERR "%s: Unable to find root bus for: %s\n", + __func__, (char *)name_buffer.pointer); BUG(); } status = acpi_evaluate_integer(child, METHOD_NAME__ADR, NULL, &adr); if (ACPI_FAILURE(status)) { - printk(KERN_ERR "%s: Unable to get _ADR (0x%x) for: ", - __func__, status); - acpi_ns_print_node_pathname(child, NULL); - printk("\n"); + printk(KERN_ERR "%s: Unable to get _ADR (0x%x) for: %s\n", + __func__, status, (char *)name_buffer.pointer); panic("%s: Unable to find host devfn\n", __func__); } + kfree(name_buffer.pointer); + slot = (adr >> 16) & 0xffff; function = adr & 0xffff; devfn = PCI_DEVFN(slot, function); @@ -300,27 +305,28 @@ find_matching_device(acpi_handle handle, u32 lvl, void *context, void **rv) int function; int slot; struct sn_pcidev_match *info = context; + struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); if (ACPI_SUCCESS(status)) { status = acpi_get_parent(handle, &parent); if (ACPI_FAILURE(status)) { + acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); printk(KERN_ERR - "%s: acpi_get_parent() failed (0x%x) for: ", - __func__, status); - acpi_ns_print_node_pathname(handle, NULL); - printk("\n"); + "%s: acpi_get_parent() failed (0x%x) for: %s\n", + __func__, status, (char *)name_buffer.pointer); + kfree(name_buffer.pointer); return AE_OK; } status = acpi_evaluate_integer(parent, METHOD_NAME__BBN, NULL, &bbn); if (ACPI_FAILURE(status)) { + acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); printk(KERN_ERR - "%s: Failed to find _BBN in parent of: ", - __func__); - acpi_ns_print_node_pathname(handle, NULL); - printk("\n"); + "%s: Failed to find _BBN in parent of: %s\n", + __func__, (char *)name_buffer.pointer); + kfree(name_buffer.pointer); return AE_OK; } @@ -350,24 +356,27 @@ sn_acpi_get_pcidev_info(struct pci_dev *dev, struct pcidev_info **pcidev_info, acpi_handle rootbus_handle; unsigned long long segment; acpi_status status; + struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; rootbus_handle = PCI_CONTROLLER(dev)->acpi_handle; status = acpi_evaluate_integer(rootbus_handle, METHOD_NAME__SEG, NULL, &segment); if (ACPI_SUCCESS(status)) { if (segment != pci_domain_nr(dev)) { + acpi_get_name(rootbus_handle, ACPI_FULL_PATHNAME, + &name_buffer); printk(KERN_ERR - "%s: Segment number mismatch, 0x%llx vs 0x%x for: ", - __func__, segment, pci_domain_nr(dev)); - acpi_ns_print_node_pathname(rootbus_handle, NULL); - printk("\n"); + "%s: Segment number mismatch, 0x%llx vs 0x%x for: %s\n", + __func__, segment, pci_domain_nr(dev), + (char *)name_buffer.pointer); + kfree(name_buffer.pointer); return 1; } } else { - printk(KERN_ERR "%s: Unable to get __SEG from: ", - __func__); - acpi_ns_print_node_pathname(rootbus_handle, NULL); - printk("\n"); + acpi_get_name(rootbus_handle, ACPI_FULL_PATHNAME, &name_buffer); + printk(KERN_ERR "%s: Unable to get __SEG from: %s\n", + __func__, (char *)name_buffer.pointer); + kfree(name_buffer.pointer); return 1; } diff --git a/arch/ia64/sn/kernel/io_common.c b/arch/ia64/sn/kernel/io_common.c index 8a924a5661dd..0d4ffa4da1da 100644 --- a/arch/ia64/sn/kernel/io_common.c +++ b/arch/ia64/sn/kernel/io_common.c @@ -26,7 +26,6 @@ #include <linux/acpi.h> #include <asm/sn/sn2/sn_hwperf.h> #include <asm/sn/acpi.h> -#include "acpi/acglobal.h" extern void sn_init_cpei_timer(void); extern void register_sn_procfs(void); @@ -473,7 +472,7 @@ sn_io_early_init(void) { struct acpi_table_header *header = NULL; - acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header); + acpi_get_table(ACPI_SIG_DSDT, 1, &header); BUG_ON(header == NULL); sn_acpi_rev = header->oem_revision; } @@ -505,7 +504,7 @@ sn_io_early_init(void) { struct acpi_table_header *header; - (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header); + (void)acpi_get_table(ACPI_SIG_DSDT, 1, &header); printk(KERN_INFO "ACPI DSDT OEM Rev 0x%x\n", header->oem_revision); } diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile index 5ddad7bd60ac..0d428278356d 100644 --- a/arch/parisc/Makefile +++ b/arch/parisc/Makefile @@ -77,7 +77,7 @@ libs-y += arch/parisc/lib/ `$(CC) -print-libgcc-file-name` drivers-$(CONFIG_OPROFILE) += arch/parisc/oprofile/ -PALO := $(shell if which palo; then : ; \ +PALO := $(shell if (which palo 2>&1); then : ; \ elif [ -x /sbin/palo ]; then echo /sbin/palo; \ fi) diff --git a/arch/parisc/include/asm/Kbuild b/arch/parisc/include/asm/Kbuild index f88b252e419c..2121d99f8364 100644 --- a/arch/parisc/include/asm/Kbuild +++ b/arch/parisc/include/asm/Kbuild @@ -1,3 +1,4 @@ include include/asm-generic/Kbuild.asm unifdef-y += pdc.h +unifdef-y += swab.h diff --git a/arch/parisc/include/asm/byteorder.h b/arch/parisc/include/asm/byteorder.h index db148313de5d..da66029c4cb2 100644 --- a/arch/parisc/include/asm/byteorder.h +++ b/arch/parisc/include/asm/byteorder.h @@ -1,82 +1,7 @@ #ifndef _PARISC_BYTEORDER_H #define _PARISC_BYTEORDER_H -#include <asm/types.h> -#include <linux/compiler.h> - -#ifdef __GNUC__ - -static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x) -{ - __asm__("dep %0, 15, 8, %0\n\t" /* deposit 00ab -> 0bab */ - "shd %%r0, %0, 8, %0" /* shift 000000ab -> 00ba */ - : "=r" (x) - : "0" (x)); - return x; -} - -static __inline__ __attribute_const__ __u32 ___arch__swab24(__u32 x) -{ - __asm__("shd %0, %0, 8, %0\n\t" /* shift xabcxabc -> cxab */ - "dep %0, 15, 8, %0\n\t" /* deposit cxab -> cbab */ - "shd %%r0, %0, 8, %0" /* shift 0000cbab -> 0cba */ - : "=r" (x) - : "0" (x)); - return x; -} - -static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x) -{ - unsigned int temp; - __asm__("shd %0, %0, 16, %1\n\t" /* shift abcdabcd -> cdab */ - "dep %1, 15, 8, %1\n\t" /* deposit cdab -> cbab */ - "shd %0, %1, 8, %0" /* shift abcdcbab -> dcba */ - : "=r" (x), "=&r" (temp) - : "0" (x)); - return x; -} - - -#if BITS_PER_LONG > 32 -/* -** From "PA-RISC 2.0 Architecture", HP Professional Books. -** See Appendix I page 8 , "Endian Byte Swapping". -** -** Pretty cool algorithm: (* == zero'd bits) -** PERMH 01234567 -> 67452301 into %0 -** HSHL 67452301 -> 7*5*3*1* into %1 -** HSHR 67452301 -> *6*4*2*0 into %0 -** OR %0 | %1 -> 76543210 into %0 (all done!) -*/ -static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 x) { - __u64 temp; - __asm__("permh,3210 %0, %0\n\t" - "hshl %0, 8, %1\n\t" - "hshr,u %0, 8, %0\n\t" - "or %1, %0, %0" - : "=r" (x), "=&r" (temp) - : "0" (x)); - return x; -} -#define __arch__swab64(x) ___arch__swab64(x) -#define __BYTEORDER_HAS_U64__ -#elif !defined(__STRICT_ANSI__) -static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 x) -{ - __u32 t1 = ___arch__swab32((__u32) x); - __u32 t2 = ___arch__swab32((__u32) (x >> 32)); - return (((__u64) t1 << 32) | t2); -} -#define __arch__swab64(x) ___arch__swab64(x) -#define __BYTEORDER_HAS_U64__ -#endif - -#define __arch__swab16(x) ___arch__swab16(x) -#define __arch__swab24(x) ___arch__swab24(x) -#define __arch__swab32(x) ___arch__swab32(x) - -#endif /* __GNUC__ */ - +#include <asm/swab.h> #include <linux/byteorder/big_endian.h> #endif /* _PARISC_BYTEORDER_H */ diff --git a/arch/parisc/include/asm/checksum.h b/arch/parisc/include/asm/checksum.h index e9639ccc3fce..c84b2fcb18a9 100644 --- a/arch/parisc/include/asm/checksum.h +++ b/arch/parisc/include/asm/checksum.h @@ -182,7 +182,7 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, #endif : "=r" (sum), "=r" (saddr), "=r" (daddr), "=r" (len) : "0" (sum), "1" (saddr), "2" (daddr), "3" (len), "r" (proto) - : "r19", "r20", "r21", "r22"); + : "r19", "r20", "r21", "r22", "memory"); return csum_fold(sum); } diff --git a/arch/parisc/include/asm/io.h b/arch/parisc/include/asm/io.h index 55ddb1842107..d3031d1f9d03 100644 --- a/arch/parisc/include/asm/io.h +++ b/arch/parisc/include/asm/io.h @@ -4,12 +4,6 @@ #include <linux/types.h> #include <asm/pgtable.h> -extern unsigned long parisc_vmerge_boundary; -extern unsigned long parisc_vmerge_max_size; - -#define BIO_VMERGE_BOUNDARY parisc_vmerge_boundary -#define BIO_VMERGE_MAX_SIZE parisc_vmerge_max_size - #define virt_to_phys(a) ((unsigned long)__pa(a)) #define phys_to_virt(a) __va(a) #define virt_to_bus virt_to_phys @@ -182,9 +176,9 @@ static inline void __raw_writeq(unsigned long long b, volatile void __iomem *add /* readb can never be const, so use __fswab instead of le*_to_cpu */ #define readb(addr) __raw_readb(addr) -#define readw(addr) __fswab16(__raw_readw(addr)) -#define readl(addr) __fswab32(__raw_readl(addr)) -#define readq(addr) __fswab64(__raw_readq(addr)) +#define readw(addr) le16_to_cpu(__raw_readw(addr)) +#define readl(addr) le32_to_cpu(__raw_readl(addr)) +#define readq(addr) le64_to_cpu(__raw_readq(addr)) #define writeb(b, addr) __raw_writeb(b, addr) #define writew(b, addr) __raw_writew(cpu_to_le16(b), addr) #define writel(b, addr) __raw_writel(cpu_to_le32(b), addr) diff --git a/arch/parisc/include/asm/mmu_context.h b/arch/parisc/include/asm/mmu_context.h index 85856c74ad1d..354b2aca990e 100644 --- a/arch/parisc/include/asm/mmu_context.h +++ b/arch/parisc/include/asm/mmu_context.h @@ -34,16 +34,21 @@ destroy_context(struct mm_struct *mm) mm->context = 0; } -static inline void load_context(mm_context_t context) +static inline unsigned long __space_to_prot(mm_context_t context) { - mtsp(context, 3); #if SPACEID_SHIFT == 0 - mtctl(context << 1,8); + return context << 1; #else - mtctl(context >> (SPACEID_SHIFT - 1),8); + return context >> (SPACEID_SHIFT - 1); #endif } +static inline void load_context(mm_context_t context) +{ + mtsp(context, 3); + mtctl(__space_to_prot(context), 8); +} + static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h index 3c9d34844c83..9d64df8754ba 100644 --- a/arch/parisc/include/asm/processor.h +++ b/arch/parisc/include/asm/processor.h @@ -17,6 +17,7 @@ #include <asm/ptrace.h> #include <asm/types.h> #include <asm/system.h> +#include <asm/percpu.h> #endif /* __ASSEMBLY__ */ #define KERNEL_STACK_SIZE (4*PAGE_SIZE) @@ -109,8 +110,7 @@ struct cpuinfo_parisc { }; extern struct system_cpuinfo_parisc boot_cpu_data; -extern struct cpuinfo_parisc cpu_data[NR_CPUS]; -#define current_cpu_data cpu_data[smp_processor_id()] +DECLARE_PER_CPU(struct cpuinfo_parisc, cpu_data); #define CPU_HVERSION ((boot_cpu_data.hversion >> 4) & 0x0FFF) diff --git a/arch/parisc/include/asm/swab.h b/arch/parisc/include/asm/swab.h new file mode 100644 index 000000000000..3ff16c5a3358 --- /dev/null +++ b/arch/parisc/include/asm/swab.h @@ -0,0 +1,66 @@ +#ifndef _PARISC_SWAB_H +#define _PARISC_SWAB_H + +#include <asm/types.h> +#include <linux/compiler.h> + +#define __SWAB_64_THRU_32__ + +static inline __attribute_const__ __u16 __arch_swab16(__u16 x) +{ + __asm__("dep %0, 15, 8, %0\n\t" /* deposit 00ab -> 0bab */ + "shd %%r0, %0, 8, %0" /* shift 000000ab -> 00ba */ + : "=r" (x) + : "0" (x)); + return x; +} +#define __arch_swab16 __arch_swab16 + +static inline __attribute_const__ __u32 __arch_swab24(__u32 x) +{ + __asm__("shd %0, %0, 8, %0\n\t" /* shift xabcxabc -> cxab */ + "dep %0, 15, 8, %0\n\t" /* deposit cxab -> cbab */ + "shd %%r0, %0, 8, %0" /* shift 0000cbab -> 0cba */ + : "=r" (x) + : "0" (x)); + return x; +} + +static inline __attribute_const__ __u32 __arch_swab32(__u32 x) +{ + unsigned int temp; + __asm__("shd %0, %0, 16, %1\n\t" /* shift abcdabcd -> cdab */ + "dep %1, 15, 8, %1\n\t" /* deposit cdab -> cbab */ + "shd %0, %1, 8, %0" /* shift abcdcbab -> dcba */ + : "=r" (x), "=&r" (temp) + : "0" (x)); + return x; +} +#define __arch_swab32 __arch_swab32 + +#if BITS_PER_LONG > 32 +/* +** From "PA-RISC 2.0 Architecture", HP Professional Books. +** See Appendix I page 8 , "Endian Byte Swapping". +** +** Pretty cool algorithm: (* == zero'd bits) +** PERMH 01234567 -> 67452301 into %0 +** HSHL 67452301 -> 7*5*3*1* into %1 +** HSHR 67452301 -> *6*4*2*0 into %0 +** OR %0 | %1 -> 76543210 into %0 (all done!) +*/ +static inline __attribute_const__ __u64 __arch_swab64(__u64 x) +{ + __u64 temp; + __asm__("permh,3210 %0, %0\n\t" + "hshl %0, 8, %1\n\t" + "hshr,u %0, 8, %0\n\t" + "or %1, %0, %0" + : "=r" (x), "=&r" (temp) + : "0" (x)); + return x; +} +#define __arch_swab64 __arch_swab64 +#endif /* BITS_PER_LONG > 32 */ + +#endif /* _PARISC_SWAB_H */ diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h index 4878b9501f24..1c6dbb6f6e56 100644 --- a/arch/parisc/include/asm/uaccess.h +++ b/arch/parisc/include/asm/uaccess.h @@ -241,4 +241,6 @@ unsigned long copy_in_user(void __user *dst, const void __user *src, unsigned lo #define __copy_to_user_inatomic __copy_to_user #define __copy_from_user_inatomic __copy_from_user +int fixup_exception(struct pt_regs *regs); + #endif /* __PARISC_UACCESS_H */ diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index 884b7ce16a3b..994bcd980909 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -549,6 +549,38 @@ static int parisc_generic_match(struct device *dev, struct device_driver *drv) return match_device(to_parisc_driver(drv), to_parisc_device(dev)); } +static ssize_t make_modalias(struct device *dev, char *buf) +{ + const struct parisc_device *padev = to_parisc_device(dev); + const struct parisc_device_id *id = &padev->id; + + return sprintf(buf, "parisc:t%02Xhv%04Xrev%02Xsv%08X\n", + (u8)id->hw_type, (u16)id->hversion, (u8)id->hversion_rev, + (u32)id->sversion); +} + +static int parisc_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + const struct parisc_device *padev; + char modalias[40]; + + if (!dev) + return -ENODEV; + + padev = to_parisc_device(dev); + if (!padev) + return -ENODEV; + + if (add_uevent_var(env, "PARISC_NAME=%s", padev->name)) + return -ENOMEM; + + make_modalias(dev, modalias); + if (add_uevent_var(env, "MODALIAS=%s", modalias)) + return -ENOMEM; + + return 0; +} + #define pa_dev_attr(name, field, format_string) \ static ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf) \ { \ @@ -566,12 +598,7 @@ pa_dev_attr_id(sversion, "0x%05x\n"); static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct parisc_device *padev = to_parisc_device(dev); - struct parisc_device_id *id = &padev->id; - - return sprintf(buf, "parisc:t%02Xhv%04Xrev%02Xsv%08X\n", - (u8)id->hw_type, (u16)id->hversion, (u8)id->hversion_rev, - (u32)id->sversion); + return make_modalias(dev, buf); } static struct device_attribute parisc_device_attrs[] = { @@ -587,6 +614,7 @@ static struct device_attribute parisc_device_attrs[] = { struct bus_type parisc_bus_type = { .name = "parisc", .match = parisc_generic_match, + .uevent = parisc_uevent, .dev_attrs = parisc_device_attrs, .probe = parisc_driver_probe, .remove = parisc_driver_remove, diff --git a/arch/parisc/kernel/hpmc.S b/arch/parisc/kernel/hpmc.S index 2cbf13b3ef11..5595a2f31181 100644 --- a/arch/parisc/kernel/hpmc.S +++ b/arch/parisc/kernel/hpmc.S @@ -80,6 +80,7 @@ END(hpmc_pim_data) .import intr_save, code ENTRY(os_hpmc) +.os_hpmc: /* * registers modified: @@ -295,5 +296,10 @@ os_hpmc_6: b . nop ENDPROC(os_hpmc) -ENTRY(os_hpmc_end) /* this label used to compute os_hpmc checksum */ +.os_hpmc_end: nop +.data +.align 4 + .export os_hpmc_size +os_hpmc_size: + .word .os_hpmc_end-.os_hpmc diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 4cea935e2f99..ac2c822928c7 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -298,7 +298,7 @@ unsigned long txn_affinity_addr(unsigned int irq, int cpu) irq_desc[irq].affinity = cpumask_of_cpu(cpu); #endif - return cpu_data[cpu].txn_addr; + return per_cpu(cpu_data, cpu).txn_addr; } @@ -309,8 +309,9 @@ unsigned long txn_alloc_addr(unsigned int virt_irq) next_cpu++; /* assign to "next" CPU we want this bugger on */ /* validate entry */ - while ((next_cpu < NR_CPUS) && (!cpu_data[next_cpu].txn_addr || - !cpu_online(next_cpu))) + while ((next_cpu < NR_CPUS) && + (!per_cpu(cpu_data, next_cpu).txn_addr || + !cpu_online(next_cpu))) next_cpu++; if (next_cpu >= NR_CPUS) @@ -359,7 +360,7 @@ void do_cpu_irq_mask(struct pt_regs *regs) printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n", irq, smp_processor_id(), cpu); gsc_writel(irq + CPU_IRQ_BASE, - cpu_data[cpu].hpa); + per_cpu(cpu_data, cpu).hpa); goto set_out; } #endif @@ -421,5 +422,5 @@ void __init init_IRQ(void) void ack_bad_irq(unsigned int irq) { - printk("unexpected IRQ %d\n", irq); + printk(KERN_WARNING "unexpected IRQ %d\n", irq); } diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index ccb68090781e..1ff366cb9685 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -52,7 +52,7 @@ #include <linux/tty.h> #include <asm/pdc.h> /* for iodc_call() proto and friends */ -static spinlock_t pdc_console_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(pdc_console_lock); static void pdc_console_write(struct console *co, const char *s, unsigned count) { diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c index f696f57faa15..75099efb3bf3 100644 --- a/arch/parisc/kernel/perf.c +++ b/arch/parisc/kernel/perf.c @@ -541,9 +541,9 @@ static int __init perf_init(void) spin_lock_init(&perf_lock); /* TODO: this only lets us access the first cpu.. what to do for SMP? */ - cpu_device = cpu_data[0].dev; + cpu_device = per_cpu(cpu_data, 0).dev; printk("Performance monitoring counters enabled for %s\n", - cpu_data[0].dev->name); + per_cpu(cpu_data, 0).dev->name); return 0; } diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c index 370086fb8333..ecb609342feb 100644 --- a/arch/parisc/kernel/processor.c +++ b/arch/parisc/kernel/processor.c @@ -3,7 +3,7 @@ * Initial setup-routines for HP 9000 based hardware. * * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * Modifications for PA-RISC (C) 1999 Helge Deller <deller@gmx.de> + * Modifications for PA-RISC (C) 1999-2008 Helge Deller <deller@gmx.de> * Modifications copyright 1999 SuSE GmbH (Philipp Rumpf) * Modifications copyright 2000 Martin K. Petersen <mkp@mkp.net> * Modifications copyright 2000 Philipp Rumpf <prumpf@tux.org> @@ -46,7 +46,7 @@ struct system_cpuinfo_parisc boot_cpu_data __read_mostly; EXPORT_SYMBOL(boot_cpu_data); -struct cpuinfo_parisc cpu_data[NR_CPUS] __read_mostly; +DEFINE_PER_CPU(struct cpuinfo_parisc, cpu_data); extern int update_cr16_clocksource(void); /* from time.c */ @@ -69,6 +69,23 @@ extern int update_cr16_clocksource(void); /* from time.c */ */ /** + * init_cpu_profiler - enable/setup per cpu profiling hooks. + * @cpunum: The processor instance. + * + * FIXME: doesn't do much yet... + */ +static void __cpuinit +init_percpu_prof(unsigned long cpunum) +{ + struct cpuinfo_parisc *p; + + p = &per_cpu(cpu_data, cpunum); + p->prof_counter = 1; + p->prof_multiplier = 1; +} + + +/** * processor_probe - Determine if processor driver should claim this device. * @dev: The device which has been found. * @@ -147,7 +164,7 @@ static int __cpuinit processor_probe(struct parisc_device *dev) } #endif - p = &cpu_data[cpuid]; + p = &per_cpu(cpu_data, cpuid); boot_cpu_data.cpu_count++; /* initialize counters - CPU 0 gets it_value set in time_init() */ @@ -162,12 +179,9 @@ static int __cpuinit processor_probe(struct parisc_device *dev) #ifdef CONFIG_SMP /* ** FIXME: review if any other initialization is clobbered - ** for boot_cpu by the above memset(). + ** for boot_cpu by the above memset(). */ - - /* stolen from init_percpu_prof() */ - cpu_data[cpuid].prof_counter = 1; - cpu_data[cpuid].prof_multiplier = 1; + init_percpu_prof(cpuid); #endif /* @@ -261,19 +275,6 @@ void __init collect_boot_cpu_data(void) } -/** - * init_cpu_profiler - enable/setup per cpu profiling hooks. - * @cpunum: The processor instance. - * - * FIXME: doesn't do much yet... - */ -static inline void __init -init_percpu_prof(int cpunum) -{ - cpu_data[cpunum].prof_counter = 1; - cpu_data[cpunum].prof_multiplier = 1; -} - /** * init_per_cpu - Handle individual processor initializations. @@ -293,7 +294,7 @@ init_percpu_prof(int cpunum) * * o Enable CPU profiling hooks. */ -int __init init_per_cpu(int cpunum) +int __cpuinit init_per_cpu(int cpunum) { int ret; struct pdc_coproc_cfg coproc_cfg; @@ -307,8 +308,8 @@ int __init init_per_cpu(int cpunum) /* FWIW, FP rev/model is a more accurate way to determine ** CPU type. CPU rev/model has some ambiguous cases. */ - cpu_data[cpunum].fp_rev = coproc_cfg.revision; - cpu_data[cpunum].fp_model = coproc_cfg.model; + per_cpu(cpu_data, cpunum).fp_rev = coproc_cfg.revision; + per_cpu(cpu_data, cpunum).fp_model = coproc_cfg.model; printk(KERN_INFO "FP[%d] enabled: Rev %ld Model %ld\n", cpunum, coproc_cfg.revision, coproc_cfg.model); @@ -344,16 +345,17 @@ int __init init_per_cpu(int cpunum) int show_cpuinfo (struct seq_file *m, void *v) { - int n; + unsigned long cpu; - for(n=0; n<boot_cpu_data.cpu_count; n++) { + for_each_online_cpu(cpu) { + const struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu); #ifdef CONFIG_SMP - if (0 == cpu_data[n].hpa) + if (0 == cpuinfo->hpa) continue; #endif - seq_printf(m, "processor\t: %d\n" + seq_printf(m, "processor\t: %lu\n" "cpu family\t: PA-RISC %s\n", - n, boot_cpu_data.family_name); + cpu, boot_cpu_data.family_name); seq_printf(m, "cpu\t\t: %s\n", boot_cpu_data.cpu_name ); @@ -365,8 +367,8 @@ show_cpuinfo (struct seq_file *m, void *v) seq_printf(m, "model\t\t: %s\n" "model name\t: %s\n", boot_cpu_data.pdc.sys_model_name, - cpu_data[n].dev ? - cpu_data[n].dev->name : "Unknown" ); + cpuinfo->dev ? + cpuinfo->dev->name : "Unknown"); seq_printf(m, "hversion\t: 0x%08x\n" "sversion\t: 0x%08x\n", @@ -377,8 +379,8 @@ show_cpuinfo (struct seq_file *m, void *v) show_cache_info(m); seq_printf(m, "bogomips\t: %lu.%02lu\n", - cpu_data[n].loops_per_jiffy / (500000 / HZ), - (cpu_data[n].loops_per_jiffy / (5000 / HZ)) % 100); + cpuinfo->loops_per_jiffy / (500000 / HZ), + (cpuinfo->loops_per_jiffy / (5000 / HZ)) % 100); seq_printf(m, "software id\t: %ld\n\n", boot_cpu_data.pdc.model.sw_id); diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c index 7d27853ff8c8..82131ca8e05c 100644 --- a/arch/parisc/kernel/setup.c +++ b/arch/parisc/kernel/setup.c @@ -58,11 +58,6 @@ int parisc_bus_is_phys __read_mostly = 1; /* Assume no IOMMU is present */ EXPORT_SYMBOL(parisc_bus_is_phys); #endif -/* This sets the vmerge boundary and size, it's here because it has to - * be available on all platforms (zero means no-virtual merging) */ -unsigned long parisc_vmerge_boundary = 0; -unsigned long parisc_vmerge_max_size = 0; - void __init setup_cmdline(char **cmdline_p) { extern unsigned int boot_args[]; @@ -321,7 +316,7 @@ static int __init parisc_init(void) processor_init(); printk(KERN_INFO "CPU(s): %d x %s at %d.%06d MHz\n", - boot_cpu_data.cpu_count, + num_present_cpus(), boot_cpu_data.cpu_name, boot_cpu_data.cpu_hz / 1000000, boot_cpu_data.cpu_hz % 1000000 ); @@ -387,8 +382,8 @@ void start_parisc(void) if (ret >= 0 && coproc_cfg.ccr_functional) { mtctl(coproc_cfg.ccr_functional, 10); - cpu_data[cpunum].fp_rev = coproc_cfg.revision; - cpu_data[cpunum].fp_model = coproc_cfg.model; + per_cpu(cpu_data, cpunum).fp_rev = coproc_cfg.revision; + per_cpu(cpu_data, cpunum).fp_model = coproc_cfg.model; asm volatile ("fstd %fr0,8(%sp)"); } else { diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index 80bc000523fa..9995d7ed5819 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -56,16 +56,17 @@ static int smp_debug_lvl = 0; if (lvl >= smp_debug_lvl) \ printk(printargs); #else -#define smp_debug(lvl, ...) +#define smp_debug(lvl, ...) do { } while(0) #endif /* DEBUG_SMP */ DEFINE_SPINLOCK(smp_lock); volatile struct task_struct *smp_init_current_idle_task; -static volatile int cpu_now_booting __read_mostly = 0; /* track which CPU is booting */ +/* track which CPU is booting */ +static volatile int cpu_now_booting __cpuinitdata; -static int parisc_max_cpus __read_mostly = 1; +static int parisc_max_cpus __cpuinitdata = 1; DEFINE_PER_CPU(spinlock_t, ipi_lock) = SPIN_LOCK_UNLOCKED; @@ -123,7 +124,7 @@ irqreturn_t ipi_interrupt(int irq, void *dev_id) { int this_cpu = smp_processor_id(); - struct cpuinfo_parisc *p = &cpu_data[this_cpu]; + struct cpuinfo_parisc *p = &per_cpu(cpu_data, this_cpu); unsigned long ops; unsigned long flags; @@ -202,13 +203,13 @@ ipi_interrupt(int irq, void *dev_id) static inline void ipi_send(int cpu, enum ipi_message_type op) { - struct cpuinfo_parisc *p = &cpu_data[cpu]; + struct cpuinfo_parisc *p = &per_cpu(cpu_data, cpu); spinlock_t *lock = &per_cpu(ipi_lock, cpu); unsigned long flags; spin_lock_irqsave(lock, flags); p->pending_ipi |= 1 << op; - gsc_writel(IPI_IRQ - CPU_IRQ_BASE, cpu_data[cpu].hpa); + gsc_writel(IPI_IRQ - CPU_IRQ_BASE, p->hpa); spin_unlock_irqrestore(lock, flags); } @@ -224,10 +225,7 @@ send_IPI_mask(cpumask_t mask, enum ipi_message_type op) static inline void send_IPI_single(int dest_cpu, enum ipi_message_type op) { - if (dest_cpu == NO_PROC_ID) { - BUG(); - return; - } + BUG_ON(dest_cpu == NO_PROC_ID); ipi_send(dest_cpu, op); } @@ -309,8 +307,7 @@ smp_cpu_init(int cpunum) /* Initialise the idle task for this CPU */ atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; - if(current->mm) - BUG(); + BUG_ON(current->mm); enter_lazy_tlb(&init_mm, current); init_IRQ(); /* make sure no IRQs are enabled or pending */ @@ -345,6 +342,7 @@ void __init smp_callin(void) */ int __cpuinit smp_boot_one_cpu(int cpuid) { + const struct cpuinfo_parisc *p = &per_cpu(cpu_data, cpuid); struct task_struct *idle; long timeout; @@ -376,7 +374,7 @@ int __cpuinit smp_boot_one_cpu(int cpuid) smp_init_current_idle_task = idle ; mb(); - printk("Releasing cpu %d now, hpa=%lx\n", cpuid, cpu_data[cpuid].hpa); + printk(KERN_INFO "Releasing cpu %d now, hpa=%lx\n", cpuid, p->hpa); /* ** This gets PDC to release the CPU from a very tight loop. @@ -387,7 +385,7 @@ int __cpuinit smp_boot_one_cpu(int cpuid) ** EIR{0}). MEM_RENDEZ is valid only when it is nonzero and the ** contents of memory are valid." */ - gsc_writel(TIMER_IRQ - CPU_IRQ_BASE, cpu_data[cpuid].hpa); + gsc_writel(TIMER_IRQ - CPU_IRQ_BASE, p->hpa); mb(); /* @@ -419,12 +417,12 @@ alive: return 0; } -void __devinit smp_prepare_boot_cpu(void) +void __init smp_prepare_boot_cpu(void) { - int bootstrap_processor=cpu_data[0].cpuid; /* CPU ID of BSP */ + int bootstrap_processor = per_cpu(cpu_data, 0).cpuid; /* Setup BSP mappings */ - printk("SMP: bootstrap CPU ID is %d\n",bootstrap_processor); + printk(KERN_INFO "SMP: bootstrap CPU ID is %d\n", bootstrap_processor); cpu_set(bootstrap_processor, cpu_online_map); cpu_set(bootstrap_processor, cpu_present_map); diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 4d09203bc693..9d46c43a4152 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -60,7 +60,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) unsigned long cycles_elapsed, ticks_elapsed; unsigned long cycles_remainder; unsigned int cpu = smp_processor_id(); - struct cpuinfo_parisc *cpuinfo = &cpu_data[cpu]; + struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu); /* gcc can optimize for "read-only" case with a local clocktick */ unsigned long cpt = clocktick; @@ -213,7 +213,7 @@ void __init start_cpu_itimer(void) mtctl(next_tick, 16); /* kick off Interval Timer (CR16) */ - cpu_data[cpu].it_value = next_tick; + per_cpu(cpu_data, cpu).it_value = next_tick; } struct platform_device rtc_parisc_dev = { diff --git a/arch/parisc/kernel/topology.c b/arch/parisc/kernel/topology.c index d71cb018a21e..f5159381fdd6 100644 --- a/arch/parisc/kernel/topology.c +++ b/arch/parisc/kernel/topology.c @@ -22,14 +22,14 @@ #include <linux/cpu.h> #include <linux/cache.h> -static struct cpu cpu_devices[NR_CPUS] __read_mostly; +static DEFINE_PER_CPU(struct cpu, cpu_devices); static int __init topology_init(void) { int num; for_each_present_cpu(num) { - register_cpu(&cpu_devices[num], num); + register_cpu(&per_cpu(cpu_devices, num), num); } return 0; } diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index 4c771cd580ec..ba658d2086f7 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -745,6 +745,10 @@ void handle_interruption(int code, struct pt_regs *regs) /* Fall Through */ case 27: /* Data memory protection ID trap */ + if (code == 27 && !user_mode(regs) && + fixup_exception(regs)) + return; + die_if_kernel("Protection id trap", regs, code); si.si_code = SEGV_MAPERR; si.si_signo = SIGSEGV; @@ -821,8 +825,8 @@ void handle_interruption(int code, struct pt_regs *regs) int __init check_ivt(void *iva) { + extern u32 os_hpmc_size; extern const u32 os_hpmc[]; - extern const u32 os_hpmc_end[]; int i; u32 check = 0; @@ -839,8 +843,7 @@ int __init check_ivt(void *iva) *ivap++ = 0; /* Compute Checksum for HPMC handler */ - - length = os_hpmc_end - os_hpmc; + length = os_hpmc_size; ivap[7] = length; hpmcp = (u32 *)os_hpmc; diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c index 6773c582e457..69dad5a850a8 100644 --- a/arch/parisc/kernel/unwind.c +++ b/arch/parisc/kernel/unwind.c @@ -372,7 +372,7 @@ void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct struct pt_regs *r = &t->thread.regs; struct pt_regs *r2; - r2 = kmalloc(sizeof(struct pt_regs), GFP_KERNEL); + r2 = kmalloc(sizeof(struct pt_regs), GFP_ATOMIC); if (!r2) return; *r2 = *r; diff --git a/arch/parisc/lib/iomap.c b/arch/parisc/lib/iomap.c index 9abed07db7fc..5069e8b2ca71 100644 --- a/arch/parisc/lib/iomap.c +++ b/arch/parisc/lib/iomap.c @@ -261,7 +261,7 @@ static const struct iomap_ops iomem_ops = { iomem_write32r, }; -const struct iomap_ops *iomap_ops[8] = { +static const struct iomap_ops *iomap_ops[8] = { [0] = &ioport_ops, [7] = &iomem_ops }; diff --git a/arch/parisc/lib/memcpy.c b/arch/parisc/lib/memcpy.c index 2d68431fc22e..bbda909c866e 100644 --- a/arch/parisc/lib/memcpy.c +++ b/arch/parisc/lib/memcpy.c @@ -275,7 +275,7 @@ handle_store_error: /* Returns 0 for success, otherwise, returns number of bytes not transferred. */ -unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len) +static unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len) { register unsigned long src, dst, t1, t2, t3; register unsigned char *pcs, *pcd; diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index b2e3e9a8cece..92c7fa4ecc3f 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -139,13 +139,41 @@ parisc_acctyp(unsigned long code, unsigned int inst) } #endif +int fixup_exception(struct pt_regs *regs) +{ + const struct exception_table_entry *fix; + + fix = search_exception_tables(regs->iaoq[0]); + if (fix) { + struct exception_data *d; + d = &__get_cpu_var(exception_data); + d->fault_ip = regs->iaoq[0]; + d->fault_space = regs->isr; + d->fault_addr = regs->ior; + + regs->iaoq[0] = ((fix->fixup) & ~3); + /* + * NOTE: In some cases the faulting instruction + * may be in the delay slot of a branch. We + * don't want to take the branch, so we don't + * increment iaoq[1], instead we set it to be + * iaoq[0]+4, and clear the B bit in the PSW + */ + regs->iaoq[1] = regs->iaoq[0] + 4; + regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */ + + return 1; + } + + return 0; +} + void do_page_fault(struct pt_regs *regs, unsigned long code, unsigned long address) { struct vm_area_struct *vma, *prev_vma; struct task_struct *tsk = current; struct mm_struct *mm = tsk->mm; - const struct exception_table_entry *fix; unsigned long acc_type; int fault; @@ -229,32 +257,8 @@ bad_area: no_context: - if (!user_mode(regs)) { - fix = search_exception_tables(regs->iaoq[0]); - - if (fix) { - struct exception_data *d; - - d = &__get_cpu_var(exception_data); - d->fault_ip = regs->iaoq[0]; - d->fault_space = regs->isr; - d->fault_addr = regs->ior; - - regs->iaoq[0] = ((fix->fixup) & ~3); - - /* - * NOTE: In some cases the faulting instruction - * may be in the delay slot of a branch. We - * don't want to take the branch, so we don't - * increment iaoq[1], instead we set it to be - * iaoq[0]+4, and clear the B bit in the PSW - */ - - regs->iaoq[1] = regs->iaoq[0] + 4; - regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */ - - return; - } + if (!user_mode(regs) && fixup_exception(regs)) { + return; } parisc_terminate("Bad Address (null pointer deref?)", regs, code, address); diff --git a/arch/powerpc/include/asm/cell-pmu.h b/arch/powerpc/include/asm/cell-pmu.h index 8066eede3a0c..b4b7338ad79e 100644 --- a/arch/powerpc/include/asm/cell-pmu.h +++ b/arch/powerpc/include/asm/cell-pmu.h @@ -37,9 +37,11 @@ #define CBE_PM_STOP_AT_MAX 0x40000000 #define CBE_PM_TRACE_MODE_GET(pm_control) (((pm_control) >> 28) & 0x3) #define CBE_PM_TRACE_MODE_SET(mode) (((mode) & 0x3) << 28) +#define CBE_PM_TRACE_BUF_OVFLW(bit) (((bit) & 0x1) << 17) #define CBE_PM_COUNT_MODE_SET(count) (((count) & 0x3) << 18) #define CBE_PM_FREEZE_ALL_CTRS 0x00100000 #define CBE_PM_ENABLE_EXT_TRACE 0x00008000 +#define CBE_PM_SPU_ADDR_TRACE_SET(msk) (((msk) & 0x3) << 9) /* Macros for the trace_address register. */ #define CBE_PM_TRACE_BUF_FULL 0x00000800 diff --git a/arch/powerpc/include/asm/oprofile_impl.h b/arch/powerpc/include/asm/oprofile_impl.h index 95035c602ba6..639dc96077ab 100644 --- a/arch/powerpc/include/asm/oprofile_impl.h +++ b/arch/powerpc/include/asm/oprofile_impl.h @@ -32,6 +32,12 @@ struct op_system_config { unsigned long mmcr0; unsigned long mmcr1; unsigned long mmcra; +#ifdef CONFIG_OPROFILE_CELL + /* Register for oprofile user tool to check cell kernel profiling + * suport. + */ + unsigned long cell_support; +#endif #endif unsigned long enable_kernel; unsigned long enable_user; diff --git a/arch/powerpc/oprofile/cell/pr_util.h b/arch/powerpc/oprofile/cell/pr_util.h index dfdbffa06818..964b93974d89 100644 --- a/arch/powerpc/oprofile/cell/pr_util.h +++ b/arch/powerpc/oprofile/cell/pr_util.h @@ -30,6 +30,10 @@ extern struct delayed_work spu_work; extern int spu_prof_running; +#define TRACE_ARRAY_SIZE 1024 + +extern spinlock_t oprof_spu_smpl_arry_lck; + struct spu_overlay_info { /* map of sections within an SPU overlay */ unsigned int vma; /* SPU virtual memory address from elf */ unsigned int size; /* size of section from elf */ @@ -89,10 +93,11 @@ void vma_map_free(struct vma_to_fileoffset_map *map); * Entry point for SPU profiling. * cycles_reset is the SPU_CYCLES count value specified by the user. */ -int start_spu_profiling(unsigned int cycles_reset); - -void stop_spu_profiling(void); +int start_spu_profiling_cycles(unsigned int cycles_reset); +void start_spu_profiling_events(void); +void stop_spu_profiling_cycles(void); +void stop_spu_profiling_events(void); /* add the necessary profiling hooks */ int spu_sync_start(void); diff --git a/arch/powerpc/oprofile/cell/spu_profiler.c b/arch/powerpc/oprofile/cell/spu_profiler.c index 83faa958b9d4..9305ddaac512 100644 --- a/arch/powerpc/oprofile/cell/spu_profiler.c +++ b/arch/powerpc/oprofile/cell/spu_profiler.c @@ -18,11 +18,21 @@ #include <asm/cell-pmu.h> #include "pr_util.h" -#define TRACE_ARRAY_SIZE 1024 #define SCALE_SHIFT 14 static u32 *samples; +/* spu_prof_running is a flag used to indicate if spu profiling is enabled + * or not. It is set by the routines start_spu_profiling_cycles() and + * start_spu_profiling_events(). The flag is cleared by the routines + * stop_spu_profiling_cycles() and stop_spu_profiling_events(). These + * routines are called via global_start() and global_stop() which are called in + * op_powerpc_start() and op_powerpc_stop(). These routines are called once + * per system as a result of the user starting/stopping oprofile. Hence, only + * one CPU per user at a time will be changing the value of spu_prof_running. + * In general, OProfile does not protect against multiple users trying to run + * OProfile at a time. + */ int spu_prof_running; static unsigned int profiling_interval; @@ -31,8 +41,8 @@ static unsigned int profiling_interval; #define SPU_PC_MASK 0xFFFF -static DEFINE_SPINLOCK(sample_array_lock); -unsigned long sample_array_lock_flags; +DEFINE_SPINLOCK(oprof_spu_smpl_arry_lck); +unsigned long oprof_spu_smpl_arry_lck_flags; void set_spu_profiling_frequency(unsigned int freq_khz, unsigned int cycles_reset) { @@ -145,13 +155,13 @@ static enum hrtimer_restart profile_spus(struct hrtimer *timer) * sample array must be loaded and then processed for a given * cpu. The sample array is not per cpu. */ - spin_lock_irqsave(&sample_array_lock, - sample_array_lock_flags); + spin_lock_irqsave(&oprof_spu_smpl_arry_lck, + oprof_spu_smpl_arry_lck_flags); num_samples = cell_spu_pc_collection(cpu); if (num_samples == 0) { - spin_unlock_irqrestore(&sample_array_lock, - sample_array_lock_flags); + spin_unlock_irqrestore(&oprof_spu_smpl_arry_lck, + oprof_spu_smpl_arry_lck_flags); continue; } @@ -162,8 +172,8 @@ static enum hrtimer_restart profile_spus(struct hrtimer *timer) num_samples); } - spin_unlock_irqrestore(&sample_array_lock, - sample_array_lock_flags); + spin_unlock_irqrestore(&oprof_spu_smpl_arry_lck, + oprof_spu_smpl_arry_lck_flags); } smp_wmb(); /* insure spu event buffer updates are written */ @@ -182,13 +192,13 @@ static enum hrtimer_restart profile_spus(struct hrtimer *timer) static struct hrtimer timer; /* - * Entry point for SPU profiling. + * Entry point for SPU cycle profiling. * NOTE: SPU profiling is done system-wide, not per-CPU. * * cycles_reset is the count value specified by the user when * setting up OProfile to count SPU_CYCLES. */ -int start_spu_profiling(unsigned int cycles_reset) +int start_spu_profiling_cycles(unsigned int cycles_reset) { ktime_t kt; @@ -212,10 +222,30 @@ int start_spu_profiling(unsigned int cycles_reset) return 0; } -void stop_spu_profiling(void) +/* + * Entry point for SPU event profiling. + * NOTE: SPU profiling is done system-wide, not per-CPU. + * + * cycles_reset is the count value specified by the user when + * setting up OProfile to count SPU_CYCLES. + */ +void start_spu_profiling_events(void) +{ + spu_prof_running = 1; + schedule_delayed_work(&spu_work, DEFAULT_TIMER_EXPIRE); + + return; +} + +void stop_spu_profiling_cycles(void) { spu_prof_running = 0; hrtimer_cancel(&timer); kfree(samples); - pr_debug("SPU_PROF: stop_spu_profiling issued\n"); + pr_debug("SPU_PROF: stop_spu_profiling_cycles issued\n"); +} + +void stop_spu_profiling_events(void) +{ + spu_prof_running = 0; } diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index 17807acb05d9..21f16edf6c8d 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -132,6 +132,28 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root) oprofilefs_create_ulong(sb, root, "mmcr0", &sys.mmcr0); oprofilefs_create_ulong(sb, root, "mmcr1", &sys.mmcr1); oprofilefs_create_ulong(sb, root, "mmcra", &sys.mmcra); +#ifdef CONFIG_OPROFILE_CELL + /* create a file the user tool can check to see what level of profiling + * support exits with this kernel. Initialize bit mask to indicate + * what support the kernel has: + * bit 0 - Supports SPU event profiling in addition to PPU + * event and cycles; and SPU cycle profiling + * bits 1-31 - Currently unused. + * + * If the file does not exist, then the kernel only supports SPU + * cycle profiling, PPU event and cycle profiling. + */ + oprofilefs_create_ulong(sb, root, "cell_support", &sys.cell_support); + sys.cell_support = 0x1; /* Note, the user OProfile tool must check + * that this bit is set before attempting to + * user SPU event profiling. Older kernels + * will not have this file, hence the user + * tool is not allowed to do SPU event + * profiling on older kernels. Older kernels + * will accept SPU events but collected data + * is garbage. + */ +#endif #endif for (i = 0; i < model->num_counters; ++i) { diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c index 25a4ec2514a3..ae06c6236d9c 100644 --- a/arch/powerpc/oprofile/op_model_cell.c +++ b/arch/powerpc/oprofile/op_model_cell.c @@ -40,14 +40,15 @@ #include "../platforms/cell/interrupt.h" #include "cell/pr_util.h" -static void cell_global_stop_spu(void); +#define PPU_PROFILING 0 +#define SPU_PROFILING_CYCLES 1 +#define SPU_PROFILING_EVENTS 2 -/* - * spu_cycle_reset is the number of cycles between samples. - * This variable is used for SPU profiling and should ONLY be set - * at the beginning of cell_reg_setup; otherwise, it's read-only. - */ -static unsigned int spu_cycle_reset; +#define SPU_EVENT_NUM_START 4100 +#define SPU_EVENT_NUM_STOP 4399 +#define SPU_PROFILE_EVENT_ADDR 4363 /* spu, address trace, decimal */ +#define SPU_PROFILE_EVENT_ADDR_MASK_A 0x146 /* sub unit set to zero */ +#define SPU_PROFILE_EVENT_ADDR_MASK_B 0x186 /* sub unit set to zero */ #define NUM_SPUS_PER_NODE 8 #define SPU_CYCLES_EVENT_NUM 2 /* event number for SPU_CYCLES */ @@ -66,6 +67,21 @@ static unsigned int spu_cycle_reset; #define MAX_SPU_COUNT 0xFFFFFF /* maximum 24 bit LFSR value */ +/* Minumum HW interval timer setting to send value to trace buffer is 10 cycle. + * To configure counter to send value every N cycles set counter to + * 2^32 - 1 - N. + */ +#define NUM_INTERVAL_CYC 0xFFFFFFFF - 10 + +/* + * spu_cycle_reset is the number of cycles between samples. + * This variable is used for SPU profiling and should ONLY be set + * at the beginning of cell_reg_setup; otherwise, it's read-only. + */ +static unsigned int spu_cycle_reset; +static unsigned int profiling_mode; +static int spu_evnt_phys_spu_indx; + struct pmc_cntrl_data { unsigned long vcntr; unsigned long evnts; @@ -105,6 +121,8 @@ struct pm_cntrl { u16 trace_mode; u16 freeze; u16 count_mode; + u16 spu_addr_trace; + u8 trace_buf_ovflw; }; static struct { @@ -122,7 +140,7 @@ static struct { #define GET_INPUT_CONTROL(x) ((x & 0x00000004) >> 2) static DEFINE_PER_CPU(unsigned long[NR_PHYS_CTRS], pmc_values); - +static unsigned long spu_pm_cnt[MAX_NUMNODES * NUM_SPUS_PER_NODE]; static struct pmc_cntrl_data pmc_cntrl[NUM_THREADS][NR_PHYS_CTRS]; /* @@ -152,6 +170,7 @@ static u32 hdw_thread; static u32 virt_cntr_inter_mask; static struct timer_list timer_virt_cntr; +static struct timer_list timer_spu_event_swap; /* * pm_signal needs to be global since it is initialized in @@ -165,7 +184,7 @@ static int spu_rtas_token; /* token for SPU cycle profiling */ static u32 reset_value[NR_PHYS_CTRS]; static int num_counters; static int oprofile_running; -static DEFINE_SPINLOCK(virt_cntr_lock); +static DEFINE_SPINLOCK(cntr_lock); static u32 ctr_enabled; @@ -336,13 +355,13 @@ static void set_pm_event(u32 ctr, int event, u32 unit_mask) for (i = 0; i < NUM_DEBUG_BUS_WORDS; i++) { if (bus_word & (1 << i)) { pm_regs.debug_bus_control |= - (bus_type << (30 - (2 * i))); + (bus_type << (30 - (2 * i))); for (j = 0; j < NUM_INPUT_BUS_WORDS; j++) { if (input_bus[j] == 0xff) { input_bus[j] = i; pm_regs.group_control |= - (i << (30 - (2 * j))); + (i << (30 - (2 * j))); break; } @@ -367,12 +386,16 @@ static void write_pm_cntrl(int cpu) if (pm_regs.pm_cntrl.stop_at_max == 1) val |= CBE_PM_STOP_AT_MAX; - if (pm_regs.pm_cntrl.trace_mode == 1) + if (pm_regs.pm_cntrl.trace_mode != 0) val |= CBE_PM_TRACE_MODE_SET(pm_regs.pm_cntrl.trace_mode); + if (pm_regs.pm_cntrl.trace_buf_ovflw == 1) + val |= CBE_PM_TRACE_BUF_OVFLW(pm_regs.pm_cntrl.trace_buf_ovflw); if (pm_regs.pm_cntrl.freeze == 1) val |= CBE_PM_FREEZE_ALL_CTRS; + val |= CBE_PM_SPU_ADDR_TRACE_SET(pm_regs.pm_cntrl.spu_addr_trace); + /* * Routine set_count_mode must be called previously to set * the count mode based on the user selection of user and kernel. @@ -441,7 +464,7 @@ static void cell_virtual_cntr(unsigned long data) * not both playing with the counters on the same node. */ - spin_lock_irqsave(&virt_cntr_lock, flags); + spin_lock_irqsave(&cntr_lock, flags); prev_hdw_thread = hdw_thread; @@ -480,7 +503,7 @@ static void cell_virtual_cntr(unsigned long data) cbe_disable_pm_interrupts(cpu); for (i = 0; i < num_counters; i++) { per_cpu(pmc_values, cpu + prev_hdw_thread)[i] - = cbe_read_ctr(cpu, i); + = cbe_read_ctr(cpu, i); if (per_cpu(pmc_values, cpu + next_hdw_thread)[i] == 0xFFFFFFFF) @@ -527,7 +550,7 @@ static void cell_virtual_cntr(unsigned long data) cbe_enable_pm(cpu); } - spin_unlock_irqrestore(&virt_cntr_lock, flags); + spin_unlock_irqrestore(&cntr_lock, flags); mod_timer(&timer_virt_cntr, jiffies + HZ / 10); } @@ -541,38 +564,146 @@ static void start_virt_cntrs(void) add_timer(&timer_virt_cntr); } -/* This function is called once for all cpus combined */ -static int cell_reg_setup(struct op_counter_config *ctr, +static int cell_reg_setup_spu_cycles(struct op_counter_config *ctr, struct op_system_config *sys, int num_ctrs) { - int i, j, cpu; - spu_cycle_reset = 0; + spu_cycle_reset = ctr[0].count; - if (ctr[0].event == SPU_CYCLES_EVENT_NUM) { - spu_cycle_reset = ctr[0].count; + /* + * Each node will need to make the rtas call to start + * and stop SPU profiling. Get the token once and store it. + */ + spu_rtas_token = rtas_token("ibm,cbe-spu-perftools"); + + if (unlikely(spu_rtas_token == RTAS_UNKNOWN_SERVICE)) { + printk(KERN_ERR + "%s: rtas token ibm,cbe-spu-perftools unknown\n", + __func__); + return -EIO; + } + return 0; +} + +/* Unfortunately, the hardware will only support event profiling + * on one SPU per node at a time. Therefore, we must time slice + * the profiling across all SPUs in the node. Note, we do this + * in parallel for each node. The following routine is called + * periodically based on kernel timer to switch which SPU is + * being monitored in a round robbin fashion. + */ +static void spu_evnt_swap(unsigned long data) +{ + int node; + int cur_phys_spu, nxt_phys_spu, cur_spu_evnt_phys_spu_indx; + unsigned long flags; + int cpu; + int ret; + u32 interrupt_mask; + + + /* enable interrupts on cntr 0 */ + interrupt_mask = CBE_PM_CTR_OVERFLOW_INTR(0); + + hdw_thread = 0; + + /* Make sure spu event interrupt handler and spu event swap + * don't access the counters simultaneously. + */ + spin_lock_irqsave(&cntr_lock, flags); + + cur_spu_evnt_phys_spu_indx = spu_evnt_phys_spu_indx; + + if (++(spu_evnt_phys_spu_indx) == NUM_SPUS_PER_NODE) + spu_evnt_phys_spu_indx = 0; + + pm_signal[0].sub_unit = spu_evnt_phys_spu_indx; + pm_signal[1].sub_unit = spu_evnt_phys_spu_indx; + pm_signal[2].sub_unit = spu_evnt_phys_spu_indx; + + /* switch the SPU being profiled on each node */ + for_each_online_cpu(cpu) { + if (cbe_get_hw_thread_id(cpu)) + continue; + + node = cbe_cpu_to_node(cpu); + cur_phys_spu = (node * NUM_SPUS_PER_NODE) + + cur_spu_evnt_phys_spu_indx; + nxt_phys_spu = (node * NUM_SPUS_PER_NODE) + + spu_evnt_phys_spu_indx; /* - * Each node will need to make the rtas call to start - * and stop SPU profiling. Get the token once and store it. + * stop counters, save counter values, restore counts + * for previous physical SPU */ - spu_rtas_token = rtas_token("ibm,cbe-spu-perftools"); + cbe_disable_pm(cpu); + cbe_disable_pm_interrupts(cpu); - if (unlikely(spu_rtas_token == RTAS_UNKNOWN_SERVICE)) { - printk(KERN_ERR - "%s: rtas token ibm,cbe-spu-perftools unknown\n", - __func__); - return -EIO; - } + spu_pm_cnt[cur_phys_spu] + = cbe_read_ctr(cpu, 0); + + /* restore previous count for the next spu to sample */ + /* NOTE, hardware issue, counter will not start if the + * counter value is at max (0xFFFFFFFF). + */ + if (spu_pm_cnt[nxt_phys_spu] >= 0xFFFFFFFF) + cbe_write_ctr(cpu, 0, 0xFFFFFFF0); + else + cbe_write_ctr(cpu, 0, spu_pm_cnt[nxt_phys_spu]); + + pm_rtas_reset_signals(cbe_cpu_to_node(cpu)); + + /* setup the debug bus measure the one event and + * the two events to route the next SPU's PC on + * the debug bus + */ + ret = pm_rtas_activate_signals(cbe_cpu_to_node(cpu), 3); + if (ret) + printk(KERN_ERR "%s: pm_rtas_activate_signals failed, " + "SPU event swap\n", __func__); + + /* clear the trace buffer, don't want to take PC for + * previous SPU*/ + cbe_write_pm(cpu, trace_address, 0); + + enable_ctr(cpu, 0, pm_regs.pm07_cntrl); + + /* Enable interrupts on the CPU thread that is starting */ + cbe_enable_pm_interrupts(cpu, hdw_thread, + interrupt_mask); + cbe_enable_pm(cpu); } - pm_rtas_token = rtas_token("ibm,cbe-perftools"); + spin_unlock_irqrestore(&cntr_lock, flags); + /* swap approximately every 0.1 seconds */ + mod_timer(&timer_spu_event_swap, jiffies + HZ / 25); +} + +static void start_spu_event_swap(void) +{ + init_timer(&timer_spu_event_swap); + timer_spu_event_swap.function = spu_evnt_swap; + timer_spu_event_swap.data = 0UL; + timer_spu_event_swap.expires = jiffies + HZ / 25; + add_timer(&timer_spu_event_swap); +} + +static int cell_reg_setup_spu_events(struct op_counter_config *ctr, + struct op_system_config *sys, int num_ctrs) +{ + int i; + + /* routine is called once for all nodes */ + + spu_evnt_phys_spu_indx = 0; /* - * For all events excetp PPU CYCLEs, each node will need to make + * For all events except PPU CYCLEs, each node will need to make * the rtas cbe-perftools call to setup and reset the debug bus. * Make the token lookup call once and store it in the global * variable pm_rtas_token. */ + pm_rtas_token = rtas_token("ibm,cbe-perftools"); + if (unlikely(pm_rtas_token == RTAS_UNKNOWN_SERVICE)) { printk(KERN_ERR "%s: rtas token ibm,cbe-perftools unknown\n", @@ -580,6 +711,58 @@ static int cell_reg_setup(struct op_counter_config *ctr, return -EIO; } + /* setup the pm_control register settings, + * settings will be written per node by the + * cell_cpu_setup() function. + */ + pm_regs.pm_cntrl.trace_buf_ovflw = 1; + + /* Use the occurrence trace mode to have SPU PC saved + * to the trace buffer. Occurrence data in trace buffer + * is not used. Bit 2 must be set to store SPU addresses. + */ + pm_regs.pm_cntrl.trace_mode = 2; + + pm_regs.pm_cntrl.spu_addr_trace = 0x1; /* using debug bus + event 2 & 3 */ + + /* setup the debug bus event array with the SPU PC routing events. + * Note, pm_signal[0] will be filled in by set_pm_event() call below. + */ + pm_signal[1].signal_group = SPU_PROFILE_EVENT_ADDR / 100; + pm_signal[1].bus_word = GET_BUS_WORD(SPU_PROFILE_EVENT_ADDR_MASK_A); + pm_signal[1].bit = SPU_PROFILE_EVENT_ADDR % 100; + pm_signal[1].sub_unit = spu_evnt_phys_spu_indx; + + pm_signal[2].signal_group = SPU_PROFILE_EVENT_ADDR / 100; + pm_signal[2].bus_word = GET_BUS_WORD(SPU_PROFILE_EVENT_ADDR_MASK_B); + pm_signal[2].bit = SPU_PROFILE_EVENT_ADDR % 100; + pm_signal[2].sub_unit = spu_evnt_phys_spu_indx; + + /* Set the user selected spu event to profile on, + * note, only one SPU profiling event is supported + */ + num_counters = 1; /* Only support one SPU event at a time */ + set_pm_event(0, ctr[0].event, ctr[0].unit_mask); + + reset_value[0] = 0xFFFFFFFF - ctr[0].count; + + /* global, used by cell_cpu_setup */ + ctr_enabled |= 1; + + /* Initialize the count for each SPU to the reset value */ + for (i=0; i < MAX_NUMNODES * NUM_SPUS_PER_NODE; i++) + spu_pm_cnt[i] = reset_value[0]; + + return 0; +} + +static int cell_reg_setup_ppu(struct op_counter_config *ctr, + struct op_system_config *sys, int num_ctrs) +{ + /* routine is called once for all nodes */ + int i, j, cpu; + num_counters = num_ctrs; if (unlikely(num_ctrs > NR_PHYS_CTRS)) { @@ -589,14 +772,6 @@ static int cell_reg_setup(struct op_counter_config *ctr, __func__); return -EIO; } - pm_regs.group_control = 0; - pm_regs.debug_bus_control = 0; - - /* setup the pm_control register */ - memset(&pm_regs.pm_cntrl, 0, sizeof(struct pm_cntrl)); - pm_regs.pm_cntrl.stop_at_max = 1; - pm_regs.pm_cntrl.trace_mode = 0; - pm_regs.pm_cntrl.freeze = 1; set_count_mode(sys->enable_kernel, sys->enable_user); @@ -665,6 +840,63 @@ static int cell_reg_setup(struct op_counter_config *ctr, } +/* This function is called once for all cpus combined */ +static int cell_reg_setup(struct op_counter_config *ctr, + struct op_system_config *sys, int num_ctrs) +{ + int ret=0; + spu_cycle_reset = 0; + + /* initialize the spu_arr_trace value, will be reset if + * doing spu event profiling. + */ + pm_regs.group_control = 0; + pm_regs.debug_bus_control = 0; + pm_regs.pm_cntrl.stop_at_max = 1; + pm_regs.pm_cntrl.trace_mode = 0; + pm_regs.pm_cntrl.freeze = 1; + pm_regs.pm_cntrl.trace_buf_ovflw = 0; + pm_regs.pm_cntrl.spu_addr_trace = 0; + + /* + * For all events except PPU CYCLEs, each node will need to make + * the rtas cbe-perftools call to setup and reset the debug bus. + * Make the token lookup call once and store it in the global + * variable pm_rtas_token. + */ + pm_rtas_token = rtas_token("ibm,cbe-perftools"); + + if (unlikely(pm_rtas_token == RTAS_UNKNOWN_SERVICE)) { + printk(KERN_ERR + "%s: rtas token ibm,cbe-perftools unknown\n", + __func__); + return -EIO; + } + + if (ctr[0].event == SPU_CYCLES_EVENT_NUM) { + profiling_mode = SPU_PROFILING_CYCLES; + ret = cell_reg_setup_spu_cycles(ctr, sys, num_ctrs); + } else if ((ctr[0].event >= SPU_EVENT_NUM_START) && + (ctr[0].event <= SPU_EVENT_NUM_STOP)) { + profiling_mode = SPU_PROFILING_EVENTS; + spu_cycle_reset = ctr[0].count; + + /* for SPU event profiling, need to setup the + * pm_signal array with the events to route the + * SPU PC before making the FW call. Note, only + * one SPU event for profiling can be specified + * at a time. + */ + cell_reg_setup_spu_events(ctr, sys, num_ctrs); + } else { + profiling_mode = PPU_PROFILING; + ret = cell_reg_setup_ppu(ctr, sys, num_ctrs); + } + + return ret; +} + + /* This function is called once for each cpu */ static int cell_cpu_setup(struct op_counter_config *cntr) @@ -672,8 +904,13 @@ static int cell_cpu_setup(struct op_counter_config *cntr) u32 cpu = smp_processor_id(); u32 num_enabled = 0; int i; + int ret; - if (spu_cycle_reset) + /* Cycle based SPU profiling does not use the performance + * counters. The trace array is configured to collect + * the data. + */ + if (profiling_mode == SPU_PROFILING_CYCLES) return 0; /* There is one performance monitor per processor chip (i.e. node), @@ -686,7 +923,6 @@ static int cell_cpu_setup(struct op_counter_config *cntr) cbe_disable_pm(cpu); cbe_disable_pm_interrupts(cpu); - cbe_write_pm(cpu, pm_interval, 0); cbe_write_pm(cpu, pm_start_stop, 0); cbe_write_pm(cpu, group_control, pm_regs.group_control); cbe_write_pm(cpu, debug_bus_control, pm_regs.debug_bus_control); @@ -703,7 +939,20 @@ static int cell_cpu_setup(struct op_counter_config *cntr) * The pm_rtas_activate_signals will return -EIO if the FW * call failed. */ - return pm_rtas_activate_signals(cbe_cpu_to_node(cpu), num_enabled); + if (profiling_mode == SPU_PROFILING_EVENTS) { + /* For SPU event profiling also need to setup the + * pm interval timer + */ + ret = pm_rtas_activate_signals(cbe_cpu_to_node(cpu), + num_enabled+2); + /* store PC from debug bus to Trace buffer as often + * as possible (every 10 cycles) + */ + cbe_write_pm(cpu, pm_interval, NUM_INTERVAL_CYC); + return ret; + } else + return pm_rtas_activate_signals(cbe_cpu_to_node(cpu), + num_enabled); } #define ENTRIES 303 @@ -885,7 +1134,122 @@ static struct notifier_block cpu_freq_notifier_block = { }; #endif -static int cell_global_start_spu(struct op_counter_config *ctr) +/* + * Note the generic OProfile stop calls do not support returning + * an error on stop. Hence, will not return an error if the FW + * calls fail on stop. Failure to reset the debug bus is not an issue. + * Failure to disable the SPU profiling is not an issue. The FW calls + * to enable the performance counters and debug bus will work even if + * the hardware was not cleanly reset. + */ +static void cell_global_stop_spu_cycles(void) +{ + int subfunc, rtn_value; + unsigned int lfsr_value; + int cpu; + + oprofile_running = 0; + smp_wmb(); + +#ifdef CONFIG_CPU_FREQ + cpufreq_unregister_notifier(&cpu_freq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); +#endif + + for_each_online_cpu(cpu) { + if (cbe_get_hw_thread_id(cpu)) + continue; + + subfunc = 3; /* + * 2 - activate SPU tracing, + * 3 - deactivate + */ + lfsr_value = 0x8f100000; + + rtn_value = rtas_call(spu_rtas_token, 3, 1, NULL, + subfunc, cbe_cpu_to_node(cpu), + lfsr_value); + + if (unlikely(rtn_value != 0)) { + printk(KERN_ERR + "%s: rtas call ibm,cbe-spu-perftools " \ + "failed, return = %d\n", + __func__, rtn_value); + } + + /* Deactivate the signals */ + pm_rtas_reset_signals(cbe_cpu_to_node(cpu)); + } + + stop_spu_profiling_cycles(); +} + +static void cell_global_stop_spu_events(void) +{ + int cpu; + oprofile_running = 0; + + stop_spu_profiling_events(); + smp_wmb(); + + for_each_online_cpu(cpu) { + if (cbe_get_hw_thread_id(cpu)) + continue; + + cbe_sync_irq(cbe_cpu_to_node(cpu)); + /* Stop the counters */ + cbe_disable_pm(cpu); + cbe_write_pm07_control(cpu, 0, 0); + + /* Deactivate the signals */ + pm_rtas_reset_signals(cbe_cpu_to_node(cpu)); + + /* Deactivate interrupts */ + cbe_disable_pm_interrupts(cpu); + } + del_timer_sync(&timer_spu_event_swap); +} + +static void cell_global_stop_ppu(void) +{ + int cpu; + + /* + * This routine will be called once for the system. + * There is one performance monitor per node, so we + * only need to perform this function once per node. + */ + del_timer_sync(&timer_virt_cntr); + oprofile_running = 0; + smp_wmb(); + + for_each_online_cpu(cpu) { + if (cbe_get_hw_thread_id(cpu)) + continue; + + cbe_sync_irq(cbe_cpu_to_node(cpu)); + /* Stop the counters */ + cbe_disable_pm(cpu); + + /* Deactivate the signals */ + pm_rtas_reset_signals(cbe_cpu_to_node(cpu)); + + /* Deactivate interrupts */ + cbe_disable_pm_interrupts(cpu); + } +} + +static void cell_global_stop(void) +{ + if (profiling_mode == PPU_PROFILING) + cell_global_stop_ppu(); + else if (profiling_mode == SPU_PROFILING_EVENTS) + cell_global_stop_spu_events(); + else + cell_global_stop_spu_cycles(); +} + +static int cell_global_start_spu_cycles(struct op_counter_config *ctr) { int subfunc; unsigned int lfsr_value; @@ -951,18 +1315,18 @@ static int cell_global_start_spu(struct op_counter_config *ctr) /* start profiling */ ret = rtas_call(spu_rtas_token, 3, 1, NULL, subfunc, - cbe_cpu_to_node(cpu), lfsr_value); + cbe_cpu_to_node(cpu), lfsr_value); if (unlikely(ret != 0)) { printk(KERN_ERR - "%s: rtas call ibm,cbe-spu-perftools failed, return = %d\n", - __func__, ret); + "%s: rtas call ibm,cbe-spu-perftools failed, " \ + "return = %d\n", __func__, ret); rtas_error = -EIO; goto out; } } - rtas_error = start_spu_profiling(spu_cycle_reset); + rtas_error = start_spu_profiling_cycles(spu_cycle_reset); if (rtas_error) goto out_stop; @@ -970,11 +1334,74 @@ static int cell_global_start_spu(struct op_counter_config *ctr) return 0; out_stop: - cell_global_stop_spu(); /* clean up the PMU/debug bus */ + cell_global_stop_spu_cycles(); /* clean up the PMU/debug bus */ out: return rtas_error; } +static int cell_global_start_spu_events(struct op_counter_config *ctr) +{ + int cpu; + u32 interrupt_mask = 0; + int rtn = 0; + + hdw_thread = 0; + + /* spu event profiling, uses the performance counters to generate + * an interrupt. The hardware is setup to store the SPU program + * counter into the trace array. The occurrence mode is used to + * enable storing data to the trace buffer. The bits are set + * to send/store the SPU address in the trace buffer. The debug + * bus must be setup to route the SPU program counter onto the + * debug bus. The occurrence data in the trace buffer is not used. + */ + + /* This routine gets called once for the system. + * There is one performance monitor per node, so we + * only need to perform this function once per node. + */ + + for_each_online_cpu(cpu) { + if (cbe_get_hw_thread_id(cpu)) + continue; + + /* + * Setup SPU event-based profiling. + * Set perf_mon_control bit 0 to a zero before + * enabling spu collection hardware. + * + * Only support one SPU event on one SPU per node. + */ + if (ctr_enabled & 1) { + cbe_write_ctr(cpu, 0, reset_value[0]); + enable_ctr(cpu, 0, pm_regs.pm07_cntrl); + interrupt_mask |= + CBE_PM_CTR_OVERFLOW_INTR(0); + } else { + /* Disable counter */ + cbe_write_pm07_control(cpu, 0, 0); + } + + cbe_get_and_clear_pm_interrupts(cpu); + cbe_enable_pm_interrupts(cpu, hdw_thread, interrupt_mask); + cbe_enable_pm(cpu); + + /* clear the trace buffer */ + cbe_write_pm(cpu, trace_address, 0); + } + + /* Start the timer to time slice collecting the event profile + * on each of the SPUs. Note, can collect profile on one SPU + * per node at a time. + */ + start_spu_event_swap(); + start_spu_profiling_events(); + oprofile_running = 1; + smp_wmb(); + + return rtn; +} + static int cell_global_start_ppu(struct op_counter_config *ctr) { u32 cpu, i; @@ -994,8 +1421,7 @@ static int cell_global_start_ppu(struct op_counter_config *ctr) if (ctr_enabled & (1 << i)) { cbe_write_ctr(cpu, i, reset_value[i]); enable_ctr(cpu, i, pm_regs.pm07_cntrl); - interrupt_mask |= - CBE_PM_CTR_OVERFLOW_INTR(i); + interrupt_mask |= CBE_PM_CTR_OVERFLOW_INTR(i); } else { /* Disable counter */ cbe_write_pm07_control(cpu, i, 0); @@ -1024,99 +1450,162 @@ static int cell_global_start_ppu(struct op_counter_config *ctr) static int cell_global_start(struct op_counter_config *ctr) { - if (spu_cycle_reset) - return cell_global_start_spu(ctr); + if (profiling_mode == SPU_PROFILING_CYCLES) + return cell_global_start_spu_cycles(ctr); + else if (profiling_mode == SPU_PROFILING_EVENTS) + return cell_global_start_spu_events(ctr); else return cell_global_start_ppu(ctr); } -/* - * Note the generic OProfile stop calls do not support returning - * an error on stop. Hence, will not return an error if the FW - * calls fail on stop. Failure to reset the debug bus is not an issue. - * Failure to disable the SPU profiling is not an issue. The FW calls - * to enable the performance counters and debug bus will work even if - * the hardware was not cleanly reset. + +/* The SPU interrupt handler + * + * SPU event profiling works as follows: + * The pm_signal[0] holds the one SPU event to be measured. It is routed on + * the debug bus using word 0 or 1. The value of pm_signal[1] and + * pm_signal[2] contain the necessary events to route the SPU program + * counter for the selected SPU onto the debug bus using words 2 and 3. + * The pm_interval register is setup to write the SPU PC value into the + * trace buffer at the maximum rate possible. The trace buffer is configured + * to store the PCs, wrapping when it is full. The performance counter is + * intialized to the max hardware count minus the number of events, N, between + * samples. Once the N events have occured, a HW counter overflow occurs + * causing the generation of a HW counter interrupt which also stops the + * writing of the SPU PC values to the trace buffer. Hence the last PC + * written to the trace buffer is the SPU PC that we want. Unfortunately, + * we have to read from the beginning of the trace buffer to get to the + * last value written. We just hope the PPU has nothing better to do then + * service this interrupt. The PC for the specific SPU being profiled is + * extracted from the trace buffer processed and stored. The trace buffer + * is cleared, interrupts are cleared, the counter is reset to max - N. + * A kernel timer is used to periodically call the routine spu_evnt_swap() + * to switch to the next physical SPU in the node to profile in round robbin + * order. This way data is collected for all SPUs on the node. It does mean + * that we need to use a relatively small value of N to ensure enough samples + * on each SPU are collected each SPU is being profiled 1/8 of the time. + * It may also be necessary to use a longer sample collection period. */ -static void cell_global_stop_spu(void) +static void cell_handle_interrupt_spu(struct pt_regs *regs, + struct op_counter_config *ctr) { - int subfunc, rtn_value; - unsigned int lfsr_value; - int cpu; + u32 cpu, cpu_tmp; + u64 trace_entry; + u32 interrupt_mask; + u64 trace_buffer[2]; + u64 last_trace_buffer; + u32 sample; + u32 trace_addr; + unsigned long sample_array_lock_flags; + int spu_num; + unsigned long flags; - oprofile_running = 0; + /* Make sure spu event interrupt handler and spu event swap + * don't access the counters simultaneously. + */ + cpu = smp_processor_id(); + spin_lock_irqsave(&cntr_lock, flags); -#ifdef CONFIG_CPU_FREQ - cpufreq_unregister_notifier(&cpu_freq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); -#endif + cpu_tmp = cpu; + cbe_disable_pm(cpu); - for_each_online_cpu(cpu) { - if (cbe_get_hw_thread_id(cpu)) - continue; + interrupt_mask = cbe_get_and_clear_pm_interrupts(cpu); - subfunc = 3; /* - * 2 - activate SPU tracing, - * 3 - deactivate - */ - lfsr_value = 0x8f100000; + sample = 0xABCDEF; + trace_entry = 0xfedcba; + last_trace_buffer = 0xdeadbeaf; - rtn_value = rtas_call(spu_rtas_token, 3, 1, NULL, - subfunc, cbe_cpu_to_node(cpu), - lfsr_value); + if ((oprofile_running == 1) && (interrupt_mask != 0)) { + /* disable writes to trace buff */ + cbe_write_pm(cpu, pm_interval, 0); - if (unlikely(rtn_value != 0)) { - printk(KERN_ERR - "%s: rtas call ibm,cbe-spu-perftools failed, return = %d\n", - __func__, rtn_value); + /* only have one perf cntr being used, cntr 0 */ + if ((interrupt_mask & CBE_PM_CTR_OVERFLOW_INTR(0)) + && ctr[0].enabled) + /* The SPU PC values will be read + * from the trace buffer, reset counter + */ + + cbe_write_ctr(cpu, 0, reset_value[0]); + + trace_addr = cbe_read_pm(cpu, trace_address); + + while (!(trace_addr & CBE_PM_TRACE_BUF_EMPTY)) { + /* There is data in the trace buffer to process + * Read the buffer until you get to the last + * entry. This is the value we want. + */ + + cbe_read_trace_buffer(cpu, trace_buffer); + trace_addr = cbe_read_pm(cpu, trace_address); } - /* Deactivate the signals */ - pm_rtas_reset_signals(cbe_cpu_to_node(cpu)); - } + /* SPU Address 16 bit count format for 128 bit + * HW trace buffer is used for the SPU PC storage + * HDR bits 0:15 + * SPU Addr 0 bits 16:31 + * SPU Addr 1 bits 32:47 + * unused bits 48:127 + * + * HDR: bit4 = 1 SPU Address 0 valid + * HDR: bit5 = 1 SPU Address 1 valid + * - unfortunately, the valid bits don't seem to work + * + * Note trace_buffer[0] holds bits 0:63 of the HW + * trace buffer, trace_buffer[1] holds bits 64:127 + */ - stop_spu_profiling(); -} + trace_entry = trace_buffer[0] + & 0x00000000FFFF0000; -static void cell_global_stop_ppu(void) -{ - int cpu; + /* only top 16 of the 18 bit SPU PC address + * is stored in trace buffer, hence shift right + * by 16 -2 bits */ + sample = trace_entry >> 14; + last_trace_buffer = trace_buffer[0]; - /* - * This routine will be called once for the system. - * There is one performance monitor per node, so we - * only need to perform this function once per node. - */ - del_timer_sync(&timer_virt_cntr); - oprofile_running = 0; - smp_wmb(); + spu_num = spu_evnt_phys_spu_indx + + (cbe_cpu_to_node(cpu) * NUM_SPUS_PER_NODE); - for_each_online_cpu(cpu) { - if (cbe_get_hw_thread_id(cpu)) - continue; + /* make sure only one process at a time is calling + * spu_sync_buffer() + */ + spin_lock_irqsave(&oprof_spu_smpl_arry_lck, + sample_array_lock_flags); + spu_sync_buffer(spu_num, &sample, 1); + spin_unlock_irqrestore(&oprof_spu_smpl_arry_lck, + sample_array_lock_flags); - cbe_sync_irq(cbe_cpu_to_node(cpu)); - /* Stop the counters */ - cbe_disable_pm(cpu); + smp_wmb(); /* insure spu event buffer updates are written + * don't want events intermingled... */ - /* Deactivate the signals */ - pm_rtas_reset_signals(cbe_cpu_to_node(cpu)); + /* The counters were frozen by the interrupt. + * Reenable the interrupt and restart the counters. + */ + cbe_write_pm(cpu, pm_interval, NUM_INTERVAL_CYC); + cbe_enable_pm_interrupts(cpu, hdw_thread, + virt_cntr_inter_mask); - /* Deactivate interrupts */ - cbe_disable_pm_interrupts(cpu); - } -} + /* clear the trace buffer, re-enable writes to trace buff */ + cbe_write_pm(cpu, trace_address, 0); + cbe_write_pm(cpu, pm_interval, NUM_INTERVAL_CYC); -static void cell_global_stop(void) -{ - if (spu_cycle_reset) - cell_global_stop_spu(); - else - cell_global_stop_ppu(); + /* The writes to the various performance counters only writes + * to a latch. The new values (interrupt setting bits, reset + * counter value etc.) are not copied to the actual registers + * until the performance monitor is enabled. In order to get + * this to work as desired, the permormance monitor needs to + * be disabled while writing to the latches. This is a + * HW design issue. + */ + write_pm_cntrl(cpu); + cbe_enable_pm(cpu); + } + spin_unlock_irqrestore(&cntr_lock, flags); } -static void cell_handle_interrupt(struct pt_regs *regs, - struct op_counter_config *ctr) +static void cell_handle_interrupt_ppu(struct pt_regs *regs, + struct op_counter_config *ctr) { u32 cpu; u64 pc; @@ -1132,7 +1621,7 @@ static void cell_handle_interrupt(struct pt_regs *regs, * routine are not running at the same time. See the * cell_virtual_cntr() routine for additional comments. */ - spin_lock_irqsave(&virt_cntr_lock, flags); + spin_lock_irqsave(&cntr_lock, flags); /* * Need to disable and reenable the performance counters @@ -1185,7 +1674,16 @@ static void cell_handle_interrupt(struct pt_regs *regs, */ cbe_enable_pm(cpu); } - spin_unlock_irqrestore(&virt_cntr_lock, flags); + spin_unlock_irqrestore(&cntr_lock, flags); +} + +static void cell_handle_interrupt(struct pt_regs *regs, + struct op_counter_config *ctr) +{ + if (profiling_mode == PPU_PROFILING) + cell_handle_interrupt_ppu(regs, ctr); + else + cell_handle_interrupt_spu(regs, ctr); } /* @@ -1195,7 +1693,8 @@ static void cell_handle_interrupt(struct pt_regs *regs, */ static int cell_sync_start(void) { - if (spu_cycle_reset) + if ((profiling_mode == SPU_PROFILING_CYCLES) || + (profiling_mode == SPU_PROFILING_EVENTS)) return spu_sync_start(); else return DO_GENERIC_SYNC; @@ -1203,7 +1702,8 @@ static int cell_sync_start(void) static int cell_sync_stop(void) { - if (spu_cycle_reset) + if ((profiling_mode == SPU_PROFILING_CYCLES) || + (profiling_mode == SPU_PROFILING_EVENTS)) return spu_sync_stop(); else return 1; diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h index 9fa9dcdf344b..e02a359d2aa5 100644 --- a/arch/x86/include/asm/bitops.h +++ b/arch/x86/include/asm/bitops.h @@ -300,7 +300,7 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr) return oldbit; } -static inline int constant_test_bit(int nr, const volatile unsigned long *addr) +static inline int constant_test_bit(unsigned int nr, const volatile unsigned long *addr) { return ((1UL << (nr % BITS_PER_LONG)) & (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0; diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 29dc0c89d4af..d37593c2f438 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -47,7 +47,7 @@ #endif static int __initdata acpi_force = 0; - +u32 acpi_rsdt_forced; #ifdef CONFIG_ACPI int acpi_disabled = 0; #else @@ -1374,6 +1374,17 @@ static void __init acpi_process_madt(void) "Invalid BIOS MADT, disabling ACPI\n"); disable_acpi(); } + } else { + /* + * ACPI found no MADT, and so ACPI wants UP PIC mode. + * In the event an MPS table was found, forget it. + * Boot with "acpi=off" to use MPS on such a system. + */ + if (smp_found_config) { + printk(KERN_WARNING PREFIX + "No APIC-table, disabling MPS\n"); + smp_found_config = 0; + } } /* @@ -1809,6 +1820,10 @@ static int __init parse_acpi(char *arg) disable_acpi(); acpi_ht = 1; } + /* acpi=rsdt use RSDT instead of XSDT */ + else if (strcmp(arg, "rsdt") == 0) { + acpi_rsdt_forced = 1; + } /* "acpi=noirq" disables ACPI interrupt routing */ else if (strcmp(arg, "noirq") == 0) { acpi_noirq_set(); diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c index c2502eb9aa83..a4805b3b4095 100644 --- a/arch/x86/kernel/acpi/cstate.c +++ b/arch/x86/kernel/acpi/cstate.c @@ -56,6 +56,7 @@ static struct cstate_entry *cpu_cstate_entry; /* per CPU ptr */ static short mwait_supported[ACPI_PROCESSOR_MAX_POWER]; #define MWAIT_SUBSTATE_MASK (0xf) +#define MWAIT_CSTATE_MASK (0xf) #define MWAIT_SUBSTATE_SIZE (4) #define CPUID_MWAIT_LEAF (5) @@ -98,7 +99,8 @@ int acpi_processor_ffh_cstate_probe(unsigned int cpu, cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx); /* Check whether this particular cx_type (in CST) is supported or not */ - cstate_type = (cx->address >> MWAIT_SUBSTATE_SIZE) + 1; + cstate_type = ((cx->address >> MWAIT_SUBSTATE_SIZE) & + MWAIT_CSTATE_MASK) + 1; edx_part = edx >> (cstate_type * MWAIT_SUBSTATE_SIZE); num_cstate_subtype = edx_part & MWAIT_SUBSTATE_MASK; diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 806b4e9051b4..707c1f6f95fa 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -159,6 +159,8 @@ static int __init acpi_sleep_setup(char *str) #endif if (strncmp(str, "old_ordering", 12) == 0) acpi_old_suspend_ordering(); + if (strncmp(str, "s4_nonvs", 8) == 0) + acpi_s4_no_nvs(); str = strchr(str, ','); if (str != NULL) str += strspn(str, ", \t"); diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 65a13943e098..e85826829cf2 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -665,6 +665,27 @@ void __init e820_mark_nosave_regions(unsigned long limit_pfn) } #endif +#ifdef CONFIG_HIBERNATION +/** + * Mark ACPI NVS memory region, so that we can save/restore it during + * hibernation and the subsequent resume. + */ +static int __init e820_mark_nvs_memory(void) +{ + int i; + + for (i = 0; i < e820.nr_map; i++) { + struct e820entry *ei = &e820.map[i]; + + if (ei->type == E820_NVS) + hibernate_nvs_register(ei->addr, ei->size); + } + + return 0; +} +core_initcall(e820_mark_nvs_memory); +#endif + /* * Early reserved memory areas. */ diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index 744aa7fc49d5..76b8cd953dee 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -201,6 +201,12 @@ struct chipset { void (*f)(int num, int slot, int func); }; +/* + * Only works for devices on the root bus. If you add any devices + * not on bus 0 readd another loop level in early_quirks(). But + * be careful because at least the Nvidia quirk here relies on + * only matching on bus 0. + */ static struct chipset early_qrk[] __initdata = { { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, nvidia_bugs }, @@ -267,17 +273,17 @@ static int __init check_dev_quirk(int num, int slot, int func) void __init early_quirks(void) { - int num, slot, func; + int slot, func; if (!early_pci_allowed()) return; /* Poor man's PCI discovery */ - for (num = 0; num < 32; num++) - for (slot = 0; slot < 32; slot++) - for (func = 0; func < 8; func++) { - /* Only probe function 0 on single fn devices */ - if (check_dev_quirk(num, slot, func)) - break; - } + /* Only scan the root bus */ + for (slot = 0; slot < 32; slot++) + for (func = 0; func < 8; func++) { + /* Only probe function 0 on single fn devices */ + if (check_dev_quirk(0, slot, func)) + break; + } } diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 98658f25f542..8fdf06e4edf9 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -2,7 +2,7 @@ * @file op_model_amd.c * athlon / K7 / K8 / Family 10h model-specific MSR operations * - * @remark Copyright 2002-2008 OProfile authors + * @remark Copyright 2002-2009 OProfile authors * @remark Read the file COPYING * * @author John Levon @@ -10,7 +10,7 @@ * @author Graydon Hoare * @author Robert Richter <robert.richter@amd.com> * @author Barry Kasindorf -*/ + */ #include <linux/oprofile.h> #include <linux/device.h> @@ -60,53 +60,10 @@ static unsigned long reset_value[NUM_COUNTERS]; #define IBS_OP_LOW_VALID_BIT (1ULL<<18) /* bit 18 */ #define IBS_OP_LOW_ENABLE (1ULL<<17) /* bit 17 */ -/* Codes used in cpu_buffer.c */ -/* This produces duplicate code, need to be fixed */ -#define IBS_FETCH_BEGIN 3 -#define IBS_OP_BEGIN 4 - -/* - * The function interface needs to be fixed, something like add - * data. Should then be added to linux/oprofile.h. - */ -extern void -oprofile_add_ibs_sample(struct pt_regs * const regs, - unsigned int * const ibs_sample, int ibs_code); - -struct ibs_fetch_sample { - /* MSRC001_1031 IBS Fetch Linear Address Register */ - unsigned int ibs_fetch_lin_addr_low; - unsigned int ibs_fetch_lin_addr_high; - /* MSRC001_1030 IBS Fetch Control Register */ - unsigned int ibs_fetch_ctl_low; - unsigned int ibs_fetch_ctl_high; - /* MSRC001_1032 IBS Fetch Physical Address Register */ - unsigned int ibs_fetch_phys_addr_low; - unsigned int ibs_fetch_phys_addr_high; -}; - -struct ibs_op_sample { - /* MSRC001_1034 IBS Op Logical Address Register (IbsRIP) */ - unsigned int ibs_op_rip_low; - unsigned int ibs_op_rip_high; - /* MSRC001_1035 IBS Op Data Register */ - unsigned int ibs_op_data1_low; - unsigned int ibs_op_data1_high; - /* MSRC001_1036 IBS Op Data 2 Register */ - unsigned int ibs_op_data2_low; - unsigned int ibs_op_data2_high; - /* MSRC001_1037 IBS Op Data 3 Register */ - unsigned int ibs_op_data3_low; - unsigned int ibs_op_data3_high; - /* MSRC001_1038 IBS DC Linear Address Register (IbsDcLinAd) */ - unsigned int ibs_dc_linear_low; - unsigned int ibs_dc_linear_high; - /* MSRC001_1039 IBS DC Physical Address Register (IbsDcPhysAd) */ - unsigned int ibs_dc_phys_low; - unsigned int ibs_dc_phys_high; -}; +#define IBS_FETCH_SIZE 6 +#define IBS_OP_SIZE 12 -static int ibs_allowed; /* AMD Family10h and later */ +static int has_ibs; /* AMD Family10h and later */ struct op_ibs_config { unsigned long op_enabled; @@ -197,31 +154,29 @@ static inline int op_amd_handle_ibs(struct pt_regs * const regs, struct op_msrs const * const msrs) { - unsigned int low, high; - struct ibs_fetch_sample ibs_fetch; - struct ibs_op_sample ibs_op; + u32 low, high; + u64 msr; + struct op_entry entry; - if (!ibs_allowed) + if (!has_ibs) return 1; if (ibs_config.fetch_enabled) { rdmsr(MSR_AMD64_IBSFETCHCTL, low, high); if (high & IBS_FETCH_HIGH_VALID_BIT) { - ibs_fetch.ibs_fetch_ctl_high = high; - ibs_fetch.ibs_fetch_ctl_low = low; - rdmsr(MSR_AMD64_IBSFETCHLINAD, low, high); - ibs_fetch.ibs_fetch_lin_addr_high = high; - ibs_fetch.ibs_fetch_lin_addr_low = low; - rdmsr(MSR_AMD64_IBSFETCHPHYSAD, low, high); - ibs_fetch.ibs_fetch_phys_addr_high = high; - ibs_fetch.ibs_fetch_phys_addr_low = low; - - oprofile_add_ibs_sample(regs, - (unsigned int *)&ibs_fetch, - IBS_FETCH_BEGIN); + rdmsrl(MSR_AMD64_IBSFETCHLINAD, msr); + oprofile_write_reserve(&entry, regs, msr, + IBS_FETCH_CODE, IBS_FETCH_SIZE); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); + oprofile_add_data(&entry, low); + oprofile_add_data(&entry, high); + rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, msr); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); + oprofile_write_commit(&entry); /* reenable the IRQ */ - rdmsr(MSR_AMD64_IBSFETCHCTL, low, high); high &= ~IBS_FETCH_HIGH_VALID_BIT; high |= IBS_FETCH_HIGH_ENABLE; low &= IBS_FETCH_LOW_MAX_CNT_MASK; @@ -232,30 +187,29 @@ op_amd_handle_ibs(struct pt_regs * const regs, if (ibs_config.op_enabled) { rdmsr(MSR_AMD64_IBSOPCTL, low, high); if (low & IBS_OP_LOW_VALID_BIT) { - rdmsr(MSR_AMD64_IBSOPRIP, low, high); - ibs_op.ibs_op_rip_low = low; - ibs_op.ibs_op_rip_high = high; - rdmsr(MSR_AMD64_IBSOPDATA, low, high); - ibs_op.ibs_op_data1_low = low; - ibs_op.ibs_op_data1_high = high; - rdmsr(MSR_AMD64_IBSOPDATA2, low, high); - ibs_op.ibs_op_data2_low = low; - ibs_op.ibs_op_data2_high = high; - rdmsr(MSR_AMD64_IBSOPDATA3, low, high); - ibs_op.ibs_op_data3_low = low; - ibs_op.ibs_op_data3_high = high; - rdmsr(MSR_AMD64_IBSDCLINAD, low, high); - ibs_op.ibs_dc_linear_low = low; - ibs_op.ibs_dc_linear_high = high; - rdmsr(MSR_AMD64_IBSDCPHYSAD, low, high); - ibs_op.ibs_dc_phys_low = low; - ibs_op.ibs_dc_phys_high = high; + rdmsrl(MSR_AMD64_IBSOPRIP, msr); + oprofile_write_reserve(&entry, regs, msr, + IBS_OP_CODE, IBS_OP_SIZE); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); + rdmsrl(MSR_AMD64_IBSOPDATA, msr); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); + rdmsrl(MSR_AMD64_IBSOPDATA2, msr); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); + rdmsrl(MSR_AMD64_IBSOPDATA3, msr); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); + rdmsrl(MSR_AMD64_IBSDCLINAD, msr); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); + rdmsrl(MSR_AMD64_IBSDCPHYSAD, msr); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); + oprofile_write_commit(&entry); /* reenable the IRQ */ - oprofile_add_ibs_sample(regs, - (unsigned int *)&ibs_op, - IBS_OP_BEGIN); - rdmsr(MSR_AMD64_IBSOPCTL, low, high); high = 0; low &= ~IBS_OP_LOW_VALID_BIT; low |= IBS_OP_LOW_ENABLE; @@ -305,14 +259,14 @@ static void op_amd_start(struct op_msrs const * const msrs) } #ifdef CONFIG_OPROFILE_IBS - if (ibs_allowed && ibs_config.fetch_enabled) { + if (has_ibs && ibs_config.fetch_enabled) { low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; high = ((ibs_config.rand_en & 0x1) << 25) /* bit 57 */ + IBS_FETCH_HIGH_ENABLE; wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); } - if (ibs_allowed && ibs_config.op_enabled) { + if (has_ibs && ibs_config.op_enabled) { low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF) + ((ibs_config.dispatched_ops & 0x1) << 19) /* bit 19 */ + IBS_OP_LOW_ENABLE; @@ -341,14 +295,14 @@ static void op_amd_stop(struct op_msrs const * const msrs) } #ifdef CONFIG_OPROFILE_IBS - if (ibs_allowed && ibs_config.fetch_enabled) { + if (has_ibs && ibs_config.fetch_enabled) { /* clear max count and enable */ low = 0; high = 0; wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); } - if (ibs_allowed && ibs_config.op_enabled) { + if (has_ibs && ibs_config.op_enabled) { /* clear max count and enable */ low = 0; high = 0; @@ -409,6 +363,7 @@ static int init_ibs_nmi(void) | IBSCTL_LVTOFFSETVAL); pci_read_config_dword(cpu_cfg, IBSCTL, &value); if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) { + pci_dev_put(cpu_cfg); printk(KERN_DEBUG "Failed to setup IBS LVT offset, " "IBSCTL = 0x%08x", value); return 1; @@ -436,20 +391,20 @@ static int init_ibs_nmi(void) /* uninitialize the APIC for the IBS interrupts if needed */ static void clear_ibs_nmi(void) { - if (ibs_allowed) + if (has_ibs) on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1); } /* initialize the APIC for the IBS interrupts if available */ static void ibs_init(void) { - ibs_allowed = boot_cpu_has(X86_FEATURE_IBS); + has_ibs = boot_cpu_has(X86_FEATURE_IBS); - if (!ibs_allowed) + if (!has_ibs) return; if (init_ibs_nmi()) { - ibs_allowed = 0; + has_ibs = 0; return; } @@ -458,7 +413,7 @@ static void ibs_init(void) static void ibs_exit(void) { - if (!ibs_allowed) + if (!has_ibs) return; clear_ibs_nmi(); @@ -478,7 +433,7 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root) if (ret) return ret; - if (!ibs_allowed) + if (!has_ibs) return ret; /* model specific files */ diff --git a/crypto/async_tx/async_tx.c b/crypto/async_tx/async_tx.c index dcbf1be149f3..f21147f3626a 100644 --- a/crypto/async_tx/async_tx.c +++ b/crypto/async_tx/async_tx.c @@ -28,351 +28,18 @@ #include <linux/async_tx.h> #ifdef CONFIG_DMA_ENGINE -static enum dma_state_client -dma_channel_add_remove(struct dma_client *client, - struct dma_chan *chan, enum dma_state state); - -static struct dma_client async_tx_dma = { - .event_callback = dma_channel_add_remove, - /* .cap_mask == 0 defaults to all channels */ -}; - -/** - * dma_cap_mask_all - enable iteration over all operation types - */ -static dma_cap_mask_t dma_cap_mask_all; - -/** - * chan_ref_percpu - tracks channel allocations per core/opertion - */ -struct chan_ref_percpu { - struct dma_chan_ref *ref; -}; - -static int channel_table_initialized; -static struct chan_ref_percpu *channel_table[DMA_TX_TYPE_END]; - -/** - * async_tx_lock - protect modification of async_tx_master_list and serialize - * rebalance operations - */ -static spinlock_t async_tx_lock; - -static LIST_HEAD(async_tx_master_list); - -/* async_tx_issue_pending_all - start all transactions on all channels */ -void async_tx_issue_pending_all(void) -{ - struct dma_chan_ref *ref; - - rcu_read_lock(); - list_for_each_entry_rcu(ref, &async_tx_master_list, node) - ref->chan->device->device_issue_pending(ref->chan); - rcu_read_unlock(); -} -EXPORT_SYMBOL_GPL(async_tx_issue_pending_all); - -/* dma_wait_for_async_tx - spin wait for a transcation to complete - * @tx: transaction to wait on - */ -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; - - if (!tx) - return DMA_SUCCESS; - - /* 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; -} -EXPORT_SYMBOL_GPL(dma_wait_for_async_tx); - -/* async_tx_run_dependencies - helper routine for dma drivers to process - * (start) dependent operations on their target channel - * @tx: transaction with dependencies - */ -void async_tx_run_dependencies(struct dma_async_tx_descriptor *tx) -{ - struct dma_async_tx_descriptor *dep = tx->next; - struct dma_async_tx_descriptor *dep_next; - struct dma_chan *chan; - - if (!dep) - return; - - chan = dep->chan; - - /* keep submitting up until a channel switch is detected - * in that case we will be called again as a result of - * processing the interrupt from async_tx_channel_switch - */ - for (; dep; dep = dep_next) { - spin_lock_bh(&dep->lock); - dep->parent = NULL; - dep_next = dep->next; - if (dep_next && dep_next->chan == chan) - dep->next = NULL; /* ->next will be submitted */ - else - dep_next = NULL; /* submit current dep and terminate */ - spin_unlock_bh(&dep->lock); - - dep->tx_submit(dep); - } - - chan->device->device_issue_pending(chan); -} -EXPORT_SYMBOL_GPL(async_tx_run_dependencies); - -static void -free_dma_chan_ref(struct rcu_head *rcu) -{ - struct dma_chan_ref *ref; - ref = container_of(rcu, struct dma_chan_ref, rcu); - kfree(ref); -} - -static void -init_dma_chan_ref(struct dma_chan_ref *ref, struct dma_chan *chan) -{ - INIT_LIST_HEAD(&ref->node); - INIT_RCU_HEAD(&ref->rcu); - ref->chan = chan; - atomic_set(&ref->count, 0); -} - -/** - * get_chan_ref_by_cap - returns the nth channel of the given capability - * defaults to returning the channel with the desired capability and the - * lowest reference count if the index can not be satisfied - * @cap: capability to match - * @index: nth channel desired, passing -1 has the effect of forcing the - * default return value - */ -static struct dma_chan_ref * -get_chan_ref_by_cap(enum dma_transaction_type cap, int index) -{ - struct dma_chan_ref *ret_ref = NULL, *min_ref = NULL, *ref; - - rcu_read_lock(); - list_for_each_entry_rcu(ref, &async_tx_master_list, node) - if (dma_has_cap(cap, ref->chan->device->cap_mask)) { - if (!min_ref) - min_ref = ref; - else if (atomic_read(&ref->count) < - atomic_read(&min_ref->count)) - min_ref = ref; - - if (index-- == 0) { - ret_ref = ref; - break; - } - } - rcu_read_unlock(); - - if (!ret_ref) - ret_ref = min_ref; - - if (ret_ref) - atomic_inc(&ret_ref->count); - - return ret_ref; -} - -/** - * async_tx_rebalance - redistribute the available channels, optimize - * for cpu isolation in the SMP case, and opertaion isolation in the - * uniprocessor case - */ -static void async_tx_rebalance(void) -{ - int cpu, cap, cpu_idx = 0; - unsigned long flags; - - if (!channel_table_initialized) - return; - - spin_lock_irqsave(&async_tx_lock, flags); - - /* undo the last distribution */ - for_each_dma_cap_mask(cap, dma_cap_mask_all) - for_each_possible_cpu(cpu) { - struct dma_chan_ref *ref = - per_cpu_ptr(channel_table[cap], cpu)->ref; - if (ref) { - atomic_set(&ref->count, 0); - per_cpu_ptr(channel_table[cap], cpu)->ref = - NULL; - } - } - - for_each_dma_cap_mask(cap, dma_cap_mask_all) - for_each_online_cpu(cpu) { - struct dma_chan_ref *new; - if (NR_CPUS > 1) - new = get_chan_ref_by_cap(cap, cpu_idx++); - else - new = get_chan_ref_by_cap(cap, -1); - - per_cpu_ptr(channel_table[cap], cpu)->ref = new; - } - - spin_unlock_irqrestore(&async_tx_lock, flags); -} - -static enum dma_state_client -dma_channel_add_remove(struct dma_client *client, - struct dma_chan *chan, enum dma_state state) -{ - unsigned long found, flags; - struct dma_chan_ref *master_ref, *ref; - enum dma_state_client ack = DMA_DUP; /* default: take no action */ - - switch (state) { - case DMA_RESOURCE_AVAILABLE: - found = 0; - rcu_read_lock(); - list_for_each_entry_rcu(ref, &async_tx_master_list, node) - if (ref->chan == chan) { - found = 1; - break; - } - rcu_read_unlock(); - - pr_debug("async_tx: dma resource available [%s]\n", - found ? "old" : "new"); - - if (!found) - ack = DMA_ACK; - else - break; - - /* add the channel to the generic management list */ - master_ref = kmalloc(sizeof(*master_ref), GFP_KERNEL); - if (master_ref) { - /* keep a reference until async_tx is unloaded */ - dma_chan_get(chan); - init_dma_chan_ref(master_ref, chan); - spin_lock_irqsave(&async_tx_lock, flags); - list_add_tail_rcu(&master_ref->node, - &async_tx_master_list); - spin_unlock_irqrestore(&async_tx_lock, - flags); - } else { - printk(KERN_WARNING "async_tx: unable to create" - " new master entry in response to" - " a DMA_RESOURCE_ADDED event" - " (-ENOMEM)\n"); - return 0; - } - - async_tx_rebalance(); - break; - case DMA_RESOURCE_REMOVED: - found = 0; - spin_lock_irqsave(&async_tx_lock, flags); - list_for_each_entry(ref, &async_tx_master_list, node) - if (ref->chan == chan) { - /* permit backing devices to go away */ - dma_chan_put(ref->chan); - list_del_rcu(&ref->node); - call_rcu(&ref->rcu, free_dma_chan_ref); - found = 1; - break; - } - spin_unlock_irqrestore(&async_tx_lock, flags); - - pr_debug("async_tx: dma resource removed [%s]\n", - found ? "ours" : "not ours"); - - if (found) - ack = DMA_ACK; - else - break; - - async_tx_rebalance(); - break; - case DMA_RESOURCE_SUSPEND: - case DMA_RESOURCE_RESUME: - printk(KERN_WARNING "async_tx: does not support dma channel" - " suspend/resume\n"); - break; - default: - BUG(); - } - - return ack; -} - -static int __init -async_tx_init(void) +static int __init async_tx_init(void) { - enum dma_transaction_type cap; - - spin_lock_init(&async_tx_lock); - bitmap_fill(dma_cap_mask_all.bits, DMA_TX_TYPE_END); - - /* an interrupt will never be an explicit operation type. - * clearing this bit prevents allocation to a slot in 'channel_table' - */ - clear_bit(DMA_INTERRUPT, dma_cap_mask_all.bits); - - for_each_dma_cap_mask(cap, dma_cap_mask_all) { - channel_table[cap] = alloc_percpu(struct chan_ref_percpu); - if (!channel_table[cap]) - goto err; - } - - channel_table_initialized = 1; - dma_async_client_register(&async_tx_dma); - dma_async_client_chan_request(&async_tx_dma); + dmaengine_get(); printk(KERN_INFO "async_tx: api initialized (async)\n"); return 0; -err: - printk(KERN_ERR "async_tx: initialization failure\n"); - - while (--cap >= 0) - free_percpu(channel_table[cap]); - - return 1; } static void __exit async_tx_exit(void) { - enum dma_transaction_type cap; - - channel_table_initialized = 0; - - for_each_dma_cap_mask(cap, dma_cap_mask_all) - if (channel_table[cap]) - free_percpu(channel_table[cap]); - - dma_async_client_unregister(&async_tx_dma); + dmaengine_put(); } /** @@ -387,16 +54,9 @@ __async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx, { /* see if we can keep the chain on one channel */ if (depend_tx && - dma_has_cap(tx_type, depend_tx->chan->device->cap_mask)) + dma_has_cap(tx_type, depend_tx->chan->device->cap_mask)) return depend_tx->chan; - else if (likely(channel_table_initialized)) { - struct dma_chan_ref *ref; - int cpu = get_cpu(); - ref = per_cpu_ptr(channel_table[tx_type], cpu)->ref; - put_cpu(); - return ref ? ref->chan : NULL; - } else - return NULL; + return dma_find_channel(tx_type); } EXPORT_SYMBOL_GPL(__async_tx_find_channel); #else diff --git a/drivers/Kconfig b/drivers/Kconfig index 2f557f570ade..00cf9553f740 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -107,4 +107,6 @@ source "drivers/uio/Kconfig" source "drivers/xen/Kconfig" source "drivers/staging/Kconfig" + +source "drivers/platform/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 6326f4dbbdab..c1bf41737936 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -105,3 +105,4 @@ obj-$(CONFIG_OF) += of/ obj-$(CONFIG_SSB) += ssb/ obj-$(CONFIG_VIRTIO) += virtio/ obj-$(CONFIG_STAGING) += staging/ +obj-y += platform/ diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index b0243fd55ac0..d7f9839ba264 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -196,90 +196,6 @@ config ACPI_NUMA depends on (X86 || IA64) default y if IA64_GENERIC || IA64_SGI_SN2 -config ACPI_WMI - tristate "WMI (EXPERIMENTAL)" - depends on X86 - depends on EXPERIMENTAL - help - This driver adds support for the ACPI-WMI (Windows Management - Instrumentation) mapper device (PNP0C14) found on some systems. - - ACPI-WMI is a proprietary extension to ACPI to expose parts of the - ACPI firmware to userspace - this is done through various vendor - defined methods and data blocks in a PNP0C14 device, which are then - made available for userspace to call. - - The implementation of this in Linux currently only exposes this to - other kernel space drivers. - - This driver is a required dependency to build the firmware specific - drivers needed on many machines, including Acer and HP laptops. - - It is safe to enable this driver even if your DSDT doesn't define - any ACPI-WMI devices. - -config ACPI_ASUS - tristate "ASUS/Medion Laptop Extras" - depends on X86 - select BACKLIGHT_CLASS_DEVICE - ---help--- - This driver provides support for extra features of ACPI-compatible - ASUS laptops. As some of Medion laptops are made by ASUS, it may also - support some Medion laptops (such as 9675 for example). It makes all - the extra buttons generate standard ACPI events that go through - /proc/acpi/events, and (on some models) adds support for changing the - display brightness and output, switching the LCD backlight on and off, - and most importantly, allows you to blink those fancy LEDs intended - for reporting mail and wireless status. - - Note: display switching code is currently considered EXPERIMENTAL, - toying with these values may even lock your machine. - - All settings are changed via /proc/acpi/asus directory entries. Owner - and group for these entries can be set with asus_uid and asus_gid - parameters. - - More information and a userspace daemon for handling the extra buttons - at <http://sourceforge.net/projects/acpi4asus/>. - - If you have an ACPI-compatible ASUS laptop, say Y or M here. This - driver is still under development, so if your laptop is unsupported or - something works not quite as expected, please use the mailing list - available on the above page (acpi4asus-user@lists.sourceforge.net). - - NOTE: This driver is deprecated and will probably be removed soon, - use asus-laptop instead. - -config ACPI_TOSHIBA - tristate "Toshiba Laptop Extras" - depends on X86 && INPUT - select INPUT_POLLDEV - select NET - select RFKILL - select BACKLIGHT_CLASS_DEVICE - ---help--- - This driver adds support for access to certain system settings - on "legacy free" Toshiba laptops. These laptops can be recognized by - their lack of a BIOS setup menu and APM support. - - On these machines, all system configuration is handled through the - ACPI. This driver is required for access to controls not covered - by the general ACPI drivers, such as LCD brightness, video output, - etc. - - This driver differs from the non-ACPI Toshiba laptop driver (located - under "Processor type and features") in several aspects. - Configuration is accessed by reading and writing text files in the - /proc tree instead of by program interface to /dev. Furthermore, no - power management functions are exposed, as those are handled by the - general ACPI drivers. - - More information about this driver is available at - <http://memebeam.org/toys/ToshibaAcpiDriver>. - - If you have a legacy free Toshiba laptop (such as the Libretto L1 - series), say Y. - config ACPI_CUSTOM_DSDT_FILE string "Custom DSDT Table file to include" default "" diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 3c0c93300f12..d80f4cc2e0da 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -2,15 +2,8 @@ # Makefile for the Linux ACPI interpreter # -export ACPI_CFLAGS - -ACPI_CFLAGS := -Os - -ifdef CONFIG_ACPI_DEBUG - ACPI_CFLAGS += -DACPI_DEBUG_OUTPUT -endif - -EXTRA_CFLAGS += $(ACPI_CFLAGS) +ccflags-y := -Os +ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT # # ACPI Boot-Time Table Parsing @@ -22,9 +15,13 @@ obj-$(CONFIG_X86) += blacklist.o # ACPI Core Subsystem (Interpreter) # obj-y += osl.o utils.o reboot.o\ - dispatcher/ events/ executer/ hardware/ \ - namespace/ parser/ resources/ tables/ \ - utilities/ + acpica/ + +# sleep related files +obj-y += wakeup.o +obj-y += main.o +obj-$(CONFIG_ACPI_SLEEP) += proc.o + # # ACPI Bus and Device Drivers @@ -35,7 +32,6 @@ ifdef CONFIG_CPU_FREQ processor-objs += processor_perflib.o endif -obj-y += sleep/ obj-y += bus.o glue.o obj-y += scan.o # Keep EC driver first. Initialization of others depend on it. @@ -59,9 +55,6 @@ obj-y += power.o obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o obj-$(CONFIG_ACPI_DEBUG) += debug.o obj-$(CONFIG_ACPI_NUMA) += numa.o -obj-$(CONFIG_ACPI_WMI) += wmi.o -obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o -obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o obj-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o obj-$(CONFIG_ACPI_SBS) += sbshc.o diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile new file mode 100644 index 000000000000..3f23298ee3fd --- /dev/null +++ b/drivers/acpi/acpica/Makefile @@ -0,0 +1,44 @@ +# +# Makefile for ACPICA Core interpreter +# + +ccflags-y := -Os +ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT + +obj-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \ + dsmethod.o dsobject.o dsutils.o dswload.o dswstate.o \ + dsinit.o + +obj-y += evevent.o evregion.o evsci.o evxfevnt.o \ + evmisc.o evrgnini.o evxface.o evxfregn.o \ + evgpe.o evgpeblk.o + +obj-y += exconfig.o exfield.o exnames.o exoparg6.o exresolv.o exstorob.o\ + exconvrt.o exfldio.o exoparg1.o exprep.o exresop.o exsystem.o\ + excreate.o exmisc.o exoparg2.o exregion.o exstore.o exutils.o \ + exdump.o exmutex.o exoparg3.o exresnte.o exstoren.o + +obj-y += hwacpi.o hwgpe.o hwregs.o hwsleep.o hwxface.o + +obj-$(ACPI_FUTURE_USAGE) += hwtimer.o + +obj-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 + +obj-$(ACPI_FUTURE_USAGE) += nsdumpdv.o + +obj-y += psargs.o psparse.o psloop.o pstree.o pswalk.o \ + psopcode.o psscope.o psutils.o psxface.o + +obj-y += rsaddr.o rscreate.o rsinfo.o rsio.o rslist.o rsmisc.o rsxface.o \ + rscalc.o rsirq.o rsmemory.o rsutils.o + +obj-$(ACPI_FUTURE_USAGE) += rsdump.o + +obj-y += tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o + +obj-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 diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h new file mode 100644 index 000000000000..3b20786cbb0d --- /dev/null +++ b/drivers/acpi/acpica/accommon.h @@ -0,0 +1,63 @@ +/****************************************************************************** + * + * Name: accommon.h - Common include files for generation of ACPICA source + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, 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. + */ + +#ifndef __ACCOMMON_H__ +#define __ACCOMMON_H__ + +/* + * Common set of includes for all ACPICA source files. + * We put them here because we don't want to duplicate them + * in the the source code again and again. + * + * Note: The order of these include files is important. + */ +#include "acconfig.h" /* Global configuration constants */ +#include "acmacros.h" /* C macros */ +#include "aclocal.h" /* Internal data types */ +#include "acobject.h" /* ACPI internal object */ +#include "acstruct.h" /* Common structures */ +#include "acglobal.h" /* All global variables */ +#include "achware.h" /* Hardware defines and interfaces */ +#include "acutils.h" /* Utility interfaces */ + +#endif /* __ACCOMMON_H__ */ diff --git a/include/acpi/acconfig.h b/drivers/acpi/acpica/acconfig.h index 29feee27f0ea..e6777fb883d2 100644 --- a/include/acpi/acconfig.h +++ b/drivers/acpi/acpica/acconfig.h @@ -61,10 +61,6 @@ * */ -/* Current ACPICA subsystem version in YYYYMMDD format */ - -#define ACPI_CA_VERSION 0x20080926 - /* * OS name, used for the _OS object. The _OS object is essentially obsolete, * but there is a large base of ASL/AML code in existing machines that check @@ -119,6 +115,10 @@ #define ACPI_ROOT_TABLE_SIZE_INCREMENT 4 +/* Maximum number of While() loop iterations before forced abort */ + +#define ACPI_MAX_LOOP_ITERATIONS 0xFFFF + /****************************************************************************** * * ACPI Specification constants (Do not change unless the specification changes) diff --git a/include/acpi/acdebug.h b/drivers/acpi/acpica/acdebug.h index 62c59df3b86c..62c59df3b86c 100644 --- a/include/acpi/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h diff --git a/include/acpi/acdispat.h b/drivers/acpi/acpica/acdispat.h index 6291904be01e..6291904be01e 100644 --- a/include/acpi/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h diff --git a/include/acpi/acevents.h b/drivers/acpi/acpica/acevents.h index d5d099bf349c..07e20135f01b 100644 --- a/include/acpi/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -93,11 +93,13 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, */ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info); -acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback); +acpi_status +acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context); acpi_status acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block); + struct acpi_gpe_block_info *gpe_block, + void *context); acpi_status acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, diff --git a/include/acpi/acglobal.h b/drivers/acpi/acpica/acglobal.h index 15dda46b70d1..ddb40f5c68fc 100644 --- a/include/acpi/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -102,6 +102,12 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE); */ ACPI_EXTERN 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); + /***************************************************************************** * * Debug support @@ -140,7 +146,7 @@ ACPI_EXTERN u32 acpi_gbl_trace_flags; */ ACPI_EXTERN struct acpi_internal_rsdt acpi_gbl_root_table_list; ACPI_EXTERN struct acpi_table_fadt acpi_gbl_FADT; -extern u8 acpi_gbl_permanent_mmap; +ACPI_EXTERN struct acpi_table_facs *acpi_gbl_FACS; /* These addresses are calculated from FADT address values */ @@ -326,6 +332,7 @@ 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/include/acpi/achware.h b/drivers/acpi/acpica/achware.h index 97a72b193276..58c69dc49ab4 100644 --- a/include/acpi/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -44,11 +44,7 @@ #ifndef __ACHWARE_H__ #define __ACHWARE_H__ -/* PM Timer ticks per second (HZ) */ - -#define PM_TIMER_FREQUENCY 3579545 - -/* Values for the _SST reserved method */ +/* Values for the _SST predefined method */ #define ACPI_SST_INDICATOR_OFF 0 #define ACPI_SST_WORKING 1 @@ -56,8 +52,6 @@ #define ACPI_SST_SLEEPING 3 #define ACPI_SST_SLEEP_CONTEXT 4 -/* Prototypes */ - /* * hwacpi - high level functions */ @@ -75,13 +69,6 @@ acpi_hw_register_read(u32 register_id, u32 * return_value); acpi_status acpi_hw_register_write(u32 register_id, u32 value); -acpi_status -acpi_hw_low_level_read(u32 width, - u32 * value, struct acpi_generic_address *reg); - -acpi_status -acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address *reg); - acpi_status acpi_hw_clear_acpi_status(void); /* @@ -94,13 +81,13 @@ acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info); acpi_status acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block); + struct acpi_gpe_block_info *gpe_block, void *context); acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info *gpe_event_info); acpi_status acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block); + struct acpi_gpe_block_info *gpe_block, void *context); acpi_status acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info, @@ -114,7 +101,8 @@ acpi_status acpi_hw_enable_all_wakeup_gpes(void); acpi_status acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block); + struct acpi_gpe_block_info *gpe_block, + void *context); #ifdef ACPI_FUTURE_USAGE /* diff --git a/include/acpi/acinterp.h b/drivers/acpi/acpica/acinterp.h index e8db7a3143a5..e8db7a3143a5 100644 --- a/include/acpi/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h diff --git a/include/acpi/aclocal.h b/drivers/acpi/acpica/aclocal.h index ecab527cf78e..492d02761bb7 100644 --- a/include/acpi/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -46,8 +46,6 @@ /* acpisrc:struct_defs -- for acpisrc conversion */ -#define ACPI_WAIT_FOREVER 0xFFFF /* u16, as per ACPI spec */ -#define ACPI_DO_NOT_WAIT 0 #define ACPI_SERIALIZED 0xFF typedef u32 acpi_mutex_handle; @@ -120,11 +118,6 @@ static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = { #define ACPI_MAX_LOCK 1 #define ACPI_NUM_LOCK ACPI_MAX_LOCK+1 -/* Owner IDs are used to track namespace nodes for selective deletion */ - -typedef u8 acpi_owner_id; -#define ACPI_OWNER_ID_MAX 0xFF - /* This Thread ID means that the mutex is not in use (unlocked) */ #define ACPI_MUTEX_NOT_ACQUIRED (acpi_thread_id) 0 @@ -165,11 +158,6 @@ typedef enum { ACPI_IMODE_EXECUTE = 0x03 } acpi_interpreter_mode; -union acpi_name_union { - u32 integer; - char ascii[4]; -}; - /* * The Namespace Node describes a named object that appears in the AML. * descriptor_type is used to differentiate between internal descriptors. @@ -216,26 +204,6 @@ struct acpi_namespace_node { #define ANOBJ_IS_BIT_OFFSET 0x40 /* i_aSL only: Reference is a bit offset */ #define ANOBJ_IS_REFERENCED 0x80 /* i_aSL only: Object was referenced */ -/* - * ACPI Table Descriptor. One per ACPI table - */ -struct acpi_table_desc { - acpi_physical_address address; - struct acpi_table_header *pointer; - u32 length; /* Length fixed at 32 bits */ - union acpi_name_union signature; - acpi_owner_id owner_id; - u8 flags; -}; - -/* Flags for above */ - -#define ACPI_TABLE_ORIGIN_UNKNOWN (0) -#define ACPI_TABLE_ORIGIN_MAPPED (1) -#define ACPI_TABLE_ORIGIN_ALLOCATED (2) -#define ACPI_TABLE_ORIGIN_MASK (3) -#define ACPI_TABLE_IS_LOADED (4) - /* One internal RSDT for table management */ struct acpi_internal_rsdt { @@ -266,15 +234,6 @@ struct acpi_ns_search_data { struct acpi_namespace_node *node; }; -/* - * Predefined Namespace items - */ -struct acpi_predefined_names { - char *name; - u8 type; - char *val; -}; - /* Object types used during package copies */ #define ACPI_COPY_TYPE_SIMPLE 0 @@ -487,10 +446,15 @@ struct acpi_gpe_walk_info { struct acpi_gpe_block_info *gpe_block; }; -typedef acpi_status(*acpi_gpe_callback) (struct acpi_gpe_xrupt_info * - gpe_xrupt_info, - struct acpi_gpe_block_info * - gpe_block); +struct acpi_gpe_device_info { + u32 index; + u32 next_block_base_index; + acpi_status status; + struct acpi_namespace_node *gpe_device; +}; + +typedef acpi_status(*acpi_gpe_callback) (struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context); /* Information about each particular fixed event */ @@ -566,6 +530,7 @@ struct acpi_control_state { union acpi_parse_object *predicate_op; u8 *aml_predicate_start; /* Start of if/while predicate */ u8 *package_end; /* End of if/while block */ + u32 loop_count; /* While() loop counter */ }; /* @@ -671,6 +636,12 @@ union acpi_parse_value { union acpi_parse_object *arg; /* arguments and contained ops */ }; +#ifdef ACPI_DISASSEMBLER +#define ACPI_DISASM_ONLY_MEMBERS(a) a; +#else +#define ACPI_DISASM_ONLY_MEMBERS(a) +#endif + #define ACPI_PARSE_COMMON \ union acpi_parse_object *parent; /* Parent op */\ u8 descriptor_type; /* To differentiate various internal objs */\ @@ -790,9 +761,6 @@ struct acpi_parse_state { * ****************************************************************************/ -#define PCI_ROOT_HID_STRING "PNP0A03" -#define PCI_EXPRESS_ROOT_HID_STRING "PNP0A08" - struct acpi_bit_register_info { u8 parent_register; u8 bit_position; @@ -1019,26 +987,4 @@ struct acpi_debug_mem_block { #define ACPI_MEM_LIST_MAX 1 #define ACPI_NUM_MEM_LISTS 2 -struct acpi_memory_list { - char *list_name; - void *list_head; - u16 object_size; - u16 max_depth; - u16 current_depth; - u16 link_offset; - -#ifdef ACPI_DBG_TRACK_ALLOCATIONS - - /* Statistics for debug memory tracking only */ - - u32 total_allocated; - u32 total_freed; - u32 max_occupied; - u32 total_size; - u32 current_total_size; - u32 requests; - u32 hits; -#endif -}; - #endif /* __ACLOCAL_H__ */ diff --git a/include/acpi/acmacros.h b/drivers/acpi/acpica/acmacros.h index 1954c9d1d012..9c127e8e2d6d 100644 --- a/include/acpi/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -45,23 +45,6 @@ #define __ACMACROS_H__ /* - * Data manipulation macros - */ -#define ACPI_LOWORD(l) ((u16)(u32)(l)) -#define ACPI_HIWORD(l) ((u16)((((u32)(l)) >> 16) & 0xFFFF)) -#define ACPI_LOBYTE(l) ((u8)(u16)(l)) -#define ACPI_HIBYTE(l) ((u8)((((u16)(l)) >> 8) & 0xFF)) - -#define ACPI_SET_BIT(target,bit) ((target) |= (bit)) -#define ACPI_CLEAR_BIT(target,bit) ((target) &= ~(bit)) -#define ACPI_MIN(a,b) (((a)<(b))?(a):(b)) -#define ACPI_MAX(a,b) (((a)>(b))?(a):(b)) - -/* Size calculation */ - -#define ACPI_ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0])) - -/* * Extract data using a pointer. Any more than a byte and we * get into potential aligment issues -- see the STORE macros below. * Use with care. @@ -76,39 +59,6 @@ #define ACPI_SET64(ptr) *ACPI_CAST_PTR (u64, ptr) /* - * Pointer manipulation - */ -#define ACPI_CAST_PTR(t, p) ((t *) (acpi_uintptr_t) (p)) -#define ACPI_CAST_INDIRECT_PTR(t, p) ((t **) (acpi_uintptr_t) (p)) -#define ACPI_ADD_PTR(t, a, b) ACPI_CAST_PTR (t, (ACPI_CAST_PTR (u8, (a)) + (acpi_size)(b))) -#define ACPI_PTR_DIFF(a, b) (acpi_size) (ACPI_CAST_PTR (u8, (a)) - ACPI_CAST_PTR (u8, (b))) - -/* Pointer/Integer type conversions */ - -#define ACPI_TO_POINTER(i) ACPI_ADD_PTR (void, (void *) NULL, (acpi_size) i) -#define ACPI_TO_INTEGER(p) ACPI_PTR_DIFF (p, (void *) NULL) -#define ACPI_OFFSET(d, f) (acpi_size) ACPI_PTR_DIFF (&(((d *)0)->f), (void *) NULL) -#define ACPI_PHYSADDR_TO_PTR(i) ACPI_TO_POINTER(i) -#define ACPI_PTR_TO_PHYSADDR(i) ACPI_TO_INTEGER(i) - -#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED -#define ACPI_COMPARE_NAME(a, b) (*ACPI_CAST_PTR (u32, (a)) == *ACPI_CAST_PTR (u32, (b))) -#else -#define ACPI_COMPARE_NAME(a, b) (!ACPI_STRNCMP (ACPI_CAST_PTR (char, (a)), ACPI_CAST_PTR (char, (b)), ACPI_NAME_SIZE)) -#endif - -/* - * Full 64-bit integer must be available on both 32-bit and 64-bit platforms - */ -struct acpi_integer_overlay { - u32 lo_dword; - u32 hi_dword; -}; - -#define ACPI_LODWORD(integer) (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->lo_dword) -#define ACPI_HIDWORD(integer) (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->hi_dword) - -/* * printf() format helpers */ @@ -209,7 +159,7 @@ struct acpi_integer_overlay { /* * The hardware does not support unaligned transfers. We must move the * data one byte at a time. These macros work whether the source or - * the destination (or both) is/are unaligned. (Little-endian move) + * the destination (or both) is/are unaligned. (Little-endian move) */ /* 16-bit source, 16/32/64 destination */ @@ -357,12 +307,6 @@ struct acpi_integer_overlay { {(u32)(Pargs), (u32)(Iargs), (u32)(flags), obj_type, class, type} #endif -#ifdef ACPI_DISASSEMBLER -#define ACPI_DISASM_ONLY_MEMBERS(a) a; -#else -#define ACPI_DISASM_ONLY_MEMBERS(a) -#endif - #define ARG_TYPE_WIDTH 5 #define ARG_1(x) ((u32)(x)) #define ARG_2(x) ((u32)(x) << (1 * ARG_TYPE_WIDTH)) @@ -388,32 +332,16 @@ struct acpi_integer_overlay { #define GET_CURRENT_ARG_TYPE(list) (list & ((u32) 0x1F)) #define INCREMENT_ARG_LIST(list) (list >>= ((u32) ARG_TYPE_WIDTH)) -#if defined (ACPI_DEBUG_OUTPUT) || !defined (ACPI_NO_ERROR_MESSAGES) -/* - * Module name is include in both debug and non-debug versions primarily for - * error messages. The __FILE__ macro is not very useful for this, because it - * often includes the entire pathname to the module - */ -#define ACPI_MODULE_NAME(name) static const char ACPI_UNUSED_VAR _acpi_module_name[] = name; -#else -#define ACPI_MODULE_NAME(name) -#endif - /* * Ascii error messages can be configured out */ #ifndef ACPI_NO_ERROR_MESSAGES -#define AE_INFO _acpi_module_name, __LINE__ /* * Error reporting. Callers module and line number are inserted by AE_INFO, * the plist contains a set of parens to allow variable-length lists. * These macros are used for both the debug and non-debug versions of the code. */ -#define ACPI_INFO(plist) acpi_ut_info plist -#define ACPI_WARNING(plist) acpi_ut_warning plist -#define ACPI_EXCEPTION(plist) acpi_ut_exception plist -#define ACPI_ERROR(plist) acpi_ut_error plist #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); @@ -421,13 +349,9 @@ struct acpi_integer_overlay { /* No error messages */ -#define ACPI_INFO(plist) -#define ACPI_WARNING(plist) -#define ACPI_EXCEPTION(plist) -#define ACPI_ERROR(plist) #define ACPI_ERROR_NAMESPACE(s, e) #define ACPI_ERROR_METHOD(s, n, p, e) -#endif +#endif /* ACPI_NO_ERROR_MESSAGES */ /* * Debug macros that are conditionally compiled @@ -435,36 +359,8 @@ struct acpi_integer_overlay { #ifdef ACPI_DEBUG_OUTPUT /* - * Common parameters used for debug output functions: - * line number, function name, module(file) name, component ID - */ -#define ACPI_DEBUG_PARAMETERS __LINE__, ACPI_GET_FUNCTION_NAME, _acpi_module_name, _COMPONENT - -/* * Function entry tracing */ - -/* - * If ACPI_GET_FUNCTION_NAME was not defined in the compiler-dependent header, - * define it now. This is the case where there the compiler does not support - * a __func__ macro or equivalent. - */ -#ifndef ACPI_GET_FUNCTION_NAME -#define ACPI_GET_FUNCTION_NAME _acpi_function_name -/* - * The Name parameter should be the procedure name as a quoted string. - * The function name is also used by the function exit macros below. - * Note: (const char) is used to be compatible with the debug interfaces - * and macros such as __func__. - */ -#define ACPI_FUNCTION_NAME(name) static const char _acpi_function_name[] = #name; - -#else -/* Compiler supports __func__ (or equivalent) -- Ignore this macro */ - -#define ACPI_FUNCTION_NAME(name) -#endif - #ifdef CONFIG_ACPI_DEBUG_FUNC_TRACE #define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a) \ @@ -584,15 +480,6 @@ struct acpi_integer_overlay { #define ACPI_DUMP_RESOURCE_LIST(a) acpi_rs_dump_resource_list(a) #define ACPI_DUMP_BUFFER(a, b) acpi_ut_dump_buffer((u8 *) a, b, DB_BYTE_DISPLAY, _COMPONENT) -/* - * Master debug print macros - * Print iff: - * 1) Debug print for the current component is enabled - * 2) Debug error level or trace level for the print statement is enabled - */ -#define ACPI_DEBUG_PRINT(plist) acpi_ut_debug_print plist -#define ACPI_DEBUG_PRINT_RAW(plist) acpi_ut_debug_print_raw plist - #else /* * This is the non-debug case -- make everything go away, @@ -603,7 +490,6 @@ struct acpi_integer_overlay { #define ACPI_DEBUG_DEFINE(a) do { } while(0) #define ACPI_DEBUG_ONLY_MEMBERS(a) do { } while(0) -#define ACPI_FUNCTION_NAME(a) do { } while(0) #define ACPI_FUNCTION_TRACE(a) do { } while(0) #define ACPI_FUNCTION_TRACE_PTR(a, b) do { } while(0) #define ACPI_FUNCTION_TRACE_U32(a, b) do { } while(0) @@ -619,8 +505,6 @@ struct acpi_integer_overlay { #define ACPI_DUMP_PATHNAME(a, b, c, d) do { } while(0) #define ACPI_DUMP_RESOURCE_LIST(a) do { } while(0) #define ACPI_DUMP_BUFFER(a, b) do { } while(0) -#define ACPI_DEBUG_PRINT(pl) do { } while(0) -#define ACPI_DEBUG_PRINT_RAW(pl) do { } while(0) #define return_VOID return #define return_ACPI_STATUS(s) return(s) @@ -629,7 +513,7 @@ struct acpi_integer_overlay { #define return_UINT32(s) return(s) #define return_PTR(s) return(s) -#endif +#endif /* ACPI_DEBUG_OUTPUT */ /* * Some code only gets executed when the debugger is built in. diff --git a/include/acpi/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index db4e6f677855..46cb5b46d280 100644 --- a/include/acpi/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -182,7 +182,9 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info); */ acpi_status acpi_ns_check_predefined_names(struct acpi_namespace_node *node, - union acpi_operand_object *return_object); + u32 user_param_count, + acpi_status return_status, + union acpi_operand_object **return_object); const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct acpi_namespace_node @@ -191,6 +193,7 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct void acpi_ns_check_parameter_count(char *pathname, struct acpi_namespace_node *node, + u32 user_param_count, const union acpi_predefined_info *info); /* diff --git a/include/acpi/acobject.h b/drivers/acpi/acpica/acobject.h index eb6f038b03d9..eb6f038b03d9 100644 --- a/include/acpi/acobject.h +++ b/drivers/acpi/acpica/acobject.h diff --git a/include/acpi/acopcode.h b/drivers/acpi/acpica/acopcode.h index dfdf63327885..dfdf63327885 100644 --- a/include/acpi/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h diff --git a/include/acpi/acparser.h b/drivers/acpi/acpica/acparser.h index 23ee0fbf5619..23ee0fbf5619 100644 --- a/include/acpi/acparser.h +++ b/drivers/acpi/acpica/acparser.h diff --git a/include/acpi/acpredef.h b/drivers/acpi/acpica/acpredef.h index 16a9ca9a66e4..16a9ca9a66e4 100644 --- a/include/acpi/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h diff --git a/include/acpi/acresrc.h b/drivers/acpi/acpica/acresrc.h index eef5bd7a59fa..eef5bd7a59fa 100644 --- a/include/acpi/acresrc.h +++ b/drivers/acpi/acpica/acresrc.h diff --git a/include/acpi/acstruct.h b/drivers/acpi/acpica/acstruct.h index 7980a26bad35..7980a26bad35 100644 --- a/include/acpi/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h diff --git a/include/acpi/actables.h b/drivers/acpi/acpica/actables.h index 0cbe1b9ab522..7ce6e33c7f78 100644 --- a/include/acpi/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -94,6 +94,8 @@ void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded); /* * tbutils - table manager utilities */ +acpi_status acpi_tb_initialize_facs(void); + u8 acpi_tb_tables_loaded(void); void diff --git a/include/acpi/acutils.h b/drivers/acpi/acpica/acutils.h index d8307b2987e3..80d8813484fe 100644 --- a/include/acpi/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -297,42 +297,6 @@ void acpi_ut_report_info(char *module_name, u32 line_number); void acpi_ut_report_warning(char *module_name, u32 line_number); -/* Error and message reporting interfaces */ - -void ACPI_INTERNAL_VAR_XFACE -acpi_ut_debug_print(u32 requested_debug_level, - u32 line_number, - const char *function_name, - const char *module_name, - u32 component_id, - const char *format, ...) ACPI_PRINTF_LIKE(6); - -void ACPI_INTERNAL_VAR_XFACE -acpi_ut_debug_print_raw(u32 requested_debug_level, - u32 line_number, - const char *function_name, - const char *module_name, - u32 component_id, - const char *format, ...) ACPI_PRINTF_LIKE(6); - -void ACPI_INTERNAL_VAR_XFACE -acpi_ut_error(const char *module_name, - u32 line_number, const char *format, ...) ACPI_PRINTF_LIKE(3); - -void ACPI_INTERNAL_VAR_XFACE -acpi_ut_exception(const char *module_name, - u32 line_number, - acpi_status status, - const char *format, ...) ACPI_PRINTF_LIKE(4); - -void ACPI_INTERNAL_VAR_XFACE -acpi_ut_warning(const char *module_name, - u32 line_number, const char *format, ...) ACPI_PRINTF_LIKE(3); - -void ACPI_INTERNAL_VAR_XFACE -acpi_ut_info(const char *module_name, - u32 line_number, const char *format, ...) ACPI_PRINTF_LIKE(3); - /* * utdelete - Object deletion and reference counts */ diff --git a/include/acpi/amlcode.h b/drivers/acpi/acpica/amlcode.h index ff851c5df698..ff851c5df698 100644 --- a/include/acpi/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h diff --git a/include/acpi/amlresrc.h b/drivers/acpi/acpica/amlresrc.h index 7b070e42b7c5..7b070e42b7c5 100644 --- a/include/acpi/amlresrc.h +++ b/drivers/acpi/acpica/amlresrc.h diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/acpica/dsfield.c index f988a5e7d2b4..53e27bc5a734 100644 --- a/drivers/acpi/dispatcher/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -42,11 +42,12 @@ */ #include <acpi/acpi.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> -#include <acpi/acparser.h> +#include "accommon.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acparser.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsfield") diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/acpica/dsinit.c index 949f7c75029e..eb144b13d8fa 100644 --- a/drivers/acpi/dispatcher/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acdispat.h> -#include <acpi/acnamesp.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "actables.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsinit") diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 279a5a60a0dd..14b8b8ed8023 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -42,11 +42,14 @@ */ #include <acpi/acpi.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#ifdef ACPI_DISASSEMBLER #include <acpi/acdisasm.h> +#endif #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsmethod") @@ -412,6 +415,9 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { status = obj_desc->method.implementation(next_walk_state); + if (status == AE_OK) { + status = AE_CTRL_TERMINATE; + } } return_ACPI_STATUS(status); diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c index d03f81bd1bcb..da0f5468184c 100644 --- a/drivers/acpi/dispatcher/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acdispat.h> -#include <acpi/acnamesp.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsmthdat") diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/acpica/dsobject.c index 4f08e599d07e..15c628e6aa00 100644 --- a/drivers/acpi/dispatcher/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -42,11 +42,12 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acnamesp.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsobject") diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index 69fae5905bb8..0c3b4dd60e8a 100644 --- a/drivers/acpi/dispatcher/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -43,13 +43,14 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> -#include <acpi/acevents.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acevents.h" +#include "actables.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsopcode") @@ -1140,10 +1141,29 @@ acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state, op->common.aml_opcode, walk_state)); switch (op->common.aml_opcode) { - case AML_IF_OP: case AML_WHILE_OP: /* + * If this is an additional iteration of a while loop, continue. + * There is no need to allocate a new control state. + */ + if (walk_state->control_state) { + if (walk_state->control_state->control.aml_predicate_start + == (walk_state->parser_state.aml - 1)) { + + /* Reset the state to start-of-loop */ + + walk_state->control_state->common.state = + ACPI_CONTROL_CONDITIONAL_EXECUTING; + break; + } + } + + /*lint -fallthrough */ + + case AML_IF_OP: + + /* * IF/WHILE: Create a new control state to manage these * constructs. We need to manage these as a stack, in order * to handle nesting. @@ -1243,13 +1263,36 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op)); - if (walk_state->control_state->common.value) { + control_state = walk_state->control_state; + if (control_state->common.value) { - /* Predicate was true, go back and evaluate it again! */ + /* Predicate was true, the body of the loop was just executed */ + /* + * This loop counter mechanism allows the interpreter to escape + * possibly infinite loops. This can occur in poorly written AML + * when the hardware does not respond within a while loop and the + * loop does not implement a timeout. + */ + control_state->control.loop_count++; + if (control_state->control.loop_count > + ACPI_MAX_LOOP_ITERATIONS) { + status = AE_AML_INFINITE_LOOP; + break; + } + + /* + * Go back and evaluate the predicate and maybe execute the loop + * another time + */ status = AE_CTRL_PENDING; + walk_state->aml_last_while = + control_state->control.aml_predicate_start; + break; } + /* Predicate was false, terminate this while loop */ + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] termination! Op=%p\n", op)); @@ -1257,9 +1300,6 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, control_state = acpi_ut_pop_generic_state(&walk_state->control_state); - - walk_state->aml_last_while = - control_state->control.aml_predicate_start; acpi_ut_delete_generic_state(control_state); break; diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/acpica/dsutils.c index b398982f0d8b..dabc23a46176 100644 --- a/drivers/acpi/dispatcher/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -42,12 +42,13 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> -#include <acpi/acdebug.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acdebug.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsutils") diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/acpica/dswexec.c index 396fe12078cd..350e6656bc89 100644 --- a/drivers/acpi/dispatcher/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -43,12 +43,13 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> -#include <acpi/acdebug.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acdebug.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dswexec") diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/acpica/dswload.c index dff7a3e445a8..3023ceaa8d54 100644 --- a/drivers/acpi/dispatcher/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -42,12 +42,13 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acevents.h" #ifdef ACPI_ASL_COMPILER #include <acpi/acdisasm.h> diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/acpica/dswscope.c index 9e6073265873..908645e72f03 100644 --- a/drivers/acpi/dispatcher/dswscope.c +++ b/drivers/acpi/acpica/dswscope.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acdispat.h> +#include "accommon.h" +#include "acdispat.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dswscope") diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/acpica/dswstate.c index b00d4af791aa..40f92bf7dce5 100644 --- a/drivers/acpi/dispatcher/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acdispat.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acparser.h" +#include "acdispat.h" +#include "acnamesp.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dswstate") diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/acpica/evevent.c index c56c5c6ea77b..803edd9e3f6a 100644 --- a/drivers/acpi/events/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acevents.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evevent") @@ -72,8 +73,8 @@ acpi_status acpi_ev_initialize_events(void) /* * Initialize the Fixed and General Purpose Events. This is done prior to - * enabling SCIs to prevent interrupts from occurring before the handlers are - * installed. + * enabling SCIs to prevent interrupts from occurring before the handlers + * are installed. */ status = acpi_ev_fixed_event_initialize(); if (ACPI_FAILURE(status)) { @@ -192,8 +193,8 @@ static acpi_status acpi_ev_fixed_event_initialize(void) acpi_status status; /* - * Initialize the structure that keeps track of fixed event handlers - * and enable the fixed events. + * Initialize the structure that keeps track of fixed event handlers and + * enable the fixed events. */ for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { acpi_gbl_fixed_event_handlers[i].handler = NULL; @@ -237,7 +238,7 @@ u32 acpi_ev_fixed_event_detect(void) /* * Read the fixed feature status and enable registers, as all the cases - * depend on their values. Ignore errors here. + * depend on their values. Ignore errors here. */ (void)acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status); (void)acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable); @@ -291,8 +292,8 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event) status_register_id, 1); /* - * Make sure we've got a handler. If not, report an error. - * The event is disabled to prevent further interrupts. + * Make sure we've got a handler. If not, report an error. The event is + * disabled to prevent further interrupts. */ if (NULL == acpi_gbl_fixed_event_handlers[event].handler) { (void)acpi_set_register(acpi_gbl_fixed_event_info[event]. diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/acpica/evgpe.c index f45c74fe745e..f345ced36477 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evgpe") @@ -125,7 +126,7 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info, (1 << (gpe_event_info->gpe_number - gpe_register_info->base_gpe_number)); - /* 1) Disable case. Simply clear all enable bits */ + /* 1) Disable case. Simply clear all enable bits */ if (type == ACPI_GPE_DISABLE) { ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, @@ -134,7 +135,7 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info, return_ACPI_STATUS(AE_OK); } - /* 2) Enable case. Set/Clear the appropriate enable bits */ + /* 2) Enable case. Set/Clear the appropriate enable bits */ switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { case ACPI_GPE_TYPE_WAKE: @@ -295,7 +296,7 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) * * FUNCTION: acpi_ev_get_gpe_event_info * - * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1 + * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1 * gpe_number - Raw GPE number * * RETURN: A GPE event_info struct. NULL if not a valid GPE @@ -372,7 +373,7 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED * - * DESCRIPTION: Detect if any GP events have occurred. This function is + * DESCRIPTION: Detect if any GP events have occurred. This function is * executed at interrupt level. * ******************************************************************************/ @@ -400,8 +401,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) /* * We need to obtain the GPE lock for both the data structs and registers - * Note: Not necessary to obtain the hardware lock, since the GPE registers - * are owned by the gpe_lock. + * Note: Not necessary to obtain the hardware lock, since the GPE + * registers are owned by the gpe_lock. */ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); @@ -410,9 +411,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) gpe_block = gpe_xrupt_list->gpe_block_list_head; while (gpe_block) { /* - * Read all of the 8-bit GPE status and enable registers - * in this GPE block, saving all of them. - * Find all currently active GP events. + * Read all of the 8-bit GPE status and enable registers in this GPE + * block, saving all of them. Find all currently active GP events. */ for (i = 0; i < gpe_block->register_count; i++) { @@ -423,10 +423,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) /* Read the Status Register */ status = - acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH, - &status_reg, - &gpe_register_info-> - status_address); + acpi_read(&status_reg, + &gpe_register_info->status_address); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -434,10 +432,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) /* Read the Enable Register */ status = - acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH, - &enable_reg, - &gpe_register_info-> - enable_address); + acpi_read(&enable_reg, + &gpe_register_info->enable_address); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -527,8 +523,8 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) (void)acpi_ev_enable_gpe(gpe_event_info, FALSE); /* - * Take a snapshot of the GPE info for this level - we copy the - * info to prevent a race condition with remove_handler/remove_block. + * Take a snapshot of the GPE info for this level - we copy the info to + * prevent a race condition with remove_handler/remove_block. */ ACPI_MEMCPY(&local_gpe_event_info, gpe_event_info, sizeof(struct acpi_gpe_event_info)); @@ -539,8 +535,8 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) } /* - * Must check for control method type dispatch one more - * time to avoid race with ev_gpe_install_handler + * Must check for control method type dispatch one more time to avoid a + * race with ev_gpe_install_handler */ if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) { @@ -584,8 +580,8 @@ static void acpi_ev_asynch_enable_gpe(void *context) if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { /* - * GPE is level-triggered, we clear the GPE status bit after - * handling the event. + * GPE is level-triggered, we clear the GPE status bit after handling + * the event. */ status = acpi_hw_clear_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { @@ -624,7 +620,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) acpi_os_gpe_count(gpe_number); /* - * If edge-triggered, clear the GPE status bit now. Note that + * If edge-triggered, clear the GPE status bit now. Note that * level-triggered events are cleared after the GPE is serviced. */ if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == @@ -650,7 +646,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) /* * Invoke the installed handler (at interrupt level) - * Ignore return status for now. TBD: leave GPE disabled on error? + * Ignore return status for now. + * TBD: leave GPE disabled on error? */ (void)gpe_event_info->dispatch.handler->address(gpe_event_info-> dispatch. @@ -708,7 +705,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) gpe_number)); /* - * Disable the GPE. The GPE will remain disabled until the ACPI + * Disable the GPE. The GPE will remain disabled until the ACPICA * Core Subsystem is restarted, or a handler is installed. */ status = acpi_ev_disable_gpe(gpe_event_info); diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index 73c058e2f5c2..484cc0565d5b 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evgpeblk") @@ -124,6 +125,7 @@ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info) * FUNCTION: acpi_ev_walk_gpe_list * * PARAMETERS: gpe_walk_callback - Routine called for each GPE block + * Context - Value passed to callback * * RETURN: Status * @@ -131,7 +133,8 @@ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info) * ******************************************************************************/ -acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback) +acpi_status +acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context) { struct acpi_gpe_block_info *gpe_block; struct acpi_gpe_xrupt_info *gpe_xrupt_info; @@ -154,8 +157,13 @@ acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback) /* One callback per GPE block */ - status = gpe_walk_callback(gpe_xrupt_info, gpe_block); + status = + gpe_walk_callback(gpe_xrupt_info, gpe_block, + context); if (ACPI_FAILURE(status)) { + if (status == AE_CTRL_END) { /* Callback abort */ + status = AE_OK; + } goto unlock_and_exit; } @@ -186,7 +194,8 @@ acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback) acpi_status acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block) + struct acpi_gpe_block_info *gpe_block, + void *context) { struct acpi_gpe_event_info *gpe_event_info; u32 i; @@ -309,17 +318,17 @@ acpi_ev_save_method_info(acpi_handle obj_handle, (gpe_block->block_base_number + (gpe_block->register_count * 8)))) { /* - * Not valid for this GPE block, just ignore it - * However, it may be valid for a different GPE block, since GPE0 and GPE1 - * methods both appear under \_GPE. + * Not valid for this GPE block, just ignore it. However, it may be + * valid for a different GPE block, since GPE0 and GPE1 methods both + * appear under \_GPE. */ return_ACPI_STATUS(AE_OK); } /* - * Now we can add this information to the gpe_event_info block - * for use during dispatch of this GPE. Default type is RUNTIME, although - * this may change when the _PRW methods are executed later. + * Now we can add this information to the gpe_event_info block for use + * during dispatch of this GPE. Default type is RUNTIME, although this may + * change when the _PRW methods are executed later. */ gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; @@ -394,8 +403,8 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, gpe_block = gpe_info->gpe_block; /* - * The _PRW object must return a package, we are only interested - * in the first element + * The _PRW object must return a package, we are only interested in the + * first element */ obj_desc = pkg_desc->package.elements[0]; @@ -434,7 +443,7 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, /* * Is this GPE within this block? * - * TRUE iff these conditions are true: + * TRUE if and only if these conditions are true: * 1) The GPE devices match. * 2) The GPE index(number) is within the range of the Gpe Block * associated with the GPE device. @@ -457,6 +466,7 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, if (ACPI_FAILURE(status)) { goto cleanup; } + status = acpi_ev_update_gpe_enable_masks(gpe_event_info, ACPI_GPE_DISABLE); @@ -476,9 +486,9 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, * RETURN: A GPE interrupt block * * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt - * block per unique interrupt level used for GPEs. - * Should be called only when the GPE lists are semaphore locked - * and not subject to change. + * block per unique interrupt level used for GPEs. Should be + * called only when the GPE lists are semaphore locked and not + * subject to change. * ******************************************************************************/ @@ -608,8 +618,9 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt) * * FUNCTION: acpi_ev_install_gpe_block * - * PARAMETERS: gpe_block - New GPE block - * interrupt_number - Xrupt to be associated with this GPE block + * PARAMETERS: gpe_block - New GPE block + * interrupt_number - Xrupt to be associated with this + * GPE block * * RETURN: Status * @@ -666,7 +677,7 @@ acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block, * * FUNCTION: acpi_ev_delete_gpe_block * - * PARAMETERS: gpe_block - Existing GPE block + * PARAMETERS: gpe_block - Existing GPE block * * RETURN: Status * @@ -688,7 +699,8 @@ acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block) /* Disable all GPEs in this block */ - status = acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block); + status = + acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block, NULL); if (!gpe_block->previous && !gpe_block->next) { @@ -715,6 +727,9 @@ acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block) acpi_os_release_lock(acpi_gbl_gpe_lock, flags); } + acpi_current_gpe_count -= + gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH; + /* Free the gpe_block */ ACPI_FREE(gpe_block->register_info); @@ -786,9 +801,9 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) /* * Initialize the GPE Register and Event structures. A goal of these - * tables is to hide the fact that there are two separate GPE register sets - * in a given GPE hardware block, the status registers occupy the first half, - * and the enable registers occupy the second half. + * tables is to hide the fact that there are two separate GPE register + * sets in a given GPE hardware block, the status registers occupy the + * first half, and the enable registers occupy the second half. */ this_register = gpe_register_info; this_event = gpe_event_info; @@ -816,10 +831,8 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) ACPI_GPE_REGISTER_WIDTH; this_register->enable_address.bit_width = ACPI_GPE_REGISTER_WIDTH; - this_register->status_address.bit_offset = - ACPI_GPE_REGISTER_WIDTH; - this_register->enable_address.bit_offset = - ACPI_GPE_REGISTER_WIDTH; + this_register->status_address.bit_offset = 0; + this_register->enable_address.bit_offset = 0; /* Init the event_info for each GPE within this register */ @@ -832,18 +845,14 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) /* Disable all GPEs within this register */ - status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, 0x00, - &this_register-> - enable_address); + status = acpi_write(0x00, &this_register->enable_address); if (ACPI_FAILURE(status)) { goto error_exit; } /* Clear any pending GPE events within this register */ - status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, 0xFF, - &this_register-> - status_address); + status = acpi_write(0xFF, &this_register->status_address); if (ACPI_FAILURE(status)) { goto error_exit; } @@ -956,6 +965,9 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, gpe_device->name.ascii, gpe_block->register_count, interrupt_number)); + /* Update global count of currently available GPEs */ + + acpi_current_gpe_count += register_count * ACPI_GPE_REGISTER_WIDTH; return_ACPI_STATUS(AE_OK); } @@ -1055,7 +1067,7 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device, /* Enable all valid runtime GPEs found above */ - status = acpi_hw_enable_runtime_gpe_block(NULL, gpe_block); + status = acpi_hw_enable_runtime_gpe_block(NULL, gpe_block, NULL); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not enable GPEs in GpeBlock %p", gpe_block)); diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/acpica/evmisc.c index 1d5670be729a..5f893057bcc6 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -42,18 +42,15 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> -#include <acpi/acnamesp.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evmisc") -/* Pointer to FACS needed for the Global Lock */ -static struct acpi_table_facs *facs = NULL; - /* Local prototypes */ - static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context); static u32 acpi_ev_global_lock_handler(void *context); @@ -152,7 +149,9 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, break; default: + /* All other types are not supported */ + return (AE_TYPE); } } @@ -193,9 +192,8 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, acpi_ut_delete_generic_state(notify_info); } } else { - /* - * There is no notify handler (per-device or system) for this device. - */ + /* There is no notify handler (per-device or system) for this device */ + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No notify handler for Notify (%4.4s, %X) node %p\n", acpi_ut_get_node_name(node), notify_value, @@ -229,9 +227,8 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context) ACPI_FUNCTION_ENTRY(); /* - * We will invoke a global notify handler if installed. - * This is done _before_ we invoke the per-device handler attached - * to the device. + * We will invoke a global notify handler if installed. This is done + * _before_ we invoke the per-device handler attached to the device. */ if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) { @@ -299,7 +296,7 @@ static u32 acpi_ev_global_lock_handler(void *context) * If we don't get it now, it will be marked pending and we will * take another interrupt when it becomes free. */ - ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired); + ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired); if (acquired) { /* Got the lock, now wake all threads waiting for it */ @@ -336,34 +333,27 @@ acpi_status acpi_ev_init_global_lock_handler(void) ACPI_FUNCTION_TRACE(ev_init_global_lock_handler); - status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, - ACPI_CAST_INDIRECT_PTR(struct - acpi_table_header, - &facs)); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + /* Attempt installation of the global lock handler */ - acpi_gbl_global_lock_present = TRUE; status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL, acpi_ev_global_lock_handler, NULL); /* - * If the global lock does not exist on this platform, the attempt - * to enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick) - * Map to AE_OK, but mark global lock as not present. - * Any attempt to actually use the global lock will be flagged - * with an error. + * If the global lock does not exist on this platform, the attempt to + * enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick). + * Map to AE_OK, but mark global lock as not present. Any attempt to + * actually use the global lock will be flagged with an error. */ if (status == AE_NO_HARDWARE_RESPONSE) { ACPI_ERROR((AE_INFO, "No response from Global Lock hardware, disabling lock")); acpi_gbl_global_lock_present = FALSE; - status = AE_OK; + return_ACPI_STATUS(AE_OK); } + acpi_gbl_global_lock_present = TRUE; return_ACPI_STATUS(status); } @@ -462,8 +452,8 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout) } /* - * Make sure that a global lock actually exists. If not, just treat - * the lock as a standard mutex. + * Make sure that a global lock actually exists. If not, just treat the + * lock as a standard mutex. */ if (!acpi_gbl_global_lock_present) { acpi_gbl_global_lock_acquired = TRUE; @@ -472,7 +462,7 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout) /* Attempt to acquire the actual hardware lock */ - ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired); + ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired); if (acquired) { /* We got the lock */ @@ -536,7 +526,7 @@ acpi_status acpi_ev_release_global_lock(void) /* Allow any thread to release the lock */ - ACPI_RELEASE_GLOBAL_LOCK(facs, pending); + ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_FACS, pending); /* * If the pending bit was set, we must write GBL_RLS to the control @@ -582,8 +572,8 @@ void acpi_ev_terminate(void) if (acpi_gbl_events_initialized) { /* - * Disable all event-related functionality. - * In all cases, on error, print a message but obviously we don't abort. + * Disable all event-related functionality. In all cases, on error, + * print a message but obviously we don't abort. */ /* Disable all fixed events */ @@ -599,7 +589,7 @@ void acpi_ev_terminate(void) /* Disable all GPEs in all GPE blocks */ - status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block); + status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL); /* Remove SCI handler */ @@ -617,7 +607,7 @@ void acpi_ev_terminate(void) /* Deallocate all handler objects installed within GPE info structs */ - status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers); + status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers, NULL); /* Return to original mode if necessary */ diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/acpica/evregion.c index 236fbd1ca438..665c0887ab4d 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -42,22 +42,15 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> -#include <acpi/acnamesp.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evregion") -#define ACPI_NUM_DEFAULT_SPACES 4 -static u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = { - ACPI_ADR_SPACE_SYSTEM_MEMORY, - ACPI_ADR_SPACE_SYSTEM_IO, - ACPI_ADR_SPACE_PCI_CONFIG, - ACPI_ADR_SPACE_DATA_TABLE -}; /* Local prototypes */ - static acpi_status acpi_ev_reg_run(acpi_handle obj_handle, u32 level, void *context, void **return_value); @@ -66,6 +59,17 @@ static acpi_status acpi_ev_install_handler(acpi_handle obj_handle, u32 level, void *context, void **return_value); +/* These are the address spaces that will get default handlers */ + +#define ACPI_NUM_DEFAULT_SPACES 4 + +static u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = { + ACPI_ADR_SPACE_SYSTEM_MEMORY, + ACPI_ADR_SPACE_SYSTEM_IO, + ACPI_ADR_SPACE_PCI_CONFIG, + ACPI_ADR_SPACE_DATA_TABLE +}; + /******************************************************************************* * * FUNCTION: acpi_ev_install_region_handlers @@ -91,18 +95,19 @@ acpi_status acpi_ev_install_region_handlers(void) } /* - * All address spaces (PCI Config, EC, SMBus) are scope dependent - * and registration must occur for a specific device. + * All address spaces (PCI Config, EC, SMBus) are scope dependent and + * registration must occur for a specific device. * - * In the case of the system memory and IO address spaces there is currently - * no device associated with the address space. For these we use the root. + * In the case of the system memory and IO address spaces there is + * currently no device associated with the address space. For these we + * use the root. * - * We install the default PCI config space handler at the root so - * that this space is immediately available even though the we have - * not enumerated all the PCI Root Buses yet. This is to conform - * to the ACPI specification which states that the PCI config - * space must be always available -- even though we are nowhere - * near ready to find the PCI root buses at this point. + * We install the default PCI config space handler at the root so that + * this space is immediately available even though the we have not + * enumerated all the PCI Root Buses yet. This is to conform to the ACPI + * specification which states that the PCI config space must be always + * available -- even though we are nowhere near ready to find the PCI root + * buses at this point. * * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler * has already been installed (via acpi_install_address_space_handler). @@ -160,12 +165,11 @@ acpi_status acpi_ev_initialize_op_regions(void) return_ACPI_STATUS(status); } - /* - * Run the _REG methods for op_regions in each default address space - */ - for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { + /* Run the _REG methods for op_regions in each default address space */ - /* TBD: Make sure handler is the DEFAULT handler, otherwise + for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { + /* + * TBD: Make sure handler is the DEFAULT handler, otherwise * _REG will have already been run. */ status = acpi_ev_execute_reg_methods(acpi_gbl_root_node, @@ -318,13 +322,13 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, } /* - * It may be the case that the region has never been initialized + * It may be the case that the region has never been initialized. * Some types of regions require special init code */ if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) { - /* - * This region has not been initialized yet, do it - */ + + /* This region has not been initialized yet, do it */ + region_setup = handler_desc->address_space.setup; if (!region_setup) { @@ -339,9 +343,9 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, } /* - * We must exit the interpreter because the region - * setup will potentially execute control methods - * (e.g., _REG method for this region) + * We must exit the interpreter because the region setup will + * potentially execute control methods (for example, the _REG method + * for this region) */ acpi_ex_exit_interpreter(); @@ -364,9 +368,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, return_ACPI_STATUS(status); } - /* - * Region initialization may have been completed by region_setup - */ + /* Region initialization may have been completed by region_setup */ + if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) { region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE; @@ -521,8 +524,8 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj, } /* - * If the region has been activated, call the setup handler - * with the deactivate notification + * If the region has been activated, call the setup handler with + * the deactivate notification */ if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) { region_setup = handler_obj->address_space.setup; @@ -668,8 +671,8 @@ acpi_ev_install_handler(acpi_handle obj_handle, } /* - * We only care about regions.and objects - * that are allowed to have address space handlers + * We only care about regions and objects that are allowed to have + * address space handlers */ if ((node->type != ACPI_TYPE_DEVICE) && (node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) { @@ -710,9 +713,9 @@ acpi_ev_install_handler(acpi_handle obj_handle, /* * Since the object we found it on was a device, then it * means that someone has already installed a handler for - * the branch of the namespace from this device on. Just + * the branch of the namespace from this device on. Just * bail out telling the walk routine to not traverse this - * branch. This preserves the scoping rule for handlers. + * branch. This preserves the scoping rule for handlers. */ return (AE_CTRL_DEPTH); } @@ -723,9 +726,8 @@ acpi_ev_install_handler(acpi_handle obj_handle, } /* - * As long as the device didn't have a handler for this - * space we don't care about it. We just ignore it and - * proceed. + * As long as the device didn't have a handler for this space we + * don't care about it. We just ignore it and proceed. */ return (AE_OK); } @@ -733,16 +735,14 @@ acpi_ev_install_handler(acpi_handle obj_handle, /* Object is a Region */ if (obj_desc->region.space_id != handler_obj->address_space.space_id) { - /* - * This region is for a different address space - * -- just ignore it - */ + + /* This region is for a different address space, just ignore it */ + return (AE_OK); } /* - * Now we have a region and it is for the handler's address - * space type. + * Now we have a region and it is for the handler's address space type. * * First disconnect region for any previous handler (if any) */ @@ -786,9 +786,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, ACPI_FUNCTION_TRACE(ev_install_space_handler); /* - * This registration is valid for only the types below - * and the root. This is where the default handlers - * get placed. + * This registration is valid for only the types below and the root. This + * is where the default handlers get placed. */ if ((node->type != ACPI_TYPE_DEVICE) && (node->type != ACPI_TYPE_PROCESSOR) && @@ -848,8 +847,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { /* - * The attached device object already exists. - * Make sure the handler is not already installed. + * The attached device object already exists. Make sure the handler + * is not already installed. */ handler_obj = obj_desc->device.handler; @@ -864,8 +863,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, handler) { /* * It is (relatively) OK to attempt to install the SAME - * handler twice. This can easily happen - * with PCI_Config space. + * handler twice. This can easily happen with the + * PCI_Config space. */ status = AE_SAME_HANDLER; goto unlock_and_exit; @@ -925,9 +924,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, /* * Install the handler * - * At this point there is no existing handler. - * Just allocate the object for the handler and link it - * into the list. + * At this point there is no existing handler. Just allocate the object + * for the handler and link it into the list. */ handler_obj = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_ADDRESS_HANDLER); @@ -1000,11 +998,10 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, ACPI_FUNCTION_TRACE(ev_execute_reg_methods); /* - * Run all _REG methods for all Operation Regions for this - * space ID. This is a separate walk in order to handle any - * interdependencies between regions and _REG methods. (i.e. handlers - * must be installed for all regions of this Space ID before we - * can run any _REG methods) + * Run all _REG methods for all Operation Regions for this space ID. This + * is a separate walk in order to handle any interdependencies between + * regions and _REG methods. (i.e. handlers must be installed for all + * regions of this Space ID before we can run any _REG methods) */ status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, @@ -1042,8 +1039,8 @@ acpi_ev_reg_run(acpi_handle obj_handle, } /* - * We only care about regions.and objects - * that are allowed to have address space handlers + * We only care about regions.and objects that are allowed to have address + * space handlers */ if ((node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) { return (AE_OK); @@ -1062,10 +1059,9 @@ acpi_ev_reg_run(acpi_handle obj_handle, /* Object is a Region */ if (obj_desc->region.space_id != space_id) { - /* - * This region is for a different address space - * -- just ignore it - */ + + /* This region is for a different address space, just ignore it */ + return (AE_OK); } diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 6b94b38df07d..f3f1fb45c3dc 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evrgnini") @@ -233,9 +234,9 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, if (ACPI_FAILURE(status)) { if (status == AE_SAME_HANDLER) { /* - * It is OK if the handler is already installed on the root - * bridge. Still need to return a context object for the - * new PCI_Config operation region, however. + * It is OK if the handler is already installed on the + * root bridge. Still need to return a context object + * for the new PCI_Config operation region, however. */ status = AE_OK; } else { @@ -272,8 +273,8 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, } /* - * For PCI_Config space access, we need the segment, bus, - * device and function numbers. Acquire them here. + * For PCI_Config space access, we need the segment, bus, device and + * function numbers. Acquire them here. * * Find the parent device object. (This allows the operation region to be * within a subscope under the device, such as a control method.) @@ -289,16 +290,16 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, } /* - * Get the PCI device and function numbers from the _ADR object - * contained in the parent's scope. + * Get the PCI device and function numbers from the _ADR object contained + * in the parent's scope. */ status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, pci_device_node, &pci_value); /* - * The default is zero, and since the allocation above zeroed - * the data, just do nothing on failure. + * The default is zero, and since the allocation above zeroed the data, + * just do nothing on failure. */ if (ACPI_SUCCESS(status)) { pci_id->device = ACPI_HIWORD(ACPI_LODWORD(pci_value)); @@ -382,9 +383,8 @@ static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) struct acpi_compatible_id_list *cid; u32 i; - /* - * Get the _HID and check for a PCI Root Bridge - */ + /* Get the _HID and check for a PCI Root Bridge */ + status = acpi_ut_execute_HID(node, &hid); if (ACPI_FAILURE(status)) { return (FALSE); @@ -394,10 +394,8 @@ static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) return (TRUE); } - /* - * The _HID did not match. - * Get the _CID and check for a PCI Root Bridge - */ + /* The _HID did not match. Get the _CID and check for a PCI Root Bridge */ + status = acpi_ut_execute_CID(node, &cid); if (ACPI_FAILURE(status)) { return (FALSE); @@ -516,9 +514,9 @@ acpi_ev_default_region_setup(acpi_handle handle, * Get the appropriate address space handler for a newly * created region. * - * This also performs address space specific initialization. For + * This also performs address space specific initialization. For * example, PCI regions must have an _ADR object that contains - * a PCI address in the scope of the definition. This address is + * a PCI address in the scope of the definition. This address is * required to perform an access to PCI config space. * * MUTEX: Interpreter should be unlocked, because we may run the _REG @@ -572,7 +570,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, if (ACPI_SUCCESS(status)) { /* * The _REG method is optional and there can be only one per region - * definition. This will be executed when the handler is attached + * definition. This will be executed when the handler is attached * or removed */ region_obj2->extra.method_REG = method_node; @@ -670,10 +668,8 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, } } - /* - * This node does not have the handler we need; - * Pop up one level - */ + /* This node does not have the handler we need; Pop up one level */ + node = acpi_ns_get_parent_node(node); } diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/acpica/evsci.c index 2a8b77877610..567b356c85af 100644 --- a/drivers/acpi/events/evsci.c +++ b/drivers/acpi/acpica/evsci.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acevents.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evsci") @@ -115,10 +116,8 @@ u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context) * if this interrupt handler is installed, ACPI is enabled. */ - /* - * GPEs: - * Check for and dispatch any GPEs that have occurred - */ + /* GPEs: Check for and dispatch any GPEs that have occurred */ + interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list); return_UINT32(interrupt_handled); @@ -158,11 +157,11 @@ u32 acpi_ev_install_sci_handler(void) * RETURN: E_OK if handler uninstalled OK, E_ERROR if handler was not * installed to begin with * - * DESCRIPTION: Remove the SCI interrupt handler. No further SCIs will be + * DESCRIPTION: Remove the SCI interrupt handler. No further SCIs will be * taken. * * Note: It doesn't seem important to disable all events or set the event - * enable registers to their original values. The OS should disable + * enable registers to their original values. The OS should disable * the SCI interrupt level when the handler is removed, so no more * events will come in. * diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/acpica/evxface.c index 94a6efe020be..3aca9010a11e 100644 --- a/drivers/acpi/events/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acevents.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acevents.h" +#include "acinterp.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evxface") @@ -267,7 +268,7 @@ acpi_install_notify_handler(acpi_handle device, /* * Root Object: * Registering a notify handler on the root object indicates that the - * caller wishes to receive notifications for all objects. Note that + * caller wishes to receive notifications for all objects. Note that * only one <external> global handler can be regsitered (per notify type). */ if (device == ACPI_ROOT_OBJECT) { diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index 41554f736b68..35485e4b60a6 100644 --- a/drivers/acpi/events/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -42,13 +42,19 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> -#include <acpi/acnamesp.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" +#include "actables.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evxfevnt") +/* Local prototypes */ +acpi_status +acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context); + /******************************************************************************* * * FUNCTION: acpi_enable @@ -60,6 +66,7 @@ ACPI_MODULE_NAME("evxfevnt") * DESCRIPTION: Transfers the system into ACPI mode. * ******************************************************************************/ + acpi_status acpi_enable(void) { acpi_status status = AE_OK; @@ -161,8 +168,8 @@ acpi_status acpi_enable_event(u32 event, u32 flags) } /* - * Enable the requested fixed event (by writing a one to the - * enable register bit) + * Enable the requested fixed event (by writing a one to the enable + * register bit) */ status = acpi_set_register(acpi_gbl_fixed_event_info[event]. @@ -343,8 +350,8 @@ acpi_status acpi_disable_event(u32 event, u32 flags) } /* - * Disable the requested fixed event (by writing a zero to the - * enable register bit) + * Disable the requested fixed event (by writing a zero to the enable + * register bit) */ status = acpi_set_register(acpi_gbl_fixed_event_info[event]. @@ -396,8 +403,8 @@ acpi_status acpi_clear_event(u32 event) } /* - * Clear the requested fixed event (By writing a one to the - * status register bit) + * Clear the requested fixed event (By writing a one to the status + * register bit) */ status = acpi_set_register(acpi_gbl_fixed_event_info[event]. @@ -717,3 +724,148 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device) } ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block) + +/******************************************************************************* + * + * FUNCTION: acpi_get_gpe_device + * + * PARAMETERS: Index - System GPE index (0-current_gpe_count) + * gpe_device - Where the parent GPE Device is returned + * + * RETURN: Status + * + * DESCRIPTION: Obtain the GPE device associated with the input index. A NULL + * gpe device indicates that the gpe number is contained in one of + * the FADT-defined gpe blocks. Otherwise, the GPE block device. + * + ******************************************************************************/ +acpi_status +acpi_get_gpe_device(u32 index, acpi_handle *gpe_device) +{ + struct acpi_gpe_device_info info; + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_get_gpe_device); + + if (!gpe_device) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + if (index >= acpi_current_gpe_count) { + return_ACPI_STATUS(AE_NOT_EXIST); + } + + /* Setup and walk the GPE list */ + + info.index = index; + info.status = AE_NOT_EXIST; + info.gpe_device = NULL; + info.next_block_base_index = 0; + + status = acpi_ev_walk_gpe_list(acpi_ev_get_gpe_device, &info); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + *gpe_device = info.gpe_device; + return_ACPI_STATUS(info.status); +} + +ACPI_EXPORT_SYMBOL(acpi_get_gpe_device) + +/******************************************************************************* + * + * FUNCTION: acpi_ev_get_gpe_device + * + * PARAMETERS: GPE_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE + * block device. NULL if the GPE is one of the FADT-defined GPEs. + * + ******************************************************************************/ +acpi_status +acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context) +{ + struct acpi_gpe_device_info *info = context; + + /* Increment Index by the number of GPEs in this block */ + + info->next_block_base_index += + (gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH); + + if (info->index < info->next_block_base_index) { + /* + * The GPE index is within this block, get the node. Leave the node + * NULL for the FADT-defined GPEs + */ + if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) { + info->gpe_device = gpe_block->node; + } + + info->status = AE_OK; + return (AE_CTRL_END); + } + + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: acpi_disable_all_gpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Disable and clear all GPEs in all GPE blocks + * + ******************************************************************************/ + +acpi_status acpi_disable_all_gpes(void) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_disable_all_gpes); + + status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_hw_disable_all_gpes(); + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); + + return_ACPI_STATUS(status); +} + +/****************************************************************************** + * + * FUNCTION: acpi_enable_all_runtime_gpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks + * + ******************************************************************************/ + +acpi_status acpi_enable_all_runtime_gpes(void) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_enable_all_runtime_gpes); + + status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_hw_enable_all_runtime_gpes(); + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); + + return_ACPI_STATUS(status); +} diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index e8750807e57d..479e7a3721be 100644 --- a/drivers/acpi/events/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -43,8 +43,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acevents.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evxfregn") diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/acpica/exconfig.c index 74da6fa52ef1..932bbc26aa04 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -42,10 +42,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> -#include <acpi/actables.h> -#include <acpi/acdispat.h> +#include "accommon.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "actables.h" +#include "acdispat.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exconfig") diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index 1d1f35adddde..0be10188316e 100644 --- a/drivers/acpi/executer/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exconvrt") diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/acpica/excreate.c index ad09696d5069..a57ad2564ab0 100644 --- a/drivers/acpi/executer/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("excreate") diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/acpica/exdump.c index d087a7d28aa5..aa313574b0df 100644 --- a/drivers/acpi/executer/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exdump") diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/acpica/exfield.c index 3e440d84226a..a352d0233857 100644 --- a/drivers/acpi/executer/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acdispat.h" +#include "acinterp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exfield") diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/acpica/exfldio.c index 9ff9d1f4615d..ef58ac4e687b 100644 --- a/drivers/acpi/executer/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -42,10 +42,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> -#include <acpi/acevents.h> -#include <acpi/acdispat.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acevents.h" +#include "acdispat.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exfldio") @@ -498,14 +499,13 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, return_ACPI_STATUS(status); } - ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "I/O to Data Register: ValuePtr %p\n", - value)); - if (read_write == ACPI_READ) { /* Read the datum from the data_register */ + ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, + "Read from Data Register\n")); + status = acpi_ex_extract_from_field(obj_desc->index_field. data_obj, value, @@ -513,6 +513,10 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, } else { /* Write the datum to the data_register */ + ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, + "Write to Data Register: Value %8.8X%8.8X\n", + ACPI_FORMAT_UINT64(*value))); + status = acpi_ex_insert_into_field(obj_desc->index_field. data_obj, value, diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/acpica/exmisc.c index efb191340059..6b0747ac683b 100644 --- a/drivers/acpi/executer/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -43,9 +43,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> -#include <acpi/amlresrc.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" +#include "amlresrc.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exmisc") diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/acpica/exmutex.c index a8bf3d713e28..d301c1f363ef 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -43,8 +43,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acinterp.h" +#include "acevents.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exmutex") diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/acpica/exnames.c index 817e67be3697..ffdae122d94a 100644 --- a/drivers/acpi/executer/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -43,8 +43,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exnames") diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index f622f9eac8a1..b530480cc7d5 100644 --- a/drivers/acpi/executer/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -43,11 +43,12 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acparser.h" +#include "acdispat.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exoparg1") diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index 368def5dffce..0b4f513ca885 100644 --- a/drivers/acpi/executer/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -42,10 +42,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acinterp.h> -#include <acpi/acevents.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acparser.h" +#include "acinterp.h" +#include "acevents.h" +#include "amlcode.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exoparg2") diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 9cb4197681af..c6520bbf882b 100644 --- a/drivers/acpi/executer/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -43,9 +43,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acinterp.h" +#include "acparser.h" +#include "amlcode.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exoparg3") diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index 67d48737af53..ae43f7670a6c 100644 --- a/drivers/acpi/executer/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -43,9 +43,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acinterp.h" +#include "acparser.h" +#include "amlcode.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exoparg6") diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/acpica/exprep.c index a7dc87ecee37..a226f74d4a5c 100644 --- a/drivers/acpi/executer/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -43,9 +43,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exprep") diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/acpica/exregion.c index 7a41c409ae4d..76ec8ff903b8 100644 --- a/drivers/acpi/executer/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acinterp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exregion") diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/acpica/exresnte.c index 423ad3635f3d..a063a74006f6 100644 --- a/drivers/acpi/executer/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -43,9 +43,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exresnte") diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/acpica/exresolv.c index 60e8c47128e9..f6105a6d6126 100644 --- a/drivers/acpi/executer/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -43,10 +43,11 @@ */ #include <acpi/acpi.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exresolv") diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/acpica/exresop.c index 0bb82593da72..3c3802764bfb 100644 --- a/drivers/acpi/executer/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -43,10 +43,11 @@ */ #include <acpi/acpi.h> -#include <acpi/amlcode.h> -#include <acpi/acparser.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "amlcode.h" +#include "acparser.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exresop") diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/acpica/exstore.c index 1c118ba78adb..e35e9b4f6a4e 100644 --- a/drivers/acpi/executer/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -43,10 +43,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acdispat.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exstore") diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/acpica/exstoren.c index eef61a00803e..145d15305f70 100644 --- a/drivers/acpi/executer/exstoren.c +++ b/drivers/acpi/acpica/exstoren.c @@ -44,8 +44,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exstoren") diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/acpica/exstorob.c index 9a75ff09fb0c..67340cc70142 100644 --- a/drivers/acpi/executer/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acinterp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exstorob") diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/acpica/exsystem.c index 68990f1df371..3d00b9357233 100644 --- a/drivers/acpi/executer/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acinterp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exsystem") diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/acpica/exutils.c index 86c03880b523..32b85d68e756 100644 --- a/drivers/acpi/executer/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -59,8 +59,9 @@ #define DEFINE_AML_GLOBALS #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exutils") diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/acpica/hwacpi.c index 816894ea839e..a9d4fea4167f 100644 --- a/drivers/acpi/hardware/hwacpi.c +++ b/drivers/acpi/acpica/hwacpi.c @@ -43,6 +43,7 @@ */ #include <acpi/acpi.h> +#include "accommon.h" #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME("hwacpi") diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 0b80db9d9197..2013b66745d2 100644 --- a/drivers/acpi/hardware/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acevents.h" #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME("hwgpe") @@ -51,7 +52,8 @@ ACPI_MODULE_NAME("hwgpe") /* Local prototypes */ static acpi_status acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block); + struct acpi_gpe_block_info *gpe_block, + void *context); /****************************************************************************** * @@ -80,8 +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_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH, &enable_mask, - &gpe_register_info->enable_address); + status = acpi_read(&enable_mask, &gpe_register_info->enable_address); if (ACPI_FAILURE(status)) { return (status); } @@ -95,9 +96,7 @@ acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) /* Write the updated enable mask */ - status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, enable_mask, - &gpe_register_info->enable_address); - + status = acpi_write(enable_mask, &gpe_register_info->enable_address); return (status); } @@ -132,8 +131,8 @@ acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info * gpe_event_info) /* Write the entire GPE (runtime) enable register */ - status = acpi_hw_low_level_write(8, gpe_register_info->enable_for_run, - &gpe_register_info->enable_address); + status = acpi_write(gpe_register_info->enable_for_run, + &gpe_register_info->enable_address); return (status); } @@ -166,9 +165,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_hw_low_level_write(8, register_bit, - &gpe_event_info->register_info-> - status_address); + status = acpi_write(register_bit, + &gpe_event_info->register_info->status_address); return (status); } @@ -227,9 +225,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, /* GPE currently active (status bit == 1)? */ - status = - acpi_hw_low_level_read(8, &in_byte, - &gpe_register_info->status_address); + status = acpi_read(&in_byte, &gpe_register_info->status_address); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -260,8 +256,8 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, ******************************************************************************/ acpi_status -acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, - struct acpi_gpe_block_info * gpe_block) +acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context) { u32 i; acpi_status status; @@ -272,9 +268,9 @@ acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, /* Disable all GPEs in this register */ - status = acpi_hw_low_level_write(8, 0x00, - &gpe_block->register_info[i]. - enable_address); + status = + acpi_write(0x00, + &gpe_block->register_info[i].enable_address); if (ACPI_FAILURE(status)) { return (status); } @@ -297,8 +293,8 @@ acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, ******************************************************************************/ acpi_status -acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, - struct acpi_gpe_block_info * gpe_block) +acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context) { u32 i; acpi_status status; @@ -309,9 +305,9 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, /* Clear status on all GPEs in this register */ - status = acpi_hw_low_level_write(8, 0xFF, - &gpe_block->register_info[i]. - status_address); + status = + acpi_write(0xFF, + &gpe_block->register_info[i].status_address); if (ACPI_FAILURE(status)) { return (status); } @@ -335,8 +331,8 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, ******************************************************************************/ acpi_status -acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, - struct acpi_gpe_block_info * gpe_block) +acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context) { u32 i; acpi_status status; @@ -352,12 +348,9 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, /* Enable all "runtime" GPEs in this register */ - status = - acpi_hw_low_level_write(8, - gpe_block->register_info[i]. - enable_for_run, - &gpe_block->register_info[i]. - enable_address); + status = acpi_write(gpe_block->register_info[i].enable_for_run, + &gpe_block->register_info[i]. + enable_address); if (ACPI_FAILURE(status)) { return (status); } @@ -382,7 +375,8 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, static acpi_status acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block) + struct acpi_gpe_block_info *gpe_block, + void *context) { u32 i; acpi_status status; @@ -396,11 +390,9 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, /* Enable all "wake" GPEs in this register */ - status = acpi_hw_low_level_write(8, - gpe_block->register_info[i]. - enable_for_wake, - &gpe_block->register_info[i]. - enable_address); + status = acpi_write(gpe_block->register_info[i].enable_for_wake, + &gpe_block->register_info[i]. + enable_address); if (ACPI_FAILURE(status)) { return (status); } @@ -427,8 +419,8 @@ acpi_status acpi_hw_disable_all_gpes(void) ACPI_FUNCTION_TRACE(hw_disable_all_gpes); - status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block); - status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block); + status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL); + status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL); return_ACPI_STATUS(status); } @@ -450,7 +442,7 @@ acpi_status acpi_hw_enable_all_runtime_gpes(void) ACPI_FUNCTION_TRACE(hw_enable_all_runtime_gpes); - status = acpi_ev_walk_gpe_list(acpi_hw_enable_runtime_gpe_block); + status = acpi_ev_walk_gpe_list(acpi_hw_enable_runtime_gpe_block, NULL); return_ACPI_STATUS(status); } @@ -472,6 +464,6 @@ acpi_status acpi_hw_enable_all_wakeup_gpes(void) ACPI_FUNCTION_TRACE(hw_enable_all_wakeup_gpes); - status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block); + status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block, NULL); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c new file mode 100644 index 000000000000..4dc43b018517 --- /dev/null +++ b/drivers/acpi/acpica/hwregs.c @@ -0,0 +1,353 @@ + +/******************************************************************************* + * + * Module Name: hwregs - Read/write access functions for the various ACPI + * control and status registers. + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, 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 "acevents.h" + +#define _COMPONENT ACPI_HARDWARE +ACPI_MODULE_NAME("hwregs") + +/******************************************************************************* + * + * FUNCTION: acpi_hw_clear_acpi_status + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Clears all fixed and general purpose status bits + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED + * + ******************************************************************************/ +acpi_status acpi_hw_clear_acpi_status(void) +{ + acpi_status status; + acpi_cpu_flags lock_flags = 0; + + ACPI_FUNCTION_TRACE(hw_clear_acpi_status); + + ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n", + ACPI_BITMASK_ALL_FIXED_STATUS, + (u16) acpi_gbl_FADT.xpm1a_event_block.address)); + + lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); + + status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, + ACPI_BITMASK_ALL_FIXED_STATUS); + if (ACPI_FAILURE(status)) { + goto unlock_and_exit; + } + + /* Clear the fixed events */ + + if (acpi_gbl_FADT.xpm1b_event_block.address) { + status = acpi_write(ACPI_BITMASK_ALL_FIXED_STATUS, + &acpi_gbl_FADT.xpm1b_event_block); + if (ACPI_FAILURE(status)) { + goto unlock_and_exit; + } + } + + /* Clear the GPE Bits in all GPE registers in all GPE blocks */ + + status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL); + + unlock_and_exit: + acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_hw_get_register_bit_mask + * + * PARAMETERS: register_id - Index of ACPI Register to access + * + * RETURN: The bitmask to be used when accessing the register + * + * DESCRIPTION: Map register_id into a register bitmask. + * + ******************************************************************************/ + +struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id) +{ + ACPI_FUNCTION_ENTRY(); + + if (register_id > ACPI_BITREG_MAX) { + ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: %X", + register_id)); + return (NULL); + } + + return (&acpi_gbl_bit_register_info[register_id]); +} + +/****************************************************************************** + * + * FUNCTION: acpi_hw_register_read + * + * PARAMETERS: register_id - ACPI Register ID + * return_value - Where the register value is returned + * + * RETURN: Status and the value read. + * + * DESCRIPTION: Read from the specified ACPI register + * + ******************************************************************************/ +acpi_status +acpi_hw_register_read(u32 register_id, u32 * return_value) +{ + u32 value1 = 0; + u32 value2 = 0; + acpi_status status; + + ACPI_FUNCTION_TRACE(hw_register_read); + + switch (register_id) { + case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ + + status = acpi_read(&value1, &acpi_gbl_FADT.xpm1a_event_block); + if (ACPI_FAILURE(status)) { + goto exit; + } + + /* PM1B is optional */ + + status = acpi_read(&value2, &acpi_gbl_FADT.xpm1b_event_block); + value1 |= value2; + break; + + case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */ + + status = acpi_read(&value1, &acpi_gbl_xpm1a_enable); + if (ACPI_FAILURE(status)) { + goto exit; + } + + /* PM1B is optional */ + + status = acpi_read(&value2, &acpi_gbl_xpm1b_enable); + value1 |= value2; + break; + + case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ + + status = acpi_read(&value1, &acpi_gbl_FADT.xpm1a_control_block); + if (ACPI_FAILURE(status)) { + goto exit; + } + + status = acpi_read(&value2, &acpi_gbl_FADT.xpm1b_control_block); + value1 |= value2; + break; + + case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ + + status = acpi_read(&value1, &acpi_gbl_FADT.xpm2_control_block); + break; + + case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ + + status = acpi_read(&value1, &acpi_gbl_FADT.xpm_timer_block); + break; + + case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ + + status = + acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8); + break; + + default: + ACPI_ERROR((AE_INFO, "Unknown Register ID: %X", register_id)); + status = AE_BAD_PARAMETER; + break; + } + + exit: + + if (ACPI_SUCCESS(status)) { + *return_value = value1; + } + + return_ACPI_STATUS(status); +} + +/****************************************************************************** + * + * FUNCTION: acpi_hw_register_write + * + * PARAMETERS: register_id - ACPI Register ID + * Value - The value to write + * + * RETURN: Status + * + * DESCRIPTION: Write to the specified ACPI register + * + * NOTE: In accordance with the ACPI specification, this function automatically + * preserves the value of the following bits, meaning that these bits cannot be + * changed via this interface: + * + * PM1_CONTROL[0] = SCI_EN + * PM1_CONTROL[9] + * PM1_STATUS[11] + * + * ACPI References: + * 1) Hardware Ignored Bits: When software writes to a register with ignored + * bit fields, it preserves the ignored bit fields + * 2) SCI_EN: OSPM always preserves this bit position + * + ******************************************************************************/ + +acpi_status acpi_hw_register_write(u32 register_id, u32 value) +{ + acpi_status status; + u32 read_value; + + ACPI_FUNCTION_TRACE(hw_register_write); + + switch (register_id) { + case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ + + /* Perform a read first to preserve certain bits (per ACPI spec) */ + + status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, + &read_value); + if (ACPI_FAILURE(status)) { + goto exit; + } + + /* Insert the bits to be preserved */ + + ACPI_INSERT_BITS(value, ACPI_PM1_STATUS_PRESERVED_BITS, + read_value); + + /* Now we can write the data */ + + status = acpi_write(value, &acpi_gbl_FADT.xpm1a_event_block); + if (ACPI_FAILURE(status)) { + goto exit; + } + + /* PM1B is optional */ + + status = acpi_write(value, &acpi_gbl_FADT.xpm1b_event_block); + break; + + case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */ + + status = acpi_write(value, &acpi_gbl_xpm1a_enable); + if (ACPI_FAILURE(status)) { + goto exit; + } + + /* PM1B is optional */ + + status = acpi_write(value, &acpi_gbl_xpm1b_enable); + break; + + case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ + + /* + * Perform a read first to preserve certain bits (per ACPI spec) + */ + status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, + &read_value); + if (ACPI_FAILURE(status)) { + goto exit; + } + + /* Insert the bits to be preserved */ + + ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS, + read_value); + + /* Now we can write the data */ + + status = acpi_write(value, &acpi_gbl_FADT.xpm1a_control_block); + if (ACPI_FAILURE(status)) { + goto exit; + } + + status = acpi_write(value, &acpi_gbl_FADT.xpm1b_control_block); + break; + + case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */ + + status = acpi_write(value, &acpi_gbl_FADT.xpm1a_control_block); + break; + + case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */ + + status = acpi_write(value, &acpi_gbl_FADT.xpm1b_control_block); + break; + + case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ + + status = acpi_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); + break; + + case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ + + /* SMI_CMD is currently always in IO space */ + + status = + acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8); + break; + + default: + status = AE_BAD_PARAMETER; + break; + } + + exit: + return_ACPI_STATUS(status); +} diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index 25dccdf179b9..a2af2a4f2f26 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "actables.h" #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME("hwsleep") @@ -52,31 +53,19 @@ ACPI_MODULE_NAME("hwsleep") * * FUNCTION: acpi_set_firmware_waking_vector * - * PARAMETERS: physical_address - Physical address of ACPI real mode + * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode * entry point. * * RETURN: Status * - * DESCRIPTION: Access function for the firmware_waking_vector field in FACS + * DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS * ******************************************************************************/ acpi_status -acpi_set_firmware_waking_vector(acpi_physical_address physical_address) +acpi_set_firmware_waking_vector(u32 physical_address) { - struct acpi_table_facs *facs; - acpi_status status; - ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); - /* Get the FACS */ - - status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, - ACPI_CAST_INDIRECT_PTR(struct - acpi_table_header, - &facs)); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } /* * According to the ACPI specification 2.0c and later, the 64-bit @@ -85,10 +74,16 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address) * Protected Mode. Some systems (for example HP dv5-1004nr) are known * to fail to resume if the 64-bit vector is used. */ - if (facs->version >= 1) - facs->xfirmware_waking_vector = 0; - facs->firmware_waking_vector = (u32)physical_address; + /* Set the 32-bit vector */ + + acpi_gbl_FACS->firmware_waking_vector = physical_address; + + /* Clear the 64-bit vector if it exists */ + + if ((acpi_gbl_FACS->length > 32) && (acpi_gbl_FACS->version >= 1)) { + acpi_gbl_FACS->xfirmware_waking_vector = 0; + } return_ACPI_STATUS(AE_OK); } @@ -97,48 +92,39 @@ ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector) /******************************************************************************* * - * FUNCTION: acpi_get_firmware_waking_vector + * FUNCTION: acpi_set_firmware_waking_vector64 * - * PARAMETERS: *physical_address - Where the contents of - * the firmware_waking_vector field of - * the FACS will be returned. + * PARAMETERS: physical_address - 64-bit physical address of ACPI protected + * mode entry point. * - * RETURN: Status, vector + * RETURN: Status * - * DESCRIPTION: Access function for the firmware_waking_vector field in FACS + * DESCRIPTION: Sets the 64-bit X_firmware_waking_vector field of the FACS, if + * it exists in the table. * ******************************************************************************/ -#ifdef ACPI_FUTURE_USAGE acpi_status -acpi_get_firmware_waking_vector(acpi_physical_address * physical_address) +acpi_set_firmware_waking_vector64(u64 physical_address) { - struct acpi_table_facs *facs; - acpi_status status; + ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64); - ACPI_FUNCTION_TRACE(acpi_get_firmware_waking_vector); - - if (!physical_address) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - /* Get the FACS */ + /* Determine if the 64-bit vector actually exists */ - status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, - ACPI_CAST_INDIRECT_PTR(struct - acpi_table_header, - &facs)); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + if ((acpi_gbl_FACS->length <= 32) || (acpi_gbl_FACS->version < 1)) { + return_ACPI_STATUS(AE_NOT_EXIST); } - /* Get the vector */ - *physical_address = (acpi_physical_address)facs->firmware_waking_vector; + /* Clear 32-bit vector, set the 64-bit X_ vector */ + + acpi_gbl_FACS->firmware_waking_vector = 0; + acpi_gbl_FACS->xfirmware_waking_vector = physical_address; return_ACPI_STATUS(AE_OK); } -ACPI_EXPORT_SYMBOL(acpi_get_firmware_waking_vector) -#endif +ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64) + /******************************************************************************* * * FUNCTION: acpi_enter_sleep_state_prep diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index b53d575491b9..b7f522c8f023 100644 --- a/drivers/acpi/hardware/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -43,6 +43,7 @@ */ #include <acpi/acpi.h> +#include "accommon.h" #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME("hwtimer") diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/acpica/hwxface.c index ddf792adcf96..ae597c0ab53f 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/acpica/hwxface.c @@ -1,10 +1,9 @@ -/******************************************************************************* +/****************************************************************************** * - * Module Name: hwregs - Read/write access functions for the various ACPI - * control and status registers. + * Module Name: hwxface - Public ACPICA hardware interfaces * - ******************************************************************************/ + *****************************************************************************/ /* * Copyright (C) 2000 - 2008, Intel Corp. @@ -44,209 +43,208 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_HARDWARE -ACPI_MODULE_NAME("hwregs") +ACPI_MODULE_NAME("hwxface") -/******************************************************************************* +/****************************************************************************** * - * FUNCTION: acpi_hw_clear_acpi_status + * FUNCTION: acpi_reset * * PARAMETERS: None * - * RETURN: None + * RETURN: Status * - * DESCRIPTION: Clears all fixed and general purpose status bits - * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED + * DESCRIPTION: Set reset register in memory or IO space. Note: Does not + * support reset register in PCI config space, this must be + * handled separately. * ******************************************************************************/ -acpi_status acpi_hw_clear_acpi_status(void) +acpi_status acpi_reset(void) { + struct acpi_generic_address *reset_reg; acpi_status status; - acpi_cpu_flags lock_flags = 0; - ACPI_FUNCTION_TRACE(hw_clear_acpi_status); + ACPI_FUNCTION_TRACE(acpi_reset); - ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n", - ACPI_BITMASK_ALL_FIXED_STATUS, - (u16) acpi_gbl_FADT.xpm1a_event_block.address)); + reset_reg = &acpi_gbl_FADT.reset_register; - lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); + /* Check if the reset register is supported */ - status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, - ACPI_BITMASK_ALL_FIXED_STATUS); - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; + if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) || + !reset_reg->address) { + return_ACPI_STATUS(AE_NOT_EXIST); } - /* Clear the fixed events */ - - if (acpi_gbl_FADT.xpm1b_event_block.address) { - status = - acpi_hw_low_level_write(16, ACPI_BITMASK_ALL_FIXED_STATUS, - &acpi_gbl_FADT.xpm1b_event_block); - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; - } - } - - /* Clear the GPE Bits in all GPE registers in all GPE blocks */ - - status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block); + /* Write the reset value to the reset register */ - unlock_and_exit: - acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); + status = acpi_write(acpi_gbl_FADT.reset_value, reset_reg); return_ACPI_STATUS(status); } -/******************************************************************************* +ACPI_EXPORT_SYMBOL(acpi_reset) + +/****************************************************************************** * - * FUNCTION: acpi_get_sleep_type_data + * FUNCTION: acpi_read * - * PARAMETERS: sleep_state - Numeric sleep state - * *sleep_type_a - Where SLP_TYPa is returned - * *sleep_type_b - Where SLP_TYPb is returned + * PARAMETERS: Value - Where the value is returned + * Reg - GAS register structure * - * RETURN: Status - ACPI status + * RETURN: Status * - * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep - * state. + * DESCRIPTION: Read from either memory or IO space. * ******************************************************************************/ - -acpi_status -acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b) +acpi_status acpi_read(u32 *value, struct acpi_generic_address *reg) { - acpi_status status = AE_OK; - struct acpi_evaluate_info *info; - - ACPI_FUNCTION_TRACE(acpi_get_sleep_type_data); - - /* Validate parameters */ - - if ((sleep_state > ACPI_S_STATES_MAX) || !sleep_type_a || !sleep_type_b) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } + u32 width; + u64 address; + acpi_status status; - /* Allocate the evaluation information block */ + ACPI_FUNCTION_NAME(acpi_read); - info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); - if (!info) { - return_ACPI_STATUS(AE_NO_MEMORY); + /* + * Must have a valid pointer to a GAS structure, and + * a non-zero address within. However, don't return an error + * because the PM1A/B code must not fail if B isn't present. + */ + if (!reg) { + return (AE_OK); } - info->pathname = - ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]); - - /* Evaluate the namespace object containing the values for this state */ - - status = acpi_ns_evaluate(info); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "%s while evaluating SleepState [%s]\n", - acpi_format_exception(status), - info->pathname)); + /* Get a local copy of the address. Handles possible alignment issues */ - goto cleanup; + ACPI_MOVE_64_TO_64(&address, ®->address); + if (!address) { + return (AE_OK); } - /* Must have a return object */ + /* Supported widths are 8/16/32 */ - if (!info->return_object) { - ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]", - info->pathname)); - status = AE_NOT_EXIST; + width = reg->bit_width; + if ((width != 8) && (width != 16) && (width != 32)) { + return (AE_SUPPORT); } - /* It must be of type Package */ + /* Initialize entire 32-bit return value to zero */ - else if (ACPI_GET_OBJECT_TYPE(info->return_object) != ACPI_TYPE_PACKAGE) { - ACPI_ERROR((AE_INFO, - "Sleep State return object is not a Package")); - status = AE_AML_OPERAND_TYPE; - } + *value = 0; /* - * The package must have at least two elements. NOTE (March 2005): This - * goes against the current ACPI spec which defines this object as a - * package with one encoded DWORD element. However, existing practice - * by BIOS vendors seems to be to have 2 or more elements, at least - * one per sleep type (A/B). + * Two address spaces supported: Memory or IO. + * PCI_Config is not supported here because the GAS struct is insufficient */ - else if (info->return_object->package.count < 2) { - ACPI_ERROR((AE_INFO, - "Sleep State return package does not have at least two elements")); - status = AE_AML_NO_OPERAND; - } + switch (reg->space_id) { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: - /* The first two elements must both be of type Integer */ + status = acpi_os_read_memory((acpi_physical_address) address, + value, width); + break; - else if ((ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[0]) - != ACPI_TYPE_INTEGER) || - (ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[1]) - != ACPI_TYPE_INTEGER)) { - ACPI_ERROR((AE_INFO, - "Sleep State return package elements are not both Integers (%s, %s)", - acpi_ut_get_object_type_name(info->return_object-> - package.elements[0]), - acpi_ut_get_object_type_name(info->return_object-> - package.elements[1]))); - status = AE_AML_OPERAND_TYPE; - } else { - /* Valid _Sx_ package size, type, and value */ + case ACPI_ADR_SPACE_SYSTEM_IO: - *sleep_type_a = (u8) - (info->return_object->package.elements[0])->integer.value; - *sleep_type_b = (u8) - (info->return_object->package.elements[1])->integer.value; - } + status = + acpi_os_read_port((acpi_io_address) address, value, width); + break; - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "While evaluating SleepState [%s], bad Sleep object %p type %s", - info->pathname, info->return_object, - acpi_ut_get_object_type_name(info-> - return_object))); + default: + ACPI_ERROR((AE_INFO, + "Unsupported address space: %X", reg->space_id)); + return (AE_BAD_PARAMETER); } - acpi_ut_remove_reference(info->return_object); + ACPI_DEBUG_PRINT((ACPI_DB_IO, + "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", + *value, width, ACPI_FORMAT_UINT64(address), + acpi_ut_get_region_name(reg->space_id))); - cleanup: - ACPI_FREE(info); - return_ACPI_STATUS(status); + return (status); } -ACPI_EXPORT_SYMBOL(acpi_get_sleep_type_data) +ACPI_EXPORT_SYMBOL(acpi_read) -/******************************************************************************* +/****************************************************************************** * - * FUNCTION: acpi_hw_get_register_bit_mask + * FUNCTION: acpi_write * - * PARAMETERS: register_id - Index of ACPI Register to access + * PARAMETERS: Value - To be written + * Reg - GAS register structure * - * RETURN: The bitmask to be used when accessing the register + * RETURN: Status * - * DESCRIPTION: Map register_id into a register bitmask. + * DESCRIPTION: Write to either memory or IO space. * ******************************************************************************/ -struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id) +acpi_status acpi_write(u32 value, struct acpi_generic_address *reg) { - ACPI_FUNCTION_ENTRY(); + u32 width; + u64 address; + acpi_status status; - if (register_id > ACPI_BITREG_MAX) { - ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: %X", - register_id)); - return (NULL); + ACPI_FUNCTION_NAME(acpi_write); + + /* + * Must have a valid pointer to a GAS structure, and + * a non-zero address within. However, don't return an error + * because the PM1A/B code must not fail if B isn't present. + */ + if (!reg) { + return (AE_OK); } - return (&acpi_gbl_bit_register_info[register_id]); + /* Get a local copy of the address. Handles possible alignment issues */ + + ACPI_MOVE_64_TO_64(&address, ®->address); + if (!address) { + return (AE_OK); + } + + /* Supported widths are 8/16/32 */ + + width = reg->bit_width; + if ((width != 8) && (width != 16) && (width != 32)) { + return (AE_SUPPORT); + } + + /* + * Two address spaces supported: Memory or IO. + * PCI_Config is not supported here because the GAS struct is insufficient + */ + switch (reg->space_id) { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + + status = acpi_os_write_memory((acpi_physical_address) address, + value, width); + break; + + case ACPI_ADR_SPACE_SYSTEM_IO: + + status = acpi_os_write_port((acpi_io_address) address, value, + width); + break; + + default: + ACPI_ERROR((AE_INFO, + "Unsupported address space: %X", reg->space_id)); + return (AE_BAD_PARAMETER); + } + + ACPI_DEBUG_PRINT((ACPI_DB_IO, + "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", + value, width, ACPI_FORMAT_UINT64(address), + acpi_ut_get_region_name(reg->space_id))); + + return (status); } +ACPI_EXPORT_SYMBOL(acpi_write) + /******************************************************************************* * - * FUNCTION: acpi_get_register + * FUNCTION: acpi_get_register_unlocked * * PARAMETERS: register_id - ID of ACPI bit_register to access * return_value - Value that was read from the register @@ -254,17 +252,16 @@ struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id) * RETURN: Status and the value read from specified Register. Value * returned is normalized to bit0 (is shifted all the way right) * - * DESCRIPTION: ACPI bit_register read function. + * DESCRIPTION: ACPI bit_register read function. Does not acquire the HW lock. * ******************************************************************************/ - -acpi_status acpi_get_register_unlocked(u32 register_id, u32 * return_value) +acpi_status acpi_get_register_unlocked(u32 register_id, u32 *return_value) { u32 register_value = 0; struct acpi_bit_register_info *bit_reg_info; acpi_status status; - ACPI_FUNCTION_TRACE(acpi_get_register); + ACPI_FUNCTION_TRACE(acpi_get_register_unlocked); /* Get the info structure corresponding to the requested ACPI Register */ @@ -296,14 +293,31 @@ acpi_status acpi_get_register_unlocked(u32 register_id, u32 * return_value) return_ACPI_STATUS(status); } -acpi_status acpi_get_register(u32 register_id, u32 * return_value) +ACPI_EXPORT_SYMBOL(acpi_get_register_unlocked) + +/******************************************************************************* + * + * FUNCTION: acpi_get_register + * + * PARAMETERS: register_id - ID of ACPI bit_register to access + * return_value - Value that was read from the register + * + * RETURN: Status and the value read from specified Register. Value + * returned is normalized to bit0 (is shifted all the way right) + * + * DESCRIPTION: ACPI bit_register read function. + * + ******************************************************************************/ +acpi_status acpi_get_register(u32 register_id, u32 *return_value) { acpi_status status; acpi_cpu_flags flags; + flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); status = acpi_get_register_unlocked(register_id, return_value); acpi_os_release_lock(acpi_gbl_hardware_lock, flags); - return status; + + return (status); } ACPI_EXPORT_SYMBOL(acpi_get_register) @@ -370,8 +384,9 @@ acpi_status acpi_set_register(u32 register_id, u32 value) bit_reg_info-> access_bit_mask); if (value) { - status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, - (u16) value); + status = + acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, + (u16) value); register_value = 0; } break; @@ -459,399 +474,120 @@ acpi_status acpi_set_register(u32 register_id, u32 value) ACPI_EXPORT_SYMBOL(acpi_set_register) -/****************************************************************************** +/******************************************************************************* * - * FUNCTION: acpi_hw_register_read + * FUNCTION: acpi_get_sleep_type_data * - * PARAMETERS: register_id - ACPI Register ID - * return_value - Where the register value is returned + * PARAMETERS: sleep_state - Numeric sleep state + * *sleep_type_a - Where SLP_TYPa is returned + * *sleep_type_b - Where SLP_TYPb is returned * - * RETURN: Status and the value read. + * RETURN: Status - ACPI status * - * DESCRIPTION: Read from the specified ACPI register + * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep + * state. * ******************************************************************************/ acpi_status -acpi_hw_register_read(u32 register_id, u32 * return_value) +acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b) { - u32 value1 = 0; - u32 value2 = 0; - acpi_status status; - - ACPI_FUNCTION_TRACE(hw_register_read); - - switch (register_id) { - case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ - - status = - acpi_hw_low_level_read(16, &value1, - &acpi_gbl_FADT.xpm1a_event_block); - if (ACPI_FAILURE(status)) { - goto exit; - } - - /* PM1B is optional */ - - status = - acpi_hw_low_level_read(16, &value2, - &acpi_gbl_FADT.xpm1b_event_block); - value1 |= value2; - break; - - case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */ - - status = - acpi_hw_low_level_read(16, &value1, &acpi_gbl_xpm1a_enable); - if (ACPI_FAILURE(status)) { - goto exit; - } - - /* PM1B is optional */ - - status = - acpi_hw_low_level_read(16, &value2, &acpi_gbl_xpm1b_enable); - value1 |= value2; - break; - - case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ - - status = - acpi_hw_low_level_read(16, &value1, - &acpi_gbl_FADT.xpm1a_control_block); - if (ACPI_FAILURE(status)) { - goto exit; - } - - status = - acpi_hw_low_level_read(16, &value2, - &acpi_gbl_FADT.xpm1b_control_block); - value1 |= value2; - break; - - case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ - - status = - acpi_hw_low_level_read(8, &value1, - &acpi_gbl_FADT.xpm2_control_block); - break; - - case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ - - status = - acpi_hw_low_level_read(32, &value1, - &acpi_gbl_FADT.xpm_timer_block); - break; + acpi_status status = AE_OK; + struct acpi_evaluate_info *info; - case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ + ACPI_FUNCTION_TRACE(acpi_get_sleep_type_data); - status = - acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8); - break; + /* Validate parameters */ - default: - ACPI_ERROR((AE_INFO, "Unknown Register ID: %X", register_id)); - status = AE_BAD_PARAMETER; - break; + if ((sleep_state > ACPI_S_STATES_MAX) || !sleep_type_a || !sleep_type_b) { + return_ACPI_STATUS(AE_BAD_PARAMETER); } - exit: + /* Allocate the evaluation information block */ - if (ACPI_SUCCESS(status)) { - *return_value = value1; + info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); + if (!info) { + return_ACPI_STATUS(AE_NO_MEMORY); } - return_ACPI_STATUS(status); -} - -/****************************************************************************** - * - * FUNCTION: acpi_hw_register_write - * - * PARAMETERS: register_id - ACPI Register ID - * Value - The value to write - * - * RETURN: Status - * - * DESCRIPTION: Write to the specified ACPI register - * - * NOTE: In accordance with the ACPI specification, this function automatically - * preserves the value of the following bits, meaning that these bits cannot be - * changed via this interface: - * - * PM1_CONTROL[0] = SCI_EN - * PM1_CONTROL[9] - * PM1_STATUS[11] - * - * ACPI References: - * 1) Hardware Ignored Bits: When software writes to a register with ignored - * bit fields, it preserves the ignored bit fields - * 2) SCI_EN: OSPM always preserves this bit position - * - ******************************************************************************/ - -acpi_status acpi_hw_register_write(u32 register_id, u32 value) -{ - acpi_status status; - u32 read_value; - - ACPI_FUNCTION_TRACE(hw_register_write); - - switch (register_id) { - case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ - - /* Perform a read first to preserve certain bits (per ACPI spec) */ - - status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, - &read_value); - if (ACPI_FAILURE(status)) { - goto exit; - } - - /* Insert the bits to be preserved */ - - ACPI_INSERT_BITS(value, ACPI_PM1_STATUS_PRESERVED_BITS, - read_value); - - /* Now we can write the data */ - - status = - acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT.xpm1a_event_block); - if (ACPI_FAILURE(status)) { - goto exit; - } - - /* PM1B is optional */ - - status = - acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT.xpm1b_event_block); - break; - - case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */ - - status = - acpi_hw_low_level_write(16, value, &acpi_gbl_xpm1a_enable); - if (ACPI_FAILURE(status)) { - goto exit; - } - - /* PM1B is optional */ - - status = - acpi_hw_low_level_write(16, value, &acpi_gbl_xpm1b_enable); - break; - - case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ - - /* - * Perform a read first to preserve certain bits (per ACPI spec) - */ - status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, - &read_value); - if (ACPI_FAILURE(status)) { - goto exit; - } - - /* Insert the bits to be preserved */ - - ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS, - read_value); - - /* Now we can write the data */ - - status = - acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT.xpm1a_control_block); - if (ACPI_FAILURE(status)) { - goto exit; - } - - status = - acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT.xpm1b_control_block); - break; - - case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */ - - status = - acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT.xpm1a_control_block); - break; - - case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */ - - status = - acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT.xpm1b_control_block); - break; - - case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ - - status = - acpi_hw_low_level_write(8, value, - &acpi_gbl_FADT.xpm2_control_block); - break; - - case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ - - status = - acpi_hw_low_level_write(32, value, - &acpi_gbl_FADT.xpm_timer_block); - break; - - case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ + info->pathname = + ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]); - /* SMI_CMD is currently always in IO space */ + /* Evaluate the namespace object containing the values for this state */ - status = - acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8); - break; + status = acpi_ns_evaluate(info); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "%s while evaluating SleepState [%s]\n", + acpi_format_exception(status), + info->pathname)); - default: - status = AE_BAD_PARAMETER; - break; + goto cleanup; } - exit: - return_ACPI_STATUS(status); -} - -/****************************************************************************** - * - * FUNCTION: acpi_hw_low_level_read - * - * PARAMETERS: Width - 8, 16, or 32 - * Value - Where the value is returned - * Reg - GAS register structure - * - * RETURN: Status - * - * DESCRIPTION: Read from either memory or IO space. - * - ******************************************************************************/ - -acpi_status -acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg) -{ - u64 address; - acpi_status status; - - ACPI_FUNCTION_NAME(hw_low_level_read); + /* Must have a return object */ - /* - * Must have a valid pointer to a GAS structure, and - * a non-zero address within. However, don't return an error - * because the PM1A/B code must not fail if B isn't present. - */ - if (!reg) { - return (AE_OK); + if (!info->return_object) { + ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]", + info->pathname)); + status = AE_NOT_EXIST; } - /* Get a local copy of the address. Handles possible alignment issues */ + /* It must be of type Package */ - ACPI_MOVE_64_TO_64(&address, ®->address); - if (!address) { - return (AE_OK); + else if (ACPI_GET_OBJECT_TYPE(info->return_object) != ACPI_TYPE_PACKAGE) { + ACPI_ERROR((AE_INFO, + "Sleep State return object is not a Package")); + status = AE_AML_OPERAND_TYPE; } - *value = 0; /* - * Two address spaces supported: Memory or IO. - * PCI_Config is not supported here because the GAS struct is insufficient + * The package must have at least two elements. NOTE (March 2005): This + * goes against the current ACPI spec which defines this object as a + * package with one encoded DWORD element. However, existing practice + * by BIOS vendors seems to be to have 2 or more elements, at least + * one per sleep type (A/B). */ - switch (reg->space_id) { - case ACPI_ADR_SPACE_SYSTEM_MEMORY: - - status = acpi_os_read_memory((acpi_physical_address) address, - value, width); - break; - - case ACPI_ADR_SPACE_SYSTEM_IO: - - status = - acpi_os_read_port((acpi_io_address) address, value, width); - break; - - default: + else if (info->return_object->package.count < 2) { ACPI_ERROR((AE_INFO, - "Unsupported address space: %X", reg->space_id)); - return (AE_BAD_PARAMETER); + "Sleep State return package does not have at least two elements")); + status = AE_AML_NO_OPERAND; } - ACPI_DEBUG_PRINT((ACPI_DB_IO, - "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", - *value, width, ACPI_FORMAT_UINT64(address), - acpi_ut_get_region_name(reg->space_id))); - - return (status); -} - -/****************************************************************************** - * - * FUNCTION: acpi_hw_low_level_write - * - * PARAMETERS: Width - 8, 16, or 32 - * Value - To be written - * Reg - GAS register structure - * - * RETURN: Status - * - * DESCRIPTION: Write to either memory or IO space. - * - ******************************************************************************/ - -acpi_status -acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg) -{ - u64 address; - acpi_status status; - - ACPI_FUNCTION_NAME(hw_low_level_write); - - /* - * Must have a valid pointer to a GAS structure, and - * a non-zero address within. However, don't return an error - * because the PM1A/B code must not fail if B isn't present. - */ - if (!reg) { - return (AE_OK); - } + /* The first two elements must both be of type Integer */ - /* Get a local copy of the address. Handles possible alignment issues */ + else if ((ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[0]) + != ACPI_TYPE_INTEGER) || + (ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[1]) + != ACPI_TYPE_INTEGER)) { + ACPI_ERROR((AE_INFO, + "Sleep State return package elements are not both Integers (%s, %s)", + acpi_ut_get_object_type_name(info->return_object-> + package.elements[0]), + acpi_ut_get_object_type_name(info->return_object-> + package.elements[1]))); + status = AE_AML_OPERAND_TYPE; + } else { + /* Valid _Sx_ package size, type, and value */ - ACPI_MOVE_64_TO_64(&address, ®->address); - if (!address) { - return (AE_OK); + *sleep_type_a = (u8) + (info->return_object->package.elements[0])->integer.value; + *sleep_type_b = (u8) + (info->return_object->package.elements[1])->integer.value; } - /* - * Two address spaces supported: Memory or IO. - * PCI_Config is not supported here because the GAS struct is insufficient - */ - switch (reg->space_id) { - case ACPI_ADR_SPACE_SYSTEM_MEMORY: - - status = acpi_os_write_memory((acpi_physical_address) address, - value, width); - break; - - case ACPI_ADR_SPACE_SYSTEM_IO: - - status = acpi_os_write_port((acpi_io_address) address, value, - width); - break; - - default: - ACPI_ERROR((AE_INFO, - "Unsupported address space: %X", reg->space_id)); - return (AE_BAD_PARAMETER); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "While evaluating SleepState [%s], bad Sleep object %p type %s", + info->pathname, info->return_object, + acpi_ut_get_object_type_name(info-> + return_object))); } - ACPI_DEBUG_PRINT((ACPI_DB_IO, - "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", - value, width, ACPI_FORMAT_UINT64(address), - acpi_ut_get_region_name(reg->space_id))); + acpi_ut_remove_reference(info->return_object); - return (status); + cleanup: + ACPI_FREE(info); + return_ACPI_STATUS(status); } + +ACPI_EXPORT_SYMBOL(acpi_get_sleep_type_data) diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index c39a7f68b889..88303ebe924c 100644 --- a/drivers/acpi/namespace/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> -#include <acpi/acdispat.h> +#include "accommon.h" +#include "amlcode.h" +#include "acnamesp.h" +#include "acdispat.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsaccess") @@ -165,12 +166,9 @@ acpi_status acpi_ns_root_initialize(void) obj_desc->method.method_flags = AML_METHOD_INTERNAL_ONLY; - -#ifndef ACPI_DUMP_APP obj_desc->method.implementation = acpi_ut_osi_implementation; #endif -#endif break; case ACPI_TYPE_INTEGER: @@ -521,11 +519,11 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, } /* - * Search namespace for each segment of the name. Loop through and + * Search namespace for each segment of the name. Loop through and * verify (or add to the namespace) each name segment. * * The object type is significant only at the last name - * segment. (We don't care about the types along the path, only + * segment. (We don't care about the types along the path, only * the type of the final target object.) */ this_search_type = ACPI_TYPE_ANY; @@ -591,6 +589,10 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, * segments). */ if (this_node->type == ACPI_TYPE_LOCAL_ALIAS) { + if (!this_node->object) { + return_ACPI_STATUS(AE_NOT_EXIST); + } + if (acpi_ns_opens_scope (((struct acpi_namespace_node *)this_node-> object)->type)) { diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index 3a1740ac2edc..f976d848fe82 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsalloc") diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/acpica/nsdump.c index cc0ae39440e4..0da33c8e9ba2 100644 --- a/drivers/acpi/namespace/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsdump") diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c index 428f50fde11a..41994fe7fbb8 100644 --- a/drivers/acpi/namespace/nsdumpdv.c +++ b/drivers/acpi/acpica/nsdumpdv.c @@ -42,6 +42,7 @@ */ #include <acpi/acpi.h> +#include "accommon.h" /* TBD: This entire module is apparently obsolete and should be removed */ @@ -49,7 +50,7 @@ ACPI_MODULE_NAME("nsdumpdv") #ifdef ACPI_OBSOLETE_FUNCTIONS #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) -#include <acpi/acnamesp.h> +#include "acnamesp.h" /******************************************************************************* * * FUNCTION: acpi_ns_dump_one_device diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/acpica/nseval.c index 4cdf03ac2b46..0f3d5f9b5966 100644 --- a/drivers/acpi/namespace/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acparser.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nseval") @@ -89,6 +90,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info) /* Initialize the return value to an invalid object */ info->return_object = NULL; + info->param_count = 0; /* * Get the actual namespace node for the target object. Handles these cases: @@ -141,41 +143,17 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info) return_ACPI_STATUS(AE_NULL_OBJECT); } - /* - * Calculate the number of arguments being passed to the method - */ + /* Count the number of arguments being passed to the method */ - info->param_count = 0; if (info->parameters) { - while (info->parameters[info->param_count]) + while (info->parameters[info->param_count]) { + if (info->param_count > ACPI_METHOD_MAX_ARG) { + return_ACPI_STATUS(AE_LIMIT); + } info->param_count++; + } } - /* - * Warning if too few or too many arguments have been passed by the - * caller. We don't want to abort here with an error because an - * incorrect number of arguments may not cause the method to fail. - * However, the method will fail if there are too few arguments passed - * and the method attempts to use one of the missing ones. - */ - - if (info->param_count < info->obj_desc->method.param_count) { - ACPI_WARNING((AE_INFO, - "Insufficient arguments - " - "method [%4.4s] needs %d, found %d", - acpi_ut_get_node_name(info->resolved_node), - info->obj_desc->method.param_count, - info->param_count)); - } else if (info->param_count > - info->obj_desc->method.param_count) { - ACPI_WARNING((AE_INFO, - "Excess arguments - " - "method [%4.4s] needs %d, found %d", - acpi_ut_get_node_name(info-> - resolved_node), - info->obj_desc->method.param_count, - info->param_count)); - } ACPI_DUMP_PATHNAME(info->resolved_node, "Execute Method:", ACPI_LV_INFO, _COMPONENT); @@ -264,32 +242,13 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info) } } - /* Validation of return values for ACPI-predefined methods and objects */ - - if ((status == AE_OK) || (status == AE_CTRL_RETURN_VALUE)) { - /* - * If this is the first evaluation, check the return value. This - * ensures that any warnings will only be emitted during the very - * first evaluation of the object. - */ - if (!(node->flags & ANOBJ_EVALUATED)) { - /* - * Check for a predefined ACPI name. If found, validate the - * returned object. - * - * Note: Ignore return status for now, emit warnings if there are - * problems with the returned object. May change later to abort - * the method on invalid return object. - */ - (void)acpi_ns_check_predefined_names(node, - info-> - return_object); - } - - /* Mark the node as having been evaluated */ - - node->flags |= ANOBJ_EVALUATED; - } + /* + * Check input argument count against the ASL-defined count for a method. + * Also check predefined names: argument count and return value against + * the ACPI specification. Some incorrect return value types are repaired. + */ + (void)acpi_ns_check_predefined_names(node, info->param_count, + status, &info->return_object); /* Check if there is a return value that must be dealt with */ diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/acpica/nsinit.c index e4c57510d798..13501cb81863 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acdispat.h" +#include "acinterp.h" #include <linux/nmi.h> #define _COMPONENT ACPI_NAMESPACE diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/acpica/nsload.c index a4a412b7c029..a0ba9e12379e 100644 --- a/drivers/acpi/namespace/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acdispat.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acdispat.h" +#include "actables.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsload") diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/acpica/nsnames.c index 42a39a7c96e9..ae3dc10a7e81 100644 --- a/drivers/acpi/namespace/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "amlcode.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsnames") diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/acpica/nsobject.c index 15fe09e24f71..08a97a57f8f9 100644 --- a/drivers/acpi/namespace/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsobject") diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/acpica/nsparse.c index a82271a9dbb3..b9e8d0070b6f 100644 --- a/drivers/acpi/namespace/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -42,10 +42,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acparser.h> -#include <acpi/acdispat.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acparser.h" +#include "acdispat.h" +#include "actables.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsparse") diff --git a/drivers/acpi/namespace/nspredef.c b/drivers/acpi/acpica/nspredef.c index 0f17cf0898c9..452703290d35 100644 --- a/drivers/acpi/namespace/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -43,8 +43,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acpredef.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acpredef.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nspredef") @@ -72,7 +73,7 @@ ACPI_MODULE_NAME("nspredef") /* Local prototypes */ static acpi_status acpi_ns_check_package(char *pathname, - union acpi_operand_object *return_object, + union acpi_operand_object **return_object_ptr, const union acpi_predefined_info *predefined); static acpi_status @@ -82,13 +83,18 @@ acpi_ns_check_package_elements(char *pathname, static acpi_status acpi_ns_check_object_type(char *pathname, - union acpi_operand_object *return_object, + union acpi_operand_object **return_object_ptr, u32 expected_btypes, u32 package_index); static acpi_status acpi_ns_check_reference(char *pathname, 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); + /* * Names for the types that can be returned by the predefined objects. * Used for warning messages. Must be in the same order as the ACPI_RTYPEs @@ -108,8 +114,8 @@ static const char *acpi_rtype_names[] = { * FUNCTION: acpi_ns_check_predefined_names * * PARAMETERS: Node - Namespace node for the method/object - * return_object - Object returned from the evaluation of this - * method/object + * return_object_ptr - Pointer to the object returned from the + * evaluation of a method or object * * RETURN: Status * @@ -119,8 +125,11 @@ static const char *acpi_rtype_names[] = { acpi_status acpi_ns_check_predefined_names(struct acpi_namespace_node *node, - union acpi_operand_object *return_object) + u32 user_param_count, + acpi_status return_status, + union acpi_operand_object **return_object_ptr) { + union acpi_operand_object *return_object = *return_object_ptr; acpi_status status = AE_OK; const union acpi_predefined_info *predefined; char *pathname; @@ -128,12 +137,6 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, /* Match the name for this method/object against the predefined list */ predefined = acpi_ns_check_for_predefined_name(node); - if (!predefined) { - - /* Name was not one of the predefined names */ - - return (AE_OK); - } /* Get the full pathname to the object, for use in error messages */ @@ -143,10 +146,37 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, } /* - * Check that the parameter count for this method is in accordance - * with the ACPI specification. + * Check that the parameter count for this method matches the ASL + * definition. For predefined names, ensure that both the caller and + * the method itself are in accordance with the ACPI specification. */ - acpi_ns_check_parameter_count(pathname, node, predefined); + acpi_ns_check_parameter_count(pathname, node, user_param_count, + predefined); + + /* 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; + } + + /* + * 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 (node->flags & ANOBJ_EVALUATED) { + goto exit; + } + + /* 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 @@ -171,7 +201,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, * We have a return value, but if one wasn't expected, just exit, this is * not a problem * - * For example, if "Implicit return value" is enabled, methods will + * For example, if the "Implicit Return" feature is enabled, methods will * always return a value */ if (!predefined->info.expected_btypes) { @@ -182,7 +212,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, * 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, + status = acpi_ns_check_object_type(pathname, return_object_ptr, predefined->info.expected_btypes, ACPI_NOT_PACKAGE); if (ACPI_FAILURE(status)) { @@ -193,11 +223,12 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, if (ACPI_GET_OBJECT_TYPE(return_object) == ACPI_TYPE_PACKAGE) { status = - acpi_ns_check_package(pathname, return_object, predefined); + acpi_ns_check_package(pathname, return_object_ptr, + predefined); } exit: - if (pathname) { + if (pathname != predefined->info.name) { ACPI_FREE(pathname); } @@ -210,6 +241,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, * * PARAMETERS: Pathname - Full pathname to the node (for error msgs) * Node - Namespace node for the method/object + * user_param_count - Number of args passed in by the caller * Predefined - Pointer to entry in predefined name table * * RETURN: None @@ -223,32 +255,76 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, void acpi_ns_check_parameter_count(char *pathname, struct acpi_namespace_node *node, + u32 user_param_count, const union acpi_predefined_info *predefined) { u32 param_count; u32 required_params_current; u32 required_params_old; - /* - * Check that the ASL-defined parameter count is what is expected for - * this predefined name. - * - * Methods have 0-7 parameters. All other types have zero. - */ + /* Methods have 0-7 parameters. All other types have zero. */ + param_count = 0; if (node->type == ACPI_TYPE_METHOD) { param_count = node->object->method.param_count; } - /* Validate parameter count - allow two different legal counts (_SCP) */ + /* Argument count check for non-predefined methods/objects */ + + if (!predefined) { + /* + * 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)); + } else if (user_param_count > param_count) { + ACPI_WARNING((AE_INFO, + "%s: Excess arguments - needs %d, found %d", + pathname, param_count, user_param_count)); + } + return; + } + + /* 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)); + } + } + + /* + * 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. + */ if ((param_count != required_params_current) && (param_count != required_params_old)) { ACPI_WARNING((AE_INFO, - "%s: Parameter count mismatch - ASL declared %d, expected %d", + "%s: Parameter count mismatch - ASL declared %d, ACPI requires %d", pathname, param_count, required_params_current)); } } @@ -307,8 +383,8 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct * FUNCTION: acpi_ns_check_package * * PARAMETERS: Pathname - Full pathname to the node (for error msgs) - * return_object - Object returned from the evaluation of a - * method or object + * 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 @@ -320,9 +396,10 @@ 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, + union acpi_operand_object **return_object_ptr, const union acpi_predefined_info *predefined) { + 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; @@ -408,7 +485,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(pathname, elements, package->ret_info. object_type1, i); if (ACPI_FAILURE(status)) { @@ -441,7 +518,7 @@ acpi_ns_check_package(char *pathname, status = acpi_ns_check_object_type(pathname, - *elements, + elements, package-> ret_info3. object_type[i], @@ -454,7 +531,7 @@ acpi_ns_check_package(char *pathname, status = acpi_ns_check_object_type(pathname, - *elements, + elements, package-> ret_info3. tail_object_type, @@ -471,7 +548,7 @@ acpi_ns_check_package(char *pathname, /* 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(pathname, elements, ACPI_RTYPE_INTEGER, 0); if (ACPI_FAILURE(status)) { return (status); @@ -509,7 +586,7 @@ acpi_ns_check_package(char *pathname, /* Each sub-object must be of type Package */ status = - acpi_ns_check_object_type(pathname, sub_package, + acpi_ns_check_object_type(pathname, &sub_package, ACPI_RTYPE_PACKAGE, i); if (ACPI_FAILURE(status)) { return (status); @@ -567,12 +644,8 @@ acpi_ns_check_package(char *pathname, for (j = 0; j < expected_count; j++) { status = acpi_ns_check_object_type(pathname, - sub_elements - [j], - package-> - ret_info2. - object_type - [j], j); + &sub_elements[j], + package->ret_info2.object_type[j], j); if (ACPI_FAILURE(status)) { return (status); } @@ -611,7 +684,7 @@ acpi_ns_check_package(char *pathname, status = acpi_ns_check_object_type(pathname, - *sub_elements, + sub_elements, ACPI_RTYPE_INTEGER, 0); if (ACPI_FAILURE(status)) { @@ -708,7 +781,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(pathname, this_element, type1, i); if (ACPI_FAILURE(status)) { return (status); @@ -717,7 +790,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(pathname, this_element, type2, (i + count1)); if (ACPI_FAILURE(status)) { return (status); @@ -733,8 +806,8 @@ acpi_ns_check_package_elements(char *pathname, * FUNCTION: acpi_ns_check_object_type * * PARAMETERS: Pathname - Full pathname to the node (for error msgs) - * return_object - Object return from the execution of this - * method/object + * 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) @@ -748,9 +821,10 @@ acpi_ns_check_package_elements(char *pathname, static acpi_status acpi_ns_check_object_type(char *pathname, - union acpi_operand_object *return_object, + union acpi_operand_object **return_object_ptr, u32 expected_btypes, u32 package_index) { + union acpi_operand_object *return_object = *return_object_ptr; acpi_status status = AE_OK; u32 return_btype; char type_buffer[48]; /* Room for 5 types */ @@ -814,6 +888,14 @@ acpi_ns_check_object_type(char *pathname, /* Is the object one of the expected types? */ if (!(return_btype & expected_btypes)) { + + /* Type mismatch -- attempt repair of the returned object */ + + status = acpi_ns_repair_object(expected_btypes, package_index, + return_object_ptr); + if (ACPI_SUCCESS(status)) { + return (status); + } goto type_error_exit; } @@ -898,3 +980,86 @@ acpi_ns_check_reference(char *pathname, return (AE_AML_OPERAND_TYPE); } + +/******************************************************************************* + * + * FUNCTION: acpi_ns_repair_object + * + * 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 + * + * RETURN: Status. AE_OK if repair was successful. + * + * DESCRIPTION: Attempt to repair/convert a return object of a type that was + * not expected. + * + ******************************************************************************/ + +static acpi_status +acpi_ns_repair_object(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 (ACPI_GET_OBJECT_TYPE(return_object)) { + 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); + } + + /* + * 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); + + /* Install the new return object */ + + acpi_ut_remove_reference(return_object); + *return_object_ptr = new_object; + + /* + * 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); + } + return (AE_OK); + + default: + break; + } + + return (AE_AML_OPERAND_TYPE); +} diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/acpica/nssearch.c index a9a80bf811b3..6fea13f3f52d 100644 --- a/drivers/acpi/namespace/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nssearch") diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/acpica/nsutils.c index b0817e1127b1..3e1149bf4aa5 100644 --- a/drivers/acpi/namespace/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -43,9 +43,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/amlcode.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acnamesp.h" +#include "amlcode.h" +#include "actables.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsutils") @@ -314,9 +315,15 @@ void acpi_ns_get_internal_name_length(struct acpi_namestring_info *info) * * strlen() + 1 covers the first name_seg, which has no path separator */ - if (acpi_ns_valid_root_prefix(next_external_char[0])) { + if (acpi_ns_valid_root_prefix(*next_external_char)) { info->fully_qualified = TRUE; next_external_char++; + + /* Skip redundant root_prefix, like \\_SB.PCI0.SBRG.EC0 */ + + while (acpi_ns_valid_root_prefix(*next_external_char)) { + next_external_char++; + } } else { /* * Handle Carat prefixes diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/acpica/nswalk.c index 3c905ce26d7d..200895fa2728 100644 --- a/drivers/acpi/namespace/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nswalk") diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index a085cc39c055..22a7171ac1ed 100644 --- a/drivers/acpi/namespace/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -43,8 +43,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfeval") diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 5efa4e7ddb0b..9589fea24997 100644 --- a/drivers/acpi/namespace/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfname") diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 2b375ee80cef..1c7efc15225f 100644 --- a/drivers/acpi/namespace/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfobj") diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/acpica/psargs.c index d830b29b85b1..b161f3544b51 100644 --- a/drivers/acpi/parser/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -42,10 +42,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> -#include <acpi/acdispat.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acnamesp.h" +#include "acdispat.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psargs") diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/acpica/psloop.c index 4647039a0d8a..c5f6ce19a401 100644 --- a/drivers/acpi/parser/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -50,9 +50,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acdispat.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acparser.h" +#include "acdispat.h" +#include "amlcode.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psloop") diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/acpica/psopcode.c index f425ab30eae8..3bc3a60194d6 100644 --- a/drivers/acpi/parser/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acopcode.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acparser.h" +#include "acopcode.h" +#include "amlcode.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psopcode") diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/acpica/psparse.c index 68e932f215ea..70838e9b608c 100644 --- a/drivers/acpi/parser/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -51,11 +51,12 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acdispat.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acparser.h" +#include "acdispat.h" +#include "amlcode.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psparse") @@ -447,10 +448,22 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) walk_state, walk_state->parser_state.aml, walk_state->parser_state.aml_size)); + if (!walk_state->parser_state.aml) { + return_ACPI_STATUS(AE_NULL_OBJECT); + } + /* Create and initialize a new thread state */ thread = acpi_ut_create_thread_state(); if (!thread) { + if (walk_state->method_desc) { + + /* Executing a control method - additional cleanup */ + + acpi_ds_terminate_control_method( + walk_state->method_desc, walk_state); + } + acpi_ds_delete_walk_state(walk_state); return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/acpica/psscope.c index ee50e67c9443..2feca5ca9581 100644 --- a/drivers/acpi/parser/psscope.c +++ b/drivers/acpi/acpica/psscope.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> +#include "accommon.h" +#include "acparser.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psscope") diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/acpica/pstree.c index 1dd355ddd182..4d3389118ec3 100644 --- a/drivers/acpi/parser/pstree.c +++ b/drivers/acpi/acpica/pstree.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("pstree") diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/acpica/psutils.c index 7cf1f65cd5bb..e636e078ad3d 100644 --- a/drivers/acpi/parser/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psutils") diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/acpica/pswalk.c index 8b86ad5a3201..78b8b791f2ae 100644 --- a/drivers/acpi/parser/pswalk.c +++ b/drivers/acpi/acpica/pswalk.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> +#include "accommon.h" +#include "acparser.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("pswalk") diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/acpica/psxface.c index 270469aae842..ff06032c0f06 100644 --- a/drivers/acpi/parser/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -42,9 +42,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acparser.h" +#include "acdispat.h" +#include "acinterp.h" +#include "amlcode.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psxface") @@ -278,6 +280,38 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) goto cleanup; } + /* Invoke an internal method if necessary */ + + if (info->obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { + status = info->obj_desc->method.implementation(walk_state); + info->return_object = walk_state->return_desc; + + /* Cleanup states */ + + acpi_ds_scope_stack_clear(walk_state); + acpi_ps_cleanup_scope(&walk_state->parser_state); + acpi_ds_terminate_control_method(walk_state->method_desc, + walk_state); + acpi_ds_delete_walk_state(walk_state); + goto cleanup; + } + + /* + * Start method evaluation with an implicit return of zero. + * This is done for Windows compatibility. + */ + if (acpi_gbl_enable_interpreter_slack) { + walk_state->implicit_return_obj = + acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + if (!walk_state->implicit_return_obj) { + status = AE_NO_MEMORY; + acpi_ds_delete_walk_state(walk_state); + goto cleanup; + } + + walk_state->implicit_return_obj->integer.value = 0; + } + /* Parse the AML */ status = acpi_ps_parse_aml(walk_state); diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/acpica/rsaddr.c index 7f96332822bf..1e437bfd8db5 100644 --- a/drivers/acpi/resources/rsaddr.c +++ b/drivers/acpi/acpica/rsaddr.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsaddr") diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/acpica/rscalc.c index 8eaaecf92009..52865ee6bc77 100644 --- a/drivers/acpi/resources/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acresrc.h" +#include "acnamesp.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rscalc") diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/acpica/rscreate.c index 08b8d73e6ee5..61566b1a0616 100644 --- a/drivers/acpi/resources/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acresrc.h" +#include "acnamesp.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rscreate") diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/acpica/rsdump.c index 6bbbb7b8941a..3f0ca5a12d34 100644 --- a/drivers/acpi/resources/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsdump") diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/acpica/rsinfo.c index 3f0a1fedbe0e..77b25fdb459c 100644 --- a/drivers/acpi/resources/rsinfo.c +++ b/drivers/acpi/acpica/rsinfo.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsinfo") diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/acpica/rsio.c index b66d42e7402e..35a49aa95609 100644 --- a/drivers/acpi/resources/rsio.c +++ b/drivers/acpi/acpica/rsio.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsio") diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/acpica/rsirq.c index a8805efc0366..2e0256983aa6 100644 --- a/drivers/acpi/resources/rsirq.c +++ b/drivers/acpi/acpica/rsirq.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsirq") diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/acpica/rslist.c index b78c7e797a19..1b1dbc69f087 100644 --- a/drivers/acpi/resources/rslist.c +++ b/drivers/acpi/acpica/rslist.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rslist") diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/acpica/rsmemory.c index 63b21abd90bb..ddc76cebdc92 100644 --- a/drivers/acpi/resources/rsmemory.c +++ b/drivers/acpi/acpica/rsmemory.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsmemory") diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index 96a6c0353255..5bc49a553284 100644 --- a/drivers/acpi/resources/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsmisc") diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/acpica/rsutils.c index f7b3bcd59ba7..bc03d5966829 100644 --- a/drivers/acpi/resources/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsutils") diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/acpica/rsxface.c index f59f4c4e034c..69a2aa5b5d83 100644 --- a/drivers/acpi/resources/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acresrc.h" +#include "acnamesp.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsxface") diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 2817158fb6a1..3636e4f8fb73 100644 --- a/drivers/acpi/tables/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -42,15 +42,16 @@ */ #include <acpi/acpi.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "actables.h" #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbfadt") /* Local prototypes */ -static void inline +static inline void acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, - u8 byte_width, u64 address); + u8 space_id, u8 byte_width, u64 address); static void acpi_tb_convert_fadt(void); @@ -60,9 +61,10 @@ static void acpi_tb_validate_fadt(void); typedef struct acpi_fadt_info { char *name; - u8 target; - u8 source; + u8 address64; + u8 address32; u8 length; + u8 default_length; u8 type; } acpi_fadt_info; @@ -71,37 +73,61 @@ typedef struct acpi_fadt_info { #define ACPI_FADT_SEPARATE_LENGTH 2 static struct acpi_fadt_info fadt_info_table[] = { - {"Pm1aEventBlock", ACPI_FADT_OFFSET(xpm1a_event_block), + {"Pm1aEventBlock", + ACPI_FADT_OFFSET(xpm1a_event_block), ACPI_FADT_OFFSET(pm1a_event_block), - ACPI_FADT_OFFSET(pm1_event_length), ACPI_FADT_REQUIRED}, + ACPI_FADT_OFFSET(pm1_event_length), + ACPI_PM1_REGISTER_WIDTH * 2, /* Enable + Status register */ + ACPI_FADT_REQUIRED}, - {"Pm1bEventBlock", ACPI_FADT_OFFSET(xpm1b_event_block), + {"Pm1bEventBlock", + ACPI_FADT_OFFSET(xpm1b_event_block), ACPI_FADT_OFFSET(pm1b_event_block), - ACPI_FADT_OFFSET(pm1_event_length), 0}, + ACPI_FADT_OFFSET(pm1_event_length), + ACPI_PM1_REGISTER_WIDTH * 2, /* Enable + Status register */ + 0}, - {"Pm1aControlBlock", ACPI_FADT_OFFSET(xpm1a_control_block), + {"Pm1aControlBlock", + ACPI_FADT_OFFSET(xpm1a_control_block), ACPI_FADT_OFFSET(pm1a_control_block), - ACPI_FADT_OFFSET(pm1_control_length), ACPI_FADT_REQUIRED}, + ACPI_FADT_OFFSET(pm1_control_length), + ACPI_PM1_REGISTER_WIDTH, + ACPI_FADT_REQUIRED}, - {"Pm1bControlBlock", ACPI_FADT_OFFSET(xpm1b_control_block), + {"Pm1bControlBlock", + ACPI_FADT_OFFSET(xpm1b_control_block), ACPI_FADT_OFFSET(pm1b_control_block), - ACPI_FADT_OFFSET(pm1_control_length), 0}, + ACPI_FADT_OFFSET(pm1_control_length), + ACPI_PM1_REGISTER_WIDTH, + 0}, - {"Pm2ControlBlock", ACPI_FADT_OFFSET(xpm2_control_block), + {"Pm2ControlBlock", + ACPI_FADT_OFFSET(xpm2_control_block), ACPI_FADT_OFFSET(pm2_control_block), - ACPI_FADT_OFFSET(pm2_control_length), ACPI_FADT_SEPARATE_LENGTH}, + ACPI_FADT_OFFSET(pm2_control_length), + ACPI_PM2_REGISTER_WIDTH, + ACPI_FADT_SEPARATE_LENGTH}, - {"PmTimerBlock", ACPI_FADT_OFFSET(xpm_timer_block), + {"PmTimerBlock", + ACPI_FADT_OFFSET(xpm_timer_block), ACPI_FADT_OFFSET(pm_timer_block), - ACPI_FADT_OFFSET(pm_timer_length), ACPI_FADT_REQUIRED}, + ACPI_FADT_OFFSET(pm_timer_length), + ACPI_PM_TIMER_WIDTH, + ACPI_FADT_REQUIRED}, - {"Gpe0Block", ACPI_FADT_OFFSET(xgpe0_block), + {"Gpe0Block", + ACPI_FADT_OFFSET(xgpe0_block), ACPI_FADT_OFFSET(gpe0_block), - ACPI_FADT_OFFSET(gpe0_block_length), ACPI_FADT_SEPARATE_LENGTH}, + ACPI_FADT_OFFSET(gpe0_block_length), + 0, + ACPI_FADT_SEPARATE_LENGTH}, - {"Gpe1Block", ACPI_FADT_OFFSET(xgpe1_block), + {"Gpe1Block", + ACPI_FADT_OFFSET(xgpe1_block), ACPI_FADT_OFFSET(gpe1_block), - ACPI_FADT_OFFSET(gpe1_block_length), ACPI_FADT_SEPARATE_LENGTH} + ACPI_FADT_OFFSET(gpe1_block_length), + 0, + ACPI_FADT_SEPARATE_LENGTH} }; #define ACPI_FADT_INFO_ENTRIES (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info)) @@ -122,9 +148,9 @@ static struct acpi_fadt_info fadt_info_table[] = { * ******************************************************************************/ -static void inline +static inline void acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, - u8 byte_width, u64 address) + u8 space_id, u8 byte_width, u64 address) { /* @@ -135,10 +161,10 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, /* All other fields are byte-wide */ - generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO; - generic_address->bit_width = byte_width << 3; + generic_address->space_id = space_id; + generic_address->bit_width = (u8)ACPI_MUL_8(byte_width); generic_address->bit_offset = 0; - generic_address->access_width = 0; + generic_address->access_width = 0; /* Access width ANY */ } /******************************************************************************* @@ -225,7 +251,8 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) */ if (length > sizeof(struct acpi_table_fadt)) { ACPI_WARNING((AE_INFO, - "FADT (revision %u) is longer than ACPI 2.0 version, truncating length 0x%X to 0x%zX", + "FADT (revision %u) is longer than ACPI 2.0 version, " + "truncating length 0x%X to 0x%zX", table->revision, (unsigned)length, sizeof(struct acpi_table_fadt))); } @@ -244,7 +271,6 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) * 2) Validate some of the important values within the FADT */ acpi_tb_convert_fadt(); - acpi_tb_validate_fadt(); } /******************************************************************************* @@ -278,22 +304,36 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) static void acpi_tb_convert_fadt(void) { - u8 pm1_register_length; - struct acpi_generic_address *target; + u8 pm1_register_bit_width; + u8 pm1_register_byte_width; + struct acpi_generic_address *target64; u32 i; /* Update the local FADT table header length */ acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); - /* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary */ - + /* + * Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary. + * Later code will always use the X 64-bit field. Also, check for an + * address mismatch between the 32-bit and 64-bit address fields + * (FIRMWARE_CTRL/X_FIRMWARE_CTRL, DSDT/X_DSDT) which would indicate + * the presence of two FACS or two DSDT tables. + */ if (!acpi_gbl_FADT.Xfacs) { acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs; + } else if (acpi_gbl_FADT.facs && + (acpi_gbl_FADT.Xfacs != (u64) acpi_gbl_FADT.facs)) { + ACPI_WARNING((AE_INFO, + "32/64 FACS address mismatch in FADT - two FACS tables!")); } if (!acpi_gbl_FADT.Xdsdt) { acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt; + } else if (acpi_gbl_FADT.dsdt && + (acpi_gbl_FADT.Xdsdt != (u64) acpi_gbl_FADT.dsdt)) { + ACPI_WARNING((AE_INFO, + "32/64 DSDT address mismatch in FADT - two DSDT tables!")); } /* @@ -312,18 +352,23 @@ static void acpi_tb_convert_fadt(void) } /* - * Expand the ACPI 1.0 32-bit V1.0 addresses to the ACPI 2.0 64-bit "X" - * generic address structures as necessary. + * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X" + * generic address structures as necessary. Later code will always use + * the 64-bit address structures. */ for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { - target = + target64 = ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, - fadt_info_table[i].target); + fadt_info_table[i].address64); - /* Expand only if the X target is null */ + /* Expand only if the 64-bit X target is null */ - if (!target->address) { - acpi_tb_init_generic_address(target, + if (!target64->address) { + + /* The space_id is always I/O for the 32-bit legacy address fields */ + + acpi_tb_init_generic_address(target64, + ACPI_ADR_SPACE_SYSTEM_IO, *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, fadt_info_table @@ -332,11 +377,64 @@ static void acpi_tb_convert_fadt(void) &acpi_gbl_FADT, fadt_info_table [i]. - source)); + address32)); + } + } + + /* Validate FADT values now, before we make any changes */ + + acpi_tb_validate_fadt(); + + /* + * Optionally check all register lengths against the default values and + * update them if they are incorrect. + */ + if (acpi_gbl_use_default_register_widths) { + for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { + target64 = + ACPI_ADD_PTR(struct acpi_generic_address, + &acpi_gbl_FADT, + fadt_info_table[i].address64); + + /* + * If a valid register (Address != 0) and the (default_length > 0) + * (Not a GPE register), then check the width against the default. + */ + if ((target64->address) && + (fadt_info_table[i].default_length > 0) && + (fadt_info_table[i].default_length != + target64->bit_width)) { + ACPI_WARNING((AE_INFO, + "Invalid length for %s: %d, using default %d", + fadt_info_table[i].name, + target64->bit_width, + fadt_info_table[i]. + default_length)); + + /* Incorrect size, set width to the default */ + + target64->bit_width = + fadt_info_table[i].default_length; + } } } /* + * Get the length of the individual PM1 registers (enable and status). + * Each register is defined to be (event block length / 2). + */ + pm1_register_bit_width = + (u8)ACPI_DIV_2(acpi_gbl_FADT.xpm1a_event_block.bit_width); + pm1_register_byte_width = (u8)ACPI_DIV_8(pm1_register_bit_width); + + /* + * Adjust the lengths of the PM1 Event Blocks so that they can be used to + * access the PM1 status register(s). Use (width / 2) + */ + acpi_gbl_FADT.xpm1a_event_block.bit_width = pm1_register_bit_width; + acpi_gbl_FADT.xpm1b_event_block.bit_width = pm1_register_bit_width; + + /* * Calculate separate GAS structs for the PM1 Enable registers. * These addresses do not appear (directly) in the FADT, so it is * useful to calculate them once, here. @@ -356,14 +454,14 @@ static void acpi_tb_convert_fadt(void) " PM1_EVT_LEN (%u)\n", acpi_gbl_FADT.xpm1a_event_block.bit_width, acpi_gbl_FADT.pm1_event_length); - pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length); /* The PM1A register block is required */ acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable, - pm1_register_length, + acpi_gbl_FADT.xpm1a_event_block.space_id, + pm1_register_byte_width, (acpi_gbl_FADT.xpm1a_event_block.address + - pm1_register_length)); + pm1_register_byte_width)); /* Don't forget to copy space_id of the GAS */ acpi_gbl_xpm1a_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id; @@ -379,9 +477,10 @@ static void acpi_tb_convert_fadt(void) acpi_gbl_FADT.xpm1b_event_block.bit_width, acpi_gbl_FADT.pm1_event_length); acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, - pm1_register_length, + acpi_gbl_FADT.xpm1b_event_block.space_id, + pm1_register_byte_width, (acpi_gbl_FADT.xpm1b_event_block. - address + pm1_register_length)); + address + pm1_register_byte_width)); /* Don't forget to copy space_id of the GAS */ acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1b_event_block.space_id; @@ -411,26 +510,63 @@ static void acpi_tb_convert_fadt(void) static void acpi_tb_validate_fadt(void) { + char *name; u32 *address32; struct acpi_generic_address *address64; u8 length; u32 i; - /* Examine all of the 64-bit extended address fields (X fields) */ + /* + * Check for FACS and DSDT address mismatches. An address mismatch between + * the 32-bit and 64-bit address fields (FIRMWARE_CTRL/X_FIRMWARE_CTRL and + * DSDT/X_DSDT) would indicate the presence of two FACS or two DSDT tables. + */ + if (acpi_gbl_FADT.facs && + (acpi_gbl_FADT.Xfacs != (u64) acpi_gbl_FADT.facs)) { + ACPI_WARNING((AE_INFO, + "32/64X FACS address mismatch in FADT - " + "two FACS tables! %8.8X/%8.8X%8.8X", + acpi_gbl_FADT.facs, + ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xfacs))); + } - for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { + if (acpi_gbl_FADT.dsdt && + (acpi_gbl_FADT.Xdsdt != (u64) acpi_gbl_FADT.dsdt)) { + ACPI_WARNING((AE_INFO, + "32/64X DSDT address mismatch in FADT - " + "two DSDT tables! %8.8X/%8.8X%8.8X", + acpi_gbl_FADT.dsdt, + ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xdsdt))); + } - /* Generate pointers to the 32-bit and 64-bit addresses and get the length */ + /* Examine all of the 64-bit extended address fields (X fields) */ - address64 = - ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, - fadt_info_table[i].target); + for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { + /* + * Generate pointers to the 32-bit and 64-bit addresses, get the + * register length (width), and the register name + */ + address64 = ACPI_ADD_PTR(struct acpi_generic_address, + &acpi_gbl_FADT, + fadt_info_table[i].address64); address32 = ACPI_ADD_PTR(u32, &acpi_gbl_FADT, - fadt_info_table[i].source); + fadt_info_table[i].address32); length = *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, fadt_info_table[i].length); + name = fadt_info_table[i].name; + + /* + * For each extended field, check for length mismatch between the + * legacy length field and the corresponding 64-bit X length field. + */ + if (address64 && (address64->bit_width != ACPI_MUL_8(length))) { + ACPI_WARNING((AE_INFO, + "32/64X length mismatch in %s: %d/%d", + name, ACPI_MUL_8(length), + address64->bit_width)); + } if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) { /* @@ -439,8 +575,8 @@ static void acpi_tb_validate_fadt(void) */ if (!address64->address || !length) { ACPI_ERROR((AE_INFO, - "Required field \"%s\" has zero address and/or length: %8.8X%8.8X/%X", - fadt_info_table[i].name, + "Required field %s has zero address and/or length: %8.8X%8.8X/%X", + name, ACPI_FORMAT_UINT64(address64-> address), length)); @@ -453,8 +589,8 @@ static void acpi_tb_validate_fadt(void) if ((address64->address && !length) || (!address64->address && length)) { ACPI_WARNING((AE_INFO, - "Optional field \"%s\" has zero address or length: %8.8X%8.8X/%X", - fadt_info_table[i].name, + "Optional field %s has zero address or length: %8.8X%8.8X/%X", + name, ACPI_FORMAT_UINT64(address64-> address), length)); @@ -466,8 +602,8 @@ static void acpi_tb_validate_fadt(void) if (address64->address && *address32 && (address64->address != (u64) * address32)) { ACPI_ERROR((AE_INFO, - "32/64X address mismatch in \"%s\": [%8.8X] [%8.8X%8.8X], using 64X", - fadt_info_table[i].name, *address32, + "32/64X address mismatch in %s: %8.8X/%8.8X%8.8X, using 64X", + name, *address32, ACPI_FORMAT_UINT64(address64->address))); } } diff --git a/drivers/acpi/tables/tbfind.c b/drivers/acpi/acpica/tbfind.c index 531584defbb8..1054dfd49207 100644 --- a/drivers/acpi/tables/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "actables.h" #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbfind") diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 18747ce8dd2f..37374b21969d 100644 --- a/drivers/acpi/tables/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acnamesp.h" +#include "actables.h" #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbinstal") diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/acpica/tbutils.c index 0cc92ef5236f..9684cc827930 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "actables.h" #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbutils") @@ -113,6 +114,30 @@ acpi_tb_check_xsdt(acpi_physical_address address) /******************************************************************************* * + * FUNCTION: acpi_tb_initialize_facs + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Create a permanent mapping for the FADT and save it in a global + * for accessing the Global Lock and Firmware Waking Vector + * + ******************************************************************************/ + +acpi_status acpi_tb_initialize_facs(void) +{ + acpi_status status; + + status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, + ACPI_CAST_INDIRECT_PTR(struct + acpi_table_header, + &acpi_gbl_FACS)); + return status; +} + +/******************************************************************************* + * * FUNCTION: acpi_tb_tables_loaded * * PARAMETERS: None @@ -420,7 +445,8 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags) /* Differentiate between RSDT and XSDT root tables */ - if (rsdp->revision > 1 && rsdp->xsdt_physical_address) { + if (rsdp->revision > 1 && rsdp->xsdt_physical_address + && !acpi_rsdt_forced) { /* * Root table is an XSDT (64-bit physical addresses). We must use the * XSDT if the revision is > 1 and the XSDT pointer is present, as per diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/acpica/tbxface.c index fd7770aa1061..c3e841f3cde9 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -43,8 +43,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acnamesp.h" +#include "actables.h" #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbxface") diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index 2d157e0f98d2..b7fc8dd43341 100644 --- a/drivers/acpi/tables/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "actables.h" #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbxfroot") diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/acpica/utalloc.c index 241c535c1753..7580f6b3069e 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acdebug.h> +#include "accommon.h" +#include "acdebug.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utalloc") diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/acpica/utcopy.c index 5b2f7c27b705..b0dcfd3c872a 100644 --- a/drivers/acpi/utilities/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_UTILITIES diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/acpica/utdebug.c index fd66ecb6741e..38821f53042c 100644 --- a/drivers/acpi/utilities/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -42,6 +42,7 @@ */ #include <acpi/acpi.h> +#include "accommon.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utdebug") @@ -136,7 +137,7 @@ static const char *acpi_ut_trim_function_name(const char *function_name) /******************************************************************************* * - * FUNCTION: acpi_ut_debug_print + * FUNCTION: acpi_debug_print * * PARAMETERS: requested_debug_level - Requested debug print level * line_number - Caller's line number (for error output) @@ -154,11 +155,11 @@ static const char *acpi_ut_trim_function_name(const char *function_name) ******************************************************************************/ void ACPI_INTERNAL_VAR_XFACE -acpi_ut_debug_print(u32 requested_debug_level, - u32 line_number, - const char *function_name, - const char *module_name, - u32 component_id, const char *format, ...) +acpi_debug_print(u32 requested_debug_level, + u32 line_number, + const char *function_name, + const char *module_name, + u32 component_id, const char *format, ...) { acpi_thread_id thread_id; va_list args; @@ -205,11 +206,11 @@ acpi_ut_debug_print(u32 requested_debug_level, va_end(args); } -ACPI_EXPORT_SYMBOL(acpi_ut_debug_print) +ACPI_EXPORT_SYMBOL(acpi_debug_print) /******************************************************************************* * - * FUNCTION: acpi_ut_debug_print_raw + * FUNCTION: acpi_debug_print_raw * * PARAMETERS: requested_debug_level - Requested debug print level * line_number - Caller's line number @@ -226,11 +227,11 @@ ACPI_EXPORT_SYMBOL(acpi_ut_debug_print) * ******************************************************************************/ void ACPI_INTERNAL_VAR_XFACE -acpi_ut_debug_print_raw(u32 requested_debug_level, - u32 line_number, - const char *function_name, - const char *module_name, - u32 component_id, const char *format, ...) +acpi_debug_print_raw(u32 requested_debug_level, + u32 line_number, + const char *function_name, + const char *module_name, + u32 component_id, const char *format, ...) { va_list args; @@ -244,7 +245,7 @@ acpi_ut_debug_print_raw(u32 requested_debug_level, va_end(args); } -ACPI_EXPORT_SYMBOL(acpi_ut_debug_print_raw) +ACPI_EXPORT_SYMBOL(acpi_debug_print_raw) /******************************************************************************* * @@ -270,9 +271,9 @@ acpi_ut_trace(u32 line_number, acpi_gbl_nesting_level++; acpi_ut_track_stack_ptr(); - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s\n", acpi_gbl_fn_entry_str); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, component_id, + "%s\n", acpi_gbl_fn_entry_str); } ACPI_EXPORT_SYMBOL(acpi_ut_trace) @@ -301,10 +302,9 @@ acpi_ut_trace_ptr(u32 line_number, acpi_gbl_nesting_level++; acpi_ut_track_stack_ptr(); - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s %p\n", acpi_gbl_fn_entry_str, - pointer); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, component_id, + "%s %p\n", acpi_gbl_fn_entry_str, pointer); } /******************************************************************************* @@ -333,10 +333,9 @@ acpi_ut_trace_str(u32 line_number, acpi_gbl_nesting_level++; acpi_ut_track_stack_ptr(); - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s %s\n", acpi_gbl_fn_entry_str, - string); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, component_id, + "%s %s\n", acpi_gbl_fn_entry_str, string); } /******************************************************************************* @@ -365,10 +364,9 @@ acpi_ut_trace_u32(u32 line_number, acpi_gbl_nesting_level++; acpi_ut_track_stack_ptr(); - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s %08X\n", acpi_gbl_fn_entry_str, - integer); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, component_id, + "%s %08X\n", acpi_gbl_fn_entry_str, integer); } /******************************************************************************* @@ -393,9 +391,9 @@ acpi_ut_exit(u32 line_number, const char *module_name, u32 component_id) { - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s\n", acpi_gbl_fn_exit_str); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, component_id, + "%s\n", acpi_gbl_fn_exit_str); acpi_gbl_nesting_level--; } @@ -426,17 +424,16 @@ acpi_ut_status_exit(u32 line_number, { if (ACPI_SUCCESS(status)) { - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s %s\n", - acpi_gbl_fn_exit_str, - acpi_format_exception(status)); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, + component_id, "%s %s\n", acpi_gbl_fn_exit_str, + acpi_format_exception(status)); } else { - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s ****Exception****: %s\n", - acpi_gbl_fn_exit_str, - acpi_format_exception(status)); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, + component_id, "%s ****Exception****: %s\n", + acpi_gbl_fn_exit_str, + acpi_format_exception(status)); } acpi_gbl_nesting_level--; @@ -467,10 +464,10 @@ acpi_ut_value_exit(u32 line_number, u32 component_id, acpi_integer value) { - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s %8.8X%8.8X\n", - acpi_gbl_fn_exit_str, ACPI_FORMAT_UINT64(value)); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, component_id, + "%s %8.8X%8.8X\n", acpi_gbl_fn_exit_str, + ACPI_FORMAT_UINT64(value)); acpi_gbl_nesting_level--; } @@ -499,9 +496,9 @@ acpi_ut_ptr_exit(u32 line_number, const char *module_name, u32 component_id, u8 *ptr) { - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s %p\n", acpi_gbl_fn_exit_str, ptr); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, component_id, + "%s %p\n", acpi_gbl_fn_exit_str, ptr); acpi_gbl_nesting_level--; } diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/acpica/utdelete.c index d197c6b29e17..a0be9e39531e 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acevents.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utdelete") diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/acpica/uteval.c index 352747e49c7a..da9450bc60f7 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/acpica/uteval.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("uteval") @@ -129,7 +130,7 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state) /* The interface is supported */ - return_ACPI_STATUS(AE_CTRL_TERMINATE); + return_ACPI_STATUS(AE_OK); } } @@ -143,13 +144,13 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state) /* The interface is supported */ - return_ACPI_STATUS(AE_CTRL_TERMINATE); + return_ACPI_STATUS(AE_OK); } /* The interface is not supported */ return_desc->integer.value = 0; - return_ACPI_STATUS(AE_CTRL_TERMINATE); + return_ACPI_STATUS(AE_OK); } /******************************************************************************* diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/acpica/utglobal.c index 17ed5ac840f7..a3ab9d9da299 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -44,11 +44,11 @@ #define DEFINE_ACPI_GLOBALS #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" -ACPI_EXPORT_SYMBOL(acpi_gbl_FADT) #define _COMPONENT ACPI_UTILITIES - ACPI_MODULE_NAME("utglobal") +ACPI_MODULE_NAME("utglobal") /******************************************************************************* * @@ -352,7 +352,7 @@ const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = { "PCI_Config", "EmbeddedControl", "SMBus", - "CMOS", + "SystemCMOS", "PCIBARTarget", "DataTable" }; @@ -756,6 +756,7 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_gpe_xrupt_list_head = NULL; acpi_gbl_gpe_fadt_blocks[0] = NULL; acpi_gbl_gpe_fadt_blocks[1] = NULL; + acpi_current_gpe_count = 0; /* Global handlers */ @@ -771,6 +772,7 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_global_lock_mutex = NULL; acpi_gbl_global_lock_acquired = FALSE; acpi_gbl_global_lock_handle = 0; + acpi_gbl_global_lock_present = FALSE; /* Miscellaneous variables */ @@ -815,5 +817,7 @@ acpi_status acpi_ut_init_globals(void) return_ACPI_STATUS(AE_OK); } +ACPI_EXPORT_SYMBOL(acpi_gbl_FADT) ACPI_EXPORT_SYMBOL(acpi_dbg_level) ACPI_EXPORT_SYMBOL(acpi_dbg_layer) +ACPI_EXPORT_SYMBOL(acpi_current_gpe_count) diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/acpica/utinit.c index cae515fc02d3..a54ca84eb362 100644 --- a/drivers/acpi/utilities/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acevents.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acevents.h" +#include "actables.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utinit") diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/acpica/utmath.c index c927324fdd26..c9f682d640ef 100644 --- a/drivers/acpi/utilities/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -42,6 +42,7 @@ */ #include <acpi/acpi.h> +#include "accommon.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utmath") diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/acpica/utmisc.c index 9089a158a874..c1f7f4e1a72d 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -44,7 +44,8 @@ #include <linux/module.h> #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utmisc") @@ -1016,7 +1017,7 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object, /******************************************************************************* * - * FUNCTION: acpi_ut_error, acpi_ut_warning, acpi_ut_info + * FUNCTION: acpi_error, acpi_exception, acpi_warning, acpi_info * * PARAMETERS: module_name - Caller's module name (for error output) * line_number - Caller's line number (for error output) @@ -1029,7 +1030,7 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object, ******************************************************************************/ void ACPI_INTERNAL_VAR_XFACE -acpi_ut_error(const char *module_name, u32 line_number, const char *format, ...) +acpi_error(const char *module_name, u32 line_number, const char *format, ...) { va_list args; @@ -1042,8 +1043,8 @@ acpi_ut_error(const char *module_name, u32 line_number, const char *format, ...) } void ACPI_INTERNAL_VAR_XFACE -acpi_ut_exception(const char *module_name, - u32 line_number, acpi_status status, const char *format, ...) +acpi_exception(const char *module_name, + u32 line_number, acpi_status status, const char *format, ...) { va_list args; @@ -1056,11 +1057,8 @@ acpi_ut_exception(const char *module_name, va_end(args); } -EXPORT_SYMBOL(acpi_ut_exception); - void ACPI_INTERNAL_VAR_XFACE -acpi_ut_warning(const char *module_name, - u32 line_number, const char *format, ...) +acpi_warning(const char *module_name, u32 line_number, const char *format, ...) { va_list args; @@ -1073,7 +1071,7 @@ acpi_ut_warning(const char *module_name, } void ACPI_INTERNAL_VAR_XFACE -acpi_ut_info(const char *module_name, u32 line_number, const char *format, ...) +acpi_info(const char *module_name, u32 line_number, const char *format, ...) { va_list args; @@ -1088,3 +1086,8 @@ acpi_ut_info(const char *module_name, u32 line_number, const char *format, ...) acpi_os_printf("\n"); va_end(args); } + +ACPI_EXPORT_SYMBOL(acpi_error) +ACPI_EXPORT_SYMBOL(acpi_exception) +ACPI_EXPORT_SYMBOL(acpi_warning) +ACPI_EXPORT_SYMBOL(acpi_info) diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/acpica/utmutex.c index 7331dde9e1b3..14eb52c4d647 100644 --- a/drivers/acpi/utilities/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -42,6 +42,7 @@ */ #include <acpi/acpi.h> +#include "accommon.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utmutex") diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/acpica/utobject.c index 4bef3cfbaccb..fd5ea7543e5b 100644 --- a/drivers/acpi/utilities/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utobject") diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/acpica/utresrc.c index c3e3e1308edc..91b7c00236f4 100644 --- a/drivers/acpi/utilities/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/amlresrc.h> +#include "accommon.h" +#include "amlresrc.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utresrc") diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/acpica/utstate.c index 63a6d3d77d88..0440c958f5a4 100644 --- a/drivers/acpi/utilities/utstate.c +++ b/drivers/acpi/acpica/utstate.c @@ -42,6 +42,7 @@ */ #include <acpi/acpi.h> +#include "accommon.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utstate") diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/acpica/utxface.c index c198a4d40583..078a22728c6b 100644 --- a/drivers/acpi/utilities/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -42,9 +42,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> -#include <acpi/acnamesp.h> -#include <acpi/acdebug.h> +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" +#include "acdebug.h" +#include "actables.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utxface") @@ -148,6 +150,16 @@ acpi_status acpi_enable_subsystem(u32 flags) } /* + * Obtain a permanent mapping for the FACS. This is required for the + * Global Lock and the Firmware Waking Vector + */ + status = acpi_tb_initialize_facs(); + if (ACPI_FAILURE(status)) { + ACPI_WARNING((AE_INFO, "Could not map the FACS table")); + return_ACPI_STATUS(status); + } + + /* * Install the default op_region handlers. These are installed unless * other handlers have already been installed via the * install_address_space_handler interface. diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 1423b0c0cd2e..65132f920459 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -471,7 +471,7 @@ static void sysfs_remove_battery(struct acpi_battery *battery) static int acpi_battery_update(struct acpi_battery *battery) { - int result; + int result, old_present = acpi_battery_present(battery); result = acpi_battery_get_status(battery); if (result) return result; @@ -482,7 +482,8 @@ static int acpi_battery_update(struct acpi_battery *battery) return 0; } #endif - if (!battery->update_time) { + if (!battery->update_time || + old_present != acpi_battery_present(battery)) { result = acpi_battery_get_info(battery); if (result) return result; diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c index 307963bd1043..332fe4b21708 100644 --- a/drivers/acpi/cm_sbs.c +++ b/drivers/acpi/cm_sbs.c @@ -27,9 +27,6 @@ #include <linux/seq_file.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> -#include <acpi/acmacros.h> -#include <acpi/actypes.h> -#include <acpi/acutils.h> ACPI_MODULE_NAME("cm_sbs"); #define ACPI_AC_CLASS "ac_adapter" diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c index c48396892008..20223cbd0d1c 100644 --- a/drivers/acpi/debug.c +++ b/drivers/acpi/debug.c @@ -9,7 +9,6 @@ #include <linux/moduleparam.h> #include <asm/uaccess.h> #include <acpi/acpi_drivers.h> -#include <acpi/acglobal.h> #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("debug"); diff --git a/drivers/acpi/dispatcher/Makefile b/drivers/acpi/dispatcher/Makefile deleted file mode 100644 index eb7e602a83cd..000000000000 --- a/drivers/acpi/dispatcher/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \ - dsmethod.o dsobject.o dsutils.o dswload.o dswstate.o \ - dsinit.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 30f3ef236ecb..8dfcbb8aff73 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -42,7 +42,6 @@ #include <asm/io.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> -#include <acpi/actypes.h> #define ACPI_EC_CLASS "embedded_controller" #define ACPI_EC_DEVICE_NAME "Embedded Controller" @@ -370,7 +369,7 @@ unlock: * Note: samsung nv5000 doesn't work with ec burst mode. * http://bugzilla.kernel.org/show_bug.cgi?id=4980 */ -int acpi_ec_burst_enable(struct acpi_ec *ec) +static int acpi_ec_burst_enable(struct acpi_ec *ec) { u8 d; struct transaction t = {.command = ACPI_EC_BURST_ENABLE, @@ -380,7 +379,7 @@ int acpi_ec_burst_enable(struct acpi_ec *ec) return acpi_ec_transaction(ec, &t, 0); } -int acpi_ec_burst_disable(struct acpi_ec *ec) +static int acpi_ec_burst_disable(struct acpi_ec *ec) { struct transaction t = {.command = ACPI_EC_BURST_DISABLE, .wdata = NULL, .rdata = NULL, @@ -756,10 +755,15 @@ static acpi_status acpi_ec_register_query_methods(acpi_handle handle, u32 level, void *context, void **return_value) { - struct acpi_namespace_node *node = handle; + char node_name[5]; + struct acpi_buffer buffer = { sizeof(node_name), node_name }; struct acpi_ec *ec = context; int value = 0; - if (sscanf(node->name.ascii, "_Q%x", &value) == 1) { + acpi_status status; + + status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); + + if (ACPI_SUCCESS(status) && sscanf(node_name, "_Q%x", &value) == 1) { acpi_ec_add_query_handler(ec, value, handle, NULL, NULL); } return AE_OK; @@ -978,9 +982,9 @@ static const struct acpi_device_id ec_device_ids[] = { int __init acpi_ec_ecdt_probe(void) { - int ret; acpi_status status; struct acpi_table_ecdt *ecdt_ptr; + acpi_handle dummy; boot_ec = make_acpi_ec(); if (!boot_ec) @@ -1006,30 +1010,31 @@ int __init acpi_ec_ecdt_probe(void) boot_ec->gpe = ecdt_ptr->gpe; boot_ec->handle = ACPI_ROOT_OBJECT; acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle); - } else { - /* This workaround is needed only on some broken machines, - * which require early EC, but fail to provide ECDT */ - acpi_handle x; - printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n"); - status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device, - boot_ec, NULL); - /* Check that acpi_get_devices actually find something */ - if (ACPI_FAILURE(status) || !boot_ec->handle) - goto error; - /* We really need to limit this workaround, the only ASUS, - * which needs it, has fake EC._INI method, so use it as flag. - * Keep boot_ec struct as it will be needed soon. - */ - if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x))) - return -ENODEV; + /* Add some basic check against completely broken table */ + if (boot_ec->data_addr != boot_ec->command_addr) + goto install; + /* fall through */ } - - ret = ec_install_handlers(boot_ec); - if (!ret) { + /* 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"); + status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device, + boot_ec, NULL); + /* Check that acpi_get_devices actually find something */ + if (ACPI_FAILURE(status) || !boot_ec->handle) + goto error; + /* We really need to limit this workaround, the only ASUS, + * which needs it, has fake EC._INI method, so use it as flag. + * Keep boot_ec struct as it will be needed soon. + */ + if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &dummy))) + return -ENODEV; +install: + if (!ec_install_handlers(boot_ec)) { first_ec = boot_ec; return 0; } - error: +error: kfree(boot_ec); boot_ec = NULL; return -ENODEV; diff --git a/drivers/acpi/events/Makefile b/drivers/acpi/events/Makefile deleted file mode 100644 index d29f2ee449cc..000000000000 --- a/drivers/acpi/events/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := evevent.o evregion.o evsci.o evxfevnt.o \ - evmisc.o evrgnini.o evxface.o evxfregn.o \ - evgpe.o evgpeblk.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/executer/Makefile b/drivers/acpi/executer/Makefile deleted file mode 100644 index e09998aa012f..000000000000 --- a/drivers/acpi/executer/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := exconfig.o exfield.o exnames.o exoparg6.o exresolv.o exstorob.o\ - exconvrt.o exfldio.o exoparg1.o exprep.o exresop.o exsystem.o\ - excreate.o exmisc.o exoparg2.o exregion.o exstore.o exutils.o \ - exdump.o exmutex.o exoparg3.o exresnte.o exstoren.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/hardware/Makefile b/drivers/acpi/hardware/Makefile deleted file mode 100644 index 438ad373b9ad..000000000000 --- a/drivers/acpi/hardware/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := hwacpi.o hwgpe.o hwregs.o hwsleep.o - -obj-$(ACPI_FUTURE_USAGE) += hwtimer.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/main.c index 28a691cc625e..7e3c609cbef2 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/main.c @@ -101,13 +101,26 @@ void __init acpi_old_suspend_ordering(void) * cases. */ static bool set_sci_en_on_resume; +/* + * The ACPI specification wants us to save NVS memory regions during hibernation + * and to restore them during the subsequent resume. However, it is not certain + * if this mechanism is going to work on all machines, so we allow the user to + * disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line + * option. + */ +static bool s4_no_nvs; + +void __init acpi_s4_no_nvs(void) +{ + s4_no_nvs = true; +} /** * acpi_pm_disable_gpes - Disable the GPEs. */ static int acpi_pm_disable_gpes(void) { - acpi_hw_disable_all_gpes(); + acpi_disable_all_gpes(); return 0; } @@ -135,7 +148,7 @@ static int acpi_pm_prepare(void) int error = __acpi_pm_prepare(); if (!error) - acpi_hw_disable_all_gpes(); + acpi_disable_all_gpes(); return error; } @@ -267,7 +280,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) * (like wakeup GPE) haven't handler, this can avoid such GPE misfire. * acpi_leave_sleep_state will reenable specific GPEs later */ - acpi_hw_disable_all_gpes(); + acpi_disable_all_gpes(); local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); @@ -394,9 +407,25 @@ void __init acpi_no_s4_hw_signature(void) static int acpi_hibernation_begin(void) { - acpi_target_sleep_state = ACPI_STATE_S4; - acpi_sleep_tts_switch(acpi_target_sleep_state); - return 0; + int error; + + error = s4_no_nvs ? 0 : hibernate_nvs_alloc(); + if (!error) { + acpi_target_sleep_state = ACPI_STATE_S4; + acpi_sleep_tts_switch(acpi_target_sleep_state); + } + + return error; +} + +static int acpi_hibernation_pre_snapshot(void) +{ + int error = acpi_pm_prepare(); + + if (!error) + hibernate_nvs_save(); + + return error; } static int acpi_hibernation_enter(void) @@ -417,6 +446,12 @@ static int acpi_hibernation_enter(void) return ACPI_SUCCESS(status) ? 0 : -EFAULT; } +static void acpi_hibernation_finish(void) +{ + hibernate_nvs_free(); + acpi_pm_finish(); +} + static void acpi_hibernation_leave(void) { /* @@ -432,18 +467,20 @@ static void acpi_hibernation_leave(void) "cannot resume!\n"); panic("ACPI S4 hardware signature mismatch"); } + /* Restore the NVS memory area */ + hibernate_nvs_restore(); } static void acpi_pm_enable_gpes(void) { - acpi_hw_enable_all_runtime_gpes(); + acpi_enable_all_runtime_gpes(); } static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_prepare, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave, @@ -469,8 +506,22 @@ static int acpi_hibernation_begin_old(void) error = acpi_sleep_prepare(ACPI_STATE_S4); + if (!error) { + if (!s4_no_nvs) + error = hibernate_nvs_alloc(); + if (!error) + acpi_target_sleep_state = ACPI_STATE_S4; + } + return error; +} + +static int acpi_hibernation_pre_snapshot_old(void) +{ + int error = acpi_pm_disable_gpes(); + if (!error) - acpi_target_sleep_state = ACPI_STATE_S4; + hibernate_nvs_save(); + return error; } @@ -481,8 +532,8 @@ static int acpi_hibernation_begin_old(void) static struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_disable_gpes, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot_old, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_disable_gpes, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave, @@ -622,7 +673,7 @@ static void acpi_power_off_prepare(void) { /* Prepare to power off the system */ acpi_sleep_prepare(ACPI_STATE_S5); - acpi_hw_disable_all_gpes(); + acpi_disable_all_gpes(); } static void acpi_power_off(void) @@ -671,7 +722,7 @@ int __init acpi_sleep_init(void) sleep_states[ACPI_STATE_S4] = 1; printk(" S4"); if (!nosigcheck) { - acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, + acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs); if (facs) s4_hardware_signature = diff --git a/drivers/acpi/namespace/Makefile b/drivers/acpi/namespace/Makefile deleted file mode 100644 index 371a2daf837f..000000000000 --- a/drivers/acpi/namespace/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-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 - -obj-$(ACPI_FUTURE_USAGE) += nsdumpdv.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 25ceae9191ef..c5e292aab0e3 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -29,7 +29,6 @@ #include <linux/errno.h> #include <linux/acpi.h> #include <acpi/acpi_bus.h> -#include <acpi/acmacros.h> #define ACPI_NUMA 0x80000000 #define _COMPONENT ACPI_NUMA diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c8111424dcb8..6729a4992f2b 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -726,7 +726,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC); if (!dpc) - return_ACPI_STATUS(AE_NO_MEMORY); + return AE_NO_MEMORY; dpc->function = function; dpc->context = context; @@ -747,7 +747,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, status = AE_ERROR; kfree(dpc); } - return_ACPI_STATUS(status); + return status; } acpi_status acpi_os_execute(acpi_execute_type type, diff --git a/drivers/acpi/parser/Makefile b/drivers/acpi/parser/Makefile deleted file mode 100644 index db24ee09cf11..000000000000 --- a/drivers/acpi/parser/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := psargs.o psparse.o psloop.o pstree.o pswalk.o \ - psopcode.o psscope.o psutils.o psxface.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index 4b252ea0e952..95650f83ce2e 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c @@ -99,7 +99,7 @@ acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id) */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Device %s has PCI address %02x:%02x:%02x.%02x\n", + "Device %s has PCI address %04x:%02x:%02x.%d\n", acpi_device_bid(device), id->segment, id->bus, id->device, id->function)); @@ -111,12 +111,11 @@ EXPORT_SYMBOL(acpi_get_pci_id); int acpi_pci_bind(struct acpi_device *device) { int result = 0; - acpi_status status = AE_OK; - struct acpi_pci_data *data = NULL; - struct acpi_pci_data *pdata = NULL; - char *pathname = NULL; - struct acpi_buffer buffer = { 0, NULL }; - acpi_handle handle = NULL; + acpi_status status; + struct acpi_pci_data *data; + struct acpi_pci_data *pdata; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_handle handle; struct pci_dev *dev; struct pci_bus *bus; @@ -124,21 +123,18 @@ int acpi_pci_bind(struct acpi_device *device) if (!device || !device->parent) return -EINVAL; - pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); - if (!pathname) - return -ENOMEM; - buffer.length = ACPI_PATHNAME_MAX; - buffer.pointer = pathname; - data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); - if (!data) { - kfree(pathname); + if (!data) return -ENOMEM; + + status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); + if (ACPI_FAILURE(status)) { + kfree(data); + return -ENODEV; } - acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n", - pathname)); + (char *)buffer.pointer)); /* * Segment & Bus @@ -166,7 +162,7 @@ int acpi_pci_bind(struct acpi_device *device) data->id.device = device->pnp.bus_address >> 16; data->id.function = device->pnp.bus_address & 0xFFFF; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %02x:%02x:%02x.%02x\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %04x:%02x:%02x.%d\n", data->id.segment, data->id.bus, data->id.device, data->id.function)); @@ -196,7 +192,7 @@ int acpi_pci_bind(struct acpi_device *device) } if (!data->dev) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Device %02x:%02x:%02x.%02x not present in PCI namespace\n", + "Device %04x:%02x:%02x.%d not present in PCI namespace\n", data->id.segment, data->id.bus, data->id.device, data->id.function)); result = -ENODEV; @@ -204,7 +200,7 @@ int acpi_pci_bind(struct acpi_device *device) } if (!data->dev->bus) { printk(KERN_ERR PREFIX - "Device %02x:%02x:%02x.%02x has invalid 'bus' field\n", + "Device %04x:%02x:%02x.%d has invalid 'bus' field\n", data->id.segment, data->id.bus, data->id.device, data->id.function); result = -ENODEV; @@ -219,7 +215,7 @@ int acpi_pci_bind(struct acpi_device *device) */ if (data->dev->subordinate) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Device %02x:%02x:%02x.%02x is a PCI bridge\n", + "Device %04x:%02x:%02x.%d is a PCI bridge\n", data->id.segment, data->id.bus, data->id.device, data->id.function)); data->bus = data->dev->subordinate; @@ -262,7 +258,7 @@ int acpi_pci_bind(struct acpi_device *device) } end: - kfree(pathname); + kfree(buffer.pointer); if (result) kfree(data); @@ -272,25 +268,21 @@ int acpi_pci_bind(struct acpi_device *device) static int acpi_pci_unbind(struct acpi_device *device) { int result = 0; - acpi_status status = AE_OK; - struct acpi_pci_data *data = NULL; - char *pathname = NULL; - struct acpi_buffer buffer = { 0, NULL }; + acpi_status status; + struct acpi_pci_data *data; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; if (!device || !device->parent) return -EINVAL; - pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); - if (!pathname) - return -ENOMEM; + status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); + if (ACPI_FAILURE(status)) + return -ENODEV; - buffer.length = ACPI_PATHNAME_MAX; - buffer.pointer = pathname; - acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n", - pathname)); - kfree(pathname); + (char *) buffer.pointer)); + kfree(buffer.pointer); status = acpi_get_data(device->handle, acpi_pci_data_handler, @@ -322,50 +314,44 @@ acpi_pci_bind_root(struct acpi_device *device, struct acpi_pci_id *id, struct pci_bus *bus) { int result = 0; - acpi_status status = AE_OK; + acpi_status status; struct acpi_pci_data *data = NULL; - char *pathname = NULL; - struct acpi_buffer buffer = { 0, NULL }; - - pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); - if (!pathname) - return -ENOMEM; - - buffer.length = ACPI_PATHNAME_MAX; - buffer.pointer = pathname; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; if (!device || !id || !bus) { - kfree(pathname); return -EINVAL; } data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); - if (!data) { - kfree(pathname); + if (!data) return -ENOMEM; - } data->id = *id; data->bus = bus; device->ops.bind = acpi_pci_bind; device->ops.unbind = acpi_pci_unbind; - acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); + status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); + if (ACPI_FAILURE(status)) { + kfree (data); + return -ENODEV; + } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI root bridge [%s] to " - "%02x:%02x\n", pathname, id->segment, id->bus)); + "%04x:%02x\n", (char *)buffer.pointer, + id->segment, id->bus)); status = acpi_attach_data(device->handle, acpi_pci_data_handler, data); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to attach ACPI-PCI context to device %s", - pathname)); + (char *)buffer.pointer)); result = -ENODEV; goto end; } end: - kfree(pathname); + kfree(buffer.pointer); if (result != 0) kfree(data); diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index bf79d83bdfbb..891bdf6679f3 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -4,6 +4,8 @@ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> * Copyright (C) 2002 Dominik Brodowski <devel@brodo.de> + * (c) Copyright 2008 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas <bjorn.helgaas@hp.com> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -41,29 +43,36 @@ #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME("pci_irq"); -static struct acpi_prt_list acpi_prt; +struct acpi_prt_entry { + struct list_head list; + struct acpi_pci_id id; + u8 pin; + acpi_handle link; + u32 index; /* GSI, or link _CRS index */ +}; + +static LIST_HEAD(acpi_prt_list); static DEFINE_SPINLOCK(acpi_prt_lock); +static inline char pin_name(int pin) +{ + return 'A' + pin - 1; +} + /* -------------------------------------------------------------------------- PCI IRQ Routing Table (PRT) Support -------------------------------------------------------------------------- */ -static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment, - int bus, - int device, int pin) +static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(struct pci_dev *dev, + int pin) { - struct acpi_prt_entry *entry = NULL; - - if (!acpi_prt.count) - return NULL; + struct acpi_prt_entry *entry; + int segment = pci_domain_nr(dev->bus); + int bus = dev->bus->number; + int device = PCI_SLOT(dev->devfn); - /* - * Parse through all PRT entries looking for a match on the specified - * PCI device's segment, bus, device, and pin (don't care about func). - * - */ spin_lock(&acpi_prt_lock); - list_for_each_entry(entry, &acpi_prt.entries, node) { + list_for_each_entry(entry, &acpi_prt_list, list) { if ((segment == entry->id.segment) && (bus == entry->id.bus) && (device == entry->id.device) @@ -72,7 +81,6 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment, return entry; } } - spin_unlock(&acpi_prt_lock); return NULL; } @@ -124,25 +132,27 @@ struct prt_quirk { char *actual_source; }; +#define PCI_INTX_PIN(c) (c - 'A' + 1) + /* * These systems have incorrect _PRT entries. The BIOS claims the PCI * interrupt at the listed segment/bus/device/pin is connected to the first * link device, but it is actually connected to the second. */ static struct prt_quirk prt_quirks[] = { - { medion_md9580, 0, 0, 9, 'A', + { medion_md9580, 0, 0, 9, PCI_INTX_PIN('A'), "\\_SB_.PCI0.ISA_.LNKA", "\\_SB_.PCI0.ISA_.LNKB"}, - { dell_optiplex, 0, 0, 0xd, 'A', + { dell_optiplex, 0, 0, 0xd, PCI_INTX_PIN('A'), "\\_SB_.LNKB", "\\_SB_.LNKA"}, - { hp_t5710, 0, 0, 1, 'A', + { hp_t5710, 0, 0, 1, PCI_INTX_PIN('A'), "\\_SB_.PCI0.LNK1", "\\_SB_.PCI0.LNK3"}, }; -static void -do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt) +static void do_prt_fixups(struct acpi_prt_entry *entry, + struct acpi_pci_routing_table *prt) { int i; struct prt_quirk *quirk; @@ -158,42 +168,43 @@ do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt) entry->id.segment == quirk->segment && entry->id.bus == quirk->bus && entry->id.device == quirk->device && - entry->pin + 'A' == quirk->pin && + entry->pin == quirk->pin && !strcmp(prt->source, quirk->source) && strlen(prt->source) >= strlen(quirk->actual_source)) { printk(KERN_WARNING PREFIX "firmware reports " "%04x:%02x:%02x PCI INT %c connected to %s; " "changing to %s\n", entry->id.segment, entry->id.bus, - entry->id.device, 'A' + entry->pin, + entry->id.device, pin_name(entry->pin), prt->source, quirk->actual_source); strcpy(prt->source, quirk->actual_source); } } } -static int -acpi_pci_irq_add_entry(acpi_handle handle, - int segment, int bus, struct acpi_pci_routing_table *prt) +static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, + struct acpi_pci_routing_table *prt) { - struct acpi_prt_entry *entry = NULL; - - - if (!prt) - return -EINVAL; + struct acpi_prt_entry *entry; entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL); if (!entry) return -ENOMEM; + /* + * Note that the _PRT uses 0=INTA, 1=INTB, etc, while PCI uses + * 1=INTA, 2=INTB. We use the PCI encoding throughout, so convert + * it here. + */ entry->id.segment = segment; entry->id.bus = bus; entry->id.device = (prt->address >> 16) & 0xFFFF; - entry->id.function = prt->address & 0xFFFF; - entry->pin = prt->pin; + entry->pin = prt->pin + 1; do_prt_fixups(entry, prt); + entry->index = prt->source_index; + /* * Type 1: Dynamic * --------------- @@ -207,10 +218,9 @@ acpi_pci_irq_add_entry(acpi_handle handle, * (e.g. exists somewhere 'below' this _PRT entry in the ACPI * namespace). */ - if (prt->source[0]) { - acpi_get_handle(handle, prt->source, &entry->link.handle); - entry->link.index = prt->source_index; - } + if (prt->source[0]) + acpi_get_handle(handle, prt->source, &entry->link); + /* * Type 2: Static * -------------- @@ -218,84 +228,38 @@ acpi_pci_irq_add_entry(acpi_handle handle, * the IRQ value, which is hardwired to specific interrupt inputs on * the interrupt controller. */ - else - entry->link.index = prt->source_index; ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO, - " %02X:%02X:%02X[%c] -> %s[%d]\n", + " %04x:%02x:%02x[%c] -> %s[%d]\n", entry->id.segment, entry->id.bus, - entry->id.device, ('A' + entry->pin), prt->source, - entry->link.index)); + entry->id.device, pin_name(entry->pin), + prt->source, entry->index)); spin_lock(&acpi_prt_lock); - list_add_tail(&entry->node, &acpi_prt.entries); - acpi_prt.count++; + list_add_tail(&entry->list, &acpi_prt_list); spin_unlock(&acpi_prt_lock); return 0; } -static void -acpi_pci_irq_del_entry(int segment, int bus, struct acpi_prt_entry *entry) -{ - if (segment == entry->id.segment && bus == entry->id.bus) { - acpi_prt.count--; - list_del(&entry->node); - kfree(entry); - } -} - int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) { - acpi_status status = AE_OK; - char *pathname = NULL; - struct acpi_buffer buffer = { 0, NULL }; - struct acpi_pci_routing_table *prt = NULL; - struct acpi_pci_routing_table *entry = NULL; - static int first_time = 1; - - - pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); - if (!pathname) - return -ENOMEM; - - if (first_time) { - acpi_prt.count = 0; - INIT_LIST_HEAD(&acpi_prt.entries); - first_time = 0; - } - - /* - * NOTE: We're given a 'handle' to the _PRT object's parent device - * (either a PCI root bridge or PCI-PCI bridge). - */ + acpi_status status; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_pci_routing_table *entry; - buffer.length = ACPI_PATHNAME_MAX; - buffer.pointer = pathname; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + /* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */ + status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + if (ACPI_FAILURE(status)) + return -ENODEV; printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n", - pathname); + (char *) buffer.pointer); - /* - * Evaluate this _PRT and add its entries to our global list (acpi_prt). - */ + kfree(buffer.pointer); - buffer.length = 0; + buffer.length = ACPI_ALLOCATE_BUFFER; buffer.pointer = NULL; - kfree(pathname); - status = acpi_get_irq_routing_table(handle, &buffer); - if (status != AE_BUFFER_OVERFLOW) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]", - acpi_format_exception(status))); - return -ENODEV; - } - - prt = kzalloc(buffer.length, GFP_KERNEL); - if (!prt) { - return -ENOMEM; - } - buffer.pointer = prt; status = acpi_get_irq_routing_table(handle, &buffer); if (ACPI_FAILURE(status)) { @@ -305,36 +269,30 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) return -ENODEV; } - entry = prt; - + entry = buffer.pointer; while (entry && (entry->length > 0)) { acpi_pci_irq_add_entry(handle, segment, bus, entry); entry = (struct acpi_pci_routing_table *) ((unsigned long)entry + entry->length); } - kfree(prt); - + kfree(buffer.pointer); return 0; } void acpi_pci_irq_del_prt(int segment, int bus) { - struct list_head *node = NULL, *n = NULL; - struct acpi_prt_entry *entry = NULL; - - if (!acpi_prt.count) { - return; - } + struct acpi_prt_entry *entry, *tmp; printk(KERN_DEBUG - "ACPI: Delete PCI Interrupt Routing Table for %x:%x\n", segment, - bus); + "ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n", + segment, bus); spin_lock(&acpi_prt_lock); - list_for_each_safe(node, n, &acpi_prt.entries) { - entry = list_entry(node, struct acpi_prt_entry, node); - - acpi_pci_irq_del_entry(segment, bus, entry); + list_for_each_entry_safe(entry, tmp, &acpi_prt_list, list) { + if (segment == entry->id.segment && bus == entry->id.bus) { + list_del(&entry->list); + kfree(entry); + } } spin_unlock(&acpi_prt_lock); } @@ -342,162 +300,26 @@ void acpi_pci_irq_del_prt(int segment, int bus) /* -------------------------------------------------------------------------- PCI Interrupt Routing Support -------------------------------------------------------------------------- */ -typedef int (*irq_lookup_func) (struct acpi_prt_entry *, int *, int *, char **); - -static int -acpi_pci_allocate_irq(struct acpi_prt_entry *entry, - int *triggering, int *polarity, char **link) -{ - int irq; - - - if (entry->link.handle) { - irq = acpi_pci_link_allocate_irq(entry->link.handle, - entry->link.index, triggering, - polarity, link); - if (irq < 0) { - printk(KERN_WARNING PREFIX - "Invalid IRQ link routing entry\n"); - return -1; - } - } else { - irq = entry->link.index; - *triggering = ACPI_LEVEL_SENSITIVE; - *polarity = ACPI_ACTIVE_LOW; - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq)); - return irq; -} - -static int -acpi_pci_free_irq(struct acpi_prt_entry *entry, - int *triggering, int *polarity, char **link) -{ - int irq; - - if (entry->link.handle) { - irq = acpi_pci_link_free_irq(entry->link.handle); - } else { - irq = entry->link.index; - } - return irq; -} - -#ifdef CONFIG_X86_IO_APIC -extern int noioapicquirk; - -static int bridge_has_boot_interrupt_variant(struct pci_bus *bus) +static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) { - struct pci_bus *bus_it; - - for (bus_it = bus ; bus_it ; bus_it = bus_it->parent) { - if (!bus_it->self) - return 0; - - printk(KERN_INFO "vendor=%04x device=%04x\n", bus_it->self->vendor, - bus_it->self->device); - - if (bus_it->self->irq_reroute_variant) - return bus_it->self->irq_reroute_variant; - } - return 0; -} -#endif /* CONFIG_X86_IO_APIC */ - -/* - * acpi_pci_irq_lookup - * success: return IRQ >= 0 - * failure: return -1 - */ -static int -acpi_pci_irq_lookup(struct pci_bus *bus, - int device, - int pin, - int *triggering, - int *polarity, char **link, irq_lookup_func func) -{ - struct acpi_prt_entry *entry = NULL; - int segment = pci_domain_nr(bus); - int bus_nr = bus->number; - int ret; - - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Searching for PRT entry for %02x:%02x:%02x[%c]\n", - segment, bus_nr, device, ('A' + pin))); - - entry = acpi_pci_irq_find_prt_entry(segment, bus_nr, device, pin); - if (!entry) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PRT entry not found\n")); - return -1; - } - - ret = func(entry, triggering, polarity, link); - -#ifdef CONFIG_X86_IO_APIC - /* - * Some chipsets (e.g. intel 6700PXH) generate a legacy INTx when the - * IRQ entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel - * does during interrupt handling). When this INTx generation cannot be - * disabled, we reroute these interrupts to their legacy equivalent to - * get rid of spurious interrupts. - */ - if (!noioapicquirk) { - switch (bridge_has_boot_interrupt_variant(bus)) { - case 0: - /* no rerouting necessary */ - break; - - case INTEL_IRQ_REROUTE_VARIANT: - /* - * Remap according to INTx routing table in 6700PXH - * specs, intel order number 302628-002, section - * 2.15.2. Other chipsets (80332, ...) have the same - * mapping and are handled here as well. - */ - printk(KERN_INFO "pci irq %d -> rerouted to legacy " - "irq %d\n", ret, (ret % 4) + 16); - ret = (ret % 4) + 16; - break; - - default: - printk(KERN_INFO "not rerouting irq %d to legacy irq: " - "unknown mapping\n", ret); - break; - } + struct acpi_prt_entry *entry; + struct pci_dev *bridge; + u8 bridge_pin, orig_pin = pin; + + entry = acpi_pci_irq_find_prt_entry(dev, pin); + if (entry) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s[%c] _PRT entry\n", + pci_name(dev), pin_name(pin))); + return entry; } -#endif /* CONFIG_X86_IO_APIC */ - - return ret; -} - -/* - * acpi_pci_irq_derive - * success: return IRQ >= 0 - * failure: return < 0 - */ -static int -acpi_pci_irq_derive(struct pci_dev *dev, - int pin, - int *triggering, - int *polarity, char **link, irq_lookup_func func) -{ - struct pci_dev *bridge = dev; - int irq = -1; - u8 bridge_pin = 0, orig_pin = pin; - - - if (!dev) - return -EINVAL; /* * Attempt to derive an IRQ for this device from a parent bridge's * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge). */ - while (irq < 0 && bridge->bus->self) { - pin = (pin + PCI_SLOT(bridge->devfn)) % 4; - bridge = bridge->bus->self; + bridge = dev->bus->self; + while (bridge) { + pin = (((pin - 1) + PCI_SLOT(dev->devfn)) % 4) + 1; if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) { /* PC card has the same IRQ as its cardbridge */ @@ -506,50 +328,40 @@ acpi_pci_irq_derive(struct pci_dev *dev, ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No interrupt pin configured for device %s\n", pci_name(bridge))); - return -1; + return NULL; } - /* Pin is from 0 to 3 */ - bridge_pin--; pin = bridge_pin; } - irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn), - pin, triggering, polarity, - link, func); - } + entry = acpi_pci_irq_find_prt_entry(bridge, pin); + if (entry) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Derived GSI for %s INT %c from %s\n", + pci_name(dev), pin_name(orig_pin), + pci_name(bridge))); + return entry; + } - if (irq < 0) { - dev_warn(&dev->dev, "can't derive routing for PCI INT %c\n", - 'A' + orig_pin); - return -1; + dev = bridge; + bridge = dev->bus->self; } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derive IRQ %d for device %s from %s\n", - irq, pci_name(dev), pci_name(bridge))); - - return irq; + dev_warn(&dev->dev, "can't derive routing for PCI INT %c\n", + pin_name(orig_pin)); + return NULL; } -/* - * acpi_pci_irq_enable - * success: return 0 - * failure: return < 0 - */ - int acpi_pci_irq_enable(struct pci_dev *dev) { - int irq = 0; - u8 pin = 0; + struct acpi_prt_entry *entry; + int gsi; + u8 pin; int triggering = ACPI_LEVEL_SENSITIVE; int polarity = ACPI_ACTIVE_LOW; char *link = NULL; char link_desc[16]; int rc; - - if (!dev) - return -EINVAL; - pin = dev->pin; if (!pin) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -557,31 +369,9 @@ int acpi_pci_irq_enable(struct pci_dev *dev) pci_name(dev))); return 0; } - pin--; - - if (!dev->bus) { - dev_err(&dev->dev, "invalid (NULL) 'bus' field\n"); - return -ENODEV; - } - - /* - * First we check the PCI IRQ routing table (PRT) for an IRQ. PRT - * values override any BIOS-assigned IRQs set during boot. - */ - irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, - &triggering, &polarity, &link, - acpi_pci_allocate_irq); - - /* - * If no PRT entry was found, we'll try to derive an IRQ from the - * device's parent bridge. - */ - if (irq < 0) - irq = acpi_pci_irq_derive(dev, pin, &triggering, - &polarity, &link, - acpi_pci_allocate_irq); - if (irq < 0) { + entry = acpi_pci_irq_lookup(dev, pin); + if (!entry) { /* * IDE legacy mode controller IRQs are magic. Why do compat * extensions always make such a nasty mess. @@ -590,12 +380,24 @@ int acpi_pci_irq_enable(struct pci_dev *dev) (dev->class & 0x05) == 0) return 0; } + + if (entry) { + if (entry->link) + gsi = acpi_pci_link_allocate_irq(entry->link, + entry->index, + &triggering, &polarity, + &link); + else + gsi = entry->index; + } else + gsi = -1; + /* * No IRQ known to the ACPI subsystem - maybe the BIOS / * driver reported one, then use it. Exit in any case. */ - if (irq < 0) { - dev_warn(&dev->dev, "PCI INT %c: no GSI", 'A' + pin); + if (gsi < 0) { + dev_warn(&dev->dev, "PCI INT %c: no GSI", pin_name(pin)); /* Interrupt Line values above 0xF are forbidden */ if (dev->irq > 0 && (dev->irq <= 0xF)) { printk(" - using IRQ %d\n", dev->irq); @@ -608,10 +410,10 @@ int acpi_pci_irq_enable(struct pci_dev *dev) } } - rc = acpi_register_gsi(irq, triggering, polarity); + rc = acpi_register_gsi(gsi, triggering, polarity); if (rc < 0) { dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n", - 'A' + pin); + pin_name(pin)); return rc; } dev->irq = rc; @@ -622,7 +424,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) link_desc[0] = '\0'; dev_info(&dev->dev, "PCI INT %c%s -> GSI %u (%s, %s) -> IRQ %d\n", - 'A' + pin, link_desc, irq, + pin_name(pin), link_desc, gsi, (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge", (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq); @@ -636,42 +438,28 @@ void __attribute__ ((weak)) acpi_unregister_gsi(u32 i) void acpi_pci_irq_disable(struct pci_dev *dev) { - int gsi = 0; - u8 pin = 0; - int triggering = ACPI_LEVEL_SENSITIVE; - int polarity = ACPI_ACTIVE_LOW; - - - if (!dev || !dev->bus) - return; + struct acpi_prt_entry *entry; + int gsi; + u8 pin; pin = dev->pin; if (!pin) return; - pin--; - /* - * First we check the PCI IRQ routing table (PRT) for an IRQ. - */ - gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, - &triggering, &polarity, NULL, - acpi_pci_free_irq); - /* - * If no PRT entry was found, we'll try to derive an IRQ from the - * device's parent bridge. - */ - if (gsi < 0) - gsi = acpi_pci_irq_derive(dev, pin, - &triggering, &polarity, NULL, - acpi_pci_free_irq); - if (gsi < 0) + entry = acpi_pci_irq_lookup(dev, pin); + if (!entry) return; + if (entry->link) + gsi = acpi_pci_link_free_irq(entry->link); + else + gsi = entry->index; + /* * TBD: It might be worth clearing dev->irq by magic constant * (e.g. PCI_UNDEFINED_IRQ). */ - dev_info(&dev->dev, "PCI INT %c disabled\n", 'A' + pin); + dev_info(&dev->dev, "PCI INT %c disabled\n", pin_name(pin)); acpi_unregister_gsi(gsi); } diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index e52ad91ce2dc..1c6e73c7865e 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -796,10 +796,6 @@ static int irqrouter_resume(struct sys_device *dev) struct list_head *node = NULL; struct acpi_pci_link *link = NULL; - - /* Make sure SCI is enabled again (Apple firmware bug?) */ - acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1); - list_for_each(node, &acpi_link.entries) { link = list_entry(node, struct acpi_pci_link, node); if (!link) { @@ -912,7 +908,7 @@ static int __init acpi_irq_nobalance_set(char *str) __setup("acpi_irq_nobalance", acpi_irq_nobalance_set); -int __init acpi_irq_balance_set(char *str) +static int __init acpi_irq_balance_set(char *str) { acpi_irq_balance = 1; return 1; diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index bb7d50dd2818..c926e7d4a0d6 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -139,6 +139,8 @@ static int acpi_power_get_state(acpi_handle handle, int *state) { acpi_status status = AE_OK; unsigned long long sta = 0; + char node_name[5]; + struct acpi_buffer buffer = { sizeof(node_name), node_name }; if (!handle || !state) @@ -151,8 +153,10 @@ static int acpi_power_get_state(acpi_handle handle, int *state) *state = (sta & 0x01)?ACPI_POWER_RESOURCE_STATE_ON: ACPI_POWER_RESOURCE_STATE_OFF; + acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n", - acpi_ut_get_node_name(handle), + node_name, *state ? "on" : "off")); return 0; diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/proc.c index 4dbc2271acf5..428c911dba08 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/proc.c @@ -28,8 +28,6 @@ static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset) { int i; - ACPI_FUNCTION_TRACE("acpi_system_sleep_seq_show"); - for (i = 0; i <= ACPI_STATE_S5; i++) { if (sleep_states[i]) { seq_printf(seq, "S%d ", i); @@ -86,49 +84,44 @@ acpi_system_write_sleep(struct file *file, #ifdef HAVE_ACPI_LEGACY_ALARM +static u32 cmos_bcd_read(int offset, int rtc_control); + static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) { u32 sec, min, hr; u32 day, mo, yr, cent = 0; + u32 today = 0; unsigned char rtc_control = 0; unsigned long flags; - ACPI_FUNCTION_TRACE("acpi_system_alarm_seq_show"); - spin_lock_irqsave(&rtc_lock, flags); - sec = CMOS_READ(RTC_SECONDS_ALARM); - min = CMOS_READ(RTC_MINUTES_ALARM); - hr = CMOS_READ(RTC_HOURS_ALARM); rtc_control = CMOS_READ(RTC_CONTROL); + sec = cmos_bcd_read(RTC_SECONDS_ALARM, rtc_control); + min = cmos_bcd_read(RTC_MINUTES_ALARM, rtc_control); + hr = cmos_bcd_read(RTC_HOURS_ALARM, rtc_control); /* If we ever get an FACP with proper values... */ - if (acpi_gbl_FADT.day_alarm) + if (acpi_gbl_FADT.day_alarm) { /* ACPI spec: only low 6 its should be cared */ day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F; - else - day = CMOS_READ(RTC_DAY_OF_MONTH); + if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + day = bcd2bin(day); + } else + day = cmos_bcd_read(RTC_DAY_OF_MONTH, rtc_control); if (acpi_gbl_FADT.month_alarm) - mo = CMOS_READ(acpi_gbl_FADT.month_alarm); - else - mo = CMOS_READ(RTC_MONTH); + mo = cmos_bcd_read(acpi_gbl_FADT.month_alarm, rtc_control); + else { + mo = cmos_bcd_read(RTC_MONTH, rtc_control); + today = cmos_bcd_read(RTC_DAY_OF_MONTH, rtc_control); + } if (acpi_gbl_FADT.century) - cent = CMOS_READ(acpi_gbl_FADT.century); + cent = cmos_bcd_read(acpi_gbl_FADT.century, rtc_control); - yr = CMOS_READ(RTC_YEAR); + yr = cmos_bcd_read(RTC_YEAR, rtc_control); spin_unlock_irqrestore(&rtc_lock, flags); - if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - sec = bcd2bin(sec); - min = bcd2bin(min); - hr = bcd2bin(hr); - day = bcd2bin(day); - mo = bcd2bin(mo); - yr = bcd2bin(yr); - cent = bcd2bin(cent); - } - /* we're trusting the FADT (see above) */ if (!acpi_gbl_FADT.century) /* If we're not trusting the FADT, we should at least make it @@ -153,6 +146,20 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) else yr += cent * 100; + /* + * Show correct dates for alarms up to a month into the future. + * This solves issues for nearly all situations with the common + * 30-day alarm clocks in PC hardware. + */ + if (day < today) { + if (mo < 12) { + mo += 1; + } else { + mo = 1; + yr += 1; + } + } + seq_printf(seq, "%4.4u-", yr); (mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo); (day > 31) ? seq_puts(seq, "** ") : seq_printf(seq, "%2.2u ", day); @@ -227,13 +234,11 @@ acpi_system_write_alarm(struct file *file, int adjust = 0; unsigned char rtc_control = 0; - ACPI_FUNCTION_TRACE("acpi_system_write_alarm"); - if (count > sizeof(alarm_string) - 1) - return_VALUE(-EINVAL); + return -EINVAL; if (copy_from_user(alarm_string, buffer, count)) - return_VALUE(-EFAULT); + return -EFAULT; alarm_string[count] = '\0'; @@ -334,7 +339,7 @@ acpi_system_write_alarm(struct file *file, result = 0; end: - return_VALUE(result ? result : count); + return result ? result : count; } #endif /* HAVE_ACPI_LEGACY_ALARM */ diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c index a6b662c00b67..93f91142d7ad 100644 --- a/drivers/acpi/reboot.c +++ b/drivers/acpi/reboot.c @@ -42,7 +42,7 @@ void acpi_reboot(void) case ACPI_ADR_SPACE_SYSTEM_MEMORY: case ACPI_ADR_SPACE_SYSTEM_IO: printk(KERN_DEBUG "ACPI MEMORY or I/O RESET_REG.\n"); - acpi_hw_low_level_write(8, reset_value, rr); + acpi_reset(); break; } /* Wait ten seconds */ diff --git a/drivers/acpi/resources/Makefile b/drivers/acpi/resources/Makefile deleted file mode 100644 index 8de4f69dfa09..000000000000 --- a/drivers/acpi/resources/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := rsaddr.o rscreate.o rsinfo.o rsio.o rslist.o rsmisc.o rsxface.o \ - rscalc.o rsirq.o rsmemory.o rsutils.o - -obj-$(ACPI_FUTURE_USAGE) += rsdump.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index e53e590252c0..0619734895b2 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -10,7 +10,6 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> -#include <acpi/actypes.h> #include <linux/wait.h> #include <linux/delay.h> #include <linux/interrupt.h> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 39b7233c3485..c54d7b6c4066 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -10,7 +10,6 @@ #include <linux/kthread.h> #include <acpi/acpi_drivers.h> -#include <acpi/acinterp.h> /* for acpi_ex_eisa_id_to_string() */ #define _COMPONENT ACPI_BUS_COMPONENT ACPI_MODULE_NAME("scan"); diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep.h index cfaf8f5b0a14..cfaf8f5b0a14 100644 --- a/drivers/acpi/sleep/sleep.h +++ b/drivers/acpi/sleep.h diff --git a/drivers/acpi/sleep/Makefile b/drivers/acpi/sleep/Makefile deleted file mode 100644 index f1fb888c2d29..000000000000 --- a/drivers/acpi/sleep/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -obj-y := wakeup.o -obj-y += main.o -obj-$(CONFIG_ACPI_SLEEP) += proc.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 6e4107f82403..391d0358a592 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -192,65 +192,6 @@ static struct attribute_group interrupt_stats_attr_group = { }; static struct kobj_attribute *counter_attrs; -static int count_num_gpes(void) -{ - int count = 0; - struct acpi_gpe_xrupt_info *gpe_xrupt_info; - struct acpi_gpe_block_info *gpe_block; - acpi_cpu_flags flags; - - flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); - - gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; - while (gpe_xrupt_info) { - gpe_block = gpe_xrupt_info->gpe_block_list_head; - while (gpe_block) { - count += gpe_block->register_count * - ACPI_GPE_REGISTER_WIDTH; - gpe_block = gpe_block->next; - } - gpe_xrupt_info = gpe_xrupt_info->next; - } - acpi_os_release_lock(acpi_gbl_gpe_lock, flags); - - return count; -} - -static int get_gpe_device(int index, acpi_handle *handle) -{ - struct acpi_gpe_xrupt_info *gpe_xrupt_info; - struct acpi_gpe_block_info *gpe_block; - acpi_cpu_flags flags; - struct acpi_namespace_node *node; - - flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); - - gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; - while (gpe_xrupt_info) { - gpe_block = gpe_xrupt_info->gpe_block_list_head; - node = gpe_block->node; - while (gpe_block) { - index -= gpe_block->register_count * - ACPI_GPE_REGISTER_WIDTH; - if (index < 0) { - acpi_os_release_lock(acpi_gbl_gpe_lock, flags); - /* return NULL if it's FADT GPE */ - if (node->type != ACPI_TYPE_DEVICE) - *handle = NULL; - else - *handle = node; - return 0; - } - node = gpe_block->node; - gpe_block = gpe_block->next; - } - gpe_xrupt_info = gpe_xrupt_info->next; - } - acpi_os_release_lock(acpi_gbl_gpe_lock, flags); - - return -ENODEV; -} - static void delete_gpe_attr_array(void) { struct event_counter *tmp = all_counters; @@ -309,7 +250,7 @@ static int get_status(u32 index, acpi_event_status *status, acpi_handle *handle) goto end; if (index < num_gpes) { - result = get_gpe_device(index, handle); + result = acpi_get_gpe_device(index, handle); if (result) { ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND, "Invalid GPE 0x%x\n", index)); @@ -436,7 +377,7 @@ void acpi_irq_stats_init(void) if (all_counters) return; - num_gpes = count_num_gpes(); + num_gpes = acpi_current_gpe_count; num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA; all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1), diff --git a/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile deleted file mode 100644 index 7385efa61622..000000000000 --- a/drivers/acpi/tables/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/utilities/Makefile b/drivers/acpi/utilities/Makefile deleted file mode 100644 index 88eff14c4894..000000000000 --- a/drivers/acpi/utilities/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-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 utcache.o utresrc.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c deleted file mode 100644 index 245fa80cf600..000000000000 --- a/drivers/acpi/utilities/utcache.c +++ /dev/null @@ -1,314 +0,0 @@ -/****************************************************************************** - * - * Module Name: utcache - local cache allocation routines - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2008, 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> - -#define _COMPONENT ACPI_UTILITIES -ACPI_MODULE_NAME("utcache") -#ifdef ACPI_USE_LOCAL_CACHE -/******************************************************************************* - * - * FUNCTION: acpi_os_create_cache - * - * PARAMETERS: cache_name - Ascii name for the cache - * object_size - Size of each cached object - * max_depth - Maximum depth of the cache (in objects) - * return_cache - Where the new cache object is returned - * - * RETURN: Status - * - * DESCRIPTION: Create a cache object - * - ******************************************************************************/ -acpi_status -acpi_os_create_cache(char *cache_name, - u16 object_size, - u16 max_depth, struct acpi_memory_list ** return_cache) -{ - struct acpi_memory_list *cache; - - ACPI_FUNCTION_ENTRY(); - - if (!cache_name || !return_cache || (object_size < 16)) { - return (AE_BAD_PARAMETER); - } - - /* Create the cache object */ - - cache = acpi_os_allocate(sizeof(struct acpi_memory_list)); - if (!cache) { - return (AE_NO_MEMORY); - } - - /* Populate the cache object and return it */ - - ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list)); - cache->link_offset = 8; - cache->list_name = cache_name; - cache->object_size = object_size; - cache->max_depth = max_depth; - - *return_cache = cache; - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_os_purge_cache - * - * PARAMETERS: Cache - Handle to cache object - * - * RETURN: Status - * - * DESCRIPTION: Free all objects within the requested cache. - * - ******************************************************************************/ - -acpi_status acpi_os_purge_cache(struct acpi_memory_list * cache) -{ - char *next; - - ACPI_FUNCTION_ENTRY(); - - if (!cache) { - return (AE_BAD_PARAMETER); - } - - /* Walk the list of objects in this cache */ - - while (cache->list_head) { - - /* Delete and unlink one cached state object */ - - next = *(ACPI_CAST_INDIRECT_PTR(char, - &(((char *)cache-> - list_head)[cache-> - link_offset]))); - ACPI_FREE(cache->list_head); - - cache->list_head = next; - cache->current_depth--; - } - - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_os_delete_cache - * - * PARAMETERS: Cache - Handle to cache object - * - * RETURN: Status - * - * DESCRIPTION: Free all objects within the requested cache and delete the - * cache object. - * - ******************************************************************************/ - -acpi_status acpi_os_delete_cache(struct acpi_memory_list * cache) -{ - acpi_status status; - - ACPI_FUNCTION_ENTRY(); - - /* Purge all objects in the cache */ - - status = acpi_os_purge_cache(cache); - if (ACPI_FAILURE(status)) { - return (status); - } - - /* Now we can delete the cache object */ - - ACPI_FREE(cache); - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_os_release_object - * - * PARAMETERS: Cache - Handle to cache object - * Object - The object to be released - * - * RETURN: None - * - * DESCRIPTION: Release an object to the specified cache. If cache is full, - * the object is deleted. - * - ******************************************************************************/ - -acpi_status -acpi_os_release_object(struct acpi_memory_list * cache, void *object) -{ - acpi_status status; - - ACPI_FUNCTION_ENTRY(); - - if (!cache || !object) { - return (AE_BAD_PARAMETER); - } - - /* If cache is full, just free this object */ - - if (cache->current_depth >= cache->max_depth) { - ACPI_FREE(object); - ACPI_MEM_TRACKING(cache->total_freed++); - } - - /* Otherwise put this object back into the cache */ - - else { - status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); - if (ACPI_FAILURE(status)) { - return (status); - } - - /* Mark the object as cached */ - - ACPI_MEMSET(object, 0xCA, cache->object_size); - ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_CACHED); - - /* Put the object at the head of the cache list */ - - *(ACPI_CAST_INDIRECT_PTR(char, - &(((char *)object)[cache-> - link_offset]))) = - cache->list_head; - cache->list_head = object; - cache->current_depth++; - - (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); - } - - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_os_acquire_object - * - * PARAMETERS: Cache - Handle to cache object - * - * RETURN: the acquired object. NULL on error - * - * DESCRIPTION: Get an object from the specified cache. If cache is empty, - * the object is allocated. - * - ******************************************************************************/ - -void *acpi_os_acquire_object(struct acpi_memory_list *cache) -{ - acpi_status status; - void *object; - - ACPI_FUNCTION_NAME(os_acquire_object); - - if (!cache) { - return (NULL); - } - - status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); - if (ACPI_FAILURE(status)) { - return (NULL); - } - - ACPI_MEM_TRACKING(cache->requests++); - - /* Check the cache first */ - - if (cache->list_head) { - - /* There is an object available, use it */ - - object = cache->list_head; - cache->list_head = *(ACPI_CAST_INDIRECT_PTR(char, - &(((char *) - object)[cache-> - link_offset]))); - - cache->current_depth--; - - ACPI_MEM_TRACKING(cache->hits++); - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Object %p from %s cache\n", object, - cache->list_name)); - - status = acpi_ut_release_mutex(ACPI_MTX_CACHES); - if (ACPI_FAILURE(status)) { - return (NULL); - } - - /* Clear (zero) the previously used Object */ - - ACPI_MEMSET(object, 0, cache->object_size); - } else { - /* The cache is empty, create a new object */ - - ACPI_MEM_TRACKING(cache->total_allocated++); - -#ifdef ACPI_DBG_TRACK_ALLOCATIONS - if ((cache->total_allocated - cache->total_freed) > - cache->max_occupied) { - cache->max_occupied = - cache->total_allocated - cache->total_freed; - } -#endif - - /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */ - - status = acpi_ut_release_mutex(ACPI_MTX_CACHES); - if (ACPI_FAILURE(status)) { - return (NULL); - } - - object = ACPI_ALLOCATE_ZEROED(cache->object_size); - if (!object) { - return (NULL); - } - } - - return (object); -} -#endif /* ACPI_USE_LOCAL_CACHE */ diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index baa441929720..f261737636da 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -36,6 +36,7 @@ #include <linux/backlight.h> #include <linux/thermal.h> #include <linux/video_output.h> +#include <linux/sort.h> #include <asm/uaccess.h> #include <acpi/acpi_bus.h> @@ -481,6 +482,7 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) int status = AE_OK; union acpi_object arg0 = { ACPI_TYPE_INTEGER }; struct acpi_object_list args = { 1, &arg0 }; + int state; arg0.integer.value = level; @@ -489,6 +491,10 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) status = acpi_evaluate_object(device->dev->handle, "_BCM", &args, NULL); device->brightness->curr = level; + for (state = 2; state < device->brightness->count; state++) + if (level == device->brightness->levels[state]) + device->backlight->props.brightness = state - 2; + return status; } @@ -626,6 +632,16 @@ acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag) } /* + * Simple comparison function used to sort backlight levels. + */ + +static int +acpi_video_cmp_level(const void *a, const void *b) +{ + return *(int *)a - *(int *)b; +} + +/* * Arg: * device : video output device (LCD, CRT, ..) * @@ -676,6 +692,10 @@ acpi_video_init_brightness(struct acpi_video_device *device) count++; } + /* don't sort the first two brightness levels */ + sort(&br->levels[2], count - 2, sizeof(br->levels[2]), + acpi_video_cmp_level, NULL); + if (count < 2) goto out_free_levels; diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index f022eb6f5637..50e3d2dbf3af 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -234,7 +234,7 @@ EXPORT_SYMBOL(acpi_video_display_switch_support); * To force that backlight or display output switching is processed by vendor * specific acpi drivers or video.ko driver. */ -int __init acpi_backlight(char *str) +static int __init acpi_backlight(char *str) { if (str == NULL || *str == '\0') return 1; @@ -250,7 +250,7 @@ int __init acpi_backlight(char *str) } __setup("acpi_backlight=", acpi_backlight); -int __init acpi_display_output(char *str) +static int __init acpi_display_output(char *str) { if (str == NULL || *str == '\0') return 1; diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/wakeup.c index dea4c23df764..2d34806d45dd 100644 --- a/drivers/acpi/sleep/wakeup.c +++ b/drivers/acpi/wakeup.c @@ -8,7 +8,6 @@ #include <acpi/acpi_drivers.h> #include <linux/kernel.h> #include <linux/types.h> -#include <acpi/acevents.h> #include "sleep.h" #define _COMPONENT ACPI_SYSTEM_COMPONENT @@ -28,8 +27,6 @@ void acpi_enable_wakeup_device_prep(u8 sleep_state) { struct list_head *node, *next; - ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device_prep"); - spin_lock(&acpi_device_lock); list_for_each_safe(node, next, &acpi_wakeup_device_list) { struct acpi_device *dev = container_of(node, @@ -61,7 +58,6 @@ void acpi_enable_wakeup_device(u8 sleep_state) * Caution: this routine must be invoked when interrupt is disabled * Refer ACPI2.0: P212 */ - ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device"); spin_lock(&acpi_device_lock); list_for_each_safe(node, next, &acpi_wakeup_device_list) { struct acpi_device *dev = @@ -103,8 +99,6 @@ void acpi_disable_wakeup_device(u8 sleep_state) { struct list_head *node, *next; - ACPI_FUNCTION_TRACE("acpi_disable_wakeup_device"); - spin_lock(&acpi_device_lock); list_for_each_safe(node, next, &acpi_wakeup_device_list) { struct acpi_device *dev = diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index ef02e488d468..6273d98d00eb 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -19,12 +19,6 @@ #include "libata.h" #include <acpi/acpi_bus.h> -#include <acpi/acnames.h> -#include <acpi/acnamesp.h> -#include <acpi/acparser.h> -#include <acpi/acexcep.h> -#include <acpi/acmacros.h> -#include <acpi/actypes.h> enum { ATA_ACPI_FILTER_SETXFER = 1 << 0, diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 175df54eb664..c507a9ac78f4 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4556,7 +4556,7 @@ void ata_sg_clean(struct ata_queued_cmd *qc) struct scatterlist *sg = qc->sg; int dir = qc->dma_dir; - WARN_ON(sg == NULL); + WARN_ON_ONCE(sg == NULL); VPRINTK("unmapping %u sg elements\n", qc->n_elem); @@ -4776,7 +4776,7 @@ void ata_qc_free(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; unsigned int tag; - WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ + WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ qc->flags = 0; tag = qc->tag; @@ -4791,8 +4791,8 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; struct ata_link *link = qc->dev->link; - WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ - WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE)); + WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ + WARN_ON_ONCE(!(qc->flags & ATA_QCFLAG_ACTIVE)); if (likely(qc->flags & ATA_QCFLAG_DMAMAP)) ata_sg_clean(qc); @@ -4878,7 +4878,7 @@ 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(ap->pflags & ATA_PFLAG_FROZEN); + WARN_ON_ONCE(ap->pflags & ATA_PFLAG_FROZEN); if (unlikely(qc->err_mask)) qc->flags |= ATA_QCFLAG_FAILED; @@ -5000,16 +5000,16 @@ void ata_qc_issue(struct ata_queued_cmd *qc) * check is skipped for old EH because it reuses active qc to * request ATAPI sense. */ - WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag)); + WARN_ON_ONCE(ap->ops->error_handler && ata_tag_valid(link->active_tag)); if (ata_is_ncq(prot)) { - WARN_ON(link->sactive & (1 << qc->tag)); + WARN_ON_ONCE(link->sactive & (1 << qc->tag)); if (!link->sactive) ap->nr_active_links++; link->sactive |= 1 << qc->tag; } else { - WARN_ON(link->sactive); + WARN_ON_ONCE(link->sactive); ap->nr_active_links++; link->active_tag = qc->tag; diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index c59ad76c84b1..0eae9b453556 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -578,7 +578,7 @@ void ata_sff_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - WARN_ON(!ioaddr->ctl_addr); + WARN_ON_ONCE(!ioaddr->ctl_addr); iowrite8(tf->hob_feature, ioaddr->feature_addr); iowrite8(tf->hob_nsect, ioaddr->nsect_addr); iowrite8(tf->hob_lbal, ioaddr->lbal_addr); @@ -651,7 +651,7 @@ void ata_sff_tf_read(struct ata_port *ap, struct ata_taskfile *tf) iowrite8(tf->ctl, ioaddr->ctl_addr); ap->last_ctl = tf->ctl; } else - WARN_ON(1); + WARN_ON_ONCE(1); } } EXPORT_SYMBOL_GPL(ata_sff_tf_read); @@ -891,7 +891,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc) /* READ/WRITE MULTIPLE */ unsigned int nsect; - WARN_ON(qc->dev->multi_count == 0); + WARN_ON_ONCE(qc->dev->multi_count == 0); nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size, qc->dev->multi_count); @@ -918,7 +918,7 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) { /* send SCSI cdb */ DPRINTK("send cdb\n"); - WARN_ON(qc->dev->cdb_len < 12); + WARN_ON_ONCE(qc->dev->cdb_len < 12); ap->ops->sff_data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1); ata_sff_sync(ap); @@ -1014,7 +1014,7 @@ next_sg: } /* consumed can be larger than count only for the last transfer */ - WARN_ON(qc->cursg && count != consumed); + WARN_ON_ONCE(qc->cursg && count != consumed); if (bytes) goto next_sg; @@ -1172,13 +1172,13 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, unsigned long flags = 0; int poll_next; - WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0); + WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0); /* Make sure ata_sff_qc_issue() does not throw things * like DMA polling into the workqueue. Notice that * in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING). */ - WARN_ON(in_wq != ata_hsm_ok_in_wq(ap, qc)); + WARN_ON_ONCE(in_wq != ata_hsm_ok_in_wq(ap, qc)); fsm_start: DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n", @@ -1387,7 +1387,7 @@ fsm_start: DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n", ap->print_id, qc->dev->devno, status); - WARN_ON(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM)); + WARN_ON_ONCE(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM)); ap->hsm_task_state = HSM_ST_IDLE; @@ -1423,7 +1423,7 @@ void ata_pio_task(struct work_struct *work) int poll_next; fsm_start: - WARN_ON(ap->hsm_task_state == HSM_ST_IDLE); + WARN_ON_ONCE(ap->hsm_task_state == HSM_ST_IDLE); /* * This is purely heuristic. This is a fast path. @@ -1512,7 +1512,7 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) break; case ATA_PROT_DMA: - WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING); + WARN_ON_ONCE(qc->tf.flags & ATA_TFLAG_POLLING); ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */ ap->ops->bmdma_setup(qc); /* set up bmdma */ @@ -1564,7 +1564,7 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) break; case ATAPI_PROT_DMA: - WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING); + WARN_ON_ONCE(qc->tf.flags & ATA_TFLAG_POLLING); ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */ ap->ops->bmdma_setup(qc); /* set up bmdma */ @@ -1576,7 +1576,7 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) break; default: - WARN_ON(1); + WARN_ON_ONCE(1); return AC_ERR_SYSTEM; } diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c index e2e332d8ff95..8b77a9802df1 100644 --- a/drivers/ata/pata_acpi.c +++ b/drivers/ata/pata_acpi.c @@ -13,12 +13,6 @@ #include <linux/device.h> #include <scsi/scsi_host.h> #include <acpi/acpi_bus.h> -#include <acpi/acnames.h> -#include <acpi/acnamesp.h> -#include <acpi/acparser.h> -#include <acpi/acexcep.h> -#include <acpi/acmacros.h> -#include <acpi/actypes.h> #include <linux/libata.h> #include <linux/ata.h> diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c index 68f052b42ed7..ed306eb1057f 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_bios.c @@ -23,8 +23,6 @@ #include <linux/security.h> #include <linux/module.h> #include <acpi/acpi.h> -#include <acpi/actypes.h> -#include <acpi/actbl.h> #include "tpm.h" #define TCG_EVENT_NAME_LEN_MAX 255 diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 8d7cf3f31450..f1df59f59a37 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -15,12 +15,14 @@ #include <linux/tick.h> #define BREAK_FUZZ 4 /* 4 us */ +#define PRED_HISTORY_PCT 50 struct menu_device { int last_state_idx; unsigned int expected_us; unsigned int predicted_us; + unsigned int current_predicted_us; unsigned int last_measured_us; unsigned int elapsed_us; }; @@ -47,6 +49,12 @@ static int menu_select(struct cpuidle_device *dev) data->expected_us = (u32) ktime_to_ns(tick_nohz_get_sleep_length()) / 1000; + /* 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++) { struct cpuidle_state *s = &dev->states[i]; @@ -97,7 +105,7 @@ static void menu_reflect(struct cpuidle_device *dev) measured_us = -1; /* Predict time until next break event */ - data->predicted_us = max(measured_us, data->last_measured_us); + data->current_predicted_us = max(measured_us, data->last_measured_us); if (last_idle_us + BREAK_FUZZ < data->expected_us - target->exit_latency) { diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c index d883e1b8bb8c..55433849bfa6 100644 --- a/drivers/dca/dca-core.c +++ b/drivers/dca/dca-core.c @@ -270,6 +270,6 @@ static void __exit dca_exit(void) dca_sysfs_exit(); } -subsys_initcall(dca_init); +arch_initcall(dca_init); module_exit(dca_exit); diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 904e57558bb5..e34b06420816 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -33,7 +33,6 @@ config INTEL_IOATDMA config INTEL_IOP_ADMA tristate "Intel IOP ADMA support" depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX - select ASYNC_CORE select DMA_ENGINE help Enable support for the Intel(R) IOP Series RAID engines. @@ -59,7 +58,6 @@ config FSL_DMA config MV_XOR bool "Marvell XOR engine support" depends on PLAT_ORION - select ASYNC_CORE select DMA_ENGINE ---help--- Enable support for the Marvell XOR engine. diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 657996517374..403dbe781122 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -31,32 +31,18 @@ * * LOCKING: * - * The subsystem keeps two global lists, dma_device_list and dma_client_list. - * Both of these are protected by a mutex, dma_list_mutex. + * The subsystem keeps a global list of dma_device structs it is protected by a + * mutex, dma_list_mutex. + * + * A subsystem can get access to a channel by calling dmaengine_get() followed + * by dma_find_channel(), or if it has need for an exclusive channel it can call + * dma_request_channel(). Once a channel is allocated a reference is taken + * against its corresponding driver to disable removal. * * Each device has a channels list, which runs unlocked but is never modified * once the device is registered, it's just setup by the driver. * - * Each client is responsible for keeping track of the channels it uses. See - * the definition of dma_event_callback in dmaengine.h. - * - * Each device has a kref, which is initialized to 1 when the device is - * registered. A kref_get is done for each device registered. When the - * device is released, the corresponding kref_put is done in the release - * method. Every time one of the device's channels is allocated to a client, - * a kref_get occurs. When the channel is freed, the corresponding kref_put - * happens. The device's release function does a completion, so - * unregister_device does a remove event, device_unregister, a kref_put - * for the first reference, then waits on the completion for all other - * references to finish. - * - * Each channel has an open-coded implementation of Rusty Russell's "bigref," - * with a kref and a per_cpu local_t. A dma_chan_get is called when a client - * signals that it wants to use a channel, and dma_chan_put is called when - * a channel is removed or a client using it is unregistered. A client can - * take extra references per outstanding transaction, as is the case with - * the NET DMA client. The release function does a kref_put on the device. - * -ChrisL, DanW + * See Documentation/dmaengine.txt for more details */ #include <linux/init.h> @@ -70,54 +56,85 @@ #include <linux/rcupdate.h> #include <linux/mutex.h> #include <linux/jiffies.h> +#include <linux/rculist.h> +#include <linux/idr.h> static DEFINE_MUTEX(dma_list_mutex); static LIST_HEAD(dma_device_list); -static LIST_HEAD(dma_client_list); +static long dmaengine_ref_count; +static struct idr dma_idr; /* --- sysfs implementation --- */ +/** + * dev_to_dma_chan - convert a device pointer to the its sysfs container object + * @dev - device node + * + * Must be called under dma_list_mutex + */ +static struct dma_chan *dev_to_dma_chan(struct device *dev) +{ + struct dma_chan_dev *chan_dev; + + chan_dev = container_of(dev, typeof(*chan_dev), device); + return chan_dev->chan; +} + static ssize_t show_memcpy_count(struct device *dev, struct device_attribute *attr, char *buf) { - struct dma_chan *chan = to_dma_chan(dev); + struct dma_chan *chan; unsigned long count = 0; int i; + int err; - for_each_possible_cpu(i) - count += per_cpu_ptr(chan->local, i)->memcpy_count; + mutex_lock(&dma_list_mutex); + chan = dev_to_dma_chan(dev); + if (chan) { + for_each_possible_cpu(i) + count += per_cpu_ptr(chan->local, i)->memcpy_count; + err = sprintf(buf, "%lu\n", count); + } else + err = -ENODEV; + mutex_unlock(&dma_list_mutex); - return sprintf(buf, "%lu\n", count); + return err; } static ssize_t show_bytes_transferred(struct device *dev, struct device_attribute *attr, char *buf) { - struct dma_chan *chan = to_dma_chan(dev); + struct dma_chan *chan; unsigned long count = 0; int i; + int err; - for_each_possible_cpu(i) - count += per_cpu_ptr(chan->local, i)->bytes_transferred; + mutex_lock(&dma_list_mutex); + chan = dev_to_dma_chan(dev); + if (chan) { + for_each_possible_cpu(i) + count += per_cpu_ptr(chan->local, i)->bytes_transferred; + err = sprintf(buf, "%lu\n", count); + } else + err = -ENODEV; + mutex_unlock(&dma_list_mutex); - return sprintf(buf, "%lu\n", count); + return err; } static ssize_t show_in_use(struct device *dev, struct device_attribute *attr, char *buf) { - struct dma_chan *chan = to_dma_chan(dev); - int in_use = 0; - - if (unlikely(chan->slow_ref) && - atomic_read(&chan->refcount.refcount) > 1) - in_use = 1; - else { - if (local_read(&(per_cpu_ptr(chan->local, - get_cpu())->refcount)) > 0) - in_use = 1; - put_cpu(); - } + struct dma_chan *chan; + int err; - return sprintf(buf, "%d\n", in_use); + mutex_lock(&dma_list_mutex); + chan = dev_to_dma_chan(dev); + if (chan) + err = sprintf(buf, "%d\n", chan->client_count); + else + err = -ENODEV; + mutex_unlock(&dma_list_mutex); + + return err; } static struct device_attribute dma_attrs[] = { @@ -127,76 +144,110 @@ static struct device_attribute dma_attrs[] = { __ATTR_NULL }; -static void dma_async_device_cleanup(struct kref *kref); - -static void dma_dev_release(struct device *dev) +static void chan_dev_release(struct device *dev) { - struct dma_chan *chan = to_dma_chan(dev); - kref_put(&chan->device->refcount, dma_async_device_cleanup); + struct dma_chan_dev *chan_dev; + + chan_dev = container_of(dev, typeof(*chan_dev), device); + if (atomic_dec_and_test(chan_dev->idr_ref)) { + mutex_lock(&dma_list_mutex); + idr_remove(&dma_idr, chan_dev->dev_id); + mutex_unlock(&dma_list_mutex); + kfree(chan_dev->idr_ref); + } + kfree(chan_dev); } static struct class dma_devclass = { .name = "dma", .dev_attrs = dma_attrs, - .dev_release = dma_dev_release, + .dev_release = chan_dev_release, }; /* --- client and device registration --- */ -#define dma_chan_satisfies_mask(chan, mask) \ - __dma_chan_satisfies_mask((chan), &(mask)) +#define dma_device_satisfies_mask(device, mask) \ + __dma_device_satisfies_mask((device), &(mask)) static int -__dma_chan_satisfies_mask(struct dma_chan *chan, dma_cap_mask_t *want) +__dma_device_satisfies_mask(struct dma_device *device, dma_cap_mask_t *want) { dma_cap_mask_t has; - bitmap_and(has.bits, want->bits, chan->device->cap_mask.bits, + bitmap_and(has.bits, want->bits, device->cap_mask.bits, DMA_TX_TYPE_END); return bitmap_equal(want->bits, has.bits, DMA_TX_TYPE_END); } +static struct module *dma_chan_to_owner(struct dma_chan *chan) +{ + return chan->device->dev->driver->owner; +} + /** - * dma_client_chan_alloc - try to allocate channels to a client - * @client: &dma_client + * balance_ref_count - catch up the channel reference count + * @chan - channel to balance ->client_count versus dmaengine_ref_count * - * Called with dma_list_mutex held. + * balance_ref_count must be called under dma_list_mutex */ -static void dma_client_chan_alloc(struct dma_client *client) +static void balance_ref_count(struct dma_chan *chan) { - struct dma_device *device; - struct dma_chan *chan; - int desc; /* allocated descriptor count */ - enum dma_state_client ack; + struct module *owner = dma_chan_to_owner(chan); - /* Find a channel */ - list_for_each_entry(device, &dma_device_list, global_node) { - /* Does the client require a specific DMA controller? */ - if (client->slave && client->slave->dma_dev - && client->slave->dma_dev != device->dev) - continue; + while (chan->client_count < dmaengine_ref_count) { + __module_get(owner); + chan->client_count++; + } +} - list_for_each_entry(chan, &device->channels, device_node) { - if (!dma_chan_satisfies_mask(chan, client->cap_mask)) - continue; +/** + * dma_chan_get - try to grab a dma channel's parent driver module + * @chan - channel to grab + * + * Must be called under dma_list_mutex + */ +static int dma_chan_get(struct dma_chan *chan) +{ + int err = -ENODEV; + struct module *owner = dma_chan_to_owner(chan); + + if (chan->client_count) { + __module_get(owner); + err = 0; + } else if (try_module_get(owner)) + err = 0; + + if (err == 0) + chan->client_count++; + + /* allocate upon first client reference */ + if (chan->client_count == 1 && err == 0) { + int desc_cnt = chan->device->device_alloc_chan_resources(chan); + + if (desc_cnt < 0) { + err = desc_cnt; + chan->client_count = 0; + module_put(owner); + } else if (!dma_has_cap(DMA_PRIVATE, chan->device->cap_mask)) + balance_ref_count(chan); + } - desc = chan->device->device_alloc_chan_resources( - chan, client); - if (desc >= 0) { - ack = client->event_callback(client, - chan, - DMA_RESOURCE_AVAILABLE); + return err; +} - /* we are done once this client rejects - * an available resource - */ - if (ack == DMA_ACK) { - dma_chan_get(chan); - chan->client_count++; - } else if (ack == DMA_NAK) - return; - } - } - } +/** + * dma_chan_put - drop a reference to a dma channel's parent driver module + * @chan - channel to release + * + * Must be called under dma_list_mutex + */ +static void dma_chan_put(struct dma_chan *chan) +{ + if (!chan->client_count) + return; /* this channel failed alloc_chan_resources */ + chan->client_count--; + module_put(dma_chan_to_owner(chan)); + if (chan->client_count == 0) + chan->device->device_free_chan_resources(chan); } enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie) @@ -218,138 +269,342 @@ enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie) EXPORT_SYMBOL(dma_sync_wait); /** - * dma_chan_cleanup - release a DMA channel's resources - * @kref: kernel reference structure that contains the DMA channel device + * dma_cap_mask_all - enable iteration over all operation types + */ +static dma_cap_mask_t dma_cap_mask_all; + +/** + * dma_chan_tbl_ent - tracks channel allocations per core/operation + * @chan - associated channel for this entry + */ +struct dma_chan_tbl_ent { + struct dma_chan *chan; +}; + +/** + * channel_table - percpu lookup table for memory-to-memory offload providers */ -void dma_chan_cleanup(struct kref *kref) +static struct dma_chan_tbl_ent *channel_table[DMA_TX_TYPE_END]; + +static int __init dma_channel_table_init(void) { - struct dma_chan *chan = container_of(kref, struct dma_chan, refcount); - chan->device->device_free_chan_resources(chan); - kref_put(&chan->device->refcount, dma_async_device_cleanup); + enum dma_transaction_type cap; + int err = 0; + + bitmap_fill(dma_cap_mask_all.bits, DMA_TX_TYPE_END); + + /* 'interrupt', 'private', and 'slave' are channel capabilities, + * but are not associated with an operation so they do not need + * an entry in the channel_table + */ + clear_bit(DMA_INTERRUPT, dma_cap_mask_all.bits); + clear_bit(DMA_PRIVATE, dma_cap_mask_all.bits); + clear_bit(DMA_SLAVE, dma_cap_mask_all.bits); + + for_each_dma_cap_mask(cap, dma_cap_mask_all) { + channel_table[cap] = alloc_percpu(struct dma_chan_tbl_ent); + if (!channel_table[cap]) { + err = -ENOMEM; + break; + } + } + + if (err) { + pr_err("dmaengine: initialization failure\n"); + for_each_dma_cap_mask(cap, dma_cap_mask_all) + if (channel_table[cap]) + free_percpu(channel_table[cap]); + } + + return err; } -EXPORT_SYMBOL(dma_chan_cleanup); +arch_initcall(dma_channel_table_init); -static void dma_chan_free_rcu(struct rcu_head *rcu) +/** + * dma_find_channel - find a channel to carry out the operation + * @tx_type: transaction type + */ +struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type) { - struct dma_chan *chan = container_of(rcu, struct dma_chan, rcu); - int bias = 0x7FFFFFFF; - int i; - for_each_possible_cpu(i) - bias -= local_read(&per_cpu_ptr(chan->local, i)->refcount); - atomic_sub(bias, &chan->refcount.refcount); - kref_put(&chan->refcount, dma_chan_cleanup); + struct dma_chan *chan; + int cpu; + + WARN_ONCE(dmaengine_ref_count == 0, + "client called %s without a reference", __func__); + + cpu = get_cpu(); + chan = per_cpu_ptr(channel_table[tx_type], cpu)->chan; + put_cpu(); + + return chan; } +EXPORT_SYMBOL(dma_find_channel); -static void dma_chan_release(struct dma_chan *chan) +/** + * dma_issue_pending_all - flush all pending operations across all channels + */ +void dma_issue_pending_all(void) { - atomic_add(0x7FFFFFFF, &chan->refcount.refcount); - chan->slow_ref = 1; - call_rcu(&chan->rcu, dma_chan_free_rcu); + struct dma_device *device; + struct dma_chan *chan; + + WARN_ONCE(dmaengine_ref_count == 0, + "client called %s without a reference", __func__); + + rcu_read_lock(); + list_for_each_entry_rcu(device, &dma_device_list, global_node) { + if (dma_has_cap(DMA_PRIVATE, device->cap_mask)) + continue; + list_for_each_entry(chan, &device->channels, device_node) + if (chan->client_count) + device->device_issue_pending(chan); + } + rcu_read_unlock(); } +EXPORT_SYMBOL(dma_issue_pending_all); /** - * dma_chans_notify_available - broadcast available channels to the clients + * nth_chan - returns the nth channel of the given capability + * @cap: capability to match + * @n: nth channel desired + * + * Defaults to returning the channel with the desired capability and the + * lowest reference count when 'n' cannot be satisfied. Must be called + * under dma_list_mutex. */ -static void dma_clients_notify_available(void) +static struct dma_chan *nth_chan(enum dma_transaction_type cap, int n) { - struct dma_client *client; + struct dma_device *device; + struct dma_chan *chan; + struct dma_chan *ret = NULL; + struct dma_chan *min = NULL; - mutex_lock(&dma_list_mutex); + list_for_each_entry(device, &dma_device_list, global_node) { + if (!dma_has_cap(cap, device->cap_mask) || + dma_has_cap(DMA_PRIVATE, device->cap_mask)) + continue; + list_for_each_entry(chan, &device->channels, device_node) { + if (!chan->client_count) + continue; + if (!min) + min = chan; + else if (chan->table_count < min->table_count) + min = chan; + + if (n-- == 0) { + ret = chan; + break; /* done */ + } + } + if (ret) + break; /* done */ + } - list_for_each_entry(client, &dma_client_list, global_node) - dma_client_chan_alloc(client); + if (!ret) + ret = min; - mutex_unlock(&dma_list_mutex); + if (ret) + ret->table_count++; + + return ret; } /** - * dma_chans_notify_available - tell the clients that a channel is going away - * @chan: channel on its way out + * dma_channel_rebalance - redistribute the available channels + * + * Optimize for cpu isolation (each cpu gets a dedicated channel for an + * operation type) in the SMP case, and operation isolation (avoid + * multi-tasking channels) in the non-SMP case. Must be called under + * dma_list_mutex. */ -static void dma_clients_notify_removed(struct dma_chan *chan) +static void dma_channel_rebalance(void) { - struct dma_client *client; - enum dma_state_client ack; + struct dma_chan *chan; + struct dma_device *device; + int cpu; + int cap; + int n; - mutex_lock(&dma_list_mutex); + /* undo the last distribution */ + for_each_dma_cap_mask(cap, dma_cap_mask_all) + for_each_possible_cpu(cpu) + per_cpu_ptr(channel_table[cap], cpu)->chan = NULL; + + list_for_each_entry(device, &dma_device_list, global_node) { + if (dma_has_cap(DMA_PRIVATE, device->cap_mask)) + continue; + list_for_each_entry(chan, &device->channels, device_node) + chan->table_count = 0; + } - list_for_each_entry(client, &dma_client_list, global_node) { - ack = client->event_callback(client, chan, - DMA_RESOURCE_REMOVED); + /* don't populate the channel_table if no clients are available */ + if (!dmaengine_ref_count) + return; - /* client was holding resources for this channel so - * free it - */ - if (ack == DMA_ACK) { - dma_chan_put(chan); - chan->client_count--; + /* redistribute available channels */ + n = 0; + for_each_dma_cap_mask(cap, dma_cap_mask_all) + for_each_online_cpu(cpu) { + if (num_possible_cpus() > 1) + chan = nth_chan(cap, n++); + else + chan = nth_chan(cap, -1); + + per_cpu_ptr(channel_table[cap], cpu)->chan = chan; + } +} + +static struct dma_chan *private_candidate(dma_cap_mask_t *mask, struct dma_device *dev, + dma_filter_fn fn, void *fn_param) +{ + struct dma_chan *chan; + + if (!__dma_device_satisfies_mask(dev, mask)) { + pr_debug("%s: wrong capabilities\n", __func__); + return NULL; + } + /* devices with multiple channels need special handling as we need to + * ensure that all channels are either private or public. + */ + if (dev->chancnt > 1 && !dma_has_cap(DMA_PRIVATE, dev->cap_mask)) + list_for_each_entry(chan, &dev->channels, device_node) { + /* some channels are already publicly allocated */ + if (chan->client_count) + return NULL; } + + list_for_each_entry(chan, &dev->channels, device_node) { + if (chan->client_count) { + pr_debug("%s: %s busy\n", + __func__, dma_chan_name(chan)); + continue; + } + if (fn && !fn(chan, fn_param)) { + pr_debug("%s: %s filter said false\n", + __func__, dma_chan_name(chan)); + continue; + } + return chan; } - mutex_unlock(&dma_list_mutex); + return NULL; } /** - * dma_async_client_register - register a &dma_client - * @client: ptr to a client structure with valid 'event_callback' and 'cap_mask' + * dma_request_channel - try to allocate an exclusive channel + * @mask: capabilities that the channel must satisfy + * @fn: optional callback to disposition available channels + * @fn_param: opaque parameter to pass to dma_filter_fn */ -void dma_async_client_register(struct dma_client *client) +struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param) { - /* validate client data */ - BUG_ON(dma_has_cap(DMA_SLAVE, client->cap_mask) && - !client->slave); + struct dma_device *device, *_d; + struct dma_chan *chan = NULL; + int err; + /* Find a channel */ + mutex_lock(&dma_list_mutex); + list_for_each_entry_safe(device, _d, &dma_device_list, global_node) { + chan = private_candidate(mask, device, fn, fn_param); + if (chan) { + /* Found a suitable channel, try to grab, prep, and + * return it. We first set DMA_PRIVATE to disable + * balance_ref_count as this channel will not be + * published in the general-purpose allocator + */ + dma_cap_set(DMA_PRIVATE, device->cap_mask); + err = dma_chan_get(chan); + + if (err == -ENODEV) { + pr_debug("%s: %s module removed\n", __func__, + dma_chan_name(chan)); + list_del_rcu(&device->global_node); + } else if (err) + pr_err("dmaengine: failed to get %s: (%d)\n", + dma_chan_name(chan), err); + else + break; + chan = NULL; + } + } + mutex_unlock(&dma_list_mutex); + + pr_debug("%s: %s (%s)\n", __func__, chan ? "success" : "fail", + chan ? dma_chan_name(chan) : NULL); + + return chan; +} +EXPORT_SYMBOL_GPL(__dma_request_channel); + +void dma_release_channel(struct dma_chan *chan) +{ mutex_lock(&dma_list_mutex); - list_add_tail(&client->global_node, &dma_client_list); + WARN_ONCE(chan->client_count != 1, + "chan reference count %d != 1\n", chan->client_count); + dma_chan_put(chan); mutex_unlock(&dma_list_mutex); } -EXPORT_SYMBOL(dma_async_client_register); +EXPORT_SYMBOL_GPL(dma_release_channel); /** - * dma_async_client_unregister - unregister a client and free the &dma_client - * @client: &dma_client to free - * - * Force frees any allocated DMA channels, frees the &dma_client memory + * dmaengine_get - register interest in dma_channels */ -void dma_async_client_unregister(struct dma_client *client) +void dmaengine_get(void) { - struct dma_device *device; + struct dma_device *device, *_d; struct dma_chan *chan; - enum dma_state_client ack; - - if (!client) - return; + int err; mutex_lock(&dma_list_mutex); - /* free all channels the client is holding */ - list_for_each_entry(device, &dma_device_list, global_node) - list_for_each_entry(chan, &device->channels, device_node) { - ack = client->event_callback(client, chan, - DMA_RESOURCE_REMOVED); + dmaengine_ref_count++; - if (ack == DMA_ACK) { - dma_chan_put(chan); - chan->client_count--; - } + /* try to grab channels */ + list_for_each_entry_safe(device, _d, &dma_device_list, global_node) { + if (dma_has_cap(DMA_PRIVATE, device->cap_mask)) + continue; + list_for_each_entry(chan, &device->channels, device_node) { + err = dma_chan_get(chan); + if (err == -ENODEV) { + /* module removed before we could use it */ + list_del_rcu(&device->global_node); + break; + } else if (err) + pr_err("dmaengine: failed to get %s: (%d)\n", + dma_chan_name(chan), err); } + } - list_del(&client->global_node); + /* if this is the first reference and there were channels + * waiting we need to rebalance to get those channels + * incorporated into the channel table + */ + if (dmaengine_ref_count == 1) + dma_channel_rebalance(); mutex_unlock(&dma_list_mutex); } -EXPORT_SYMBOL(dma_async_client_unregister); +EXPORT_SYMBOL(dmaengine_get); /** - * dma_async_client_chan_request - send all available channels to the - * client that satisfy the capability mask - * @client - requester + * dmaengine_put - let dma drivers be removed when ref_count == 0 */ -void dma_async_client_chan_request(struct dma_client *client) +void dmaengine_put(void) { + struct dma_device *device; + struct dma_chan *chan; + mutex_lock(&dma_list_mutex); - dma_client_chan_alloc(client); + dmaengine_ref_count--; + BUG_ON(dmaengine_ref_count < 0); + /* drop channel references */ + list_for_each_entry(device, &dma_device_list, global_node) { + if (dma_has_cap(DMA_PRIVATE, device->cap_mask)) + continue; + list_for_each_entry(chan, &device->channels, device_node) + dma_chan_put(chan); + } mutex_unlock(&dma_list_mutex); } -EXPORT_SYMBOL(dma_async_client_chan_request); +EXPORT_SYMBOL(dmaengine_put); /** * dma_async_device_register - registers DMA devices found @@ -357,9 +612,9 @@ EXPORT_SYMBOL(dma_async_client_chan_request); */ int dma_async_device_register(struct dma_device *device) { - static int id; int chancnt = 0, rc; struct dma_chan* chan; + atomic_t *idr_ref; if (!device) return -ENODEV; @@ -386,57 +641,83 @@ int dma_async_device_register(struct dma_device *device) BUG_ON(!device->device_issue_pending); BUG_ON(!device->dev); - init_completion(&device->done); - kref_init(&device->refcount); - + idr_ref = kmalloc(sizeof(*idr_ref), GFP_KERNEL); + if (!idr_ref) + return -ENOMEM; + atomic_set(idr_ref, 0); + idr_retry: + if (!idr_pre_get(&dma_idr, GFP_KERNEL)) + return -ENOMEM; mutex_lock(&dma_list_mutex); - device->dev_id = id++; + rc = idr_get_new(&dma_idr, NULL, &device->dev_id); mutex_unlock(&dma_list_mutex); + if (rc == -EAGAIN) + goto idr_retry; + else if (rc != 0) + return rc; /* represent channels in sysfs. Probably want devs too */ list_for_each_entry(chan, &device->channels, device_node) { chan->local = alloc_percpu(typeof(*chan->local)); if (chan->local == NULL) continue; + chan->dev = kzalloc(sizeof(*chan->dev), GFP_KERNEL); + if (chan->dev == NULL) { + free_percpu(chan->local); + continue; + } chan->chan_id = chancnt++; - chan->dev.class = &dma_devclass; - chan->dev.parent = device->dev; - dev_set_name(&chan->dev, "dma%dchan%d", + chan->dev->device.class = &dma_devclass; + chan->dev->device.parent = device->dev; + chan->dev->chan = chan; + chan->dev->idr_ref = idr_ref; + chan->dev->dev_id = device->dev_id; + atomic_inc(idr_ref); + dev_set_name(&chan->dev->device, "dma%dchan%d", device->dev_id, chan->chan_id); - rc = device_register(&chan->dev); + rc = device_register(&chan->dev->device); if (rc) { - chancnt--; free_percpu(chan->local); chan->local = NULL; goto err_out; } - - /* One for the channel, one of the class device */ - kref_get(&device->refcount); - kref_get(&device->refcount); - kref_init(&chan->refcount); chan->client_count = 0; - chan->slow_ref = 0; - INIT_RCU_HEAD(&chan->rcu); } + device->chancnt = chancnt; mutex_lock(&dma_list_mutex); - list_add_tail(&device->global_node, &dma_device_list); + /* take references on public channels */ + if (dmaengine_ref_count && !dma_has_cap(DMA_PRIVATE, device->cap_mask)) + list_for_each_entry(chan, &device->channels, device_node) { + /* if clients are already waiting for channels we need + * to take references on their behalf + */ + if (dma_chan_get(chan) == -ENODEV) { + /* note we can only get here for the first + * channel as the remaining channels are + * guaranteed to get a reference + */ + rc = -ENODEV; + mutex_unlock(&dma_list_mutex); + goto err_out; + } + } + list_add_tail_rcu(&device->global_node, &dma_device_list); + dma_channel_rebalance(); mutex_unlock(&dma_list_mutex); - dma_clients_notify_available(); - return 0; err_out: list_for_each_entry(chan, &device->channels, device_node) { if (chan->local == NULL) continue; - kref_put(&device->refcount, dma_async_device_cleanup); - device_unregister(&chan->dev); - chancnt--; + mutex_lock(&dma_list_mutex); + chan->dev->chan = NULL; + mutex_unlock(&dma_list_mutex); + device_unregister(&chan->dev->device); free_percpu(chan->local); } return rc; @@ -444,37 +725,30 @@ err_out: EXPORT_SYMBOL(dma_async_device_register); /** - * dma_async_device_cleanup - function called when all references are released - * @kref: kernel reference object - */ -static void dma_async_device_cleanup(struct kref *kref) -{ - struct dma_device *device; - - device = container_of(kref, struct dma_device, refcount); - complete(&device->done); -} - -/** - * dma_async_device_unregister - unregisters DMA devices + * dma_async_device_unregister - unregister a DMA device * @device: &dma_device + * + * This routine is called by dma driver exit routines, dmaengine holds module + * references to prevent it being called while channels are in use. */ void dma_async_device_unregister(struct dma_device *device) { struct dma_chan *chan; mutex_lock(&dma_list_mutex); - list_del(&device->global_node); + list_del_rcu(&device->global_node); + dma_channel_rebalance(); mutex_unlock(&dma_list_mutex); list_for_each_entry(chan, &device->channels, device_node) { - dma_clients_notify_removed(chan); - device_unregister(&chan->dev); - dma_chan_release(chan); + WARN_ONCE(chan->client_count, + "%s called while %d clients hold a reference\n", + __func__, chan->client_count); + mutex_lock(&dma_list_mutex); + chan->dev->chan = NULL; + mutex_unlock(&dma_list_mutex); + device_unregister(&chan->dev->device); } - - kref_put(&device->refcount, dma_async_device_cleanup); - wait_for_completion(&device->done); } EXPORT_SYMBOL(dma_async_device_unregister); @@ -626,10 +900,96 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx, } 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; + + 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; +} +EXPORT_SYMBOL_GPL(dma_wait_for_async_tx); + +/* dma_run_dependencies - helper routine for dma drivers to process + * (start) dependent operations on their target channel + * @tx: transaction with dependencies + */ +void dma_run_dependencies(struct dma_async_tx_descriptor *tx) +{ + struct dma_async_tx_descriptor *dep = tx->next; + struct dma_async_tx_descriptor *dep_next; + struct dma_chan *chan; + + if (!dep) + return; + + chan = dep->chan; + + /* keep submitting up until a channel switch is detected + * in that case we will be called again as a result of + * processing the interrupt from async_tx_channel_switch + */ + for (; dep; dep = dep_next) { + spin_lock_bh(&dep->lock); + dep->parent = NULL; + dep_next = dep->next; + if (dep_next && dep_next->chan == chan) + dep->next = NULL; /* ->next will be submitted */ + else + dep_next = NULL; /* submit current dep and terminate */ + spin_unlock_bh(&dep->lock); + + dep->tx_submit(dep); + } + + chan->device->device_issue_pending(chan); +} +EXPORT_SYMBOL_GPL(dma_run_dependencies); + static int __init dma_bus_init(void) { + idr_init(&dma_idr); mutex_init(&dma_list_mutex); return class_register(&dma_devclass); } -subsys_initcall(dma_bus_init); +arch_initcall(dma_bus_init); + diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index ed9636bfb54a..3603f1ea5b28 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -35,7 +35,7 @@ MODULE_PARM_DESC(threads_per_chan, static unsigned int max_channels; module_param(max_channels, uint, S_IRUGO); -MODULE_PARM_DESC(nr_channels, +MODULE_PARM_DESC(max_channels, "Maximum number of channels to use (default: all)"); /* @@ -71,7 +71,7 @@ struct dmatest_chan { /* * These are protected by dma_list_mutex since they're only used by - * the DMA client event callback + * the DMA filter function callback */ static LIST_HEAD(dmatest_channels); static unsigned int nr_channels; @@ -80,7 +80,7 @@ static bool dmatest_match_channel(struct dma_chan *chan) { if (test_channel[0] == '\0') return true; - return strcmp(dev_name(&chan->dev), test_channel) == 0; + return strcmp(dma_chan_name(chan), test_channel) == 0; } static bool dmatest_match_device(struct dma_device *device) @@ -215,7 +215,6 @@ static int dmatest_func(void *data) smp_rmb(); chan = thread->chan; - dma_chan_get(chan); while (!kthread_should_stop()) { total_tests++; @@ -293,7 +292,6 @@ static int dmatest_func(void *data) } ret = 0; - dma_chan_put(chan); kfree(thread->dstbuf); err_dstbuf: kfree(thread->srcbuf); @@ -319,21 +317,16 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc) kfree(dtc); } -static enum dma_state_client dmatest_add_channel(struct dma_chan *chan) +static int dmatest_add_channel(struct dma_chan *chan) { struct dmatest_chan *dtc; struct dmatest_thread *thread; unsigned int i; - /* Have we already been told about this channel? */ - list_for_each_entry(dtc, &dmatest_channels, node) - if (dtc->chan == chan) - return DMA_DUP; - dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL); if (!dtc) { - pr_warning("dmatest: No memory for %s\n", dev_name(&chan->dev)); - return DMA_NAK; + pr_warning("dmatest: No memory for %s\n", dma_chan_name(chan)); + return -ENOMEM; } dtc->chan = chan; @@ -343,16 +336,16 @@ static enum dma_state_client dmatest_add_channel(struct dma_chan *chan) thread = kzalloc(sizeof(struct dmatest_thread), GFP_KERNEL); if (!thread) { pr_warning("dmatest: No memory for %s-test%u\n", - dev_name(&chan->dev), i); + dma_chan_name(chan), i); break; } thread->chan = dtc->chan; smp_wmb(); thread->task = kthread_run(dmatest_func, thread, "%s-test%u", - dev_name(&chan->dev), i); + dma_chan_name(chan), i); if (IS_ERR(thread->task)) { pr_warning("dmatest: Failed to run thread %s-test%u\n", - dev_name(&chan->dev), i); + dma_chan_name(chan), i); kfree(thread); break; } @@ -362,86 +355,62 @@ static enum dma_state_client dmatest_add_channel(struct dma_chan *chan) list_add_tail(&thread->node, &dtc->threads); } - pr_info("dmatest: Started %u threads using %s\n", i, dev_name(&chan->dev)); + pr_info("dmatest: Started %u threads using %s\n", i, dma_chan_name(chan)); list_add_tail(&dtc->node, &dmatest_channels); nr_channels++; - return DMA_ACK; -} - -static enum dma_state_client dmatest_remove_channel(struct dma_chan *chan) -{ - struct dmatest_chan *dtc, *_dtc; - - list_for_each_entry_safe(dtc, _dtc, &dmatest_channels, node) { - if (dtc->chan == chan) { - list_del(&dtc->node); - dmatest_cleanup_channel(dtc); - pr_debug("dmatest: lost channel %s\n", - dev_name(&chan->dev)); - return DMA_ACK; - } - } - - return DMA_DUP; + return 0; } -/* - * Start testing threads as new channels are assigned to us, and kill - * them when the channels go away. - * - * When we unregister the client, all channels are removed so this - * will also take care of cleaning things up when the module is - * unloaded. - */ -static enum dma_state_client -dmatest_event(struct dma_client *client, struct dma_chan *chan, - enum dma_state state) +static bool filter(struct dma_chan *chan, void *param) { - enum dma_state_client ack = DMA_NAK; - - switch (state) { - case DMA_RESOURCE_AVAILABLE: - if (!dmatest_match_channel(chan) - || !dmatest_match_device(chan->device)) - ack = DMA_DUP; - else if (max_channels && nr_channels >= max_channels) - ack = DMA_NAK; - else - ack = dmatest_add_channel(chan); - break; - - case DMA_RESOURCE_REMOVED: - ack = dmatest_remove_channel(chan); - break; - - default: - pr_info("dmatest: Unhandled event %u (%s)\n", - state, dev_name(&chan->dev)); - break; - } - - return ack; + if (!dmatest_match_channel(chan) || !dmatest_match_device(chan->device)) + return false; + else + return true; } -static struct dma_client dmatest_client = { - .event_callback = dmatest_event, -}; - static int __init dmatest_init(void) { - dma_cap_set(DMA_MEMCPY, dmatest_client.cap_mask); - dma_async_client_register(&dmatest_client); - dma_async_client_chan_request(&dmatest_client); + dma_cap_mask_t mask; + struct dma_chan *chan; + int err = 0; + + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + for (;;) { + chan = dma_request_channel(mask, filter, NULL); + if (chan) { + err = dmatest_add_channel(chan); + if (err == 0) + continue; + else { + dma_release_channel(chan); + break; /* add_channel failed, punt */ + } + } else + break; /* no more channels available */ + if (max_channels && nr_channels >= max_channels) + break; /* we have all we need */ + } - return 0; + return err; } -module_init(dmatest_init); +/* when compiled-in wait for drivers to load first */ +late_initcall(dmatest_init); static void __exit dmatest_exit(void) { - dma_async_client_unregister(&dmatest_client); + struct dmatest_chan *dtc, *_dtc; + + list_for_each_entry_safe(dtc, _dtc, &dmatest_channels, node) { + list_del(&dtc->node); + dmatest_cleanup_channel(dtc); + pr_debug("dmatest: dropped channel %s\n", + dma_chan_name(dtc->chan)); + dma_release_channel(dtc->chan); + } } module_exit(dmatest_exit); diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 0778d99aea7c..6b702cc46b3d 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -70,6 +70,15 @@ * the controller, though. */ +static struct device *chan2dev(struct dma_chan *chan) +{ + return &chan->dev->device; +} +static struct device *chan2parent(struct dma_chan *chan) +{ + return chan->dev->device.parent; +} + static struct dw_desc *dwc_first_active(struct dw_dma_chan *dwc) { return list_entry(dwc->active_list.next, struct dw_desc, desc_node); @@ -93,12 +102,12 @@ static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc) ret = desc; break; } - dev_dbg(&dwc->chan.dev, "desc %p not ACKed\n", desc); + dev_dbg(chan2dev(&dwc->chan), "desc %p not ACKed\n", desc); i++; } spin_unlock_bh(&dwc->lock); - dev_vdbg(&dwc->chan.dev, "scanned %u descriptors on freelist\n", i); + dev_vdbg(chan2dev(&dwc->chan), "scanned %u descriptors on freelist\n", i); return ret; } @@ -108,10 +117,10 @@ 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) - dma_sync_single_for_cpu(dwc->chan.dev.parent, + dma_sync_single_for_cpu(chan2parent(&dwc->chan), child->txd.phys, sizeof(child->lli), DMA_TO_DEVICE); - dma_sync_single_for_cpu(dwc->chan.dev.parent, + dma_sync_single_for_cpu(chan2parent(&dwc->chan), desc->txd.phys, sizeof(desc->lli), DMA_TO_DEVICE); } @@ -129,11 +138,11 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc) spin_lock_bh(&dwc->lock); list_for_each_entry(child, &desc->txd.tx_list, desc_node) - dev_vdbg(&dwc->chan.dev, + dev_vdbg(chan2dev(&dwc->chan), "moving child desc %p to freelist\n", child); list_splice_init(&desc->txd.tx_list, &dwc->free_list); - dev_vdbg(&dwc->chan.dev, "moving desc %p to freelist\n", desc); + 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); } @@ -163,9 +172,9 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first) /* ASSERT: channel is idle */ if (dma_readl(dw, CH_EN) & dwc->mask) { - dev_err(&dwc->chan.dev, + dev_err(chan2dev(&dwc->chan), "BUG: Attempted to start non-idle channel\n"); - dev_err(&dwc->chan.dev, + dev_err(chan2dev(&dwc->chan), " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n", channel_readl(dwc, SAR), channel_readl(dwc, DAR), @@ -193,7 +202,7 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc) void *param; struct dma_async_tx_descriptor *txd = &desc->txd; - dev_vdbg(&dwc->chan.dev, "descriptor %u complete\n", txd->cookie); + dev_vdbg(chan2dev(&dwc->chan), "descriptor %u complete\n", txd->cookie); dwc->completed = txd->cookie; callback = txd->callback; @@ -208,11 +217,11 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc) * mapped before they were submitted... */ if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) - dma_unmap_page(dwc->chan.dev.parent, desc->lli.dar, desc->len, - DMA_FROM_DEVICE); + 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(dwc->chan.dev.parent, desc->lli.sar, desc->len, - DMA_TO_DEVICE); + dma_unmap_page(chan2parent(&dwc->chan), desc->lli.sar, + desc->len, DMA_TO_DEVICE); /* * The API requires that no submissions are done from a @@ -228,7 +237,7 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc) LIST_HEAD(list); if (dma_readl(dw, CH_EN) & dwc->mask) { - dev_err(&dwc->chan.dev, + dev_err(chan2dev(&dwc->chan), "BUG: XFER bit set, but channel not idle!\n"); /* Try to continue after resetting the channel... */ @@ -273,7 +282,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) return; } - dev_vdbg(&dwc->chan.dev, "scan_descriptors: llp=0x%x\n", llp); + dev_vdbg(chan2dev(&dwc->chan), "scan_descriptors: llp=0x%x\n", llp); list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) { if (desc->lli.llp == llp) @@ -292,7 +301,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) dwc_descriptor_complete(dwc, desc); } - dev_err(&dwc->chan.dev, + dev_err(chan2dev(&dwc->chan), "BUG: All descriptors done, but channel not idle!\n"); /* Try to continue after resetting the channel... */ @@ -308,7 +317,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) static void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_lli *lli) { - dev_printk(KERN_CRIT, &dwc->chan.dev, + dev_printk(KERN_CRIT, chan2dev(&dwc->chan), " desc: s0x%x d0x%x l0x%x c0x%x:%x\n", lli->sar, lli->dar, lli->llp, lli->ctlhi, lli->ctllo); @@ -342,9 +351,9 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc) * controller flagged an error instead of scribbling over * random memory locations. */ - dev_printk(KERN_CRIT, &dwc->chan.dev, + dev_printk(KERN_CRIT, chan2dev(&dwc->chan), "Bad descriptor submitted for DMA!\n"); - dev_printk(KERN_CRIT, &dwc->chan.dev, + 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) @@ -442,12 +451,12 @@ static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx) * for DMA. But this is hard to do in a race-free manner. */ if (list_empty(&dwc->active_list)) { - dev_vdbg(&tx->chan->dev, "tx_submit: started %u\n", + dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n", desc->txd.cookie); dwc_dostart(dwc, desc); list_add_tail(&desc->desc_node, &dwc->active_list); } else { - dev_vdbg(&tx->chan->dev, "tx_submit: queued %u\n", + dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n", desc->txd.cookie); list_add_tail(&desc->desc_node, &dwc->queue); @@ -472,11 +481,11 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, unsigned int dst_width; u32 ctllo; - dev_vdbg(&chan->dev, "prep_dma_memcpy d0x%x s0x%x l0x%zx f0x%lx\n", + dev_vdbg(chan2dev(chan), "prep_dma_memcpy d0x%x s0x%x l0x%zx f0x%lx\n", dest, src, len, flags); if (unlikely(!len)) { - dev_dbg(&chan->dev, "prep_dma_memcpy: length is zero!\n"); + dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n"); return NULL; } @@ -516,7 +525,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, first = desc; } else { prev->lli.llp = desc->txd.phys; - dma_sync_single_for_device(chan->dev.parent, + dma_sync_single_for_device(chan2parent(chan), prev->txd.phys, sizeof(prev->lli), DMA_TO_DEVICE); list_add_tail(&desc->desc_node, @@ -531,7 +540,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, prev->lli.ctllo |= DWC_CTLL_INT_EN; prev->lli.llp = 0; - dma_sync_single_for_device(chan->dev.parent, + dma_sync_single_for_device(chan2parent(chan), prev->txd.phys, sizeof(prev->lli), DMA_TO_DEVICE); @@ -562,15 +571,15 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, struct scatterlist *sg; size_t total_len = 0; - dev_vdbg(&chan->dev, "prep_dma_slave\n"); + dev_vdbg(chan2dev(chan), "prep_dma_slave\n"); if (unlikely(!dws || !sg_len)) return NULL; - reg_width = dws->slave.reg_width; + reg_width = dws->reg_width; prev = first = NULL; - sg_len = dma_map_sg(chan->dev.parent, sgl, sg_len, direction); + sg_len = dma_map_sg(chan2parent(chan), sgl, sg_len, direction); switch (direction) { case DMA_TO_DEVICE: @@ -579,7 +588,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | DWC_CTLL_DST_FIX | DWC_CTLL_SRC_INC | DWC_CTLL_FC_M2P); - reg = dws->slave.tx_reg; + reg = dws->tx_reg; for_each_sg(sgl, sg, sg_len, i) { struct dw_desc *desc; u32 len; @@ -587,7 +596,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, desc = dwc_desc_get(dwc); if (!desc) { - dev_err(&chan->dev, + dev_err(chan2dev(chan), "not enough descriptors available\n"); goto err_desc_get; } @@ -607,7 +616,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, first = desc; } else { prev->lli.llp = desc->txd.phys; - dma_sync_single_for_device(chan->dev.parent, + dma_sync_single_for_device(chan2parent(chan), prev->txd.phys, sizeof(prev->lli), DMA_TO_DEVICE); @@ -625,7 +634,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | DWC_CTLL_SRC_FIX | DWC_CTLL_FC_P2M); - reg = dws->slave.rx_reg; + reg = dws->rx_reg; for_each_sg(sgl, sg, sg_len, i) { struct dw_desc *desc; u32 len; @@ -633,7 +642,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, desc = dwc_desc_get(dwc); if (!desc) { - dev_err(&chan->dev, + dev_err(chan2dev(chan), "not enough descriptors available\n"); goto err_desc_get; } @@ -653,7 +662,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, first = desc; } else { prev->lli.llp = desc->txd.phys; - dma_sync_single_for_device(chan->dev.parent, + dma_sync_single_for_device(chan2parent(chan), prev->txd.phys, sizeof(prev->lli), DMA_TO_DEVICE); @@ -673,7 +682,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, prev->lli.ctllo |= DWC_CTLL_INT_EN; prev->lli.llp = 0; - dma_sync_single_for_device(chan->dev.parent, + dma_sync_single_for_device(chan2parent(chan), prev->txd.phys, sizeof(prev->lli), DMA_TO_DEVICE); @@ -758,29 +767,21 @@ static void dwc_issue_pending(struct dma_chan *chan) spin_unlock_bh(&dwc->lock); } -static int dwc_alloc_chan_resources(struct dma_chan *chan, - struct dma_client *client) +static int dwc_alloc_chan_resources(struct dma_chan *chan) { struct dw_dma_chan *dwc = to_dw_dma_chan(chan); struct dw_dma *dw = to_dw_dma(chan->device); struct dw_desc *desc; - struct dma_slave *slave; struct dw_dma_slave *dws; int i; u32 cfghi; u32 cfglo; - dev_vdbg(&chan->dev, "alloc_chan_resources\n"); - - /* Channels doing slave DMA can only handle one client. */ - if (dwc->dws || client->slave) { - if (chan->client_count) - return -EBUSY; - } + dev_vdbg(chan2dev(chan), "alloc_chan_resources\n"); /* ASSERT: channel is idle */ if (dma_readl(dw, CH_EN) & dwc->mask) { - dev_dbg(&chan->dev, "DMA channel not idle?\n"); + dev_dbg(chan2dev(chan), "DMA channel not idle?\n"); return -EIO; } @@ -789,23 +790,17 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan, cfghi = DWC_CFGH_FIFO_MODE; cfglo = 0; - slave = client->slave; - if (slave) { + dws = dwc->dws; + if (dws) { /* * We need controller-specific data to set up slave * transfers. */ - BUG_ON(!slave->dma_dev || slave->dma_dev != dw->dma.dev); - - dws = container_of(slave, struct dw_dma_slave, slave); + BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev); - dwc->dws = dws; cfghi = dws->cfg_hi; cfglo = dws->cfg_lo; - } else { - dwc->dws = NULL; } - channel_writel(dwc, CFG_LO, cfglo); channel_writel(dwc, CFG_HI, cfghi); @@ -822,7 +817,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan, desc = kzalloc(sizeof(struct dw_desc), GFP_KERNEL); if (!desc) { - dev_info(&chan->dev, + dev_info(chan2dev(chan), "only allocated %d descriptors\n", i); spin_lock_bh(&dwc->lock); break; @@ -832,7 +827,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan, desc->txd.tx_submit = dwc_tx_submit; desc->txd.flags = DMA_CTRL_ACK; INIT_LIST_HEAD(&desc->txd.tx_list); - desc->txd.phys = dma_map_single(chan->dev.parent, &desc->lli, + desc->txd.phys = dma_map_single(chan2parent(chan), &desc->lli, sizeof(desc->lli), DMA_TO_DEVICE); dwc_desc_put(dwc, desc); @@ -847,7 +842,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan, spin_unlock_bh(&dwc->lock); - dev_dbg(&chan->dev, + dev_dbg(chan2dev(chan), "alloc_chan_resources allocated %d descriptors\n", i); return i; @@ -860,7 +855,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan) struct dw_desc *desc, *_desc; LIST_HEAD(list); - dev_dbg(&chan->dev, "free_chan_resources (descs allocated=%u)\n", + dev_dbg(chan2dev(chan), "free_chan_resources (descs allocated=%u)\n", dwc->descs_allocated); /* ASSERT: channel is idle */ @@ -881,13 +876,13 @@ static void dwc_free_chan_resources(struct dma_chan *chan) spin_unlock_bh(&dwc->lock); list_for_each_entry_safe(desc, _desc, &list, desc_node) { - dev_vdbg(&chan->dev, " freeing descriptor %p\n", desc); - dma_unmap_single(chan->dev.parent, desc->txd.phys, + dev_vdbg(chan2dev(chan), " freeing descriptor %p\n", desc); + dma_unmap_single(chan2parent(chan), desc->txd.phys, sizeof(desc->lli), DMA_TO_DEVICE); kfree(desc); } - dev_vdbg(&chan->dev, "free_chan_resources done\n"); + dev_vdbg(chan2dev(chan), "free_chan_resources done\n"); } /*----------------------------------------------------------------------*/ diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 0b95dcce447e..ca70a21afc68 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -366,8 +366,7 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor( * * Return - The number of descriptors allocated. */ -static int fsl_dma_alloc_chan_resources(struct dma_chan *chan, - struct dma_client *client) +static int fsl_dma_alloc_chan_resources(struct dma_chan *chan) { struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan); @@ -823,7 +822,7 @@ static int __devinit fsl_dma_chan_probe(struct fsl_dma_device *fdev, */ WARN_ON(fdev->feature != new_fsl_chan->feature); - new_fsl_chan->dev = &new_fsl_chan->common.dev; + new_fsl_chan->dev = &new_fsl_chan->common.dev->device; new_fsl_chan->reg_base = ioremap(new_fsl_chan->reg.start, new_fsl_chan->reg.end - new_fsl_chan->reg.start + 1); diff --git a/drivers/dma/ioat.c b/drivers/dma/ioat.c index 9b16a3af9a0a..4105d6575b64 100644 --- a/drivers/dma/ioat.c +++ b/drivers/dma/ioat.c @@ -75,60 +75,10 @@ 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 int ioat_setup_functionality(struct pci_dev *pdev, void __iomem *iobase) -{ - struct ioat_device *device = pci_get_drvdata(pdev); - u8 version; - int err = 0; - - version = readb(iobase + IOAT_VER_OFFSET); - switch (version) { - 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; - return err; -} - -static void ioat_shutdown_functionality(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; - } -} - static struct pci_driver ioat_pci_driver = { .name = "ioatdma", .id_table = ioat_pci_tbl, .probe = ioat_probe, - .shutdown = ioat_shutdown_functionality, .remove = __devexit_p(ioat_remove), }; @@ -179,7 +129,29 @@ static int __devinit ioat_probe(struct pci_dev *pdev, pci_set_master(pdev); - err = ioat_setup_functionality(pdev, iobase); + 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; @@ -198,17 +170,21 @@ err_enable_device: return err; } -/* - * It is unsafe to remove this module: if removed while a requested - * dma is outstanding, esp. from tcp, it is possible to hang while - * waiting for something that will never finish. However, if you're - * feeling lucky, this usually works just fine. - */ static void __devexit ioat_remove(struct pci_dev *pdev) { struct ioat_device *device = pci_get_drvdata(pdev); - ioat_shutdown_functionality(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); } diff --git a/drivers/dma/ioat_dma.c b/drivers/dma/ioat_dma.c index 6607fdd00b1c..b3759c4b6536 100644 --- a/drivers/dma/ioat_dma.c +++ b/drivers/dma/ioat_dma.c @@ -734,8 +734,7 @@ static void ioat2_dma_massage_chan_desc(struct ioat_dma_chan *ioat_chan) * 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 dma_client *client) +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; @@ -1341,12 +1340,11 @@ static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan) */ #define IOAT_TEST_SIZE 2000 -DECLARE_COMPLETION(test_completion); static void ioat_dma_test_callback(void *dma_async_param) { - printk(KERN_ERR "ioatdma: ioat_dma_test_callback(%p)\n", - dma_async_param); - complete(&test_completion); + struct completion *cmp = dma_async_param; + + complete(cmp); } /** @@ -1363,6 +1361,7 @@ static int ioat_dma_self_test(struct ioatdma_device *device) dma_addr_t dma_dest, dma_src; dma_cookie_t cookie; int err = 0; + struct completion cmp; src = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, GFP_KERNEL); if (!src) @@ -1381,7 +1380,7 @@ static int ioat_dma_self_test(struct ioatdma_device *device) dma_chan = container_of(device->common.channels.next, struct dma_chan, device_node); - if (device->common.device_alloc_chan_resources(dma_chan, NULL) < 1) { + if (device->common.device_alloc_chan_resources(dma_chan) < 1) { dev_err(&device->pdev->dev, "selftest cannot allocate chan resource\n"); err = -ENODEV; @@ -1402,8 +1401,9 @@ static int ioat_dma_self_test(struct ioatdma_device *device) } async_tx_ack(tx); + init_completion(&cmp); tx->callback = ioat_dma_test_callback; - tx->callback_param = (void *)0x8086; + tx->callback_param = &cmp; cookie = tx->tx_submit(tx); if (cookie < 0) { dev_err(&device->pdev->dev, @@ -1413,7 +1413,7 @@ static int ioat_dma_self_test(struct ioatdma_device *device) } device->common.device_issue_pending(dma_chan); - wait_for_completion_timeout(&test_completion, msecs_to_jiffies(3000)); + wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000)); if (device->common.device_is_tx_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) { diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index 6be317262200..ea5440dd10dc 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -24,7 +24,6 @@ #include <linux/init.h> #include <linux/module.h> -#include <linux/async_tx.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/spinlock.h> @@ -116,7 +115,7 @@ iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc, } /* run dependent operations */ - async_tx_run_dependencies(&desc->async_tx); + dma_run_dependencies(&desc->async_tx); return cookie; } @@ -270,8 +269,6 @@ static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan) break; } - BUG_ON(!seen_current); - if (cookie > 0) { iop_chan->completed_cookie = cookie; pr_debug("\tcompleted cookie %d\n", cookie); @@ -471,8 +468,7 @@ static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan); * greater than 2x the number slots needed to satisfy a device->max_xor * request. * */ -static int iop_adma_alloc_chan_resources(struct dma_chan *chan, - struct dma_client *client) +static int iop_adma_alloc_chan_resources(struct dma_chan *chan) { char *hw_desc; int idx; @@ -866,7 +862,7 @@ static int __devinit iop_adma_memcpy_self_test(struct iop_adma_device *device) dma_chan = container_of(device->common.channels.next, struct dma_chan, device_node); - if (iop_adma_alloc_chan_resources(dma_chan, NULL) < 1) { + if (iop_adma_alloc_chan_resources(dma_chan) < 1) { err = -ENODEV; goto out; } @@ -964,7 +960,7 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device) dma_chan = container_of(device->common.channels.next, struct dma_chan, device_node); - if (iop_adma_alloc_chan_resources(dma_chan, NULL) < 1) { + if (iop_adma_alloc_chan_resources(dma_chan) < 1) { err = -ENODEV; goto out; } @@ -1115,26 +1111,13 @@ static int __devexit iop_adma_remove(struct platform_device *dev) struct iop_adma_device *device = platform_get_drvdata(dev); struct dma_chan *chan, *_chan; struct iop_adma_chan *iop_chan; - int i; struct iop_adma_platform_data *plat_data = dev->dev.platform_data; dma_async_device_unregister(&device->common); - for (i = 0; i < 3; i++) { - unsigned int irq; - irq = platform_get_irq(dev, i); - free_irq(irq, device); - } - dma_free_coherent(&dev->dev, plat_data->pool_size, device->dma_desc_pool_virt, device->dma_desc_pool); - do { - struct resource *res; - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start); - } while (0); - list_for_each_entry_safe(chan, _chan, &device->common.channels, device_node) { iop_chan = to_iop_adma_chan(chan); @@ -1255,7 +1238,6 @@ static int __devinit iop_adma_probe(struct platform_device *pdev) spin_lock_init(&iop_chan->lock); INIT_LIST_HEAD(&iop_chan->chain); INIT_LIST_HEAD(&iop_chan->all_slots); - INIT_RCU_HEAD(&iop_chan->common.rcu); iop_chan->common.device = dma_dev; list_add_tail(&iop_chan->common.device_node, &dma_dev->channels); @@ -1431,16 +1413,12 @@ static int __init iop_adma_init (void) return platform_driver_register(&iop_adma_driver); } -/* it's currently unsafe to unload this module */ -#if 0 static void __exit iop_adma_exit (void) { platform_driver_unregister(&iop_adma_driver); return; } module_exit(iop_adma_exit); -#endif - module_init(iop_adma_init); MODULE_AUTHOR("Intel Corporation"); diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index bcda17426411..d35cbd1ff0b3 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -18,7 +18,6 @@ #include <linux/init.h> #include <linux/module.h> -#include <linux/async_tx.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/spinlock.h> @@ -340,7 +339,7 @@ mv_xor_run_tx_complete_actions(struct mv_xor_desc_slot *desc, } /* run dependent operations */ - async_tx_run_dependencies(&desc->async_tx); + dma_run_dependencies(&desc->async_tx); return cookie; } @@ -607,8 +606,7 @@ submit_done: } /* returns the number of allocated descriptors */ -static int mv_xor_alloc_chan_resources(struct dma_chan *chan, - struct dma_client *client) +static int mv_xor_alloc_chan_resources(struct dma_chan *chan) { char *hw_desc; int idx; @@ -958,7 +956,7 @@ static int __devinit mv_xor_memcpy_self_test(struct mv_xor_device *device) dma_chan = container_of(device->common.channels.next, struct dma_chan, device_node); - if (mv_xor_alloc_chan_resources(dma_chan, NULL) < 1) { + if (mv_xor_alloc_chan_resources(dma_chan) < 1) { err = -ENODEV; goto out; } @@ -1053,7 +1051,7 @@ mv_xor_xor_self_test(struct mv_xor_device *device) dma_chan = container_of(device->common.channels.next, struct dma_chan, device_node); - if (mv_xor_alloc_chan_resources(dma_chan, NULL) < 1) { + if (mv_xor_alloc_chan_resources(dma_chan) < 1) { err = -ENODEV; goto out; } @@ -1221,7 +1219,6 @@ static int __devinit mv_xor_probe(struct platform_device *pdev) INIT_LIST_HEAD(&mv_chan->chain); INIT_LIST_HEAD(&mv_chan->completed_slots); INIT_LIST_HEAD(&mv_chan->all_slots); - INIT_RCU_HEAD(&mv_chan->common.rcu); mv_chan->common.device = dma_dev; list_add_tail(&mv_chan->common.device_node, &dma_dev->channels); diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index 2f9e941968d6..d8f295bdad76 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -18,12 +18,6 @@ #include <linux/dmi.h> #include <acpi/acpi_bus.h> -#include <acpi/acnames.h> -#include <acpi/acnamesp.h> -#include <acpi/acparser.h> -#include <acpi/acexcep.h> -#include <acpi/acmacros.h> -#include <acpi/actypes.h> #define REGS_PER_GTF 7 struct taskfile_array { diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 3949a1c73451..419c378bd24b 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -120,7 +120,7 @@ config TIFM_CORE cards are supported via 'MMC/SD Card support: TI Flash Media MMC/SD Interface support (MMC_TIFM_SD)'. - To compile this driver as a module, choose M here: the module will + To compile this driver as a module, choose M here: the module will be called tifm_core. config TIFM_7XX1 @@ -133,100 +133,9 @@ config TIFM_7XX1 To make actual use of the device, you will have to select some flash card format drivers, as outlined in the TIFM_CORE Help. - To compile this driver as a module, choose M here: the module will + To compile this driver as a module, choose M here: the module will be called tifm_7xx1. -config ACER_WMI - tristate "Acer WMI Laptop Extras (EXPERIMENTAL)" - depends on X86 - depends on EXPERIMENTAL - depends on ACPI - depends on LEDS_CLASS - depends on NEW_LEDS - depends on BACKLIGHT_CLASS_DEVICE - depends on SERIO_I8042 - depends on RFKILL - select ACPI_WMI - ---help--- - This is a driver for newer Acer (and Wistron) laptops. It adds - wireless radio and bluetooth control, and on some laptops, - exposes the mail LED and LCD backlight. - - For more information about this driver see - <file:Documentation/laptops/acer-wmi.txt> - - If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M - here. - -config ASUS_LAPTOP - tristate "Asus Laptop Extras (EXPERIMENTAL)" - depends on X86 - depends on ACPI - depends on EXPERIMENTAL && !ACPI_ASUS - depends on LEDS_CLASS - depends on NEW_LEDS - depends on BACKLIGHT_CLASS_DEVICE - ---help--- - This is the new Linux driver for Asus laptops. It may also support some - MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate - standard ACPI events that go through /proc/acpi/events. It also adds - support for video output switching, LCD backlight control, Bluetooth and - Wlan control, and most importantly, allows you to blink those fancy LEDs. - - For more information and a userspace daemon for handling the extra - buttons see <http://acpi4asus.sf.net/>. - - If you have an ACPI-compatible ASUS laptop, say Y or M here. - -config FUJITSU_LAPTOP - tristate "Fujitsu Laptop Extras" - depends on X86 - depends on ACPI - depends on INPUT - depends on BACKLIGHT_CLASS_DEVICE - ---help--- - This is a driver for laptops built by Fujitsu: - - * P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks - * Possibly other Fujitsu laptop models - * Tested with S6410 and S7020 - - It adds support for LCD brightness control and some hotkeys. - - If you have a Fujitsu laptop, say Y or M here. - -config FUJITSU_LAPTOP_DEBUG - bool "Verbose debug mode for Fujitsu Laptop Extras" - depends on FUJITSU_LAPTOP - default n - ---help--- - Enables extra debug output from the fujitsu extras driver, at the - expense of a slight increase in driver size. - - If you are not sure, say N here. - -config TC1100_WMI - tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)" - depends on X86 && !X86_64 - depends on EXPERIMENTAL - depends on ACPI - select ACPI_WMI - ---help--- - This is a driver for the WMI extensions (wireless and bluetooth power - control) of the HP Compaq TC1100 tablet. - -config HP_WMI - tristate "HP WMI extras" - depends on ACPI_WMI - depends on INPUT - depends on RFKILL - help - Say Y here if you want to support WMI-based hotkeys on HP laptops and - to read data from WMI such as docking or ambient light sensor state. - - To compile this driver as a module, choose M here: the module will - be called hp-wmi. - config ICS932S401 tristate "Integrated Circuits ICS932S401" depends on I2C && EXPERIMENTAL @@ -237,170 +146,6 @@ config ICS932S401 This driver can also be built as a module. If so, the module will be called ics932s401. -config MSI_LAPTOP - tristate "MSI Laptop Extras" - depends on X86 - depends on ACPI - depends on BACKLIGHT_CLASS_DEVICE - ---help--- - This is a driver for laptops built by MSI (MICRO-STAR - INTERNATIONAL): - - MSI MegaBook S270 (MS-1013) - Cytron/TCM/Medion/Tchibo MD96100/SAM2000 - - It adds support for Bluetooth, WLAN and LCD brightness control. - - More information about this driver is available at - <http://0pointer.de/lennart/tchibo.html>. - - If you have an MSI S270 laptop, say Y or M here. - -config PANASONIC_LAPTOP - tristate "Panasonic Laptop Extras" - depends on X86 && INPUT && ACPI - depends on BACKLIGHT_CLASS_DEVICE - ---help--- - This driver adds support for access to backlight control and hotkeys - on Panasonic Let's Note laptops. - - If you have a Panasonic Let's note laptop (such as the R1(N variant), - R2, R3, R5, T2, W2 and Y2 series), say Y. - -config COMPAL_LAPTOP - tristate "Compal Laptop Extras" - depends on X86 - depends on ACPI - depends on BACKLIGHT_CLASS_DEVICE - ---help--- - This is a driver for laptops built by Compal: - - Compal FL90/IFL90 - Compal FL91/IFL91 - Compal FL92/JFL92 - Compal FT00/IFT00 - - It adds support for Bluetooth, WLAN and LCD brightness control. - - If you have an Compal FL9x/IFL9x/FT00 laptop, say Y or M here. - -config SONY_LAPTOP - tristate "Sony Laptop Extras" - depends on X86 && ACPI - select BACKLIGHT_CLASS_DEVICE - depends on INPUT - ---help--- - This mini-driver drives the SNC and SPIC devices present in the ACPI - BIOS of the Sony Vaio laptops. - - It gives access to some extra laptop functionalities like Bluetooth, - screen brightness control, Fn keys and allows powering on/off some - devices. - - Read <file:Documentation/laptops/sony-laptop.txt> for more information. - -config SONYPI_COMPAT - bool "Sonypi compatibility" - depends on SONY_LAPTOP - ---help--- - Build the sonypi driver compatibility code into the sony-laptop driver. - -config THINKPAD_ACPI - tristate "ThinkPad ACPI Laptop Extras" - depends on X86 && ACPI - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE - select HWMON - select NVRAM - select INPUT - select NEW_LEDS - select LEDS_CLASS - select NET - select RFKILL - ---help--- - This is a driver for the IBM and Lenovo ThinkPad laptops. It adds - support for Fn-Fx key combinations, Bluetooth control, video - output switching, ThinkLight control, UltraBay eject and more. - For more information about this driver see - <file:Documentation/laptops/thinkpad-acpi.txt> and - <http://ibm-acpi.sf.net/> . - - This driver was formerly known as ibm-acpi. - - If you have an IBM or Lenovo ThinkPad laptop, say Y or M here. - -config THINKPAD_ACPI_DEBUG - bool "Verbose debug mode" - depends on THINKPAD_ACPI - default n - ---help--- - Enables extra debugging information, at the expense of a slightly - increase in driver size. - - If you are not sure, say N here. - -config THINKPAD_ACPI_DOCK - bool "Legacy Docking Station Support" - depends on THINKPAD_ACPI - depends on ACPI_DOCK=n - default n - ---help--- - Allows the thinkpad_acpi driver to handle docking station events. - This support was made obsolete by the generic ACPI docking station - support (CONFIG_ACPI_DOCK). It will allow locking and removing the - laptop from the docking station, but will not properly connect PCI - devices. - - If you are not sure, say N here. - -config THINKPAD_ACPI_BAY - bool "Legacy Removable Bay Support" - depends on THINKPAD_ACPI - default y - ---help--- - Allows the thinkpad_acpi driver to handle removable bays. It will - electrically disable the device in the bay, and also generate - notifications when the bay lever is ejected or inserted. - - If you are not sure, say Y here. - -config THINKPAD_ACPI_VIDEO - bool "Video output control support" - depends on THINKPAD_ACPI - default y - ---help--- - Allows the thinkpad_acpi driver to provide an interface to control - the various video output ports. - - This feature often won't work well, depending on ThinkPad model, - display state, video output devices in use, whether there is a X - server running, phase of the moon, and the current mood of - Schroedinger's cat. If you can use X.org's RandR to control - your ThinkPad's video output ports instead of this feature, - don't think twice: do it and say N here to save some memory. - - If you are not sure, say Y here. - -config THINKPAD_ACPI_HOTKEY_POLL - bool "Support NVRAM polling for hot keys" - depends on THINKPAD_ACPI - default y - ---help--- - Some thinkpad models benefit from NVRAM polling to detect a few of - the hot key press events. If you know your ThinkPad model does not - need to do NVRAM polling to support any of the hot keys you use, - unselecting this option will save about 1kB of memory. - - ThinkPads T40 and newer, R52 and newer, and X31 and newer are - unlikely to need NVRAM polling in their latest BIOS versions. - - NVRAM polling can detect at most the following keys: ThinkPad/Access - IBM, Zoom, Switch Display (fn+F7), ThinkLight, Volume up/down/mute, - Brightness up/down, Display Expand (fn+F8), Hibernate (fn+F12). - - If you are not sure, say Y here. The driver enables polling only if - it is strictly necessary to do so. - config ATMEL_SSC tristate "Device driver for Atmel SSC peripheral" depends on AVR32 || ARCH_AT91 @@ -413,31 +158,6 @@ config ATMEL_SSC If unsure, say N. -config INTEL_MENLOW - tristate "Thermal Management driver for Intel menlow platform" - depends on ACPI_THERMAL - select THERMAL - depends on X86 - ---help--- - ACPI thermal management enhancement driver on - Intel Menlow platform. - - If unsure, say N. - -config EEEPC_LAPTOP - tristate "Eee PC Hotkey Driver (EXPERIMENTAL)" - depends on X86 - depends on ACPI - depends on BACKLIGHT_CLASS_DEVICE - depends on HWMON - depends on EXPERIMENTAL - depends on RFKILL - ---help--- - This driver supports the Fn-Fx keys on Eee PC laptops. - It also adds the ability to switch camera/wlan on/off. - - If you have an Eee PC laptop, say Y or M here. - config ENCLOSURE_SERVICES tristate "Enclosure Services" default n diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 5de863a0e395..9cf8ae6e4b39 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -1,33 +1,20 @@ # # Makefile for misc devices that really don't fit anywhere else. # -obj- := misc.o # Dummy rule to force built-in.o to be made obj-$(CONFIG_IBM_ASM) += ibmasm/ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ -obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o -obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o -obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o -obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o -obj-$(CONFIG_ACER_WMI) += acer-wmi.o obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o -obj-$(CONFIG_HP_WMI) += hp-wmi.o obj-$(CONFIG_ICS932S401) += ics932s401.o -obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_PHANTOM) += phantom.o obj-$(CONFIG_SGI_IOC4) += ioc4.o -obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o -obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o -obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o -obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o -obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o obj-$(CONFIG_KGDB_TESTS) += kgdbts.o obj-$(CONFIG_SGI_XP) += sgi-xp/ diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 1e97916914ad..76bfe16c09b1 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -55,7 +55,6 @@ enum atmel_mci_state { struct atmel_mci_dma { #ifdef CONFIG_MMC_ATMELMCI_DMA - struct dma_client client; struct dma_chan *chan; struct dma_async_tx_descriptor *data_desc; #endif @@ -593,10 +592,8 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) /* If we don't have a channel, we can't do DMA */ chan = host->dma.chan; - if (chan) { - dma_chan_get(chan); + if (chan) host->data_chan = chan; - } if (!chan) return -ENODEV; @@ -1443,60 +1440,6 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -#ifdef CONFIG_MMC_ATMELMCI_DMA - -static inline struct atmel_mci * -dma_client_to_atmel_mci(struct dma_client *client) -{ - return container_of(client, struct atmel_mci, dma.client); -} - -static enum dma_state_client atmci_dma_event(struct dma_client *client, - struct dma_chan *chan, enum dma_state state) -{ - struct atmel_mci *host; - enum dma_state_client ret = DMA_NAK; - - host = dma_client_to_atmel_mci(client); - - switch (state) { - case DMA_RESOURCE_AVAILABLE: - spin_lock_bh(&host->lock); - if (!host->dma.chan) { - host->dma.chan = chan; - ret = DMA_ACK; - } - spin_unlock_bh(&host->lock); - - if (ret == DMA_ACK) - dev_info(&host->pdev->dev, - "Using %s for DMA transfers\n", - chan->dev.bus_id); - break; - - case DMA_RESOURCE_REMOVED: - spin_lock_bh(&host->lock); - if (host->dma.chan == chan) { - host->dma.chan = NULL; - ret = DMA_ACK; - } - spin_unlock_bh(&host->lock); - - if (ret == DMA_ACK) - dev_info(&host->pdev->dev, - "Lost %s, falling back to PIO\n", - chan->dev.bus_id); - break; - - default: - break; - } - - - return ret; -} -#endif /* CONFIG_MMC_ATMELMCI_DMA */ - static int __init atmci_init_slot(struct atmel_mci *host, struct mci_slot_pdata *slot_data, unsigned int id, u32 sdc_reg) @@ -1600,6 +1543,18 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot, mmc_free_host(slot->mmc); } +#ifdef CONFIG_MMC_ATMELMCI_DMA +static bool filter(struct dma_chan *chan, void *slave) +{ + struct dw_dma_slave *dws = slave; + + if (dws->dma_dev == chan->device->dev) + return true; + else + return false; +} +#endif + static int __init atmci_probe(struct platform_device *pdev) { struct mci_platform_data *pdata; @@ -1652,22 +1607,20 @@ static int __init atmci_probe(struct platform_device *pdev) goto err_request_irq; #ifdef CONFIG_MMC_ATMELMCI_DMA - if (pdata->dma_slave) { - struct dma_slave *slave = pdata->dma_slave; + if (pdata->dma_slave.dma_dev) { + struct dw_dma_slave *dws = &pdata->dma_slave; + dma_cap_mask_t mask; - slave->tx_reg = regs->start + MCI_TDR; - slave->rx_reg = regs->start + MCI_RDR; + dws->tx_reg = regs->start + MCI_TDR; + dws->rx_reg = regs->start + MCI_RDR; /* Try to grab a DMA channel */ - host->dma.client.event_callback = atmci_dma_event; - dma_cap_set(DMA_SLAVE, host->dma.client.cap_mask); - host->dma.client.slave = slave; - - dma_async_client_register(&host->dma.client); - dma_async_client_chan_request(&host->dma.client); - } else { - dev_notice(&pdev->dev, "DMA not available, using PIO\n"); + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + host->dma.chan = dma_request_channel(mask, filter, dws); } + if (!host->dma.chan) + dev_notice(&pdev->dev, "DMA not available, using PIO\n"); #endif /* CONFIG_MMC_ATMELMCI_DMA */ platform_set_drvdata(pdev, host); @@ -1699,8 +1652,8 @@ static int __init atmci_probe(struct platform_device *pdev) err_init_slot: #ifdef CONFIG_MMC_ATMELMCI_DMA - if (pdata->dma_slave) - dma_async_client_unregister(&host->dma.client); + if (host->dma.chan) + dma_release_channel(host->dma.chan); #endif free_irq(irq, host); err_request_irq: @@ -1731,8 +1684,8 @@ static int __exit atmci_remove(struct platform_device *pdev) clk_disable(host->mck); #ifdef CONFIG_MMC_ATMELMCI_DMA - if (host->dma.client.slave) - dma_async_client_unregister(&host->dma.client); + if (host->dma.chan) + dma_release_channel(host->dma.chan); #endif free_irq(platform_get_irq(pdev, 0), host); @@ -1761,7 +1714,7 @@ static void __exit atmci_exit(void) platform_driver_unregister(&atmci_driver); } -module_init(atmci_init); +late_initcall(atmci_init); /* try to load after dma driver when built-in */ module_exit(atmci_exit); MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver"); diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index a90d50c2c3e5..7d04fb9ddcaa 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -45,6 +45,14 @@ config MTD_PARTITIONS devices. Partitioning on NFTL 'devices' is a different - that's the 'normal' form of partitioning used on a block device. +config MTD_TESTS + tristate "MTD tests support" + depends on m + help + This option includes various MTD tests into compilation. The tests + should normally be compiled as kernel modules. The modules perform + various checks and verifications when loaded. + config MTD_REDBOOT_PARTS tristate "RedBoot partition table parsing" depends on MTD_PARTITIONS @@ -316,6 +324,8 @@ source "drivers/mtd/nand/Kconfig" source "drivers/mtd/onenand/Kconfig" +source "drivers/mtd/lpddr/Kconfig" + source "drivers/mtd/ubi/Kconfig" endif # MTD diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 4b77335715f0..4521b1ecce45 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -29,6 +29,6 @@ obj-$(CONFIG_MTD_OOPS) += mtdoops.o nftl-objs := nftlcore.o nftlmount.o inftl-objs := inftlcore.o inftlmount.o -obj-y += chips/ maps/ devices/ nand/ onenand/ +obj-y += chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/ obj-$(CONFIG_MTD_UBI) += ubi/ diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index c93a8be5d5f1..f5ab6fa1057b 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -58,8 +58,8 @@ static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t static int cfi_intelext_writev(struct mtd_info *, const struct kvec *, unsigned long, loff_t, size_t *); static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); static void cfi_intelext_sync (struct mtd_info *); -static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len); -static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); +static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); #ifdef CONFIG_MTD_OTP static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); @@ -558,8 +558,8 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) } for (i=0; i<mtd->numeraseregions;i++){ - printk(KERN_DEBUG "erase region %d: offset=0x%x,size=0x%x,blocks=%d\n", - i,mtd->eraseregions[i].offset, + printk(KERN_DEBUG "erase region %d: offset=0x%llx,size=0x%x,blocks=%d\n", + i,(unsigned long long)mtd->eraseregions[i].offset, mtd->eraseregions[i].erasesize, mtd->eraseregions[i].numblocks); } @@ -2058,7 +2058,7 @@ out: put_chip(map, chip, adr); return ret; } -static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { int ret; @@ -2082,7 +2082,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) return ret; } -static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { int ret; diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index d74ec46aa032..94bb61e19047 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -71,8 +71,8 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr); #include "fwh_lock.h" -static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, size_t len); -static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); +static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); static struct mtd_chip_driver cfi_amdstd_chipdrv = { .probe = NULL, /* Not usable directly */ @@ -322,6 +322,14 @@ static struct cfi_fixup fixup_table[] = { }; +static void cfi_fixup_major_minor(struct cfi_private *cfi, + struct cfi_pri_amdstd *extp) +{ + if (cfi->mfr == CFI_MFR_SAMSUNG && cfi->id == 0x257e && + extp->MajorVersion == '0') + extp->MajorVersion = '1'; +} + struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) { struct cfi_private *cfi = map->fldrv_priv; @@ -363,6 +371,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) return NULL; } + cfi_fixup_major_minor(cfi, extp); + if (extp->MajorVersion != '1' || (extp->MinorVersion < '0' || extp->MinorVersion > '4')) { printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query " @@ -1774,12 +1784,12 @@ out_unlock: return ret; } -static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { return cfi_varsize_frob(mtd, do_atmel_lock, ofs, len, NULL); } -static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { return cfi_varsize_frob(mtd, do_atmel_unlock, ofs, len, NULL); } diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index d4714dd9f7ab..6c740f346f91 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -42,8 +42,8 @@ static int cfi_staa_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); static int cfi_staa_erase_varsize(struct mtd_info *, struct erase_info *); static void cfi_staa_sync (struct mtd_info *); -static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len); -static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); +static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); static int cfi_staa_suspend (struct mtd_info *); static void cfi_staa_resume (struct mtd_info *); @@ -221,8 +221,8 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) } for (i=0; i<mtd->numeraseregions;i++){ - printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n", - i,mtd->eraseregions[i].offset, + printk(KERN_DEBUG "%d: offset=0x%llx,size=0x%x,blocks=%d\n", + i, (unsigned long long)mtd->eraseregions[i].offset, mtd->eraseregions[i].erasesize, mtd->eraseregions[i].numblocks); } @@ -964,7 +964,7 @@ static int cfi_staa_erase_varsize(struct mtd_info *mtd, adr += regions[i].erasesize; len -= regions[i].erasesize; - if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift))) + if (adr % (1<< cfi->chipshift) == (((unsigned long)regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift))) i++; if (adr >> cfi->chipshift) { @@ -1135,7 +1135,7 @@ retry: spin_unlock_bh(chip->mutex); return 0; } -static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -1284,7 +1284,7 @@ retry: spin_unlock_bh(chip->mutex); return 0; } -static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h index ab44f2b996f8..57e0e4e921f9 100644 --- a/drivers/mtd/chips/fwh_lock.h +++ b/drivers/mtd/chips/fwh_lock.h @@ -77,7 +77,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, } -static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len) +static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len) { int ret; @@ -88,7 +88,7 @@ static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len) } -static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len) +static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len) { int ret; diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index f4bda4cee495..578de1c67bfe 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c @@ -619,7 +619,7 @@ static struct mtd_partition lart_partitions[] = { }; #endif -int __init lart_flash_init (void) +static int __init lart_flash_init (void) { int result; memset (&mtd,0,sizeof (mtd)); @@ -690,7 +690,7 @@ int __init lart_flash_init (void) return (result); } -void __exit lart_flash_exit (void) +static void __exit lart_flash_exit (void) { #ifndef HAVE_PARTITIONS del_mtd_device (&mtd); @@ -705,5 +705,3 @@ module_exit (lart_flash_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Abraham vd Merwe <abraham@2d3d.co.za>"); MODULE_DESCRIPTION("MTD driver for Intel 28F160F3 on LART board"); - - diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 5733f0643843..7c3fc766dcf1 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -20,6 +20,7 @@ #include <linux/device.h> #include <linux/interrupt.h> #include <linux/mutex.h> +#include <linux/math64.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> @@ -169,9 +170,9 @@ static int wait_till_ready(struct m25p *flash) */ static int erase_chip(struct m25p *flash) { - DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB\n", - dev_name(&flash->spi->dev), __func__, - flash->mtd.size / 1024); + DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %lldKiB\n", + dev_name(&flash->spi->dev), __func__, + (long long)(flash->mtd.size >> 10)); /* Wait until finished previous write command. */ if (wait_till_ready(flash)) @@ -232,18 +233,18 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) { struct m25p *flash = mtd_to_m25p(mtd); u32 addr,len; + uint32_t rem; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", - dev_name(&flash->spi->dev), __func__, "at", - (u32)instr->addr, instr->len); + DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%llx, len %lld\n", + dev_name(&flash->spi->dev), __func__, "at", + (long long)instr->addr, (long long)instr->len); /* sanity checks */ if (instr->addr + instr->len > flash->mtd.size) return -EINVAL; - if ((instr->addr % mtd->erasesize) != 0 - || (instr->len % mtd->erasesize) != 0) { + div_u64_rem(instr->len, mtd->erasesize, &rem); + if (rem) return -EINVAL; - } addr = instr->addr; len = instr->len; @@ -677,24 +678,24 @@ static int __devinit m25p_probe(struct spi_device *spi) flash->mtd.erasesize = info->sector_size; } - dev_info(&spi->dev, "%s (%d Kbytes)\n", info->name, - flash->mtd.size / 1024); + dev_info(&spi->dev, "%s (%lld Kbytes)\n", info->name, + (long long)flash->mtd.size >> 10); DEBUG(MTD_DEBUG_LEVEL2, - "mtd .name = %s, .size = 0x%.8x (%uMiB) " + "mtd .name = %s, .size = 0x%llx (%lldMiB) " ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", flash->mtd.name, - flash->mtd.size, flash->mtd.size / (1024*1024), + (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), flash->mtd.erasesize, flash->mtd.erasesize / 1024, flash->mtd.numeraseregions); if (flash->mtd.numeraseregions) for (i = 0; i < flash->mtd.numeraseregions; i++) DEBUG(MTD_DEBUG_LEVEL2, - "mtd.eraseregions[%d] = { .offset = 0x%.8x, " + "mtd.eraseregions[%d] = { .offset = 0x%llx, " ".erasesize = 0x%.8x (%uKiB), " ".numblocks = %d }\n", - i, flash->mtd.eraseregions[i].offset, + i, (long long)flash->mtd.eraseregions[i].offset, flash->mtd.eraseregions[i].erasesize, flash->mtd.eraseregions[i].erasesize / 1024, flash->mtd.eraseregions[i].numblocks); @@ -722,12 +723,12 @@ static int __devinit m25p_probe(struct spi_device *spi) if (nr_parts > 0) { for (i = 0; i < nr_parts; i++) { DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " - "{.name = %s, .offset = 0x%.8x, " - ".size = 0x%.8x (%uKiB) }\n", + "{.name = %s, .offset = 0x%llx, " + ".size = 0x%llx (%lldKiB) }\n", i, parts[i].name, - parts[i].offset, - parts[i].size, - parts[i].size / 1024); + (long long)parts[i].offset, + (long long)parts[i].size, + (long long)(parts[i].size >> 10)); } flash->partitioned = 1; return add_mtd_partitions(&flash->mtd, parts, nr_parts); diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 65126cd668ff..d44f741ae229 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -16,6 +16,7 @@ #include <linux/device.h> #include <linux/mutex.h> #include <linux/err.h> +#include <linux/math64.h> #include <linux/spi/spi.h> #include <linux/spi/flash.h> @@ -152,15 +153,20 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) struct spi_message msg; unsigned blocksize = priv->page_size << 3; uint8_t *command; + uint32_t rem; - DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%x len 0x%x\n", - dev_name(&spi->dev), - instr->addr, instr->len); + DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%llx len 0x%llx\n", + dev_name(&spi->dev), (long long)instr->addr, + (long long)instr->len); /* Sanity checks */ - if ((instr->addr + instr->len) > mtd->size - || (instr->len % priv->page_size) != 0 - || (instr->addr % priv->page_size) != 0) + if (instr->addr + instr->len > mtd->size) + return -EINVAL; + div_u64_rem(instr->len, priv->page_size, &rem); + if (rem) + return -EINVAL; + div_u64_rem(instr->addr, priv->page_size, &rem); + if (rem) return -EINVAL; spi_message_init(&msg); @@ -178,7 +184,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) /* Calculate flash page address; use block erase (for speed) if * we're at a block boundary and need to erase the whole block. */ - pageaddr = instr->addr / priv->page_size; + pageaddr = div_u64(instr->len, priv->page_size); do_block = (pageaddr & 0x7) == 0 && instr->len >= blocksize; pageaddr = pageaddr << priv->page_offset; @@ -667,8 +673,8 @@ add_dataflash_otp(struct spi_device *spi, char *name, if (revision >= 'c') otp_tag = otp_setup(device, revision); - dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes%s\n", - name, DIV_ROUND_UP(device->size, 1024), + dev_info(&spi->dev, "%s (%lld KBytes) pagesize %d bytes%s\n", + name, (long long)((device->size + 1023) >> 10), pagesize, otp_tag); dev_set_drvdata(&spi->dev, priv); diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 9bf581c4f740..a790c062af1f 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -109,25 +109,25 @@ module_param(shuffle_freq, int, 0); /* Each memory region corresponds to a minor device */ typedef struct partition_t { struct mtd_blktrans_dev mbd; - u_int32_t state; - u_int32_t *VirtualBlockMap; - u_int32_t *VirtualPageMap; - u_int32_t FreeTotal; + uint32_t state; + uint32_t *VirtualBlockMap; + uint32_t *VirtualPageMap; + uint32_t FreeTotal; struct eun_info_t { - u_int32_t Offset; - u_int32_t EraseCount; - u_int32_t Free; - u_int32_t Deleted; + uint32_t Offset; + uint32_t EraseCount; + uint32_t Free; + uint32_t Deleted; } *EUNInfo; struct xfer_info_t { - u_int32_t Offset; - u_int32_t EraseCount; - u_int16_t state; + uint32_t Offset; + uint32_t EraseCount; + uint16_t state; } *XferInfo; - u_int16_t bam_index; - u_int32_t *bam_cache; - u_int16_t DataUnits; - u_int32_t BlocksPerUnit; + uint16_t bam_index; + uint32_t *bam_cache; + uint16_t DataUnits; + uint32_t BlocksPerUnit; erase_unit_header_t header; } partition_t; @@ -199,8 +199,8 @@ static int scan_header(partition_t *part) static int build_maps(partition_t *part) { erase_unit_header_t header; - u_int16_t xvalid, xtrans, i; - u_int blocks, j; + uint16_t xvalid, xtrans, i; + unsigned blocks, j; int hdr_ok, ret = -1; ssize_t retval; loff_t offset; @@ -269,14 +269,14 @@ static int build_maps(partition_t *part) /* Set up virtual page map */ blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize; - part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t)); + part->VirtualBlockMap = vmalloc(blocks * sizeof(uint32_t)); if (!part->VirtualBlockMap) goto out_XferInfo; - memset(part->VirtualBlockMap, 0xff, blocks * sizeof(u_int32_t)); + memset(part->VirtualBlockMap, 0xff, blocks * sizeof(uint32_t)); part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize; - part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(u_int32_t), + part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(uint32_t), GFP_KERNEL); if (!part->bam_cache) goto out_VirtualBlockMap; @@ -290,7 +290,7 @@ static int build_maps(partition_t *part) offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset); ret = part->mbd.mtd->read(part->mbd.mtd, offset, - part->BlocksPerUnit * sizeof(u_int32_t), &retval, + part->BlocksPerUnit * sizeof(uint32_t), &retval, (unsigned char *)part->bam_cache); if (ret) @@ -332,7 +332,7 @@ out: ======================================================================*/ static int erase_xfer(partition_t *part, - u_int16_t xfernum) + uint16_t xfernum) { int ret; struct xfer_info_t *xfer; @@ -408,7 +408,7 @@ static int prepare_xfer(partition_t *part, int i) erase_unit_header_t header; struct xfer_info_t *xfer; int nbam, ret; - u_int32_t ctl; + uint32_t ctl; ssize_t retlen; loff_t offset; @@ -430,15 +430,15 @@ static int prepare_xfer(partition_t *part, int i) } /* Write the BAM stub */ - nbam = (part->BlocksPerUnit * sizeof(u_int32_t) + + nbam = (part->BlocksPerUnit * sizeof(uint32_t) + le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE; offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset); ctl = cpu_to_le32(BLOCK_CONTROL); - for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) { + for (i = 0; i < nbam; i++, offset += sizeof(uint32_t)) { - ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), + ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen, (u_char *)&ctl); if (ret) @@ -461,18 +461,18 @@ static int prepare_xfer(partition_t *part, int i) ======================================================================*/ -static int copy_erase_unit(partition_t *part, u_int16_t srcunit, - u_int16_t xferunit) +static int copy_erase_unit(partition_t *part, uint16_t srcunit, + uint16_t xferunit) { u_char buf[SECTOR_SIZE]; struct eun_info_t *eun; struct xfer_info_t *xfer; - u_int32_t src, dest, free, i; - u_int16_t unit; + uint32_t src, dest, free, i; + uint16_t unit; int ret; ssize_t retlen; loff_t offset; - u_int16_t srcunitswap = cpu_to_le16(srcunit); + uint16_t srcunitswap = cpu_to_le16(srcunit); eun = &part->EUNInfo[srcunit]; xfer = &part->XferInfo[xferunit]; @@ -486,7 +486,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, offset = eun->Offset + le32_to_cpu(part->header.BAMOffset); ret = part->mbd.mtd->read(part->mbd.mtd, offset, - part->BlocksPerUnit * sizeof(u_int32_t), + part->BlocksPerUnit * sizeof(uint32_t), &retlen, (u_char *) (part->bam_cache)); /* mark the cache bad, in case we get an error later */ @@ -503,7 +503,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, offset = xfer->Offset + 20; /* Bad! */ unit = cpu_to_le16(0x7fff); - ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t), + ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(uint16_t), &retlen, (u_char *) &unit); if (ret) { @@ -560,7 +560,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, /* All clear? Then update the LogicalEUN again */ - ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t), + ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(uint16_t), &retlen, (u_char *)&srcunitswap); if (ret) { @@ -605,8 +605,8 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, static int reclaim_block(partition_t *part) { - u_int16_t i, eun, xfer; - u_int32_t best; + uint16_t i, eun, xfer; + uint32_t best; int queued, ret; DEBUG(0, "ftl_cs: reclaiming space...\n"); @@ -723,10 +723,10 @@ static void dump_lists(partition_t *part) } #endif -static u_int32_t find_free(partition_t *part) +static uint32_t find_free(partition_t *part) { - u_int16_t stop, eun; - u_int32_t blk; + uint16_t stop, eun; + uint32_t blk; size_t retlen; int ret; @@ -749,7 +749,7 @@ static u_int32_t find_free(partition_t *part) ret = part->mbd.mtd->read(part->mbd.mtd, part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset), - part->BlocksPerUnit * sizeof(u_int32_t), + part->BlocksPerUnit * sizeof(uint32_t), &retlen, (u_char *) (part->bam_cache)); if (ret) { @@ -786,7 +786,7 @@ static u_int32_t find_free(partition_t *part) static int ftl_read(partition_t *part, caddr_t buffer, u_long sector, u_long nblocks) { - u_int32_t log_addr, bsize; + uint32_t log_addr, bsize; u_long i; int ret; size_t offset, retlen; @@ -829,14 +829,14 @@ static int ftl_read(partition_t *part, caddr_t buffer, ======================================================================*/ -static int set_bam_entry(partition_t *part, u_int32_t log_addr, - u_int32_t virt_addr) +static int set_bam_entry(partition_t *part, uint32_t log_addr, + uint32_t virt_addr) { - u_int32_t bsize, blk, le_virt_addr; + uint32_t bsize, blk, le_virt_addr; #ifdef PSYCHO_DEBUG - u_int32_t old_addr; + uint32_t old_addr; #endif - u_int16_t eun; + uint16_t eun; int ret; size_t retlen, offset; @@ -845,11 +845,11 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr, bsize = 1 << part->header.EraseUnitSize; eun = log_addr / bsize; blk = (log_addr % bsize) / SECTOR_SIZE; - offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) + + offset = (part->EUNInfo[eun].Offset + blk * sizeof(uint32_t) + le32_to_cpu(part->header.BAMOffset)); #ifdef PSYCHO_DEBUG - ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t), + ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(uint32_t), &retlen, (u_char *)&old_addr); if (ret) { printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret); @@ -886,7 +886,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr, #endif part->bam_cache[blk] = le_virt_addr; } - ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), + ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen, (u_char *)&le_virt_addr); if (ret) { @@ -900,7 +900,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr, static int ftl_write(partition_t *part, caddr_t buffer, u_long sector, u_long nblocks) { - u_int32_t bsize, log_addr, virt_addr, old_addr, blk; + uint32_t bsize, log_addr, virt_addr, old_addr, blk; u_long i; int ret; size_t retlen, offset; diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 50ce13887f63..73f05227dc8c 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -50,7 +50,7 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) struct INFTLrecord *inftl; unsigned long temp; - if (mtd->type != MTD_NANDFLASH) + if (mtd->type != MTD_NANDFLASH || mtd->size > UINT_MAX) return; /* OK, this is moderately ugly. But probably safe. Alternatives? */ if (memcmp(mtd->name, "DiskOnChip", 10)) diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 9113628ed1ef..f751dd97c549 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -63,7 +63,7 @@ static int find_boot_record(struct INFTLrecord *inftl) * otherwise. */ inftl->EraseSize = inftl->mbd.mtd->erasesize; - inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize; + inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize; inftl->MediaUnit = BLOCK_NIL; @@ -187,7 +187,7 @@ static int find_boot_record(struct INFTLrecord *inftl) mh->BlockMultiplierBits); inftl->EraseSize = inftl->mbd.mtd->erasesize << mh->BlockMultiplierBits; - inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize; + inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize; block >>= mh->BlockMultiplierBits; } diff --git a/drivers/mtd/lpddr/Kconfig b/drivers/mtd/lpddr/Kconfig new file mode 100644 index 000000000000..acd4ea9b2278 --- /dev/null +++ b/drivers/mtd/lpddr/Kconfig @@ -0,0 +1,22 @@ +# drivers/mtd/chips/Kconfig + +menu "LPDDR flash memory drivers" + depends on MTD!=n + +config MTD_LPDDR + tristate "Support for LPDDR flash chips" + select MTD_QINFO_PROBE + help + This option enables support of LPDDR (Low power double data rate) + flash chips. Synonymous with Mobile-DDR. It is a new standard for + DDR memories, intended for battery-operated systems. + +config MTD_QINFO_PROBE + tristate "Detect flash chips by QINFO probe" + help + Device Information for LPDDR chips is offered through the Overlay + Window QINFO interface, permits software to be used for entire + families of devices. This serves similar purpose of CFI on legacy + Flash products +endmenu + diff --git a/drivers/mtd/lpddr/Makefile b/drivers/mtd/lpddr/Makefile new file mode 100644 index 000000000000..da48e46b5812 --- /dev/null +++ b/drivers/mtd/lpddr/Makefile @@ -0,0 +1,6 @@ +# +# linux/drivers/mtd/lpddr/Makefile +# + +obj-$(CONFIG_MTD_QINFO_PROBE) += qinfo_probe.o +obj-$(CONFIG_MTD_LPDDR) += lpddr_cmds.o diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c new file mode 100644 index 000000000000..e22ca49583e7 --- /dev/null +++ b/drivers/mtd/lpddr/lpddr_cmds.c @@ -0,0 +1,796 @@ +/* + * LPDDR flash memory device operations. This module provides read, write, + * erase, lock/unlock support for LPDDR flash memories + * (C) 2008 Korolev Alexey <akorolev@infradead.org> + * (C) 2008 Vasiliy Leonenko <vasiliy.leonenko@gmail.com> + * Many thanks to Roman Borisov for intial enabling + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * TODO: + * Implement VPP management + * Implement XIP support + * Implement OTP support + */ +#include <linux/mtd/pfow.h> +#include <linux/mtd/qinfo.h> + +static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len, + size_t *retlen, u_char *buf); +static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to, + size_t len, size_t *retlen, const u_char *buf); +static int lpddr_writev(struct mtd_info *mtd, const struct kvec *vecs, + unsigned long count, loff_t to, size_t *retlen); +static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr); +static int lpddr_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len, + size_t *retlen, void **mtdbuf, resource_size_t *phys); +static void lpddr_unpoint(struct mtd_info *mtd, loff_t adr, size_t len); +static int get_chip(struct map_info *map, struct flchip *chip, int mode); +static int chip_ready(struct map_info *map, struct flchip *chip, int mode); +static void put_chip(struct map_info *map, struct flchip *chip); + +struct mtd_info *lpddr_cmdset(struct map_info *map) +{ + struct lpddr_private *lpddr = map->fldrv_priv; + struct flchip_shared *shared; + struct flchip *chip; + struct mtd_info *mtd; + int numchips; + int i, j; + + mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); + if (!mtd) { + printk(KERN_ERR "Failed to allocate memory for MTD device\n"); + return NULL; + } + mtd->priv = map; + mtd->type = MTD_NORFLASH; + + /* Fill in the default mtd operations */ + mtd->read = lpddr_read; + mtd->type = MTD_NORFLASH; + mtd->flags = MTD_CAP_NORFLASH; + mtd->flags &= ~MTD_BIT_WRITEABLE; + mtd->erase = lpddr_erase; + mtd->write = lpddr_write_buffers; + mtd->writev = lpddr_writev; + mtd->read_oob = NULL; + mtd->write_oob = NULL; + mtd->sync = NULL; + mtd->lock = lpddr_lock; + mtd->unlock = lpddr_unlock; + mtd->suspend = NULL; + mtd->resume = NULL; + if (map_is_linear(map)) { + mtd->point = lpddr_point; + mtd->unpoint = lpddr_unpoint; + } + mtd->block_isbad = NULL; + mtd->block_markbad = NULL; + mtd->size = 1 << lpddr->qinfo->DevSizeShift; + mtd->erasesize = 1 << lpddr->qinfo->UniformBlockSizeShift; + mtd->writesize = 1 << lpddr->qinfo->BufSizeShift; + + shared = kmalloc(sizeof(struct flchip_shared) * lpddr->numchips, + GFP_KERNEL); + if (!shared) { + kfree(lpddr); + kfree(mtd); + return NULL; + } + + chip = &lpddr->chips[0]; + numchips = lpddr->numchips / lpddr->qinfo->HWPartsNum; + for (i = 0; i < numchips; i++) { + shared[i].writing = shared[i].erasing = NULL; + spin_lock_init(&shared[i].lock); + for (j = 0; j < lpddr->qinfo->HWPartsNum; j++) { + *chip = lpddr->chips[i]; + chip->start += j << lpddr->chipshift; + chip->oldstate = chip->state = FL_READY; + chip->priv = &shared[i]; + /* those should be reset too since + they create memory references. */ + init_waitqueue_head(&chip->wq); + spin_lock_init(&chip->_spinlock); + chip->mutex = &chip->_spinlock; + chip++; + } + } + + return mtd; +} +EXPORT_SYMBOL(lpddr_cmdset); + +static int wait_for_ready(struct map_info *map, struct flchip *chip, + unsigned int chip_op_time) +{ + unsigned int timeo, reset_timeo, sleep_time; + unsigned int dsr; + flstate_t chip_state = chip->state; + int ret = 0; + + /* set our timeout to 8 times the expected delay */ + timeo = chip_op_time * 8; + if (!timeo) + timeo = 500000; + reset_timeo = timeo; + sleep_time = chip_op_time / 2; + + for (;;) { + dsr = CMDVAL(map_read(map, map->pfow_base + PFOW_DSR)); + if (dsr & DSR_READY_STATUS) + break; + if (!timeo) { + printk(KERN_ERR "%s: Flash timeout error state %d \n", + map->name, chip_state); + ret = -ETIME; + break; + } + + /* OK Still waiting. Drop the lock, wait a while and retry. */ + spin_unlock(chip->mutex); + if (sleep_time >= 1000000/HZ) { + /* + * Half of the normal delay still remaining + * can be performed with a sleeping delay instead + * of busy waiting. + */ + msleep(sleep_time/1000); + timeo -= sleep_time; + sleep_time = 1000000/HZ; + } else { + udelay(1); + cond_resched(); + timeo--; + } + spin_lock(chip->mutex); + + while (chip->state != chip_state) { + /* Someone's suspended the operation: sleep */ + DECLARE_WAITQUEUE(wait, current); + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + spin_lock(chip->mutex); + } + if (chip->erase_suspended || chip->write_suspended) { + /* Suspend has occured while sleep: reset timeout */ + timeo = reset_timeo; + chip->erase_suspended = chip->write_suspended = 0; + } + } + /* check status for errors */ + if (dsr & DSR_ERR) { + /* Clear DSR*/ + map_write(map, CMD(~(DSR_ERR)), map->pfow_base + PFOW_DSR); + printk(KERN_WARNING"%s: Bad status on wait: 0x%x \n", + map->name, dsr); + print_drs_error(dsr); + ret = -EIO; + } + chip->state = FL_READY; + return ret; +} + +static int get_chip(struct map_info *map, struct flchip *chip, int mode) +{ + int ret; + DECLARE_WAITQUEUE(wait, current); + + retry: + if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING) + && chip->state != FL_SYNCING) { + /* + * OK. We have possibility for contension on the write/erase + * operations which are global to the real chip and not per + * partition. So let's fight it over in the partition which + * currently has authority on the operation. + * + * The rules are as follows: + * + * - any write operation must own shared->writing. + * + * - any erase operation must own _both_ shared->writing and + * shared->erasing. + * + * - contension arbitration is handled in the owner's context. + * + * The 'shared' struct can be read and/or written only when + * its lock is taken. + */ + struct flchip_shared *shared = chip->priv; + struct flchip *contender; + spin_lock(&shared->lock); + contender = shared->writing; + if (contender && contender != chip) { + /* + * The engine to perform desired operation on this + * partition is already in use by someone else. + * Let's fight over it in the context of the chip + * currently using it. If it is possible to suspend, + * that other partition will do just that, otherwise + * it'll happily send us to sleep. In any case, when + * get_chip returns success we're clear to go ahead. + */ + ret = spin_trylock(contender->mutex); + spin_unlock(&shared->lock); + if (!ret) + goto retry; + spin_unlock(chip->mutex); + ret = chip_ready(map, contender, mode); + spin_lock(chip->mutex); + + if (ret == -EAGAIN) { + spin_unlock(contender->mutex); + goto retry; + } + if (ret) { + spin_unlock(contender->mutex); + return ret; + } + spin_lock(&shared->lock); + + /* We should not own chip if it is already in FL_SYNCING + * state. Put contender and retry. */ + if (chip->state == FL_SYNCING) { + put_chip(map, contender); + spin_unlock(contender->mutex); + goto retry; + } + spin_unlock(contender->mutex); + } + + /* Check if we have suspended erase on this chip. + Must sleep in such a case. */ + if (mode == FL_ERASING && shared->erasing + && shared->erasing->oldstate == FL_ERASING) { + spin_unlock(&shared->lock); + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + spin_lock(chip->mutex); + goto retry; + } + + /* We now own it */ + shared->writing = chip; + if (mode == FL_ERASING) + shared->erasing = chip; + spin_unlock(&shared->lock); + } + + ret = chip_ready(map, chip, mode); + if (ret == -EAGAIN) + goto retry; + + return ret; +} + +static int chip_ready(struct map_info *map, struct flchip *chip, int mode) +{ + struct lpddr_private *lpddr = map->fldrv_priv; + int ret = 0; + DECLARE_WAITQUEUE(wait, current); + + /* Prevent setting state FL_SYNCING for chip in suspended state. */ + if (FL_SYNCING == mode && FL_READY != chip->oldstate) + goto sleep; + + switch (chip->state) { + case FL_READY: + case FL_JEDEC_QUERY: + return 0; + + case FL_ERASING: + if (!lpddr->qinfo->SuspEraseSupp || + !(mode == FL_READY || mode == FL_POINT)) + goto sleep; + + map_write(map, CMD(LPDDR_SUSPEND), + map->pfow_base + PFOW_PROGRAM_ERASE_SUSPEND); + chip->oldstate = FL_ERASING; + chip->state = FL_ERASE_SUSPENDING; + ret = wait_for_ready(map, chip, 0); + if (ret) { + /* Oops. something got wrong. */ + /* Resume and pretend we weren't here. */ + map_write(map, CMD(LPDDR_RESUME), + map->pfow_base + PFOW_COMMAND_CODE); + map_write(map, CMD(LPDDR_START_EXECUTION), + map->pfow_base + PFOW_COMMAND_EXECUTE); + chip->state = FL_ERASING; + chip->oldstate = FL_READY; + printk(KERN_ERR "%s: suspend operation failed." + "State may be wrong \n", map->name); + return -EIO; + } + chip->erase_suspended = 1; + chip->state = FL_READY; + return 0; + /* Erase suspend */ + case FL_POINT: + /* Only if there's no operation suspended... */ + if (mode == FL_READY && chip->oldstate == FL_READY) + return 0; + + default: +sleep: + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + spin_lock(chip->mutex); + return -EAGAIN; + } +} + +static void put_chip(struct map_info *map, struct flchip *chip) +{ + if (chip->priv) { + struct flchip_shared *shared = chip->priv; + spin_lock(&shared->lock); + if (shared->writing == chip && chip->oldstate == FL_READY) { + /* We own the ability to write, but we're done */ + shared->writing = shared->erasing; + if (shared->writing && shared->writing != chip) { + /* give back the ownership */ + struct flchip *loaner = shared->writing; + spin_lock(loaner->mutex); + spin_unlock(&shared->lock); + spin_unlock(chip->mutex); + put_chip(map, loaner); + spin_lock(chip->mutex); + spin_unlock(loaner->mutex); + wake_up(&chip->wq); + return; + } + shared->erasing = NULL; + shared->writing = NULL; + } else if (shared->erasing == chip && shared->writing != chip) { + /* + * We own the ability to erase without the ability + * to write, which means the erase was suspended + * and some other partition is currently writing. + * Don't let the switch below mess things up since + * we don't have ownership to resume anything. + */ + spin_unlock(&shared->lock); + wake_up(&chip->wq); + return; + } + spin_unlock(&shared->lock); + } + + switch (chip->oldstate) { + case FL_ERASING: + chip->state = chip->oldstate; + map_write(map, CMD(LPDDR_RESUME), + map->pfow_base + PFOW_COMMAND_CODE); + map_write(map, CMD(LPDDR_START_EXECUTION), + map->pfow_base + PFOW_COMMAND_EXECUTE); + chip->oldstate = FL_READY; + chip->state = FL_ERASING; + break; + case FL_READY: + break; + default: + printk(KERN_ERR "%s: put_chip() called with oldstate %d!\n", + map->name, chip->oldstate); + } + wake_up(&chip->wq); +} + +int do_write_buffer(struct map_info *map, struct flchip *chip, + unsigned long adr, const struct kvec **pvec, + unsigned long *pvec_seek, int len) +{ + struct lpddr_private *lpddr = map->fldrv_priv; + map_word datum; + int ret, wbufsize, word_gap, words; + const struct kvec *vec; + unsigned long vec_seek; + unsigned long prog_buf_ofs; + + wbufsize = 1 << lpddr->qinfo->BufSizeShift; + + spin_lock(chip->mutex); + ret = get_chip(map, chip, FL_WRITING); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } + /* Figure out the number of words to write */ + word_gap = (-adr & (map_bankwidth(map)-1)); + words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map); + if (!word_gap) { + words--; + } else { + word_gap = map_bankwidth(map) - word_gap; + adr -= word_gap; + datum = map_word_ff(map); + } + /* Write data */ + /* Get the program buffer offset from PFOW register data first*/ + prog_buf_ofs = map->pfow_base + CMDVAL(map_read(map, + map->pfow_base + PFOW_PROGRAM_BUFFER_OFFSET)); + vec = *pvec; + vec_seek = *pvec_seek; + do { + int n = map_bankwidth(map) - word_gap; + + if (n > vec->iov_len - vec_seek) + n = vec->iov_len - vec_seek; + if (n > len) + n = len; + + if (!word_gap && (len < map_bankwidth(map))) + datum = map_word_ff(map); + + datum = map_word_load_partial(map, datum, + vec->iov_base + vec_seek, word_gap, n); + + len -= n; + word_gap += n; + if (!len || word_gap == map_bankwidth(map)) { + map_write(map, datum, prog_buf_ofs); + prog_buf_ofs += map_bankwidth(map); + word_gap = 0; + } + + vec_seek += n; + if (vec_seek == vec->iov_len) { + vec++; + vec_seek = 0; + } + } while (len); + *pvec = vec; + *pvec_seek = vec_seek; + + /* GO GO GO */ + send_pfow_command(map, LPDDR_BUFF_PROGRAM, adr, wbufsize, NULL); + chip->state = FL_WRITING; + ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->ProgBufferTime)); + if (ret) { + printk(KERN_WARNING"%s Buffer program error: %d at %lx; \n", + map->name, ret, adr); + goto out; + } + + out: put_chip(map, chip); + spin_unlock(chip->mutex); + return ret; +} + +int do_erase_oneblock(struct mtd_info *mtd, loff_t adr) +{ + struct map_info *map = mtd->priv; + struct lpddr_private *lpddr = map->fldrv_priv; + int chipnum = adr >> lpddr->chipshift; + struct flchip *chip = &lpddr->chips[chipnum]; + int ret; + + spin_lock(chip->mutex); + ret = get_chip(map, chip, FL_ERASING); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } + send_pfow_command(map, LPDDR_BLOCK_ERASE, adr, 0, NULL); + chip->state = FL_ERASING; + ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->BlockEraseTime)*1000); + if (ret) { + printk(KERN_WARNING"%s Erase block error %d at : %llx\n", + map->name, ret, adr); + goto out; + } + out: put_chip(map, chip); + spin_unlock(chip->mutex); + return ret; +} + +static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len, + size_t *retlen, u_char *buf) +{ + struct map_info *map = mtd->priv; + struct lpddr_private *lpddr = map->fldrv_priv; + int chipnum = adr >> lpddr->chipshift; + struct flchip *chip = &lpddr->chips[chipnum]; + int ret = 0; + + spin_lock(chip->mutex); + ret = get_chip(map, chip, FL_READY); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } + + map_copy_from(map, buf, adr, len); + *retlen = len; + + put_chip(map, chip); + spin_unlock(chip->mutex); + return ret; +} + +static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len, + size_t *retlen, void **mtdbuf, resource_size_t *phys) +{ + struct map_info *map = mtd->priv; + struct lpddr_private *lpddr = map->fldrv_priv; + int chipnum = adr >> lpddr->chipshift; + unsigned long ofs, last_end = 0; + struct flchip *chip = &lpddr->chips[chipnum]; + int ret = 0; + + if (!map->virt || (adr + len > mtd->size)) + return -EINVAL; + + /* ofs: offset within the first chip that the first read should start */ + ofs = adr - (chipnum << lpddr->chipshift); + + *mtdbuf = (void *)map->virt + chip->start + ofs; + *retlen = 0; + + while (len) { + unsigned long thislen; + + if (chipnum >= lpddr->numchips) + break; + + /* We cannot point across chips that are virtually disjoint */ + if (!last_end) + last_end = chip->start; + else if (chip->start != last_end) + break; + + if ((len + ofs - 1) >> lpddr->chipshift) + thislen = (1<<lpddr->chipshift) - ofs; + else + thislen = len; + /* get the chip */ + spin_lock(chip->mutex); + ret = get_chip(map, chip, FL_POINT); + spin_unlock(chip->mutex); + if (ret) + break; + + chip->state = FL_POINT; + chip->ref_point_counter++; + *retlen += thislen; + len -= thislen; + + ofs = 0; + last_end += 1 << lpddr->chipshift; + chipnum++; + chip = &lpddr->chips[chipnum]; + } + return 0; +} + +static void lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len) +{ + struct map_info *map = mtd->priv; + struct lpddr_private *lpddr = map->fldrv_priv; + int chipnum = adr >> lpddr->chipshift; + unsigned long ofs; + + /* ofs: offset within the first chip that the first read should start */ + ofs = adr - (chipnum << lpddr->chipshift); + + while (len) { + unsigned long thislen; + struct flchip *chip; + + chip = &lpddr->chips[chipnum]; + if (chipnum >= lpddr->numchips) + break; + + if ((len + ofs - 1) >> lpddr->chipshift) + thislen = (1<<lpddr->chipshift) - ofs; + else + thislen = len; + + spin_lock(chip->mutex); + if (chip->state == FL_POINT) { + chip->ref_point_counter--; + if (chip->ref_point_counter == 0) + chip->state = FL_READY; + } else + printk(KERN_WARNING "%s: Warning: unpoint called on non" + "pointed region\n", map->name); + + put_chip(map, chip); + spin_unlock(chip->mutex); + + len -= thislen; + ofs = 0; + chipnum++; + } +} + +static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct kvec vec; + + vec.iov_base = (void *) buf; + vec.iov_len = len; + + return lpddr_writev(mtd, &vec, 1, to, retlen); +} + + +static int lpddr_writev(struct mtd_info *mtd, const struct kvec *vecs, + unsigned long count, loff_t to, size_t *retlen) +{ + struct map_info *map = mtd->priv; + struct lpddr_private *lpddr = map->fldrv_priv; + int ret = 0; + int chipnum; + unsigned long ofs, vec_seek, i; + int wbufsize = 1 << lpddr->qinfo->BufSizeShift; + + size_t len = 0; + + for (i = 0; i < count; i++) + len += vecs[i].iov_len; + + *retlen = 0; + if (!len) + return 0; + + chipnum = to >> lpddr->chipshift; + + ofs = to; + vec_seek = 0; + + do { + /* We must not cross write block boundaries */ + int size = wbufsize - (ofs & (wbufsize-1)); + + if (size > len) + size = len; + + ret = do_write_buffer(map, &lpddr->chips[chipnum], + ofs, &vecs, &vec_seek, size); + if (ret) + return ret; + + ofs += size; + (*retlen) += size; + len -= size; + + /* Be nice and reschedule with the chip in a usable + * state for other processes */ + cond_resched(); + + } while (len); + + return 0; +} + +static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + unsigned long ofs, len; + int ret; + struct map_info *map = mtd->priv; + struct lpddr_private *lpddr = map->fldrv_priv; + int size = 1 << lpddr->qinfo->UniformBlockSizeShift; + + ofs = instr->addr; + len = instr->len; + + if (ofs > mtd->size || (len + ofs) > mtd->size) + return -EINVAL; + + while (len > 0) { + ret = do_erase_oneblock(mtd, ofs); + if (ret) + return ret; + ofs += size; + len -= size; + } + instr->state = MTD_ERASE_DONE; + mtd_erase_callback(instr); + + return 0; +} + +#define DO_XXLOCK_LOCK 1 +#define DO_XXLOCK_UNLOCK 2 +int do_xxlock(struct mtd_info *mtd, loff_t adr, uint32_t len, int thunk) +{ + int ret = 0; + struct map_info *map = mtd->priv; + struct lpddr_private *lpddr = map->fldrv_priv; + int chipnum = adr >> lpddr->chipshift; + struct flchip *chip = &lpddr->chips[chipnum]; + + spin_lock(chip->mutex); + ret = get_chip(map, chip, FL_LOCKING); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } + + if (thunk == DO_XXLOCK_LOCK) { + send_pfow_command(map, LPDDR_LOCK_BLOCK, adr, adr + len, NULL); + chip->state = FL_LOCKING; + } else if (thunk == DO_XXLOCK_UNLOCK) { + send_pfow_command(map, LPDDR_UNLOCK_BLOCK, adr, adr + len, NULL); + chip->state = FL_UNLOCKING; + } else + BUG(); + + ret = wait_for_ready(map, chip, 1); + if (ret) { + printk(KERN_ERR "%s: block unlock error status %d \n", + map->name, ret); + goto out; + } +out: put_chip(map, chip); + spin_unlock(chip->mutex); + return ret; +} + +static int lpddr_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + return do_xxlock(mtd, ofs, len, DO_XXLOCK_LOCK); +} + +static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + return do_xxlock(mtd, ofs, len, DO_XXLOCK_UNLOCK); +} + +int word_program(struct map_info *map, loff_t adr, uint32_t curval) +{ + int ret; + struct lpddr_private *lpddr = map->fldrv_priv; + int chipnum = adr >> lpddr->chipshift; + struct flchip *chip = &lpddr->chips[chipnum]; + + spin_lock(chip->mutex); + ret = get_chip(map, chip, FL_WRITING); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } + + send_pfow_command(map, LPDDR_WORD_PROGRAM, adr, 0x00, (map_word *)&curval); + + ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->SingleWordProgTime)); + if (ret) { + printk(KERN_WARNING"%s word_program error at: %llx; val: %x\n", + map->name, adr, curval); + goto out; + } + +out: put_chip(map, chip); + spin_unlock(chip->mutex); + return ret; +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alexey Korolev <akorolev@infradead.org>"); +MODULE_DESCRIPTION("MTD driver for LPDDR flash chips"); diff --git a/drivers/mtd/lpddr/qinfo_probe.c b/drivers/mtd/lpddr/qinfo_probe.c new file mode 100644 index 000000000000..79bf40f48b75 --- /dev/null +++ b/drivers/mtd/lpddr/qinfo_probe.c @@ -0,0 +1,255 @@ +/* + * Probing flash chips with QINFO records. + * (C) 2008 Korolev Alexey <akorolev@infradead.org> + * (C) 2008 Vasiliy Leonenko <vasiliy.leonenko@gmail.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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/interrupt.h> + +#include <linux/mtd/xip.h> +#include <linux/mtd/map.h> +#include <linux/mtd/pfow.h> +#include <linux/mtd/qinfo.h> + +static int lpddr_chip_setup(struct map_info *map, struct lpddr_private *lpddr); +struct mtd_info *lpddr_probe(struct map_info *map); +static struct lpddr_private *lpddr_probe_chip(struct map_info *map); +static int lpddr_pfow_present(struct map_info *map, + struct lpddr_private *lpddr); + +static struct qinfo_query_info qinfo_array[] = { + /* General device info */ + {0, 0, "DevSizeShift", "Device size 2^n bytes"}, + {0, 3, "BufSizeShift", "Program buffer size 2^n bytes"}, + /* Erase block information */ + {1, 1, "TotalBlocksNum", "Total number of blocks"}, + {1, 2, "UniformBlockSizeShift", "Uniform block size 2^n bytes"}, + /* Partition information */ + {2, 1, "HWPartsNum", "Number of hardware partitions"}, + /* Optional features */ + {5, 1, "SuspEraseSupp", "Suspend erase supported"}, + /* Operation typical time */ + {10, 0, "SingleWordProgTime", "Single word program 2^n u-sec"}, + {10, 1, "ProgBufferTime", "Program buffer write 2^n u-sec"}, + {10, 2, "BlockEraseTime", "Block erase 2^n m-sec"}, + {10, 3, "FullChipEraseTime", "Full chip erase 2^n m-sec"}, +}; + +static long lpddr_get_qinforec_pos(struct map_info *map, char *id_str) +{ + int qinfo_lines = sizeof(qinfo_array)/sizeof(struct qinfo_query_info); + int i; + int bankwidth = map_bankwidth(map) * 8; + int major, minor; + + for (i = 0; i < qinfo_lines; i++) { + if (strcmp(id_str, qinfo_array[i].id_str) == 0) { + major = qinfo_array[i].major & ((1 << bankwidth) - 1); + minor = qinfo_array[i].minor & ((1 << bankwidth) - 1); + return minor | (major << bankwidth); + } + } + printk(KERN_ERR"%s qinfo id string is wrong! \n", map->name); + BUG(); + return -1; +} + +static uint16_t lpddr_info_query(struct map_info *map, char *id_str) +{ + unsigned int dsr, val; + int bits_per_chip = map_bankwidth(map) * 8; + unsigned long adr = lpddr_get_qinforec_pos(map, id_str); + int attempts = 20; + + /* Write a request for the PFOW record */ + map_write(map, CMD(LPDDR_INFO_QUERY), + map->pfow_base + PFOW_COMMAND_CODE); + map_write(map, CMD(adr & ((1 << bits_per_chip) - 1)), + map->pfow_base + PFOW_COMMAND_ADDRESS_L); + map_write(map, CMD(adr >> bits_per_chip), + map->pfow_base + PFOW_COMMAND_ADDRESS_H); + map_write(map, CMD(LPDDR_START_EXECUTION), + map->pfow_base + PFOW_COMMAND_EXECUTE); + + while ((attempts--) > 0) { + dsr = CMDVAL(map_read(map, map->pfow_base + PFOW_DSR)); + if (dsr & DSR_READY_STATUS) + break; + udelay(10); + } + + val = CMDVAL(map_read(map, map->pfow_base + PFOW_COMMAND_DATA)); + return val; +} + +static int lpddr_pfow_present(struct map_info *map, struct lpddr_private *lpddr) +{ + map_word pfow_val[4]; + + /* Check identification string */ + pfow_val[0] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_P); + pfow_val[1] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_F); + pfow_val[2] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_O); + pfow_val[3] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_W); + + if (!map_word_equal(map, CMD('P'), pfow_val[0])) + goto out; + + if (!map_word_equal(map, CMD('F'), pfow_val[1])) + goto out; + + if (!map_word_equal(map, CMD('O'), pfow_val[2])) + goto out; + + if (!map_word_equal(map, CMD('W'), pfow_val[3])) + goto out; + + return 1; /* "PFOW" is found */ +out: + printk(KERN_WARNING"%s: PFOW string at 0x%lx is not found \n", + map->name, map->pfow_base); + return 0; +} + +static int lpddr_chip_setup(struct map_info *map, struct lpddr_private *lpddr) +{ + + lpddr->qinfo = kmalloc(sizeof(struct qinfo_chip), GFP_KERNEL); + if (!lpddr->qinfo) { + printk(KERN_WARNING "%s: no memory for LPDDR qinfo structure\n", + map->name); + return 0; + } + memset(lpddr->qinfo, 0, sizeof(struct qinfo_chip)); + + /* Get the ManuID */ + lpddr->ManufactId = CMDVAL(map_read(map, map->pfow_base + PFOW_MANUFACTURER_ID)); + /* Get the DeviceID */ + lpddr->DevId = CMDVAL(map_read(map, map->pfow_base + PFOW_DEVICE_ID)); + /* read parameters from chip qinfo table */ + lpddr->qinfo->DevSizeShift = lpddr_info_query(map, "DevSizeShift"); + lpddr->qinfo->TotalBlocksNum = lpddr_info_query(map, "TotalBlocksNum"); + lpddr->qinfo->BufSizeShift = lpddr_info_query(map, "BufSizeShift"); + lpddr->qinfo->HWPartsNum = lpddr_info_query(map, "HWPartsNum"); + lpddr->qinfo->UniformBlockSizeShift = + lpddr_info_query(map, "UniformBlockSizeShift"); + lpddr->qinfo->SuspEraseSupp = lpddr_info_query(map, "SuspEraseSupp"); + lpddr->qinfo->SingleWordProgTime = + lpddr_info_query(map, "SingleWordProgTime"); + lpddr->qinfo->ProgBufferTime = lpddr_info_query(map, "ProgBufferTime"); + lpddr->qinfo->BlockEraseTime = lpddr_info_query(map, "BlockEraseTime"); + return 1; +} +static struct lpddr_private *lpddr_probe_chip(struct map_info *map) +{ + struct lpddr_private lpddr; + struct lpddr_private *retlpddr; + int numvirtchips; + + + if ((map->pfow_base + 0x1000) >= map->size) { + printk(KERN_NOTICE"%s Probe at base (0x%08lx) past the end of" + "the map(0x%08lx)\n", map->name, + (unsigned long)map->pfow_base, map->size - 1); + return NULL; + } + memset(&lpddr, 0, sizeof(struct lpddr_private)); + if (!lpddr_pfow_present(map, &lpddr)) + return NULL; + + if (!lpddr_chip_setup(map, &lpddr)) + return NULL; + + /* Ok so we found a chip */ + lpddr.chipshift = lpddr.qinfo->DevSizeShift; + lpddr.numchips = 1; + + numvirtchips = lpddr.numchips * lpddr.qinfo->HWPartsNum; + retlpddr = kmalloc(sizeof(struct lpddr_private) + + numvirtchips * sizeof(struct flchip), GFP_KERNEL); + if (!retlpddr) + return NULL; + + memset(retlpddr, 0, sizeof(struct lpddr_private) + + numvirtchips * sizeof(struct flchip)); + memcpy(retlpddr, &lpddr, sizeof(struct lpddr_private)); + + retlpddr->numchips = numvirtchips; + retlpddr->chipshift = retlpddr->qinfo->DevSizeShift - + __ffs(retlpddr->qinfo->HWPartsNum); + + return retlpddr; +} + +struct mtd_info *lpddr_probe(struct map_info *map) +{ + struct mtd_info *mtd = NULL; + struct lpddr_private *lpddr; + + /* First probe the map to see if we havecan open PFOW here */ + lpddr = lpddr_probe_chip(map); + if (!lpddr) + return NULL; + + map->fldrv_priv = lpddr; + mtd = lpddr_cmdset(map); + if (mtd) { + if (mtd->size > map->size) { + printk(KERN_WARNING "Reducing visibility of %ldKiB chip" + "to %ldKiB\n", (unsigned long)mtd->size >> 10, + (unsigned long)map->size >> 10); + mtd->size = map->size; + } + return mtd; + } + + kfree(lpddr->qinfo); + kfree(lpddr); + map->fldrv_priv = NULL; + return NULL; +} + +static struct mtd_chip_driver lpddr_chipdrv = { + .probe = lpddr_probe, + .name = "qinfo_probe", + .module = THIS_MODULE +}; + +static int __init lpddr_probe_init(void) +{ + register_mtd_chip_driver(&lpddr_chipdrv); + return 0; +} + +static void __exit lpddr_probe_exit(void) +{ + unregister_mtd_chip_driver(&lpddr_chipdrv); +} + +module_init(lpddr_probe_init); +module_exit(lpddr_probe_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vasiliy Leonenko <vasiliy.leonenko@gmail.com>"); +MODULE_DESCRIPTION("Driver to probe qinfo flash chips"); + diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 5ea169362164..0225cbbf22de 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -10,8 +10,8 @@ config MTD_COMPLEX_MAPPINGS paged mappings of flash chips. config MTD_PHYSMAP - tristate "CFI Flash device in physical memory map" - depends on MTD_CFI || MTD_JEDECPROBE || MTD_ROM + tristate "Flash device in physical memory map" + depends on MTD_CFI || MTD_JEDECPROBE || MTD_ROM || MTD_LPDDR help This provides a 'mapping' driver which allows the NOR Flash and ROM driver code to communicate with chips which are mapped @@ -23,9 +23,20 @@ config MTD_PHYSMAP To compile this driver as a module, choose M here: the module will be called physmap. +config MTD_PHYSMAP_COMPAT + bool "Physmap compat support" + depends on MTD_PHYSMAP + default n + help + Setup a simple mapping via the Kconfig options. Normally the + physmap configuration options are done via your board's + resource file. + + If unsure, say N here. + config MTD_PHYSMAP_START hex "Physical start address of flash mapping" - depends on MTD_PHYSMAP + depends on MTD_PHYSMAP_COMPAT default "0x8000000" help This is the physical memory location at which the flash chips @@ -37,7 +48,7 @@ config MTD_PHYSMAP_START config MTD_PHYSMAP_LEN hex "Physical length of flash mapping" - depends on MTD_PHYSMAP + depends on MTD_PHYSMAP_COMPAT default "0" help This is the total length of the mapping of the flash chips on @@ -51,7 +62,7 @@ config MTD_PHYSMAP_LEN config MTD_PHYSMAP_BANKWIDTH int "Bank width in octets" - depends on MTD_PHYSMAP + depends on MTD_PHYSMAP_COMPAT default "2" help This is the total width of the data bus of the flash devices diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c index 82811bcb0436..845ad4f2a542 100644 --- a/drivers/mtd/maps/alchemy-flash.c +++ b/drivers/mtd/maps/alchemy-flash.c @@ -111,7 +111,7 @@ static struct mtd_partition alchemy_partitions[] = { static struct mtd_info *mymtd; -int __init alchemy_mtd_init(void) +static int __init alchemy_mtd_init(void) { struct mtd_partition *parts; int nb_parts = 0; diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index d1eec7d3243f..237733d094c4 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -232,8 +232,8 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, /* Trim the size if we are larger than the map */ if (map->mtd->size > map->map.size) { printk(KERN_WARNING MOD_NAME - " rom(%u) larger than window(%lu). fixing...\n", - map->mtd->size, map->map.size); + " rom(%llu) larger than window(%lu). fixing...\n", + (unsigned long long)map->mtd->size, map->map.size); map->mtd->size = map->map.size; } if (window->rsrc.parent) { diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c index 0ecc3f6d735b..b4ed81611918 100644 --- a/drivers/mtd/maps/cfi_flagadm.c +++ b/drivers/mtd/maps/cfi_flagadm.c @@ -88,7 +88,7 @@ struct mtd_partition flagadm_parts[] = { static struct mtd_info *mymtd; -int __init init_flagadm(void) +static int __init init_flagadm(void) { printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n", FLASH_SIZE, FLASH_PHYS_ADDR); diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c index 1a6feb4474de..5f7a245ed132 100644 --- a/drivers/mtd/maps/ck804xrom.c +++ b/drivers/mtd/maps/ck804xrom.c @@ -263,8 +263,8 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev, /* Trim the size if we are larger than the map */ if (map->mtd->size > map->map.size) { printk(KERN_WARNING MOD_NAME - " rom(%u) larger than window(%lu). fixing...\n", - map->mtd->size, map->map.size); + " rom(%llu) larger than window(%lu). fixing...\n", + (unsigned long long)map->mtd->size, map->map.size); map->mtd->size = map->map.size; } if (window->rsrc.parent) { diff --git a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c index e115667bf1d0..cfacfa6f45dd 100644 --- a/drivers/mtd/maps/dbox2-flash.c +++ b/drivers/mtd/maps/dbox2-flash.c @@ -69,7 +69,7 @@ struct map_info dbox2_flash_map = { .phys = WINDOW_ADDR, }; -int __init init_dbox2_flash(void) +static int __init init_dbox2_flash(void) { printk(KERN_NOTICE "D-Box 2 flash driver (size->0x%X mem->0x%X)\n", WINDOW_SIZE, WINDOW_ADDR); dbox2_flash_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c index 9433738c1664..be9e90b44587 100644 --- a/drivers/mtd/maps/edb7312.c +++ b/drivers/mtd/maps/edb7312.c @@ -71,7 +71,7 @@ static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; static int mtd_parts_nb = 0; static struct mtd_partition *mtd_parts = 0; -int __init init_edb7312nor(void) +static int __init init_edb7312nor(void) { static const char *rom_probe_types[] = PROBETYPES; const char **type; diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c index bbbcdd4c8d13..11a2f57df9cf 100644 --- a/drivers/mtd/maps/esb2rom.c +++ b/drivers/mtd/maps/esb2rom.c @@ -324,8 +324,8 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev, /* Trim the size if we are larger than the map */ if (map->mtd->size > map->map.size) { printk(KERN_WARNING MOD_NAME - " rom(%u) larger than window(%lu). fixing...\n", - map->mtd->size, map->map.size); + " rom(%llu) larger than window(%lu). fixing...\n", + (unsigned long long)map->mtd->size, map->map.size); map->mtd->size = map->map.size; } if (window->rsrc.parent) { diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c index a8e3fde4cbd5..1e43124d498b 100644 --- a/drivers/mtd/maps/fortunet.c +++ b/drivers/mtd/maps/fortunet.c @@ -181,7 +181,7 @@ __setup("MTD_Partition=", MTD_New_Partition); /* Backwards-spelling-compatibility */ __setup("MTD_Partion=", MTD_New_Partition); -int __init init_fortunet(void) +static int __init init_fortunet(void) { int ix,iy; for(iy=ix=0;ix<MAX_NUM_REGIONS;ix++) diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c index 3b959fad1c4e..72c724fa8c27 100644 --- a/drivers/mtd/maps/h720x-flash.c +++ b/drivers/mtd/maps/h720x-flash.c @@ -65,7 +65,7 @@ static const char *probes[] = { "cmdlinepart", NULL }; /* * Initialize FLASH support */ -int __init h720x_mtd_init(void) +static int __init h720x_mtd_init(void) { char *part_type = NULL; diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index aeb6c916e23f..c32bc28920b3 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -258,8 +258,8 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, /* Trim the size if we are larger than the map */ if (map->mtd->size > map->map.size) { printk(KERN_WARNING MOD_NAME - " rom(%u) larger than window(%lu). fixing...\n", - map->mtd->size, map->map.size); + " rom(%llu) larger than window(%lu). fixing...\n", + (unsigned long long)map->mtd->size, map->map.size); map->mtd->size = map->map.size; } if (window->rsrc.parent) { diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index 2682ab51a367..998a27da97f3 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c @@ -70,7 +70,7 @@ static struct mtd_partition *mtd_parts[NUM_FLASHBANKS]; static const char *probes[] = { "cmdlinepart", NULL }; -int __init init_impa7(void) +static int __init init_impa7(void) { static const char *rom_probe_types[] = PROBETYPES; const char **type; diff --git a/drivers/mtd/maps/ipaq-flash.c b/drivers/mtd/maps/ipaq-flash.c index ed58f6a77bd9..748c85f635f1 100644 --- a/drivers/mtd/maps/ipaq-flash.c +++ b/drivers/mtd/maps/ipaq-flash.c @@ -202,7 +202,7 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; static int __init h1900_special_case(void); -int __init ipaq_mtd_init(void) +static int __init ipaq_mtd_init(void) { struct mtd_partition *parts = NULL; int nb_parts = 0; diff --git a/drivers/mtd/maps/mbx860.c b/drivers/mtd/maps/mbx860.c index 706f67394b07..0eb5a7c85380 100644 --- a/drivers/mtd/maps/mbx860.c +++ b/drivers/mtd/maps/mbx860.c @@ -55,7 +55,7 @@ struct map_info mbx_map = { .bankwidth = 4, }; -int __init init_mbx(void) +static int __init init_mbx(void) { printk(KERN_NOTICE "Motorola MBX flash device: 0x%x at 0x%x\n", WINDOW_SIZE*4, WINDOW_ADDR); mbx_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index 965e6c6d6ab0..a97133eb9d70 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c @@ -226,7 +226,7 @@ static int __init nettel_init(void) if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) { printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n", - amd_mtd->size>>10); + (int)(amd_mtd->size>>10)); amd_mtd->owner = THIS_MODULE; @@ -357,13 +357,12 @@ static int __init nettel_init(void) *intel1par = 0; } - printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %dK\n", - (intel_mtd->size >> 10)); + printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %lldKiB\n", + (unsigned long long)(intel_mtd->size >> 10)); intel_mtd->owner = THIS_MODULE; - num_intel_partitions = sizeof(nettel_intel_partitions) / - sizeof(nettel_intel_partitions[0]); + num_intel_partitions = ARRAY_SIZE(nettel_intel_partitions); if (intelboot) { /* diff --git a/drivers/mtd/maps/octagon-5066.c b/drivers/mtd/maps/octagon-5066.c index 43e04c1d22a9..2b2e45093218 100644 --- a/drivers/mtd/maps/octagon-5066.c +++ b/drivers/mtd/maps/octagon-5066.c @@ -184,7 +184,7 @@ void cleanup_oct5066(void) release_region(PAGE_IO, 1); } -int __init init_oct5066(void) +static int __init init_oct5066(void) { int i; int ret = 0; diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index 1db16e549e38..87743661d48e 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -29,7 +29,6 @@ struct physmap_flash_info { struct map_info map[MAX_RESOURCES]; #ifdef CONFIG_MTD_PARTITIONS int nr_parts; - struct mtd_partition *parts; #endif }; @@ -56,14 +55,10 @@ static int physmap_flash_remove(struct platform_device *dev) for (i = 0; i < MAX_RESOURCES; i++) { if (info->mtd[i] != NULL) { #ifdef CONFIG_MTD_PARTITIONS - if (info->nr_parts) { + if (info->nr_parts || physmap_data->nr_parts) del_mtd_partitions(info->mtd[i]); - kfree(info->parts); - } else if (physmap_data->nr_parts) { - del_mtd_partitions(info->mtd[i]); - } else { + else del_mtd_device(info->mtd[i]); - } #else del_mtd_device(info->mtd[i]); #endif @@ -73,7 +68,12 @@ static int physmap_flash_remove(struct platform_device *dev) return 0; } -static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL }; +static const char *rom_probe_types[] = { + "cfi_probe", + "jedec_probe", + "qinfo_probe", + "map_rom", + NULL }; #ifdef CONFIG_MTD_PARTITIONS static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; #endif @@ -86,6 +86,9 @@ static int physmap_flash_probe(struct platform_device *dev) int err = 0; int i; int devices_found = 0; +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *parts; +#endif physmap_data = dev->dev.platform_data; if (physmap_data == NULL) @@ -119,6 +122,7 @@ static int physmap_flash_probe(struct platform_device *dev) info->map[i].size = dev->resource[i].end - dev->resource[i].start + 1; info->map[i].bankwidth = physmap_data->width; info->map[i].set_vpp = physmap_data->set_vpp; + info->map[i].pfow_base = physmap_data->pfow_base; info->map[i].virt = devm_ioremap(&dev->dev, info->map[i].phys, info->map[i].size); @@ -163,9 +167,10 @@ static int physmap_flash_probe(struct platform_device *dev) goto err_out; #ifdef CONFIG_MTD_PARTITIONS - err = parse_mtd_partitions(info->cmtd, part_probe_types, &info->parts, 0); + err = parse_mtd_partitions(info->cmtd, part_probe_types, &parts, 0); if (err > 0) { - add_mtd_partitions(info->cmtd, info->parts, err); + add_mtd_partitions(info->cmtd, parts, err); + kfree(parts); return 0; } @@ -251,14 +256,7 @@ static struct platform_driver physmap_flash_driver = { }; -#ifdef CONFIG_MTD_PHYSMAP_LEN -#if CONFIG_MTD_PHYSMAP_LEN != 0 -#warning using PHYSMAP compat code -#define PHYSMAP_COMPAT -#endif -#endif - -#ifdef PHYSMAP_COMPAT +#ifdef CONFIG_MTD_PHYSMAP_COMPAT static struct physmap_flash_data physmap_flash_data = { .width = CONFIG_MTD_PHYSMAP_BANKWIDTH, }; @@ -302,7 +300,7 @@ static int __init physmap_init(void) int err; err = platform_driver_register(&physmap_flash_driver); -#ifdef PHYSMAP_COMPAT +#ifdef CONFIG_MTD_PHYSMAP_COMPAT if (err == 0) platform_device_register(&physmap_flash); #endif @@ -312,7 +310,7 @@ static int __init physmap_init(void) static void __exit physmap_exit(void) { -#ifdef PHYSMAP_COMPAT +#ifdef CONFIG_MTD_PHYSMAP_COMPAT platform_device_unregister(&physmap_flash); #endif platform_driver_unregister(&physmap_flash_driver); @@ -326,8 +324,7 @@ MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); MODULE_DESCRIPTION("Generic configurable MTD map driver"); /* legacy platform drivers can't hotplug or coldplg */ -#ifndef PHYSMAP_COMPAT +#ifndef CONFIG_MTD_PHYSMAP_COMPAT /* work with hotplug and coldplug */ MODULE_ALIAS("platform:physmap-flash"); #endif - diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c index f43ba2815cbb..4768bd5459d6 100644 --- a/drivers/mtd/maps/pmcmsp-flash.c +++ b/drivers/mtd/maps/pmcmsp-flash.c @@ -48,7 +48,7 @@ static int fcnt; #define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n", __func__, __LINE__) -int __init init_msp_flash(void) +static int __init init_msp_flash(void) { int i, j; int offset, coff; diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c index de002eb1a7fe..933c0b63b016 100644 --- a/drivers/mtd/maps/redwood.c +++ b/drivers/mtd/maps/redwood.c @@ -122,7 +122,7 @@ struct map_info redwood_flash_map = { static struct mtd_info *redwood_mtd; -int __init init_redwood_flash(void) +static int __init init_redwood_flash(void) { int err; diff --git a/drivers/mtd/maps/rpxlite.c b/drivers/mtd/maps/rpxlite.c index 14d90edb4430..3e3ef53d4fd4 100644 --- a/drivers/mtd/maps/rpxlite.c +++ b/drivers/mtd/maps/rpxlite.c @@ -23,7 +23,7 @@ static struct map_info rpxlite_map = { .phys = WINDOW_ADDR, }; -int __init init_rpxlite(void) +static int __init init_rpxlite(void) { printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR); rpxlite_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c index 6e1e99cd2b59..d5374cdcb163 100644 --- a/drivers/mtd/maps/sbc8240.c +++ b/drivers/mtd/maps/sbc8240.c @@ -136,7 +136,7 @@ static struct mtd_part_def sbc8240_part_banks[NUM_FLASH_BANKS]; #endif /* CONFIG_MTD_PARTITIONS */ -int __init init_sbc8240_mtd (void) +static int __init init_sbc8240_mtd (void) { static struct _cjs { u_long addr; diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c index 21169e6d646c..7e329f09a548 100644 --- a/drivers/mtd/maps/scb2_flash.c +++ b/drivers/mtd/maps/scb2_flash.c @@ -118,7 +118,8 @@ scb2_fixup_mtd(struct mtd_info *mtd) struct mtd_erase_region_info *region = &mtd->eraseregions[i]; if (region->numblocks * region->erasesize > mtd->size) { - region->numblocks = (mtd->size / region->erasesize); + region->numblocks = ((unsigned long)mtd->size / + region->erasesize); done = 1; } else { region->numblocks = 0; @@ -187,8 +188,9 @@ scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent) return -ENODEV; } - printk(KERN_NOTICE MODNAME ": chip size 0x%x at offset 0x%x\n", - scb2_mtd->size, SCB2_WINDOW - scb2_mtd->size); + printk(KERN_NOTICE MODNAME ": chip size 0x%llx at offset 0x%llx\n", + (unsigned long long)scb2_mtd->size, + (unsigned long long)(SCB2_WINDOW - scb2_mtd->size)); add_mtd_device(scb2_mtd); diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c index 026eab028189..b392f096c706 100644 --- a/drivers/mtd/maps/sharpsl-flash.c +++ b/drivers/mtd/maps/sharpsl-flash.c @@ -47,7 +47,7 @@ static struct mtd_partition sharpsl_partitions[1] = { } }; -int __init init_sharpsl(void) +static int __init init_sharpsl(void) { struct mtd_partition *parts; int nb_parts = 0; diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c index a5d3d8531faa..60146984f4be 100644 --- a/drivers/mtd/maps/tqm8xxl.c +++ b/drivers/mtd/maps/tqm8xxl.c @@ -109,7 +109,7 @@ static struct mtd_partition tqm8xxl_fs_partitions[] = { }; #endif -int __init init_tqm_mtd(void) +static int __init init_tqm_mtd(void) { int idx = 0, ret = 0; unsigned long flash_addr, flash_size, mtd_size = 0; diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index 0dc645f8152f..81756e397711 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -51,7 +51,7 @@ int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len, /****************************************************************************/ -int __init uclinux_mtd_init(void) +static int __init uclinux_mtd_init(void) { struct mtd_info *mtd; struct map_info *mapp; @@ -94,7 +94,7 @@ int __init uclinux_mtd_init(void) /****************************************************************************/ -void __exit uclinux_mtd_cleanup(void) +static void __exit uclinux_mtd_cleanup(void) { if (uclinux_ram_mtdinfo) { del_mtd_partitions(uclinux_ram_mtdinfo); diff --git a/drivers/mtd/maps/vmax301.c b/drivers/mtd/maps/vmax301.c index 5a0c9a353b0f..6d452dcdfe34 100644 --- a/drivers/mtd/maps/vmax301.c +++ b/drivers/mtd/maps/vmax301.c @@ -146,7 +146,7 @@ static void __exit cleanup_vmax301(void) iounmap((void *)vmax_map[0].map_priv_1 - WINDOW_START); } -int __init init_vmax301(void) +static int __init init_vmax301(void) { int i; unsigned long iomapadr; diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c index 413b0cf9bbd2..933a2b6598b4 100644 --- a/drivers/mtd/maps/wr_sbc82xx_flash.c +++ b/drivers/mtd/maps/wr_sbc82xx_flash.c @@ -74,7 +74,7 @@ do { \ } \ } while (0); -int __init init_sbc82xx_flash(void) +static int __init init_sbc82xx_flash(void) { volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl; int bigflash; diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index bcffeda2df3d..e9ec59e9a566 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -450,16 +450,20 @@ static int mtd_ioctl(struct inode *inode, struct file *file, if (!erase) ret = -ENOMEM; else { + struct erase_info_user einfo; + wait_queue_head_t waitq; DECLARE_WAITQUEUE(wait, current); init_waitqueue_head(&waitq); - if (copy_from_user(&erase->addr, argp, + if (copy_from_user(&einfo, argp, sizeof(struct erase_info_user))) { kfree(erase); return -EFAULT; } + erase->addr = einfo.start; + erase->len = einfo.length; erase->mtd = mtd; erase->callback = mtdchar_erase_callback; erase->priv = (unsigned long)&waitq; diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 1a05cf37851e..3dbb1b38db66 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -197,7 +197,7 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs, continue; } - size = min(total_len, (size_t)(subdev->size - to)); + size = min_t(uint64_t, total_len, subdev->size - to); wsize = size; /* store for future use */ entry_high = entry_low; @@ -385,7 +385,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) struct mtd_concat *concat = CONCAT(mtd); struct mtd_info *subdev; int i, err; - u_int32_t length, offset = 0; + uint64_t length, offset = 0; struct erase_info *erase; if (!(mtd->flags & MTD_WRITEABLE)) @@ -518,7 +518,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) return 0; } -static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_concat *concat = CONCAT(mtd); int i, err = -EINVAL; @@ -528,7 +528,7 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len) for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; - size_t size; + uint64_t size; if (ofs >= subdev->size) { size = 0; @@ -556,7 +556,7 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len) return err; } -static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_concat *concat = CONCAT(mtd); int i, err = 0; @@ -566,7 +566,7 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; - size_t size; + uint64_t size; if (ofs >= subdev->size) { size = 0; @@ -696,7 +696,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c int i; size_t size; struct mtd_concat *concat; - u_int32_t max_erasesize, curr_erasesize; + uint32_t max_erasesize, curr_erasesize; int num_erase_region; printk(KERN_NOTICE "Concatenating MTD devices:\n"); @@ -842,12 +842,14 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.erasesize = curr_erasesize; concat->mtd.numeraseregions = 0; } else { + uint64_t tmp64; + /* * erase block size varies across the subdevices: allocate * space to store the data describing the variable erase regions */ struct mtd_erase_region_info *erase_region_p; - u_int32_t begin, position; + uint64_t begin, position; concat->mtd.erasesize = max_erasesize; concat->mtd.numeraseregions = num_erase_region; @@ -879,8 +881,9 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c erase_region_p->offset = begin; erase_region_p->erasesize = curr_erasesize; - erase_region_p->numblocks = - (position - begin) / curr_erasesize; + tmp64 = position - begin; + do_div(tmp64, curr_erasesize); + erase_region_p->numblocks = tmp64; begin = position; curr_erasesize = subdev[i]->erasesize; @@ -897,9 +900,9 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c erase_region_p->offset = begin; erase_region_p->erasesize = curr_erasesize; - erase_region_p->numblocks = - (position - - begin) / curr_erasesize; + tmp64 = position - begin; + do_div(tmp64, curr_erasesize); + erase_region_p->numblocks = tmp64; begin = position; curr_erasesize = @@ -909,14 +912,16 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c } position += subdev[i]->eraseregions[j]. - numblocks * curr_erasesize; + numblocks * (uint64_t)curr_erasesize; } } } /* Now write the final entry */ erase_region_p->offset = begin; erase_region_p->erasesize = curr_erasesize; - erase_region_p->numblocks = (position - begin) / curr_erasesize; + tmp64 = position - begin; + do_div(tmp64, curr_erasesize); + erase_region_p->numblocks = tmp64; } return &concat->mtd; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index a9d246949820..76fe0a1e7a5e 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -57,6 +57,19 @@ int add_mtd_device(struct mtd_info *mtd) mtd->index = i; mtd->usecount = 0; + if (is_power_of_2(mtd->erasesize)) + mtd->erasesize_shift = ffs(mtd->erasesize) - 1; + else + mtd->erasesize_shift = 0; + + if (is_power_of_2(mtd->writesize)) + mtd->writesize_shift = ffs(mtd->writesize) - 1; + else + mtd->writesize_shift = 0; + + mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1; + mtd->writesize_mask = (1 << mtd->writesize_shift) - 1; + /* Some chips always power up locked. Unlock them now */ if ((mtd->flags & MTD_WRITEABLE) && (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) { @@ -344,7 +357,8 @@ static inline int mtd_proc_info (char *buf, int i) if (!this) return 0; - return sprintf(buf, "mtd%d: %8.8x %8.8x \"%s\"\n", i, this->size, + return sprintf(buf, "mtd%d: %8.8llx %8.8x \"%s\"\n", i, + (unsigned long long)this->size, this->erasesize, this->name); } diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index aebb3b27edbd..1a6b3beabe8d 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -80,9 +80,9 @@ static int mtdoops_erase_block(struct mtd_info *mtd, int offset) if (ret) { set_current_state(TASK_RUNNING); remove_wait_queue(&wait_q, &wait); - printk (KERN_WARNING "mtdoops: erase of region [0x%x, 0x%x] " + printk (KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] " "on \"%s\" failed\n", - erase.addr, erase.len, mtd->name); + (unsigned long long)erase.addr, (unsigned long long)erase.len, mtd->name); return ret; } @@ -289,7 +289,10 @@ static void mtdoops_notify_add(struct mtd_info *mtd) } cxt->mtd = mtd; - cxt->oops_pages = mtd->size / OOPS_PAGE_SIZE; + if (mtd->size > INT_MAX) + cxt->oops_pages = INT_MAX / OOPS_PAGE_SIZE; + else + cxt->oops_pages = (int)mtd->size / OOPS_PAGE_SIZE; find_next_position(cxt); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 3728913fa5fa..144e6b613a77 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -26,7 +26,7 @@ static LIST_HEAD(mtd_partitions); struct mtd_part { struct mtd_info mtd; struct mtd_info *master; - u_int32_t offset; + uint64_t offset; int index; struct list_head list; int registered; @@ -235,7 +235,7 @@ void mtd_erase_callback(struct erase_info *instr) } EXPORT_SYMBOL_GPL(mtd_erase_callback); -static int part_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_part *part = PART(mtd); if ((len + ofs) > mtd->size) @@ -243,7 +243,7 @@ static int part_lock(struct mtd_info *mtd, loff_t ofs, size_t len) return part->master->lock(part->master, ofs + part->offset, len); } -static int part_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_part *part = PART(mtd); if ((len + ofs) > mtd->size) @@ -317,7 +317,7 @@ EXPORT_SYMBOL(del_mtd_partitions); static struct mtd_part *add_one_partition(struct mtd_info *master, const struct mtd_partition *part, int partno, - u_int32_t cur_offset) + uint64_t cur_offset) { struct mtd_part *slave; @@ -395,19 +395,19 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, slave->offset = cur_offset; if (slave->offset == MTDPART_OFS_NXTBLK) { slave->offset = cur_offset; - if ((cur_offset % master->erasesize) != 0) { + if (mtd_mod_by_eb(cur_offset, master) != 0) { /* Round up to next erasesize */ - slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize; + slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize; printk(KERN_NOTICE "Moving partition %d: " - "0x%08x -> 0x%08x\n", partno, - cur_offset, slave->offset); + "0x%012llx -> 0x%012llx\n", partno, + (unsigned long long)cur_offset, (unsigned long long)slave->offset); } } if (slave->mtd.size == MTDPART_SIZ_FULL) slave->mtd.size = master->size - slave->offset; - printk(KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, - slave->offset + slave->mtd.size, slave->mtd.name); + printk(KERN_NOTICE "0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset, + (unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name); /* let's do some sanity checks */ if (slave->offset >= master->size) { @@ -420,13 +420,13 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, } if (slave->offset + slave->mtd.size > master->size) { slave->mtd.size = master->size - slave->offset; - printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n", - part->name, master->name, slave->mtd.size); + printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n", + part->name, master->name, (unsigned long long)slave->mtd.size); } if (master->numeraseregions > 1) { /* Deal with variable erase size stuff */ int i, max = master->numeraseregions; - u32 end = slave->offset + slave->mtd.size; + u64 end = slave->offset + slave->mtd.size; struct mtd_erase_region_info *regions = master->eraseregions; /* Find the first erase regions which is part of this @@ -449,7 +449,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, } if ((slave->mtd.flags & MTD_WRITEABLE) && - (slave->offset % slave->mtd.erasesize)) { + mtd_mod_by_eb(slave->offset, &slave->mtd)) { /* Doesn't start on a boundary of major erase size */ /* FIXME: Let it be writable if it is on a boundary of * _minor_ erase size though */ @@ -458,7 +458,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, part->name); } if ((slave->mtd.flags & MTD_WRITEABLE) && - (slave->mtd.size % slave->mtd.erasesize)) { + mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) { slave->mtd.flags &= ~MTD_WRITEABLE; printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", part->name); @@ -466,7 +466,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, slave->mtd.ecclayout = master->ecclayout; if (master->block_isbad) { - uint32_t offs = 0; + uint64_t offs = 0; while (offs < slave->mtd.size) { if (master->block_isbad(master, @@ -501,7 +501,7 @@ int add_mtd_partitions(struct mtd_info *master, int nbparts) { struct mtd_part *slave; - u_int32_t cur_offset = 0; + uint64_t cur_offset = 0; int i; printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index f8ae0400c49c..8b12e6e109d3 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -163,6 +163,13 @@ config MTD_NAND_S3C2410_HWECC incorrect ECC generation, and if using these, the default of software ECC is preferable. +config MTD_NAND_NDFC + tristate "NDFC NanD Flash Controller" + depends on 4xx + select MTD_NAND_ECC_SMC + help + NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs + config MTD_NAND_S3C2410_CLKSTOP bool "S3C2410 NAND IDLE clock stop" depends on MTD_NAND_S3C2410 diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c index 962380394855..6d9649159a18 100644 --- a/drivers/mtd/nand/alauda.c +++ b/drivers/mtd/nand/alauda.c @@ -676,11 +676,11 @@ static int alauda_probe(struct usb_interface *interface, goto error; al->write_out = usb_sndbulkpipe(al->dev, - ep_wr->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + usb_endpoint_num(ep_wr)); al->bulk_in = usb_rcvbulkpipe(al->dev, - ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + usb_endpoint_num(ep_in)); al->bulk_out = usb_sndbulkpipe(al->dev, - ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + usb_endpoint_num(ep_out)); /* second device is identical up to now */ memcpy(al+1, al, sizeof(*al)); diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index b8064bf3aee4..22a6b2e50e91 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -90,7 +90,7 @@ static int timing[3]; module_param_array(timing, int, &numtimings, 0644); #ifdef CONFIG_MTD_PARTITIONS -static const char *part_probes[] = { "RedBoot", NULL }; +static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; #endif /* Hrm. Why isn't this already conditional on something in the struct device? */ @@ -805,10 +805,13 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, add_mtd_device(mtd); #ifdef CONFIG_MTD_PARTITIONS +#ifdef CONFIG_MTD_CMDLINE_PARTS + mtd->name = "cafe_nand"; +#endif nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0); if (nr_parts > 0) { cafe->parts = parts; - dev_info(&cafe->pdev->dev, "%d RedBoot partitions found\n", nr_parts); + dev_info(&cafe->pdev->dev, "%d partitions found\n", nr_parts); add_mtd_partitions(mtd, parts, nr_parts); } #endif diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 4aa5bd6158da..65929db29446 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -777,7 +777,9 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) /* Fill in fsl_elbc_mtd structure */ priv->mtd.priv = chip; priv->mtd.owner = THIS_MODULE; - priv->fmr = 0; /* rest filled in later */ + + /* Set the ECCM according to the settings in bootloader.*/ + priv->fmr = in_be32(&lbc->fmr) & FMR_ECCM; /* fill in nand_chip structure */ /* set up function call table */ diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 0a9c9cd33f96..0c3afccde8a2 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2014,13 +2014,14 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt) { - int page, len, status, pages_per_block, ret, chipnr; + int page, status, pages_per_block, ret, chipnr; struct nand_chip *chip = mtd->priv; - int rewrite_bbt[NAND_MAX_CHIPS]={0}; + loff_t rewrite_bbt[NAND_MAX_CHIPS]={0}; unsigned int bbt_masked_page = 0xffffffff; + loff_t len; - DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n", - (unsigned int)instr->addr, (unsigned int)instr->len); + DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%012llx, len = %llu\n", + (unsigned long long)instr->addr, (unsigned long long)instr->len); /* Start address must align on block boundary */ if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) { @@ -2116,7 +2117,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); instr->state = MTD_ERASE_FAILED; - instr->fail_addr = (page << chip->page_shift); + instr->fail_addr = + ((loff_t)page << chip->page_shift); goto erase_exit; } @@ -2126,7 +2128,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, */ if (bbt_masked_page != 0xffffffff && (page & BBT_PAGE_MASK) == bbt_masked_page) - rewrite_bbt[chipnr] = (page << chip->page_shift); + rewrite_bbt[chipnr] = + ((loff_t)page << chip->page_shift); /* Increment page address and decrement length */ len -= (1 << chip->phys_erase_shift); @@ -2173,7 +2176,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, continue; /* update the BBT for chip */ DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt " - "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr], + "(%d:0x%0llx 0x%0x)\n", chipnr, rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]); nand_update_bbt(mtd, rewrite_bbt[chipnr]); } @@ -2365,7 +2368,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, if (!mtd->name) mtd->name = type->name; - chip->chipsize = type->chipsize << 20; + chip->chipsize = (uint64_t)type->chipsize << 20; /* Newer devices have all the information in additional id bytes */ if (!type->pagesize) { @@ -2423,7 +2426,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->bbt_erase_shift = chip->phys_erase_shift = ffs(mtd->erasesize) - 1; - chip->chip_shift = ffs(chip->chipsize) - 1; + if (chip->chipsize & 0xffffffff) + chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; + else + chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1; /* Set the bad block position */ chip->badblockpos = mtd->writesize > 512 ? @@ -2517,7 +2523,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips) /** * nand_scan_tail - [NAND Interface] Scan for the NAND device * @mtd: MTD device structure - * @maxchips: Number of chips to scan for * * This is the second phase of the normal nand_scan() function. It * fills out all the uninitialized function pointers with the defaults diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 0b1c48595f12..55c23e5cd210 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -171,16 +171,16 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, if (tmp == msk) continue; if (reserved_block_code && (tmp == reserved_block_code)) { - printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n", - ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n", + (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); mtd->ecc_stats.bbtblocks++; continue; } /* Leave it for now, if its matured we can move this * message to MTD_DEBUG_LEVEL0 */ - printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", - ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n", + (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); /* Factory marked bad or worn out ? */ if (tmp == 0) this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); @@ -284,7 +284,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, /* Read the primary version, if available */ if (td->options & NAND_BBT_VERSION) { - scan_read_raw(mtd, buf, td->pages[0] << this->page_shift, + scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, mtd->writesize); td->version[0] = buf[mtd->writesize + td->veroffs]; printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", @@ -293,7 +293,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, /* Read the mirror version, if available */ if (md && (md->options & NAND_BBT_VERSION)) { - scan_read_raw(mtd, buf, md->pages[0] << this->page_shift, + scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, mtd->writesize); md->version[0] = buf[mtd->writesize + md->veroffs]; printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", @@ -411,7 +411,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, numblocks = this->chipsize >> (this->bbt_erase_shift - 1); startblock = chip * numblocks; numblocks += startblock; - from = startblock << (this->bbt_erase_shift - 1); + from = (loff_t)startblock << (this->bbt_erase_shift - 1); } for (i = startblock; i < numblocks;) { @@ -428,8 +428,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, if (ret) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); - printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", - i >> 1, (unsigned int)from); + printk(KERN_WARNING "Bad eraseblock %d at 0x%012llx\n", + i >> 1, (unsigned long long)from); mtd->ecc_stats.badblocks++; } @@ -495,7 +495,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr for (block = 0; block < td->maxblocks; block++) { int actblock = startblock + dir * block; - loff_t offs = actblock << this->bbt_erase_shift; + loff_t offs = (loff_t)actblock << this->bbt_erase_shift; /* Read first page */ scan_read_raw(mtd, buf, offs, mtd->writesize); @@ -719,7 +719,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, memset(&einfo, 0, sizeof(einfo)); einfo.mtd = mtd; - einfo.addr = (unsigned long)to; + einfo.addr = to; einfo.len = 1 << this->bbt_erase_shift; res = nand_erase_nand(mtd, &einfo, 1); if (res < 0) @@ -729,8 +729,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (res < 0) goto outerr; - printk(KERN_DEBUG "Bad block table written to 0x%08x, version " - "0x%02X\n", (unsigned int)to, td->version[chip]); + printk(KERN_DEBUG "Bad block table written to 0x%012llx, version " + "0x%02X\n", (unsigned long long)to, td->version[chip]); /* Mark it as used */ td->pages[chip] = page; @@ -910,7 +910,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) newval = oldval | (0x2 << (block & 0x06)); this->bbt[(block >> 3)] = newval; if ((oldval != newval) && td->reserved_block_code) - nand_update_bbt(mtd, block << (this->bbt_erase_shift - 1)); + nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1)); continue; } update = 0; @@ -931,7 +931,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) new ones have been marked, then we need to update the stored bbts. This should only happen once. */ if (update && td->reserved_block_code) - nand_update_bbt(mtd, (block - 2) << (this->bbt_erase_shift - 1)); + nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1)); } } @@ -1027,7 +1027,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) if (!this->bbt || !td) return -EINVAL; - len = mtd->size >> (this->bbt_erase_shift + 2); /* Allocate a temporary buffer for one eraseblock incl. oob */ len = (1 << this->bbt_erase_shift); len += (len >> this->page_shift) * mtd->oobsize; diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index ae7c57781a68..cd0711b83ac4 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -38,6 +38,9 @@ #include <linux/delay.h> #include <linux/list.h> #include <linux/random.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/pagemap.h> /* Default simulator parameters values */ #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ @@ -100,6 +103,7 @@ static unsigned int bitflips = 0; static char *gravepages = NULL; static unsigned int rptwear = 0; static unsigned int overridesize = 0; +static char *cache_file = NULL; module_param(first_id_byte, uint, 0400); module_param(second_id_byte, uint, 0400); @@ -122,12 +126,13 @@ module_param(bitflips, uint, 0400); module_param(gravepages, charp, 0400); module_param(rptwear, uint, 0400); module_param(overridesize, uint, 0400); +module_param(cache_file, charp, 0400); MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); -MODULE_PARM_DESC(access_delay, "Initial page access delay (microiseconds)"); +MODULE_PARM_DESC(access_delay, "Initial page access delay (microseconds)"); MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds"); MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)"); MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)"); @@ -153,6 +158,7 @@ MODULE_PARM_DESC(rptwear, "Number of erases inbetween reporting wear, if MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " "The size is specified in erase blocks and as the exponent of a power of two" " e.g. 5 means a size of 32 erase blocks"); +MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory"); /* The largest possible page size */ #define NS_LARGEST_PAGE_SIZE 2048 @@ -266,6 +272,9 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I */ #define NS_MAX_PREVSTATES 1 +/* Maximum page cache pages needed to read or write a NAND page to the cache_file */ +#define NS_MAX_HELD_PAGES 16 + /* * A union to represent flash memory contents and flash buffer. */ @@ -295,6 +304,9 @@ struct nandsim { /* The simulated NAND flash pages array */ union ns_mem *pages; + /* Slab allocator for nand pages */ + struct kmem_cache *nand_pages_slab; + /* Internal buffer of page + OOB size bytes */ union ns_mem buf; @@ -335,6 +347,13 @@ struct nandsim { int ale; /* address Latch Enable */ int wp; /* write Protect */ } lines; + + /* Fields needed when using a cache file */ + struct file *cfile; /* Open file */ + unsigned char *pages_written; /* Which pages have been written */ + void *file_buf; + struct page *held_pages[NS_MAX_HELD_PAGES]; + int held_cnt; }; /* @@ -420,25 +439,69 @@ static struct mtd_info *nsmtd; static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE]; /* - * Allocate array of page pointers and initialize the array to NULL - * pointers. + * Allocate array of page pointers, create slab allocation for an array + * and initialize the array by NULL pointers. * * RETURNS: 0 if success, -ENOMEM if memory alloc fails. */ static int alloc_device(struct nandsim *ns) { - int i; + struct file *cfile; + int i, err; + + if (cache_file) { + cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600); + if (IS_ERR(cfile)) + return PTR_ERR(cfile); + if (!cfile->f_op || (!cfile->f_op->read && !cfile->f_op->aio_read)) { + NS_ERR("alloc_device: cache file not readable\n"); + err = -EINVAL; + goto err_close; + } + if (!cfile->f_op->write && !cfile->f_op->aio_write) { + NS_ERR("alloc_device: cache file not writeable\n"); + err = -EINVAL; + goto err_close; + } + ns->pages_written = vmalloc(ns->geom.pgnum); + if (!ns->pages_written) { + NS_ERR("alloc_device: unable to allocate pages written array\n"); + err = -ENOMEM; + goto err_close; + } + ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL); + if (!ns->file_buf) { + NS_ERR("alloc_device: unable to allocate file buf\n"); + err = -ENOMEM; + goto err_free; + } + ns->cfile = cfile; + memset(ns->pages_written, 0, ns->geom.pgnum); + return 0; + } ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem)); if (!ns->pages) { - NS_ERR("alloc_map: unable to allocate page array\n"); + NS_ERR("alloc_device: unable to allocate page array\n"); return -ENOMEM; } for (i = 0; i < ns->geom.pgnum; i++) { ns->pages[i].byte = NULL; } + ns->nand_pages_slab = kmem_cache_create("nandsim", + ns->geom.pgszoob, 0, 0, NULL); + if (!ns->nand_pages_slab) { + NS_ERR("cache_create: unable to create kmem_cache\n"); + return -ENOMEM; + } return 0; + +err_free: + vfree(ns->pages_written); +err_close: + filp_close(cfile, NULL); + return err; } /* @@ -448,11 +511,20 @@ static void free_device(struct nandsim *ns) { int i; + if (ns->cfile) { + kfree(ns->file_buf); + vfree(ns->pages_written); + filp_close(ns->cfile, NULL); + return; + } + if (ns->pages) { for (i = 0; i < ns->geom.pgnum; i++) { if (ns->pages[i].byte) - kfree(ns->pages[i].byte); + kmem_cache_free(ns->nand_pages_slab, + ns->pages[i].byte); } + kmem_cache_destroy(ns->nand_pages_slab); vfree(ns->pages); } } @@ -464,7 +536,7 @@ static char *get_partition_name(int i) return kstrdup(buf, GFP_KERNEL); } -static u_int64_t divide(u_int64_t n, u_int32_t d) +static uint64_t divide(uint64_t n, uint32_t d) { do_div(n, d); return n; @@ -480,8 +552,8 @@ static int init_nandsim(struct mtd_info *mtd) struct nand_chip *chip = (struct nand_chip *)mtd->priv; struct nandsim *ns = (struct nandsim *)(chip->priv); int i, ret = 0; - u_int64_t remains; - u_int64_t next_offset; + uint64_t remains; + uint64_t next_offset; if (NS_IS_INITIALIZED(ns)) { NS_ERR("init_nandsim: nandsim is already initialized\n"); @@ -548,7 +620,7 @@ static int init_nandsim(struct mtd_info *mtd) remains = ns->geom.totsz; next_offset = 0; for (i = 0; i < parts_num; ++i) { - u_int64_t part_sz = (u_int64_t)parts[i] * ns->geom.secsz; + uint64_t part_sz = (uint64_t)parts[i] * ns->geom.secsz; if (!part_sz || part_sz > remains) { NS_ERR("bad partition size.\n"); @@ -1211,6 +1283,97 @@ static int find_operation(struct nandsim *ns, uint32_t flag) return -1; } +static void put_pages(struct nandsim *ns) +{ + int i; + + for (i = 0; i < ns->held_cnt; i++) + page_cache_release(ns->held_pages[i]); +} + +/* Get page cache pages in advance to provide NOFS memory allocation */ +static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t pos) +{ + pgoff_t index, start_index, end_index; + struct page *page; + struct address_space *mapping = file->f_mapping; + + start_index = pos >> PAGE_CACHE_SHIFT; + end_index = (pos + count - 1) >> PAGE_CACHE_SHIFT; + if (end_index - start_index + 1 > NS_MAX_HELD_PAGES) + return -EINVAL; + ns->held_cnt = 0; + for (index = start_index; index <= end_index; index++) { + page = find_get_page(mapping, index); + if (page == NULL) { + page = find_or_create_page(mapping, index, GFP_NOFS); + if (page == NULL) { + write_inode_now(mapping->host, 1); + page = find_or_create_page(mapping, index, GFP_NOFS); + } + if (page == NULL) { + put_pages(ns); + return -ENOMEM; + } + unlock_page(page); + } + ns->held_pages[ns->held_cnt++] = page; + } + return 0; +} + +static int set_memalloc(void) +{ + if (current->flags & PF_MEMALLOC) + return 0; + current->flags |= PF_MEMALLOC; + return 1; +} + +static void clear_memalloc(int memalloc) +{ + if (memalloc) + current->flags &= ~PF_MEMALLOC; +} + +static ssize_t read_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos) +{ + mm_segment_t old_fs; + ssize_t tx; + int err, memalloc; + + err = get_pages(ns, file, count, *pos); + if (err) + return err; + old_fs = get_fs(); + set_fs(get_ds()); + memalloc = set_memalloc(); + tx = vfs_read(file, (char __user *)buf, count, pos); + clear_memalloc(memalloc); + set_fs(old_fs); + put_pages(ns); + return tx; +} + +static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos) +{ + mm_segment_t old_fs; + ssize_t tx; + int err, memalloc; + + err = get_pages(ns, file, count, *pos); + if (err) + return err; + old_fs = get_fs(); + set_fs(get_ds()); + memalloc = set_memalloc(); + tx = vfs_write(file, (char __user *)buf, count, pos); + clear_memalloc(memalloc); + set_fs(old_fs); + put_pages(ns); + return tx; +} + /* * Returns a pointer to the current page. */ @@ -1227,6 +1390,38 @@ static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns) return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off; } +int do_read_error(struct nandsim *ns, int num) +{ + unsigned int page_no = ns->regs.row; + + if (read_error(page_no)) { + int i; + memset(ns->buf.byte, 0xFF, num); + for (i = 0; i < num; ++i) + ns->buf.byte[i] = random32(); + NS_WARN("simulating read error in page %u\n", page_no); + return 1; + } + return 0; +} + +void do_bit_flips(struct nandsim *ns, int num) +{ + if (bitflips && random32() < (1 << 22)) { + int flips = 1; + if (bitflips > 1) + flips = (random32() % (int) bitflips) + 1; + while (flips--) { + int pos = random32() % (num * 8); + ns->buf.byte[pos / 8] ^= (1 << (pos % 8)); + NS_WARN("read_page: flipping bit %d in page %d " + "reading from %d ecc: corrected=%u failed=%u\n", + pos, ns->regs.row, ns->regs.column + ns->regs.off, + nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed); + } + } +} + /* * Fill the NAND buffer with data read from the specified page. */ @@ -1234,36 +1429,40 @@ static void read_page(struct nandsim *ns, int num) { union ns_mem *mypage; + if (ns->cfile) { + if (!ns->pages_written[ns->regs.row]) { + NS_DBG("read_page: page %d not written\n", ns->regs.row); + memset(ns->buf.byte, 0xFF, num); + } else { + loff_t pos; + ssize_t tx; + + NS_DBG("read_page: page %d written, reading from %d\n", + ns->regs.row, ns->regs.column + ns->regs.off); + if (do_read_error(ns, num)) + return; + pos = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off; + tx = read_file(ns, ns->cfile, ns->buf.byte, num, &pos); + if (tx != num) { + NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx); + return; + } + do_bit_flips(ns, num); + } + return; + } + mypage = NS_GET_PAGE(ns); if (mypage->byte == NULL) { NS_DBG("read_page: page %d not allocated\n", ns->regs.row); memset(ns->buf.byte, 0xFF, num); } else { - unsigned int page_no = ns->regs.row; NS_DBG("read_page: page %d allocated, reading from %d\n", ns->regs.row, ns->regs.column + ns->regs.off); - if (read_error(page_no)) { - int i; - memset(ns->buf.byte, 0xFF, num); - for (i = 0; i < num; ++i) - ns->buf.byte[i] = random32(); - NS_WARN("simulating read error in page %u\n", page_no); + if (do_read_error(ns, num)) return; - } memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); - if (bitflips && random32() < (1 << 22)) { - int flips = 1; - if (bitflips > 1) - flips = (random32() % (int) bitflips) + 1; - while (flips--) { - int pos = random32() % (num * 8); - ns->buf.byte[pos / 8] ^= (1 << (pos % 8)); - NS_WARN("read_page: flipping bit %d in page %d " - "reading from %d ecc: corrected=%u failed=%u\n", - pos, ns->regs.row, ns->regs.column + ns->regs.off, - nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed); - } - } + do_bit_flips(ns, num); } } @@ -1275,11 +1474,20 @@ static void erase_sector(struct nandsim *ns) union ns_mem *mypage; int i; + if (ns->cfile) { + for (i = 0; i < ns->geom.pgsec; i++) + if (ns->pages_written[ns->regs.row + i]) { + NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i); + ns->pages_written[ns->regs.row + i] = 0; + } + return; + } + mypage = NS_GET_PAGE(ns); for (i = 0; i < ns->geom.pgsec; i++) { if (mypage->byte != NULL) { NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i); - kfree(mypage->byte); + kmem_cache_free(ns->nand_pages_slab, mypage->byte); mypage->byte = NULL; } mypage++; @@ -1295,16 +1503,57 @@ static int prog_page(struct nandsim *ns, int num) union ns_mem *mypage; u_char *pg_off; + if (ns->cfile) { + loff_t off, pos; + ssize_t tx; + int all; + + NS_DBG("prog_page: writing page %d\n", ns->regs.row); + pg_off = ns->file_buf + ns->regs.column + ns->regs.off; + off = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off; + if (!ns->pages_written[ns->regs.row]) { + all = 1; + memset(ns->file_buf, 0xff, ns->geom.pgszoob); + } else { + all = 0; + pos = off; + tx = read_file(ns, ns->cfile, pg_off, num, &pos); + if (tx != num) { + NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx); + return -1; + } + } + for (i = 0; i < num; i++) + pg_off[i] &= ns->buf.byte[i]; + if (all) { + pos = (loff_t)ns->regs.row * ns->geom.pgszoob; + tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, &pos); + if (tx != ns->geom.pgszoob) { + NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx); + return -1; + } + ns->pages_written[ns->regs.row] = 1; + } else { + pos = off; + tx = write_file(ns, ns->cfile, pg_off, num, &pos); + if (tx != num) { + NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx); + return -1; + } + } + return 0; + } + mypage = NS_GET_PAGE(ns); if (mypage->byte == NULL) { NS_DBG("prog_page: allocating page %d\n", ns->regs.row); /* * We allocate memory with GFP_NOFS because a flash FS may * utilize this. If it is holding an FS lock, then gets here, - * then kmalloc runs writeback which goes to the FS again - * and deadlocks. This was seen in practice. + * then kernel memory alloc runs writeback which goes to the FS + * again and deadlocks. This was seen in practice. */ - mypage->byte = kmalloc(ns->geom.pgszoob, GFP_NOFS); + mypage->byte = kmem_cache_alloc(ns->nand_pages_slab, GFP_NOFS); if (mypage->byte == NULL) { NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row); return -1; @@ -1736,13 +1985,17 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte) /* Check if chip is expecting command */ if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) { - /* - * We are in situation when something else (not command) - * was expected but command was input. In this case ignore - * previous command(s)/state(s) and accept the last one. - */ - NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, " - "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); + /* Do not warn if only 2 id bytes are read */ + if (!(ns->regs.command == NAND_CMD_READID && + NS_STATE(ns->state) == STATE_DATAOUT_ID && ns->regs.count == 2)) { + /* + * We are in situation when something else (not command) + * was expected but command was input. In this case ignore + * previous command(s)/state(s) and accept the last one. + */ + NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, " + "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); + } switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); } @@ -2044,7 +2297,7 @@ static int __init ns_init_module(void) } if (overridesize) { - u_int64_t new_size = (u_int64_t)nsmtd->erasesize << overridesize; + uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize; if (new_size >> overridesize != nsmtd->erasesize) { NS_ERR("overridesize is too big\n"); goto err_exit; diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 955959eb02d4..582cf80f555a 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -2,12 +2,20 @@ * drivers/mtd/ndfc.c * * Overview: - * Platform independend driver for NDFC (NanD Flash Controller) + * Platform independent driver for NDFC (NanD Flash Controller) * integrated into EP440 cores * + * Ported to an OF platform driver by Sean MacLennan + * + * The NDFC supports multiple chips, but this driver only supports a + * single chip since I do not have access to any boards with + * multiple chips. + * * Author: Thomas Gleixner * * Copyright 2006 IBM + * Copyright 2008 PIKA Technologies + * Sean MacLennan <smaclennan@pikatech.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 @@ -21,27 +29,20 @@ #include <linux/mtd/partitions.h> #include <linux/mtd/ndfc.h> #include <linux/mtd/mtd.h> -#include <linux/platform_device.h> - +#include <linux/of_platform.h> #include <asm/io.h> -#ifdef CONFIG_40x -#include <asm/ibm405.h> -#else -#include <asm/ibm44x.h> -#endif - -struct ndfc_nand_mtd { - struct mtd_info mtd; - struct nand_chip chip; - struct platform_nand_chip *pl_chip; -}; -static struct ndfc_nand_mtd ndfc_mtd[NDFC_MAX_BANKS]; struct ndfc_controller { - void __iomem *ndfcbase; - struct nand_hw_control ndfc_control; - atomic_t childs_active; + struct of_device *ofdev; + void __iomem *ndfcbase; + struct mtd_info mtd; + struct nand_chip chip; + int chip_select; + struct nand_hw_control ndfc_control; +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *parts; +#endif }; static struct ndfc_controller ndfc_ctrl; @@ -50,17 +51,14 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip) { uint32_t ccr; struct ndfc_controller *ndfc = &ndfc_ctrl; - struct nand_chip *nandchip = mtd->priv; - struct ndfc_nand_mtd *nandmtd = nandchip->priv; - struct platform_nand_chip *pchip = nandmtd->pl_chip; - ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR); + ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); if (chip >= 0) { ccr &= ~NDFC_CCR_BS_MASK; - ccr |= NDFC_CCR_BS(chip + pchip->chip_offset); + ccr |= NDFC_CCR_BS(chip + ndfc->chip_select); } else ccr |= NDFC_CCR_RESET_CE; - __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR); + out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); } static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) @@ -80,7 +78,7 @@ static int ndfc_ready(struct mtd_info *mtd) { struct ndfc_controller *ndfc = &ndfc_ctrl; - return __raw_readl(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; + return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; } static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) @@ -88,9 +86,9 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) uint32_t ccr; struct ndfc_controller *ndfc = &ndfc_ctrl; - ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR); + ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); ccr |= NDFC_CCR_RESET_ECC; - __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR); + out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); wmb(); } @@ -102,9 +100,10 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd, uint8_t *p = (uint8_t *)&ecc; wmb(); - ecc = __raw_readl(ndfc->ndfcbase + NDFC_ECC); - ecc_code[0] = p[1]; - ecc_code[1] = p[2]; + ecc = in_be32(ndfc->ndfcbase + NDFC_ECC); + /* The NDFC uses Smart Media (SMC) bytes order */ + ecc_code[0] = p[2]; + ecc_code[1] = p[1]; ecc_code[2] = p[3]; return 0; @@ -123,7 +122,7 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) uint32_t *p = (uint32_t *) buf; for(;len > 0; len -= 4) - *p++ = __raw_readl(ndfc->ndfcbase + NDFC_DATA); + *p++ = in_be32(ndfc->ndfcbase + NDFC_DATA); } static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) @@ -132,7 +131,7 @@ static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) uint32_t *p = (uint32_t *) buf; for(;len > 0; len -= 4) - __raw_writel(*p++, ndfc->ndfcbase + NDFC_DATA); + out_be32(ndfc->ndfcbase + NDFC_DATA, *p++); } static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) @@ -141,7 +140,7 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) uint32_t *p = (uint32_t *) buf; for(;len > 0; len -= 4) - if (*p++ != __raw_readl(ndfc->ndfcbase + NDFC_DATA)) + if (*p++ != in_be32(ndfc->ndfcbase + NDFC_DATA)) return -EFAULT; return 0; } @@ -149,10 +148,19 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) /* * Initialize chip structure */ -static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) +static int ndfc_chip_init(struct ndfc_controller *ndfc, + struct device_node *node) { - struct ndfc_controller *ndfc = &ndfc_ctrl; - struct nand_chip *chip = &mtd->chip; +#ifdef CONFIG_MTD_PARTITIONS +#ifdef CONFIG_MTD_CMDLINE_PARTS + static const char *part_types[] = { "cmdlinepart", NULL }; +#else + static const char *part_types[] = { NULL }; +#endif +#endif + struct device_node *flash_np; + struct nand_chip *chip = &ndfc->chip; + int ret; chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; @@ -160,8 +168,6 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) chip->dev_ready = ndfc_ready; chip->select_chip = ndfc_select_chip; chip->chip_delay = 50; - chip->priv = mtd; - chip->options = mtd->pl_chip->options; chip->controller = &ndfc->ndfc_control; chip->read_buf = ndfc_read_buf; chip->write_buf = ndfc_write_buf; @@ -172,143 +178,136 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) chip->ecc.mode = NAND_ECC_HW; chip->ecc.size = 256; chip->ecc.bytes = 3; - chip->ecclayout = chip->ecc.layout = mtd->pl_chip->ecclayout; - mtd->mtd.priv = chip; - mtd->mtd.owner = THIS_MODULE; -} - -static int ndfc_chip_probe(struct platform_device *pdev) -{ - struct platform_nand_chip *nc = pdev->dev.platform_data; - struct ndfc_chip_settings *settings = nc->priv; - struct ndfc_controller *ndfc = &ndfc_ctrl; - struct ndfc_nand_mtd *nandmtd; - - if (nc->chip_offset >= NDFC_MAX_BANKS || nc->nr_chips > NDFC_MAX_BANKS) - return -EINVAL; - - /* Set the bank settings */ - __raw_writel(settings->bank_settings, - ndfc->ndfcbase + NDFC_BCFG0 + (nc->chip_offset << 2)); - nandmtd = &ndfc_mtd[pdev->id]; - if (nandmtd->pl_chip) - return -EBUSY; + ndfc->mtd.priv = chip; + ndfc->mtd.owner = THIS_MODULE; - nandmtd->pl_chip = nc; - ndfc_chip_init(nandmtd); - - /* Scan for chips */ - if (nand_scan(&nandmtd->mtd, nc->nr_chips)) { - nandmtd->pl_chip = NULL; + flash_np = of_get_next_child(node, NULL); + if (!flash_np) return -ENODEV; + + ndfc->mtd.name = kasprintf(GFP_KERNEL, "%s.%s", + ndfc->ofdev->dev.bus_id, flash_np->name); + if (!ndfc->mtd.name) { + ret = -ENOMEM; + goto err; } -#ifdef CONFIG_MTD_PARTITIONS - printk("Number of partitions %d\n", nc->nr_partitions); - if (nc->nr_partitions) { - /* Add the full device, so complete dumps can be made */ - add_mtd_device(&nandmtd->mtd); - add_mtd_partitions(&nandmtd->mtd, nc->partitions, - nc->nr_partitions); + ret = nand_scan(&ndfc->mtd, 1); + if (ret) + goto err; - } else -#else - add_mtd_device(&nandmtd->mtd); +#ifdef CONFIG_MTD_PARTITIONS + ret = parse_mtd_partitions(&ndfc->mtd, part_types, &ndfc->parts, 0); + if (ret < 0) + goto err; + +#ifdef CONFIG_MTD_OF_PARTS + if (ret == 0) { + ret = of_mtd_parse_partitions(&ndfc->ofdev->dev, flash_np, + &ndfc->parts); + if (ret < 0) + goto err; + } #endif - atomic_inc(&ndfc->childs_active); - return 0; -} + if (ret > 0) + ret = add_mtd_partitions(&ndfc->mtd, ndfc->parts, ret); + else +#endif + ret = add_mtd_device(&ndfc->mtd); -static int ndfc_chip_remove(struct platform_device *pdev) -{ - return 0; +err: + of_node_put(flash_np); + if (ret) + kfree(ndfc->mtd.name); + return ret; } -static int ndfc_nand_probe(struct platform_device *pdev) +static int __devinit ndfc_probe(struct of_device *ofdev, + const struct of_device_id *match) { - struct platform_nand_ctrl *nc = pdev->dev.platform_data; - struct ndfc_controller_settings *settings = nc->priv; - struct resource *res = pdev->resource; struct ndfc_controller *ndfc = &ndfc_ctrl; - unsigned long long phys = settings->ndfc_erpn | res->start; + const u32 *reg; + u32 ccr; + int err, len; -#ifndef CONFIG_PHYS_64BIT - ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1); -#else - ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1); -#endif + spin_lock_init(&ndfc->ndfc_control.lock); + init_waitqueue_head(&ndfc->ndfc_control.wq); + ndfc->ofdev = ofdev; + dev_set_drvdata(&ofdev->dev, ndfc); + + /* Read the reg property to get the chip select */ + reg = of_get_property(ofdev->node, "reg", &len); + if (reg == NULL || len != 12) { + dev_err(&ofdev->dev, "unable read reg property (%d)\n", len); + return -ENOENT; + } + ndfc->chip_select = reg[0]; + + ndfc->ndfcbase = of_iomap(ofdev->node, 0); if (!ndfc->ndfcbase) { - printk(KERN_ERR "NDFC: ioremap failed\n"); + dev_err(&ofdev->dev, "failed to get memory\n"); return -EIO; } - __raw_writel(settings->ccr_settings, ndfc->ndfcbase + NDFC_CCR); + ccr = NDFC_CCR_BS(ndfc->chip_select); - spin_lock_init(&ndfc->ndfc_control.lock); - init_waitqueue_head(&ndfc->ndfc_control.wq); + /* It is ok if ccr does not exist - just default to 0 */ + reg = of_get_property(ofdev->node, "ccr", NULL); + if (reg) + ccr |= *reg; - platform_set_drvdata(pdev, ndfc); + out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); - printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n", - __raw_readl(ndfc->ndfcbase + NDFC_REVID)); + /* Set the bank settings if given */ + reg = of_get_property(ofdev->node, "bank-settings", NULL); + if (reg) { + int offset = NDFC_BCFG0 + (ndfc->chip_select << 2); + out_be32(ndfc->ndfcbase + offset, *reg); + } + + err = ndfc_chip_init(ndfc, ofdev->node); + if (err) { + iounmap(ndfc->ndfcbase); + return err; + } return 0; } -static int ndfc_nand_remove(struct platform_device *pdev) +static int __devexit ndfc_remove(struct of_device *ofdev) { - struct ndfc_controller *ndfc = platform_get_drvdata(pdev); + struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev); - if (atomic_read(&ndfc->childs_active)) - return -EBUSY; + nand_release(&ndfc->mtd); - if (ndfc) { - platform_set_drvdata(pdev, NULL); - iounmap(ndfc_ctrl.ndfcbase); - ndfc_ctrl.ndfcbase = NULL; - } return 0; } -/* driver device registration */ - -static struct platform_driver ndfc_chip_driver = { - .probe = ndfc_chip_probe, - .remove = ndfc_chip_remove, - .driver = { - .name = "ndfc-chip", - .owner = THIS_MODULE, - }, +static const struct of_device_id ndfc_match[] = { + { .compatible = "ibm,ndfc", }, + {} }; +MODULE_DEVICE_TABLE(of, ndfc_match); -static struct platform_driver ndfc_nand_driver = { - .probe = ndfc_nand_probe, - .remove = ndfc_nand_remove, - .driver = { - .name = "ndfc-nand", - .owner = THIS_MODULE, +static struct of_platform_driver ndfc_driver = { + .driver = { + .name = "ndfc", }, + .match_table = ndfc_match, + .probe = ndfc_probe, + .remove = __devexit_p(ndfc_remove), }; static int __init ndfc_nand_init(void) { - int ret; - - spin_lock_init(&ndfc_ctrl.ndfc_control.lock); - init_waitqueue_head(&ndfc_ctrl.ndfc_control.wq); - - ret = platform_driver_register(&ndfc_nand_driver); - if (!ret) - ret = platform_driver_register(&ndfc_chip_driver); - return ret; + return of_register_platform_driver(&ndfc_driver); } static void __exit ndfc_nand_exit(void) { - platform_driver_unregister(&ndfc_chip_driver); - platform_driver_unregister(&ndfc_nand_driver); + of_unregister_platform_driver(&ndfc_driver); } module_init(ndfc_nand_init); @@ -316,6 +315,4 @@ module_exit(ndfc_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); -MODULE_DESCRIPTION("Platform driver for NDFC"); -MODULE_ALIAS("platform:ndfc-chip"); -MODULE_ALIAS("platform:ndfc-nand"); +MODULE_DESCRIPTION("OF Platform driver for NDFC"); diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index fc4144495610..cc55cbc2b308 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -298,7 +298,7 @@ static struct pxa3xx_nand_flash *builtin_flash_types[] = { #define NDTR1_tAR(c) (min((c), 15) << 0) /* convert nano-seconds to nand flash controller clock cycles */ -#define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) + 1) +#define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) - 1) static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, const struct pxa3xx_nand_timing *t) @@ -368,14 +368,14 @@ static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, /* large block, 2 cycles for column address * row address starts from 3rd cycle */ - info->ndcb1 |= (page_addr << 16) | (column & 0xffff); + info->ndcb1 |= page_addr << 16; if (info->row_addr_cycles == 3) info->ndcb2 = (page_addr >> 16) & 0xff; } else /* small block, 1 cycles for column address * row address starts from 2nd cycle */ - info->ndcb1 = (page_addr << 8) | (column & 0xff); + info->ndcb1 = page_addr << 8; if (cmd == cmdset->program) info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS; diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 30a518e211bd..54ec7542a7b7 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -2,6 +2,7 @@ * drivers/mtd/nand/sharpsl.c * * Copyright (C) 2004 Richard Purdie + * Copyright (C) 2008 Dmitry Baryshkov * * Based on Sharp's NAND driver sharp_sl.c * @@ -19,22 +20,31 @@ #include <linux/mtd/nand.h> #include <linux/mtd/nand_ecc.h> #include <linux/mtd/partitions.h> +#include <linux/mtd/sharpsl.h> #include <linux/interrupt.h> +#include <linux/platform_device.h> + #include <asm/io.h> #include <mach/hardware.h> #include <asm/mach-types.h> -static void __iomem *sharpsl_io_base; -static int sharpsl_phys_base = 0x0C000000; +struct sharpsl_nand { + struct mtd_info mtd; + struct nand_chip chip; + + void __iomem *io; +}; + +#define mtd_to_sharpsl(_mtd) container_of(_mtd, struct sharpsl_nand, mtd) /* register offset */ -#define ECCLPLB sharpsl_io_base+0x00 /* line parity 7 - 0 bit */ -#define ECCLPUB sharpsl_io_base+0x04 /* line parity 15 - 8 bit */ -#define ECCCP sharpsl_io_base+0x08 /* column parity 5 - 0 bit */ -#define ECCCNTR sharpsl_io_base+0x0C /* ECC byte counter */ -#define ECCCLRR sharpsl_io_base+0x10 /* cleare ECC */ -#define FLASHIO sharpsl_io_base+0x14 /* Flash I/O */ -#define FLASHCTL sharpsl_io_base+0x18 /* Flash Control */ +#define ECCLPLB 0x00 /* line parity 7 - 0 bit */ +#define ECCLPUB 0x04 /* line parity 15 - 8 bit */ +#define ECCCP 0x08 /* column parity 5 - 0 bit */ +#define ECCCNTR 0x0C /* ECC byte counter */ +#define ECCCLRR 0x10 /* cleare ECC */ +#define FLASHIO 0x14 /* Flash I/O */ +#define FLASHCTL 0x18 /* Flash Control */ /* Flash control bit */ #define FLRYBY (1 << 5) @@ -45,35 +55,6 @@ static int sharpsl_phys_base = 0x0C000000; #define FLCE0 (1 << 0) /* - * MTD structure for SharpSL - */ -static struct mtd_info *sharpsl_mtd = NULL; - -/* - * Define partitions for flash device - */ -#define DEFAULT_NUM_PARTITIONS 3 - -static int nr_partitions; -static struct mtd_partition sharpsl_nand_default_partition_info[] = { - { - .name = "System Area", - .offset = 0, - .size = 7 * 1024 * 1024, - }, - { - .name = "Root Filesystem", - .offset = 7 * 1024 * 1024, - .size = 30 * 1024 * 1024, - }, - { - .name = "Home Filesystem", - .offset = MTDPART_OFS_APPEND, - .size = MTDPART_SIZ_FULL, - }, -}; - -/* * hardware specific access to control-lines * ctrl: * NAND_CNE: bit 0 -> ! bit 0 & 4 @@ -84,6 +65,7 @@ static struct mtd_partition sharpsl_nand_default_partition_info[] = { static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { + struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); struct nand_chip *chip = mtd->priv; if (ctrl & NAND_CTRL_CHANGE) { @@ -93,103 +75,97 @@ static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd, bits ^= 0x11; - writeb((readb(FLASHCTL) & ~0x17) | bits, FLASHCTL); + writeb((readb(sharpsl->io + FLASHCTL) & ~0x17) | bits, sharpsl->io + FLASHCTL); } if (cmd != NAND_CMD_NONE) writeb(cmd, chip->IO_ADDR_W); } -static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; - -static struct nand_bbt_descr sharpsl_bbt = { - .options = 0, - .offs = 4, - .len = 2, - .pattern = scan_ff_pattern -}; - -static struct nand_bbt_descr sharpsl_akita_bbt = { - .options = 0, - .offs = 4, - .len = 1, - .pattern = scan_ff_pattern -}; - -static struct nand_ecclayout akita_oobinfo = { - .eccbytes = 24, - .eccpos = { - 0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11, - 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23, - 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37}, - .oobfree = {{0x08, 0x09}} -}; - static int sharpsl_nand_dev_ready(struct mtd_info *mtd) { - return !((readb(FLASHCTL) & FLRYBY) == 0); + struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); + return !((readb(sharpsl->io + FLASHCTL) & FLRYBY) == 0); } static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode) { - writeb(0, ECCCLRR); + struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); + writeb(0, sharpsl->io + ECCCLRR); } static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code) { - ecc_code[0] = ~readb(ECCLPUB); - ecc_code[1] = ~readb(ECCLPLB); - ecc_code[2] = (~readb(ECCCP) << 2) | 0x03; - return readb(ECCCNTR) != 0; + struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); + ecc_code[0] = ~readb(sharpsl->io + ECCLPUB); + ecc_code[1] = ~readb(sharpsl->io + ECCLPLB); + ecc_code[2] = (~readb(sharpsl->io + ECCCP) << 2) | 0x03; + return readb(sharpsl->io + ECCCNTR) != 0; } #ifdef CONFIG_MTD_PARTITIONS -const char *part_probes[] = { "cmdlinepart", NULL }; +static const char *part_probes[] = { "cmdlinepart", NULL }; #endif /* * Main initialization routine */ -static int __init sharpsl_nand_init(void) +static int __devinit sharpsl_nand_probe(struct platform_device *pdev) { struct nand_chip *this; +#ifdef CONFIG_MTD_PARTITIONS struct mtd_partition *sharpsl_partition_info; + int nr_partitions; +#endif + struct resource *r; int err = 0; + struct sharpsl_nand *sharpsl; + struct sharpsl_nand_platform_data *data = pdev->dev.platform_data; + + if (!data) { + dev_err(&pdev->dev, "no platform data!\n"); + return -EINVAL; + } /* Allocate memory for MTD device structure and private data */ - sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); - if (!sharpsl_mtd) { + sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL); + if (!sharpsl) { printk("Unable to allocate SharpSL NAND MTD device structure.\n"); return -ENOMEM; } + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "no io memory resource defined!\n"); + err = -ENODEV; + goto err_get_res; + } + /* map physical address */ - sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000); - if (!sharpsl_io_base) { + sharpsl->io = ioremap(r->start, resource_size(r)); + if (!sharpsl->io) { printk("ioremap to access Sharp SL NAND chip failed\n"); - kfree(sharpsl_mtd); - return -EIO; + err = -EIO; + goto err_ioremap; } /* Get pointer to private data */ - this = (struct nand_chip *)(&sharpsl_mtd[1]); - - /* Initialize structures */ - memset(sharpsl_mtd, 0, sizeof(struct mtd_info)); - memset(this, 0, sizeof(struct nand_chip)); + this = (struct nand_chip *)(&sharpsl->chip); /* Link the private data with the MTD structure */ - sharpsl_mtd->priv = this; - sharpsl_mtd->owner = THIS_MODULE; + sharpsl->mtd.priv = this; + sharpsl->mtd.owner = THIS_MODULE; + + platform_set_drvdata(pdev, sharpsl); /* * PXA initialize */ - writeb(readb(FLASHCTL) | FLWP, FLASHCTL); + writeb(readb(sharpsl->io + FLASHCTL) | FLWP, sharpsl->io + FLASHCTL); /* Set address of NAND IO lines */ - this->IO_ADDR_R = FLASHIO; - this->IO_ADDR_W = FLASHIO; + this->IO_ADDR_R = sharpsl->io + FLASHIO; + this->IO_ADDR_W = sharpsl->io + FLASHIO; /* Set address of hardware control function */ this->cmd_ctrl = sharpsl_nand_hwcontrol; this->dev_ready = sharpsl_nand_dev_ready; @@ -199,68 +175,89 @@ static int __init sharpsl_nand_init(void) this->ecc.mode = NAND_ECC_HW; this->ecc.size = 256; this->ecc.bytes = 3; - this->badblock_pattern = &sharpsl_bbt; - if (machine_is_akita() || machine_is_borzoi()) { - this->badblock_pattern = &sharpsl_akita_bbt; - this->ecc.layout = &akita_oobinfo; - } + this->badblock_pattern = data->badblock_pattern; + this->ecc.layout = data->ecc_layout; this->ecc.hwctl = sharpsl_nand_enable_hwecc; this->ecc.calculate = sharpsl_nand_calculate_ecc; this->ecc.correct = nand_correct_data; /* Scan to find existence of the device */ - err = nand_scan(sharpsl_mtd, 1); - if (err) { - iounmap(sharpsl_io_base); - kfree(sharpsl_mtd); - return err; - } + err = nand_scan(&sharpsl->mtd, 1); + if (err) + goto err_scan; /* Register the partitions */ - sharpsl_mtd->name = "sharpsl-nand"; - nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, &sharpsl_partition_info, 0); - + sharpsl->mtd.name = "sharpsl-nand"; +#ifdef CONFIG_MTD_PARTITIONS + nr_partitions = parse_mtd_partitions(&sharpsl->mtd, part_probes, &sharpsl_partition_info, 0); if (nr_partitions <= 0) { - nr_partitions = DEFAULT_NUM_PARTITIONS; - sharpsl_partition_info = sharpsl_nand_default_partition_info; - if (machine_is_poodle()) { - sharpsl_partition_info[1].size = 22 * 1024 * 1024; - } else if (machine_is_corgi() || machine_is_shepherd()) { - sharpsl_partition_info[1].size = 25 * 1024 * 1024; - } else if (machine_is_husky()) { - sharpsl_partition_info[1].size = 53 * 1024 * 1024; - } else if (machine_is_spitz()) { - sharpsl_partition_info[1].size = 5 * 1024 * 1024; - } else if (machine_is_akita()) { - sharpsl_partition_info[1].size = 58 * 1024 * 1024; - } else if (machine_is_borzoi()) { - sharpsl_partition_info[1].size = 32 * 1024 * 1024; - } + nr_partitions = data->nr_partitions; + sharpsl_partition_info = data->partitions; } - add_mtd_partitions(sharpsl_mtd, sharpsl_partition_info, nr_partitions); + if (nr_partitions > 0) + err = add_mtd_partitions(&sharpsl->mtd, sharpsl_partition_info, nr_partitions); + else +#endif + err = add_mtd_device(&sharpsl->mtd); + if (err) + goto err_add; /* Return happy */ return 0; -} -module_init(sharpsl_nand_init); +err_add: + nand_release(&sharpsl->mtd); + +err_scan: + platform_set_drvdata(pdev, NULL); + iounmap(sharpsl->io); +err_ioremap: +err_get_res: + kfree(sharpsl); + return err; +} /* * Clean up routine */ -static void __exit sharpsl_nand_cleanup(void) +static int __devexit sharpsl_nand_remove(struct platform_device *pdev) { + struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev); + /* Release resources, unregister device */ - nand_release(sharpsl_mtd); + nand_release(&sharpsl->mtd); - iounmap(sharpsl_io_base); + platform_set_drvdata(pdev, NULL); + + iounmap(sharpsl->io); /* Free the MTD device structure */ - kfree(sharpsl_mtd); + kfree(sharpsl); + + return 0; +} + +static struct platform_driver sharpsl_nand_driver = { + .driver = { + .name = "sharpsl-nand", + .owner = THIS_MODULE, + }, + .probe = sharpsl_nand_probe, + .remove = __devexit_p(sharpsl_nand_remove), +}; + +static int __init sharpsl_nand_init(void) +{ + return platform_driver_register(&sharpsl_nand_driver); } +module_init(sharpsl_nand_init); -module_exit(sharpsl_nand_cleanup); +static void __exit sharpsl_nand_exit(void) +{ + platform_driver_unregister(&sharpsl_nand_driver); +} +module_exit(sharpsl_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index 320b929abe79..d1c4546513f7 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -39,7 +39,7 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) struct NFTLrecord *nftl; unsigned long temp; - if (mtd->type != MTD_NANDFLASH) + if (mtd->type != MTD_NANDFLASH || mtd->size > UINT_MAX) return; /* OK, this is moderately ugly. But probably safe. Alternatives? */ if (memcmp(mtd->name, "DiskOnChip", 10)) diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index ccc4f209fbb5..8b22b1836e9f 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -51,7 +51,7 @@ static int find_boot_record(struct NFTLrecord *nftl) the mtd device accordingly. We could even get rid of nftl->EraseSize if there were any point in doing so. */ nftl->EraseSize = nftl->mbd.mtd->erasesize; - nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize; + nftl->nb_blocks = (u32)nftl->mbd.mtd->size / nftl->EraseSize; nftl->MediaUnit = BLOCK_NIL; nftl->SpareMediaUnit = BLOCK_NIL; @@ -168,7 +168,7 @@ device is already correct. printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n", mh->UnitSizeFactor); nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor); - nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize; + nftl->nb_blocks = (u32)nftl->mbd.mtd->size / nftl->EraseSize; } #endif nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN); diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 90ed319f26e6..529af271db17 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1772,7 +1772,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) int len; int ret = 0; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); + DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%012llx, len = %llu\n", (unsigned long long) instr->addr, (unsigned long long) instr->len); block_size = (1 << this->erase_shift); @@ -1810,7 +1810,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) /* Check if we have a bad block, we do not erase bad blocks */ if (onenand_block_isbad_nolock(mtd, addr, 0)) { - printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr); + printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%012llx\n", (unsigned long long) addr); instr->state = MTD_ERASE_FAILED; goto erase_exit; } @@ -2029,7 +2029,7 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int * * Lock one or more blocks */ -static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int onenand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { int ret; @@ -2047,7 +2047,7 @@ static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len) * * Unlock one or more blocks */ -static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { int ret; diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index e538c0a72abb..d2aa9c46530f 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -21,8 +21,6 @@ #include <asm/types.h> -#define const_cpu_to_le16 __constant_cpu_to_le16 - static int block_size = 0; module_param(block_size, int, 0); MODULE_PARM_DESC(block_size, "Block size to use by RFD, defaults to erase unit size"); @@ -156,7 +154,7 @@ static int scan_header(struct partition *part) size_t retlen; sectors_per_block = part->block_size / SECTOR_SIZE; - part->total_blocks = part->mbd.mtd->size / part->block_size; + part->total_blocks = (u32)part->mbd.mtd->size / part->block_size; if (part->total_blocks < 2) return -ENOENT; @@ -276,16 +274,17 @@ static void erase_callback(struct erase_info *erase) part = (struct partition*)erase->priv; - i = erase->addr / part->block_size; - if (i >= part->total_blocks || part->blocks[i].offset != erase->addr) { - printk(KERN_ERR PREFIX "erase callback for unknown offset %x " - "on '%s'\n", erase->addr, part->mbd.mtd->name); + i = (u32)erase->addr / part->block_size; + if (i >= part->total_blocks || part->blocks[i].offset != erase->addr || + erase->addr > UINT_MAX) { + printk(KERN_ERR PREFIX "erase callback for unknown offset %llx " + "on '%s'\n", (unsigned long long)erase->addr, part->mbd.mtd->name); return; } if (erase->state != MTD_ERASE_DONE) { - printk(KERN_WARNING PREFIX "erase failed at 0x%x on '%s', " - "state %d\n", erase->addr, + printk(KERN_WARNING PREFIX "erase failed at 0x%llx on '%s', " + "state %d\n", (unsigned long long)erase->addr, part->mbd.mtd->name, erase->state); part->blocks[i].state = BLOCK_FAILED; @@ -297,7 +296,7 @@ static void erase_callback(struct erase_info *erase) return; } - magic = const_cpu_to_le16(RFD_MAGIC); + magic = cpu_to_le16(RFD_MAGIC); part->blocks[i].state = BLOCK_ERASED; part->blocks[i].free_sectors = part->data_sectors_per_block; @@ -345,9 +344,9 @@ static int erase_block(struct partition *part, int block) rc = part->mbd.mtd->erase(part->mbd.mtd, erase); if (rc) { - printk(KERN_ERR PREFIX "erase of region %x,%x on '%s' " - "failed\n", erase->addr, erase->len, - part->mbd.mtd->name); + printk(KERN_ERR PREFIX "erase of region %llx,%llx on '%s' " + "failed\n", (unsigned long long)erase->addr, + (unsigned long long)erase->len, part->mbd.mtd->name); kfree(erase); } @@ -587,7 +586,7 @@ static int mark_sector_deleted(struct partition *part, u_long old_addr) int block, offset, rc; u_long addr; size_t retlen; - u16 del = const_cpu_to_le16(SECTOR_DELETED); + u16 del = cpu_to_le16(SECTOR_DELETED); block = old_addr / part->block_size; offset = (old_addr % part->block_size) / SECTOR_SIZE - @@ -763,7 +762,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) { struct partition *part; - if (mtd->type != MTD_NORFLASH) + if (mtd->type != MTD_NORFLASH || mtd->size > UINT_MAX) return; part = kzalloc(sizeof(struct partition), GFP_KERNEL); diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index 33a5d6ed6f18..3f67e00d98e0 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c @@ -294,7 +294,8 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) int cis_sector; /* Check for small page NAND flash */ - if (mtd->type != MTD_NANDFLASH || mtd->oobsize != OOB_SIZE) + if (mtd->type != MTD_NANDFLASH || mtd->oobsize != OOB_SIZE || + mtd->size > UINT_MAX) return; /* Check for SSDFC format by reading CIS/IDI sector */ @@ -316,7 +317,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ssfdc->cis_block = cis_sector / (mtd->erasesize >> SECTOR_SHIFT); ssfdc->erase_size = mtd->erasesize; - ssfdc->map_len = mtd->size / mtd->erasesize; + ssfdc->map_len = (u32)mtd->size / mtd->erasesize; DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n", @@ -327,7 +328,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ssfdc->heads = 16; ssfdc->sectors = 32; get_chs(mtd->size, NULL, &ssfdc->heads, &ssfdc->sectors); - ssfdc->cylinders = (unsigned short)((mtd->size >> SECTOR_SHIFT) / + ssfdc->cylinders = (unsigned short)(((u32)mtd->size >> SECTOR_SHIFT) / ((long)ssfdc->sectors * (long)ssfdc->heads)); DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n", diff --git a/drivers/mtd/tests/Makefile b/drivers/mtd/tests/Makefile new file mode 100644 index 000000000000..c1d501335006 --- /dev/null +++ b/drivers/mtd/tests/Makefile @@ -0,0 +1,7 @@ +obj-$(CONFIG_MTD_TESTS) += mtd_oobtest.o +obj-$(CONFIG_MTD_TESTS) += mtd_pagetest.o +obj-$(CONFIG_MTD_TESTS) += mtd_readtest.o +obj-$(CONFIG_MTD_TESTS) += mtd_speedtest.o +obj-$(CONFIG_MTD_TESTS) += mtd_stresstest.o +obj-$(CONFIG_MTD_TESTS) += mtd_subpagetest.o +obj-$(CONFIG_MTD_TESTS) += mtd_torturetest.o diff --git a/drivers/mtd/tests/mtd_oobtest.c b/drivers/mtd/tests/mtd_oobtest.c new file mode 100644 index 000000000000..afbc3f8126db --- /dev/null +++ b/drivers/mtd/tests/mtd_oobtest.c @@ -0,0 +1,742 @@ +/* + * Copyright (C) 2006-2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Test OOB read and write on MTD device. + * + * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> + */ + +#include <asm/div64.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/mtd/mtd.h> +#include <linux/sched.h> + +#define PRINT_PREF KERN_INFO "mtd_oobtest: " + +static int dev; +module_param(dev, int, S_IRUGO); +MODULE_PARM_DESC(dev, "MTD device number to use"); + +static struct mtd_info *mtd; +static unsigned char *readbuf; +static unsigned char *writebuf; +static unsigned char *bbt; + +static int ebcnt; +static int pgcnt; +static int errcnt; +static int use_offset; +static int use_len; +static int use_len_max; +static int vary_offset; +static unsigned long next = 1; + +static inline unsigned int simple_rand(void) +{ + next = next * 1103515245 + 12345; + return (unsigned int)((next / 65536) % 32768); +} + +static inline void simple_srand(unsigned long seed) +{ + next = seed; +} + +static void set_random_data(unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; ++i) + buf[i] = simple_rand(); +} + +static int erase_eraseblock(int ebnum) +{ + int err; + struct erase_info ei; + loff_t addr = ebnum * mtd->erasesize; + + memset(&ei, 0, sizeof(struct erase_info)); + ei.mtd = mtd; + ei.addr = addr; + ei.len = mtd->erasesize; + + err = mtd->erase(mtd, &ei); + if (err) { + printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + return err; + } + + if (ei.state == MTD_ERASE_FAILED) { + printk(PRINT_PREF "some erase error occurred at EB %d\n", + ebnum); + return -EIO; + } + + return 0; +} + +static int erase_whole_device(void) +{ + int err; + unsigned int i; + + printk(PRINT_PREF "erasing whole device\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = erase_eraseblock(i); + if (err) + return err; + cond_resched(); + } + printk(PRINT_PREF "erased %u eraseblocks\n", i); + return 0; +} + +static void do_vary_offset(void) +{ + use_len -= 1; + if (use_len < 1) { + use_offset += 1; + if (use_offset >= use_len_max) + use_offset = 0; + use_len = use_len_max - use_offset; + } +} + +static int write_eraseblock(int ebnum) +{ + int i; + struct mtd_oob_ops ops; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + + for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { + set_random_data(writebuf, use_len); + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = use_len; + ops.oobretlen = 0; + ops.ooboffs = use_offset; + ops.datbuf = 0; + ops.oobbuf = writebuf; + err = mtd->write_oob(mtd, addr, &ops); + if (err || ops.oobretlen != use_len) { + printk(PRINT_PREF "error: writeoob failed at %#llx\n", + (long long)addr); + printk(PRINT_PREF "error: use_len %d, use_offset %d\n", + use_len, use_offset); + errcnt += 1; + return err ? err : -1; + } + if (vary_offset) + do_vary_offset(); + } + + return err; +} + +static int write_whole_device(void) +{ + int err; + unsigned int i; + + printk(PRINT_PREF "writing OOBs of whole device\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock(i); + if (err) + return err; + if (i % 256 == 0) + printk(PRINT_PREF "written up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "written %u eraseblocks\n", i); + return 0; +} + +static int verify_eraseblock(int ebnum) +{ + int i; + struct mtd_oob_ops ops; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + + for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { + set_random_data(writebuf, use_len); + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = use_len; + ops.oobretlen = 0; + ops.ooboffs = use_offset; + ops.datbuf = 0; + ops.oobbuf = readbuf; + err = mtd->read_oob(mtd, addr, &ops); + if (err || ops.oobretlen != use_len) { + printk(PRINT_PREF "error: readoob failed at %#llx\n", + (long long)addr); + errcnt += 1; + return err ? err : -1; + } + if (memcmp(readbuf, writebuf, use_len)) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + errcnt += 1; + if (errcnt > 1000) { + printk(PRINT_PREF "error: too many errors\n"); + return -1; + } + } + if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) { + int k; + + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = mtd->ecclayout->oobavail; + ops.oobretlen = 0; + ops.ooboffs = 0; + ops.datbuf = 0; + ops.oobbuf = readbuf; + err = mtd->read_oob(mtd, addr, &ops); + if (err || ops.oobretlen != mtd->ecclayout->oobavail) { + printk(PRINT_PREF "error: readoob failed at " + "%#llx\n", (long long)addr); + errcnt += 1; + return err ? err : -1; + } + if (memcmp(readbuf + use_offset, writebuf, use_len)) { + printk(PRINT_PREF "error: verify failed at " + "%#llx\n", (long long)addr); + errcnt += 1; + if (errcnt > 1000) { + printk(PRINT_PREF "error: too many " + "errors\n"); + return -1; + } + } + for (k = 0; k < use_offset; ++k) + if (readbuf[k] != 0xff) { + printk(PRINT_PREF "error: verify 0xff " + "failed at %#llx\n", + (long long)addr); + errcnt += 1; + if (errcnt > 1000) { + printk(PRINT_PREF "error: too " + "many errors\n"); + return -1; + } + } + for (k = use_offset + use_len; + k < mtd->ecclayout->oobavail; ++k) + if (readbuf[k] != 0xff) { + printk(PRINT_PREF "error: verify 0xff " + "failed at %#llx\n", + (long long)addr); + errcnt += 1; + if (errcnt > 1000) { + printk(PRINT_PREF "error: too " + "many errors\n"); + return -1; + } + } + } + if (vary_offset) + do_vary_offset(); + } + return err; +} + +static int verify_eraseblock_in_one_go(int ebnum) +{ + struct mtd_oob_ops ops; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + size_t len = mtd->ecclayout->oobavail * pgcnt; + + set_random_data(writebuf, len); + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = len; + ops.oobretlen = 0; + ops.ooboffs = 0; + ops.datbuf = 0; + ops.oobbuf = readbuf; + err = mtd->read_oob(mtd, addr, &ops); + if (err || ops.oobretlen != len) { + printk(PRINT_PREF "error: readoob failed at %#llx\n", + (long long)addr); + errcnt += 1; + return err ? err : -1; + } + if (memcmp(readbuf, writebuf, len)) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + errcnt += 1; + if (errcnt > 1000) { + printk(PRINT_PREF "error: too many errors\n"); + return -1; + } + } + + return err; +} + +static int verify_all_eraseblocks(void) +{ + int err; + unsigned int i; + + printk(PRINT_PREF "verifying all eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = verify_eraseblock(i); + if (err) + return err; + if (i % 256 == 0) + printk(PRINT_PREF "verified up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "verified %u eraseblocks\n", i); + return 0; +} + +static int is_block_bad(int ebnum) +{ + int ret; + loff_t addr = ebnum * mtd->erasesize; + + ret = mtd->block_isbad(mtd, addr); + if (ret) + printk(PRINT_PREF "block %d is bad\n", ebnum); + return ret; +} + +static int scan_for_bad_eraseblocks(void) +{ + int i, bad = 0; + + bbt = kmalloc(ebcnt, GFP_KERNEL); + if (!bbt) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + return -ENOMEM; + } + memset(bbt, 0 , ebcnt); + + printk(PRINT_PREF "scanning for bad eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + bbt[i] = is_block_bad(i) ? 1 : 0; + if (bbt[i]) + bad += 1; + cond_resched(); + } + printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + return 0; +} + +static int __init mtd_oobtest_init(void) +{ + int err = 0; + unsigned int i; + uint64_t tmp; + struct mtd_oob_ops ops; + loff_t addr = 0, addr0; + + printk(KERN_INFO "\n"); + printk(KERN_INFO "=================================================\n"); + printk(PRINT_PREF "MTD device: %d\n", dev); + + mtd = get_mtd_device(NULL, dev); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + printk(PRINT_PREF "error: cannot get MTD device\n"); + return err; + } + + if (mtd->type != MTD_NANDFLASH) { + printk(PRINT_PREF "this test requires NAND flash\n"); + goto out; + } + + tmp = mtd->size; + do_div(tmp, mtd->erasesize); + ebcnt = tmp; + pgcnt = mtd->erasesize / mtd->writesize; + + printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + "page size %u, count of eraseblocks %u, pages per " + "eraseblock %u, OOB size %u\n", + (unsigned long long)mtd->size, mtd->erasesize, + mtd->writesize, ebcnt, pgcnt, mtd->oobsize); + + err = -ENOMEM; + mtd->erasesize = mtd->erasesize; + readbuf = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!readbuf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!writebuf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + + err = scan_for_bad_eraseblocks(); + if (err) + goto out; + + use_offset = 0; + use_len = mtd->ecclayout->oobavail; + use_len_max = mtd->ecclayout->oobavail; + vary_offset = 0; + + /* First test: write all OOB, read it back and verify */ + printk(PRINT_PREF "test 1 of 5\n"); + + err = erase_whole_device(); + if (err) + goto out; + + simple_srand(1); + err = write_whole_device(); + if (err) + goto out; + + simple_srand(1); + err = verify_all_eraseblocks(); + if (err) + goto out; + + /* + * Second test: write all OOB, a block at a time, read it back and + * verify. + */ + printk(PRINT_PREF "test 2 of 5\n"); + + err = erase_whole_device(); + if (err) + goto out; + + simple_srand(3); + err = write_whole_device(); + if (err) + goto out; + + /* Check all eraseblocks */ + simple_srand(3); + printk(PRINT_PREF "verifying all eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = verify_eraseblock_in_one_go(i); + if (err) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "verified up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "verified %u eraseblocks\n", i); + + /* + * Third test: write OOB at varying offsets and lengths, read it back + * and verify. + */ + printk(PRINT_PREF "test 3 of 5\n"); + + err = erase_whole_device(); + if (err) + goto out; + + /* Write all eraseblocks */ + use_offset = 0; + use_len = mtd->ecclayout->oobavail; + use_len_max = mtd->ecclayout->oobavail; + vary_offset = 1; + simple_srand(5); + printk(PRINT_PREF "writing OOBs of whole device\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock(i); + if (err) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "written up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "written %u eraseblocks\n", i); + + /* Check all eraseblocks */ + use_offset = 0; + use_len = mtd->ecclayout->oobavail; + use_len_max = mtd->ecclayout->oobavail; + vary_offset = 1; + simple_srand(5); + err = verify_all_eraseblocks(); + if (err) + goto out; + + use_offset = 0; + use_len = mtd->ecclayout->oobavail; + use_len_max = mtd->ecclayout->oobavail; + vary_offset = 0; + + /* Fourth test: try to write off end of device */ + printk(PRINT_PREF "test 4 of 5\n"); + + err = erase_whole_device(); + if (err) + goto out; + + addr0 = 0; + for (i = 0; bbt[i] && i < ebcnt; ++i) + addr0 += mtd->erasesize; + + /* Attempt to write off end of OOB */ + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = 1; + ops.oobretlen = 0; + ops.ooboffs = mtd->ecclayout->oobavail; + ops.datbuf = 0; + ops.oobbuf = writebuf; + printk(PRINT_PREF "attempting to start write past end of OOB\n"); + printk(PRINT_PREF "an error is expected...\n"); + err = mtd->write_oob(mtd, addr0, &ops); + if (err) { + printk(PRINT_PREF "error occurred as expected\n"); + err = 0; + } else { + printk(PRINT_PREF "error: can write past end of OOB\n"); + errcnt += 1; + } + + /* Attempt to read off end of OOB */ + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = 1; + ops.oobretlen = 0; + ops.ooboffs = mtd->ecclayout->oobavail; + ops.datbuf = 0; + ops.oobbuf = readbuf; + printk(PRINT_PREF "attempting to start read past end of OOB\n"); + printk(PRINT_PREF "an error is expected...\n"); + err = mtd->read_oob(mtd, addr0, &ops); + if (err) { + printk(PRINT_PREF "error occurred as expected\n"); + err = 0; + } else { + printk(PRINT_PREF "error: can read past end of OOB\n"); + errcnt += 1; + } + + if (bbt[ebcnt - 1]) + printk(PRINT_PREF "skipping end of device tests because last " + "block is bad\n"); + else { + /* Attempt to write off end of device */ + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = mtd->ecclayout->oobavail + 1; + ops.oobretlen = 0; + ops.ooboffs = 0; + ops.datbuf = 0; + ops.oobbuf = writebuf; + printk(PRINT_PREF "attempting to write past end of device\n"); + printk(PRINT_PREF "an error is expected...\n"); + err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops); + if (err) { + printk(PRINT_PREF "error occurred as expected\n"); + err = 0; + } else { + printk(PRINT_PREF "error: wrote past end of device\n"); + errcnt += 1; + } + + /* Attempt to read off end of device */ + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = mtd->ecclayout->oobavail + 1; + ops.oobretlen = 0; + ops.ooboffs = 0; + ops.datbuf = 0; + ops.oobbuf = readbuf; + printk(PRINT_PREF "attempting to read past end of device\n"); + printk(PRINT_PREF "an error is expected...\n"); + err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops); + if (err) { + printk(PRINT_PREF "error occurred as expected\n"); + err = 0; + } else { + printk(PRINT_PREF "error: read past end of device\n"); + errcnt += 1; + } + + err = erase_eraseblock(ebcnt - 1); + if (err) + goto out; + + /* Attempt to write off end of device */ + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = mtd->ecclayout->oobavail; + ops.oobretlen = 0; + ops.ooboffs = 1; + ops.datbuf = 0; + ops.oobbuf = writebuf; + printk(PRINT_PREF "attempting to write past end of device\n"); + printk(PRINT_PREF "an error is expected...\n"); + err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops); + if (err) { + printk(PRINT_PREF "error occurred as expected\n"); + err = 0; + } else { + printk(PRINT_PREF "error: wrote past end of device\n"); + errcnt += 1; + } + + /* Attempt to read off end of device */ + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = mtd->ecclayout->oobavail; + ops.oobretlen = 0; + ops.ooboffs = 1; + ops.datbuf = 0; + ops.oobbuf = readbuf; + printk(PRINT_PREF "attempting to read past end of device\n"); + printk(PRINT_PREF "an error is expected...\n"); + err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops); + if (err) { + printk(PRINT_PREF "error occurred as expected\n"); + err = 0; + } else { + printk(PRINT_PREF "error: read past end of device\n"); + errcnt += 1; + } + } + + /* Fifth test: write / read across block boundaries */ + printk(PRINT_PREF "test 5 of 5\n"); + + /* Erase all eraseblocks */ + err = erase_whole_device(); + if (err) + goto out; + + /* Write all eraseblocks */ + simple_srand(11); + printk(PRINT_PREF "writing OOBs of whole device\n"); + for (i = 0; i < ebcnt - 1; ++i) { + int cnt = 2; + int pg; + size_t sz = mtd->ecclayout->oobavail; + if (bbt[i] || bbt[i + 1]) + continue; + addr = (i + 1) * mtd->erasesize - mtd->writesize; + for (pg = 0; pg < cnt; ++pg) { + set_random_data(writebuf, sz); + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = sz; + ops.oobretlen = 0; + ops.ooboffs = 0; + ops.datbuf = 0; + ops.oobbuf = writebuf; + err = mtd->write_oob(mtd, addr, &ops); + if (err) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "written up to eraseblock " + "%u\n", i); + cond_resched(); + addr += mtd->writesize; + } + } + printk(PRINT_PREF "written %u eraseblocks\n", i); + + /* Check all eraseblocks */ + simple_srand(11); + printk(PRINT_PREF "verifying all eraseblocks\n"); + for (i = 0; i < ebcnt - 1; ++i) { + if (bbt[i] || bbt[i + 1]) + continue; + set_random_data(writebuf, mtd->ecclayout->oobavail * 2); + addr = (i + 1) * mtd->erasesize - mtd->writesize; + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = mtd->ecclayout->oobavail * 2; + ops.oobretlen = 0; + ops.ooboffs = 0; + ops.datbuf = 0; + ops.oobbuf = readbuf; + err = mtd->read_oob(mtd, addr, &ops); + if (err) + goto out; + if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + errcnt += 1; + if (errcnt > 1000) { + printk(PRINT_PREF "error: too many errors\n"); + goto out; + } + } + if (i % 256 == 0) + printk(PRINT_PREF "verified up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "verified %u eraseblocks\n", i); + + printk(PRINT_PREF "finished with %d errors\n", errcnt); +out: + kfree(bbt); + kfree(writebuf); + kfree(readbuf); + put_mtd_device(mtd); + if (err) + printk(PRINT_PREF "error %d occurred\n", err); + printk(KERN_INFO "=================================================\n"); + return err; +} +module_init(mtd_oobtest_init); + +static void __exit mtd_oobtest_exit(void) +{ + return; +} +module_exit(mtd_oobtest_exit); + +MODULE_DESCRIPTION("Out-of-band test module"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/tests/mtd_pagetest.c b/drivers/mtd/tests/mtd_pagetest.c new file mode 100644 index 000000000000..9648818b9e2c --- /dev/null +++ b/drivers/mtd/tests/mtd_pagetest.c @@ -0,0 +1,632 @@ +/* + * Copyright (C) 2006-2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Test page read and write on MTD device. + * + * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> + */ + +#include <asm/div64.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/mtd/mtd.h> +#include <linux/sched.h> + +#define PRINT_PREF KERN_INFO "mtd_pagetest: " + +static int dev; +module_param(dev, int, S_IRUGO); +MODULE_PARM_DESC(dev, "MTD device number to use"); + +static struct mtd_info *mtd; +static unsigned char *twopages; +static unsigned char *writebuf; +static unsigned char *boundary; +static unsigned char *bbt; + +static int pgsize; +static int bufsize; +static int ebcnt; +static int pgcnt; +static int errcnt; +static unsigned long next = 1; + +static inline unsigned int simple_rand(void) +{ + next = next * 1103515245 + 12345; + return (unsigned int)((next / 65536) % 32768); +} + +static inline void simple_srand(unsigned long seed) +{ + next = seed; +} + +static void set_random_data(unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; ++i) + buf[i] = simple_rand(); +} + +static int erase_eraseblock(int ebnum) +{ + int err; + struct erase_info ei; + loff_t addr = ebnum * mtd->erasesize; + + memset(&ei, 0, sizeof(struct erase_info)); + ei.mtd = mtd; + ei.addr = addr; + ei.len = mtd->erasesize; + + err = mtd->erase(mtd, &ei); + if (err) { + printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + return err; + } + + if (ei.state == MTD_ERASE_FAILED) { + printk(PRINT_PREF "some erase error occurred at EB %d\n", + ebnum); + return -EIO; + } + + return 0; +} + +static int write_eraseblock(int ebnum) +{ + int err = 0; + size_t written = 0; + loff_t addr = ebnum * mtd->erasesize; + + set_random_data(writebuf, mtd->erasesize); + cond_resched(); + err = mtd->write(mtd, addr, mtd->erasesize, &written, writebuf); + if (err || written != mtd->erasesize) + printk(PRINT_PREF "error: write failed at %#llx\n", + (long long)addr); + + return err; +} + +static int verify_eraseblock(int ebnum) +{ + uint32_t j; + size_t read = 0; + int err = 0, i; + loff_t addr0, addrn; + loff_t addr = ebnum * mtd->erasesize; + + addr0 = 0; + for (i = 0; bbt[i] && i < ebcnt; ++i) + addr0 += mtd->erasesize; + + addrn = mtd->size; + for (i = 0; bbt[ebcnt - i - 1] && i < ebcnt; ++i) + addrn -= mtd->erasesize; + + set_random_data(writebuf, mtd->erasesize); + for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) { + /* Do a read to set the internal dataRAMs to different data */ + err = mtd->read(mtd, addr0, bufsize, &read, twopages); + if (err == -EUCLEAN) + err = 0; + if (err || read != bufsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr0); + return err; + } + err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); + if (err == -EUCLEAN) + err = 0; + if (err || read != bufsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)(addrn - bufsize)); + return err; + } + memset(twopages, 0, bufsize); + read = 0; + err = mtd->read(mtd, addr, bufsize, &read, twopages); + if (err == -EUCLEAN) + err = 0; + if (err || read != bufsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + break; + } + if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + errcnt += 1; + } + } + /* Check boundary between eraseblocks */ + if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) { + unsigned long oldnext = next; + /* Do a read to set the internal dataRAMs to different data */ + err = mtd->read(mtd, addr0, bufsize, &read, twopages); + if (err == -EUCLEAN) + err = 0; + if (err || read != bufsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr0); + return err; + } + err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); + if (err == -EUCLEAN) + err = 0; + if (err || read != bufsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)(addrn - bufsize)); + return err; + } + memset(twopages, 0, bufsize); + read = 0; + err = mtd->read(mtd, addr, bufsize, &read, twopages); + if (err == -EUCLEAN) + err = 0; + if (err || read != bufsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + return err; + } + memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize); + set_random_data(boundary + pgsize, pgsize); + if (memcmp(twopages, boundary, bufsize)) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + errcnt += 1; + } + next = oldnext; + } + return err; +} + +static int crosstest(void) +{ + size_t read = 0; + int err = 0, i; + loff_t addr, addr0, addrn; + unsigned char *pp1, *pp2, *pp3, *pp4; + + printk(PRINT_PREF "crosstest\n"); + pp1 = kmalloc(pgsize * 4, GFP_KERNEL); + if (!pp1) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + return -ENOMEM; + } + pp2 = pp1 + pgsize; + pp3 = pp2 + pgsize; + pp4 = pp3 + pgsize; + memset(pp1, 0, pgsize * 4); + + addr0 = 0; + for (i = 0; bbt[i] && i < ebcnt; ++i) + addr0 += mtd->erasesize; + + addrn = mtd->size; + for (i = 0; bbt[ebcnt - i - 1] && i < ebcnt; ++i) + addrn -= mtd->erasesize; + + /* Read 2nd-to-last page to pp1 */ + read = 0; + addr = addrn - pgsize - pgsize; + err = mtd->read(mtd, addr, pgsize, &read, pp1); + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + kfree(pp1); + return err; + } + + /* Read 3rd-to-last page to pp1 */ + read = 0; + addr = addrn - pgsize - pgsize - pgsize; + err = mtd->read(mtd, addr, pgsize, &read, pp1); + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + kfree(pp1); + return err; + } + + /* Read first page to pp2 */ + read = 0; + addr = addr0; + printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); + err = mtd->read(mtd, addr, pgsize, &read, pp2); + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + kfree(pp1); + return err; + } + + /* Read last page to pp3 */ + read = 0; + addr = addrn - pgsize; + printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); + err = mtd->read(mtd, addr, pgsize, &read, pp3); + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + kfree(pp1); + return err; + } + + /* Read first page again to pp4 */ + read = 0; + addr = addr0; + printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); + err = mtd->read(mtd, addr, pgsize, &read, pp4); + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + kfree(pp1); + return err; + } + + /* pp2 and pp4 should be the same */ + printk(PRINT_PREF "verifying pages read at %#llx match\n", + (long long)addr0); + if (memcmp(pp2, pp4, pgsize)) { + printk(PRINT_PREF "verify failed!\n"); + errcnt += 1; + } else if (!err) + printk(PRINT_PREF "crosstest ok\n"); + kfree(pp1); + return err; +} + +static int erasecrosstest(void) +{ + size_t read = 0, written = 0; + int err = 0, i, ebnum, ok = 1, ebnum2; + loff_t addr0; + char *readbuf = twopages; + + printk(PRINT_PREF "erasecrosstest\n"); + + ebnum = 0; + addr0 = 0; + for (i = 0; bbt[i] && i < ebcnt; ++i) { + addr0 += mtd->erasesize; + ebnum += 1; + } + + ebnum2 = ebcnt - 1; + while (ebnum2 && bbt[ebnum2]) + ebnum2 -= 1; + + printk(PRINT_PREF "erasing block %d\n", ebnum); + err = erase_eraseblock(ebnum); + if (err) + return err; + + printk(PRINT_PREF "writing 1st page of block %d\n", ebnum); + set_random_data(writebuf, pgsize); + strcpy(writebuf, "There is no data like this!"); + err = mtd->write(mtd, addr0, pgsize, &written, writebuf); + if (err || written != pgsize) { + printk(PRINT_PREF "error: write failed at %#llx\n", + (long long)addr0); + return err ? err : -1; + } + + printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); + memset(readbuf, 0, pgsize); + err = mtd->read(mtd, addr0, pgsize, &read, readbuf); + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr0); + return err ? err : -1; + } + + printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum); + if (memcmp(writebuf, readbuf, pgsize)) { + printk(PRINT_PREF "verify failed!\n"); + errcnt += 1; + ok = 0; + return err; + } + + printk(PRINT_PREF "erasing block %d\n", ebnum); + err = erase_eraseblock(ebnum); + if (err) + return err; + + printk(PRINT_PREF "writing 1st page of block %d\n", ebnum); + set_random_data(writebuf, pgsize); + strcpy(writebuf, "There is no data like this!"); + err = mtd->write(mtd, addr0, pgsize, &written, writebuf); + if (err || written != pgsize) { + printk(PRINT_PREF "error: write failed at %#llx\n", + (long long)addr0); + return err ? err : -1; + } + + printk(PRINT_PREF "erasing block %d\n", ebnum2); + err = erase_eraseblock(ebnum2); + if (err) + return err; + + printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); + memset(readbuf, 0, pgsize); + err = mtd->read(mtd, addr0, pgsize, &read, readbuf); + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr0); + return err ? err : -1; + } + + printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum); + if (memcmp(writebuf, readbuf, pgsize)) { + printk(PRINT_PREF "verify failed!\n"); + errcnt += 1; + ok = 0; + } + + if (ok && !err) + printk(PRINT_PREF "erasecrosstest ok\n"); + return err; +} + +static int erasetest(void) +{ + size_t read = 0, written = 0; + int err = 0, i, ebnum, ok = 1; + loff_t addr0; + + printk(PRINT_PREF "erasetest\n"); + + ebnum = 0; + addr0 = 0; + for (i = 0; bbt[i] && i < ebcnt; ++i) { + addr0 += mtd->erasesize; + ebnum += 1; + } + + printk(PRINT_PREF "erasing block %d\n", ebnum); + err = erase_eraseblock(ebnum); + if (err) + return err; + + printk(PRINT_PREF "writing 1st page of block %d\n", ebnum); + set_random_data(writebuf, pgsize); + err = mtd->write(mtd, addr0, pgsize, &written, writebuf); + if (err || written != pgsize) { + printk(PRINT_PREF "error: write failed at %#llx\n", + (long long)addr0); + return err ? err : -1; + } + + printk(PRINT_PREF "erasing block %d\n", ebnum); + err = erase_eraseblock(ebnum); + if (err) + return err; + + printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); + err = mtd->read(mtd, addr0, pgsize, &read, twopages); + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr0); + return err ? err : -1; + } + + printk(PRINT_PREF "verifying 1st page of block %d is all 0xff\n", + ebnum); + for (i = 0; i < pgsize; ++i) + if (twopages[i] != 0xff) { + printk(PRINT_PREF "verifying all 0xff failed at %d\n", + i); + errcnt += 1; + ok = 0; + break; + } + + if (ok && !err) + printk(PRINT_PREF "erasetest ok\n"); + + return err; +} + +static int is_block_bad(int ebnum) +{ + loff_t addr = ebnum * mtd->erasesize; + int ret; + + ret = mtd->block_isbad(mtd, addr); + if (ret) + printk(PRINT_PREF "block %d is bad\n", ebnum); + return ret; +} + +static int scan_for_bad_eraseblocks(void) +{ + int i, bad = 0; + + bbt = kmalloc(ebcnt, GFP_KERNEL); + if (!bbt) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + return -ENOMEM; + } + memset(bbt, 0 , ebcnt); + + printk(PRINT_PREF "scanning for bad eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + bbt[i] = is_block_bad(i) ? 1 : 0; + if (bbt[i]) + bad += 1; + cond_resched(); + } + printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + return 0; +} + +static int __init mtd_pagetest_init(void) +{ + int err = 0; + uint64_t tmp; + uint32_t i; + + printk(KERN_INFO "\n"); + printk(KERN_INFO "=================================================\n"); + printk(PRINT_PREF "MTD device: %d\n", dev); + + mtd = get_mtd_device(NULL, dev); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + printk(PRINT_PREF "error: cannot get MTD device\n"); + return err; + } + + if (mtd->type != MTD_NANDFLASH) { + printk(PRINT_PREF "this test requires NAND flash\n"); + goto out; + } + + tmp = mtd->size; + do_div(tmp, mtd->erasesize); + ebcnt = tmp; + pgcnt = mtd->erasesize / mtd->writesize; + + printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + "page size %u, count of eraseblocks %u, pages per " + "eraseblock %u, OOB size %u\n", + (unsigned long long)mtd->size, mtd->erasesize, + pgsize, ebcnt, pgcnt, mtd->oobsize); + + err = -ENOMEM; + bufsize = pgsize * 2; + writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!writebuf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + twopages = kmalloc(bufsize, GFP_KERNEL); + if (!twopages) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + boundary = kmalloc(bufsize, GFP_KERNEL); + if (!boundary) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + + err = scan_for_bad_eraseblocks(); + if (err) + goto out; + + /* Erase all eraseblocks */ + printk(PRINT_PREF "erasing whole device\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = erase_eraseblock(i); + if (err) + goto out; + cond_resched(); + } + printk(PRINT_PREF "erased %u eraseblocks\n", i); + + /* Write all eraseblocks */ + simple_srand(1); + printk(PRINT_PREF "writing whole device\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock(i); + if (err) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "written up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "written %u eraseblocks\n", i); + + /* Check all eraseblocks */ + simple_srand(1); + printk(PRINT_PREF "verifying all eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = verify_eraseblock(i); + if (err) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "verified up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "verified %u eraseblocks\n", i); + + err = crosstest(); + if (err) + goto out; + + err = erasecrosstest(); + if (err) + goto out; + + err = erasetest(); + if (err) + goto out; + + printk(PRINT_PREF "finished with %d errors\n", errcnt); +out: + + kfree(bbt); + kfree(boundary); + kfree(twopages); + kfree(writebuf); + put_mtd_device(mtd); + if (err) + printk(PRINT_PREF "error %d occurred\n", err); + printk(KERN_INFO "=================================================\n"); + return err; +} +module_init(mtd_pagetest_init); + +static void __exit mtd_pagetest_exit(void) +{ + return; +} +module_exit(mtd_pagetest_exit); + +MODULE_DESCRIPTION("NAND page test"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c new file mode 100644 index 000000000000..645e77fdc63d --- /dev/null +++ b/drivers/mtd/tests/mtd_readtest.c @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2006-2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Check MTD device read. + * + * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/mtd/mtd.h> +#include <linux/sched.h> + +#define PRINT_PREF KERN_INFO "mtd_readtest: " + +static int dev; +module_param(dev, int, S_IRUGO); +MODULE_PARM_DESC(dev, "MTD device number to use"); + +static struct mtd_info *mtd; +static unsigned char *iobuf; +static unsigned char *iobuf1; +static unsigned char *bbt; + +static int pgsize; +static int ebcnt; +static int pgcnt; + +static int read_eraseblock_by_page(int ebnum) +{ + size_t read = 0; + int i, ret, err = 0; + loff_t addr = ebnum * mtd->erasesize; + void *buf = iobuf; + void *oobbuf = iobuf1; + + for (i = 0; i < pgcnt; i++) { + memset(buf, 0 , pgcnt); + ret = mtd->read(mtd, addr, pgsize, &read, buf); + if (ret == -EUCLEAN) + ret = 0; + if (ret || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + if (!err) + err = ret; + if (!err) + err = -EINVAL; + } + if (mtd->oobsize) { + struct mtd_oob_ops ops; + + ops.mode = MTD_OOB_PLACE; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = mtd->oobsize; + ops.oobretlen = 0; + ops.ooboffs = 0; + ops.datbuf = 0; + ops.oobbuf = oobbuf; + ret = mtd->read_oob(mtd, addr, &ops); + if (ret || ops.oobretlen != mtd->oobsize) { + printk(PRINT_PREF "error: read oob failed at " + "%#llx\n", (long long)addr); + if (!err) + err = ret; + if (!err) + err = -EINVAL; + } + oobbuf += mtd->oobsize; + } + addr += pgsize; + buf += pgsize; + } + + return err; +} + +static void dump_eraseblock(int ebnum) +{ + int i, j, n; + char line[128]; + int pg, oob; + + printk(PRINT_PREF "dumping eraseblock %d\n", ebnum); + n = mtd->erasesize; + for (i = 0; i < n;) { + char *p = line; + + p += sprintf(p, "%05x: ", i); + for (j = 0; j < 32 && i < n; j++, i++) + p += sprintf(p, "%02x", (unsigned int)iobuf[i]); + printk(KERN_CRIT "%s\n", line); + cond_resched(); + } + if (!mtd->oobsize) + return; + printk(PRINT_PREF "dumping oob from eraseblock %d\n", ebnum); + n = mtd->oobsize; + for (pg = 0, i = 0; pg < pgcnt; pg++) + for (oob = 0; oob < n;) { + char *p = line; + + p += sprintf(p, "%05x: ", i); + for (j = 0; j < 32 && oob < n; j++, oob++, i++) + p += sprintf(p, "%02x", + (unsigned int)iobuf1[i]); + printk(KERN_CRIT "%s\n", line); + cond_resched(); + } +} + +static int is_block_bad(int ebnum) +{ + loff_t addr = ebnum * mtd->erasesize; + int ret; + + ret = mtd->block_isbad(mtd, addr); + if (ret) + printk(PRINT_PREF "block %d is bad\n", ebnum); + return ret; +} + +static int scan_for_bad_eraseblocks(void) +{ + int i, bad = 0; + + bbt = kmalloc(ebcnt, GFP_KERNEL); + if (!bbt) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + return -ENOMEM; + } + memset(bbt, 0 , ebcnt); + + printk(PRINT_PREF "scanning for bad eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + bbt[i] = is_block_bad(i) ? 1 : 0; + if (bbt[i]) + bad += 1; + cond_resched(); + } + printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + return 0; +} + +static int __init mtd_readtest_init(void) +{ + uint64_t tmp; + int err, i; + + printk(KERN_INFO "\n"); + printk(KERN_INFO "=================================================\n"); + printk(PRINT_PREF "MTD device: %d\n", dev); + + mtd = get_mtd_device(NULL, dev); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + printk(PRINT_PREF "error: Cannot get MTD device\n"); + return err; + } + + if (mtd->writesize == 1) { + printk(PRINT_PREF "not NAND flash, assume page size is 512 " + "bytes.\n"); + pgsize = 512; + } else + pgsize = mtd->writesize; + + tmp = mtd->size; + do_div(tmp, mtd->erasesize); + ebcnt = tmp; + pgcnt = mtd->erasesize / mtd->writesize; + + printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + "page size %u, count of eraseblocks %u, pages per " + "eraseblock %u, OOB size %u\n", + (unsigned long long)mtd->size, mtd->erasesize, + pgsize, ebcnt, pgcnt, mtd->oobsize); + + err = -ENOMEM; + iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!iobuf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!iobuf1) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + + err = scan_for_bad_eraseblocks(); + if (err) + goto out; + + /* Read all eraseblocks 1 page at a time */ + printk(PRINT_PREF "testing page read\n"); + for (i = 0; i < ebcnt; ++i) { + int ret; + + if (bbt[i]) + continue; + ret = read_eraseblock_by_page(i); + if (ret) { + dump_eraseblock(i); + if (!err) + err = ret; + } + cond_resched(); + } + + if (err) + printk(PRINT_PREF "finished with errors\n"); + else + printk(PRINT_PREF "finished\n"); + +out: + + kfree(iobuf); + kfree(iobuf1); + kfree(bbt); + put_mtd_device(mtd); + if (err) + printk(PRINT_PREF "error %d occurred\n", err); + printk(KERN_INFO "=================================================\n"); + return err; +} +module_init(mtd_readtest_init); + +static void __exit mtd_readtest_exit(void) +{ + return; +} +module_exit(mtd_readtest_exit); + +MODULE_DESCRIPTION("Read test module"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c new file mode 100644 index 000000000000..141363a7e805 --- /dev/null +++ b/drivers/mtd/tests/mtd_speedtest.c @@ -0,0 +1,502 @@ +/* + * Copyright (C) 2007 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Test read and write speed of a MTD device. + * + * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/mtd/mtd.h> +#include <linux/sched.h> + +#define PRINT_PREF KERN_INFO "mtd_speedtest: " + +static int dev; +module_param(dev, int, S_IRUGO); +MODULE_PARM_DESC(dev, "MTD device number to use"); + +static struct mtd_info *mtd; +static unsigned char *iobuf; +static unsigned char *bbt; + +static int pgsize; +static int ebcnt; +static int pgcnt; +static int goodebcnt; +static struct timeval start, finish; +static unsigned long next = 1; + +static inline unsigned int simple_rand(void) +{ + next = next * 1103515245 + 12345; + return (unsigned int)((next / 65536) % 32768); +} + +static inline void simple_srand(unsigned long seed) +{ + next = seed; +} + +static void set_random_data(unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; ++i) + buf[i] = simple_rand(); +} + +static int erase_eraseblock(int ebnum) +{ + int err; + struct erase_info ei; + loff_t addr = ebnum * mtd->erasesize; + + memset(&ei, 0, sizeof(struct erase_info)); + ei.mtd = mtd; + ei.addr = addr; + ei.len = mtd->erasesize; + + err = mtd->erase(mtd, &ei); + if (err) { + printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + return err; + } + + if (ei.state == MTD_ERASE_FAILED) { + printk(PRINT_PREF "some erase error occurred at EB %d\n", + ebnum); + return -EIO; + } + + return 0; +} + +static int erase_whole_device(void) +{ + int err; + unsigned int i; + + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = erase_eraseblock(i); + if (err) + return err; + cond_resched(); + } + return 0; +} + +static int write_eraseblock(int ebnum) +{ + size_t written = 0; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + + err = mtd->write(mtd, addr, mtd->erasesize, &written, iobuf); + if (err || written != mtd->erasesize) { + printk(PRINT_PREF "error: write failed at %#llx\n", addr); + if (!err) + err = -EINVAL; + } + + return err; +} + +static int write_eraseblock_by_page(int ebnum) +{ + size_t written = 0; + int i, err = 0; + loff_t addr = ebnum * mtd->erasesize; + void *buf = iobuf; + + for (i = 0; i < pgcnt; i++) { + err = mtd->write(mtd, addr, pgsize, &written, buf); + if (err || written != pgsize) { + printk(PRINT_PREF "error: write failed at %#llx\n", + addr); + if (!err) + err = -EINVAL; + break; + } + addr += pgsize; + buf += pgsize; + } + + return err; +} + +static int write_eraseblock_by_2pages(int ebnum) +{ + size_t written = 0, sz = pgsize * 2; + int i, n = pgcnt / 2, err = 0; + loff_t addr = ebnum * mtd->erasesize; + void *buf = iobuf; + + for (i = 0; i < n; i++) { + err = mtd->write(mtd, addr, sz, &written, buf); + if (err || written != sz) { + printk(PRINT_PREF "error: write failed at %#llx\n", + addr); + if (!err) + err = -EINVAL; + return err; + } + addr += sz; + buf += sz; + } + if (pgcnt % 2) { + err = mtd->write(mtd, addr, pgsize, &written, buf); + if (err || written != pgsize) { + printk(PRINT_PREF "error: write failed at %#llx\n", + addr); + if (!err) + err = -EINVAL; + } + } + + return err; +} + +static int read_eraseblock(int ebnum) +{ + size_t read = 0; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + + err = mtd->read(mtd, addr, mtd->erasesize, &read, iobuf); + /* Ignore corrected ECC errors */ + if (err == -EUCLEAN) + err = 0; + if (err || read != mtd->erasesize) { + printk(PRINT_PREF "error: read failed at %#llx\n", addr); + if (!err) + err = -EINVAL; + } + + return err; +} + +static int read_eraseblock_by_page(int ebnum) +{ + size_t read = 0; + int i, err = 0; + loff_t addr = ebnum * mtd->erasesize; + void *buf = iobuf; + + for (i = 0; i < pgcnt; i++) { + err = mtd->read(mtd, addr, pgsize, &read, buf); + /* Ignore corrected ECC errors */ + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + addr); + if (!err) + err = -EINVAL; + break; + } + addr += pgsize; + buf += pgsize; + } + + return err; +} + +static int read_eraseblock_by_2pages(int ebnum) +{ + size_t read = 0, sz = pgsize * 2; + int i, n = pgcnt / 2, err = 0; + loff_t addr = ebnum * mtd->erasesize; + void *buf = iobuf; + + for (i = 0; i < n; i++) { + err = mtd->read(mtd, addr, sz, &read, buf); + /* Ignore corrected ECC errors */ + if (err == -EUCLEAN) + err = 0; + if (err || read != sz) { + printk(PRINT_PREF "error: read failed at %#llx\n", + addr); + if (!err) + err = -EINVAL; + return err; + } + addr += sz; + buf += sz; + } + if (pgcnt % 2) { + err = mtd->read(mtd, addr, pgsize, &read, buf); + /* Ignore corrected ECC errors */ + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + addr); + if (!err) + err = -EINVAL; + } + } + + return err; +} + +static int is_block_bad(int ebnum) +{ + loff_t addr = ebnum * mtd->erasesize; + int ret; + + ret = mtd->block_isbad(mtd, addr); + if (ret) + printk(PRINT_PREF "block %d is bad\n", ebnum); + return ret; +} + +static inline void start_timing(void) +{ + do_gettimeofday(&start); +} + +static inline void stop_timing(void) +{ + do_gettimeofday(&finish); +} + +static long calc_speed(void) +{ + long ms, k, speed; + + ms = (finish.tv_sec - start.tv_sec) * 1000 + + (finish.tv_usec - start.tv_usec) / 1000; + k = goodebcnt * mtd->erasesize / 1024; + speed = (k * 1000) / ms; + return speed; +} + +static int scan_for_bad_eraseblocks(void) +{ + int i, bad = 0; + + bbt = kmalloc(ebcnt, GFP_KERNEL); + if (!bbt) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + return -ENOMEM; + } + memset(bbt, 0 , ebcnt); + + printk(PRINT_PREF "scanning for bad eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + bbt[i] = is_block_bad(i) ? 1 : 0; + if (bbt[i]) + bad += 1; + cond_resched(); + } + printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + goodebcnt = ebcnt - bad; + return 0; +} + +static int __init mtd_speedtest_init(void) +{ + int err, i; + long speed; + uint64_t tmp; + + printk(KERN_INFO "\n"); + printk(KERN_INFO "=================================================\n"); + printk(PRINT_PREF "MTD device: %d\n", dev); + + mtd = get_mtd_device(NULL, dev); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + printk(PRINT_PREF "error: cannot get MTD device\n"); + return err; + } + + if (mtd->writesize == 1) { + printk(PRINT_PREF "not NAND flash, assume page size is 512 " + "bytes.\n"); + pgsize = 512; + } else + pgsize = mtd->writesize; + + tmp = mtd->size; + do_div(tmp, mtd->erasesize); + ebcnt = tmp; + pgcnt = mtd->erasesize / mtd->writesize; + + printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + "page size %u, count of eraseblocks %u, pages per " + "eraseblock %u, OOB size %u\n", + (unsigned long long)mtd->size, mtd->erasesize, + pgsize, ebcnt, pgcnt, mtd->oobsize); + + err = -ENOMEM; + iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!iobuf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + + simple_srand(1); + set_random_data(iobuf, mtd->erasesize); + + err = scan_for_bad_eraseblocks(); + if (err) + goto out; + + err = erase_whole_device(); + if (err) + goto out; + + /* Write all eraseblocks, 1 eraseblock at a time */ + printk(PRINT_PREF "testing eraseblock write speed\n"); + start_timing(); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock(i); + if (err) + goto out; + cond_resched(); + } + stop_timing(); + speed = calc_speed(); + printk(PRINT_PREF "eraseblock write speed is %ld KiB/s\n", speed); + + /* Read all eraseblocks, 1 eraseblock at a time */ + printk(PRINT_PREF "testing eraseblock read speed\n"); + start_timing(); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = read_eraseblock(i); + if (err) + goto out; + cond_resched(); + } + stop_timing(); + speed = calc_speed(); + printk(PRINT_PREF "eraseblock read speed is %ld KiB/s\n", speed); + + err = erase_whole_device(); + if (err) + goto out; + + /* Write all eraseblocks, 1 page at a time */ + printk(PRINT_PREF "testing page write speed\n"); + start_timing(); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock_by_page(i); + if (err) + goto out; + cond_resched(); + } + stop_timing(); + speed = calc_speed(); + printk(PRINT_PREF "page write speed is %ld KiB/s\n", speed); + + /* Read all eraseblocks, 1 page at a time */ + printk(PRINT_PREF "testing page read speed\n"); + start_timing(); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = read_eraseblock_by_page(i); + if (err) + goto out; + cond_resched(); + } + stop_timing(); + speed = calc_speed(); + printk(PRINT_PREF "page read speed is %ld KiB/s\n", speed); + + err = erase_whole_device(); + if (err) + goto out; + + /* Write all eraseblocks, 2 pages at a time */ + printk(PRINT_PREF "testing 2 page write speed\n"); + start_timing(); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock_by_2pages(i); + if (err) + goto out; + cond_resched(); + } + stop_timing(); + speed = calc_speed(); + printk(PRINT_PREF "2 page write speed is %ld KiB/s\n", speed); + + /* Read all eraseblocks, 2 pages at a time */ + printk(PRINT_PREF "testing 2 page read speed\n"); + start_timing(); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = read_eraseblock_by_2pages(i); + if (err) + goto out; + cond_resched(); + } + stop_timing(); + speed = calc_speed(); + printk(PRINT_PREF "2 page read speed is %ld KiB/s\n", speed); + + /* Erase all eraseblocks */ + printk(PRINT_PREF "Testing erase speed\n"); + start_timing(); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = erase_eraseblock(i); + if (err) + goto out; + cond_resched(); + } + stop_timing(); + speed = calc_speed(); + printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed); + + printk(PRINT_PREF "finished\n"); +out: + kfree(iobuf); + kfree(bbt); + put_mtd_device(mtd); + if (err) + printk(PRINT_PREF "error %d occurred\n", err); + printk(KERN_INFO "=================================================\n"); + return err; +} +module_init(mtd_speedtest_init); + +static void __exit mtd_speedtest_exit(void) +{ + return; +} +module_exit(mtd_speedtest_exit); + +MODULE_DESCRIPTION("Speed test module"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c new file mode 100644 index 000000000000..63920476b57a --- /dev/null +++ b/drivers/mtd/tests/mtd_stresstest.c @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2006-2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Test random reads, writes and erases on MTD device. + * + * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/mtd/mtd.h> +#include <linux/sched.h> +#include <linux/vmalloc.h> + +#define PRINT_PREF KERN_INFO "mtd_stresstest: " + +static int dev; +module_param(dev, int, S_IRUGO); +MODULE_PARM_DESC(dev, "MTD device number to use"); + +static int count = 10000; +module_param(count, int, S_IRUGO); +MODULE_PARM_DESC(count, "Number of operations to do (default is 10000)"); + +static struct mtd_info *mtd; +static unsigned char *writebuf; +static unsigned char *readbuf; +static unsigned char *bbt; +static int *offsets; + +static int pgsize; +static int bufsize; +static int ebcnt; +static int pgcnt; +static unsigned long next = 1; + +static inline unsigned int simple_rand(void) +{ + next = next * 1103515245 + 12345; + return (unsigned int)((next / 65536) % 32768); +} + +static inline void simple_srand(unsigned long seed) +{ + next = seed; +} + +static int rand_eb(void) +{ + int eb; + +again: + if (ebcnt < 32768) + eb = simple_rand(); + else + eb = (simple_rand() << 15) | simple_rand(); + /* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */ + eb %= (ebcnt - 1); + if (bbt[eb]) + goto again; + return eb; +} + +static int rand_offs(void) +{ + int offs; + + if (bufsize < 32768) + offs = simple_rand(); + else + offs = (simple_rand() << 15) | simple_rand(); + offs %= bufsize; + return offs; +} + +static int rand_len(int offs) +{ + int len; + + if (bufsize < 32768) + len = simple_rand(); + else + len = (simple_rand() << 15) | simple_rand(); + len %= (bufsize - offs); + return len; +} + +static int erase_eraseblock(int ebnum) +{ + int err; + struct erase_info ei; + loff_t addr = ebnum * mtd->erasesize; + + memset(&ei, 0, sizeof(struct erase_info)); + ei.mtd = mtd; + ei.addr = addr; + ei.len = mtd->erasesize; + + err = mtd->erase(mtd, &ei); + if (unlikely(err)) { + printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + return err; + } + + if (unlikely(ei.state == MTD_ERASE_FAILED)) { + printk(PRINT_PREF "some erase error occurred at EB %d\n", + ebnum); + return -EIO; + } + + return 0; +} + +static int is_block_bad(int ebnum) +{ + loff_t addr = ebnum * mtd->erasesize; + int ret; + + ret = mtd->block_isbad(mtd, addr); + if (ret) + printk(PRINT_PREF "block %d is bad\n", ebnum); + return ret; +} + +static int do_read(void) +{ + size_t read = 0; + int eb = rand_eb(); + int offs = rand_offs(); + int len = rand_len(offs), err; + loff_t addr; + + if (bbt[eb + 1]) { + if (offs >= mtd->erasesize) + offs -= mtd->erasesize; + if (offs + len > mtd->erasesize) + len = mtd->erasesize - offs; + } + addr = eb * mtd->erasesize + offs; + err = mtd->read(mtd, addr, len, &read, readbuf); + if (err == -EUCLEAN) + err = 0; + if (unlikely(err || read != len)) { + printk(PRINT_PREF "error: read failed at 0x%llx\n", + (long long)addr); + if (!err) + err = -EINVAL; + return err; + } + return 0; +} + +static int do_write(void) +{ + int eb = rand_eb(), offs, err, len; + size_t written = 0; + loff_t addr; + + offs = offsets[eb]; + if (offs >= mtd->erasesize) { + err = erase_eraseblock(eb); + if (err) + return err; + offs = offsets[eb] = 0; + } + len = rand_len(offs); + len = ((len + pgsize - 1) / pgsize) * pgsize; + if (offs + len > mtd->erasesize) { + if (bbt[eb + 1]) + len = mtd->erasesize - offs; + else { + err = erase_eraseblock(eb + 1); + if (err) + return err; + offsets[eb + 1] = 0; + } + } + addr = eb * mtd->erasesize + offs; + err = mtd->write(mtd, addr, len, &written, writebuf); + if (unlikely(err || written != len)) { + printk(PRINT_PREF "error: write failed at 0x%llx\n", + (long long)addr); + if (!err) + err = -EINVAL; + return err; + } + offs += len; + while (offs > mtd->erasesize) { + offsets[eb++] = mtd->erasesize; + offs -= mtd->erasesize; + } + offsets[eb] = offs; + return 0; +} + +static int do_operation(void) +{ + if (simple_rand() & 1) + return do_read(); + else + return do_write(); +} + +static int scan_for_bad_eraseblocks(void) +{ + int i, bad = 0; + + bbt = kmalloc(ebcnt, GFP_KERNEL); + if (!bbt) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + return -ENOMEM; + } + memset(bbt, 0 , ebcnt); + + printk(PRINT_PREF "scanning for bad eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + bbt[i] = is_block_bad(i) ? 1 : 0; + if (bbt[i]) + bad += 1; + cond_resched(); + } + printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + return 0; +} + +static int __init mtd_stresstest_init(void) +{ + int err; + int i, op; + uint64_t tmp; + + printk(KERN_INFO "\n"); + printk(KERN_INFO "=================================================\n"); + printk(PRINT_PREF "MTD device: %d\n", dev); + + mtd = get_mtd_device(NULL, dev); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + printk(PRINT_PREF "error: cannot get MTD device\n"); + return err; + } + + if (mtd->writesize == 1) { + printk(PRINT_PREF "not NAND flash, assume page size is 512 " + "bytes.\n"); + pgsize = 512; + } else + pgsize = mtd->writesize; + + tmp = mtd->size; + do_div(tmp, mtd->erasesize); + ebcnt = tmp; + pgcnt = mtd->erasesize / mtd->writesize; + + printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + "page size %u, count of eraseblocks %u, pages per " + "eraseblock %u, OOB size %u\n", + (unsigned long long)mtd->size, mtd->erasesize, + pgsize, ebcnt, pgcnt, mtd->oobsize); + + /* Read or write up 2 eraseblocks at a time */ + bufsize = mtd->erasesize * 2; + + err = -ENOMEM; + readbuf = vmalloc(bufsize); + writebuf = vmalloc(bufsize); + offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL); + if (!readbuf || !writebuf || !offsets) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + for (i = 0; i < ebcnt; i++) + offsets[i] = mtd->erasesize; + simple_srand(current->pid); + for (i = 0; i < bufsize; i++) + writebuf[i] = simple_rand(); + + err = scan_for_bad_eraseblocks(); + if (err) + goto out; + + /* Do operations */ + printk(PRINT_PREF "doing operations\n"); + for (op = 0; op < count; op++) { + if ((op & 1023) == 0) + printk(PRINT_PREF "%d operations done\n", op); + err = do_operation(); + if (err) + goto out; + cond_resched(); + } + printk(PRINT_PREF "finished, %d operations done\n", op); + +out: + kfree(offsets); + kfree(bbt); + vfree(writebuf); + vfree(readbuf); + put_mtd_device(mtd); + if (err) + printk(PRINT_PREF "error %d occurred\n", err); + printk(KERN_INFO "=================================================\n"); + return err; +} +module_init(mtd_stresstest_init); + +static void __exit mtd_stresstest_exit(void) +{ + return; +} +module_exit(mtd_stresstest_exit); + +MODULE_DESCRIPTION("Stress test module"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/tests/mtd_subpagetest.c b/drivers/mtd/tests/mtd_subpagetest.c new file mode 100644 index 000000000000..5b889724268e --- /dev/null +++ b/drivers/mtd/tests/mtd_subpagetest.c @@ -0,0 +1,525 @@ +/* + * Copyright (C) 2006-2007 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Test sub-page read and write on MTD device. + * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/mtd/mtd.h> +#include <linux/sched.h> + +#define PRINT_PREF KERN_INFO "mtd_subpagetest: " + +static int dev; +module_param(dev, int, S_IRUGO); +MODULE_PARM_DESC(dev, "MTD device number to use"); + +static struct mtd_info *mtd; +static unsigned char *writebuf; +static unsigned char *readbuf; +static unsigned char *bbt; + +static int subpgsize; +static int bufsize; +static int ebcnt; +static int pgcnt; +static int errcnt; +static unsigned long next = 1; + +static inline unsigned int simple_rand(void) +{ + next = next * 1103515245 + 12345; + return (unsigned int)((next / 65536) % 32768); +} + +static inline void simple_srand(unsigned long seed) +{ + next = seed; +} + +static void set_random_data(unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; ++i) + buf[i] = simple_rand(); +} + +static inline void clear_data(unsigned char *buf, size_t len) +{ + memset(buf, 0, len); +} + +static int erase_eraseblock(int ebnum) +{ + int err; + struct erase_info ei; + loff_t addr = ebnum * mtd->erasesize; + + memset(&ei, 0, sizeof(struct erase_info)); + ei.mtd = mtd; + ei.addr = addr; + ei.len = mtd->erasesize; + + err = mtd->erase(mtd, &ei); + if (err) { + printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + return err; + } + + if (ei.state == MTD_ERASE_FAILED) { + printk(PRINT_PREF "some erase error occurred at EB %d\n", + ebnum); + return -EIO; + } + + return 0; +} + +static int erase_whole_device(void) +{ + int err; + unsigned int i; + + printk(PRINT_PREF "erasing whole device\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = erase_eraseblock(i); + if (err) + return err; + cond_resched(); + } + printk(PRINT_PREF "erased %u eraseblocks\n", i); + return 0; +} + +static int write_eraseblock(int ebnum) +{ + size_t written = 0; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + + set_random_data(writebuf, subpgsize); + err = mtd->write(mtd, addr, subpgsize, &written, writebuf); + if (unlikely(err || written != subpgsize)) { + printk(PRINT_PREF "error: write failed at %#llx\n", + (long long)addr); + if (written != subpgsize) { + printk(PRINT_PREF " write size: %#x\n", subpgsize); + printk(PRINT_PREF " written: %#zx\n", written); + } + return err ? err : -1; + } + + addr += subpgsize; + + set_random_data(writebuf, subpgsize); + err = mtd->write(mtd, addr, subpgsize, &written, writebuf); + if (unlikely(err || written != subpgsize)) { + printk(PRINT_PREF "error: write failed at %#llx\n", + (long long)addr); + if (written != subpgsize) { + printk(PRINT_PREF " write size: %#x\n", subpgsize); + printk(PRINT_PREF " written: %#zx\n", written); + } + return err ? err : -1; + } + + return err; +} + +static int write_eraseblock2(int ebnum) +{ + size_t written = 0; + int err = 0, k; + loff_t addr = ebnum * mtd->erasesize; + + for (k = 1; k < 33; ++k) { + if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) + break; + set_random_data(writebuf, subpgsize * k); + err = mtd->write(mtd, addr, subpgsize * k, &written, writebuf); + if (unlikely(err || written != subpgsize * k)) { + printk(PRINT_PREF "error: write failed at %#llx\n", + (long long)addr); + if (written != subpgsize) { + printk(PRINT_PREF " write size: %#x\n", + subpgsize * k); + printk(PRINT_PREF " written: %#08zx\n", + written); + } + return err ? err : -1; + } + addr += subpgsize * k; + } + + return err; +} + +static void print_subpage(unsigned char *p) +{ + int i, j; + + for (i = 0; i < subpgsize; ) { + for (j = 0; i < subpgsize && j < 32; ++i, ++j) + printk("%02x", *p++); + printk("\n"); + } +} + +static int verify_eraseblock(int ebnum) +{ + size_t read = 0; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + + set_random_data(writebuf, subpgsize); + clear_data(readbuf, subpgsize); + read = 0; + err = mtd->read(mtd, addr, subpgsize, &read, readbuf); + if (unlikely(err || read != subpgsize)) { + if (err == -EUCLEAN && read == subpgsize) { + printk(PRINT_PREF "ECC correction at %#llx\n", + (long long)addr); + err = 0; + } else { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + return err ? err : -1; + } + } + if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + printk(PRINT_PREF "------------- written----------------\n"); + print_subpage(writebuf); + printk(PRINT_PREF "------------- read ------------------\n"); + print_subpage(readbuf); + printk(PRINT_PREF "-------------------------------------\n"); + errcnt += 1; + } + + addr += subpgsize; + + set_random_data(writebuf, subpgsize); + clear_data(readbuf, subpgsize); + read = 0; + err = mtd->read(mtd, addr, subpgsize, &read, readbuf); + if (unlikely(err || read != subpgsize)) { + if (err == -EUCLEAN && read == subpgsize) { + printk(PRINT_PREF "ECC correction at %#llx\n", + (long long)addr); + err = 0; + } else { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + return err ? err : -1; + } + } + if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + printk(PRINT_PREF "------------- written----------------\n"); + print_subpage(writebuf); + printk(PRINT_PREF "------------- read ------------------\n"); + print_subpage(readbuf); + printk(PRINT_PREF "-------------------------------------\n"); + errcnt += 1; + } + + return err; +} + +static int verify_eraseblock2(int ebnum) +{ + size_t read = 0; + int err = 0, k; + loff_t addr = ebnum * mtd->erasesize; + + for (k = 1; k < 33; ++k) { + if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) + break; + set_random_data(writebuf, subpgsize * k); + clear_data(readbuf, subpgsize * k); + read = 0; + err = mtd->read(mtd, addr, subpgsize * k, &read, readbuf); + if (unlikely(err || read != subpgsize * k)) { + if (err == -EUCLEAN && read == subpgsize * k) { + printk(PRINT_PREF "ECC correction at %#llx\n", + (long long)addr); + err = 0; + } else { + printk(PRINT_PREF "error: read failed at " + "%#llx\n", (long long)addr); + return err ? err : -1; + } + } + if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + errcnt += 1; + } + addr += subpgsize * k; + } + + return err; +} + +static int verify_eraseblock_ff(int ebnum) +{ + uint32_t j; + size_t read = 0; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + + memset(writebuf, 0xff, subpgsize); + for (j = 0; j < mtd->erasesize / subpgsize; ++j) { + clear_data(readbuf, subpgsize); + read = 0; + err = mtd->read(mtd, addr, subpgsize, &read, readbuf); + if (unlikely(err || read != subpgsize)) { + if (err == -EUCLEAN && read == subpgsize) { + printk(PRINT_PREF "ECC correction at %#llx\n", + (long long)addr); + err = 0; + } else { + printk(PRINT_PREF "error: read failed at " + "%#llx\n", (long long)addr); + return err ? err : -1; + } + } + if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { + printk(PRINT_PREF "error: verify 0xff failed at " + "%#llx\n", (long long)addr); + errcnt += 1; + } + addr += subpgsize; + } + + return err; +} + +static int verify_all_eraseblocks_ff(void) +{ + int err; + unsigned int i; + + printk(PRINT_PREF "verifying all eraseblocks for 0xff\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = verify_eraseblock_ff(i); + if (err) + return err; + if (i % 256 == 0) + printk(PRINT_PREF "verified up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "verified %u eraseblocks\n", i); + return 0; +} + +static int is_block_bad(int ebnum) +{ + loff_t addr = ebnum * mtd->erasesize; + int ret; + + ret = mtd->block_isbad(mtd, addr); + if (ret) + printk(PRINT_PREF "block %d is bad\n", ebnum); + return ret; +} + +static int scan_for_bad_eraseblocks(void) +{ + int i, bad = 0; + + bbt = kmalloc(ebcnt, GFP_KERNEL); + if (!bbt) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + return -ENOMEM; + } + memset(bbt, 0 , ebcnt); + + printk(PRINT_PREF "scanning for bad eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + bbt[i] = is_block_bad(i) ? 1 : 0; + if (bbt[i]) + bad += 1; + cond_resched(); + } + printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + return 0; +} + +static int __init mtd_subpagetest_init(void) +{ + int err = 0; + uint32_t i; + uint64_t tmp; + + printk(KERN_INFO "\n"); + printk(KERN_INFO "=================================================\n"); + printk(PRINT_PREF "MTD device: %d\n", dev); + + mtd = get_mtd_device(NULL, dev); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + printk(PRINT_PREF "error: cannot get MTD device\n"); + return err; + } + + if (mtd->type != MTD_NANDFLASH) { + printk(PRINT_PREF "this test requires NAND flash\n"); + goto out; + } + + subpgsize = mtd->writesize >> mtd->subpage_sft; + printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + "page size %u, subpage size %u, count of eraseblocks %u, " + "pages per eraseblock %u, OOB size %u\n", + (unsigned long long)mtd->size, mtd->erasesize, + mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize); + + err = -ENOMEM; + bufsize = subpgsize * 32; + writebuf = kmalloc(bufsize, GFP_KERNEL); + if (!writebuf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + readbuf = kmalloc(bufsize, GFP_KERNEL); + if (!readbuf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + + tmp = mtd->size; + do_div(tmp, mtd->erasesize); + ebcnt = tmp; + pgcnt = mtd->erasesize / mtd->writesize; + + err = scan_for_bad_eraseblocks(); + if (err) + goto out; + + err = erase_whole_device(); + if (err) + goto out; + + printk(PRINT_PREF "writing whole device\n"); + simple_srand(1); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock(i); + if (unlikely(err)) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "written up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "written %u eraseblocks\n", i); + + simple_srand(1); + printk(PRINT_PREF "verifying all eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = verify_eraseblock(i); + if (unlikely(err)) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "verified up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "verified %u eraseblocks\n", i); + + err = erase_whole_device(); + if (err) + goto out; + + err = verify_all_eraseblocks_ff(); + if (err) + goto out; + + /* Write all eraseblocks */ + simple_srand(3); + printk(PRINT_PREF "writing whole device\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock2(i); + if (unlikely(err)) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "written up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "written %u eraseblocks\n", i); + + /* Check all eraseblocks */ + simple_srand(3); + printk(PRINT_PREF "verifying all eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = verify_eraseblock2(i); + if (unlikely(err)) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "verified up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "verified %u eraseblocks\n", i); + + err = erase_whole_device(); + if (err) + goto out; + + err = verify_all_eraseblocks_ff(); + if (err) + goto out; + + printk(PRINT_PREF "finished with %d errors\n", errcnt); + +out: + kfree(bbt); + kfree(readbuf); + kfree(writebuf); + put_mtd_device(mtd); + if (err) + printk(PRINT_PREF "error %d occurred\n", err); + printk(KERN_INFO "=================================================\n"); + return err; +} +module_init(mtd_subpagetest_init); + +static void __exit mtd_subpagetest_exit(void) +{ + return; +} +module_exit(mtd_subpagetest_exit); + +MODULE_DESCRIPTION("Subpage test module"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/tests/mtd_torturetest.c b/drivers/mtd/tests/mtd_torturetest.c new file mode 100644 index 000000000000..631a0ab3a33c --- /dev/null +++ b/drivers/mtd/tests/mtd_torturetest.c @@ -0,0 +1,530 @@ +/* + * Copyright (C) 2006-2008 Artem Bityutskiy + * Copyright (C) 2006-2008 Jarkko Lavinen + * Copyright (C) 2006-2008 Adrian Hunter + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Authors: Artem Bityutskiy, Jarkko Lavinen, Adria Hunter + * + * WARNING: this test program may kill your flash and your device. Do not + * use it unless you know what you do. Authors are not responsible for any + * damage caused by this program. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/mtd/mtd.h> +#include <linux/sched.h> + +#define PRINT_PREF KERN_INFO "mtd_torturetest: " +#define RETRIES 3 + +static int eb = 8; +module_param(eb, int, S_IRUGO); +MODULE_PARM_DESC(eb, "eraseblock number within the selected MTD device"); + +static int ebcnt = 32; +module_param(ebcnt, int, S_IRUGO); +MODULE_PARM_DESC(ebcnt, "number of consecutive eraseblocks to torture"); + +static int pgcnt; +module_param(pgcnt, int, S_IRUGO); +MODULE_PARM_DESC(pgcnt, "number of pages per eraseblock to torture (0 => all)"); + +static int dev; +module_param(dev, int, S_IRUGO); +MODULE_PARM_DESC(dev, "MTD device number to use"); + +static int gran = 512; +module_param(gran, int, S_IRUGO); +MODULE_PARM_DESC(gran, "how often the status information should be printed"); + +static int check = 1; +module_param(check, int, S_IRUGO); +MODULE_PARM_DESC(check, "if the written data should be checked"); + +static unsigned int cycles_count; +module_param(cycles_count, uint, S_IRUGO); +MODULE_PARM_DESC(cycles_count, "how many erase cycles to do " + "(infinite by default)"); + +static struct mtd_info *mtd; + +/* This buffer contains 0x555555...0xAAAAAA... pattern */ +static unsigned char *patt_5A5; +/* This buffer contains 0xAAAAAA...0x555555... pattern */ +static unsigned char *patt_A5A; +/* This buffer contains all 0xFF bytes */ +static unsigned char *patt_FF; +/* This a temporary buffer is use when checking data */ +static unsigned char *check_buf; +/* How many erase cycles were done */ +static unsigned int erase_cycles; + +static int pgsize; +static struct timeval start, finish; + +static void report_corrupt(unsigned char *read, unsigned char *written); + +static inline void start_timing(void) +{ + do_gettimeofday(&start); +} + +static inline void stop_timing(void) +{ + do_gettimeofday(&finish); +} + +/* + * Erase eraseblock number @ebnum. + */ +static inline int erase_eraseblock(int ebnum) +{ + int err; + struct erase_info ei; + loff_t addr = ebnum * mtd->erasesize; + + memset(&ei, 0, sizeof(struct erase_info)); + ei.mtd = mtd; + ei.addr = addr; + ei.len = mtd->erasesize; + + err = mtd->erase(mtd, &ei); + if (err) { + printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + return err; + } + + if (ei.state == MTD_ERASE_FAILED) { + printk(PRINT_PREF "some erase error occurred at EB %d\n", + ebnum); + return -EIO; + } + + return 0; +} + +/* + * Check that the contents of eraseblock number @enbum is equivalent to the + * @buf buffer. + */ +static inline int check_eraseblock(int ebnum, unsigned char *buf) +{ + int err, retries = 0; + size_t read = 0; + loff_t addr = ebnum * mtd->erasesize; + size_t len = mtd->erasesize; + + if (pgcnt) { + addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize; + len = pgcnt * pgsize; + } + +retry: + err = mtd->read(mtd, addr, len, &read, check_buf); + if (err == -EUCLEAN) + printk(PRINT_PREF "single bit flip occurred at EB %d " + "MTD reported that it was fixed.\n", ebnum); + else if (err) { + printk(PRINT_PREF "error %d while reading EB %d, " + "read %zd\n", err, ebnum, read); + return err; + } + + if (read != len) { + printk(PRINT_PREF "failed to read %zd bytes from EB %d, " + "read only %zd, but no error reported\n", + len, ebnum, read); + return -EIO; + } + + if (memcmp(buf, check_buf, len)) { + printk(PRINT_PREF "read wrong data from EB %d\n", ebnum); + report_corrupt(check_buf, buf); + + if (retries++ < RETRIES) { + /* Try read again */ + yield(); + printk(PRINT_PREF "re-try reading data from EB %d\n", + ebnum); + goto retry; + } else { + printk(PRINT_PREF "retried %d times, still errors, " + "give-up\n", RETRIES); + return -EINVAL; + } + } + + if (retries != 0) + printk(PRINT_PREF "only attempt number %d was OK (!!!)\n", + retries); + + return 0; +} + +static inline int write_pattern(int ebnum, void *buf) +{ + int err; + size_t written = 0; + loff_t addr = ebnum * mtd->erasesize; + size_t len = mtd->erasesize; + + if (pgcnt) { + addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize; + len = pgcnt * pgsize; + } + err = mtd->write(mtd, addr, len, &written, buf); + if (err) { + printk(PRINT_PREF "error %d while writing EB %d, written %zd" + " bytes\n", err, ebnum, written); + return err; + } + if (written != len) { + printk(PRINT_PREF "written only %zd bytes of %zd, but no error" + " reported\n", written, len); + return -EIO; + } + + return 0; +} + +static int __init tort_init(void) +{ + int err = 0, i, infinite = !cycles_count; + int bad_ebs[ebcnt]; + + printk(KERN_INFO "\n"); + printk(KERN_INFO "=================================================\n"); + printk(PRINT_PREF "Warning: this program is trying to wear out your " + "flash, stop it if this is not wanted.\n"); + printk(PRINT_PREF "MTD device: %d\n", dev); + printk(PRINT_PREF "torture %d eraseblocks (%d-%d) of mtd%d\n", + ebcnt, eb, eb + ebcnt - 1, dev); + if (pgcnt) + printk(PRINT_PREF "torturing just %d pages per eraseblock\n", + pgcnt); + printk(PRINT_PREF "write verify %s\n", check ? "enabled" : "disabled"); + + mtd = get_mtd_device(NULL, dev); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + printk(PRINT_PREF "error: cannot get MTD device\n"); + return err; + } + + if (mtd->writesize == 1) { + printk(PRINT_PREF "not NAND flash, assume page size is 512 " + "bytes.\n"); + pgsize = 512; + } else + pgsize = mtd->writesize; + + if (pgcnt && (pgcnt > mtd->erasesize / pgsize || pgcnt < 0)) { + printk(PRINT_PREF "error: invalid pgcnt value %d\n", pgcnt); + goto out_mtd; + } + + err = -ENOMEM; + patt_5A5 = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!patt_5A5) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out_mtd; + } + + patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!patt_A5A) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out_patt_5A5; + } + + patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!patt_FF) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out_patt_A5A; + } + + check_buf = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!check_buf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out_patt_FF; + } + + err = 0; + + /* Initialize patterns */ + memset(patt_FF, 0xFF, mtd->erasesize); + for (i = 0; i < mtd->erasesize / pgsize; i++) { + if (!(i & 1)) { + memset(patt_5A5 + i * pgsize, 0x55, pgsize); + memset(patt_A5A + i * pgsize, 0xAA, pgsize); + } else { + memset(patt_5A5 + i * pgsize, 0xAA, pgsize); + memset(patt_A5A + i * pgsize, 0x55, pgsize); + } + } + + /* + * Check if there is a bad eraseblock among those we are going to test. + */ + memset(&bad_ebs[0], 0, sizeof(int) * ebcnt); + if (mtd->block_isbad) { + for (i = eb; i < eb + ebcnt; i++) { + err = mtd->block_isbad(mtd, + (loff_t)i * mtd->erasesize); + + if (err < 0) { + printk(PRINT_PREF "block_isbad() returned %d " + "for EB %d\n", err, i); + goto out; + } + + if (err) { + printk("EB %d is bad. Skip it.\n", i); + bad_ebs[i - eb] = 1; + } + } + } + + start_timing(); + while (1) { + int i; + void *patt; + + /* Erase all eraseblocks */ + for (i = eb; i < eb + ebcnt; i++) { + if (bad_ebs[i - eb]) + continue; + err = erase_eraseblock(i); + if (err) + goto out; + cond_resched(); + } + + /* Check if the eraseblocks contain only 0xFF bytes */ + if (check) { + for (i = eb; i < eb + ebcnt; i++) { + if (bad_ebs[i - eb]) + continue; + err = check_eraseblock(i, patt_FF); + if (err) { + printk(PRINT_PREF "verify failed" + " for 0xFF... pattern\n"); + goto out; + } + cond_resched(); + } + } + + /* Write the pattern */ + for (i = eb; i < eb + ebcnt; i++) { + if (bad_ebs[i - eb]) + continue; + if ((eb + erase_cycles) & 1) + patt = patt_5A5; + else + patt = patt_A5A; + err = write_pattern(i, patt); + if (err) + goto out; + cond_resched(); + } + + /* Verify what we wrote */ + if (check) { + for (i = eb; i < eb + ebcnt; i++) { + if (bad_ebs[i - eb]) + continue; + if ((eb + erase_cycles) & 1) + patt = patt_5A5; + else + patt = patt_A5A; + err = check_eraseblock(i, patt); + if (err) { + printk(PRINT_PREF "verify failed for %s" + " pattern\n", + ((eb + erase_cycles) & 1) ? + "0x55AA55..." : "0xAA55AA..."); + goto out; + } + cond_resched(); + } + } + + erase_cycles += 1; + + if (erase_cycles % gran == 0) { + long ms; + + stop_timing(); + ms = (finish.tv_sec - start.tv_sec) * 1000 + + (finish.tv_usec - start.tv_usec) / 1000; + printk(PRINT_PREF "%08u erase cycles done, took %lu " + "milliseconds (%lu seconds)\n", + erase_cycles, ms, ms / 1000); + start_timing(); + } + + if (!infinite && --cycles_count == 0) + break; + } +out: + + printk(PRINT_PREF "finished after %u erase cycles\n", + erase_cycles); + kfree(check_buf); +out_patt_FF: + kfree(patt_FF); +out_patt_A5A: + kfree(patt_A5A); +out_patt_5A5: + kfree(patt_5A5); +out_mtd: + put_mtd_device(mtd); + if (err) + printk(PRINT_PREF "error %d occurred during torturing\n", err); + printk(KERN_INFO "=================================================\n"); + return err; +} +module_init(tort_init); + +static void __exit tort_exit(void) +{ + return; +} +module_exit(tort_exit); + +static int countdiffs(unsigned char *buf, unsigned char *check_buf, + unsigned offset, unsigned len, unsigned *bytesp, + unsigned *bitsp); +static void print_bufs(unsigned char *read, unsigned char *written, int start, + int len); + +/* + * Report the detailed information about how the read EB differs from what was + * written. + */ +static void report_corrupt(unsigned char *read, unsigned char *written) +{ + int i; + int bytes, bits, pages, first; + int offset, len; + size_t check_len = mtd->erasesize; + + if (pgcnt) + check_len = pgcnt * pgsize; + + bytes = bits = pages = 0; + for (i = 0; i < check_len; i += pgsize) + if (countdiffs(written, read, i, pgsize, &bytes, + &bits) >= 0) + pages++; + + printk(PRINT_PREF "verify fails on %d pages, %d bytes/%d bits\n", + pages, bytes, bits); + printk(PRINT_PREF "The following is a list of all differences between" + " what was read from flash and what was expected\n"); + + for (i = 0; i < check_len; i += pgsize) { + cond_resched(); + bytes = bits = 0; + first = countdiffs(written, read, i, pgsize, &bytes, + &bits); + if (first < 0) + continue; + + printk("-------------------------------------------------------" + "----------------------------------\n"); + + printk(PRINT_PREF "Page %zd has %d bytes/%d bits failing verify," + " starting at offset 0x%x\n", + (mtd->erasesize - check_len + i) / pgsize, + bytes, bits, first); + + offset = first & ~0x7; + len = ((first + bytes) | 0x7) + 1 - offset; + + print_bufs(read, written, offset, len); + } +} + +static void print_bufs(unsigned char *read, unsigned char *written, int start, + int len) +{ + int i = 0, j1, j2; + char *diff; + + printk("Offset Read Written\n"); + while (i < len) { + printk("0x%08x: ", start + i); + diff = " "; + for (j1 = 0; j1 < 8 && i + j1 < len; j1++) { + printk(" %02x", read[start + i + j1]); + if (read[start + i + j1] != written[start + i + j1]) + diff = "***"; + } + + while (j1 < 8) { + printk(" "); + j1 += 1; + } + + printk(" %s ", diff); + + for (j2 = 0; j2 < 8 && i + j2 < len; j2++) + printk(" %02x", written[start + i + j2]); + printk("\n"); + i += 8; + } +} + +/* + * Count the number of differing bytes and bits and return the first differing + * offset. + */ +static int countdiffs(unsigned char *buf, unsigned char *check_buf, + unsigned offset, unsigned len, unsigned *bytesp, + unsigned *bitsp) +{ + unsigned i, bit; + int first = -1; + + for (i = offset; i < offset + len; i++) + if (buf[i] != check_buf[i]) { + first = i; + break; + } + + while (i < offset + len) { + if (buf[i] != check_buf[i]) { + (*bytesp)++; + bit = 1; + while (bit < 256) { + if ((buf[i] & bit) != (check_buf[i] & bit)) + (*bitsp)++; + bit <<= 1; + } + } + i++; + } + + return first; +} + +MODULE_DESCRIPTION("Eraseblock torturing module"); +MODULE_AUTHOR("Artem Bityutskiy, Jarkko Lavinen, Adrian Hunter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 7caf22cd5ad0..9082768cc6c3 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -561,7 +561,7 @@ static int io_init(struct ubi_device *ubi) */ ubi->peb_size = ubi->mtd->erasesize; - ubi->peb_count = ubi->mtd->size / ubi->mtd->erasesize; + ubi->peb_count = mtd_div_by_eb(ubi->mtd->size, ubi->mtd); ubi->flash_size = ubi->mtd->size; if (ubi->mtd->block_isbad && ubi->mtd->block_markbad) diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c index 605812bb0b1a..6dd4f5e77f82 100644 --- a/drivers/mtd/ubi/gluebi.c +++ b/drivers/mtd/ubi/gluebi.c @@ -215,7 +215,8 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) struct ubi_volume *vol; struct ubi_device *ubi; - dbg_gen("erase %u bytes at offset %u", instr->len, instr->addr); + dbg_gen("erase %llu bytes at offset %llu", (unsigned long long)instr->len, + (unsigned long long)instr->addr); if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize) return -EINVAL; @@ -223,11 +224,11 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) if (instr->len < 0 || instr->addr + instr->len > mtd->size) return -EINVAL; - if (instr->addr % mtd->writesize || instr->len % mtd->writesize) + if (mtd_mod_by_ws(instr->addr, mtd) || mtd_mod_by_ws(instr->len, mtd)) return -EINVAL; - lnum = instr->addr / mtd->erasesize; - count = instr->len / mtd->erasesize; + lnum = mtd_div_by_eb(instr->addr, mtd); + count = mtd_div_by_eb(instr->len, mtd); vol = container_of(mtd, struct ubi_volume, gluebi_mtd); ubi = vol->ubi; @@ -255,7 +256,7 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) out_err: instr->state = MTD_ERASE_FAILED; - instr->fail_addr = lnum * mtd->erasesize; + instr->fail_addr = (long long)lnum * mtd->erasesize; return err; } @@ -294,7 +295,7 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol) * bytes. */ if (vol->vol_type == UBI_DYNAMIC_VOLUME) - mtd->size = vol->usable_leb_size * vol->reserved_pebs; + mtd->size = (long long)vol->usable_leb_size * vol->reserved_pebs; else mtd->size = vol->used_bytes; @@ -304,8 +305,8 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol) return -ENFILE; } - dbg_gen("added mtd%d (\"%s\"), size %u, EB size %u", - mtd->index, mtd->name, mtd->size, mtd->erasesize); + dbg_gen("added mtd%d (\"%s\"), size %llu, EB size %u", + mtd->index, mtd->name, (unsigned long long)mtd->size, mtd->erasesize); return 0; } diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 65e8294a9e29..9da5a4b81133 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -1,11 +1,12 @@ /** * @file buffer_sync.c * - * @remark Copyright 2002 OProfile authors + * @remark Copyright 2002-2009 OProfile authors * @remark Read the file COPYING * * @author John Levon <levon@movementarian.org> * @author Barry Kasindorf + * @author Robert Richter <robert.richter@amd.com> * * This is the core of the buffer management. Each * CPU buffer is processed and entered into the @@ -315,88 +316,73 @@ static void add_trace_begin(void) add_event_entry(TRACE_BEGIN_CODE); } -#ifdef CONFIG_OPROFILE_IBS - -#define IBS_FETCH_CODE_SIZE 2 -#define IBS_OP_CODE_SIZE 5 - -/* - * Add IBS fetch and op entries to event buffer - */ -static void add_ibs_begin(int cpu, int code, struct mm_struct *mm) +static void add_data(struct op_entry *entry, struct mm_struct *mm) { - unsigned long rip; - int i, count; - unsigned long ibs_cookie = 0; + unsigned long code, pc, val; + unsigned long cookie; off_t offset; - struct op_sample *sample; - - sample = cpu_buffer_read_entry(cpu); - if (!sample) - goto Error; - rip = sample->eip; -#ifdef __LP64__ - rip += sample->event << 32; -#endif + if (!op_cpu_buffer_get_data(entry, &code)) + return; + if (!op_cpu_buffer_get_data(entry, &pc)) + return; + if (!op_cpu_buffer_get_size(entry)) + return; if (mm) { - ibs_cookie = lookup_dcookie(mm, rip, &offset); + cookie = lookup_dcookie(mm, pc, &offset); - if (ibs_cookie == NO_COOKIE) - offset = rip; - if (ibs_cookie == INVALID_COOKIE) { + if (cookie == NO_COOKIE) + offset = pc; + if (cookie == INVALID_COOKIE) { atomic_inc(&oprofile_stats.sample_lost_no_mapping); - offset = rip; + offset = pc; } - if (ibs_cookie != last_cookie) { - add_cookie_switch(ibs_cookie); - last_cookie = ibs_cookie; + if (cookie != last_cookie) { + add_cookie_switch(cookie); + last_cookie = cookie; } } else - offset = rip; + offset = pc; add_event_entry(ESCAPE_CODE); add_event_entry(code); add_event_entry(offset); /* Offset from Dcookie */ - /* we send the Dcookie offset, but send the raw Linear Add also*/ - add_event_entry(sample->eip); - add_event_entry(sample->event); - - if (code == IBS_FETCH_CODE) - count = IBS_FETCH_CODE_SIZE; /*IBS FETCH is 2 int64s*/ - else - count = IBS_OP_CODE_SIZE; /*IBS OP is 5 int64s*/ - - for (i = 0; i < count; i++) { - sample = cpu_buffer_read_entry(cpu); - if (!sample) - goto Error; - add_event_entry(sample->eip); - add_event_entry(sample->event); - } - - return; - -Error: - return; + while (op_cpu_buffer_get_data(entry, &val)) + add_event_entry(val); } -#endif - -static void add_sample_entry(unsigned long offset, unsigned long event) +static inline void add_sample_entry(unsigned long offset, unsigned long event) { add_event_entry(offset); add_event_entry(event); } -static int add_us_sample(struct mm_struct *mm, struct op_sample *s) +/* + * Add a sample to the global event buffer. If possible the + * sample is converted into a persistent dentry/offset pair + * for later lookup from userspace. Return 0 on failure. + */ +static int +add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel) { unsigned long cookie; off_t offset; + if (in_kernel) { + add_sample_entry(s->eip, s->event); + return 1; + } + + /* add userspace sample */ + + if (!mm) { + atomic_inc(&oprofile_stats.sample_lost_no_mm); + return 0; + } + cookie = lookup_dcookie(mm, s->eip, &offset); if (cookie == INVALID_COOKIE) { @@ -415,25 +401,6 @@ static int add_us_sample(struct mm_struct *mm, struct op_sample *s) } -/* Add a sample to the global event buffer. If possible the - * sample is converted into a persistent dentry/offset pair - * for later lookup from userspace. - */ -static int -add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel) -{ - if (in_kernel) { - add_sample_entry(s->eip, s->event); - return 1; - } else if (mm) { - return add_us_sample(mm, s); - } else { - atomic_inc(&oprofile_stats.sample_lost_no_mm); - } - return 0; -} - - static void release_mm(struct mm_struct *mm) { if (!mm) @@ -526,66 +493,69 @@ void sync_buffer(int cpu) { struct mm_struct *mm = NULL; struct mm_struct *oldmm; + unsigned long val; struct task_struct *new; unsigned long cookie = 0; int in_kernel = 1; sync_buffer_state state = sb_buffer_start; unsigned int i; unsigned long available; + unsigned long flags; + struct op_entry entry; + struct op_sample *sample; mutex_lock(&buffer_mutex); add_cpu_switch(cpu); - cpu_buffer_reset(cpu); - available = cpu_buffer_entries(cpu); + op_cpu_buffer_reset(cpu); + available = op_cpu_buffer_entries(cpu); for (i = 0; i < available; ++i) { - struct op_sample *s = cpu_buffer_read_entry(cpu); - if (!s) + sample = op_cpu_buffer_read_entry(&entry, cpu); + if (!sample) break; - if (is_code(s->eip)) { - switch (s->event) { - case 0: - case CPU_IS_KERNEL: + if (is_code(sample->eip)) { + flags = sample->event; + if (flags & TRACE_BEGIN) { + state = sb_bt_start; + add_trace_begin(); + } + if (flags & KERNEL_CTX_SWITCH) { /* kernel/userspace switch */ - in_kernel = s->event; + in_kernel = flags & IS_KERNEL; if (state == sb_buffer_start) state = sb_sample_start; - add_kernel_ctx_switch(s->event); - break; - case CPU_TRACE_BEGIN: - state = sb_bt_start; - add_trace_begin(); - break; -#ifdef CONFIG_OPROFILE_IBS - case IBS_FETCH_BEGIN: - state = sb_bt_start; - add_ibs_begin(cpu, IBS_FETCH_CODE, mm); - break; - case IBS_OP_BEGIN: - state = sb_bt_start; - add_ibs_begin(cpu, IBS_OP_CODE, mm); - break; -#endif - default: + add_kernel_ctx_switch(flags & IS_KERNEL); + } + if (flags & USER_CTX_SWITCH + && op_cpu_buffer_get_data(&entry, &val)) { /* userspace context switch */ + new = (struct task_struct *)val; oldmm = mm; - new = (struct task_struct *)s->event; release_mm(oldmm); mm = take_tasks_mm(new); if (mm != oldmm) cookie = get_exec_dcookie(mm); add_user_ctx_switch(new, cookie); - break; - } - } else if (state >= sb_bt_start && - !add_sample(mm, s, in_kernel)) { - if (state == sb_bt_start) { - state = sb_bt_ignore; - atomic_inc(&oprofile_stats.bt_lost_no_mapping); } + if (op_cpu_buffer_get_size(&entry)) + add_data(&entry, mm); + continue; + } + + if (state < sb_bt_start) + /* ignore sample */ + continue; + + if (add_sample(mm, sample, in_kernel)) + continue; + + /* ignore backtraces if failed to add a sample */ + if (state == sb_bt_start) { + state = sb_bt_ignore; + atomic_inc(&oprofile_stats.bt_lost_no_mapping); } } release_mm(mm); diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 61090969158f..2e03b6d796d3 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -1,11 +1,12 @@ /** * @file cpu_buffer.c * - * @remark Copyright 2002 OProfile authors + * @remark Copyright 2002-2009 OProfile authors * @remark Read the file COPYING * * @author John Levon <levon@movementarian.org> * @author Barry Kasindorf <barry.kasindorf@amd.com> + * @author Robert Richter <robert.richter@amd.com> * * Each CPU has a local buffer that stores PC value/event * pairs. We also log context switches when we notice them. @@ -45,8 +46,8 @@ * can be changed to a single buffer solution when the ring buffer * access is implemented as non-locking atomic code. */ -struct ring_buffer *op_ring_buffer_read; -struct ring_buffer *op_ring_buffer_write; +static struct ring_buffer *op_ring_buffer_read; +static struct ring_buffer *op_ring_buffer_write; DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); static void wq_sync_buffer(struct work_struct *work); @@ -54,19 +55,9 @@ static void wq_sync_buffer(struct work_struct *work); #define DEFAULT_TIMER_EXPIRE (HZ / 10) static int work_enabled; -void free_cpu_buffers(void) -{ - if (op_ring_buffer_read) - ring_buffer_free(op_ring_buffer_read); - op_ring_buffer_read = NULL; - if (op_ring_buffer_write) - ring_buffer_free(op_ring_buffer_write); - op_ring_buffer_write = NULL; -} - unsigned long oprofile_get_cpu_buffer_size(void) { - return fs_cpu_buffer_size; + return oprofile_cpu_buffer_size; } void oprofile_cpu_buffer_inc_smpl_lost(void) @@ -77,11 +68,21 @@ void oprofile_cpu_buffer_inc_smpl_lost(void) cpu_buf->sample_lost_overflow++; } +void free_cpu_buffers(void) +{ + if (op_ring_buffer_read) + ring_buffer_free(op_ring_buffer_read); + op_ring_buffer_read = NULL; + if (op_ring_buffer_write) + ring_buffer_free(op_ring_buffer_write); + op_ring_buffer_write = NULL; +} + int alloc_cpu_buffers(void) { int i; - unsigned long buffer_size = fs_cpu_buffer_size; + unsigned long buffer_size = oprofile_cpu_buffer_size; op_ring_buffer_read = ring_buffer_alloc(buffer_size, OP_BUFFER_FLAGS); if (!op_ring_buffer_read) @@ -97,8 +98,6 @@ int alloc_cpu_buffers(void) b->last_is_kernel = -1; b->tracing = 0; b->buffer_size = buffer_size; - b->tail_pos = 0; - b->head_pos = 0; b->sample_received = 0; b->sample_lost_overflow = 0; b->backtrace_aborted = 0; @@ -145,47 +144,156 @@ void end_cpu_work(void) flush_scheduled_work(); } -static inline int -add_sample(struct oprofile_cpu_buffer *cpu_buf, - unsigned long pc, unsigned long event) +/* + * This function prepares the cpu buffer to write a sample. + * + * Struct op_entry is used during operations on the ring buffer while + * struct op_sample contains the data that is stored in the ring + * buffer. Struct entry can be uninitialized. The function reserves a + * data array that is specified by size. Use + * op_cpu_buffer_write_commit() after preparing the sample. In case of + * errors a null pointer is returned, otherwise the pointer to the + * sample. + * + */ +struct op_sample +*op_cpu_buffer_write_reserve(struct op_entry *entry, unsigned long size) +{ + entry->event = ring_buffer_lock_reserve + (op_ring_buffer_write, sizeof(struct op_sample) + + size * sizeof(entry->sample->data[0]), &entry->irq_flags); + if (entry->event) + entry->sample = ring_buffer_event_data(entry->event); + else + entry->sample = NULL; + + if (!entry->sample) + return NULL; + + entry->size = size; + entry->data = entry->sample->data; + + return entry->sample; +} + +int op_cpu_buffer_write_commit(struct op_entry *entry) +{ + return ring_buffer_unlock_commit(op_ring_buffer_write, entry->event, + entry->irq_flags); +} + +struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu) +{ + struct ring_buffer_event *e; + e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL); + if (e) + goto event; + if (ring_buffer_swap_cpu(op_ring_buffer_read, + op_ring_buffer_write, + cpu)) + return NULL; + e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL); + if (e) + goto event; + return NULL; + +event: + entry->event = e; + entry->sample = ring_buffer_event_data(e); + entry->size = (ring_buffer_event_length(e) - sizeof(struct op_sample)) + / sizeof(entry->sample->data[0]); + entry->data = entry->sample->data; + return entry->sample; +} + +unsigned long op_cpu_buffer_entries(int cpu) +{ + return ring_buffer_entries_cpu(op_ring_buffer_read, cpu) + + ring_buffer_entries_cpu(op_ring_buffer_write, cpu); +} + +static int +op_add_code(struct oprofile_cpu_buffer *cpu_buf, unsigned long backtrace, + int is_kernel, struct task_struct *task) { struct op_entry entry; - int ret; + struct op_sample *sample; + unsigned long flags; + int size; + + flags = 0; + + if (backtrace) + flags |= TRACE_BEGIN; + + /* notice a switch from user->kernel or vice versa */ + is_kernel = !!is_kernel; + if (cpu_buf->last_is_kernel != is_kernel) { + cpu_buf->last_is_kernel = is_kernel; + flags |= KERNEL_CTX_SWITCH; + if (is_kernel) + flags |= IS_KERNEL; + } + + /* notice a task switch */ + if (cpu_buf->last_task != task) { + cpu_buf->last_task = task; + flags |= USER_CTX_SWITCH; + } + + if (!flags) + /* nothing to do */ + return 0; + + if (flags & USER_CTX_SWITCH) + size = 1; + else + size = 0; + + sample = op_cpu_buffer_write_reserve(&entry, size); + if (!sample) + return -ENOMEM; - ret = cpu_buffer_write_entry(&entry); - if (ret) - return ret; + sample->eip = ESCAPE_CODE; + sample->event = flags; - entry.sample->eip = pc; - entry.sample->event = event; + if (size) + op_cpu_buffer_add_data(&entry, (unsigned long)task); - ret = cpu_buffer_write_commit(&entry); - if (ret) - return ret; + op_cpu_buffer_write_commit(&entry); return 0; } static inline int -add_code(struct oprofile_cpu_buffer *buffer, unsigned long value) +op_add_sample(struct oprofile_cpu_buffer *cpu_buf, + unsigned long pc, unsigned long event) { - return add_sample(buffer, ESCAPE_CODE, value); + struct op_entry entry; + struct op_sample *sample; + + sample = op_cpu_buffer_write_reserve(&entry, 0); + if (!sample) + return -ENOMEM; + + sample->eip = pc; + sample->event = event; + + return op_cpu_buffer_write_commit(&entry); } -/* This must be safe from any context. It's safe writing here - * because of the head/tail separation of the writer and reader - * of the CPU buffer. +/* + * This must be safe from any context. * * is_kernel is needed because on some architectures you cannot * tell if you are in kernel or user space simply by looking at * pc. We tag this in the buffer by generating kernel enter/exit * events whenever is_kernel changes */ -static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, - int is_kernel, unsigned long event) +static int +log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, + unsigned long backtrace, int is_kernel, unsigned long event) { - struct task_struct *task; - cpu_buf->sample_received++; if (pc == ESCAPE_CODE) { @@ -193,25 +301,10 @@ static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, return 0; } - is_kernel = !!is_kernel; - - task = current; - - /* notice a switch from user->kernel or vice versa */ - if (cpu_buf->last_is_kernel != is_kernel) { - cpu_buf->last_is_kernel = is_kernel; - if (add_code(cpu_buf, is_kernel)) - goto fail; - } - - /* notice a task switch */ - if (cpu_buf->last_task != task) { - cpu_buf->last_task = task; - if (add_code(cpu_buf, (unsigned long)task)) - goto fail; - } + if (op_add_code(cpu_buf, backtrace, is_kernel, current)) + goto fail; - if (add_sample(cpu_buf, pc, event)) + if (op_add_sample(cpu_buf, pc, event)) goto fail; return 1; @@ -221,109 +314,102 @@ fail: return 0; } -static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) +static inline void oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) { - add_code(cpu_buf, CPU_TRACE_BEGIN); cpu_buf->tracing = 1; - return 1; } -static void oprofile_end_trace(struct oprofile_cpu_buffer *cpu_buf) +static inline void oprofile_end_trace(struct oprofile_cpu_buffer *cpu_buf) { cpu_buf->tracing = 0; } -void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, - unsigned long event, int is_kernel) +static inline void +__oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, + unsigned long event, int is_kernel) { struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); - - if (!backtrace_depth) { - log_sample(cpu_buf, pc, is_kernel, event); - return; - } - - if (!oprofile_begin_trace(cpu_buf)) - return; + unsigned long backtrace = oprofile_backtrace_depth; /* * if log_sample() fail we can't backtrace since we lost the * source of this event */ - if (log_sample(cpu_buf, pc, is_kernel, event)) - oprofile_ops.backtrace(regs, backtrace_depth); + if (!log_sample(cpu_buf, pc, backtrace, is_kernel, event)) + /* failed */ + return; + + if (!backtrace) + return; + + oprofile_begin_trace(cpu_buf); + oprofile_ops.backtrace(regs, backtrace); oprofile_end_trace(cpu_buf); } +void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, + unsigned long event, int is_kernel) +{ + __oprofile_add_ext_sample(pc, regs, event, is_kernel); +} + void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) { int is_kernel = !user_mode(regs); unsigned long pc = profile_pc(regs); - oprofile_add_ext_sample(pc, regs, event, is_kernel); + __oprofile_add_ext_sample(pc, regs, event, is_kernel); } -#ifdef CONFIG_OPROFILE_IBS - -#define MAX_IBS_SAMPLE_SIZE 14 - -void oprofile_add_ibs_sample(struct pt_regs * const regs, - unsigned int * const ibs_sample, int ibs_code) +/* + * Add samples with data to the ring buffer. + * + * Use oprofile_add_data(&entry, val) to add data and + * oprofile_write_commit(&entry) to commit the sample. + */ +void +oprofile_write_reserve(struct op_entry *entry, struct pt_regs * const regs, + unsigned long pc, int code, int size) { + struct op_sample *sample; int is_kernel = !user_mode(regs); struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); - struct task_struct *task; - int fail = 0; cpu_buf->sample_received++; - /* notice a switch from user->kernel or vice versa */ - if (cpu_buf->last_is_kernel != is_kernel) { - if (add_code(cpu_buf, is_kernel)) - goto fail; - cpu_buf->last_is_kernel = is_kernel; - } - - /* notice a task switch */ - if (!is_kernel) { - task = current; - if (cpu_buf->last_task != task) { - if (add_code(cpu_buf, (unsigned long)task)) - goto fail; - cpu_buf->last_task = task; - } - } - - fail = fail || add_code(cpu_buf, ibs_code); - fail = fail || add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]); - fail = fail || add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]); - fail = fail || add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]); - - if (ibs_code == IBS_OP_BEGIN) { - fail = fail || add_sample(cpu_buf, ibs_sample[6], ibs_sample[7]); - fail = fail || add_sample(cpu_buf, ibs_sample[8], ibs_sample[9]); - fail = fail || add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]); - } + /* no backtraces for samples with data */ + if (op_add_code(cpu_buf, 0, is_kernel, current)) + goto fail; - if (fail) + sample = op_cpu_buffer_write_reserve(entry, size + 2); + if (!sample) goto fail; + sample->eip = ESCAPE_CODE; + sample->event = 0; /* no flags */ - if (backtrace_depth) - oprofile_ops.backtrace(regs, backtrace_depth); + op_cpu_buffer_add_data(entry, code); + op_cpu_buffer_add_data(entry, pc); return; fail: cpu_buf->sample_lost_overflow++; - return; } -#endif +int oprofile_add_data(struct op_entry *entry, unsigned long val) +{ + return op_cpu_buffer_add_data(entry, val); +} + +int oprofile_write_commit(struct op_entry *entry) +{ + return op_cpu_buffer_write_commit(entry); +} void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) { struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); - log_sample(cpu_buf, pc, is_kernel, event); + log_sample(cpu_buf, pc, 0, is_kernel, event); } void oprofile_add_trace(unsigned long pc) @@ -340,7 +426,7 @@ void oprofile_add_trace(unsigned long pc) if (pc == ESCAPE_CODE) goto fail; - if (add_sample(cpu_buf, pc, 0)) + if (op_add_sample(cpu_buf, pc, 0)) goto fail; return; diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index aacb0f0bc566..63f81c44846a 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -1,10 +1,11 @@ /** * @file cpu_buffer.h * - * @remark Copyright 2002 OProfile authors + * @remark Copyright 2002-2009 OProfile authors * @remark Read the file COPYING * * @author John Levon <levon@movementarian.org> + * @author Robert Richter <robert.richter@amd.com> */ #ifndef OPROFILE_CPU_BUFFER_H @@ -31,17 +32,12 @@ void end_cpu_work(void); struct op_sample { unsigned long eip; unsigned long event; + unsigned long data[0]; }; -struct op_entry { - struct ring_buffer_event *event; - struct op_sample *sample; - unsigned long irq_flags; -}; +struct op_entry; struct oprofile_cpu_buffer { - volatile unsigned long head_pos; - volatile unsigned long tail_pos; unsigned long buffer_size; struct task_struct *last_task; int last_is_kernel; @@ -54,8 +50,6 @@ struct oprofile_cpu_buffer { struct delayed_work work; }; -extern struct ring_buffer *op_ring_buffer_read; -extern struct ring_buffer *op_ring_buffer_write; DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); /* @@ -64,7 +58,7 @@ DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); * reset these to invalid values; the next sample collected will * populate the buffer with proper values to initialize the buffer */ -static inline void cpu_buffer_reset(int cpu) +static inline void op_cpu_buffer_reset(int cpu) { struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu); @@ -72,55 +66,48 @@ static inline void cpu_buffer_reset(int cpu) cpu_buf->last_task = NULL; } -static inline int cpu_buffer_write_entry(struct op_entry *entry) -{ - entry->event = ring_buffer_lock_reserve(op_ring_buffer_write, - sizeof(struct op_sample), - &entry->irq_flags); - if (entry->event) - entry->sample = ring_buffer_event_data(entry->event); - else - entry->sample = NULL; - - if (!entry->sample) - return -ENOMEM; - - return 0; -} +struct op_sample +*op_cpu_buffer_write_reserve(struct op_entry *entry, unsigned long size); +int op_cpu_buffer_write_commit(struct op_entry *entry); +struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu); +unsigned long op_cpu_buffer_entries(int cpu); -static inline int cpu_buffer_write_commit(struct op_entry *entry) +/* returns the remaining free size of data in the entry */ +static inline +int op_cpu_buffer_add_data(struct op_entry *entry, unsigned long val) { - return ring_buffer_unlock_commit(op_ring_buffer_write, entry->event, - entry->irq_flags); + if (!entry->size) + return 0; + *entry->data = val; + entry->size--; + entry->data++; + return entry->size; } -static inline struct op_sample *cpu_buffer_read_entry(int cpu) +/* returns the size of data in the entry */ +static inline +int op_cpu_buffer_get_size(struct op_entry *entry) { - struct ring_buffer_event *e; - e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL); - if (e) - return ring_buffer_event_data(e); - if (ring_buffer_swap_cpu(op_ring_buffer_read, - op_ring_buffer_write, - cpu)) - return NULL; - e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL); - if (e) - return ring_buffer_event_data(e); - return NULL; + return entry->size; } -/* "acquire" as many cpu buffer slots as we can */ -static inline unsigned long cpu_buffer_entries(int cpu) +/* returns 0 if empty or the size of data including the current value */ +static inline +int op_cpu_buffer_get_data(struct op_entry *entry, unsigned long *val) { - return ring_buffer_entries_cpu(op_ring_buffer_read, cpu) - + ring_buffer_entries_cpu(op_ring_buffer_write, cpu); + int size = entry->size; + if (!size) + return 0; + *val = *entry->data; + entry->size--; + entry->data++; + return size; } -/* transient events for the CPU buffer -> event buffer */ -#define CPU_IS_KERNEL 1 -#define CPU_TRACE_BEGIN 2 -#define IBS_FETCH_BEGIN 3 -#define IBS_OP_BEGIN 4 +/* extra data flags */ +#define KERNEL_CTX_SWITCH (1UL << 0) +#define IS_KERNEL (1UL << 1) +#define TRACE_BEGIN (1UL << 2) +#define USER_CTX_SWITCH (1UL << 3) #endif /* OPROFILE_CPU_BUFFER_H */ diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c index 191a3202cecc..2b7ae366ceb1 100644 --- a/drivers/oprofile/event_buffer.c +++ b/drivers/oprofile/event_buffer.c @@ -73,8 +73,8 @@ int alloc_event_buffer(void) unsigned long flags; spin_lock_irqsave(&oprofilefs_lock, flags); - buffer_size = fs_buffer_size; - buffer_watershed = fs_buffer_watershed; + buffer_size = oprofile_buffer_size; + buffer_watershed = oprofile_buffer_watershed; spin_unlock_irqrestore(&oprofilefs_lock, flags); if (buffer_watershed >= buffer_size) diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index cd375907f26f..3cffce90f82a 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -23,7 +23,7 @@ struct oprofile_operations oprofile_ops; unsigned long oprofile_started; -unsigned long backtrace_depth; +unsigned long oprofile_backtrace_depth; static unsigned long is_setup; static DEFINE_MUTEX(start_mutex); @@ -172,7 +172,7 @@ int oprofile_set_backtrace(unsigned long val) goto out; } - backtrace_depth = val; + oprofile_backtrace_depth = val; out: mutex_unlock(&start_mutex); diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h index 5df0c21a608f..c288d3c24b50 100644 --- a/drivers/oprofile/oprof.h +++ b/drivers/oprofile/oprof.h @@ -21,12 +21,12 @@ void oprofile_stop(void); struct oprofile_operations; -extern unsigned long fs_buffer_size; -extern unsigned long fs_cpu_buffer_size; -extern unsigned long fs_buffer_watershed; +extern unsigned long oprofile_buffer_size; +extern unsigned long oprofile_cpu_buffer_size; +extern unsigned long oprofile_buffer_watershed; extern struct oprofile_operations oprofile_ops; extern unsigned long oprofile_started; -extern unsigned long backtrace_depth; +extern unsigned long oprofile_backtrace_depth; struct super_block; struct dentry; diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index d8201998b0b7..5d36ffc30dd5 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -14,17 +14,18 @@ #include "oprofile_stats.h" #include "oprof.h" -#define FS_BUFFER_SIZE_DEFAULT 131072 -#define FS_CPU_BUFFER_SIZE_DEFAULT 8192 -#define FS_BUFFER_WATERSHED_DEFAULT 32768 /* FIXME: tune */ +#define BUFFER_SIZE_DEFAULT 131072 +#define CPU_BUFFER_SIZE_DEFAULT 8192 +#define BUFFER_WATERSHED_DEFAULT 32768 /* FIXME: tune */ -unsigned long fs_buffer_size; -unsigned long fs_cpu_buffer_size; -unsigned long fs_buffer_watershed; +unsigned long oprofile_buffer_size; +unsigned long oprofile_cpu_buffer_size; +unsigned long oprofile_buffer_watershed; static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { - return oprofilefs_ulong_to_user(backtrace_depth, buf, count, offset); + return oprofilefs_ulong_to_user(oprofile_backtrace_depth, buf, count, + offset); } @@ -125,16 +126,16 @@ static const struct file_operations dump_fops = { void oprofile_create_files(struct super_block *sb, struct dentry *root) { /* reinitialize default values */ - fs_buffer_size = FS_BUFFER_SIZE_DEFAULT; - fs_cpu_buffer_size = FS_CPU_BUFFER_SIZE_DEFAULT; - fs_buffer_watershed = FS_BUFFER_WATERSHED_DEFAULT; + oprofile_buffer_size = BUFFER_SIZE_DEFAULT; + oprofile_cpu_buffer_size = CPU_BUFFER_SIZE_DEFAULT; + oprofile_buffer_watershed = BUFFER_WATERSHED_DEFAULT; oprofilefs_create_file(sb, root, "enable", &enable_fops); oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666); oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops); - oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size); - oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed); - oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &fs_cpu_buffer_size); + oprofilefs_create_ulong(sb, root, "buffer_size", &oprofile_buffer_size); + oprofilefs_create_ulong(sb, root, "buffer_watershed", &oprofile_buffer_watershed); + oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &oprofile_cpu_buffer_size); oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops); oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops); oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops); diff --git a/drivers/parisc/asp.c b/drivers/parisc/asp.c index 821369135369..7931133526c4 100644 --- a/drivers/parisc/asp.c +++ b/drivers/parisc/asp.c @@ -71,8 +71,7 @@ static void asp_choose_irq(struct parisc_device *dev, void *ctrl) */ #define ASP_INTERRUPT_ADDR 0xf0800000 -int __init -asp_init_chip(struct parisc_device *dev) +static int __init asp_init_chip(struct parisc_device *dev) { struct gsc_irq gsc_irq; int ret; diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index dcc1e9958d2f..cd4dd7ed2c06 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -555,7 +555,7 @@ static u32 hint_lookup[] = { * (Load Coherence Index) instruction. The 8 bits used for the virtual * index are bits 12:19 of the value returned by LCI. */ -void CCIO_INLINE +static void CCIO_INLINE ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, unsigned long hints) { @@ -1578,8 +1578,6 @@ static int __init ccio_probe(struct parisc_device *dev) ioc_count++; - parisc_vmerge_boundary = IOVP_SIZE; - parisc_vmerge_max_size = BITS_PER_LONG * IOVP_SIZE; parisc_has_iommu(); return 0; } diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 77cc8bfef8c9..d539d9df88e7 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -287,7 +287,7 @@ DINO_PORT_OUT(b, 8, 3) DINO_PORT_OUT(w, 16, 2) DINO_PORT_OUT(l, 32, 0) -struct pci_port_ops dino_port_ops = { +static struct pci_port_ops dino_port_ops = { .inb = dino_in8, .inw = dino_in16, .inl = dino_in32, @@ -690,7 +690,7 @@ dino_fixup_bus(struct pci_bus *bus) } -struct pci_bios_ops dino_bios_ops = { +static struct pci_bios_ops dino_bios_ops = { .init = dino_bios_init, .fixup_bus = dino_fixup_bus }; diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c index 65eee67aa2ae..13856415b432 100644 --- a/drivers/parisc/hppb.c +++ b/drivers/parisc/hppb.c @@ -29,7 +29,7 @@ struct hppb_card { struct hppb_card *next; }; -struct hppb_card hppb_card_head = { +static struct hppb_card hppb_card_head = { .hpa = 0, .next = NULL, }; diff --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c index bee510098ce8..e65727ca9fc0 100644 --- a/drivers/parisc/lasi.c +++ b/drivers/parisc/lasi.c @@ -107,7 +107,7 @@ lasi_init_irq(struct gsc_asic *this_lasi) #else -void __init lasi_led_init(unsigned long lasi_hpa) +static void __init lasi_led_init(unsigned long lasi_hpa) { unsigned long datareg; @@ -163,8 +163,7 @@ static void lasi_power_off(void) gsc_writel(0x02, datareg); } -int __init -lasi_init_chip(struct parisc_device *dev) +static int __init lasi_init_chip(struct parisc_device *dev) { extern void (*chassis_power_off)(void); struct gsc_asic *lasi; diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index a28c8946deaa..d8233de8c75d 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -824,7 +824,7 @@ lba_fixup_bus(struct pci_bus *bus) } -struct pci_bios_ops lba_bios_ops = { +static struct pci_bios_ops lba_bios_ops = { .init = lba_bios_init, .fixup_bus = lba_fixup_bus, }; diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index bc73b96346ff..3fac8f81d59d 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -561,7 +561,7 @@ typedef unsigned long space_t; * IOMMU uses little endian for the pdir. */ -void SBA_INLINE +static void SBA_INLINE sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, unsigned long hint) { @@ -1874,7 +1874,7 @@ static struct parisc_device_id sba_tbl[] = { { 0, } }; -int sba_driver_callback(struct parisc_device *); +static int sba_driver_callback(struct parisc_device *); static struct parisc_driver sba_driver = { .name = MODULE_NAME, @@ -1887,8 +1887,7 @@ static struct parisc_driver sba_driver = { ** If so, initialize the chip and tell other partners in crime they ** have work to do. */ -int -sba_driver_callback(struct parisc_device *dev) +static int sba_driver_callback(struct parisc_device *dev) { struct sba_device *sba_dev; u32 func_class; @@ -1979,8 +1978,6 @@ sba_driver_callback(struct parisc_device *dev) proc_create("sba_iommu-bitmap", 0, root, &sba_proc_bitmap_fops); #endif - parisc_vmerge_boundary = IOVP_SIZE; - parisc_vmerge_max_size = IOVP_SIZE * BITS_PER_LONG; parisc_has_iommu(); return 0; } diff --git a/drivers/parisc/wax.c b/drivers/parisc/wax.c index 892a83bbe73d..da9d5ad1353c 100644 --- a/drivers/parisc/wax.c +++ b/drivers/parisc/wax.c @@ -68,8 +68,7 @@ wax_init_irq(struct gsc_asic *wax) // gsc_writel(0xFFFFFFFF, base+0x2000); /* RS232-B on Wax */ } -int __init -wax_init_chip(struct parisc_device *dev) +static int __init wax_init_chip(struct parisc_device *dev) { struct gsc_asic *wax; struct parisc_device *parent; diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index c62ab8d240aa..1c1141801060 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -33,7 +33,6 @@ #include <linux/pci-acpi.h> #include <acpi/acpi.h> #include <acpi/acpi_bus.h> -#include <acpi/actypes.h> #define MY_NAME "acpi_pcihp" diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 27fd18f019f8..db85284ffb62 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -217,7 +217,6 @@ struct hpc_ops { #ifdef CONFIG_ACPI #include <acpi/acpi.h> #include <acpi/acpi_bus.h> -#include <acpi/actypes.h> #include <linux/pci-acpi.h> extern void __init pciehp_acpi_slot_detection_init(void); diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 3582512e7226..deea8a187eb8 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -13,8 +13,6 @@ #include <linux/module.h> #include <linux/pci-aspm.h> #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acresrc.h> #include <acpi/acpi_bus.h> #include <linux/pci-acpi.h> diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig new file mode 100644 index 000000000000..9652c3fe7f5e --- /dev/null +++ b/drivers/platform/Kconfig @@ -0,0 +1,5 @@ +# drivers/platform/Kconfig + +if X86 +source "drivers/platform/x86/Kconfig" +endif diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile new file mode 100644 index 000000000000..782953ae4c03 --- /dev/null +++ b/drivers/platform/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for linux/drivers/platform +# + +obj-$(CONFIG_X86) += x86/ diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig new file mode 100644 index 000000000000..e65448e99b48 --- /dev/null +++ b/drivers/platform/x86/Kconfig @@ -0,0 +1,375 @@ +# +# X86 Platform Specific Drivers +# + +menuconfig X86_PLATFORM_DEVICES + bool "X86 Platform Specific Device Drivers" + default y + ---help--- + Say Y here to get to see options for device drivers for various + x86 platforms, including vendor-specific laptop extension drivers. + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. + +if X86_PLATFORM_DEVICES + +config ACER_WMI + tristate "Acer WMI Laptop Extras (EXPERIMENTAL)" + depends on EXPERIMENTAL + depends on ACPI + depends on LEDS_CLASS + depends on NEW_LEDS + depends on BACKLIGHT_CLASS_DEVICE + depends on SERIO_I8042 + depends on RFKILL + select ACPI_WMI + ---help--- + This is a driver for newer Acer (and Wistron) laptops. It adds + wireless radio and bluetooth control, and on some laptops, + exposes the mail LED and LCD backlight. + + For more information about this driver see + <file:Documentation/laptops/acer-wmi.txt> + + If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M + here. + +config ASUS_LAPTOP + tristate "Asus Laptop Extras (EXPERIMENTAL)" + depends on ACPI + depends on EXPERIMENTAL && !ACPI_ASUS + depends on LEDS_CLASS + depends on NEW_LEDS + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This is the new Linux driver for Asus laptops. It may also support some + MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate + standard ACPI events that go through /proc/acpi/events. It also adds + support for video output switching, LCD backlight control, Bluetooth and + Wlan control, and most importantly, allows you to blink those fancy LEDs. + + For more information and a userspace daemon for handling the extra + buttons see <http://acpi4asus.sf.net/>. + + If you have an ACPI-compatible ASUS laptop, say Y or M here. + +config FUJITSU_LAPTOP + tristate "Fujitsu Laptop Extras" + depends on ACPI + depends on INPUT + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This is a driver for laptops built by Fujitsu: + + * P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks + * Possibly other Fujitsu laptop models + * Tested with S6410 and S7020 + + It adds support for LCD brightness control and some hotkeys. + + If you have a Fujitsu laptop, say Y or M here. + +config FUJITSU_LAPTOP_DEBUG + bool "Verbose debug mode for Fujitsu Laptop Extras" + depends on FUJITSU_LAPTOP + default n + ---help--- + Enables extra debug output from the fujitsu extras driver, at the + expense of a slight increase in driver size. + + If you are not sure, say N here. + +config TC1100_WMI + tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)" + depends on !X86_64 + depends on EXPERIMENTAL + depends on ACPI + select ACPI_WMI + ---help--- + This is a driver for the WMI extensions (wireless and bluetooth power + control) of the HP Compaq TC1100 tablet. + +config HP_WMI + tristate "HP WMI extras" + depends on ACPI_WMI + depends on INPUT + depends on RFKILL + help + Say Y here if you want to support WMI-based hotkeys on HP laptops and + to read data from WMI such as docking or ambient light sensor state. + + To compile this driver as a module, choose M here: the module will + be called hp-wmi. + +config MSI_LAPTOP + tristate "MSI Laptop Extras" + depends on ACPI + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This is a driver for laptops built by MSI (MICRO-STAR + INTERNATIONAL): + + MSI MegaBook S270 (MS-1013) + Cytron/TCM/Medion/Tchibo MD96100/SAM2000 + + It adds support for Bluetooth, WLAN and LCD brightness control. + + More information about this driver is available at + <http://0pointer.de/lennart/tchibo.html>. + + If you have an MSI S270 laptop, say Y or M here. + +config PANASONIC_LAPTOP + tristate "Panasonic Laptop Extras" + depends on INPUT && ACPI + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This driver adds support for access to backlight control and hotkeys + on Panasonic Let's Note laptops. + + If you have a Panasonic Let's note laptop (such as the R1(N variant), + R2, R3, R5, T2, W2 and Y2 series), say Y. + +config COMPAL_LAPTOP + tristate "Compal Laptop Extras" + depends on ACPI + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This is a driver for laptops built by Compal: + + Compal FL90/IFL90 + Compal FL91/IFL91 + Compal FL92/JFL92 + Compal FT00/IFT00 + + It adds support for Bluetooth, WLAN and LCD brightness control. + + If you have an Compal FL9x/IFL9x/FT00 laptop, say Y or M here. + +config SONY_LAPTOP + tristate "Sony Laptop Extras" + depends on ACPI + select BACKLIGHT_CLASS_DEVICE + depends on INPUT + ---help--- + This mini-driver drives the SNC and SPIC devices present in the ACPI + BIOS of the Sony Vaio laptops. + + It gives access to some extra laptop functionalities like Bluetooth, + screen brightness control, Fn keys and allows powering on/off some + devices. + + Read <file:Documentation/laptops/sony-laptop.txt> for more information. + +config SONYPI_COMPAT + bool "Sonypi compatibility" + depends on SONY_LAPTOP + ---help--- + Build the sonypi driver compatibility code into the sony-laptop driver. + +config THINKPAD_ACPI + tristate "ThinkPad ACPI Laptop Extras" + depends on ACPI + select BACKLIGHT_LCD_SUPPORT + select BACKLIGHT_CLASS_DEVICE + select HWMON + select NVRAM + select INPUT + select NEW_LEDS + select LEDS_CLASS + select NET + select RFKILL + ---help--- + This is a driver for the IBM and Lenovo ThinkPad laptops. It adds + support for Fn-Fx key combinations, Bluetooth control, video + output switching, ThinkLight control, UltraBay eject and more. + For more information about this driver see + <file:Documentation/laptops/thinkpad-acpi.txt> and + <http://ibm-acpi.sf.net/> . + + This driver was formerly known as ibm-acpi. + + If you have an IBM or Lenovo ThinkPad laptop, say Y or M here. + +config THINKPAD_ACPI_DEBUG + bool "Verbose debug mode" + depends on THINKPAD_ACPI + default n + ---help--- + Enables extra debugging information, at the expense of a slightly + increase in driver size. + + If you are not sure, say N here. + +config THINKPAD_ACPI_DOCK + bool "Legacy Docking Station Support" + depends on THINKPAD_ACPI + depends on ACPI_DOCK=n + default n + ---help--- + Allows the thinkpad_acpi driver to handle docking station events. + This support was made obsolete by the generic ACPI docking station + support (CONFIG_ACPI_DOCK). It will allow locking and removing the + laptop from the docking station, but will not properly connect PCI + devices. + + If you are not sure, say N here. + +config THINKPAD_ACPI_BAY + bool "Legacy Removable Bay Support" + depends on THINKPAD_ACPI + default y + ---help--- + Allows the thinkpad_acpi driver to handle removable bays. It will + electrically disable the device in the bay, and also generate + notifications when the bay lever is ejected or inserted. + + If you are not sure, say Y here. + +config THINKPAD_ACPI_VIDEO + bool "Video output control support" + depends on THINKPAD_ACPI + default y + ---help--- + Allows the thinkpad_acpi driver to provide an interface to control + the various video output ports. + + This feature often won't work well, depending on ThinkPad model, + display state, video output devices in use, whether there is a X + server running, phase of the moon, and the current mood of + Schroedinger's cat. If you can use X.org's RandR to control + your ThinkPad's video output ports instead of this feature, + don't think twice: do it and say N here to save some memory. + + If you are not sure, say Y here. + +config THINKPAD_ACPI_HOTKEY_POLL + bool "Support NVRAM polling for hot keys" + depends on THINKPAD_ACPI + default y + ---help--- + Some thinkpad models benefit from NVRAM polling to detect a few of + the hot key press events. If you know your ThinkPad model does not + need to do NVRAM polling to support any of the hot keys you use, + unselecting this option will save about 1kB of memory. + + ThinkPads T40 and newer, R52 and newer, and X31 and newer are + unlikely to need NVRAM polling in their latest BIOS versions. + + NVRAM polling can detect at most the following keys: ThinkPad/Access + IBM, Zoom, Switch Display (fn+F7), ThinkLight, Volume up/down/mute, + Brightness up/down, Display Expand (fn+F8), Hibernate (fn+F12). + + If you are not sure, say Y here. The driver enables polling only if + it is strictly necessary to do so. + +config INTEL_MENLOW + tristate "Thermal Management driver for Intel menlow platform" + depends on ACPI_THERMAL + select THERMAL + ---help--- + ACPI thermal management enhancement driver on + Intel Menlow platform. + + If unsure, say N. + +config EEEPC_LAPTOP + tristate "Eee PC Hotkey Driver (EXPERIMENTAL)" + depends on ACPI + depends on EXPERIMENTAL + select BACKLIGHT_CLASS_DEVICE + select HWMON + select RFKILL + ---help--- + This driver supports the Fn-Fx keys on Eee PC laptops. + It also adds the ability to switch camera/wlan on/off. + + If you have an Eee PC laptop, say Y or M here. + + +config ACPI_WMI + tristate "WMI (EXPERIMENTAL)" + depends on ACPI + depends on EXPERIMENTAL + help + This driver adds support for the ACPI-WMI (Windows Management + Instrumentation) mapper device (PNP0C14) found on some systems. + + ACPI-WMI is a proprietary extension to ACPI to expose parts of the + ACPI firmware to userspace - this is done through various vendor + defined methods and data blocks in a PNP0C14 device, which are then + made available for userspace to call. + + The implementation of this in Linux currently only exposes this to + other kernel space drivers. + + This driver is a required dependency to build the firmware specific + drivers needed on many machines, including Acer and HP laptops. + + It is safe to enable this driver even if your DSDT doesn't define + any ACPI-WMI devices. + +config ACPI_ASUS + tristate "ASUS/Medion Laptop Extras" + depends on ACPI + select BACKLIGHT_CLASS_DEVICE + ---help--- + This driver provides support for extra features of ACPI-compatible + ASUS laptops. As some of Medion laptops are made by ASUS, it may also + support some Medion laptops (such as 9675 for example). It makes all + the extra buttons generate standard ACPI events that go through + /proc/acpi/events, and (on some models) adds support for changing the + display brightness and output, switching the LCD backlight on and off, + and most importantly, allows you to blink those fancy LEDs intended + for reporting mail and wireless status. + + Note: display switching code is currently considered EXPERIMENTAL, + toying with these values may even lock your machine. + + All settings are changed via /proc/acpi/asus directory entries. Owner + and group for these entries can be set with asus_uid and asus_gid + parameters. + + More information and a userspace daemon for handling the extra buttons + at <http://sourceforge.net/projects/acpi4asus/>. + + If you have an ACPI-compatible ASUS laptop, say Y or M here. This + driver is still under development, so if your laptop is unsupported or + something works not quite as expected, please use the mailing list + available on the above page (acpi4asus-user@lists.sourceforge.net). + + NOTE: This driver is deprecated and will probably be removed soon, + use asus-laptop instead. + +config ACPI_TOSHIBA + tristate "Toshiba Laptop Extras" + depends on ACPI + depends on INPUT + select INPUT_POLLDEV + select NET + select RFKILL + select BACKLIGHT_CLASS_DEVICE + ---help--- + This driver adds support for access to certain system settings + on "legacy free" Toshiba laptops. These laptops can be recognized by + their lack of a BIOS setup menu and APM support. + + On these machines, all system configuration is handled through the + ACPI. This driver is required for access to controls not covered + by the general ACPI drivers, such as LCD brightness, video output, + etc. + + This driver differs from the non-ACPI Toshiba laptop driver (located + under "Processor type and features") in several aspects. + Configuration is accessed by reading and writing text files in the + /proc tree instead of by program interface to /dev. Furthermore, no + power management functions are exposed, as those are handled by the + general ACPI drivers. + + More information about this driver is available at + <http://memebeam.org/toys/ToshibaAcpiDriver>. + + If you have a legacy free Toshiba laptop (such as the Libretto L1 + series), say Y. +endif # X86_PLATFORM_DEVICES diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile new file mode 100644 index 000000000000..1e9de2ae0de5 --- /dev/null +++ b/drivers/platform/x86/Makefile @@ -0,0 +1,19 @@ +# +# Makefile for linux/drivers/platform/x86 +# x86 Platform-Specific Drivers +# +obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o +obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o +obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o +obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o +obj-$(CONFIG_ACER_WMI) += acer-wmi.o +obj-$(CONFIG_HP_WMI) += hp-wmi.o +obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o +obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o +obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o +obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o +obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o +obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o +obj-$(CONFIG_ACPI_WMI) += wmi.o +obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o +obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o diff --git a/drivers/misc/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 94c9f911824e..94c9f911824e 100644 --- a/drivers/misc/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c diff --git a/drivers/misc/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 8fb8b3591048..8fb8b3591048 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c diff --git a/drivers/acpi/asus_acpi.c b/drivers/platform/x86/asus_acpi.c index 1e74988c7b2d..1e74988c7b2d 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/platform/x86/asus_acpi.c diff --git a/drivers/misc/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index 11003bba10d3..11003bba10d3 100644 --- a/drivers/misc/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c diff --git a/drivers/misc/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 02fe2b8b8939..02fe2b8b8939 100644 --- a/drivers/misc/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index a7dd3e9fb79d..65dc41540c62 100644 --- a/drivers/misc/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -3,6 +3,7 @@ /* Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@physics.adelaide.edu.au> Copyright (C) 2008 Peter Gruber <nokos@gmx.net> + Copyright (C) 2008 Tony Vroon <tony@linx.net> Based on earlier work: Copyright (C) 2003 Shane Spencer <shane@bogomip.com> Adrian Yee <brewt-fujitsu@brewt.org> @@ -65,8 +66,11 @@ #include <linux/kfifo.h> #include <linux/video_output.h> #include <linux/platform_device.h> +#ifdef CONFIG_LEDS_CLASS +#include <linux/leds.h> +#endif -#define FUJITSU_DRIVER_VERSION "0.4.3" +#define FUJITSU_DRIVER_VERSION "0.5.0" #define FUJITSU_LCD_N_LEVELS 8 @@ -83,6 +87,24 @@ #define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86 #define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 +/* FUNC interface - command values */ +#define FUNC_RFKILL 0x1000 +#define FUNC_LEDS 0x1001 +#define FUNC_BUTTONS 0x1002 +#define FUNC_BACKLIGHT 0x1004 + +/* FUNC interface - responses */ +#define UNSUPPORTED_CMD 0x80000000 + +#ifdef CONFIG_LEDS_CLASS +/* FUNC interface - LED control */ +#define FUNC_LED_OFF 0x1 +#define FUNC_LED_ON 0x30001 +#define KEYBOARD_LAMPS 0x100 +#define LOGOLAMP_POWERON 0x2000 +#define LOGOLAMP_ALWAYS 0x4000 +#endif + /* Hotkey details */ #define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */ #define KEY2_CODE 0x411 @@ -133,7 +155,6 @@ struct fujitsu_t { static struct fujitsu_t *fujitsu; static int use_alt_lcd_levels = -1; -static int disable_brightness_keys = -1; static int disable_brightness_adjust = -1; /* Device used to access other hotkeys on the laptop */ @@ -145,8 +166,9 @@ struct fujitsu_hotkey_t { struct platform_device *pf_device; struct kfifo *fifo; spinlock_t fifo_lock; - - unsigned int irb; /* info about the pressed buttons */ + int rfkill_state; + int logolamp_registered; + int kblamps_registered; }; static struct fujitsu_hotkey_t *fujitsu_hotkey; @@ -154,12 +176,139 @@ static struct fujitsu_hotkey_t *fujitsu_hotkey; static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event, void *data); +#ifdef CONFIG_LEDS_CLASS +static enum led_brightness logolamp_get(struct led_classdev *cdev); +static void logolamp_set(struct led_classdev *cdev, + enum led_brightness brightness); + +struct led_classdev logolamp_led = { + .name = "fujitsu::logolamp", + .brightness_get = logolamp_get, + .brightness_set = logolamp_set +}; + +static enum led_brightness kblamps_get(struct led_classdev *cdev); +static void kblamps_set(struct led_classdev *cdev, + enum led_brightness brightness); + +struct led_classdev kblamps_led = { + .name = "fujitsu::kblamps", + .brightness_get = kblamps_get, + .brightness_set = kblamps_set +}; +#endif + #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG static u32 dbg_level = 0x03; #endif static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data); +/* Fujitsu ACPI interface function */ + +static int call_fext_func(int cmd, int arg0, int arg1, int arg2) +{ + acpi_status status = AE_OK; + union acpi_object params[4] = { + { .type = ACPI_TYPE_INTEGER }, + { .type = ACPI_TYPE_INTEGER }, + { .type = ACPI_TYPE_INTEGER }, + { .type = ACPI_TYPE_INTEGER } + }; + struct acpi_object_list arg_list = { 4, ¶ms[0] }; + struct acpi_buffer output; + union acpi_object out_obj; + acpi_handle handle = NULL; + + status = acpi_get_handle(fujitsu_hotkey->acpi_handle, "FUNC", &handle); + if (ACPI_FAILURE(status)) { + vdbg_printk(FUJLAPTOP_DBG_ERROR, + "FUNC interface is not present\n"); + return -ENODEV; + } + + params[0].integer.value = cmd; + params[1].integer.value = arg0; + params[2].integer.value = arg1; + params[3].integer.value = arg2; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, NULL, &arg_list, &output); + if (ACPI_FAILURE(status)) { + vdbg_printk(FUJLAPTOP_DBG_WARN, + "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n", + cmd, arg0, arg1, arg2); + return -ENODEV; + } + + if (out_obj.type != ACPI_TYPE_INTEGER) { + vdbg_printk(FUJLAPTOP_DBG_WARN, + "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) did not " + "return an integer\n", + cmd, arg0, arg1, arg2); + return -ENODEV; + } + + vdbg_printk(FUJLAPTOP_DBG_TRACE, + "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n", + cmd, arg0, arg1, arg2, (int)out_obj.integer.value); + return out_obj.integer.value; +} + +#ifdef CONFIG_LEDS_CLASS +/* LED class callbacks */ + +static void logolamp_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + if (brightness >= LED_FULL) { + call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); + call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON); + } else if (brightness >= LED_HALF) { + call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); + call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF); + } else { + call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF); + } +} + +static void kblamps_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + if (brightness >= LED_FULL) + call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON); + else + call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF); +} + +static enum led_brightness logolamp_get(struct led_classdev *cdev) +{ + enum led_brightness brightness = LED_OFF; + int poweron, always; + + poweron = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); + if (poweron == FUNC_LED_ON) { + brightness = LED_HALF; + always = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); + if (always == FUNC_LED_ON) + brightness = LED_FULL; + } + return brightness; +} + +static enum led_brightness kblamps_get(struct led_classdev *cdev) +{ + enum led_brightness brightness = LED_OFF; + + if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON) + brightness = LED_FULL; + + return brightness; +} +#endif + /* Hardware access for LCD brightness control */ static int set_lcd_level(int level) @@ -263,44 +412,34 @@ static int get_max_brightness(void) return fujitsu->max_brightness; } -static int get_lcd_level_alt(void) -{ - unsigned long long state = 0; - acpi_status status = AE_OK; - - vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLS\n"); - - status = - acpi_evaluate_integer(fujitsu->acpi_handle, "GBLS", NULL, &state); - if (status < 0) - return status; - - fujitsu->brightness_level = state & 0x0fffffff; - - if (state & 0x80000000) - fujitsu->brightness_changed = 1; - else - fujitsu->brightness_changed = 0; - - return fujitsu->brightness_level; -} - /* Backlight device stuff */ static int bl_get_brightness(struct backlight_device *b) { - if (use_alt_lcd_levels) - return get_lcd_level_alt(); - else - return get_lcd_level(); + return get_lcd_level(); } static int bl_update_status(struct backlight_device *b) { + int ret; + if (b->props.power == 4) + ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3); + else + ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0); + if (ret != 0) + vdbg_printk(FUJLAPTOP_DBG_ERROR, + "Unable to adjust backlight power, error code %i\n", + ret); + if (use_alt_lcd_levels) - return set_lcd_level_alt(b->props.brightness); + ret = set_lcd_level_alt(b->props.brightness); else - return set_lcd_level(b->props.brightness); + ret = set_lcd_level(b->props.brightness); + if (ret != 0) + vdbg_printk(FUJLAPTOP_DBG_ERROR, + "Unable to adjust LCD brightness, error code %i\n", + ret); + return ret; } static struct backlight_ops fujitsubl_ops = { @@ -344,10 +483,7 @@ static ssize_t show_lcd_level(struct device *dev, int ret; - if (use_alt_lcd_levels) - ret = get_lcd_level_alt(); - else - ret = get_lcd_level(); + ret = get_lcd_level(); if (ret < 0) return ret; @@ -372,52 +508,71 @@ static ssize_t store_lcd_level(struct device *dev, if (ret < 0) return ret; - if (use_alt_lcd_levels) - ret = get_lcd_level_alt(); - else - ret = get_lcd_level(); + ret = get_lcd_level(); if (ret < 0) return ret; return count; } -/* Hardware access for hotkey device */ - -static int get_irb(void) +static ssize_t +ignore_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { - unsigned long long state = 0; - acpi_status status = AE_OK; - - vdbg_printk(FUJLAPTOP_DBG_TRACE, "Get irb\n"); - - status = - acpi_evaluate_integer(fujitsu_hotkey->acpi_handle, "GIRB", NULL, - &state); - if (status < 0) - return status; + return count; +} - fujitsu_hotkey->irb = state; +static ssize_t +show_lid_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD) + return sprintf(buf, "unknown\n"); + if (fujitsu_hotkey->rfkill_state & 0x100) + return sprintf(buf, "open\n"); + else + return sprintf(buf, "closed\n"); +} - return fujitsu_hotkey->irb; +static ssize_t +show_dock_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD) + return sprintf(buf, "unknown\n"); + if (fujitsu_hotkey->rfkill_state & 0x200) + return sprintf(buf, "docked\n"); + else + return sprintf(buf, "undocked\n"); } static ssize_t -ignore_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) +show_radios_state(struct device *dev, + struct device_attribute *attr, char *buf) { - return count; + if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD) + return sprintf(buf, "unknown\n"); + if (fujitsu_hotkey->rfkill_state & 0x20) + return sprintf(buf, "on\n"); + else + return sprintf(buf, "killed\n"); } static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store); static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed, ignore_store); static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); +static DEVICE_ATTR(lid, 0444, show_lid_state, ignore_store); +static DEVICE_ATTR(dock, 0444, show_dock_state, ignore_store); +static DEVICE_ATTR(radios, 0444, show_radios_state, ignore_store); static struct attribute *fujitsupf_attributes[] = { &dev_attr_brightness_changed.attr, &dev_attr_max_brightness.attr, &dev_attr_lcd_level.attr, + &dev_attr_lid.attr, + &dev_attr_dock.attr, + &dev_attr_radios.attr, NULL }; @@ -435,24 +590,16 @@ static struct platform_driver fujitsupf_driver = { static void dmi_check_cb_common(const struct dmi_system_id *id) { acpi_handle handle; - int have_blnf; printk(KERN_INFO "fujitsu-laptop: Identified laptop model '%s'.\n", id->ident); - have_blnf = ACPI_SUCCESS - (acpi_get_handle(NULL, "\\_SB.PCI0.GFX0.LCD.BLNF", &handle)); if (use_alt_lcd_levels == -1) { - vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detecting usealt\n"); - use_alt_lcd_levels = 1; - } - if (disable_brightness_keys == -1) { - vdbg_printk(FUJLAPTOP_DBG_TRACE, - "auto-detecting disable_keys\n"); - disable_brightness_keys = have_blnf ? 1 : 0; - } - if (disable_brightness_adjust == -1) { - vdbg_printk(FUJLAPTOP_DBG_TRACE, - "auto-detecting disable_adjust\n"); - disable_brightness_adjust = have_blnf ? 0 : 1; + if (ACPI_SUCCESS(acpi_get_handle(NULL, + "\\_SB.PCI0.LPCB.FJEX.SBL2", &handle))) + use_alt_lcd_levels = 1; + else + use_alt_lcd_levels = 0; + vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detected usealt as " + "%i\n", use_alt_lcd_levels); } } @@ -581,19 +728,14 @@ static int acpi_fujitsu_add(struct acpi_device *device) /* do config (detect defaults) */ use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0; - disable_brightness_keys = disable_brightness_keys == 1 ? 1 : 0; disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0; vdbg_printk(FUJLAPTOP_DBG_INFO, - "config: [alt interface: %d], [key disable: %d], [adjust disable: %d]\n", - use_alt_lcd_levels, disable_brightness_keys, - disable_brightness_adjust); + "config: [alt interface: %d], [adjust disable: %d]\n", + use_alt_lcd_levels, disable_brightness_adjust); if (get_max_brightness() <= 0) fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS; - if (use_alt_lcd_levels) - get_lcd_level_alt(); - else - get_lcd_level(); + get_lcd_level(); return result; @@ -644,43 +786,23 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data) case ACPI_FUJITSU_NOTIFY_CODE1: keycode = 0; oldb = fujitsu->brightness_level; - get_lcd_level(); /* the alt version always yields changed */ + get_lcd_level(); newb = fujitsu->brightness_level; vdbg_printk(FUJLAPTOP_DBG_TRACE, "brightness button event [%i -> %i (%i)]\n", oldb, newb, fujitsu->brightness_changed); - if (oldb == newb && fujitsu->brightness_changed) { - keycode = 0; - if (disable_brightness_keys != 1) { - if (oldb == 0) { - acpi_bus_generate_proc_event - (fujitsu->dev, - ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, - 0); - keycode = KEY_BRIGHTNESSDOWN; - } else if (oldb == - (fujitsu->max_brightness) - 1) { - acpi_bus_generate_proc_event - (fujitsu->dev, - ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, - 0); - keycode = KEY_BRIGHTNESSUP; - } - } - } else if (oldb < newb) { + if (oldb < newb) { if (disable_brightness_adjust != 1) { if (use_alt_lcd_levels) set_lcd_level_alt(newb); else set_lcd_level(newb); } - if (disable_brightness_keys != 1) { - acpi_bus_generate_proc_event(fujitsu->dev, - ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0); - keycode = KEY_BRIGHTNESSUP; - } + acpi_bus_generate_proc_event(fujitsu->dev, + ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0); + keycode = KEY_BRIGHTNESSUP; } else if (oldb > newb) { if (disable_brightness_adjust != 1) { if (use_alt_lcd_levels) @@ -688,13 +810,9 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data) else set_lcd_level(newb); } - if (disable_brightness_keys != 1) { - acpi_bus_generate_proc_event(fujitsu->dev, - ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0); - keycode = KEY_BRIGHTNESSDOWN; - } - } else { - keycode = KEY_UNKNOWN; + acpi_bus_generate_proc_event(fujitsu->dev, + ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0); + keycode = KEY_BRIGHTNESSDOWN; } break; default: @@ -771,7 +889,8 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) input->id.bustype = BUS_HOST; input->id.product = 0x06; input->dev.parent = &device->dev; - input->evbit[0] = BIT(EV_KEY); + + set_bit(EV_KEY, input->evbit); set_bit(fujitsu->keycode1, input->keybit); set_bit(fujitsu->keycode2, input->keybit); set_bit(fujitsu->keycode3, input->keybit); @@ -803,10 +922,44 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) printk(KERN_ERR "_INI Method failed\n"); } - i = 0; /* Discard hotkey ringbuffer */ - while (get_irb() != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) ; + i = 0; + while (call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 + && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) + ; /* No action, result is discarded */ vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i); + fujitsu_hotkey->rfkill_state = + call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0); + + /* Suspect this is a keymap of the application panel, print it */ + printk(KERN_INFO "fujitsu-laptop: BTNI: [0x%x]\n", + call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0)); + + #ifdef CONFIG_LEDS_CLASS + if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { + result = led_classdev_register(&fujitsu->pf_device->dev, + &logolamp_led); + if (result == 0) { + fujitsu_hotkey->logolamp_registered = 1; + } else { + printk(KERN_ERR "fujitsu-laptop: Could not register " + "LED handler for logo lamp, error %i\n", result); + } + } + + if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && + (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { + result = led_classdev_register(&fujitsu->pf_device->dev, + &kblamps_led); + if (result == 0) { + fujitsu_hotkey->kblamps_registered = 1; + } else { + printk(KERN_ERR "fujitsu-laptop: Could not register " + "LED handler for keyboard lamps, error %i\n", result); + } + } + #endif + return result; end: @@ -852,16 +1005,15 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event, input = fujitsu_hotkey->input; - vdbg_printk(FUJLAPTOP_DBG_TRACE, "Hotkey event\n"); + fujitsu_hotkey->rfkill_state = + call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0); switch (event) { case ACPI_FUJITSU_NOTIFY_CODE1: i = 0; - while ((irb = get_irb()) != 0 - && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { - vdbg_printk(FUJLAPTOP_DBG_TRACE, "GIRB result [%x]\n", - irb); - + while ((irb = + call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 + && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { switch (irb & 0x4ff) { case KEY1_CODE: keycode = fujitsu->keycode1; @@ -1035,6 +1187,15 @@ static int __init fujitsu_init(void) goto fail_hotkey1; } + /* Sync backlight power status (needs FUJ02E3 device, hence deferred) */ + + if (!acpi_video_backlight_support()) { + if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3) + fujitsu->bl_device->props.power = 4; + else + fujitsu->bl_device->props.power = 0; + } + printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION " successfully loaded.\n"); @@ -1074,6 +1235,14 @@ fail_acpi: static void __exit fujitsu_cleanup(void) { + #ifdef CONFIG_LEDS_CLASS + if (fujitsu_hotkey->logolamp_registered != 0) + led_classdev_unregister(&logolamp_led); + + if (fujitsu_hotkey->kblamps_registered != 0) + led_classdev_unregister(&kblamps_led); + #endif + sysfs_remove_group(&fujitsu->pf_device->dev.kobj, &fujitsupf_attribute_group); platform_device_unregister(fujitsu->pf_device); @@ -1098,9 +1267,6 @@ module_exit(fujitsu_cleanup); module_param(use_alt_lcd_levels, uint, 0644); MODULE_PARM_DESC(use_alt_lcd_levels, "Use alternative interface for lcd_levels (needed for Lifebook s6410)."); -module_param(disable_brightness_keys, uint, 0644); -MODULE_PARM_DESC(disable_brightness_keys, - "Disable brightness keys (eg. if they are already handled by the generic ACPI_VIDEO device)."); module_param(disable_brightness_adjust, uint, 0644); MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment ."); #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG @@ -1108,12 +1274,13 @@ module_param_named(debug, dbg_level, uint, 0644); MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); #endif -MODULE_AUTHOR("Jonathan Woithe, Peter Gruber"); +MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon"); MODULE_DESCRIPTION("Fujitsu laptop extras support"); MODULE_VERSION(FUJITSU_DRIVER_VERSION); MODULE_LICENSE("GPL"); MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*"); +MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1E6:*:cvrS6420:*"); MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*"); static struct pnp_device_id pnp_ids[] = { diff --git a/drivers/misc/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 4b7c24c519c3..4b7c24c519c3 100644 --- a/drivers/misc/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c diff --git a/drivers/misc/intel_menlow.c b/drivers/platform/x86/intel_menlow.c index 27b7662955bb..27b7662955bb 100644 --- a/drivers/misc/intel_menlow.c +++ b/drivers/platform/x86/intel_menlow.c diff --git a/drivers/misc/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 759763d18e4c..759763d18e4c 100644 --- a/drivers/misc/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c diff --git a/drivers/misc/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 4a1bc64485d5..f30db367c82e 100644 --- a/drivers/misc/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -241,8 +241,6 @@ static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val) }; acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("acpi_pcc_write_sset"); - status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET, ¶ms, NULL); @@ -254,8 +252,6 @@ static inline int acpi_pcc_get_sqty(struct acpi_device *device) unsigned long long s; acpi_status status; - ACPI_FUNCTION_TRACE("acpi_pcc_get_sqty"); - status = acpi_evaluate_integer(device->handle, METHOD_HKEY_SQTY, NULL, &s); if (ACPI_SUCCESS(status)) @@ -274,8 +270,6 @@ static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf) union acpi_object *hkey = NULL; int i; - ACPI_FUNCTION_TRACE("acpi_pcc_retrieve_biosdata"); - status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SINF, 0, &buffer); if (ACPI_FAILURE(status)) { @@ -501,8 +495,6 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) int key_code, hkey_num; unsigned long long result; - ACPI_FUNCTION_TRACE("acpi_pcc_generate_keyinput"); - rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY, NULL, &result); if (!ACPI_SUCCESS(rc)) { @@ -538,8 +530,6 @@ static void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data) { struct pcc_acpi *pcc = (struct pcc_acpi *) data; - ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_notify"); - switch (event) { case HKEY_NOTIFY: acpi_pcc_generate_keyinput(pcc); @@ -554,8 +544,6 @@ static int acpi_pcc_init_input(struct pcc_acpi *pcc) { int i, rc; - ACPI_FUNCTION_TRACE("acpi_pcc_init_input"); - pcc->input_dev = input_allocate_device(); if (!pcc->input_dev) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, @@ -597,8 +585,6 @@ static int acpi_pcc_hotkey_resume(struct acpi_device *device) struct pcc_acpi *pcc = acpi_driver_data(device); acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_resume"); - if (device == NULL || pcc == NULL) return -EINVAL; @@ -616,8 +602,6 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) struct pcc_acpi *pcc; int num_sifr, result; - ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_add"); - if (!device) return -EINVAL; @@ -714,8 +698,6 @@ static int __init acpi_pcc_init(void) { int result = 0; - ACPI_FUNCTION_TRACE("acpi_pcc_init"); - if (acpi_disabled) return -ENODEV; @@ -733,8 +715,6 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type) { struct pcc_acpi *pcc = acpi_driver_data(device); - ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_remove"); - if (!device || !pcc) return -EINVAL; @@ -757,8 +737,6 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type) static void __exit acpi_pcc_exit(void) { - ACPI_FUNCTION_TRACE("acpi_pcc_exit"); - acpi_bus_unregister_driver(&acpi_pcc_driver); } diff --git a/drivers/misc/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 571b211608d1..537959d07148 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -935,14 +935,17 @@ static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) static acpi_status sony_walk_callback(acpi_handle handle, u32 level, void *context, void **return_value) { - struct acpi_namespace_node *node; - union acpi_operand_object *operand; + struct acpi_device_info *info; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - node = (struct acpi_namespace_node *)handle; - operand = (union acpi_operand_object *)node->object; + if (ACPI_SUCCESS(acpi_get_object_info(handle, &buffer))) { + info = buffer.pointer; - printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", node->name.ascii, - (u32) operand->method.param_count); + printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", + (char *)&info->name, info->param_count); + + kfree(buffer.pointer); + } return AE_OK; } diff --git a/drivers/misc/tc1100-wmi.c b/drivers/platform/x86/tc1100-wmi.c index f25e4c974dcf..b4a4aa9ee482 100644 --- a/drivers/misc/tc1100-wmi.c +++ b/drivers/platform/x86/tc1100-wmi.c @@ -30,7 +30,6 @@ #include <linux/init.h> #include <linux/types.h> #include <acpi/acpi.h> -#include <acpi/actypes.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> #include <linux/platform_device.h> diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 899766e16fa8..3478453eba7a 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -76,7 +76,6 @@ #include <linux/workqueue.h> #include <acpi/acpi_drivers.h> -#include <acpi/acnamesp.h> #include <linux/pci_ids.h> diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 40e60fc2e596..40e60fc2e596 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c diff --git a/drivers/acpi/wmi.c b/drivers/platform/x86/wmi.c index 8a8b377712c9..8a8b377712c9 100644 --- a/drivers/acpi/wmi.c +++ b/drivers/platform/x86/wmi.c diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 383e47c392a4..2834846a185d 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -23,7 +23,6 @@ #include <linux/pnp.h> #include <linux/mod_devicetable.h> #include <acpi/acpi_bus.h> -#include <acpi/actypes.h> #include "../base.h" #include "pnpacpi.h" diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c index 346d633655e7..c6bfa6fe1a2a 100644 --- a/drivers/rtc/rtc-parisc.c +++ b/drivers/rtc/rtc-parisc.c @@ -34,7 +34,8 @@ static int parisc_get_time(struct device *dev, struct rtc_time *tm) static int parisc_set_time(struct device *dev, struct rtc_time *tm) { struct parisc_rtc *p = dev_get_drvdata(dev); - unsigned long flags, ret; + unsigned long flags; + int ret; spin_lock_irqsave(&p->lock, flags); ret = set_rtc_time(tm); diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c index c73fa89b5f8a..170d289ac785 100644 --- a/fs/jffs2/compr_rubin.c +++ b/fs/jffs2/compr_rubin.c @@ -22,9 +22,7 @@ #define BIT_DIVIDER_MIPS 1043 -static int bits_mips[8] = { 277,249,290,267,229,341,212,241}; /* mips32 */ - -#include <linux/errno.h> +static int bits_mips[8] = { 277, 249, 290, 267, 229, 341, 212, 241}; struct pushpull { unsigned char *buf; @@ -43,7 +41,9 @@ struct rubin_state { int bits[8]; }; -static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen, unsigned ofs, unsigned reserve) +static inline void init_pushpull(struct pushpull *pp, char *buf, + unsigned buflen, unsigned ofs, + unsigned reserve) { pp->buf = buf; pp->buflen = buflen; @@ -53,16 +53,14 @@ static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen static inline int pushbit(struct pushpull *pp, int bit, int use_reserved) { - if (pp->ofs >= pp->buflen - (use_reserved?0:pp->reserve)) { + if (pp->ofs >= pp->buflen - (use_reserved?0:pp->reserve)) return -ENOSPC; - } - if (bit) { - pp->buf[pp->ofs >> 3] |= (1<<(7-(pp->ofs &7))); - } - else { - pp->buf[pp->ofs >> 3] &= ~(1<<(7-(pp->ofs &7))); - } + if (bit) + pp->buf[pp->ofs >> 3] |= (1<<(7-(pp->ofs & 7))); + else + pp->buf[pp->ofs >> 3] &= ~(1<<(7-(pp->ofs & 7))); + pp->ofs++; return 0; @@ -97,6 +95,7 @@ static void init_rubin(struct rubin_state *rs, int div, int *bits) rs->p = (long) (2 * UPPER_BIT_RUBIN); rs->bit_number = (long) 0; rs->bit_divider = div; + for (c=0; c<8; c++) rs->bits[c] = bits[c]; } @@ -108,7 +107,8 @@ static int encode(struct rubin_state *rs, long A, long B, int symbol) long i0, i1; int ret; - while ((rs->q >= UPPER_BIT_RUBIN) || ((rs->p + rs->q) <= UPPER_BIT_RUBIN)) { + while ((rs->q >= UPPER_BIT_RUBIN) || + ((rs->p + rs->q) <= UPPER_BIT_RUBIN)) { rs->bit_number++; ret = pushbit(&rs->pp, (rs->q & UPPER_BIT_RUBIN) ? 1 : 0, 0); @@ -119,12 +119,12 @@ static int encode(struct rubin_state *rs, long A, long B, int symbol) rs->p <<= 1; } i0 = A * rs->p / (A + B); - if (i0 <= 0) { + if (i0 <= 0) i0 = 1; - } - if (i0 >= rs->p) { + + if (i0 >= rs->p) i0 = rs->p - 1; - } + i1 = rs->p - i0; if (symbol == 0) @@ -157,11 +157,13 @@ static void init_decode(struct rubin_state *rs, int div, int *bits) /* behalve lower */ rs->rec_q = 0; - for (rs->bit_number = 0; rs->bit_number++ < RUBIN_REG_SIZE; rs->rec_q = rs->rec_q * 2 + (long) (pullbit(&rs->pp))) + for (rs->bit_number = 0; rs->bit_number++ < RUBIN_REG_SIZE; + rs->rec_q = rs->rec_q * 2 + (long) (pullbit(&rs->pp))) ; } -static void __do_decode(struct rubin_state *rs, unsigned long p, unsigned long q) +static void __do_decode(struct rubin_state *rs, unsigned long p, + unsigned long q) { register unsigned long lower_bits_rubin = LOWER_BITS_RUBIN; unsigned long rec_q; @@ -207,12 +209,11 @@ static int decode(struct rubin_state *rs, long A, long B) __do_decode(rs, p, q); i0 = A * rs->p / (A + B); - if (i0 <= 0) { + if (i0 <= 0) i0 = 1; - } - if (i0 >= rs->p) { + + if (i0 >= rs->p) i0 = rs->p - 1; - } threshold = rs->q + i0; symbol = rs->rec_q >= threshold; @@ -234,14 +235,15 @@ static int out_byte(struct rubin_state *rs, unsigned char byte) struct rubin_state rs_copy; rs_copy = *rs; - for (i=0;i<8;i++) { - ret = encode(rs, rs->bit_divider-rs->bits[i],rs->bits[i],byte&1); + for (i=0; i<8; i++) { + ret = encode(rs, rs->bit_divider-rs->bits[i], + rs->bits[i], byte & 1); if (ret) { /* Failed. Restore old state */ *rs = rs_copy; return ret; } - byte=byte>>1; + byte >>= 1 ; } return 0; } @@ -251,7 +253,8 @@ static int in_byte(struct rubin_state *rs) int i, result = 0, bit_divider = rs->bit_divider; for (i = 0; i < 8; i++) - result |= decode(rs, bit_divider - rs->bits[i], rs->bits[i]) << i; + result |= decode(rs, bit_divider - rs->bits[i], + rs->bits[i]) << i; return result; } @@ -259,7 +262,8 @@ static int in_byte(struct rubin_state *rs) static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, - unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen) + unsigned char *cpage_out, uint32_t *sourcelen, + uint32_t *dstlen) { int outpos = 0; int pos=0; @@ -295,7 +299,8 @@ static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen, void *model) { - return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); + return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, + cpage_out, sourcelen, dstlen); } #endif static int jffs2_dynrubin_compress(unsigned char *data_in, @@ -316,9 +321,8 @@ static int jffs2_dynrubin_compress(unsigned char *data_in, return -1; memset(histo, 0, 256); - for (i=0; i<mysrclen; i++) { + for (i=0; i<mysrclen; i++) histo[data_in[i]]++; - } memset(bits, 0, sizeof(int)*8); for (i=0; i<256; i++) { if (i&128) @@ -346,7 +350,8 @@ static int jffs2_dynrubin_compress(unsigned char *data_in, cpage_out[i] = bits[i]; } - ret = rubin_do_compress(256, bits, data_in, cpage_out+8, &mysrclen, &mydstlen); + ret = rubin_do_compress(256, bits, data_in, cpage_out+8, &mysrclen, + &mydstlen); if (ret) return ret; @@ -363,8 +368,10 @@ static int jffs2_dynrubin_compress(unsigned char *data_in, return 0; } -static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in, - unsigned char *page_out, uint32_t srclen, uint32_t destlen) +static void rubin_do_decompress(int bit_divider, int *bits, + unsigned char *cdata_in, + unsigned char *page_out, uint32_t srclen, + uint32_t destlen) { int outpos = 0; struct rubin_state rs; @@ -372,9 +379,8 @@ static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata init_pushpull(&rs.pp, cdata_in, srclen, 0, 0); init_decode(&rs, bit_divider, bits); - while (outpos < destlen) { + while (outpos < destlen) page_out[outpos++] = in_byte(&rs); - } } @@ -383,7 +389,8 @@ static int jffs2_rubinmips_decompress(unsigned char *data_in, uint32_t sourcelen, uint32_t dstlen, void *model) { - rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); + rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, + cpage_out, sourcelen, dstlen); return 0; } @@ -398,52 +405,53 @@ static int jffs2_dynrubin_decompress(unsigned char *data_in, for (c=0; c<8; c++) bits[c] = data_in[c]; - rubin_do_decompress(256, bits, data_in+8, cpage_out, sourcelen-8, dstlen); + rubin_do_decompress(256, bits, data_in+8, cpage_out, sourcelen-8, + dstlen); return 0; } static struct jffs2_compressor jffs2_rubinmips_comp = { - .priority = JFFS2_RUBINMIPS_PRIORITY, - .name = "rubinmips", - .compr = JFFS2_COMPR_DYNRUBIN, - .compress = NULL, /*&jffs2_rubinmips_compress,*/ - .decompress = &jffs2_rubinmips_decompress, + .priority = JFFS2_RUBINMIPS_PRIORITY, + .name = "rubinmips", + .compr = JFFS2_COMPR_DYNRUBIN, + .compress = NULL, /*&jffs2_rubinmips_compress,*/ + .decompress = &jffs2_rubinmips_decompress, #ifdef JFFS2_RUBINMIPS_DISABLED - .disabled = 1, + .disabled = 1, #else - .disabled = 0, + .disabled = 0, #endif }; int jffs2_rubinmips_init(void) { - return jffs2_register_compressor(&jffs2_rubinmips_comp); + return jffs2_register_compressor(&jffs2_rubinmips_comp); } void jffs2_rubinmips_exit(void) { - jffs2_unregister_compressor(&jffs2_rubinmips_comp); + jffs2_unregister_compressor(&jffs2_rubinmips_comp); } static struct jffs2_compressor jffs2_dynrubin_comp = { - .priority = JFFS2_DYNRUBIN_PRIORITY, - .name = "dynrubin", - .compr = JFFS2_COMPR_RUBINMIPS, - .compress = jffs2_dynrubin_compress, - .decompress = &jffs2_dynrubin_decompress, + .priority = JFFS2_DYNRUBIN_PRIORITY, + .name = "dynrubin", + .compr = JFFS2_COMPR_RUBINMIPS, + .compress = jffs2_dynrubin_compress, + .decompress = &jffs2_dynrubin_decompress, #ifdef JFFS2_DYNRUBIN_DISABLED - .disabled = 1, + .disabled = 1, #else - .disabled = 0, + .disabled = 0, #endif }; int jffs2_dynrubin_init(void) { - return jffs2_register_compressor(&jffs2_dynrubin_comp); + return jffs2_register_compressor(&jffs2_dynrubin_comp); } void jffs2_dynrubin_exit(void) { - jffs2_unregister_compressor(&jffs2_dynrubin_comp); + jffs2_unregister_compressor(&jffs2_dynrubin_comp); } diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 259461b910af..c32b4a1ad6cf 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -175,7 +175,7 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock { /* For NAND, if the failure did not occur at the device level for a specific physical page, don't bother updating the bad block table. */ - if (jffs2_cleanmarker_oob(c) && (bad_offset != MTD_FAIL_ADDR_UNKNOWN)) { + if (jffs2_cleanmarker_oob(c) && (bad_offset != (uint32_t)MTD_FAIL_ADDR_UNKNOWN)) { /* We had a device-level failure to erase. Let's see if we've failed too many times. */ if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { @@ -209,7 +209,8 @@ static void jffs2_erase_callback(struct erase_info *instr) struct erase_priv_struct *priv = (void *)instr->priv; if(instr->state != MTD_ERASE_DONE) { - printk(KERN_WARNING "Erase at 0x%08x finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n", instr->addr, instr->state); + printk(KERN_WARNING "Erase at 0x%08llx finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n", + (unsigned long long)instr->addr, instr->state); jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr); } else { jffs2_erase_succeeded(priv->c, priv->jeb); diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h deleted file mode 100644 index 0c1ed387073c..000000000000 --- a/include/acpi/acdisasm.h +++ /dev/null @@ -1,445 +0,0 @@ -/****************************************************************************** - * - * Name: acdisasm.h - AML disassembler - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2008, 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. - */ - -#ifndef __ACDISASM_H__ -#define __ACDISASM_H__ - -#include "amlresrc.h" - -#define BLOCK_NONE 0 -#define BLOCK_PAREN 1 -#define BLOCK_BRACE 2 -#define BLOCK_COMMA_LIST 4 -#define ACPI_DEFAULT_RESNAME *(u32 *) "__RD" - -struct acpi_external_list { - char *path; - char *internal_path; - struct acpi_external_list *next; - u32 value; - u16 length; - u8 type; -}; - -extern struct acpi_external_list *acpi_gbl_external_list; - -typedef const struct acpi_dmtable_info { - u8 opcode; - u8 offset; - char *name; - -} acpi_dmtable_info; - -/* - * Values for Opcode above. - * Note: 0-7 must not change, used as a flag shift value - */ -#define ACPI_DMT_FLAG0 0 -#define ACPI_DMT_FLAG1 1 -#define ACPI_DMT_FLAG2 2 -#define ACPI_DMT_FLAG3 3 -#define ACPI_DMT_FLAG4 4 -#define ACPI_DMT_FLAG5 5 -#define ACPI_DMT_FLAG6 6 -#define ACPI_DMT_FLAG7 7 -#define ACPI_DMT_FLAGS0 8 -#define ACPI_DMT_FLAGS2 9 -#define ACPI_DMT_UINT8 10 -#define ACPI_DMT_UINT16 11 -#define ACPI_DMT_UINT24 12 -#define ACPI_DMT_UINT32 13 -#define ACPI_DMT_UINT56 14 -#define ACPI_DMT_UINT64 15 -#define ACPI_DMT_STRING 16 -#define ACPI_DMT_NAME4 17 -#define ACPI_DMT_NAME6 18 -#define ACPI_DMT_NAME8 19 -#define ACPI_DMT_CHKSUM 20 -#define ACPI_DMT_SPACEID 21 -#define ACPI_DMT_GAS 22 -#define ACPI_DMT_ASF 23 -#define ACPI_DMT_DMAR 24 -#define ACPI_DMT_HEST 25 -#define ACPI_DMT_HESTNTFY 26 -#define ACPI_DMT_HESTNTYP 27 -#define ACPI_DMT_MADT 28 -#define ACPI_DMT_SRAT 29 -#define ACPI_DMT_EXIT 30 -#define ACPI_DMT_SIG 31 - -typedef -void (*acpi_dmtable_handler) (struct acpi_table_header * table); - -struct acpi_dmtable_data { - char *signature; - struct acpi_dmtable_info *table_info; - acpi_dmtable_handler table_handler; - char *name; -}; - -struct acpi_op_walk_info { - u32 level; - u32 last_level; - u32 count; - u32 bit_offset; - u32 flags; - struct acpi_walk_state *walk_state; -}; - -typedef -acpi_status(*asl_walk_callback) (union acpi_parse_object * op, - u32 level, void *context); - -struct acpi_resource_tag { - u32 bit_index; - char *tag; -}; - -/* Strings used for decoding flags to ASL keywords */ - -extern const char *acpi_gbl_word_decode[]; -extern const char *acpi_gbl_irq_decode[]; -extern const char *acpi_gbl_lock_rule[]; -extern const char *acpi_gbl_access_types[]; -extern const char *acpi_gbl_update_rules[]; -extern const char *acpi_gbl_match_ops[]; - -extern struct acpi_dmtable_info acpi_dm_table_info_asf0[]; -extern struct acpi_dmtable_info acpi_dm_table_info_asf1[]; -extern struct acpi_dmtable_info acpi_dm_table_info_asf1a[]; -extern struct acpi_dmtable_info acpi_dm_table_info_asf2[]; -extern struct acpi_dmtable_info acpi_dm_table_info_asf2a[]; -extern struct acpi_dmtable_info acpi_dm_table_info_asf3[]; -extern struct acpi_dmtable_info acpi_dm_table_info_asf4[]; -extern struct acpi_dmtable_info acpi_dm_table_info_asf_hdr[]; -extern struct acpi_dmtable_info acpi_dm_table_info_boot[]; -extern struct acpi_dmtable_info acpi_dm_table_info_bert[]; -extern struct acpi_dmtable_info acpi_dm_table_info_cpep[]; -extern struct acpi_dmtable_info acpi_dm_table_info_cpep0[]; -extern struct acpi_dmtable_info acpi_dm_table_info_dbgp[]; -extern struct acpi_dmtable_info acpi_dm_table_info_dmar[]; -extern struct acpi_dmtable_info acpi_dm_table_info_dmar_hdr[]; -extern struct acpi_dmtable_info acpi_dm_table_info_dmar_scope[]; -extern struct acpi_dmtable_info acpi_dm_table_info_dmar0[]; -extern struct acpi_dmtable_info acpi_dm_table_info_dmar1[]; -extern struct acpi_dmtable_info acpi_dm_table_info_dmar2[]; -extern struct acpi_dmtable_info acpi_dm_table_info_ecdt[]; -extern struct acpi_dmtable_info acpi_dm_table_info_einj[]; -extern struct acpi_dmtable_info acpi_dm_table_info_einj0[]; -extern struct acpi_dmtable_info acpi_dm_table_info_erst[]; -extern struct acpi_dmtable_info acpi_dm_table_info_facs[]; -extern struct acpi_dmtable_info acpi_dm_table_info_fadt1[]; -extern struct acpi_dmtable_info acpi_dm_table_info_fadt2[]; -extern struct acpi_dmtable_info acpi_dm_table_info_gas[]; -extern struct acpi_dmtable_info acpi_dm_table_info_header[]; -extern struct acpi_dmtable_info acpi_dm_table_info_hest[]; -extern struct acpi_dmtable_info acpi_dm_table_info_hest9[]; -extern struct acpi_dmtable_info acpi_dm_table_info_hest_notify[]; -extern struct acpi_dmtable_info acpi_dm_table_info_hpet[]; -extern struct acpi_dmtable_info acpi_dm_table_info_madt[]; -extern struct acpi_dmtable_info acpi_dm_table_info_madt0[]; -extern struct acpi_dmtable_info acpi_dm_table_info_madt1[]; -extern struct acpi_dmtable_info acpi_dm_table_info_madt2[]; -extern struct acpi_dmtable_info acpi_dm_table_info_madt3[]; -extern struct acpi_dmtable_info acpi_dm_table_info_madt4[]; -extern struct acpi_dmtable_info acpi_dm_table_info_madt5[]; -extern struct acpi_dmtable_info acpi_dm_table_info_madt6[]; -extern struct acpi_dmtable_info acpi_dm_table_info_madt7[]; -extern struct acpi_dmtable_info acpi_dm_table_info_madt8[]; -extern struct acpi_dmtable_info acpi_dm_table_info_madt9[]; -extern struct acpi_dmtable_info acpi_dm_table_info_madt10[]; -extern struct acpi_dmtable_info acpi_dm_table_info_madt_hdr[]; -extern struct acpi_dmtable_info acpi_dm_table_info_mcfg[]; -extern struct acpi_dmtable_info acpi_dm_table_info_mcfg0[]; -extern struct acpi_dmtable_info acpi_dm_table_info_rsdp1[]; -extern struct acpi_dmtable_info acpi_dm_table_info_rsdp2[]; -extern struct acpi_dmtable_info acpi_dm_table_info_sbst[]; -extern struct acpi_dmtable_info acpi_dm_table_info_slic[]; -extern struct acpi_dmtable_info acpi_dm_table_info_slit[]; -extern struct acpi_dmtable_info acpi_dm_table_info_spcr[]; -extern struct acpi_dmtable_info acpi_dm_table_info_spmi[]; -extern struct acpi_dmtable_info acpi_dm_table_info_srat[]; -extern struct acpi_dmtable_info acpi_dm_table_info_srat_hdr[]; -extern struct acpi_dmtable_info acpi_dm_table_info_srat0[]; -extern struct acpi_dmtable_info acpi_dm_table_info_srat1[]; -extern struct acpi_dmtable_info acpi_dm_table_info_srat2[]; -extern struct acpi_dmtable_info acpi_dm_table_info_tcpa[]; -extern struct acpi_dmtable_info acpi_dm_table_info_wdrt[]; - -/* - * dmtable - */ -void acpi_dm_dump_data_table(struct acpi_table_header *table); - -acpi_status -acpi_dm_dump_table(u32 table_length, - u32 table_offset, - void *table, - u32 sub_table_length, struct acpi_dmtable_info *info); - -void acpi_dm_line_header(u32 offset, u32 byte_length, char *name); - -void acpi_dm_line_header2(u32 offset, u32 byte_length, char *name, u32 value); - -/* - * dmtbdump - */ -void acpi_dm_dump_asf(struct acpi_table_header *table); - -void acpi_dm_dump_cpep(struct acpi_table_header *table); - -void acpi_dm_dump_dmar(struct acpi_table_header *table); - -void acpi_dm_dump_einj(struct acpi_table_header *table); - -void acpi_dm_dump_erst(struct acpi_table_header *table); - -void acpi_dm_dump_fadt(struct acpi_table_header *table); - -void acpi_dm_dump_hest(struct acpi_table_header *table); - -void acpi_dm_dump_mcfg(struct acpi_table_header *table); - -void acpi_dm_dump_madt(struct acpi_table_header *table); - -u32 acpi_dm_dump_rsdp(struct acpi_table_header *table); - -void acpi_dm_dump_rsdt(struct acpi_table_header *table); - -void acpi_dm_dump_slit(struct acpi_table_header *table); - -void acpi_dm_dump_srat(struct acpi_table_header *table); - -void acpi_dm_dump_xsdt(struct acpi_table_header *table); - -/* - * dmwalk - */ -void -acpi_dm_disassemble(struct acpi_walk_state *walk_state, - union acpi_parse_object *origin, u32 num_opcodes); - -void -acpi_dm_walk_parse_tree(union acpi_parse_object *op, - asl_walk_callback descending_callback, - asl_walk_callback ascending_callback, void *context); - -/* - * dmopcode - */ -void -acpi_dm_disassemble_one_op(struct acpi_walk_state *walk_state, - struct acpi_op_walk_info *info, - union acpi_parse_object *op); - -void acpi_dm_decode_internal_object(union acpi_operand_object *obj_desc); - -u32 acpi_dm_list_type(union acpi_parse_object *op); - -void acpi_dm_method_flags(union acpi_parse_object *op); - -void acpi_dm_field_flags(union acpi_parse_object *op); - -void acpi_dm_address_space(u8 space_id); - -void acpi_dm_region_flags(union acpi_parse_object *op); - -void acpi_dm_match_op(union acpi_parse_object *op); - -u8 acpi_dm_comma_if_list_member(union acpi_parse_object *op); - -void acpi_dm_comma_if_field_member(union acpi_parse_object *op); - -/* - * dmnames - */ -u32 acpi_dm_dump_name(char *name); - -acpi_status -acpi_ps_display_object_pathname(struct acpi_walk_state *walk_state, - union acpi_parse_object *op); - -void acpi_dm_namestring(char *name); - -/* - * dmobject - */ -void -acpi_dm_display_internal_object(union acpi_operand_object *obj_desc, - struct acpi_walk_state *walk_state); - -void acpi_dm_display_arguments(struct acpi_walk_state *walk_state); - -void acpi_dm_display_locals(struct acpi_walk_state *walk_state); - -void -acpi_dm_dump_method_info(acpi_status status, - struct acpi_walk_state *walk_state, - union acpi_parse_object *op); - -/* - * dmbuffer - */ -void acpi_dm_disasm_byte_list(u32 level, u8 * byte_data, u32 byte_count); - -void -acpi_dm_byte_list(struct acpi_op_walk_info *info, union acpi_parse_object *op); - -void acpi_dm_is_eisa_id(union acpi_parse_object *op); - -void acpi_dm_eisa_id(u32 encoded_id); - -u8 acpi_dm_is_unicode_buffer(union acpi_parse_object *op); - -u8 acpi_dm_is_string_buffer(union acpi_parse_object *op); - -/* - * dmresrc - */ -void acpi_dm_dump_integer8(u8 value, char *name); - -void acpi_dm_dump_integer16(u16 value, char *name); - -void acpi_dm_dump_integer32(u32 value, char *name); - -void acpi_dm_dump_integer64(u64 value, char *name); - -void -acpi_dm_resource_template(struct acpi_op_walk_info *info, - union acpi_parse_object *op, - u8 * byte_data, u32 byte_count); - -acpi_status acpi_dm_is_resource_template(union acpi_parse_object *op); - -void acpi_dm_indent(u32 level); - -void acpi_dm_bit_list(u16 mask); - -void acpi_dm_decode_attribute(u8 attribute); - -void acpi_dm_descriptor_name(void); - -/* - * dmresrcl - */ -void -acpi_dm_word_descriptor(union aml_resource *resource, u32 length, u32 level); - -void -acpi_dm_dword_descriptor(union aml_resource *resource, u32 length, u32 level); - -void -acpi_dm_extended_descriptor(union aml_resource *resource, - u32 length, u32 level); - -void -acpi_dm_qword_descriptor(union aml_resource *resource, u32 length, u32 level); - -void -acpi_dm_memory24_descriptor(union aml_resource *resource, - u32 length, u32 level); - -void -acpi_dm_memory32_descriptor(union aml_resource *resource, - u32 length, u32 level); - -void -acpi_dm_fixed_memory32_descriptor(union aml_resource *resource, - u32 length, u32 level); - -void -acpi_dm_generic_register_descriptor(union aml_resource *resource, - u32 length, u32 level); - -void -acpi_dm_interrupt_descriptor(union aml_resource *resource, - u32 length, u32 level); - -void -acpi_dm_vendor_large_descriptor(union aml_resource *resource, - u32 length, u32 level); - -void acpi_dm_vendor_common(char *name, u8 * byte_data, u32 length, u32 level); - -/* - * dmresrcs - */ -void -acpi_dm_irq_descriptor(union aml_resource *resource, u32 length, u32 level); - -void -acpi_dm_dma_descriptor(union aml_resource *resource, u32 length, u32 level); - -void acpi_dm_io_descriptor(union aml_resource *resource, u32 length, u32 level); - -void -acpi_dm_fixed_io_descriptor(union aml_resource *resource, - u32 length, u32 level); - -void -acpi_dm_start_dependent_descriptor(union aml_resource *resource, - u32 length, u32 level); - -void -acpi_dm_end_dependent_descriptor(union aml_resource *resource, - u32 length, u32 level); - -void -acpi_dm_vendor_small_descriptor(union aml_resource *resource, - u32 length, u32 level); - -/* - * dmutils - */ -void acpi_dm_add_to_external_list(char *path, u8 type, u32 value); - -/* - * dmrestag - */ -void acpi_dm_find_resources(union acpi_parse_object *root); - -void -acpi_dm_check_resource_reference(union acpi_parse_object *op, - struct acpi_walk_state *walk_state); - -#endif /* __ACDISASM_H__ */ diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h index 84f5cb242863..eda04546cdf6 100644 --- a/include/acpi/acexcep.h +++ b/include/acpi/acexcep.h @@ -153,8 +153,9 @@ #define AE_AML_CIRCULAR_REFERENCE (acpi_status) (0x001E | AE_CODE_AML) #define AE_AML_BAD_RESOURCE_LENGTH (acpi_status) (0x001F | AE_CODE_AML) #define AE_AML_ILLEGAL_ADDRESS (acpi_status) (0x0020 | AE_CODE_AML) +#define AE_AML_INFINITE_LOOP (acpi_status) (0x0021 | AE_CODE_AML) -#define AE_CODE_AML_MAX 0x0020 +#define AE_CODE_AML_MAX 0x0021 /* * Internal exceptions used for control @@ -175,6 +176,8 @@ #define AE_CODE_CTRL_MAX 0x000D +/* Exception strings for acpi_format_exception */ + #ifdef DEFINE_ACPI_GLOBALS /* @@ -267,6 +270,7 @@ char const *acpi_gbl_exception_names_aml[] = { "AE_AML_CIRCULAR_REFERENCE", "AE_AML_BAD_RESOURCE_LENGTH", "AE_AML_ILLEGAL_ADDRESS", + "AE_AML_INFINITE_LOOP" }; char const *acpi_gbl_exception_names_ctrl[] = { diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index db8852d8bcf7..5c823d5ab783 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -45,9 +45,9 @@ #define __ACOUTPUT_H__ /* - * Debug levels and component IDs. These are used to control the - * granularity of the output of the DEBUG_PRINT macro -- on a per- - * component basis and a per-exception-type basis. + * Debug levels and component IDs. These are used to control the + * granularity of the output of the ACPI_DEBUG_PRINT macro -- on a + * per-component basis and a per-exception-type basis. */ /* Component IDs are used in the global "DebugLayer" */ @@ -69,8 +69,10 @@ #define ACPI_COMPILER 0x00001000 #define ACPI_TOOLS 0x00002000 +#define ACPI_EXAMPLE 0x00004000 +#define ACPI_DRIVER 0x00008000 -#define ACPI_ALL_COMPONENTS 0x00003FFF +#define ACPI_ALL_COMPONENTS 0x0000FFFF #define ACPI_COMPONENT_DEFAULT (ACPI_ALL_COMPONENTS) /* Component IDs reserved for ACPI drivers */ @@ -78,7 +80,7 @@ #define ACPI_ALL_DRIVERS 0xFFFF0000 /* - * Raw debug output levels, do not use these in the DEBUG_PRINT macros + * Raw debug output levels, do not use these in the ACPI_DEBUG_PRINT macros */ #define ACPI_LV_INIT 0x00000001 #define ACPI_LV_DEBUG_OBJECT 0x00000002 @@ -176,4 +178,95 @@ #define ACPI_NORMAL_DEFAULT (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT) #define ACPI_DEBUG_ALL (ACPI_LV_AML_DISASSEMBLE | ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_ALL) +#if defined (ACPI_DEBUG_OUTPUT) || !defined (ACPI_NO_ERROR_MESSAGES) +/* + * Module name is included in both debug and non-debug versions primarily for + * error messages. The __FILE__ macro is not very useful for this, because it + * often includes the entire pathname to the module + */ +#define ACPI_MODULE_NAME(name) static const char ACPI_UNUSED_VAR _acpi_module_name[] = name; +#else +#define ACPI_MODULE_NAME(name) +#endif + +/* + * Ascii error messages can be configured out + */ +#ifndef ACPI_NO_ERROR_MESSAGES +#define AE_INFO _acpi_module_name, __LINE__ + +/* + * Error reporting. Callers module and line number are inserted by AE_INFO, + * the plist contains a set of parens to allow variable-length lists. + * These macros are used for both the debug and non-debug versions of the code. + */ +#define ACPI_INFO(plist) acpi_info plist +#define ACPI_WARNING(plist) acpi_warning plist +#define ACPI_EXCEPTION(plist) acpi_exception plist +#define ACPI_ERROR(plist) acpi_error plist + +#else + +/* No error messages */ + +#define ACPI_INFO(plist) +#define ACPI_WARNING(plist) +#define ACPI_EXCEPTION(plist) +#define ACPI_ERROR(plist) + +#endif /* ACPI_NO_ERROR_MESSAGES */ + +/* + * Debug macros that are conditionally compiled + */ +#ifdef ACPI_DEBUG_OUTPUT + +/* + * If ACPI_GET_FUNCTION_NAME was not defined in the compiler-dependent header, + * define it now. This is the case where there the compiler does not support + * a __FUNCTION__ macro or equivalent. + */ +#ifndef ACPI_GET_FUNCTION_NAME +#define ACPI_GET_FUNCTION_NAME _acpi_function_name + +/* + * The Name parameter should be the procedure name as a quoted string. + * The function name is also used by the function exit macros below. + * Note: (const char) is used to be compatible with the debug interfaces + * and macros such as __FUNCTION__. + */ +#define ACPI_FUNCTION_NAME(name) static const char _acpi_function_name[] = #name; + +#else +/* Compiler supports __FUNCTION__ (or equivalent) -- Ignore this macro */ + +#define ACPI_FUNCTION_NAME(name) +#endif /* ACPI_GET_FUNCTION_NAME */ + +/* + * Common parameters used for debug output functions: + * line number, function name, module(file) name, component ID + */ +#define ACPI_DEBUG_PARAMETERS __LINE__, ACPI_GET_FUNCTION_NAME, _acpi_module_name, _COMPONENT + +/* + * Master debug print macros + * Print message if and only if: + * 1) Debug print for the current component is enabled + * 2) Debug error level or trace level for the print statement is enabled + */ +#define ACPI_DEBUG_PRINT(plist) acpi_debug_print plist +#define ACPI_DEBUG_PRINT_RAW(plist) acpi_debug_print_raw plist + +#else +/* + * This is the non-debug case -- make everything go away, + * leaving no executable debug code! + */ +#define ACPI_FUNCTION_NAME(a) +#define ACPI_DEBUG_PRINT(pl) +#define ACPI_DEBUG_PRINT_RAW(pl) + +#endif /* ACPI_DEBUG_OUTPUT */ + #endif /* __ACOUTPUT_H__ */ diff --git a/include/acpi/acpi.h b/include/acpi/acpi.h index c515ef6cc89e..472b7bf0c5d4 100644 --- a/include/acpi/acpi.h +++ b/include/acpi/acpi.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Name: acpi.h - Master include file, Publics and external data. + * Name: acpi.h - Master public include file used to interface to ACPICA * *****************************************************************************/ @@ -45,25 +45,22 @@ #define __ACPI_H__ /* - * Common includes for all ACPI driver files - * We put them here because we don't want to duplicate them - * in the rest of the source code again and again. + * Public include files for use by code that will interface to ACPICA. + * + * Information includes the ACPICA data types, names, exceptions, and + * external interface prototypes. Also included are the definitions for + * all ACPI tables (FADT, MADT, etc.) + * + * Note: The order of these include files is important. */ -#include "acnames.h" /* Global ACPI names and strings */ -#include "acconfig.h" /* Configuration constants */ -#include "platform/acenv.h" /* Target environment specific items */ -#include "actypes.h" /* Fundamental common data types */ -#include "acexcep.h" /* ACPI exception codes */ -#include "acmacros.h" /* C macros */ +#include "platform/acenv.h" /* Environment-specific items */ +#include "acnames.h" /* Common ACPI names and strings */ +#include "actypes.h" /* ACPICA data types and structures */ +#include "acexcep.h" /* ACPICA exceptions */ #include "actbl.h" /* ACPI table definitions */ -#include "aclocal.h" /* Internal data types */ #include "acoutput.h" /* Error output and Debug macros */ -#include "acpiosxf.h" /* Interfaces to the ACPI-to-OS layer */ +#include "acrestyp.h" /* Resource Descriptor structs */ +#include "acpiosxf.h" /* OSL interfaces (ACPICA-to-OS) */ #include "acpixf.h" /* ACPI core subsystem external interfaces */ -#include "acobject.h" /* ACPI internal object */ -#include "acstruct.h" /* Common structures */ -#include "acglobal.h" /* All global variables */ -#include "achware.h" /* Hardware defines and interfaces */ -#include "acutils.h" /* Utility interfaces */ #endif /* __ACPI_H__ */ diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index b91440ac0d16..a62720a7edc0 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -121,8 +121,11 @@ acpi_os_wait_semaphore(acpi_semaphore handle, u32 units, u16 timeout); acpi_status acpi_os_signal_semaphore(acpi_semaphore handle, u32 units); /* - * Mutex primitives + * Mutex primitives. May be configured to use semaphores instead via + * ACPI_MUTEX_TYPE (see platform/acenv.h) */ +#if (ACPI_MUTEX_TYPE != ACPI_BINARY_SEMAPHORE) + acpi_status acpi_os_create_mutex(acpi_mutex * out_handle); void acpi_os_delete_mutex(acpi_mutex handle); @@ -130,13 +133,7 @@ void acpi_os_delete_mutex(acpi_mutex handle); acpi_status acpi_os_acquire_mutex(acpi_mutex handle, u16 timeout); void acpi_os_release_mutex(acpi_mutex handle); - -/* Temporary macros for Mutex* interfaces, map to existing semaphore xfaces */ - -#define acpi_os_create_mutex(out_handle) acpi_os_create_semaphore (1, 1, out_handle) -#define acpi_os_delete_mutex(handle) (void) acpi_os_delete_semaphore (handle) -#define acpi_os_acquire_mutex(handle,time) acpi_os_wait_semaphore (handle, 1, time) -#define acpi_os_release_mutex(handle) (void) acpi_os_signal_semaphore (handle, 1) +#endif /* * Memory allocation and mapping diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 33bc0e3b1954..c8e8cf45830f 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -45,9 +45,32 @@ #ifndef __ACXFACE_H__ #define __ACXFACE_H__ +/* Current ACPICA subsystem version in YYYYMMDD format */ + +#define ACPI_CA_VERSION 0x20081204 + #include "actypes.h" #include "actbl.h" +extern u8 acpi_gbl_permanent_mmap; + +/* + * Globals that are publically available, allowing for + * run time configuration + */ +extern u32 acpi_dbg_level; +extern u32 acpi_dbg_layer; +extern u8 acpi_gbl_enable_interpreter_slack; +extern u8 acpi_gbl_all_methods_serialized; +extern u8 acpi_gbl_create_osi_method; +extern u8 acpi_gbl_leave_wake_gpes_disabled; +extern acpi_name acpi_gbl_trace_method_name; +extern u32 acpi_gbl_trace_flags; + +extern u32 acpi_current_gpe_count; +extern struct acpi_table_fadt acpi_gbl_FADT; + +extern u32 acpi_rsdt_forced; /* * Global interfaces */ @@ -79,11 +102,6 @@ const char *acpi_format_exception(acpi_status exception); acpi_status acpi_purge_cached_objects(void); -#ifdef ACPI_FUTURE_USAGE -acpi_status -acpi_install_initialization_handler(acpi_init_handler handler, u32 function); -#endif - /* * ACPI Memory management */ @@ -193,9 +211,12 @@ acpi_status acpi_get_id(acpi_handle object, acpi_owner_id * out_type); acpi_status acpi_get_parent(acpi_handle object, acpi_handle * out_handle); /* - * Event handler interfaces + * Handler interfaces */ acpi_status +acpi_install_initialization_handler(acpi_init_handler handler, u32 function); + +acpi_status acpi_install_fixed_event_handler(u32 acpi_event, acpi_event_handler handler, void *context); @@ -227,6 +248,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device, u32 gpe_number, u32 type, acpi_event_handler address, void *context); +acpi_status +acpi_remove_gpe_handler(acpi_handle gpe_device, + u32 gpe_number, acpi_event_handler address); + #ifdef ACPI_FUTURE_USAGE acpi_status acpi_install_exception_handler(acpi_exception_handler handler); #endif @@ -238,10 +263,6 @@ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle); acpi_status acpi_release_global_lock(u32 handle); -acpi_status -acpi_remove_gpe_handler(acpi_handle gpe_device, - u32 gpe_number, acpi_event_handler address); - acpi_status acpi_enable_event(u32 event, u32 flags); acpi_status acpi_disable_event(u32 event, u32 flags); @@ -250,6 +271,9 @@ acpi_status acpi_clear_event(u32 event); acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status); +/* + * GPE Interfaces + */ acpi_status acpi_set_gpe_type(acpi_handle gpe_device, u32 gpe_number, u8 type); acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number); @@ -263,6 +287,12 @@ acpi_get_gpe_status(acpi_handle gpe_device, u32 gpe_number, u32 flags, acpi_event_status * event_status); +acpi_status acpi_disable_all_gpes(void); + +acpi_status acpi_enable_all_runtime_gpes(void); + +acpi_status acpi_get_gpe_device(u32 gpe_index, acpi_handle *gpe_device); + acpi_status acpi_install_gpe_block(acpi_handle gpe_device, struct acpi_generic_address *gpe_block_address, @@ -313,6 +343,8 @@ acpi_resource_to_address64(struct acpi_resource *resource, /* * Hardware (ACPI device) interfaces */ +acpi_status acpi_reset(void); + acpi_status acpi_get_register(u32 register_id, u32 * return_value); acpi_status acpi_get_register_unlocked(u32 register_id, u32 *return_value); @@ -320,12 +352,14 @@ acpi_status acpi_get_register_unlocked(u32 register_id, u32 *return_value); acpi_status acpi_set_register(u32 register_id, u32 value); acpi_status -acpi_set_firmware_waking_vector(acpi_physical_address physical_address); +acpi_set_firmware_waking_vector(u32 physical_address); -#ifdef ACPI_FUTURE_USAGE acpi_status -acpi_get_firmware_waking_vector(acpi_physical_address * physical_address); -#endif +acpi_set_firmware_waking_vector64(u64 physical_address); + +acpi_status acpi_read(u32 *value, struct acpi_generic_address *reg); + +acpi_status acpi_write(u32 value, struct acpi_generic_address *reg); acpi_status acpi_get_sleep_type_data(u8 sleep_state, u8 * slp_typ_a, u8 * slp_typ_b); @@ -340,4 +374,42 @@ acpi_status acpi_leave_sleep_state_prep(u8 sleep_state); acpi_status acpi_leave_sleep_state(u8 sleep_state); +/* + * Debug output + */ +void ACPI_INTERNAL_VAR_XFACE +acpi_error(const char *module_name, + u32 line_number, const char *format, ...) ACPI_PRINTF_LIKE(3); + +void ACPI_INTERNAL_VAR_XFACE +acpi_exception(const char *module_name, + u32 line_number, + acpi_status status, const char *format, ...) ACPI_PRINTF_LIKE(4); + +void ACPI_INTERNAL_VAR_XFACE +acpi_warning(const char *module_name, + u32 line_number, const char *format, ...) ACPI_PRINTF_LIKE(3); + +void ACPI_INTERNAL_VAR_XFACE +acpi_info(const char *module_name, + u32 line_number, const char *format, ...) ACPI_PRINTF_LIKE(3); + +#ifdef ACPI_DEBUG_OUTPUT + +void ACPI_INTERNAL_VAR_XFACE +acpi_debug_print(u32 requested_debug_level, + u32 line_number, + const char *function_name, + const char *module_name, + u32 component_id, const char *format, ...) ACPI_PRINTF_LIKE(6); + +void ACPI_INTERNAL_VAR_XFACE +acpi_debug_print_raw(u32 requested_debug_level, + u32 line_number, + const char *function_name, + const char *module_name, + u32 component_id, + const char *format, ...) ACPI_PRINTF_LIKE(6); +#endif + #endif /* __ACXFACE_H__ */ diff --git a/include/acpi/acrestyp.h b/include/acpi/acrestyp.h new file mode 100644 index 000000000000..9ffe00feada6 --- /dev/null +++ b/include/acpi/acrestyp.h @@ -0,0 +1,405 @@ +/****************************************************************************** + * + * Name: acrestyp.h - Defines, types, and structures for resource descriptors + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, 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. + */ + +#ifndef __ACRESTYP_H__ +#define __ACRESTYP_H__ + +/* + * Definitions for Resource Attributes + */ +typedef u16 acpi_rs_length; /* Resource Length field is fixed at 16 bits */ +typedef u32 acpi_rsdesc_size; /* Max Resource Descriptor size is (Length+3) = (64_k-1)+3 */ + +/* + * Memory Attributes + */ +#define ACPI_READ_ONLY_MEMORY (u8) 0x00 +#define ACPI_READ_WRITE_MEMORY (u8) 0x01 + +#define ACPI_NON_CACHEABLE_MEMORY (u8) 0x00 +#define ACPI_CACHABLE_MEMORY (u8) 0x01 +#define ACPI_WRITE_COMBINING_MEMORY (u8) 0x02 +#define ACPI_PREFETCHABLE_MEMORY (u8) 0x03 + +/* + * IO Attributes + * The ISA IO ranges are: n000-n0_fFh, n400-n4_fFh, n800-n8_fFh, n_c00-n_cFFh. + * The non-ISA IO ranges are: n100-n3_fFh, n500-n7_fFh, n900-n_bFFh, n_cd0-n_fFFh. + */ +#define ACPI_NON_ISA_ONLY_RANGES (u8) 0x01 +#define ACPI_ISA_ONLY_RANGES (u8) 0x02 +#define ACPI_ENTIRE_RANGE (ACPI_NON_ISA_ONLY_RANGES | ACPI_ISA_ONLY_RANGES) + +/* Type of translation - 1=Sparse, 0=Dense */ + +#define ACPI_SPARSE_TRANSLATION (u8) 0x01 + +/* + * IO Port Descriptor Decode + */ +#define ACPI_DECODE_10 (u8) 0x00 /* 10-bit IO address decode */ +#define ACPI_DECODE_16 (u8) 0x01 /* 16-bit IO address decode */ + +/* + * IRQ Attributes + */ +#define ACPI_LEVEL_SENSITIVE (u8) 0x00 +#define ACPI_EDGE_SENSITIVE (u8) 0x01 + +#define ACPI_ACTIVE_HIGH (u8) 0x00 +#define ACPI_ACTIVE_LOW (u8) 0x01 + +#define ACPI_EXCLUSIVE (u8) 0x00 +#define ACPI_SHARED (u8) 0x01 + +/* + * DMA Attributes + */ +#define ACPI_COMPATIBILITY (u8) 0x00 +#define ACPI_TYPE_A (u8) 0x01 +#define ACPI_TYPE_B (u8) 0x02 +#define ACPI_TYPE_F (u8) 0x03 + +#define ACPI_NOT_BUS_MASTER (u8) 0x00 +#define ACPI_BUS_MASTER (u8) 0x01 + +#define ACPI_TRANSFER_8 (u8) 0x00 +#define ACPI_TRANSFER_8_16 (u8) 0x01 +#define ACPI_TRANSFER_16 (u8) 0x02 + +/* + * Start Dependent Functions Priority definitions + */ +#define ACPI_GOOD_CONFIGURATION (u8) 0x00 +#define ACPI_ACCEPTABLE_CONFIGURATION (u8) 0x01 +#define ACPI_SUB_OPTIMAL_CONFIGURATION (u8) 0x02 + +/* + * 16, 32 and 64-bit Address Descriptor resource types + */ +#define ACPI_MEMORY_RANGE (u8) 0x00 +#define ACPI_IO_RANGE (u8) 0x01 +#define ACPI_BUS_NUMBER_RANGE (u8) 0x02 + +#define ACPI_ADDRESS_NOT_FIXED (u8) 0x00 +#define ACPI_ADDRESS_FIXED (u8) 0x01 + +#define ACPI_POS_DECODE (u8) 0x00 +#define ACPI_SUB_DECODE (u8) 0x01 + +#define ACPI_PRODUCER (u8) 0x00 +#define ACPI_CONSUMER (u8) 0x01 + +/* + * If possible, pack the following structures to byte alignment + */ +#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED +#pragma pack(1) +#endif + +/* UUID data structures for use in vendor-defined resource descriptors */ + +struct acpi_uuid { + u8 data[ACPI_UUID_LENGTH]; +}; + +struct acpi_vendor_uuid { + u8 subtype; + u8 data[ACPI_UUID_LENGTH]; +}; + +/* + * Structures used to describe device resources + */ +struct acpi_resource_irq { + u8 descriptor_length; + u8 triggering; + u8 polarity; + u8 sharable; + u8 interrupt_count; + u8 interrupts[1]; +}; + +struct acpi_resource_dma { + u8 type; + u8 bus_master; + u8 transfer; + u8 channel_count; + u8 channels[1]; +}; + +struct acpi_resource_start_dependent { + u8 descriptor_length; + u8 compatibility_priority; + u8 performance_robustness; +}; + +/* + * The END_DEPENDENT_FUNCTIONS_RESOURCE struct is not + * needed because it has no fields + */ + +struct acpi_resource_io { + u8 io_decode; + u8 alignment; + u8 address_length; + u16 minimum; + u16 maximum; +}; + +struct acpi_resource_fixed_io { + u16 address; + u8 address_length; +}; + +struct acpi_resource_vendor { + u16 byte_length; + u8 byte_data[1]; +}; + +/* Vendor resource with UUID info (introduced in ACPI 3.0) */ + +struct acpi_resource_vendor_typed { + u16 byte_length; + u8 uuid_subtype; + u8 uuid[ACPI_UUID_LENGTH]; + u8 byte_data[1]; +}; + +struct acpi_resource_end_tag { + u8 checksum; +}; + +struct acpi_resource_memory24 { + u8 write_protect; + u16 minimum; + u16 maximum; + u16 alignment; + u16 address_length; +}; + +struct acpi_resource_memory32 { + u8 write_protect; + u32 minimum; + u32 maximum; + u32 alignment; + u32 address_length; +}; + +struct acpi_resource_fixed_memory32 { + u8 write_protect; + u32 address; + u32 address_length; +}; + +struct acpi_memory_attribute { + u8 write_protect; + u8 caching; + u8 range_type; + u8 translation; +}; + +struct acpi_io_attribute { + u8 range_type; + u8 translation; + u8 translation_type; + u8 reserved1; +}; + +union acpi_resource_attribute { + struct acpi_memory_attribute mem; + struct acpi_io_attribute io; + + /* Used for the *word_space macros */ + + u8 type_specific; +}; + +struct acpi_resource_source { + u8 index; + u16 string_length; + char *string_ptr; +}; + +/* Fields common to all address descriptors, 16/32/64 bit */ + +#define ACPI_RESOURCE_ADDRESS_COMMON \ + u8 resource_type; \ + u8 producer_consumer; \ + u8 decode; \ + u8 min_address_fixed; \ + u8 max_address_fixed; \ + union acpi_resource_attribute info; + +struct acpi_resource_address { +ACPI_RESOURCE_ADDRESS_COMMON}; + +struct acpi_resource_address16 { + ACPI_RESOURCE_ADDRESS_COMMON u16 granularity; + u16 minimum; + u16 maximum; + u16 translation_offset; + u16 address_length; + struct acpi_resource_source resource_source; +}; + +struct acpi_resource_address32 { + ACPI_RESOURCE_ADDRESS_COMMON u32 granularity; + u32 minimum; + u32 maximum; + u32 translation_offset; + u32 address_length; + struct acpi_resource_source resource_source; +}; + +struct acpi_resource_address64 { + ACPI_RESOURCE_ADDRESS_COMMON u64 granularity; + u64 minimum; + u64 maximum; + u64 translation_offset; + u64 address_length; + struct acpi_resource_source resource_source; +}; + +struct acpi_resource_extended_address64 { + ACPI_RESOURCE_ADDRESS_COMMON u8 revision_iD; + u64 granularity; + u64 minimum; + u64 maximum; + u64 translation_offset; + u64 address_length; + u64 type_specific; +}; + +struct acpi_resource_extended_irq { + u8 producer_consumer; + u8 triggering; + u8 polarity; + u8 sharable; + u8 interrupt_count; + struct acpi_resource_source resource_source; + u32 interrupts[1]; +}; + +struct acpi_resource_generic_register { + u8 space_id; + u8 bit_width; + u8 bit_offset; + u8 access_size; + u64 address; +}; + +/* ACPI_RESOURCE_TYPEs */ + +#define ACPI_RESOURCE_TYPE_IRQ 0 +#define ACPI_RESOURCE_TYPE_DMA 1 +#define ACPI_RESOURCE_TYPE_START_DEPENDENT 2 +#define ACPI_RESOURCE_TYPE_END_DEPENDENT 3 +#define ACPI_RESOURCE_TYPE_IO 4 +#define ACPI_RESOURCE_TYPE_FIXED_IO 5 +#define ACPI_RESOURCE_TYPE_VENDOR 6 +#define ACPI_RESOURCE_TYPE_END_TAG 7 +#define ACPI_RESOURCE_TYPE_MEMORY24 8 +#define ACPI_RESOURCE_TYPE_MEMORY32 9 +#define ACPI_RESOURCE_TYPE_FIXED_MEMORY32 10 +#define ACPI_RESOURCE_TYPE_ADDRESS16 11 +#define ACPI_RESOURCE_TYPE_ADDRESS32 12 +#define ACPI_RESOURCE_TYPE_ADDRESS64 13 +#define ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 14 /* ACPI 3.0 */ +#define ACPI_RESOURCE_TYPE_EXTENDED_IRQ 15 +#define ACPI_RESOURCE_TYPE_GENERIC_REGISTER 16 +#define ACPI_RESOURCE_TYPE_MAX 16 + +/* Master union for resource descriptors */ + +union acpi_resource_data { + struct acpi_resource_irq irq; + struct acpi_resource_dma dma; + struct acpi_resource_start_dependent start_dpf; + struct acpi_resource_io io; + struct acpi_resource_fixed_io fixed_io; + struct acpi_resource_vendor vendor; + struct acpi_resource_vendor_typed vendor_typed; + struct acpi_resource_end_tag end_tag; + struct acpi_resource_memory24 memory24; + struct acpi_resource_memory32 memory32; + struct acpi_resource_fixed_memory32 fixed_memory32; + struct acpi_resource_address16 address16; + struct acpi_resource_address32 address32; + struct acpi_resource_address64 address64; + struct acpi_resource_extended_address64 ext_address64; + struct acpi_resource_extended_irq extended_irq; + struct acpi_resource_generic_register generic_reg; + + /* Common fields */ + + struct acpi_resource_address address; /* Common 16/32/64 address fields */ +}; + +/* Common resource header */ + +struct acpi_resource { + u32 type; + u32 length; + union acpi_resource_data data; +}; + +/* restore default alignment */ + +#pragma pack() + +#define ACPI_RS_SIZE_NO_DATA 8 /* Id + Length fields */ +#define ACPI_RS_SIZE_MIN (u32) ACPI_ROUND_UP_TO_NATIVE_WORD (12) +#define ACPI_RS_SIZE(type) (u32) (ACPI_RS_SIZE_NO_DATA + sizeof (type)) + +#define ACPI_NEXT_RESOURCE(res) (struct acpi_resource *)((u8 *) res + res->length) + +struct acpi_pci_routing_table { + u32 length; + u32 pin; + acpi_integer address; /* here for 64-bit alignment */ + u32 source_index; + char source[4]; /* pad to 64 bits so sizeof() works in all cases */ +}; + +#endif /* __ACRESTYP_H__ */ diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index 13a3d9ad92db..813e4b6c2c0d 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -288,6 +288,31 @@ enum acpi_prefered_pm_profiles { #define ACPI_FADT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_fadt, f) +union acpi_name_union { + u32 integer; + char ascii[4]; +}; + +/* + * Internal ACPI Table Descriptor. One per ACPI table + */ +struct acpi_table_desc { + acpi_physical_address address; + struct acpi_table_header *pointer; + u32 length; /* Length fixed at 32 bits */ + union acpi_name_union signature; + acpi_owner_id owner_id; + u8 flags; +}; + +/* Flags for above */ + +#define ACPI_TABLE_ORIGIN_UNKNOWN (0) +#define ACPI_TABLE_ORIGIN_MAPPED (1) +#define ACPI_TABLE_ORIGIN_ALLOCATED (2) +#define ACPI_TABLE_ORIGIN_MASK (3) +#define ACPI_TABLE_IS_LOADED (4) + /* * Get the remaining ACPI tables */ diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index 63f5b4cf4de1..18963b968114 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -627,7 +627,7 @@ struct acpi_hest_aer_common { u32 uncorrectable_error_mask; u32 uncorrectable_error_severity; u32 correctable_error_mask; - u32 advanced_error_cababilities; + u32 advanced_error_capabilities; }; /* Hardware Error Notification */ diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 8222e8de0d1c..a20aab510173 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -204,11 +204,10 @@ typedef u32 acpi_physical_address; /******************************************************************************* * - * OS-dependent and compiler-dependent types + * OS-dependent types * * If the defaults below are not appropriate for the host system, they can - * be defined in the compiler-specific or OS-specific header, and this will - * take precedence. + * be defined in the OS-specific header, and this will take precedence. * ******************************************************************************/ @@ -218,12 +217,6 @@ typedef u32 acpi_physical_address; #define acpi_thread_id acpi_size #endif -/* Object returned from acpi_os_create_lock */ - -#ifndef acpi_spinlock -#define acpi_spinlock void * -#endif - /* Flags for acpi_os_acquire_lock/acpi_os_release_lock */ #ifndef acpi_cpu_flags @@ -233,9 +226,51 @@ typedef u32 acpi_physical_address; /* Object returned from acpi_os_create_cache */ #ifndef acpi_cache_t +#ifdef ACPI_USE_LOCAL_CACHE #define acpi_cache_t struct acpi_memory_list +#else +#define acpi_cache_t void * +#endif +#endif + +/* + * Synchronization objects - Mutexes, Semaphores, and spin_locks + */ +#if (ACPI_MUTEX_TYPE == ACPI_BINARY_SEMAPHORE) +/* + * These macros are used if the host OS does not support a mutex object. + * Map the OSL Mutex interfaces to binary semaphores. + */ +#define acpi_mutex acpi_semaphore +#define acpi_os_create_mutex(out_handle) acpi_os_create_semaphore (1, 1, out_handle) +#define acpi_os_delete_mutex(handle) (void) acpi_os_delete_semaphore (handle) +#define acpi_os_acquire_mutex(handle,time) acpi_os_wait_semaphore (handle, 1, time) +#define acpi_os_release_mutex(handle) (void) acpi_os_signal_semaphore (handle, 1) +#endif + +/* Configurable types for synchronization objects */ + +#ifndef acpi_spinlock +#define acpi_spinlock void * +#endif + +#ifndef acpi_semaphore +#define acpi_semaphore void * +#endif + +#ifndef acpi_mutex +#define acpi_mutex void * #endif +/******************************************************************************* + * + * Compiler-dependent types + * + * If the defaults below are not appropriate for the host compiler, they can + * be defined in the compiler-specific header, and this will take precedence. + * + ******************************************************************************/ + /* Use C99 uintptr_t for pointer casting if available, "void *" otherwise */ #ifndef acpi_uintptr_t @@ -268,6 +303,43 @@ typedef u32 acpi_physical_address; #define ACPI_EXPORT_SYMBOL(symbol) #endif +/****************************************************************************** + * + * ACPI Specification constants (Do not change unless the specification changes) + * + *****************************************************************************/ + +/* Number of distinct FADT-based GPE register blocks (GPE0 and GPE1) */ + +#define ACPI_MAX_GPE_BLOCKS 2 + +/* Default ACPI register widths */ + +#define ACPI_GPE_REGISTER_WIDTH 8 +#define ACPI_PM1_REGISTER_WIDTH 16 +#define ACPI_PM2_REGISTER_WIDTH 8 +#define ACPI_PM_TIMER_WIDTH 32 + +/* Names within the namespace are 4 bytes long */ + +#define ACPI_NAME_SIZE 4 +#define ACPI_PATH_SEGMENT_LENGTH 5 /* 4 chars for name + 1 char for separator */ +#define ACPI_PATH_SEPARATOR '.' + +/* Sizes for ACPI table headers */ + +#define ACPI_OEM_ID_SIZE 6 +#define ACPI_OEM_TABLE_ID_SIZE 8 + +/* ACPI/PNP hardware IDs */ + +#define PCI_ROOT_HID_STRING "PNP0A03" +#define PCI_EXPRESS_ROOT_HID_STRING "PNP0A08" + +/* PM Timer ticks per second (HZ) */ + +#define PM_TIMER_FREQUENCY 3579545 + /******************************************************************************* * * Independent types @@ -291,13 +363,18 @@ typedef u32 acpi_physical_address; #endif /* - * Mescellaneous types + * Miscellaneous types */ typedef u32 acpi_status; /* All ACPI Exceptions */ typedef u32 acpi_name; /* 4-byte ACPI name */ typedef char *acpi_string; /* Null terminated ASCII string */ typedef void *acpi_handle; /* Actually a ptr to a NS Node */ +/* Owner IDs are used to track namespace nodes for selective deletion */ + +typedef u8 acpi_owner_id; +#define ACPI_OWNER_ID_MAX 0xFF + struct uint64_struct { u32 lo; u32 hi; @@ -313,13 +390,8 @@ struct uint32_struct { u32 hi; }; -/* Synchronization objects */ - -#define acpi_mutex void * -#define acpi_semaphore void * - /* - * Acpi integer width. In ACPI version 1, integers are 32 bits. In ACPI + * Acpi integer width. In ACPI version 1, integers are 32 bits. In ACPI * version 2, integers are 64 bits. Note that this pertains to the ACPI integer * type only, not other integers used in the implementation of the ACPI CA * subsystem. @@ -338,10 +410,75 @@ typedef unsigned long long acpi_integer; #define ACPI_MAX16_DECIMAL_DIGITS 5 #define ACPI_MAX8_DECIMAL_DIGITS 3 +/* PM Timer ticks per second (HZ) */ + +#define PM_TIMER_FREQUENCY 3579545 + /* * Constants with special meanings */ #define ACPI_ROOT_OBJECT ACPI_ADD_PTR (acpi_handle, NULL, ACPI_MAX_PTR) +#define ACPI_WAIT_FOREVER 0xFFFF /* u16, as per ACPI spec */ +#define ACPI_DO_NOT_WAIT 0 + +/******************************************************************************* + * + * Commonly used macros + * + ******************************************************************************/ + +/* Data manipulation */ + +#define ACPI_LOWORD(l) ((u16)(u32)(l)) +#define ACPI_HIWORD(l) ((u16)((((u32)(l)) >> 16) & 0xFFFF)) +#define ACPI_LOBYTE(l) ((u8)(u16)(l)) +#define ACPI_HIBYTE(l) ((u8)((((u16)(l)) >> 8) & 0xFF)) + +/* Full 64-bit integer must be available on both 32-bit and 64-bit platforms */ + +struct acpi_integer_overlay { + u32 lo_dword; + u32 hi_dword; +}; + +#define ACPI_LODWORD(integer) (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->lo_dword) +#define ACPI_HIDWORD(integer) (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->hi_dword) + +#define ACPI_SET_BIT(target,bit) ((target) |= (bit)) +#define ACPI_CLEAR_BIT(target,bit) ((target) &= ~(bit)) +#define ACPI_MIN(a,b) (((a)<(b))?(a):(b)) +#define ACPI_MAX(a,b) (((a)>(b))?(a):(b)) + +/* Size calculation */ + +#define ACPI_ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0])) + +/* Pointer manipulation */ + +#define ACPI_CAST_PTR(t, p) ((t *) (acpi_uintptr_t) (p)) +#define ACPI_CAST_INDIRECT_PTR(t, p) ((t **) (acpi_uintptr_t) (p)) +#define ACPI_ADD_PTR(t, a, b) ACPI_CAST_PTR (t, (ACPI_CAST_PTR (u8, (a)) + (acpi_size)(b))) +#define ACPI_PTR_DIFF(a, b) (acpi_size) (ACPI_CAST_PTR (u8, (a)) - ACPI_CAST_PTR (u8, (b))) + +/* Pointer/Integer type conversions */ + +#define ACPI_TO_POINTER(i) ACPI_ADD_PTR (void, (void *) NULL,(acpi_size) i) +#define ACPI_TO_INTEGER(p) ACPI_PTR_DIFF (p, (void *) NULL) +#define ACPI_OFFSET(d, f) (acpi_size) ACPI_PTR_DIFF (&(((d *)0)->f), (void *) NULL) +#define ACPI_PHYSADDR_TO_PTR(i) ACPI_TO_POINTER(i) +#define ACPI_PTR_TO_PHYSADDR(i) ACPI_TO_INTEGER(i) + +#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED +#define ACPI_COMPARE_NAME(a,b) (*ACPI_CAST_PTR (u32, (a)) == *ACPI_CAST_PTR (u32, (b))) +#else +#define ACPI_COMPARE_NAME(a,b) (!ACPI_STRNCMP (ACPI_CAST_PTR (char, (a)), ACPI_CAST_PTR (char, (b)), ACPI_NAME_SIZE)) +#endif + +/******************************************************************************* + * + * Miscellaneous constants + * + ******************************************************************************/ /* * Initialization sequence @@ -414,7 +551,7 @@ typedef unsigned long long acpi_integer; #define ACPI_NOTIFY_MAX 0x0B /* - * Types associated with ACPI names and objects. The first group of + * Types associated with ACPI names and objects. The first group of * values (up to ACPI_TYPE_EXTERNAL_MAX) correspond to the definition * of the ACPI object_type() operator (See the ACPI Spec). Therefore, * only add to the first group if the spec changes. @@ -732,6 +869,15 @@ struct acpi_buffer { #define ACPI_NAME_TYPE_MAX 1 /* + * Predefined Namespace items + */ +struct acpi_predefined_names { + char *name; + u8 type; + char *val; +}; + +/* * Structure and flags for acpi_get_system_info */ #define ACPI_SYS_MODE_UNKNOWN 0x0000 @@ -787,7 +933,7 @@ acpi_status(*acpi_exception_handler) (acpi_status aml_status, u16 opcode, u32 aml_offset, void *context); -/* Table Event handler (Load, load_table etc) and types */ +/* Table Event handler (Load, load_table, etc.) and types */ typedef acpi_status(*acpi_tbl_handler) (u32 event, void *table, void *context); @@ -823,6 +969,12 @@ acpi_status(*acpi_walk_callback) (acpi_handle obj_handle, #define ACPI_INTERRUPT_NOT_HANDLED 0x00 #define ACPI_INTERRUPT_HANDLED 0x01 +/* Length of _HID, _UID, _CID, and UUID values */ + +#define ACPI_DEVICE_ID_LENGTH 0x09 +#define ACPI_MAX_CID_LENGTH 48 +#define ACPI_UUID_LENGTH 16 + /* Common string version of device HIDs and UIDs */ struct acpica_device_id { @@ -900,357 +1052,28 @@ struct acpi_mem_space_context { }; /* - * Definitions for Resource Attributes - */ -typedef u16 acpi_rs_length; /* Resource Length field is fixed at 16 bits */ -typedef u32 acpi_rsdesc_size; /* Max Resource Descriptor size is (Length+3) = (64_k-1)+3 */ - -/* - * Memory Attributes - */ -#define ACPI_READ_ONLY_MEMORY (u8) 0x00 -#define ACPI_READ_WRITE_MEMORY (u8) 0x01 - -#define ACPI_NON_CACHEABLE_MEMORY (u8) 0x00 -#define ACPI_CACHABLE_MEMORY (u8) 0x01 -#define ACPI_WRITE_COMBINING_MEMORY (u8) 0x02 -#define ACPI_PREFETCHABLE_MEMORY (u8) 0x03 - -/* - * IO Attributes - * The ISA IO ranges are: n000-n0_fFh, n400-n4_fFh, n800-n8_fFh, n_c00-n_cFFh. - * The non-ISA IO ranges are: n100-n3_fFh, n500-n7_fFh, n900-n_bFFh, n_cd0-n_fFFh. + * struct acpi_memory_list is used only if the ACPICA local cache is enabled */ -#define ACPI_NON_ISA_ONLY_RANGES (u8) 0x01 -#define ACPI_ISA_ONLY_RANGES (u8) 0x02 -#define ACPI_ENTIRE_RANGE (ACPI_NON_ISA_ONLY_RANGES | ACPI_ISA_ONLY_RANGES) - -/* Type of translation - 1=Sparse, 0=Dense */ - -#define ACPI_SPARSE_TRANSLATION (u8) 0x01 - -/* - * IO Port Descriptor Decode - */ -#define ACPI_DECODE_10 (u8) 0x00 /* 10-bit IO address decode */ -#define ACPI_DECODE_16 (u8) 0x01 /* 16-bit IO address decode */ - -/* - * IRQ Attributes - */ -#define ACPI_LEVEL_SENSITIVE (u8) 0x00 -#define ACPI_EDGE_SENSITIVE (u8) 0x01 - -#define ACPI_ACTIVE_HIGH (u8) 0x00 -#define ACPI_ACTIVE_LOW (u8) 0x01 - -#define ACPI_EXCLUSIVE (u8) 0x00 -#define ACPI_SHARED (u8) 0x01 - -/* - * DMA Attributes - */ -#define ACPI_COMPATIBILITY (u8) 0x00 -#define ACPI_TYPE_A (u8) 0x01 -#define ACPI_TYPE_B (u8) 0x02 -#define ACPI_TYPE_F (u8) 0x03 - -#define ACPI_NOT_BUS_MASTER (u8) 0x00 -#define ACPI_BUS_MASTER (u8) 0x01 - -#define ACPI_TRANSFER_8 (u8) 0x00 -#define ACPI_TRANSFER_8_16 (u8) 0x01 -#define ACPI_TRANSFER_16 (u8) 0x02 - -/* - * Start Dependent Functions Priority definitions - */ -#define ACPI_GOOD_CONFIGURATION (u8) 0x00 -#define ACPI_ACCEPTABLE_CONFIGURATION (u8) 0x01 -#define ACPI_SUB_OPTIMAL_CONFIGURATION (u8) 0x02 - -/* - * 16, 32 and 64-bit Address Descriptor resource types - */ -#define ACPI_MEMORY_RANGE (u8) 0x00 -#define ACPI_IO_RANGE (u8) 0x01 -#define ACPI_BUS_NUMBER_RANGE (u8) 0x02 - -#define ACPI_ADDRESS_NOT_FIXED (u8) 0x00 -#define ACPI_ADDRESS_FIXED (u8) 0x01 - -#define ACPI_POS_DECODE (u8) 0x00 -#define ACPI_SUB_DECODE (u8) 0x01 - -#define ACPI_PRODUCER (u8) 0x00 -#define ACPI_CONSUMER (u8) 0x01 - -/* - * If possible, pack the following structures to byte alignment - */ -#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED -#pragma pack(1) +struct acpi_memory_list { + char *list_name; + void *list_head; + u16 object_size; + u16 max_depth; + u16 current_depth; + u16 link_offset; + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + + /* Statistics for debug memory tracking only */ + + u32 total_allocated; + u32 total_freed; + u32 max_occupied; + u32 total_size; + u32 current_total_size; + u32 requests; + u32 hits; #endif - -/* UUID data structures for use in vendor-defined resource descriptors */ - -struct acpi_uuid { - u8 data[ACPI_UUID_LENGTH]; -}; - -struct acpi_vendor_uuid { - u8 subtype; - u8 data[ACPI_UUID_LENGTH]; -}; - -/* - * Structures used to describe device resources - */ -struct acpi_resource_irq { - u8 descriptor_length; - u8 triggering; - u8 polarity; - u8 sharable; - u8 interrupt_count; - u8 interrupts[1]; -}; - -struct acpi_resource_dma { - u8 type; - u8 bus_master; - u8 transfer; - u8 channel_count; - u8 channels[1]; -}; - -struct acpi_resource_start_dependent { - u8 descriptor_length; - u8 compatibility_priority; - u8 performance_robustness; -}; - -/* - * END_DEPENDENT_FUNCTIONS_RESOURCE struct is not - * needed because it has no fields - */ - -struct acpi_resource_io { - u8 io_decode; - u8 alignment; - u8 address_length; - u16 minimum; - u16 maximum; -}; - -struct acpi_resource_fixed_io { - u16 address; - u8 address_length; -}; - -struct acpi_resource_vendor { - u16 byte_length; - u8 byte_data[1]; -}; - -/* Vendor resource with UUID info (introduced in ACPI 3.0) */ - -struct acpi_resource_vendor_typed { - u16 byte_length; - u8 uuid_subtype; - u8 uuid[ACPI_UUID_LENGTH]; - u8 byte_data[1]; -}; - -struct acpi_resource_end_tag { - u8 checksum; -}; - -struct acpi_resource_memory24 { - u8 write_protect; - u16 minimum; - u16 maximum; - u16 alignment; - u16 address_length; -}; - -struct acpi_resource_memory32 { - u8 write_protect; - u32 minimum; - u32 maximum; - u32 alignment; - u32 address_length; -}; - -struct acpi_resource_fixed_memory32 { - u8 write_protect; - u32 address; - u32 address_length; -}; - -struct acpi_memory_attribute { - u8 write_protect; - u8 caching; - u8 range_type; - u8 translation; -}; - -struct acpi_io_attribute { - u8 range_type; - u8 translation; - u8 translation_type; - u8 reserved1; -}; - -union acpi_resource_attribute { - struct acpi_memory_attribute mem; - struct acpi_io_attribute io; - - /* Used for the *word_space macros */ - - u8 type_specific; -}; - -struct acpi_resource_source { - u8 index; - u16 string_length; - char *string_ptr; -}; - -/* Fields common to all address descriptors, 16/32/64 bit */ - -#define ACPI_RESOURCE_ADDRESS_COMMON \ - u8 resource_type; \ - u8 producer_consumer; \ - u8 decode; \ - u8 min_address_fixed; \ - u8 max_address_fixed; \ - union acpi_resource_attribute info; - -struct acpi_resource_address { -ACPI_RESOURCE_ADDRESS_COMMON}; - -struct acpi_resource_address16 { - ACPI_RESOURCE_ADDRESS_COMMON u16 granularity; - u16 minimum; - u16 maximum; - u16 translation_offset; - u16 address_length; - struct acpi_resource_source resource_source; -}; - -struct acpi_resource_address32 { - ACPI_RESOURCE_ADDRESS_COMMON u32 granularity; - u32 minimum; - u32 maximum; - u32 translation_offset; - u32 address_length; - struct acpi_resource_source resource_source; -}; - -struct acpi_resource_address64 { - ACPI_RESOURCE_ADDRESS_COMMON u64 granularity; - u64 minimum; - u64 maximum; - u64 translation_offset; - u64 address_length; - struct acpi_resource_source resource_source; -}; - -struct acpi_resource_extended_address64 { - ACPI_RESOURCE_ADDRESS_COMMON u8 revision_iD; - u64 granularity; - u64 minimum; - u64 maximum; - u64 translation_offset; - u64 address_length; - u64 type_specific; -}; - -struct acpi_resource_extended_irq { - u8 producer_consumer; - u8 triggering; - u8 polarity; - u8 sharable; - u8 interrupt_count; - struct acpi_resource_source resource_source; - u32 interrupts[1]; -}; - -struct acpi_resource_generic_register { - u8 space_id; - u8 bit_width; - u8 bit_offset; - u8 access_size; - u64 address; -}; - -/* ACPI_RESOURCE_TYPEs */ - -#define ACPI_RESOURCE_TYPE_IRQ 0 -#define ACPI_RESOURCE_TYPE_DMA 1 -#define ACPI_RESOURCE_TYPE_START_DEPENDENT 2 -#define ACPI_RESOURCE_TYPE_END_DEPENDENT 3 -#define ACPI_RESOURCE_TYPE_IO 4 -#define ACPI_RESOURCE_TYPE_FIXED_IO 5 -#define ACPI_RESOURCE_TYPE_VENDOR 6 -#define ACPI_RESOURCE_TYPE_END_TAG 7 -#define ACPI_RESOURCE_TYPE_MEMORY24 8 -#define ACPI_RESOURCE_TYPE_MEMORY32 9 -#define ACPI_RESOURCE_TYPE_FIXED_MEMORY32 10 -#define ACPI_RESOURCE_TYPE_ADDRESS16 11 -#define ACPI_RESOURCE_TYPE_ADDRESS32 12 -#define ACPI_RESOURCE_TYPE_ADDRESS64 13 -#define ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 14 /* ACPI 3.0 */ -#define ACPI_RESOURCE_TYPE_EXTENDED_IRQ 15 -#define ACPI_RESOURCE_TYPE_GENERIC_REGISTER 16 -#define ACPI_RESOURCE_TYPE_MAX 16 - -union acpi_resource_data { - struct acpi_resource_irq irq; - struct acpi_resource_dma dma; - struct acpi_resource_start_dependent start_dpf; - struct acpi_resource_io io; - struct acpi_resource_fixed_io fixed_io; - struct acpi_resource_vendor vendor; - struct acpi_resource_vendor_typed vendor_typed; - struct acpi_resource_end_tag end_tag; - struct acpi_resource_memory24 memory24; - struct acpi_resource_memory32 memory32; - struct acpi_resource_fixed_memory32 fixed_memory32; - struct acpi_resource_address16 address16; - struct acpi_resource_address32 address32; - struct acpi_resource_address64 address64; - struct acpi_resource_extended_address64 ext_address64; - struct acpi_resource_extended_irq extended_irq; - struct acpi_resource_generic_register generic_reg; - - /* Common fields */ - - struct acpi_resource_address address; /* Common 16/32/64 address fields */ -}; - -struct acpi_resource { - u32 type; - u32 length; - union acpi_resource_data data; -}; - -/* restore default alignment */ - -#pragma pack() - -#define ACPI_RS_SIZE_NO_DATA 8 /* Id + Length fields */ -#define ACPI_RS_SIZE_MIN (u32) ACPI_ROUND_UP_TO_NATIVE_WORD (12) -#define ACPI_RS_SIZE(type) (u32) (ACPI_RS_SIZE_NO_DATA + sizeof (type)) - -#define ACPI_NEXT_RESOURCE(res) (struct acpi_resource *)((u8 *) res + res->length) - -struct acpi_pci_routing_table { - u32 length; - u32 pin; - acpi_integer address; /* here for 64-bit alignment */ - u32 source_index; - char source[4]; /* pad to 64 bits so sizeof() works in all cases */ }; #endif /* __ACTYPES_H__ */ diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index fcd2572e428c..e62f10d9a7d8 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -44,14 +44,26 @@ #ifndef __ACENV_H__ #define __ACENV_H__ -/* +/* Types for ACPI_MUTEX_TYPE */ + +#define ACPI_BINARY_SEMAPHORE 0 +#define ACPI_OSL_MUTEX 1 + +/* Types for DEBUGGER_THREADING */ + +#define DEBUGGER_SINGLE_THREADED 0 +#define DEBUGGER_MULTI_THREADED 1 + +/****************************************************************************** + * * Configuration for ACPI tools and utilities - */ + * + *****************************************************************************/ #ifdef ACPI_LIBRARY /* * Note: The non-debug version of the acpi_library does not contain any - * debug support, for minimimal size. The debug version uses ACPI_FULL_DEBUG + * debug support, for minimal size. The debug version uses ACPI_FULL_DEBUG */ #define ACPI_USE_LOCAL_CACHE #endif @@ -75,17 +87,6 @@ #define ACPI_DBG_TRACK_ALLOCATIONS #endif -#ifdef ACPI_DASM_APP -#ifndef MSDOS -#define ACPI_DEBUG_OUTPUT -#endif -#define ACPI_APPLICATION -#define ACPI_DISASSEMBLER -#define ACPI_NO_METHOD_EXECUTION -#define ACPI_LARGE_NAMESPACE_NODE -#define ACPI_DATA_TABLE_DISASSEMBLY -#endif - #ifdef ACPI_APPLICATION #define ACPI_USE_SYSTEM_CLIBRARY #define ACPI_USE_LOCAL_CACHE @@ -179,6 +180,19 @@ /*! [End] no source code translation !*/ +/****************************************************************************** + * + * Miscellaneous configuration + * + *****************************************************************************/ + +/* + * Are mutexes supported by the host? default is no, use binary semaphores. + */ +#ifndef ACPI_MUTEX_TYPE +#define ACPI_MUTEX_TYPE ACPI_BINARY_SEMAPHORE +#endif + /* * Debugger threading model * Use single threaded if the entire subsystem is contained in an application @@ -187,9 +201,6 @@ * By default the model is single threaded if ACPI_APPLICATION is set, * multi-threaded if ACPI_APPLICATION is not set. */ -#define DEBUGGER_SINGLE_THREADED 0 -#define DEBUGGER_MULTI_THREADED 1 - #ifndef DEBUGGER_THREADING #ifdef ACPI_APPLICATION #define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 0515e754449d..6d49b2a498c4 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -46,6 +46,7 @@ #define ACPI_USE_SYSTEM_CLIBRARY #define ACPI_USE_DO_WHILE_0 +#define ACPI_MUTEX_TYPE ACPI_BINARY_SEMAPHORE #ifdef __KERNEL__ @@ -70,9 +71,6 @@ #define ACPI_EXPORT_SYMBOL(symbol) EXPORT_SYMBOL(symbol); #define strtoul simple_strtoul -/* Full namespace pathname length limit - arbitrary */ -#define ACPI_PATHNAME_MAX 256 - #else /* !__KERNEL__ */ #include <stdarg.h> diff --git a/include/linux/acpi.h b/include/linux/acpi.h index fba8051fb297..6fce2fc2d124 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -131,22 +131,6 @@ extern int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity); */ void acpi_unregister_gsi (u32 gsi); -struct acpi_prt_entry { - struct list_head node; - struct acpi_pci_id id; - u8 pin; - struct { - acpi_handle handle; - u32 index; - } link; - u32 irq; -}; - -struct acpi_prt_list { - int count; - struct list_head entries; -}; - struct pci_dev; int acpi_pci_irq_enable (struct pci_dev *dev); @@ -270,6 +254,7 @@ int acpi_check_mem_region(resource_size_t start, resource_size_t n, #ifdef CONFIG_PM_SLEEP void __init acpi_no_s4_hw_signature(void); void __init acpi_old_suspend_ordering(void); +void __init acpi_s4_no_nvs(void); #endif /* CONFIG_PM_SLEEP */ #else /* CONFIG_ACPI */ diff --git a/include/linux/async_tx.h b/include/linux/async_tx.h index 0f50d4cc4360..45f6297821bd 100644 --- a/include/linux/async_tx.h +++ b/include/linux/async_tx.h @@ -59,9 +59,7 @@ enum async_tx_flags { }; #ifdef CONFIG_DMA_ENGINE -void async_tx_issue_pending_all(void); -enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx); -void async_tx_run_dependencies(struct dma_async_tx_descriptor *tx); +#define async_tx_issue_pending_all dma_issue_pending_all #ifdef CONFIG_ARCH_HAS_ASYNC_TX_FIND_CHANNEL #include <asm/async_tx.h> #else @@ -77,19 +75,6 @@ static inline void async_tx_issue_pending_all(void) do { } while (0); } -static inline enum dma_status -dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx) -{ - return DMA_SUCCESS; -} - -static inline void -async_tx_run_dependencies(struct dma_async_tx_descriptor *tx, - struct dma_chan *host_chan) -{ - do { } while (0); -} - static inline struct dma_chan * async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx, enum dma_transaction_type tx_type, struct page **dst, int dst_count, diff --git a/include/linux/atmel-mci.h b/include/linux/atmel-mci.h index 2a2213eefd85..2f1f95737acb 100644 --- a/include/linux/atmel-mci.h +++ b/include/linux/atmel-mci.h @@ -3,7 +3,7 @@ #define ATMEL_MCI_MAX_NR_SLOTS 2 -struct dma_slave; +#include <linux/dw_dmac.h> /** * struct mci_slot_pdata - board-specific per-slot configuration @@ -28,11 +28,11 @@ struct mci_slot_pdata { /** * struct mci_platform_data - board-specific MMC/SDcard configuration - * @dma_slave: DMA slave interface to use in data transfers, or NULL. + * @dma_slave: DMA slave interface to use in data transfers. * @slot: Per-slot configuration data. */ struct mci_platform_data { - struct dma_slave *dma_slave; + struct dw_dma_slave dma_slave; struct mci_slot_pdata slot[ATMEL_MCI_MAX_NR_SLOTS]; }; diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index adb0b084eb5a..64dea2ab326c 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -29,32 +29,6 @@ #include <linux/dma-mapping.h> /** - * enum dma_state - resource PNP/power management state - * @DMA_RESOURCE_SUSPEND: DMA device going into low power state - * @DMA_RESOURCE_RESUME: DMA device returning to full power - * @DMA_RESOURCE_AVAILABLE: DMA device available to the system - * @DMA_RESOURCE_REMOVED: DMA device removed from the system - */ -enum dma_state { - DMA_RESOURCE_SUSPEND, - DMA_RESOURCE_RESUME, - DMA_RESOURCE_AVAILABLE, - DMA_RESOURCE_REMOVED, -}; - -/** - * enum dma_state_client - state of the channel in the client - * @DMA_ACK: client would like to use, or was using this channel - * @DMA_DUP: client has already seen this channel, or is not using this channel - * @DMA_NAK: client does not want to see any more channels - */ -enum dma_state_client { - DMA_ACK, - DMA_DUP, - DMA_NAK, -}; - -/** * typedef dma_cookie_t - an opaque DMA cookie * * if dma_cookie_t is >0 it's a DMA request cookie, <0 it's an error code @@ -89,23 +63,13 @@ enum dma_transaction_type { DMA_MEMSET, DMA_MEMCPY_CRC32C, DMA_INTERRUPT, + DMA_PRIVATE, DMA_SLAVE, }; /* last transaction type for creation of the capabilities mask */ #define DMA_TX_TYPE_END (DMA_SLAVE + 1) -/** - * enum dma_slave_width - DMA slave register access width. - * @DMA_SLAVE_WIDTH_8BIT: Do 8-bit slave register accesses - * @DMA_SLAVE_WIDTH_16BIT: Do 16-bit slave register accesses - * @DMA_SLAVE_WIDTH_32BIT: Do 32-bit slave register accesses - */ -enum dma_slave_width { - DMA_SLAVE_WIDTH_8BIT, - DMA_SLAVE_WIDTH_16BIT, - DMA_SLAVE_WIDTH_32BIT, -}; /** * enum dma_ctrl_flags - DMA flags to augment operation preparation, @@ -132,32 +96,6 @@ enum dma_ctrl_flags { typedef struct { DECLARE_BITMAP(bits, DMA_TX_TYPE_END); } dma_cap_mask_t; /** - * struct dma_slave - Information about a DMA slave - * @dev: device acting as DMA slave - * @dma_dev: required DMA master device. If non-NULL, the client can not be - * bound to other masters than this. - * @tx_reg: physical address of data register used for - * memory-to-peripheral transfers - * @rx_reg: physical address of data register used for - * peripheral-to-memory transfers - * @reg_width: peripheral register width - * - * If dma_dev is non-NULL, the client can not be bound to other DMA - * masters than the one corresponding to this device. The DMA master - * driver may use this to determine if there is controller-specific - * data wrapped around this struct. Drivers of platform code that sets - * the dma_dev field must therefore make sure to use an appropriate - * controller-specific dma slave structure wrapping this struct. - */ -struct dma_slave { - struct device *dev; - struct device *dma_dev; - dma_addr_t tx_reg; - dma_addr_t rx_reg; - enum dma_slave_width reg_width; -}; - -/** * struct dma_chan_percpu - the per-CPU part of struct dma_chan * @refcount: local_t used for open-coded "bigref" counting * @memcpy_count: transaction counter @@ -165,7 +103,6 @@ struct dma_slave { */ struct dma_chan_percpu { - local_t refcount; /* stats */ unsigned long memcpy_count; unsigned long bytes_transferred; @@ -176,13 +113,14 @@ struct dma_chan_percpu { * @device: ptr to the dma device who supplies this channel, always !%NULL * @cookie: last cookie value returned to client * @chan_id: channel ID for sysfs - * @class_dev: class device for sysfs + * @dev: class device for sysfs * @refcount: kref, used in "bigref" slow-mode * @slow_ref: indicates that the DMA channel is free * @rcu: the DMA channel's RCU head * @device_node: used to add this to the device chan list * @local: per-cpu pointer to a struct dma_chan_percpu * @client-count: how many clients are using this channel + * @table_count: number of appearances in the mem-to-mem allocation table */ struct dma_chan { struct dma_device *device; @@ -190,73 +128,47 @@ struct dma_chan { /* sysfs */ int chan_id; - struct device dev; - - struct kref refcount; - int slow_ref; - struct rcu_head rcu; + struct dma_chan_dev *dev; struct list_head device_node; struct dma_chan_percpu *local; int client_count; + int table_count; }; -#define to_dma_chan(p) container_of(p, struct dma_chan, dev) - -void dma_chan_cleanup(struct kref *kref); - -static inline void dma_chan_get(struct dma_chan *chan) -{ - if (unlikely(chan->slow_ref)) - kref_get(&chan->refcount); - else { - local_inc(&(per_cpu_ptr(chan->local, get_cpu())->refcount)); - put_cpu(); - } -} +/** + * struct dma_chan_dev - relate sysfs device node to backing channel device + * @chan - driver channel device + * @device - sysfs device + * @dev_id - parent dma_device dev_id + * @idr_ref - reference count to gate release of dma_device dev_id + */ +struct dma_chan_dev { + struct dma_chan *chan; + struct device device; + int dev_id; + atomic_t *idr_ref; +}; -static inline void dma_chan_put(struct dma_chan *chan) +static inline const char *dma_chan_name(struct dma_chan *chan) { - if (unlikely(chan->slow_ref)) - kref_put(&chan->refcount, dma_chan_cleanup); - else { - local_dec(&(per_cpu_ptr(chan->local, get_cpu())->refcount)); - put_cpu(); - } + return dev_name(&chan->dev->device); } -/* - * typedef dma_event_callback - function pointer to a DMA event callback - * For each channel added to the system this routine is called for each client. - * If the client would like to use the channel it returns '1' to signal (ack) - * the dmaengine core to take out a reference on the channel and its - * corresponding device. A client must not 'ack' an available channel more - * than once. When a channel is removed all clients are notified. If a client - * is using the channel it must 'ack' the removal. A client must not 'ack' a - * removed channel more than once. - * @client - 'this' pointer for the client context - * @chan - channel to be acted upon - * @state - available or removed - */ -struct dma_client; -typedef enum dma_state_client (*dma_event_callback) (struct dma_client *client, - struct dma_chan *chan, enum dma_state state); +void dma_chan_cleanup(struct kref *kref); /** - * struct dma_client - info on the entity making use of DMA services - * @event_callback: func ptr to call when something happens - * @cap_mask: only return channels that satisfy the requested capabilities - * a value of zero corresponds to any capability - * @slave: data for preparing slave transfer. Must be non-NULL iff the - * DMA_SLAVE capability is requested. - * @global_node: list_head for global dma_client_list + * typedef dma_filter_fn - callback filter for dma_request_channel + * @chan: channel to be reviewed + * @filter_param: opaque parameter passed through dma_request_channel + * + * When this optional parameter is specified in a call to dma_request_channel a + * suitable channel is passed to this routine for further dispositioning before + * being returned. Where 'suitable' indicates a non-busy channel that + * satisfies the given capability mask. It returns 'true' to indicate that the + * channel is suitable. */ -struct dma_client { - dma_event_callback event_callback; - dma_cap_mask_t cap_mask; - struct dma_slave *slave; - struct list_head global_node; -}; +typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param); typedef void (*dma_async_tx_callback)(void *dma_async_param); /** @@ -323,14 +235,10 @@ struct dma_device { dma_cap_mask_t cap_mask; int max_xor; - struct kref refcount; - struct completion done; - int dev_id; struct device *dev; - int (*device_alloc_chan_resources)(struct dma_chan *chan, - struct dma_client *client); + int (*device_alloc_chan_resources)(struct dma_chan *chan); void (*device_free_chan_resources)(struct dma_chan *chan); struct dma_async_tx_descriptor *(*device_prep_dma_memcpy)( @@ -362,9 +270,8 @@ struct dma_device { /* --- public DMA engine API --- */ -void dma_async_client_register(struct dma_client *client); -void dma_async_client_unregister(struct dma_client *client); -void dma_async_client_chan_request(struct dma_client *client); +void dmaengine_get(void); +void dmaengine_put(void); dma_cookie_t dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest, void *src, size_t len); dma_cookie_t dma_async_memcpy_buf_to_pg(struct dma_chan *chan, @@ -406,6 +313,12 @@ __dma_cap_set(enum dma_transaction_type tx_type, dma_cap_mask_t *dstp) set_bit(tx_type, dstp->bits); } +#define dma_cap_zero(mask) __dma_cap_zero(&(mask)) +static inline void __dma_cap_zero(dma_cap_mask_t *dstp) +{ + bitmap_zero(dstp->bits, DMA_TX_TYPE_END); +} + #define dma_has_cap(tx, mask) __dma_has_cap((tx), &(mask)) static inline int __dma_has_cap(enum dma_transaction_type tx_type, dma_cap_mask_t *srcp) @@ -475,11 +388,25 @@ static inline enum dma_status dma_async_is_complete(dma_cookie_t cookie, } enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie); +#ifdef CONFIG_DMA_ENGINE +enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx); +#else +static inline enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx) +{ + return DMA_SUCCESS; +} +#endif /* --- DMA device --- */ int dma_async_device_register(struct dma_device *device); void dma_async_device_unregister(struct dma_device *device); +void dma_run_dependencies(struct dma_async_tx_descriptor *tx); +struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type); +void dma_issue_pending_all(void); +#define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y) +struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param); +void dma_release_channel(struct dma_chan *chan); /* --- Helper iov-locking functions --- */ diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h index 04d217b442bf..d797dde247f7 100644 --- a/include/linux/dw_dmac.h +++ b/include/linux/dw_dmac.h @@ -22,14 +22,34 @@ struct dw_dma_platform_data { }; /** + * enum dw_dma_slave_width - DMA slave register access width. + * @DMA_SLAVE_WIDTH_8BIT: Do 8-bit slave register accesses + * @DMA_SLAVE_WIDTH_16BIT: Do 16-bit slave register accesses + * @DMA_SLAVE_WIDTH_32BIT: Do 32-bit slave register accesses + */ +enum dw_dma_slave_width { + DW_DMA_SLAVE_WIDTH_8BIT, + DW_DMA_SLAVE_WIDTH_16BIT, + DW_DMA_SLAVE_WIDTH_32BIT, +}; + +/** * struct dw_dma_slave - Controller-specific information about a slave - * @slave: Generic information about the slave - * @ctl_lo: Platform-specific initializer for the CTL_LO register + * + * @dma_dev: required DMA master device + * @tx_reg: physical address of data register used for + * memory-to-peripheral transfers + * @rx_reg: physical address of data register used for + * peripheral-to-memory transfers + * @reg_width: peripheral register width * @cfg_hi: Platform-specific initializer for the CFG_HI register * @cfg_lo: Platform-specific initializer for the CFG_LO register */ struct dw_dma_slave { - struct dma_slave slave; + struct device *dma_dev; + dma_addr_t tx_reg; + dma_addr_t rx_reg; + enum dw_dma_slave_width reg_width; u32 cfg_hi; u32 cfg_lo; }; @@ -54,9 +74,4 @@ struct dw_dma_slave { #define DWC_CFGL_HS_DST_POL (1 << 18) /* dst handshake active low */ #define DWC_CFGL_HS_SRC_POL (1 << 19) /* src handshake active low */ -static inline struct dw_dma_slave *to_dw_dma_slave(struct dma_slave *slave) -{ - return container_of(slave, struct dw_dma_slave, slave); -} - #endif /* DW_DMAC_H */ diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index 00e2b575021f..88d3d8fbf9f2 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h @@ -520,6 +520,7 @@ struct cfi_fixup { #define CFI_MFR_AMD 0x0001 #define CFI_MFR_ATMEL 0x001F +#define CFI_MFR_SAMSUNG 0x00EC #define CFI_MFR_ST 0x0020 /* STMicroelectronics */ void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup* fixups); diff --git a/include/linux/mtd/ftl.h b/include/linux/mtd/ftl.h index 0be442f881dd..0555f7a0b9ed 100644 --- a/include/linux/mtd/ftl.h +++ b/include/linux/mtd/ftl.h @@ -32,25 +32,25 @@ #define _LINUX_FTL_H typedef struct erase_unit_header_t { - u_int8_t LinkTargetTuple[5]; - u_int8_t DataOrgTuple[10]; - u_int8_t NumTransferUnits; - u_int32_t EraseCount; - u_int16_t LogicalEUN; - u_int8_t BlockSize; - u_int8_t EraseUnitSize; - u_int16_t FirstPhysicalEUN; - u_int16_t NumEraseUnits; - u_int32_t FormattedSize; - u_int32_t FirstVMAddress; - u_int16_t NumVMPages; - u_int8_t Flags; - u_int8_t Code; - u_int32_t SerialNumber; - u_int32_t AltEUHOffset; - u_int32_t BAMOffset; - u_int8_t Reserved[12]; - u_int8_t EndTuple[2]; + uint8_t LinkTargetTuple[5]; + uint8_t DataOrgTuple[10]; + uint8_t NumTransferUnits; + uint32_t EraseCount; + uint16_t LogicalEUN; + uint8_t BlockSize; + uint8_t EraseUnitSize; + uint16_t FirstPhysicalEUN; + uint16_t NumEraseUnits; + uint32_t FormattedSize; + uint32_t FirstVMAddress; + uint16_t NumVMPages; + uint8_t Flags; + uint8_t Code; + uint32_t SerialNumber; + uint32_t AltEUHOffset; + uint32_t BAMOffset; + uint8_t Reserved[12]; + uint8_t EndTuple[2]; } erase_unit_header_t; /* Flags in erase_unit_header_t */ diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index aa30244492c6..b981b8772217 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -223,6 +223,7 @@ struct map_info { must leave it enabled. */ void (*set_vpp)(struct map_info *, int); + unsigned long pfow_base; unsigned long map_priv_1; unsigned long map_priv_2; void *fldrv_priv; diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 64433eb411d7..3aa5d77c2cdb 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -15,6 +15,8 @@ #include <linux/mtd/compatmac.h> #include <mtd/mtd-abi.h> +#include <asm/div64.h> + #define MTD_CHAR_MAJOR 90 #define MTD_BLOCK_MAJOR 31 #define MAX_MTD_DEVICES 32 @@ -25,20 +27,20 @@ #define MTD_ERASE_DONE 0x08 #define MTD_ERASE_FAILED 0x10 -#define MTD_FAIL_ADDR_UNKNOWN 0xffffffff +#define MTD_FAIL_ADDR_UNKNOWN -1LL /* If the erase fails, fail_addr might indicate exactly which block failed. If fail_addr = MTD_FAIL_ADDR_UNKNOWN, the failure was not at the device level or was not specific to any particular block. */ struct erase_info { struct mtd_info *mtd; - u_int32_t addr; - u_int32_t len; - u_int32_t fail_addr; + uint64_t addr; + uint64_t len; + uint64_t fail_addr; u_long time; u_long retries; - u_int dev; - u_int cell; + unsigned dev; + unsigned cell; void (*callback) (struct erase_info *self); u_long priv; u_char state; @@ -46,9 +48,9 @@ struct erase_info { }; struct mtd_erase_region_info { - u_int32_t offset; /* At which this region starts, from the beginning of the MTD */ - u_int32_t erasesize; /* For this region */ - u_int32_t numblocks; /* Number of blocks of erasesize in this region */ + uint64_t offset; /* At which this region starts, from the beginning of the MTD */ + uint32_t erasesize; /* For this region */ + uint32_t numblocks; /* Number of blocks of erasesize in this region */ unsigned long *lockmap; /* If keeping bitmap of locks */ }; @@ -100,14 +102,14 @@ struct mtd_oob_ops { struct mtd_info { u_char type; - u_int32_t flags; - u_int32_t size; // Total size of the MTD + uint32_t flags; + uint64_t size; // Total size of the MTD /* "Major" erase size for the device. Naïve users may take this * to be the only erase size available, or may use the more detailed * information below if they desire */ - u_int32_t erasesize; + uint32_t erasesize; /* Minimal writable flash unit size. In case of NOR flash it is 1 (even * though individual bits can be cleared), in case of NAND flash it is * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR @@ -115,10 +117,20 @@ struct mtd_info { * Any driver registering a struct mtd_info must ensure a writesize of * 1 or larger. */ - u_int32_t writesize; + uint32_t writesize; + + uint32_t oobsize; // Amount of OOB data per block (e.g. 16) + uint32_t oobavail; // Available OOB bytes per block - u_int32_t oobsize; // Amount of OOB data per block (e.g. 16) - u_int32_t oobavail; // Available OOB bytes per block + /* + * If erasesize is a power of 2 then the shift is stored in + * erasesize_shift otherwise erasesize_shift is zero. Ditto writesize. + */ + unsigned int erasesize_shift; + unsigned int writesize_shift; + /* Masks based on erasesize_shift and writesize_shift */ + unsigned int erasesize_mask; + unsigned int writesize_mask; // Kernel-only stuff starts here. const char *name; @@ -190,8 +202,8 @@ struct mtd_info { void (*sync) (struct mtd_info *mtd); /* Chip-supported device locking */ - int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len); - int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len); + int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len); + int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len); /* Power Management functions */ int (*suspend) (struct mtd_info *mtd); @@ -221,6 +233,35 @@ struct mtd_info { void (*put_device) (struct mtd_info *mtd); }; +static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd) +{ + if (mtd->erasesize_shift) + return sz >> mtd->erasesize_shift; + do_div(sz, mtd->erasesize); + return sz; +} + +static inline uint32_t mtd_mod_by_eb(uint64_t sz, struct mtd_info *mtd) +{ + if (mtd->erasesize_shift) + return sz & mtd->erasesize_mask; + return do_div(sz, mtd->erasesize); +} + +static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd) +{ + if (mtd->writesize_shift) + return sz >> mtd->writesize_shift; + do_div(sz, mtd->writesize); + return sz; +} + +static inline uint32_t mtd_mod_by_ws(uint64_t sz, struct mtd_info *mtd) +{ + if (mtd->writesize_shift) + return sz & mtd->writesize_mask; + return do_div(sz, mtd->writesize); +} /* Kernel-side ioctl definitions */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 733d3f3b4eb8..db5b63da2a7e 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -335,17 +335,12 @@ struct nand_buffers { * @erase_cmd: [INTERN] erase command write function, selectable due to AND support * @scan_bbt: [REPLACEABLE] function to scan bad block table * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR) - * @wq: [INTERN] wait queue to sleep on if a NAND operation is in progress * @state: [INTERN] the current state of the NAND device * @oob_poi: poison value buffer * @page_shift: [INTERN] number of address bits in a page (column address bits) * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry * @chip_shift: [INTERN] number of address bits in one chip - * @datbuf: [INTERN] internal buffer for one page + oob - * @oobbuf: [INTERN] oob buffer for one eraseblock - * @oobdirty: [INTERN] indicates that oob_buf must be reinitialized - * @data_poi: [INTERN] pointer to a data buffer * @options: [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about * special functionality. See the defines for further explanation * @badblockpos: [INTERN] position of the bad block marker in the oob area @@ -399,7 +394,7 @@ struct nand_chip { int bbt_erase_shift; int chip_shift; int numchips; - unsigned long chipsize; + uint64_t chipsize; int pagemask; int pagebuf; int subpagesize; diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index c92b4d439609..a45dd831b3f8 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -36,9 +36,9 @@ struct mtd_partition { char *name; /* identifier string */ - u_int32_t size; /* partition size */ - u_int32_t offset; /* offset within the master MTD space */ - u_int32_t mask_flags; /* master MTD flags to mask out for this partition */ + uint64_t size; /* partition size */ + uint64_t offset; /* offset within the master MTD space */ + uint32_t mask_flags; /* master MTD flags to mask out for this partition */ struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only)*/ struct mtd_info **mtdp; /* pointer to store the MTD object */ }; diff --git a/include/linux/mtd/pfow.h b/include/linux/mtd/pfow.h new file mode 100644 index 000000000000..b730d4f84655 --- /dev/null +++ b/include/linux/mtd/pfow.h @@ -0,0 +1,159 @@ +/* Primary function overlay window definitions + * and service functions used by LPDDR chips + */ +#ifndef __LINUX_MTD_PFOW_H +#define __LINUX_MTD_PFOW_H + +#include <linux/mtd/qinfo.h> + +/* PFOW registers addressing */ +/* Address of symbol "P" */ +#define PFOW_QUERY_STRING_P 0x0000 +/* Address of symbol "F" */ +#define PFOW_QUERY_STRING_F 0x0002 +/* Address of symbol "O" */ +#define PFOW_QUERY_STRING_O 0x0004 +/* Address of symbol "W" */ +#define PFOW_QUERY_STRING_W 0x0006 +/* Identification info for LPDDR chip */ +#define PFOW_MANUFACTURER_ID 0x0020 +#define PFOW_DEVICE_ID 0x0022 +/* Address in PFOW where prog buffer can can be found */ +#define PFOW_PROGRAM_BUFFER_OFFSET 0x0040 +/* Size of program buffer in words */ +#define PFOW_PROGRAM_BUFFER_SIZE 0x0042 +/* Address command code register */ +#define PFOW_COMMAND_CODE 0x0080 +/* command data register */ +#define PFOW_COMMAND_DATA 0x0084 +/* command address register lower address bits */ +#define PFOW_COMMAND_ADDRESS_L 0x0088 +/* command address register upper address bits */ +#define PFOW_COMMAND_ADDRESS_H 0x008a +/* number of bytes to be proggrammed lower address bits */ +#define PFOW_DATA_COUNT_L 0x0090 +/* number of bytes to be proggrammed higher address bits */ +#define PFOW_DATA_COUNT_H 0x0092 +/* command execution register, the only possible value is 0x01 */ +#define PFOW_COMMAND_EXECUTE 0x00c0 +/* 0x01 should be written at this address to clear buffer */ +#define PFOW_CLEAR_PROGRAM_BUFFER 0x00c4 +/* device program/erase suspend register */ +#define PFOW_PROGRAM_ERASE_SUSPEND 0x00c8 +/* device status register */ +#define PFOW_DSR 0x00cc + +/* LPDDR memory device command codes */ +/* They are possible values of PFOW command code register */ +#define LPDDR_WORD_PROGRAM 0x0041 +#define LPDDR_BUFF_PROGRAM 0x00E9 +#define LPDDR_BLOCK_ERASE 0x0020 +#define LPDDR_LOCK_BLOCK 0x0061 +#define LPDDR_UNLOCK_BLOCK 0x0062 +#define LPDDR_READ_BLOCK_LOCK_STATUS 0x0065 +#define LPDDR_INFO_QUERY 0x0098 +#define LPDDR_READ_OTP 0x0097 +#define LPDDR_PROG_OTP 0x00C0 +#define LPDDR_RESUME 0x00D0 + +/* Defines possible value of PFOW command execution register */ +#define LPDDR_START_EXECUTION 0x0001 + +/* Defines possible value of PFOW program/erase suspend register */ +#define LPDDR_SUSPEND 0x0001 + +/* Possible values of PFOW device status register */ +/* access R - read; RC read & clearable */ +#define DSR_DPS (1<<1) /* RC; device protect status + * 0 - not protected 1 - locked */ +#define DSR_PSS (1<<2) /* R; program suspend status; + * 0-prog in progress/completed, + * 1- prog suspended */ +#define DSR_VPPS (1<<3) /* RC; 0-Vpp OK, * 1-Vpp low */ +#define DSR_PROGRAM_STATUS (1<<4) /* RC; 0-successful, 1-error */ +#define DSR_ERASE_STATUS (1<<5) /* RC; erase or blank check status; + * 0-success erase/blank check, + * 1 blank check error */ +#define DSR_ESS (1<<6) /* R; erase suspend status; + * 0-erase in progress/complete, + * 1 erase suspended */ +#define DSR_READY_STATUS (1<<7) /* R; Device status + * 0-busy, + * 1-ready */ +#define DSR_RPS (0x3<<8) /* RC; region program status + * 00 - Success, + * 01-re-program attempt in region with + * object mode data, + * 10-object mode program w attempt in + * region with control mode data + * 11-attempt to program invalid half + * with 0x41 command */ +#define DSR_AOS (1<<12) /* RC; 1- AO related failure */ +#define DSR_AVAILABLE (1<<15) /* R; Device availbility + * 1 - Device available + * 0 - not available */ + +/* The superset of all possible error bits in DSR */ +#define DSR_ERR 0x133A + +static inline void send_pfow_command(struct map_info *map, + unsigned long cmd_code, unsigned long adr, + unsigned long len, map_word *datum) +{ + int bits_per_chip = map_bankwidth(map) * 8; + int chipnum; + struct lpddr_private *lpddr = map->fldrv_priv; + chipnum = adr >> lpddr->chipshift; + + map_write(map, CMD(cmd_code), map->pfow_base + PFOW_COMMAND_CODE); + map_write(map, CMD(adr & ((1<<bits_per_chip) - 1)), + map->pfow_base + PFOW_COMMAND_ADDRESS_L); + map_write(map, CMD(adr>>bits_per_chip), + map->pfow_base + PFOW_COMMAND_ADDRESS_H); + if (len) { + map_write(map, CMD(len & ((1<<bits_per_chip) - 1)), + map->pfow_base + PFOW_DATA_COUNT_L); + map_write(map, CMD(len>>bits_per_chip), + map->pfow_base + PFOW_DATA_COUNT_H); + } + if (datum) + map_write(map, *datum, map->pfow_base + PFOW_COMMAND_DATA); + + /* Command execution start */ + map_write(map, CMD(LPDDR_START_EXECUTION), + map->pfow_base + PFOW_COMMAND_EXECUTE); +} + +static inline void print_drs_error(unsigned dsr) +{ + int prog_status = (dsr & DSR_RPS) >> 8; + + if (!(dsr & DSR_AVAILABLE)) + printk(KERN_NOTICE"DSR.15: (0) Device not Available\n"); + if (prog_status & 0x03) + printk(KERN_NOTICE"DSR.9,8: (11) Attempt to program invalid " + "half with 41h command\n"); + else if (prog_status & 0x02) + printk(KERN_NOTICE"DSR.9,8: (10) Object Mode Program attempt " + "in region with Control Mode data\n"); + else if (prog_status & 0x01) + printk(KERN_NOTICE"DSR.9,8: (01) Program attempt in region " + "with Object Mode data\n"); + if (!(dsr & DSR_READY_STATUS)) + printk(KERN_NOTICE"DSR.7: (0) Device is Busy\n"); + if (dsr & DSR_ESS) + printk(KERN_NOTICE"DSR.6: (1) Erase Suspended\n"); + if (dsr & DSR_ERASE_STATUS) + printk(KERN_NOTICE"DSR.5: (1) Erase/Blank check error\n"); + if (dsr & DSR_PROGRAM_STATUS) + printk(KERN_NOTICE"DSR.4: (1) Program Error\n"); + if (dsr & DSR_VPPS) + printk(KERN_NOTICE"DSR.3: (1) Vpp low detect, operation " + "aborted\n"); + if (dsr & DSR_PSS) + printk(KERN_NOTICE"DSR.2: (1) Program suspended\n"); + if (dsr & DSR_DPS) + printk(KERN_NOTICE"DSR.1: (1) Aborted Erase/Program attempt " + "on locked block\n"); +} +#endif /* __LINUX_MTD_PFOW_H */ diff --git a/include/linux/mtd/physmap.h b/include/linux/mtd/physmap.h index c8e63a5ee72e..76f7cabf07d3 100644 --- a/include/linux/mtd/physmap.h +++ b/include/linux/mtd/physmap.h @@ -24,6 +24,7 @@ struct physmap_flash_data { unsigned int width; void (*set_vpp)(struct map_info *, int); unsigned int nr_parts; + unsigned int pfow_base; struct mtd_partition *parts; }; diff --git a/include/linux/mtd/qinfo.h b/include/linux/mtd/qinfo.h new file mode 100644 index 000000000000..7b3d487d8b3f --- /dev/null +++ b/include/linux/mtd/qinfo.h @@ -0,0 +1,91 @@ +#ifndef __LINUX_MTD_QINFO_H +#define __LINUX_MTD_QINFO_H + +#include <linux/mtd/map.h> +#include <linux/wait.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/flashchip.h> +#include <linux/mtd/partitions.h> + +/* lpddr_private describes lpddr flash chip in memory map + * @ManufactId - Chip Manufacture ID + * @DevId - Chip Device ID + * @qinfo - pointer to qinfo records describing the chip + * @numchips - number of chips including virual RWW partitions + * @chipshift - Chip/partiton size 2^chipshift + * @chips - per-chip data structure + */ +struct lpddr_private { + uint16_t ManufactId; + uint16_t DevId; + struct qinfo_chip *qinfo; + int numchips; + unsigned long chipshift; + struct flchip chips[0]; +}; + +/* qinfo_query_info structure contains request information for + * each qinfo record + * @major - major number of qinfo record + * @major - minor number of qinfo record + * @id_str - descriptive string to access the record + * @desc - detailed description for the qinfo record + */ +struct qinfo_query_info { + uint8_t major; + uint8_t minor; + char *id_str; + char *desc; +}; + +/* + * qinfo_chip structure contains necessary qinfo records data + * @DevSizeShift - Device size 2^n bytes + * @BufSizeShift - Program buffer size 2^n bytes + * @TotalBlocksNum - Total number of blocks + * @UniformBlockSizeShift - Uniform block size 2^UniformBlockSizeShift bytes + * @HWPartsNum - Number of hardware partitions + * @SuspEraseSupp - Suspend erase supported + * @SingleWordProgTime - Single word program 2^SingleWordProgTime u-sec + * @ProgBufferTime - Program buffer write 2^ProgBufferTime u-sec + * @BlockEraseTime - Block erase 2^BlockEraseTime m-sec + */ +struct qinfo_chip { + /* General device info */ + uint16_t DevSizeShift; + uint16_t BufSizeShift; + /* Erase block information */ + uint16_t TotalBlocksNum; + uint16_t UniformBlockSizeShift; + /* Partition information */ + uint16_t HWPartsNum; + /* Optional features */ + uint16_t SuspEraseSupp; + /* Operation typical time */ + uint16_t SingleWordProgTime; + uint16_t ProgBufferTime; + uint16_t BlockEraseTime; +}; + +/* defines for fixup usage */ +#define LPDDR_MFR_ANY 0xffff +#define LPDDR_ID_ANY 0xffff +#define NUMONYX_MFGR_ID 0x0089 +#define R18_DEVICE_ID_1G 0x893c + +static inline map_word lpddr_build_cmd(u_long cmd, struct map_info *map) +{ + map_word val = { {0} }; + val.x[0] = cmd; + return val; +} + +#define CMD(x) lpddr_build_cmd(x, map) +#define CMDVAL(cmd) cmd.x[0] + +struct mtd_info *lpddr_cmdset(struct map_info *); + +#endif + diff --git a/include/linux/mtd/sharpsl.h b/include/linux/mtd/sharpsl.h new file mode 100644 index 000000000000..25f4d2a845c1 --- /dev/null +++ b/include/linux/mtd/sharpsl.h @@ -0,0 +1,20 @@ +/* + * SharpSL NAND support + * + * Copyright (C) 2008 Dmitry Baryshkov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +struct sharpsl_nand_platform_data { + struct nand_bbt_descr *badblock_pattern; + struct nand_ecclayout *ecc_layout; + struct mtd_partition *partitions; + unsigned int nr_partitions; +}; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 114091be8872..f24556813375 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1125,9 +1125,6 @@ struct softnet_data struct sk_buff *completion_queue; struct napi_struct backlog; -#ifdef CONFIG_NET_DMA - struct dma_chan *net_dma; -#endif }; DECLARE_PER_CPU(struct softnet_data,softnet_data); diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index 1ce9fe572e51..1d9518bc4c58 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h @@ -164,4 +164,22 @@ void oprofile_put_buff(unsigned long *buf, unsigned int start, unsigned long oprofile_get_cpu_buffer_size(void); void oprofile_cpu_buffer_inc_smpl_lost(void); +/* cpu buffer functions */ + +struct op_sample; + +struct op_entry { + struct ring_buffer_event *event; + struct op_sample *sample; + unsigned long irq_flags; + unsigned long size; + unsigned long *data; +}; + +void oprofile_write_reserve(struct op_entry *entry, + struct pt_regs * const regs, + unsigned long pc, int code, int size); +int oprofile_add_data(struct op_entry *entry, unsigned long val); +int oprofile_write_commit(struct op_entry *entry); + #endif /* OPROFILE_H */ diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index f7cc204fab07..20998746518e 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -223,7 +223,6 @@ struct hotplug_params { #ifdef CONFIG_ACPI #include <acpi/acpi.h> #include <acpi/acpi_bus.h> -#include <acpi/actypes.h> extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, struct hotplug_params *hpp); int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags); diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 2ce8207686e2..2b409c44db83 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -232,6 +232,11 @@ extern unsigned long get_safe_page(gfp_t gfp_mask); extern void hibernation_set_ops(struct platform_hibernation_ops *ops); extern int hibernate(void); +extern int hibernate_nvs_register(unsigned long start, unsigned long size); +extern int hibernate_nvs_alloc(void); +extern void hibernate_nvs_free(void); +extern void hibernate_nvs_save(void); +extern void hibernate_nvs_restore(void); #else /* CONFIG_HIBERNATION */ static inline int swsusp_page_is_forbidden(struct page *p) { return 0; } static inline void swsusp_set_page_free(struct page *p) {} @@ -239,6 +244,14 @@ static inline void swsusp_unset_page_free(struct page *p) {} static inline void hibernation_set_ops(struct platform_hibernation_ops *ops) {} static inline int hibernate(void) { return -ENOSYS; } +static inline int hibernate_nvs_register(unsigned long a, unsigned long b) +{ + return 0; +} +static inline int hibernate_nvs_alloc(void) { return 0; } +static inline void hibernate_nvs_free(void) {} +static inline void hibernate_nvs_save(void) {} +static inline void hibernate_nvs_restore(void) {} #endif /* CONFIG_HIBERNATION */ #ifdef CONFIG_PM_SLEEP diff --git a/include/net/netdma.h b/include/net/netdma.h index f28c6e064e8f..8ba8ce284eeb 100644 --- a/include/net/netdma.h +++ b/include/net/netdma.h @@ -24,17 +24,6 @@ #include <linux/dmaengine.h> #include <linux/skbuff.h> -static inline struct dma_chan *get_softnet_dma(void) -{ - struct dma_chan *chan; - rcu_read_lock(); - chan = rcu_dereference(__get_cpu_var(softnet_data).net_dma); - if (chan) - dma_chan_get(chan); - rcu_read_unlock(); - return chan; -} - int dma_skb_copy_datagram_iovec(struct dma_chan* chan, struct sk_buff *skb, int offset, struct iovec *to, size_t len, struct dma_pinned_list *pinned_list); diff --git a/kernel/cred.c b/kernel/cred.c index ff7bc071991c..043f78c133c4 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -506,6 +506,7 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) else old = get_cred(&init_cred); + *new = *old; get_uid(new->user); get_group_info(new->group_info); @@ -529,6 +530,7 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) error: put_cred(new); + put_cred(old); return NULL; } EXPORT_SYMBOL(prepare_kernel_cred); diff --git a/kernel/power/disk.c b/kernel/power/disk.c index f77d3819ef57..45e8541ab7e3 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c @@ -258,12 +258,12 @@ int hibernation_snapshot(int platform_mode) { int error; - /* Free memory before shutting down devices. */ - error = swsusp_shrink_memory(); + error = platform_begin(platform_mode); if (error) return error; - error = platform_begin(platform_mode); + /* Free memory before shutting down devices. */ + error = swsusp_shrink_memory(); if (error) goto Close; diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 5d2ab836e998..f5fc2d7680f2 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -25,6 +25,7 @@ #include <linux/syscalls.h> #include <linux/console.h> #include <linux/highmem.h> +#include <linux/list.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> @@ -192,12 +193,6 @@ static void *chain_alloc(struct chain_allocator *ca, unsigned int size) return ret; } -static void chain_free(struct chain_allocator *ca, int clear_page_nosave) -{ - free_list_of_pages(ca->chain, clear_page_nosave); - memset(ca, 0, sizeof(struct chain_allocator)); -} - /** * Data types related to memory bitmaps. * @@ -233,7 +228,7 @@ static void chain_free(struct chain_allocator *ca, int clear_page_nosave) #define BM_BITS_PER_BLOCK (PAGE_SIZE << 3) struct bm_block { - struct bm_block *next; /* next element of the list */ + struct list_head hook; /* hook into a list of bitmap blocks */ unsigned long start_pfn; /* pfn represented by the first bit */ unsigned long end_pfn; /* pfn represented by the last bit plus 1 */ unsigned long *data; /* bitmap representing pages */ @@ -244,24 +239,15 @@ static inline unsigned long bm_block_bits(struct bm_block *bb) return bb->end_pfn - bb->start_pfn; } -struct zone_bitmap { - struct zone_bitmap *next; /* next element of the list */ - unsigned long start_pfn; /* minimal pfn in this zone */ - unsigned long end_pfn; /* maximal pfn in this zone plus 1 */ - struct bm_block *bm_blocks; /* list of bitmap blocks */ - struct bm_block *cur_block; /* recently used bitmap block */ -}; - /* strcut bm_position is used for browsing memory bitmaps */ struct bm_position { - struct zone_bitmap *zone_bm; struct bm_block *block; int bit; }; struct memory_bitmap { - struct zone_bitmap *zone_bm_list; /* list of zone bitmaps */ + struct list_head blocks; /* list of bitmap blocks */ struct linked_page *p_list; /* list of pages used to store zone * bitmap objects and bitmap block * objects @@ -273,11 +259,7 @@ struct memory_bitmap { static void memory_bm_position_reset(struct memory_bitmap *bm) { - struct zone_bitmap *zone_bm; - - zone_bm = bm->zone_bm_list; - bm->cur.zone_bm = zone_bm; - bm->cur.block = zone_bm->bm_blocks; + bm->cur.block = list_entry(bm->blocks.next, struct bm_block, hook); bm->cur.bit = 0; } @@ -285,151 +267,184 @@ static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free); /** * create_bm_block_list - create a list of block bitmap objects + * @nr_blocks - number of blocks to allocate + * @list - list to put the allocated blocks into + * @ca - chain allocator to be used for allocating memory */ - -static inline struct bm_block * -create_bm_block_list(unsigned int nr_blocks, struct chain_allocator *ca) +static int create_bm_block_list(unsigned long pages, + struct list_head *list, + struct chain_allocator *ca) { - struct bm_block *bblist = NULL; + unsigned int nr_blocks = DIV_ROUND_UP(pages, BM_BITS_PER_BLOCK); while (nr_blocks-- > 0) { struct bm_block *bb; bb = chain_alloc(ca, sizeof(struct bm_block)); if (!bb) - return NULL; - - bb->next = bblist; - bblist = bb; + return -ENOMEM; + list_add(&bb->hook, list); } - return bblist; + + return 0; } +struct mem_extent { + struct list_head hook; + unsigned long start; + unsigned long end; +}; + /** - * create_zone_bm_list - create a list of zone bitmap objects + * free_mem_extents - free a list of memory extents + * @list - list of extents to empty */ +static void free_mem_extents(struct list_head *list) +{ + struct mem_extent *ext, *aux; -static inline struct zone_bitmap * -create_zone_bm_list(unsigned int nr_zones, struct chain_allocator *ca) + list_for_each_entry_safe(ext, aux, list, hook) { + list_del(&ext->hook); + kfree(ext); + } +} + +/** + * create_mem_extents - create a list of memory extents representing + * contiguous ranges of PFNs + * @list - list to put the extents into + * @gfp_mask - mask to use for memory allocations + */ +static int create_mem_extents(struct list_head *list, gfp_t gfp_mask) { - struct zone_bitmap *zbmlist = NULL; + struct zone *zone; - while (nr_zones-- > 0) { - struct zone_bitmap *zbm; + INIT_LIST_HEAD(list); - zbm = chain_alloc(ca, sizeof(struct zone_bitmap)); - if (!zbm) - return NULL; + for_each_zone(zone) { + unsigned long zone_start, zone_end; + struct mem_extent *ext, *cur, *aux; + + if (!populated_zone(zone)) + continue; - zbm->next = zbmlist; - zbmlist = zbm; + zone_start = zone->zone_start_pfn; + zone_end = zone->zone_start_pfn + zone->spanned_pages; + + list_for_each_entry(ext, list, hook) + if (zone_start <= ext->end) + break; + + if (&ext->hook == list || zone_end < ext->start) { + /* New extent is necessary */ + struct mem_extent *new_ext; + + new_ext = kzalloc(sizeof(struct mem_extent), gfp_mask); + if (!new_ext) { + free_mem_extents(list); + return -ENOMEM; + } + new_ext->start = zone_start; + new_ext->end = zone_end; + list_add_tail(&new_ext->hook, &ext->hook); + continue; + } + + /* Merge this zone's range of PFNs with the existing one */ + if (zone_start < ext->start) + ext->start = zone_start; + if (zone_end > ext->end) + ext->end = zone_end; + + /* More merging may be possible */ + cur = ext; + list_for_each_entry_safe_continue(cur, aux, list, hook) { + if (zone_end < cur->start) + break; + if (zone_end < cur->end) + ext->end = cur->end; + list_del(&cur->hook); + kfree(cur); + } } - return zbmlist; + + return 0; } /** * memory_bm_create - allocate memory for a memory bitmap */ - static int memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask, int safe_needed) { struct chain_allocator ca; - struct zone *zone; - struct zone_bitmap *zone_bm; - struct bm_block *bb; - unsigned int nr; + struct list_head mem_extents; + struct mem_extent *ext; + int error; chain_init(&ca, gfp_mask, safe_needed); + INIT_LIST_HEAD(&bm->blocks); - /* Compute the number of zones */ - nr = 0; - for_each_zone(zone) - if (populated_zone(zone)) - nr++; - - /* Allocate the list of zones bitmap objects */ - zone_bm = create_zone_bm_list(nr, &ca); - bm->zone_bm_list = zone_bm; - if (!zone_bm) { - chain_free(&ca, PG_UNSAFE_CLEAR); - return -ENOMEM; - } - - /* Initialize the zone bitmap objects */ - for_each_zone(zone) { - unsigned long pfn; + error = create_mem_extents(&mem_extents, gfp_mask); + if (error) + return error; - if (!populated_zone(zone)) - continue; + list_for_each_entry(ext, &mem_extents, hook) { + struct bm_block *bb; + unsigned long pfn = ext->start; + unsigned long pages = ext->end - ext->start; - zone_bm->start_pfn = zone->zone_start_pfn; - zone_bm->end_pfn = zone->zone_start_pfn + zone->spanned_pages; - /* Allocate the list of bitmap block objects */ - nr = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK); - bb = create_bm_block_list(nr, &ca); - zone_bm->bm_blocks = bb; - zone_bm->cur_block = bb; - if (!bb) - goto Free; + bb = list_entry(bm->blocks.prev, struct bm_block, hook); - nr = zone->spanned_pages; - pfn = zone->zone_start_pfn; - /* Initialize the bitmap block objects */ - while (bb) { - unsigned long *ptr; + error = create_bm_block_list(pages, bm->blocks.prev, &ca); + if (error) + goto Error; - ptr = get_image_page(gfp_mask, safe_needed); - bb->data = ptr; - if (!ptr) - goto Free; + list_for_each_entry_continue(bb, &bm->blocks, hook) { + bb->data = get_image_page(gfp_mask, safe_needed); + if (!bb->data) { + error = -ENOMEM; + goto Error; + } bb->start_pfn = pfn; - if (nr >= BM_BITS_PER_BLOCK) { + if (pages >= BM_BITS_PER_BLOCK) { pfn += BM_BITS_PER_BLOCK; - nr -= BM_BITS_PER_BLOCK; + pages -= BM_BITS_PER_BLOCK; } else { /* This is executed only once in the loop */ - pfn += nr; + pfn += pages; } bb->end_pfn = pfn; - bb = bb->next; } - zone_bm = zone_bm->next; } + bm->p_list = ca.chain; memory_bm_position_reset(bm); - return 0; + Exit: + free_mem_extents(&mem_extents); + return error; - Free: + Error: bm->p_list = ca.chain; memory_bm_free(bm, PG_UNSAFE_CLEAR); - return -ENOMEM; + goto Exit; } /** * memory_bm_free - free memory occupied by the memory bitmap @bm */ - static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free) { - struct zone_bitmap *zone_bm; + struct bm_block *bb; - /* Free the list of bit blocks for each zone_bitmap object */ - zone_bm = bm->zone_bm_list; - while (zone_bm) { - struct bm_block *bb; + list_for_each_entry(bb, &bm->blocks, hook) + if (bb->data) + free_image_page(bb->data, clear_nosave_free); - bb = zone_bm->bm_blocks; - while (bb) { - if (bb->data) - free_image_page(bb->data, clear_nosave_free); - bb = bb->next; - } - zone_bm = zone_bm->next; - } free_list_of_pages(bm->p_list, clear_nosave_free); - bm->zone_bm_list = NULL; + + INIT_LIST_HEAD(&bm->blocks); } /** @@ -437,38 +452,33 @@ static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free) * to given pfn. The cur_zone_bm member of @bm and the cur_block member * of @bm->cur_zone_bm are updated. */ - static int memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn, void **addr, unsigned int *bit_nr) { - struct zone_bitmap *zone_bm; struct bm_block *bb; - /* Check if the pfn is from the current zone */ - zone_bm = bm->cur.zone_bm; - if (pfn < zone_bm->start_pfn || pfn >= zone_bm->end_pfn) { - zone_bm = bm->zone_bm_list; - /* We don't assume that the zones are sorted by pfns */ - while (pfn < zone_bm->start_pfn || pfn >= zone_bm->end_pfn) { - zone_bm = zone_bm->next; - - if (!zone_bm) - return -EFAULT; - } - bm->cur.zone_bm = zone_bm; - } - /* Check if the pfn corresponds to the current bitmap block */ - bb = zone_bm->cur_block; + /* + * Check if the pfn corresponds to the current bitmap block and find + * the block where it fits if this is not the case. + */ + bb = bm->cur.block; if (pfn < bb->start_pfn) - bb = zone_bm->bm_blocks; + list_for_each_entry_continue_reverse(bb, &bm->blocks, hook) + if (pfn >= bb->start_pfn) + break; - while (pfn >= bb->end_pfn) { - bb = bb->next; + if (pfn >= bb->end_pfn) + list_for_each_entry_continue(bb, &bm->blocks, hook) + if (pfn >= bb->start_pfn && pfn < bb->end_pfn) + break; - BUG_ON(!bb); - } - zone_bm->cur_block = bb; + if (&bb->hook == &bm->blocks) + return -EFAULT; + + /* The block has been found */ + bm->cur.block = bb; pfn -= bb->start_pfn; + bm->cur.bit = pfn + 1; *bit_nr = pfn; *addr = bb->data; return 0; @@ -519,6 +529,14 @@ static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn) return test_bit(bit, addr); } +static bool memory_bm_pfn_present(struct memory_bitmap *bm, unsigned long pfn) +{ + void *addr; + unsigned int bit; + + return !memory_bm_find_bit(bm, pfn, &addr, &bit); +} + /** * memory_bm_next_pfn - find the pfn that corresponds to the next set bit * in the bitmap @bm. If the pfn cannot be found, BM_END_OF_MAP is @@ -530,29 +548,21 @@ static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn) static unsigned long memory_bm_next_pfn(struct memory_bitmap *bm) { - struct zone_bitmap *zone_bm; struct bm_block *bb; int bit; + bb = bm->cur.block; do { - bb = bm->cur.block; - do { - bit = bm->cur.bit; - bit = find_next_bit(bb->data, bm_block_bits(bb), bit); - if (bit < bm_block_bits(bb)) - goto Return_pfn; - - bb = bb->next; - bm->cur.block = bb; - bm->cur.bit = 0; - } while (bb); - zone_bm = bm->cur.zone_bm->next; - if (zone_bm) { - bm->cur.zone_bm = zone_bm; - bm->cur.block = zone_bm->bm_blocks; - bm->cur.bit = 0; - } - } while (zone_bm); + bit = bm->cur.bit; + bit = find_next_bit(bb->data, bm_block_bits(bb), bit); + if (bit < bm_block_bits(bb)) + goto Return_pfn; + + bb = list_entry(bb->hook.next, struct bm_block, hook); + bm->cur.block = bb; + bm->cur.bit = 0; + } while (&bb->hook != &bm->blocks); + memory_bm_position_reset(bm); return BM_END_OF_MAP; @@ -808,8 +818,7 @@ static unsigned int count_free_highmem_pages(void) * We should save the page if it isn't Nosave or NosaveFree, or Reserved, * and it isn't a part of a free chunk of pages. */ - -static struct page *saveable_highmem_page(unsigned long pfn) +static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn) { struct page *page; @@ -817,6 +826,8 @@ static struct page *saveable_highmem_page(unsigned long pfn) return NULL; page = pfn_to_page(pfn); + if (page_zone(page) != zone) + return NULL; BUG_ON(!PageHighMem(page)); @@ -846,13 +857,16 @@ unsigned int count_highmem_pages(void) mark_free_pages(zone); max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) - if (saveable_highmem_page(pfn)) + if (saveable_highmem_page(zone, pfn)) n++; } return n; } #else -static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; } +static inline void *saveable_highmem_page(struct zone *z, unsigned long p) +{ + return NULL; +} #endif /* CONFIG_HIGHMEM */ /** @@ -863,8 +877,7 @@ static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; } * of pages statically defined as 'unsaveable', and it isn't a part of * a free chunk of pages. */ - -static struct page *saveable_page(unsigned long pfn) +static struct page *saveable_page(struct zone *zone, unsigned long pfn) { struct page *page; @@ -872,6 +885,8 @@ static struct page *saveable_page(unsigned long pfn) return NULL; page = pfn_to_page(pfn); + if (page_zone(page) != zone) + return NULL; BUG_ON(PageHighMem(page)); @@ -903,7 +918,7 @@ unsigned int count_data_pages(void) mark_free_pages(zone); max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) - if(saveable_page(pfn)) + if (saveable_page(zone, pfn)) n++; } return n; @@ -944,7 +959,7 @@ static inline struct page * page_is_saveable(struct zone *zone, unsigned long pfn) { return is_highmem(zone) ? - saveable_highmem_page(pfn) : saveable_page(pfn); + saveable_highmem_page(zone, pfn) : saveable_page(zone, pfn); } static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) @@ -966,7 +981,7 @@ static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) * data modified by kmap_atomic() */ safe_copy_page(buffer, s_page); - dst = kmap_atomic(pfn_to_page(dst_pfn), KM_USER0); + dst = kmap_atomic(d_page, KM_USER0); memcpy(dst, buffer, PAGE_SIZE); kunmap_atomic(dst, KM_USER0); } else { @@ -975,7 +990,7 @@ static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) } } #else -#define page_is_saveable(zone, pfn) saveable_page(pfn) +#define page_is_saveable(zone, pfn) saveable_page(zone, pfn) static inline void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) { @@ -1459,9 +1474,7 @@ load_header(struct swsusp_info *info) * unpack_orig_pfns - for each element of @buf[] (1 page at a time) set * the corresponding bit in the memory bitmap @bm */ - -static inline void -unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm) +static int unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm) { int j; @@ -1469,8 +1482,13 @@ unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm) if (unlikely(buf[j] == BM_END_OF_MAP)) break; - memory_bm_set_bit(bm, buf[j]); + if (memory_bm_pfn_present(bm, buf[j])) + memory_bm_set_bit(bm, buf[j]); + else + return -EFAULT; } + + return 0; } /* List of "safe" pages that may be used to store data loaded from the suspend @@ -1608,7 +1626,7 @@ get_highmem_page_buffer(struct page *page, struct chain_allocator *ca) pbe = chain_alloc(ca, sizeof(struct highmem_pbe)); if (!pbe) { swsusp_free(); - return NULL; + return ERR_PTR(-ENOMEM); } pbe->orig_page = page; if (safe_highmem_pages > 0) { @@ -1677,7 +1695,7 @@ prepare_highmem_image(struct memory_bitmap *bm, unsigned int *nr_highmem_p) static inline void * get_highmem_page_buffer(struct page *page, struct chain_allocator *ca) { - return NULL; + return ERR_PTR(-EINVAL); } static inline void copy_last_highmem_page(void) {} @@ -1788,8 +1806,13 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm) static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca) { struct pbe *pbe; - struct page *page = pfn_to_page(memory_bm_next_pfn(bm)); + struct page *page; + unsigned long pfn = memory_bm_next_pfn(bm); + if (pfn == BM_END_OF_MAP) + return ERR_PTR(-EFAULT); + + page = pfn_to_page(pfn); if (PageHighMem(page)) return get_highmem_page_buffer(page, ca); @@ -1805,7 +1828,7 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca) pbe = chain_alloc(ca, sizeof(struct pbe)); if (!pbe) { swsusp_free(); - return NULL; + return ERR_PTR(-ENOMEM); } pbe->orig_address = page_address(page); pbe->address = safe_pages_list; @@ -1868,7 +1891,10 @@ int snapshot_write_next(struct snapshot_handle *handle, size_t count) return error; } else if (handle->prev <= nr_meta_pages) { - unpack_orig_pfns(buffer, ©_bm); + error = unpack_orig_pfns(buffer, ©_bm); + if (error) + return error; + if (handle->prev == nr_meta_pages) { error = prepare_image(&orig_bm, ©_bm); if (error) @@ -1879,12 +1905,14 @@ int snapshot_write_next(struct snapshot_handle *handle, size_t count) restore_pblist = NULL; handle->buffer = get_buffer(&orig_bm, &ca); handle->sync_read = 0; - if (!handle->buffer) - return -ENOMEM; + if (IS_ERR(handle->buffer)) + return PTR_ERR(handle->buffer); } } else { copy_last_highmem_page(); handle->buffer = get_buffer(&orig_bm, &ca); + if (IS_ERR(handle->buffer)) + return PTR_ERR(handle->buffer); if (handle->buffer != buffer) handle->sync_read = 0; } diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index 023ff2a31d89..a92c91451559 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c @@ -262,3 +262,125 @@ int swsusp_shrink_memory(void) return 0; } + +/* + * Platforms, like ACPI, may want us to save some memory used by them during + * hibernation and to restore the contents of this memory during the subsequent + * resume. The code below implements a mechanism allowing us to do that. + */ + +struct nvs_page { + unsigned long phys_start; + unsigned int size; + void *kaddr; + void *data; + struct list_head node; +}; + +static LIST_HEAD(nvs_list); + +/** + * hibernate_nvs_register - register platform NVS memory region to save + * @start - physical address of the region + * @size - size of the region + * + * The NVS region need not be page-aligned (both ends) and we arrange + * things so that the data from page-aligned addresses in this region will + * be copied into separate RAM pages. + */ +int hibernate_nvs_register(unsigned long start, unsigned long size) +{ + struct nvs_page *entry, *next; + + while (size > 0) { + unsigned int nr_bytes; + + entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL); + if (!entry) + goto Error; + + list_add_tail(&entry->node, &nvs_list); + entry->phys_start = start; + nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK); + entry->size = (size < nr_bytes) ? size : nr_bytes; + + start += entry->size; + size -= entry->size; + } + return 0; + + Error: + list_for_each_entry_safe(entry, next, &nvs_list, node) { + list_del(&entry->node); + kfree(entry); + } + return -ENOMEM; +} + +/** + * hibernate_nvs_free - free data pages allocated for saving NVS regions + */ +void hibernate_nvs_free(void) +{ + struct nvs_page *entry; + + list_for_each_entry(entry, &nvs_list, node) + if (entry->data) { + free_page((unsigned long)entry->data); + entry->data = NULL; + if (entry->kaddr) { + iounmap(entry->kaddr); + entry->kaddr = NULL; + } + } +} + +/** + * hibernate_nvs_alloc - allocate memory necessary for saving NVS regions + */ +int hibernate_nvs_alloc(void) +{ + struct nvs_page *entry; + + list_for_each_entry(entry, &nvs_list, node) { + entry->data = (void *)__get_free_page(GFP_KERNEL); + if (!entry->data) { + hibernate_nvs_free(); + return -ENOMEM; + } + } + return 0; +} + +/** + * hibernate_nvs_save - save NVS memory regions + */ +void hibernate_nvs_save(void) +{ + struct nvs_page *entry; + + printk(KERN_INFO "PM: Saving platform NVS memory\n"); + + list_for_each_entry(entry, &nvs_list, node) + if (entry->data) { + entry->kaddr = ioremap(entry->phys_start, entry->size); + memcpy(entry->data, entry->kaddr, entry->size); + } +} + +/** + * hibernate_nvs_restore - restore NVS memory regions + * + * This function is going to be called with interrupts disabled, so it + * cannot iounmap the virtual addresses used to access the NVS region. + */ +void hibernate_nvs_restore(void) +{ + struct nvs_page *entry; + + printk(KERN_INFO "PM: Restoring platform NVS memory\n"); + + list_for_each_entry(entry, &nvs_list, node) + if (entry->data) + memcpy(entry->kaddr, entry->data, entry->size); +} diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index a9d9760dc7b6..8b0daf0662ef 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -168,7 +168,13 @@ rb_event_length(struct ring_buffer_event *event) */ unsigned ring_buffer_event_length(struct ring_buffer_event *event) { - return rb_event_length(event); + unsigned length = rb_event_length(event); + if (event->type != RINGBUF_TYPE_DATA) + return length; + length -= RB_EVNT_HDR_SIZE; + if (length > RB_MAX_SMALL_DATA + sizeof(event->array[0])) + length -= sizeof(event->array[0]); + return length; } EXPORT_SYMBOL_GPL(ring_buffer_event_length); diff --git a/net/core/dev.c b/net/core/dev.c index bab8bcedd62e..5f736f1ceeae 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -170,25 +170,6 @@ static DEFINE_SPINLOCK(ptype_lock); static struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly; static struct list_head ptype_all __read_mostly; /* Taps */ -#ifdef CONFIG_NET_DMA -struct net_dma { - struct dma_client client; - spinlock_t lock; - cpumask_t channel_mask; - struct dma_chan **channels; -}; - -static enum dma_state_client -netdev_dma_event(struct dma_client *client, struct dma_chan *chan, - enum dma_state state); - -static struct net_dma net_dma = { - .client = { - .event_callback = netdev_dma_event, - }, -}; -#endif - /* * The @dev_base_head list is protected by @dev_base_lock and the rtnl * semaphore. @@ -2754,14 +2735,7 @@ out: * There may not be any more sk_buffs coming right now, so push * any pending DMA copies to hardware */ - if (!cpus_empty(net_dma.channel_mask)) { - int chan_idx; - for_each_cpu_mask_nr(chan_idx, net_dma.channel_mask) { - struct dma_chan *chan = net_dma.channels[chan_idx]; - if (chan) - dma_async_memcpy_issue_pending(chan); - } - } + dma_issue_pending_all(); #endif return; @@ -4952,122 +4926,6 @@ static int dev_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -#ifdef CONFIG_NET_DMA -/** - * net_dma_rebalance - try to maintain one DMA channel per CPU - * @net_dma: DMA client and associated data (lock, channels, channel_mask) - * - * This is called when the number of channels allocated to the net_dma client - * changes. The net_dma client tries to have one DMA channel per CPU. - */ - -static void net_dma_rebalance(struct net_dma *net_dma) -{ - unsigned int cpu, i, n, chan_idx; - struct dma_chan *chan; - - if (cpus_empty(net_dma->channel_mask)) { - for_each_online_cpu(cpu) - rcu_assign_pointer(per_cpu(softnet_data, cpu).net_dma, NULL); - return; - } - - i = 0; - cpu = first_cpu(cpu_online_map); - - for_each_cpu_mask_nr(chan_idx, net_dma->channel_mask) { - chan = net_dma->channels[chan_idx]; - - n = ((num_online_cpus() / cpus_weight(net_dma->channel_mask)) - + (i < (num_online_cpus() % - cpus_weight(net_dma->channel_mask)) ? 1 : 0)); - - while(n) { - per_cpu(softnet_data, cpu).net_dma = chan; - cpu = next_cpu(cpu, cpu_online_map); - n--; - } - i++; - } -} - -/** - * netdev_dma_event - event callback for the net_dma_client - * @client: should always be net_dma_client - * @chan: DMA channel for the event - * @state: DMA state to be handled - */ -static enum dma_state_client -netdev_dma_event(struct dma_client *client, struct dma_chan *chan, - enum dma_state state) -{ - int i, found = 0, pos = -1; - struct net_dma *net_dma = - container_of(client, struct net_dma, client); - enum dma_state_client ack = DMA_DUP; /* default: take no action */ - - spin_lock(&net_dma->lock); - switch (state) { - case DMA_RESOURCE_AVAILABLE: - for (i = 0; i < nr_cpu_ids; i++) - if (net_dma->channels[i] == chan) { - found = 1; - break; - } else if (net_dma->channels[i] == NULL && pos < 0) - pos = i; - - if (!found && pos >= 0) { - ack = DMA_ACK; - net_dma->channels[pos] = chan; - cpu_set(pos, net_dma->channel_mask); - net_dma_rebalance(net_dma); - } - break; - case DMA_RESOURCE_REMOVED: - for (i = 0; i < nr_cpu_ids; i++) - if (net_dma->channels[i] == chan) { - found = 1; - pos = i; - break; - } - - if (found) { - ack = DMA_ACK; - cpu_clear(pos, net_dma->channel_mask); - net_dma->channels[i] = NULL; - net_dma_rebalance(net_dma); - } - break; - default: - break; - } - spin_unlock(&net_dma->lock); - - return ack; -} - -/** - * netdev_dma_register - register the networking subsystem as a DMA client - */ -static int __init netdev_dma_register(void) -{ - net_dma.channels = kzalloc(nr_cpu_ids * sizeof(struct net_dma), - GFP_KERNEL); - if (unlikely(!net_dma.channels)) { - printk(KERN_NOTICE - "netdev_dma: no memory for net_dma.channels\n"); - return -ENOMEM; - } - spin_lock_init(&net_dma.lock); - dma_cap_set(DMA_MEMCPY, net_dma.client.cap_mask); - dma_async_client_register(&net_dma.client); - dma_async_client_chan_request(&net_dma.client); - return 0; -} - -#else -static int __init netdev_dma_register(void) { return -ENODEV; } -#endif /* CONFIG_NET_DMA */ /** * netdev_increment_features - increment feature set by one @@ -5287,14 +5145,15 @@ static int __init net_dev_init(void) if (register_pernet_device(&default_device_ops)) goto out; - netdev_dma_register(); - open_softirq(NET_TX_SOFTIRQ, net_tx_action); open_softirq(NET_RX_SOFTIRQ, net_rx_action); hotcpu_notifier(dev_cpu_callback, 0); dst_init(); dev_mcast_init(); + #ifdef CONFIG_NET_DMA + dmaengine_get(); + #endif rc = 0; out: return rc; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index bd6ff907d9e4..ce572f9dff02 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1313,7 +1313,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if ((available < target) && (len > sysctl_tcp_dma_copybreak) && !(flags & MSG_PEEK) && !sysctl_tcp_low_latency && - __get_cpu_var(softnet_data).net_dma) { + dma_find_channel(DMA_MEMCPY)) { preempt_enable_no_resched(); tp->ucopy.pinned_list = dma_pin_iovec_pages(msg->msg_iov, len); @@ -1523,7 +1523,7 @@ do_prequeue: if (!(flags & MSG_TRUNC)) { #ifdef CONFIG_NET_DMA if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list) - tp->ucopy.dma_chan = get_softnet_dma(); + tp->ucopy.dma_chan = dma_find_channel(DMA_MEMCPY); if (tp->ucopy.dma_chan) { tp->ucopy.dma_cookie = dma_skb_copy_datagram_iovec( @@ -1628,7 +1628,6 @@ skip_copy: /* Safe to free early-copied skbs now */ __skb_queue_purge(&sk->sk_async_wait_queue); - dma_chan_put(tp->ucopy.dma_chan); tp->ucopy.dma_chan = NULL; } if (tp->ucopy.pinned_list) { diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 99b7ecbe8893..a6961d75c7ea 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5005,7 +5005,7 @@ static int tcp_dma_try_early_copy(struct sock *sk, struct sk_buff *skb, return 0; if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list) - tp->ucopy.dma_chan = get_softnet_dma(); + tp->ucopy.dma_chan = dma_find_channel(DMA_MEMCPY); if (tp->ucopy.dma_chan && skb_csum_unnecessary(skb)) { diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 9d839fa9331e..19d7b429a262 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1594,7 +1594,7 @@ process: #ifdef CONFIG_NET_DMA struct tcp_sock *tp = tcp_sk(sk); if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list) - tp->ucopy.dma_chan = get_softnet_dma(); + tp->ucopy.dma_chan = dma_find_channel(DMA_MEMCPY); if (tp->ucopy.dma_chan) ret = tcp_v4_do_rcv(sk, skb); else diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 1297306d729c..e5b85d45bee8 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1675,7 +1675,7 @@ process: #ifdef CONFIG_NET_DMA struct tcp_sock *tp = tcp_sk(sk); if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list) - tp->ucopy.dma_chan = get_softnet_dma(); + tp->ucopy.dma_chan = dma_find_channel(DMA_MEMCPY); if (tp->ucopy.dma_chan) ret = tcp_v6_do_rcv(sk, skb); else |