LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Regression in 32-bit ppc kernel
From: Larry Finger @ 2012-04-24 22:58 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Paul Mackerras; +Cc: linuxppc-dev, LKML

Hi,

Somewhere between v3.2 and v3.3, the kernel in my Powerbook G4 started issuing 
the following traceback on bootup:

[   40.264006] irq 23: nobody cared (try booting with the "irqpoll" option)
[   40.264031] Call Trace:
[   40.264070] [dfff3f00] [c000984c] show_stack+0x7c/0x194 (unreliable)
[   40.264102] [dfff3f40] [c00a6840] __report_bad_irq+0x44/0xf4
[   40.264119] [dfff3f60] [c00a6adc] note_interrupt+0x1ec/0x2ac
[   40.264135] [dfff3f80] [c00a48a8] handle_irq_event_percpu+0x250/0x2b8
[   40.264152] [dfff3fd0] [c00a4944] handle_irq_event+0x34/0x54
[   40.264169] [dfff3fe0] [c00a7514] handle_fasteoi_irq+0xb4/0x124
[   40.264192] [dfff3ff0] [c000f5bc] call_handle_irq+0x18/0x28
[   40.264208] [dec85ce0] [c000719c] do_IRQ+0x114/0x1cc
[   40.264226] [dec85d10] [c0015868] ret_from_except+0x0/0x1c
[   40.264254] --- Exception: 501 at find_vma+0x10/0x80
[   40.264259]     LR = do_page_fault+0x26c/0x6ac
[   40.264272] [dec85dd0] [c03f0128] do_page_fault+0x25c/0x6ac (unreliable)
[   40.264289] [dec85f40] [c00155e4] handle_page_fault+0xc/0x80
[   40.264327] --- Exception: 301 at 0x4800a174

The problem still exists in v3.4-rc3. I am currently doing a bisection of this 
problem, but it will take a long time to complete.

Note: IRQ 23 is not active in v3.2.

Thanks,

Larry

^ permalink raw reply

* Re: Regression in 32-bit ppc kernel
From: Benjamin Herrenschmidt @ 2012-04-24 23:53 UTC (permalink / raw)
  To: Larry Finger; +Cc: linuxppc-dev, Paul Mackerras, LKML
In-Reply-To: <4F973026.3020103@lwfinger.net>

On Tue, 2012-04-24 at 17:58 -0500, Larry Finger wrote:
> Hi,
> 
> Somewhere between v3.2 and v3.3, the kernel in my Powerbook G4 started issuing 
> the following traceback on bootup:

Does it continue working afterward or not at all ?

Are you using the old IDE driver or the newer libata based pata_macio ?

Cheers,
Ben.

> [   40.264006] irq 23: nobody cared (try booting with the "irqpoll" option)
> [   40.264031] Call Trace:
> [   40.264070] [dfff3f00] [c000984c] show_stack+0x7c/0x194 (unreliable)
> [   40.264102] [dfff3f40] [c00a6840] __report_bad_irq+0x44/0xf4
> [   40.264119] [dfff3f60] [c00a6adc] note_interrupt+0x1ec/0x2ac
> [   40.264135] [dfff3f80] [c00a48a8] handle_irq_event_percpu+0x250/0x2b8
> [   40.264152] [dfff3fd0] [c00a4944] handle_irq_event+0x34/0x54
> [   40.264169] [dfff3fe0] [c00a7514] handle_fasteoi_irq+0xb4/0x124
> [   40.264192] [dfff3ff0] [c000f5bc] call_handle_irq+0x18/0x28
> [   40.264208] [dec85ce0] [c000719c] do_IRQ+0x114/0x1cc
> [   40.264226] [dec85d10] [c0015868] ret_from_except+0x0/0x1c
> [   40.264254] --- Exception: 501 at find_vma+0x10/0x80
> [   40.264259]     LR = do_page_fault+0x26c/0x6ac
> [   40.264272] [dec85dd0] [c03f0128] do_page_fault+0x25c/0x6ac (unreliable)
> [   40.264289] [dec85f40] [c00155e4] handle_page_fault+0xc/0x80
> [   40.264327] --- Exception: 301 at 0x4800a174
> 
> The problem still exists in v3.4-rc3. I am currently doing a bisection of this 
> problem, but it will take a long time to complete.
> 
> Note: IRQ 23 is not active in v3.2.
> 
> Thanks,
> 
> Larry

^ permalink raw reply

* 3.4-rc3 compile failed on IBM Power6
From: Ryan Wang @ 2012-04-25  0:22 UTC (permalink / raw)
  To: Nishanth Aravamudan, linuxppc-dev, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 19014 bytes --]

# gcc --version
gcc (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3)
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

platform    : pSeries
model        : IBM,9117-MMA
machine        : CHRP IBM,9117-MMA



# make O=../build/3.4-rc4/
  GEN     /usr/src/kernels/build/3.4-rc4/Makefile
  HOSTLD  scripts/kconfig/conf
scripts/kconfig/conf --silentoldconfig Kconfig
  Using /usr/src/kernels/linux as source for kernel
  GEN     /usr/src/kernels/build/3.4-rc4/Makefile
  WRAP    arch/powerpc/include/generated/asm/rwsem.h
  CHK     include/linux/version.h
  UPD     include/linux/version.h
  CHK     include/generated/utsrelease.h
  UPD     include/generated/utsrelease.h
  CC      kernel/bounds.s
  GEN     include/generated/bounds.h
  CC      arch/powerpc/kernel/asm-offsets.s
  GEN     include/generated/asm-offsets.h
  CALL    /usr/src/kernels/linux/scripts/checksyscalls.sh
  HOSTCC  scripts/dtc/checks.o
  HOSTCC  scripts/dtc/data.o
  SHIPPED scripts/dtc/dtc-lexer.lex.c
  SHIPPED scripts/dtc/dtc-parser.tab.h
  HOSTCC  scripts/dtc/dtc-lexer.lex.o
  SHIPPED scripts/dtc/dtc-parser.tab.c
  HOSTCC  scripts/dtc/dtc-parser.tab.o
  HOSTCC  scripts/dtc/dtc.o
  HOSTCC  scripts/dtc/flattree.o
  HOSTCC  scripts/dtc/fstree.o
  HOSTCC  scripts/dtc/livetree.o
  HOSTCC  scripts/dtc/srcpos.o
  HOSTCC  scripts/dtc/treesource.o
  HOSTCC  scripts/dtc/util.o
  HOSTLD  scripts/dtc/dtc
  HOSTCC  scripts/genksyms/genksyms.o
  SHIPPED scripts/genksyms/lex.lex.c
  SHIPPED scripts/genksyms/keywords.hash.c
  SHIPPED scripts/genksyms/parse.tab.h
  HOSTCC  scripts/genksyms/lex.lex.o
  SHIPPED scripts/genksyms/parse.tab.c
  HOSTCC  scripts/genksyms/parse.tab.o
  HOSTLD  scripts/genksyms/genksyms
  CC      scripts/mod/empty.o
  HOSTCC  scripts/mod/mk_elfconfig
  MKELF   scripts/mod/elfconfig.h
  HOSTCC  scripts/mod/file2alias.o
  HOSTCC  scripts/mod/modpost.o
  HOSTCC  scripts/mod/sumversion.o
  HOSTLD  scripts/mod/modpost
  HOSTCC  scripts/selinux/genheaders/genheaders
  HOSTCC  scripts/selinux/mdp/mdp
  HOSTCC  scripts/kallsyms
  HOSTCC  scripts/pnmtologo
  HOSTCC  scripts/conmakehash
  HOSTCC  scripts/bin2c
  CC      init/main.o
  CHK     include/generated/compile.h
  UPD     include/generated/compile.h
  CC      init/version.o
  CC      init/do_mounts.o
  CC      init/do_mounts_rd.o
  CC      init/do_mounts_initrd.o
  CC      init/do_mounts_md.o
  LD      init/mounts.o
  CC      init/initramfs.o
  LD      init/built-in.o
  HOSTCC  usr/gen_init_cpio
  GEN     usr/initramfs_data.cpio
  AS      usr/initramfs_data.o
  LD      usr/built-in.o
  CC      arch/powerpc/kernel/cputable.o
  CC      arch/powerpc/kernel/ptrace.o
  CC      arch/powerpc/kernel/syscalls.o
  CC      arch/powerpc/kernel/irq.o
  CC      arch/powerpc/kernel/align.o
  CC      arch/powerpc/kernel/signal_32.o
  CC      arch/powerpc/kernel/pmc.o
  CC      arch/powerpc/kernel/vdso.o
  CC      arch/powerpc/kernel/init_task.o
  CC      arch/powerpc/kernel/process.o
  CPP     arch/powerpc/kernel/systbl_chk.i
  CALL    /usr/src/kernels/linux/arch/powerpc/kernel/systbl_chk.sh
  AS      arch/powerpc/kernel/systbl.o
  CC      arch/powerpc/kernel/idle.o
  CC      arch/powerpc/kernel/signal.o
  CC      arch/powerpc/kernel/sysfs.o
  CC      arch/powerpc/kernel/cacheinfo.o
  CC      arch/powerpc/kernel/time.o
  CC      arch/powerpc/kernel/prom.o
  CC      arch/powerpc/kernel/traps.o
  CC      arch/powerpc/kernel/setup-common.o
  CC      arch/powerpc/kernel/udbg.o
  AS      arch/powerpc/kernel/misc.o
  CC      arch/powerpc/kernel/io.o
  CC      arch/powerpc/kernel/dma.o
  AS      arch/powerpc/kernel/misc_64.o
  LDS     arch/powerpc/kernel/vdso32/vdso32.lds
  VDSO32A arch/powerpc/kernel/vdso32/sigtramp.o
  VDSO32A arch/powerpc/kernel/vdso32/gettimeofday.o
  VDSO32A arch/powerpc/kernel/vdso32/datapage.o
  VDSO32A arch/powerpc/kernel/vdso32/cacheflush.o
  VDSO32A arch/powerpc/kernel/vdso32/note.o
  VDSO32L arch/powerpc/kernel/vdso32/vdso32.so.dbg
  OBJCOPY arch/powerpc/kernel/vdso32/vdso32.so
  AS      arch/powerpc/kernel/vdso32/vdso32_wrapper.o
  LD      arch/powerpc/kernel/vdso32/built-in.o
  LDS     arch/powerpc/kernel/vdso64/vdso64.lds
  VDSO64A arch/powerpc/kernel/vdso64/sigtramp.o
  VDSO64A arch/powerpc/kernel/vdso64/gettimeofday.o
  VDSO64A arch/powerpc/kernel/vdso64/datapage.o
  VDSO64A arch/powerpc/kernel/vdso64/cacheflush.o
  VDSO64A arch/powerpc/kernel/vdso64/note.o
  VDSO64L arch/powerpc/kernel/vdso64/vdso64.so.dbg
  OBJCOPY arch/powerpc/kernel/vdso64/vdso64.so
  AS      arch/powerpc/kernel/vdso64/vdso64_wrapper.o
  LD      arch/powerpc/kernel/vdso64/built-in.o
  CC      arch/powerpc/kernel/setup_64.o
  CC      arch/powerpc/kernel/sys_ppc32.o
  CC      arch/powerpc/kernel/signal_64.o
  CC      arch/powerpc/kernel/ptrace32.o
  CC      arch/powerpc/kernel/paca.o
  CC      arch/powerpc/kernel/nvram_64.o
  CC      arch/powerpc/kernel/firmware.o
  CC      arch/powerpc/kernel/hw_breakpoint.o
  AS      arch/powerpc/kernel/cpu_setup_ppc970.o
  AS      arch/powerpc/kernel/cpu_setup_pa6t.o
  AS      arch/powerpc/kernel/cpu_setup_power7.o
  CC      arch/powerpc/kernel/vecemu.o
  AS      arch/powerpc/kernel/idle_power7.o
  CC      arch/powerpc/kernel/of_platform.o
  CC      arch/powerpc/kernel/prom_parse.o
  CC      arch/powerpc/kernel/proc_powerpc.o
  CC      arch/powerpc/kernel/rtas.o
  CC      arch/powerpc/kernel/rtas-rtc.o
  CC      arch/powerpc/kernel/rtas_pci.o
  CC      arch/powerpc/kernel/rtasd.o
  CC      arch/powerpc/kernel/rtas_flash.o
  CC      arch/powerpc/kernel/rtas-proc.o
  CC      arch/powerpc/kernel/lparcfg.o
  CC      arch/powerpc/kernel/vio.o
  CC      arch/powerpc/kernel/ibmebus.o
  CC      arch/powerpc/kernel/crash_dump.o
  CC      arch/powerpc/kernel/module.o
  CC      arch/powerpc/kernel/module_64.o
  CC      arch/powerpc/kernel/dma-iommu.o
  CC      arch/powerpc/kernel/iommu.o
  CC      arch/powerpc/kernel/kgdb.o
  CC      arch/powerpc/kernel/prom_init.o
  CC      arch/powerpc/kernel/ppc_ksyms.o
  CC      arch/powerpc/kernel/btext.o
  CC      arch/powerpc/kernel/smp.o
  CC      arch/powerpc/kernel/kprobes.o
  CC      arch/powerpc/kernel/legacy_serial.o
  CC      arch/powerpc/kernel/udbg_16550.o
  CC      arch/powerpc/kernel/stacktrace.o
  CC      arch/powerpc/kernel/dma-swiotlb.o
  CC      arch/powerpc/kernel/pci_64.o
  CC      arch/powerpc/kernel/pci_dn.o
  CC      arch/powerpc/kernel/isa-bridge.o
  CC      arch/powerpc/kernel/pci-common.o
  CC      arch/powerpc/kernel/pci_of_scan.o
  CC      arch/powerpc/kernel/msi.o
  CC      arch/powerpc/kernel/machine_kexec.o
  CC      arch/powerpc/kernel/crash.o
  CC      arch/powerpc/kernel/machine_kexec_64.o
  CC      arch/powerpc/kernel/audit.o
  CC      arch/powerpc/kernel/io-workarounds.o
  AS      arch/powerpc/kernel/reloc_64.o
  CC      arch/powerpc/kernel/compat_audit.o
  AS      arch/powerpc/kernel/ppc_save_regs.o
  CALL    /usr/src/kernels/linux/arch/powerpc/kernel/prom_init_check.sh
  LD      arch/powerpc/kernel/built-in.o
WARNING: arch/powerpc/kernel/built-in.o(.text+0x2ab2c): Section mismatch in
reference from the function .prom_query_opal() to the function
.init.text:.call_prom()
The function .prom_query_opal() references
the function __init .call_prom().
This is often because .prom_query_opal lacks a __init
annotation or the annotation of .call_prom is wrong.

WARNING: arch/powerpc/kernel/built-in.o(.text+0x2ab54): Section mismatch in
reference from the function .prom_query_opal() to the function
.init.text:.call_prom()
The function .prom_query_opal() references
the function __init .call_prom().
This is often because .prom_query_opal lacks a __init
annotation or the annotation of .call_prom is wrong.

WARNING: arch/powerpc/kernel/built-in.o(.text+0x2ab64): Section mismatch in
reference from the function .prom_query_opal() to the function
.init.text:.prom_printf()
The function .prom_query_opal() references
the function __init .prom_printf().
This is often because .prom_query_opal lacks a __init
annotation or the annotation of .prom_printf is wrong.

WARNING: arch/powerpc/kernel/built-in.o(.text+0x2abbc): Section mismatch in
reference from the function .prom_query_opal() to the function
.init.text:.prom_printf()
The function .prom_query_opal() references
the function __init .prom_printf().
This is often because .prom_query_opal lacks a __init
annotation or the annotation of .prom_printf is wrong.

WARNING: arch/powerpc/kernel/built-in.o(.text+0x2ac2c): Section mismatch in
reference from the function .prom_query_opal() to the function
.init.text:.prom_printf()
The function .prom_query_opal() references
the function __init .prom_printf().
This is often because .prom_query_opal lacks a __init
annotation or the annotation of .prom_printf is wrong.

WARNING: arch/powerpc/kernel/built-in.o(.text+0x2ac4c): Section mismatch in
reference from the function .prom_query_opal() to the function
.init.text:.prom_printf()
The function .prom_query_opal() references
the function __init .prom_printf().
This is often because .prom_query_opal lacks a __init
annotation or the annotation of .prom_printf is wrong.

WARNING: arch/powerpc/kernel/built-in.o(.text+0x2af40): Section mismatch in
reference from the function .prom_opal_takeover() to the function
.init.text:.prom_printf()
The function .prom_opal_takeover() references
the function __init .prom_printf().
This is often because .prom_opal_takeover lacks a __init
annotation or the annotation of .prom_printf is wrong.

WARNING: arch/powerpc/kernel/built-in.o(.text+0x2af44): Section mismatch in
reference from the function .prom_opal_takeover() to the function
.init.text:.prom_close_stdin()
The function .prom_opal_takeover() references
the function __init .prom_close_stdin().
This is often because .prom_opal_takeover lacks a __init
annotation or the annotation of .prom_close_stdin is wrong.

  AS      arch/powerpc/kernel/head_64.o
  LDS     arch/powerpc/kernel/vmlinux.lds
  AS      arch/powerpc/kernel/fpu.o
  AS      arch/powerpc/kernel/vector.o
  AS      arch/powerpc/kernel/entry_64.o
  CC      arch/powerpc/mm/fault.o
  CC      arch/powerpc/mm/mem.o
  CC      arch/powerpc/mm/pgtable.o
  CC      arch/powerpc/mm/gup.o
  CC      arch/powerpc/mm/init_64.o
  CC      arch/powerpc/mm/pgtable_64.o
  CC      arch/powerpc/mm/mmap_64.o
  CC      arch/powerpc/mm/hash_utils_64.o
  AS      arch/powerpc/mm/slb_low.o
  CC      arch/powerpc/mm/slb.o
  CC      arch/powerpc/mm/stab.o
  CC      arch/powerpc/mm/hash_native_64.o
  AS      arch/powerpc/mm/hash_low_64.o
  CC      arch/powerpc/mm/tlb_hash64.o
  CC      arch/powerpc/mm/mmu_context_hash64.o
  CC      arch/powerpc/mm/numa.o
  CC      arch/powerpc/mm/slice.o
  CC      arch/powerpc/mm/hugetlbpage.o
  CC      arch/powerpc/mm/hugetlbpage-hash64.o
  CC      arch/powerpc/mm/subpage-prot.o
  LD      arch/powerpc/mm/built-in.o
  AS      arch/powerpc/lib/string.o
  CC      arch/powerpc/lib/alloc.o
  AS      arch/powerpc/lib/checksum_64.o
  AS      arch/powerpc/lib/crtsavres.o
  CC      arch/powerpc/lib/devres.o
  AS      arch/powerpc/lib/copypage_64.o
  AS      arch/powerpc/lib/copyuser_64.o
  AS      arch/powerpc/lib/memcpy_64.o
  CC      arch/powerpc/lib/usercopy_64.o
  AS      arch/powerpc/lib/mem_64.o
  CC      arch/powerpc/lib/checksum_wrappers_64.o
  AS      arch/powerpc/lib/hweight_64.o
  AS      arch/powerpc/lib/copyuser_power7.o
  CC      arch/powerpc/lib/sstep.o
  AS      arch/powerpc/lib/ldstfp.o
  CC      arch/powerpc/lib/locks.o
  CC      arch/powerpc/lib/copyuser_power7_vmx.o
  CC      arch/powerpc/lib/code-patching.o
  CC      arch/powerpc/lib/feature-fixups.o
  LD      arch/powerpc/lib/built-in.o
  CC      arch/powerpc/sysdev/mpic.o
  CC      arch/powerpc/sysdev/mpic_msi.o
  CC      arch/powerpc/sysdev/mpic_u3msi.o
  CC      arch/powerpc/sysdev/mpic_pasemi_msi.o
  CC      arch/powerpc/sysdev/msi_bitmap.o
  CC      arch/powerpc/sysdev/pmi.o
  CC      arch/powerpc/sysdev/mmio_nvram.o
  CC      arch/powerpc/sysdev/simple_gpio.o
  CC      arch/powerpc/sysdev/rtc_cmos_setup.o
  CC      arch/powerpc/sysdev/i8259.o
  CC      arch/powerpc/sysdev/dcr.o
  CC      arch/powerpc/sysdev/xics/xics-common.o
  CC      arch/powerpc/sysdev/xics/icp-native.o
  CC      arch/powerpc/sysdev/xics/icp-hv.o
  CC      arch/powerpc/sysdev/xics/ics-rtas.o
  CC      arch/powerpc/sysdev/xics/ics-opal.o
  LD      arch/powerpc/sysdev/xics/built-in.o
WARNING: arch/powerpc/sysdev/xics/built-in.o(.text+0x1624): Section
mismatch in reference from the function .ics_rtas_init() to the function
.init.text:.xics_register_ics()
The function .ics_rtas_init() references
the function __init .xics_register_ics().
This is often because .ics_rtas_init lacks a __init
annotation or the annotation of .xics_register_ics is wrong.

  LD      arch/powerpc/sysdev/built-in.o
WARNING: arch/powerpc/sysdev/built-in.o(.text+0x8de4): Section mismatch in
reference from the function .ics_rtas_init() to the function
.init.text:.xics_register_ics()
The function .ics_rtas_init() references
the function __init .xics_register_ics().
This is often because .ics_rtas_init lacks a __init
annotation or the annotation of .xics_register_ics is wrong.

  CC [M]  arch/powerpc/sysdev/axonram.o
  CC      arch/powerpc/platforms/cell/cbe_regs.o
  CC      arch/powerpc/platforms/cell/interrupt.o
  CC      arch/powerpc/platforms/cell/pervasive.o
  CC      arch/powerpc/platforms/cell/iommu.o
  CC      arch/powerpc/platforms/cell/setup.o
  CC      arch/powerpc/platforms/cell/spider-pic.o
  CC      arch/powerpc/platforms/cell/pmu.o
  CC      arch/powerpc/platforms/cell/spider-pci.o
  CC      arch/powerpc/platforms/cell/ras.o
  CC      arch/powerpc/platforms/cell/cbe_powerbutton.o
  CC      arch/powerpc/platforms/cell/smp.o
  CC      arch/powerpc/platforms/cell/spu_callbacks.o
  CC      arch/powerpc/platforms/cell/spu_base.o
  CC      arch/powerpc/platforms/cell/spu_notify.o
  CC      arch/powerpc/platforms/cell/spu_syscalls.o
  CC      arch/powerpc/platforms/cell/spu_fault.o
  CC      arch/powerpc/platforms/cell/spu_priv1_mmio.o
  CC      arch/powerpc/platforms/cell/spu_manage.o
  LD      arch/powerpc/platforms/cell/spufs/built-in.o
  CC [M]  arch/powerpc/platforms/cell/spufs/inode.o
  CC [M]  arch/powerpc/platforms/cell/spufs/file.o
  CC [M]  arch/powerpc/platforms/cell/spufs/context.o
  CC [M]  arch/powerpc/platforms/cell/spufs/syscalls.o
  CC [M]  arch/powerpc/platforms/cell/spufs/coredump.o
  CC [M]  arch/powerpc/platforms/cell/spufs/sched.o
  CC [M]  arch/powerpc/platforms/cell/spufs/backing_ops.o
  CC [M]  arch/powerpc/platforms/cell/spufs/hw_ops.o
  CC [M]  arch/powerpc/platforms/cell/spufs/run.o
  CC [M]  arch/powerpc/platforms/cell/spufs/gang.o
  SHIPPED arch/powerpc/platforms/cell/spufs/spu_save_dump.h
  SHIPPED arch/powerpc/platforms/cell/spufs/spu_restore_dump.h
  CC [M]  arch/powerpc/platforms/cell/spufs/switch.o
  CC [M]  arch/powerpc/platforms/cell/spufs/fault.o
  CC [M]  arch/powerpc/platforms/cell/spufs/lscsa_alloc.o
  LD [M]  arch/powerpc/platforms/cell/spufs/spufs.o
  CC      arch/powerpc/platforms/cell/axon_msi.o
  CC      arch/powerpc/platforms/cell/qpace_setup.o
  LD      arch/powerpc/platforms/cell/built-in.o
  CC [M]  arch/powerpc/platforms/cell/cbe_thermal.o
  CC [M]  arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.o
  CC [M]  arch/powerpc/platforms/cell/cbe_cpufreq.o
  LD [M]  arch/powerpc/platforms/cell/cbe-cpufreq.o
  CC [M]  arch/powerpc/platforms/cell/cpufreq_spudemand.o
  CC      arch/powerpc/platforms/pasemi/setup.o
  CC      arch/powerpc/platforms/pasemi/pci.o
  CC      arch/powerpc/platforms/pasemi/time.o
  CC      arch/powerpc/platforms/pasemi/idle.o
  AS      arch/powerpc/platforms/pasemi/powersave.o
  CC      arch/powerpc/platforms/pasemi/iommu.o
  CC      arch/powerpc/platforms/pasemi/dma_lib.o
  CC      arch/powerpc/platforms/pasemi/misc.o
  CC      arch/powerpc/platforms/pasemi/cpufreq.o
  LD      arch/powerpc/platforms/pasemi/built-in.o
  CC [M]  arch/powerpc/platforms/pasemi/gpio_mdio.o
  CC      arch/powerpc/platforms/powernv/setup.o
  AS      arch/powerpc/platforms/powernv/opal-takeover.o
  AS      arch/powerpc/platforms/powernv/opal-wrappers.o
  CC      arch/powerpc/platforms/powernv/opal.o
  CC      arch/powerpc/platforms/powernv/opal-rtc.o
  CC      arch/powerpc/platforms/powernv/opal-nvram.o
  CC      arch/powerpc/platforms/powernv/smp.o
  CC      arch/powerpc/platforms/powernv/pci.o
  CC      arch/powerpc/platforms/powernv/pci-p5ioc2.o
  CC      arch/powerpc/platforms/powernv/pci-ioda.o
  LD      arch/powerpc/platforms/powernv/built-in.o
  CC      arch/powerpc/platforms/pseries/lpar.o
  AS      arch/powerpc/platforms/pseries/hvCall.o
  CC      arch/powerpc/platforms/pseries/nvram.o
  CC      arch/powerpc/platforms/pseries/reconfig.o
  CC      arch/powerpc/platforms/pseries/setup.o
  CC      arch/powerpc/platforms/pseries/iommu.o
/usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c: In function
‘query_ddw’:
/usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:823: error:
implicit declaration of function ‘pci_dev_to_eeh_dev’
/usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:823: warning:
assignment makes pointer from integer without a cast
/usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:824: error:
dereferencing pointer to incomplete type
/usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:825: error:
dereferencing pointer to incomplete type
/usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:826: error:
dereferencing pointer to incomplete type
/usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:827: error:
dereferencing pointer to incomplete type
/usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c: In function
‘create_ddw’:
/usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:852: warning:
assignment makes pointer from integer without a cast
/usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:853: error:
dereferencing pointer to incomplete type
/usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:854: error:
dereferencing pointer to incomplete type
/usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:855: error:
dereferencing pointer to incomplete type
/usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:856: error:
dereferencing pointer to incomplete type
make[3]: *** [arch/powerpc/platforms/pseries/iommu.o] Error 1
make[2]: *** [arch/powerpc/platforms/pseries] Error 2
make[1]: *** [arch/powerpc/platforms] Error 2
make: *** [sub-make] Error 2

[-- Attachment #2: Type: text/html, Size: 19946 bytes --]

^ permalink raw reply

* Re: 3.4-rc3 compile failed on IBM Power6
From: Nishanth Aravamudan @ 2012-04-25  0:54 UTC (permalink / raw)
  To: Ryan Wang; +Cc: Nishanth Aravamudan, linuxppc-dev, linux-kernel, Gavin Shan
In-Reply-To: <CAPxxNQmfkJLPHq0BvzxOnLFO-e0FRmaF1VqLhP-jMqF-ziM2tA@mail.gmail.com>

Hi Ryan,

Thanks for the report!

On 25.04.2012 [08:22:19 +0800], Ryan Wang wrote:
> # gcc --version
> gcc (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3)
> Copyright (C) 2010 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions.  There is NO
> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
> 
> platform    : pSeries
> model        : IBM,9117-MMA
> machine        : CHRP IBM,9117-MMA

<snip>

>   CC      arch/powerpc/platforms/pseries/iommu.o
> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c: In function
> ?query_ddw?:
> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:823: error:
> implicit declaration of function ?pci_dev_to_eeh_dev?
> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:823: warning:
> assignment makes pointer from integer without a cast
> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:824: error:
> dereferencing pointer to incomplete type
> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:825: error:
> dereferencing pointer to incomplete type
> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:826: error:
> dereferencing pointer to incomplete type
> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:827: error:
> dereferencing pointer to incomplete type
> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c: In function
> ?create_ddw?:
> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:852: warning:
> assignment makes pointer from integer without a cast
> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:853: error:
> dereferencing pointer to incomplete type
> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:854: error:
> dereferencing pointer to incomplete type
> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:855: error:
> dereferencing pointer to incomplete type
> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:856: error:
> dereferencing pointer to incomplete type
> make[3]: *** [arch/powerpc/platforms/pseries/iommu.o] Error 1
> make[2]: *** [arch/powerpc/platforms/pseries] Error 2
> make[1]: *** [arch/powerpc/platforms] Error 2
> make: *** [sub-make] Error 2

Do you have CONFIG_EEH set in your .config? I'm guessing not, and that
causes pci.h to not define pci_dev_to_eeh_dev().

Gavin, I think this is broken by your
39baadbf36cee3ede5fdb8a34006d9109e5e2570. Probably need a wrapper for
pci_dev_to_eeh_dev() when !CONFIG_EEH?

Actually, looking at it more, eeh_dev, which is protected by CONFIG_EEH
in arch/powerpc/include/asm/eeh.h won't be defined in such situations
and is the type of the return from pci_dev_to_eeh_dev(). So that's going
to be broken completely if !CONFIG_EEH as above.

So maybe the callers should be EEH-unaware (as they were before) and the
callee becomes of the EEH variety (at compile-time) if CONFIG_EEH is
set?

Thanks,
Nish

-- 
Nishanth Aravamudan <nacc@us.ibm.com>
IBM Linux Technology Center

^ permalink raw reply

* [PATCH] drivers/ps3: Fix checkpatch warnings in ps3av.c
From: Geoff Levand @ 2012-04-25  1:19 UTC (permalink / raw)
  To: Geert Uytterhoeven; +Cc: cbe-oss-dev, linuxppc-dev, Valentin Ilie, linux-kernel
In-Reply-To: <CAMuHMdUQmTzjVfb=fwKJCmov+OuFYDHU-wW4T2kEXigpVxeGPg@mail.gmail.com>


From: Valentin Ilie <valentin.ilie@gmail.com>

Signed-off-by: Valentin Ilie <valentin.ilie@gmail.com>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: Geoff Levand <geoff@infradead.org>
---

Hi Geert,

Here's what I queued for v3.5, let me know if you have any concerns.

-Geoff

 drivers/ps3/ps3av.c |   24 +++++++++---------------
 1 file changed, 9 insertions(+), 15 deletions(-)

diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index a409fa0..93d0a8b 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -338,7 +338,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
 	mutex_unlock(&ps3av->mutex);
 	return 0;
 
-      err:
+err:
 	mutex_unlock(&ps3av->mutex);
 	printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res);
 	return res;
@@ -477,7 +477,6 @@ int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source)
 
 	return 0;
 }
-
 EXPORT_SYMBOL_GPL(ps3av_set_audio_mode);
 
 static int ps3av_set_videomode(void)
@@ -501,7 +500,7 @@ static void ps3av_set_videomode_packet(u32 id)
 
 	video_mode = &video_mode_table[id & PS3AV_MODE_MASK];
 
-	avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO;	/* num of head */
+	avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */
 	avb_param.num_of_audio_pkt = 0;
 	avb_param.num_of_av_video_pkt = ps3av->av_hw_conf.num_of_hdmi +
 					ps3av->av_hw_conf.num_of_avmulti;
@@ -521,7 +520,7 @@ static void ps3av_set_videomode_packet(u32 id)
 #ifndef PS3AV_HDMI_YUV
 		if (ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 ||
 		    ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_1)
-			av_video_cs = RGB8;	/* use RGB for HDMI */
+			av_video_cs = RGB8; /* use RGB for HDMI */
 #endif
 		len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len],
 						 ps3av->av_port[i],
@@ -590,8 +589,8 @@ static void ps3avd(struct work_struct *work)
 #define SHIFT_VESA	8
 
 static const struct {
-	unsigned mask : 19;
-	unsigned id :  4;
+	unsigned mask:19;
+	unsigned id:4;
 } ps3av_preferred_modes[] = {
 	{ PS3AV_RESBIT_WUXGA      << SHIFT_VESA, PS3AV_MODE_WUXGA   },
 	{ PS3AV_RESBIT_1920x1080P << SHIFT_60,   PS3AV_MODE_1080P60 },
@@ -667,7 +666,8 @@ static enum ps3av_mode_num ps3av_hdmi_get_id(struct ps3av_info_monitor *info)
 	return id;
 }
 
