LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v2] powerpc: add hugepagesz boot-time parameter
From: David Gibson @ 2007-12-20  4:33 UTC (permalink / raw)
  To: Jon Tollefson; +Cc: mel, linuxppc-dev, csnook, Paul Mackerras, arnd
In-Reply-To: <47699CC3.1050909@linux.vnet.ibm.com>

On Wed, Dec 19, 2007 at 04:35:47PM -0600, Jon Tollefson wrote:
> Paul, please include this in 2.6.25 if there are no objections.
> 
> This patch adds the hugepagesz boot-time parameter for ppc64.  It lets
> one pick the size for huge pages. The choices available are 64K and 16M
> when the base page size is 4k. It defaults to 16M (previously the only
> only choice) if nothing or an invalid choice is specified.
> 
> Tested 64K huge pages successfully with the libhugetlbfs 1.2.
> 
> Changes from v1:
>     disallow 64K huge pages when base page size is 64K since we can't
> distinguish between
>         base and huge pages when doing a hash_page()
>     collapsed pmd_offset and pmd_alloc to inline calls to simplify the
> main code
>     removed printing of the huge page size in mm/hugetlb.c since this
> information is already
>        available in /proc/meminfo and leaves the remaining changes all
> powerpc specific

[snip]
> @@ -82,11 +81,31 @@ static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp,
>  	return 0;
>  }
>  
> +#ifndef CONFIG_PPC_64K_PAGES
> +static inline
> +pmd_t *hpmd_offset(pud_t *pud, unsigned long addr)
> +{
> +	if (HPAGE_SHIFT == HPAGE_SHIFT_64K)
> +		return pmd_offset(pud, addr);
> +	else
> +		return (pmd_t *) pud;
> +}
> +static inline
> +pmd_t *hpmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long addr)
> +{
> +	if (HPAGE_SHIFT == HPAGE_SHIFT_64K)
> +		return pmd_alloc(mm, pud, addr);
> +	else
> +		return (pmd_t *) pud;
> +}
> +#endif
> +

