summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-12-28 16:54:33 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2008-12-28 16:54:33 -0800
commit3c92ec8ae91ecf59d88c798301833d7cf83f2179 (patch)
tree08a38cd3523c42bd49882f17cd501fd879e7ca1c /drivers
parentc4c9f0183b7c4e97836e8fecbb67898b06c47e78 (diff)
parentca9153a3a2a7556d091dfe080e42b0e67881fff6 (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (144 commits) powerpc/44x: Support 16K/64K base page sizes on 44x powerpc: Force memory size to be a multiple of PAGE_SIZE powerpc/32: Wire up the trampoline code for kdump powerpc/32: Add the ability for a classic ppc kernel to be loaded at 32M powerpc/32: Allow __ioremap on RAM addresses for kdump kernel powerpc/32: Setup OF properties for kdump powerpc/32/kdump: Implement crash_setup_regs() using ppc_save_regs() powerpc: Prepare xmon_save_regs for use with kdump powerpc: Remove default kexec/crash_kernel ops assignments powerpc: Make default kexec/crash_kernel ops implicit powerpc: Setup OF properties for ppc32 kexec powerpc/pseries: Fix cpu hotplug powerpc: Fix KVM build on ppc440 powerpc/cell: add QPACE as a separate Cell platform powerpc/cell: fix build breakage with CONFIG_SPUFS disabled powerpc/mpc5200: fix error paths in PSC UART probe function powerpc/mpc5200: add rts/cts handling in PSC UART driver powerpc/mpc5200: Make PSC UART driver update serial errors counters powerpc/mpc5200: Remove obsolete code from mpc5200 MDIO driver powerpc/mpc5200: Add MDMA/UDMA support to MPC5200 ATA driver ... Fix trivial conflict in drivers/char/Makefile as per Paul's directions
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/Kconfig3
-rw-r--r--drivers/ata/pata_mpc52xx.c546
-rw-r--r--drivers/char/Kconfig6
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/bsr.c84
-rw-r--r--drivers/char/hvc_console.c13
-rw-r--r--drivers/char/hvc_console.h2
-rw-r--r--drivers/char/hvc_iseries.c4
-rw-r--r--drivers/char/hvc_udbg.c96
-rw-r--r--drivers/char/hvc_vio.c4
-rw-r--r--drivers/char/hvcs.c2
-rw-r--r--drivers/char/hvsi.c2
-rw-r--r--drivers/edac/Kconfig2
-rw-r--r--drivers/macintosh/via-pmu.c4
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c5
-rw-r--r--drivers/net/fec_mpc52xx_phy.c5
-rw-r--r--drivers/of/base.c68
-rw-r--r--drivers/of/gpio.c70
-rw-r--r--drivers/of/of_i2c.c11
-rw-r--r--drivers/pci/hotplug/rpadlpar_core.c69
-rw-r--r--drivers/ps3/ps3av.c20
-rw-r--r--drivers/ps3/ps3av_cmd.c4
-rw-r--r--drivers/rapidio/rio-scan.c8
-rw-r--r--drivers/serial/mpc52xx_uart.c74
-rw-r--r--drivers/serial/pmac_zilog.c27
-rw-r--r--drivers/video/controlfb.c4
-rw-r--r--drivers/video/ps3fb.c23
27 files changed, 926 insertions, 231 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 421b7c71e72d..1a7be96d627b 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -456,7 +456,8 @@ config PATA_MARVELL
config PATA_MPC52xx
tristate "Freescale MPC52xx SoC internal IDE"
- depends on PPC_MPC52xx
+ depends on PPC_MPC52xx && PPC_BESTCOMM
+ select PPC_BESTCOMM_ATA
help
This option enables support for integrated IDE controller
of the Freescale MPC52xx SoC.
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index a9e827356d06..50ae6d13078a 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -6,6 +6,9 @@
* Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
* Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
*
+ * UDMA support based on patches by Freescale (Bernard Kuhn, John Rigby),
+ * Domen Puncer and Tim Yamin.
+ *
* 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.
@@ -17,28 +20,46 @@
#include <linux/delay.h>
#include <linux/libata.h>
#include <linux/of_platform.h>
+#include <linux/types.h>
-#include <asm/types.h>
+#include <asm/cacheflush.h>
#include <asm/prom.h>
#include <asm/mpc52xx.h>
+#include <sysdev/bestcomm/bestcomm.h>
+#include <sysdev/bestcomm/bestcomm_priv.h>
+#include <sysdev/bestcomm/ata.h>
#define DRV_NAME "mpc52xx_ata"
-#define DRV_VERSION "0.1.2"
-
/* Private structures used by the driver */
struct mpc52xx_ata_timings {
u32 pio1;
u32 pio2;
+ u32 mdma1;
+ u32 mdma2;
+ u32 udma1;
+ u32 udma2;
+ u32 udma3;
+ u32 udma4;
+ u32 udma5;
+ int using_udma;
};
struct mpc52xx_ata_priv {
unsigned int ipb_period;
- struct mpc52xx_ata __iomem * ata_regs;
+ struct mpc52xx_ata __iomem *ata_regs;
+ phys_addr_t ata_regs_pa;
int ata_irq;
struct mpc52xx_ata_timings timings[2];
int csel;
+
+ /* DMA */
+ struct bcom_task *dmatsk;
+ const struct udmaspec *udmaspec;
+ const struct mdmaspec *mdmaspec;
+ int mpc52xx_ata_dma_last_write;
+ int waiting_for_dma;
};
@@ -53,6 +74,107 @@ static const int ataspec_ta[5] = { 35, 35, 35, 35, 35};
#define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c)))
+/* ======================================================================== */
+
+/* ATAPI-4 MDMA specs (in clocks) */
+struct mdmaspec {
+ u32 t0M;
+ u32 td;
+ u32 th;
+ u32 tj;
+ u32 tkw;
+ u32 tm;
+ u32 tn;
+};
+
+static const struct mdmaspec mdmaspec66[3] = {
+ { .t0M = 32, .td = 15, .th = 2, .tj = 2, .tkw = 15, .tm = 4, .tn = 1 },
+ { .t0M = 10, .td = 6, .th = 1, .tj = 1, .tkw = 4, .tm = 2, .tn = 1 },
+ { .t0M = 8, .td = 5, .th = 1, .tj = 1, .tkw = 2, .tm = 2, .tn = 1 },
+};
+
+static const struct mdmaspec mdmaspec132[3] = {
+ { .t0M = 64, .td = 29, .th = 3, .tj = 3, .tkw = 29, .tm = 7, .tn = 2 },
+ { .t0M = 20, .td = 11, .th = 2, .tj = 1, .tkw = 7, .tm = 4, .tn = 1 },
+ { .t0M = 16, .td = 10, .th = 2, .tj = 1, .tkw = 4, .tm = 4, .tn = 1 },
+};
+
+/* ATAPI-4 UDMA specs (in clocks) */
+struct udmaspec {
+ u32 tcyc;
+ u32 t2cyc;
+ u32 tds;
+ u32 tdh;
+ u32 tdvs;
+ u32 tdvh;
+ u32 tfs;
+ u32 tli;
+ u32 tmli;
+ u32 taz;
+ u32 tzah;
+ u32 tenv;
+ u32 tsr;
+ u32 trfs;
+ u32 trp;
+ u32 tack;
+ u32 tss;
+};
+
+static const struct udmaspec udmaspec66[6] = {
+ { .tcyc = 8, .t2cyc = 16, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1,
+ .tfs = 16, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
+ .tsr = 3, .trfs = 5, .trp = 11, .tack = 2, .tss = 4,
+ },
+ { .tcyc = 5, .t2cyc = 11, .tds = 1, .tdh = 1, .tdvs = 4, .tdvh = 1,
+ .tfs = 14, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
+ .tsr = 2, .trfs = 5, .trp = 9, .tack = 2, .tss = 4,
+ },
+ { .tcyc = 4, .t2cyc = 8, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1,
+ .tfs = 12, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
+ .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4,
+ },
+ { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 2, .tdvh = 1,
+ .tfs = 9, .tli = 7, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
+ .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4,
+ },
+ { .tcyc = 2, .t2cyc = 4, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1,
+ .tfs = 8, .tli = 8, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
+ .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4,
+ },
+ { .tcyc = 2, .t2cyc = 2, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1,
+ .tfs = 6, .tli = 5, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
+ .tsr = 2, .trfs = 4, .trp = 6, .tack = 2, .tss = 4,
+ },
+};
+
+static const struct udmaspec udmaspec132[6] = {
+ { .tcyc = 15, .t2cyc = 31, .tds = 2, .tdh = 1, .tdvs = 10, .tdvh = 1,
+ .tfs = 30, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3,
+ .tsr = 7, .trfs = 10, .trp = 22, .tack = 3, .tss = 7,
+ },
+ { .tcyc = 10, .t2cyc = 21, .tds = 2, .tdh = 1, .tdvs = 7, .tdvh = 1,
+ .tfs = 27, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3,
+ .tsr = 4, .trfs = 10, .trp = 17, .tack = 3, .tss = 7,
+ },
+ { .tcyc = 6, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1,
+ .tfs = 23, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3,
+ .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7,
+ },
+ { .tcyc = 7, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1,
+ .tfs = 15, .tli = 13, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3,
+ .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7,
+ },
+ { .tcyc = 2, .t2cyc = 5, .tds = 0, .tdh = 0, .tdvs = 1, .tdvh = 1,
+ .tfs = 16, .tli = 14, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
+ .tsr = 2, .trfs = 7, .trp = 13, .tack = 2, .tss = 6,
+ },
+ { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1,
+ .tfs = 12, .tli = 10, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3,
+ .tsr = 3, .trfs = 7, .trp = 12, .tack = 3, .tss = 7,
+ },
+};
+
+/* ======================================================================== */
/* Bit definitions inside the registers */
#define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */
@@ -66,6 +188,7 @@ static const int ataspec_ta[5] = { 35, 35, 35, 35, 35};
#define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */
#define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */
+#define MPC52xx_ATA_FIFOSTAT_ERROR 0x40 /* FIFO Error */
#define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */
#define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */
@@ -75,6 +198,8 @@ static const int ataspec_ta[5] = { 35, 35, 35, 35, 35};
#define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */
#define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */
+#define MAX_DMA_BUFFERS 128
+#define MAX_DMA_BUFFER_SIZE 0x20000u
/* Structure of the hardware registers */
struct mpc52xx_ata {
@@ -140,7 +265,6 @@ struct mpc52xx_ata {
/* MPC52xx low level hw control */
-
static int
mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio)
{
@@ -148,7 +272,7 @@ mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio)
unsigned int ipb_period = priv->ipb_period;
unsigned int t0, t1, t2_8, t2_16, t2i, t4, ta;
- if ((pio<0) || (pio>4))
+ if ((pio < 0) || (pio > 4))
return -EINVAL;
t0 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t0[pio]);
@@ -165,6 +289,43 @@ mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio)
return 0;
}
+static int
+mpc52xx_ata_compute_mdma_timings(struct mpc52xx_ata_priv *priv, int dev,
+ int speed)
+{
+ struct mpc52xx_ata_timings *t = &priv->timings[dev];
+ const struct mdmaspec *s = &priv->mdmaspec[speed];
+
+ if (speed < 0 || speed > 2)
+ return -EINVAL;
+
+ t->mdma1 = (s->t0M << 24) | (s->td << 16) | (s->tkw << 8) | (s->tm);
+ t->mdma2 = (s->th << 24) | (s->tj << 16) | (s->tn << 8);
+ t->using_udma = 0;
+
+ return 0;
+}
+
+static int
+mpc52xx_ata_compute_udma_timings(struct mpc52xx_ata_priv *priv, int dev,
+ int speed)
+{
+ struct mpc52xx_ata_timings *t = &priv->timings[dev];
+ const struct udmaspec *s = &priv->udmaspec[speed];
+
+ if (speed < 0 || speed > 2)
+ return -EINVAL;
+
+ t->udma1 = (s->t2cyc << 24) | (s->tcyc << 16) | (s->tds << 8) | s->tdh;
+ t->udma2 = (s->tdvs << 24) | (s->tdvh << 16) | (s->tfs << 8) | s->tli;
+ t->udma3 = (s->tmli << 24) | (s->taz << 16) | (s->tenv << 8) | s->tsr;
+ t->udma4 = (s->tss << 24) | (s->trfs << 16) | (s->trp << 8) | s->tack;
+ t->udma5 = (s->tzah << 24);
+ t->using_udma = 1;
+
+ return 0;
+}
+
static void
mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device)
{
@@ -173,14 +334,13 @@ mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device)
out_be32(&regs->pio1, timing->pio1);
out_be32(&regs->pio2, timing->pio2);
- out_be32(&regs->mdma1, 0);
- out_be32(&regs->mdma2, 0);
- out_be32(&regs->udma1, 0);
- out_be32(&regs->udma2, 0);
- out_be32(&regs->udma3, 0);
- out_be32(&regs->udma4, 0);
- out_be32(&regs->udma5, 0);
-
+ out_be32(&regs->mdma1, timing->mdma1);
+ out_be32(&regs->mdma2, timing->mdma2);
+ out_be32(&regs->udma1, timing->udma1);
+ out_be32(&regs->udma2, timing->udma2);
+ out_be32(&regs->udma3, timing->udma3);
+ out_be32(&regs->udma4, timing->udma4);
+ out_be32(&regs->udma5, timing->udma5);
priv->csel = device;
}
@@ -208,7 +368,7 @@ mpc52xx_ata_hw_init(struct mpc52xx_ata_priv *priv)
/* Set the time slot to 1us */
tslot = CALC_CLKCYC(priv->ipb_period, 1000000);
- out_be32(&regs->share_cnt, tslot << 16 );
+ out_be32(&regs->share_cnt, tslot << 16);
/* Init timings to PIO0 */
memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings));
@@ -237,13 +397,37 @@ mpc52xx_ata_set_piomode(struct ata_port *ap, struct ata_device *adev)
rv = mpc52xx_ata_compute_pio_timings(priv, adev->devno, pio);
if (rv) {
- printk(KERN_ERR DRV_NAME
- ": Trying to select invalid PIO mode %d\n", pio);
+ dev_err(ap->dev, "error: invalid PIO mode: %d\n", pio);
+ return;
+ }
+
+ mpc52xx_ata_apply_timings(priv, adev->devno);
+}
+
+static void
+mpc52xx_ata_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+ int rv;
+
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ int dma = adev->dma_mode - XFER_UDMA_0;
+ rv = mpc52xx_ata_compute_udma_timings(priv, adev->devno, dma);
+ } else {
+ int dma = adev->dma_mode - XFER_MW_DMA_0;
+ rv = mpc52xx_ata_compute_mdma_timings(priv, adev->devno, dma);
+ }
+
+ if (rv) {
+ dev_alert(ap->dev,
+ "Trying to select invalid DMA mode %d\n",
+ adev->dma_mode);
return;
}
mpc52xx_ata_apply_timings(priv, adev->devno);
}
+
static void
mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device)
{
@@ -252,7 +436,173 @@ mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device)
if (device != priv->csel)
mpc52xx_ata_apply_timings(priv, device);
- ata_sff_dev_select(ap,device);
+ ata_sff_dev_select(ap, device);
+}
+
+static int
+mpc52xx_ata_build_dmatable(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+ struct bcom_ata_bd *bd;
+ unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE), si;
+ struct scatterlist *sg;
+ int count = 0;
+
+ if (read)
+ bcom_ata_rx_prepare(priv->dmatsk);
+ else
+ bcom_ata_tx_prepare(priv->dmatsk);
+
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ dma_addr_t cur_addr = sg_dma_address(sg);
+ u32 cur_len = sg_dma_len(sg);
+
+ while (cur_len) {
+ unsigned int tc = min(cur_len, MAX_DMA_BUFFER_SIZE);
+ bd = (struct bcom_ata_bd *)
+ bcom_prepare_next_buffer(priv->dmatsk);
+
+ if (read) {
+ bd->status = tc;
+ bd->src_pa = (__force u32) priv->ata_regs_pa +
+ offsetof(struct mpc52xx_ata, fifo_data);
+ bd->dst_pa = (__force u32) cur_addr;
+ } else {
+ bd->status = tc;
+ bd->src_pa = (__force u32) cur_addr;
+ bd->dst_pa = (__force u32) priv->ata_regs_pa +
+ offsetof(struct mpc52xx_ata, fifo_data);
+ }
+
+ bcom_submit_next_buffer(priv->dmatsk, NULL);
+
+ cur_addr += tc;
+ cur_len -= tc;
+ count++;
+
+ if (count > MAX_DMA_BUFFERS) {
+ dev_alert(ap->dev, "dma table"
+ "too small\n");
+ goto use_pio_instead;
+ }
+ }
+ }
+ return 1;
+
+ use_pio_instead:
+ bcom_ata_reset_bd(priv->dmatsk);
+ return 0;
+}
+
+static void
+mpc52xx_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+ struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+
+ unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE);
+ u8 dma_mode;
+
+ if (!mpc52xx_ata_build_dmatable(qc))
+ dev_alert(ap->dev, "%s: %i, return 1?\n",
+ __func__, __LINE__);
+
+ /* Check FIFO is OK... */
+ if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR)
+ dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n",
+ __func__, in_8(&priv->ata_regs->fifo_status));
+
+ if (read) {
+ dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_READ |
+ MPC52xx_ATA_DMAMODE_FE;
+
+ /* Setup FIFO if direction changed */
+ if (priv->mpc52xx_ata_dma_last_write != 0) {
+ priv->mpc52xx_ata_dma_last_write = 0;
+
+ /* Configure FIFO with granularity to 7 */
+ out_8(&regs->fifo_control, 7);
+ out_be16(&regs->fifo_alarm, 128);
+
+ /* Set FIFO Reset bit (FR) */
+ out_8(&regs->dma_mode, MPC52xx_ATA_DMAMODE_FR);
+ }
+ } else {
+ dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_WRITE;
+
+ /* Setup FIFO if direction changed */
+ if (priv->mpc52xx_ata_dma_last_write != 1) {
+ priv->mpc52xx_ata_dma_last_write = 1;
+
+ /* Configure FIFO with granularity to 4 */
+ out_8(&regs->fifo_control, 4);
+ out_be16(&regs->fifo_alarm, 128);
+ }
+ }
+
+ if (priv->timings[qc->dev->devno].using_udma)
+ dma_mode |= MPC52xx_ATA_DMAMODE_UDMA;
+
+ out_8(&regs->dma_mode, dma_mode);
+ priv->waiting_for_dma = ATA_DMA_ACTIVE;
+
+ ata_wait_idle(ap);
+ ap->ops->sff_exec_command(ap, &qc->tf);
+}
+
+static void
+mpc52xx_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+
+ bcom_set_task_auto_start(priv->dmatsk->tasknum, priv->dmatsk->tasknum);
+ bcom_enable(priv->dmatsk);
+}
+
+static void
+mpc52xx_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+
+ bcom_disable(priv->dmatsk);
+ bcom_ata_reset_bd(priv->dmatsk);
+ priv->waiting_for_dma = 0;
+
+ /* Check FIFO is OK... */
+ if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR)
+ dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n",
+ __func__, in_8(&priv->ata_regs->fifo_status));
+}
+
+static u8
+mpc52xx_bmdma_status(struct ata_port *ap)
+{
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+
+ /* Check FIFO is OK... */
+ if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) {
+ dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n",
+ __func__, in_8(&priv->ata_regs->fifo_status));
+ return priv->waiting_for_dma | ATA_DMA_ERR;
+ }
+
+ return priv->waiting_for_dma;
+}
+
+static irqreturn_t
+mpc52xx_ata_task_irq(int irq, void *vpriv)
+{
+ struct mpc52xx_ata_priv *priv = vpriv;
+ while (bcom_buffer_done(priv->dmatsk))
+ bcom_retrieve_buffer(priv->dmatsk, NULL, NULL);
+
+ priv->waiting_for_dma |= ATA_DMA_INTR;
+
+ return IRQ_HANDLED;
}
static struct scsi_host_template mpc52xx_ata_sht = {
@@ -262,14 +612,18 @@ static struct scsi_host_template mpc52xx_ata_sht = {
static struct ata_port_operations mpc52xx_ata_port_ops = {
.inherits = &ata_sff_port_ops,
.sff_dev_select = mpc52xx_ata_dev_select,
- .cable_detect = ata_cable_40wire,
.set_piomode = mpc52xx_ata_set_piomode,
- .post_internal_cmd = ATA_OP_NULL,
+ .set_dmamode = mpc52xx_ata_set_dmamode,
+ .bmdma_setup = mpc52xx_bmdma_setup,
+ .bmdma_start = mpc52xx_bmdma_start,
+ .bmdma_stop = mpc52xx_bmdma_stop,
+ .bmdma_status = mpc52xx_bmdma_status,
+ .qc_prep = ata_noop_qc_prep,
};
static int __devinit
mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
- unsigned long raw_ata_regs)
+ unsigned long raw_ata_regs, int mwdma_mask, int udma_mask)
{
struct ata_host *host;
struct ata_port *ap;
@@ -281,9 +635,9 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
ap = host->ports[0];
ap->flags |= ATA_FLAG_SLAVE_POSS;
- ap->pio_mask = 0x1f; /* Up to PIO4 */
- ap->mwdma_mask = 0x00; /* No MWDMA */
- ap->udma_mask = 0x00; /* No UDMA */
+ ap->pio_mask = ATA_PIO4;
+ ap->mwdma_mask = mwdma_mask;
+ ap->udma_mask = udma_mask;
ap->ops = &mpc52xx_ata_port_ops;
host->private_data = priv;
@@ -330,89 +684,139 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
{
unsigned int ipb_freq;
struct resource res_mem;
- int ata_irq;
+ int ata_irq = 0;
struct mpc52xx_ata __iomem *ata_regs;
- struct mpc52xx_ata_priv *priv;
- int rv;
+ struct mpc52xx_ata_priv *priv = NULL;
+ int rv, ret, task_irq = 0;
+ int mwdma_mask = 0, udma_mask = 0;
+ const __be32 *prop;
+ int proplen;
+ struct bcom_task *dmatsk = NULL;
/* Get ipb frequency */
ipb_freq = mpc52xx_find_ipb_freq(op->node);
if (!ipb_freq) {
- printk(KERN_ERR DRV_NAME ": "
- "Unable to find IPB Bus frequency\n" );
+ dev_err(&op->dev, "could not determine IPB bus frequency\n");
return -ENODEV;
}
- /* Get IRQ and register */
+ /* Get device base address from device tree, request the region
+ * and ioremap it. */
rv = of_address_to_resource(op->node, 0, &res_mem);
if (rv) {
- printk(KERN_ERR DRV_NAME ": "
- "Error while parsing device node resource\n" );
+ dev_err(&op->dev, "could not determine device base address\n");
return rv;
}
- ata_irq = irq_of_parse_and_map(op->node, 0);
- if (ata_irq == NO_IRQ) {
- printk(KERN_ERR DRV_NAME ": "
- "Error while mapping the irq\n");
- return -EINVAL;
- }
-
- /* Request mem region */
if (!devm_request_mem_region(&op->dev, res_mem.start,
- sizeof(struct mpc52xx_ata), DRV_NAME)) {
- printk(KERN_ERR DRV_NAME ": "
- "Error while requesting mem region\n");
- rv = -EBUSY;
- goto err;
+ sizeof(*ata_regs), DRV_NAME)) {
+ dev_err(&op->dev, "error requesting register region\n");
+ return -EBUSY;
}
- /* Remap registers */
- ata_regs = devm_ioremap(&op->dev, res_mem.start,
- sizeof(struct mpc52xx_ata));
+ ata_regs = devm_ioremap(&op->dev, res_mem.start, sizeof(*ata_regs));
if (!ata_regs) {
- printk(KERN_ERR DRV_NAME ": "
- "Error while mapping register set\n");
+ dev_err(&op->dev, "error mapping device registers\n");
rv = -ENOMEM;
goto err;
}
+ /*
+ * By default, all DMA modes are disabled for the MPC5200. Some
+ * boards don't have the required signals routed to make DMA work.
+ * Also, the MPC5200B has a silicon bug that causes data corruption
+ * with UDMA if it is used at the same time as the LocalPlus bus.
+ *
+ * Instead of trying to guess what modes are usable, check the
+ * ATA device tree node to find out what DMA modes work on the board.
+ * UDMA/MWDMA modes can also be forced by adding "libata.force=<mode>"
+ * to the kernel boot parameters.
+ *
+ * The MPC5200 ATA controller supports MWDMA modes 0, 1 and 2 and
+ * UDMA modes 0, 1 and 2.
+ */
+ prop = of_get_property(op->node, "mwdma-mode", &proplen);
+ if ((prop) && (proplen >= 4))
+ mwdma_mask = 0x7 & ((1 << (*prop + 1)) - 1);
+ prop = of_get_property(op->node, "udma-mode", &proplen);
+ if ((prop) && (proplen >= 4))
+ udma_mask = 0x7 & ((1 << (*prop + 1)) - 1);
+
+ ata_irq = irq_of_parse_and_map(op->node, 0);
+ if (ata_irq == NO_IRQ) {
+ dev_err(&op->dev, "error mapping irq\n");
+ return -EINVAL;
+ }
+
/* Prepare our private structure */
- priv = devm_kzalloc(&op->dev, sizeof(struct mpc52xx_ata_priv),
- GFP_ATOMIC);
+ priv = devm_kzalloc(&op->dev, sizeof(*priv), GFP_ATOMIC);
if (!priv) {
- printk(KERN_ERR DRV_NAME ": "
- "Error while allocating private structure\n");
+ dev_err(&op->dev, "error allocating private structure\n");
rv = -ENOMEM;
goto err;
}
priv->ipb_period = 1000000000 / (ipb_freq / 1000);
priv->ata_regs = ata_regs;
+ priv->ata_regs_pa = res_mem.start;
priv->ata_irq = ata_irq;
priv->csel = -1;
+ priv->mpc52xx_ata_dma_last_write = -1;
+
+ if (ipb_freq/1000000 == 66) {
+ priv->mdmaspec = mdmaspec66;
+ priv->udmaspec = udmaspec66;
+ } else {
+ priv->mdmaspec = mdmaspec132;
+ priv->udmaspec = udmaspec132;
+ }
+
+ /* Allocate a BestComm task for DMA */
+ dmatsk = bcom_ata_init(MAX_DMA_BUFFERS, MAX_DMA_BUFFER_SIZE);
+ if (!dmatsk) {
+ dev_err(&op->dev, "bestcomm initialization failed\n");
+ rv = -ENOMEM;
+ goto err;
+ }
+
+ task_irq = bcom_get_task_irq(dmatsk);
+ ret = request_irq(task_irq, &mpc52xx_ata_task_irq, IRQF_DISABLED,
+ "ATA task", priv);
+ if (ret) {
+ dev_err(&op->dev, "error requesting DMA IRQ\n");
+ goto err;
+ }
+ priv->dmatsk = dmatsk;
/* Init the hw */
rv = mpc52xx_ata_hw_init(priv);
if (rv) {
- printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+ dev_err(&op->dev, "error initializing hardware\n");
goto err;
}
/* Register ourselves to libata */
- rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start);
+ rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start,
+ mwdma_mask, udma_mask);
if (rv) {
- printk(KERN_ERR DRV_NAME ": "
- "Error while registering to ATA layer\n");
- return rv;
+ dev_err(&op->dev, "error registering with ATA layer\n");
+ goto err;
}
- /* Done */
return 0;
- /* Error path */
-err:
- irq_dispose_mapping(ata_irq);
+ err:
+ devm_release_mem_region(&op->dev, res_mem.start, sizeof(*ata_regs));
+ if (ata_irq)
+ irq_dispose_mapping(ata_irq);
+ if (task_irq)
+ irq_dispose_mapping(task_irq);
+ if (dmatsk)
+ bcom_ata_release(dmatsk);
+ if (ata_regs)
+ devm_iounmap(&op->dev, ata_regs);
+ if (priv)
+ devm_kfree(&op->dev, priv);
return rv;
}
@@ -420,10 +824,23 @@ static int
mpc52xx_ata_remove(struct of_device *op)
{
struct mpc52xx_ata_priv *priv;
+ int task_irq;
+ /* Deregister the ATA interface */
priv = mpc52xx_ata_remove_one(&op->dev);
+
+ /* Clean up DMA */
+ task_irq = bcom_get_task_irq(priv->dmatsk);
+ irq_dispose_mapping(task_irq);
+ bcom_ata_release(priv->dmatsk);
irq_dispose_mapping(priv->ata_irq);
+ /* Clear up IO allocations */
+ devm_iounmap(&op->dev, priv->ata_regs);
+ devm_release_mem_region(&op->dev, priv->ata_regs_pa,
+ sizeof(*priv->ata_regs));
+ devm_kfree(&op->dev, priv);
+
return 0;
}
@@ -447,7 +864,7 @@ mpc52xx_ata_resume(struct of_device *op)
rv = mpc52xx_ata_hw_init(priv);
if (rv) {
- printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+ dev_err(host->dev, "error initializing hardware\n");
return rv;
}
@@ -507,5 +924,4 @@ MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(of, mpc52xx_ata_of_match);
-MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 8783457b93d3..c602b547cc6e 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -641,6 +641,12 @@ config HVC_XEN
help
Xen virtual console device driver
+config HVC_UDBG
+ bool "udbg based fake hypervisor console"
+ depends on PPC && EXPERIMENTAL
+ select HVC_DRIVER
+ default n
+
config VIRTIO_CONSOLE
tristate "Virtio console"
depends on VIRTIO
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 36151bae0d72..9caf5b5ad1c0 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_HVC_IRQ) += hvc_irq.o
obj-$(CONFIG_HVC_XEN) += hvc_xen.o
obj-$(CONFIG_HVC_IUCV) += hvc_iucv.o
+obj-$(CONFIG_HVC_UDBG) += hvc_udbg.o
obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c
index 456f54db73e2..977dfb1096a0 100644
--- a/drivers/char/bsr.c
+++ b/drivers/char/bsr.c
@@ -60,6 +60,8 @@ struct bsr_dev {
unsigned bsr_num; /* bsr id number for its type */
int bsr_minor;
+ struct list_head bsr_list;
+
dev_t bsr_dev;
struct cdev bsr_cdev;
struct device *bsr_device;
@@ -67,8 +69,8 @@ struct bsr_dev {
};
-static unsigned num_bsr_devs;
-static struct bsr_dev *bsr_devs;
+static unsigned total_bsr_devs;
+static struct list_head bsr_devs = LIST_HEAD_INIT(bsr_devs);
static struct class *bsr_class;
static int bsr_major;
@@ -146,24 +148,25 @@ const static struct file_operations bsr_fops = {
static void bsr_cleanup_devs(void)
{
- int i;
- for (i=0 ; i < num_bsr_devs; i++) {
- struct bsr_dev *cur = bsr_devs + i;
+ struct bsr_dev *cur, *n;
+
+ list_for_each_entry_safe(cur, n, &bsr_devs, bsr_list) {
if (cur->bsr_device) {
cdev_del(&cur->bsr_cdev);
device_del(cur->bsr_device);
}
+ list_del(&cur->bsr_list);
+ kfree(cur);
}
-
- kfree(bsr_devs);
}
-static int bsr_create_devs(struct device_node *bn)
+static int bsr_add_node(struct device_node *bn)
{
- int bsr_stride_len, bsr_bytes_len;
+ int bsr_stride_len, bsr_bytes_len, num_bsr_devs;
const u32 *bsr_stride;
const u32 *bsr_bytes;
unsigned i;
+ int ret = -ENODEV;
bsr_stride = of_get_property(bn, "ibm,lock-stride", &bsr_stride_len);
bsr_bytes = of_get_property(bn, "ibm,#lock-bytes", &bsr_bytes_len);
@@ -171,35 +174,36 @@ static int bsr_create_devs(struct device_node *bn)
if (!bsr_stride || !bsr_bytes ||
(bsr_stride_len != bsr_bytes_len)) {
printk(KERN_ERR "bsr of-node has missing/incorrect property\n");
- return -ENODEV;
+ return ret;
}
num_bsr_devs = bsr_bytes_len / sizeof(u32);
- /* only a warning, its informational since we'll fail and exit */
- WARN_ON(num_bsr_devs > BSR_MAX_DEVS);
-
- bsr_devs = kzalloc(sizeof(struct bsr_dev) * num_bsr_devs, GFP_KERNEL);
- if (!bsr_devs)
- return -ENOMEM;
-
for (i = 0 ; i < num_bsr_devs; i++) {
- struct bsr_dev *cur = bsr_devs + i;
+ struct bsr_dev *cur = kzalloc(sizeof(struct bsr_dev),
+ GFP_KERNEL);
struct resource res;
int result;
+ if (!cur) {
+ printk(KERN_ERR "Unable to alloc bsr dev\n");
+ ret = -ENOMEM;
+ goto out_err;
+ }
+
result = of_address_to_resource(bn, i, &res);
if (result < 0) {
- printk(KERN_ERR "bsr of-node has invalid reg property\n");
- goto out_err;
+ printk(KERN_ERR "bsr of-node has invalid reg property, skipping\n");
+ kfree(cur);
+ continue;
}
- cur->bsr_minor = i;
+ cur->bsr_minor = i + total_bsr_devs;
cur->bsr_addr = res.start;
cur->bsr_len = res.end - res.start + 1;
cur->bsr_bytes = bsr_bytes[i];
cur->bsr_stride = bsr_stride[i];
- cur->bsr_dev = MKDEV(bsr_major, i);
+ cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs);
switch(cur->bsr_bytes) {
case 8:
@@ -220,14 +224,15 @@ static int bsr_create_devs(struct device_node *bn)
}
cur->bsr_num = bsr_types[cur->bsr_type];
- bsr_types[cur->bsr_type] = cur->bsr_num + 1;
snprintf(cur->bsr_name, 32, "bsr%d_%d",
cur->bsr_bytes, cur->bsr_num);
cdev_init(&cur->bsr_cdev, &bsr_fops);
result = cdev_add(&cur->bsr_cdev, cur->bsr_dev, 1);
- if (result)
+ if (result) {
+ kfree(cur);
goto out_err;
+ }
cur->bsr_device = device_create(bsr_class, NULL, cur->bsr_dev,
cur, cur->bsr_name);
@@ -235,16 +240,37 @@ static int bsr_create_devs(struct device_node *bn)
printk(KERN_ERR "device_create failed for %s\n",
cur->bsr_name);
cdev_del(&cur->bsr_cdev);
+ kfree(cur);
goto out_err;
}
+
+ bsr_types[cur->bsr_type] = cur->bsr_num + 1;
+ list_add_tail(&cur->bsr_list, &bsr_devs);
}
+ total_bsr_devs += num_bsr_devs;
+
return 0;
out_err:
bsr_cleanup_devs();
- return -ENODEV;
+ return ret;
+}
+
+static int bsr_create_devs(struct device_node *bn)
+{
+ int ret;
+
+ while (bn) {
+ ret = bsr_add_node(bn);
+ if (ret) {
+ of_node_put(bn);
+ return ret;
+ }
+ bn = of_find_compatible_node(bn, NULL, "ibm,bsr");
+ }
+ return 0;
}
static int __init bsr_init(void)
@@ -254,7 +280,7 @@ static int __init bsr_init(void)
int ret = -ENODEV;
int result;
- np = of_find_compatible_node(NULL, "ibm,bsr", "ibm,bsr");
+ np = of_find_compatible_node(NULL, NULL, "ibm,bsr");
if (!np)
goto out_err;
@@ -272,10 +298,10 @@ static int __init bsr_init(void)
goto out_err_2;
}
- if ((ret = bsr_create_devs(np)) < 0)
+ if ((ret = bsr_create_devs(np)) < 0) {
+ np = NULL;
goto out_err_3;
-
- of_node_put(np);
+ }
return 0;
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 5b819b12675a..fb57f67bb427 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -642,8 +642,11 @@ int hvc_poll(struct hvc_struct *hp)
/* Handle the SysRq Hack */
/* XXX should support a sequence */
if (buf[i] == '\x0f') { /* ^O */
- sysrq_pressed = 1;
- continue;
+ /* if ^O is pressed again, reset
+ * sysrq_pressed and flip ^O char */
+ sysrq_pressed = !sysrq_pressed;
+ if (sysrq_pressed)
+ continue;
} else if (sysrq_pressed) {
handle_sysrq(buf[i], tty);
sysrq_pressed = 0;
@@ -689,10 +692,8 @@ EXPORT_SYMBOL_GPL(hvc_poll);
*/
void hvc_resize(struct hvc_struct *hp, struct winsize ws)
{
- if ((hp->ws.ws_row != ws.ws_row) || (hp->ws.ws_col != ws.ws_col)) {
- hp->ws = ws;
- schedule_work(&hp->tty_resize);
- }
+ hp->ws = ws;
+ schedule_work(&hp->tty_resize);
}
/*
diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h
index 8297dbc2e6ec..3c85d78c975c 100644
--- a/drivers/char/hvc_console.h
+++ b/drivers/char/hvc_console.h
@@ -48,7 +48,7 @@ struct hvc_struct {
spinlock_t lock;
int index;
struct tty_struct *tty;
- unsigned int count;
+ int count;
int do_wakeup;
char *outbuf;
int outbuf_size;
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index b74a2f8ab908..449727b6166d 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -575,8 +575,10 @@ static int __init hvc_find_vtys(void)
* of console adapters.
*/
if ((num_found >= MAX_NR_HVC_CONSOLES) ||
- (num_found >= VTTY_PORTS))
+ (num_found >= VTTY_PORTS)) {
+ of_node_put(vty);
break;
+ }
vtermno = of_get_property(vty, "reg", NULL);
if (!vtermno)
diff --git a/drivers/char/hvc_udbg.c b/drivers/char/hvc_udbg.c
new file mode 100644
index 000000000000..bd63ba878a56
--- /dev/null
+++ b/drivers/char/hvc_udbg.c
@@ -0,0 +1,96 @@
+/*
+ * udbg interface to hvc_console.c
+ *
+ * (C) Copyright David Gibson, IBM Corporation 2008.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/irq.h>
+
+#include <asm/udbg.h>
+
+#include "hvc_console.h"
+
+struct hvc_struct *hvc_udbg_dev;
+
+static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ udbg_putc(buf[i]);
+
+ return i;
+}
+
+static int hvc_udbg_get(uint32_t vtermno, char *buf, int count)
+{
+ int i, c;
+
+ if (!udbg_getc_poll)
+ return 0;
+
+ for (i = 0; i < count; i++) {
+ if ((c = udbg_getc_poll()) == -1)
+ break;
+ buf[i] = c;
+ }
+
+ return i;
+}
+
+static struct hv_ops hvc_udbg_ops = {
+ .get_chars = hvc_udbg_get,
+ .put_chars = hvc_udbg_put,
+};
+
+static int __init hvc_udbg_init(void)
+{
+ struct hvc_struct *hp;
+
+ BUG_ON(hvc_udbg_dev);
+
+ hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16);
+ if (IS_ERR(hp))
+ return PTR_ERR(hp);
+
+ hvc_udbg_dev = hp;
+
+ return 0;
+}
+module_init(hvc_udbg_init);
+
+static void __exit hvc_udbg_exit(void)
+{
+ if (hvc_udbg_dev)
+ hvc_remove(hvc_udbg_dev);
+}
+module_exit(hvc_udbg_exit);
+
+static int __init hvc_udbg_console_init(void)
+{
+ hvc_instantiate(0, 0, &hvc_udbg_ops);
+ add_preferred_console("hvc", 0, NULL);
+
+ return 0;
+}
+console_initcall(hvc_udbg_console_init);
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index 019e0b58593d..bd62dc86b47d 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -153,8 +153,10 @@ static int hvc_find_vtys(void)
/* We have statically defined space for only a certain number
* of console adapters.
*/
- if (num_found >= MAX_NR_HVC_CONSOLES)
+ if (num_found >= MAX_NR_HVC_CONSOLES) {
+ of_node_put(vty);
break;
+ }
vtermno = of_get_property(vty, "reg", NULL);
if (!vtermno)
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index 473d9b14439a..6e6eb445d374 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -269,7 +269,7 @@ struct hvcs_struct {
unsigned int index;
struct tty_struct *tty;
- unsigned int open_count;
+ int open_count;
/*
* Used to tell the driver kernel_thread what operations need to take
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index 59c6f9ab94e4..af055287271a 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -75,7 +75,7 @@ struct hvsi_struct {
spinlock_t lock;
int index;
struct tty_struct *tty;
- unsigned int count;
+ int count;
uint8_t throttle_buf[128];
uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */
/* inbuf is for packet reassembly. leave a little room for leftovers. */
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index e0dbd388757f..e2667a8c2997 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -161,7 +161,7 @@ config EDAC_PASEMI
config EDAC_CELL
tristate "Cell Broadband Engine memory controller"
- depends on EDAC_MM_EDAC && PPC_CELL_NATIVE
+ depends on EDAC_MM_EDAC && PPC_CELL_COMMON
help
Support for error detection and correction on the
Cell Broadband Engine internal memory controller
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index d524dc245a2c..b40fb9b6c862 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -1814,7 +1814,7 @@ static int powerbook_sleep_grackle(void)
_set_L2CR(save_l2cr);
/* Restore userland MMU context */
- set_context(current->active_mm->context.id, current->active_mm->pgd);
+ switch_mmu_context(NULL, current->active_mm);
/* Power things up */
pmu_unlock();
@@ -1903,7 +1903,7 @@ powerbook_sleep_Core99(void)
_set_L3CR(save_l3cr);
/* Restore userland MMU context */
- set_context(current->active_mm->context.id, current->active_mm->pgd);
+ switch_mmu_context(NULL, current->active_mm);
/* Tell PMU we are ready */
pmu_unlock();
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index 7f2be4baaeda..7847e981ac33 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -87,11 +87,12 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id,
return NULL;
}
- len = i2c_smbus_read_word_data(&sat->i2c, 9);
- if (len < 0) {
+ err = i2c_smbus_read_word_data(&sat->i2c, 9);
+ if (err < 0) {
printk(KERN_ERR "smu_sat_get_sdb_part rd len error\n");
return NULL;
}
+ len = err;
if (len == 0) {
printk(KERN_ERR "smu_sat_get_sdb_part no partition %x\n", id);
return NULL;
diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c
index 45dd9bdc5d62..dd9bfa42ac34 100644
--- a/drivers/net/fec_mpc52xx_phy.c
+++ b/drivers/net/fec_mpc52xx_phy.c
@@ -122,9 +122,6 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of,
out_be32(&priv->regs->mii_speed,
((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1);
- /* enable MII interrupt */
- out_be32(&priv->regs->imask, in_be32(&priv->regs->imask) | FEC_IMASK_MII);
-
err = mdiobus_register(bus);
if (err)
goto out_unmap;
@@ -156,7 +153,7 @@ static int mpc52xx_fec_mdio_remove(struct of_device *of)
iounmap(priv->regs);
for (i=0; i<PHY_MAX_ADDR; i++)
- if (bus->irq[i])
+ if (bus->irq[i] != PHY_POLL)
irq_dispose_mapping(bus->irq[i]);
kfree(priv);
kfree(bus->irq);
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 7c79e94a35ea..cd17092b82bd 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -329,6 +329,41 @@ struct device_node *of_find_compatible_node(struct device_node *from,
EXPORT_SYMBOL(of_find_compatible_node);
/**
+ * of_find_node_with_property - Find a node which has a property with
+ * the given name.
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned. of_node_put() will be called on it
+ * @prop_name: The name of the property to look for.
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_with_property(struct device_node *from,
+ const char *prop_name)
+{
+ struct device_node *np;
+ struct property *pp;
+
+ read_lock(&devtree_lock);
+ np = from ? from->allnext : allnodes;
+ for (; np; np = np->allnext) {
+ for (pp = np->properties; pp != 0; pp = pp->next) {
+ if (of_prop_cmp(pp->name, prop_name) == 0) {
+ of_node_get(np);
+ goto out;
+ }
+ }
+ }
+out:
+ of_node_put(from);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_with_property);
+
+/**
* of_match_node - Tell if an device_node has a matching of_match structure
* @matches: array of of device match structures to search in
* @node: the of device structure to match against
@@ -464,8 +499,8 @@ EXPORT_SYMBOL_GPL(of_modalias_node);
* @list_name: property name that contains a list
* @cells_name: property name that specifies phandles' arguments count
* @index: index of a phandle to parse out
- * @out_node: pointer to device_node struct pointer (will be filled)
- * @out_args: pointer to arguments pointer (will be filled)
+ * @out_node: optional pointer to device_node struct pointer (will be filled)
+ * @out_args: optional pointer to arguments pointer (will be filled)
*
* This function is useful to parse lists of phandles and their arguments.
* Returns 0 on success and fills out_node and out_args, on error returns
@@ -499,7 +534,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
int size;
int cur_index = 0;
struct device_node *node = NULL;
- const void *args;
+ const void *args = NULL;
list = of_get_property(np, list_name, &size);
if (!list) {
@@ -512,14 +547,12 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
const u32 *cells;
const phandle *phandle;
- phandle = list;
- args = list + 1;
+ phandle = list++;
+ args = list;
/* one cell hole in the list = <>; */
- if (!*phandle) {
- list++;
+ if (!*phandle)
goto next;
- }
node = of_find_node_by_phandle(*phandle);
if (!node) {
@@ -535,8 +568,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
goto err1;
}
- /* Next phandle is at offset of one phandle cell + #cells */
- list += 1 + *cells;
+ list += *cells;
if (list > list_end) {
pr_debug("%s: insufficient arguments length\n",
np->full_name);
@@ -548,16 +580,26 @@ next:
of_node_put(node);
node = NULL;
+ args = NULL;
cur_index++;
}
if (!node) {
- ret = -ENOENT;
+ /*
+ * args w/o node indicates that the loop above has stopped at
+ * the 'hole' cell. Report this differently.
+ */
+ if (args)
+ ret = -EEXIST;
+ else
+ ret = -ENOENT;
goto err0;
}
- *out_node = node;
- *out_args = args;
+ if (out_node)
+ *out_node = node;
+ if (out_args)
+ *out_args = args;
return 0;
err1:
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
index 7cd7301b5839..6eea601a9204 100644
--- a/drivers/of/gpio.c
+++ b/drivers/of/gpio.c
@@ -19,14 +19,17 @@
#include <asm/prom.h>
/**
- * of_get_gpio - Get a GPIO number from the device tree to use with GPIO API
+ * of_get_gpio_flags - Get a GPIO number and flags to use with GPIO API
* @np: device node to get GPIO from
* @index: index of the GPIO
+ * @flags: a flags pointer to fill in
*
* Returns GPIO number to use with Linux generic GPIO API, or one of the errno
- * value on the error condition.
+ * value on the error condition. If @flags is not NULL the function also fills
+ * in flags for the GPIO.
*/
-int of_get_gpio(struct device_node *np, int index)
+int of_get_gpio_flags(struct device_node *np, int index,
+ enum of_gpio_flags *flags)
{
int ret;
struct device_node *gc;
@@ -59,7 +62,11 @@ int of_get_gpio(struct device_node *np, int index)
goto err1;
}
- ret = of_gc->xlate(of_gc, np, gpio_spec);
+ /* .xlate might decide to not fill in the flags, so clear it. */
+ if (flags)
+ *flags = 0;
+
+ ret = of_gc->xlate(of_gc, np, gpio_spec, flags);
if (ret < 0)
goto err1;
@@ -70,26 +77,75 @@ err0:
pr_debug("%s exited with status %d\n", __func__, ret);
return ret;
}
-EXPORT_SYMBOL(of_get_gpio);
+EXPORT_SYMBOL(of_get_gpio_flags);
/**
- * of_gpio_simple_xlate - translate gpio_spec to the GPIO number
+ * of_gpio_count - Count GPIOs for a device
+ * @np: device node to count GPIOs for
+ *
+ * The function returns the count of GPIOs specified for a node.
+ *
+ * Note that the empty GPIO specifiers counts too. For example,
+ *
+ * gpios = <0
+ * &pio1 1 2
+ * 0
+ * &pio2 3 4>;
+ *
+ * defines four GPIOs (so this function will return 4), two of which
+ * are not specified.
+ */
+unsigned int of_gpio_count(struct device_node *np)
+{
+ unsigned int cnt = 0;
+
+ do {
+ int ret;
+
+ ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells",
+ cnt, NULL, NULL);
+ /* A hole in the gpios = <> counts anyway. */
+ if (ret < 0 && ret != -EEXIST)
+ break;
+ } while (++cnt);
+
+ return cnt;
+}
+EXPORT_SYMBOL(of_gpio_count);
+
+/**
+ * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
* @of_gc: pointer to the of_gpio_chip structure
* @np: device node of the GPIO chip
* @gpio_spec: gpio specifier as found in the device tree
+ * @flags: a flags pointer to fill in
*
* This is simple translation function, suitable for the most 1:1 mapped
* gpio chips. This function performs only one sanity check: whether gpio
* is less than ngpios (that is specified in the gpio_chip).
*/
int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np,
- const void *gpio_spec)
+ const void *gpio_spec, enum of_gpio_flags *flags)
{
const u32 *gpio = gpio_spec;
+ /*
+ * We're discouraging gpio_cells < 2, since that way you'll have to
+ * write your own xlate function (that will have to retrive the GPIO
+ * number and the flags from a single gpio cell -- this is possible,
+ * but not recommended).
+ */
+ if (of_gc->gpio_cells < 2) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
if (*gpio > of_gc->gc.ngpio)
return -EINVAL;
+ if (flags)
+ *flags = gpio[1];
+
return *gpio;
}
EXPORT_SYMBOL(of_gpio_simple_xlate);
diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c
index 24bbef777c19..e1b0ad6e918f 100644
--- a/drivers/of/of_i2c.c
+++ b/drivers/of/of_i2c.c
@@ -24,6 +24,7 @@ void of_register_i2c_devices(struct i2c_adapter *adap,
for_each_child_of_node(adap_node, node) {
struct i2c_board_info info = {};
+ struct dev_archdata dev_ad = {};
const u32 *addr;
int len;
@@ -41,6 +42,9 @@ void of_register_i2c_devices(struct i2c_adapter *adap,
info.addr = *addr;
+ dev_archdata_set_node(&dev_ad, node);
+ info.archdata = &dev_ad;
+
request_module("%s", info.type);
result = i2c_new_device(adap, &info);
@@ -51,6 +55,13 @@ void of_register_i2c_devices(struct i2c_adapter *adap,
irq_dispose_mapping(info.irq);
continue;
}
+
+ /*
+ * Get the node to not lose the dev_archdata->of_node.
+ * Currently there is no way to put it back, as well as no
+ * of_unregister_i2c_devices() call.
+ */
+ of_node_get(node);
}
}
EXPORT_SYMBOL(of_register_i2c_devices);
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index 9c2a22fed18b..4e3e0382c16e 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -14,6 +14,9 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+
+#undef DEBUG
+
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/string.h>
@@ -151,20 +154,20 @@ static void dlpar_pci_add_bus(struct device_node *dn)
return;
}
+ /* Scan below the new bridge */
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
of_scan_pci_bridge(dn, dev);
- pcibios_fixup_new_pci_devices(dev->subordinate);
-
- /* Claim new bus resources */
- pcibios_claim_one_bus(dev->bus);
-
/* Map IO space for child bus, which may or may not succeed */
pcibios_map_io_space(dev->subordinate);
- /* Add new devices to global lists. Register in proc, sysfs. */
- pci_bus_add_devices(phb->bus);
+ /* Finish adding it : resource allocation, adding devices, etc...
+ * Note that we need to perform the finish pass on the -parent-
+ * bus of the EADS bridge so the bridge device itself gets
+ * properly added
+ */
+ pcibios_finish_adding_to_bus(phb->bus);
}
static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
@@ -203,27 +206,6 @@ static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
return 0;
}
-static int dlpar_remove_root_bus(struct pci_controller *phb)
-{
- struct pci_bus *phb_bus;
- int rc;
-
- phb_bus = phb->bus;
- if (!(list_empty(&phb_bus->children) &&
- list_empty(&phb_bus->devices))) {
- return -EBUSY;
- }
-
- rc = pcibios_remove_root_bus(phb);
- if (rc)
- return -EIO;
-
- device_unregister(phb_bus->bridge);
- pci_remove_bus(phb_bus);
-
- return 0;
-}
-
static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
{
struct slot *slot;
@@ -235,18 +217,15 @@ static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
/* If pci slot is hotplugable, use hotplug to remove it */
slot = find_php_slot(dn);
- if (slot) {
- if (rpaphp_deregister_slot(slot)) {
- printk(KERN_ERR
- "%s: unable to remove hotplug slot %s\n",
- __func__, drc_name);
- return -EIO;
- }
+ if (slot && rpaphp_deregister_slot(slot)) {
+ printk(KERN_ERR "%s: unable to remove hotplug slot %s\n",
+ __func__, drc_name);
+ return -EIO;
}
pdn = dn->data;
BUG_ON(!pdn || !pdn->phb);
- rc = dlpar_remove_root_bus(pdn->phb);
+ rc = remove_phb_dynamic(pdn->phb);
if (rc < 0)
return rc;
@@ -378,26 +357,38 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
if (!bus)
return -EINVAL;
- /* If pci slot is hotplugable, use hotplug to remove it */
+ pr_debug("PCI: Removing PCI slot below EADS bridge %s\n",
+ bus->self ? pci_name(bus->self) : "<!PHB!>");
+
slot = find_php_slot(dn);
if (slot) {
+ pr_debug("PCI: Removing hotplug slot for %04x:%02x...\n",
+ pci_domain_nr(bus), bus->number);
+
if (rpaphp_deregister_slot(slot)) {
printk(KERN_ERR
"%s: unable to remove hotplug slot %s\n",
__func__, drc_name);
return -EIO;
}
- } else
- pcibios_remove_pci_devices(bus);
+ }
+
+ /* Remove all devices below slot */
+ pcibios_remove_pci_devices(bus);
+ /* Unmap PCI IO space */
if (pcibios_unmap_io_space(bus)) {
printk(KERN_ERR "%s: failed to unmap bus range\n",
__func__);
return -ERANGE;
}
+ /* Remove the EADS bridge device itself */
BUG_ON(!bus->self);
+ pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
+ eeh_remove_bus_device(bus->self);
pci_remove_bus_device(bus->self);
+
return 0;
}
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index 06848b254d57..5324978b73fb 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -59,8 +59,6 @@ static struct ps3av {
struct ps3av_reply_hdr reply_hdr;
u8 raw[PS3AV_BUF_SIZE];
} recv_buf;
- void (*flip_ctl)(int on, void *data);
- void *flip_data;
} *ps3av;
/* color space */
@@ -939,24 +937,6 @@ int ps3av_audio_mute(int mute)
EXPORT_SYMBOL_GPL(ps3av_audio_mute);
-void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data),
- void *flip_data)
-{
- mutex_lock(&ps3av->mutex);
- ps3av->flip_ctl = flip_ctl;
- ps3av->flip_data = flip_data;
- mutex_unlock(&ps3av->mutex);
-}
-EXPORT_SYMBOL_GPL(ps3av_register_flip_ctl);
-
-void ps3av_flip_ctl(int on)
-{
- mutex_lock(&ps3av->mutex);
- if (ps3av->flip_ctl)
- ps3av->flip_ctl(on, ps3av->flip_data);
- mutex_unlock(&ps3av->mutex);
-}
-
static int ps3av_probe(struct ps3_system_bus_device *dev)
{
int res;
diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c
index 11eb50318fec..716596e8e5b0 100644
--- a/drivers/ps3/ps3av_cmd.c
+++ b/drivers/ps3/ps3av_cmd.c
@@ -864,7 +864,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len)
{
int res;
- ps3av_flip_ctl(0); /* flip off */
+ mutex_lock(&ps3_gpu_mutex);
/* avb packet */
res = ps3av_do_pkt(PS3AV_CID_AVB_PARAM, send_len, sizeof(*avb),
@@ -878,7 +878,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len)
res);
out:
- ps3av_flip_ctl(1); /* flip on */
+ mutex_unlock(&ps3_gpu_mutex);
return res;
}
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 643a6b98462b..5c13f61bfb1b 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -365,15 +365,15 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
rdid++)
rswitch->route_table[rdid] = RIO_INVALID_ROUTE;
rdev->rswitch = rswitch;
- sprintf(rio_name(rdev), "%02x:s:%04x", rdev->net->id,
- rdev->rswitch->switchid);
+ dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id,
+ rdev->rswitch->switchid);
rio_route_set_ops(rdev);
list_add_tail(&rswitch->node, &rio_switches);
} else
- sprintf(rio_name(rdev), "%02x:e:%04x", rdev->net->id,
- rdev->destid);
+ dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id,
+ rdev->destid);
rdev->dev.bus = &rio_bus_type;
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 28c00c3d58f5..0c3a2ab1612c 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -429,14 +429,24 @@ mpc52xx_uart_tx_empty(struct uart_port *port)
static void
mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- /* Not implemented */
+ if (mctrl & TIOCM_RTS)
+ out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS);
+ else
+ out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS);
}
static unsigned int
mpc52xx_uart_get_mctrl(struct uart_port *port)
{
- /* Not implemented */
- return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+ unsigned int ret = TIOCM_DSR;
+ u8 status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
+
+ if (!(status & MPC52xx_PSC_CTS))
+ ret |= TIOCM_CTS;
+ if (!(status & MPC52xx_PSC_DCD))
+ ret |= TIOCM_CAR;
+
+ return ret;
}
static void
@@ -479,7 +489,15 @@ mpc52xx_uart_stop_rx(struct uart_port *port)
static void
mpc52xx_uart_enable_ms(struct uart_port *port)
{
- /* Not implemented */
+ struct mpc52xx_psc __iomem *psc = PSC(port);
+
+ /* clear D_*-bits by reading them */
+ in_8(&psc->mpc52xx_psc_ipcr);
+ /* enable CTS and DCD as IPC interrupts */
+ out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD);
+
+ port->read_status_mask |= MPC52xx_PSC_IMR_IPC;
+ out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
}
static void
@@ -580,6 +598,10 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
MPC52xx_PSC_MODE_ONE_STOP_5_BITS :
MPC52xx_PSC_MODE_ONE_STOP;
+ if (new->c_cflag & CRTSCTS) {
+ mr1 |= MPC52xx_PSC_MODE_RXRTS;
+ mr2 |= MPC52xx_PSC_MODE_TXCTS;
+ }
baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
@@ -617,6 +639,9 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
out_8(&psc->ctur, ctr >> 8);
out_8(&psc->ctlr, ctr & 0xff);
+ if (UART_ENABLE_MS(port, new->c_cflag))
+ mpc52xx_uart_enable_ms(port);
+
/* Reenable TX & RX */
out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
@@ -752,10 +777,15 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
if (status & MPC52xx_PSC_SR_RB) {
flag = TTY_BREAK;
uart_handle_break(port);
- } else if (status & MPC52xx_PSC_SR_PE)
+ port->icount.brk++;
+ } else if (status & MPC52xx_PSC_SR_PE) {
flag = TTY_PARITY;
- else if (status & MPC52xx_PSC_SR_FE)
+ port->icount.parity++;
+ }
+ else if (status & MPC52xx_PSC_SR_FE) {
flag = TTY_FRAME;
+ port->icount.frame++;
+ }
/* Clear error condition */
out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT);
@@ -769,6 +799,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
* affect the current character
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ port->icount.overrun++;
}
}
@@ -826,6 +857,7 @@ mpc52xx_uart_int(int irq, void *dev_id)
struct uart_port *port = dev_id;
unsigned long pass = ISR_PASS_LIMIT;
unsigned int keepgoing;
+ u8 status;
spin_lock(&port->lock);
@@ -842,6 +874,13 @@ mpc52xx_uart_int(int irq, void *dev_id)
if (psc_ops->tx_rdy(port))
keepgoing |= mpc52xx_uart_int_tx_chars(port);
+ status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
+ if (status & MPC52xx_PSC_D_DCD)
+ uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD));
+
+ if (status & MPC52xx_PSC_D_CTS)
+ uart_handle_cts_change(port, !(status & MPC52xx_PSC_CTS));
+
/* Limit number of iteration */
if (!(--pass))
keepgoing = 0;
@@ -1109,22 +1148,29 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
return ret;
port->mapbase = res.start;
+ if (!port->mapbase) {
+ dev_dbg(&op->dev, "Could not allocate resources for PSC\n");
+ return -EINVAL;
+ }
+
port->irq = irq_of_parse_and_map(op->node, 0);
+ if (port->irq == NO_IRQ) {
+ dev_dbg(&op->dev, "Could not get irq\n");
+ return -EINVAL;
+ }
dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n",
(void *)port->mapbase, port->irq, port->uartclk);
- if ((port->irq == NO_IRQ) || !port->mapbase) {
- printk(KERN_ERR "Could not allocate resources for PSC\n");
- return -EINVAL;
- }
-
/* Add the port to the uart sub-system */
ret = uart_add_one_port(&mpc52xx_uart_driver, port);
- if (!ret)
- dev_set_drvdata(&op->dev, (void *)port);
+ if (ret) {
+ irq_dispose_mapping(port->irq);
+ return ret;
+ }
- return ret;
+ dev_set_drvdata(&op->dev, (void *)port);
+ return 0;
}
static int
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 317b061f7641..ad3488504010 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -1383,6 +1383,29 @@ static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser)
return -EINVAL;
}
+#ifdef CONFIG_CONSOLE_POLL
+
+static int pmz_poll_get_char(struct uart_port *port)
+{
+ struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+ while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0)
+ udelay(5);
+ return read_zsdata(uap);
+}
+
+static void pmz_poll_put_char(struct uart_port *port, unsigned char c)
+{
+ struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+ /* Wait for the transmit buffer to empty. */
+ while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
+ udelay(5);
+ write_zsdata(uap, c);
+}
+
+#endif
+
static struct uart_ops pmz_pops = {
.tx_empty = pmz_tx_empty,
.set_mctrl = pmz_set_mctrl,
@@ -1400,6 +1423,10 @@ static struct uart_ops pmz_pops = {
.request_port = pmz_request_port,
.config_port = pmz_config_port,
.verify_port = pmz_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = pmz_poll_get_char,
+ .poll_put_char = pmz_poll_put_char,
+#endif
};
/*
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index b0be7eac32d8..49fcbe8f18ac 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -298,10 +298,10 @@ static int controlfb_mmap(struct fb_info *info,
return -EINVAL;
start = info->fix.mmio_start;
len = PAGE_ALIGN((start & ~PAGE_MASK)+info->fix.mmio_len);
- pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
} else {
/* framebuffer */
- pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU;
+ vma->vm_page_prot = pgprot_cached_wthru(vma->vm_page_prot);
}
start &= PAGE_MASK;
if ((vma->vm_end - vma->vm_start + off) > len)
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 4b5d80771904..38ac805db97d 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -460,12 +460,16 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
line_length |= (u64)src_line_length << 32;
src_offset += GPU_FB_START;
+
+ mutex_lock(&ps3_gpu_mutex);
status = lv1_gpu_context_attribute(ps3fb.context_handle,
L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
dst_offset, GPU_IOIF + src_offset,
L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
(width << 16) | height,
line_length);
+ mutex_unlock(&ps3_gpu_mutex);
+
if (status)
dev_err(dev,
"%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
@@ -784,15 +788,6 @@ static int ps3fb_wait_for_vsync(u32 crtc)
return 0;
}
-static void ps3fb_flip_ctl(int on, void *data)
-{
- struct ps3fb_priv *priv = data;
- if (on)
- atomic_dec_if_positive(&priv->ext_flip);
- else
- atomic_inc(&priv->ext_flip);
-}
-
/*
* ioctl
@@ -1228,7 +1223,6 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
}
ps3fb.task = task;
- ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb);
return 0;
@@ -1258,10 +1252,9 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
- ps3fb_flip_ctl(0, &ps3fb); /* flip off */
+ atomic_inc(&ps3fb.ext_flip); /* flip off */
ps3fb.dinfo->irq.mask = 0;
- ps3av_register_flip_ctl(NULL, NULL);
if (ps3fb.task) {
struct task_struct *task = ps3fb.task;
ps3fb.task = NULL;
@@ -1296,8 +1289,8 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
}
static struct ps3_system_bus_driver ps3fb_driver = {
- .match_id = PS3_MATCH_ID_GRAPHICS,
- .match_sub_id = PS3_MATCH_SUB_ID_FB,
+ .match_id = PS3_MATCH_ID_GPU,
+ .match_sub_id = PS3_MATCH_SUB_ID_GPU_FB,
.core.name = DEVICE_NAME,
.core.owner = THIS_MODULE,
.probe = ps3fb_probe,
@@ -1355,4 +1348,4 @@ module_exit(ps3fb_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver");
MODULE_AUTHOR("Sony Computer Entertainment Inc.");
-MODULE_ALIAS(PS3_MODULE_ALIAS_GRAPHICS);
+MODULE_ALIAS(PS3_MODULE_ALIAS_GPU_FB);