-static void ps3av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info)
+static void ps3av_monitor_info_dump(
+	const struct ps3av_pkt_av_get_monitor_info *monitor_info)
 {
 	const struct ps3av_info_monitor *info = &monitor_info->info;
 	const struct ps3av_info_audio *audio = info->audio;
@@ -717,8 +717,8 @@ static void ps3av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *
 
 	/* audio block */
 	for (i = 0; i < info->num_of_audio_block; i++) {
-		pr_debug("audio[%d] type: %02x max_ch: %02x fs: %02x sbit: "
-			 "%02x\n",
+		pr_debug(
+			"audio[%d] type: %02x max_ch: %02x fs: %02x sbit: %02x\n",
 			 i, audio->type, audio->max_num_of_ch, audio->fs,
 			 audio->sbit);
 		audio++;
@@ -870,21 +870,18 @@ int ps3av_set_video_mode(int id)
 
 	return 0;
 }
-
 EXPORT_SYMBOL_GPL(ps3av_set_video_mode);
 
 int ps3av_get_auto_mode(void)
 {
 	return ps3av_auto_videomode(&ps3av->av_hw_conf);
 }
-
 EXPORT_SYMBOL_GPL(ps3av_get_auto_mode);
 
 int ps3av_get_mode(void)
 {
 	return ps3av ? ps3av->ps3av_mode : 0;
 }
-
 EXPORT_SYMBOL_GPL(ps3av_get_mode);
 
 /* get resolution by video_mode */
@@ -902,7 +899,6 @@ int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres)
 	*yres = video_mode_table[id].y;
 	return 0;
 }
-
 EXPORT_SYMBOL_GPL(ps3av_video_mode2res);
 
 /* mute */
@@ -911,7 +907,6 @@ int ps3av_video_mute(int mute)
 	return ps3av_set_av_video_mute(mute ? PS3AV_CMD_MUTE_ON
 					    : PS3AV_CMD_MUTE_OFF);
 }
-
 EXPORT_SYMBOL_GPL(ps3av_video_mute);
 
 /* mute analog output only */
@@ -935,7 +930,6 @@ int ps3av_audio_mute(int mute)
 	return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON
 					 : PS3AV_CMD_MUTE_OFF);
 }
-
 EXPORT_SYMBOL_GPL(ps3av_audio_mute);
 
 static int __devinit ps3av_probe(struct ps3_system_bus_device *dev)
-- 
1.7.9.5

^ permalink raw reply related

* Re: 3.4-rc3 compile failed on IBM Power6
From: Gavin Shan @ 2012-04-25  1:50 UTC (permalink / raw)
  To: Nishanth Aravamudan, Ryan Wang; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20120425005432.GA14663@linux.vnet.ibm.com>

Hi Nish,

>> # gcc --version
>> gcc (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3)
>> Copyright (C) 2010 Free Software Foundation, Inc.
>> This is free software; see the source for copying conditions.  There is NO
>> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>> 
>> platform    : pSeries
>> model        : IBM,9117-MMA
>> machine        : CHRP IBM,9117-MMA
>
><snip>
>
>>   CC      arch/powerpc/platforms/pseries/iommu.o
>> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c: In function
>> ?query_ddw?:
>> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:823: error:
>> implicit declaration of function ?pci_dev_to_eeh_dev?
>> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:823: warning:
>> assignment makes pointer from integer without a cast
>> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:824: error:
>> dereferencing pointer to incomplete type
>> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:825: error:
>> dereferencing pointer to incomplete type
>> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:826: error:
>> dereferencing pointer to incomplete type
>> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:827: error:
>> dereferencing pointer to incomplete type
>> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c: In function
>> ?create_ddw?:
>> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:852: warning:
>> assignment makes pointer from integer without a cast
>> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:853: error:
>> dereferencing pointer to incomplete type
>> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:854: error:
>> dereferencing pointer to incomplete type
>> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:855: error:
>> dereferencing pointer to incomplete type
>> /usr/src/kernels/linux/arch/powerpc/platforms/pseries/iommu.c:856: error:
>> dereferencing pointer to incomplete type
>> make[3]: *** [arch/powerpc/platforms/pseries/iommu.o] Error 1
>> make[2]: *** [arch/powerpc/platforms/pseries] Error 2
>> make[1]: *** [arch/powerpc/platforms] Error 2
>> make: *** [sub-make] Error 2
>
>Do you have CONFIG_EEH set in your .config? I'm guessing not, and that
>causes pci.h to not define pci_dev_to_eeh_dev().
>
>Gavin, I think this is broken by your
>39baadbf36cee3ede5fdb8a34006d9109e5e2570. Probably need a wrapper for
>pci_dev_to_eeh_dev() when !CONFIG_EEH?
>
>Actually, looking at it more, eeh_dev, which is protected by CONFIG_EEH
>in arch/powerpc/include/asm/eeh.h won't be defined in such situations
>and is the type of the return from pci_dev_to_eeh_dev(). So that's going
>to be broken completely if !CONFIG_EEH as above.
>

I think it's because iommu.c depends on CONFIG_EEH heavily anyway with
or without the fix 39baadbf36cee3ede5fdb8a34006d9109e5e2570. That means
without CONFIG_EEH, iommu.c won't work properly even it can be compiled
successfully :-)

The story behind is that the PCI device is expected to be PE sensitive.
While setting up its DMA (through IOMMU), the number of the PE to which
the PCI device belongs to is passed to the related RTAS call. So the
PE number of the PCI device is expected if possible. As I knew, the PE
number of the PCI device is -ONLY- figured out by EEH.
 
>So maybe the callers should be EEH-unaware (as they were before) and the
>callee becomes of the EEH variety (at compile-time) if CONFIG_EEH is
>set?
>

In order to make iommu.c irrelative to CONFIG_EEH, we might figure out
the PE number of the PCI device during PCI probe time. Here're some
rough thoughts about the rework.

	- Introduce additional field "int pe_num" to "struct dev_archdata".
	  That would be traced like: (struct pci_dev)->(struct device dev)
	  ->(struct dev_archdata archdata).
	- During the PCI probe time (maybe pci_fixup_early), we can figure
	  out the PE number.

Then we can retrieve the PE number of PCI device from "int pe_num" and needn't
care CONFIG_EEH has been turned on or off. I'm not sure Ben has any comments
on the idea? 

Thanks,
Gavin
 

^ permalink raw reply

* Re: Regression in 32-bit ppc kernel
From: Larry Finger @ 2012-04-25  2:37 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, Paul Mackerras, LKML
In-Reply-To: <1335311621.15830.42.camel@pasglop>

On 04/24/2012 06:53 PM, Benjamin Herrenschmidt wrote:
> On Tue, 2012-04-24 at 17:58 -0500, Larry Finger wrote:
>> Hi,
>>
>> Somewhere between v3.2 and v3.3, the kernel in my Powerbook G4 started issuing
>> the following traceback on bootup:
>
> Does it continue working afterward or not at all ?
>
> Are you using the old IDE driver or the newer libata based pata_macio ?

Yes, it finishes the boot, and appears to work correctly. If a device is 
missing, I do not know what it is.

I think I am using the old IDE driver.

Larry

^ permalink raw reply

* Re: 3.4-rc3 compile failed on IBM Power6
From: Benjamin Herrenschmidt @ 2012-04-25  4:10 UTC (permalink / raw)
  To: Gavin Shan; +Cc: Nishanth Aravamudan, linuxppc-dev, Ryan Wang, linux-kernel
In-Reply-To: <20120425015044.GA4637@shangw>

On Wed, 2012-04-25 at 09:50 +0800, Gavin Shan wrote:
> In order to make iommu.c irrelative to CONFIG_EEH, we might figure out
> the PE number of the PCI device during PCI probe time. Here're some
> rough thoughts about the rework.
> 
>         - Introduce additional field "int pe_num" to "struct dev_archdata".
>           That would be traced like: (struct pci_dev)->(struct device dev)
>           ->(struct dev_archdata archdata).
>         - During the PCI probe time (maybe pci_fixup_early), we can figure
>           out the PE number.
> 
> Then we can retrieve the PE number of PCI device from "int pe_num" and needn't
> care CONFIG_EEH has been turned on or off. I'm not sure Ben has any comments
> on the idea? 

Just select EEH from pseries Kconfig, no point in keeping that a user visible option.

Cheers,
Ben.

^ permalink raw reply

* Re: Regression in 32-bit ppc kernel
From: Benjamin Herrenschmidt @ 2012-04-25  4:11 UTC (permalink / raw)
  To: Larry Finger; +Cc: linuxppc-dev, Paul Mackerras, LKML
In-Reply-To: <4F976352.4060001@lwfinger.net>

On Tue, 2012-04-24 at 21:37 -0500, Larry Finger wrote:
> >> Somewhere between v3.2 and v3.3, the kernel in my Powerbook G4
> started issuing
> >> the following traceback on bootup:
> >
> > Does it continue working afterward or not at all ?
> >
> > Are you using the old IDE driver or the newer libata based
> pata_macio ?
> 
> Yes, it finishes the boot, and appears to work correctly. If a device
> is 
> missing, I do not know what it is.
> 
> I think I am using the old IDE driver.
> 
Interesting. Does it make a difference if you switch to pata_macio ?

Cheers,
Ben.

^ permalink raw reply

* [PATCH] ppc/pseries: rivet CONFIG_EEH for pSeries platform
From: Gavin Shan @ 2012-04-25  5:11 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: openspace.wang, nacc, Gavin Shan

Recently, Ryan Wang tried to compile PPC pSeries platform without
CONFIG_EEH and eventually run into errors. Nishanth Aravamudan
helped to narrow down the root cause. Actually, the pSeries platform
depends on CONFIG_EEH heavily and that won't work properly without
EEH support.

According to Ben's suggestion, the patch make CONFIG_EEH invisible
and keep it as always selected on pSeries platform.

Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/pseries/Kconfig |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index aadbe4f..178a5f3 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -30,9 +30,9 @@ config PPC_SPLPAR
 	  two or more partitions.
 
 config EEH
-	bool "PCI Extended Error Handling (EEH)" if EXPERT
+	bool
 	depends on PPC_PSERIES && PCI
-	default y if !EXPERT
+	default y
 
 config PSERIES_MSI
        bool
-- 
1.7.5.4

^ permalink raw reply related

* Re: [PATCH][2/3][RFC] TDM Framework
From: Benjamin Herrenschmidt @ 2012-04-25  5:49 UTC (permalink / raw)
  To: Poonam Aggrwal; +Cc: Sandeep Singh, linuxppc-dev
In-Reply-To: <1331384221-29661-1-git-send-email-poonam.aggrwal@freescale.com>

On Sat, 2012-03-10 at 18:27 +0530, Poonam Aggrwal wrote:
> From: Sandeep Singh <Sandeep@freescale.com>
> 
> TDM Framework is an attempt to provide a platform independent layer which
> can offer a standard interface  for TDM access to different client modules.
> Beneath, the framework layer can house different types of TDM drivers to handle
> various TDM devices, the hardware intricacies of the devices being completely
> taken care by TDM drivers.

Neither the changeset comment, the code, not the Documentation file
(which are non-existent, at least in this patch, though mentioned),
define what "TDM" actually is :-)

Cheers,
Ben.


