include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / arch / powerpc / sysdev / fsl_rio.c
index d2d1470..71fba88 100644 (file)
 #include <linux/types.h>
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
+#include <linux/device.h>
 #include <linux/rio.h>
 #include <linux/rio_drv.h>
 #include <linux/of_platform.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
 
 #include <asm/io.h>
 
 #define IRQ_RIO_RX(m)          (((struct rio_priv *)(m->priv))->rxirq)
 
 #define RIO_ATMU_REGS_OFFSET   0x10c00
-#define RIO_MSG_REGS_OFFSET    0x11000
+#define RIO_P_MSG_REGS_OFFSET  0x11000
+#define RIO_S_MSG_REGS_OFFSET  0x13000
+#define RIO_ESCSR              0x158
+#define RIO_CCSR               0x15c
+#define RIO_ISR_AACR           0x10120
+#define RIO_ISR_AACR_AA                0x1     /* Accept All ID */
 #define RIO_MAINT_WIN_SIZE     0x400000
 #define RIO_DBELL_WIN_SIZE     0x1000
 
 #define DOORBELL_DSR_TE                0x00000080
 #define DOORBELL_DSR_QFI       0x00000010
 #define DOORBELL_DSR_DIQI      0x00000001
-#define DOORBELL_TID_OFFSET    0x03
-#define DOORBELL_SID_OFFSET    0x05
+#define DOORBELL_TID_OFFSET    0x02
+#define DOORBELL_SID_OFFSET    0x04
 #define DOORBELL_INFO_OFFSET   0x06
 
 #define DOORBELL_MESSAGE_SIZE  0x08
