* 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: [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
* [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 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
* 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
* 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: 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
* [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
* [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 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 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 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 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
* 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] [POWERPC] Fix PCI IRQ fallback code to not map IRQ 0
From: Benjamin Herrenschmidt @ 2007-12-20 4:10 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
The PCI IRQ code has a fallback when the device-tree parsing fails, that
tries to map the interrupt indicated by PCI_INTERRUPT_LINE if the firmware
set something in there. This is a bit fragile but has proven useful in some
cases so far. However, it's causing us to incorrectly try to map interrupt 0
on various setups, so let's prevent that case, as none of the cases where
the fallback is legit should have an IRQ 0.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/pci-common.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
--- linux-merge.orig/arch/powerpc/kernel/pci-common.c 2007-12-14 15:49:36.000000000 +1100
+++ linux-merge/arch/powerpc/kernel/pci-common.c 2007-12-14 15:49:36.000000000 +1100
@@ -225,10 +225,11 @@ int pci_read_irq_line(struct pci_dev *pc
if (pin == 0)
return -1;
if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &line) ||
- line == 0xff) {
+ line == 0xff || line == 0) {
return -1;
}
- DBG(" -> no map ! Using irq line %d from PCI config\n", line);
+ DBG(" -> no map ! Using line %d (pin %d) from PCI config\n",
+ line, pin);
virq = irq_create_mapping(NULL, line);
if (virq != NO_IRQ)
^ permalink raw reply
* [PATCH] [POWERPC] Fix for via-pmu based backlight control
From: Benjamin Herrenschmidt @ 2007-12-20 4:00 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
This patch fixes a few issues with via-pmu based backlight control.
First, it fixes a sign problem with the setup of the backlight
curve since the values there -can- (and will) go negative.
Then, it reworks the interaction between this and the via-pmu sleep
code to properly restore backlight on wakeup from sleep.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
drivers/macintosh/via-pmu-backlight.c | 48 ++++++++++++++++++++--------------
drivers/macintosh/via-pmu.c | 26 +++++++-----------
include/linux/pmu.h | 2 +
3 files changed, 42 insertions(+), 34 deletions(-)
--- linux-merge.orig/drivers/macintosh/via-pmu-backlight.c 2007-12-20 11:54:57.000000000 +1100
+++ linux-merge/drivers/macintosh/via-pmu-backlight.c 2007-12-20 12:49:04.000000000 +1100
@@ -22,7 +22,7 @@ static u8 bl_curve[FB_BACKLIGHT_LEVELS];
static void pmu_backlight_init_curve(u8 off, u8 min, u8 max)
{
- unsigned int i, flat, count, range = (max - min);
+ int i, flat, count, range = (max - min);
bl_curve[0] = off;
@@ -68,17 +68,11 @@ static int pmu_backlight_get_level_brigh
return pmulevel;
}
-static int pmu_backlight_update_status(struct backlight_device *bd)
+static int __pmu_backlight_update_status(struct backlight_device *bd)
{
struct adb_request req;
- unsigned long flags;
int level = bd->props.brightness;
- spin_lock_irqsave(&pmu_backlight_lock, flags);
-
- /* Don't update brightness when sleeping */
- if (sleeping)
- goto out;
if (bd->props.power != FB_BLANK_UNBLANK ||
bd->props.fb_blank != FB_BLANK_UNBLANK)
@@ -99,12 +93,23 @@ static int pmu_backlight_update_status(s
pmu_wait_complete(&req);
}
-out:
- spin_unlock_irqrestore(&pmu_backlight_lock, flags);
-
return 0;
}
+static int pmu_backlight_update_status(struct backlight_device *bd)
+{
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&pmu_backlight_lock, flags);
+ /* Don't update brightness when sleeping */
+ if (!sleeping)
+ rc = __pmu_backlight_update_status(bd);
+ spin_unlock_irqrestore(&pmu_backlight_lock, flags);
+ return rc;
+}
+
+
static int pmu_backlight_get_brightness(struct backlight_device *bd)
{
return bd->props.brightness;
@@ -123,6 +128,16 @@ void pmu_backlight_set_sleep(int sleep)
spin_lock_irqsave(&pmu_backlight_lock, flags);
sleeping = sleep;
+ if (pmac_backlight) {
+ if (sleep) {
+ struct adb_request req;
+
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_BACKLIGHT | PMU_POW_OFF);
+ pmu_wait_complete(&req);
+ } else
+ __pmu_backlight_update_status(pmac_backlight);
+ }
spin_unlock_irqrestore(&pmu_backlight_lock, flags);
}
#endif /* CONFIG_PM */
@@ -148,8 +163,8 @@ void __init pmu_backlight_init()
bd = backlight_device_register(name, NULL, NULL, &pmu_backlight_data);
if (IS_ERR(bd)) {
- printk("pmubl: Backlight registration failed\n");
- goto error;
+ printk(KERN_ERR "PMU Backlight registration failed\n");
+ return;
}
bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
pmu_backlight_init_curve(0x7F, 0x46, 0x0E);
@@ -171,10 +186,5 @@ void __init pmu_backlight_init()
bd->props.power = FB_BLANK_UNBLANK;
backlight_update_status(bd);
- printk("pmubl: Backlight initialized (%s)\n", name);
-
- return;
-
-error:
- return;
+ printk(KERN_INFO "PMU Backlight initialized (%s)\n", name);
}
Index: linux-merge/drivers/macintosh/via-pmu.c
===================================================================
--- linux-merge.orig/drivers/macintosh/via-pmu.c 2007-12-20 12:11:12.000000000 +1100
+++ linux-merge/drivers/macintosh/via-pmu.c 2007-12-20 12:12:46.000000000 +1100
@@ -1758,8 +1758,6 @@ restore_via_state(void)
out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
}
-extern void pmu_backlight_set_sleep(int sleep);
-
#define GRACKLE_PM (1<<7)
#define GRACKLE_DOZE (1<<5)
#define GRACKLE_NAP (1<<4)
@@ -2176,11 +2174,6 @@ pmu_release(struct inode *inode, struct
*/
void arch_suspend_disable_irqs(void)
{
-#ifdef CONFIG_PMAC_BACKLIGHT
- /* Tell backlight code not to muck around with the chip anymore */
- pmu_backlight_set_sleep(1);
-#endif
-
/* Call platform functions marked "on sleep" */
pmac_pfunc_i2c_suspend();
pmac_pfunc_base_suspend();
@@ -2236,11 +2229,6 @@ static int powerbook_sleep(suspend_state
mdelay(100);
-#ifdef CONFIG_PMAC_BACKLIGHT
- /* Tell backlight code it can use the chip again */
- pmu_backlight_set_sleep(0);
-#endif
-
return 0;
}
@@ -2493,10 +2481,15 @@ static int pmu_sys_suspend(struct sys_de
if (state.event != PM_EVENT_SUSPEND || pmu_sys_suspended)
return 0;
- /* Suspend PMU event interrupts */
+ /* Suspend PMU event interrupts */\
pmu_suspend();
-
pmu_sys_suspended = 1;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ /* Tell backlight code not to muck around with the chip anymore */
+ pmu_backlight_set_sleep(1);
+#endif
+
return 0;
}
@@ -2511,9 +2504,12 @@ static int pmu_sys_resume(struct sys_dev
pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
pmu_wait_complete(&req);
+#ifdef CONFIG_PMAC_BACKLIGHT
+ /* Tell backlight code it can use the chip again */
+ pmu_backlight_set_sleep(0);
+#endif
/* Resume PMU event interrupts */
pmu_resume();
-
pmu_sys_suspended = 0;
return 0;
Index: linux-merge/include/linux/pmu.h
===================================================================
--- linux-merge.orig/include/linux/pmu.h 2007-12-20 12:11:33.000000000 +1100
+++ linux-merge/include/linux/pmu.h 2007-12-20 12:11:36.000000000 +1100
@@ -159,6 +159,8 @@ extern void pmu_unlock(void);
extern int pmu_present(void);
extern int pmu_get_model(void);
+extern void pmu_backlight_set_sleep(int sleep);
+
#define PMU_MAX_BATTERIES 2
/* values for pmu_power_flags */
^ permalink raw reply
* Re: [PATCH] ASoC drivers for the Freescale MPC8610 SoC
From: Olof Johansson @ 2007-12-20 4:06 UTC (permalink / raw)
To: Timur Tabi; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <11981089894052-git-send-email-timur@freescale.com>
Hi,
This is a fairly substantial driver to get through, but here are some
initial comments on some of the simpler stuff:
On Wed, Dec 19, 2007 at 06:03:09PM -0600, Timur Tabi wrote:
> This patch adds ALSA SoC device drivers for the Freescale MPC8610 SoC
> and the MPC8610-HPCD reference board.
[...]
> diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
> index 6390895..6e1bde3 100644
> --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
> +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
> @@ -34,9 +34,27 @@
>
> #include <asm/mpic.h>
>
> +#include <asm/of_platform.h>
> #include <sysdev/fsl_pci.h>
> #include <sysdev/fsl_soc.h>
>
> +static struct of_device_id mpc8610_ids[] = {
> + { .type = "soc", },
> + {}
Please scan based on compatible instead of device_type.
> diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
> new file mode 100644
> index 0000000..4a5bbd2
> --- /dev/null
> +++ b/sound/soc/fsl/Kconfig
> @@ -0,0 +1,21 @@
> +menu "ALSA SoC audio for Freescale SOCs"
> +
> +config SND_SOC_MPC8610
> + bool "ALSA SoC support for the MPC8610 SOC"
> + depends on SND_SOC #&& MPC8610_HPCD
> + default y #if MPC8610
> + help
> + Say Y if you want to add support for codecs attached to the SSI
> + device on an MPC8610.
Don't default configs to 'y'. Also, what's with the commented-out
dependencies and if?
> +config SND_SOC_MPC8610_HPCD
> + # ALSA SoC support for Freescale MPC8610HPCD
> + bool "ALSA SoC support for the Freescale MPC8610 HPCD board"
> + depends on SND_SOC_MPC8610
> + select SND_SOC_CS4270
> + select SND_SOC_CS4270_VD33_ERRATA
> + default y #if MPC8610_HPCD
> + help
> + Say Y if you want to enable audio on the Freescale MPC8610 HPCD.
Same here w.r.t. defaults and dependencies.
> diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
> new file mode 100644
> index 0000000..6b86be0
> --- /dev/null
> +++ b/sound/soc/fsl/fsl_dma.c
> @@ -0,0 +1,819 @@
> +/*
> + * Freescale DMA ALSA SoC PCM driver
> + *
> + * Author: Timur Tabi <timur@freescale.com>
> + *
> + * Copyright 2007 Freescale Semiconductor, Inc. This file is licensed under
> + * the terms of the GNU General Public License version 2. This program
> + * is licensed "as is" without any warranty of any kind, whether express
> + * or implied.
> + *
> + * This driver implements ASoC support for the Elo DMA controller, which is
> + * the DMA controller on Freescale 83xx, 85xx, and 86xx SOCs. In ALSA terms,
> + * the PCM driver is what handles the DMA buffer.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/platform_device.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/interrupt.h>
> +#include <linux/delay.h>
> +
> +#include <sound/driver.h>
> +#include <sound/core.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/soc.h>
> +
> +#include <asm/io.h>
> +
> +#include "fsl_dma.h"
> +
> +/*
> + * The formats that the DMA controller supports, which is anything
> + * that is 8, 16, or 32 bits.
> + */
> +#define FSLDMA_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
> + SNDRV_PCM_FMTBIT_U8 | \
> + SNDRV_PCM_FMTBIT_S16_LE | \
> + SNDRV_PCM_FMTBIT_S16_BE | \
> + SNDRV_PCM_FMTBIT_U16_LE | \
> + SNDRV_PCM_FMTBIT_U16_BE | \
> + SNDRV_PCM_FMTBIT_S24_LE | \
> + SNDRV_PCM_FMTBIT_S24_BE | \
> + SNDRV_PCM_FMTBIT_U24_LE | \
> + SNDRV_PCM_FMTBIT_U24_BE | \
> + SNDRV_PCM_FMTBIT_S32_LE | \
> + SNDRV_PCM_FMTBIT_S32_BE | \
> + SNDRV_PCM_FMTBIT_U32_LE | \
> + SNDRV_PCM_FMTBIT_U32_BE)
> +
> +#define FSLDMA_PCM_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
> + SNDRV_PCM_RATE_CONTINUOUS)
> +
> +/* DMA global data. This structure is used by fsl_dma_open() to determine
> + * which DMA channels to assign to a substream. Unfortunately, ASoC V1 does
> + * not allow the machine driver to provide this information to the PCM
> + * driver in advance, and there's no way to differentiate between the two
> + * DMA controllers. So for now, this driver only supports one SSI device
> + * using two DMA channels. We cannot support multiple DMA devices.
> + *
> + * ssi_stx_phys: bus address of SSI STX register
> + * ssi_srx_phys: bus address of SSI SRX register
> + * dma_channel: pointer to the DMA channel's registers
> + * irq: IRQ for this DMA channel
> + * assigned: set to 1 if that DMA channel is assigned to a substream
> + */
This goes for the whole patch: You've got good documentation, but it's
not in docbook format. Please reformat it since it should be a pretty
simple thing to do.
> +/*
> + * Initialize this PCM driver.
> + *
> + * This function is called when the codec driver calls snd_soc_new_pcms(),
> + * once for each .dai_link in the machine driver's snd_soc_machine
> + * structure.
> + */
> +static int fsl_dma_new(struct snd_card *card, struct snd_soc_codec_dai *dai,
> + struct snd_pcm *pcm)
> +{
> + static u64 fsl_dma_dmamask = 0xffffffff;
> + int ret;
> +
> + if (!card->dev->dma_mask)
> + card->dev->dma_mask = &fsl_dma_dmamask;
I haven't read how your channel allocation works, but providing a
pointer to a local static variable is a bit fishy no matter what.
> + /* Find the DMA channels to use. For now, we always use the first DMA
> + controller. */
> + for_each_compatible_node(dma_np, NULL, "fsl,mpc8610-dma") {
> + iprop = of_get_property(dma_np, "cell-index", NULL);
> + if (iprop && (*iprop == 0)) {
> + of_node_put(dma_np);
> + break;
> + }
> + }
Do you ever anticipate having other dma users on the system, such as
memcpy offload? You'll probably need allocation support for channels
when that day comes (I ended up writing a simple library for dma channel
management for that very reason on my platform).
-Olof
^ permalink raw reply
* [PATCH 19/19] [POWERPC] Disable PCI IO/Mem on a device when resources can't be allocated
From: Benjamin Herrenschmidt @ 2007-12-20 3:55 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <1198122881.874131.56762399546.qpush@grosgo>
This patch changes the PowerPC PCI code to disable IO and/or Memory
decoding on a PCI device when a resource of that type failed to be
allocated. This is done to avoid having unallocated dangling BARs enabled
that might try to decode on top of other devices.
If a proper resource is assigned later on, then pci_enable_device()
will take care of re-enabling decoding.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/pci-common.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
--- linux-merge.orig/arch/powerpc/kernel/pci-common.c 2007-12-20 14:51:19.000000000 +1100
+++ linux-merge/arch/powerpc/kernel/pci-common.c 2007-12-20 14:51:20.000000000 +1100
@@ -1034,7 +1034,7 @@ clear_resource:
}
}
-static inline void __devinit alloc_resource(struct pci_dev *dev, int idx)
+static inline int __devinit alloc_resource(struct pci_dev *dev, int idx)
{
struct resource *pr, *r = &dev->resource[idx];
@@ -1058,7 +1058,10 @@ static inline void __devinit alloc_resou
r->flags |= IORESOURCE_UNSET;
r->end -= r->start;
r->start = 0;
+
+ return -EBUSY;
}
+ return 0;
}
static void __init pcibios_allocate_resources(int pass)
@@ -1080,8 +1083,12 @@ static void __init pcibios_allocate_reso
disabled = !(command & PCI_COMMAND_IO);
else
disabled = !(command & PCI_COMMAND_MEMORY);
- if (pass == disabled)
- alloc_resource(dev, idx);
+ if (pass == disabled && alloc_resource(dev, idx)) {
+ command &= ~(r->flags & (IORESOURCE_IO |
+ IORESOURCE_MEM));
+ pci_write_config_word(dev,
+ PCI_COMMAND, command);
+ }
}
if (pass)
continue;
^ permalink raw reply
* [PATCH 18/19] [POWERPC] Fixup skipping of PowerMac PCI<->PCI bridge "closed" resources
From: Benjamin Herrenschmidt @ 2007-12-20 3:55 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <1198122881.874131.56762399546.qpush@grosgo>
Apple firmware has a strange way to "close" bridge resources by setting
them to some bogus values that overlap RAM (strangely, I haven't seen it
conflicting with DMA so far...). This explicitely closes them to avoid
problems. Previously, they would be closed as a consequence of failing
to be allocated, but this makes it more explicit, and thus the log
message is more explicit too.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/pci-common.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
--- linux-merge.orig/arch/powerpc/kernel/pci-common.c 2007-12-19 15:47:23.000000000 +1100
+++ linux-merge/arch/powerpc/kernel/pci-common.c 2007-12-19 15:58:59.000000000 +1100
@@ -776,6 +776,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI
static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
{
+ struct pci_controller *hose = pci_bus_to_host(bus);
struct pci_dev *dev = bus->self;
pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB");
@@ -793,6 +794,27 @@ static void __devinit __pcibios_fixup_bu
if (!res->flags || bus->self->transparent)
continue;
+ /* On PowerMac, Apple leaves bridge windows open over
+ * an inaccessible region of memory space (0...fffff)
+ * which is somewhat bogus, but that's what they think
+ * means disabled...
+ *
+ * We clear those to force them to be reallocated later
+ *
+ * We detect such regions by the fact that the base is
+ * equal to the pci_mem_offset of the host bridge and
+ * their size is smaller than 1M.
+ */
+ if (res->start == hose->pci_mem_offset &&
+ res->end < 0x100000) {
+ printk(KERN_INFO
+ "PCI: Closing bogus Apple Firmware"
+ " region %d on bus 0x%02x\n",
+ i, bus->number);
+ res->flags = 0;
+ continue;
+ }
+
pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
pci_name(dev), i,
(unsigned long long)res->start,\
^ permalink raw reply
* [PATCH 17/19] [POWERPC] Improve resource setup of PowerMac G5 HT bridge
From: Benjamin Herrenschmidt @ 2007-12-20 3:55 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <1198122881.874131.56762399546.qpush@grosgo>
The device node for the HT bridge on G5s doesn't contain useful ranges.
We used to give it a bunch of the known PCI space and then punch a "hole"
in it based on where the AGP or PCIe region was. This reworks it to
use the actual register in the bridge that controls the decoding instead.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/platforms/powermac/pci.c | 146 +++++++++++++++-------------------
1 file changed, 66 insertions(+), 80 deletions(-)
--- linux-merge.orig/arch/powerpc/platforms/powermac/pci.c 2007-12-19 15:53:00.000000000 +1100
+++ linux-merge/arch/powerpc/platforms/powermac/pci.c 2007-12-19 15:55:29.000000000 +1100
@@ -40,8 +40,6 @@
static int has_uninorth;
#ifdef CONFIG_PPC64
static struct pci_controller *u3_agp;
-static struct pci_controller *u4_pcie;
-static struct pci_controller *u3_ht;
#else
static int has_second_ohare;
#endif /* CONFIG_PPC64 */
@@ -779,16 +777,50 @@ static void __init setup_u4_pcie(struct
*/
hose->first_busno = 0x00;
hose->last_busno = 0xff;
- u4_pcie = hose;
+}
+
+static void __init parse_region_decode(struct pci_controller *hose,
+ u32 decode)
+{
+ unsigned long base, end, next = -1;
+ int i, cur = -1;
+
+ /* Iterate through all bits. We ignore the last bit as this region is
+ * reserved for the ROM among other niceties
+ */
+ for (i = 0; i < 31; i++) {
+ if ((decode & (0x80000000 >> i)) == 0)
+ continue;
+ if (i < 16) {
+ base = 0xf0000000 | (((u32)i) << 24);
+ end = base + 0x00ffffff;
+ } else {
+ base = ((u32)i-16) << 28;
+ end = base + 0x0fffffff;
+ }
+ if (base != next) {
+ if (++cur >= 3) {
+ printk(KERN_WARNING "PCI: Too many ranges !\n");
+ break;
+ }
+ hose->mem_resources[cur].flags = IORESOURCE_MEM;
+ hose->mem_resources[cur].name = hose->dn->full_name;
+ hose->mem_resources[cur].start = base;
+ hose->mem_resources[cur].end = end;
+ DBG(" %d: 0x%08lx-0x%08lx\n", cur, base, end);
+ } else {
+ DBG(" : -0x%08lx\n", end);
+ hose->mem_resources[cur].end = end;
+ }
+ next = end + 1;
+ }
}
static void __init setup_u3_ht(struct pci_controller* hose)
{
struct device_node *np = hose->dn;
- struct pci_controller *other = NULL;
struct resource cfg_res, self_res;
- int i, cur;
-
+ u32 decode;
hose->ops = &u3_ht_pci_ops;
@@ -808,12 +840,9 @@ static void __init setup_u3_ht(struct pc
self_res.end - self_res.start + 1);
/*
- * /ht node doesn't expose a "ranges" property, so we "remove"
- * regions that have been allocated to AGP. So far, this version of
- * the code doesn't assign any of the 0xfxxxxxxx "fine" memory regions
- * to /ht. We need to fix that sooner or later by either parsing all
- * child "ranges" properties or figuring out the U3 address space
- * decoding logic and then read its configuration register (if any).
+ * /ht node doesn't expose a "ranges" property, we read the register
+ * that controls the decoding logic and use that for memory regions.
+ * The IO region is hard coded since it is fixed in HW as well.
*/
hose->io_base_phys = 0xf4000000;
hose->pci_io_size = 0x00400000;
@@ -824,76 +853,33 @@ static void __init setup_u3_ht(struct pc
hose->pci_mem_offset = 0;
hose->first_busno = 0;
hose->last_busno = 0xef;
- hose->mem_resources[0].name = np->full_name;
- hose->mem_resources[0].start = 0x80000000;
- hose->mem_resources[0].end = 0xefffffff;
- hose->mem_resources[0].flags = IORESOURCE_MEM;
-
- u3_ht = hose;
-
- if (u3_agp != NULL)
- other = u3_agp;
- else if (u4_pcie != NULL)
- other = u4_pcie;
- if (other == NULL) {
- DBG("U3/4 has no AGP/PCIE, using full resource range\n");
- return;
- }
+ /* Note: fix offset when cfg_addr becomes a void * */
+ decode = in_be32(hose->cfg_addr + 0x80);
- /* Fixup bus range vs. PCIE */
- if (u4_pcie)
- hose->last_busno = u4_pcie->first_busno - 1;
-
- /* We "remove" the AGP resources from the resources allocated to HT,
- * that is we create "holes". However, that code does assumptions
- * that so far happen to be true (cross fingers...), typically that
- * resources in the AGP node are properly ordered
- */
- cur = 0;
- for (i=0; i<3; i++) {
- struct resource *res = &other->mem_resources[i];
- if (res->flags != IORESOURCE_MEM)
- continue;
- /* We don't care about "fine" resources */
- if (res->start >= 0xf0000000)
- continue;
- /* Check if it's just a matter of "shrinking" us in one
- * direction
- */
- if (hose->mem_resources[cur].start == res->start) {
- DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n",
- cur, hose->mem_resources[cur].start,
- res->end + 1);
- hose->mem_resources[cur].start = res->end + 1;
- continue;
- }
- if (hose->mem_resources[cur].end == res->end) {
- DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n",
- cur, hose->mem_resources[cur].end,
- res->start - 1);
- hose->mem_resources[cur].end = res->start - 1;
- continue;
- }
- /* No, it's not the case, we need a hole */
- if (cur == 2) {
- /* not enough resources for a hole, we drop part
- * of the range
- */
- printk(KERN_WARNING "Running out of resources"
- " for /ht host !\n");
- hose->mem_resources[cur].end = res->start - 1;
- continue;
- }
- cur++;
- DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n",
- cur-1, res->start - 1, cur, res->end + 1);
- hose->mem_resources[cur].name = np->full_name;
- hose->mem_resources[cur].flags = IORESOURCE_MEM;
- hose->mem_resources[cur].start = res->end + 1;
- hose->mem_resources[cur].end = hose->mem_resources[cur-1].end;
- hose->mem_resources[cur-1].end = res->start - 1;
- }
+ DBG("PCI: Apple HT bridge decode register: 0x%08x\n", decode);
+
+ /* NOTE: The decode register setup is a bit weird... region
+ * 0xf8000000 for example is marked as enabled in there while it's
+ & actually the memory controller registers.
+ * That means that we are incorrectly attributing it to HT.
+ *
+ * In a similar vein, region 0xf4000000 is actually the HT IO space but
+ * also marked as enabled in here and 0xf9000000 is used by some other
+ * internal bits of the northbridge.
+ *
+ * Unfortunately, we can't just mask out those bit as we would end
+ * up with more regions than we can cope (linux can only cope with
+ * 3 memory regions for a PHB at this stage).
+ *
+ * So for now, we just do a little hack. We happen to -know- that
+ * Apple firmware doesn't assign things below 0xfa000000 for that
+ * bridge anyway so we mask out all bits we don't want.
+ */
+ decode &= 0x003fffff;
+
+ /* Now parse the resulting bits and build resources */
+ parse_region_decode(hose, decode);
}
#endif /* CONFIG_PPC64 */
^ permalink raw reply
* [PATCH 16/19] [POWERPC] Enable self-view of the HT host bridge on PowerMac G5
From: Benjamin Herrenschmidt @ 2007-12-20 3:55 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <1198122881.874131.56762399546.qpush@grosgo>
This enables the PCI code to see the device that represents the
HT host bridge on the PowerMac G5.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/platforms/powermac/pci.c | 54 ++++++++++++++++++++------------
arch/powerpc/platforms/powermac/setup.c | 4 +-
2 files changed, 38 insertions(+), 20 deletions(-)
--- linux-merge.orig/arch/powerpc/platforms/powermac/pci.c 2007-12-19 15:47:23.000000000 +1100
+++ linux-merge/arch/powerpc/platforms/powermac/pci.c 2007-12-19 15:50:46.000000000 +1100
@@ -314,10 +314,13 @@ static int u3_ht_skip_device(struct pci_
/* We only allow config cycles to devices that are in OF device-tree
* as we are apparently having some weird things going on with some
- * revs of K2 on recent G5s
+ * revs of K2 on recent G5s, except for the host bridge itself, which
+ * is missing from the tree but we know we can probe.
*/
if (bus->self)
busdn = pci_device_to_OF_node(bus->self);
+ else if (devfn == 0)
+ return 0;
else
busdn = hose->dn;
for (dn = busdn->child; dn; dn = dn->sibling)
@@ -344,14 +347,15 @@ static int u3_ht_skip_device(struct pci_
+ (((unsigned int)bus) << 16) \
+ 0x01000000UL)
-static volatile void __iomem *u3_ht_cfg_access(struct pci_controller* hose,
- u8 bus, u8 devfn, u8 offset)
+static void __iomem *u3_ht_cfg_access(struct pci_controller *hose, u8 bus,
+ u8 devfn, u8 offset, int *swap)
{
+ *swap = 1;
if (bus == hose->first_busno) {
- /* For now, we don't self probe U3 HT bridge */
- if (PCI_SLOT(devfn) == 0)
- return NULL;
- return hose->cfg_data + U3_HT_CFA0(devfn, offset);
+ if (devfn != 0)
+ return hose->cfg_data + U3_HT_CFA0(devfn, offset);
+ *swap = 0;
+ return ((void __iomem *)hose->cfg_addr) + (offset << 2);
} else
return hose->cfg_data + U3_HT_CFA1(bus, devfn, offset);
}
@@ -360,14 +364,15 @@ static int u3_ht_read_config(struct pci_
int offset, int len, u32 *val)
{
struct pci_controller *hose;
- volatile void __iomem *addr;
+ void __iomem *addr;
+ int swap;
hose = pci_bus_to_host(bus);
if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
if (offset >= 0x100)
return PCIBIOS_BAD_REGISTER_NUMBER;
- addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+ addr = u3_ht_cfg_access(hose, bus->number, devfn, offset, &swap);
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -397,10 +402,10 @@ static int u3_ht_read_config(struct pci_
*val = in_8(addr);
break;
case 2:
- *val = in_le16(addr);
+ *val = swap ? in_le16(addr) : in_be16(addr);
break;
default:
- *val = in_le32(addr);
+ *val = swap ? in_le32(addr) : in_be32(addr);
break;
}
return PCIBIOS_SUCCESSFUL;
@@ -410,14 +415,15 @@ static int u3_ht_write_config(struct pci
int offset, int len, u32 val)
{
struct pci_controller *hose;
- volatile void __iomem *addr;
+ void __iomem *addr;
+ int swap;
hose = pci_bus_to_host(bus);
if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
if (offset >= 0x100)
return PCIBIOS_BAD_REGISTER_NUMBER;
- addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+ addr = u3_ht_cfg_access(hose, bus->number, devfn, offset, &swap);
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -439,10 +445,10 @@ static int u3_ht_write_config(struct pci
out_8(addr, val);
break;
case 2:
- out_le16(addr, val);
+ swap ? out_le16(addr, val) : out_be16(addr, val);
break;
default:
- out_le32((u32 __iomem *)addr, val);
+ swap ? out_le32(addr, val) : out_be32(addr, val);
break;
}
return PCIBIOS_SUCCESSFUL;
@@ -780,16 +786,26 @@ static void __init setup_u3_ht(struct pc
{
struct device_node *np = hose->dn;
struct pci_controller *other = NULL;
+ struct resource cfg_res, self_res;
int i, cur;
hose->ops = &u3_ht_pci_ops;
- /* We hard code the address because of the different size of
- * the reg address cell, we shall fix that by killing struct
- * reg_property and using some accessor functions instead
+ /* Get base addresses from OF tree
+ */
+ if (of_address_to_resource(np, 0, &cfg_res) ||
+ of_address_to_resource(np, 1, &self_res)) {
+ printk(KERN_ERR "PCI: Failed to get U3/U4 HT resources !\n");
+ return;
+ }
+
+ /* Map external cfg space access into cfg_data and self registers
+ * into cfg_addr
*/
- hose->cfg_data = ioremap(0xf2000000, 0x02000000);
+ hose->cfg_data = ioremap(cfg_res.start, 0x02000000);
+ hose->cfg_addr = ioremap(self_res.start,
+ self_res.end - self_res.start + 1);
/*
* /ht node doesn't expose a "ranges" property, so we "remove"
Index: linux-merge/arch/powerpc/platforms/powermac/setup.c
===================================================================
--- linux-merge.orig/arch/powerpc/platforms/powermac/setup.c 2007-12-19 15:45:18.000000000 +1100
+++ linux-merge/arch/powerpc/platforms/powermac/setup.c 2007-12-19 15:47:24.000000000 +1100
@@ -613,9 +613,11 @@ static int pmac_pci_probe_mode(struct pc
/* We need to use normal PCI probing for the AGP bus,
* since the device for the AGP bridge isn't in the tree.
+ * Same for the PCIe host on U4 and the HT host bridge.
*/
if (bus->self == NULL && (of_device_is_compatible(node, "u3-agp") ||
- of_device_is_compatible(node, "u4-pcie")))
+ of_device_is_compatible(node, "u4-pcie") ||
+ of_device_is_compatible(node, "u3-ht")))
return PCI_PROBE_NORMAL;
return PCI_PROBE_DEVTREE;
}
^ permalink raw reply
* [PATCH 15/19] [POWERPC] Various fixes to pcibios_enable_device()
From: Benjamin Herrenschmidt @ 2007-12-20 3:55 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <1198122881.874131.56762399546.qpush@grosgo>
Our implementation of pcibios_enable_device() has a couple of problems.
One is that it should not check IORESOURCE_UNSET, as this might be
left dangling after resource assignment (shouldn't but there are
bugs), but instead, we make it check resource->parent which should
be a reliable indication that the resource has been successfully
claimed (it's in the resource tree).
Then, we also need to skip ROM resources that haven't been enabled
as x86 does.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/pci-common.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
--- linux-merge.orig/arch/powerpc/kernel/pci-common.c 2007-12-14 15:49:34.000000000 +1100
+++ linux-merge/arch/powerpc/kernel/pci-common.c 2007-12-14 15:49:36.000000000 +1100
@@ -1147,7 +1147,10 @@ int pcibios_enable_device(struct pci_dev
r = &dev->resource[idx];
if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
continue;
- if (r->flags & IORESOURCE_UNSET) {
+ if ((idx == PCI_ROM_RESOURCE) &&
+ (!(r->flags & IORESOURCE_ROM_ENABLE)))
+ continue;
+ if (r->parent == NULL) {
printk(KERN_ERR "PCI: Device %s not available because"
" of resource collisions\n", pci_name(dev));
return -EINVAL;
^ permalink raw reply
* [PATCH 14/19] [POWERPC] Clear pci_probe_only on 64 bits PowerMac
From: Benjamin Herrenschmidt @ 2007-12-20 3:54 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <1198122881.874131.56762399546.qpush@grosgo>
It should now be safe to re-assign unassigned resources on 64 bits PowerMac
machines (G5s). This clears pci_probe_only on those.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/platforms/powermac/pci.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- linux-merge.orig/arch/powerpc/platforms/powermac/pci.c 2007-12-14 15:49:34.000000000 +1100
+++ linux-merge/arch/powerpc/platforms/powermac/pci.c 2007-12-14 15:49:35.000000000 +1100
@@ -1041,8 +1041,8 @@ void __init pmac_pci_init(void)
}
/* pmac_check_ht_link(); */
- /* Tell pci.c to not use the common resource allocation mechanism */
- pci_probe_only = 1;
+ /* We can allocate missing resources if any */
+ pci_probe_only = 0;
#else /* CONFIG_PPC64 */
init_p2pbridge();
^ permalink raw reply
* [PATCH 13/19] [POWERPC] Fixup powermac enable device hook
From: Benjamin Herrenschmidt @ 2007-12-20 3:54 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <1198122881.874131.56762399546.qpush@grosgo>
Powermac's use of the pcibios_enable_device_hook() got slightly
broken by the recent PCI merge in that it won't be called for
the "initial" case of assigning resources to a previously
unassigned device. This was an abuse of that hook anyway, so
instead we now use a header quirk.
While at it, we move a #ifdef CONFIG_PPC32 to enclose more code
that is only ever used on 32 bits.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/platforms/powermac/pci.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
--- linux-merge.orig/arch/powerpc/platforms/powermac/pci.c 2007-12-14 15:49:34.000000000 +1100
+++ linux-merge/arch/powerpc/platforms/powermac/pci.c 2007-12-14 15:49:34.000000000 +1100
@@ -1058,6 +1058,7 @@ void __init pmac_pci_init(void)
#endif
}
+#ifdef CONFIG_PPC32
int pmac_pci_enable_device_hook(struct pci_dev *dev)
{
struct device_node* node;
@@ -1106,7 +1107,6 @@ int pmac_pci_enable_device_hook(struct p
* bridge and we must not, for example, enable MWI or set the
* cache line size on them.
*/
-#ifdef CONFIG_PPC32
if (updatecfg) {
u16 cmd;
@@ -1118,12 +1118,23 @@ int pmac_pci_enable_device_hook(struct p
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
L1_CACHE_BYTES >> 2);
-#endif
}
return 0;
}
+void __devinit pmac_pci_fixup_ohci(struct pci_dev *dev)
+{
+ struct device_node *node = pci_device_to_OF_node(dev);
+
+ /* We don't want to assign resources to USB controllers
+ * absent from the OF tree (iBook second controller)
+ */
+ if (dev->class == PCI_CLASS_SERIAL_USB_OHCI && !node)
+ dev->resource[0].flags = 0;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_APPLE, PCI_ANY_ID, pmac_pci_fixup_ohci);
+
/* We power down some devices after they have been probed. They'll
* be powered back on later on
*/
@@ -1171,7 +1182,6 @@ void __init pmac_pcibios_after_init(void
of_node_put(nd);
}
-#ifdef CONFIG_PPC32
void pmac_pci_fixup_cardbus(struct pci_dev* dev)
{
if (!machine_is(powermac))
@@ -1259,7 +1269,7 @@ void pmac_pci_fixup_pciata(struct pci_de
}
}
DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata);
-#endif
+#endif /* CONFIG_PPC32 */
/*
* Disable second function on K2-SATA, it's broken
^ permalink raw reply
* [PATCH 12/19] [POWERPC] Merge 32 and 64 bits pcibios_enable_device
From: Benjamin Herrenschmidt @ 2007-12-20 3:54 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <1198122881.874131.56762399546.qpush@grosgo>
This merge the two implementations, based on the previously
fixed up 32 bits one. The pcibios_enable_device_hook in ppc_md
is now available for ppc64 use. Also remove the new unused
"initial" parameter from it and fixup users.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/pci-common.c | 38 +++++++++++++++++++++++++++++++++
arch/powerpc/kernel/pci_32.c | 37 --------------------------------
arch/powerpc/kernel/pci_64.c | 30 --------------------------
arch/powerpc/platforms/powermac/pci.c | 22 ++++++++-----------
arch/powerpc/platforms/powermac/pmac.h | 2 -
include/asm-powerpc/machdep.h | 10 +++-----
6 files changed, 53 insertions(+), 86 deletions(-)
--- linux-merge.orig/arch/powerpc/kernel/pci-common.c 2007-12-14 15:49:33.000000000 +1100
+++ linux-merge/arch/powerpc/kernel/pci-common.c 2007-12-14 15:49:34.000000000 +1100
@@ -1127,3 +1127,41 @@ void __devinit pcibios_claim_one_bus(str
}
EXPORT_SYMBOL_GPL(pcibios_claim_one_bus);
#endif /* CONFIG_HOTPLUG */
+
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+ u16 cmd, old_cmd;
+ int idx;
+ struct resource *r;
+
+ if (ppc_md.pcibios_enable_device_hook)
+ if (ppc_md.pcibios_enable_device_hook(dev))
+ return -EINVAL;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ old_cmd = cmd;
+ for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) {
+ /* Only set up the requested stuff */
+ if (!(mask & (1 << idx)))
+ continue;
+ r = &dev->resource[idx];
+ if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
+ continue;
+ if (r->flags & IORESOURCE_UNSET) {
+ printk(KERN_ERR "PCI: Device %s not available because"
+ " of resource collisions\n", pci_name(dev));
+ return -EINVAL;
+ }
+ if (r->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ if (r->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ if (cmd != old_cmd) {
+ printk("PCI: Enabling device %s (%04x -> %04x)\n",
+ pci_name(dev), old_cmd, cmd);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ return 0;
+}
+
Index: linux-merge/include/asm-powerpc/machdep.h
===================================================================
--- linux-merge.orig/include/asm-powerpc/machdep.h 2007-12-14 15:49:31.000000000 +1100
+++ linux-merge/include/asm-powerpc/machdep.h 2007-12-14 15:49:34.000000000 +1100
@@ -204,12 +204,6 @@ struct machdep_calls {
/*
* optional PCI "hooks"
*/
-
- /* Called when pci_enable_device() is called (initial=0) or
- * when a device with no assigned resource is found (initial=1).
- * Returns 0 to allow assignment/enabling of the device. */
- int (*pcibios_enable_device_hook)(struct pci_dev *, int initial);
-
/* Called in indirect_* to avoid touching devices */
int (*pci_exclude_device)(struct pci_controller *, unsigned char, unsigned char);
@@ -225,6 +219,10 @@ struct machdep_calls {
/* Called for each PCI bus in the system when it's probed */
void (*pcibios_fixup_bus)(struct pci_bus *);
+ /* Called when pci_enable_device() is called. Returns 0 to
+ * allow assignment/enabling of the device. */
+ int (*pcibios_enable_device_hook)(struct pci_dev *);
+
/* Called to shutdown machine specific hardware not already controlled
* by other drivers.
*/
Index: linux-merge/arch/powerpc/kernel/pci_32.c
===================================================================
--- linux-merge.orig/arch/powerpc/kernel/pci_32.c 2007-12-14 15:49:33.000000000 +1100
+++ linux-merge/arch/powerpc/kernel/pci_32.c 2007-12-14 15:49:34.000000000 +1100
@@ -518,43 +518,6 @@ pcibios_update_irq(struct pci_dev *dev,
/* XXX FIXME - update OF device tree node interrupt property */
}
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
- u16 cmd, old_cmd;
- int idx;
- struct resource *r;
-
- if (ppc_md.pcibios_enable_device_hook)
- if (ppc_md.pcibios_enable_device_hook(dev, 0))
- return -EINVAL;
-
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
- old_cmd = cmd;
- for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) {
- /* Only set up the requested stuff */
- if (!(mask & (1 << idx)))
- continue;
- r = &dev->resource[idx];
- if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
- continue;
- if (r->flags & IORESOURCE_UNSET) {
- printk(KERN_ERR "PCI: Device %s not available because"
- " of resource collisions\n", pci_name(dev));
- return -EINVAL;
- }
- if (r->flags & IORESOURCE_IO)
- cmd |= PCI_COMMAND_IO;
- if (r->flags & IORESOURCE_MEM)
- cmd |= PCI_COMMAND_MEMORY;
- }
- if (cmd != old_cmd) {
- printk("PCI: Enabling device %s (%04x -> %04x)\n",
- pci_name(dev), old_cmd, cmd);
- pci_write_config_word(dev, PCI_COMMAND, cmd);
- }
- return 0;
-}
-
static struct pci_controller*
pci_bus_to_hose(int bus)
{
Index: linux-merge/arch/powerpc/kernel/pci_64.c
===================================================================
--- linux-merge.orig/arch/powerpc/kernel/pci_64.c 2007-12-14 15:49:33.000000000 +1100
+++ linux-merge/arch/powerpc/kernel/pci_64.c 2007-12-14 15:49:34.000000000 +1100
@@ -420,36 +420,6 @@ static int __init pcibios_init(void)
subsys_initcall(pcibios_init);
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
- u16 cmd, oldcmd;
- int i;
-
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
- oldcmd = cmd;
-
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- struct resource *res = &dev->resource[i];
-
- /* Only set up the requested stuff */
- if (!(mask & (1<<i)))
- continue;
-
- if (res->flags & IORESOURCE_IO)
- cmd |= PCI_COMMAND_IO;
- if (res->flags & IORESOURCE_MEM)
- cmd |= PCI_COMMAND_MEMORY;
- }
-
- if (cmd != oldcmd) {
- printk(KERN_DEBUG "PCI: Enabling device: (%s), cmd %x\n",
- pci_name(dev), cmd);
- /* Enable the appropriate bits in the PCI command register. */
- pci_write_config_word(dev, PCI_COMMAND, cmd);
- }
- return 0;
-}
-
#ifdef CONFIG_HOTPLUG
int pcibios_unmap_io_space(struct pci_bus *bus)
Index: linux-merge/arch/powerpc/platforms/powermac/pci.c
===================================================================
--- linux-merge.orig/arch/powerpc/platforms/powermac/pci.c 2007-12-14 15:49:32.000000000 +1100
+++ linux-merge/arch/powerpc/platforms/powermac/pci.c 2007-12-14 15:49:34.000000000 +1100
@@ -1058,8 +1058,7 @@ void __init pmac_pci_init(void)
#endif
}
-int
-pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
+int pmac_pci_enable_device_hook(struct pci_dev *dev)
{
struct device_node* node;
int updatecfg = 0;
@@ -1101,26 +1100,25 @@ pmac_pci_enable_device_hook(struct pci_d
updatecfg = 1;
}
+ /*
+ * Fixup various header fields on 32 bits. We don't do that on
+ * 64 bits as some of these have strange values behind the HT
+ * bridge and we must not, for example, enable MWI or set the
+ * cache line size on them.
+ */
+#ifdef CONFIG_PPC32
if (updatecfg) {
u16 cmd;
- /*
- * Make sure PCI is correctly configured
- *
- * We use old pci_bios versions of the function since, by
- * default, gmac is not powered up, and so will be absent
- * from the kernel initial PCI lookup.
- *
- * Should be replaced by 2.4 new PCI mechanisms and really
- * register the device.
- */
pci_read_config_word(dev, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER
| PCI_COMMAND_INVALIDATE;
pci_write_config_word(dev, PCI_COMMAND, cmd);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16);
+
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
L1_CACHE_BYTES >> 2);
+#endif
}
return 0;
Index: linux-merge/arch/powerpc/platforms/powermac/pmac.h
===================================================================
--- linux-merge.orig/arch/powerpc/platforms/powermac/pmac.h 2007-12-14 15:48:58.000000000 +1100
+++ linux-merge/arch/powerpc/platforms/powermac/pmac.h 2007-12-14 15:49:34.000000000 +1100
@@ -26,7 +26,7 @@ extern void pmac_pci_init(void);
extern void pmac_nvram_update(void);
extern unsigned char pmac_nvram_read_byte(int addr);
extern void pmac_nvram_write_byte(int addr, unsigned char val);
-extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial);
+extern int pmac_pci_enable_device_hook(struct pci_dev *dev);
extern void pmac_pcibios_after_init(void);
extern int of_show_percpuinfo(struct seq_file *m, int i);
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox