aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/fsl_rio.c
diff options
context:
space:
mode:
authorAlexandre Bounine <alexandre.bounine@idt.com>2010-05-26 17:44:00 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-27 12:12:51 -0400
commit5b2074ae4f2baa64b59792477ea6d21c1a5ab4bd (patch)
tree0ddc3959154d5529adf6c058d814258279ce3bd5 /arch/powerpc/sysdev/fsl_rio.c
parente5cabeb3d60f9cd3e3950aff071319ae0e2d08d8 (diff)
rapidio, powerpc/85xx: add Port-Write message handler for SRIO port
Add RapidIO Port-Write message handler for Freescale SoCs with RapidIO port. Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com> Tested-by: Thomas Moll <thomas.moll@sysgo.com> Cc: Matt Porter <mporter@kernel.crashing.org> Cc: Li Yang <leoli@freescale.com> Cc: Kumar Gala <galak@kernel.crashing.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/powerpc/sysdev/fsl_rio.c')
-rw-r--r--arch/powerpc/sysdev/fsl_rio.c263
1 files changed, 260 insertions, 3 deletions
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index cb0d74927f04..73d5f3e142ab 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -1,6 +1,11 @@
1/* 1/*
2 * Freescale MPC85xx/MPC86xx RapidIO support 2 * Freescale MPC85xx/MPC86xx RapidIO support
3 * 3 *
4 * Copyright 2009 Integrated Device Technology, Inc.
5 * Alex Bounine <alexandre.bounine@idt.com>
6 * - Added Port-Write message handling
7 * - Added Machine Check exception handling
8 *
4 * Copyright (C) 2007, 2008 Freescale Semiconductor, Inc. 9 * Copyright (C) 2007, 2008 Freescale Semiconductor, Inc.
5 * Zhang Wei <wei.zhang@freescale.com> 10 * Zhang Wei <wei.zhang@freescale.com>
6 * 11 *
@@ -24,19 +29,26 @@
24#include <linux/of_platform.h> 29#include <linux/of_platform.h>
25#include <linux/delay.h> 30#include <linux/delay.h>
26#include <linux/slab.h> 31#include <linux/slab.h>
32#include <linux/kfifo.h>
27 33
28#include <asm/io.h> 34#include <asm/io.h>
29 35
36#undef DEBUG_PW /* Port-Write debugging */
37
30/* RapidIO definition irq, which read from OF-tree */ 38/* RapidIO definition irq, which read from OF-tree */
31#define IRQ_RIO_BELL(m) (((struct rio_priv *)(m->priv))->bellirq) 39#define IRQ_RIO_BELL(m) (((struct rio_priv *)(m->priv))->bellirq)
32#define IRQ_RIO_TX(m) (((struct rio_priv *)(m->priv))->txirq) 40#define IRQ_RIO_TX(m) (((struct rio_priv *)(m->priv))->txirq)
33#define IRQ_RIO_RX(m) (((struct rio_priv *)(m->priv))->rxirq) 41#define IRQ_RIO_RX(m) (((struct rio_priv *)(m->priv))->rxirq)
42#define IRQ_RIO_PW(m) (((struct rio_priv *)(m->priv))->pwirq)
34 43
35#define RIO_ATMU_REGS_OFFSET 0x10c00 44#define RIO_ATMU_REGS_OFFSET 0x10c00
36#define RIO_P_MSG_REGS_OFFSET 0x11000 45#define RIO_P_MSG_REGS_OFFSET 0x11000
37#define RIO_S_MSG_REGS_OFFSET 0x13000 46#define RIO_S_MSG_REGS_OFFSET 0x13000
38#define RIO_ESCSR 0x158 47#define RIO_ESCSR 0x158
39#define RIO_CCSR 0x15c 48#define RIO_CCSR 0x15c
49#define RIO_LTLEDCSR 0x0608
50#define RIO_LTLEECSR 0x060c
51#define RIO_EPWISR 0x10010
40#define RIO_ISR_AACR 0x10120 52#define RIO_ISR_AACR 0x10120
41#define RIO_ISR_AACR_AA 0x1 /* Accept All ID */ 53#define RIO_ISR_AACR_AA 0x1 /* Accept All ID */
42#define RIO_MAINT_WIN_SIZE 0x400000 54#define RIO_MAINT_WIN_SIZE 0x400000
@@ -55,6 +67,18 @@
55#define RIO_MSG_ISR_QFI 0x00000010 67#define RIO_MSG_ISR_QFI 0x00000010
56#define RIO_MSG_ISR_DIQI 0x00000001 68#define RIO_MSG_ISR_DIQI 0x00000001
57 69
70#define RIO_IPWMR_SEN 0x00100000
71#define RIO_IPWMR_QFIE 0x00000100
72#define RIO_IPWMR_EIE 0x00000020
73#define RIO_IPWMR_CQ 0x00000002
74#define RIO_IPWMR_PWE 0x00000001
75
76#define RIO_IPWSR_QF 0x00100000
77#define RIO_IPWSR_TE 0x00000080
78#define RIO_IPWSR_QFI 0x00000010
79#define RIO_IPWSR_PWD 0x00000008
80#define RIO_IPWSR_PWB 0x00000004
81
58#define RIO_MSG_DESC_SIZE 32 82#define RIO_MSG_DESC_SIZE 32
59#define RIO_MSG_BUFFER_SIZE 4096 83#define RIO_MSG_BUFFER_SIZE 4096
60#define RIO_MIN_TX_RING_SIZE 2 84#define RIO_MIN_TX_RING_SIZE 2
@@ -121,7 +145,7 @@ struct rio_msg_regs {
121 u32 pad10[26]; 145 u32 pad10[26];
122 u32 pwmr; 146 u32 pwmr;
123 u32 pwsr; 147 u32 pwsr;
124 u32 pad11; 148 u32 epwqbar;
125 u32 pwqbar; 149 u32 pwqbar;
126}; 150};
127 151
@@ -160,6 +184,14 @@ struct rio_msg_rx_ring {
160 void *dev_id; 184 void *dev_id;
161}; 185};
162 186
187struct rio_port_write_msg {
188 void *virt;
189 dma_addr_t phys;
190 u32 msg_count;
191 u32 err_count;
192 u32 discard_count;
193};
194
163struct rio_priv { 195struct rio_priv {
164 struct device *dev; 196 struct device *dev;
165 void __iomem *regs_win; 197 void __iomem *regs_win;
@@ -172,9 +204,14 @@ struct rio_priv {
172 struct rio_dbell_ring dbell_ring; 204 struct rio_dbell_ring dbell_ring;
173 struct rio_msg_tx_ring msg_tx_ring; 205 struct rio_msg_tx_ring msg_tx_ring;
174 struct rio_msg_rx_ring msg_rx_ring; 206 struct rio_msg_rx_ring msg_rx_ring;
207 struct rio_port_write_msg port_write_msg;
175 int bellirq; 208 int bellirq;
176 int txirq; 209 int txirq;
177 int rxirq; 210 int rxirq;
211 int pwirq;
212 struct work_struct pw_work;
213 struct kfifo pw_fifo;
214 spinlock_t pw_fifo_lock;
178}; 215};
179 216
180/** 217/**
@@ -930,6 +967,223 @@ static int fsl_rio_doorbell_init(struct rio_mport *mport)
930 return rc; 967 return rc;
931} 968}
932 969
970/**
971 * fsl_rio_port_write_handler - MPC85xx port write interrupt handler
972 * @irq: Linux interrupt number
973 * @dev_instance: Pointer to interrupt-specific data
974 *
975 * Handles port write interrupts. Parses a list of registered
976 * port write event handlers and executes a matching event handler.
977 */
978static irqreturn_t
979fsl_rio_port_write_handler(int irq, void *dev_instance)
980{
981 u32 ipwmr, ipwsr;
982 struct rio_mport *port = (struct rio_mport *)dev_instance;
983 struct rio_priv *priv = port->priv;
984 u32 epwisr, tmp;
985
986 ipwmr = in_be32(&priv->msg_regs->pwmr);
987 ipwsr = in_be32(&priv->msg_regs->pwsr);
988
989 epwisr = in_be32(priv->regs_win + RIO_EPWISR);
990 if (epwisr & 0x80000000) {
991 tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
992 pr_info("RIO_LTLEDCSR = 0x%x\n", tmp);
993 out_be32(priv->regs_win + RIO_LTLEDCSR, 0);
994 }
995
996 if (!(epwisr & 0x00000001))
997 return IRQ_HANDLED;
998
999#ifdef DEBUG_PW
1000 pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr);
1001 if (ipwsr & RIO_IPWSR_QF)
1002 pr_debug(" QF");
1003 if (ipwsr & RIO_IPWSR_TE)
1004 pr_debug(" TE");
1005 if (ipwsr & RIO_IPWSR_QFI)
1006 pr_debug(" QFI");
1007 if (ipwsr & RIO_IPWSR_PWD)
1008 pr_debug(" PWD");
1009 if (ipwsr & RIO_IPWSR_PWB)
1010 pr_debug(" PWB");
1011 pr_debug(" )\n");
1012#endif
1013 out_be32(&priv->msg_regs->pwsr,
1014 ipwsr & (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
1015
1016 if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) {
1017 priv->port_write_msg.err_count++;
1018 pr_info("RIO: Port-Write Transaction Err (%d)\n",
1019 priv->port_write_msg.err_count);
1020 }
1021 if (ipwsr & RIO_IPWSR_PWD) {
1022 priv->port_write_msg.discard_count++;
1023 pr_info("RIO: Port Discarded Port-Write Msg(s) (%d)\n",
1024 priv->port_write_msg.discard_count);
1025 }
1026
1027 /* Schedule deferred processing if PW was received */
1028 if (ipwsr & RIO_IPWSR_QFI) {
1029 /* Save PW message (if there is room in FIFO),
1030 * otherwise discard it.
1031 */
1032 if (kfifo_avail(&priv->pw_fifo) >= RIO_PW_MSG_SIZE) {
1033 priv->port_write_msg.msg_count++;
1034 kfifo_in(&priv->pw_fifo, priv->port_write_msg.virt,
1035 RIO_PW_MSG_SIZE);
1036 } else {
1037 priv->port_write_msg.discard_count++;
1038 pr_info("RIO: ISR Discarded Port-Write Msg(s) (%d)\n",
1039 priv->port_write_msg.discard_count);
1040 }
1041 schedule_work(&priv->pw_work);
1042 }
1043
1044 /* Issue Clear Queue command. This allows another
1045 * port-write to be received.
1046 */
1047 out_be32(&priv->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
1048
1049 return IRQ_HANDLED;
1050}
1051
1052static void fsl_pw_dpc(struct work_struct *work)
1053{
1054 struct rio_priv *priv = container_of(work, struct rio_priv, pw_work);
1055 unsigned long flags;
1056 u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)];
1057
1058 /*
1059 * Process port-write messages
1060 */
1061 spin_lock_irqsave(&priv->pw_fifo_lock, flags);
1062 while (kfifo_out(&priv->pw_fifo, (unsigned char *)msg_buffer,
1063 RIO_PW_MSG_SIZE)) {
1064 /* Process one message */
1065 spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
1066#ifdef DEBUG_PW
1067 {
1068 u32 i;
1069 pr_debug("%s : Port-Write Message:", __func__);
1070 for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); i++) {
1071 if ((i%4) == 0)
1072 pr_debug("\n0x%02x: 0x%08x", i*4,
1073 msg_buffer[i]);
1074 else
1075 pr_debug(" 0x%08x", msg_buffer[i]);
1076 }
1077 pr_debug("\n");
1078 }
1079#endif
1080 /* Pass the port-write message to RIO core for processing */
1081 rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer);
1082 spin_lock_irqsave(&priv->pw_fifo_lock, flags);
1083 }
1084 spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
1085}
1086
1087/**
1088 * fsl_rio_pw_enable - enable/disable port-write interface init
1089 * @mport: Master port implementing the port write unit
1090 * @enable: 1=enable; 0=disable port-write message handling
1091 */
1092static int fsl_rio_pw_enable(struct rio_mport *mport, int enable)
1093{
1094 struct rio_priv *priv = mport->priv;
1095 u32 rval;
1096
1097 rval = in_be32(&priv->msg_regs->pwmr);
1098
1099 if (enable)
1100 rval |= RIO_IPWMR_PWE;
1101 else
1102 rval &= ~RIO_IPWMR_PWE;
1103
1104 out_be32(&priv->msg_regs->pwmr, rval);
1105
1106 return 0;
1107}
1108
1109/**
1110 * fsl_rio_port_write_init - MPC85xx port write interface init
1111 * @mport: Master port implementing the port write unit
1112 *
1113 * Initializes port write unit hardware and DMA buffer
1114 * ring. Called from fsl_rio_setup(). Returns %0 on success
1115 * or %-ENOMEM on failure.
1116 */
1117static int fsl_rio_port_write_init(struct rio_mport *mport)
1118{
1119 struct rio_priv *priv = mport->priv;
1120 int rc = 0;
1121
1122 /* Following configurations require a disabled port write controller */
1123 out_be32(&priv->msg_regs->pwmr,
1124 in_be32(&priv->msg_regs->pwmr) & ~RIO_IPWMR_PWE);
1125
1126 /* Initialize port write */
1127 priv->port_write_msg.virt = dma_alloc_coherent(priv->dev,
1128 RIO_PW_MSG_SIZE,
1129 &priv->port_write_msg.phys, GFP_KERNEL);
1130 if (!priv->port_write_msg.virt) {
1131 pr_err("RIO: unable allocate port write queue\n");
1132 return -ENOMEM;
1133 }
1134
1135 priv->port_write_msg.err_count = 0;
1136 priv->port_write_msg.discard_count = 0;
1137
1138 /* Point dequeue/enqueue pointers at first entry */
1139 out_be32(&priv->msg_regs->epwqbar, 0);
1140 out_be32(&priv->msg_regs->pwqbar, (u32) priv->port_write_msg.phys);
1141
1142 pr_debug("EIPWQBAR: 0x%08x IPWQBAR: 0x%08x\n",
1143 in_be32(&priv->msg_regs->epwqbar),
1144 in_be32(&priv->msg_regs->pwqbar));
1145
1146 /* Clear interrupt status IPWSR */
1147 out_be32(&priv->msg_regs->pwsr,
1148 (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
1149
1150 /* Configure port write contoller for snooping enable all reporting,
1151 clear queue full */
1152 out_be32(&priv->msg_regs->pwmr,
1153 RIO_IPWMR_SEN | RIO_IPWMR_QFIE | RIO_IPWMR_EIE | RIO_IPWMR_CQ);
1154
1155
1156 /* Hook up port-write handler */
1157 rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler, 0,
1158 "port-write", (void *)mport);
1159 if (rc < 0) {
1160 pr_err("MPC85xx RIO: unable to request inbound doorbell irq");
1161 goto err_out;
1162 }
1163
1164 INIT_WORK(&priv->pw_work, fsl_pw_dpc);
1165 spin_lock_init(&priv->pw_fifo_lock);
1166 if (kfifo_alloc(&priv->pw_fifo, RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) {
1167 pr_err("FIFO allocation failed\n");
1168 rc = -ENOMEM;
1169 goto err_out_irq;
1170 }
1171
1172 pr_debug("IPWMR: 0x%08x IPWSR: 0x%08x\n",
1173 in_be32(&priv->msg_regs->pwmr),
1174 in_be32(&priv->msg_regs->pwsr));
1175
1176 return rc;
1177
1178err_out_irq:
1179 free_irq(IRQ_RIO_PW(mport), (void *)mport);
1180err_out:
1181 dma_free_coherent(priv->dev, RIO_PW_MSG_SIZE,
1182 priv->port_write_msg.virt,
1183 priv->port_write_msg.phys);
1184 return rc;
1185}
1186
933static char *cmdline = NULL; 1187static char *cmdline = NULL;
934 1188
935static int fsl_rio_get_hdid(int index) 1189static int fsl_rio_get_hdid(int index)
@@ -1067,6 +1321,7 @@ int fsl_rio_setup(struct of_device *dev)
1067 ops->cread = fsl_rio_config_read; 1321 ops->cread = fsl_rio_config_read;
1068 ops->cwrite = fsl_rio_config_write; 1322 ops->cwrite = fsl_rio_config_write;
1069 ops->dsend = fsl_rio_doorbell_send; 1323 ops->dsend = fsl_rio_doorbell_send;
1324 ops->pwenable = fsl_rio_pw_enable;
1070 1325
1071 port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL); 1326 port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL);
1072 if (!port) { 1327 if (!port) {
@@ -1089,11 +1344,12 @@ int fsl_rio_setup(struct of_device *dev)
1089 port->iores.flags = IORESOURCE_MEM; 1344 port->iores.flags = IORESOURCE_MEM;
1090 port->iores.name = "rio_io_win"; 1345 port->iores.name = "rio_io_win";
1091 1346
1347 priv->pwirq = irq_of_parse_and_map(dev->node, 0);
1092 priv->bellirq = irq_of_parse_and_map(dev->dev.of_node, 2); 1348 priv->bellirq = irq_of_parse_and_map(dev->dev.of_node, 2);
1093 priv->txirq = irq_of_parse_and_map(dev->dev.of_node, 3); 1349 priv->txirq = irq_of_parse_and_map(dev->dev.of_node, 3);
1094 priv->rxirq = irq_of_parse_and_map(dev->dev.of_node, 4); 1350 priv->rxirq = irq_of_parse_and_map(dev->dev.of_node, 4);
1095 dev_info(&dev->dev, "bellirq: %d, txirq: %d, rxirq %d\n", priv->bellirq, 1351 dev_info(&dev->dev, "pwirq: %d, bellirq: %d, txirq: %d, rxirq %d\n",
1096 priv->txirq, priv->rxirq); 1352 priv->pwirq, priv->bellirq, priv->txirq, priv->rxirq);
1097 1353
1098 rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff); 1354 rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
1099 rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0); 1355 rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0);
@@ -1175,6 +1431,7 @@ int fsl_rio_setup(struct of_device *dev)
1175 (law_start + RIO_MAINT_WIN_SIZE) >> 12); 1431 (law_start + RIO_MAINT_WIN_SIZE) >> 12);
1176 out_be32(&priv->dbell_atmu_regs->rowar, 0x8004200b); /* 4k */ 1432 out_be32(&priv->dbell_atmu_regs->rowar, 0x8004200b); /* 4k */
1177 fsl_rio_doorbell_init(port); 1433 fsl_rio_doorbell_init(port);
1434 fsl_rio_port_write_init(port);
1178 1435
1179 return 0; 1436 return 0;
1180err: 1437err: