diff options
author | Markus Lidel <Markus.Lidel@shadowconnect.com> | 2006-02-03 14:04:29 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-02-03 19:32:07 +0300 |
commit | 8b3e09e19932835fb77c63aaf3b1af6117e78871 (patch) | |
tree | d98125db1fe2ee0c82426cac98c954cd62842e88 | |
parent | 15d8ec7d08fbb7876e292b42bc92da8d82df7ea9 (diff) | |
download | linux-8b3e09e19932835fb77c63aaf3b1af6117e78871.tar.xz |
[PATCH] I2O: fix and workaround for Motorola/Freescale controller
- This controller violates the I2O spec for the I/O registers. The patch
contains a workaround which moves the registers to the proper location.
(originally author: Matthew Starzewski)
- If a message frame is beyond the mapped address range a error is
returned.
Signed-off-by: Markus Lidel <Markus.Lidel@shadowconnect.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/message/i2o/core.h | 3 | ||||
-rw-r--r-- | drivers/message/i2o/pci.c | 18 | ||||
-rw-r--r-- | include/linux/i2o.h | 6 |
3 files changed, 25 insertions, 2 deletions
diff --git a/drivers/message/i2o/core.h b/drivers/message/i2o/core.h index 90628562851e..184974cc734d 100644 --- a/drivers/message/i2o/core.h +++ b/drivers/message/i2o/core.h @@ -60,4 +60,7 @@ extern void i2o_iop_remove(struct i2o_controller *); #define I2O_IN_PORT 0x40 #define I2O_OUT_PORT 0x44 +/* Motorola/Freescale specific register offset */ +#define I2O_MOTOROLA_PORT_OFFSET 0x10400 + #define I2O_IRQ_OUTBOUND_POST 0x00000008 diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c index e2e3fc79c78a..4f1515cae5dc 100644 --- a/drivers/message/i2o/pci.c +++ b/drivers/message/i2o/pci.c @@ -168,6 +168,24 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c) c->in_port = c->base.virt + I2O_IN_PORT; c->out_port = c->base.virt + I2O_OUT_PORT; + /* Motorola/Freescale chip does not follow spec */ + if (pdev->vendor == PCI_VENDOR_ID_MOTOROLA && pdev->device == 0x18c0) { + /* Check if CPU is enabled */ + if (be32_to_cpu(readl(c->base.virt + 0x10000)) & 0x10000000) { + printk(KERN_INFO "%s: MPC82XX needs CPU running to " + "service I2O.\n", c->name); + i2o_pci_free(c); + return -ENODEV; + } else { + c->irq_status += I2O_MOTOROLA_PORT_OFFSET; + c->irq_mask += I2O_MOTOROLA_PORT_OFFSET; + c->in_port += I2O_MOTOROLA_PORT_OFFSET; + c->out_port += I2O_MOTOROLA_PORT_OFFSET; + printk(KERN_INFO "%s: MPC82XX workarounds activated.\n", + c->name); + } + } + if (i2o_dma_alloc(dev, &c->status, 8, GFP_KERNEL)) { i2o_pci_free(c); return -ENOMEM; diff --git a/include/linux/i2o.h b/include/linux/i2o.h index 9ba806796667..5a9d8c599171 100644 --- a/include/linux/i2o.h +++ b/include/linux/i2o.h @@ -1115,9 +1115,11 @@ static inline struct i2o_message *i2o_msg_get(struct i2o_controller *c) return ERR_PTR(-ENOMEM); mmsg->mfa = readl(c->in_port); - if (mmsg->mfa == I2O_QUEUE_EMPTY) { + if (unlikely(mmsg->mfa >= c->in_queue.len)) { mempool_free(mmsg, c->in_msg.mempool); - return ERR_PTR(-EBUSY); + if(mmsg->mfa == I2O_QUEUE_EMPTY) + return ERR_PTR(-EBUSY); + return ERR_PTR(-EFAULT); } return &mmsg->msg; |