Blame view

drivers/block/xsysace.c 33.2 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
74489a91d   Grant Likely   Add support for X...
2
3
4
5
  /*
   * Xilinx SystemACE device driver
   *
   * Copyright 2007 Secret Lab Technologies Ltd.
74489a91d   Grant Likely   Add support for X...
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
   */
  
  /*
   * The SystemACE chip is designed to configure FPGAs by loading an FPGA
   * bitstream from a file on a CF card and squirting it into FPGAs connected
   * to the SystemACE JTAG chain.  It also has the advantage of providing an
   * MPU interface which can be used to control the FPGA configuration process
   * and to use the attached CF card for general purpose storage.
   *
   * This driver is a block device driver for the SystemACE.
   *
   * Initialization:
   *    The driver registers itself as a platform_device driver at module
   *    load time.  The platform bus will take care of calling the
   *    ace_probe() method for all SystemACE instances in the system.  Any
   *    number of SystemACE instances are supported.  ace_probe() calls
   *    ace_setup() which initialized all data structures, reads the CF
   *    id structure and registers the device.
   *
   * Processing:
   *    Just about all of the heavy lifting in this driver is performed by
   *    a Finite State Machine (FSM).  The driver needs to wait on a number
   *    of events; some raised by interrupts, some which need to be polled
   *    for.  Describing all of the behaviour in a FSM seems to be the
   *    easiest way to keep the complexity low and make it easy to
   *    understand what the driver is doing.  If the block ops or the
   *    request function need to interact with the hardware, then they
   *    simply need to flag the request and kick of FSM processing.
   *
   *    The FSM itself is atomic-safe code which can be run from any
   *    context.  The general process flow is:
   *    1. obtain the ace->lock spinlock.
   *    2. loop on ace_fsm_dostate() until the ace->fsm_continue flag is
   *       cleared.
   *    3. release the lock.
   *
   *    Individual states do not sleep in any way.  If a condition needs to
   *    be waited for then the state much clear the fsm_continue flag and
   *    either schedule the FSM to be run again at a later time, or expect
   *    an interrupt to call the FSM when the desired condition is met.
   *
   *    In normal operation, the FSM is processed at interrupt context
   *    either when the driver's tasklet is scheduled, or when an irq is
   *    raised by the hardware.  The tasklet can be scheduled at any time.
   *    The request method in particular schedules the tasklet when a new
   *    request has been indicated by the block layer.  Once started, the
   *    FSM proceeds as far as it can processing the request until it
   *    needs on a hardware event.  At this point, it must yield execution.
   *
   *    A state has two options when yielding execution:
   *    1. ace_fsm_yield()
   *       - Call if need to poll for event.
   *       - clears the fsm_continue flag to exit the processing loop
   *       - reschedules the tasklet to run again as soon as possible
   *    2. ace_fsm_yieldirq()
   *       - Call if an irq is expected from the HW
   *       - clears the fsm_continue flag to exit the processing loop
   *       - does not reschedule the tasklet so the FSM will not be processed
   *         again until an irq is received.
   *    After calling a yield function, the state must return control back
   *    to the FSM main loop.
   *
   *    Additionally, the driver maintains a kernel timer which can process
   *    the FSM.  If the FSM gets stalled, typically due to a missed
   *    interrupt, then the kernel timer will expire and the driver can
   *    continue where it left off.
   *
   * To Do:
   *    - Add FPGA configuration control interface.
   *    - Request major number from lanana
   */
  
  #undef DEBUG
  
  #include <linux/module.h>
  #include <linux/ctype.h>
  #include <linux/init.h>
  #include <linux/interrupt.h>
  #include <linux/errno.h>
  #include <linux/kernel.h>
  #include <linux/delay.h>
  #include <linux/slab.h>
804186fa9   Jens Axboe   xsysace: convert ...
88
  #include <linux/blk-mq.h>
2a48fc0ab   Arnd Bergmann   block: autoconver...
89
  #include <linux/mutex.h>
4aaf2fec7   Bartlomiej Zolnierkiewicz   xsysace: make it ...
90
  #include <linux/ata.h>
74489a91d   Grant Likely   Add support for X...
91
92
  #include <linux/hdreg.h>
  #include <linux/platform_device.h>
95e896c35   Grant Likely   Sysace: Add of_pl...
93
  #if defined(CONFIG_OF)
7a50d06e2   Graeme Smecher   of: fix missing h...
94
  #include <linux/of_address.h>
95e896c35   Grant Likely   Sysace: Add of_pl...
95
96
97
  #include <linux/of_device.h>
  #include <linux/of_platform.h>
  #endif
74489a91d   Grant Likely   Add support for X...
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  
  MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
  MODULE_DESCRIPTION("Xilinx SystemACE device driver");
  MODULE_LICENSE("GPL");
  
  /* SystemACE register definitions */
  #define ACE_BUSMODE (0x00)
  
  #define ACE_STATUS (0x04)
  #define ACE_STATUS_CFGLOCK      (0x00000001)
  #define ACE_STATUS_MPULOCK      (0x00000002)
  #define ACE_STATUS_CFGERROR     (0x00000004)	/* config controller error */
  #define ACE_STATUS_CFCERROR     (0x00000008)	/* CF controller error */
  #define ACE_STATUS_CFDETECT     (0x00000010)
  #define ACE_STATUS_DATABUFRDY   (0x00000020)
  #define ACE_STATUS_DATABUFMODE  (0x00000040)
  #define ACE_STATUS_CFGDONE      (0x00000080)
  #define ACE_STATUS_RDYFORCFCMD  (0x00000100)
  #define ACE_STATUS_CFGMODEPIN   (0x00000200)
  #define ACE_STATUS_CFGADDR_MASK (0x0000e000)
  #define ACE_STATUS_CFBSY        (0x00020000)
  #define ACE_STATUS_CFRDY        (0x00040000)
  #define ACE_STATUS_CFDWF        (0x00080000)
  #define ACE_STATUS_CFDSC        (0x00100000)
  #define ACE_STATUS_CFDRQ        (0x00200000)
  #define ACE_STATUS_CFCORR       (0x00400000)
  #define ACE_STATUS_CFERR        (0x00800000)
  
  #define ACE_ERROR (0x08)
  #define ACE_CFGLBA (0x0c)
  #define ACE_MPULBA (0x10)
  
  #define ACE_SECCNTCMD (0x14)
  #define ACE_SECCNTCMD_RESET      (0x0100)
  #define ACE_SECCNTCMD_IDENTIFY   (0x0200)
  #define ACE_SECCNTCMD_READ_DATA  (0x0300)
  #define ACE_SECCNTCMD_WRITE_DATA (0x0400)
  #define ACE_SECCNTCMD_ABORT      (0x0600)
  
  #define ACE_VERSION (0x16)
  #define ACE_VERSION_REVISION_MASK (0x00FF)
  #define ACE_VERSION_MINOR_MASK    (0x0F00)
  #define ACE_VERSION_MAJOR_MASK    (0xF000)
  
  #define ACE_CTRL (0x18)
  #define ACE_CTRL_FORCELOCKREQ   (0x0001)
  #define ACE_CTRL_LOCKREQ        (0x0002)
  #define ACE_CTRL_FORCECFGADDR   (0x0004)
  #define ACE_CTRL_FORCECFGMODE   (0x0008)
  #define ACE_CTRL_CFGMODE        (0x0010)
  #define ACE_CTRL_CFGSTART       (0x0020)
  #define ACE_CTRL_CFGSEL         (0x0040)
  #define ACE_CTRL_CFGRESET       (0x0080)
  #define ACE_CTRL_DATABUFRDYIRQ  (0x0100)
  #define ACE_CTRL_ERRORIRQ       (0x0200)
  #define ACE_CTRL_CFGDONEIRQ     (0x0400)
  #define ACE_CTRL_RESETIRQ       (0x0800)
  #define ACE_CTRL_CFGPROG        (0x1000)
  #define ACE_CTRL_CFGADDR_MASK   (0xe000)
  
  #define ACE_FATSTAT (0x1c)
  
  #define ACE_NUM_MINORS 16
  #define ACE_SECTOR_SIZE (512)
  #define ACE_FIFO_SIZE (32)
  #define ACE_BUF_PER_SECTOR (ACE_SECTOR_SIZE / ACE_FIFO_SIZE)
4a24d8610   Grant Likely   Sysace: minor rew...
164
165
  #define ACE_BUS_WIDTH_8  0
  #define ACE_BUS_WIDTH_16 1