> This framework layer will allow any type of TDM device to hook with it.
> For example Freescale controller as on MPC8315, UCC based TDM controller, or 
> any other controller.
> 
> The main functions of this Framework are:
> - provides interface to TDM clients to access TDM functionalities.
> - provides standard interface for TDM drivers to hook with the framework. 
> - handles various data handling stuff and buffer management.
> 
> In future this Framework will be extended to provide Interface for Line control
> devices also. For example SLIC, E1/T1 Framers etc.
> 
> Limitations/Future Work
> ---------------------------
> 1. Presently the framework supports only Single Port channelised mode.
> 2. Also the configurability options are limited which will be extended later on.
> 3. Only kernel mode TDM clients are supported currently. Support for User mode
> clients will be added later. 
> 
> Signed-off-by: Sandeep Singh <Sandeep@freescale.com>
> Signed-off-by: Poonam Aggrwal <poonam.aggrwal@freescale.com>
> ---
>  A couple of todos' are left in the patch, we are working on it and will be
> addressed in the updated patch set.
>  drivers/Kconfig                 |    1 +
>  drivers/Makefile                |    1 +
>  drivers/tdm/Kconfig             |   25 +
>  drivers/tdm/tdm-core.c          | 1146 +++++++++++++++++++++++++++++++++++++++
>  include/linux/mod_devicetable.h |   11 +
>  include/linux/tdm.h             |  347 ++++++++++++
>  6 files changed, 1531 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/tdm/Kconfig
>  create mode 100644 drivers/tdm/tdm-core.c
>  create mode 100644 include/linux/tdm.h
> 
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index ad6c1eb..25f7f5b 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -130,4 +130,5 @@ source "drivers/virt/Kconfig"
>  
>  source "drivers/net/dpa/NetCommSw/Kconfig"
>  
> +source "drivers/tdm/Kconfig"
>  endmenu
> diff --git a/drivers/Makefile b/drivers/Makefile
> index cd546eb..362b5ed 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -102,6 +102,7 @@ obj-$(CONFIG_INFINIBAND)	+= infiniband/
>  obj-$(CONFIG_SGI_SN)		+= sn/
>  obj-y				+= firmware/
>  obj-$(CONFIG_CRYPTO)		+= crypto/
> +obj-$(CONFIG_TDM)		+= tdm/
>  obj-$(CONFIG_SUPERH)		+= sh/
>  obj-$(CONFIG_ARCH_SHMOBILE)	+= sh/
>  ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
> diff --git a/drivers/tdm/Kconfig b/drivers/tdm/Kconfig
> new file mode 100644
> index 0000000..8db2b05
> --- /dev/null
> +++ b/drivers/tdm/Kconfig
> @@ -0,0 +1,25 @@
> +#
> +# TDM subsystem configuration
> +#
> +
> +menuconfig TDM
> +	tristate "TDM support"
> +	---help---
> +	  More information is contained in the directory <file:Documentation/tdm/>,
> +	  especially in the file called "summary" there.
> +	  If you want TDM support, you should say Y here and also to the
> +	  specific driver for your bus adapter(s) below.
> +
> +	  This TDM support can also be built as a module.  If so, the module
> +	  will be called tdm-core.
> +
> +if TDM
> +
> +config TDM_DEBUG_CORE
> +	bool "TDM Core debugging messages"
> +	help
> +	  Say Y here if you want the TDM core to produce a bunch of debug
> +	  messages to the system log.  Select this if you are having a
> +	  problem with TDM support and want to see more of what is going on.
> +
> +endif # TDM
> diff --git a/drivers/tdm/tdm-core.c b/drivers/tdm/tdm-core.c
> new file mode 100644
> index 0000000..cdda260
> --- /dev/null
> +++ b/drivers/tdm/tdm-core.c
> @@ -0,0 +1,1146 @@
> +/* driver/tdm/tdm-core.c
> + *
> + * Copyright (C) 2012 Freescale Semiconductor, Inc, All rights reserved.
> + *
> + * TDM core is the interface between TDM clients and TDM devices.
> + * It is also intended to serve as an interface for line controld
> + * devices later on.
> + *
> + * Author:Hemant Agrawal <hemant@freescale.com>
> + *	Rajesh Gumasta <rajesh.gumasta@freescale.com>
> + *
> + * Modified by Sandeep Kr Singh <sandeep@freescale.com>
> + *		Poonam Aggarwal <poonam.aggarwal@freescale.com>
> + * 1. Added framework based initialization of device.
> + * 2. All the init/run time configuration is now done by framework.
> + * 3. Added channel level operations.
> + *
> + * 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.,
> + * 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +/* if read write debug required */
> +#undef TDM_CORE_DEBUG
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/tdm.h>
> +#include <linux/init.h>
> +#include <linux/idr.h>
> +#include <linux/mutex.h>
> +#include <linux/completion.h>
> +#include <linux/hardirq.h>
> +#include <linux/irqflags.h>
> +#include <linux/list.h>
> +#include <linux/uaccess.h>
> +#include <linux/io.h>
> +#include "device/tdm_fsl.h"
> +
> +
> +static DEFINE_MUTEX(tdm_core_lock);
> +static DEFINE_IDR(tdm_adapter_idr);
> +/* List of TDM adapters registered with TDM framework */
> +LIST_HEAD(adapter_list);
> +
> +/* List of TDM clients registered with TDM framework */
> +LIST_HEAD(driver_list);
> +
> +/* In case the previous data is not fetched by the client driver, the
> + * de-interleaving function will  discard the old data and rewrite the
> + * new data */
> +static int use_latest_tdm_data = 1;
> +
> +/* this tasklet is created for each adapter instance */
> +static void tdm_data_tasklet_fn(unsigned long);
> +
> +/* tries to match client driver with the adapter */
> +static int tdm_device_match(struct tdm_driver *driver, struct tdm_adapter *adap)
> +{
> +	/* match on an id table if there is one */
> +	if (driver->id_table && driver->id_table->name[0]) {
> +		if (!(strcmp(driver->id_table->name, adap->name)))
> +			return (int)driver->id_table;
> +	}
> +	return TDM_E_OK;
> +}
> +
> +static int tdm_attach_driver_adap(struct tdm_driver *driver,
> +					struct tdm_adapter *adap)
> +{
> +	/* if driver is already attached to any other adapter, return*/
> +	if (driver->adapter && (driver->adapter != adap))
> +		return TDM_E_OK;
> +
> +	driver->adapter = adap;
> +
> +	if (driver->attach_adapter) {
> +		if (driver->attach_adapter(adap) < 0)
> +			/* We ignore the return code; if it fails, too bad */
> +			pr_err("attach_adapter failed for driver [%s]\n",
> +				driver->name);
> +	}
> +	adap->drv_count++;
> +
> +	if (!adap->tasklet_conf) {
> +		tasklet_init(&adap->tdm_data_tasklet, tdm_data_tasklet_fn,
> +						(unsigned long)adap);
> +		adap->tasklet_conf = 1;
> +	}
> +
> +	return TDM_E_OK;
> +}
> +
> +/* Detach client driver and adapter */
> +static int tdm_detach_driver_adap(struct tdm_driver *driver,
> +					struct tdm_adapter *adap)
> +{
> +	int res = TDM_E_OK;
> +
> +	if (!driver->adapter || (driver->adapter != adap))
> +		return TDM_E_OK;
> +
> +	if (!driver->detach_adapter)
> +		return TDM_E_OK;
> +
> +	adap->drv_count--;
> +
> +	/* If no more driver is registed with the adapter*/
> +	if (!adap->drv_count && adap->tasklet_conf) {
> +		tasklet_disable(&adap->tdm_data_tasklet);
> +		tasklet_kill(&adap->tdm_data_tasklet);
> +		adap->tasklet_conf = 0;
> +	}
> +
> +	if (driver->detach_adapter) {
> +		if (driver->detach_adapter(adap))
> +			pr_err("detach_adapter failed for driver [%s]\n",
> +				driver->name);
> +	}
> +
> +	driver->adapter = NULL;
> +	return res;
> +}
> +
> +/* TDM adapter Registration/De-registration with TDM framework */
> +
> +static int tdm_register_adapter(struct tdm_adapter *adap)
> +{
> +	int res = TDM_E_OK;
> +	struct tdm_driver *driver, *next;
> +
> +	if (!adap) {
> +		pr_err("%s:Invalid handle\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	mutex_init(&adap->adap_lock);
> +	INIT_LIST_HEAD(&adap->myports);
> +	spin_lock_init(&adap->portlist_lock);
> +
> +	adap->drv_count = 0;
> +	adap->tasklet_conf = 0;
> +
> +	list_add_tail(&adap->list, &adapter_list);
> +
> +	/* initialization of driver by framework in default configuration */
> +	init_config_adapter(adap);
> +
> +	/* Notify drivers */
> +	pr_info("adapter [%s] registered\n", adap->name);
> +	mutex_lock(&tdm_core_lock);
> +	list_for_each_entry_safe(driver, next, &driver_list, list) {
> +		if (tdm_device_match(driver, adap)) {
> +			res = tdm_attach_driver_adap(driver, adap);
> +			pr_info(
> +			"Driver(ID=%d) is attached with Adapter %s(ID = %d)\n",
> +				driver->id, adap->name, adap->id);
> +		}
> +	}
> +	mutex_unlock(&tdm_core_lock);
> +
> +	return res;
> +}
> +
> +/*
> + * tdm_add_adapter - declare tdm adapter, use dynamic device number
> + * @adapter: the adapter to add
> + * Context: can sleep
> + *
> + * This routine is used to declare a TDM adapter
> + * When this returns zero, a new device number will be allocated and stored
> + * in adap->id, and the specified adapter became available for the clients.
> + * Otherwise, a negative errno value is returned.
> + */
> +int tdm_add_adapter(struct tdm_adapter *adapter)
> +{
> +	int id, res = TDM_E_OK;
> +	if (!adapter) {
> +		pr_err("%s:Invalid handle\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +retry:
> +	if (idr_pre_get(&tdm_adapter_idr, GFP_KERNEL) == 0)
> +		return -ENOMEM;
> +
> +	mutex_lock(&tdm_core_lock);
> +	res = idr_get_new(&tdm_adapter_idr, adapter, &id);
> +	mutex_unlock(&tdm_core_lock);
> +
> +	if (res < 0) {
> +		if (res == -EAGAIN)
> +			goto retry;
> +		return res;
> +	}
> +
> +	adapter->id = id;
> +	return tdm_register_adapter(adapter);
> +}
> +EXPORT_SYMBOL(tdm_add_adapter);
> +
> +
> +/**
> + * tdm_del_adapter - unregister TDM adapter
> + * @adap: the adapter being unregistered
> + *
> + * This unregisters an TDM adapter which was previously registered
> + * by @tdm_add_adapter.
> + */
> +int tdm_del_adapter(struct tdm_adapter *adap)
> +{
> +	int res = TDM_E_OK;
> +	struct tdm_adapter *found;
> +	struct tdm_driver *driver, *next;
> +
> +	if (!adap) {
> +		pr_err("%s:Invalid handle\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	/* First make sure that this adapter was ever added */
> +	mutex_lock(&tdm_core_lock);
> +	found = idr_find(&tdm_adapter_idr, adap->id);
> +	mutex_unlock(&tdm_core_lock);
> +	if (found != adap) {
> +		pr_err("tdm-core: attempting to delete unregistered "
> +			 "adapter [%s]\n", adap->name);
> +		return -EINVAL;
> +	}
> +
> +	/*disable and kill the data processing tasklet */
> +	if (adap->tasklet_conf) {
> +		tasklet_disable(&adap->tdm_data_tasklet);
> +		tasklet_kill(&adap->tdm_data_tasklet);
> +		adap->tasklet_conf = 0;
> +	}
> +
> +	/* Detach any active ports. This can't fail, thus we do not
> +	   checking the returned value. */
> +	mutex_lock(&tdm_core_lock);
> +	list_for_each_entry_safe(driver, next, &driver_list, list) {
> +		if (tdm_device_match(driver, adap)) {
> +			tdm_detach_driver_adap(driver, adap);
> +			pr_info(
> +			"Driver(ID=%d) is detached from Adapter %s(ID = %d)\n",
> +				 driver->id, adap->name, adap->id);
> +		}
> +	}
> +	mutex_unlock(&tdm_core_lock);
> +
> +	mutex_lock(&tdm_core_lock);
> +	idr_remove(&tdm_adapter_idr, adap->id);
> +	mutex_unlock(&tdm_core_lock);
> +
> +	pr_debug("adapter [%s] unregistered\n", adap->name);
> +
> +	list_del(&adap->list);
> +	/* Clear the device structure in case this adapter is ever going to be
> +	   added again */
> +	adap->parent = NULL;
> +
> +	return res;
> +}
> +EXPORT_SYMBOL(tdm_del_adapter);
> +
> +/* TDM Client Drivers Registration/De-registration Functions */
> +int tdm_register_driver(struct tdm_driver *driver)
> +{
> +	int res = TDM_E_OK;
> +	struct tdm_adapter *adap, *next;
> +
> +	list_add_tail(&driver->list, &driver_list);
> +
> +	mutex_lock(&tdm_core_lock);
> +	/* Walk the adapters that are already present */
> +	list_for_each_entry_safe(adap, next, &adapter_list, list) {
> +		if (tdm_device_match(driver, adap)) {
> +			res = tdm_attach_driver_adap(driver, adap);
> +			pr_info("TDM Driver(ID=%d)is attached with Adapter"
> +				"%s(ID = %d) drv_count=%d", driver->id,
> +				adap->name, adap->id, adap->drv_count);
> +		break;
> +		}
> +	}
> +	mutex_unlock(&tdm_core_lock);
> +
> +	return res;
> +}
> +EXPORT_SYMBOL(tdm_register_driver);
> +
> +/*
> + * tdm_unregister_driver - unregister TDM client driver from TDM framework
> + * @driver: the driver being unregistered
> + */
> +void tdm_unregister_driver(struct tdm_driver *driver)
> +{
> +	if (!driver) {
> +		pr_err("%s:Invalid handle\n", __func__);
> +		return;
> +	}
> +       /* A driver can register to only one adapter,
> +	* so no need to browse the list */
> +	mutex_lock(&tdm_core_lock);
> +	tdm_detach_driver_adap(driver, driver->adapter);
> +	mutex_unlock(&tdm_core_lock);
> +
> +	list_del(&driver->list);
> +
> +	pr_debug("tdm-core: driver [%s] unregistered\n", driver->name);
> +}
> +EXPORT_SYMBOL(tdm_unregister_driver);
> +
> +/* TDM Framework init and exit */
> +static int __init tdm_init(void)
> +{
> +	pr_info("%s\n", __func__);
> +	return TDM_E_OK;
> +}
> +
> +static void __exit tdm_exit(void)
> +{
> +	pr_info("%s\n", __func__);
> +	return;
> +}
> +
> +/* We must initialize early, because some subsystems register tdm drivers
> + * in subsys_initcall() code, but are linked (and initialized) before tdm.
> + */
> +postcore_initcall(tdm_init);
> +module_exit(tdm_exit);
> +
> +
> +/* Interface to the tdm device/adapter */
> +
> +/* tdm_adap_send - issue a TDM write
> + * @adap: Handle to TDM device
> + * @buf: Data that will be written to the TDM device
> + * @count: How many bytes to write
> + *
> + * Returns negative errno, or else the number of bytes written.
> + */
> +int tdm_adap_send(struct tdm_adapter *adap, void **buf, int count)
> +{
> +	int res;
> +
> +	if ((adap == NULL) || (buf == NULL)) { /* invalid handle*/
> +		pr_err("%s: Invalid Handle\n", __func__);
> +		return -ENXIO;
> +	}
> +
> +	if (adap->algo->tdm_write)
> +		res = adap->algo->tdm_write(adap, buf, count);
> +	else {
> +		pr_err("TDM level write not supported\n");
> +		return -EOPNOTSUPP;
> +	}
> +
> +	/* If everything went ok (i.e. frame transmitted), return #bytes
> +	   transmitted, else error code. */
> +	return (res == 1) ? count : res;
> +}
> +EXPORT_SYMBOL(tdm_adap_send);
> +
> +/**
> + * tdm_adap_recv - issue a TDM read
> + * @adap: Handle to TDM device
> + * @buf: Where to store data read from TDM device
> + *
> + * Returns negative errno, or else the number of bytes read.
> + */
> +int tdm_adap_recv(struct tdm_adapter *adap, void **buf)
> +{
> +	int res;
> +
> +	if (adap->algo->tdm_read)
> +		res = adap->algo->tdm_read(adap, (u16 **)buf);
> +	else {
> +		pr_err("TDM level read not supported\n");
> +		return -EOPNOTSUPP;
> +	}
> +	/* If everything went ok (i.e. frame received), return #bytes
> +	   transmitted, else error code. */
> +	return res;
> +}
> +
> +/**
> + * tdm_adap_get_write_buf - get next write TDM device buffer
> + * @adap: Handle to TDM device
> + * @buf: pointer to TDM device buffer
> + *
> + * Returns negative errno, or else size of the write buffer.
> + */
> +int tdm_adap_get_write_buf(struct tdm_adapter *adap, void **buf)
> +{
> +	int res;
> +
> +	if (adap->algo->tdm_get_write_buf) {
> +		res = adap->algo->tdm_get_write_buf(adap, (u16 **)buf);
> +	} else {
> +		pr_err("TDM level write buf get not supported\n");
> +		return -EOPNOTSUPP;
> +	}
> +	/* If everything went ok (i.e. 1 msg received), return #bytes
> +	   transmitted, else error code. */
> +	return res;
> +}
> +EXPORT_SYMBOL(tdm_adap_get_write_buf);
> +
> +int tdm_adap_enable(struct tdm_driver *drv)
> +{
> +	int res;
> +	struct tdm_adapter *adap;
> +	if (drv == NULL) { /* invalid handle*/
> +		pr_err("%s: Invalid Handle\n", __func__);
> +		return -ENXIO;
> +	}
> +	adap = drv->adapter;
> +
> +	if (adap->algo->tdm_enable) {
> +		res = adap->algo->tdm_enable(adap);
> +	} else {
> +		pr_err("TDM level enable not supported\n");
> +		return -EOPNOTSUPP;
> +	}
> +	return res;
> +}
> +EXPORT_SYMBOL(tdm_adap_enable);
> +
> +int tdm_adap_disable(struct tdm_driver *drv)
> +{
> +	int res;
> +	struct tdm_adapter *adap;
> +	if (drv == NULL) { /* invalid handle*/
> +		pr_err("%s: Invalid Handle\n", __func__);
> +		return -ENXIO;
> +	}
> +	adap = drv->adapter;
> +
> +	if (adap->algo->tdm_disable) {
> +		res = adap->algo->tdm_disable(adap);
> +	} else {
> +		pr_err("TDM level enable not supported\n");
> +		return -EOPNOTSUPP;
> +	}
> +	return res;
> +}
> +EXPORT_SYMBOL(tdm_adap_disable);
> +
> +struct tdm_adapter *tdm_get_adapter(int id)
> +{
> +	struct tdm_adapter *adapter;
> +
> +	mutex_lock(&tdm_core_lock);
> +	adapter = idr_find(&tdm_adapter_idr, id);
> +	if (adapter && !try_module_get(adapter->owner))
> +		adapter = NULL;
> +
> +	mutex_unlock(&tdm_core_lock);
> +
> +	return adapter;
> +}
> +EXPORT_SYMBOL(tdm_get_adapter);
> +
> +void tdm_put_adapter(struct tdm_adapter *adap)
> +{
> +	module_put(adap->owner);
> +}
> +EXPORT_SYMBOL(tdm_put_adapter);
> +
> +
> +/* Port Level APIs of TDM Framework */
> +unsigned int tdm_port_open(struct tdm_driver *driver, void **h_port)
> +{
> +	struct tdm_port *port;
> +	struct tdm_adapter *adap;
> +	unsigned long		flags;
> +	int res = TDM_E_OK;
> +
> +	if (driver == NULL) {
> +		pr_err("driver NULL\n");
> +		return -ENODEV;
> +	}
> +	if (driver->adapter == NULL) {
> +		pr_err("adapter NULL\n");
> +		return -ENODEV;
> +	}
> +
> +	adap = tdm_get_adapter(driver->adapter->id);
> +	if (!adap)
> +		return -ENODEV;
> +
> +	/* This creates an anonymous tdm_port, which may later be
> +	 * pointed to some slot.
> +	 *
> +	 */
> +	port = kzalloc(sizeof(*port), GFP_KERNEL);
> +	if (!port) {
> +		res = -ENOMEM;
> +		goto out;
> +	}
> +
> +	init_waitqueue_head(&port->ch_wait_queue);
> +
> +
> +	port->rx_max_frames = NUM_SAMPLES_PER_FRAME;
> +	port->port_cfg.port_mode = e_TDM_PORT_CHANNELIZED;
> +
> +	port->in_use = 1;
> +
> +	snprintf(driver->name, TDM_NAME_SIZE, "tdm-dev");
> +	port->driver = driver;
> +	port->adapter = adap;
> +
> +	spin_lock_irqsave(&adap->portlist_lock, flags);
> +	list_add_tail(&port->list, &adap->myports);
> +	spin_unlock_irqrestore(&adap->portlist_lock, flags);
> +
> +	INIT_LIST_HEAD(&port->mychannels);
> +
> +	*h_port = port;
> +
> +out:
> +	return res;
> +}
> +EXPORT_SYMBOL(tdm_port_open);
> +
> +unsigned int tdm_port_close(void *h_port)
> +{
> +	struct tdm_adapter *adap;
> +	struct tdm_driver *driver;
> +	struct tdm_port *port;
> +	struct tdm_channel *temp, *channel;
> +	unsigned long		flags;
> +	int res = TDM_E_OK;
> +	port = (struct tdm_port *)h_port;
> +
> +	if (port == NULL) { /* invalid handle*/
> +		pr_err("Invalid Handle");
> +		return -ENXIO;
> +	}
> +
> +	driver =  port->driver;
> +
> +	if (driver == NULL) {
> +		pr_err("driver NULL\n");
> +		res = -ENODEV;
> +		goto out;
> +	}
> +	if (driver->adapter == NULL) {
> +		pr_err("adapter NULL\n");
> +		res = -ENODEV;
> +		goto out;
> +	}
> +
> +	list_for_each_entry_safe(channel, temp, &port->mychannels, list) {
> +	if (channel)
> +		if (channel->in_use) {
> +			pr_err("%s: Cannot close port. Channel in use\n",
> +								__func__);
> +			res = -ENXIO;
> +			goto out;
> +			}
> +	}
> +	adap = driver->adapter;
> +
> +	spin_lock_irqsave(&adap->portlist_lock, flags);
> +	list_del(&port->list);
> +	spin_unlock_irqrestore(&adap->portlist_lock, flags);
> +
> +	if (port->p_port_data != NULL) {
> +		int i;
> +		struct tdm_bd *ch_bd;
> +
> +		/* If the tdm is in channelised mode,
> +		de-allocate the channelised buffer */
> +		ch_bd = &(port->p_port_data->rx_data_fifo[0]);
> +		for (i = 0; ch_bd && i < TDM_CH_RX_BD_RING_SIZE; i++) {
> +			ch_bd->flag = 0;
> +			ch_bd++;
> +		}
> +		ch_bd = &(port->p_port_data->tx_data_fifo[0]);
> +		for (i = 0; ch_bd && i < TDM_CH_TX_BD_RING_SIZE; i++) {
> +			ch_bd->flag = 0;
> +			ch_bd++;
> +		}
> +		kfree(port->p_port_data);
> +	}
> +	kfree(port);
> +	return res;
> +out:
> +	if (port)
> +		kfree(port->p_port_data);
> +	kfree(port);
> +	return res;
> +}
> +EXPORT_SYMBOL(tdm_port_close);
> +
> +unsigned int tdm_channel_read(void *h_port, void *h_channel,
> +				void *p_data, u16 *size)
> +{
> +	struct tdm_port *port;
> +	struct tdm_channel *channel;
> +	struct tdm_bd *rx_bd;
> +	unsigned long flags;
> +	int i, res = TDM_E_OK;
> +	unsigned short *buf, *buf1;
> +	port = (struct tdm_port *)h_port;
> +	channel = (struct tdm_channel *)h_channel;
> +
> +	if ((port && channel) == 0) { /* invalid handle*/
> +		pr_err("%s:Invalid Handle\n", __func__);
> +		return -ENXIO;
> +	}
> +
> +	if (!port->in_use)
> +		return -EIO;
> +	if (!channel->p_ch_data || !channel->in_use)
> +		return -EIO;
> +
> +	spin_lock_irqsave(&channel->p_ch_data->rx_channel_lock, flags);
> +	rx_bd = channel->p_ch_data->rx_out_data;
> +
> +	if (rx_bd->flag) {
> +		*size = rx_bd->length;
> +		buf = (u16 *) p_data;
> +		buf1 = (u16 *)rx_bd->p_data;
> +		for (i = 0; i < NUM_SAMPLES_PER_FRAME; i++)
> +			buf[i] = buf1[i];
> +		rx_bd->flag = 0;
> +		rx_bd->offset = 0;
> +		channel->p_ch_data->rx_out_data = (rx_bd->wrap) ?
> +				channel->p_ch_data->rx_data_fifo : rx_bd + 1;
> +
> +	} else {
> +		spin_unlock_irqrestore(&channel->p_ch_data->rx_channel_lock,
> +						flags);
> +		pr_info("No Data Available");
> +		return -EAGAIN;
> +	}
> +	spin_unlock_irqrestore(&channel->p_ch_data->rx_channel_lock, flags);
> +
> +	return res;
> +}
> +EXPORT_SYMBOL(tdm_channel_read);
> +
> +
> +unsigned int tdm_channel_write(void *h_port, void *h_channel,
> +				void *p_data, u16 size)
> +{
> +	struct tdm_port *port;
> +	struct tdm_channel *channel;
> +	struct tdm_bd *tx_bd;
> +	unsigned long flags;
> +	int err = TDM_E_OK;
> +	port = (struct tdm_port *)h_port;
> +	channel = (struct tdm_channel *)h_channel;
> +#ifdef TDM_CORE_DEBUG
> +	bool data_flag = 0;
> +#endif
> +
> +	if ((port && channel) == 0) { /* invalid handle*/
> +		pr_err("Invalid Handle");
> +		return -ENXIO;
> +	}
> +
> +	if (p_data == NULL) { /* invalid data*/
> +		pr_err("Invalid Data");
> +		return -EFAULT;
> +	}
> +
> +	if (!port->in_use)
> +		return -EIO;
> +	if (!channel->p_ch_data || !channel->in_use)
> +		return -EIO;
> +
> +	spin_lock_irqsave(&channel->p_ch_data->tx_channel_lock, flags);
> +	tx_bd = channel->p_ch_data->tx_in_data;
> +
> +	if (!tx_bd->flag) {
> +		tx_bd->length = size;
> +		memcpy(tx_bd->p_data, p_data,
> +			size * port->adapter->adapt_cfg.slot_width);
> +		tx_bd->flag = 1;
> +		tx_bd->offset = 0;
> +		channel->p_ch_data->tx_in_data = (tx_bd->wrap) ?
> +				channel->p_ch_data->tx_data_fifo : tx_bd+1;
> +		port->port_stat.tx_pkt_count++;
> +#ifdef TDM_CORE_DEBUG
> +		data_flag = 1;
> +#endif
> +	} else {
> +		spin_unlock_irqrestore(&channel->p_ch_data->tx_channel_lock,
> +						flags);
> +		port->port_stat.tx_pkt_drop_count++;
> +		pr_err("E_NO_MEMORY -Failed Transmit");
> +		return -ENOMEM;
> +	}
> +	spin_unlock_irqrestore(&channel->p_ch_data->tx_channel_lock, flags);
> +
> +#ifdef	TDM_CORE_DEBUG
> +	if (data_flag) {
> +		int k;
> +		pr_info("\nTX port:%d - Write - Port TX-%d\n",
> +						port->port_id, size);
> +		for (k = 0; k < size; k++)
> +			pr_info("%x", p_data[k]);
> +		pr_info("\n");
> +	}
> +#endif
> +	return err;
> +}
> +EXPORT_SYMBOL(tdm_channel_write);
> +
> +wait_queue_head_t *tdm_port_get_wait_queue(void  *h_port)
> +{
> +	struct tdm_port *port;
> +	port = (struct tdm_port *)h_port;
> +
> +	if (port == NULL) { /* invalid handle*/
> +		pr_err("Invalid Handle");
> +		return NULL;
> +	}
> +
> +	return &port->ch_wait_queue;
> +
> +}
> +EXPORT_SYMBOL(tdm_port_get_wait_queue);
> +
> +/* Driver Function for select and poll. Based on Port no, it sleeps on
> + * waitqueue */
> +unsigned int tdm_port_poll(void *h_port, unsigned int wait_time)
> +{
> +	struct tdm_port *port;
> +	unsigned long timeout = msecs_to_jiffies(wait_time);
> +	port = (struct tdm_port *)h_port;
> +
> +	if (port == NULL) { /* invalid handle*/
> +		pr_err("%s: Invalid Handle\n", __func__);
> +		return -ENXIO;
> +	}
> +	if (!port->p_port_data || !port->in_use)
> +		return -EIO;
> +
> +	if (port->p_port_data->rx_out_data->flag) {
> +		pr_debug("Data Available");
> +		return TDM_E_OK;
> +	}
> +	if (timeout) {
> +		wait_event_interruptible_timeout(port->ch_wait_queue,
> +					  port->p_port_data->rx_out_data->flag,
> +					  timeout);
> +
> +		if (port->p_port_data->rx_out_data->flag) {
> +			pr_debug("Data Available");
> +			return TDM_E_OK;
> +		}
> +	}
> +	return -EAGAIN;
> +}
> +EXPORT_SYMBOL(tdm_port_poll);
> +
> +unsigned int tdm_port_get_stats(void *h_port, struct tdm_port_stats *portStat)
> +{
> +	struct tdm_port *port;
> +	int port_num;
> +	port = (struct tdm_port *)h_port;
> +
> +	if (port == NULL || portStat == NULL) { /* invalid handle*/
> +		pr_err("Invalid Handle");
> +		return -ENXIO;
> +	}
> +	port_num =  port->port_id;
> +
> +	memcpy(portStat, &port->port_stat, sizeof(struct tdm_port_stats));
> +
> +	pr_info("TDM Port %d Get Stats", port_num);
> +
> +	return TDM_E_OK;
> +}
> +EXPORT_SYMBOL(tdm_port_get_stats);
> +
> +/* Data handling functions */
> +
> +static int tdm_data_rx_deinterleave(struct tdm_adapter *adap)
> +{
> +	struct tdm_port *port, *next;
> +	struct tdm_channel *channel, *temp;
> +	struct tdm_bd	*ch_bd;
> +
> +	int i, buf_size, ch_data_len;
> +	u16 *input_tdm_buffer;
> +	u16 *pcm_buffer;
> +	int slot_width;
> +	int frame_ch_data_size;
> +	bool ch_data;
> +	int bytes_in_fifo_per_frame;
> +	int bytes_slot_offset;
> +
> +	ch_data_len = NUM_SAMPLES_PER_FRAME;
> +	frame_ch_data_size = NUM_SAMPLES_PER_FRAME;
> +	ch_data = 0;
> +
> +	if (!adap) { /* invalid handle*/
> +		pr_err("%s: Invalid Handle\n", __func__);
> +		return -ENXIO;
> +	}
> +
> +	slot_width = adap->adapt_cfg.slot_width;
> +	buf_size = tdm_adap_recv(adap, (void **)&input_tdm_buffer);
> +	if (buf_size <= 0 || !input_tdm_buffer)
> +		return -EINVAL;
> +
> +	bytes_in_fifo_per_frame = buf_size/frame_ch_data_size;
> +	bytes_slot_offset = bytes_in_fifo_per_frame/slot_width;
> +
> +	/* de-interleaving for all ports*/
> +	list_for_each_entry_safe(port, next, &adap->myports, list) {
> +
> +		/* if the port is not open */
> +		if (!port->in_use)
> +			continue;
> +
> +		list_for_each_entry_safe(channel, temp, &port->mychannels,
> +							list) {
> +		/* if the channel is not open */
> +		if (!channel->in_use || !channel->p_ch_data)
> +			continue;
> +		ch_bd = channel->p_ch_data->rx_in_data;
> +		spin_lock(&channel->p_ch_data->rx_channel_lock);
> +			/*if old data is to be discarded */
> +		if (use_latest_tdm_data)
> +			if (ch_bd->flag) {
> +				ch_bd->flag = 0;
> +				ch_bd->offset = 0;
> +				if (ch_bd == channel->p_ch_data->rx_out_data)
> +					channel->p_ch_data->rx_out_data =
> +						ch_bd->wrap ?
> +						channel->p_ch_data->rx_data_fifo
> +						: ch_bd+1;
> +					port->port_stat.rx_pkt_drop_count++;
> +				}
> +			/* if the bd is empty */
> +			if (!ch_bd->flag) {
> +				if (ch_bd->offset == 0)
> +					ch_bd->length = port->rx_max_frames;
> +
> +				pcm_buffer = ch_bd->p_data + ch_bd->offset;
> +				/* De-interleaving the data */
> +				for (i = 0; i < ch_data_len; i++) {
> +					pcm_buffer[i]
> +					= input_tdm_buffer[i*bytes_slot_offset +
> +						channel->ch_id];
> +				}
> +				ch_bd->offset += ch_data_len * slot_width;
> +
> +				if (ch_bd->offset >=
> +					(ch_bd->length - frame_ch_data_size)*
> +						(adap->adapt_cfg.slot_width)) {
> +					ch_bd->flag = 1;
> +					ch_bd->offset = 0;
> +					channel->p_ch_data->rx_in_data =
> +						ch_bd->wrap ?
> +						channel->p_ch_data->rx_data_fifo
> +						: ch_bd+1;
> +					ch_data = 1;
> +				}
> +			} else {
> +				port->port_stat.rx_pkt_drop_count++;
> +			}
> +		spin_unlock(&channel->p_ch_data->rx_channel_lock);
> +		}
> +
> +		if (ch_data) {
> +			/*	Wake up the Port Data Poll event */
> +			wake_up_interruptible(&port->ch_wait_queue);
> +#ifdef	TDM_CORE_DEBUG
> +			pr_info("Port RX-%d-%d\n", channel->ch_id, ch_data_len);
> +			for (i = 0; i < ch_data_len; i++)
> +				pr_info("%x", pcm_buffer[i]);
> +			pr_info("\n");
> +#endif
> +			port->port_stat.rx_pkt_count++;
> +			ch_data = 0;
> +		}
> +	}
> +	return TDM_E_OK;
> +}
> +
> +static int tdm_data_tx_interleave(struct tdm_adapter *adap)
> +{
> +	struct tdm_port *port, *next;
> +	struct tdm_channel *channel, *temp;
> +	struct tdm_bd	*ch_bd;
> +	int i, buf_size, ch_data_len = NUM_SAMPLES_PER_FRAME;
> +	bool last_data = 0;
> +	u16 *output_tdm_buffer;
> +	u16 *pcm_buffer;
> +	int frame_ch_data_size = NUM_SAMPLES_PER_FRAME;
> +	int bytes_in_fifo_per_frame;
> +	int bytes_slot_offset;
> +
> +#ifdef TDM_CORE_DEBUG
> +	u8	data_flag = 0;
> +#endif
> +
> +	if (adap == NULL) { /* invalid handle*/
> +		pr_err("%s: Invalid Handle\n", __func__);
> +		return -ENXIO;
> +	}
> +
> +	buf_size = tdm_adap_get_write_buf(adap, (void **)&output_tdm_buffer);
> +	if (buf_size <= 0 || !output_tdm_buffer)
> +		return -EINVAL;
> +
> +	bytes_in_fifo_per_frame = buf_size/frame_ch_data_size;
> +	bytes_slot_offset = bytes_in_fifo_per_frame/adap->adapt_cfg.slot_width;
> +
> +
> +	memset(output_tdm_buffer, 0, sizeof(buf_size));
> +
> +	list_for_each_entry_safe(port, next, &adap->myports, list) {
> +
> +		/* check if the port is open */
> +		if (!port->in_use)
> +			continue;
> +
> +		list_for_each_entry_safe(channel, temp, &port->mychannels,
> +								list) {
> +		pr_debug("TX-Tdm %d (slots-)", channel->ch_id);
> +
> +
> +		/* if the channel is open */
> +		if (!channel->in_use || !channel->p_ch_data)
> +			continue;
> +
> +		spin_lock(&channel->p_ch_data->tx_channel_lock);
> +		if (!channel->in_use || !channel->p_ch_data)
> +			continue;
> +			ch_bd = channel->p_ch_data->tx_out_data;
> +			if (ch_bd->flag) {
> +				pcm_buffer = (u16 *)((uint8_t *)ch_bd->p_data +
> +						ch_bd->offset);
> +				/*if the buffer has less frames than required */
> +				if (frame_ch_data_size >=
> +					((ch_bd->length) - (ch_bd->offset/
> +						adap->adapt_cfg.slot_width))) {
> +					ch_data_len =
> +					(ch_bd->length) - (ch_bd->offset/
> +						adap->adapt_cfg.slot_width);
> +					last_data = 1;
> +				} else {
> +					ch_data_len = frame_ch_data_size;
> +				}
> +				/* Interleaving the data */
> +				for (i = 0; i < ch_data_len; i++) {
> +					/* TODO- need to be generic for any size
> +					   assignment*/
> +					output_tdm_buffer[channel->ch_id +
> +						bytes_slot_offset * i] =
> +								pcm_buffer[i];
> +				}
> +				/* If all the data of this buffer is
> +							transmitted */
> +				if (last_data) {
> +					ch_bd->flag = 0;
> +					ch_bd->offset = 0;
> +					channel->p_ch_data->tx_out_data =
> +						ch_bd->wrap ?
> +						channel->p_ch_data->tx_data_fifo
> +						: ch_bd+1;
> +					port->port_stat.tx_pkt_conf_count++;
> +				} else {
> +					ch_bd->offset += ch_data_len *
> +						(adap->adapt_cfg.slot_width);
> +				}
> +#ifdef	TDM_CORE_DEBUG
> +				data_flag = 1;
> +#endif
> +			}
> +		spin_unlock(&channel->p_ch_data->tx_channel_lock);
> +		}
> +	}
> +
> +#ifdef	TDM_CORE_DEBUG
> +	if (data_flag) {
> +		pr_info("TX-TDM Interleaved Data-\n");
> +		for (i = 0; i < 64; i++)
> +			pr_info("%x", output_tdm_buffer[i]);
> +		pr_info("\n");
> +	  }
> +#endif
> +	return TDM_E_OK;
> +}
> +
> +/* Channel Level APIs of TDM Framework */
> +int tdm_channel_open(u16 chanid, u16 ch_width, struct tdm_port *port,
> +				void **h_channel)
> +{
> +	struct tdm_channel *channel, *temp;
> +	unsigned long		flags;
> +	struct tdm_ch_data	*p_ch_data;
> +	int res = TDM_E_OK;
> +
> +	if (!(port && h_channel)) {
> +		pr_err("%s: Invalid handle\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (ch_width != 1) {
> +		pr_err("%s: Mode not supported\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	list_for_each_entry_safe(channel, temp, &port->mychannels, list) {
> +		if (channel->ch_id == chanid) {
> +			pr_err("%s: Channel %d already open\n",
> +						__func__, chanid);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
> +	if (!channel) {
> +		res = -ENOMEM;
> +		goto out;
> +	}
> +
> +	p_ch_data = kzalloc(sizeof(struct tdm_port_data), GFP_KERNEL);
> +	if (!p_ch_data) {
> +		res = -ENOMEM;
> +		goto outdata;
> +	}
> +
> +	p_ch_data->rx_data_fifo[TDM_CH_RX_BD_RING_SIZE-1].wrap = 1;
> +	p_ch_data->tx_data_fifo[TDM_CH_TX_BD_RING_SIZE-1].wrap = 1;
> +
> +	p_ch_data->rx_in_data = p_ch_data->rx_data_fifo;
> +	p_ch_data->rx_out_data = p_ch_data->rx_data_fifo;
> +	p_ch_data->tx_in_data = p_ch_data->tx_data_fifo;
> +	p_ch_data->tx_out_data = p_ch_data->tx_data_fifo;
> +	spin_lock_init(&p_ch_data->rx_channel_lock);
> +	spin_lock_init(&p_ch_data->tx_channel_lock);
> +
> +	channel->p_ch_data = p_ch_data;
> +
> +	channel->ch_id = chanid;
> +	channel->ch_cfg.first_slot = chanid;
> +	channel->ch_cfg.num_slots = 1;	/* This is 1 for channelized mode and
> +						configurable for other modes */
> +	channel->port = port;
> +	channel->in_use = 1;
> +
> +	spin_lock_irqsave(&port->ch_list_lock, flags);
> +	list_add_tail(&channel->list, &port->mychannels);
> +	spin_unlock_irqrestore(&port->ch_list_lock, flags);
> +
> +	*h_channel = channel;
> +
> +	return res;
> +
> +outdata:
> +	kfree(channel);
> +out:
> +	return res;
> +}
> +EXPORT_SYMBOL(tdm_channel_open);
> +
> +int tdm_channel_close(u16 chanid, u16 ch_width, struct tdm_port *port,
> +				struct tdm_channel *h_channel)
> +{
> +	struct tdm_channel *channel;
> +	unsigned long		flags;
> +	int res = TDM_E_OK;
> +	channel = h_channel;
> +
> +	if (!(port && channel)) {
> +		pr_err("%s: Invalid handle\n", __func__);
> +		res = -EINVAL;
> +		goto out;
> +	}
> +
> +	if (ch_width != 1) {
> +		pr_err("%s: Mode not supported\n", __func__);
> +		res = -EINVAL;
> +		goto out;
> +	}
> +
> +	spin_lock_irqsave(&port->ch_list_lock, flags);
> +	list_del(&channel->list);
> +	spin_unlock_irqrestore(&port->ch_list_lock, flags);
> +
> +out:
> +	if (channel)
> +		kfree(channel->p_ch_data);
> +	kfree(channel);
> +	return res;
> +}
> +EXPORT_SYMBOL(tdm_channel_close);
> +
> +void init_config_adapter(struct tdm_adapter *adap)
> +{
> +	struct fsl_tdm_adapt_cfg default_adapt_cfg = {
> +		.loopback = e_TDM_PROCESS_NORMAL,
> +		.num_ch = NUM_CHANNELS,
> +		.ch_size_type = CHANNEL_16BIT_LIN,
> +		.frame_len = NUM_SAMPLES_PER_FRAME,
> +		.num_frames = NUM_SAMPLES_PER_FRAME,
> +		.adap_mode = e_TDM_ADAPTER_MODE_NONE
> +			 };
> +
> +	default_adapt_cfg.slot_width = default_adapt_cfg.ch_size_type/3 + 1;
> +
> +	memcpy(&adap->adapt_cfg, &default_adapt_cfg,
> +		sizeof(struct fsl_tdm_adapt_cfg));
> +
> +	return;
> +}
> +EXPORT_SYMBOL(init_config_adapter);
> +
> +static void tdm_data_tasklet_fn(unsigned long data)
> +{
> +	struct tdm_adapter *adapter;
> +	adapter = (struct tdm_adapter *)data;
> +	if (adapter != NULL) {
> +		tdm_data_tx_interleave(adapter);
> +		tdm_data_rx_deinterleave(adapter);
> +	}
> +}
> +
> +
> +MODULE_AUTHOR("Hemant Agrawal <hemant@freescale.com> and "
> +	"Rajesh Gumasta <rajesh.gumasta@freescale.com>");
> +MODULE_DESCRIPTION("TDM Driver Framework Core");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
> index ae28e93..dc1a655 100644
> --- a/include/linux/mod_devicetable.h
> +++ b/include/linux/mod_devicetable.h
> @@ -416,6 +416,17 @@ struct i2c_device_id {
>  			__attribute__((aligned(sizeof(kernel_ulong_t))));
>  };
>  
> +/* tdm */
> +
> +#define TDM_NAME_SIZE   20
> +#define TDM_MODULE_PREFIX "tdm:"
> +
> +struct tdm_device_id {
> +	char name[TDM_NAME_SIZE];
> +	kernel_ulong_t driver_data      /* Data private to the driver */
> +			__attribute__((aligned(sizeof(kernel_ulong_t))));
> +};
> +
>  /* spi */
>  
>  #define SPI_NAME_SIZE	32
> diff --git a/include/linux/tdm.h b/include/linux/tdm.h
> new file mode 100644
> index 0000000..8cf4ef5
> --- /dev/null
> +++ b/include/linux/tdm.h
> @@ -0,0 +1,347 @@
> +/* include/linux/tdm.h
> + *
> + * Copyright (C) 2012 Freescale Semiconductor, Inc, All rights reserved.
> + *
> + * tdm.h - definitions for the tdm-device framework interface
> + *
> + * Author:Hemant Agrawal <hemant@freescale.com>
> + *	Rajesh Gumasta <rajesh.gumasta@freescale.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.,
> + * 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +
> +#ifndef _LINUX_TDM_H
> +#define _LINUX_TDM_H
> +
> +#ifdef __KERNEL__
> +#include <linux/types.h>
> +#include <linux/module.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/device.h>	/* for struct device */
> +#include <linux/sched.h>	/* for completion */
> +#include <linux/mutex.h>
> +#include <linux/interrupt.h>
> +
> +#define CHANNEL_8BIT_LIN	0	/* 8 bit linear */
> +#define CHANNEL_8BIT_ULAW	1	/* 8 bit Mu-law */
> +#define CHANNEL_8BIT_ALAW	2	/* 8 bit A-law */
> +#define CHANNEL_16BIT_LIN	3	/* 16 bit Linear */
> +
> +#define NUM_CHANNELS		16
> +#define NUM_SAMPLES_PER_MS	8		/* 8 samples per milli sec per
> +						 channel. Req for voice data */
> +#define NUM_MS			10
> +#define NUM_SAMPLES_PER_FRAME	(NUM_MS * NUM_SAMPLES_PER_MS) /* Number of
> +						samples for 1 client buffer */
> +#define NUM_OF_TDM_BUF		3
> +
> +/* General options */
> +
> +struct tdm_adapt_algorithm;
> +struct tdm_adapter;
> +struct tdm_port;
> +struct tdm_driver;
> +
> +/* Align addr on a size boundary - adjust address up if needed */
> +/* returns min value greater than size which is multiple of alignment */
> +static inline int ALIGN_SIZE(u64 size, u32 alignment)
> +{
> +	return (size + alignment - 1) & (~(alignment - 1));
> +}
> +
> +/**
> + * struct tdm_driver - represent an TDM device driver
> + * @class: What kind of tdm device we instantiate (for detect)
> + * @id:Driver id
> + * @name: Name of the driver
> + * @attach_adapter: Callback for device addition (for legacy drivers)
> + * @detach_adapter: Callback for device removal (for legacy drivers)
> + * @probe: Callback for device binding
> + * @remove: Callback for device unbinding
> + * @shutdown: Callback for device shutdown
> + * @suspend: Callback for device suspend
> + * @resume: Callback for device resume
> + * @command: Callback for sending commands to device
> + * @id_table: List of TDM devices supported by this driver
> + * @list: List of drivers created (for tdm-core use only)
> + */
> +struct tdm_driver {
> +	unsigned int class;
> +	unsigned int id;
> +	char name[TDM_NAME_SIZE];
> +
> +	int (*attach_adapter)(struct tdm_adapter *);
> +	int (*detach_adapter)(struct tdm_adapter *);
> +
> +	/* Standard driver model interfaces */
> +	int (*probe)(const struct tdm_device_id *);
> +	int (*remove)(void);
> +
> +	/* driver model interfaces that don't relate to enumeration */
> +	void (*shutdown)(void);
> +	int (*suspend)(pm_message_t mesg);
> +	int (*resume)(void);
> +
> +	/* a ioctl like command that can be used to perform specific functions
> +	 * with the device.
> +	 */
> +	int (*command)(unsigned int cmd, void *arg);
> +
> +	const struct tdm_device_id *id_table;
> +
> +	/* The associated adapter for this driver */
> +	struct tdm_adapter *adapter;
> +	struct list_head list;
> +};
> +
> +/* tdm per port statistics structure, used for providing and storing tdm port
> + * statistics.
> + */
> +struct tdm_port_stats {
> +	unsigned int rx_pkt_count;	/* Rx frame count per channel */
> +	unsigned int rx_pkt_drop_count;	/* Rx drop count per channel to
> +					 clean space for new buffer */
> +	unsigned int tx_pkt_count;	/* Tx frame count per channel */
> +	unsigned int tx_pkt_conf_count;	/* Tx frame confirmation count per
> +					 channel */
> +	unsigned int tx_pkt_drop_count;	/* Tx drop count per channel due to
> +					 queue full */
> +};
> +
> +
> +/* tdm Buffer Descriptor, used for Creating Interleaved and De-interleaved
> + * FIFOs
> + */
> +struct tdm_bd {
> +	unsigned char flag;		/* BD is full or empty */
> +	unsigned char wrap;		/* BD is last in the queue */
> +	unsigned short length;	/* Length of Data in BD */
> +	/*TODO: use dyanmic memory */
> +	unsigned short p_data[NUM_SAMPLES_PER_FRAME];	/* Data Pointer */
> +	unsigned long offset;	/* Offset of the Data Pointer to be used */
> +};
> +
> +#define TDM_CH_RX_BD_RING_SIZE	3
> +#define TDM_CH_TX_BD_RING_SIZE	3
> +
> +/* tdm RX-TX Channelised Data */
> +struct tdm_port_data {
> +	struct tdm_bd rx_data_fifo[TDM_CH_RX_BD_RING_SIZE]; /* Rx Channel Data
> +								BD Ring */
> +	struct tdm_bd *rx_in_data;	/* Current Channel Rx BD to be filled by
> +						de-interleave function */
> +	struct tdm_bd *rx_out_data;	/* Current Channel Rx BD to be
> +							read by App */
> +	struct tdm_bd tx_data_fifo[TDM_CH_TX_BD_RING_SIZE]; /* Tx Channel Data
> +								BD Ring */
> +	struct tdm_bd *tx_in_data;	/* Current Channel Tx BD to be
> +						 filled by App */
> +	struct tdm_bd *tx_out_data;	/* Current Channel Tx BD to be read by
> +						interleave function */
> +	spinlock_t rx_channel_lock;	/* Spin Lock for Rx Channel */
> +	spinlock_t tx_channel_lock;	/* Spin Lock for Tx Channel */
> +};
> +
> +/* structure tdm_port_cfg - contains configuration params for a port */
> +struct tdm_port_cfg {
> +	unsigned short port_mode;
> +};
> +
> +/* struct tdm_port - represent an TDM ports for a device */
> +struct tdm_port {
> +	unsigned short port_id;
> +	unsigned short in_use;		/* Port is enabled? */
> +	uint16_t rx_max_frames;		/* Received Port frames
> +					 before allowing Read Operation in
> +					 Port Mode */
> +
> +	struct tdm_port_stats port_stat;/* A structure parameters defining
> +					 TDM port statistics. */
> +	struct tdm_port_data *p_port_data;	/* a structure parameters
> +						defining tdm channelised data */
> +	wait_queue_head_t ch_wait_queue;	/* waitQueue for RX Port Data */
> +
> +	struct tdm_driver *driver;	/* driver for this port */
> +	struct tdm_adapter *adapter;	/* adapter for this port */
> +	struct list_head list;		/* list of ports */
> +	struct list_head mychannels;	/* list of channels, created on this
> +					 port*/
> +	spinlock_t ch_list_lock;	/* Spin Lock for channel_list */
> +	struct tdm_port_cfg port_cfg;/* A structure parameters defining
> +					 TDM port configuration. */
> +};
> +
> +/* tdm RX-TX Channelised Data */
> +struct tdm_ch_data {
> +	struct tdm_bd rx_data_fifo[TDM_CH_RX_BD_RING_SIZE]; /* Rx Port Data BD
> +								Ring */
> +	struct tdm_bd *rx_in_data;	/* Current Port Rx BD to be filled by
> +						de-interleave function */
> +	struct tdm_bd *rx_out_data; /* Current Port Rx BD to be read by App */
> +	struct tdm_bd tx_data_fifo[TDM_CH_TX_BD_RING_SIZE]; /* Tx Port Data BD
> +								Ring */
> +	struct tdm_bd *tx_in_data;	/* Current Port Tx BD to be filled by
> +						App */
> +	struct tdm_bd *tx_out_data;	/* Current Port Tx BD to be read by
> +						interleave function */
> +	spinlock_t rx_channel_lock;	/* Spin Lock for Rx Port */
> +	spinlock_t tx_channel_lock;	/* Spin Lock for Tx Port */
> +};
> +
> +/* Channel config params */
> +struct tdm_ch_cfg {
> +	unsigned short num_slots;
> +	unsigned short first_slot;
> +};
> +
> +/* struct tdm_channel- represent a TDM channel for a port */
> +struct tdm_channel {
> +	u16 ch_id;			/* logical channel number */
> +	struct list_head list;		/* list of channels in a port*/
> +	struct tdm_port *port;		/* port for this channel */
> +	u16 in_use;			/* channel is enabled? */
> +	struct tdm_ch_cfg ch_cfg;	/* channel configuration */
> +	struct tdm_ch_data *p_ch_data;	/* data storage space for channel */
> +};
> +
> +/* tdm_adapt_algorithm is for accessing the routines of device */
> +struct tdm_adapt_algorithm {
> +	u32 (*tdm_read)(struct tdm_adapter *, u16 **);
> +	u32 (*tdm_get_write_buf)(struct tdm_adapter *, u16 **);
> +	u32 (*tdm_write)(struct tdm_adapter *, void * , unsigned int len);
> +	int (*tdm_enable)(struct tdm_adapter *);
> +	int (*tdm_disable)(struct tdm_adapter *);
> +};
> +
> +/* tdm_adapter_mode is to define in mode of the device */
> +enum tdm_adapter_mode {
> +	e_TDM_ADAPTER_MODE_NONE = 0x00,
> +	e_TDM_ADAPTER_MODE_T1 = 0x01,
> +	e_TDM_ADAPTER_MODE_E1 = 0x02,
> +	e_TDM_ADAPTER_MODE_T1_RAW = 0x10,
> +	e_TDM_ADAPTER_MODE_E1_RAW = 0x20,
> +};
> +
> +/* tdm_port_mode defines the mode in which the port is configured to operate
> + * It can be channelized/full/fractional.
> + */
> +enum tdm_port_mode {
> +	e_TDM_PORT_CHANNELIZED = 0	/* Channelized mode */
> +	, e_TDM_PORT_FULL = 1		/* Full mode */
> +	, e_TDM_PORT_FRACTIONAL = 2	/* Fractional mode */
> +};
> +
> +/* tdm_process_mode used for testing the tdm device in normal mode or internal
> + * loopback or external loopback
> + */
> +enum tdm_process_mode {
> +	e_TDM_PROCESS_NORMAL = 0	/* Normal mode */
> +	, e_TDM_PROCESS_INT_LPB = 1	/* Internal loop mode */
> +	, e_TDM_PROCESS_EXT_LPB = 2	/* External Loopback mode */
> +};
> +
> +
> +/* TDM configuration parameters */
> +struct fsl_tdm_adapt_cfg {
> +	u8 num_ch;		/* Number of channels in this adpater */
> +	u8 ch_size_type;		/* reciever/transmit channel
> +						size for all channels */
> +	u8 slot_width;		/* 1 or 2 Is defined by channel type */
> +	u8 frame_len;		/* Length of frame in samples */
> +	u32 num_frames;
> +	u8 loopback;			/* loopback or normal */
> +	u8 adap_mode;			/* 0=None, 1= T1, 2= T1-FULL, 3=E1,
> +						4 = E1-FULL */
> +	int max_num_ports;		/* Not Used: Max Number of ports that
> +					can be created on this adapter */
> +	int max_timeslots;		/* Max Number of timeslots that are
> +					supported on this adapter */
> +};
> +
> +/*
> + * tdm_adapter is the structure used to identify a physical tdm device along
> + * with the access algorithms necessary to access it.
> + */
> +struct tdm_adapter {
> +	struct module *owner;	/* owner of the adapter module */
> +	unsigned int id;	/* Adapter Id */
> +	unsigned int class;	/* classes to allow probing for */
> +	unsigned int drv_count;	/* Number of drivers associated with the
> +				 adapter */
> +
> +	const struct tdm_adapt_algorithm *algo;	/* the algorithm to access the
> +						 adapter*/
> +
> +	char name[TDM_NAME_SIZE];	/* Name of Adapter */
> +	struct mutex adap_lock;
> +	struct device *parent;		/*Not Used*/
> +
> +	struct tasklet_struct tdm_data_tasklet;	/* tasklet handle to perform
> +						 data processing*/
> +	int tasklet_conf;	/* flag for tasklet configuration */
> +	int tdm_rx_flag;
> +
> +	struct list_head myports;	/* list of ports, created on this
> +					 adapter */
> +	struct list_head list;
> +	spinlock_t portlist_lock;	/* Spin Lock for port_list */
> +	void *data;
> +	struct fsl_tdm_adapt_cfg adapt_cfg;
> +};
> +
> +static inline void *tdm_get_adapdata(const struct tdm_adapter *dev)
> +{
> +	return dev->data;
> +}
> +
> +static inline void tdm_set_adapdata(struct tdm_adapter *dev, void *data)
> +{
> +	dev->data = data;
> +}
> +
> +/* functions exported by tdm.o */
> +
> +extern int tdm_add_adapter(struct tdm_adapter *);
> +extern int tdm_del_adapter(struct tdm_adapter *);
> +extern int tdm_register_driver(struct tdm_driver *);
> +extern void tdm_del_driver(struct tdm_driver *);
> +extern void tdm_unregister_driver(struct tdm_driver *);
> +extern void init_config_adapter(struct tdm_adapter *);
> +
> +extern unsigned int tdm_port_open(struct tdm_driver *, void **);
> +extern unsigned int tdm_port_close(void *);
> +extern unsigned int tdm_port_ioctl(void *, unsigned int, unsigned long);
> +extern unsigned int tdm_channel_read(void *, void *, void *, u16 *);
> +extern unsigned int tdm_channel_write(void *, void * , void *, u16);
> +extern unsigned int tdm_port_poll(void *, unsigned int);
> +
> +extern int tdm_channel_open(u16, u16, struct tdm_port *, void **);
> +extern int tdm_channel_close(u16, u16, struct tdm_port *,
> +						struct tdm_channel *);
> +
> +static inline int tdm_add_driver(struct tdm_driver *driver)
> +{
> +	return tdm_register_driver(driver);
> +}
> +
> +extern struct tdm_adapter *tdm_get_adapter(int id);
> +extern void tdm_put_adapter(struct tdm_adapter *adap);
> +
> +#endif /* __KERNEL__ */
> +
> +#define TDM_E_OK 0
> +
> +#endif /* _LINUX_TDM_H */

^ permalink raw reply

* Re: 3.4-rc3 compile failed on IBM Power6
From: Gavin Shan @ 2012-04-25  5:50 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Nishanth Aravamudan, linuxppc-dev, Ryan Wang, linux-kernel
In-Reply-To: <1335327042.21961.27.camel@pasglop>

>> In order to make iommu.c irrelative to CONFIG_EEH, we might figure out
>> the PE number of the PCI device during PCI probe time. Here're some
>> rough thoughts about the rework.
>> 
>>         - Introduce additional field "int pe_num" to "struct dev_archdata".
>>           That would be traced like: (struct pci_dev)->(struct device dev)
>>           ->(struct dev_archdata archdata).
>>         - During the PCI probe time (maybe pci_fixup_early), we can figure
>>           out the PE number.
>> 
>> Then we can retrieve the PE number of PCI device from "int pe_num" and needn't
>> care CONFIG_EEH has been turned on or off. I'm not sure Ben has any comments
>> on the idea? 
>
>Just select EEH from pseries Kconfig, no point in keeping that a user visible option.
>

Thanks for the suggestion, Ben :-)

I've sent one trivial patch against it.

>Cheers,
>Ben.
>
>

Thanks,
Gavin

^ permalink raw reply

* Re: [PATCH 00/15] PowerMac i2c API conversions & windfarm updates
From: Andreas Schwab @ 2012-04-25  8:00 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: khali, linuxppc-dev
In-Reply-To: <1334823416-9138-1-git-send-email-benh__1987.51832726902$1334826600$gmane$org@kernel.crashing.org>

Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:

> The biggest change is that windfarm is ported to generally use
> the new model, and I've written a new set of windfarm modules to
> take over from the old therm_pm72 (which was mostly unfixable)
> on the PowerMac G5 AGP and Xserve G5 machines.

I have the impression that the new driver keeps the fans running faster
all the time.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply

* Re: [PATCH 00/15] PowerMac i2c API conversions & windfarm updates
From: Benjamin Herrenschmidt @ 2012-04-25  8:38 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: khali, linuxppc-dev
In-Reply-To: <m2397sz1er.fsf@igel.home>

On Wed, 2012-04-25 at 10:00 +0200, Andreas Schwab wrote:
> Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
> 
> > The biggest change is that windfarm is ported to generally use
> > the new model, and I've written a new set of windfarm modules to
> > take over from the old therm_pm72 (which was mostly unfixable)
> > on the PowerMac G5 AGP and Xserve G5 machines.
> 
> I have the impression that the new driver keeps the fans running faster
> all the time.

There's a few things you can try. Both drivers put the various values &
speeds in sysfs, tho in different places. You can do a test such as
overnight idle or something like that and compare the averages.

Also, does the new driver properly react to load ?

The algorithm should be identical and the factors fed to it as well, but
there's always the possibility that I screwed up something.

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH 0/2] Kdump support for 47x
From: Suzuki K. Poulose @ 2012-04-25  9:22 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <20120416082449.27331.12488.stgit@suzukikp.in.ibm.com>

On 04/16/2012 01:56 PM, Suzuki K. Poulose wrote:
> The following series implements Kexec/Kdump support for
> PPC_47x based platforms. Doesn't support SMP yet.
>
> I have tested these patches on the following simulators:
>          1) simics
>          2) IBM ISS for ppc476.
>
> Changes since V1:
>   * Initialize the SPRN_PID to kernel pid (0) before the TLB operations in
>     setup_map_47x
>
>

Josh,

Did you get a chance to look at this ?

Thanks

Suzuki

> ---
>
> Suzuki K. Poulose (2):
>        [47x] Enable CRASH_DUMP
>        [47x] Kernel support for KEXEC
>
>
>   arch/powerpc/Kconfig          |    4 -
>   arch/powerpc/kernel/misc_32.S |  195 ++++++++++++++++++++++++++++++++++++++++-
>   2 files changed, 191 insertions(+), 8 deletions(-)
>

^ permalink raw reply

* Re: [PATCH 00/15] PowerMac i2c API conversions & windfarm updates
From: Andreas Schwab @ 2012-04-25 10:29 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: khali, linuxppc-dev
In-Reply-To: <1335343125.21961.33.camel@pasglop>

Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:

> Also, does the new driver properly react to load ?

The old driver keeps the cpu fans running at 300 rpm (lowest speed?)
for much longer when the cpus are put busy.  Only when the cpus are back
idle it speeds them up to 1200 rpm or more for some time depending on
how long the cpus were busy.  The new driver is faster at speeding up
the fans to around 800 rpm when cpus get busy, and keeps them running
longer at that speed, but doesn't appear to select much higher speeds.

The old driver appears to be better suited to desktops, whereas the new
driver is probably better for servers.

But the most annoying sound appears to be coming from the slots fan.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply

* Re: [PATCH 0/2] Kdump support for 47x
From: Josh Boyer @ 2012-04-25 13:07 UTC (permalink / raw)
  To: Suzuki K. Poulose; +Cc: linuxppc-dev
In-Reply-To: <4F97C243.80806@in.ibm.com>

On Wed, Apr 25, 2012 at 5:22 AM, Suzuki K. Poulose <suzuki@in.ibm.com> wrot=
e:
> On 04/16/2012 01:56 PM, Suzuki K. Poulose wrote:
>>
>> The following series implements Kexec/Kdump support for
>> PPC_47x based platforms. Doesn't support SMP yet.
>>
>> I have tested these patches on the following simulators:
>> =A0 =A0 =A0 =A0 1) simics
>> =A0 =A0 =A0 =A0 2) IBM ISS for ppc476.
>>
>> Changes since V1:
>> =A0* Initialize the SPRN_PID to kernel pid (0) before the TLB operations=
 in
>> =A0 =A0setup_map_47x
>>
>>
>
> Josh,
>
> Did you get a chance to look at this ?

Not yet.  I'll try to get to this and some other patches APM submitted
before the end of the week.  Apologies for the delay.

josh

^ permalink raw reply

* Re: Regression in 32-bit ppc kernel
From: Larry Finger @ 2012-04-25 15:00 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, Paul Mackerras, LKML
In-Reply-To: <1335327081.21961.28.camel@pasglop>

On 04/24/2012 11:11 PM, Benjamin Herrenschmidt wrote:
> On Tue, 2012-04-24 at 21:37 -0500, Larry Finger wrote:
>>>> Somewhere between v3.2 and v3.3, the kernel in my Powerbook G4
>> started issuing
>>>> the following traceback on bootup:
>>>
>>> Does it continue working afterward or not at all ?
>>>
>>> Are you using the old IDE driver or the newer libata based
>> pata_macio ?
>>
>> Yes, it finishes the boot, and appears to work correctly. If a device
>> is
>> missing, I do not know what it is.
>>
>> I think I am using the old IDE driver.
>>
> Interesting. Does it make a difference if you switch to pata_macio ?

After a few tries, I managed to change over to pata_macio. Fortunately, most of 
the system used dev-by-id or UUID, thus most of the process was getting all the 
kernel pieces built in.

Unfortunately, the original problem remains. I have resumed the bisecting - only 
11 steps to go. I should have it by Friday! :)

Larry

^ permalink raw reply

* [PATCH 05/10] powerpc/ps3: Use highmem region from repository
From: Andre Heider @ 2012-04-25 19:19 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: cbe-oss-dev, Andre Heider, linuxppc-dev, Nathan Whitehorn,
	Hector Martin
In-Reply-To: <cover.1335379330.git.geoff@infradead.org>

Use any preallocated highmem region setup by the bootloader.
This implementation only checks for the existance of a single
region at region_index=0.

This feature allows the bootloader to preallocate highmem
regions and pass the region locations to the kernel through
the repository.  Preallocated regions can be used to hold the
initrd or other large data.  If no region info exists, the
kernel retains the old behavior and attempts to allocate the
highmem region itself.

Based on Hector Martin's patch "Get lv1 high memory region from
devtree".

CC: Hector Martin <hector@marcansoft.com>
Signed-off-by: Andre Heider <a.heider@gmail.com>
CC: Nathan Whitehorn <nwhitehorn@freebsd.org>
Signed-off-by: Geoff Levand <geoff@infradead.org>
---
 arch/powerpc/platforms/ps3/mm.c |   51 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 49 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
index de2aea4..05a2bcb 100644
--- a/arch/powerpc/platforms/ps3/mm.c
+++ b/arch/powerpc/platforms/ps3/mm.c
@@ -79,12 +79,14 @@ enum {
  * @base: base address
  * @size: size in bytes
  * @offset: difference between base and rm.size
+ * @destroy: flag if region should be destroyed upon shutdown
  */
 
 struct mem_region {
 	u64 base;
 	u64 size;
 	unsigned long offset;
+	int destroy;
 };
 
 /**
@@ -262,6 +264,7 @@ static int ps3_mm_region_create(struct mem_region *r, unsigned long size)
 		goto zero_region;
 	}
 
+	r->destroy = 1;
 	r->offset = r->base - map.rm.size;
 	return result;
 
@@ -279,7 +282,14 @@ static void ps3_mm_region_destroy(struct mem_region *r)
 {
 	int result;
 
+	if (!r->destroy) {
+		pr_info("%s:%d: Not destroying high region: %llxh %llxh\n",
+			__func__, __LINE__, r->base, r->size);
+		return;
+	}
+
 	DBG("%s:%d: r->base = %llxh\n", __func__, __LINE__, r->base);
+
 	if (r->base) {
 		result = lv1_release_memory(r->base);
 		BUG_ON(result);
@@ -288,6 +298,36 @@ static void ps3_mm_region_destroy(struct mem_region *r)
 	}
 }
 
+static int ps3_mm_get_repository_highmem(struct mem_region *r)
+{
+	int result;
+
+	/* Assume a single highmem region. */
+
+	result = ps3_repository_read_highmem_info(0, &r->base, &r->size);
+
+	if (result)
+		goto zero_region;
+
+	if (!r->base || !r->size) {
+		result = -1;
+		goto zero_region;
+	}
+
+	r->offset = r->base - map.rm.size;
+
+	DBG("%s:%d: Found high region in repository: %llxh %llxh\n",
+	    __func__, __LINE__, r->base, r->size);
+
+	return 0;
+
+zero_region:
+	DBG("%s:%d: No high region in repository.\n", __func__, __LINE__);
+
+	r->size = r->base = r->offset = 0;
+	return result;
+}
+
 /**
  * ps3_mm_add_memory - hot add memory
  */
@@ -304,6 +344,12 @@ static int __init ps3_mm_add_memory(void)
 
 	BUG_ON(!mem_init_done);
 
+	if (!map.r1.size) {
+		DBG("%s:%d: No region 1, not adding memory\n",
+		    __func__, __LINE__);
+		return 0;
+	}
+
 	start_addr = map.rm.size;
 	start_pfn = start_addr >> PAGE_SHIFT;
 	nr_pages = (map.r1.size + PAGE_SIZE - 1) >> PAGE_SHIFT;
@@ -1217,9 +1263,10 @@ void __init ps3_mm_init(void)
 	BUG_ON(map.rm.base);
 	BUG_ON(!map.rm.size);
 
+	/* Check if we got the highmem region from an earlier boot step */
 
-	/* arrange to do this in ps3_mm_add_memory */
-	ps3_mm_region_create(&map.r1, map.total - map.rm.size);
+	if (ps3_mm_get_repository_highmem(&map.r1))
+		ps3_mm_region_create(&map.r1, map.total - map.rm.size);
 
 	/* correct map.total for the real total amount of memory we use */
 	map.total = map.rm.size + map.r1.size;
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 01/10] powerpc/ps3: Correct lv1 repository routine names
From: Geoff Levand @ 2012-04-25 19:19 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: cbe-oss-dev, Andre Heider, linuxppc-dev, Nathan Whitehorn
In-Reply-To: <cover.1335379330.git.geoff@infradead.org>

Rename these repo routines:

  modify_repository_node_value => write_repository_node
  remove_repository_node => delete_repository_node

Signed-off-by: Geoff Levand <geoff@infradead.org>
---
 arch/powerpc/include/asm/lv1call.h |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/include/asm/lv1call.h b/arch/powerpc/include/asm/lv1call.h
index 233f9ec..f511767 100644
--- a/arch/powerpc/include/asm/lv1call.h
+++ b/arch/powerpc/include/asm/lv1call.h
@@ -265,8 +265,8 @@ LV1_CALL(get_spe_irq_outlet,                            2, 1,  78 )
 LV1_CALL(set_spe_privilege_state_area_1_register,       3, 0,  79 )
 LV1_CALL(create_repository_node,                        6, 0,  90 )
 LV1_CALL(read_repository_node,                          5, 2,  91 )
-LV1_CALL(modify_repository_node_value,                  6, 0,  92 )
-LV1_CALL(remove_repository_node,                        4, 0,  93 )
+LV1_CALL(write_repository_node,                         6, 0,  92 )
+LV1_CALL(delete_repository_node,                        4, 0,  93 )
 LV1_CALL(read_htab_entries,                             2, 5,  95 )
 LV1_CALL(set_dabr,                                      2, 0,  96 )
 LV1_CALL(get_total_execution_time,                      2, 1, 103 )
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 04/10] powerpc/ps3: Add highmem repository read routines
From: Andre Heider @ 2012-04-25 19:19 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: cbe-oss-dev, Andre Heider, linuxppc-dev, Nathan Whitehorn
In-Reply-To: <cover.1335379330.git.geoff@infradead.org>

Add repository helper routines to read highmem region info.

Bootloaders that preallocate highmem regions must place the
region info into the repository at these well known nodes.
These routines allow second stage kernles to read the region
info from those nodes.

Signed-off-by: Andre Heider <a.heider@gmail.com>
CC: Nathan Whitehorn <nwhitehorn@freebsd.org>
Signed-off-by: Geoff Levand <geoff@infradead.org>
---
 arch/powerpc/platforms/ps3/platform.h   |    7 ++++
 arch/powerpc/platforms/ps3/repository.c |   66 +++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+)

diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h
index 4012a86..d71329a 100644
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -188,6 +188,13 @@ int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size);
 int ps3_repository_read_region_total(u64 *region_total);
 int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size,
 	u64 *region_total);
+int ps3_repository_read_highmem_region_count(unsigned int *region_count);
+int ps3_repository_read_highmem_base(unsigned int region_index,
+	u64 *highmem_base);
+int ps3_repository_read_highmem_size(unsigned int region_index,
+	u64 *highmem_size);
+int ps3_repository_read_highmem_info(unsigned int region_index,
+	u64 *highmem_base, u64 *highmem_size);
 
 int ps3_repository_write_highmem_region_count(unsigned int region_count);
 int ps3_repository_write_highmem_base(unsigned int region_index,
diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c
index c73f3a6..9b47ba7 100644
--- a/arch/powerpc/platforms/ps3/repository.c
+++ b/arch/powerpc/platforms/ps3/repository.c
@@ -779,6 +779,72 @@ int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, u64 *region_total)
 }
 
 /**
+ * ps3_repository_read_highmem_region_count - Read the number of highmem regions
+ *
+ * Bootloaders must arrange the repository nodes such that regions are indexed
+ * with a region_index from 0 to region_count-1.
+ */
+
+int ps3_repository_read_highmem_region_count(unsigned int *region_count)
+{
+	int result;
+	u64 v1 = 0;
+
+	result = read_node(PS3_LPAR_ID_CURRENT,
+		make_first_field("highmem", 0),
+		make_field("region", 0),
+		make_field("count", 0),
+		0,
+		&v1, NULL);
+	*region_count = v1;
+	return result;
+}
+
+
+int ps3_repository_read_highmem_base(unsigned int region_index,
+	u64 *highmem_base)
+{
+	return read_node(PS3_LPAR_ID_CURRENT,
+		make_first_field("highmem", 0),
+		make_field("region", region_index),
+		make_field("base", 0),
+		0,
+		highmem_base, NULL);
+}
+
+int ps3_repository_read_highmem_size(unsigned int region_index,
+	u64 *highmem_size)
+{
+	return read_node(PS3_LPAR_ID_CURRENT,
+		make_first_field("highmem", 0),
+		make_field("region", region_index),
+		make_field("size", 0),
+		0,
+		highmem_size, NULL);
+}
+
+/**
+ * ps3_repository_read_highmem_info - Read high memory region info
+ * @region_index: Region index, {0,..,region_count-1}.
+ * @highmem_base: High memory base address.
+ * @highmem_size: High memory size.
+ *
+ * Bootloaders that preallocate highmem regions must place the
+ * region info into the repository at these well known nodes.
+ */
+
+int ps3_repository_read_highmem_info(unsigned int region_index,
+	u64 *highmem_base, u64 *highmem_size)
+{
+	int result;
+
+	*highmem_base = 0;
+	result = ps3_repository_read_highmem_base(region_index, highmem_base);
+	return result ? result
+		: ps3_repository_read_highmem_size(region_index, highmem_size);
+}
+
+/**
  * ps3_repository_read_num_spu_reserved - Number of physical spus reserved.
  * @num_spu: Number of physical spus.
  */
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 06/10] powerpc/ps3: Add highmem region memory early
From: Hector Martin @ 2012-04-25 19:19 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: cbe-oss-dev, Andre Heider, linuxppc-dev, Nathan Whitehorn,
	Hector Martin
