Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
s390
cio
airq.c
Go to the documentation of this file.
1
/*
2
* Support for adapter interruptions
3
*
4
* Copyright IBM Corp. 1999, 2007
5
* Author(s): Ingo Adlung <
[email protected]
>
6
* Cornelia Huck <
[email protected]
>
7
* Arnd Bergmann <
[email protected]
>
8
* Peter Oberparleiter <
[email protected]
>
9
*/
10
11
#include <
linux/init.h
>
12
#include <linux/module.h>
13
#include <linux/slab.h>
14
#include <
linux/rcupdate.h
>
15
16
#include <
asm/airq.h
>
17
#include <
asm/isc.h
>
18
19
#include "
cio.h
"
20
#include "
cio_debug.h
"
21
22
#define NR_AIRQS 32
23
#define NR_AIRQS_PER_WORD sizeof(unsigned long)
24
#define NR_AIRQ_WORDS (NR_AIRQS / NR_AIRQS_PER_WORD)
25
26
union
indicator_t
{
27
unsigned
long
word
[
NR_AIRQ_WORDS
];
28
unsigned
char
byte
[
NR_AIRQS
];
29
}
__attribute__
((packed));
30
31
struct
airq_t
{
32
adapter_int_handler_t
handler
;
33
void
*
drv_data
;
34
};
35
36
static
union
indicator_t
indicators[
MAX_ISC
+1];
37
static
struct
airq_t
*airqs[
MAX_ISC
+1][
NR_AIRQS
];
38
39
static
int
register_airq(
struct
airq_t
*airq,
u8
isc
)
40
{
41
int
i
;
42
43
for
(i = 0; i <
NR_AIRQS
; i++)
44
if
(!
cmpxchg
(&airqs[isc][i],
NULL
, airq))
45
return
i
;
46
return
-
ENOMEM
;
47
}
48
59
void
*
s390_register_adapter_interrupt
(
adapter_int_handler_t
handler
,
60
void
*
drv_data
,
u8
isc)
61
{
62
struct
airq_t
*airq;
63
char
dbf_txt[16];
64
int
ret
;
65
66
if
(isc >
MAX_ISC
)
67
return
ERR_PTR(-
EINVAL
);
68
airq =
kmalloc
(
sizeof
(
struct
airq_t
),
GFP_KERNEL
);
69
if
(!airq) {
70
ret = -
ENOMEM
;
71
goto
out
;
72
}
73
airq->
handler
=
handler
;
74
airq->
drv_data
=
drv_data
;
75
76
ret = register_airq(airq, isc);
77
out
:
78
snprintf
(dbf_txt,
sizeof
(dbf_txt),
"rairq:%d"
, ret);
79
CIO_TRACE_EVENT
(4, dbf_txt);
80
if
(ret < 0) {
81
kfree
(airq);
82
return
ERR_PTR(ret);
83
}
else
84
return
&indicators[
isc
].
byte
[
ret
];
85
}
86
EXPORT_SYMBOL
(
s390_register_adapter_interrupt
);
87
93
void
s390_unregister_adapter_interrupt
(
void
*
ind
,
u8
isc)
94
{
95
struct
airq_t
*airq;
96
char
dbf_txt[16];
97
int
i
;
98
99
i = (
int
) ((
addr_t
)
ind
) - ((
addr_t
) &indicators[
isc
].
byte
[0]);
100
snprintf
(dbf_txt,
sizeof
(dbf_txt),
"urairq:%d"
, i);
101
CIO_TRACE_EVENT
(4, dbf_txt);
102
indicators[
isc
].
byte
[
i
] = 0;
103
airq =
xchg
(&airqs[isc][i],
NULL
);
104
/*
105
* Allow interrupts to complete. This will ensure that the airq handle
106
* is no longer referenced by any interrupt handler.
107
*/
108
synchronize_sched
();
109
kfree
(airq);
110
}
111
EXPORT_SYMBOL
(
s390_unregister_adapter_interrupt
);
112
113
#define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8))
114
115
void
do_adapter_IO
(
u8
isc)
116
{
117
int
w
;
118
int
i
;
119
unsigned
long
word
;
120
struct
airq_t
*airq;
121
122
/*
123
* Access indicator array in word-sized chunks to minimize storage
124
* fetch operations.
125
*/
126
for
(w = 0; w <
NR_AIRQ_WORDS
; w++) {
127
word = indicators[
isc
].
word
[
w
];
128
i = w *
NR_AIRQS_PER_WORD
;
129
/*
130
* Check bytes within word for active indicators.
131
*/
132
while
(word) {
133
if
(word &
INDICATOR_MASK
) {
134
airq = airqs[
isc
][
i
];
135
/* Make sure gcc reads from airqs only once. */
136
barrier
();
137
if
(
likely
(airq))
138
airq->
handler
(&indicators[isc].
byte
[i],
139
airq->
drv_data
);
140
else
141
/*
142
* Reset ill-behaved indicator.
143
*/
144
indicators[
isc
].
byte
[
i
] = 0;
145
}
146
word <<= 8;
147
i++;
148
}
149
}
150
}
Generated on Thu Jan 10 2013 14:17:41 for Linux Kernel by
1.8.2