74489a91d   Grant Likely   Add support for X...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  struct ace_reg_ops;
  
  struct ace_device {
  	/* driver state data */
  	int id;
  	int media_change;
  	int users;
  	struct list_head list;
  
  	/* finite state machine data */
  	struct tasklet_struct fsm_tasklet;
  	uint fsm_task;		/* Current activity (ACE_TASK_*) */
  	uint fsm_state;		/* Current state (ACE_FSM_STATE_*) */
  	uint fsm_continue_flag;	/* cleared to exit FSM mainloop */
  	uint fsm_iter_num;
  	struct timer_list stall_timer;
  
  	/* Transfer state/result, use for both id and block request */
  	struct request *req;	/* request being processed */
  	void *data_ptr;		/* pointer to I/O buffer */
  	int data_count;		/* number of buffers remaining */
  	int data_result;	/* Result of transfer; 0 := success */
  
  	int id_req_count;	/* count of id requests */
  	int id_result;
  	struct completion id_completion;	/* used when id req finishes */
  	int in_irq;
  
  	/* Details of hardware device */
c14464bf7   Yuri Tikhonov   xsysace: Fix driv...
195
  	resource_size_t physaddr;
b5515d86f   Grant Likely   Sysace: sparse fixes
196
  	void __iomem *baseaddr;
74489a91d   Grant Likely   Add support for X...
197
198
199
200
201
202
203
204
205
206
  	int irq;
  	int bus_width;		/* 0 := 8 bit; 1 := 16 bit */
  	struct ace_reg_ops *reg_ops;
  	int lock_count;
  
  	/* Block device data structures */
  	spinlock_t lock;
  	struct device *dev;
  	struct request_queue *queue;
  	struct gendisk *gd;
804186fa9   Jens Axboe   xsysace: convert ...
207
208
  	struct blk_mq_tag_set tag_set;
  	struct list_head rq_list;
74489a91d   Grant Likely   Add support for X...
209
210
  
  	/* Inserted CF card parameters */
4aaf2fec7   Bartlomiej Zolnierkiewicz   xsysace: make it ...
211
  	u16 cf_id[ATA_ID_WORDS];
74489a91d   Grant Likely   Add support for X...
212
  };
2a48fc0ab   Arnd Bergmann   block: autoconver...
213
  static DEFINE_MUTEX(xsysace_mutex);