I'm baffled by this section of code; I can't see how it can work
properly with 64k base page size.  hpmd_offset() and hpmd_alloc() are
only defined if the base page size is 4k, but they appear to be used
unconditionally in huge_pte_offset() and huge_pte_alloc() (since you
remove the #ifdef that was there).

>  /* Modelled after find_linux_pte() */
>  pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
>  {
>  	pgd_t *pg;
>  	pud_t *pu;
> +	pmd_t *pm;
>  
>  	BUG_ON(get_slice_psize(mm, addr) != mmu_huge_psize);
>  
> @@ -96,14 +115,9 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
>  	if (!pgd_none(*pg)) {
>  		pu = pud_offset(pg, addr);
>  		if (!pud_none(*pu)) {
> -#ifdef CONFIG_PPC_64K_PAGES
> -			pmd_t *pm;
> -			pm = pmd_offset(pu, addr);
> +			pm = hpmd_offset(pu, addr);
>  			if (!pmd_none(*pm))
>  				return hugepte_offset((hugepd_t *)pm, addr);
> -#else
> -			return hugepte_offset((hugepd_t *)pu, addr);
> -#endif
>  		}
>  	}
>  
> @@ -114,6 +128,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
>  {
>  	pgd_t *pg;
>  	pud_t *pu;
> +	pmd_t *pm;
>  	hugepd_t *hpdp = NULL;
>  
>  	BUG_ON(get_slice_psize(mm, addr) != mmu_huge_psize);
> @@ -124,14 +139,9 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
>  	pu = pud_alloc(mm, pg, addr);
>  
>  	if (pu) {
> -#ifdef CONFIG_PPC_64K_PAGES
> -		pmd_t *pm;
> -		pm = pmd_alloc(mm, pu, addr);
> +		pm = hpmd_alloc(mm, pu, addr);
>  		if (pm)
>  			hpdp = (hugepd_t *)pm;
> -#else
> -		hpdp = (hugepd_t *)pu;
> -#endif
>  	}
>  
>  	if (! hpdp)

[snip]
> diff --git a/include/asm-powerpc/pgtable.h b/include/asm-powerpc/pgtable.h
> index d18ffe7..66ff7e5 100644
> --- a/include/asm-powerpc/pgtable.h
> +++ b/include/asm-powerpc/pgtable.h
> @@ -37,6 +37,12 @@ extern void paging_init(void);
>  #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
>  		remap_pfn_range(vma, vaddr, pfn, size, prot)
>  
> +/* Base page size affects how we walk hugetlb page tables */
> +#ifdef CONFIG_PPC_64K_PAGES
> +#define hpmd_offset(pud, addr)		pmd_offset(pud, addr)
> +#define hpmd_alloc(mm, pud, addr)	pmd_alloc(mm, pud, addr)
> +#endif

These functions are only used in hugetlbpage.c, I don't see any reason
they should go in the header file.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply

* [PATCH 3/5] Clean up error returns
From: Jon Smirl @ 2007-12-20  4:41 UTC (permalink / raw)
  To: i2c, linuxppc-dev, linux-kernel
In-Reply-To: <20071220044136.20091.70984.stgit@terra.home>

Return errors that were being ignored in the mpc-i2c driver

Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
---

 drivers/i2c/busses/i2c-mpc.c |   30 +++++++++++++++++-------------
 1 files changed, 17 insertions(+), 13 deletions(-)


diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index d8de4ac..7c35a8f 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -180,7 +180,7 @@ static void mpc_i2c_stop(struct mpc_i2c *i2c)
 static int mpc_write(struct mpc_i2c *i2c, int target,
 		     const u8 * data, int length, int restart)
 {
-	int i;
+	int i, result;
 	unsigned timeout = i2c->adap.timeout;
 	u32 flags = restart ? CCR_RSTA : 0;
 
@@ -192,15 +192,17 @@ static int mpc_write(struct mpc_i2c *i2c, int target,
 	/* Write target byte */
 	writeb((target << 1), i2c->base + MPC_I2C_DR);
 
-	if (i2c_wait(i2c, timeout, 1) < 0)
-		return -1;
+	result = i2c_wait(i2c, timeout, 1);
+	if (result < 0)
+		return result;
 
 	for (i = 0; i < length; i++) {
 		/* Write data byte */
 		writeb(data[i], i2c->base + MPC_I2C_DR);
 
-		if (i2c_wait(i2c, timeout, 1) < 0)
-			return -1;
+		result = i2c_wait(i2c, timeout, 1);
+		if (result < 0)
+			return result;
 	}
 
 	return 0;
@@ -210,7 +212,7 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
 		    u8 * data, int length, int restart)
 {
 	unsigned timeout = i2c->adap.timeout;
-	int i;
+	int i, result;
 	u32 flags = restart ? CCR_RSTA : 0;
 
 	/* Start with MEN */
@@ -221,8 +223,9 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
 	/* Write target address byte - this time with the read flag set */
 	writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
 
-	if (i2c_wait(i2c, timeout, 1) < 0)
-		return -1;
+	result = i2c_wait(i2c, timeout, 1);
+	if (result < 0)
+		return result;
 
 	if (length) {
 		if (length == 1)
@@ -234,8 +237,9 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
 	}
 
 	for (i = 0; i < length; i++) {
-		if (i2c_wait(i2c, timeout, 0) < 0)
-			return -1;
+		result = i2c_wait(i2c, timeout, 0);
+		if (result < 0)
+			return result;
 
 		/* Generate txack on next to last byte */
 		if (i == length - 2)
@@ -321,9 +325,9 @@ static int fsl_i2c_probe(struct platform_device *pdev)
 
 	pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data;
 
-	if (!(i2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) {
+	i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
 		return -ENOMEM;
-	}
 
 	i2c->irq = platform_get_irq(pdev, 0);
 	if (i2c->irq < 0) {
@@ -381,7 +385,7 @@ static int fsl_i2c_remove(struct platform_device *pdev)
 	i2c_del_adapter(&i2c->adap);
 	platform_set_drvdata(pdev, NULL);
 
-	if (i2c->irq != 0)
+	if (i2c->irq != NO_IRQ)
 		free_irq(i2c->irq, i2c);
 
 	iounmap(i2c->base);

^ permalink raw reply related

* [PATCH 0/5] Version 17, series to add device tree naming to i2c
From: Jon Smirl @ 2007-12-20  4:41 UTC (permalink / raw)
  To: i2c, linuxppc-dev, linux-kernel

Since copying i2c-mpc.c to maintain support for the ppc architecture seems to be an issue; instead rework i2c-mpc.c to use CONFIG_PPC_MERGE #ifdefs to support both the ppc and powerpc architecture. When ppc is deleted in six months these #ifdefs will need to be removed.

Another rework of the i2c for powerpc device tree patch. This version implements standard alias naming only on the powerpc platform and only for the device tree names. The old naming mechanism of i2c_client.name,driver_name is left in place and not changed for non-powerpc platforms. This patch is fully capable of dynamically loading the i2c modules. You can modprobe in the i2c-mpc driver and the i2c modules described in the device tree will be automatically loaded. Modules also work if compiled in.

The follow on patch to module-init-tools is also needed since the i2c subsystem has never implemented dynamic loading.

The following series implements standard linux module aliasing for i2c modules on arch=powerpc. It then converts the mpc i2c driver from being a platform driver to an open firmware one. I2C device names are picked up from the device tree. Module aliasing is used to translate from device tree names into to linux kernel names. Several i2c drivers are updated to use the new aliasing. 

--
Jon Smirl
jonsmirl@gmail.com 

^ permalink raw reply

* [PATCH 5/5] Convert pfc8563 i2c driver from old style to new style
From: Jon Smirl @ 2007-12-20  4:41 UTC (permalink / raw)
  To: i2c, linuxppc-dev, linux-kernel
In-Reply-To: <20071220044136.20091.70984.stgit@terra.home>

Convert pfc8563 i2c driver from old style to new style. The
driver is also modified to support device tree names via the
i2c mod alias mechanism.

Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
---

 drivers/rtc/rtc-pcf8563.c |  107 +++++++++++----------------------------------
 1 files changed, 27 insertions(+), 80 deletions(-)


diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 0242d80..e1ea2a0 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -25,10 +25,6 @@
  * located at 0x51 will pass the validation routine due to
  * the way the registers are implemented.
  */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-
-/* Module parameters */
-I2C_CLIENT_INSMOD;
 
 #define PCF8563_REG_ST1		0x00 /* status */
 #define PCF8563_REG_ST2		0x01
@@ -72,9 +68,6 @@ struct pcf8563 {
 	int c_polarity;	/* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
 };
 
-static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind);
-static int pcf8563_detach(struct i2c_client *client);
-
 /*
  * In the routines that deal directly with the pcf8563 hardware, we use
  * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
@@ -257,98 +250,52 @@ static const struct rtc_class_ops pcf8563_rtc_ops = {
 	.set_time	= pcf8563_rtc_set_time,
 };
 
-static int pcf8563_attach(struct i2c_adapter *adapter)
+static int pcf8563_remove(struct i2c_client *client)
 {
-	return i2c_probe(adapter, &addr_data, pcf8563_probe);
+	struct rtc_device *rtc = i2c_get_clientdata(client);
+
+	if (rtc)
+		rtc_device_unregister(rtc);
+
+	return 0;
 }
 
+static struct i2c_device_id pcf8563_id[] = {
+	OF_I2C_ID("philips,pcf8563", 0)
+	OF_I2C_ID("epson,rtc8564", 0)
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, pcf8563_id);
+
+static int pcf8563_probe(struct i2c_client *client, const struct i2c_device_id *id);
+
 static struct i2c_driver pcf8563_driver = {
 	.driver		= {
-		.name	= "pcf8563",
+		.name	= "rtc-pcf8563",
 	},
 	.id		= I2C_DRIVERID_PCF8563,
-	.attach_adapter = &pcf8563_attach,
-	.detach_client	= &pcf8563_detach,
+	.probe = &pcf8563_probe,
+	.remove = &pcf8563_remove,
+	.id_table	= pcf8563_id,
 };
 
-static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
+static int pcf8563_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
-	struct pcf8563 *pcf8563;
-	struct i2c_client *client;
+	int result;
 	struct rtc_device *rtc;
 
-	int err = 0;
-
-	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
-
-	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
-		err = -ENODEV;
-		goto exit;
-	}
-
-	if (!(pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL))) {
-		err = -ENOMEM;
-		goto exit;
-	}
-
-	client = &pcf8563->client;
-	client->addr = address;
-	client->driver = &pcf8563_driver;
-	client->adapter	= adapter;
-
-	strlcpy(client->name, pcf8563_driver.driver.name, I2C_NAME_SIZE);
-
-	/* Verify the chip is really an PCF8563 */
-	if (kind < 0) {
-		if (pcf8563_validate_client(client) < 0) {
-			err = -ENODEV;
-			goto exit_kfree;
-		}
-	}
-
-	/* Inform the i2c layer */
-	if ((err = i2c_attach_client(client)))
-		goto exit_kfree;
-
-	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+	result = pcf8563_validate_client(client);
+	if (result)
+		return result;
 
 	rtc = rtc_device_register(pcf8563_driver.driver.name, &client->dev,
 				&pcf8563_rtc_ops, THIS_MODULE);
-
-	if (IS_ERR(rtc)) {
-		err = PTR_ERR(rtc);
-		goto exit_detach;
-	}
+	if (IS_ERR(rtc))
+		return PTR_ERR(rtc);
 
 	i2c_set_clientdata(client, rtc);
 
 	return 0;
-
-exit_detach:
-	i2c_detach_client(client);
-
-exit_kfree:
-	kfree(pcf8563);
-
-exit:
-	return err;
-}
-
-static int pcf8563_detach(struct i2c_client *client)
-{
-	struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
-	int err;
-	struct rtc_device *rtc = i2c_get_clientdata(client);
-
-	if (rtc)
-		rtc_device_unregister(rtc);
-
-	if ((err = i2c_detach_client(client)))
-		return err;
-
-	kfree(pcf8563);
-
-	return 0;
 }
 
 static int __init pcf8563_init(void)

^ permalink raw reply related

* [PATCH 2/5] Modify several rtc drivers to use the alias names list property of i2c
From: Jon Smirl @ 2007-12-20  4:41 UTC (permalink / raw)
  To: i2c, linuxppc-dev, linux-kernel
In-Reply-To: <20071220044136.20091.70984.stgit@terra.home>

This patch modifies the ds1307, ds1374, and rs5c372 i2c drivers to support
device tree names using the new i2c mod alias support

Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
---

 arch/powerpc/sysdev/fsl_soc.c |   44 ++++----------------------------
 drivers/rtc/rtc-ds1307.c      |   20 +++++++++++++-
 drivers/rtc/rtc-ds1374.c      |    9 ++++++
 drivers/rtc/rtc-m41t80.c      |   57 ++++++++++++++++++++++++++++-------------
 drivers/rtc/rtc-rs5c372.c     |   16 ++++++++++--
 5 files changed, 85 insertions(+), 61 deletions(-)


diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 3ace747..268638a 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -320,48 +320,12 @@ arch_initcall(gfar_of_init);
 
 #ifdef CONFIG_I2C_BOARDINFO
 #include <linux/i2c.h>
-struct i2c_driver_device {
-	char	*of_device;
-	char	*i2c_driver;
-	char	*i2c_type;
-};
-
-static struct i2c_driver_device i2c_devices[] __initdata = {
-	{"ricoh,rs5c372a", "rtc-rs5c372", "rs5c372a",},
-	{"ricoh,rs5c372b", "rtc-rs5c372", "rs5c372b",},
-	{"ricoh,rv5c386",  "rtc-rs5c372", "rv5c386",},
-	{"ricoh,rv5c387a", "rtc-rs5c372", "rv5c387a",},
-	{"dallas,ds1307",  "rtc-ds1307",  "ds1307",},
-	{"dallas,ds1337",  "rtc-ds1307",  "ds1337",},
-	{"dallas,ds1338",  "rtc-ds1307",  "ds1338",},
-	{"dallas,ds1339",  "rtc-ds1307",  "ds1339",},
-	{"dallas,ds1340",  "rtc-ds1307",  "ds1340",},
-	{"stm,m41t00",     "rtc-ds1307",  "m41t00"},
-	{"dallas,ds1374",  "rtc-ds1374",  "rtc-ds1374",},
-};
-
-static int __init of_find_i2c_driver(struct device_node *node,
-				     struct i2c_board_info *info)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) {
-		if (!of_device_is_compatible(node, i2c_devices[i].of_device))
-			continue;
-		if (strlcpy(info->driver_name, i2c_devices[i].i2c_driver,
-			    KOBJ_NAME_LEN) >= KOBJ_NAME_LEN ||
-		    strlcpy(info->type, i2c_devices[i].i2c_type,
-			    I2C_NAME_SIZE) >= I2C_NAME_SIZE)
-			return -ENOMEM;
-		return 0;
-	}
-	return -ENODEV;
-}
 
 static void __init of_register_i2c_devices(struct device_node *adap_node,
 					   int bus_num)
 {
 	struct device_node *node = NULL;
+	const char *compatible;
 
 	while ((node = of_get_next_child(adap_node, node))) {
 		struct i2c_board_info info = {};
@@ -378,8 +342,12 @@ static void __init of_register_i2c_devices(struct device_node *adap_node,
 		if (info.irq == NO_IRQ)
 			info.irq = -1;
 
-		if (of_find_i2c_driver(node, &info) < 0)
+		compatible = of_get_property(node, "compatible", &len);
+		if (!compatible) {
+			printk(KERN_WARNING "i2c-mpc.c: invalid entry, missing compatible attribute\n");
 			continue;
+		}
+		strncpy(info.driver_name, compatible, sizeof(info.driver_name));
 
 		info.addr = *addr;
 
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index bc1c7fe..d4874ff 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -139,6 +139,17 @@ static inline const struct chip_desc *find_chip(const char *s)
 	return NULL;
 }
 
+static struct i2c_device_id ds1307_id[] = {
+	OF_I2C_ID("dallas,ds1307", ds_1307)
+	OF_I2C_ID("dallas,ds1337", ds_1337)
+	OF_I2C_ID("dallas,ds1338", ds_1338)
+	OF_I2C_ID("dallas,ds1339", ds_1339)
+	OF_I2C_ID("dallas,ds1340", ds_1340)
+	OF_I2C_ID("stm,m41t00", m41t00)
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, ds1307_id);
+
 static int ds1307_get_time(struct device *dev, struct rtc_time *t)
 {
 	struct ds1307	*ds1307 = dev_get_drvdata(dev);
@@ -326,7 +337,7 @@ static struct bin_attribute nvram = {
 
 static struct i2c_driver ds1307_driver;
 
-static int __devinit ds1307_probe(struct i2c_client *client)
+static int __devinit ds1307_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
 	struct ds1307		*ds1307;
 	int			err = -ENODEV;
@@ -334,7 +345,11 @@ static int __devinit ds1307_probe(struct i2c_client *client)
 	const struct chip_desc	*chip;
 	struct i2c_adapter	*adapter = to_i2c_adapter(client->dev.parent);
 
-	chip = find_chip(client->name);
+	if (id)
+		chip = &chips[id->driver_data];
+	else
+		chip = find_chip(client->name);
+
 	if (!chip) {
 		dev_err(&client->dev, "unknown chip type '%s'\n",
 				client->name);
@@ -537,6 +552,7 @@ static struct i2c_driver ds1307_driver = {
 	},
 	.probe		= ds1307_probe,
 	.remove		= __devexit_p(ds1307_remove),
+	.id_table	= ds1307_id,
 };
 
 static int __init ds1307_init(void)
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index 45bda18..6dc05c4 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -41,6 +41,12 @@
 #define DS1374_REG_SR_AF	0x01 /* Alarm Flag */
 #define DS1374_REG_TCR		0x09 /* Trickle Charge */
 
+static struct i2c_device_id ds1374_id[] = {
+	OF_I2C_ID("dallas,ds1374", 0)
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, ds1374_id);
+
 struct ds1374 {
 	struct i2c_client *client;
 	struct rtc_device *rtc;
@@ -355,7 +361,7 @@ static const struct rtc_class_ops ds1374_rtc_ops = {
 	.ioctl = ds1374_ioctl,
 };
 
-static int ds1374_probe(struct i2c_client *client)
+static int ds1374_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
 	struct ds1374 *ds1374;
 	int ret;
@@ -429,6 +435,7 @@ static struct i2c_driver ds1374_driver = {
 	},
 	.probe = ds1374_probe,
 	.remove = __devexit_p(ds1374_remove),
+	.id_table = ds1374_id,
 };
 
 static int __init ds1374_init(void)
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 1cb33ca..fc33f77 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -100,8 +100,21 @@ static const struct m41t80_chip_info m41t80_chip_info_tbl[] = {
 	},
 };
 
+static struct i2c_device_id m41t80_id[] = {
+	OF_I2C_ID("stm,m41t80", 0)
+	OF_I2C_ID("stm,m41t81", M41T80_FEATURE_HT)
+	OF_I2C_ID("stm,m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL)
+	OF_I2C_ID("stm,m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL)
+	OF_I2C_ID("stm,m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL)
+	OF_I2C_ID("stm,m41t84", M41T80_FEATURE_HT | M41T80_FEATURE_BL)
+	OF_I2C_ID("stm,m41t85", M41T80_FEATURE_HT | M41T80_FEATURE_BL)
+	OF_I2C_ID("stm,m41t87", M41T80_FEATURE_HT | M41T80_FEATURE_BL)
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, m41t80_id);
+
 struct m41t80_data {
-	const struct m41t80_chip_info *chip;
+	u8 features;
 	struct rtc_device *rtc;
 };
 
@@ -208,7 +221,7 @@ static int m41t80_rtc_proc(struct device *dev, struct seq_file *seq)
 	struct m41t80_data *clientdata = i2c_get_clientdata(client);
 	u8 reg;
 
-	if (clientdata->chip->features & M41T80_FEATURE_BL) {
+	if (clientdata->features & M41T80_FEATURE_BL) {
 		reg = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
 		seq_printf(seq, "battery\t\t: %s\n",
 			   (reg & M41T80_FLAGS_BATT_LOW) ? "exhausted" : "ok");
@@ -756,12 +769,12 @@ static struct notifier_block wdt_notifier = {
  *
  *****************************************************************************
  */
-static int m41t80_probe(struct i2c_client *client)
+static int m41t80_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
 	int i, rc = 0;
 	struct rtc_device *rtc = NULL;
 	struct rtc_time tm;
-	const struct m41t80_chip_info *chip;
+	u8 features;
 	struct m41t80_data *clientdata = NULL;
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C
@@ -773,17 +786,24 @@ static int m41t80_probe(struct i2c_client *client)
 	dev_info(&client->dev,
 		 "chip found, driver version " DRV_VERSION "\n");
 
-	chip = NULL;
-	for (i = 0; i < ARRAY_SIZE(m41t80_chip_info_tbl); i++) {
-		if (!strcmp(m41t80_chip_info_tbl[i].name, client->name)) {
-			chip = &m41t80_chip_info_tbl[i];
-			break;
+	if (id)
+		features = id->driver_data;
+	else {
+		const struct m41t80_chip_info *chip;
+
+		chip = NULL;
+		for (i = 0; i < ARRAY_SIZE(m41t80_chip_info_tbl); i++) {
+			if (!strcmp(m41t80_chip_info_tbl[i].name, client->name)) {
+				chip = &m41t80_chip_info_tbl[i];
+				break;
+			}
 		}
-	}
-	if (!chip) {
-		dev_err(&client->dev, "%s is not supported\n", client->name);
-		rc = -ENODEV;
-		goto exit;
+		if (!chip) {
+			dev_err(&client->dev, "%s is not supported\n", client->name);
+			rc = -ENODEV;
+			goto exit;
+		}
+		features = chip->features;
 	}
 
 	clientdata = kzalloc(sizeof(*clientdata), GFP_KERNEL);
@@ -801,7 +821,7 @@ static int m41t80_probe(struct i2c_client *client)
 	}
 
 	clientdata->rtc = rtc;
-	clientdata->chip = chip;
+	clientdata->features = features;
 	i2c_set_clientdata(client, clientdata);
 
 	/* Make sure HT (Halt Update) bit is cleared */
@@ -810,7 +830,7 @@ static int m41t80_probe(struct i2c_client *client)
 		goto ht_err;
 
 	if (rc & M41T80_ALHOUR_HT) {
-		if (chip->features & M41T80_FEATURE_HT) {
+		if (features & M41T80_FEATURE_HT) {
 			m41t80_get_datetime(client, &tm);
 			dev_info(&client->dev, "HT bit was set!\n");
 			dev_info(&client->dev,
@@ -842,7 +862,7 @@ static int m41t80_probe(struct i2c_client *client)
 		goto exit;
 
 #ifdef CONFIG_RTC_DRV_M41T80_WDT
-	if (chip->features & M41T80_FEATURE_HT) {
+	if (features & M41T80_FEATURE_HT) {
 		rc = misc_register(&wdt_dev);
 		if (rc)
 			goto exit;
@@ -878,7 +898,7 @@ static int m41t80_remove(struct i2c_client *client)
 	struct rtc_device *rtc = clientdata->rtc;
 
 #ifdef CONFIG_RTC_DRV_M41T80_WDT
-	if (clientdata->chip->features & M41T80_FEATURE_HT) {
+	if (clientdata->features & M41T80_FEATURE_HT) {
 		misc_deregister(&wdt_dev);
 		unregister_reboot_notifier(&wdt_notifier);
 	}
@@ -896,6 +916,7 @@ static struct i2c_driver m41t80_driver = {
 	},
 	.probe = m41t80_probe,
 	.remove = m41t80_remove,
+	.id_table = m41t80_id,
 };
 
 static int __init m41t80_rtc_init(void)
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 6b67b50..e2022c0 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -69,6 +69,15 @@ enum rtc_type {
 	rtc_rv5c387a,
 };
 
+static struct i2c_device_id rs5c372_id[] = {
+	OF_I2C_ID("ricoh,rs5c372a", rtc_rs5c372a)
+	OF_I2C_ID("ricoh,rs5c372b", rtc_rs5c372b)
+	OF_I2C_ID("ricoh,rv5c386", rtc_rv5c386)
+	OF_I2C_ID("ricoh,rv5c387a", rtc_rv5c387a)
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, rs5c372_id);
+
 /* REVISIT:  this assumes that:
  *  - we're in the 21st century, so it's safe to ignore the century
  *    bit for rv5c38[67] (REG_MONTH bit 7);
@@ -494,7 +503,7 @@ static void rs5c_sysfs_unregister(struct device *dev)
 
 static struct i2c_driver rs5c372_driver;
 
-static int rs5c372_probe(struct i2c_client *client)
+static int rs5c372_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
 	int err = 0;
 	struct rs5c372 *rs5c372;
@@ -522,7 +531,9 @@ static int rs5c372_probe(struct i2c_client *client)
 	if (err < 0)
 		goto exit_kfree;
 
-	if (strcmp(client->name, "rs5c372a") == 0)
+	if (id)
+		rs5c372->type = id->driver_data;
+	else if (strcmp(client->name, "rs5c372a") == 0)
 		rs5c372->type = rtc_rs5c372a;
 	else if (strcmp(client->name, "rs5c372b") == 0)
 		rs5c372->type = rtc_rs5c372b;
@@ -651,6 +662,7 @@ static struct i2c_driver rs5c372_driver = {
 	},
 	.probe		= rs5c372_probe,
 	.remove		= rs5c372_remove,
+	.id_table	= rs5c372_id,
 };
 
 static __init int rs5c372_init(void)

^ permalink raw reply related

* [PATCH 1/5] Implement module aliasing for i2c to translate from device tree names
From: Jon Smirl @ 2007-12-20  4:41 UTC (permalink / raw)
  To: i2c, linuxppc-dev, linux-kernel
In-Reply-To: <20071220044136.20091.70984.stgit@terra.home>

This patch allows new style i2c chip drivers to have alias names using
the official kernel aliasing system and MODULE_DEVICE_TABLE(). I've
tested it on PowerPC and x86. This change is required for PowerPC
device tree support.

Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
---

 drivers/i2c/i2c-core.c          |   32 ++++++++++++++++++++++++++------
 include/linux/i2c.h             |    9 ++++-----
 include/linux/mod_devicetable.h |   20 ++++++++++++++++++++
 scripts/mod/file2alias.c        |   19 +++++++++++++++++++
 4 files changed, 69 insertions(+), 11 deletions(-)


diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index b5e13e4..fce06fd 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -47,10 +47,25 @@ static DEFINE_IDR(i2c_adapter_idr);
 
 /* ------------------------------------------------------------------------- */
 
-static int i2c_device_match(struct device *dev, struct device_driver *drv)
+static const struct i2c_device_id *i2c_device_match(const struct i2c_device_id *id, struct i2c_client *client)
+{
+	/* only powerpc drivers implement the id_table,
+	 * it is empty on other platforms */
+	if (id) {
+		while (id->name[0]) {
+			if (strcmp(client->driver_name, id->name) == 0)
+				return id;
+			id++;
+		}
+	}
+	return NULL;
+}
+
+static int i2c_bus_match(struct device *dev, struct device_driver *drv)
 {
 	struct i2c_client	*client = to_i2c_client(dev);
 	struct i2c_driver	*driver = to_i2c_driver(drv);
+	const struct i2c_device_id *found_id;
 
 	/* make legacy i2c drivers bypass driver model probing entirely;
 	 * such drivers scan each i2c adapter/bus themselves.
@@ -58,9 +73,11 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv)
 	if (!is_newstyle_driver(driver))
 		return 0;
 
-	/* new style drivers use the same kind of driver matching policy
-	 * as platform devices or SPI:  compare device and driver IDs.
-	 */
+	/* match on an id table if there is one */
+	found_id = i2c_device_match(driver->id_table, client);
+	if (found_id)
+		return 1;
+
 	return strcmp(client->driver_name, drv->name) == 0;
 }
 
@@ -89,12 +106,15 @@ static int i2c_device_probe(struct device *dev)
 {
 	struct i2c_client	*client = to_i2c_client(dev);
 	struct i2c_driver	*driver = to_i2c_driver(dev->driver);
+	const struct i2c_device_id *id;
 
 	if (!driver->probe)
 		return -ENODEV;
 	client->driver = driver;
 	dev_dbg(dev, "probe\n");
-	return driver->probe(client);
+
+	id = i2c_device_match(driver->id_table, client);
+	return driver->probe(client, id);
 }
 
 static int i2c_device_remove(struct device *dev)
@@ -189,7 +209,7 @@ static struct device_attribute i2c_dev_attrs[] = {
 static struct bus_type i2c_bus_type = {
 	.name		= "i2c",
 	.dev_attrs	= i2c_dev_attrs,
-	.match		= i2c_device_match,
+	.match		= i2c_bus_match,
 	.uevent		= i2c_device_uevent,
 	.probe		= i2c_device_probe,
 	.remove		= i2c_device_remove,
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index a100c9f..49fc682 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -126,7 +126,7 @@ struct i2c_driver {
 	 * With the driver model, device enumeration is NEVER done by drivers;
 	 * it's done by infrastructure.  (NEW STYLE DRIVERS ONLY)
 	 */
-	int (*probe)(struct i2c_client *);
+	int (*probe)(struct i2c_client *, const struct i2c_device_id *id);
 	int (*remove)(struct i2c_client *);
 
 	/* driver model interfaces that don't relate to enumeration  */
@@ -141,11 +141,10 @@ struct i2c_driver {
 
 	struct device_driver driver;
 	struct list_head list;
+	struct i2c_device_id *id_table;
 };
 #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
 
-#define I2C_NAME_SIZE	20
-
 /**
  * struct i2c_client - represent an I2C slave device
  * @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address;
@@ -179,7 +178,7 @@ struct i2c_client {
 					/* to the client		*/
 	struct device dev;		/* the device structure		*/
 	int irq;			/* irq issued by device (or -1) */
-	char driver_name[KOBJ_NAME_LEN];
+	char driver_name[I2C_NAME_SIZE];
 	struct list_head list;
 	struct completion released;
 };
@@ -223,7 +222,7 @@ static inline void i2c_set_clientdata (struct i2c_client *dev, void *data)
  * with the adapter already known.
  */
 struct i2c_board_info {
-	char		driver_name[KOBJ_NAME_LEN];
+	char		driver_name[I2C_NAME_SIZE];
 	char		type[I2C_NAME_SIZE];
 	unsigned short	flags;
 	unsigned short	addr;
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index e9fddb4..d66038a 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -367,4 +367,24 @@ struct virtio_device_id {
 };
 #define VIRTIO_DEV_ANY_ID	0xffffffff
 
+/* i2c */
+
+/* These defines are used to separate PowerPC open firmware
+ * drivers into their own namespace */
+#define I2C_NAME_SIZE	(16*3)
+#define I2C_MODULE_PREFIX "i2c:N"
+#ifdef CONFIG_OF
+#define OF_I2C_PREFIX "OF,"
+#define I2C_OF_MODULE_PREFIX I2C_MODULE_PREFIX OF_I2C_PREFIX
+#define OF_I2C_ID(s,d) {OF_I2C_PREFIX s, (d) },
+#else
+#define OF_I2C_ID(s,d)
+#endif
+
+struct i2c_device_id {
+	char name[I2C_NAME_SIZE];
+	kernel_ulong_t driver_data;	/* Data private to the driver */
+};
+
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index d802b5a..da43742 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -539,6 +539,21 @@ static int do_virtio_entry(const char *filename, struct virtio_device_id *id,
 	return 1;
 }
 
+/* Looks like: i2c:Ns */
+static int do_i2c_entry(const char *filename, struct i2c_device_id *id,
+			   char *alias)
+{
+    char *tmp;
+    sprintf (alias, I2C_MODULE_PREFIX "%s", id->name);
+
+    /* Replace all whitespace with underscores */
+    for (tmp = alias; tmp && *tmp; tmp++)
+        if (isspace (*tmp))
+            *tmp = '_';
+
+    return 1;
+}
+
 /* Ignore any prefix, eg. v850 prepends _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -669,6 +684,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
 		do_table(symval, sym->st_size,
 			 sizeof(struct virtio_device_id), "virtio",
 			 do_virtio_entry, mod);
+	else if (sym_is(symname, "__mod_i2c_device_table"))
+		do_table(symval, sym->st_size,
+			 sizeof(struct i2c_device_id), "i2c",
+			 do_i2c_entry, mod);
 	free(zeros);
 }
 

^ permalink raw reply related

* [PATCH 4/5] Convert PowerPC MPC i2c to of_platform_driver from platform_driver
From: Jon Smirl @ 2007-12-20  4:41 UTC (permalink / raw)
  To: i2c, linuxppc-dev, linux-kernel
In-Reply-To: <20071220044136.20091.70984.stgit@terra.home>

Convert MPC i2c driver from being a platform_driver to an open firmware version. Error returns were improved. Routine names were changed from fsl_ to mpc_ to make them match the file name.

Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
---

 arch/powerpc/sysdev/fsl_soc.c |   96 ----------------------
 drivers/i2c/busses/i2c-mpc.c  |  183 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 180 insertions(+), 99 deletions(-)


diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 268638a..d6ef264 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -318,102 +318,6 @@ err:
 
 arch_initcall(gfar_of_init);
 
-#ifdef CONFIG_I2C_BOARDINFO
-#include <linux/i2c.h>
-
-static void __init of_register_i2c_devices(struct device_node *adap_node,
-					   int bus_num)
-{
-	struct device_node *node = NULL;
-	const char *compatible;
-
-	while ((node = of_get_next_child(adap_node, node))) {
-		struct i2c_board_info info = {};
-		const u32 *addr;
-		int len;
-
-		addr = of_get_property(node, "reg", &len);
-		if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) {
-			printk(KERN_WARNING "fsl_soc.c: invalid i2c device entry\n");
-			continue;
-		}
-
-		info.irq = irq_of_parse_and_map(node, 0);
-		if (info.irq == NO_IRQ)
-			info.irq = -1;
-
-		compatible = of_get_property(node, "compatible", &len);
-		if (!compatible) {
-			printk(KERN_WARNING "i2c-mpc.c: invalid entry, missing compatible attribute\n");
-			continue;
-		}
-		strncpy(info.driver_name, compatible, sizeof(info.driver_name));
-
-		info.addr = *addr;
-
-		i2c_register_board_info(bus_num, &info, 1);
-	}
-}
-
-static int __init fsl_i2c_of_init(void)
-{
-	struct device_node *np;
-	unsigned int i;
-	struct platform_device *i2c_dev;
-	int ret;
-
-	for (np = NULL, i = 0;
-	     (np = of_find_compatible_node(np, "i2c", "fsl-i2c")) != NULL;
-	     i++) {
-		struct resource r[2];
-		struct fsl_i2c_platform_data i2c_data;
-		const unsigned char *flags = NULL;
-
-		memset(&r, 0, sizeof(r));
-		memset(&i2c_data, 0, sizeof(i2c_data));
-
-		ret = of_address_to_resource(np, 0, &r[0]);
-		if (ret)
-			goto err;
-
-		of_irq_to_resource(np, 0, &r[1]);
-
-		i2c_dev = platform_device_register_simple("fsl-i2c", i, r, 2);
-		if (IS_ERR(i2c_dev)) {
-			ret = PTR_ERR(i2c_dev);
-			goto err;
-		}
-
-		i2c_data.device_flags = 0;
-		flags = of_get_property(np, "dfsrr", NULL);
-		if (flags)
-			i2c_data.device_flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
-
-		flags = of_get_property(np, "fsl5200-clocking", NULL);
-		if (flags)
-			i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200;
-
-		ret =
-		    platform_device_add_data(i2c_dev, &i2c_data,
-					     sizeof(struct
-						    fsl_i2c_platform_data));
-		if (ret)
-			goto unreg;
-
-		of_register_i2c_devices(np, i);
-	}
-
-	return 0;
-
-unreg:
-	platform_device_unregister(i2c_dev);
-err:
-	return ret;
-}
-
-arch_initcall(fsl_i2c_of_init);
-#endif
-
 #ifdef CONFIG_PPC_83xx
 static int __init mpc83xx_wdt_init(void)
 {
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 7c35a8f..4f2e7ea 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -17,7 +17,7 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/init.h>
-#include <linux/platform_device.h>
+#include <linux/of_platform.h>
 
 #include <asm/io.h>
 #include <linux/fsl_devices.h>
@@ -25,13 +25,13 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 
-#define MPC_I2C_ADDR  0x00
+#define DRV_NAME "mpc-i2c"
+
 #define MPC_I2C_FDR 	0x04
 #define MPC_I2C_CR	0x08
 #define MPC_I2C_SR	0x0c
 #define MPC_I2C_DR	0x10
 #define MPC_I2C_DFSRR 0x14
-#define MPC_I2C_REGION 0x20
 
 #define CCR_MEN  0x80
 #define CCR_MIEN 0x40
@@ -316,6 +316,181 @@ static struct i2c_adapter mpc_ops = {
 	.retries = 1
 };
 
+struct i2c_driver_device {
+	char	*of_device;
+	char	*i2c_driver;
+	char	*i2c_type;
+};
+
+#ifdef CONFIG_PPC_MERGE
+
+static void of_register_i2c_devices(struct i2c_adapter *adap, struct device_node *adap_node)
+{
+	struct device_node *node = NULL;
+
+	while ((node = of_get_next_child(adap_node, node))) {
+		struct i2c_board_info info;
+		const u32 *addr;
+		const char *compatible;
+		int len;
+
+		addr = of_get_property(node, "reg", &len);
+		if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) {
+			printk(KERN_ERR "i2c-mpc.c: invalid entry, missing reg attribute\n");
+			continue;
+		}
+
+		info.irq = irq_of_parse_and_map(node, 0);
+		if (info.irq == NO_IRQ)
+			info.irq = -1;
+
+		compatible = of_get_property(node, "compatible", &len);
+		if (!compatible) {
+			printk(KERN_ERR "i2c-mpc.c: invalid entry, missing compatible attribute\n");
+			continue;
+		}
+		
+		/* need full alias i2c:NOF,vendor,device */
+		strcpy(info.driver_name, I2C_OF_MODULE_PREFIX);
+		strncat(info.driver_name, compatible, sizeof(info.driver_name));
+		request_module(info.driver_name);
+		
+		/* need module alias OF,vendor,device */
+		strcpy(info.driver_name, OF_I2C_PREFIX);
+		strncat(info.driver_name, compatible, sizeof(info.driver_name));
+		
+		info.type[0] = '\0';
+		info.platform_data = NULL;
+		info.addr = *addr;
+
+		if (!i2c_new_device(adap, &info)) {
+			printk(KERN_ERR "i2c-mpc.c: Failed to load driver for %s\n", info.driver_name);
+			continue;
+		}
+	}
+}
+
+static int mpc_i2c_probe(struct of_device *op, const struct of_device_id *match)
+{
+	int result = 0;
+	struct mpc_i2c *i2c;
+
+	i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	if (of_get_property(op->node, "dfsrr", NULL))
+		i2c->flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
+
+	if (of_device_is_compatible(op->node, "mpc5200-i2c"))
+		i2c->flags |= FSL_I2C_DEV_CLOCK_5200;
+
+	init_waitqueue_head(&i2c->queue);
+
+	i2c->base = of_iomap(op->node, 0);
+	if (!i2c->base) {
+		printk(KERN_ERR "i2c-mpc - failed to map controller\n");
+		result = -ENOMEM;
+		goto fail_map;
+	}
+
+	i2c->irq = irq_of_parse_and_map(op->node, 0);
+	if (i2c->irq == NO_IRQ) {
+		result = -ENXIO;
+		goto fail_irq;
+	}
+
+	result = request_irq(i2c->irq, mpc_i2c_isr, IRQF_SHARED, "i2c-mpc", i2c);
+	if (result < 0) {
+		printk(KERN_ERR "i2c-mpc - failed to attach interrupt\n");
+		goto fail_request;
+	}
+
+	mpc_i2c_setclock(i2c);
+
+	dev_set_drvdata(&op->dev, i2c);
+
+	i2c->adap = mpc_ops;
+	i2c_set_adapdata(&i2c->adap, i2c);
+	i2c->adap.dev.parent = &op->dev;
+
+	result = i2c_add_adapter(&i2c->adap);
+	if (result < 0) {
+		printk(KERN_ERR "i2c-mpc - failed to add adapter\n");
+		goto fail_add;
+	}
+
+	of_register_i2c_devices(&i2c->adap, op->node);
+
+	return result;
+
+fail_add:
+	free_irq(i2c->irq, i2c);
+fail_request:
+	irq_dispose_mapping(i2c->irq);
+fail_irq:
+	iounmap(i2c->base);
+fail_map:
+	kfree(i2c);
+	return result;
+};
+
+static int mpc_i2c_remove(struct of_device *op)
+{
+	struct mpc_i2c *i2c = dev_get_drvdata(&op->dev);
+
+	i2c_del_adapter(&i2c->adap);
+	dev_set_drvdata(&op->dev, NULL);
+
+	if (i2c->irq != NO_IRQ)
+		free_irq(i2c->irq, i2c);
+
+	irq_dispose_mapping(i2c->irq);
+	iounmap(i2c->base);
+	kfree(i2c);
+	return 0;
+};
+
+static struct of_device_id mpc_i2c_of_match[] = {
+	{
+		.compatible	= "fsl-i2c",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, mpc_i2c_of_match);
+
+
+/* Structure for a device driver */
+static struct of_platform_driver mpc_i2c_driver = {
+	.match_table	= mpc_i2c_of_match,
+	.probe		= mpc_i2c_probe,
+	.remove		= __devexit_p(mpc_i2c_remove),
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= DRV_NAME,
+	},
+};
+
+static int __init mpc_i2c_init(void)
+{
+	int rv;
+
+	rv = of_register_platform_driver(&mpc_i2c_driver);
+	if (rv)
+		printk(KERN_ERR DRV_NAME " of_register_platform_driver failed (%i)\n", rv);
+	return rv;
+}
+
+static void __exit mpc_i2c_exit(void)
+{
+	of_unregister_platform_driver(&mpc_i2c_driver);
+}
+
+module_init(mpc_i2c_init);
+module_exit(mpc_i2c_exit);
+
+#else
+
 static int fsl_i2c_probe(struct platform_device *pdev)
 {
 	int result = 0;
@@ -416,6 +591,8 @@ static void __exit fsl_i2c_exit(void)
 module_init(fsl_i2c_init);
 module_exit(fsl_i2c_exit);
 
+#endif
+
 MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
 MODULE_DESCRIPTION
     ("I2C-Bus adapter for MPC107 bridge and MPC824x/85xx/52xx processors");

^ permalink raw reply related

* Re: [PATCH 4/5] Convert PowerPC MPC i2c to of_platform_driver from platform_driver
From: David Gibson @ 2007-12-20  5:16 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, i2c, linux-kernel
In-Reply-To: <20071220044144.20091.35917.stgit@terra.home>

On Wed, Dec 19, 2007 at 11:41:44PM -0500, Jon Smirl wrote:
> Convert MPC i2c driver from being a platform_driver to an open
> firmware version. Error returns were improved. Routine names were
> changed from fsl_ to mpc_ to make them match the file name.

In discussions BenH and I have had, we've actually concluded that
moving this from platform drivers to of_platform drives is not
actually a good idea.

In fact we're planning to move away from of_platform devices and
drivers and instead develop a framework for instantiating platform
devices or i2c devices or whatever devices from the device tree nodes.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply

* tiny login
From: pjmaiya @ 2007-12-20  4:25 UTC (permalink / raw)
  To: linuxppc-dev, linuxppc-embedded

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

hi,
I am using tiny login provided by montavista. Binaries already obtained from tool provided from montavista.We are able to add only 10 users. But I need to add more than 10 users.
I have already downloaded free open source for tinylogin (tinylogin-1.4). Can we modifiy this source code of this version and support users more than 10??
If yes, can somebody inform step to build tiny login and installation method.

thanx in advance
pjmaiya

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

^ permalink raw reply

* Re: [PATCH 4/5] Convert PowerPC MPC i2c to of_platform_driver from platform_driver
From: Olof Johansson @ 2007-12-20  6:01 UTC (permalink / raw)
  To: Jon Smirl, i2c, linuxppc-dev, linux-kernel
In-Reply-To: <20071220051618.GB29058@localhost.localdomain>

On Thu, Dec 20, 2007 at 04:16:18PM +1100, David Gibson wrote:
> On Wed, Dec 19, 2007 at 11:41:44PM -0500, Jon Smirl wrote:
> > Convert MPC i2c driver from being a platform_driver to an open
> > firmware version. Error returns were improved. Routine names were
> > changed from fsl_ to mpc_ to make them match the file name.
> 
> In discussions BenH and I have had, we've actually concluded that
> moving this from platform drivers to of_platform drives is not
> actually a good idea.
> 
> In fact we're planning to move away from of_platform devices and
> drivers and instead develop a framework for instantiating platform
> devices or i2c devices or whatever devices from the device tree nodes.

There's been talk about that for a long time. Whenever that framework
is done, all the other drivers that have been converted (or written)
must/can be converted back as well.

Meanwhile, this should go in so those of us who can make use of the
other improvements the series brings can make use of them.


Thanks,

Olof

^ permalink raw reply

* Re: [PATCH 4/5] Convert PowerPC MPC i2c to of_platform_driver from platform_driver
From: Stefan Roese @ 2007-12-20  6:04 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: linux-kernel, i2c, David Gibson
In-Reply-To: <20071220051618.GB29058@localhost.localdomain>

On Thursday 20 December 2007, David Gibson wrote:
> On Wed, Dec 19, 2007 at 11:41:44PM -0500, Jon Smirl wrote:
> > Convert MPC i2c driver from being a platform_driver to an open
> > firmware version. Error returns were improved. Routine names were
> > changed from fsl_ to mpc_ to make them match the file name.
>
> In discussions BenH and I have had, we've actually concluded that
> moving this from platform drivers to of_platform drives is not
> actually a good idea.
>
> In fact we're planning to move away from of_platform devices and
> drivers and instead develop a framework for instantiating platform
> devices or i2c devices or whatever devices from the device tree nodes.

Now that is interesting news. I like this idea.

But what should be done to support the still missing devices in the 4xx 
arch/powerpc tree, like I2C, NAND etc.? Should we wait with those driver till 
this framework is available?

Thanks.

Cheers,
Stefan

^ permalink raw reply

* [PATCH] [RFC] Xilinx SystemACE: Add media hotplug support
From: Grant Likely @ 2007-12-20  6:23 UTC (permalink / raw)
  To: axboe, linux-kernel, linuxppc-dev, sr, monstr, jwilliams,
	stephen.neuendorffer

From: Grant Likely <grant.likely@secretlab.ca>

Please review and comment.  This patch works in my setup, but I haven't
tested exhaustively yet.  I also need to fixup the documentation to
reflect new states before I request this patch to be merged.

Question for the block layer experts:  I'm using add_disk()/del_gendisk()
functions to inform the kernel of media insertion and removal events.  Is
this the best way to do this?  I looked at the .media_changed and
.revalidate_disk hooks, but it doesn't seem like they offer the driver
any way to notify the kernel of media removal (as opposed to the kernel
asking the driver)

Cheers,
g.
---

 drivers/block/xsysace.c |  265 ++++++++++++++++++++++++++++++++++-------------
 1 files changed, 189 insertions(+), 76 deletions(-)

diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index 0cdc868..9b3df96 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -53,7 +53,7 @@
  *    The request method in particular schedules the tasklet when a new
  *    request has been indicated by the block layer.  Once started, the
  *    FSM proceeds as far as it can processing the request until it
- *    needs on a hardware event.  At this point, it must yield execution.
+ *    needs a hardware event.  At this point, it must yield execution.
  *
  *    A state has two options when yielding execution:
  *    1. ace_fsm_yield()
@@ -71,7 +71,8 @@
  *    Additionally, the driver maintains a kernel timer which can process
  *    the FSM.  If the FSM gets stalled, typically due to a missed
  *    interrupt, then the kernel timer will expire and the driver can
- *    continue where it left off.
+ *    continue where it left off.  The stall timer is also used to watch
+ *    for media removal/insertion events.
  *
  * To Do:
  *    - Add FPGA configuration control interface.
@@ -90,6 +91,7 @@
 #include <linux/slab.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
+#include <linux/workqueue.h>
 #include <linux/platform_device.h>
 #if defined(CONFIG_OF)
 #include <linux/of_device.h>
@@ -170,17 +172,18 @@ struct ace_reg_ops;
 struct ace_device {
 	/* driver state data */
 	int id;
-	int media_change;
 	int users;
 	struct list_head list;
 
 	/* finite state machine data */
 	struct tasklet_struct fsm_tasklet;
+	struct work_struct fsm_worker;
 	uint fsm_task;		/* Current activity (ACE_TASK_*) */
 	uint fsm_state;		/* Current state (ACE_FSM_STATE_*) */
 	uint fsm_continue_flag;	/* cleared to exit FSM mainloop */
 	uint fsm_iter_num;
 	struct timer_list stall_timer;
+	int stall_count;
 
 	/* Transfer state/result, use for both id and block request */
 	struct request *req;	/* request being processed */
@@ -189,7 +192,6 @@ struct ace_device {
 	int data_result;	/* Result of transfer; 0 := success */
 
 	int id_req_count;	/* count of id requests */
-	int id_result;
 	struct completion id_completion;	/* used when id req finishes */
 	int in_irq;
 
@@ -212,6 +214,7 @@ struct ace_device {
 };
 
 static int ace_major;
+struct workqueue_struct *ace_workqueue;
 
 /* ---------------------------------------------------------------------
  * Low level register access
@@ -429,21 +432,24 @@ void ace_fix_driveid(struct hd_driveid *id)
 #define ACE_TASK_IDENTIFY  1
 #define ACE_TASK_READ      2
 #define ACE_TASK_WRITE     3
-#define ACE_FSM_NUM_TASKS  4
+#define ACE_NUM_TASKS      4
 
 /* FSM state definitions */
-#define ACE_FSM_STATE_IDLE               0
-#define ACE_FSM_STATE_REQ_LOCK           1
-#define ACE_FSM_STATE_WAIT_LOCK          2
-#define ACE_FSM_STATE_WAIT_CFREADY       3
-#define ACE_FSM_STATE_IDENTIFY_PREPARE   4
-#define ACE_FSM_STATE_IDENTIFY_TRANSFER  5
-#define ACE_FSM_STATE_IDENTIFY_COMPLETE  6
-#define ACE_FSM_STATE_REQ_PREPARE        7
-#define ACE_FSM_STATE_REQ_TRANSFER       8
-#define ACE_FSM_STATE_REQ_COMPLETE       9
-#define ACE_FSM_STATE_ERROR             10
-#define ACE_FSM_NUM_STATES              11
+#define ACE_FSM_STATE_NO_MEDIA           0
+#define ACE_FSM_STATE_KICKSTART          1
+#define ACE_FSM_STATE_IDLE               2
+#define ACE_FSM_STATE_REQ_LOCK           3
+#define ACE_FSM_STATE_WAIT_LOCK          4
+#define ACE_FSM_STATE_WAIT_CFREADY       5
+#define ACE_FSM_STATE_IDENTIFY_PREPARE   6
+#define ACE_FSM_STATE_IDENTIFY_TRANSFER  7
+#define ACE_FSM_STATE_IDENTIFY_COMPLETE  8
+#define ACE_FSM_STATE_REQ_PREPARE        9
+#define ACE_FSM_STATE_REQ_TRANSFER      10
+#define ACE_FSM_STATE_REQ_COMPLETE      11
+#define ACE_FSM_STATE_INVALIDATE_MEDIA  12
+#define ACE_FSM_STATE_MEDIA_DISABLED    13
+#define ACE_FSM_NUM_STATES              14
 
 /* Set flag to exit FSM loop and reschedule tasklet */
 static inline void ace_fsm_yield(struct ace_device *ace)
@@ -490,18 +496,53 @@ static void ace_fsm_dostate(struct ace_device *ace)
 		ace->fsm_state, ace->id_req_count);
 #endif
 
+	/* Before doing anything; check the CF detect bit.  If the card
+	 * is not present; then there are only a couple of states which
+	 * we can be in */
+	if ((ace_in(ace, ACE_STATUS) & ACE_STATUS_CFDETECT) == 0) {
+		/* Card is missing; short circuit to appropriate state */
+		switch (ace->fsm_state) {
+		  case ACE_FSM_STATE_NO_MEDIA:
+		  case ACE_FSM_STATE_MEDIA_DISABLED:
+			ace->fsm_state = ACE_FSM_STATE_NO_MEDIA;
+			break;
+
+		  default:
+			ace->fsm_state = ACE_FSM_STATE_INVALIDATE_MEDIA;
+		}
+	}
+
+	/* Process the next state in the FSM */
 	switch (ace->fsm_state) {
+	case ACE_FSM_STATE_NO_MEDIA:
+		/* No media inserted into the drive.  If media is inserted
+		 * then kick the workqueue.  The workqueue will cause a
+		 * transition to the IDLE state. */
+		if (ace_in(ace, ACE_STATUS) & ACE_STATUS_CFDETECT) {
+			ace->fsm_state = ACE_FSM_STATE_KICKSTART;
+			break;
+		}
+		ace->fsm_continue_flag = 0;
+		break;
+
+	case ACE_FSM_STATE_KICKSTART:
+		/* Everything looks good hardware wise; kick off the
+		 * initialization sequence.
+		 *
+		 * fsm_worker causes transition from here to the IDLE state.
+		 * The FSM cannot transition itself.
+		 */
+		queue_work(ace_workqueue, &ace->fsm_worker);
+		ace->fsm_continue_flag = 0;
+		break;
+
 	case ACE_FSM_STATE_IDLE:
 		/* See if there is anything to do */
 		if (ace->id_req_count || ace_get_next_request(ace->queue)) {
 			ace->fsm_iter_num++;
 			ace->fsm_state = ACE_FSM_STATE_REQ_LOCK;
-			mod_timer(&ace->stall_timer, jiffies + HZ);
-			if (!timer_pending(&ace->stall_timer))
-				add_timer(&ace->stall_timer);
 			break;
 		}
-		del_timer(&ace->stall_timer);
 		ace->fsm_continue_flag = 0;
 		break;
 
@@ -538,7 +579,10 @@ static void ace_fsm_dostate(struct ace_device *ace)
 			break;
 		}
 
-		/* Device is ready for command; determine what to do next */
+		/* Device is ready for command; determine what to do next.
+		 * - If a revalidate is pending, do that.
+		 * - Otherwise go to to process the next block request.
+		 */
 		if (ace->id_req_count)
 			ace->fsm_state = ACE_FSM_STATE_IDENTIFY_PREPARE;
 		else
@@ -598,22 +642,19 @@ static void ace_fsm_dostate(struct ace_device *ace)
 
 		if (ace->data_result) {
 			/* Error occured, disable the disk */
-			ace->media_change = 1;
-			set_capacity(ace->gd, 0);
 			dev_err(ace->dev, "error fetching CF id (%i)\n",
 				ace->data_result);
-		} else {
-			ace->media_change = 0;
-
-			/* Record disk parameters */
-			set_capacity(ace->gd, ace->cf_id.lba_capacity);
-			dev_info(ace->dev, "capacity: %i sectors\n",
-				 ace->cf_id.lba_capacity);
+			ace->fsm_state = ACE_FSM_STATE_INVALIDATE_MEDIA;
+			break;
 		}
 
-		/* We're done, drop to IDLE state and notify waiters */
+		/* Record disk parameters */
+		set_capacity(ace->gd, ace->cf_id.lba_capacity);
+		dev_info(ace->dev, "capacity: %i sectors\n",
+			 ace->cf_id.lba_capacity);
 		ace->fsm_state = ACE_FSM_STATE_IDLE;
-		ace->id_result = ace->data_result;
+
+		/* We're done, notify waiters */
 		while (ace->id_req_count) {
 			complete(&ace->id_completion);
 			ace->id_req_count--;
@@ -727,12 +768,90 @@ static void ace_fsm_dostate(struct ace_device *ace)
 		ace->fsm_state = ACE_FSM_STATE_IDLE;
 		break;
 
+	case ACE_FSM_STATE_INVALIDATE_MEDIA:
+		/* The media has been removed, or a fatal error has
+		 * occured.
+		 *
+		 * This state can only transition to the MEDIA_DISABLED
+		 * state; but it is not done in this state machine handler
+		 * Rather, when this state is entered, the workqueue is
+		 * kicked to deregister the gendisk and it is the workqueue
+		 * that causes the transition to the MEDIA_DISABLED state
+		 */
+
+		/* If there are any waiters, wake them up so they are not
+		 * hung on the problem */
+		while (ace->id_req_count) {
+			complete(&ace->id_completion);
+			ace->id_req_count--;
+		}
+
+		/* Schedule the worker to invalidate the block device */
+		queue_work(ace_workqueue, &ace->fsm_worker);
+		ace->fsm_continue_flag = 0;
+		break;
+
+	case ACE_FSM_STATE_MEDIA_DISABLED:
+		/* The media is no longer registered.  If the sysace reports
+		 * that the media has been removed, then we can transition
+		 * to the NO_MEDIA state.
+		 */
+		ace->fsm_continue_flag = 0;
+		break;
+
 	default:
-		ace->fsm_state = ACE_FSM_STATE_IDLE;
+		/* Something weird has happened.  Go to the catchall
+		 * exception handling state */
+		ace->fsm_state = ACE_FSM_STATE_INVALIDATE_MEDIA;
 		break;
 	}
 }
 
+static void ace_fsm_work(struct work_struct *work)
+{
+	struct ace_device *ace;
+	unsigned long flags;
+
+	ace = container_of(work, struct ace_device, fsm_worker);
+
+	/* Note on worker states: this worker can only begin processing if
+	 * the FSM is either in the KICKSTART or the INVALIDATE_MEDIA states.
+	 * In both cases, the FSM cannot transition out of the state itself.
+	 * Instead, this worker must begin processing and cause a transition
+	 * to the next state manually. */
+	if (ace->fsm_state == ACE_FSM_STATE_KICKSTART) {
+		/* Hardware is ready for initialization sequence */
+		dev_info(ace->dev, "Kickstart\n");
+		ace->fsm_state = ACE_FSM_STATE_IDLE;
+
+		spin_lock_irqsave(&ace->lock, flags);
+		ace->id_req_count++;
+		spin_unlock_irqrestore(&ace->lock, flags);
+
+		tasklet_schedule(&ace->fsm_tasklet);
+		wait_for_completion(&ace->id_completion);
+
+		/* Make the sysace device 'live' */
+		if (ace->fsm_state != ACE_FSM_STATE_INVALIDATE_MEDIA);
+			add_disk(ace->gd);
+	}
+
+	if (ace->fsm_state == ACE_FSM_STATE_INVALIDATE_MEDIA) {
+		dev_info(ace->dev, "card error/removed; Invalidating\n");
+		/* Media has been removed or an error has occured.
+		 * Unregister the block device so it can no longer be used.
+		 */
+		if (ace->gd->flags & GENHD_FL_UP)
+			del_gendisk(ace->gd);
+
+		/* All done; go to the MEDIA_DISABLED state.
+		 * This is safe to do w/o the lock because the FSM is stalled
+		 * on the INVALIDATE_MEDIA state.
+		 */
+		ace->fsm_state = ACE_FSM_STATE_MEDIA_DISABLED;
+	};
+}
+
 static void ace_fsm_tasklet(unsigned long data)
 {
 	struct ace_device *ace = (void *)data;
@@ -753,10 +872,28 @@ static void ace_stall_timer(unsigned long data)
 	struct ace_device *ace = (void *)data;
 	unsigned long flags;
 
-	dev_warn(ace->dev,
-		 "kicking stalled fsm; state=%i task=%i iter=%i dc=%i\n",
-		 ace->fsm_state, ace->fsm_task, ace->fsm_iter_num,
-		 ace->data_count);
+	/* Report if FSM stalls when we don't expect it. */
+	switch (ace->fsm_state) {
+	  case ACE_FSM_STATE_NO_MEDIA:
+	  case ACE_FSM_STATE_KICKSTART:
+	  case ACE_FSM_STATE_IDLE:
+		break;
+
+	  case ACE_FSM_STATE_INVALIDATE_MEDIA:
+	  case ACE_FSM_STATE_MEDIA_DISABLED:
+		dev_warn(ace->dev, "FSM timer: state=%i t=%i i=%i dc=%i\n",
+			 ace->fsm_state, ace->fsm_task,
+			 ace->fsm_iter_num, ace->data_count);
+
+	  default:
+		ace->stall_count++;
+		if (ace->stall_count > 2)
+			dev_warn(ace->dev, "kicking stalled FSM; "
+				           "state=%i t=%i i=%i dc=%i\n",
+				 ace->fsm_state, ace->fsm_task,
+				 ace->fsm_iter_num, ace->data_count);
+	}
+
 	spin_lock_irqsave(&ace->lock, flags);
 
 	/* Rearm the stall timer *before* entering FSM (which may then
@@ -798,6 +935,7 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id)
 	/* be safe and get the lock */
 	spin_lock(&ace->lock);
 	ace->in_irq = 1;
+	ace->stall_count = 0;
 
 	/* clear the interrupt */
 	creg = ace_in(ace, ACE_CTRL);
@@ -845,36 +983,6 @@ static void ace_request(struct request_queue * q)
 	}
 }
 
-static int ace_media_changed(struct gendisk *gd)
-{
-	struct ace_device *ace = gd->private_data;
-	dev_dbg(ace->dev, "ace_media_changed(): %i\n", ace->media_change);
-
-	return ace->media_change;
-}
-
-static int ace_revalidate_disk(struct gendisk *gd)
-{
-	struct ace_device *ace = gd->private_data;
-	unsigned long flags;
-
-	dev_dbg(ace->dev, "ace_revalidate_disk()\n");
-
-	if (ace->media_change) {
-		dev_dbg(ace->dev, "requesting cf id and scheduling tasklet\n");
-
-		spin_lock_irqsave(&ace->lock, flags);
-		ace->id_req_count++;
-		spin_unlock_irqrestore(&ace->lock, flags);
-
-		tasklet_schedule(&ace->fsm_tasklet);
-		wait_for_completion(&ace->id_completion);
-	}
-
-	dev_dbg(ace->dev, "revalidate complete\n");
-	return ace->id_result;
-}
-
 static int ace_open(struct inode *inode, struct file *filp)
 {
 	struct ace_device *ace = inode->i_bdev->bd_disk->private_data;
@@ -926,8 +1034,6 @@ static struct block_device_operations ace_fops = {
 	.owner = THIS_MODULE,
 	.open = ace_open,
 	.release = ace_release,
-	.media_changed = ace_media_changed,
-	.revalidate_disk = ace_revalidate_disk,
 	.getgeo = ace_getgeo,
 };
 
@@ -954,8 +1060,9 @@ static int __devinit ace_setup(struct ace_device *ace)
 		goto err_ioremap;
 
 	/*
-	 * Initialize the state machine tasklet and stall timer
+	 * Initialize the state machine work, tasklet and stall timer
 	 */
+	INIT_WORK(&ace->fsm_worker, ace_fsm_work);
 	tasklet_init(&ace->fsm_tasklet, ace_fsm_tasklet, (unsigned long)ace);
 	setup_timer(&ace->stall_timer, ace_stall_timer, (unsigned long)ace);
 
@@ -1026,11 +1133,8 @@ static int __devinit ace_setup(struct ace_device *ace)
 	dev_dbg(ace->dev, "physaddr 0x%lx, mapped to 0x%p, irq=%i\n",
 		ace->physaddr, ace->baseaddr, ace->irq);
 
-	ace->media_change = 1;
-	ace_revalidate_disk(ace->gd);
-
-	/* Make the sysace device 'live' */
-	add_disk(ace->gd);
+	/* Kick things off */
+	mod_timer(&ace->stall_timer, jiffies + HZ);
 
 	return 0;
 
@@ -1244,6 +1348,12 @@ static int __init ace_init(void)
 {
 	int rc;
 
+	ace_workqueue = create_singlethread_workqueue("xsysace");
+	if (!ace_workqueue) {
+		rc = -ENOMEM;
+		goto err_wq;
+	}
+
 	ace_major = register_blkdev(ace_major, "xsysace");
 	if (ace_major <= 0) {
 		rc = -ENOMEM;
@@ -1267,6 +1377,8 @@ err_plat:
 err_of:
 	unregister_blkdev(ace_major, "xsysace");
 err_blk:
+	destroy_workqueue(ace_workqueue);
+err_wq:
 	printk(KERN_ERR "xsysace: registration failed; err=%i\n", rc);
 	return rc;
 }
@@ -1274,6 +1386,7 @@ err_blk:
 static void __exit ace_exit(void)
 {
 	pr_debug("Unregistering Xilinx SystemACE driver\n");
+	destroy_workqueue(ace_workqueue);
 	platform_driver_unregister(&ace_platform_driver);
 	ace_of_unregister();
 	unregister_blkdev(ace_major, "xsysace");

^ permalink raw reply related

* Re: [PATCH] [RFC] Xilinx SystemACE: Add media hotplug support
From: Grant Likely @ 2007-12-20  6:30 UTC (permalink / raw)
  To: axboe, linux-kernel, linuxppc-dev, sr, monstr, jwilliams,
	stephen.neuendorffer
In-Reply-To: <20071220062348.16448.24575.stgit@trillian.secretlab.ca>

On 12/19/07, Grant Likely <grant.likely@secretlab.ca> wrote:
> From: Grant Likely <grant.likely@secretlab.ca>
>
> Please review and comment.  This patch works in my setup, but I haven't
> tested exhaustively yet.  I also need to fixup the documentation to
> reflect new states before I request this patch to be merged.
>
> Question for the block layer experts:  I'm using add_disk()/del_gendisk()
> functions to inform the kernel of media insertion and removal events.  Is
> this the best way to do this?  I looked at the .media_changed and
> .revalidate_disk hooks, but it doesn't seem like they offer the driver
> any way to notify the kernel of media removal (as opposed to the kernel
> asking the driver)

Heh, actually I *know* I'm doing the wrong thing; but I'm hoping I've
got better chances of getting steered in the right direction if I
start by throwing code out there.  Currently this patch handles
insertion/removal just fine if nothing is mounted, but gets stuck if
the disk is in use.  How do I get the kernel to cancel all pending
requests when deregistering the device?

Thanks,
g.

-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195

^ permalink raw reply

* Re: MPC885 - USB HCI drivers.
From: Jonathan Journo @ 2007-12-20  6:53 UTC (permalink / raw)
  To: linuxppc-embedded@ozlabs.org

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

Hello Pantelis ,

I saw you used usb host driver on mpc8xx. I am trying to make one on MPC885 because vxworks drivers are not compatible with it.

To begin I tried to make the loopback mode (test) working but it doesn't work.
Is there anything that is not mentioned on the datasheet in" USB host controller initialization example" that I have to know to make it work.

Thanks for any help.
Jonathan
Journo.

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

^ permalink raw reply

* Re: some questions about XUP and the generation of ace file
From: greenlean @ 2007-12-20 10:12 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <14418941.post@talk.nabble.com>


Hi,=20

I'm responding myself and windstorm. First of all, I'm Spanish and I suppos=
e
you too...

Xilinx has translate the compiler tools to spanish, and if you have a look
to the line 430 of the file /opt/Xilinx91i/EDK91i/data/xmd/genace.tcl you
can see

if { [catch {set saddr [exec powerpc-eabi-objdump -x $elffile | grep -w
"start address"]} err] } {

this line pruduces the error. If we do an obj-dump of this file, one using
the ELDK compiler and other one using the EDK cross compiler tool, we see:

$ppc_4xx-objdump -x zImage.elf | less --> Compilador ELDK 4.1
****************************************************************
architecture: powerpc:common, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address0x00400000

Program Header:
****************************************************************

$powerpc-eabi-objdump -x zImage.elf  --> Xilinx PowerPC compiler
****************************************************************
arquitectura: powerpc:common, opciones 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
direcci=C3=B3n de inicio 0x00400000

Encabezado del Programa:
****************************************************************

That's the error, you must translate the start address tag in the opt file
to your language.... In my case this is

if { [catch {set saddr [exec powerpc-eabi-objdump -x $elffile | grep -w
"direcci=C3=B3n de inicio"]} err] } {

By...

PD: I still have a problem with the zImage.elf file  generated by the
compiler, xmd told me that the file is corrupted that this is not an valid
elf file, I posted it some time ago, and I've  no response if someone knows
why it's happening please contact me.



greenlean wrote:
>=20
> Hi windstorm,
>=20
> Have you correct the error, you get when generating the ace file?? I'm
> trying to build the linux system for the XUPV2P board, and I have the sam=
e
> error:
>=20
> Using GenACE option file : xupGenace.opt
> Error: Executable zImage.elf does not contain start address..
>=20
> As you and Xilinx said in the answer
> (http://www.xilinx.com/support/answers/23192.htm) my genace.tcl file is
> patched, and it uses de powerPC objdump.
>=20
> I have tryed to use the ppc_4xx-objdump cross tool of ELDK instead of the
> powerpc-eabi-objdump that is used in the genace.tcl file, and the result
> was an error:
>=20
> ***********
> Executing xmd script : /opt/Xilinx91i/EDK91i/data/xmd/genace.tcl
>=20
> #######################################################################
> XMD GenACE utility. Generate SystemACE File from bit/elf/data Files
> #######################################################################
> Using GenACE option file : xupGenace.opt
> GenACE Options:
>         Board      : user
>         Jtag Devs  : xc2vp30
>         FPGA pos   : 1
>         JPROG      : true
>         HW File    : implementation/download.bit
>         ACE File   : system.ace
>         nCPUs      : 1
>=20
>         Processor ppc_hw_1 Information
>                 Debug opt : -debugdevice devicenr 1 cpunr 1
>                 ELF files : zImage.elf
>                 Start PC Address : 0x00400000
>=20
> ############################################################
> Converting Bitstream 'implementation/download.bit' to SVF file
> 'implementation/download.svf'
> Executing 'impact -batch bit2svf.scr'
>=20
> Copying implementation/download.svf File to  system.svf File
>=20
>=20
> ############################################################
> Converting ELF file 'zImage.elf' to SVF file 'zImage.svf'
> Error: E02 Failed to download ELF file
>=20
> ERROR(1053): UNABLE to Read Elf File. The Elf File Maybe Corrupted
>         : zImage.elf
>=20
>=20
> *********
>=20
>=20
>=20
> but the Error:executable zImage.elf does not contain start address..
> didn't appear. And the compiler assign the address  0x00400000...
>=20
> This error is the same, that xmd told me if I try to download directly th=
e
> linux kernel to the board, maybe there is any relation...
>=20
> I don't know what is happening...
>=20
> Any info or help???
>=20
>=20
>=20
> windstorm wrote:
>>=20
>> 1 it's strange. the ns16550.c do exist in the arch/ppc/boot/
>> directory, not arch/ppc/boot/common. I just download the source
>> yesterday.
>>=20
>> 2 Can you show me some reference about the "small bootloader"? Or any
>> web material about it?
>>=20
>> 2007/8/10, Grant Likely <grant.likely@secretlab.ca>:
>>> On 8/10/07, windstorm <likunarmstrong@gmail.com> wrote:
>>> > Hello all:
>>> >
>>> > I am trying to transfer the Linux onto XUP board. The kernel source I
>>> > used is from the git trees from andrei konovalov or grant likely. But
>>> > I encounter two questions now.
>>> >
>>> > 1 Generally, I should correct the kernel source file
>>> > arch/ppc/boot/common/ns16550.c, In that file, changing SERIAL_BAUD
>>> > from 9600 to 38400  makes the bootloader talk at 38400. I always do i=
t
>>> > when I use standard kernel source. But this time I found out that the
>>> > ns16550.c's path is arch/ppc/boot/, not arch/ppc/boot/common/, and
>>> > there was no "SERIAL_BAUD" string any more. So, how can I control the
>>> > baud rate?
>>>
>>> ???
>>>
>>> I don't know what you're referring to.  ns16550.c is in
>>> arch/ppc/boot/common on my tree, and it still contains the SERIAL_BAUD
>>> #define.
>>>
>>> >
>>> > 2 I have compiled the kernel and obtained a Image.elf whose size is
>>> > 1.7MB, and then it's time for creating a system.ace file which I can
>>> > put onto a compact flash card.  I Changed the file xupGenace.opt like
>>> > the follow:
>>>
>>> You can do this, but I don't think it's a particularly good idea.
>>> Binding the kernel image into an ACE file results in a *very* large
>>> ace file, and it's slow.  Consider the fact that doing it that way
>>> means that you're transferring the entire 1.7MB image via JTAG.
>>>
>>> I've also seem problems where DDR isn't fully initialized before the
>>> SystemACE tries to transfer the image which results in a non-booting
>>> system.
>>>
>>> What I do, is I've got a small bootloader that lives in BRAM and is
>>> just smart enough to load an elf file off of the CF card.  If I can
>>> get permission to do so, I'll publish the source for my utility.
>>>
>>> >
>>> > -jprog
>>> > -board user
>>> > -target ppc_hw
>>> > -hw ./implementation/download.bit
>>> > -elf zImage.elf
>>> > -configdevice devicenr 1 idcode 0x1127e093 irlength 14 partname
>>> xc2vp30
>>> > -debugdevice devicenr 1 cpunr 1
>>> > -ace system.ace
>>> >
>>> > and executed the command: xmd -tcl genace.tcl -opt genace.opt
>>> >
>>> > and the result I saw is:  Using GenACE option file : genace.opt
>>> > Error: Executable zImage.elf does not contain start address..
>>> >
>>> > I examine the information by google, some said that it's the bug of
>>> > development tools without sp, but both my ISE and EDK was patched.
>>> > Others said that it's because of the "mb-objdump", we should chage it
>>> > into "powerpc-eaci-objdump", and actually I had done this correction.
>>> > BUT, the error still here.
>>> >
>>> > Could anyone please to help me about this question? I will be very
>>> grateful.
>>>
>>> Very odd.  I haven't seen this problem myself so I can't be much help.
>>> sorry.
>>>
>>> >
>>> > BTW, could any kind person send any basic config file, which had been
>>> > proved that the kernel compiled based on it could work good on XUP
>>> > board?
>>>
>>> I don't have that board, sorry
>>>
>>> g.
>>>
>>> --
>>> Grant Likely, B.Sc., P.Eng.
>>> Secret Lab Technologies Ltd.
>>> grant.likely@secretlab.ca
>>> (403) 399-0195
>>>
>>=20
>>=20
>> --=20
>> web: http://www.forwind.cn
>> msn: likunarmstrong at hotmail.com
>> _______________________________________________
>> Linuxppc-embedded mailing list
>> Linuxppc-embedded@ozlabs.org
>> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>>=20
>>=20
>=20
>=20

--=20
View this message in context: http://www.nabble.com/some-questions-about-XU=
P-and-the-generation-of-ace-file-tp12090990p14433748.html
Sent from the linuxppc-embedded mailing list archive at Nabble.com.

^ permalink raw reply

* Re: tiny login
From: Clemens Koller @ 2007-12-20 10:45 UTC (permalink / raw)
  To: pjmaiya; +Cc: linuxppc-dev, linuxppc-embedded
In-Reply-To: <001401c842c0$69c0dba0$4601a8c0@signet>

pjmaiya schrieb:
> hi,

- don't cross-post
- don't post HTML to the lists

> I am using tiny login provided by montavista. Binaries already obtained 
> from tool provided from montavista. We are able to add only 10 users. 
> But I need to add more than 10 users.

Tried to contact montavista for support? ;-)

> I have already downloaded free open source for tinylogin 
> (tinylogin-1.4). Can we modifiy this source code of this version and 
> support users more than 10??
> If yes, can somebody inform step to build tiny login and installation 
> method.

Well, you propably want to understand the advantage of open source
software first. You can (depending on the license) change the code
according to your needs...

Read: http://tldp.org/HOWTO/Software-Building-HOWTO.html

If you have questions, please tell exactly, where you have a problem.

$ wget http://tinylogin.busybox.net/downloads/tinylogin-1.4.tar.bz2
$ tar xvf tinylogin-1.4.tar.bz2
$ cd tinylogin-1.4
$ make

works like a charm.

A quick look into login.c says:
// login defines
#define TIMEOUT       60
#define FAIL_DELAY    3
#define EMPTY_USERNAME_COUNT    10
                                ^^^^
... which looks quite promising!
Ask the busybox guys for details since this is off-topic here.

Regards,

Clemens Koller
__________________________________
R&D Imaging Devices
Anagramm GmbH
Rupert-Mayer-Straße 45/1
Linhof Werksgelände
D-81379 München
Tel.089-741518-50
Fax 089-741518-19
http://www.anagramm-technology.com

^ permalink raw reply

* More patches added to for-2.6.25 and master branches of powerpc.git
From: Paul Mackerras @ 2007-12-20 11:00 UTC (permalink / raw)
  To: linuxppc-dev

Andre Detsch (1):
      [POWERPC] cell: safer of_has_vicinity routine

Balbir Singh (1):
      [POWERPC] Fake NUMA emulation for PowerPC

Benjamin Herrenschmidt (20):
      [POWERPC] pci32: Remove bogus alignment message
      [POWERPC] pci32: Use generic pci_assign_unassign_resources
      [POWERPC] pci32: Remove PowerMac P2P bridge IO hack
      [POWERPC] pci32: Add flags modifying the PCI code behaviour
      [POWERPC] pci32: Remove obsolete PowerMac bus number hack
      [POWERPC] pci32: Add platform option to enable /proc PCI domains
      [POWERPC] Merge pcibios_resource_to_bus/bus_to_resource
      [POWERPC] Merge PCI resource fixups
      [POWERPC] Merge PCI resource allocation & assignment
      [POWERPC] fix iSeries PCI resource management
      [POWERPC] Updates/fixes to 32 bits pcibios_enable_device()
      [POWERPC] Merge 32 and 64 bits pcibios_enable_device
      [POWERPC] Fixup powermac enable device hook
      [POWERPC] Clear pci_probe_only on 64 bits PowerMac
      [POWERPC] Various fixes to pcibios_enable_device()
      [POWERPC] Enable self-view of the HT host bridge on PowerMac G5
      [POWERPC] Improve resource setup of PowerMac G5 HT bridge
      [POWERPC] Fixup skipping of PowerMac PCI<->PCI bridge "closed" resources
      [POWERPC] Disable PCI IO/Mem on a device when resources can't be allocated
      [POWERPC] Fix PCI IRQ fallback code to not map IRQ 0

Bob Nelson (1):
      [POWERPC] OProfile: fix cbe pm signal routing problem

Cyrill Gorcunov (1):
      [POWERPC] CHRP: Fix possible NULL pointer dereference

David Gibson (2):
      [POWERPC] Merge dtc upstream source
      [POWERPC] Use embedded dtc in kernel builds

Grant Likely (1):
      [POWERPC] Add machine initcall macros

Ishizaki Kou (3):
      [POWERPC] cell: add missing '\n'
      [POWERPC] Cleanup calling mmio_nvram_init
      [POWERPC] celleb: Split machine definition

Jeremy Kerr (6):
      [POWERPC] cell: export force_sig_info()
      [POWERPC] cell: handle kernel SLB setup in spu_base.c
      [POWERPC] cell: use spu_load_slb for SLB setup
      [POWERPC] cell: add spu_64k_pages_available() check
      [POWERPC] cell: handle SPE kernel mappings that cross segment boundaries
      [POWERPC] cell: catch errors from sysfs_create_group()

Jochen Friedrich (2):
      [POWERPC] Add support for PORTA and PORTB odr registers
      [POWERPC] Move CPM command handling into the cpm drivers

Johannes Berg (3):
      [POWERPC] adb: Replace sleep notifier with platform driver suspend/resume hooks
      [POWERPC] via-pmu: Kill sleep notifiers completely
      [POWERPC] powermac: Use generic suspend code

Jon Loeliger (3):
      [POWERPC] 8xxx: Convert #include of asm/of_{platform, device}.h into linux/of_{platform, device}.h.
      [POWERPC] 86xx: Add aliases node to 8641hpcn DTS file.
      [POWERPC] cell: Convert #include of asm/of_{platform, device}.h into linux/of_{platform, device}.h.

Julia Lawall (3):
      [POWERPC] arch/ppc: Remove an unnecessary pci_dev_put
      [POWERPC] arch/powerpc: Add missing of_node_put
      [POWERPC] cell/cbe_regs.c: Add missing of_node_put

Kevin Corry (1):
      [POWERPC] perfmon2: make pm_interval register read/write

Kumar Gala (5):
      [POWERPC] Add SPRN for Embedded registers specified in PowerISA 2.04
      [POWERPC] Emulate isel (Integer Select) instruction
      [POWERPC] FSL: I2C device tree cleanups
      [POWERPC] FSL: enet device tree cleanups
      [POWERPC] FSL: Added aliases node to device trees

Li Yang (5):
      [POWERPC] add e300c4 entry to cputable
      [POWERPC] ipic: add new interrupts introduced by new chip
      [POWERPC] 83xx: Add platform support for MPC837x MDS board
      [POWERPC] 83xx: Add MPC837x MDS default kernel configuration
      [POWERPC] ipic: ack only for edge interrupts

Li Zefan (1):
      [POWERPC] Don't cast a struct pointer to list_head pointer

Lucas Woods (2):
      [POWERPC] arch/powerpc: Remove duplicate includes
      [POWERPC] arch/ppc: Remove duplicate includes

Michael Ellerman (1):
      [POWERPC] Implement pci_set_dma_mask() in terms of the dma_ops

Milton Miller (6):
      [POWERPC] Push down or eliminate smp_processor_id calls in xics code
      [POWERPC] init_decrementer_clockevent can be static __init
      [POWERPC] Use __get_cpu_var in time.c
      [POWERPC] Timer interrupt: use a struct for two per_cpu varables
      [POWERPC] Depend on ->initialized in calc_steal_time
      [POWERPC] Optimize account_system_vtime

Olof Johansson (3):
      [POWERPC] MPIC: Minor optimization of ipi handler
      [POWERPC] pasemi: Implement MSI support
      [POWERPC] holly.c: Remove unnecessary include of linux/ide.h

Paul Mackerras (5):
      [POWERPC] Convert media-bay.c to use the kthread API
      [POWERPC] Convert adb.c to use kthread API and not spin on ADB requests
      [POWERPC] Convert therm_pm72.c to use the kthread API
      [POWERPC] Convert therm_windtunnel.c to use the kthread API
      [POWERPC] Fix sleep on powerbook 3400

Scott Wood (5):
      [POWERPC] 8xx: Convert mpc866ads to the new device binding.
      [POWERPC] 83xx: mpc834x_mds: Fix whitespace and call of_platform_bus_probe().
      [POWERPC] 83xx: mpc8313erdb: Fix whitespace.
      [POWERPC] wrapper: Rename offset in offset_devp()
      [POWERPC] wrapper: Treat NULL as root node in devp_offset; add devp_offset_find()

Stephen Rothwell (2):
      [POWERPC] iSeries: Fix unregistering HV event handlers
      [POWERPC] Stop the TOC overflowing for large builds

Timur Tabi (4):
      [POWERPC] 86xx: fix guts_set_dmacr() and add guts_set_pmuxcr_dma() to immap_86xx.h
      [POWERPC] QE: change qe_setbrg() to take an enum qe_clock instead of an integer
      [POWERPC] qe: add function qe_clock_source()
      [POWERPC] ucc_geth: use rx-clock-name and tx-clock-name device tree properties

joe@perches.com (4):
      [POWERPC] arch/powerpc/: Spelling fixes
      [POWERPC] include/asm-powerpc/: Spelling fixes
      [POWERPC] arch/ppc/: Spelling fixes
      [POWERPC] include/asm-ppc/: Spelling fixes

^ permalink raw reply

* [PATCH -mm 13/43] powerpc ptrace special regs
From: Roland McGrath @ 2007-12-20 11:57 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
In-Reply-To: <20071220115200.C767E26F98A@magilla.localdomain>

This isolates the ptrace code for the special-case registers msr and trap
from the ptrace-layout dispatch code.  This should inline away completely.
It cleanly separates the low-level machine magic that has to be done for
deep reasons, from the superficial details of the ptrace interface.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/powerpc/kernel/ptrace.c |   45 ++++++++++++++++++++++++++++--------------
 1 files changed, 30 insertions(+), 15 deletions(-)

diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 8c25b00..4edc118 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -60,20 +60,38 @@
 #define PT_MAX_PUT_REG	PT_CCR
 #endif
 
+static unsigned long get_user_msr(struct task_struct *task)
+{
+	return task->thread.regs->msr | task->thread.fpexc_mode;
+}
+
+static int set_user_msr(struct task_struct *task, unsigned long msr)
+{
+	task->thread.regs->msr &= ~MSR_DEBUGCHANGE;
+	task->thread.regs->msr |= msr & MSR_DEBUGCHANGE;
+	return 0;
+}
+
+/*
+ * We prevent mucking around with the reserved area of trap
+ * which are used internally by the kernel.
+ */
+static int set_user_trap(struct task_struct *task, unsigned long trap)
+{
+	task->thread.regs->trap = trap & 0xfff0;
+	return 0;
+}
+
 /*
  * Get contents of register REGNO in task TASK.
  */
 unsigned long ptrace_get_reg(struct task_struct *task, int regno)
 {
-	unsigned long tmp = 0;
-
 	if (task->thread.regs == NULL)
 		return -EIO;
 
-	if (regno == PT_MSR) {
-		tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
-		return tmp | task->thread.fpexc_mode;
-	}
+	if (regno == PT_MSR)
+		return get_user_msr(task);
 
 	if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
 		return ((unsigned long *)task->thread.regs)[regno];
@@ -89,15 +107,12 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
 	if (task->thread.regs == NULL)
 		return -EIO;
 
-	if (regno <= PT_MAX_PUT_REG || regno == PT_TRAP) {
-		if (regno == PT_MSR)
-			data = (data & MSR_DEBUGCHANGE)
-				| (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
-		/* We prevent mucking around with the reserved area of trap
-		 * which are used internally by the kernel
-		 */
-		if (regno == PT_TRAP)
-			data &= 0xfff0;
+	if (regno == PT_MSR)
+		return set_user_msr(task, data);
+	if (regno == PT_TRAP)
+		return set_user_trap(task, data);
+
+	if (regno <= PT_MAX_PUT_REG) {
 		((unsigned long *)task->thread.regs)[regno] = data;
 		return 0;
 	}
-- 
1.5.3.6

^ permalink raw reply related

* [PATCH -mm 14/43] powerpc user_regset gpr
From: Roland McGrath @ 2007-12-20 11:57 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
In-Reply-To: <20071220115200.C767E26F98A@magilla.localdomain>

This implements user_regset-style accessors for the powerpc general registers.
In the future these functions will be the only place that needs to understand
the user_regset layout (core dump format) and how it maps to the internal
representation of user thread state.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/powerpc/kernel/ptrace.c |   91 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 91 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 4edc118..e493fc0 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -119,6 +119,97 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
 	return -EIO;
 }
 
+static int gpr_get(struct task_struct *target, const struct user_regset *regset,
+		   unsigned int pos, unsigned int count,
+		   void *kbuf, void __user *ubuf)
+{
+	int ret;
+
+	if (target->thread.regs == NULL)
+		return -EIO;
+
+	CHECK_FULL_REGS(target->thread.regs);
+
+	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				  target->thread.regs,
+				  0, offsetof(struct pt_regs, msr));
+	if (!ret) {
+		unsigned long msr = get_user_msr(target);
+		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &msr,
+					  offsetof(struct pt_regs, msr),
+					  offsetof(struct pt_regs, msr) +
+					  sizeof(msr));
+	}
+
+	BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
+		     offsetof(struct pt_regs, msr) + sizeof(long));
+
+	if (!ret)
+		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+					  &target->thread.regs->orig_gpr3,
+					  offsetof(struct pt_regs, orig_gpr3),
+					  sizeof(struct pt_regs));
+	if (!ret)
+		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+					       sizeof(struct pt_regs), -1);
+
+	return ret;
+}
+
+static int gpr_set(struct task_struct *target, const struct user_regset *regset,
+		   unsigned int pos, unsigned int count,
+		   const void *kbuf, const void __user *ubuf)
+{
+	unsigned long reg;
+	int ret;
+
+	if (target->thread.regs == NULL)
+		return -EIO;
+
+	CHECK_FULL_REGS(target->thread.regs);
+
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				 target->thread.regs,
+				 0, PT_MSR * sizeof(reg));
+
+	if (!ret && count > 0) {
+		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &reg,
+					 PT_MSR * sizeof(reg),
+					 (PT_MSR + 1) * sizeof(reg));
+		if (!ret)
+			ret = set_user_msr(target, reg);
+	}
+
+	BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
+		     offsetof(struct pt_regs, msr) + sizeof(long));
+
+	if (!ret)
+		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+					 &target->thread.regs->orig_gpr3,
+					 PT_ORIG_R3 * sizeof(reg),
+					 (PT_MAX_PUT_REG + 1) * sizeof(reg));
+
+	if (PT_MAX_PUT_REG + 1 < PT_TRAP && !ret)
+		ret = user_regset_copyin_ignore(
+			&pos, &count, &kbuf, &ubuf,
+			(PT_MAX_PUT_REG + 1) * sizeof(reg),
+			PT_TRAP * sizeof(reg));
+
+	if (!ret && count > 0) {
+		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &reg,
+					 PT_TRAP * sizeof(reg),
+					 (PT_TRAP + 1) * sizeof(reg));
+		if (!ret)
+			ret = set_user_trap(target, reg);
+	}
+
+	if (!ret)
+		ret = user_regset_copyin_ignore(
+			&pos, &count, &kbuf, &ubuf,
+			(PT_TRAP + 1) * sizeof(reg), -1);
+
+	return ret;
+}
 
 static int fpr_get(struct task_struct *target, const struct user_regset *regset,
 		   unsigned int pos, unsigned int count,
-- 
1.5.3.6

^ permalink raw reply related

* [PATCH -mm 19/43] powerpc core dump cleanup
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
In-Reply-To: <20071220115200.C767E26F98A@magilla.localdomain>

Remove some dead code we no longer need now that the
user_regset interfaces are doing all these jobs.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/powerpc/kernel/process.c |   48 -----------------------------------------
 include/asm-powerpc/elf.h     |   46 ---------------------------------------
 2 files changed, 0 insertions(+), 94 deletions(-)

diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index b9d8837..9c2983c 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -104,17 +104,6 @@ void enable_kernel_fp(void)
 }
 EXPORT_SYMBOL(enable_kernel_fp);
 
-int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs)
-{
-	if (!tsk->thread.regs)
-		return 0;
-	flush_fp_to_thread(current);
-
-	memcpy(fpregs, &tsk->thread.fpr[0], sizeof(*fpregs));
-
-	return 1;
-}
-
 #ifdef CONFIG_ALTIVEC
 void enable_kernel_altivec(void)
 {
@@ -148,35 +137,6 @@ void flush_altivec_to_thread(struct task_struct *tsk)
 		preempt_enable();
 	}
 }
-
-int dump_task_altivec(struct task_struct *tsk, elf_vrregset_t *vrregs)
-{
-	/* ELF_NVRREG includes the VSCR and VRSAVE which we need to save
-	 * separately, see below */
-	const int nregs = ELF_NVRREG - 2;
-	elf_vrreg_t *reg;
-	u32 *dest;
-
-	if (tsk == current)
-		flush_altivec_to_thread(tsk);
-
-	reg = (elf_vrreg_t *)vrregs;
-
-	/* copy the 32 vr registers */
-	memcpy(reg, &tsk->thread.vr[0], nregs * sizeof(*reg));
-	reg += nregs;
-
-	/* copy the vscr */
-	memcpy(reg, &tsk->thread.vscr, sizeof(*reg));
-	reg++;
-
-	/* vrsave is stored in the high 32bit slot of the final 128bits */
-	memset(reg, 0, sizeof(*reg));
-	dest = (u32 *)reg;
-	*dest = tsk->thread.vrsave;
-
-	return 1;
-}
 #endif /* CONFIG_ALTIVEC */
 
 #ifdef CONFIG_SPE
@@ -209,14 +169,6 @@ void flush_spe_to_thread(struct task_struct *tsk)
 		preempt_enable();
 	}
 }
-
-int dump_spe(struct pt_regs *regs, elf_vrregset_t *evrregs)
-{
-	flush_spe_to_thread(current);
-	/* We copy u32 evr[32] + u64 acc + u32 spefscr -> 35 */
-	memcpy(evrregs, &current->thread.evr[0], sizeof(u32) * 35);
-	return 1;
-}
 #endif /* CONFIG_SPE */
 
 #ifndef CONFIG_SMP
diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h
index 9080d85..fe309b4 100644
--- a/include/asm-powerpc/elf.h
+++ b/include/asm-powerpc/elf.h
@@ -178,52 +178,6 @@ typedef elf_vrreg_t elf_vrregset_t32[ELF_NVRREG32];
 
 #define ELF_ET_DYN_BASE         (0x20000000)
 
-/*
- * Our registers are always unsigned longs, whether we're a 32 bit
- * process or 64 bit, on either a 64 bit or 32 bit kernel.
- *
- * This macro relies on elf_regs[i] having the right type to truncate to,
- * either u32 or u64.  It defines the body of the elf_core_copy_regs
- * function, either the native one with elf_gregset_t elf_regs or
- * the 32-bit one with elf_gregset_t32 elf_regs.
- */
-#define PPC_ELF_CORE_COPY_REGS(elf_regs, regs) \
-	int i, nregs = min(sizeof(*regs) / sizeof(unsigned long), \
-			   (size_t)ELF_NGREG);			  \
-	for (i = 0; i < nregs; i++) \
-		elf_regs[i] = ((unsigned long *) regs)[i]; \
-	memset(&elf_regs[i], 0, (ELF_NGREG - i) * sizeof(elf_regs[0]))
-
-/* Common routine for both 32-bit and 64-bit native processes */
-static inline void ppc_elf_core_copy_regs(elf_gregset_t elf_regs,
-					  struct pt_regs *regs)
-{
-	PPC_ELF_CORE_COPY_REGS(elf_regs, regs);
-}
-#define ELF_CORE_COPY_REGS(gregs, regs) ppc_elf_core_copy_regs(gregs, regs);
-
-static inline int dump_task_regs(struct task_struct *tsk,
-				 elf_gregset_t *elf_regs)
-{
-	struct pt_regs *regs = tsk->thread.regs;
-	if (regs)
-		ppc_elf_core_copy_regs(*elf_regs, regs);
-
-	return 1;
-}
-#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs)
-
-extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *); 
-#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
-
-typedef elf_vrregset_t elf_fpxregset_t;
-
-#ifdef CONFIG_ALTIVEC
-extern int dump_task_altivec(struct task_struct *, elf_vrregset_t *vrregs);
-#define ELF_CORE_COPY_XFPREGS(tsk, regs) dump_task_altivec(tsk, regs)
-#define ELF_CORE_XFPREG_TYPE NT_PPC_VMX
-#endif
-
 #endif /* __KERNEL__ */
 
 /* ELF_HWCAP yields a mask that user programs can use to figure out what
-- 
1.5.3.6

^ permalink raw reply related

* [PATCH -mm 17/43] powerpc CORE_DUMP_USE_REGSET
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
In-Reply-To: <20071220115200.C767E26F98A@magilla.localdomain>

This switches powerpc to using the user_regset-based code for ELF core
dumps.  The core dumps come out exactly the same either way, except that
the NT_PPC_VMX note is now omitted for any thread that never touched its
Altivec registers (thread_struct.vr_used).

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 include/asm-powerpc/elf.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h
index 6bd07ef..fd9bf8b 100644
--- a/include/asm-powerpc/elf.h
+++ b/include/asm-powerpc/elf.h
@@ -167,6 +167,7 @@ typedef elf_vrreg_t elf_vrregset_t32[ELF_NVRREG32];
 #define elf_check_arch(x) ((x)->e_machine == ELF_ARCH)
 
 #define USE_ELF_CORE_DUMP
+#define CORE_DUMP_USE_REGSET
 #define ELF_EXEC_PAGESIZE	PAGE_SIZE
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
-- 
1.5.3.6

^ permalink raw reply related

* [PATCH -mm 20/43] powerpc SPE core dump
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
In-Reply-To: <20071220115200.C767E26F98A@magilla.localdomain>

This makes the SPE register data appear in ELF core dumps,
using the new n_type value NT_PPC_SPE (0x101).  This new
note type is not used by any consumers of core files yet,
but support can be added.  I don't even have any hardware
with SPE capabilities, so I've never seen such a note.
But this demonstrates how simple it is to export register
information in core dumps when the user_regset style is
used for the low-level code.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/powerpc/kernel/ptrace.c |    2 +-
 include/linux/elf.h          |    1 +
 2 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index e961e10..0231e7d 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -642,7 +642,7 @@ static const struct user_regset compat_regsets[] = {
 #endif
 #ifdef CONFIG_SPE
 	[REGSET_SPE] = {
-		.n = 35,
+		.core_note_type = NT_PPC_SPE, .n = 35,
 		.size = sizeof(u32), .align = sizeof(u32),
 		.active = evr_active, .get = evr_get, .set = evr_set
 	},
diff --git a/include/linux/elf.h b/include/linux/elf.h
index 576e83b..ba268b2 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -355,6 +355,7 @@ typedef struct elf64_shdr {
 #define NT_AUXV		6
 #define NT_PRXFPREG     0x46e62b7f      /* copied from gdb5.1/include/elf/common.h */
 #define NT_PPC_VMX	0x100		/* PowerPC Altivec/VMX registers */
+#define NT_PPC_SPE	0x101		/* PowerPC SPE/EVR registers */
 
 
 /* Note header in a PT_NOTE section */
-- 
1.5.3.6

^ permalink raw reply related

* [PATCH -mm 22/43] powerpc ptrace generic peekdata/pokedata
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
In-Reply-To: <20071220115200.C767E26F98A@magilla.localdomain>

Now that ptrace_request handles these, we can drop some more boilerplate.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/powerpc/kernel/ptrace.c |   12 ------------
 1 files changed, 0 insertions(+), 12 deletions(-)

diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index eb27bd9..3e228d6 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -697,12 +697,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 	int ret = -EPERM;
 
 	switch (request) {
-	/* when I and D space are separate, these will need to be fixed. */
-	case PTRACE_PEEKTEXT: /* read word at location addr. */
-	case PTRACE_PEEKDATA:
-		ret = generic_ptrace_peekdata(child, addr, data);
-		break;
-
 	/* read the word at location addr in the USER area. */
 	case PTRACE_PEEKUSR: {
 		unsigned long index, tmp;
@@ -730,12 +724,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 		break;
 	}
 
-	/* If I and D space are separate, this will have to be fixed. */
-	case PTRACE_POKETEXT: /* write the word at location addr. */
-	case PTRACE_POKEDATA:
-		ret = generic_ptrace_pokedata(child, addr, data);
-		break;
-
 	/* write the word at location addr in the USER area */
 	case PTRACE_POKEUSR: {
 		unsigned long index;
-- 
1.5.3.6

^ permalink raw reply related

* [PATCH -mm 21/43] powerpc ptrace user_regset
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
In-Reply-To: <20071220115200.C767E26F98A@magilla.localdomain>

This replaces all the code for powerpc PTRACE_*REGS* requests with
simple calls to copy_regset_from_user and copy_regset_to_user.  All
the ptrace formats are either the whole corresponding user_regset
format (core dump format) or a leading subset of it, so we can get
rid of all the remaining embedded knowledge of both those layouts
and of the internal data structures they correspond to.  Only the
user_reget accessors need to implement that.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/powerpc/kernel/ptrace.c |  234 +++++++++++-------------------------------
 1 files changed, 59 insertions(+), 175 deletions(-)

diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 0231e7d..eb27bd9 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -237,24 +237,6 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
 				  &target->thread.fpr, 0, -1);
 }
 
-static int get_fpregs(void __user *data, struct task_struct *task,
-		      int has_fpscr)
-{
-	unsigned int count = has_fpscr ? 33 : 32;
-	if (!access_ok(VERIFY_WRITE, data, count * sizeof(double)))
-		return -EFAULT;
-	return fpr_get(task, NULL, 0, count * sizeof(double), NULL, data);
-}
-
-static int set_fpregs(void __user *data, struct task_struct *task,
-		      int has_fpscr)
-{
-	unsigned int count = has_fpscr ? 33 : 32;
-	if (!access_ok(VERIFY_READ, data, count * sizeof(double)))
-		return -EFAULT;
-	return fpr_set(task, NULL, 0, count * sizeof(double), NULL, data);
-}
-
 
 #ifdef CONFIG_ALTIVEC
 /*
@@ -339,31 +321,6 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
 
 	return ret;
 }
-
-/*
- * Get contents of AltiVec register state in task TASK
- */
-static int get_vrregs(unsigned long __user *data, struct task_struct *task)
-{
-	if (!access_ok(VERIFY_WRITE, data,
-		       33 * sizeof(vector128) + sizeof(u32)))
-		return -EFAULT;
-
-	return vr_get(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32),
-		      NULL, data);
-}
-
-/*
- * Write contents of AltiVec register state into task TASK.
- */
-static int set_vrregs(struct task_struct *task, unsigned long __user *data)
-{
-	if (!access_ok(VERIFY_READ, data, 33 * sizeof(vector128) + sizeof(u32)))
-		return -EFAULT;
-
-	return vr_set(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32),
-		      NULL, data);
-}
 #endif /* CONFIG_ALTIVEC */
 
 #ifdef CONFIG_SPE
@@ -430,28 +387,6 @@ static int evr_set(struct task_struct *target, const struct user_regset *regset,
 
 	return ret;
 }
-
-/*
- * Get contents of SPE register state in task TASK.
- */
-static int get_evrregs(unsigned long __user *data, struct task_struct *task)
-{
-	if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(u32)))
-		return -EFAULT;
-
-	return evr_get(task, NULL, 0, 35 * sizeof(u32), NULL, data);
-}
-
-/*
- * Write contents of SPE register state into task TASK.
- */
-static int set_evrregs(struct task_struct *task, unsigned long *data)
-{
-	if (!access_ok(VERIFY_READ, data, 35 * sizeof(u32)))
-		return -EFAULT;
-
-	return evr_set(task, NULL, 0, 35 * sizeof(u32), NULL, data);
-}
 #endif /* CONFIG_SPE */
 
 
@@ -732,55 +667,29 @@ void ptrace_disable(struct task_struct *child)
 static long arch_ptrace_old(struct task_struct *child, long request, long addr,
 			    long data)
 {
-	int ret = -EPERM;
-
-	switch(request) {
-	case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
-		int i;
-		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
-		unsigned long __user *tmp = (unsigned long __user *)addr;
-
-		CHECK_FULL_REGS(child->thread.regs);
-		for (i = 0; i < 32; i++) {
-			ret = put_user(*reg, tmp);
-			if (ret)
-				break;
-			reg++;
-			tmp++;
-		}
-		break;
-	}
-
-	case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
-		int i;
-		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
-		unsigned long __user *tmp = (unsigned long __user *)addr;
-
-		CHECK_FULL_REGS(child->thread.regs);
-		for (i = 0; i < 32; i++) {
-			ret = get_user(*reg, tmp);
-			if (ret)
-				break;
-			reg++;
-			tmp++;
-		}
-		break;
-	}
-
-	case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
-		flush_fp_to_thread(child);
-		ret = get_fpregs((void __user *)addr, child, 0);
-		break;
-	}
-
-	case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
-		flush_fp_to_thread(child);
-		ret = set_fpregs((void __user *)addr, child, 0);
-		break;
+	switch (request) {
+	case PPC_PTRACE_GETREGS:	/* Get GPRs 0 - 31. */
+		return copy_regset_to_user(child, &user_ppc_native_view,
+					   REGSET_GPR, 0, 32 * sizeof(long),
+					   (void __user *) data);
+
+	case PPC_PTRACE_SETREGS:	/* Set GPRs 0 - 31. */
+		return copy_regset_from_user(child, &user_ppc_native_view,
+					     REGSET_GPR, 0, 32 * sizeof(long),
+					     (const void __user *) data);
+
+	case PPC_PTRACE_GETFPREGS:	/* Get FPRs 0 - 31. */
+		return copy_regset_to_user(child, &user_ppc_native_view,
+					   REGSET_FPR, 0, 32 * sizeof(double),
+					   (void __user *) data);
+
+	case PPC_PTRACE_SETFPREGS:	/* Set FPRs 0 - 31. */
+		return copy_regset_from_user(child, &user_ppc_native_view,
+					     REGSET_FPR, 0, 32 * sizeof(double),
+					     (const void __user *) data);
 	}
 
-	}
-	return ret;
+	return -EPERM;
 }
 
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
@@ -871,85 +780,60 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 #ifdef CONFIG_PPC64
 	case PTRACE_GETREGS64:
 #endif
-	case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
-		int ui;
-	  	if (!access_ok(VERIFY_WRITE, (void __user *)data,
-			       sizeof(struct pt_regs))) {
-			ret = -EIO;
-			break;
-		}
-		CHECK_FULL_REGS(child->thread.regs);
-		ret = 0;
-		for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
-			ret |= __put_user(ptrace_get_reg(child, ui),
-					  (unsigned long __user *) data);
-			data += sizeof(long);
-		}
-		break;
-	}
+	case PTRACE_GETREGS:	/* Get all pt_regs from the child. */
+		return copy_regset_to_user(child, &user_ppc_native_view,
+					   REGSET_GPR,
+					   0, sizeof(struct pt_regs),
+					   (void __user *) data);
 
 #ifdef CONFIG_PPC64
 	case PTRACE_SETREGS64:
 #endif
-	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
-		unsigned long tmp;
-		int ui;
-	  	if (!access_ok(VERIFY_READ, (void __user *)data,
-			       sizeof(struct pt_regs))) {
-			ret = -EIO;
-			break;
-		}
-		CHECK_FULL_REGS(child->thread.regs);
-		ret = 0;
-		for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
-			ret = __get_user(tmp, (unsigned long __user *) data);
-			if (ret)
-				break;
-			ptrace_put_reg(child, ui, tmp);
-			data += sizeof(long);
-		}
-		break;
-	}
-
-	case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */
-		flush_fp_to_thread(child);
-		ret = get_fpregs((void __user *)data, child, 1);
-		break;
-	}
-
-	case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */
-		flush_fp_to_thread(child);
-		ret = set_fpregs((void __user *)data, child, 1);
-		break;
-	}
+	case PTRACE_SETREGS:	/* Set all gp regs in the child. */
+		return copy_regset_from_user(child, &user_ppc_native_view,
+					     REGSET_GPR,
+					     0, sizeof(struct pt_regs),
+					     (const void __user *) data);
+
+	case PTRACE_GETFPREGS: /* Get the child FPU state (FPR0...31 + FPSCR) */
+		return copy_regset_to_user(child, &user_ppc_native_view,
+					   REGSET_FPR,
+					   0, sizeof(elf_fpregset_t),
+					   (void __user *) data);
+
+	case PTRACE_SETFPREGS: /* Set the child FPU state (FPR0...31 + FPSCR) */
+		return copy_regset_from_user(child, &user_ppc_native_view,
+					     REGSET_FPR,
+					     0, sizeof(elf_fpregset_t),
+					     (const void __user *) data);
 
 #ifdef CONFIG_ALTIVEC
 	case PTRACE_GETVRREGS:
-		/* Get the child altivec register state. */
-		flush_altivec_to_thread(child);
-		ret = get_vrregs((unsigned long __user *)data, child);
-		break;
+		return copy_regset_to_user(child, &user_ppc_native_view,
+					   REGSET_VMX,
+					   0, (33 * sizeof(vector128) +
+					       sizeof(u32)),
+					   (void __user *) data);
 
 	case PTRACE_SETVRREGS:
-		/* Set the child altivec register state. */
-		flush_altivec_to_thread(child);
-		ret = set_vrregs(child, (unsigned long __user *)data);
-		break;
+		return copy_regset_from_user(child, &user_ppc_native_view,
+					     REGSET_VMX,
+					     0, (33 * sizeof(vector128) +
+						 sizeof(u32)),
+					     (const void __user *) data);
 #endif
 #ifdef CONFIG_SPE
 	case PTRACE_GETEVRREGS:
 		/* Get the child spe register state. */
-		flush_spe_to_thread(child);
-		ret = get_evrregs((unsigned long __user *)data, child);
-		break;
+		return copy_regset_to_user(child, &user_ppc_native_view,
+					   REGSET_SPE, 0, 35 * sizeof(u32),
+					   (void __user *) data);
 
 	case PTRACE_SETEVRREGS:
 		/* Set the child spe register state. */
-		/* this is to clear the MSR_SPE bit to force a reload
-		 * of register state from memory */
-		flush_spe_to_thread(child);
-		ret = set_evrregs(child, (unsigned long __user *)data);
-		break;
+		return copy_regset_from_user(child, &user_ppc_native_view,
+					     REGSET_SPE, 0, 35 * sizeof(u32),
+					     (const void __user *) data);
 #endif
 
 	/* Old reverse args ptrace callss */
-- 
1.5.3.6

^ permalink raw reply related

* [PATCH -mm 24/43] powerpc compat_sys_ptrace
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
In-Reply-To: <20071220115200.C767E26F98A@magilla.localdomain>

This replaces powerpc's compat_sys_ptrace with a compat_arch_ptrace and
enables the new generic definition of compat_sys_ptrace instead.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/powerpc/kernel/ptrace32.c |   33 +++++----------------------------
 include/asm-powerpc/ptrace.h   |    2 ++
 2 files changed, 7 insertions(+), 28 deletions(-)

diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 6612304..0f6eea0 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -85,33 +85,13 @@ static long compat_ptrace_old(struct task_struct *child, long request,
 	return ret;
 }
 
-long compat_sys_ptrace(int request, int pid, unsigned long addr,
-		       unsigned long data)
+long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
+			compat_ulong_t caddr, compat_ulong_t cdata)
 {
-	struct task_struct *child;
+	unsigned long addr = caddr;
+	unsigned long data = cdata;
 	int ret;
 
-	lock_kernel();
-	if (request == PTRACE_TRACEME) {
-		ret = ptrace_traceme();
-		goto out;
-	}
-
-	child = ptrace_get_task_struct(pid);
-	if (IS_ERR(child)) {
-		ret = PTR_ERR(child);
-		goto out;
-	}
-
-	if (request == PTRACE_ATTACH) {
-		ret = ptrace_attach(child);
-		goto out_tsk;
-	}
-
-	ret = ptrace_check_attach(child, request == PTRACE_KILL);
-	if (ret < 0)
-		goto out_tsk;
-
 	switch (request) {
 	/*
 	 * Read 4 bytes of the other process' storage
@@ -375,9 +355,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
 		ret = compat_ptrace_request(child, request, addr, data);
 		break;
 	}
-out_tsk:
-	put_task_struct(child);
-out:
-	unlock_kernel();
+
 	return ret;
 }
diff --git a/include/asm-powerpc/ptrace.h b/include/asm-powerpc/ptrace.h
index 3063363..a8cb00c 100644
--- a/include/asm-powerpc/ptrace.h
+++ b/include/asm-powerpc/ptrace.h
@@ -55,6 +55,8 @@ struct pt_regs {
 
 #ifdef __powerpc64__
 
+#define __ARCH_WANT_COMPAT_SYS_PTRACE
+
 #define STACK_FRAME_OVERHEAD	112	/* size of minimum stack frame */
 
 /* Size of dummy stack frame allocated when calling signal handler. */
-- 
1.5.3.6

^ permalink raw reply related


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