415
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
1 /*
|
417
|
2 * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
|
|
3 *
|
|
4 * This file is released under the GPLv2. See the COPYING file for more
|
|
5 * details.
|
415
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
6 */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
7
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
8 #include <channel.h>
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
9 #include <io.h>
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
10 #include <interrupt.h>
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
11 #include <device.h>
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
12 #include <sched.h>
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
13 #include <atomic.h>
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
14 #include <spinlock.h>
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
15 #include <buddy.h>
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
16 #include <sched.h>
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
17
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
18 /*
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
19 * Helper function to make sure the io_op has everything set right
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
20 */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
21 static int __verify_io_op(struct io_op *ioop)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
22 {
|
618
|
23 FIXME("check everything that makes sense to check");
|
415
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
24 return 0;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
25 }
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
26
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
27 static void __reset_reserved_fields(struct io_op *ioop)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
28 {
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
29 ioop->orb.__zero1 = 0;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
30
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
31 ioop->orb.__reserved1 = 0;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
32 ioop->orb.__reserved2 = 0;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
33 ioop->orb.__reserved3 = 0;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
34 ioop->orb.__reserved4 = 0;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
35 ioop->orb.__reserved5 = 0;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
36 ioop->orb.__reserved6 = 0;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
37 }
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
38
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
39 /* NOTE: assumes dev->q_lock is held */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
40 static void __submit_io(struct device *dev)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
41 {
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
42 struct io_op *ioop;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
43 int err;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
44
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
45 if (dev->q_cur)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
46 return;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
47
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
48 if (list_empty(&dev->q_out))
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
49 return;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
50
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
51 ioop = list_entry(dev->q_out.next, struct io_op, list);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
52
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
53 err = start_sch(dev->sch, &ioop->orb);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
54 if (!err) {
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
55 list_del(&ioop->list);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
56 dev->q_cur = ioop;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
57 } else
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
58 ioop->err = err;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
59 }
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
60
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
61 /*
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
62 * Submit an I/O request to a subchannel, and set up everything needed to
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
63 * handle the operation
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
64 */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
65 int submit_io(struct device *dev, struct io_op *ioop, int flags)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
66 {
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
67 static atomic_t op_id_counter;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
68 unsigned long intmask;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
69 int err = -EBUSY;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
70
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
71 err = __verify_io_op(ioop);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
72 if (err)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
73 return 0;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
74
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
75 /* make sure all reserved fields have the right values */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
76 __reset_reserved_fields(ioop);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
77
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
78 ioop->err = 0;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
79 ioop->orb.param = atomic_inc_return(&op_id_counter);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
80 atomic_set(&ioop->done, 0);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
81
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
82 /* add it to the list of ops */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
83 spin_lock_intsave(&dev->q_lock, &intmask);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
84 list_add_tail(&ioop->list, &dev->q_out);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
85
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
86 __submit_io(dev); /* try to submit an IO right now */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
87 spin_unlock_intrestore(&dev->q_lock, intmask);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
88
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
89 if (flags & CAN_LOOP) {
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
90 while(!atomic_read(&ioop->done))
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
91 ;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
92 } else if (flags & CAN_SLEEP) {
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
93 while(!atomic_read(&ioop->done))
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
94 schedule();
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
95 }
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
96
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
97 return 0;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
98 }
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
99
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
100 /*
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
101 * Initialize the channel I/O subsystem
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
102 */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
103 void init_io(void)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
104 {
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
105 u64 cr6;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
106
|
614
9bbe38598c2f
cp & login NSS: use {get,set}_cr to enable I/O subclasses
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
diff
changeset
|
107 cr6 = get_cr(6);
|
9bbe38598c2f
cp & login NSS: use {get,set}_cr to enable I/O subclasses
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
diff
changeset
|
108
|
415
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
109 /* enable all I/O interrupt classes */
|
614
9bbe38598c2f
cp & login NSS: use {get,set}_cr to enable I/O subclasses
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
diff
changeset
|
110 cr6 |= BIT64(32);
|
9bbe38598c2f
cp & login NSS: use {get,set}_cr to enable I/O subclasses
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
diff
changeset
|
111 cr6 |= BIT64(33);
|
9bbe38598c2f
cp & login NSS: use {get,set}_cr to enable I/O subclasses
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
diff
changeset
|
112 cr6 |= BIT64(34);
|
9bbe38598c2f
cp & login NSS: use {get,set}_cr to enable I/O subclasses
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
diff
changeset
|
113 cr6 |= BIT64(35);
|
9bbe38598c2f
cp & login NSS: use {get,set}_cr to enable I/O subclasses
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
diff
changeset
|
114 cr6 |= BIT64(36);
|
9bbe38598c2f
cp & login NSS: use {get,set}_cr to enable I/O subclasses
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
diff
changeset
|
115 cr6 |= BIT64(37);
|
9bbe38598c2f
cp & login NSS: use {get,set}_cr to enable I/O subclasses
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
diff
changeset
|
116 cr6 |= BIT64(38);
|
9bbe38598c2f
cp & login NSS: use {get,set}_cr to enable I/O subclasses
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
diff
changeset
|
117 cr6 |= BIT64(39);
|
9bbe38598c2f
cp & login NSS: use {get,set}_cr to enable I/O subclasses
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
diff
changeset
|
118
|
9bbe38598c2f
cp & login NSS: use {get,set}_cr to enable I/O subclasses
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
diff
changeset
|
119 set_cr(6, cr6);
|
415
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
120 }
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
121
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
122 static int default_io_handler(struct device *dev, struct io_op *ioop, struct irb *irb)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
123 {
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
124 ioop->err = -EAGAIN;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
125
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
126 /* Unit check? */
|
618
|
127 if (irb->scsw.dev_status & 0x02) {
|
|
128 FIXME("we should bail");
|
|
129 ioop->err = -EUCHECK;
|
|
130 }
|
415
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
131
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
132 /* Device End is set, we're done */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
133 if (irb->scsw.dev_status & 0x04)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
134 ioop->err = 0;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
135
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
136 return 0;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
137 }
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
138
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
139 static void __cpu_initiated_io(struct device *dev, struct io_op *ioop, struct irb *irb)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
140 {
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
141 unsigned long intmask;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
142
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
143 ioop->err = test_sch(dev->sch, irb);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
144
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
145 if (!ioop->err && ioop->handler)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
146 ioop->handler(dev, ioop, irb);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
147 else if (!ioop->err)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
148 default_io_handler(dev, ioop, irb);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
149
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
150 /*
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
151 * We can do this, because the test_sch function sets ->err, and
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
152 * therefore regardless of ->handler being defined, ->err will have
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
153 * a reasonable value
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
154 */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
155 if (ioop->err == -EAGAIN)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
156 return; /* leave handler registered */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
157
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
158 /* ...and remove it form the list */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
159 spin_lock_intsave(&dev->q_lock, &intmask);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
160 dev->q_cur = NULL;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
161
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
162 __submit_io(dev); /* try to submit another IO */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
163 spin_unlock_intrestore(&dev->q_lock, intmask);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
164
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
165 /* flag io_op as done... */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
166 atomic_set(&ioop->done, 1);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
167
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
168 /* call the destructor if there is one */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
169 if (ioop->dtor)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
170 ioop->dtor(dev, ioop);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
171 }
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
172
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
173 static void __dev_initiated_io(struct device *dev, struct irb *irb)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
174 {
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
175 }
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
176
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
177 /*
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
178 * I/O Interrupt handler (C portion)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
179 */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
180 void __io_int_handler(void)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
181 {
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
182 unsigned long intmask;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
183 struct io_op *ioop;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
184 struct device *dev;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
185 struct irb irb;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
186
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
187 dev = find_device_by_sch(IO_INT_CODE->ssid);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
188 BUG_ON(IS_ERR(dev));
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
189
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
190 spin_lock_intsave(&dev->q_lock, &intmask);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
191 ioop = dev->q_cur;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
192 spin_unlock_intrestore(&dev->q_lock, intmask);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
193
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
194 if (ioop && ioop->orb.param == IO_INT_CODE->param &&
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
195 dev->sch == IO_INT_CODE->ssid) {
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
196 /*
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
197 * CPU-initiated operation
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
198 */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
199
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
200 __cpu_initiated_io(dev, ioop, &irb);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
201 dev_put(dev);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
202 return;
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
203 }
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
204
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
205 /*
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
206 * device-initiated operation
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
207 */
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
208 BUG_ON(test_sch(dev->sch, &irb));
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
209
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
210 atomic_inc(&dev->attention);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
211
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
212 if (dev->dev->interrupt)
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
213 dev->dev->interrupt(dev, &irb);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
214 else
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
215 __dev_initiated_io(dev, &irb);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
216 dev_put(dev);
|
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
parents:
diff
changeset
|
217 }
|