In-Reply-To: <cover.1335379330.git.geoff@infradead.org>

Real mode memory can be limited and runs out quickly as memory is allocated
during kernel startup.  Having the highmem available sooner fixes this.

This change simplifies the memory management code by converting from hotplug
memory to logical memory blocks.

Signed-off-by: Hector Martin <hector@marcansoft.com>
Signed-off-by: Andre Heider <a.heider@gmail.com>
Signed-off-by: Geoff Levand <geoff@infradead.org>
---
 arch/powerpc/platforms/ps3/mm.c |   66 ++++++---------------------------------
 1 file changed, 10 insertions(+), 56 deletions(-)

diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
index 05a2bcb..0c9f643 100644
--- a/arch/powerpc/platforms/ps3/mm.c
+++ b/arch/powerpc/platforms/ps3/mm.c
@@ -20,7 +20,6 @@
 
 #include <linux/kernel.h>
 #include <linux/export.h>
-#include <linux/memory_hotplug.h>
 #include <linux/memblock.h>
 #include <linux/slab.h>
 
@@ -98,7 +97,7 @@ struct mem_region {
  * The HV virtual address space (vas) allows for hotplug memory regions.
  * Memory regions can be created and destroyed in the vas at runtime.
  * @rm: real mode (bootmem) region
- * @r1: hotplug memory region(s)
+ * @r1: highmem region(s)
  *
  * ps3 addresses
  * virt_addr: a cpu 'translated' effective address
@@ -224,10 +223,6 @@ void ps3_mm_vas_destroy(void)
 	}
 }
 
