aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Dubov <oakad@yahoo.com>2008-03-10 14:43:40 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-03-10 21:01:18 -0400
commit92b22d935fed1e4d88b9b6f9a674ab2a4272ee78 (patch)
tree021bfaaf98ce4af76c6761142fe6bcf3621fbd01
parent2a4f2568c22a381d7568314052c1dd40f6d3680a (diff)
tifm: fix the MemoryStick host fifo handling code
Additional input received from JMicron on MemoryStick host interfaces showed that some assumtions in fifo handling code were incorrect. This patch also fixes data corruption used to occure during PIO transfers. Signed-off-by: Alex Dubov <oakad@yahoo.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/memstick/host/tifm_ms.c524
-rw-r--r--include/linux/tifm.h2
2 files changed, 264 insertions, 262 deletions
diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c
index c62e709ca771..b88f5b30efbf 100644
--- a/drivers/memstick/host/tifm_ms.c
+++ b/drivers/memstick/host/tifm_ms.c
@@ -24,275 +24,289 @@
24static int no_dma; 24static int no_dma;
25module_param(no_dma, bool, 0644); 25module_param(no_dma, bool, 0644);
26 26
27#define TIFM_MS_TIMEOUT 0x00100 27/*
28#define TIFM_MS_BADCRC 0x00200 28 * Some control bits of TIFM appear to conform to Sony's reference design,
29#define TIFM_MS_EOTPC 0x01000 29 * so I'm just assuming they all are.
30#define TIFM_MS_INT 0x02000 30 */
31
32/* The meaning of the bit majority in this constant is unknown. */
33#define TIFM_MS_SERIAL 0x04010
34 31
35#define TIFM_MS_SYS_LATCH 0x00100 32#define TIFM_MS_STAT_DRQ 0x04000
36#define TIFM_MS_SYS_NOT_RDY 0x00800 33#define TIFM_MS_STAT_MSINT 0x02000
37#define TIFM_MS_SYS_DATA 0x10000 34#define TIFM_MS_STAT_RDY 0x01000
35#define TIFM_MS_STAT_CRC 0x00200
36#define TIFM_MS_STAT_TOE 0x00100
37#define TIFM_MS_STAT_EMP 0x00020
38#define TIFM_MS_STAT_FUL 0x00010
39#define TIFM_MS_STAT_CED 0x00008
40#define TIFM_MS_STAT_ERR 0x00004
41#define TIFM_MS_STAT_BRQ 0x00002
42#define TIFM_MS_STAT_CNK 0x00001
43
44#define TIFM_MS_SYS_DMA 0x10000
45#define TIFM_MS_SYS_RESET 0x08000
46#define TIFM_MS_SYS_SRAC 0x04000
47#define TIFM_MS_SYS_INTEN 0x02000
48#define TIFM_MS_SYS_NOCRC 0x01000
49#define TIFM_MS_SYS_INTCLR 0x00800
50#define TIFM_MS_SYS_MSIEN 0x00400
51#define TIFM_MS_SYS_FCLR 0x00200
52#define TIFM_MS_SYS_FDIR 0x00100
53#define TIFM_MS_SYS_DAM 0x00080
54#define TIFM_MS_SYS_DRM 0x00040
55#define TIFM_MS_SYS_DRQSL 0x00020
56#define TIFM_MS_SYS_REI 0x00010
57#define TIFM_MS_SYS_REO 0x00008
58#define TIFM_MS_SYS_BSY_MASK 0x00007
59
60#define TIFM_MS_SYS_FIFO (TIFM_MS_SYS_INTEN | TIFM_MS_SYS_MSIEN \
61 | TIFM_MS_SYS_FCLR | TIFM_MS_SYS_BSY_MASK)
38 62
39/* Hardware flags */ 63/* Hardware flags */
40enum { 64enum {
41 CMD_READY = 0x0001, 65 CMD_READY = 0x01,
42 FIFO_READY = 0x0002, 66 FIFO_READY = 0x02,
43 CARD_READY = 0x0004, 67 CARD_INT = 0x04
44 DATA_CARRY = 0x0008
45}; 68};
46 69
47struct tifm_ms { 70struct tifm_ms {
48 struct tifm_dev *dev; 71 struct tifm_dev *dev;
49 unsigned short eject:1, 72 struct timer_list timer;
50 no_dma:1; 73 struct memstick_request *req;
51 unsigned short cmd_flags;
52 unsigned int mode_mask; 74 unsigned int mode_mask;
53 unsigned int block_pos; 75 unsigned int block_pos;
54 unsigned long timeout_jiffies; 76 unsigned long timeout_jiffies;
55 77 unsigned char eject:1,
56 struct timer_list timer; 78 use_dma:1;
57 struct memstick_request *req; 79 unsigned char cmd_flags;
80 unsigned char io_pos;
58 unsigned int io_word; 81 unsigned int io_word;
59}; 82};
60 83
61static void tifm_ms_read_fifo(struct tifm_ms *host, unsigned int fifo_offset, 84static unsigned int tifm_ms_read_data(struct tifm_ms *host,
62 struct page *pg, unsigned int page_off, 85 unsigned char *buf, unsigned int length)
63 unsigned int length)
64{ 86{
65 struct tifm_dev *sock = host->dev; 87 struct tifm_dev *sock = host->dev;
66 unsigned int cnt = 0, off = 0; 88 unsigned int off = 0;
67 unsigned char *buf = kmap_atomic(pg, KM_BIO_DST_IRQ) + page_off; 89
90 while (host->io_pos && length) {
91 buf[off++] = host->io_word & 0xff;
92 host->io_word >>= 8;
93 length--;
94 host->io_pos--;
95 }
96
97 if (!length)
98 return off;
99
100 while (!(TIFM_MS_STAT_EMP & readl(sock->addr + SOCK_MS_STATUS))) {
101 if (length < 4)
102 break;
103 *(unsigned int *)(buf + off) = __raw_readl(sock->addr
104 + SOCK_MS_DATA);
105 length -= 4;
106 off += 4;
107 }
68 108
69 if (host->cmd_flags & DATA_CARRY) { 109 if (length
70 while ((fifo_offset & 3) && length) { 110 && !(TIFM_MS_STAT_EMP & readl(sock->addr + SOCK_MS_STATUS))) {
111 host->io_word = readl(sock->addr + SOCK_MS_DATA);
112 for (host->io_pos = 4; host->io_pos; --host->io_pos) {
71 buf[off++] = host->io_word & 0xff; 113 buf[off++] = host->io_word & 0xff;
72 host->io_word >>= 8; 114 host->io_word >>= 8;
73 length--; 115 length--;
74 fifo_offset++; 116 if (!length)
117 break;
75 } 118 }
76 if (!(fifo_offset & 3))
77 host->cmd_flags &= ~DATA_CARRY;
78 if (!length)
79 return;
80 } 119 }
81 120
82 do { 121 return off;
83 host->io_word = readl(sock->addr + SOCK_FIFO_ACCESS
84 + fifo_offset);
85 cnt = 4;
86 while (length && cnt) {
87 buf[off++] = (host->io_word >> 8) & 0xff;
88 cnt--;
89 length--;
90 }
91 fifo_offset += 4 - cnt;
92 } while (length);
93
94 if (cnt)
95 host->cmd_flags |= DATA_CARRY;
96
97 kunmap_atomic(buf - page_off, KM_BIO_DST_IRQ);
98} 122}
99 123
100static void tifm_ms_write_fifo(struct tifm_ms *host, unsigned int fifo_offset, 124static unsigned int tifm_ms_write_data(struct tifm_ms *host,
101 struct page *pg, unsigned int page_off, 125 unsigned char *buf, unsigned int length)
102 unsigned int length)
103{ 126{
104 struct tifm_dev *sock = host->dev; 127 struct tifm_dev *sock = host->dev;
105 unsigned int cnt = 0, off = 0; 128 unsigned int off = 0;
106 unsigned char *buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + page_off;
107 129
108 if (host->cmd_flags & DATA_CARRY) { 130 if (host->io_pos) {
109 while (fifo_offset & 3) { 131 while (host->io_pos < 4 && length) {
110 host->io_word |= buf[off++] << (8 * (fifo_offset & 3)); 132 host->io_word |= buf[off++] << (host->io_pos * 8);
133 host->io_pos++;
111 length--; 134 length--;
112 fifo_offset++;
113 }
114 if (!(fifo_offset & 3)) {
115 writel(host->io_word, sock->addr + SOCK_FIFO_ACCESS
116 + fifo_offset - 4);
117
118 host->cmd_flags &= ~DATA_CARRY;
119 } 135 }
120 if (!length)
121 return;
122 } 136 }
123 137
124 do { 138 if (host->io_pos == 4
125 cnt = 4; 139 && !(TIFM_MS_STAT_FUL & readl(sock->addr + SOCK_MS_STATUS))) {
140 writel(TIFM_MS_SYS_FDIR | readl(sock->addr + SOCK_MS_SYSTEM),
141 sock->addr + SOCK_MS_SYSTEM);
142 writel(host->io_word, sock->addr + SOCK_MS_DATA);
143 host->io_pos = 0;
126 host->io_word = 0; 144 host->io_word = 0;
127 while (length && cnt) { 145 } else if (host->io_pos) {
128 host->io_word |= buf[off++] << (4 - cnt); 146 return off;
129 cnt--; 147 }
130 length--;
131 }
132 fifo_offset += 4 - cnt;
133 if (!cnt)
134 writel(host->io_word, sock->addr + SOCK_FIFO_ACCESS
135 + fifo_offset - 4);
136
137 } while (length);
138
139 if (cnt)
140 host->cmd_flags |= DATA_CARRY;
141 148
142 kunmap_atomic(buf - page_off, KM_BIO_SRC_IRQ); 149 if (!length)
143} 150 return off;
144 151
145static void tifm_ms_move_block(struct tifm_ms *host, unsigned int length) 152 while (!(TIFM_MS_STAT_FUL & readl(sock->addr + SOCK_MS_STATUS))) {
146{ 153 if (length < 4)
147 unsigned int t_size; 154 break;
148 unsigned int off = host->req->sg.offset + host->block_pos; 155 writel(TIFM_MS_SYS_FDIR | readl(sock->addr + SOCK_MS_SYSTEM),
149 unsigned int p_off, p_cnt; 156 sock->addr + SOCK_MS_SYSTEM);
150 struct page *pg; 157 __raw_writel(*(unsigned int *)(buf + off),
151 unsigned long flags; 158 sock->addr + SOCK_MS_DATA);
159 length -= 4;
160 off += 4;
161 }
152 162
153 dev_dbg(&host->dev->dev, "moving block\n"); 163 switch (length) {
154 local_irq_save(flags); 164 case 3:
155 t_size = length; 165 host->io_word |= buf[off + 2] << 16;
156 while (t_size) { 166 host->io_pos++;
157 pg = nth_page(sg_page(&host->req->sg), off >> PAGE_SHIFT); 167 case 2:
158 p_off = offset_in_page(off); 168 host->io_word |= buf[off + 1] << 8;
159 p_cnt = PAGE_SIZE - p_off; 169 host->io_pos++;
160 p_cnt = min(p_cnt, t_size); 170 case 1:
171 host->io_word |= buf[off];
172 host->io_pos++;
173 }
161 174
162 if (host->req->data_dir == WRITE) 175 off += host->io_pos;
163 tifm_ms_write_fifo(host, length - t_size,
164 pg, p_off, p_cnt);
165 else
166 tifm_ms_read_fifo(host, length - t_size,
167 pg, p_off, p_cnt);
168 176
169 t_size -= p_cnt; 177 return off;
170 }
171 local_irq_restore(flags);
172} 178}
173 179
174static int tifm_ms_transfer_data(struct tifm_ms *host, int skip) 180static unsigned int tifm_ms_transfer_data(struct tifm_ms *host)
175{ 181{
176 struct tifm_dev *sock = host->dev; 182 struct tifm_dev *sock = host->dev;
177 unsigned int length = host->req->sg.length - host->block_pos; 183 unsigned int length;
184 unsigned int off;
185 unsigned int t_size, p_off, p_cnt;
186 unsigned char *buf;
187 struct page *pg;
188 unsigned long flags = 0;
178 189
179 if (!length) 190 if (host->req->long_data) {
180 return 1; 191 length = host->req->sg.length - host->block_pos;
192 off = host->req->sg.offset + host->block_pos;
193 } else {
194 length = host->req->data_len - host->block_pos;
195 off = 0;
196 }
197 dev_dbg(&sock->dev, "fifo data transfer, %d, %d\n", length,
198 host->block_pos);
199
200 while (length) {
201 if (host->req->long_data) {
202 pg = nth_page(sg_page(&host->req->sg),
203 off >> PAGE_SHIFT);
204 p_off = offset_in_page(off);
205 p_cnt = PAGE_SIZE - p_off;
206 p_cnt = min(p_cnt, length);
207
208 local_irq_save(flags);
209 buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + p_off;
210 } else {
211 buf = host->req->data + host->block_pos;
212 p_cnt = host->req->data_len - host->block_pos;
213 }
181 214
182 if (length > TIFM_FIFO_SIZE) 215 t_size = host->req->data_dir == WRITE
183 length = TIFM_FIFO_SIZE; 216 ? tifm_ms_write_data(host, buf, p_cnt)
217 : tifm_ms_read_data(host, buf, p_cnt);
184 218
185 if (!skip) { 219 if (host->req->long_data) {
186 tifm_ms_move_block(host, length); 220 kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ);
187 host->block_pos += length; 221 local_irq_restore(flags);
188 } 222 }
189 223
190 if ((host->req->data_dir == READ) 224 if (!t_size)
191 && (host->block_pos == host->req->sg.length)) 225 break;
192 return 1; 226 host->block_pos += t_size;
227 length -= t_size;
228 off += t_size;
229 }
193 230
194 writel(ilog2(length) - 2, sock->addr + SOCK_FIFO_PAGE_SIZE); 231 dev_dbg(&sock->dev, "fifo data transfer, %d remaining\n", length);
195 if (host->req->data_dir == WRITE) 232 if (!length && (host->req->data_dir == WRITE)) {
196 writel((1 << 8) | TIFM_DMA_TX, sock->addr + SOCK_DMA_CONTROL); 233 if (host->io_pos) {
197 else 234 writel(TIFM_MS_SYS_FDIR
198 writel((1 << 8), sock->addr + SOCK_DMA_CONTROL); 235 | readl(sock->addr + SOCK_MS_SYSTEM),
236 sock->addr + SOCK_MS_SYSTEM);
237 writel(host->io_word, sock->addr + SOCK_MS_DATA);
238 }
239 writel(TIFM_MS_SYS_FDIR
240 | readl(sock->addr + SOCK_MS_SYSTEM),
241 sock->addr + SOCK_MS_SYSTEM);
242 writel(0, sock->addr + SOCK_MS_DATA);
243 } else {
244 readl(sock->addr + SOCK_MS_DATA);
245 }
199 246
200 return 0; 247 return length;
201} 248}
202 249
203static int tifm_ms_issue_cmd(struct tifm_ms *host) 250static int tifm_ms_issue_cmd(struct tifm_ms *host)
204{ 251{
205 struct tifm_dev *sock = host->dev; 252 struct tifm_dev *sock = host->dev;
206 unsigned char *data; 253 unsigned char *data;
207 unsigned int data_len = 0, cmd = 0, cmd_mask = 0, cnt, tval = 0; 254 unsigned int data_len, cmd, sys_param;
208 255
209 host->cmd_flags = 0; 256 host->cmd_flags = 0;
257 host->block_pos = 0;
258 host->io_pos = 0;
259 host->io_word = 0;
260 host->cmd_flags = 0;
210 261
211 if (host->req->long_data) { 262 data = host->req->data;
212 if (!host->no_dma) {
213 if (1 != tifm_map_sg(sock, &host->req->sg, 1,
214 host->req->data_dir == READ
215 ? PCI_DMA_FROMDEVICE
216 : PCI_DMA_TODEVICE)) {
217 host->req->error = -ENOMEM;
218 return host->req->error;
219 }
220 data_len = sg_dma_len(&host->req->sg);
221 } else
222 data_len = host->req->sg.length;
223
224 writel(TIFM_FIFO_INT_SETALL,
225 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
226 writel(TIFM_FIFO_ENABLE,
227 sock->addr + SOCK_FIFO_CONTROL);
228 writel(TIFM_FIFO_INTMASK,
229 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
230 263
231 if (!host->no_dma) { 264 host->use_dma = !no_dma;
232 writel(ilog2(data_len) - 2,
233 sock->addr + SOCK_FIFO_PAGE_SIZE);
234 writel(sg_dma_address(&host->req->sg),
235 sock->addr + SOCK_DMA_ADDRESS);
236 if (host->req->data_dir == WRITE)
237 writel((1 << 8) | TIFM_DMA_TX | TIFM_DMA_EN,
238 sock->addr + SOCK_DMA_CONTROL);
239 else
240 writel((1 << 8) | TIFM_DMA_EN,
241 sock->addr + SOCK_DMA_CONTROL);
242 } else {
243 tifm_ms_transfer_data(host,
244 host->req->data_dir == READ);
245 }
246 265
247 cmd_mask = readl(sock->addr + SOCK_MS_SYSTEM); 266 if (host->req->long_data) {
248 cmd_mask |= TIFM_MS_SYS_DATA | TIFM_MS_SYS_NOT_RDY; 267 data_len = host->req->sg.length;
249 writel(cmd_mask, sock->addr + SOCK_MS_SYSTEM); 268 if (!is_power_of_2(data_len))
269 host->use_dma = 0;
250 } else { 270 } else {
251 data = host->req->data;
252 data_len = host->req->data_len; 271 data_len = host->req->data_len;
272 host->use_dma = 0;
273 }
253 274
254 cmd_mask = host->mode_mask | 0x2607; /* unknown constant */ 275 writel(TIFM_FIFO_INT_SETALL,
255 276 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
256 if (host->req->data_dir == WRITE) { 277 writel(TIFM_FIFO_ENABLE,
257 cmd_mask |= TIFM_MS_SYS_LATCH; 278 sock->addr + SOCK_FIFO_CONTROL);
258 writel(cmd_mask, sock->addr + SOCK_MS_SYSTEM); 279
259 for (cnt = 0; (data_len - cnt) >= 4; cnt += 4) { 280 if (host->use_dma) {
260 writel(TIFM_MS_SYS_LATCH 281 if (1 != tifm_map_sg(sock, &host->req->sg, 1,
261 | readl(sock->addr + SOCK_MS_SYSTEM), 282 host->req->data_dir == READ
262 sock->addr + SOCK_MS_SYSTEM); 283 ? PCI_DMA_FROMDEVICE
263 __raw_writel(*(unsigned int *)(data + cnt), 284 : PCI_DMA_TODEVICE)) {
264 sock->addr + SOCK_MS_DATA); 285 host->req->error = -ENOMEM;
265 dev_dbg(&sock->dev, "writing %x\n", 286 return host->req->error;
266 *(int *)(data + cnt)); 287 }
267 } 288 data_len = sg_dma_len(&host->req->sg);
268 switch (data_len - cnt) {
269 case 3:
270 tval |= data[cnt + 2] << 16;
271 case 2:
272 tval |= data[cnt + 1] << 8;
273 case 1:
274 tval |= data[cnt];
275 writel(TIFM_MS_SYS_LATCH
276 | readl(sock->addr + SOCK_MS_SYSTEM),
277 sock->addr + SOCK_MS_SYSTEM);
278 writel(tval, sock->addr + SOCK_MS_DATA);
279 dev_dbg(&sock->dev, "writing %x\n", tval);
280 }
281 289
282 writel(TIFM_MS_SYS_LATCH 290 writel(ilog2(data_len) - 2,
283 | readl(sock->addr + SOCK_MS_SYSTEM), 291 sock->addr + SOCK_FIFO_PAGE_SIZE);
284 sock->addr + SOCK_MS_SYSTEM); 292 writel(TIFM_FIFO_INTMASK,
285 writel(0, sock->addr + SOCK_MS_DATA); 293 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
286 dev_dbg(&sock->dev, "writing %x\n", 0); 294 sys_param = TIFM_DMA_EN | (1 << 8);
295 if (host->req->data_dir == WRITE)
296 sys_param |= TIFM_DMA_TX;
287 297
288 } else 298 writel(TIFM_FIFO_INTMASK,
289 writel(cmd_mask, sock->addr + SOCK_MS_SYSTEM); 299 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
290 300
291 cmd_mask = readl(sock->addr + SOCK_MS_SYSTEM); 301 writel(sg_dma_address(&host->req->sg),
292 cmd_mask &= ~TIFM_MS_SYS_DATA; 302 sock->addr + SOCK_DMA_ADDRESS);
293 cmd_mask |= TIFM_MS_SYS_NOT_RDY; 303 writel(sys_param, sock->addr + SOCK_DMA_CONTROL);
294 dev_dbg(&sock->dev, "mask %x\n", cmd_mask); 304 } else {
295 writel(cmd_mask, sock->addr + SOCK_MS_SYSTEM); 305 writel(host->mode_mask | TIFM_MS_SYS_FIFO,
306 sock->addr + SOCK_MS_SYSTEM);
307
308 writel(TIFM_FIFO_MORE,
309 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
296 } 310 }
297 311
298 mod_timer(&host->timer, jiffies + host->timeout_jiffies); 312 mod_timer(&host->timer, jiffies + host->timeout_jiffies);
@@ -300,11 +314,21 @@ static int tifm_ms_issue_cmd(struct tifm_ms *host)
300 sock->addr + SOCK_CONTROL); 314 sock->addr + SOCK_CONTROL);
301 host->req->error = 0; 315 host->req->error = 0;
302 316
317 sys_param = readl(sock->addr + SOCK_MS_SYSTEM);
318 sys_param |= TIFM_MS_SYS_INTCLR;
319
320 if (host->use_dma)
321 sys_param |= TIFM_MS_SYS_DMA;
322 else
323 sys_param &= ~TIFM_MS_SYS_DMA;
324
325 writel(sys_param, sock->addr + SOCK_MS_SYSTEM);
326
303 cmd = (host->req->tpc & 0xf) << 12; 327 cmd = (host->req->tpc & 0xf) << 12;
304 cmd |= data_len; 328 cmd |= data_len;
305 writel(cmd, sock->addr + SOCK_MS_COMMAND); 329 writel(cmd, sock->addr + SOCK_MS_COMMAND);
306 330
307 dev_dbg(&sock->dev, "executing TPC %x, %x\n", cmd, cmd_mask); 331 dev_dbg(&sock->dev, "executing TPC %x, %x\n", cmd, sys_param);
308 return 0; 332 return 0;
309} 333}
310 334
@@ -312,47 +336,20 @@ static void tifm_ms_complete_cmd(struct tifm_ms *host)
312{ 336{
313 struct tifm_dev *sock = host->dev; 337 struct tifm_dev *sock = host->dev;
314 struct memstick_host *msh = tifm_get_drvdata(sock); 338 struct memstick_host *msh = tifm_get_drvdata(sock);
315 unsigned int tval = 0, data_len;
316 unsigned char *data;
317 int rc; 339 int rc;
318 340
319 del_timer(&host->timer); 341 del_timer(&host->timer);
320 if (host->req->long_data) {
321 if (!host->no_dma)
322 tifm_unmap_sg(sock, &host->req->sg, 1,
323 host->req->data_dir == READ
324 ? PCI_DMA_FROMDEVICE
325 : PCI_DMA_TODEVICE);
326 } else {
327 writel(~TIFM_MS_SYS_DATA & readl(sock->addr + SOCK_MS_SYSTEM),
328 sock->addr + SOCK_MS_SYSTEM);
329
330 data = host->req->data;
331 data_len = host->req->data_len;
332 342
333 if (host->req->data_dir == READ) { 343 if (host->use_dma)
334 for (rc = 0; (data_len - rc) >= 4; rc += 4) 344 tifm_unmap_sg(sock, &host->req->sg, 1,
335 *(int *)(data + rc) 345 host->req->data_dir == READ
336 = __raw_readl(sock->addr 346 ? PCI_DMA_FROMDEVICE
337 + SOCK_MS_DATA); 347 : PCI_DMA_TODEVICE);
338
339 if (data_len - rc)
340 tval = readl(sock->addr + SOCK_MS_DATA);
341 switch (data_len - rc) {
342 case 3:
343 data[rc + 2] = (tval >> 16) & 0xff;
344 case 2:
345 data[rc + 1] = (tval >> 8) & 0xff;
346 case 1:
347 data[rc] = tval & 0xff;
348 }
349 readl(sock->addr + SOCK_MS_DATA);
350 }
351 }
352 348
353 writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), 349 writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
354 sock->addr + SOCK_CONTROL); 350 sock->addr + SOCK_CONTROL);
355 351
352 dev_dbg(&sock->dev, "TPC complete\n");
356 do { 353 do {
357 rc = memstick_next_req(msh, &host->req); 354 rc = memstick_next_req(msh, &host->req);
358 } while (!rc && tifm_ms_issue_cmd(host)); 355 } while (!rc && tifm_ms_issue_cmd(host));
@@ -363,11 +360,10 @@ static int tifm_ms_check_status(struct tifm_ms *host)
363 if (!host->req->error) { 360 if (!host->req->error) {
364 if (!(host->cmd_flags & CMD_READY)) 361 if (!(host->cmd_flags & CMD_READY))
365 return 1; 362 return 1;
366 if (host->req->long_data 363 if (!(host->cmd_flags & FIFO_READY))
367 && !(host->cmd_flags & FIFO_READY))
368 return 1; 364 return 1;
369 if (host->req->need_card_int 365 if (host->req->need_card_int
370 && !(host->cmd_flags & CARD_READY)) 366 && !(host->cmd_flags & CARD_INT))
371 return 1; 367 return 1;
372 } 368 }
373 return 0; 369 return 0;
@@ -377,18 +373,24 @@ static int tifm_ms_check_status(struct tifm_ms *host)
377static void tifm_ms_data_event(struct tifm_dev *sock) 373static void tifm_ms_data_event(struct tifm_dev *sock)
378{ 374{
379 struct tifm_ms *host; 375 struct tifm_ms *host;
380 unsigned int fifo_status = 0; 376 unsigned int fifo_status = 0, host_status = 0;
381 int rc = 1; 377 int rc = 1;
382 378
383 spin_lock(&sock->lock); 379 spin_lock(&sock->lock);
384 host = memstick_priv((struct memstick_host *)tifm_get_drvdata(sock)); 380 host = memstick_priv((struct memstick_host *)tifm_get_drvdata(sock));
385 fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); 381 fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
386 dev_dbg(&sock->dev, "data event: fifo_status %x, flags %x\n", 382 host_status = readl(sock->addr + SOCK_MS_STATUS);
387 fifo_status, host->cmd_flags); 383 dev_dbg(&sock->dev,
384 "data event: fifo_status %x, host_status %x, flags %x\n",
385 fifo_status, host_status, host->cmd_flags);
388 386
389 if (host->req) { 387 if (host->req) {
390 if (fifo_status & TIFM_FIFO_READY) { 388 if (host->use_dma && (fifo_status & 1)) {
391 if (!host->no_dma || tifm_ms_transfer_data(host, 0)) { 389 host->cmd_flags |= FIFO_READY;
390 rc = tifm_ms_check_status(host);
391 }
392 if (!host->use_dma && (fifo_status & TIFM_FIFO_MORE)) {
393 if (!tifm_ms_transfer_data(host)) {
392 host->cmd_flags |= FIFO_READY; 394 host->cmd_flags |= FIFO_READY;
393 rc = tifm_ms_check_status(host); 395 rc = tifm_ms_check_status(host);
394 } 396 }
@@ -417,9 +419,9 @@ static void tifm_ms_card_event(struct tifm_dev *sock)
417 host_status, host->cmd_flags); 419 host_status, host->cmd_flags);
418 420
419 if (host->req) { 421 if (host->req) {
420 if (host_status & TIFM_MS_TIMEOUT) 422 if (host_status & TIFM_MS_STAT_TOE)
421 host->req->error = -ETIME; 423 host->req->error = -ETIME;
422 else if (host_status & TIFM_MS_BADCRC) 424 else if (host_status & TIFM_MS_STAT_CRC)
423 host->req->error = -EILSEQ; 425 host->req->error = -EILSEQ;
424 426
425 if (host->req->error) { 427 if (host->req->error) {
@@ -428,18 +430,17 @@ static void tifm_ms_card_event(struct tifm_dev *sock)
428 writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); 430 writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);
429 } 431 }
430 432
431 if (host_status & TIFM_MS_EOTPC) 433 if (host_status & TIFM_MS_STAT_RDY)
432 host->cmd_flags |= CMD_READY; 434 host->cmd_flags |= CMD_READY;
433 if (host_status & TIFM_MS_INT) 435
434 host->cmd_flags |= CARD_READY; 436 if (host_status & TIFM_MS_STAT_MSINT)
437 host->cmd_flags |= CARD_INT;
435 438
436 rc = tifm_ms_check_status(host); 439 rc = tifm_ms_check_status(host);
437 440
438 } 441 }
439 442
440 writel(TIFM_MS_SYS_NOT_RDY | readl(sock->addr + SOCK_MS_SYSTEM), 443 writel(TIFM_MS_SYS_INTCLR | readl(sock->addr + SOCK_MS_SYSTEM),
441 sock->addr + SOCK_MS_SYSTEM);
442 writel((~TIFM_MS_SYS_DATA) & readl(sock->addr + SOCK_MS_SYSTEM),
443 sock->addr + SOCK_MS_SYSTEM); 444 sock->addr + SOCK_MS_SYSTEM);
444 445
445 if (!rc) 446 if (!rc)
@@ -499,7 +500,7 @@ static void tifm_ms_set_param(struct memstick_host *msh,
499 break; 500 break;
500 case MEMSTICK_INTERFACE: 501 case MEMSTICK_INTERFACE:
501 if (value == MEMSTICK_SERIAL) { 502 if (value == MEMSTICK_SERIAL) {
502 host->mode_mask = TIFM_MS_SERIAL; 503 host->mode_mask = TIFM_MS_SYS_SRAC | TIFM_MS_SYS_REI;
503 writel((~TIFM_CTRL_FAST_CLK) 504 writel((~TIFM_CTRL_FAST_CLK)
504 & readl(sock->addr + SOCK_CONTROL), 505 & readl(sock->addr + SOCK_CONTROL),
505 sock->addr + SOCK_CONTROL); 506 sock->addr + SOCK_CONTROL);
@@ -535,9 +536,10 @@ static int tifm_ms_initialize_host(struct tifm_ms *host)
535 struct tifm_dev *sock = host->dev; 536 struct tifm_dev *sock = host->dev;
536 struct memstick_host *msh = tifm_get_drvdata(sock); 537 struct memstick_host *msh = tifm_get_drvdata(sock);
537 538
538 host->mode_mask = TIFM_MS_SERIAL; 539 host->mode_mask = TIFM_MS_SYS_SRAC | TIFM_MS_SYS_REI;
539 writel(0x8000, sock->addr + SOCK_MS_SYSTEM); 540 writel(TIFM_MS_SYS_RESET, sock->addr + SOCK_MS_SYSTEM);
540 writel(0x0200 | TIFM_MS_SYS_NOT_RDY, sock->addr + SOCK_MS_SYSTEM); 541 writel(TIFM_MS_SYS_FCLR | TIFM_MS_SYS_INTCLR,
542 sock->addr + SOCK_MS_SYSTEM);
541 writel(0xffffffff, sock->addr + SOCK_MS_STATUS); 543 writel(0xffffffff, sock->addr + SOCK_MS_STATUS);
542 if (tifm_has_ms_pif(sock)) 544 if (tifm_has_ms_pif(sock))
543 msh->caps |= MEMSTICK_CAP_PAR4; 545 msh->caps |= MEMSTICK_CAP_PAR4;
@@ -566,7 +568,6 @@ static int tifm_ms_probe(struct tifm_dev *sock)
566 tifm_set_drvdata(sock, msh); 568 tifm_set_drvdata(sock, msh);
567 host->dev = sock; 569 host->dev = sock;
568 host->timeout_jiffies = msecs_to_jiffies(1000); 570 host->timeout_jiffies = msecs_to_jiffies(1000);
569 host->no_dma = no_dma;
570 571
571 setup_timer(&host->timer, tifm_ms_abort, (unsigned long)host); 572 setup_timer(&host->timer, tifm_ms_abort, (unsigned long)host);
572 573
@@ -599,7 +600,7 @@ static void tifm_ms_remove(struct tifm_dev *sock)
599 writel(TIFM_FIFO_INT_SETALL, 600 writel(TIFM_FIFO_INT_SETALL,
600 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); 601 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
601 writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); 602 writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);
602 if (host->req->long_data && !host->no_dma) 603 if (host->use_dma)
603 tifm_unmap_sg(sock, &host->req->sg, 1, 604 tifm_unmap_sg(sock, &host->req->sg, 1,
604 host->req->data_dir == READ 605 host->req->data_dir == READ
605 ? PCI_DMA_TODEVICE 606 ? PCI_DMA_TODEVICE
@@ -616,7 +617,8 @@ static void tifm_ms_remove(struct tifm_dev *sock)
616 617
617 memstick_remove_host(msh); 618 memstick_remove_host(msh);
618 619
619 writel(0x0200 | TIFM_MS_SYS_NOT_RDY, sock->addr + SOCK_MS_SYSTEM); 620 writel(TIFM_MS_SYS_FCLR | TIFM_MS_SYS_INTCLR,
621 sock->addr + SOCK_MS_SYSTEM);
620 writel(0xffffffff, sock->addr + SOCK_MS_STATUS); 622 writel(0xffffffff, sock->addr + SOCK_MS_STATUS);
621 623
622 memstick_free_host(msh); 624 memstick_free_host(msh);
diff --git a/include/linux/tifm.h b/include/linux/tifm.h
index da76ed85f595..848c0f392541 100644
--- a/include/linux/tifm.h
+++ b/include/linux/tifm.h
@@ -70,9 +70,9 @@ enum {
70 70
71#define TIFM_FIFO_ENABLE 0x00000001 71#define TIFM_FIFO_ENABLE 0x00000001
72#define TIFM_FIFO_READY 0x00000001 72#define TIFM_FIFO_READY 0x00000001
73#define TIFM_FIFO_MORE 0x00000008
73#define TIFM_FIFO_INT_SETALL 0x0000ffff 74#define TIFM_FIFO_INT_SETALL 0x0000ffff
74#define TIFM_FIFO_INTMASK 0x00000005 75#define TIFM_FIFO_INTMASK 0x00000005
75#define TIFM_FIFO_SIZE 0x00000200
76 76
77#define TIFM_DMA_RESET 0x00000002 77#define TIFM_DMA_RESET 0x00000002
78#define TIFM_DMA_TX 0x00008000 78#define TIFM_DMA_TX 0x00008000