LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [RFC PATCH 0/8] memory-hotplug : hot-remove physical memory(clear page table)
From: Wen Congyang @ 2012-07-23  9:11 UTC (permalink / raw)
  To: Yasuaki Ishimatsu
  Cc: len.brown, linux-acpi, linux-kernel, linux-mm, paulus,
	minchan.kim, kosaki.motohiro, rientjes, cl, linuxppc-dev, akpm,
	liuj97
In-Reply-To: <5009094B.3090506@jp.fujitsu.com>

At 07/20/2012 03:31 PM, Yasuaki Ishimatsu Wrote:
> [Hi Wen,
> 
> Good news!! I was waiting for this patch to come.
> Applying the patches, can we hot-remove physical memory completely?

If all functions success, I guess so.

Thanks
Wen Congyang

> 
> Thanks,
> Yasuaki Ishimatsu
> 
> 2012/07/20 16:06, Wen Congyang wrote:
>> This patch series aims to support physical memory hot-remove(clear
>> page table).
>>
>> This patch series base on ishimatsu's patch series. You can get it here:
>> http://www.spinics.net/lists/linux-acpi/msg36804.html
>>
>> The patches can remove following things:
>>    - page table of removed memory
>>
>> If you find lack of function for physical memory hot-remove, please
>> let me
>> know.
>>
>> Note:
>> * The patch "remove memory info from list before freeing it" is being
>> disccussed
>>    in other thread. But for testing the patch series, the patch is
>> needed.
>>    So I added the patch as [PATCH 0/8].
>> * You need to apply ishimatsu's patch series first before applying
>> this patch
>>    series.
>>
>> Wen Congyang (8):
>>    memory-hotplug: store the node id in acpi_memory_device
>>    memory-hotplug: offline memory only when it is onlined
>>    memory-hotplug: call remove_memory() to cleanup when removing memory
>>      device
>>    memory-hotplug: export the function acpi_bus_remove()
>>    memory-hotplug: call acpi_bus_remove() to remove memory device
>>    memory-hotplug: introduce new function arch_remove_memory()
>>    x86: make __split_large_page() generally avialable
>>    memory-hotplug: implement arch_remove_memory()
>>
>>   arch/ia64/mm/init.c                  |   16 ++++
>>   arch/powerpc/mm/mem.c                |   14 +++
>>   arch/s390/mm/init.c                  |    8 ++
>>   arch/sh/mm/init.c                    |   15 +++
>>   arch/tile/mm/init.c                  |    8 ++
>>   arch/x86/include/asm/pgtable_types.h |    1 +
>>   arch/x86/mm/init_32.c                |   10 ++
>>   arch/x86/mm/init_64.c                |  160
>> ++++++++++++++++++++++++++++++++++
>>   arch/x86/mm/pageattr.c               |   47 +++++-----
>>   drivers/acpi/acpi_memhotplug.c       |   24 ++++--
>>   drivers/acpi/scan.c                  |    3 +-
>>   include/acpi/acpi_bus.h              |    1 +
>>   include/linux/memory_hotplug.h       |    1 +
>>   mm/memory_hotplug.c                  |    2 +-
>>   14 files changed, 280 insertions(+), 30 deletions(-)
>>
> 
> 
> 

^ permalink raw reply

* [PATCH 24/25] macintosh/mediabay: make data used as *of_device_id.data const
From: Uwe Kleine-König @ 2012-07-23  9:13 UTC (permalink / raw)
  To: Grant Likely, Arnd Bergmann, Rob Herring, Benjamin Herrenschmidt
  Cc: linuxppc-dev, linux-arm-kernel, kernel
In-Reply-To: <1343034810-3386-1-git-send-email-u.kleine-koenig@pengutronix.de>

From: Arnd Bergmann <arnd@arndb.de>

[ukl: split Arnd's patch by driver]

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/macintosh/mediabay.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 54bf584..3f8d032 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -669,7 +669,7 @@ static int media_bay_resume(struct macio_dev *mdev)
 
 /* Definitions of "ops" structures.
  */
-static struct mb_ops ohare_mb_ops = {
+static const struct mb_ops ohare_mb_ops = {
 	.name		= "Ohare",
 	.content	= ohare_mb_content,
 	.power		= ohare_mb_power,
@@ -678,7 +678,7 @@ static struct mb_ops ohare_mb_ops = {
 	.un_reset_ide	= ohare_mb_un_reset_ide,
 };
 
-static struct mb_ops heathrow_mb_ops = {
+static const struct mb_ops heathrow_mb_ops = {
 	.name		= "Heathrow",
 	.content	= heathrow_mb_content,
 	.power		= heathrow_mb_power,
@@ -687,7 +687,7 @@ static struct mb_ops heathrow_mb_ops = {
 	.un_reset_ide	= heathrow_mb_un_reset_ide,
 };
 
-static struct mb_ops keylargo_mb_ops = {
+static const struct mb_ops keylargo_mb_ops = {
 	.name		= "KeyLargo",
 	.init		= keylargo_mb_init,
 	.content	= keylargo_mb_content,
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 23/25] i2c/mpc: make data used as *of_device_id.data const
From: Uwe Kleine-König @ 2012-07-23  9:13 UTC (permalink / raw)
  To: Grant Likely, Arnd Bergmann, Rob Herring, Ben Dooks, Wolfram Sang
  Cc: linuxppc-dev, linux-arm-kernel, kernel, linux-i2c
In-Reply-To: <1343034810-3386-1-git-send-email-u.kleine-koenig@pengutronix.de>

From: Arnd Bergmann <arnd@arndb.de>

[ukl: split Arnd's patch by driver]

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/i2c/busses/i2c-mpc.c |   10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 775062c..57f7703 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -730,24 +730,24 @@ static int mpc_i2c_resume(struct device *dev)
 SIMPLE_DEV_PM_OPS(mpc_i2c_pm_ops, mpc_i2c_suspend, mpc_i2c_resume);
 #endif
 
-static struct mpc_i2c_data mpc_i2c_data_512x __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_512x __devinitdata = {
 	.setup = mpc_i2c_setup_512x,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
 	.setup = mpc_i2c_setup_52xx,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_8313 __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_8313 __devinitdata = {
 	.setup = mpc_i2c_setup_8xxx,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_8543 __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_8543 __devinitdata = {
 	.setup = mpc_i2c_setup_8xxx,
 	.prescaler = 2,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_8544 __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_8544 __devinitdata = {
 	.setup = mpc_i2c_setup_8xxx,
 	.prescaler = 3,
 };
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 17/25] watchdog/mpc8xxx: add a const qualifier
From: Uwe Kleine-König @ 2012-07-23  9:13 UTC (permalink / raw)
  To: Grant Likely, Arnd Bergmann, Rob Herring, Wim Van Sebroeck
  Cc: linuxppc-dev, linux-arm-kernel, kernel, linux-watchdog
In-Reply-To: <1343034810-3386-1-git-send-email-u.kleine-koenig@pengutronix.de>

From: Arnd Bergmann <arnd@arndb.de>

This prepares *of_device_id.data becoming const. Without this change
the following warning would occur:

	drivers/watchdog/mpc8xxx_wdt.c: In function 'mpc8xxx_wdt_probe':
	drivers/watchdog/mpc8xxx_wdt.c:203:11: warning: assignment discards 'const' qualifier from pointer target type [enabled by default]

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
[ukl: split Arnd's patch by driver and add changelog]
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/watchdog/mpc8xxx_wdt.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
index 40f7bf1..e6a038a 100644
--- a/drivers/watchdog/mpc8xxx_wdt.c
+++ b/drivers/watchdog/mpc8xxx_wdt.c
@@ -193,7 +193,7 @@ static int __devinit mpc8xxx_wdt_probe(struct platform_device *ofdev)
 	int ret;
 	const struct of_device_id *match;
 	struct device_node *np = ofdev->dev.of_node;
-	struct mpc8xxx_wdt_type *wdt_type;
+	const struct mpc8xxx_wdt_type *wdt_type;
 	u32 freq = fsl_get_sys_freq();
 	bool enabled;
 
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 13/25] macintosh/mediabay: add a const qualifier
From: Uwe Kleine-König @ 2012-07-23  9:13 UTC (permalink / raw)
  To: Grant Likely, Arnd Bergmann, Rob Herring, Benjamin Herrenschmidt
  Cc: linuxppc-dev, linux-arm-kernel, kernel
In-Reply-To: <1343034810-3386-1-git-send-email-u.kleine-koenig@pengutronix.de>

This prepares *of_device_id.data becoming const. Without this change
the following warning would occur:

	drivers/macintosh/mediabay.c: In function 'media_bay_attach':
	drivers/macintosh/mediabay.c:589:11: warning: assignment discards 'const' qualifier from pointer target type [enabled by default]

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/macintosh/mediabay.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 831d751..54bf584 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -63,7 +63,7 @@ struct media_bay_info {
 	int				value_count;
 	int				timer;
 	struct macio_dev		*mdev;
-	struct mb_ops*			ops;
+	const struct mb_ops*		ops;
 	int				index;
 	int				cached_gpio;
 	int				sleeping;
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 21/25] powerpc/fsl_msi: drop unneeded cast to non-const pointer
From: Uwe Kleine-König @ 2012-07-23  9:13 UTC (permalink / raw)
  To: Grant Likely, Arnd Bergmann, Rob Herring, Benjamin Herrenschmidt,
	Paul Mackerras, Timur Tabi, Kumar Gala
  Cc: linuxppc-dev, linux-arm-kernel, kernel
In-Reply-To: <1343034810-3386-1-git-send-email-u.kleine-koenig@pengutronix.de>

From: Arnd Bergmann <arnd@arndb.de>

This cast is unneeded since *of_device_id.data became const.

[ukl: split Arnd's patch by driver and add changelog]

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 arch/powerpc/sysdev/fsl_msi.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index a40acd6..51ffafa 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -502,15 +502,15 @@ static const struct fsl_msi_feature vmpic_msi_feature = {
 static const struct of_device_id fsl_of_msi_ids[] = {
 	{
 		.compatible = "fsl,mpic-msi",
-		.data = (void *)&mpic_msi_feature,
+		.data = &mpic_msi_feature,
 	},
 	{
 		.compatible = "fsl,ipic-msi",
-		.data = (void *)&ipic_msi_feature,
+		.data = &ipic_msi_feature,
 	},
 	{
 		.compatible = "fsl,vmpic-msi",
-		.data = (void *)&vmpic_msi_feature,
+		.data = &vmpic_msi_feature,
 	},
 	{}
 };
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 15/25] powerpc/fsl_msi: add a const qualifier
From: Uwe Kleine-König @ 2012-07-23  9:13 UTC (permalink / raw)
  To: Grant Likely, Arnd Bergmann, Rob Herring, Benjamin Herrenschmidt,
	Paul Mackerras, Timur Tabi, Kumar Gala
  Cc: linuxppc-dev, linux-arm-kernel, kernel
In-Reply-To: <1343034810-3386-1-git-send-email-u.kleine-koenig@pengutronix.de>

This prepares *of_device_id.data becoming const. Without this change
the following warning would occur:

	arch/powerpc/sysdev/fsl_msi.c: In function 'fsl_of_msi_probe':
	arch/powerpc/sysdev/fsl_msi.c:379:11: error: assignment discards 'const' qualifier from pointer target type [-Werror]

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 arch/powerpc/sysdev/fsl_msi.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index 6e097de..a40acd6 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -368,7 +368,7 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
 	int err, i, j, irq_index, count;
 	int rc;
 	const u32 *p;
-	struct fsl_msi_feature *features;
+	const struct fsl_msi_feature *features;
 	int len;
 	u32 offset;
 	static const u32 all_avail[] = { 0, NR_MSI_IRQS };
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 08/25] gpio/mpc8xxx: add a const qualifier
From: Uwe Kleine-König @ 2012-07-23  9:13 UTC (permalink / raw)
  To: Grant Likely, Arnd Bergmann, Rob Herring, Linus Walleij
  Cc: linuxppc-dev, linux-arm-kernel, kernel
In-Reply-To: <1343034810-3386-1-git-send-email-u.kleine-koenig@pengutronix.de>

This prepares *of_device_id.data becoming const. Without this change
the following warning would occur:

	drivers/gpio/gpio-mpc8xxx.c: In function 'mpc8xxx_add_controller':
	drivers/gpio/gpio-mpc8xxx.c:360:30: warning: assignment discards 'const' qualifier from pointer target type [enabled by default]

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/gpio/gpio-mpc8xxx.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index 5a1817e..9ae29cc 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -38,7 +38,7 @@ struct mpc8xxx_gpio_chip {
 	 */
 	u32 data;
 	struct irq_domain *irq;
-	void *of_dev_id_data;
+	const void *of_dev_id_data;
 };
 
 static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 16/25] powerpc/celleb_pci: add a const qualifier
From: Uwe Kleine-König @ 2012-07-23  9:13 UTC (permalink / raw)
  To: Grant Likely, Arnd Bergmann, Rob Herring, Benjamin Herrenschmidt,
	Paul Mackerras, cbe-oss-dev
  Cc: linuxppc-dev, linux-arm-kernel, kernel
In-Reply-To: <1343034810-3386-1-git-send-email-u.kleine-koenig@pengutronix.de>

This prepares *of_device_id.data becoming const. Without this change
the following warning would occur:

	arch/powerpc/platforms/cell/celleb_pci.c: In function 'celleb_setup_phb':
	arch/powerpc/platforms/cell/celleb_pci.c:485:11: warning: assignment discards 'const' qualifier from pointer target type [enabled by default]

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 arch/powerpc/platforms/cell/celleb_pci.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/platforms/cell/celleb_pci.c b/arch/powerpc/platforms/cell/celleb_pci.c
index 5822141..abc8af4 100644
--- a/arch/powerpc/platforms/cell/celleb_pci.c
+++ b/arch/powerpc/platforms/cell/celleb_pci.c
@@ -472,7 +472,7 @@ int __init celleb_setup_phb(struct pci_controller *phb)
 {
 	struct device_node *dev = phb->dn;
 	const struct of_device_id *match;
-	struct celleb_phb_spec *phb_spec;
+	const struct celleb_phb_spec *phb_spec;
 	int rc;
 
 	match = of_match_node(celleb_phb_match, dev);
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 10/25] i2c/mpc: add a const qualifier
From: Uwe Kleine-König @ 2012-07-23  9:13 UTC (permalink / raw)
  To: Grant Likely, Arnd Bergmann, Rob Herring, Ben Dooks, Wolfram Sang
  Cc: linuxppc-dev, linux-arm-kernel, kernel, linux-i2c
In-Reply-To: <1343034810-3386-1-git-send-email-u.kleine-koenig@pengutronix.de>

This prepares *of_device_id.data becoming const. Without this change
the following warning would occur:

	drivers/i2c/busses/i2c-mpc.c: In function 'fsl_i2c_probe':
	drivers/i2c/busses/i2c-mpc.c:650:31: warning: initialization discards 'const' qualifier from pointer target type [enabled by default]

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/i2c/busses/i2c-mpc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index b76731e..775062c 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -647,7 +647,7 @@ static int __devinit fsl_i2c_probe(struct platform_device *op)
 	}
 
 	if (match->data) {
-		struct mpc_i2c_data *data = match->data;
+		const struct mpc_i2c_data *data = match->data;
 		data->setup(op->dev.of_node, i2c, clock, data->prescaler);
 	} else {
 		/* Backwards compatibility */
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 14/25] powerpc/83xx: add a const qualifier
From: Uwe Kleine-König @ 2012-07-23  9:13 UTC (permalink / raw)
  To: Grant Likely, Arnd Bergmann, Rob Herring, Kumar Gala,
	Benjamin Herrenschmidt, Paul Mackerras
  Cc: linuxppc-dev, linux-arm-kernel, kernel
In-Reply-To: <1343034810-3386-1-git-send-email-u.kleine-koenig@pengutronix.de>

This prepares *of_device_id.data becoming const. Without this change
the following warning would occur:

	arch/powerpc/platforms/83xx/suspend.c: In function 'pmc_probe':
	arch/powerpc/platforms/83xx/suspend.c:336:7: error: assignment discards 'const' qualifier from pointer target type [-Werror]

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 arch/powerpc/platforms/83xx/suspend.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c
index 1a04671..1d769a2 100644
--- a/arch/powerpc/platforms/83xx/suspend.c
+++ b/arch/powerpc/platforms/83xx/suspend.c
@@ -326,7 +326,7 @@ static int pmc_probe(struct platform_device *ofdev)
 	const struct of_device_id *match;
 	struct device_node *np = ofdev->dev.of_node;
 	struct resource res;
-	struct pmc_type *type;
+	const struct pmc_type *type;
 	int ret = 0;
 
 	match = of_match_device(pmc_match, &ofdev->dev);
-- 
1.7.10.4

^ permalink raw reply related

* Re: [PATCH -V3 09/11] arch/powerpc: Use 50 bits of VSID in slbmte
From: Paul Mackerras @ 2012-07-23  9:36 UTC (permalink / raw)
  To: Aneesh Kumar K.V; +Cc: linuxppc-dev
In-Reply-To: <87394ij3aa.fsf@skywalker.in.ibm.com>

On Mon, Jul 23, 2012 at 01:51:49PM +0530, Aneesh Kumar K.V wrote:
> Paul Mackerras <paulus@samba.org> writes:
> 
> > On Mon, Jul 09, 2012 at 06:43:39PM +0530, Aneesh Kumar K.V wrote:
> >> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
> >> 
> >> Increase the number of valid VSID bits in slbmte instruction.
> >> We will use the new bits when we increase valid VSID bits.
> >> 
> >> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> >> ---
> >>  arch/powerpc/mm/slb_low.S |    4 ++--
> >>  1 file changed, 2 insertions(+), 2 deletions(-)
> >> 
> >> diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
> >> index c355af6..c1fc81c 100644
> >> --- a/arch/powerpc/mm/slb_low.S
> >> +++ b/arch/powerpc/mm/slb_low.S
> >> @@ -226,7 +226,7 @@ _GLOBAL(slb_allocate_user)
> >>   */
> >>  slb_finish_load:
> >>  	ASM_VSID_SCRAMBLE(r10,r9,256M)
> >> -	rldimi	r11,r10,SLB_VSID_SHIFT,16	/* combine VSID and flags */
> >> +	rldimi	r11,r10,SLB_VSID_SHIFT,2	/* combine VSID and flags */
> >
> > You can't do that without either changing ASM_VSID_SCRAMBLE or masking
> > the VSID it generates to 36 bits, since the logic in ASM_VSID_SCRAMBLE
> > can leave non-zero bits in the high 28 bits of the result.  Similarly
> > for the 1T case.
> >
> 
> How about change ASM_VSID_SCRAMBLE to clear the high bits ? That would
> also make it close to vsid_scramble()

One more instruction in a hot path - I'd rather not.  How about
changing the rldimi instruction to:
	rldimi	r11,r10,SLB_VSID_SHIFT,(64-SLB_VSID_SHIFT-VSID_BITS_256M)

and similarly for the 1T case.  That will give the proper masking
when you change VSID_BITS_256M.

Paul.

^ permalink raw reply

* Re: [PATCH -V3 11/11] arch/powerpc: Add 64TB support
From: Paul Mackerras @ 2012-07-23  9:39 UTC (permalink / raw)
  To: Aneesh Kumar K.V; +Cc: linuxppc-dev
In-Reply-To: <1341839621-28332-12-git-send-email-aneesh.kumar@linux.vnet.ibm.com>

On Mon, Jul 09, 2012 at 06:43:41PM +0530, Aneesh Kumar K.V wrote:

> -#define USER_ESID_BITS		16
> -#define USER_ESID_BITS_1T	4
> +#define USER_ESID_BITS		18
> +#define USER_ESID_BITS_1T	6

You also need to change the proto-VSID generation for kernel addresses
when you do this.  If you don't you'll end up with some user processes
using the same VSIDs as we use for the kernel addresses, meaning that
those processes won't run very well...

Paul.

^ permalink raw reply

* [PATCH] using get/put_user64 apis on 64bit machine
From: Bharat Bhushan @ 2012-07-23 10:16 UTC (permalink / raw)
  To: linuxppc-dev, galak, agraf, scottwood; +Cc: Bharat Bhushan

On powerpc64 machine get/put_user64() is same as get/put_user() while
on powerpc32 machine get_user64 is different. With this patch we can
use get_user64() and put_user64() on 32 and 64 bit machines.

Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
 arch/powerpc/include/asm/uaccess.h |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
index 17bb40c..01743aa 100644
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -114,10 +114,17 @@ struct exception_table_entry {
 #define __put_user(x, ptr) \
 	__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
 
+/*
+ * On powerpc64 machine get/put_user64() is same as get/put_user() while
+ * on powerpc32 machine get_user64 is different.
+ */
 #ifndef __powerpc64__
 #define __get_user64(x, ptr) \
 	__get_user64_nocheck((x), (ptr), sizeof(*(ptr)))
 #define __put_user64(x, ptr) __put_user(x, ptr)
+#else
+#define __get_user64(x, ptr) __get_user(x, ptr) 
+#define __put_user64(x, ptr) __put_user(x, ptr)
 #endif
 
 #define __get_user_inatomic(x, ptr) \
-- 
1.7.0.4

^ permalink raw reply related

* Re: [PATCH -V3 11/11] arch/powerpc: Add 64TB support
From: Aneesh Kumar K.V @ 2012-07-23 10:22 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <20120723093951.GB29264@bloggs.ozlabs.ibm.com>

Paul Mackerras <paulus@samba.org> writes:

> On Mon, Jul 09, 2012 at 06:43:41PM +0530, Aneesh Kumar K.V wrote:
>
>> -#define USER_ESID_BITS		16
>> -#define USER_ESID_BITS_1T	4
>> +#define USER_ESID_BITS		18
>> +#define USER_ESID_BITS_1T	6
>
> You also need to change the proto-VSID generation for kernel addresses
> when you do this.  If you don't you'll end up with some user processes
> using the same VSIDs as we use for the kernel addresses, meaning that
> those processes won't run very well...
>

Can you explain this more. right now we generate vsid as below

vsid_scramble(ea >> SID_SHIFT, 256M) for kernel

vsid_scramble((context << USER_ESID_BITS) | (ea >> SID_SHIFT), 256M);
for user

what changes are you suggesting ?

-aneesh

^ permalink raw reply

* Re: [PATCH -V3 09/11] arch/powerpc: Use 50 bits of VSID in slbmte
From: Aneesh Kumar K.V @ 2012-07-23 10:22 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <20120723093611.GA29264@bloggs.ozlabs.ibm.com>

Paul Mackerras <paulus@samba.org> writes:

> On Mon, Jul 23, 2012 at 01:51:49PM +0530, Aneesh Kumar K.V wrote:
>> Paul Mackerras <paulus@samba.org> writes:
>> 
>> > On Mon, Jul 09, 2012 at 06:43:39PM +0530, Aneesh Kumar K.V wrote:
>> >> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
>> >> 
>> >> Increase the number of valid VSID bits in slbmte instruction.
>> >> We will use the new bits when we increase valid VSID bits.
>> >> 
>> >> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
>> >> ---
>> >>  arch/powerpc/mm/slb_low.S |    4 ++--
>> >>  1 file changed, 2 insertions(+), 2 deletions(-)
>> >> 
>> >> diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
>> >> index c355af6..c1fc81c 100644
>> >> --- a/arch/powerpc/mm/slb_low.S
>> >> +++ b/arch/powerpc/mm/slb_low.S
>> >> @@ -226,7 +226,7 @@ _GLOBAL(slb_allocate_user)
>> >>   */
>> >>  slb_finish_load:
>> >>  	ASM_VSID_SCRAMBLE(r10,r9,256M)
>> >> -	rldimi	r11,r10,SLB_VSID_SHIFT,16	/* combine VSID and flags */
>> >> +	rldimi	r11,r10,SLB_VSID_SHIFT,2	/* combine VSID and flags */
>> >
>> > You can't do that without either changing ASM_VSID_SCRAMBLE or masking
>> > the VSID it generates to 36 bits, since the logic in ASM_VSID_SCRAMBLE
>> > can leave non-zero bits in the high 28 bits of the result.  Similarly
>> > for the 1T case.
>> >
>> 
>> How about change ASM_VSID_SCRAMBLE to clear the high bits ? That would
>> also make it close to vsid_scramble()
>
> One more instruction in a hot path - I'd rather not.  How about
> changing the rldimi instruction to:
> 	rldimi	r11,r10,SLB_VSID_SHIFT,(64-SLB_VSID_SHIFT-VSID_BITS_256M)
>
> and similarly for the 1T case.  That will give the proper masking
> when you change VSID_BITS_256M.
>

This is better. I have made this change.

-aneesh

^ permalink raw reply

* [1/3][PATCH][upstream]Adding documentation for TDM
From: b37400 @ 2012-07-23 10:49 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Sandeep Singh, Poonam Aggrwal
In-Reply-To: <1343040588-16002-1-git-send-email-b37400@freescale.com>

From: Sandeep Singh <Sandeep@freescale.com>

 tdm-summary.txt contains general description about TDM.
 tdm-framework.txt contains specific description of TDM framework.

Signed-off-by: Sandeep Singh <Sandeep@freescale.com>
Signed-off-by: Poonam Aggrwal <poonam.aggrwal@freescale.com>
---
 Documentation/tdm/tdm-framework.txt |  264 +++++++++++++++++++++++++++++++++++
 Documentation/tdm/tdm-summary.txt   |  103 ++++++++++++++
 2 files changed, 367 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/tdm/tdm-framework.txt
 create mode 100644 Documentation/tdm/tdm-summary.txt

diff --git a/Documentation/tdm/tdm-framework.txt b/Documentation/tdm/tdm-framework.txt
new file mode 100644
index 0000000..b5a98bf
--- /dev/null
+++ b/Documentation/tdm/tdm-framework.txt
@@ -0,0 +1,264 @@
+This document gives an overview of TDM framework and its interface with low
+level drivers and upper level users/clients.
+
+Terminology:
+============
+1. TDM: Time Division Multiplexing.
+2. TDM channel: The channel is the smallest entity on which all the TDM read/
+   write operations will occur. Technically each channel maps to a set of
+   consecutive time slots on the physical TDM frame. The channels will be
+   dynamically created and destroyed using tdm_open_channel and
+   tdm_close_channel.
+3. TDM adapter or Adapter: Refers to an instance of TDM controller/device on
+   the system.
+4. TDM frame: Is a set of TDM channels which is transmitted sequentially over
+   time. The frame start is identified by a frame sync signal that is briefly
+   asserted at the beginning of each frame.
+
+X----------TDM Frame 0-------------X------TDM Frame 1-----------------X
+|----|----|----|----|----|----|----|----|----|----|----|----|----|----|
+| 0  | 1  | 2  | 3  | 4  | ...|  n |  0 | 1  |  2 |  3 | 4  | ...| n  |...
+|----|----|----|----|----|----|----|----|----|----|----|----|----|----|
+<---->				   <---->
+ch 0				   ch 0
+
+4. TDM client: Application/driver which registers with TDM framework to use TDM
+   device.
+5. TDM port: It can be seen as a virtual device exposed to a client. At a time
+   TDM port can work in one of the follwing configurations:
+   full/fractional/E1/T1/raw.
+
+TDM modes
+========
+A TDM device can operate in one of the following modes:
+1. Single port full mode - Single user/no interleaving
+2. Single port channelised mode (raw, E1, T1)- many users using different
+   channels
+3. Single port fractional mode -
+4. Multi port mode - multiple users using different ports in different
+   configurations.
+
+All the above configurations differ in number of TDM client they support,
+number of TDM channels and number of TDM ports.
+
+Currently we are supporting only single port channelised mode. Hence all the
+explanations below refer to channelised mode of TDM. This framework can be
+easily extended to support other modes.
+
+Single port Channelised Mode
+==============================
+In single port channelised mode there can be only one port and each channel
+can have only one time slot.The number of active channels can be less than
+the maximum supported channels/slots.
+
+X----------TDM Frame 0-------------X------TDM Frame 1-----------------X
+|----|----|----|----|----|----|----|----|----|----|----|----|----|----|
+| 0  | 1  | 2  | 3  | 4  | ...|  n |  0 | 1  |  2 |  3 | 4  | ...| n  |...
+|----|----|----|----|----|----|----|----|----|----|----|----|----|----|
+<----><--->				   <---->
+ch 0	ch1			   ch 0
+client0 client1
+
+TDM Subsystem Overview
+========================
+
+	 |-----------------------|
+	 |user mode TDM clients  |
+	 |-----------------------|
+		||
+-------------------------------------------------------------------
+  tdm-dev.c     ||
+		||
+	        ||                    	     |------------------------|
+	    client register            	     | kernel mode TDM clients|
+	        ||                     	     |------------------------|
+	        ||					||
+	        || 					||
+		||		  		client register
+		||					||
+		\/		   		        \/
+      ______________________________________________________________
+      |                 					   |
+      |                 client interface                           |
+      |------------------------------------------------------------|
+      |             TDM Subsystem Framework         	           |
+      |                   (tdm-core.c)                             |
+      |                                                            |
+      | ->buffer handling                                          |
+      | ->interleaving/de-interleaving                             |
+      |                                                            |
+      |------------------------------------------------------------|
+      |    TDM interface                  Line control interface   |
+      |____________________________________________________________|
+          /\                                       /\
+          ||                                       ||
+    device register                          device register
+          ||                                       ||
+          ||                                       ||
+
+     fsl_tdm.c                 ucc_tdm.c         slic_zarlink.c framer.c
+--------------------------------------------------------------------------
+_______________________    _____________________  ________    ________
+|		      |	   |		       |  |	 |    |      |
+|[h/w] TDM controller |    |UCC TDM controller |  | SLIC |    |Framer|
+|_____________________|    |___________________|  |______|    |______|
+
+
+
+TDM Adapter Registration:
+=========================
+All the TDM adapter drivers will get registered as platform drivers to Linux.
+For every instance of the TDM adapter the relevant driver will be probed.
+As part of probe the driver will
+1. Do the basic initialization in terms of memory allocation for various
+   driver specific data structures, interrupts registration, etc.
+2. Initialize the TDM adapter and configure it in default configuration.
+   like operating mode, number of channels, channel type, etc.
+3. Add the TDM adapter to the TDM Framework via tdm_add_adapter() API.
+   As a result TDM framework will add this adapter to it's queue of
+   available adapters. As part of this adapter registration TDM framework
+   is also supplied a list of access algorithms for the particular TDM
+   adapter.
+4. Notifies the clients
+
+TDM Client Registration:
+========================
+Every TDM client gets itself registered with the TDM framework layer as
+a TDM driver using the API tdm_add_driver(). As part of this the TDM client
+supplies to the TDM framework the adapter with which it wants to hook and
+the function pointers of attach and detach functions which must be called
+as soon as the requested adapter is available.
+
+As a result the TDM framework keeps association of TDM adapters and TDM
+client drivers.
+As soon as this association gets established a tasklet is created for the
+adapter which is handled by tdm_data_tasklet_fn. The primary function of
+this tasklet acts as an interface to transfer the TDM data between the
+TDM adapter and the TDM client drivers.
+
+
+Currently TDM adaper can only be used in the default configuration.
+ie the configuration cannot be modified by TDM clients. This will
+be enhanced in future.
+
+Data handling:
+==============
+Some basic assumptions about data handling:
+
+1. As per standard voice rate of 8Khz or 8192Hz. Which means 8192 samples must
+be sent every second. So if there are multiple clients sending voice data
+over TDM interface the rate should be such that the individual samples
+sent by them must be transmitted at 8Kz.
+
+This is defined in the driver as
+
+	#define CH_1_MS_FRAMES		8
+
+2. Number of milliseconds at which TDM Rx interrupts occur
+This is basically the time for which the TDM data is sent in one Tx or Rx
+cycle of TDM controller hardware. In one DMA we send the data for 10ms.
+This gives enough time so that no buffer overflow or under-run occurs for
+transmit and receive respectively.
+
+	#define NUM_MS                  10
+
+3. TDM has programmable slot length (8 bits or 16 bits). This can be
+   configured by:
+
+	#define NUM_BYTES_PER_SLOT	8
+or
+	#define NUM_BYTES_PER_SLOT	16
+
+depending on the type of sample. For example the sample could be 16 bit linear
+or 8bit u-law encoded etc. Presently only word length of 16 is supported
+which is the default configuration.
+
+4. Number of channels means the total number of channels per TDM port.
+For example for E1 mode it will be 24, for T1 it will be 32, etc.
+There can also be raw mode, where the use case is not E1 or T1.
+Here the number of channels can be any number as per the use case.
+
+The whole framework follows a triple buffer approach to make sure that TDM data
+is played continuously at the desired rate.
+
+Buffers Involved:
+=================
+
+1.TDM driver or device buffers:
+These buffers are the device level buffers. They contain the TDM data which is
+transmitted/received on the TDM physical signals. As such these buffers must
+be allocated from driver layer so that all the hardware requirements are met.
+As an optimized design to remove extra memcopies, the client can pass the data
+in the same buffers. But this is only true for full mode of TDM. Where the
+user data can be straightaway passed to the hardware for transmission.
+Although in other cases memcopy cannot be avoided, because the framework layer
+will have to interleave the individual channels data to create the TDM frame
+data buffer.For channelised mode size of this buffer will be governed by:
+
+-	number of channels
+- 	number of slots per channel
+-	number of bytes per slot
+- 	number of frames per ms
+-	number of ms
+
+For a channelised mode with single port the size of the device level buffer
+will be:
+
+channels * slots per channel * bytes per slot * frames per ms *
+number of ms channels * NUM_BYTES_PER_SLOT * NUM_MS * CH_1_MS_FRAMES
+
+There will be 3 such buffers.
+
+2.Channel level buffers:
+In case the TDM device is configured for multiport/multichannel the Framework
+layer needs to maintain the data for each channel. Hence for each channel
+opened a Buffer Descriptor ring of 3 BDs(see note below) is allocated both for
+transmit and receive. The client reads from/writes to the buffers pointed by
+these BD rings.
+
+The framework layer maintains a Data Process Tasklet per TDM device which is
+scheduled from every Rx interrupt. The interrupt handling periodicity is
+governed by the TDM data buffer size configured in the above section. The data
+tasklet when scheduled, will do Rx and Tx processing to copy the data from/to
+the channel specific interleaved buffers. The TDM controller will DMA the
+data which is copied in the interleaved buffers or device level buffers.
+
+TDM framework provides the port level APIs and channel level APIs to the TDM
+client drivers to send and receive the respective data on different TDM slots.
+
+
+num of buffers = 3
+
+TDM client1           	TDM Client2
+
+buf0------->buf1	buf0------->buf1
+^            |		^            |
+|            V		|            V
+----buf2------		------buf2----
+     |				|
+     |				|
+     |				|
+     V				V
+-----------------------------------------
+|					|
+|    	 DATA Tasklet			|
+|					|
+-----------------------------------------
+		|
+		|
+		V
+-----------------------------------------
+|    	 TDM buffer interleaved * 3	|
+-----------------------------------------
+
+
+Not Implemented/Future work:
+============================
+1. TDM client will use the default configuration which is done at init time
+   and is not configurable. In future this should be made configurable as per
+   the needs of client.
+2. The TDM framework still needs to be enhanced to configure the ports and
+   their attributes. Currently only single port channelised mode is supported.
+3. Line control interface is not available in the framework presently.
+   Presently it offer very minimal kind of interface.
+4. SLIC interface will be enhanced as per Zarlink Open source APIs in future.
diff --git a/Documentation/tdm/tdm-summary.txt b/Documentation/tdm/tdm-summary.txt
new file mode 100644
index 0000000..f010f76
--- /dev/null
+++ b/Documentation/tdm/tdm-summary.txt
@@ -0,0 +1,103 @@
+Time Division Multiplexing (TDM)
+=================================
+
+TDM is a type of digital or analog multiplexing in which two or more bit
+streams or signals are transferred apparently simultaneously as sub-channels
+in one communication channel, but are physically taking turns on the channel.
+
+The time domain is divided into several recurrent timeslots of fixed duration.
+These timeslot are grouped together to form a channel. A sample byte or data
+block of channel 1 is transmitted during timeslots allocated to channel 1,
+channel 2 during timeslot for channel 2, etc.
+
+One TDM frame consists of multiple channels. After the last channel the cycle
+starts all over again with a new frame, starting with the second sample, byte
+or data block from channel 1, and so on.
+
+X----------TDM Frame 0-------------X------TDM Frame 1-----------------X
+|----|----|----|----|----|----|----|----|----|----|----|----|----|----|
+| 0  | 1  | 2  | 3  | 4  | ...|  n |  0 | 1  |  2 |  3 | 4  | ...| n  |...
+|----|----|----|----|----|----|----|----|----|----|----|----|----|----|
+<---->				   <---->
+channel 0			   channel 0
+-------------------------------------------------------------------->
+         Increasing Time
+
+Physical TDM interface
+=======================
+
+Physically TDM interface is a serial full duplex interface designed to
+communicate with variety of serial devices like industry standard framers,
+codecs, other DSPs, and microprocessors. It is typically used to transfer
+samples in a periodic manner. The TDM consists of independent transmitter and
+receiver sections with independent clock generation and frame synchronization.
+
+External TDM signals are:
+1. TDM_TCK: TDM Transmit clock
+2. TDM_RCK: TDM Receive clock
+3. TDM_TFS: TDM Tx frame sync to identify frame boundary
+4. TDM_RFS: TDM Rx Frame sync to identify frame boundary
+5. TDM_TD: TDM Tx data
+6. TDM_RD: TDM Rx data
+
+TDM is generally used to simultaneously transmit periodic data for multiple
+users. Common use cases would be to carry voice for various telephone
+subscribers in the telephone networks. It is widely used to carry telephonic
+data of various industry standards like E1/T1 data, etc.
+
+T1 Details
+==========
+T1 frame consists of 24 channels of 8 bits each plus one frame alignment bit.
+So a T1 frame has a total of 24x8 + 1 = 193 bits. Since each T1 frame contains
+one byte of voice data for each of 24 channels and the system needs to maintain
+a data rate of 8000 samples/sec. This would require 8000 frames/sec to be sent,
+yielding a data rate of 8000x193 bit/sec = 1.544 Mbps.
+
+E1 Details
+===========
+E1 frame consists of 32 channels each of 8 bits. Thus having a total frame
+length of 32x8 = 256 bits. Similar to the case of T1 it has to maintain a data
+rate of 8000 frames/sec. Thus having a data rate of 8000 x 256 bits/sec =
+2.048 Mbps.
+
+TDM use cases
+=============
+
+With SLIC kind of devices
+=========================
+SLIC stands for Subscriber Line Interface Card.
+Typically TDM systems consist of TDM controller and a line control device.
+
+The TDM controller interfaces to the line control device through TDM interface
+which is digital TDM multiplexed data.
+
+The Line controller has the functionality to interface with the TDM controller
+at one end and interface with the analog units at the other. For example if the
+line control device is a SLIC kind of device.
+The typical setup would be:
+
+|------------------|
+|		   |
+|		   | /-------\  |---------|
+|   TDM controller |/   TDM   \ |  SLIC   |<--------> s-ch0 analog phone 1
+|		   |\   data  / |         |<--------> s-ch1 analog phone 2
+|		   | \-------/  |---------|<--------> s-ch2 analog phone 3
+|		   |<----digital---->     <analog>
+|------------------|
+
+
+
+Another use case (VoIP):
+========================
+
+                             Voice packets on network
+     |--------|     |------|      _________      |------|     |------|
+>----|        |/---\|  TDM |     (         )     | TDM  |/---\|      |----->
+<----| SLIC   |\---/|      |     ( n/w     )     |      |\---/| SLIC |-----<
+>----|        |     |------|      ---------      |------|     |      |----->
+     |--------|      mux                          demux       |------|
+
+In the above figure analog phones are connected to the hosts via SLICs.
+The voice spoken on the phones is multiplexed converted into VoIP packets
+and sent over network. At the rendering end the multiplexed data
+is de-multiplexed and sent to respective listeners via SLIC.
-- 
1.5.6.5

^ permalink raw reply related

* [2/3][PATCH][upstream] TDM Framework
From: b37400 @ 2012-07-23 10:49 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Sandeep Singh, Poonam Aggrwal

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.
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, etc

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.

Presently the framework supports only Single Port channelised mode.
Also the configurability options are limited which will be extended later on.
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>
---

Based on: git://git.am.freescale.net/gitolite/mirrors/galak-powerpc.git
Branch: master
Checkpatch: passed

First patch version was RFC.

Changes since RFC:
	- Since all read/write operations are in TDM are channel based, polling
	on TDM channel for data instead of TDM port before going for read/write.
	- Also corrected a faulty error leg
	- Removed unused function tdm_port_get_wait_queue.

	Incorporated Scott's comments:
	- Removed TDM_CORE_DEBUG.
	- Added sysfs knob to change use_latest_tdm_data at runtime.
	- Works more silently now (lesser prints).
	- Cosmetic errors rectified.
	- Removed unused function tdm_init.
	- Removed unused variables.
	- Removed unnecessary typecast and NULL check.
	- Removed #include "device/tdm_fsl.h".

	Incorporated Timur's comments:
	- Handled errors.
	- Used dev_err instead of pr_err
	- Removed extern from function declaration.



 drivers/Kconfig                 |    1 +
 drivers/Makefile                |    1 +
 drivers/tdm/Kconfig             |   18 +
 drivers/tdm/Makefile            |    5 +
 drivers/tdm/tdm-core.c          | 1082 +++++++++++++++++++++++++++++++++++++++
 include/linux/mod_devicetable.h |   11 +
 include/linux/tdm.h             |  338 ++++++++++++
 7 files changed, 1456 insertions(+), 0 deletions(-)
 create mode 100644 drivers/tdm/Kconfig
 create mode 100644 drivers/tdm/Makefile
 create mode 100644 drivers/tdm/tdm-core.c
 create mode 100644 include/linux/tdm.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 5afe5d1..abd6c83 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -136,4 +136,5 @@ source "drivers/virt/Kconfig"
 
 source "drivers/devfreq/Kconfig"
 
+source "drivers/tdm/Kconfig"
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 1b31421..7cb88e3 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -104,6 +104,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..0b0fda8
--- /dev/null
+++ b/drivers/tdm/Kconfig
@@ -0,0 +1,18 @@
+#
+# 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
+
+endif # TDM
diff --git a/drivers/tdm/Makefile b/drivers/tdm/Makefile
new file mode 100644
index 0000000..84e2cb9
--- /dev/null
+++ b/drivers/tdm/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the TDM core.
+#
+
+obj-$(CONFIG_TDM)		+= tdm-core.o
diff --git a/drivers/tdm/tdm-core.c b/drivers/tdm/tdm-core.c
new file mode 100644
index 0000000..9973b6b
--- /dev/null
+++ b/drivers/tdm/tdm-core.c
@@ -0,0 +1,1082 @@
+/* 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 controlled
+ * 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.
+ * 4. Added sysfs knob to configure use_latest_tdm_data at runtime.
+ *
+ * Note that some parts of this code may have been derived from i2c subsystem.
+ *
+ * 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.
+ */
+
+
+#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>
+
+
+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;
+
+/* Data structures required for sysfs */
+static struct tdm_sysfs attr = {
+	.attr.name = "use_latest_data",
+	.attr.mode = 0664,
+	.cmd_type = TDM_LATEST_DATA,
+};
+
+static struct attribute *tdm_attr[] = {
+	&attr.attr,
+	NULL
+};
+
+const struct sysfs_ops tdm_ops = {
+	.show = tdm_show_sysfs,
+	.store = tdm_store_sysfs,
+};
+
+static struct kobj_type tdm_type = {
+	.sysfs_ops = &tdm_ops,
+	.default_attrs = tdm_attr,
+};
+
+/* 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)
+{
+	int ret = TDM_E_OK;
+	/* if driver is already attached to any other adapter, return*/
+	if (driver->adapter && (driver->adapter != adap))
+		return ret;
+
+	driver->adapter = adap;
+
+	if (driver->attach_adapter) {
+		ret = driver->attach_adapter(adap);
+		if (ret < 0) {
+			pr_err("attach_adapter failed for driver [%s] err:%d\n"
+					, driver->name, ret);
+			return ret;
+		}
+	}
+	adap->drv_count++;
+
+	if (!adap->tasklet_conf) {
+		tdm_sysfs_init();
+		tasklet_init(&adap->tdm_data_tasklet, tdm_data_tasklet_fn,
+				(unsigned long)adap);
+		adap->tasklet_conf = 1;
+	}
+
+	return ret;
+}
+
+/* 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;
+
+	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;
+
+	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);
+			if (res == TDM_E_OK) {
+				pr_info("Driver(ID=%d) is "
+						"attached with Adapter %s(ID"
+						" = %d)\n", driver->id,
+						adap->name, adap->id);
+			} else {
+				pr_err("Driver(ID=%d) is unable "
+						"to attach 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;
+
+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;
+
+	/* 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);
+		}
+	}
+	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);
+			if (res == TDM_E_OK) {
+				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);
+			} else {
+				pr_err("TDM Driver(ID=%d) unable to attach "
+						"to 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)
+{
+	/* 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);
+
+/* 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->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;
+	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;
+	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 */
+int tdm_port_open(struct tdm_driver *driver, struct tdm_port **h_port)
+{
+	struct tdm_port *port;
+	struct tdm_adapter *adap;
+	unsigned long		flags;
+	int res = TDM_E_OK;
+
+	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;
+	}
+
+	port->rx_max_frames = NUM_SAMPLES_PER_FRAME;
+	port->port_cfg.port_mode = TDM_PORT_CHANNELIZED;
+
+	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);
+
+int tdm_port_close(struct tdm_port *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 = h_port;
+
+	driver =  port->driver;
+
+	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);
+
+int tdm_channel_read(struct tdm_port *h_port, struct tdm_channel *h_channel,
+		void *p_data, u16 *size)
+{
+	struct tdm_channel *channel;
+	struct tdm_bd *rx_bd;
+	unsigned long flags;
+	int i, res = TDM_E_OK;
+	unsigned short *buf, *buf1;
+	channel = h_channel;
+
+	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_debug("No Data Available");
+		return -EAGAIN;
+	}
+	spin_unlock_irqrestore(&channel->p_ch_data->rx_channel_lock, flags);
+
+	return res;
+}
+EXPORT_SYMBOL(tdm_channel_read);
+
+
+int tdm_channel_write(struct tdm_port *h_port, struct tdm_channel *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 = h_port;
+	channel = h_channel;
+#ifdef DEBUG
+	bool data_flag = 0;
+#endif
+
+	if (p_data == NULL) { /* invalid data*/
+		pr_err("Invalid Data");
+		return -EFAULT;
+	}
+
+	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 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	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);
+
+/* Driver Function for select and poll. Based on Channel, it sleeps on
+ * waitqueue */
+int tdm_ch_poll(struct tdm_channel *h_channel, unsigned int wait_time)
+{
+	struct tdm_channel *channel;
+	unsigned long timeout = msecs_to_jiffies(wait_time);
+	channel = h_channel;
+
+	if (!channel->p_ch_data || !channel->in_use)
+		return -EIO;
+
+	if (channel->p_ch_data->rx_out_data->flag) {
+		pr_debug("Data Available");
+		return TDM_E_OK;
+	}
+	if (timeout) {
+		wait_event_interruptible_timeout(channel->ch_wait_queue,
+				channel->p_ch_data->rx_out_data->flag,
+				timeout);
+
+		if (channel->p_ch_data->rx_out_data->flag) {
+			pr_debug("Data Available");
+			return TDM_E_OK;
+		}
+	}
+	return -EAGAIN;
+}
+EXPORT_SYMBOL(tdm_ch_poll);
+
+unsigned int tdm_port_get_stats(struct tdm_port *h_port,
+		struct tdm_port_stats *portStat)
+{
+	struct tdm_port *port;
+	int port_num;
+	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;
+
+	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) {
+
+		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 && 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;
+					wake_up_interruptible
+						(&channel->ch_wait_queue);
+				}
+			} 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 */
+#ifdef	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 DEBUG
+	u8	data_flag = 0;
+#endif
+
+	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) {
+
+		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 genric 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	DEBUG
+				data_flag = 1;
+#endif
+			}
+			spin_unlock(&channel->p_ch_data->tx_channel_lock);
+		}
+	}
+
+#ifdef	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,
+		struct tdm_channel **h_channel)
+{
+	struct tdm_channel *channel, *temp;
+	unsigned long		flags;
+	struct tdm_ch_data	*p_ch_data;
+	int res = TDM_E_OK;
+
+	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;
+	}
+
+	init_waitqueue_head(&channel->ch_wait_queue);
+	p_ch_data = kzalloc(sizeof(struct tdm_ch_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_sysfs_init(void)
+{
+	struct kobject *tdm_kobj;
+	int err = 1;
+	tdm_kobj = kzalloc(sizeof(*tdm_kobj), GFP_KERNEL);
+	if (tdm_kobj) {
+		kobject_init(tdm_kobj, &tdm_type);
+		if (kobject_add(tdm_kobj, NULL, "%s", "tdm")) {
+			pr_err("Sysfs creation failed\n");
+			kobject_put(tdm_kobj);
+			err = -EINVAL;
+			goto out;
+		}
+	} else {
+		pr_err("Unable to allocate tdm_kobj\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+out:
+	return err;
+}
+
+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;
+
+	spin_lock_irqsave(&port->ch_list_lock, flags);
+	list_del(&channel->list);
+	spin_unlock_irqrestore(&port->ch_list_lock, flags);
+
+	if (channel)
+		kfree(channel->p_ch_data);
+	kfree(channel);
+	return res;
+}
+EXPORT_SYMBOL(tdm_channel_close);
+
+ssize_t tdm_show_sysfs(struct kobject *kobj,
+		struct attribute *attr, char *buf)
+{
+	int retval = 0;
+	struct tdm_sysfs *a = container_of(attr,
+			struct tdm_sysfs, attr);
+	switch (a->cmd_type) {
+	case TDM_LATEST_DATA:
+		pr_info("use_latest_tdm_data: %d\n", use_latest_tdm_data);
+		break;
+	default:
+		pr_info("Invalid cmd_type value\n");
+		return -EINVAL;
+	}
+	return retval;
+}
+
+ssize_t tdm_store_sysfs(struct kobject *kobj,
+		struct attribute *attr, const char *buf, size_t len)
+{
+	struct tdm_sysfs *a = container_of(attr,
+			struct tdm_sysfs, attr);
+
+	sscanf(buf, "%d", &a->data);
+	use_latest_tdm_data = a->data;
+	return strlen(buf);
+}
+
+void init_config_adapter(struct tdm_adapter *adap)
+{
+	struct fsl_tdm_adapt_cfg default_adapt_cfg = {
+		.loopback = 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 = 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);
+
+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 83ac071..573ac40 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -425,6 +425,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..a2f9628
--- /dev/null
+++ b/include/linux/tdm.h
@@ -0,0 +1,338 @@
+/* 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
+
+#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>
+#include <linux/sysfs.h>
+
+#define TDM_LATEST_DATA		1
+#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 */
+
+/*
+ * Default adapter configuration. All the TDM adapters registered with
+ * framework will be configured with following default configuration.
+ */
+#define NUM_CHANNELS	16
+
+/* Default configuration for typical voice data sample. These parameters
+ * will generally not be required to be changed for voice type applications.
+ */
+#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;
+
+
+/**
+ * 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);
+
+	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 */
+
+	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 */
+	u8 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 */
+	wait_queue_head_t ch_wait_queue;/* waitQueue for RX Channel Data */
+};
+
+/* 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 {
+	TDM_ADAPTER_MODE_NONE = 0x00,
+	TDM_ADAPTER_MODE_T1 = 0x01,
+	TDM_ADAPTER_MODE_E1 = 0x02,
+	TDM_ADAPTER_MODE_T1_RAW = 0x10,
+	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 {
+	TDM_PORT_CHANNELIZED = 0,	/* Channelized mode */
+	TDM_PORT_FULL = 1,		/* Full mode */
+	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 {
+	TDM_PROCESS_NORMAL = 0,		/* Normal mode */
+	TDM_PROCESS_INT_LPB = 1,	/* Internal loop mode */
+	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_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 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;
+
+	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;
+	void *data;
+	struct fsl_tdm_adapt_cfg adapt_cfg;
+};
+
+struct tdm_sysfs {
+	struct attribute attr;
+	int data;
+	u32 cmd_type;
+};
+
+/* functions exported by tdm.o */
+
+int tdm_add_adapter(struct tdm_adapter *adpater);
+int tdm_del_adapter(struct tdm_adapter *adapter);
+int tdm_register_driver(struct tdm_driver *driver);
+void tdm_unregister_driver(struct tdm_driver *driver);
+void init_config_adapter(struct tdm_adapter *adapter);
+
+int tdm_port_open(struct tdm_driver *driver, struct tdm_port **h_port);
+int tdm_port_close(struct tdm_port *h_port);
+int tdm_channel_read(struct tdm_port *h_port, struct tdm_channel *h_channel,
+		void *p_data, u16 *size);
+int tdm_channel_write(struct tdm_port *h_port, struct tdm_channel *h_channel,
+		void *p_data, u16 size);
+int tdm_ch_poll(struct tdm_channel *h_channel, unsigned int wait_time);
+
+int tdm_channel_open(u16 chanid, u16 ch_width, struct tdm_port *port,
+		struct tdm_channel **h_channel);
+int tdm_channel_close(u16 chanid, u16 ch_width, struct tdm_port *port,
+		struct tdm_channel *h_channel);
+/* this tasklet is created for each adapter instance */
+void tdm_data_tasklet_fn(unsigned long);
+int tdm_sysfs_init(void);
+ssize_t tdm_show_sysfs(struct kobject *kobj,
+		struct attribute *attr, char *buf);
+ssize_t tdm_store_sysfs(struct kobject *kobj,
+		struct attribute *attr, const char *buf, size_t len);
+
+struct tdm_adapter *tdm_get_adapter(int id);
+void tdm_put_adapter(struct tdm_adapter *adap);
+
+#endif /* __KERNEL__ */
+
+#define TDM_E_OK 0
-- 
1.5.6.5

^ permalink raw reply related

* [3/3][PATCH][upstream]Added TDM device support and Freescale Starlite driver
From: b37400 @ 2012-07-23 10:49 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Sandeep Singh, Poonam Aggrwal
In-Reply-To: <1343040588-16002-2-git-send-email-b37400@freescale.com>

From: Sandeep Singh <Sandeep@freescale.com>

Freescale TDM controller consists of a TDM module supporting 128 channels
running at up to 50 Mbps with 8-bit and 16-bit word size. The TDM bus connects
gluelessly to most T1/E1 frames as well as to common buses such as the H.110,
SCAS, and MVIP. TDM also supports an I2S mode. The TDM module operates in
independent or shared mode when receiving or transmitting data.

This controller is available on MPC8315, P1010, P1020, P1022 and P1024 Freescale SOCs.

The driver registers itself with the TDM Framework & provides TDM functionality to the client modules.

In its present form this driver supports only channelised mode.

Signed-off-by: Sandeep Singh <Sandeep@freescale.com>
Signed-off-by: Poonam Aggrwal <poonam.aggrwal@freescale.com>
---

Based on: git://git.am.freescale.net/gitolite/mirrors/galak-powerpc.git
Branch: master
Checkpatch: passed

First patch version was RFC

Changes from RFC:
	- Enabling Tx FIFO for TDM
	- Removed unused variables.
	- PMUXCR has been removed as it is taken care by u-boot

	Incorporated Timur's comments:
	- Improved Copyright statement.
	- Removed unused function.
	- Introduced read after each write to register
	- Used spin_event_timeout for polling
	- Removed unused spinlock
	- Moved all macros and structures from header file to tdm_fsl.c
	- Rectified cosmetic problems.

 drivers/tdm/Kconfig          |    3 -
 drivers/tdm/Makefile         |    2 +-
 drivers/tdm/device/Kconfig   |   15 +
 drivers/tdm/device/Makefile  |    9 +
 drivers/tdm/device/tdm_fsl.c | 1186 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 1211 insertions(+), 4 deletions(-)
 create mode 100644 drivers/tdm/device/Kconfig
 create mode 100644 drivers/tdm/device/Makefile
 create mode 100644 drivers/tdm/device/tdm_fsl.c

diff --git a/drivers/tdm/Kconfig b/drivers/tdm/Kconfig
index 0b0fda8..69b8987 100644
--- a/drivers/tdm/Kconfig
+++ b/drivers/tdm/Kconfig
@@ -13,6 +13,3 @@ menuconfig TDM
 	  This TDM support can also be built as a module.  If so, the module
 	  will be called tdm-core.
 
-if TDM
-
-endif # TDM
diff --git a/drivers/tdm/Makefile b/drivers/tdm/Makefile
index 84e2cb9..a605b3d 100644
--- a/drivers/tdm/Makefile
+++ b/drivers/tdm/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the TDM core.
 #
 
-obj-$(CONFIG_TDM)		+= tdm-core.o
+obj-$(CONFIG_TDM)		+= tdm-core.o device/
diff --git a/drivers/tdm/device/Kconfig b/drivers/tdm/device/Kconfig
new file mode 100644
index 0000000..9fd1b06
--- /dev/null
+++ b/drivers/tdm/device/Kconfig
@@ -0,0 +1,15 @@
+#
+# TDM device configuration
+#
+
+menu "TDM Device support"
+
+config TDM_FSL
+        tristate "Driver for Freescale TDM controller"
+        depends on FSL_SOC
+        ---help---
+          This is a driver for Freescale TDM controller. The controller
+          is found in various Freescale SOCs viz MPC8315, P1020. The TDM driver
+          basically multiplexes and demultiplexes data from different channels.
+          The TDM can interface SLIC kind of devices.
+endmenu
diff --git a/drivers/tdm/device/Makefile b/drivers/tdm/device/Makefile
new file mode 100644
index 0000000..4156d7f
--- /dev/null
+++ b/drivers/tdm/device/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the TDM device drivers.
+#
+
+obj-y	+= tdm_fsl.o
+
+#ifeq ($(CONFIG_TDM_DEBUG_BUS),y)
+#EXTRA_CFLAGS += -DDEBUG
+#endif
diff --git a/drivers/tdm/device/tdm_fsl.c b/drivers/tdm/device/tdm_fsl.c
new file mode 100644
index 0000000..732bcb8
--- /dev/null
+++ b/drivers/tdm/device/tdm_fsl.c
@@ -0,0 +1,1186 @@
+/*
+ * Copyright 2007-2012 Freescale Semiconductor, Inc, All rights reserved.
+ *
+ * TDM driver for Freescale TDM controller.
+ * This driver can interface with SLIC device to run VOIP kind of
+ * applications.
+ *
+ * Author: P. V. Suresh <pala@freescale.com>
+ *	Hemant Agrawal <hemant@freescale.com>
+ *	Rajesh Gumasta <rajesh.gumasta@freescale.com>
+ *
+ * Modifier: Sandeep Kr. Singh <sandeep@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * 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.
+ */
+
+/*
+ * Note that this is a complete rewrite of P.V. Suresh's driver code.
+ * But we have used so much of his original code and ideas that it seems
+ * only fair to recognize him as co-author -- Rajesh & Hemant
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/tdm.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+#include <sysdev/fsl_soc.h>
+
+#define DRV_DESC "Freescale TDM Driver Adapter"
+#define DRV_NAME "fsl_tdm"
+
+/* TDM data register offset */
+#define TDM_TDR_OFFSET 0x108
+#define TDM_RDR_OFFSET 0x100
+#define TDM_DATAREG_OFFSET 0x100
+#define TDM_CLKREG_OFFSET 0x180
+
+/* TCD params */
+#define SOFF_VAL	0x08
+#define DOFF_VAL	0x08
+#define NBYTES		0x08 /*Minor Bytes transfer count*/
+#define SLAST		0x00 /* last source addr adjustment*/
+#define SLAST_SGA	0x00
+#define DLAST_SGA	0x00
+
+/* RIR Params*/
+#define RIR_RFSD_VAL	0x01
+#define RIR_RFWM_VAL	0x00
+
+/* TIR Params*/
+#define TIR_RFSD_VAL	0x01
+#define TIR_RFWM_VAL	0x00
+
+/* TDMTCEN */
+#define NUM_TDMTCEN_REG		0x04
+#define TDMTCEN_REG_LEN		32
+
+
+#define DMAC_TX_INT 1
+#define DMAC_RX_INT 2
+
+/* DMA GPOR */
+#define DMAGPOR_SNOOP	0x00000040	/* Enable Snooping */
+
+/* DMA Control Register (DMACR) */
+#define DMACR_EMLM	0x00000080	/* Enable Minor loop Mapping */
+#define DMACR_CLM	0x00000040	/* Continuous link mode */
+#define DMACR_HALT	0x00000020	/* Halt DMA */
+#define DMACR_HOE	0x00000010	/* Halt on Error */
+#define DMACR_ERGA	0x00000008	/* Round robin among the groups */
+#define DMACR_ERCA	0x00000004	/* Round robin Port Arbitration */
+#define DMACR_EDBG	0x00000002	/* Debug */
+#define DMACR_EBW	0x00000001	/* Enable Buffer */
+
+/* DMA Error Status DMAES */
+#define DMAES_VLD	0x80000000	/* Logical OR of all DMA errors. */
+#define DMAES_ECX	0x00010000	/* Transfer cancelled */
+#define DMAES_GPE	0x00008000	/* Group priority error */
+#define DMAES_CPE	0x00004000	/* Channel priority error */
+/* errored/cancelled channel */
+#define DMAES_ERRCHN(errch)	(((errch) & 0x1F00) >> 8)
+#define DMAES_SAE	0x00000080	/* Source address error */
+#define DMAES_SOE	0x00000040	/* Source offset error */
+#define DMAES_DAE	0x00000020	/* Destination address error */
+#define DMAES_DOE	0x00000010	/* Destination offset error */
+#define DMAES_NCE	0x00000008	/* Nbytes citer error */
+#define DMAES_SGE	0x00000004	/* Scatter gather error */
+#define DMAES_SBE	0x00000002	/* Source bus error */
+#define DMAES_DBE	0x00000001	/* Destination bus error */
+
+/* DMA Enable Request (DMAERQH, DMAERQL) Enable/disable device
+	request for the channel */
+#define DMA_SET_ENABLE_REQUEST(regs, ch)	out_8(((regs)->dmasreq), ch)
+#define DMA_CLEAR_ENABLE_REQUEST(regs, ch)	out_8(((regs)->dmacerq), ch)
+
+/* DMA Enable Error Interrupt (DMAEEIH, DMAEEIL) Enable/disable
+	error interrupt for the channel */
+#define DMA_SET_ENABLE_ERROR_INT(regs, ch)	out_8(((regs)->dmaseei), ch)
+#define DMA_CLEAR_ENABLE_ERROR_INT(regs, ch)	out_8(((regs)->dmaceei), ch)
+
+/*   Clear interrupt/error for the channel */
+#define DMA_CLEAR_INTT_REQUEST(regs, ch)	out_8(((regs)->dmacint), ch)
+#define DMA_CLEAR_ERROR(regs, ch)	out_8(((regs)->dmacerr), ch)
+
+/* Clear done bit for the channel */
+#define DMA_CLEAR_DONE_BIT(regs, ch)	out_8(((regs)->dmacdne), ch)
+/* Set start bit for the channel */
+#define DMA_SET_START_BIT(regs, ch)	out_8(((regs)->dmassrt), ch)
+
+#define TDMTX_DMA_CH	0	/* TDM Tx uses DMA channel 0 HardWired */
+#define TDMRX_DMA_CH	1	/* TDM Rx uses DMA channel 1 Hardwired */
+#define TCD_SIZE 64	/* 64 byte buffer for TCD */
+
+/* Source address modulo */
+#define DMA_TCD1_SMOD(smod)   (((smod) & 0x1F) << 27)
+/* Source data transfer size */
+#define DMA_TCD1_SSIZE(ssize) (((ssize) & 0x7) << 24)
+
+/* Destination address modulo */
+#define DMA_TCD1_DMOD(dmod)   (((dmod) & 0x1F) << 19)
+/* data transfer size  */
+#define DMA_TCD1_DSIZE(dsize) (((dsize) & 0x7) << 16)
+
+/* Source address signed offset */
+#define DMA_TCD1_SOFF(soff)   ((soff) & 0xFFFF)
+
+/* Enable link to another channel on minor iteration completion. */
+#define DMA_TCD5_E_MINOR_LINK 0x80000000
+/* Link to this channel. */
+#define DMA_TCD5_LINK_CH(ch) (((ch) & 0x3F) << 25)
+/* Current iteration count when linking disnabled */
+#define DMA_TCD5_CITER_DISABLE_LINK(citer) (((citer) & 0x7FFF) << 16)
+/* Current iteration count when linking enabled */
+#define DMA_TCD5_CITER_ENABLE_LINK(citer) (((citer) & 0x00FF) << 16)
+/*  Destination address signed offset */
+#define DMA_TCD5_DOFF(doff) ((doff) & 0xFFFF)
+
+/* Beginning iteration count when linking disabled */
+#define DMA_TCD7_BITER_DISABLE_LINK(citer) (((citer) & 0x7FFF) << 16)
+/* Beginning iteration count when linking enabled */
+#define DMA_TCD7_BITER_ENABLE_LINK(citer) (((citer) & 0x00FF) << 16)
+#define DMA_TCD7_BWC(bw) (((bw)&0x3)<<14)	/* BandWidth Control. */
+/* Link channel number */
+#define DMA_TCD7_LINKCH(ch)   (((ch) & 0x1F) << 8)
+#define DMA_TCD7_DONE		0x00000080	/* Channel done  */
+#define DMA_TCD7_ACTIVE		0x00000040	/* Channel active */
+#define DMA_TCD7_E_MAJOR_LINK	0x00000020	/* channel to channel linking */
+#define DMA_TCD7_E_SG		0x00000010	/* Enable scatter gather */
+#define DMA_TCD7_D_REQ		0x00000008	/* Disable request */
+/* interrupt on half major counter */
+#define DMA_TCD7_INT_HALF	0x00000004
+#define DMA_TCD7_INT_MAJ	0x00000002	/* interrupt on major counter */
+#define DMA_TCD7_START		0x00000001	/* Channel start */
+
+/* Source data transfer size */
+#define SSIZE_08BITS		0x00
+#define SSIZE_16BITS		0x01
+#define SSIZE_32BITS		0x02
+#define SSIZE_64BITS		0x03
+
+/* max number of TDM-DMA channels */
+#define DMA_MAX_CHANNELS 4
+
+/* each DMA-ch contains 8 Transfer Control Discriptors  */
+#define MAX_TCD_WORD 8
+
+/* TDMGIR  General Interface Register */
+#define GIR_LPBK	0x00000004	/* loopback mode */
+#define GIR_CTS		0x00000002	/* Common TDM signals */
+#define GIR_RTS		0x00000001	/* Rx & Tx sharing */
+
+/* TDMRIR Recieve Interface Rgister */
+#define RIR_RFWM_MASK	0x00000003	/* Recieve FIFO Watermark */
+#define RIR_RFWM_SHIFT	16
+#define RIR_RFWM(x)     ((x & RIR_RFWM_MASK) << RIR_RFWM_SHIFT)
+#define RIR_RFEN	0x00008000	/* Recieve FIFO Enable */
+#define RIR_RWEN	0x00004000	/* Recieve Wide FIFO Enable */
+#define RIR_RDMA	0x00000040	/* Recieve DMA Enable */
+#define RIR_RFSD_SHIFT	0x00000004	/* Recieve Frame Sync Delay */
+#define RIR_RFSD_MASK	0x00000003
+#define RIR_RFSD(x)	((x & RIR_RFSD_MASK) << RIR_RFSD_SHIFT)
+#define RIR_RSO		0x00002000	/* Recieve sync Out */
+#define RIR_RSL		0x00000800	/* Recieve sync Out Length */
+#define RIR_RSOE	0x00000400	/* Recieve sync Out Edge */
+#define RIR_RCOE	0x00000200	/* Recieve Clock Output Enable */
+#define RIR_RSA		0x00000008	/* Recieve Sync Active */
+#define RIR_RDE		0x00000004	/* Recieve Data Edge */
+#define RIR_RFSE	0x00000002	/* Recieve Frame Sync Edge */
+#define RIR_RRDO	0x00000001	/* Revieve Reversed Data Order */
+
+/* TDMTIR  Transmit Interface Rgister */
+#define TIR_TFWM_MASK	0x00000003	/* Transmit FIFO Watermark */
+#define TIR_TFWM_SHIFT	16
+#define TIR_TFWM(x)	((x & TIR_TFWM_MASK) << TIR_TFWM_SHIFT)
+#define TIR_TFEN	0x00008000	/* Transmit FIFO Enable */
+#define TIR_TWEN	0x00004000	/* Transmit Wide FIFO Enable */
+#define TIR_TDMA	0x00000040	/* Transmit DMA Enable */
+#define TIR_TFSD_SHIFT	0x00000004	/* Transmit Frame Sync Delay */
+#define TIR_TFSD_MASK	0x00000003
+#define TIR_TFSD(x)	((x & TIR_TFSD_MASK) << TIR_TFSD_SHIFT)
+#define TIR_TSO		0x00002000	/* Transmit Sync Output */
+#define TIR_TSL		0x00000800	/* Transmit sync Out Length */
+#define TIR_TSOE	0x00000400	/* Transmit sync Out Edge */
+#define TIR_TCOE	0x00000200	/* Transmit Clock Output Enable */
+#define TIR_TSA		0x00000008	/* Transmit Sync Active */
+#define TIR_TDE		0x00000004	/* Transmit Data Edge */
+#define TIR_TFSE	0x00000002	/* Transmit Frame Sync Edge */
+#define TIR_TRDO	0x00000001	/* Transmit Reversed Data Order */
+
+/*TDMRFP  Revieve Frame Parameters */
+#define RFP_RNCF_SHIFT	0x00000010	/* Number of Channels in TDM Frame */
+#define RFP_RNCF_MASK	0x000000FF
+#define RFP_RNCF(x)	(((x - 1) & RFP_RNCF_MASK) << RFP_RNCF_SHIFT)
+#define RFP_RCS_SHIFT	0x00000004	/* Recieve Channel Size */
+#define RFP_RCS_MASK	0x00000003
+#define RFP_RCS(x)	((x & RFP_RCS_MASK) << RFP_RCS_SHIFT)
+#define RFP_RT1		0x00000002	/* Recieve T1 Frame */
+
+/*TDMTFP Transmit Frame Parameters */
+#define TFP_TNCF_SHIFT	0x00000010	/* Number of Channels in TDM Frame */
+#define TFP_TNCF_MASK	0x000000FF
+#define TFP_TNCF(x)	(((x - 1) & TFP_TNCF_MASK) << TFP_TNCF_SHIFT)
+#define TFP_TCS_SHIFT	0x00000004	/* Transmit Channel Size */
+#define TFP_TCS_MASK	0x00000003
+#define TFP_TCS(x)	((x & RFP_RCS_MASK) << RFP_RCS_SHIFT)
+#define TFP_TT1		0x00000002	/* Transmit T1 Frame */
+
+
+/* TDMRCR  Recieve Control Register */
+#define RCR_REN		0x00000001	/* Recieve Enable */
+/* TDMTCR  Transmit Control Register */
+#define TCR_TEN		0x00000001	/* Transmit Enable */
+
+/* TDMRIER receive interrupt enable register */
+#define RIER_RCEUE	0x00000100	/* Channel Enable Update Enable */
+#define RIER_RLCEE	0x00000080	/* Recieve Last Channel Event Enable */
+#define RIER_RFSEE	0x00000040	/* Recieve Frame Sync Event Enable */
+#define RIER_RFFEE	0x00000020	/* Recieve FIFO Full Event Enable */
+#define RIER_RDREE	0x00000010	/* Recieve Data Ready Event Enable */
+#define RIER_RSEEE	0x00000008	/* Recieve Sync Error Event Enable */
+#define RIER_ROEE	0x00000004	/* Recieve Overrun Event Enable */
+
+/* TDMTIER  transmit interrupt enable register */
+#define TIER_TCEUE	0x00000100	/* Channel Enable Update Enable */
+#define TIER_TLCEE	0x00000080	/* Transmit Last Channel Event */
+#define TIER_TFSEE	0x00000040	/* Transmit Frame Sync Event Enable */
+#define TIER_TFFEE	0x00000020	/* Transmit FIFO Full Event Enable */
+#define TIER_TDREE	0x00000010	/* Transmit Data Ready Event Enable */
+#define TIER_TSEEE	0x00000008	/* Transmit Sync Error Event Enable */
+#define TIER_TUEE	0x00000004	/* Transmit Overrun Event Enable */
+
+/* TDMRER  Recieve Event Register */
+#define RER_RCEU	0x00000100	/* Recieve Channel Enable Update */
+#define RER_RLCE	0x00000080	/* Recieve Last Channel Event */
+#define RER_RFSE	0x00000040	/* Recieve Frame Sync Event */
+#define RER_RFFE	0x00000020	/* Recieve FIFO Full Event */
+#define RER_RDRE	0x00000010	/* Recieve Data Ready Event */
+#define RER_RSEE	0x00000008	/* Recieve Sync Error Event */
+#define RER_ROE		0x00000004	/* Recieve Overrun Event */
+
+/* TDMTER  Transmit Event Register */
+#define TER_TCEU	0x00000100	/* Transmit Channel Enable Update */
+#define TER_TLCE	0x00000080	/* Transmit Last Channel Event */
+#define TER_TFSE	0x00000040	/* Transmit Frame Sync Event */
+#define TER_TFEE	0x00000020	/* Transmit FIFO Full Event */
+#define TER_TDRE	0x00000010	/* Transmit Data Ready Event */
+#define TER_TSEE	0x00000008	/* Transmit Sync Error Event */
+#define TER_TUE		0x00000004	/* Transmit Overrun Event */
+
+/* TDMRSR  Recieve Status Register */
+#define RSR_RFCNT	0x00000038	/* Recieve FIFO counter */
+#define RSSS_MASK	0x00000003	/* Recieve SYNC Status */
+#define RSR_RSSS_SHIFT  1
+#define RSR_RSSS(sss)	(((sss) >> (RSR_RSSS_SHIFT)) & (RSR_RSSS_MASK))
+#define RSR_RENS	0x00000001	/* Recieve Enable Status */
+
+/* TDMTSR  Transmit Status Register */
+#define TSR_TFCNT	0x00000038	/* Transmit FIFO counter */
+#define TSR_TSSS_MASK	0x00000003	/* Transmit SYNC Status */
+#define TSR_TSSS_SHIFT	1
+#define TSR_TSSS(sss)	(((sss) >> (TSR_TSSS_SHIFT)) & TSR_TSSS_MASK)
+#define TSR_TENS	0x00000001	/* Transmit Enable Status */
+
+
+/* channel parameters   */
+#define TDM_ENABLE_TIMEOUT	1000	/* time out for TDM rx, tx enable */
+#define NUM_OF_TDM_BUF		3	/* Number of tdm buffers for startlite
+					   DMA */
+#define ALIGNED_2_BYTES		0x02	/* 2-bytes alignment */
+#define ALIGNED_4_BYTES		0x04	/* 4-bytes alignment */
+#define ALIGNED_8_BYTES		0x08	/* 8-bytes alignment */
+#define ALIGNED_16_BYTES	0x10	/* 16-bytes alignment */
+#define ALIGNED_32_BYTES	0x20	/* 32-bytes alignment */
+#define ALIGNED_64_BYTES	0x40	/* 64-bytes alignment */
+
+static int tdmen = 1;
+
+module_param(tdmen, int, S_IRUSR);
+MODULE_PARM_DESC(tdmen, "Enable TDM: Enable=1, Disable=0(default)");
+
+/* DMAC TCD structure */
+struct tcd {
+	u32 tcd[MAX_TCD_WORD];
+};
+
+/* DMA Controllor */
+struct dmac_regs {
+	u32 dmacr;		/* DMA Control Register			*/
+	u32 dmaes;		/* DMA Error Status Register		*/
+	u32 dmaerqh;		/* DMA Enable Request			*/
+	u32 dmaerql;		/* DMA Enable Request			*/
+	u32 dmaeeih;		/* DMA Enable Error Interrupt		*/
+	u32 dmaeeil;		/* DMA Enable Error Interrupt		*/
+
+	u8 dmaserq;		/* DMA Set Enable Request		*/
+	u8 dmacerq;		/* DMA Clear Enable Request		*/
+	u8 dmaseei;		/* DMA Set Enable Error Interrupt	*/
+	u8 dmaceei;		/* DMA Clear Enable Error Interrupt	*/
+
+	u8 dmacint;		/* DMA Clear Interrupt Request		*/
+	u8 dmacerr;		/* DMA Clear Error			*/
+	u8 dmassrt;		/* DMA Set Start Bit			*/
+	u8 dmacdne;		/* DMA Clear Done Bit			*/
+
+	u32 dmainth;		/* DMA Interrupt Request High		*/
+	u32 dmaintl;		/* DMA Interrupt Request		*/
+	u32 dmaerrh;		/* DMA Error				*/
+	u32 dmaerrl;		/* DMA Error				*/
+	u32 dmahrsh;		/* DMA Hardware Request status		*/
+	u32 dmahrsl;		/* DMA HardWired Request status		*/
+	u32 dmagpor;		/* DMA General Purpose Register		*/
+	u8 reserved0[0xC4];
+	u8 dchpri[DMA_MAX_CHANNELS];	/* DMA Port Priority		*/
+	u8 reserved1[0xEFC];
+	struct tcd tcd[DMA_MAX_CHANNELS];	/*Transfer Control Descriptor */
+};
+
+/* TDM  Control Registers. */
+struct tdm_regs {
+	u32 gir;		/*  General Interface Register  */
+	u32 rir;		/*  Receive Interface Register  */
+	u32 tir;		/*  Transmit Interface Register */
+	u32 rfp;		/*  Receive Frame Parameters    */
+	u32 tfp;		/*  Transmit Frame Parameters   */
+	u8 reserved0[0xC];
+	u32 rcen[4];		/*  Recieve Channel Enabled     */
+	u8 reserved1[0x10];
+	u32 tcen[4];		/*  Transmit Channel Enabled    */
+	u8 reservedd2[0x10];
+	u32 tcma[4];		/*  Transmit Channel Mask       */
+	u8 reservederved3[0x10];
+	u32 rcr;		/*  Receiver Control Register           */
+	u32 tcr;		/*  Transmitter Control Register        */
+	u32 rier;		/*  Receive Interrupt Enable Register   */
+	u32 tier;		/*  Transmit Interrupt Enable Register  */
+	u8 reserved4[0x10];
+	u32 rer;		/*  Receive Event Register              */
+	u32 ter;		/*  Transmit Event Register             */
+	u32 rsr;		/*  Receive Status Register             */
+	u32 tsr;		/*  Transmit Status Register            */
+};
+
+struct tdm_data {
+	u64 rdr;		/* Receive Data Register */
+	u64 tdr;		/* Transmit Dataa Register */
+};
+
+struct tdm_clock {
+	u32 rx;			/* Transmit Dataa Register */
+	u32 tx;			/* Receive Data Register */
+};
+
+
+struct tdm_priv {
+	struct tdm_regs __iomem *tdm_regs;
+	struct tdm_data __iomem *data_regs;
+	struct dmac_regs __iomem *dmac_regs;
+	struct tdm_clock __iomem *clk_regs;
+	u32 ptdm_base;
+	u8 *tdm_input_data;
+	u8 *tdm_output_data;
+	dma_addr_t dma_input_paddr;	/* dma mapped buffer for TDM Rx */
+	dma_addr_t dma_output_paddr;	/* dma mapped buffer for TDM Tx */
+	void *dma_input_vaddr;
+	void *dma_output_vaddr;
+	u32 phase_rx;
+	u32 phase_tx;
+	struct tcd *dma_rx_tcd[NUM_OF_TDM_BUF];
+	struct tcd *dma_tx_tcd[NUM_OF_TDM_BUF];
+	dma_addr_t dma_rx_tcd_paddr;
+	dma_addr_t dma_tx_tcd_paddr;
+	void *dma_rx_tcd_vaddr;
+	void *dma_tx_tcd_vaddr;
+	u32 tdm_buffer_size;
+	u32 tdm_err_intr;
+	u32 dmac_err_intr;
+	u32 dmac_done_intr;
+	int tdm_active;
+	struct device *device;
+	spinlock_t tdmlock;
+	struct tdm_adapter *adap;
+};
+
+/* Extend a given size to make it alignable */
+static inline int ALIGNABLE_SIZE(u32 size, u32 alignment)
+{
+	return size + alignment - 1;
+}
+
+/* Align a given address */
+static inline void *ALIGN_ADDRESS(void *address, u32 alignment)
+{
+	return (void *)(((unsigned long) address + alignment - 1) &
+			(~(alignment - 1)));
+}
+
+/* Size of the buffer */
+static inline int TDM_1BUF_SIZE(u32 num_ch, u32 channel_size, u32 frame_size)
+{
+	return frame_size *
+		ALIGN(channel_size * num_ch, ALIGNED_8_BYTES);
+}
+
+/* Alignable size of the 3 buffers */
+static inline int TDM_3BUF_SIZE(u32 num_ch, u32 channel_size, u32 frame_size)
+{
+	return
+	    ALIGNABLE_SIZE((TDM_1BUF_SIZE(num_ch, channel_size, frame_size) *
+			    NUM_OF_TDM_BUF), ALIGNED_8_BYTES);
+}
+
+
+
+/* Initialize the Tx Transmit Control Descriptor parameters*/
+static void tx_tcd_init(struct tdm_priv *priv)
+{
+	int i;
+	u32 iter;
+	u32 offset;
+	dma_addr_t physaddr;
+	struct tdm_adapter *adap;
+	int bytes_in_fifo_per_frame;
+	adap = priv->adap;
+
+	if (!adap) {
+		dev_err(priv->device, "%s:Invalid handle\n", __func__);
+		return;
+	}
+	bytes_in_fifo_per_frame =
+		ALIGN(adap->adapt_cfg.num_ch * adap->adapt_cfg.slot_width, 8);
+
+	iter = (bytes_in_fifo_per_frame / NBYTES) * adap->adapt_cfg.num_frames;
+
+	for (i = 0; i < NUM_OF_TDM_BUF; i++) {
+		offset = i * adap->adapt_cfg.num_frames *
+			bytes_in_fifo_per_frame;
+		/* TCD word 0: source addr */
+		priv->dma_tx_tcd[i]->tcd[0] = (u32)priv->dma_output_paddr
+			+ offset;
+
+		/* TCD word 1: ssize=dsize=64bit, soff=8, smod=dmod=0 */
+		priv->dma_tx_tcd[i]->tcd[1] =
+			DMA_TCD1_SOFF(SOFF_VAL) | DMA_TCD1_SSIZE(SSIZE_64BITS) |
+			DMA_TCD1_DSIZE(SSIZE_64BITS);
+
+		/*
+		 * TCD word 2: number of bytes for minor loop, wide fifo
+		 *  8 bytes for dma
+		 */
+		priv->dma_tx_tcd[i]->tcd[2] = NBYTES;
+
+		/* TCD word 3: last source addr adjustment = 0 */
+		priv->dma_tx_tcd[i]->tcd[3] = SLAST;
+
+		/* TCD word 4: destination addr */
+		priv->dma_tx_tcd[i]->tcd[4] = TDM_TDR_OFFSET + priv->ptdm_base;
+
+		/*
+		 * channel to channel linking is disabled ,
+		 * destination offset is inc destination adr by 8,
+		 * current iteration(citer) = number of transfers for frame
+		 */
+		/* TCD word 5: citer count, dest addr offset */
+		priv->dma_tx_tcd[i]->tcd[5] = DMA_TCD5_CITER_DISABLE_LINK(iter);
+
+		/* TCD word 6: enable scater gather, interrupt on 1 Frame, */
+		priv->dma_tx_tcd[i]->tcd[6] = SLAST_SGA;
+
+		/*
+		 * TCD word 7: begining major iteration count(biter),
+		 * channel control/status
+		 */
+		priv->dma_tx_tcd[i]->tcd[7] =
+			DMA_TCD7_BITER_DISABLE_LINK(iter) | DMA_TCD7_E_SG;
+	}
+
+	/* Linking the TCDs togather for SG operation */
+	physaddr = priv->dma_tx_tcd_paddr;
+	priv->dma_tx_tcd[2]->tcd[6] = ALIGN(physaddr, ALIGNED_32_BYTES);
+	physaddr += TCD_SIZE;
+	priv->dma_tx_tcd[0]->tcd[6] = ALIGN(physaddr, ALIGNED_32_BYTES);
+	physaddr += TCD_SIZE;
+	priv->dma_tx_tcd[1]->tcd[6] = ALIGN(physaddr, ALIGNED_32_BYTES);
+}
+
+/* Initialize the Rx Transmit Control Discriptor parameters */
+static void rx_tcd_init(struct tdm_priv *priv)
+{
+	int i;
+	u32 iter;
+	u32 offset;
+	dma_addr_t physaddr;
+	struct tdm_adapter *adap;
+	int bytes_in_fifo_per_frame;
+	adap = priv->adap;
+	bytes_in_fifo_per_frame =
+		ALIGN(adap->adapt_cfg.num_ch * adap->adapt_cfg.slot_width, 8);
+
+	iter = (bytes_in_fifo_per_frame / NBYTES) * adap->adapt_cfg.num_frames;
+
+	for (i = 0; i < NUM_OF_TDM_BUF; i++) {
+		/* TCD word 0: source addr */
+		priv->dma_rx_tcd[i]->tcd[0] = TDM_RDR_OFFSET + priv->ptdm_base;
+
+		/* TCD word 1: ssize=dsize=64bit, soff=smod=dmod=0 */
+		priv->dma_rx_tcd[i]->tcd[1] =
+			DMA_TCD1_SSIZE(SSIZE_64BITS) |
+			DMA_TCD1_DSIZE(SSIZE_64BITS);
+
+		/*
+		 * TCD word 2: number of bytes for minor loop,
+		 * wide fifo 8 bytes for dma
+		 */
+		priv->dma_rx_tcd[i]->tcd[2] = NBYTES;
+
+		/* TCD word 3: last source addr adjustment = 0 */
+		priv->dma_rx_tcd[i]->tcd[3] = SLAST;
+
+		offset = i * adap->adapt_cfg.num_frames *
+			bytes_in_fifo_per_frame;
+
+		/* TCD word 4: destination addr */
+		priv->dma_rx_tcd[i]->tcd[4] = (u32)priv->dma_input_paddr
+			+ offset;
+
+		/*
+		 * channel to channel linking is disabled ,
+		 * destination offset is inc destination adr by 8,
+		 * current iteration(citer) = number of transfers for frame
+		 */
+		/* TCD word 5: citer count, dest addr offset */
+		priv->dma_rx_tcd[i]->tcd[5] =
+			DMA_TCD5_DOFF(DOFF_VAL) |
+			DMA_TCD5_CITER_DISABLE_LINK(iter);
+
+		/* TCD word 6: enable scater gather, interrupt on 1 Frame, */
+		priv->dma_rx_tcd[i]->tcd[6] = DLAST_SGA;
+
+		/*
+		 * TCD word 7: begining major iteration count(biter),
+		 * channel control/status
+		 */
+		priv->dma_rx_tcd[i]->tcd[7] =
+			DMA_TCD7_BITER_DISABLE_LINK(iter) | DMA_TCD7_E_SG |
+			DMA_TCD7_INT_MAJ;
+	}
+
+	/* Next TCD for SG operation */
+	physaddr = priv->dma_rx_tcd_paddr;
+	priv->dma_rx_tcd[2]->tcd[6] = ALIGN(physaddr, ALIGNED_32_BYTES);
+	physaddr += TCD_SIZE;
+	priv->dma_rx_tcd[0]->tcd[6] = ALIGN(physaddr, ALIGNED_32_BYTES);
+	physaddr += TCD_SIZE;
+	priv->dma_rx_tcd[1]->tcd[6] = ALIGN(physaddr, ALIGNED_32_BYTES);
+}
+
+static irqreturn_t dmac_done_isr(int irq, void *p)
+{
+	u32 ch;
+	int ret = IRQ_NONE;
+	struct tdm_priv *priv;
+
+	priv = p;
+
+	ch = in_be32(&priv->dmac_regs->dmaintl);
+
+	/* clear interrupt */
+	if (ch & DMAC_RX_INT) {
+		out_8(&priv->dmac_regs->dmacint, TDMRX_DMA_CH);
+		ret = IRQ_HANDLED;
+		/* track phases for Rx/Tx */
+		priv->phase_rx += 1;
+		if (priv->phase_rx == NUM_OF_TDM_BUF)
+			priv->phase_rx = 0;
+	}
+	if (ch & DMAC_TX_INT) {
+		out_8(&priv->dmac_regs->dmacint, TDMTX_DMA_CH);
+		ret = IRQ_HANDLED;
+	}
+
+	if (ret == IRQ_HANDLED) {
+		/* set the flag and wake up the thread */
+		priv->adap->tdm_rx_flag = 1;
+
+		/* schedule the tasklet */
+		if (priv->adap->tasklet_conf)
+			tasklet_schedule(&priv->adap->tdm_data_tasklet);
+	}
+	return ret;
+}
+
+static int init_tdm(struct tdm_priv *priv)
+{
+	u8 *buf;
+	int i;
+	int buf_size;
+	dma_addr_t physaddr = 0;
+	int ret = 0;
+	struct tdm_adapter *adap;
+
+
+	adap = priv->adap;
+
+	/*
+	 * Allocate memory for Rx/Tx buffer according to active time slots
+	 * BufferSize = NUM_OF_TDM_BUF * NUM_SAMPLES_PER_FRAME * slot_width *
+	 * num_ch
+	 */
+	/*Allocating Rx Buffer*/
+	buf_size = TDM_3BUF_SIZE(adap->adapt_cfg.num_ch,
+			adap->adapt_cfg.slot_width,
+			adap->adapt_cfg.num_frames);
+	buf = dma_alloc_coherent(priv->device, buf_size, &physaddr, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_alloc_ip;
+	}
+	priv->dma_input_paddr = physaddr;
+	priv->dma_input_vaddr = buf;
+	priv->tdm_input_data = ALIGN_ADDRESS(buf, ALIGNED_8_BYTES);
+
+	buf = dma_alloc_coherent(priv->device, buf_size, &physaddr, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_alloc_op;
+	}
+	priv->dma_output_paddr = physaddr;
+	priv->dma_output_vaddr = buf;
+	priv->tdm_output_data = ALIGN_ADDRESS(buf, ALIGNED_8_BYTES);
+
+	/* allocate memory for TCD buffer descriptors */
+	buf = dma_alloc_coherent(priv->device, NUM_OF_TDM_BUF * TCD_SIZE,
+			&physaddr, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_alloc_rx;
+	}
+
+	memset(buf, 0, NUM_OF_TDM_BUF * TCD_SIZE);
+	priv->dma_rx_tcd_paddr = physaddr;
+	priv->dma_rx_tcd_vaddr = buf;
+	for (i = 0; i < NUM_OF_TDM_BUF; i++) {
+		priv->dma_rx_tcd[i] = ALIGN_ADDRESS(buf, ALIGNED_32_BYTES);
+		buf += TCD_SIZE;
+	}
+
+	buf = dma_alloc_coherent(priv->device, 3 * TCD_SIZE, &physaddr,
+			GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_alloc_tx;
+	}
+	memset(buf, 0, NUM_OF_TDM_BUF * TCD_SIZE);
+	priv->dma_tx_tcd_paddr = physaddr;
+	priv->dma_tx_tcd_vaddr = buf;
+	for (i = 0; i < NUM_OF_TDM_BUF; i++) {
+		priv->dma_tx_tcd[i] = ALIGN_ADDRESS(buf, ALIGNED_32_BYTES);
+		buf += TCD_SIZE;
+	}
+
+	priv->phase_rx = 0;
+	priv->phase_tx = 0;
+	return 0;
+
+err_alloc_tx:
+	dma_free_coherent(priv->device, NUM_OF_TDM_BUF * TCD_SIZE,
+			priv->dma_rx_tcd_vaddr, priv->dma_rx_tcd_paddr);
+err_alloc_rx:
+	dma_free_coherent(priv->device, buf_size, priv->dma_output_vaddr,
+			priv->dma_output_paddr);
+err_alloc_op:
+	dma_free_coherent(priv->device, buf_size, priv->dma_input_vaddr,
+			priv->dma_input_paddr);
+err_alloc_ip:
+	return ret;
+}
+
+/* TDM register programming */
+static int tdm_fsl_reg_init(struct tdm_priv *priv)
+{
+	int i;
+	int ch_size_type;
+	struct tdm_adapter *adap;
+
+	if (!priv) {
+		pr_err("%s: Invalid handle\n", __func__);
+		return -EINVAL;
+	}
+	adap = priv->adap;
+
+	/* channel/group round robin */
+	out_be32(&priv->dmac_regs->dmacr, DMACR_ERGA | DMACR_ERCA);
+	/* Enable error Interrupts for TDM Rx &Tx */
+	out_8(&priv->dmac_regs->dmaseei, TDMTX_DMA_CH);
+	in_8(&priv->dmac_regs->dmaseei);
+	out_8(&priv->dmac_regs->dmaseei, TDMRX_DMA_CH);
+	in_8(&priv->dmac_regs->dmaseei);
+	out_be32(&priv->dmac_regs->dmagpor, DMAGPOR_SNOOP);
+
+	tx_tcd_init(priv);
+	rx_tcd_init(priv);
+
+	/* TDM RD->TD loopback, Share T/R Fsync,Clock */
+	if (adap->adapt_cfg.loopback)
+		out_be32(&priv->tdm_regs->gir, GIR_LPBK | GIR_RTS);
+	else
+		out_be32(&priv->tdm_regs->gir, GIR_RTS);
+
+	/*
+	 *  Rx Water mark 0,  FIFO enable,  Wide fifo, DMA enable for RX,
+	 *  Receive Sync out, syncwidth = ch width, Rx clk out,zero sync,
+	 *  falling edge , data order
+	 */
+
+	out_be32(&priv->tdm_regs->rir,
+			RIR_RFWM(RIR_RFWM_VAL) | RIR_RFEN | RIR_RWEN |
+			RIR_RDMA | RIR_RSL | RIR_RSO | RIR_RCOE | RIR_RRDO |
+			RIR_RFSD(RIR_RFSD_VAL));
+	out_be32(&priv->tdm_regs->tir,
+			TIR_TFWM(TIR_RFWM_VAL) | TIR_TFEN | TIR_TWEN |
+			TIR_TDMA | TIR_TSL | TIR_TSO | TIR_TRDO |
+			TIR_TFSD(TIR_RFSD_VAL));
+
+	/* no of channels ,Channel size-coading */
+	switch (adap->adapt_cfg.ch_size_type) {
+	case CHANNEL_8BIT_LIN:
+		ch_size_type = CHANNEL_8BIT_LIN;
+		break;
+	case CHANNEL_8BIT_ULAW:
+		ch_size_type = CHANNEL_8BIT_ULAW;
+		break;
+	case CHANNEL_8BIT_ALAW:
+		ch_size_type = CHANNEL_8BIT_ALAW;
+		break;
+	case CHANNEL_16BIT_LIN:
+		ch_size_type = CHANNEL_16BIT_LIN;
+		break;
+	default:
+		dev_err(priv->device, "%s:Invalid channel size_type\n"
+				"Setting channel to default size: 16 bits",
+				__func__);
+		ch_size_type = CHANNEL_16BIT_LIN;
+	}
+	out_be32(&priv->tdm_regs->rfp,
+			RFP_RNCF(adap->adapt_cfg.num_ch) |
+			RFP_RCS(ch_size_type));
+	out_be32(&priv->tdm_regs->tfp,
+			TFP_TNCF(adap->adapt_cfg.num_ch) |
+			TFP_TCS(ch_size_type));
+
+	out_be32(&priv->tdm_regs->rier, 0);
+	out_be32(&priv->tdm_regs->tier, 0);
+
+	/* clear all receive and transmit chs */
+	for (i = 0; i < 4; i++) {
+		out_be32(&priv->tdm_regs->tcma[i], 0);
+		out_be32(&priv->tdm_regs->tcen[i], 0);
+		out_be32(&priv->tdm_regs->rcen[i], 0);
+	}
+
+	return 0;
+
+}
+
+static void tdm_fsl_stop(struct tdm_priv *priv)
+{
+	/* stop the Tx & Rx */
+	out_be32(&priv->tdm_regs->tcr, 0);
+	out_be32(&priv->tdm_regs->rcr, 0);
+
+	/* Clear DMA error Enable Request DMAEEIH/L */
+	out_8(&priv->dmac_regs->dmaceei, TDMTX_DMA_CH);
+	in_8(&priv->dmac_regs->dmaceei);
+	out_8(&priv->dmac_regs->dmaceei, TDMRX_DMA_CH);
+	in_8(&priv->dmac_regs->dmaceei);
+	out_8(&priv->dmac_regs->dmacint, TDMRX_DMA_CH);
+	in_8(&priv->dmac_regs->dmacint);
+	out_8(&priv->dmac_regs->dmacint, TDMTX_DMA_CH);
+	in_8(&priv->dmac_regs->dmacint);
+
+	/* disable the dma request */
+	out_8(&priv->dmac_regs->dmacerq, TDMRX_DMA_CH);
+	in_8(&priv->dmac_regs->dmacerq);
+	out_8(&priv->dmac_regs->dmacerq, TDMTX_DMA_CH);
+}
+
+static int tdm_fsl_disable(struct tdm_adapter *adap)
+{
+	struct tdm_priv *priv;
+
+	priv = adap->data;
+	if (priv->tdm_active == 0) {
+		dev_warn(priv->device, "already Disabled");
+		return 0;
+	}
+
+	spin_lock(&priv->tdmlock);
+	priv->tdm_active = 0;
+	spin_unlock(&priv->tdmlock);
+
+	return 0;
+}
+
+static int tdm_fsl_enable(struct tdm_adapter *adap)
+{
+	int i;
+	u32 ch_enab[NUM_TDMTCEN_REG] = {0};
+	unsigned long timeout;
+	struct tdm_priv *priv;
+	u32 ph;
+
+	priv = adap->data;
+	ph = priv->phase_tx;
+
+	if (priv->tdm_active == 1) {
+		dev_warn(priv->device, "already Enabled");
+		return 0;
+	}
+
+	/* enable the Channels required 0 to number of ch -1 */
+	for (i = 0; i < adap->adapt_cfg.num_ch; i++)
+		ch_enab[i / TDMTCEN_REG_LEN] |= (1 << (i & 0x1F));
+
+	for (i = 0; i < NUM_TDMTCEN_REG; i++) {
+		out_be32(&priv->tdm_regs->rcen[i], ch_enab[i]);
+		out_be32(&priv->tdm_regs->tcen[i], ch_enab[i]);
+	}
+
+	/* Clear the DONE bit */
+	out_8(&priv->dmac_regs->dmacdne, TDMRX_DMA_CH);
+	in_8(&priv->dmac_regs->dmacdne);
+	out_8(&priv->dmac_regs->dmacdne, TDMTX_DMA_CH);
+
+	/* Load the Tx  transfer control descriptors */
+	for (i = 0; i < MAX_TCD_WORD; i++)
+		out_be32(&priv->dmac_regs->tcd[TDMTX_DMA_CH].tcd[i],
+				priv->dma_tx_tcd[ph]->tcd[i]);
+
+	/* Load the Rx  transfer control descriptors */
+	for (i = 0; i < MAX_TCD_WORD; i++)
+		out_be32(&priv->dmac_regs->tcd[TDMRX_DMA_CH].tcd[i],
+				priv->dma_rx_tcd[ph]->tcd[i]);
+
+	/* enable the dma request */
+	out_8(&priv->dmac_regs->dmaserq, TDMRX_DMA_CH);
+	in_8(&priv->dmac_regs->dmaserq);
+	out_8(&priv->dmac_regs->dmaserq, TDMTX_DMA_CH);
+
+	/* Enable Receiver, transmitter */
+	timeout = jiffies + TDM_ENABLE_TIMEOUT;
+	out_be32(&priv->tdm_regs->tcr, TCR_TEN);
+	spin_event_timeout(!(in_be32(&priv->tdm_regs->tsr) & TSR_TENS),
+			timeout, 0);
+
+	timeout = jiffies + TDM_ENABLE_TIMEOUT;
+	out_be32(&priv->tdm_regs->rcr, RCR_REN);
+	spin_event_timeout(!(in_be32(&priv->tdm_regs->rsr) & RSR_RENS),
+			timeout, 0);
+
+	spin_lock(&priv->tdmlock);
+	priv->tdm_active = 1;
+	spin_unlock(&priv->tdmlock);
+
+	return 1;
+}
+
+static u32 tdm_fsl_read(struct tdm_adapter *adap,
+		u16 **input_tdm_buffer)
+{
+	struct tdm_priv *priv;
+	u32 phase_rx;
+	u32 buf_addr, buf_size;
+	int bytes_in_fifo_per_frame;
+
+	/* point to where to start for the current phase data processing */
+	bytes_in_fifo_per_frame =
+		ALIGN(adap->adapt_cfg.num_ch * adap->adapt_cfg.slot_width, 8);
+
+	priv = adap->data;
+	if (!priv) {
+		pr_err("%s: Invalid handle\n", __func__);
+		return -EINVAL;
+	}
+
+	if (priv->tdm_active == 0) {
+		dev_warn(priv->device, "TDM is not ready");
+		return 0;
+	}
+
+	if (priv->phase_rx == 0)
+		phase_rx = NUM_OF_TDM_BUF - 1;
+	else
+		phase_rx = priv->phase_rx - 1;
+
+	buf_size = bytes_in_fifo_per_frame * adap->adapt_cfg.num_frames;
+	buf_addr = buf_size * phase_rx;
+	*input_tdm_buffer = (u16 *)(priv->tdm_input_data + buf_addr);
+
+	return buf_size;
+}
+
+static u32 tdm_fsl_get_write_buf(struct tdm_adapter *adap,
+		u16 **output_tdm_buffer)
+{
+	struct tdm_priv *priv;
+	u32 tmp;
+	u32 phase_tx;
+	u32 buf_addr, buf_size;
+	int bytes_in_fifo_per_frame;
+
+	/* point to where to start for the current phase data processing */
+	bytes_in_fifo_per_frame =
+		ALIGN(adap->adapt_cfg.num_ch * adap->adapt_cfg.slot_width, 8);
+
+	priv = adap->data;
+	if (!priv) {
+		pr_err("%s: Invalid handle\n", __func__);
+		return -EINVAL;
+	}
+
+	if (priv->tdm_active == 0) {
+		dev_warn(priv->device, "TDM is not ready");
+		return 0;
+	}
+
+	tmp = in_be32(&priv->dmac_regs->tcd[TDMTX_DMA_CH].tcd[0]);
+
+	tmp -= priv->dma_tx_tcd[0]->tcd[0];
+
+	priv->phase_tx = tmp/(bytes_in_fifo_per_frame *
+			adap->adapt_cfg.num_frames);
+
+	if (priv->phase_tx == 0)
+		phase_tx = NUM_OF_TDM_BUF - 1;
+	else
+		phase_tx = priv->phase_tx - 1;
+
+	buf_size = bytes_in_fifo_per_frame * adap->adapt_cfg.num_frames;
+	buf_addr = buf_size * phase_tx;
+	*output_tdm_buffer = (u16 *)(priv->tdm_output_data + buf_addr);
+
+	return buf_size;
+}
+
+static const struct tdm_adapt_algorithm tdm_algo = {
+	.tdm_read = tdm_fsl_read,
+	.tdm_get_write_buf = tdm_fsl_get_write_buf,
+	.tdm_enable = tdm_fsl_enable,
+	.tdm_disable = tdm_fsl_disable,
+};
+
+static struct tdm_adapter tdm_fsl_ops = {
+	.owner = THIS_MODULE,
+	.name = "fsl_tdm",
+	.algo = &tdm_algo,
+};
+
+static int __devinit tdm_fsl_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct tdm_priv *priv;
+	struct resource res;
+
+	priv = kzalloc(sizeof(struct tdm_priv), GFP_KERNEL);
+	if (!priv) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	dev_set_drvdata(&pdev->dev, priv);
+	priv->device = &pdev->dev;
+	ret = of_address_to_resource(pdev->dev.of_node, 0, &res);
+	if (ret) {
+		ret = -EINVAL;
+		goto err_resource;
+	}
+
+	priv->ptdm_base = (u32)res.start;
+	priv->tdm_regs = of_iomap(pdev->dev.of_node, 0);
+	if (!priv->tdm_regs) {
+		ret = -ENOMEM;
+		goto err_tdmregs;
+	}
+
+	priv->dmac_regs = of_iomap(pdev->dev.of_node, 1);
+	if (!priv->dmac_regs) {
+		ret = -ENOMEM;
+		goto err_dmacreg;
+	}
+
+	priv->dmac_done_intr = irq_of_parse_and_map(pdev->dev.of_node, 0);
+	if (priv->dmac_done_intr ==  NO_IRQ) {
+		ret = -EINVAL;
+		goto err_dmacdone_irqmap;
+	}
+	ret = request_irq(priv->dmac_done_intr, dmac_done_isr, 0,
+			"dmac_done_isr", priv);
+	if (ret)
+		goto err_dmacdoneisr;
+
+	priv->adap = &tdm_fsl_ops;
+
+	/* Wait q initilization */
+	priv->adap->tdm_rx_flag = 0;
+	/* TODO - these should be configured by dts or init time */
+	priv->adap->data = priv;
+	priv->adap->parent = &pdev->dev;
+
+	ret = tdm_add_adapter(priv->adap);
+	if (ret < 0) {
+		dev_err(priv->device, "failed to add adapter\n");
+		goto fail_adapter;
+	}
+
+	/* Device does not supports 36 bit mode */
+	dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+
+	ret = init_tdm(priv);
+	if (ret)
+		goto err_tdminit;
+
+	tdm_fsl_reg_init(priv);
+
+	spin_lock_init(&priv->tdmlock);
+	priv->tdm_active = 0;
+
+	if (tdmen) {
+		ret = tdm_fsl_enable(priv->adap);
+		if (!ret)
+			goto err_tdminit;
+	}
+
+	return 0;
+
+err_tdminit:
+fail_adapter:
+	free_irq(priv->dmac_done_intr, priv);
+err_dmacdoneisr:
+	free_irq(priv->tdm_err_intr, priv);
+err_dmacdone_irqmap:
+	irq_dispose_mapping(priv->dmac_done_intr);
+err_dmacreg:
+	iounmap(priv->dmac_regs);
+err_tdmregs:
+err_resource:
+	dev_set_drvdata(&pdev->dev, NULL);
+	kfree(priv);
+err_alloc:
+	return ret;
+}
+
+static int __devexit tdm_fsl_remove(struct platform_device *pdev)
+{
+	struct tdm_priv *priv;
+	int buf_size;
+	struct tdm_adapter *adap;
+
+	if (!pdev) {
+		pr_err("%s: Invalid handle\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = dev_get_drvdata(&pdev->dev);
+	adap = priv->adap;
+
+	tdm_fsl_disable(priv->adap);
+
+	tdm_fsl_stop(priv);
+
+	tdm_del_adapter(priv->adap);
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	/* free the irqs and dispose their mapping */
+	free_irq(priv->tdm_err_intr, priv);
+	free_irq(priv->dmac_done_intr, priv);
+	irq_dispose_mapping(priv->tdm_err_intr);
+	irq_dispose_mapping(priv->dmac_done_intr);
+	iounmap(priv->tdm_regs);
+	iounmap(priv->dmac_regs);
+
+	/* free the buffers */
+	buf_size =
+		TDM_3BUF_SIZE(adap->adapt_cfg.num_ch,
+				adap->adapt_cfg.slot_width,
+				adap->adapt_cfg.num_frames);
+	dma_free_coherent(priv->device, buf_size, priv->dma_input_vaddr,
+			priv->dma_input_paddr);
+	dma_free_coherent(priv->device, buf_size, priv->dma_output_vaddr,
+			priv->dma_output_paddr);
+
+	/* free the TCDs */
+	dma_free_coherent(priv->device, NUM_OF_TDM_BUF * TCD_SIZE,
+			priv->dma_rx_tcd_vaddr,  priv->dma_rx_tcd_paddr);
+	dma_free_coherent(priv->device, NUM_OF_TDM_BUF * TCD_SIZE,
+			priv->dma_tx_tcd_vaddr,  priv->dma_tx_tcd_paddr);
+	dev_set_drvdata(&pdev->dev, NULL);
+	kfree(priv);
+	return 0;
+}
+
+static const struct of_device_id fsl_tdm_match[] = {
+	{
+		.compatible = "fsl,tdm1.0",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, fsl_tdm_match);
+
+static struct platform_driver tdm_fsl_driver = {
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= DRV_NAME,
+		.of_match_table	= fsl_tdm_match,
+
+	},
+	.probe		= tdm_fsl_probe,
+	.remove		= __devexit_p(tdm_fsl_remove),
+};
+
+static int __init tdm_fsl_init(void)
+{
+	int ret;
+	pr_info(DRV_NAME ": " DRV_DESC ":Init\n");
+	ret = platform_driver_register(&tdm_fsl_driver);
+	if (ret)
+		pr_err(DRV_NAME  "of_register_platform_driver failed (%i)\n",
+				ret);
+	return ret;
+}
+
+static void __exit tdm_fsl_exit(void)
+{
+	pr_info(DRV_NAME ": " DRV_DESC ":Exit\n");
+	platform_driver_unregister(&tdm_fsl_driver);
+}
+
+module_init(tdm_fsl_init);
+module_exit(tdm_fsl_exit);
+/*
+   module_platform_driver(tdm_fsl_driver);
+ */
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("P.V.Suresh, Freescale Semiconductor");
+MODULE_DESCRIPTION("Driver For Freescale TDM controller");
-- 
1.5.6.5

^ permalink raw reply related

* Re: [PATCH 17/25] watchdog/mpc8xxx: add a const qualifier
From: Wim Van Sebroeck @ 2012-07-23 10:37 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: linux-watchdog, Arnd Bergmann, Rob Herring, kernel, linuxppc-dev,
	linux-arm-kernel
In-Reply-To: <1343034810-3386-18-git-send-email-u.kleine-koenig@pengutronix.de>

Hi Uwe,

> From: Arnd Bergmann <arnd@arndb.de>
> 
> This prepares *of_device_id.data becoming const. Without this change
> the following warning would occur:
> 
> 	drivers/watchdog/mpc8xxx_wdt.c: In function 'mpc8xxx_wdt_probe':
> 	drivers/watchdog/mpc8xxx_wdt.c:203:11: warning: assignment discards 'const' qualifier from pointer target type [enabled by default]
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> [ukl: split Arnd's patch by driver and add changelog]
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

Acked-by: Wim Van Sebroeck <wim@iguana.be>

Kind regards,
Wim.

^ permalink raw reply

* Re: [PATCH -V3 11/11] arch/powerpc: Add 64TB support
From: Paul Mackerras @ 2012-07-23 11:06 UTC (permalink / raw)
  To: Aneesh Kumar K.V; +Cc: linuxppc-dev
In-Reply-To: <87txwyhj5e.fsf@skywalker.in.ibm.com>

On Mon, Jul 23, 2012 at 03:52:05PM +0530, Aneesh Kumar K.V wrote:
> Paul Mackerras <paulus@samba.org> writes:
> 
> > On Mon, Jul 09, 2012 at 06:43:41PM +0530, Aneesh Kumar K.V wrote:
> >
> >> -#define USER_ESID_BITS		16
> >> -#define USER_ESID_BITS_1T	4
> >> +#define USER_ESID_BITS		18
> >> +#define USER_ESID_BITS_1T	6
> >
> > You also need to change the proto-VSID generation for kernel addresses
> > when you do this.  If you don't you'll end up with some user processes
> > using the same VSIDs as we use for the kernel addresses, meaning that
> > those processes won't run very well...
> >
> 
> Can you explain this more. right now we generate vsid as below
> 
> vsid_scramble(ea >> SID_SHIFT, 256M) for kernel
> 
> vsid_scramble((context << USER_ESID_BITS) | (ea >> SID_SHIFT), 256M);
> for user
> 
> what changes are you suggesting ?

Think about it.  With the current values of USER_ESID_BITS and
CONTEXT_BITS, and the addresses we use for kernel mappings, there are
no values of context, user_ea and kernel_ea for which

kernel_ea >> SID_SHIFT == (context << USER_ESID_BITS) | (user_ea >> SID_SHIFT)

If you increase USER_ESID_BITS, then there will be some context values
for which that equation becomes true.  For example, if you increase
USER_ESID_BITS to 18, then context 0x30000 will generate the same
proto-VSIDs as the kernel linear mapping.  Since we can hand out
contexts up to 0x7ffff (with CONTEXT_BITS = 19), there is a collision.

In other words, the proto-VSID space (the space of values that are
input to vsid_scramble) is currently divided into two mutually
exclusive regions: from 0 to 2^35 - 1 for user processes, and from
2^35 to 2^36 - 1 for kernel addresses.  You are wanting to expand the
amount of proto-VSID space that user processes can use, but you need
either to move the kernel portion of the space, or to make sure that
the context allocator doesn't hand out context values that would
collide with the kernel portion of the space (or both).

Paul.

^ permalink raw reply

* RE: [1/3][PATCH][upstream]Adding documentation for TDM
From: David Laight @ 2012-07-23 12:32 UTC (permalink / raw)
  To: b37400, linuxppc-dev; +Cc: Sandeep Singh, Poonam Aggrwal
In-Reply-To: <1343040588-16002-2-git-send-email-b37400@freescale.com>

> +3. TDM has programmable slot length (8 bits or 16 bits). This can be
> +   configured by:
> +
> +	#define NUM_BYTES_PER_SLOT	8

I presume you meant NUM_BITS_PER_SLOT ?
These constants need name-space protection

> +or
> +	#define NUM_BYTES_PER_SLOT	16
> +
> +depending on the type of sample. For example the sample could be 16
> +bit linear +or 8bit u-law encoded etc.
> +Presently only word length of 16 is supported
> +which is the default configuration.

For flexibility you need to allow for 8bit samples
being converted as:
1) 8bit raw ulaw or alaw data (unchanged from line).
2) 8bit raw data, bit reversed, any hdlc protocol
   is bit reversed from audio [1].
3) 8bit audio, converted from alaw to ulaw
4) 8bit audio, converted from ulaw to alaw
5) 16bit linear converted to/from alaw or ulaw
and on a per-timeslot basis.

[1] most hdlc stuff probably can't stand the 10ms
epochs though, so this is limited use for serious work.

	David

^ permalink raw reply

* Memory management problems on a custom PPC 8270 board
From: Geoffrey Bugniot @ 2012-07-23 15:34 UTC (permalink / raw)
  To: linuxppc-dev

Hi,

I've ported on a custom board U-Boot and Linux 2.6.39.4. It seems to work
well until the kernel is begin to manipulate "data/file" with a size larger
than about 5 Mo. I suppose that's a VM management problem, but I'm not
sure.

In fact, when I use "cp file1 file2" with file1 >= 5/6 Mo, the kernel panics.
Same behaviour with a command like "tar cvf file.tar.gz file1 file2...".

I got something like that :

[  148.891584] Kernel panic - not syncing: Attempted to kill init!
[  148.897503] Call Trace:
[  148.899934] [c7829d10] [c0008fbc] show_stack+0x4c/0x138 (unreliable)
[  148.906470] [c7829d50] [c03be7d8] panic+0xa4/0x1e8
[  148.911401] [c7829db0] [c0025580] do_exit+0x94/0x630
[  148.916501] [c7829e00] [c0025bdc] do_group_exit+0x80/0xac
[  148.922071] [c7829e10] [c00340d8] get_signal_to_deliver+0x474/0x490
[  148.928515] [c7829e70] [c0009aa4] do_signal_pending.constprop.9+0x40/0x22c
[  148.935586] [c7829f30] [c0009d88] do_signal+0x24/0x50
[  148.940793] [c7829f40] [c000f76c] do_user_signal+0x74/0xc4
[  148.946419] --- Exception: 700 at 0xfec5394
[  148.946433]     LR = 0x1000410c
[  148.954009] Rebooting in 3 seconds..

When I use netsniff-ng, with default parameters, kernel hangs too. But If I
specify a small ring buffer size with option "netsniff-ng -S 3MB" all is
running fine. Here, is the dump when netsniff-ng causes a crash:

root@pLinesE_VMEb:~# netsniff-ng
netsniff-ng 0.5.5.0 -- pid (245)
[   36.065574] device eth0 entered promiscuous mode
nice (0), scheduler (0 prio 0)
1 of 1 CPUs online, affinity bitstring (1)
No device specified, using `eth0`.
No filter applied. Switching to `all traffic`.

[   36.159714] BUG: Bad page state in process netsniff-ng  pfn:05401
[   36.165759] page:c0401020 count:0 mapcount:1 mapping:  (null) index:0x0
[   36.172548] page flags: 0x0()
[   36.175539] Call Trace:
[   36.178079] [c786fcc0] [c0008380] show_stack+0x4c/0x138 (unreliable)
[   36.184625] [c786fd00] [c005bb9c] bad_page+0xd4/0xec
[   36.189723] [c786fd10] [c005bfb4] get_page_from_freelist+0x334/0x450
[   36.196263] [c786fda0] [c005c7fc] __alloc_pages_nodemask+0x108/0x63c
[   36.202801] [c786fe40] [c005cd4c] __get_free_pages+0x1c/0x50
[   36.208628] [c786fe50] [c01f0080] packet_set_ring+0x158/0x360
[   36.214537] [c786fe90] [c01f05d8] packet_setsockopt+0x350/0x88c
[   36.220641] [c786fee0] [c017387c] sys_setsockopt+0x80/0xa8
[   36.226277] [c786ff10] [c017410c] sys_socketcall+0x18c/0x1f8
[   36.232112] [c786ff40] [c000e0a8] ret_from_syscall+0x0/0x38
[   36.237830] --- Exception: c01 at 0xff21ec8
[   36.237841]     LR = 0x10006de8
[   36.245387] Disabling lock debugging due to kernel taint
...
[] Unable to handle kernel paging request for data at address 0x00000004
[   41.356750] Faulting instruction address: 0xc005c3f4
[   41.361864] Oops: Kernel access of bad area, sig: 11 [#1]
[   41.367410] Interface Concept pLinesE_VMEb
[   41.371622] last sysfs file: /sys/kernel/uevent_seqnum
[   41.376914] NIP: c005c3f4 LR: c005d304 CTR: 00000009
[   41.382024] REGS: c7815bc0 TRAP: 0300   Tainted: G    B        (2.6.39.4)
[   41.389003] MSR: 00001032 <ME,IR,DR>  CR: 22222424  XER: 20000000
[   41.395278] DAR: 00000004, DSISR: 22000000
[] TASK = c780e000[1] 'init' THREAD: c7814000
GPR00: c0450458 c7815c70 c780e000 c0331f54 00000007 00000000 00000000 00000080
GPR08: 00000002 00000001 c0331fa4 00000000 22002442 1001f308 c7ab3000 c799b0fc
GPR16: c045b4b4 00000000 c0340000 ffffffff ffffff80 c0331fa0 00100100 00200200
GPR24: 00000001 c045b4c0 00000005 00000000 00000001 c0450440 00000007 c0331f54
[   41.439213] NIP [c005c3f4] free_pcppages_bulk+0x26c/0x2e8
[   41.444747] LR [c005d304] free_hot_cold_page+0x178/0x194
[   41.450200] Call Trace:
[] [c7815c70] [c005bdd0] get_page_from_freelist+0x150/0x450 (unreliable)
[   41.460427] [c7815cc0] [c005d304] free_hot_cold_page+0x178/0x194
[   41.466609] [c7815ce0] [c005f908] __put_single_page+0x34/0x3c
[   41.472532] [c7815cf0] [c0068ba4] unmap_vmas+0x310/0x52c
[   41.477986] [c7815d70] [c006d984] exit_mmap+0xa4/0x130
[   41.483288] [c7815d90] [c001c97c] mmput+0x48/0xc4
[   41.488113] [c7815da0] [c0020020] exit_mm+0x118/0x120
[   41.493309] [c7815dd0] [c002172c] do_exit+0x1b4/0x5c8
[   41.498505] [c7815e20] [c0021c00] do_group_exit+0x80/0xac
[   41.504065] [c7815e30] [c002c000] get_signal_to_deliver+0x2e4/0x300
[   41.510526] [c7815e70] [c0008e6c] do_signal_pending.constprop.9+0x40/0x22c
[   41.517591] [c7815f30] [c0009150] do_signal+0x24/0x50
[   41.522801] [c7815f40] [c000e88c] do_user_signal+0x74/0xc4
[   41.528430] --- Exception: 700 at 0xfec5394
[   41.528440]     LR = 0x1000410c
[   41.535948] Instruction dump:
92bd0018 917d001c 900b0000 48000034 1d69002c 56b51838 381d0018 7eb55a14
3ab50020 7ebfaa14 81750004 39550004 <900b0004> 917d0018 915d001c 90150004
[   41.555131] ---[ end trace d0a9d484110ce6f6 ]---
[   41.559873] Fixing recursive fault but reboot is needed!
[   41.565346] BUG: scheduling while atomic: init/1/0x00000001
[   41.571070] Call Trace:
[] [c78159f0] [c0008380] show_stack+0x4c/0x138 (unreliable)
[   41.580144] [c7815a30] [c01f4198] __schedule_bug+0x58/0x60
[   41.585776] [c7815a40] [c01f1fa8] schedule+0x64/0x3b8
[   41.590974] [c7815b30] [c0021670] do_exit+0xf8/0x5c8
[   41.596081] [c7815b80] [c000b340] die+0x184/0x190
[   41.600920] [c7815ba0] [c0011c9c] bad_page_fault+0xdc/0xe4
[   41.606566] [c7815bb0] [c000e548] handle_page_fault+0x7c/0x80
[   41.612498] --- Exception: 300 at free_pcppages_bulk+0x26c/0x2e8
[   41.612510]     LR = free_hot_cold_page+0x178/0x194
[] [c7815c70] [c005bdd0] get_page_from_freelist+0x150/0x450 (unreliable)
[   41.631384] [c7815cc0] [c005d304] free_hot_cold_page+0x178/0x194
[   41.637566] [c7815ce0] [c005f908] __put_single_page+0x34/0x3c
[   41.643488] [c7815cf0] [c0068ba4] unmap_vmas+0x310/0x52c
[   41.648944] [c7815d70] [c006d984] exit_mmap+0xa4/0x130
[   41.654244] [c7815d90] [c001c97c] mmput+0x48/0xc4
[   41.659068] [c7815da0] [c0020020] exit_mm+0x118/0x120
[   41.664265] [c7815dd0] [c002172c] do_exit+0x1b4/0x5c8
[   41.669461] [c7815e20] [c0021c00] do_group_exit+0x80/0xac
[   41.675021] [c7815e30] [c002c000] get_signal_to_deliver+0x2e4/0x300
[   41.681480] [c7815e70] [c0008e6c] do_signal_pending.constprop.9+0x40/0x22c
[   41.688548] [c7815f30] [c0009150] do_signal+0x24/0x50
[   41.693752] [c7815f40] [c000e88c] do_user_signal+0x74/0xc4
[   41.699387] --- Exception: 700 at 0xfec5394
[   41.699397]     LR = 0x1000410c
[] Unable to handle kernel paging request for data at address 0x00000004
[   45.146562] Faulting instruction address: 0xc005d014
[   45.151676] Oops: Kernel access of bad area, sig: 11 [#2]
[   45.157221] Interface Concept pLinesE_VMEb
[   45.161434] last sysfs file: /sys/kernel/uevent_seqnum
[   45.166725] NIP: c005d014 LR: c005d168 CTR: c00200ec
[   45.171835] REGS: c7825e40 TRAP: 0300   Tainted: G    B D      (2.6.39.4)
[   45.178815] MSR: 00001032 <ME,IR,DR>  CR: 42042044  XER: 20000000
[   45.185089] DAR: 00000004, DSISR: 22000000
[   45.189303] TASK = c781e590[6] 'rcu_kthread' THREAD: c7824000
GPR00: c0450318 c7825ef0 c781e590 ffffffff 00200200 00100100 00000001 ffffffc0
GPR08: 00000000 00000000 00000080 c0331fa4 00000000 1008f4d4 00000000 00000000
GPR16: 07f986bc 00000000 07b1e300 07b1e2a8 07f9b138 07f6480c 07f9c044 07f896ec
GPR24: 00000000 00000001 c0331fa0 00000001 00000001 00000000 c0331f54 c0450300
[   45.229652] NIP [c005d014] free_one_page+0x218/0x278
[   45.234736] LR [c005d168] __free_pages_ok+0xf4/0x100
[   45.239832] Call Trace:
[   45.242355] [c7825f20] [c005d168] __free_pages_ok+0xf4/0x100
[   45.248191] [c7825f40] [c001c7b0] free_task+0x38/0x50
[   45.253376] [c7825f50] [c0020130] delayed_put_task_struct+0x44/0x4c
[   45.259834] [c7825f60] [c004c880] rcu_process_callbacks+0x8c/0xa0
[   45.266096] [c7825f70] [c004c968] rcu_kthread+0xd4/0xe8
[   45.271474] [c7825fb0] [c0036204] kthread+0x78/0x7c
[   45.276498] [c7825ff0] [c000d240] kernel_thread+0x4c/0x68
[   45.282034] Instruction dump:
935f0018 913f001c 90090000 48000034 1d3b002c 575a1838 381f0018 7f5a4a14
3b5a0020 7f5ed214 813a0004 397a0004
913f0018 917f001c 901a0004
[   45.301845] Kernel panic - not syncing: Fatal exception in interrupt
[   45.308376] Call Trace:
[   45.310909] [c7825d60] [c0008380] show_stack+0x4c/0x138 (unreliable)
[   45.317449] [c7825da0] [c01f4244] panic+0xa4/0x1d8
[   45.322364] [c7825e00] [c000b334] die+0x178/0x190
[   45.327204] [c7825e20] [c0011c9c] bad_page_fault+0xdc/0xe4
[   45.332853] [c7825e30] [c000e548] handle_page_fault+0x7c/0x80
[   45.338781] --- Exception: 300 at free_one_page+0x218/0x278
[   45.338793]     LR = __free_pages_ok+0xf4/0x100
[   45.349148] [c7825ef0] [00000000]   (null) (unreliable)
[   45.354532] [c7825f20] [c005d168] __free_pages_ok+0xf4/0x100
[   45.360367] [c7825f40] [c001c7b0] free_task+0x38/0x50
[   45.365554] [c7825f50] [c0020130] delayed_put_task_struct+0x44/0x4c
[   45.372011] [c7825f60] [c004c880] rcu_process_callbacks+0x8c/0xa0
[   45.378275] [c7825f70] [c004c968] rcu_kthread+0xd4/0xe8
[   45.383653] [c7825fb0] [c0036204] kthread+0x78/0x7c
[   45.388671] [c7825ff0] [c000d240] kernel_thread+0x4c/0x68
[   45.394219] Rebooting in 3 seconds..


My complete dmesg output :

root@pLinesE_VMEb:~# dmesg 
[    0.000000] Using Interface Concept pLinesE_VMEb machine description
[    0.000000] Linux version 2.6.39.4 (gbt@eingpcb180) (gcc version 4.6.1
20110627 (prerelease) (GCC) ) #1 Mon Jul 23 16:06:44 CEST 2012
[    0.000000] Top of RAM: 0x8000000, Total RAM: 0x8000000
[    0.000000] Memory hole size: 0MB
[    0.000000] Zone PFN ranges:
[    0.000000]   DMA      0x00000000 -> 0x00008000
[    0.000000]   Normal   empty
[    0.000000] Movable zone start PFN for each node
[    0.000000] early_node_map[1] active PFN ranges
[    0.000000]     0: 0x00000000 -> 0x00008000
[    0.000000] On node 0 totalpages: 32768
[    0.000000] free_area_init_node: node 0, pgdat c031ac18, node_mem_map
c0340000
[    0.000000]   DMA zone: 256 pages used for memmap
[    0.000000]   DMA zone: 0 pages reserved
[    0.000000]   DMA zone: 32512 pages, LIFO batch:7
[    0.000000] pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768
[    0.000000] pcpu-alloc: [0] 0 
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total
pages: 32512
[    0.000000] Kernel command line: console=ttyCPM0,115200n8 mtdparts=
physmap-flash.0:0xc00000(system)ro,-(rootfs) rootfstype=jffs2 root=
/dev/mtdblock1 panic=3
[    0.000000] PID hash table entries: 512 (order: -1, 2048 bytes)
[    0.000000] Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
[    0.000000] Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] Memory: 126552k/131072k available (3060k kernel code, 4520k
reserved, 144k data, 115k bss, 744k init)
[    0.000000] Kernel virtual memory layout:
[    0.000000]   * 0xfffdf000..0xfffff000  : fixmap
[    0.000000]   * 0xfdfae000..0xfe000000  : early ioremap
[    0.000000]   * 0xc9000000..0xfdfae000  : vmalloc & ioremap
[    0.000000] NR_IRQS:512
[    0.000000] time_init: decrementer frequency = 25.000000 MHz
[    0.000000] time_init: processor frequency   = 400.000000 MHz
[    0.000000] clocksource: timebase mult[a000000] shift[22] registered
[    0.000000] clockevent: decrementer mult[6666666] shift[32] cpu[0]
[    0.000000] Console: colour dummy device 80x25
[    0.000000] irq: irq 4 on host /soc@ff000000/interrupt-controller
@10c00 mapped to virtual irq 16
[    0.000000] console [ttyCPM0] enabled
[    0.134107] pid_max: default: 32768 minimum: 301
[    0.138914] Mount-cache hash table entries: 512
[    0.147310] NET: Registered protocol family 16
[    0.152617] Registering qe_ic with sysfs...
[    0.157694] bio: create slab <bio-0> at 0
[    0.163351] Switching to clocksource timebase
[    0.167824] FS-Cache: Loaded
[    0.171694] Switched to NOHz mode on CPU #0
[    0.190952] NET: Registered protocol family 2
[    0.195470] IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
[    0.202853] TCP established hash table entries: 4096 (order: 3, 32768 bytes)
[    0.210249] TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
[    0.216812] TCP: Hash tables configured (established 4096 bind 4096)
[    0.223183] TCP reno registered
[    0.226430] UDP hash table entries: 256 (order: 0, 4096 bytes)
[    0.232469] UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
[    0.239592] NET: Registered protocol family 1
[    0.355317] irq: irq 32 on host /soc@ff000000/interrupt-controller
@10c00 mapped to virtual irq 32
[    0.355820] irq: irq 33 on host /soc@ff000000/interrupt-controller
@10c00 mapped to virtual irq 33
[    0.356251] irq: irq 34 on host /soc@ff000000/interrupt-controller
@10c00 mapped to virtual irq 34
[    0.358242] JFFS2 version 2.2. © 2001-2006 Red Hat, Inc.
[    0.363900] msgmni has been set to 247
[    0.374732] Block layer SCSI generic (bsg) driver version 0.4 loaded
(major 254)
[    0.382160] io scheduler noop registered (default)
[    0.387052] io scheduler deadline registered
[    0.391447] io scheduler cfq registered
[    0.396188] ff011a80.serial: ttyCPM0 at MMIO 0xc9058a80 (irq = 16) is
a CPM UART
[    0.404044] Freescale QUICC Engine UART device driver
[    0.409067] ucc-uart: could not register UART driver
[    0.424369] brd: module loaded
[    0.428300] physmap platform flash device: 04000000 at f0000000
[    0.438232] physmap-flash.0: Found 1 x16 devices at 0x0 in 16-bit bank.
Manufacturer ID 0x000001 Chip ID 0x002301
[    0.448661] Amd/Fujitsu Extended Query Table at 0x0040
[    0.453912]   Amd/Fujitsu Extended Query version 1.3.
[    0.459111] number of CFI chips: 1
[    0.462632] 2 cmdlinepart partitions found on MTD device physmap-flash.0
[    0.469499] Creating 2 MTD partitions on "physmap-flash.0":
[    0.475240] 0x000000000000-0x000000c00000 : "system"
[    0.482169] 0x000000c00000-0x000004000000 : "rootfs"
[    0.489835] eth0: fs_enet: aa:bb:cc:00:00:00
[    0.495138] eth1: fs_enet: 00:00:00:00:00:00
[    0.500501] eth2: fs_enet: 00:00:00:00:00:00
[    0.505200] CPM2 Bitbanged MII: probed
[    0.508929] irq: irq 25 on host /soc@ff000000/interrupt-controller@10c00
mapped to virtual irq 25
[    0.511018] IPv4 over IPv4 tunneling driver
[    0.516127] GRE over IPv4 demultiplexor driver
[    0.520304] GRE over IPv4 tunneling driver
[    0.525817] TCP bic registered
[    0.528735] TCP cubic registered
[    0.532023] TCP westwood registered
[    0.535551] TCP htcp registered
[    0.538826] Initializing XFRM netlink socket
[    0.543267] NET: Registered protocol family 17
[    0.547887] NET: Registered protocol family 15
[    0.553647] Freeing unused kernel memory: 744k init
[    3.997732] udev[74]: starting version 164


Any help will be appreciated...

Regars,
G.B.

^ permalink raw reply

* Re: [PATCH] of: require a match on all fields of of_device_id
From: Scott Wood @ 2012-07-23 15:52 UTC (permalink / raw)
  To: Rob Herring; +Cc: devicetree-discuss, Thierry Reding, linuxppc-dev
In-Reply-To: <500CAF49.1060003@gmail.com>

On 07/22/2012 08:56 PM, Rob Herring wrote:
> On 07/18/2012 11:04 AM, Scott Wood wrote:
>> On 07/17/2012 09:38 PM, Rob Herring wrote:
>>> On 07/17/2012 08:11 PM, Scott Wood wrote:
>>>> Commit 107a84e61cdd3406c842a0e4be7efffd3a05dba6 ("of: match by compatible
>>>> property first") breaks the gianfar ethernet driver found on various
>>>> Freescale PPC chips.
>>>
>>> You do know this is reverted, right?
>>
>> No, I didn't.  I got it via Kumar's next branch, and saw that it was
>> still in your fixes-for-grant branch, and didn't see any revert-related
>> e-mail activity on the devicetree-discuss list about it.  I now see that
>> it was reverted directly in Linus's tree (I didn't see either the
>> original or the revert in Linus's tree when I checked, but apparently I
>> hadn't fetched that as recently as I thought).
>>
>>> Here's my fix (untested) which is a bit simpler. I'm assuming if we care
>>> about which compatible string we are matching to, then we require name
>>> and type are blank and we only care about compatible strings.
>>
>> Any particular reason for making that assumption?  We should be avoiding
>> the need for .name or .type matching in new bindings, but this seems
>> like unnecessarily inconsistent behavior.
> 
> Only to ensure we don't change existing behavior and I think trying to
> cover all possibilities will be nearly impossible. For example, what if
> we match on both a specific compatible prop alone and a less specific
> compatible prop plus name and/or type. Which one do we pick as the
> better match?

Whichever one has a compatible string that is listed earlier.  Having an
additional type/name field doesn't necessarily make it a better match --
it's just there to resolve ambiguity (or sometimes for no good reason at
all).

You're going to change existing behavior in some case no matter what,
short of a match table flag saying "it's OK to not keep depending on
link order", or just not making the change.  Might as well change it to
something sane.

-Scott

^ permalink raw reply

* Re: [PATCH] powerpc/mm: add ZONE_NORMAL zone for 64 bit kernel
From: Scott Wood @ 2012-07-23 16:17 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Mingkai Hu, linuxppc-dev, Shaohui Xie, Chen Yuanquan
In-Reply-To: <1343023569.2957.19.camel@pasglop>

On 07/23/2012 01:06 AM, Benjamin Herrenschmidt wrote:
> On Fri, 2012-07-20 at 20:21 +0800, Shaohui Xie wrote:
>> PowerPC platform only supports ZONE_DMA zone for 64bit kernel, so all the
>> memory will be put into this zone. If the memory size is greater than
>> the device's DMA capability and device uses dma_alloc_coherent to allocate
>> memory, it will get an address which is over the device's DMA addressing,
>> the device will fail.
>>
>> So we split the memory to two zones by adding a zone ZONE_NORMAL, since
>> we already allocate PCICSRBAR/PEXCSRBAR right below the 4G boundary (if the
>> lowest PCI address is above 4G), so we constrain the DMA zone ZONE_DMA
>> to 2GB, also, we clear the flag __GFP_DMA and set it only if the device's
>> dma_mask < total memory size. By doing this, devices which cannot DMA all
>> the memory will be limited to ZONE_DMA, but devices which can DMA all the
>> memory will not be affected by this limitation.
> 
> This is wrong.

How so?

> Don't you have an iommu do deal with those devices anyway ?

Yes, but we don't yet have DMA API support for it, it would lower
performance because we'd have to use a lot of subwindows which are
poorly cached (and even then we wouldn't be able to map more than 256
pages at once on a given device), and the IOMMU may not be available at
all if we're being virtualized.

> What about swiotlb ?

That doesn't help with alloc_coherent().

> If you *really* need to honor 32 (or 31 even) bit DMAs,

31-bit is to accommodate PCI, which has PEXCSRBAR that must live under 4
GiB and can't be disabled.

> what you -may- want to do is create a ZONE_DMA32 like other architectures, do not
> hijack the historical ZONE_DMA.

Could you point me to somewhere that clearly defines what ZONE_DMA is to
be used for, such that this counts as hijacking (but using ZONE_DMA32 to
mean 31-bit wouldn't)?  The only arches I see using ZONE_DMA32 (x86 and
mips) also have a separate, more restrictive ZONE_DMA.  PowerPC doesn't.
 It uses ZONE_DMA to point to all of memory (except highmem on 32-bit)
-- how is that not hijacking, if this is?  We can't have ZONE_DMA be
less restrictive than ZONE_DMA32, because the fallback rules are
hardcoded the other way around in generic code.

The exact threshold for ZONE_DMA could be made platform-configurable.

> But even then, I'm dubious this is really needed.

We'd like our drivers to stop crashing with more than 4GiB of RAM on 64-bit.

-Scott

^ permalink raw reply


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