-/*============================================================================*/
-/* memory hotplug routines                                                    */
-/*============================================================================*/
-
 /**
  * ps3_mm_region_create - create a memory region in the vas
  * @r: pointer to a struct mem_region to accept initialized values
@@ -328,56 +323,6 @@ zero_region:
 	return result;
 }
 
-/**
- * ps3_mm_add_memory - hot add memory
- */
-
-static int __init ps3_mm_add_memory(void)
-{
-	int result;
-	unsigned long start_addr;
-	unsigned long start_pfn;
-	unsigned long nr_pages;
-
-	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
-		return -ENODEV;
-
-	BUG_ON(!mem_init_done);
-
-	if (!map.r1.size) {
-		DBG("%s:%d: No region 1, not adding memory\n",
-		    __func__, __LINE__);
-		return 0;
-	}
-
-	start_addr = map.rm.size;
-	start_pfn = start_addr >> PAGE_SHIFT;
-	nr_pages = (map.r1.size + PAGE_SIZE - 1) >> PAGE_SHIFT;
-
-	DBG("%s:%d: start_addr %lxh, start_pfn %lxh, nr_pages %lxh\n",
-		__func__, __LINE__, start_addr, start_pfn, nr_pages);
-
-	result = add_memory(0, start_addr, map.r1.size);
-
-	if (result) {
-		pr_err("%s:%d: add_memory failed: (%d)\n",
-			__func__, __LINE__, result);
-		return result;
-	}
-
-	memblock_add(start_addr, map.r1.size);
-
-	result = online_pages(start_pfn, nr_pages);
-
-	if (result)
-		pr_err("%s:%d: online_pages failed: (%d)\n",
-			__func__, __LINE__, result);
-
-	return result;
-}
-
-device_initcall(ps3_mm_add_memory);
-
 /*============================================================================*/
 /* dma routines                                                               */
 /*============================================================================*/