74489a91d   Grant Likely   Add support for X...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
  static int ace_major;
  
  /* ---------------------------------------------------------------------
   * Low level register access
   */
  
  struct ace_reg_ops {
  	u16(*in) (struct ace_device * ace, int reg);
  	void (*out) (struct ace_device * ace, int reg, u16 val);
  	void (*datain) (struct ace_device * ace);
  	void (*dataout) (struct ace_device * ace);
  };
  
  /* 8 Bit bus width */
  static u16 ace_in_8(struct ace_device *ace, int reg)
  {
b5515d86f   Grant Likely   Sysace: sparse fixes
230
  	void __iomem *r = ace->baseaddr + reg;
74489a91d   Grant Likely   Add support for X...
231
232
233
234
235
  	return in_8(r) | (in_8(r + 1) << 8);
  }
  
  static void ace_out_8(struct ace_device *ace, int reg, u16 val)
  {
b5515d86f   Grant Likely   Sysace: sparse fixes
236
  	void __iomem *r = ace->baseaddr + reg;
74489a91d   Grant Likely   Add support for X...
237
238
239
240
241
242
  	out_8(r, val);
  	out_8(r + 1, val >> 8);
  }
  
  static void ace_datain_8(struct ace_device *ace)
  {
b5515d86f   Grant Likely   Sysace: sparse fixes
243
  	void __iomem *r = ace->baseaddr + 0x40;
74489a91d   Grant Likely   Add support for X...
244
245
246
247
248
249
250
251
252
  	u8 *dst = ace->data_ptr;
  	int i = ACE_FIFO_SIZE;
  	while (i--)
  		*dst++ = in_8(r++);
  	ace->data_ptr = dst;
  }
  
  static void ace_dataout_8(struct ace_device *ace)
  {
b5515d86f   Grant Likely   Sysace: sparse fixes
253
  	void __iomem *r = ace->baseaddr + 0x40;
74489a91d   Grant Likely   Add support for X...
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
  	u8 *src = ace->data_ptr;
  	int i = ACE_FIFO_SIZE;
  	while (i--)
  		out_8(r++, *src++);
  	ace->data_ptr = src;
  }
  
  static struct ace_reg_ops ace_reg_8_ops = {
  	.in = ace_in_8,
  	.out = ace_out_8,
  	.datain = ace_datain_8,
  	.dataout = ace_dataout_8,
  };
  
  /* 16 bit big endian bus attachment */
  static u16 ace_in_be16(struct ace_device *ace, int reg)
  {
  	return in_be16(ace->baseaddr + reg);
  }
  
  static void ace_out_be16(struct ace_device *ace, int reg, u16 val)
  {
  	out_be16(ace->baseaddr + reg, val);
  }
  
  static void ace_datain_be16(struct ace_device *ace)
  {
  	int i = ACE_FIFO_SIZE / 2;
  	u16 *dst = ace->data_ptr;
  	while (i--)
  		*dst++ = in_le16(ace->baseaddr + 0x40);
  	ace->data_ptr = dst;
  }
  
  static void ace_dataout_be16(struct ace_device *ace)
  {
  	int i = ACE_FIFO_SIZE / 2;
  	u16 *src = ace->data_ptr;
  	while (i--)
  		out_le16(ace->baseaddr + 0x40, *src++);
  	ace->data_ptr = src;
  }
  
  /* 16 bit little endian bus attachment */
  static u16 ace_in_le16(struct ace_device *ace, int reg)
  {
  	return in_le16(ace->baseaddr + reg);
  }
  
  static void ace_out_le16(struct ace_device *ace, int reg, u16 val)
  {
  	out_le16(ace->baseaddr + reg, val);
  }
  
  static void ace_datain_le16(struct ace_device *ace)
  {
  	int i = ACE_FIFO_SIZE / 2;
  	u16 *dst = ace->data_ptr;
  	while (i--)
  		*dst++ = in_be16(ace->baseaddr + 0x40);
  	ace->data_ptr = dst;
  }
  
  static void ace_dataout_le16(struct ace_device *ace)
  {
  	int i = ACE_FIFO_SIZE / 2;
  	u16 *src = ace->data_ptr;
  	while (i--)
  		out_be16(ace->baseaddr + 0x40, *src++);
  	ace->data_ptr = src;
  }
  
  static struct ace_reg_ops ace_reg_be16_ops = {
  	.in = ace_in_be16,
  	.out = ace_out_be16,
  	.datain = ace_datain_be16,
  	.dataout = ace_dataout_be16,
  };
  
  static struct ace_reg_ops ace_reg_le16_ops = {
  	.in = ace_in_le16,
  	.out = ace_out_le16,
  	.datain = ace_datain_le16,
  	.dataout = ace_dataout_le16,
  };
  
  static inline u16 ace_in(struct ace_device *ace, int reg)
  {
  	return ace->reg_ops->in(ace, reg);
  }
  
  static inline u32 ace_in32(struct ace_device *ace, int reg)
  {
  	return ace_in(ace, reg) | (ace_in(ace, reg + 2) << 16);
  }
  
  static inline void ace_out(struct ace_device *ace, int reg, u16 val)
  {
  	ace->reg_ops->out(ace, reg, val);
  }
  
  static inline void ace_out32(struct ace_device *ace, int reg, u32 val)
  {
  	ace_out(ace, reg, val);
  	ace_out(ace, reg + 2, val >> 16);
  }
  
  /* ---------------------------------------------------------------------
   * Debug support functions
   */
  
  #if defined(DEBUG)
  static void ace_dump_mem(void *base, int len)
  {
  	const char *ptr = base;
  	int i, j;
  
  	for (i = 0; i < len; i += 16) {
  		printk(KERN_INFO "%.8x:", i);
  		for (j = 0; j < 16; j++) {
  			if (!(j % 4))
  				printk(" ");
  			printk("%.2x", ptr[i + j]);
  		}
  		printk(" ");
  		for (j = 0; j < 16; j++)
  			printk("%c", isprint(ptr[i + j]) ? ptr[i + j] : '.');
  		printk("
  ");
  	}
  }
  #else
  static inline void ace_dump_mem(void *base, int len)
  {
  }
  #endif
  
  static void ace_dump_regs(struct ace_device *ace)
  {
ad361c988   Joe Perches   Remove multiple K...
393
394
395
396
397
398
399
  	dev_info(ace->dev,
  		 "    ctrl:  %.8x  seccnt/cmd: %.4x      ver:%.4x
  "
  		 "    status:%.8x  mpu_lba:%.8x  busmode:%4x
  "
  		 "    error: %.8x  cfg_lba:%.8x  fatstat:%.4x
  ",
74489a91d   Grant Likely   Add support for X...
400
401
402
403
404
405
406
407
408
  		 ace_in32(ace, ACE_CTRL),
  		 ace_in(ace, ACE_SECCNTCMD),
  		 ace_in(ace, ACE_VERSION),
  		 ace_in32(ace, ACE_STATUS),
  		 ace_in32(ace, ACE_MPULBA),
  		 ace_in(ace, ACE_BUSMODE),
  		 ace_in32(ace, ACE_ERROR),
  		 ace_in32(ace, ACE_CFGLBA), ace_in(ace, ACE_FATSTAT));
  }
4937a269c   Michal Simek   xilinx systemace:...
409
  static void ace_fix_driveid(u16 *id)
74489a91d   Grant Likely   Add support for X...
410
411
  {
  #if defined(__BIG_ENDIAN)
74489a91d   Grant Likely   Add support for X...
412
413
414
  	int i;
  
  	/* All half words have wrong byte order; swap the bytes */
4aaf2fec7   Bartlomiej Zolnierkiewicz   xsysace: make it ...
415
416
  	for (i = 0; i < ATA_ID_WORDS; i++, id++)
  		*id = le16_to_cpu(*id);
74489a91d   Grant Likely   Add support for X...
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
  #endif
  }
  
  /* ---------------------------------------------------------------------
   * Finite State Machine (FSM) implementation
   */
  
  /* FSM tasks; used to direct state transitions */
  #define ACE_TASK_IDLE      0
  #define ACE_TASK_IDENTIFY  1
  #define ACE_TASK_READ      2
  #define ACE_TASK_WRITE     3
  #define ACE_FSM_NUM_TASKS  4
  
  /* FSM state definitions */
  #define ACE_FSM_STATE_IDLE               0
  #define ACE_FSM_STATE_REQ_LOCK           1
  #define ACE_FSM_STATE_WAIT_LOCK          2
  #define ACE_FSM_STATE_WAIT_CFREADY       3
  #define ACE_FSM_STATE_IDENTIFY_PREPARE   4
  #define ACE_FSM_STATE_IDENTIFY_TRANSFER  5
  #define ACE_FSM_STATE_IDENTIFY_COMPLETE  6
  #define ACE_FSM_STATE_REQ_PREPARE        7
  #define ACE_FSM_STATE_REQ_TRANSFER       8
  #define ACE_FSM_STATE_REQ_COMPLETE       9
  #define ACE_FSM_STATE_ERROR             10
  #define ACE_FSM_NUM_STATES              11
  
  /* Set flag to exit FSM loop and reschedule tasklet */
7cb6e22ba   Andy Shevchenko   xsysace: use plat...
446
  static inline void ace_fsm_yieldpoll(struct ace_device *ace)
74489a91d   Grant Likely   Add support for X...
447
  {
74489a91d   Grant Likely   Add support for X...
448
449
450
  	tasklet_schedule(&ace->fsm_tasklet);
  	ace->fsm_continue_flag = 0;
  }
7cb6e22ba   Andy Shevchenko   xsysace: use plat...
451
452
453
454
455
456
  static inline void ace_fsm_yield(struct ace_device *ace)
  {
  	dev_dbg(ace->dev, "%s()
  ", __func__);
  	ace_fsm_yieldpoll(ace);
  }
74489a91d   Grant Likely   Add support for X...
457
458
459
460
461
  /* Set flag to exit FSM loop and wait for IRQ to reschedule tasklet */
  static inline void ace_fsm_yieldirq(struct ace_device *ace)
  {
  	dev_dbg(ace->dev, "ace_fsm_yieldirq()
  ");
7cb6e22ba   Andy Shevchenko   xsysace: use plat...
462
463
464
465
  	if (ace->irq > 0)
  		ace->fsm_continue_flag = 0;
  	else
  		ace_fsm_yieldpoll(ace);
74489a91d   Grant Likely   Add support for X...
466
  }
804186fa9   Jens Axboe   xsysace: convert ...
467
468
469
470
471
472
  static bool ace_has_next_request(struct request_queue *q)
  {
  	struct ace_device *ace = q->queuedata;
  
  	return !list_empty(&ace->rq_list);
  }
74489a91d   Grant Likely   Add support for X...
473
  /* Get the next read/write request; ending requests that we don't handle */
4937a269c   Michal Simek   xilinx systemace:...
474
  static struct request *ace_get_next_request(struct request_queue *q)
74489a91d   Grant Likely   Add support for X...
475
  {
804186fa9   Jens Axboe   xsysace: convert ...
476
477
  	struct ace_device *ace = q->queuedata;
  	struct request *rq;
74489a91d   Grant Likely   Add support for X...
478

804186fa9   Jens Axboe   xsysace: convert ...
479
480
481
482
  	rq = list_first_entry_or_null(&ace->rq_list, struct request, queuelist);
  	if (rq) {
  		list_del_init(&rq->queuelist);
  		blk_mq_start_request(rq);
74489a91d   Grant Likely   Add support for X...
483
  	}
804186fa9   Jens Axboe   xsysace: convert ...
484
485
  
  	return NULL;
74489a91d   Grant Likely   Add support for X...
486
487
488
489
490
491
492
493
  }
  
  static void ace_fsm_dostate(struct ace_device *ace)
  {
  	struct request *req;
  	u32 status;
  	u16 val;
  	int count;
74489a91d   Grant Likely   Add support for X...
494
495
496
497
498
499
  
  #if defined(DEBUG)
  	dev_dbg(ace->dev, "fsm_state=%i, id_req_count=%i
  ",
  		ace->fsm_state, ace->id_req_count);
  #endif
bfbd442f6   Grant Likely   Fix Xilinx System...
500
501
502
503
504
505
506
507
508
  	/* Verify that there is actually a CF in the slot. If not, then
  	 * bail out back to the idle state and wake up all the waiters */
  	status = ace_in32(ace, ACE_STATUS);
  	if ((status & ACE_STATUS_CFDETECT) == 0) {
  		ace->fsm_state = ACE_FSM_STATE_IDLE;
  		ace->media_change = 1;
  		set_capacity(ace->gd, 0);
  		dev_info(ace->dev, "No CF in slot
  ");
2d75ce084   Tejun Heo   xsysace: dequeue ...
509
510
  		/* Drop all in-flight and pending requests */
  		if (ace->req) {
804186fa9   Jens Axboe   xsysace: convert ...
511
  			blk_mq_end_request(ace->req, BLK_STS_IOERR);
2d75ce084   Tejun Heo   xsysace: dequeue ...
512
513
  			ace->req = NULL;
  		}
804186fa9   Jens Axboe   xsysace: convert ...
514
515
  		while ((req = ace_get_next_request(ace->queue)) != NULL)
  			blk_mq_end_request(req, BLK_STS_IOERR);
bfbd442f6   Grant Likely   Fix Xilinx System...
516
517
518
519
520
521
522
523
524
  
  		/* Drop back to IDLE state and notify waiters */
  		ace->fsm_state = ACE_FSM_STATE_IDLE;
  		ace->id_result = -EIO;
  		while (ace->id_req_count) {
  			complete(&ace->id_completion);
  			ace->id_req_count--;
  		}
  	}
74489a91d   Grant Likely   Add support for X...
525
526
527
  	switch (ace->fsm_state) {
  	case ACE_FSM_STATE_IDLE:
  		/* See if there is anything to do */
804186fa9   Jens Axboe   xsysace: convert ...
528
  		if (ace->id_req_count || ace_has_next_request(ace->queue)) {
74489a91d   Grant Likely   Add support for X...
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
  			ace->fsm_iter_num++;
  			ace->fsm_state = ACE_FSM_STATE_REQ_LOCK;
  			mod_timer(&ace->stall_timer, jiffies + HZ);
  			if (!timer_pending(&ace->stall_timer))
  				add_timer(&ace->stall_timer);
  			break;
  		}
  		del_timer(&ace->stall_timer);
  		ace->fsm_continue_flag = 0;
  		break;
  
  	case ACE_FSM_STATE_REQ_LOCK:
  		if (ace_in(ace, ACE_STATUS) & ACE_STATUS_MPULOCK) {
  			/* Already have the lock, jump to next state */
  			ace->fsm_state = ACE_FSM_STATE_WAIT_CFREADY;
  			break;
  		}
  
  		/* Request the lock */
  		val = ace_in(ace, ACE_CTRL);
  		ace_out(ace, ACE_CTRL, val | ACE_CTRL_LOCKREQ);
  		ace->fsm_state = ACE_FSM_STATE_WAIT_LOCK;
  		break;
  
  	case ACE_FSM_STATE_WAIT_LOCK:
  		if (ace_in(ace, ACE_STATUS) & ACE_STATUS_MPULOCK) {
  			/* got the lock; move to next state */
  			ace->fsm_state = ACE_FSM_STATE_WAIT_CFREADY;
  			break;
  		}
  
  		/* wait a bit for the lock */
  		ace_fsm_yield(ace);
  		break;
  
  	case ACE_FSM_STATE_WAIT_CFREADY:
  		status = ace_in32(ace, ACE_STATUS);
  		if (!(status & ACE_STATUS_RDYFORCFCMD) ||
  		    (status & ACE_STATUS_CFBSY)) {
  			/* CF card isn't ready; it needs to be polled */
  			ace_fsm_yield(ace);
  			break;
  		}
  
  		/* Device is ready for command; determine what to do next */
  		if (ace->id_req_count)
  			ace->fsm_state = ACE_FSM_STATE_IDENTIFY_PREPARE;
  		else
  			ace->fsm_state = ACE_FSM_STATE_REQ_PREPARE;
  		break;
  
  	case ACE_FSM_STATE_IDENTIFY_PREPARE:
  		/* Send identify command */
  		ace->fsm_task = ACE_TASK_IDENTIFY;
f0edef8c8   Grant Likely   xsysace: Fix dere...
583
  		ace->data_ptr = ace->cf_id;
74489a91d   Grant Likely   Add support for X...
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
  		ace->data_count = ACE_BUF_PER_SECTOR;
  		ace_out(ace, ACE_SECCNTCMD, ACE_SECCNTCMD_IDENTIFY);
  
  		/* As per datasheet, put config controller in reset */
  		val = ace_in(ace, ACE_CTRL);
  		ace_out(ace, ACE_CTRL, val | ACE_CTRL_CFGRESET);
  
  		/* irq handler takes over from this point; wait for the
  		 * transfer to complete */
  		ace->fsm_state = ACE_FSM_STATE_IDENTIFY_TRANSFER;
  		ace_fsm_yieldirq(ace);
  		break;
  
  	case ACE_FSM_STATE_IDENTIFY_TRANSFER:
  		/* Check that the sysace is ready to receive data */
  		status = ace_in32(ace, ACE_STATUS);
  		if (status & ACE_STATUS_CFBSY) {
  			dev_dbg(ace->dev, "CFBSY set; t=%i iter=%i dc=%i
  ",
  				ace->fsm_task, ace->fsm_iter_num,
  				ace->data_count);
  			ace_fsm_yield(ace);
  			break;
  		}
  		if (!(status & ACE_STATUS_DATABUFRDY)) {
  			ace_fsm_yield(ace);
  			break;
  		}
  
  		/* Transfer the next buffer */
  		ace->reg_ops->datain(ace);
  		ace->data_count--;
  
  		/* If there are still buffers to be transfers; jump out here */
  		if (ace->data_count != 0) {
  			ace_fsm_yieldirq(ace);
  			break;
  		}
  
  		/* transfer finished; kick state machine */
  		dev_dbg(ace->dev, "identify finished
  ");
  		ace->fsm_state = ACE_FSM_STATE_IDENTIFY_COMPLETE;
  		break;
  
  	case ACE_FSM_STATE_IDENTIFY_COMPLETE:
f0edef8c8   Grant Likely   xsysace: Fix dere...
630
631
  		ace_fix_driveid(ace->cf_id);
  		ace_dump_mem(ace->cf_id, 512);	/* Debug: Dump out disk ID */
74489a91d   Grant Likely   Add support for X...
632
633
  
  		if (ace->data_result) {
25985edce   Lucas De Marchi   Fix common misspe...
634
  			/* Error occurred, disable the disk */
74489a91d   Grant Likely   Add support for X...
635
636
637
638
639
640
641
642
643
  			ace->media_change = 1;
  			set_capacity(ace->gd, 0);
  			dev_err(ace->dev, "error fetching CF id (%i)
  ",
  				ace->data_result);
  		} else {
  			ace->media_change = 0;
  
  			/* Record disk parameters */
4aaf2fec7   Bartlomiej Zolnierkiewicz   xsysace: make it ...
644
  			set_capacity(ace->gd,
f0edef8c8   Grant Likely   xsysace: Fix dere...
645
  				ata_id_u32(ace->cf_id, ATA_ID_LBA_CAPACITY));
74489a91d   Grant Likely   Add support for X...
646
647
  			dev_info(ace->dev, "capacity: %i sectors
  ",
f0edef8c8   Grant Likely   xsysace: Fix dere...
648
  				ata_id_u32(ace->cf_id, ATA_ID_LBA_CAPACITY));
74489a91d   Grant Likely   Add support for X...
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
  		}
  
  		/* We're done, drop to IDLE state and notify waiters */
  		ace->fsm_state = ACE_FSM_STATE_IDLE;
  		ace->id_result = ace->data_result;
  		while (ace->id_req_count) {
  			complete(&ace->id_completion);
  			ace->id_req_count--;
  		}
  		break;
  
  	case ACE_FSM_STATE_REQ_PREPARE:
  		req = ace_get_next_request(ace->queue);
  		if (!req) {
  			ace->fsm_state = ACE_FSM_STATE_IDLE;
  			break;
  		}
  
  		/* Okay, it's a data request, set it up for transfer */
  		dev_dbg(ace->dev,
5b93629b4   Tejun Heo   block: implement ...
669
670
  			"request: sec=%llx hcnt=%x, ccnt=%x, dir=%i
  ",
83096ebf1   Tejun Heo   block: convert to...
671
672
673
  			(unsigned long long)blk_rq_pos(req),
  			blk_rq_sectors(req), blk_rq_cur_sectors(req),
  			rq_data_dir(req));
74489a91d   Grant Likely   Add support for X...
674
675
  
  		ace->req = req;
b4f42e283   Jens Axboe   block: remove str...
676
  		ace->data_ptr = bio_data(req->bio);
83096ebf1   Tejun Heo   block: convert to...
677
678
  		ace->data_count = blk_rq_cur_sectors(req) * ACE_BUF_PER_SECTOR;
  		ace_out32(ace, ACE_MPULBA, blk_rq_pos(req) & 0x0FFFFFFF);
74489a91d   Grant Likely   Add support for X...
679

5b93629b4   Tejun Heo   block: implement ...
680
  		count = blk_rq_sectors(req);
74489a91d   Grant Likely   Add support for X...
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
  		if (rq_data_dir(req)) {
  			/* Kick off write request */
  			dev_dbg(ace->dev, "write data
  ");
  			ace->fsm_task = ACE_TASK_WRITE;
  			ace_out(ace, ACE_SECCNTCMD,
  				count | ACE_SECCNTCMD_WRITE_DATA);
  		} else {
  			/* Kick off read request */
  			dev_dbg(ace->dev, "read data
  ");
  			ace->fsm_task = ACE_TASK_READ;
  			ace_out(ace, ACE_SECCNTCMD,
  				count | ACE_SECCNTCMD_READ_DATA);
  		}
  
  		/* As per datasheet, put config controller in reset */
  		val = ace_in(ace, ACE_CTRL);
  		ace_out(ace, ACE_CTRL, val | ACE_CTRL_CFGRESET);
  
  		/* Move to the transfer state.  The systemace will raise
  		 * an interrupt once there is something to do
  		 */
  		ace->fsm_state = ACE_FSM_STATE_REQ_TRANSFER;
  		if (ace->fsm_task == ACE_TASK_READ)
  			ace_fsm_yieldirq(ace);	/* wait for data ready */
  		break;
  
  	case ACE_FSM_STATE_REQ_TRANSFER:
  		/* Check that the sysace is ready to receive data */
  		status = ace_in32(ace, ACE_STATUS);
  		if (status & ACE_STATUS_CFBSY) {
  			dev_dbg(ace->dev,
  				"CFBSY set; t=%i iter=%i c=%i dc=%i irq=%i
  ",
  				ace->fsm_task, ace->fsm_iter_num,
83096ebf1   Tejun Heo   block: convert to...
717
  				blk_rq_cur_sectors(ace->req) * 16,
74489a91d   Grant Likely   Add support for X...
718
719
720
721
722
723
724
725
726
  				ace->data_count, ace->in_irq);
  			ace_fsm_yield(ace);	/* need to poll CFBSY bit */
  			break;
  		}
  		if (!(status & ACE_STATUS_DATABUFRDY)) {
  			dev_dbg(ace->dev,
  				"DATABUF not set; t=%i iter=%i c=%i dc=%i irq=%i
  ",
  				ace->fsm_task, ace->fsm_iter_num,
83096ebf1   Tejun Heo   block: convert to...
727
  				blk_rq_cur_sectors(ace->req) * 16,
74489a91d   Grant Likely   Add support for X...
728
729
730
731
732
733
  				ace->data_count, ace->in_irq);
  			ace_fsm_yieldirq(ace);
  			break;
  		}
  
  		/* Transfer the next buffer */
74489a91d   Grant Likely   Add support for X...
734
735
736
737
738
739
740
741
742
743
744
745
746
  		if (ace->fsm_task == ACE_TASK_WRITE)
  			ace->reg_ops->dataout(ace);
  		else
  			ace->reg_ops->datain(ace);
  		ace->data_count--;
  
  		/* If there are still buffers to be transfers; jump out here */
  		if (ace->data_count != 0) {
  			ace_fsm_yieldirq(ace);
  			break;
  		}
  
  		/* bio finished; is there another one? */
804186fa9   Jens Axboe   xsysace: convert ...
747
748
  		if (blk_update_request(ace->req, BLK_STS_OK,
  		    blk_rq_cur_bytes(ace->req))) {
5b93629b4   Tejun Heo   block: implement ...
749
750
751
  			/* dev_dbg(ace->dev, "next block; h=%u c=%u
  ",
  			 *      blk_rq_sectors(ace->req),
83096ebf1   Tejun Heo   block: convert to...
752
  			 *      blk_rq_cur_sectors(ace->req));
74489a91d   Grant Likely   Add support for X...
753
  			 */
b4f42e283   Jens Axboe   block: remove str...
754
  			ace->data_ptr = bio_data(ace->req->bio);
83096ebf1   Tejun Heo   block: convert to...
755
  			ace->data_count = blk_rq_cur_sectors(ace->req) * 16;
74489a91d   Grant Likely   Add support for X...
756
757
758
759
760
761
762
763
  			ace_fsm_yieldirq(ace);
  			break;
  		}
  
  		ace->fsm_state = ACE_FSM_STATE_REQ_COMPLETE;
  		break;
  
  	case ACE_FSM_STATE_REQ_COMPLETE:
74489a91d   Grant Likely   Add support for X...
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
  		ace->req = NULL;
  
  		/* Finished request; go to idle state */
  		ace->fsm_state = ACE_FSM_STATE_IDLE;
  		break;
  
  	default:
  		ace->fsm_state = ACE_FSM_STATE_IDLE;
  		break;
  	}
  }
  
  static void ace_fsm_tasklet(unsigned long data)
  {
  	struct ace_device *ace = (void *)data;
  	unsigned long flags;
  
  	spin_lock_irqsave(&ace->lock, flags);
  
  	/* Loop over state machine until told to stop */
  	ace->fsm_continue_flag = 1;
  	while (ace->fsm_continue_flag)
  		ace_fsm_dostate(ace);
  
  	spin_unlock_irqrestore(&ace->lock, flags);
  }
e99e88a9d   Kees Cook   treewide: setup_t...
790
  static void ace_stall_timer(struct timer_list *t)
74489a91d   Grant Likely   Add support for X...
791
  {
e99e88a9d   Kees Cook   treewide: setup_t...
792
  	struct ace_device *ace = from_timer(ace, t, stall_timer);
74489a91d   Grant Likely   Add support for X...
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
  	unsigned long flags;
  
  	dev_warn(ace->dev,
  		 "kicking stalled fsm; state=%i task=%i iter=%i dc=%i
  ",
  		 ace->fsm_state, ace->fsm_task, ace->fsm_iter_num,
  		 ace->data_count);
  	spin_lock_irqsave(&ace->lock, flags);
  
  	/* Rearm the stall timer *before* entering FSM (which may then
  	 * delete the timer) */
  	mod_timer(&ace->stall_timer, jiffies + HZ);
  
  	/* Loop over state machine until told to stop */
  	ace->fsm_continue_flag = 1;
  	while (ace->fsm_continue_flag)
  		ace_fsm_dostate(ace);
  
  	spin_unlock_irqrestore(&ace->lock, flags);
  }
  
  /* ---------------------------------------------------------------------
   * Interrupt handling routines
   */
  static int ace_interrupt_checkstate(struct ace_device *ace)
  {
  	u32 sreg = ace_in32(ace, ACE_STATUS);
  	u16 creg = ace_in(ace, ACE_CTRL);
25985edce   Lucas De Marchi   Fix common misspe...
821
  	/* Check for error occurrence */
74489a91d   Grant Likely   Add support for X...
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
  	if ((sreg & (ACE_STATUS_CFGERROR | ACE_STATUS_CFCERROR)) &&
  	    (creg & ACE_CTRL_ERRORIRQ)) {
  		dev_err(ace->dev, "transfer failure
  ");
  		ace_dump_regs(ace);
  		return -EIO;
  	}
  
  	return 0;
  }
  
  static irqreturn_t ace_interrupt(int irq, void *dev_id)
  {
  	u16 creg;
  	struct ace_device *ace = dev_id;
  
  	/* be safe and get the lock */
  	spin_lock(&ace->lock);
  	ace->in_irq = 1;
  
  	/* clear the interrupt */
  	creg = ace_in(ace, ACE_CTRL);
  	ace_out(ace, ACE_CTRL, creg | ACE_CTRL_RESETIRQ);
  	ace_out(ace, ACE_CTRL, creg);
  
  	/* check for IO failures */
  	if (ace_interrupt_checkstate(ace))
  		ace->data_result = -EIO;
  
  	if (ace->fsm_task == 0) {
  		dev_err(ace->dev,
  			"spurious irq; stat=%.8x ctrl=%.8x cmd=%.4x
  ",
  			ace_in32(ace, ACE_STATUS), ace_in32(ace, ACE_CTRL),
  			ace_in(ace, ACE_SECCNTCMD));
  		dev_err(ace->dev, "fsm_task=%i fsm_state=%i data_count=%i
  ",
  			ace->fsm_task, ace->fsm_state, ace->data_count);
  	}
  
  	/* Loop over state machine until told to stop */
  	ace->fsm_continue_flag = 1;
  	while (ace->fsm_continue_flag)
  		ace_fsm_dostate(ace);
  
  	/* done with interrupt; drop the lock */
  	ace->in_irq = 0;
  	spin_unlock(&ace->lock);
  
  	return IRQ_HANDLED;
  }
  
  /* ---------------------------------------------------------------------
   * Block ops
   */
804186fa9   Jens Axboe   xsysace: convert ...
877
878
  static blk_status_t ace_queue_rq(struct blk_mq_hw_ctx *hctx,
  				 const struct blk_mq_queue_data *bd)
74489a91d   Grant Likely   Add support for X...
879
  {
804186fa9   Jens Axboe   xsysace: convert ...
880
881
  	struct ace_device *ace = hctx->queue->queuedata;
  	struct request *req = bd->rq;
74489a91d   Grant Likely   Add support for X...
882

804186fa9   Jens Axboe   xsysace: convert ...
883
884
885
  	if (blk_rq_is_passthrough(req)) {
  		blk_mq_start_request(req);
  		return BLK_STS_IOERR;
74489a91d   Grant Likely   Add support for X...
886
  	}
804186fa9   Jens Axboe   xsysace: convert ...
887
888
889
890
891
892
893
  
  	spin_lock_irq(&ace->lock);
  	list_add_tail(&req->queuelist, &ace->rq_list);
  	spin_unlock_irq(&ace->lock);
  
  	tasklet_schedule(&ace->fsm_tasklet);
  	return BLK_STS_OK;
74489a91d   Grant Likely   Add support for X...
894
  }
3a200911a   Tejun Heo   xsysace: Convert ...
895
  static unsigned int ace_check_events(struct gendisk *gd, unsigned int clearing)
74489a91d   Grant Likely   Add support for X...
896
897
  {
  	struct ace_device *ace = gd->private_data;
3a200911a   Tejun Heo   xsysace: Convert ...
898
899
  	dev_dbg(ace->dev, "ace_check_events(): %i
  ", ace->media_change);
74489a91d   Grant Likely   Add support for X...
900

3a200911a   Tejun Heo   xsysace: Convert ...
901
  	return ace->media_change ? DISK_EVENT_MEDIA_CHANGE : 0;
74489a91d   Grant Likely   Add support for X...
902
  }
77f93bfd0   Christoph Hellwig   xsysace: simplify...
903
  static void ace_media_changed(struct ace_device *ace)
74489a91d   Grant Likely   Add support for X...
904
  {
74489a91d   Grant Likely   Add support for X...
905
  	unsigned long flags;
77f93bfd0   Christoph Hellwig   xsysace: simplify...
906
907
  	dev_dbg(ace->dev, "requesting cf id and scheduling tasklet
  ");
74489a91d   Grant Likely   Add support for X...
908

77f93bfd0   Christoph Hellwig   xsysace: simplify...
909
910
911
  	spin_lock_irqsave(&ace->lock, flags);
  	ace->id_req_count++;
  	spin_unlock_irqrestore(&ace->lock, flags);
74489a91d   Grant Likely   Add support for X...
912

77f93bfd0   Christoph Hellwig   xsysace: simplify...
913
914
  	tasklet_schedule(&ace->fsm_tasklet);
  	wait_for_completion(&ace->id_completion);
74489a91d   Grant Likely   Add support for X...
915
916
917
  
  	dev_dbg(ace->dev, "revalidate complete
  ");
74489a91d   Grant Likely   Add support for X...
918
  }
f3f68b367   Al Viro   [PATCH] switch xy...
919
  static int ace_open(struct block_device *bdev, fmode_t mode)
74489a91d   Grant Likely   Add support for X...
920
  {
f3f68b367   Al Viro   [PATCH] switch xy...
921
  	struct ace_device *ace = bdev->bd_disk->private_data;
74489a91d   Grant Likely   Add support for X...
922
923
924
925
  	unsigned long flags;
  
  	dev_dbg(ace->dev, "ace_open() users=%i
  ", ace->users + 1);
2a48fc0ab   Arnd Bergmann   block: autoconver...
926
  	mutex_lock(&xsysace_mutex);
74489a91d   Grant Likely   Add support for X...
927
928
929
  	spin_lock_irqsave(&ace->lock, flags);
  	ace->users++;
  	spin_unlock_irqrestore(&ace->lock, flags);
77f93bfd0   Christoph Hellwig   xsysace: simplify...
930
931
  	if (bdev_check_media_change(bdev) && ace->media_change)
  		ace_media_changed(ace);
2a48fc0ab   Arnd Bergmann   block: autoconver...
932
  	mutex_unlock(&xsysace_mutex);
6e9624b8c   Arnd Bergmann   block: push down ...
933

74489a91d   Grant Likely   Add support for X...
934
935
  	return 0;
  }
db2a144be   Al Viro   block_device_oper...
936
  static void ace_release(struct gendisk *disk, fmode_t mode)
74489a91d   Grant Likely   Add support for X...
937
  {
f3f68b367   Al Viro   [PATCH] switch xy...
938
  	struct ace_device *ace = disk->private_data;
74489a91d   Grant Likely   Add support for X...
939
940
941
942
943
  	unsigned long flags;
  	u16 val;
  
  	dev_dbg(ace->dev, "ace_release() users=%i
  ", ace->users - 1);
2a48fc0ab   Arnd Bergmann   block: autoconver...
944
  	mutex_lock(&xsysace_mutex);
74489a91d   Grant Likely   Add support for X...
945
946
947
948
949
950
951
  	spin_lock_irqsave(&ace->lock, flags);
  	ace->users--;
  	if (ace->users == 0) {
  		val = ace_in(ace, ACE_CTRL);
  		ace_out(ace, ACE_CTRL, val & ~ACE_CTRL_LOCKREQ);
  	}
  	spin_unlock_irqrestore(&ace->lock, flags);
2a48fc0ab   Arnd Bergmann   block: autoconver...
952
  	mutex_unlock(&xsysace_mutex);
74489a91d   Grant Likely   Add support for X...
953
  }
a6b3a93e1   Christoph Hellwig   sysace: HDIO_GETG...
954
  static int ace_getgeo(struct block_device *bdev, struct hd_geometry *geo)
74489a91d   Grant Likely   Add support for X...
955
  {
a6b3a93e1   Christoph Hellwig   sysace: HDIO_GETG...
956
  	struct ace_device *ace = bdev->bd_disk->private_data;
f0edef8c8   Grant Likely   xsysace: Fix dere...
957
  	u16 *cf_id = ace->cf_id;
74489a91d   Grant Likely   Add support for X...
958

a6b3a93e1   Christoph Hellwig   sysace: HDIO_GETG...
959
960
  	dev_dbg(ace->dev, "ace_getgeo()
  ");
4aaf2fec7   Bartlomiej Zolnierkiewicz   xsysace: make it ...
961
962
963
  	geo->heads	= cf_id[ATA_ID_HEADS];
  	geo->sectors	= cf_id[ATA_ID_SECTORS];
  	geo->cylinders	= cf_id[ATA_ID_CYLS];
a6b3a93e1   Christoph Hellwig   sysace: HDIO_GETG...
964
965
  
  	return 0;
74489a91d   Grant Likely   Add support for X...
966
  }
83d5cde47   Alexey Dobriyan   const: make block...
967
  static const struct block_device_operations ace_fops = {
74489a91d   Grant Likely   Add support for X...
968
  	.owner = THIS_MODULE,
f3f68b367   Al Viro   [PATCH] switch xy...
969
970
  	.open = ace_open,
  	.release = ace_release,
3a200911a   Tejun Heo   xsysace: Convert ...
971
  	.check_events = ace_check_events,
a6b3a93e1   Christoph Hellwig   sysace: HDIO_GETG...
972
  	.getgeo = ace_getgeo,
74489a91d   Grant Likely   Add support for X...
973
  };
804186fa9   Jens Axboe   xsysace: convert ...
974
975
976
  static const struct blk_mq_ops ace_mq_ops = {
  	.queue_rq	= ace_queue_rq,
  };
74489a91d   Grant Likely   Add support for X...
977
978
979
  /* --------------------------------------------------------------------
   * SystemACE device setup/teardown code
   */
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
980
  static int ace_setup(struct ace_device *ace)
74489a91d   Grant Likely   Add support for X...
981
982
983
  {
  	u16 version;
  	u16 val;
74489a91d   Grant Likely   Add support for X...
984
  	int rc;
4a24d8610   Grant Likely   Sysace: minor rew...
985
986
  	dev_dbg(ace->dev, "ace_setup(ace=0x%p)
  ", ace);
c14464bf7   Yuri Tikhonov   xsysace: Fix driv...
987
988
989
  	dev_dbg(ace->dev, "physaddr=0x%llx irq=%i
  ",
  		(unsigned long long)ace->physaddr, ace->irq);
4a24d8610   Grant Likely   Sysace: minor rew...
990

74489a91d   Grant Likely   Add support for X...
991
992
  	spin_lock_init(&ace->lock);
  	init_completion(&ace->id_completion);
804186fa9   Jens Axboe   xsysace: convert ...
993
  	INIT_LIST_HEAD(&ace->rq_list);
74489a91d   Grant Likely   Add support for X...
994
995
996
997
998
999
1000
  
  	/*
  	 * Map the device
  	 */
  	ace->baseaddr = ioremap(ace->physaddr, 0x80);
  	if (!ace->baseaddr)
  		goto err_ioremap;
74489a91d   Grant Likely   Add support for X...
1001
1002
1003
1004
  	/*
  	 * Initialize the state machine tasklet and stall timer
  	 */
  	tasklet_init(&ace->fsm_tasklet, ace_fsm_tasklet, (unsigned long)ace);
e99e88a9d   Kees Cook   treewide: setup_t...
1005
  	timer_setup(&ace->stall_timer, ace_stall_timer, 0);
74489a91d   Grant Likely   Add support for X...
1006
1007
1008
1009
  
  	/*
  	 * Initialize the request queue
  	 */
804186fa9   Jens Axboe   xsysace: convert ...
1010
1011
1012
1013
1014
  	ace->queue = blk_mq_init_sq_queue(&ace->tag_set, &ace_mq_ops, 2,
  						BLK_MQ_F_SHOULD_MERGE);
  	if (IS_ERR(ace->queue)) {
  		rc = PTR_ERR(ace->queue);
  		ace->queue = NULL;
74489a91d   Grant Likely   Add support for X...
1015
  		goto err_blk_initq;
804186fa9   Jens Axboe   xsysace: convert ...
1016
1017
  	}
  	ace->queue->queuedata = ace;
e1defc4ff   Martin K. Petersen   block: Do away wi...
1018
  	blk_queue_logical_block_size(ace->queue, 512);
8fc450443   Christoph Hellwig   block: don't set ...
1019
  	blk_queue_bounce_limit(ace->queue, BLK_BOUNCE_HIGH);
74489a91d   Grant Likely   Add support for X...
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
  
  	/*
  	 * Allocate and initialize GD structure
  	 */
  	ace->gd = alloc_disk(ACE_NUM_MINORS);
  	if (!ace->gd)
  		goto err_alloc_disk;
  
  	ace->gd->major = ace_major;
  	ace->gd->first_minor = ace->id * ACE_NUM_MINORS;
  	ace->gd->fops = &ace_fops;
773008f6f   Martin Wilck   Revert "block: un...
1031
  	ace->gd->events = DISK_EVENT_MEDIA_CHANGE;
74489a91d   Grant Likely   Add support for X...
1032
1033
1034
1035
1036
  	ace->gd->queue = ace->queue;
  	ace->gd->private_data = ace;
  	snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a');
  
  	/* set bus width */
4a24d8610   Grant Likely   Sysace: minor rew...
1037
  	if (ace->bus_width == ACE_BUS_WIDTH_16) {
74489a91d   Grant Likely   Add support for X...
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
  		/* 0x0101 should work regardless of endianess */
  		ace_out_le16(ace, ACE_BUSMODE, 0x0101);
  
  		/* read it back to determine endianess */
  		if (ace_in_le16(ace, ACE_BUSMODE) == 0x0001)
  			ace->reg_ops = &ace_reg_le16_ops;
  		else
  			ace->reg_ops = &ace_reg_be16_ops;
  	} else {
  		ace_out_8(ace, ACE_BUSMODE, 0x00);
  		ace->reg_ops = &ace_reg_8_ops;
  	}
  
  	/* Make sure version register is sane */
  	version = ace_in(ace, ACE_VERSION);
  	if ((version == 0) || (version == 0xFFFF))
  		goto err_read;
  
  	/* Put sysace in a sane state by clearing most control reg bits */
  	ace_out(ace, ACE_CTRL, ACE_CTRL_FORCECFGMODE |
  		ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ);
32f6fff47   Grant Likely   Sysace: Move IRQ ...
1059
  	/* Now we can hook up the irq handler */
7cb6e22ba   Andy Shevchenko   xsysace: use plat...
1060
  	if (ace->irq > 0) {
32f6fff47   Grant Likely   Sysace: Move IRQ ...
1061
1062
1063
1064
1065
  		rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace);
  		if (rc) {
  			/* Failure - fall back to polled mode */
  			dev_err(ace->dev, "request_irq failed
  ");
7cb6e22ba   Andy Shevchenko   xsysace: use plat...
1066
  			ace->irq = rc;
32f6fff47   Grant Likely   Sysace: Move IRQ ...
1067
1068
  		}
  	}
d2bbf3da3   Grant Likely   Sysace: Don't ena...
1069
1070
1071
1072
  	/* Enable interrupts */
  	val = ace_in(ace, ACE_CTRL);
  	val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ;
  	ace_out(ace, ACE_CTRL, val);
74489a91d   Grant Likely   Add support for X...
1073
1074
1075
1076
  	/* Print the identification */
  	dev_info(ace->dev, "Xilinx SystemACE revision %i.%i.%i
  ",
  		 (version >> 12) & 0xf, (version >> 8) & 0x0f, version & 0xff);
c14464bf7   Yuri Tikhonov   xsysace: Fix driv...
1077
1078
1079
  	dev_dbg(ace->dev, "physaddr 0x%llx, mapped to 0x%p, irq=%i
  ",
  		(unsigned long long) ace->physaddr, ace->baseaddr, ace->irq);
74489a91d   Grant Likely   Add support for X...
1080
1081
  
  	ace->media_change = 1;
77f93bfd0   Christoph Hellwig   xsysace: simplify...
1082
  	ace_media_changed(ace);
74489a91d   Grant Likely   Add support for X...
1083
1084
1085
1086
1087
  
  	/* Make the sysace device 'live' */
  	add_disk(ace->gd);
  
  	return 0;
ed155a95a   Grant Likely   Sysace: Labels in...
1088
  err_read:
47b16820c   Guenter Roeck   xsysace: Fix erro...
1089
1090
  	/* prevent double queue cleanup */
  	ace->gd->queue = NULL;
74489a91d   Grant Likely   Add support for X...
1091
  	put_disk(ace->gd);
ed155a95a   Grant Likely   Sysace: Labels in...
1092
  err_alloc_disk:
74489a91d   Grant Likely   Add support for X...
1093
  	blk_cleanup_queue(ace->queue);
804186fa9   Jens Axboe   xsysace: convert ...
1094
  	blk_mq_free_tag_set(&ace->tag_set);
ed155a95a   Grant Likely   Sysace: Labels in...
1095
  err_blk_initq:
74489a91d   Grant Likely   Add support for X...
1096
  	iounmap(ace->baseaddr);
ed155a95a   Grant Likely   Sysace: Labels in...
1097
  err_ioremap:
c14464bf7   Yuri Tikhonov   xsysace: Fix driv...
1098
1099
1100
  	dev_info(ace->dev, "xsysace: error initializing device at 0x%llx
  ",
  		 (unsigned long long) ace->physaddr);
74489a91d   Grant Likely   Add support for X...
1101
1102
  	return -ENOMEM;
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
1103
  static void ace_teardown(struct ace_device *ace)
74489a91d   Grant Likely   Add support for X...
1104
1105
1106
1107
1108
  {
  	if (ace->gd) {
  		del_gendisk(ace->gd);
  		put_disk(ace->gd);
  	}
804186fa9   Jens Axboe   xsysace: convert ...
1109
  	if (ace->queue) {
74489a91d   Grant Likely   Add support for X...
1110
  		blk_cleanup_queue(ace->queue);
804186fa9   Jens Axboe   xsysace: convert ...
1111
1112
  		blk_mq_free_tag_set(&ace->tag_set);
  	}
74489a91d   Grant Likely   Add support for X...
1113
1114
  
  	tasklet_kill(&ace->fsm_tasklet);
7cb6e22ba   Andy Shevchenko   xsysace: use plat...
1115
  	if (ace->irq > 0)
74489a91d   Grant Likely   Add support for X...
1116
1117
1118
1119
  		free_irq(ace->irq, ace);
  
  	iounmap(ace->baseaddr);
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
1120
1121
  static int ace_alloc(struct device *dev, int id, resource_size_t physaddr,
  		     int irq, int bus_width)
74489a91d   Grant Likely   Add support for X...
1122
  {
74489a91d   Grant Likely   Add support for X...
1123
  	struct ace_device *ace;
1b4554665   Grant Likely   Sysace: Move stru...
1124
1125
1126
  	int rc;
  	dev_dbg(dev, "ace_alloc(%p)
  ", dev);
74489a91d   Grant Likely   Add support for X...
1127

1b4554665   Grant Likely   Sysace: Move stru...
1128
  	/* Allocate and initialize the ace device structure */
74489a91d   Grant Likely   Add support for X...
1129
  	ace = kzalloc(sizeof(struct ace_device), GFP_KERNEL);
1b4554665   Grant Likely   Sysace: Move stru...
1130
1131
  	if (!ace) {
  		rc = -ENOMEM;
74489a91d   Grant Likely   Add support for X...
1132
  		goto err_alloc;
74489a91d   Grant Likely   Add support for X...
1133
  	}
1b4554665   Grant Likely   Sysace: Move stru...
1134
1135
1136
1137
1138
  	ace->dev = dev;
  	ace->id = id;
  	ace->physaddr = physaddr;
  	ace->irq = irq;
  	ace->bus_width = bus_width;
74489a91d   Grant Likely   Add support for X...
1139

1b4554665   Grant Likely   Sysace: Move stru...
1140
  	/* Call the setup code */
34e1b8341   Grant Likely   Sysace: Minor cod...
1141
1142
  	rc = ace_setup(ace);
  	if (rc)
74489a91d   Grant Likely   Add support for X...
1143
  		goto err_setup;
1b4554665   Grant Likely   Sysace: Move stru...
1144
  	dev_set_drvdata(dev, ace);
74489a91d   Grant Likely   Add support for X...
1145
  	return 0;
ed155a95a   Grant Likely   Sysace: Labels in...
1146
  err_setup:
1b4554665   Grant Likely   Sysace: Move stru...
1147
  	dev_set_drvdata(dev, NULL);
74489a91d   Grant Likely   Add support for X...
1148
  	kfree(ace);
ed155a95a   Grant Likely   Sysace: Labels in...
1149
  err_alloc:
1b4554665   Grant Likely   Sysace: Move stru...
1150
1151
1152
  	dev_err(dev, "could not initialize device, err=%i
  ", rc);
  	return rc;
74489a91d   Grant Likely   Add support for X...
1153
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
1154
  static void ace_free(struct device *dev)
74489a91d   Grant Likely   Add support for X...
1155
  {
1b4554665   Grant Likely   Sysace: Move stru...
1156
1157
1158
  	struct ace_device *ace = dev_get_drvdata(dev);
  	dev_dbg(dev, "ace_free(%p)
  ", dev);
74489a91d   Grant Likely   Add support for X...
1159
1160
1161
  
  	if (ace) {
  		ace_teardown(ace);
1b4554665   Grant Likely   Sysace: Move stru...
1162
  		dev_set_drvdata(dev, NULL);
74489a91d   Grant Likely   Add support for X...
1163
1164
  		kfree(ace);
  	}
1b4554665   Grant Likely   Sysace: Move stru...
1165
1166
1167
1168
1169
  }
  
  /* ---------------------------------------------------------------------
   * Platform Bus Support
   */
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
1170
  static int ace_probe(struct platform_device *dev)
1b4554665   Grant Likely   Sysace: Move stru...
1171
  {
4a24d8610   Grant Likely   Sysace: minor rew...
1172
  	int bus_width = ACE_BUS_WIDTH_16; /* FIXME: should not be hard coded */
7cb6e22ba   Andy Shevchenko   xsysace: use plat...
1173
1174
  	resource_size_t physaddr;
  	struct resource *res;
5d10302f4   Grant Likely   dt: remove extra ...
1175
  	u32 id = dev->id;
7cb6e22ba   Andy Shevchenko   xsysace: use plat...
1176
  	int irq;
1b4554665   Grant Likely   Sysace: Move stru...
1177
1178
1179
1180
  	int i;
  
  	dev_dbg(&dev->dev, "ace_probe(%p)
  ", dev);
5d10302f4   Grant Likely   dt: remove extra ...
1181
  	/* device id and bus width */
585dc0c2f   Gernot Vormayr   drivers/block/xsy...
1182
  	if (of_property_read_u32(dev->dev.of_node, "port-number", &id))
5d10302f4   Grant Likely   dt: remove extra ...
1183
1184
1185
  		id = 0;
  	if (of_find_property(dev->dev.of_node, "8-bit", NULL))
  		bus_width = ACE_BUS_WIDTH_8;
7cb6e22ba   Andy Shevchenko   xsysace: use plat...
1186
1187
1188
1189
1190
1191
1192
1193
1194
  	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
  	if (!res)
  		return -EINVAL;
  
  	physaddr = res->start;
  	if (!physaddr)
  		return -ENODEV;
  
  	irq = platform_get_irq_optional(dev, 0);
1b4554665   Grant Likely   Sysace: Move stru...
1195

25985edce   Lucas De Marchi   Fix common misspe...
1196
  	/* Call the bus-independent setup code */
1b4554665   Grant Likely   Sysace: Move stru...
1197
1198
  	return ace_alloc(&dev->dev, id, physaddr, irq, bus_width);
  }
74489a91d   Grant Likely   Add support for X...
1199

1b4554665   Grant Likely   Sysace: Move stru...
1200
1201
1202
  /*
   * Platform bus remove() method
   */
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
1203
  static int ace_remove(struct platform_device *dev)
1b4554665   Grant Likely   Sysace: Move stru...
1204
1205
  {
  	ace_free(&dev->dev);
74489a91d   Grant Likely   Add support for X...
1206
1207
  	return 0;
  }
95e896c35   Grant Likely   Sysace: Add of_pl...
1208
  #if defined(CONFIG_OF)
95e896c35   Grant Likely   Sysace: Add of_pl...
1209
  /* Match table for of_platform binding */
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
1210
  static const struct of_device_id ace_of_match[] = {
0e349b0e2   Stephen Neuendorffer   [POWERPC] Xilinx:...
1211
1212
1213
  	{ .compatible = "xlnx,opb-sysace-1.00.b", },
  	{ .compatible = "xlnx,opb-sysace-1.00.c", },
  	{ .compatible = "xlnx,xps-sysace-1.00.a", },
f5020384e   Yuri Tikhonov   powerpc/xsysace: ...
1214
  	{ .compatible = "xlnx,sysace", },
95e896c35   Grant Likely   Sysace: Add of_pl...
1215
1216
1217
  	{},
  };
  MODULE_DEVICE_TABLE(of, ace_of_match);
5d10302f4   Grant Likely   dt: remove extra ...
1218
1219
1220
  #else /* CONFIG_OF */
  #define ace_of_match NULL
  #endif /* CONFIG_OF */
95e896c35   Grant Likely   Sysace: Add of_pl...
1221

5d10302f4   Grant Likely   dt: remove extra ...
1222
1223
  static struct platform_driver ace_platform_driver = {
  	.probe = ace_probe,
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
1224
  	.remove = ace_remove,
95e896c35   Grant Likely   Sysace: Add of_pl...
1225
  	.driver = {
5d10302f4   Grant Likely   dt: remove extra ...
1226
  		.name = "xsysace",
4018294b5   Grant Likely   of: Remove duplic...
1227
  		.of_match_table = ace_of_match,
95e896c35   Grant Likely   Sysace: Add of_pl...
1228
1229
  	},
  };
95e896c35   Grant Likely   Sysace: Add of_pl...
1230
  /* ---------------------------------------------------------------------
74489a91d   Grant Likely   Add support for X...
1231
1232
1233
1234
   * Module init/exit routines
   */
  static int __init ace_init(void)
  {
edec49616   Grant Likely   Sysace: Use the e...
1235
  	int rc;
74489a91d   Grant Likely   Add support for X...
1236
1237
  	ace_major = register_blkdev(ace_major, "xsysace");
  	if (ace_major <= 0) {
edec49616   Grant Likely   Sysace: Use the e...
1238
1239
  		rc = -ENOMEM;
  		goto err_blk;
74489a91d   Grant Likely   Add support for X...
1240
  	}
34e1b8341   Grant Likely   Sysace: Minor cod...
1241
1242
  	rc = platform_driver_register(&ace_platform_driver);
  	if (rc)
edec49616   Grant Likely   Sysace: Use the e...
1243
1244
1245
1246
1247
  		goto err_plat;
  
  	pr_info("Xilinx SystemACE device driver, major=%i
  ", ace_major);
  	return 0;
ed155a95a   Grant Likely   Sysace: Labels in...
1248
  err_plat:
edec49616   Grant Likely   Sysace: Use the e...
1249
  	unregister_blkdev(ace_major, "xsysace");
ed155a95a   Grant Likely   Sysace: Labels in...
1250
  err_blk:
edec49616   Grant Likely   Sysace: Use the e...
1251
1252
1253
  	printk(KERN_ERR "xsysace: registration failed; err=%i
  ", rc);
  	return rc;
74489a91d   Grant Likely   Add support for X...
1254
  }
5d10302f4   Grant Likely   dt: remove extra ...
1255
  module_init(ace_init);
74489a91d   Grant Likely   Add support for X...
1256
1257
1258
1259
1260
  
  static void __exit ace_exit(void)
  {
  	pr_debug("Unregistering Xilinx SystemACE driver
  ");
edec49616   Grant Likely   Sysace: Use the e...
1261
  	platform_driver_unregister(&ace_platform_driver);
c6d4d6348   Akinobu Mita   unregister_blkdev...
1262
  	unregister_blkdev(ace_major, "xsysace");
74489a91d   Grant Likely   Add support for X...
1263
  }
74489a91d   Grant Likely   Add support for X...
1264
  module_exit(ace_exit);