-#define DBELL_SID(x)           (*(u8 *)(x + DOORBELL_SID_OFFSET))
-#define DBELL_TID(x)           (*(u8 *)(x + DOORBELL_TID_OFFSET))
+#define DBELL_SID(x)           (*(u16 *)(x + DOORBELL_SID_OFFSET))
+#define DBELL_TID(x)           (*(u16 *)(x + DOORBELL_TID_OFFSET))
 #define DBELL_INF(x)           (*(u16 *)(x + DOORBELL_INFO_OFFSET))
 
 struct rio_atmu_regs {
        u32 rowtar;
-       u32 pad1;
+       u32 rowtear;
        u32 rowbar;
        u32 pad2;
        u32 rowar;
@@ -95,7 +103,15 @@ struct rio_msg_regs {
        u32 ifqdpar;
        u32 pad6;
        u32 ifqepar;
-       u32 pad7[250];
+       u32 pad7[226];
+       u32 odmr;
+       u32 odsr;
+       u32 res0[4];
+       u32 oddpr;
+       u32 oddatr;
+       u32 res1[3];
+       u32 odretcr;
+       u32 res2[12];
        u32 dmr;
        u32 dsr;
        u32 pad8;
@@ -145,6 +161,7 @@ struct rio_msg_rx_ring {
 };
 
 struct rio_priv {
+       struct device *dev;
        void __iomem *regs_win;
        struct rio_atmu_regs __iomem *atmu_regs;
        struct rio_atmu_regs __iomem *maint_atmu_regs;
@@ -162,6 +179,7 @@ struct rio_priv {
 
 /**
  * fsl_rio_doorbell_send - Send a MPC85xx doorbell message
+ * @mport: RapidIO master port info
  * @index: ID of RapidIO interface
  * @destid: Destination ID of target device
  * @data: 16-bit info field of RapidIO doorbell message
@@ -175,14 +193,29 @@ static int fsl_rio_doorbell_send(struct rio_mport *mport,
        struct rio_priv *priv = mport->priv;
        pr_debug("fsl_doorbell_send: index %d destid %4.4x data %4.4x\n",
                 index, destid, data);
-       out_be32(&priv->dbell_atmu_regs->rowtar, destid << 22);
-       out_be16(priv->dbell_win, data);
+       switch (mport->phy_type) {
+       case RIO_PHY_PARALLEL:
+               out_be32(&priv->dbell_atmu_regs->rowtar, destid << 22);
+               out_be16(priv->dbell_win, data);
+               break;
+       case RIO_PHY_SERIAL:
+               /* In the serial version silicons, such as MPC8548, MPC8641,
+                * below operations is must be.
+                */
+               out_be32(&priv->msg_regs->odmr, 0x00000000);
+               out_be32(&priv->msg_regs->odretcr, 0x00000004);
+               out_be32(&priv->msg_regs->oddpr, destid << 16);
+               out_be32(&priv->msg_regs->oddatr, data);
+               out_be32(&priv->msg_regs->odmr, 0x00000001);
+               break;
+       }
 
        return 0;
 }
 
 /**
  * fsl_local_config_read - Generate a MPC85xx local config space read
+ * @mport: RapidIO master port info
  * @index: ID of RapdiIO interface
  * @offset: Offset into configuration space
  * @len: Length (in bytes) of the maintenance transaction
@@ -204,6 +237,7 @@ static int fsl_local_config_read(struct rio_mport *mport,
 
 /**
  * fsl_local_config_write - Generate a MPC85xx local config space write
+ * @mport: RapidIO master port info
  * @index: ID of RapdiIO interface
  * @offset: Offset into configuration space
  * @len: Length (in bytes) of the maintenance transaction
@@ -226,6 +260,7 @@ static int fsl_local_config_write(struct rio_mport *mport,
 
 /**
  * fsl_rio_config_read - Generate a MPC85xx read maintenance transaction
+ * @mport: RapidIO master port info
  * @index: ID of RapdiIO interface
  * @destid: Destination ID of transaction
  * @hopcount: Number of hops to target device
@@ -267,6 +302,7 @@ fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid,
 
 /**
  * fsl_rio_config_write - Generate a MPC85xx write maintenance transaction
+ * @mport: RapidIO master port info
  * @index: ID of RapdiIO interface
  * @destid: Destination ID of transaction
  * @hopcount: Number of hops to target device
@@ -342,11 +378,22 @@ rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
                memset(priv->msg_tx_ring.virt_buffer[priv->msg_tx_ring.tx_slot]
                                + len, 0, RIO_MAX_MSG_SIZE - len);
 
-       /* Set mbox field for message */
-       desc->dport = mbox & 0x3;
+       switch (mport->phy_type) {
+       case RIO_PHY_PARALLEL:
+               /* Set mbox field for message */
+               desc->dport = mbox & 0x3;
 
-       /* Enable EOMI interrupt, set priority, and set destid */
-       desc->dattr = 0x28000000 | (rdev->destid << 2);
+               /* Enable EOMI interrupt, set priority, and set destid */
+               desc->dattr = 0x28000000 | (rdev->destid << 2);
+               break;
+       case RIO_PHY_SERIAL:
+               /* Set mbox field for message, and set destid */
+               desc->dport = (rdev->destid << 16) | (mbox & 0x3);
+
+               /* Enable EOMI interrupt and priority */
+               desc->dattr = 0x28000000;
+               break;
+       }
 
        /* Set transfer size aligned to next power of 2 (in double words) */
        desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len);
@@ -440,13 +487,13 @@ int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entr
 
        for (i = 0; i < priv->msg_tx_ring.size; i++) {
                priv->msg_tx_ring.virt_buffer[i] =
-                       dma_alloc_coherent(NULL, RIO_MSG_BUFFER_SIZE,
+                       dma_alloc_coherent(priv->dev, RIO_MSG_BUFFER_SIZE,
                                &priv->msg_tx_ring.phys_buffer[i], GFP_KERNEL);
                if (!priv->msg_tx_ring.virt_buffer[i]) {
                        rc = -ENOMEM;
                        for (j = 0; j < priv->msg_tx_ring.size; j++)
                                if (priv->msg_tx_ring.virt_buffer[j])
-                                       dma_free_coherent(NULL,
+                                       dma_free_coherent(priv->dev,
                                                        RIO_MSG_BUFFER_SIZE,
                                                        priv->msg_tx_ring.
                                                        virt_buffer[j],
@@ -457,7 +504,7 @@ int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entr
        }
 
        /* Initialize outbound message descriptor ring */
-       priv->msg_tx_ring.virt = dma_alloc_coherent(NULL,
+       priv->msg_tx_ring.virt = dma_alloc_coherent(priv->dev,
                                priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
                                &priv->msg_tx_ring.phys, GFP_KERNEL);
        if (!priv->msg_tx_ring.virt) {
@@ -505,12 +552,13 @@ int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entr
        return rc;
 
       out_irq:
-       dma_free_coherent(NULL, priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
+       dma_free_coherent(priv->dev,
+                         priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
                          priv->msg_tx_ring.virt, priv->msg_tx_ring.phys);
 
       out_dma:
        for (i = 0; i < priv->msg_tx_ring.size; i++)
-               dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE,
+               dma_free_coherent(priv->dev, RIO_MSG_BUFFER_SIZE,
                                  priv->msg_tx_ring.virt_buffer[i],
                                  priv->msg_tx_ring.phys_buffer[i]);
 
@@ -532,7 +580,8 @@ void rio_close_outb_mbox(struct rio_mport *mport, int mbox)
        out_be32(&priv->msg_regs->omr, 0);
 
        /* Free ring */
-       dma_free_coherent(NULL, priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
+       dma_free_coherent(priv->dev,
+                         priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
                          priv->msg_tx_ring.virt, priv->msg_tx_ring.phys);
 
        /* Free interrupt */
@@ -610,7 +659,7 @@ int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entri
                priv->msg_rx_ring.virt_buffer[i] = NULL;
 
        /* Initialize inbound message ring */
-       priv->msg_rx_ring.virt = dma_alloc_coherent(NULL,
+       priv->msg_rx_ring.virt = dma_alloc_coherent(priv->dev,
                                priv->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
                                &priv->msg_rx_ring.phys, GFP_KERNEL);
        if (!priv->msg_rx_ring.virt) {
@@ -629,7 +678,7 @@ int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entri
        rc = request_irq(IRQ_RIO_RX(mport), fsl_rio_rx_handler, 0,
                         "msg_rx", (void *)mport);
        if (rc < 0) {
-               dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE,
+               dma_free_coherent(priv->dev, RIO_MSG_BUFFER_SIZE,
                                  priv->msg_tx_ring.virt_buffer[i],
                                  priv->msg_tx_ring.phys_buffer[i]);
                goto out;
@@ -669,7 +718,7 @@ void rio_close_inb_mbox(struct rio_mport *mport, int mbox)
        out_be32(&priv->msg_regs->imr, 0);
 
        /* Free ring */
-       dma_free_coherent(NULL, priv->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
+       dma_free_coherent(priv->dev, priv->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
                          priv->msg_rx_ring.virt, priv->msg_rx_ring.phys);
 
        /* Free interrupt */
@@ -846,7 +895,7 @@ static int fsl_rio_doorbell_init(struct rio_mport *mport)
        }
 
        /* Initialize inbound doorbells */
-       priv->dbell_ring.virt = dma_alloc_coherent(NULL, 512 *
+       priv->dbell_ring.virt = dma_alloc_coherent(priv->dev, 512 *
                    DOORBELL_MESSAGE_SIZE, &priv->dbell_ring.phys, GFP_KERNEL);
        if (!priv->dbell_ring.virt) {
                printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n");
@@ -867,7 +916,7 @@ static int fsl_rio_doorbell_init(struct rio_mport *mport)
                         "dbell_rx", (void *)mport);
        if (rc < 0) {
                iounmap(priv->dbell_win);
-               dma_free_coherent(NULL, 512 * DOORBELL_MESSAGE_SIZE,
+               dma_free_coherent(priv->dev, 512 * DOORBELL_MESSAGE_SIZE,
                                  priv->dbell_ring.virt, priv->dbell_ring.phys);
                printk(KERN_ERR
                       "MPC85xx RIO: unable to request inbound doorbell irq");
@@ -903,9 +952,51 @@ static int fsl_rio_get_cmdline(char *s)
 
 __setup("riohdid=", fsl_rio_get_cmdline);
 
+static inline void fsl_rio_info(struct device *dev, u32 ccsr)
+{
+       const char *str;
+       if (ccsr & 1) {
+               /* Serial phy */
+               switch (ccsr >> 30) {
+               case 0:
+                       str = "1";
+                       break;
+               case 1:
+                       str = "4";
+                       break;
+               default:
+                       str = "Unknown";
+                       break;
+               }
+               dev_info(dev, "Hardware port width: %s\n", str);
+
+               switch ((ccsr >> 27) & 7) {
+               case 0:
+                       str = "Single-lane 0";
+                       break;
+               case 1:
+                       str = "Single-lane 2";
+                       break;
+               case 2:
+                       str = "Four-lane";
+                       break;
+               default:
+                       str = "Unknown";
+                       break;
+               }
+               dev_info(dev, "Training connection status: %s\n", str);
+       } else {
+               /* Parallel phy */
+               if (!(ccsr & 0x80000000))
+                       dev_info(dev, "Output port operating in 8-bit mode\n");
+               if (!(ccsr & 0x08000000))
+                       dev_info(dev, "Input port operating in 8-bit mode\n");
+       }
+}
+
 /**
- * fsl_rio_setup - Setup MPC85xx RapidIO interface
- * @fsl_rio_setup - Setup Freescale PowerPC RapidIO interface
+ * fsl_rio_setup - Setup Freescale PowerPC RapidIO interface
+ * @dev: of_device pointer
  *
  * Initializes MPC85xx RapidIO hardware interface, configures
  * master port with system-specific info, and registers the
@@ -920,6 +1011,7 @@ int fsl_rio_setup(struct of_device *dev)
        const u32 *dt_range, *cell;
        struct resource regs;
        int rlen;
+       u32 ccsr;
        u64 law_start, law_size;
        int paw, aw, sw;
 
@@ -935,8 +1027,7 @@ int fsl_rio_setup(struct of_device *dev)
                return -EFAULT;
        }
        dev_info(&dev->dev, "Of-device full name %s\n", dev->node->full_name);
-       dev_info(&dev->dev, "Regs start 0x%08x size 0x%08x\n",  regs.start,
-                                               regs.end - regs.start + 1);
+       dev_info(&dev->dev, "Regs: %pR\n", &regs);
 
        dt_range = of_get_property(dev->node, "ranges", &rlen);
        if (!dt_range) {
@@ -967,6 +1058,10 @@ int fsl_rio_setup(struct of_device *dev)
                        law_start, law_size);
 
        ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL);
+       if (!ops) {
+               rc = -ENOMEM;
+               goto err_ops;
+       }
        ops->lcread = fsl_local_config_read;
        ops->lcwrite = fsl_local_config_write;
        ops->cread = fsl_rio_config_read;
@@ -974,6 +1069,10 @@ int fsl_rio_setup(struct of_device *dev)
        ops->dsend = fsl_rio_doorbell_send;
 
        port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL);
+       if (!port) {
+               rc = -ENOMEM;
+               goto err_port;
+       }
        port->id = 0;
        port->index = 0;
 
@@ -981,13 +1080,14 @@ int fsl_rio_setup(struct of_device *dev)
        if (!priv) {
                printk(KERN_ERR "Can't alloc memory for 'priv'\n");
                rc = -ENOMEM;
-               goto err;
+               goto err_priv;
        }
 
        INIT_LIST_HEAD(&port->dbells);
        port->iores.start = law_start;
-       port->iores.end = law_start + law_size;
+       port->iores.end = law_start + law_size - 1;
        port->iores.flags = IORESOURCE_MEM;
+       port->iores.name = "rio_io_win";
 
        priv->bellirq = irq_of_parse_and_map(dev->node, 2);
        priv->txirq = irq_of_parse_and_map(dev->node, 3);
@@ -1000,6 +1100,8 @@ int fsl_rio_setup(struct of_device *dev)
        rio_init_mbox_res(&port->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0);
        strcpy(port->name, "RIO0 mport");
 
+       priv->dev = &dev->dev;
+
        port->ops = ops;
        port->host_deviceid = fsl_rio_get_hdid(port->id);
 
@@ -1007,31 +1109,82 @@ int fsl_rio_setup(struct of_device *dev)
        rio_register_mport(port);
 
        priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1);
+
+       /* Probe the master port phy type */
+       ccsr = in_be32(priv->regs_win + RIO_CCSR);
+       port->phy_type = (ccsr & 1) ? RIO_PHY_SERIAL : RIO_PHY_PARALLEL;
+       dev_info(&dev->dev, "RapidIO PHY type: %s\n",
+                       (port->phy_type == RIO_PHY_PARALLEL) ? "parallel" :
+                       ((port->phy_type == RIO_PHY_SERIAL) ? "serial" :
+                        "unknown"));
+       /* Checking the port training status */
+       if (in_be32((priv->regs_win + RIO_ESCSR)) & 1) {
+               dev_err(&dev->dev, "Port is not ready. "
+                                  "Try to restart connection...\n");
+               switch (port->phy_type) {
+               case RIO_PHY_SERIAL:
+                       /* Disable ports */
+                       out_be32(priv->regs_win + RIO_CCSR, 0);
+                       /* Set 1x lane */
+                       setbits32(priv->regs_win + RIO_CCSR, 0x02000000);
+                       /* Enable ports */
+                       setbits32(priv->regs_win + RIO_CCSR, 0x00600000);
+                       break;
+               case RIO_PHY_PARALLEL:
+                       /* Disable ports */
+                       out_be32(priv->regs_win + RIO_CCSR, 0x22000000);
+                       /* Enable ports */
+                       out_be32(priv->regs_win + RIO_CCSR, 0x44000000);
+                       break;
+               }
+               msleep(100);
+               if (in_be32((priv->regs_win + RIO_ESCSR)) & 1) {
+                       dev_err(&dev->dev, "Port restart failed.\n");
+                       rc = -ENOLINK;
+                       goto err;
+               }
+               dev_info(&dev->dev, "Port restart success!\n");
+       }
+       fsl_rio_info(&dev->dev, ccsr);
+
+       port->sys_size = (in_be32((priv->regs_win + RIO_PEF_CAR))
+                                       & RIO_PEF_CTLS) >> 4;
+       dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n",
+                       port->sys_size ? 65536 : 256);
+
        priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win
                                        + RIO_ATMU_REGS_OFFSET);
        priv->maint_atmu_regs = priv->atmu_regs + 1;
        priv->dbell_atmu_regs = priv->atmu_regs + 2;
-       priv->msg_regs = (struct rio_msg_regs *)(priv->regs_win
-                                                       + RIO_MSG_REGS_OFFSET);
+       priv->msg_regs = (struct rio_msg_regs *)(priv->regs_win +
+                               ((port->phy_type == RIO_PHY_SERIAL) ?
+                               RIO_S_MSG_REGS_OFFSET : RIO_P_MSG_REGS_OFFSET));
+
+       /* Set to receive any dist ID for serial RapidIO controller. */
+       if (port->phy_type == RIO_PHY_SERIAL)
+               out_be32((priv->regs_win + RIO_ISR_AACR), RIO_ISR_AACR_AA);
 
        /* Configure maintenance transaction window */
-       out_be32(&priv->maint_atmu_regs->rowbar, 0x000c0000);
-       out_be32(&priv->maint_atmu_regs->rowar, 0x80077015);
+       out_be32(&priv->maint_atmu_regs->rowbar, law_start >> 12);
+       out_be32(&priv->maint_atmu_regs->rowar, 0x80077015);    /* 4M */
 
        priv->maint_win = ioremap(law_start, RIO_MAINT_WIN_SIZE);
 
        /* Configure outbound doorbell window */
-       out_be32(&priv->dbell_atmu_regs->rowbar, 0x000c0400);
-       out_be32(&priv->dbell_atmu_regs->rowar, 0x8004200b);
+       out_be32(&priv->dbell_atmu_regs->rowbar,
+                       (law_start + RIO_MAINT_WIN_SIZE) >> 12);
+       out_be32(&priv->dbell_atmu_regs->rowar, 0x8004200b);    /* 4k */
        fsl_rio_doorbell_init(port);
 
        return 0;
 err:
-       if (priv)
-               iounmap(priv->regs_win);
-       kfree(ops);
+       iounmap(priv->regs_win);
        kfree(priv);
+err_priv:
        kfree(port);
+err_port:
+       kfree(ops);
+err_ops:
        return rc;
 }