@@ -1271,6 +1216,15 @@ void __init ps3_mm_init(void)
 	/* correct map.total for the real total amount of memory we use */
 	map.total = map.rm.size + map.r1.size;
 
+	if (!map.r1.size) {
+		DBG("%s:%d: No highmem region found\n", __func__, __LINE__);
+	} else {
+		DBG("%s:%d: Adding highmem region: %llxh %llxh\n",
+			__func__, __LINE__, map.rm.size,
+			map.total - map.rm.size);
+		memblock_add(map.rm.size, map.total - map.rm.size);
+	}
+
 	DBG(" <- %s:%d\n", __func__, __LINE__);
 }
 
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL] PS3 updates for Linux-3.5
From: Geoff Levand @ 2012-04-25 19:19 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: cbe-oss-dev, Andre Heider, Hector Martin, Valentin Ilie,
	Nathan Whitehorn, linuxppc-dev

Hi Ben,

I queued up the PS3 updates I have for v3.5.  Please pull.

-Geoff

The following changes since commit 66f75a5d028beaf67c931435fdc3e7823125730c:

  Linux 3.4-rc4 (2012-04-21 14:47:52 -0700)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/geoff/ps3-linux.git for-powerpc

for you to fetch changes up to 3252c8a3d0bf3c6af6ce7c76c40444943cda2943:

  powerpc/ps3: Refresh ps3_defconfig (2012-04-24 18:18:01 -0700)

----------------------------------------------------------------
Andre Heider (3):
      powerpc/ps3: Add highmem repository read routines
      powerpc/ps3: Use highmem region from repository
      powerpc/ps3: Remove MEMORY_HOTPLUG requirement

Geoff Levand (5):
      powerpc/ps3: Correct lv1 repository routine names
      powerpc/ps3: Add PS3 repository write support
      powerpc/ps3: Add highmem repository write routines
      powerpc/ps3: Minor Kconfig cleanup
      powerpc/ps3: Refresh ps3_defconfig

Hector Martin (1):
      powerpc/ps3: Add highmem region memory early

Valentin Ilie (1):
      drivers/ps3: Fix checkpatch warnings in ps3av.c

 arch/powerpc/configs/ps3_defconfig      |    6 -
 arch/powerpc/include/asm/lv1call.h      |    4 +-
 arch/powerpc/platforms/ps3/Kconfig      |   22 +++-
 arch/powerpc/platforms/ps3/mm.c         |   77 ++++++------
 arch/powerpc/platforms/ps3/platform.h   |   16 +++
 arch/powerpc/platforms/ps3/repository.c |  198 +++++++++++++++++++++++++++++++
 drivers/ps3/ps3av.c                     |   24 ++--
 7 files changed, 281 insertions(+), 66 deletions(-)

Andre Heider (3):
  powerpc/ps3: Add highmem repository read routines
  powerpc/ps3: Use highmem region from repository
  powerpc/ps3: Remove MEMORY_HOTPLUG requirement

Geoff Levand (5):
  powerpc/ps3: Correct lv1 repository routine names
  powerpc/ps3: Add PS3 repository write support
  powerpc/ps3: Add highmem repository write routines
  powerpc/ps3: Minor Kconfig cleanup
  powerpc/ps3: Refresh ps3_defconfig

Hector Martin (1):
  powerpc/ps3: Add highmem region memory early

Valentin Ilie (1):
  drivers/ps3: Fix checkpatch warnings in ps3av.c

 arch/powerpc/configs/ps3_defconfig      |    6 -
 arch/powerpc/include/asm/lv1call.h      |    4 +-
 arch/powerpc/platforms/ps3/Kconfig      |   22 +++-
 arch/powerpc/platforms/ps3/mm.c         |   77 ++++++------
 arch/powerpc/platforms/ps3/platform.h   |   16 +++
 arch/powerpc/platforms/ps3/repository.c |  198 +++++++++++++++++++++++++++++++
 drivers/ps3/ps3av.c                     |   24 ++--
 7 files changed, 281 insertions(+), 66 deletions(-)

-- 
1.7.9.5

^ permalink raw reply

* [PATCH 02/10] powerpc/ps3: Add PS3 repository write support
From: Geoff Levand @ 2012-04-25 19:19 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: cbe-oss-dev, Andre Heider, linuxppc-dev, Nathan Whitehorn
In-Reply-To: <cover.1335379330.git.geoff@infradead.org>

Add a new config option CONFIG_PS3_REPOSITORY_WRITE that
conditionally builds in support to create, write and delete
nodes in the PS3 system repository.

This support will allow Linux based bootloaders to manage data
in the system repository for use by later boot stages,

Signed-off-by: Geoff Levand <geoff@infradead.org>
---
 arch/powerpc/platforms/ps3/Kconfig      |   13 +++++++
 arch/powerpc/platforms/ps3/repository.c |   58 +++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+)

diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
index 476d9d9..4210aaa 100644
--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -88,6 +88,19 @@ config PS3_SYS_MANAGER
 	  This support is required for system control.  In
 	  general, all users will say Y or M.
 
+config PS3_REPOSITORY_WRITE
+	bool "PS3 Repository write support" if PS3_ADVANCED
+	depends on PPC_PS3
+	default n
+	help
+	  Enables support for writing to the PS3 System Repository.
+
+	  This support is intended for bootloaders that need to store data
+	  in the repository for later boot stages.
+
+	  If in doubt, say N here and reduce the size of the kernel by a
+	  small amount.
+
 config PS3_STORAGE
 	depends on PPC_PS3
 	tristate
diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c
index 7bdfea3..b31142c 100644
--- a/arch/powerpc/platforms/ps3/repository.c
+++ b/arch/powerpc/platforms/ps3/repository.c
@@ -1002,6 +1002,64 @@ int ps3_repository_read_lpm_privileges(unsigned int be_index, u64 *lpar,
 			    lpar, rights);
 }
 
+#if defined(CONFIG_PS3_REPOSITORY_WRITE)
+
+static int create_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2)
+{
+	int result;
+
+	dump_node(0, n1, n2, n3, n4, v1, v2);
+
+	result = lv1_create_repository_node(n1, n2, n3, n4, v1, v2);
+
+	if (result) {
+		pr_devel("%s:%d: lv1_create_repository_node failed: %s\n",
+			__func__, __LINE__, ps3_result(result));
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+static int delete_node(u64 n1, u64 n2, u64 n3, u64 n4)
+{
+	int result;
+
+	dump_node(0, n1, n2, n3, n4, 0, 0);
+
+	result = lv1_delete_repository_node(n1, n2, n3, n4);
+
+	if (result) {
+		pr_devel("%s:%d: lv1_delete_repository_node failed: %s\n",
+			__func__, __LINE__, ps3_result(result));
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+static int write_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2)
+{
+	int result;
+
+	result = create_node(n1, n2, n3, n4, v1, v2);
+
+	if (!result)
+		return 0;
+
+	result = lv1_write_repository_node(n1, n2, n3, n4, v1, v2);
+
+	if (result) {
+		pr_devel("%s:%d: lv1_write_repository_node failed: %s\n",
+			__func__, __LINE__, ps3_result(result));
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+#endif /* defined(CONFIG_PS3_WRITE_REPOSITORY) */
+
 #if defined(DEBUG)
 
 int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo)
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 03/10] powerpc/ps3: Add highmem repository write routines
From: Geoff Levand @ 2012-04-25 19:19 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: cbe-oss-dev, Andre Heider, linuxppc-dev, Nathan Whitehorn
In-Reply-To: <cover.1335379330.git.geoff@infradead.org>

Add routines to allow Linux based bootloaders to create and/or
modify highmem region info in the PS3 system repository where
it can be retrived by later boot stages.

Signed-off-by: Geoff Levand <geoff@infradead.org>
---
 arch/powerpc/platforms/ps3/platform.h   |    9 ++++
 arch/powerpc/platforms/ps3/repository.c |   74 +++++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+)

diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h
index 1a633ed..4012a86 100644
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -189,6 +189,15 @@ int ps3_repository_read_region_total(u64 *region_total);
 int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size,
 	u64 *region_total);
 
+int ps3_repository_write_highmem_region_count(unsigned int region_count);
+int ps3_repository_write_highmem_base(unsigned int region_index,
+	u64 highmem_base);
+int ps3_repository_write_highmem_size(unsigned int region_index,
+	u64 highmem_size);
+int ps3_repository_write_highmem_info(unsigned int region_index,
+	u64 highmem_base, u64 highmem_size);
+int ps3_repository_delete_highmem_info(unsigned int region_index);
+
 /* repository pme info */
 
 int ps3_repository_read_num_be(unsigned int *num_be);
diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c
index b31142c..c73f3a6 100644
--- a/arch/powerpc/platforms/ps3/repository.c
+++ b/arch/powerpc/platforms/ps3/repository.c
@@ -1058,6 +1058,80 @@ static int write_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2)
 	return 0;
 }
 
+int ps3_repository_write_highmem_region_count(unsigned int region_count)
+{
+	int result;
+	u64 v1 = (u64)region_count;
+
+	result = write_node(
+		make_first_field("highmem", 0),
+		make_field("region", 0),
+		make_field("count", 0),
+		0,
+		v1, 0);
+	return result;
+}
+
+int ps3_repository_write_highmem_base(unsigned int region_index,
+	u64 highmem_base)
+{
+	return write_node(
+		make_first_field("highmem", 0),
+		make_field("region", region_index),
+		make_field("base", 0),
+		0,
+		highmem_base, 0);
+}
+
+int ps3_repository_write_highmem_size(unsigned int region_index,
+	u64 highmem_size)
+{
+	return write_node(
+		make_first_field("highmem", 0),
+		make_field("region", region_index),
+		make_field("size", 0),
+		0,
+		highmem_size, 0);
+}
+
+int ps3_repository_write_highmem_info(unsigned int region_index,
+	u64 highmem_base, u64 highmem_size)
+{
+	int result;
+
+	result = ps3_repository_write_highmem_base(region_index, highmem_base);
+	return result ? result
+		: ps3_repository_write_highmem_size(region_index, highmem_size);
+}
+
+static int ps3_repository_delete_highmem_base(unsigned int region_index)
+{
+	return delete_node(
+		make_first_field("highmem", 0),
+		make_field("region", region_index),
+		make_field("base", 0),
+		0);
+}
+
+static int ps3_repository_delete_highmem_size(unsigned int region_index)
+{
+	return delete_node(
+		make_first_field("highmem", 0),
+		make_field("region", region_index),
+		make_field("size", 0),
+		0);
+}
+
+int ps3_repository_delete_highmem_info(unsigned int region_index)
+{
+	int result;
+
+	result = ps3_repository_delete_highmem_base(region_index);
+	result += ps3_repository_delete_highmem_size(region_index);
+
+	return result ? -1 : 0;
+}
+
 #endif /* defined(CONFIG_PS3_WRITE_REPOSITORY) */
 
 #if defined(DEBUG)
-- 
1.7.9.5

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox