Commit 3dbda77e6f3375f87090cfce97b2551d3723521b
Committed by
Jiri Kosina
1 parent
31d0f84591
Exists in
master
and in
4 other branches
trivial: fix typos "man[ae]g?ment" -> "management"
Signed-off-by: Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Showing 18 changed files with 21 additions and 21 deletions Inline Diff
- Documentation/DocBook/mtdnand.tmpl
- Documentation/DocBook/scsi.tmpl
- Documentation/scsi/ChangeLog.megaraid
- Documentation/sound/alsa/HD-Audio-Models.txt
- Documentation/trace/ftrace.txt
- arch/arm/Makefile
- arch/frv/lib/cache.S
- arch/mn10300/include/asm/cacheflush.h
- drivers/media/dvb/siano/smscoreapi.c
- drivers/media/dvb/siano/smscoreapi.h
- drivers/media/radio/radio-mr800.c
- drivers/message/fusion/mptbase.c
- drivers/net/macb.c
- drivers/net/wireless/ath/ath5k/reg.h
- drivers/net/wireless/atmel.c
- drivers/usb/host/xhci.h
- drivers/usb/wusbcore/wa-hc.h
- include/linux/mISDNif.h
Documentation/DocBook/mtdnand.tmpl
1 | <?xml version="1.0" encoding="UTF-8"?> | 1 | <?xml version="1.0" encoding="UTF-8"?> |
2 | <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" | 2 | <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" |
3 | "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []> | 3 | "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []> |
4 | 4 | ||
5 | <book id="MTD-NAND-Guide"> | 5 | <book id="MTD-NAND-Guide"> |
6 | <bookinfo> | 6 | <bookinfo> |
7 | <title>MTD NAND Driver Programming Interface</title> | 7 | <title>MTD NAND Driver Programming Interface</title> |
8 | 8 | ||
9 | <authorgroup> | 9 | <authorgroup> |
10 | <author> | 10 | <author> |
11 | <firstname>Thomas</firstname> | 11 | <firstname>Thomas</firstname> |
12 | <surname>Gleixner</surname> | 12 | <surname>Gleixner</surname> |
13 | <affiliation> | 13 | <affiliation> |
14 | <address> | 14 | <address> |
15 | <email>tglx@linutronix.de</email> | 15 | <email>tglx@linutronix.de</email> |
16 | </address> | 16 | </address> |
17 | </affiliation> | 17 | </affiliation> |
18 | </author> | 18 | </author> |
19 | </authorgroup> | 19 | </authorgroup> |
20 | 20 | ||
21 | <copyright> | 21 | <copyright> |
22 | <year>2004</year> | 22 | <year>2004</year> |
23 | <holder>Thomas Gleixner</holder> | 23 | <holder>Thomas Gleixner</holder> |
24 | </copyright> | 24 | </copyright> |
25 | 25 | ||
26 | <legalnotice> | 26 | <legalnotice> |
27 | <para> | 27 | <para> |
28 | This documentation is free software; you can redistribute | 28 | This documentation is free software; you can redistribute |
29 | it and/or modify it under the terms of the GNU General Public | 29 | it and/or modify it under the terms of the GNU General Public |
30 | License version 2 as published by the Free Software Foundation. | 30 | License version 2 as published by the Free Software Foundation. |
31 | </para> | 31 | </para> |
32 | 32 | ||
33 | <para> | 33 | <para> |
34 | This program is distributed in the hope that it will be | 34 | This program is distributed in the hope that it will be |
35 | useful, but WITHOUT ANY WARRANTY; without even the implied | 35 | useful, but WITHOUT ANY WARRANTY; without even the implied |
36 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 36 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
37 | See the GNU General Public License for more details. | 37 | See the GNU General Public License for more details. |
38 | </para> | 38 | </para> |
39 | 39 | ||
40 | <para> | 40 | <para> |
41 | You should have received a copy of the GNU General Public | 41 | You should have received a copy of the GNU General Public |
42 | License along with this program; if not, write to the Free | 42 | License along with this program; if not, write to the Free |
43 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 43 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
44 | MA 02111-1307 USA | 44 | MA 02111-1307 USA |
45 | </para> | 45 | </para> |
46 | 46 | ||
47 | <para> | 47 | <para> |
48 | For more details see the file COPYING in the source | 48 | For more details see the file COPYING in the source |
49 | distribution of Linux. | 49 | distribution of Linux. |
50 | </para> | 50 | </para> |
51 | </legalnotice> | 51 | </legalnotice> |
52 | </bookinfo> | 52 | </bookinfo> |
53 | 53 | ||
54 | <toc></toc> | 54 | <toc></toc> |
55 | 55 | ||
56 | <chapter id="intro"> | 56 | <chapter id="intro"> |
57 | <title>Introduction</title> | 57 | <title>Introduction</title> |
58 | <para> | 58 | <para> |
59 | The generic NAND driver supports almost all NAND and AG-AND based | 59 | The generic NAND driver supports almost all NAND and AG-AND based |
60 | chips and connects them to the Memory Technology Devices (MTD) | 60 | chips and connects them to the Memory Technology Devices (MTD) |
61 | subsystem of the Linux Kernel. | 61 | subsystem of the Linux Kernel. |
62 | </para> | 62 | </para> |
63 | <para> | 63 | <para> |
64 | This documentation is provided for developers who want to implement | 64 | This documentation is provided for developers who want to implement |
65 | board drivers or filesystem drivers suitable for NAND devices. | 65 | board drivers or filesystem drivers suitable for NAND devices. |
66 | </para> | 66 | </para> |
67 | </chapter> | 67 | </chapter> |
68 | 68 | ||
69 | <chapter id="bugs"> | 69 | <chapter id="bugs"> |
70 | <title>Known Bugs And Assumptions</title> | 70 | <title>Known Bugs And Assumptions</title> |
71 | <para> | 71 | <para> |
72 | None. | 72 | None. |
73 | </para> | 73 | </para> |
74 | </chapter> | 74 | </chapter> |
75 | 75 | ||
76 | <chapter id="dochints"> | 76 | <chapter id="dochints"> |
77 | <title>Documentation hints</title> | 77 | <title>Documentation hints</title> |
78 | <para> | 78 | <para> |
79 | The function and structure docs are autogenerated. Each function and | 79 | The function and structure docs are autogenerated. Each function and |
80 | struct member has a short description which is marked with an [XXX] identifier. | 80 | struct member has a short description which is marked with an [XXX] identifier. |
81 | The following chapters explain the meaning of those identifiers. | 81 | The following chapters explain the meaning of those identifiers. |
82 | </para> | 82 | </para> |
83 | <sect1 id="Function_identifiers_XXX"> | 83 | <sect1 id="Function_identifiers_XXX"> |
84 | <title>Function identifiers [XXX]</title> | 84 | <title>Function identifiers [XXX]</title> |
85 | <para> | 85 | <para> |
86 | The functions are marked with [XXX] identifiers in the short | 86 | The functions are marked with [XXX] identifiers in the short |
87 | comment. The identifiers explain the usage and scope of the | 87 | comment. The identifiers explain the usage and scope of the |
88 | functions. Following identifiers are used: | 88 | functions. Following identifiers are used: |
89 | </para> | 89 | </para> |
90 | <itemizedlist> | 90 | <itemizedlist> |
91 | <listitem><para> | 91 | <listitem><para> |
92 | [MTD Interface]</para><para> | 92 | [MTD Interface]</para><para> |
93 | These functions provide the interface to the MTD kernel API. | 93 | These functions provide the interface to the MTD kernel API. |
94 | They are not replacable and provide functionality | 94 | They are not replacable and provide functionality |
95 | which is complete hardware independent. | 95 | which is complete hardware independent. |
96 | </para></listitem> | 96 | </para></listitem> |
97 | <listitem><para> | 97 | <listitem><para> |
98 | [NAND Interface]</para><para> | 98 | [NAND Interface]</para><para> |
99 | These functions are exported and provide the interface to the NAND kernel API. | 99 | These functions are exported and provide the interface to the NAND kernel API. |
100 | </para></listitem> | 100 | </para></listitem> |
101 | <listitem><para> | 101 | <listitem><para> |
102 | [GENERIC]</para><para> | 102 | [GENERIC]</para><para> |
103 | Generic functions are not replacable and provide functionality | 103 | Generic functions are not replacable and provide functionality |
104 | which is complete hardware independent. | 104 | which is complete hardware independent. |
105 | </para></listitem> | 105 | </para></listitem> |
106 | <listitem><para> | 106 | <listitem><para> |
107 | [DEFAULT]</para><para> | 107 | [DEFAULT]</para><para> |
108 | Default functions provide hardware related functionality which is suitable | 108 | Default functions provide hardware related functionality which is suitable |
109 | for most of the implementations. These functions can be replaced by the | 109 | for most of the implementations. These functions can be replaced by the |
110 | board driver if neccecary. Those functions are called via pointers in the | 110 | board driver if neccecary. Those functions are called via pointers in the |
111 | NAND chip description structure. The board driver can set the functions which | 111 | NAND chip description structure. The board driver can set the functions which |
112 | should be replaced by board dependent functions before calling nand_scan(). | 112 | should be replaced by board dependent functions before calling nand_scan(). |
113 | If the function pointer is NULL on entry to nand_scan() then the pointer | 113 | If the function pointer is NULL on entry to nand_scan() then the pointer |
114 | is set to the default function which is suitable for the detected chip type. | 114 | is set to the default function which is suitable for the detected chip type. |
115 | </para></listitem> | 115 | </para></listitem> |
116 | </itemizedlist> | 116 | </itemizedlist> |
117 | </sect1> | 117 | </sect1> |
118 | <sect1 id="Struct_member_identifiers_XXX"> | 118 | <sect1 id="Struct_member_identifiers_XXX"> |
119 | <title>Struct member identifiers [XXX]</title> | 119 | <title>Struct member identifiers [XXX]</title> |
120 | <para> | 120 | <para> |
121 | The struct members are marked with [XXX] identifiers in the | 121 | The struct members are marked with [XXX] identifiers in the |
122 | comment. The identifiers explain the usage and scope of the | 122 | comment. The identifiers explain the usage and scope of the |
123 | members. Following identifiers are used: | 123 | members. Following identifiers are used: |
124 | </para> | 124 | </para> |
125 | <itemizedlist> | 125 | <itemizedlist> |
126 | <listitem><para> | 126 | <listitem><para> |
127 | [INTERN]</para><para> | 127 | [INTERN]</para><para> |
128 | These members are for NAND driver internal use only and must not be | 128 | These members are for NAND driver internal use only and must not be |
129 | modified. Most of these values are calculated from the chip geometry | 129 | modified. Most of these values are calculated from the chip geometry |
130 | information which is evaluated during nand_scan(). | 130 | information which is evaluated during nand_scan(). |
131 | </para></listitem> | 131 | </para></listitem> |
132 | <listitem><para> | 132 | <listitem><para> |
133 | [REPLACEABLE]</para><para> | 133 | [REPLACEABLE]</para><para> |
134 | Replaceable members hold hardware related functions which can be | 134 | Replaceable members hold hardware related functions which can be |
135 | provided by the board driver. The board driver can set the functions which | 135 | provided by the board driver. The board driver can set the functions which |
136 | should be replaced by board dependent functions before calling nand_scan(). | 136 | should be replaced by board dependent functions before calling nand_scan(). |
137 | If the function pointer is NULL on entry to nand_scan() then the pointer | 137 | If the function pointer is NULL on entry to nand_scan() then the pointer |
138 | is set to the default function which is suitable for the detected chip type. | 138 | is set to the default function which is suitable for the detected chip type. |
139 | </para></listitem> | 139 | </para></listitem> |
140 | <listitem><para> | 140 | <listitem><para> |
141 | [BOARDSPECIFIC]</para><para> | 141 | [BOARDSPECIFIC]</para><para> |
142 | Board specific members hold hardware related information which must | 142 | Board specific members hold hardware related information which must |
143 | be provided by the board driver. The board driver must set the function | 143 | be provided by the board driver. The board driver must set the function |
144 | pointers and datafields before calling nand_scan(). | 144 | pointers and datafields before calling nand_scan(). |
145 | </para></listitem> | 145 | </para></listitem> |
146 | <listitem><para> | 146 | <listitem><para> |
147 | [OPTIONAL]</para><para> | 147 | [OPTIONAL]</para><para> |
148 | Optional members can hold information relevant for the board driver. The | 148 | Optional members can hold information relevant for the board driver. The |
149 | generic NAND driver code does not use this information. | 149 | generic NAND driver code does not use this information. |
150 | </para></listitem> | 150 | </para></listitem> |
151 | </itemizedlist> | 151 | </itemizedlist> |
152 | </sect1> | 152 | </sect1> |
153 | </chapter> | 153 | </chapter> |
154 | 154 | ||
155 | <chapter id="basicboarddriver"> | 155 | <chapter id="basicboarddriver"> |
156 | <title>Basic board driver</title> | 156 | <title>Basic board driver</title> |
157 | <para> | 157 | <para> |
158 | For most boards it will be sufficient to provide just the | 158 | For most boards it will be sufficient to provide just the |
159 | basic functions and fill out some really board dependent | 159 | basic functions and fill out some really board dependent |
160 | members in the nand chip description structure. | 160 | members in the nand chip description structure. |
161 | </para> | 161 | </para> |
162 | <sect1 id="Basic_defines"> | 162 | <sect1 id="Basic_defines"> |
163 | <title>Basic defines</title> | 163 | <title>Basic defines</title> |
164 | <para> | 164 | <para> |
165 | At least you have to provide a mtd structure and | 165 | At least you have to provide a mtd structure and |
166 | a storage for the ioremap'ed chip address. | 166 | a storage for the ioremap'ed chip address. |
167 | You can allocate the mtd structure using kmalloc | 167 | You can allocate the mtd structure using kmalloc |
168 | or you can allocate it statically. | 168 | or you can allocate it statically. |
169 | In case of static allocation you have to allocate | 169 | In case of static allocation you have to allocate |
170 | a nand_chip structure too. | 170 | a nand_chip structure too. |
171 | </para> | 171 | </para> |
172 | <para> | 172 | <para> |
173 | Kmalloc based example | 173 | Kmalloc based example |
174 | </para> | 174 | </para> |
175 | <programlisting> | 175 | <programlisting> |
176 | static struct mtd_info *board_mtd; | 176 | static struct mtd_info *board_mtd; |
177 | static unsigned long baseaddr; | 177 | static unsigned long baseaddr; |
178 | </programlisting> | 178 | </programlisting> |
179 | <para> | 179 | <para> |
180 | Static example | 180 | Static example |
181 | </para> | 181 | </para> |
182 | <programlisting> | 182 | <programlisting> |
183 | static struct mtd_info board_mtd; | 183 | static struct mtd_info board_mtd; |
184 | static struct nand_chip board_chip; | 184 | static struct nand_chip board_chip; |
185 | static unsigned long baseaddr; | 185 | static unsigned long baseaddr; |
186 | </programlisting> | 186 | </programlisting> |
187 | </sect1> | 187 | </sect1> |
188 | <sect1 id="Partition_defines"> | 188 | <sect1 id="Partition_defines"> |
189 | <title>Partition defines</title> | 189 | <title>Partition defines</title> |
190 | <para> | 190 | <para> |
191 | If you want to divide your device into partitions, then | 191 | If you want to divide your device into partitions, then |
192 | enable the configuration switch CONFIG_MTD_PARTITIONS and define | 192 | enable the configuration switch CONFIG_MTD_PARTITIONS and define |
193 | a partitioning scheme suitable to your board. | 193 | a partitioning scheme suitable to your board. |
194 | </para> | 194 | </para> |
195 | <programlisting> | 195 | <programlisting> |
196 | #define NUM_PARTITIONS 2 | 196 | #define NUM_PARTITIONS 2 |
197 | static struct mtd_partition partition_info[] = { | 197 | static struct mtd_partition partition_info[] = { |
198 | { .name = "Flash partition 1", | 198 | { .name = "Flash partition 1", |
199 | .offset = 0, | 199 | .offset = 0, |
200 | .size = 8 * 1024 * 1024 }, | 200 | .size = 8 * 1024 * 1024 }, |
201 | { .name = "Flash partition 2", | 201 | { .name = "Flash partition 2", |
202 | .offset = MTDPART_OFS_NEXT, | 202 | .offset = MTDPART_OFS_NEXT, |
203 | .size = MTDPART_SIZ_FULL }, | 203 | .size = MTDPART_SIZ_FULL }, |
204 | }; | 204 | }; |
205 | </programlisting> | 205 | </programlisting> |
206 | </sect1> | 206 | </sect1> |
207 | <sect1 id="Hardware_control_functions"> | 207 | <sect1 id="Hardware_control_functions"> |
208 | <title>Hardware control function</title> | 208 | <title>Hardware control function</title> |
209 | <para> | 209 | <para> |
210 | The hardware control function provides access to the | 210 | The hardware control function provides access to the |
211 | control pins of the NAND chip(s). | 211 | control pins of the NAND chip(s). |
212 | The access can be done by GPIO pins or by address lines. | 212 | The access can be done by GPIO pins or by address lines. |
213 | If you use address lines, make sure that the timing | 213 | If you use address lines, make sure that the timing |
214 | requirements are met. | 214 | requirements are met. |
215 | </para> | 215 | </para> |
216 | <para> | 216 | <para> |
217 | <emphasis>GPIO based example</emphasis> | 217 | <emphasis>GPIO based example</emphasis> |
218 | </para> | 218 | </para> |
219 | <programlisting> | 219 | <programlisting> |
220 | static void board_hwcontrol(struct mtd_info *mtd, int cmd) | 220 | static void board_hwcontrol(struct mtd_info *mtd, int cmd) |
221 | { | 221 | { |
222 | switch(cmd){ | 222 | switch(cmd){ |
223 | case NAND_CTL_SETCLE: /* Set CLE pin high */ break; | 223 | case NAND_CTL_SETCLE: /* Set CLE pin high */ break; |
224 | case NAND_CTL_CLRCLE: /* Set CLE pin low */ break; | 224 | case NAND_CTL_CLRCLE: /* Set CLE pin low */ break; |
225 | case NAND_CTL_SETALE: /* Set ALE pin high */ break; | 225 | case NAND_CTL_SETALE: /* Set ALE pin high */ break; |
226 | case NAND_CTL_CLRALE: /* Set ALE pin low */ break; | 226 | case NAND_CTL_CLRALE: /* Set ALE pin low */ break; |
227 | case NAND_CTL_SETNCE: /* Set nCE pin low */ break; | 227 | case NAND_CTL_SETNCE: /* Set nCE pin low */ break; |
228 | case NAND_CTL_CLRNCE: /* Set nCE pin high */ break; | 228 | case NAND_CTL_CLRNCE: /* Set nCE pin high */ break; |
229 | } | 229 | } |
230 | } | 230 | } |
231 | </programlisting> | 231 | </programlisting> |
232 | <para> | 232 | <para> |
233 | <emphasis>Address lines based example.</emphasis> It's assumed that the | 233 | <emphasis>Address lines based example.</emphasis> It's assumed that the |
234 | nCE pin is driven by a chip select decoder. | 234 | nCE pin is driven by a chip select decoder. |
235 | </para> | 235 | </para> |
236 | <programlisting> | 236 | <programlisting> |
237 | static void board_hwcontrol(struct mtd_info *mtd, int cmd) | 237 | static void board_hwcontrol(struct mtd_info *mtd, int cmd) |
238 | { | 238 | { |
239 | struct nand_chip *this = (struct nand_chip *) mtd->priv; | 239 | struct nand_chip *this = (struct nand_chip *) mtd->priv; |
240 | switch(cmd){ | 240 | switch(cmd){ |
241 | case NAND_CTL_SETCLE: this->IO_ADDR_W |= CLE_ADRR_BIT; break; | 241 | case NAND_CTL_SETCLE: this->IO_ADDR_W |= CLE_ADRR_BIT; break; |
242 | case NAND_CTL_CLRCLE: this->IO_ADDR_W &= ~CLE_ADRR_BIT; break; | 242 | case NAND_CTL_CLRCLE: this->IO_ADDR_W &= ~CLE_ADRR_BIT; break; |
243 | case NAND_CTL_SETALE: this->IO_ADDR_W |= ALE_ADRR_BIT; break; | 243 | case NAND_CTL_SETALE: this->IO_ADDR_W |= ALE_ADRR_BIT; break; |
244 | case NAND_CTL_CLRALE: this->IO_ADDR_W &= ~ALE_ADRR_BIT; break; | 244 | case NAND_CTL_CLRALE: this->IO_ADDR_W &= ~ALE_ADRR_BIT; break; |
245 | } | 245 | } |
246 | } | 246 | } |
247 | </programlisting> | 247 | </programlisting> |
248 | </sect1> | 248 | </sect1> |
249 | <sect1 id="Device_ready_function"> | 249 | <sect1 id="Device_ready_function"> |
250 | <title>Device ready function</title> | 250 | <title>Device ready function</title> |
251 | <para> | 251 | <para> |
252 | If the hardware interface has the ready busy pin of the NAND chip connected to a | 252 | If the hardware interface has the ready busy pin of the NAND chip connected to a |
253 | GPIO or other accesible I/O pin, this function is used to read back the state of the | 253 | GPIO or other accesible I/O pin, this function is used to read back the state of the |
254 | pin. The function has no arguments and should return 0, if the device is busy (R/B pin | 254 | pin. The function has no arguments and should return 0, if the device is busy (R/B pin |
255 | is low) and 1, if the device is ready (R/B pin is high). | 255 | is low) and 1, if the device is ready (R/B pin is high). |
256 | If the hardware interface does not give access to the ready busy pin, then | 256 | If the hardware interface does not give access to the ready busy pin, then |
257 | the function must not be defined and the function pointer this->dev_ready is set to NULL. | 257 | the function must not be defined and the function pointer this->dev_ready is set to NULL. |
258 | </para> | 258 | </para> |
259 | </sect1> | 259 | </sect1> |
260 | <sect1 id="Init_function"> | 260 | <sect1 id="Init_function"> |
261 | <title>Init function</title> | 261 | <title>Init function</title> |
262 | <para> | 262 | <para> |
263 | The init function allocates memory and sets up all the board | 263 | The init function allocates memory and sets up all the board |
264 | specific parameters and function pointers. When everything | 264 | specific parameters and function pointers. When everything |
265 | is set up nand_scan() is called. This function tries to | 265 | is set up nand_scan() is called. This function tries to |
266 | detect and identify then chip. If a chip is found all the | 266 | detect and identify then chip. If a chip is found all the |
267 | internal data fields are initialized accordingly. | 267 | internal data fields are initialized accordingly. |
268 | The structure(s) have to be zeroed out first and then filled with the neccecary | 268 | The structure(s) have to be zeroed out first and then filled with the neccecary |
269 | information about the device. | 269 | information about the device. |
270 | </para> | 270 | </para> |
271 | <programlisting> | 271 | <programlisting> |
272 | int __init board_init (void) | 272 | int __init board_init (void) |
273 | { | 273 | { |
274 | struct nand_chip *this; | 274 | struct nand_chip *this; |
275 | int err = 0; | 275 | int err = 0; |
276 | 276 | ||
277 | /* Allocate memory for MTD device structure and private data */ | 277 | /* Allocate memory for MTD device structure and private data */ |
278 | board_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); | 278 | board_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); |
279 | if (!board_mtd) { | 279 | if (!board_mtd) { |
280 | printk ("Unable to allocate NAND MTD device structure.\n"); | 280 | printk ("Unable to allocate NAND MTD device structure.\n"); |
281 | err = -ENOMEM; | 281 | err = -ENOMEM; |
282 | goto out; | 282 | goto out; |
283 | } | 283 | } |
284 | 284 | ||
285 | /* map physical address */ | 285 | /* map physical address */ |
286 | baseaddr = (unsigned long)ioremap(CHIP_PHYSICAL_ADDRESS, 1024); | 286 | baseaddr = (unsigned long)ioremap(CHIP_PHYSICAL_ADDRESS, 1024); |
287 | if(!baseaddr){ | 287 | if(!baseaddr){ |
288 | printk("Ioremap to access NAND chip failed\n"); | 288 | printk("Ioremap to access NAND chip failed\n"); |
289 | err = -EIO; | 289 | err = -EIO; |
290 | goto out_mtd; | 290 | goto out_mtd; |
291 | } | 291 | } |
292 | 292 | ||
293 | /* Get pointer to private data */ | 293 | /* Get pointer to private data */ |
294 | this = (struct nand_chip *) (); | 294 | this = (struct nand_chip *) (); |
295 | /* Link the private data with the MTD structure */ | 295 | /* Link the private data with the MTD structure */ |
296 | board_mtd->priv = this; | 296 | board_mtd->priv = this; |
297 | 297 | ||
298 | /* Set address of NAND IO lines */ | 298 | /* Set address of NAND IO lines */ |
299 | this->IO_ADDR_R = baseaddr; | 299 | this->IO_ADDR_R = baseaddr; |
300 | this->IO_ADDR_W = baseaddr; | 300 | this->IO_ADDR_W = baseaddr; |
301 | /* Reference hardware control function */ | 301 | /* Reference hardware control function */ |
302 | this->hwcontrol = board_hwcontrol; | 302 | this->hwcontrol = board_hwcontrol; |
303 | /* Set command delay time, see datasheet for correct value */ | 303 | /* Set command delay time, see datasheet for correct value */ |
304 | this->chip_delay = CHIP_DEPENDEND_COMMAND_DELAY; | 304 | this->chip_delay = CHIP_DEPENDEND_COMMAND_DELAY; |
305 | /* Assign the device ready function, if available */ | 305 | /* Assign the device ready function, if available */ |
306 | this->dev_ready = board_dev_ready; | 306 | this->dev_ready = board_dev_ready; |
307 | this->eccmode = NAND_ECC_SOFT; | 307 | this->eccmode = NAND_ECC_SOFT; |
308 | 308 | ||
309 | /* Scan to find existence of the device */ | 309 | /* Scan to find existence of the device */ |
310 | if (nand_scan (board_mtd, 1)) { | 310 | if (nand_scan (board_mtd, 1)) { |
311 | err = -ENXIO; | 311 | err = -ENXIO; |
312 | goto out_ior; | 312 | goto out_ior; |
313 | } | 313 | } |
314 | 314 | ||
315 | add_mtd_partitions(board_mtd, partition_info, NUM_PARTITIONS); | 315 | add_mtd_partitions(board_mtd, partition_info, NUM_PARTITIONS); |
316 | goto out; | 316 | goto out; |
317 | 317 | ||
318 | out_ior: | 318 | out_ior: |
319 | iounmap((void *)baseaddr); | 319 | iounmap((void *)baseaddr); |
320 | out_mtd: | 320 | out_mtd: |
321 | kfree (board_mtd); | 321 | kfree (board_mtd); |
322 | out: | 322 | out: |
323 | return err; | 323 | return err; |
324 | } | 324 | } |
325 | module_init(board_init); | 325 | module_init(board_init); |
326 | </programlisting> | 326 | </programlisting> |
327 | </sect1> | 327 | </sect1> |
328 | <sect1 id="Exit_function"> | 328 | <sect1 id="Exit_function"> |
329 | <title>Exit function</title> | 329 | <title>Exit function</title> |
330 | <para> | 330 | <para> |
331 | The exit function is only neccecary if the driver is | 331 | The exit function is only neccecary if the driver is |
332 | compiled as a module. It releases all resources which | 332 | compiled as a module. It releases all resources which |
333 | are held by the chip driver and unregisters the partitions | 333 | are held by the chip driver and unregisters the partitions |
334 | in the MTD layer. | 334 | in the MTD layer. |
335 | </para> | 335 | </para> |
336 | <programlisting> | 336 | <programlisting> |
337 | #ifdef MODULE | 337 | #ifdef MODULE |
338 | static void __exit board_cleanup (void) | 338 | static void __exit board_cleanup (void) |
339 | { | 339 | { |
340 | /* Release resources, unregister device */ | 340 | /* Release resources, unregister device */ |
341 | nand_release (board_mtd); | 341 | nand_release (board_mtd); |
342 | 342 | ||
343 | /* unmap physical address */ | 343 | /* unmap physical address */ |
344 | iounmap((void *)baseaddr); | 344 | iounmap((void *)baseaddr); |
345 | 345 | ||
346 | /* Free the MTD device structure */ | 346 | /* Free the MTD device structure */ |
347 | kfree (board_mtd); | 347 | kfree (board_mtd); |
348 | } | 348 | } |
349 | module_exit(board_cleanup); | 349 | module_exit(board_cleanup); |
350 | #endif | 350 | #endif |
351 | </programlisting> | 351 | </programlisting> |
352 | </sect1> | 352 | </sect1> |
353 | </chapter> | 353 | </chapter> |
354 | 354 | ||
355 | <chapter id="boarddriversadvanced"> | 355 | <chapter id="boarddriversadvanced"> |
356 | <title>Advanced board driver functions</title> | 356 | <title>Advanced board driver functions</title> |
357 | <para> | 357 | <para> |
358 | This chapter describes the advanced functionality of the NAND | 358 | This chapter describes the advanced functionality of the NAND |
359 | driver. For a list of functions which can be overridden by the board | 359 | driver. For a list of functions which can be overridden by the board |
360 | driver see the documentation of the nand_chip structure. | 360 | driver see the documentation of the nand_chip structure. |
361 | </para> | 361 | </para> |
362 | <sect1 id="Multiple_chip_control"> | 362 | <sect1 id="Multiple_chip_control"> |
363 | <title>Multiple chip control</title> | 363 | <title>Multiple chip control</title> |
364 | <para> | 364 | <para> |
365 | The nand driver can control chip arrays. Therefor the | 365 | The nand driver can control chip arrays. Therefor the |
366 | board driver must provide an own select_chip function. This | 366 | board driver must provide an own select_chip function. This |
367 | function must (de)select the requested chip. | 367 | function must (de)select the requested chip. |
368 | The function pointer in the nand_chip structure must | 368 | The function pointer in the nand_chip structure must |
369 | be set before calling nand_scan(). The maxchip parameter | 369 | be set before calling nand_scan(). The maxchip parameter |
370 | of nand_scan() defines the maximum number of chips to | 370 | of nand_scan() defines the maximum number of chips to |
371 | scan for. Make sure that the select_chip function can | 371 | scan for. Make sure that the select_chip function can |
372 | handle the requested number of chips. | 372 | handle the requested number of chips. |
373 | </para> | 373 | </para> |
374 | <para> | 374 | <para> |
375 | The nand driver concatenates the chips to one virtual | 375 | The nand driver concatenates the chips to one virtual |
376 | chip and provides this virtual chip to the MTD layer. | 376 | chip and provides this virtual chip to the MTD layer. |
377 | </para> | 377 | </para> |
378 | <para> | 378 | <para> |
379 | <emphasis>Note: The driver can only handle linear chip arrays | 379 | <emphasis>Note: The driver can only handle linear chip arrays |
380 | of equally sized chips. There is no support for | 380 | of equally sized chips. There is no support for |
381 | parallel arrays which extend the buswidth.</emphasis> | 381 | parallel arrays which extend the buswidth.</emphasis> |
382 | </para> | 382 | </para> |
383 | <para> | 383 | <para> |
384 | <emphasis>GPIO based example</emphasis> | 384 | <emphasis>GPIO based example</emphasis> |
385 | </para> | 385 | </para> |
386 | <programlisting> | 386 | <programlisting> |
387 | static void board_select_chip (struct mtd_info *mtd, int chip) | 387 | static void board_select_chip (struct mtd_info *mtd, int chip) |
388 | { | 388 | { |
389 | /* Deselect all chips, set all nCE pins high */ | 389 | /* Deselect all chips, set all nCE pins high */ |
390 | GPIO(BOARD_NAND_NCE) |= 0xff; | 390 | GPIO(BOARD_NAND_NCE) |= 0xff; |
391 | if (chip >= 0) | 391 | if (chip >= 0) |
392 | GPIO(BOARD_NAND_NCE) &= ~ (1 << chip); | 392 | GPIO(BOARD_NAND_NCE) &= ~ (1 << chip); |
393 | } | 393 | } |
394 | </programlisting> | 394 | </programlisting> |
395 | <para> | 395 | <para> |
396 | <emphasis>Address lines based example.</emphasis> | 396 | <emphasis>Address lines based example.</emphasis> |
397 | Its assumed that the nCE pins are connected to an | 397 | Its assumed that the nCE pins are connected to an |
398 | address decoder. | 398 | address decoder. |
399 | </para> | 399 | </para> |
400 | <programlisting> | 400 | <programlisting> |
401 | static void board_select_chip (struct mtd_info *mtd, int chip) | 401 | static void board_select_chip (struct mtd_info *mtd, int chip) |
402 | { | 402 | { |
403 | struct nand_chip *this = (struct nand_chip *) mtd->priv; | 403 | struct nand_chip *this = (struct nand_chip *) mtd->priv; |
404 | 404 | ||
405 | /* Deselect all chips */ | 405 | /* Deselect all chips */ |
406 | this->IO_ADDR_R &= ~BOARD_NAND_ADDR_MASK; | 406 | this->IO_ADDR_R &= ~BOARD_NAND_ADDR_MASK; |
407 | this->IO_ADDR_W &= ~BOARD_NAND_ADDR_MASK; | 407 | this->IO_ADDR_W &= ~BOARD_NAND_ADDR_MASK; |
408 | switch (chip) { | 408 | switch (chip) { |
409 | case 0: | 409 | case 0: |
410 | this->IO_ADDR_R |= BOARD_NAND_ADDR_CHIP0; | 410 | this->IO_ADDR_R |= BOARD_NAND_ADDR_CHIP0; |
411 | this->IO_ADDR_W |= BOARD_NAND_ADDR_CHIP0; | 411 | this->IO_ADDR_W |= BOARD_NAND_ADDR_CHIP0; |
412 | break; | 412 | break; |
413 | .... | 413 | .... |
414 | case n: | 414 | case n: |
415 | this->IO_ADDR_R |= BOARD_NAND_ADDR_CHIPn; | 415 | this->IO_ADDR_R |= BOARD_NAND_ADDR_CHIPn; |
416 | this->IO_ADDR_W |= BOARD_NAND_ADDR_CHIPn; | 416 | this->IO_ADDR_W |= BOARD_NAND_ADDR_CHIPn; |
417 | break; | 417 | break; |
418 | } | 418 | } |
419 | } | 419 | } |
420 | </programlisting> | 420 | </programlisting> |
421 | </sect1> | 421 | </sect1> |
422 | <sect1 id="Hardware_ECC_support"> | 422 | <sect1 id="Hardware_ECC_support"> |
423 | <title>Hardware ECC support</title> | 423 | <title>Hardware ECC support</title> |
424 | <sect2 id="Functions_and_constants"> | 424 | <sect2 id="Functions_and_constants"> |
425 | <title>Functions and constants</title> | 425 | <title>Functions and constants</title> |
426 | <para> | 426 | <para> |
427 | The nand driver supports three different types of | 427 | The nand driver supports three different types of |
428 | hardware ECC. | 428 | hardware ECC. |
429 | <itemizedlist> | 429 | <itemizedlist> |
430 | <listitem><para>NAND_ECC_HW3_256</para><para> | 430 | <listitem><para>NAND_ECC_HW3_256</para><para> |
431 | Hardware ECC generator providing 3 bytes ECC per | 431 | Hardware ECC generator providing 3 bytes ECC per |
432 | 256 byte. | 432 | 256 byte. |
433 | </para> </listitem> | 433 | </para> </listitem> |
434 | <listitem><para>NAND_ECC_HW3_512</para><para> | 434 | <listitem><para>NAND_ECC_HW3_512</para><para> |
435 | Hardware ECC generator providing 3 bytes ECC per | 435 | Hardware ECC generator providing 3 bytes ECC per |
436 | 512 byte. | 436 | 512 byte. |
437 | </para> </listitem> | 437 | </para> </listitem> |
438 | <listitem><para>NAND_ECC_HW6_512</para><para> | 438 | <listitem><para>NAND_ECC_HW6_512</para><para> |
439 | Hardware ECC generator providing 6 bytes ECC per | 439 | Hardware ECC generator providing 6 bytes ECC per |
440 | 512 byte. | 440 | 512 byte. |
441 | </para> </listitem> | 441 | </para> </listitem> |
442 | <listitem><para>NAND_ECC_HW8_512</para><para> | 442 | <listitem><para>NAND_ECC_HW8_512</para><para> |
443 | Hardware ECC generator providing 6 bytes ECC per | 443 | Hardware ECC generator providing 6 bytes ECC per |
444 | 512 byte. | 444 | 512 byte. |
445 | </para> </listitem> | 445 | </para> </listitem> |
446 | </itemizedlist> | 446 | </itemizedlist> |
447 | If your hardware generator has a different functionality | 447 | If your hardware generator has a different functionality |
448 | add it at the appropriate place in nand_base.c | 448 | add it at the appropriate place in nand_base.c |
449 | </para> | 449 | </para> |
450 | <para> | 450 | <para> |
451 | The board driver must provide following functions: | 451 | The board driver must provide following functions: |
452 | <itemizedlist> | 452 | <itemizedlist> |
453 | <listitem><para>enable_hwecc</para><para> | 453 | <listitem><para>enable_hwecc</para><para> |
454 | This function is called before reading / writing to | 454 | This function is called before reading / writing to |
455 | the chip. Reset or initialize the hardware generator | 455 | the chip. Reset or initialize the hardware generator |
456 | in this function. The function is called with an | 456 | in this function. The function is called with an |
457 | argument which let you distinguish between read | 457 | argument which let you distinguish between read |
458 | and write operations. | 458 | and write operations. |
459 | </para> </listitem> | 459 | </para> </listitem> |
460 | <listitem><para>calculate_ecc</para><para> | 460 | <listitem><para>calculate_ecc</para><para> |
461 | This function is called after read / write from / to | 461 | This function is called after read / write from / to |
462 | the chip. Transfer the ECC from the hardware to | 462 | the chip. Transfer the ECC from the hardware to |
463 | the buffer. If the option NAND_HWECC_SYNDROME is set | 463 | the buffer. If the option NAND_HWECC_SYNDROME is set |
464 | then the function is only called on write. See below. | 464 | then the function is only called on write. See below. |
465 | </para> </listitem> | 465 | </para> </listitem> |
466 | <listitem><para>correct_data</para><para> | 466 | <listitem><para>correct_data</para><para> |
467 | In case of an ECC error this function is called for | 467 | In case of an ECC error this function is called for |
468 | error detection and correction. Return 1 respectively 2 | 468 | error detection and correction. Return 1 respectively 2 |
469 | in case the error can be corrected. If the error is | 469 | in case the error can be corrected. If the error is |
470 | not correctable return -1. If your hardware generator | 470 | not correctable return -1. If your hardware generator |
471 | matches the default algorithm of the nand_ecc software | 471 | matches the default algorithm of the nand_ecc software |
472 | generator then use the correction function provided | 472 | generator then use the correction function provided |
473 | by nand_ecc instead of implementing duplicated code. | 473 | by nand_ecc instead of implementing duplicated code. |
474 | </para> </listitem> | 474 | </para> </listitem> |
475 | </itemizedlist> | 475 | </itemizedlist> |
476 | </para> | 476 | </para> |
477 | </sect2> | 477 | </sect2> |
478 | <sect2 id="Hardware_ECC_with_syndrome_calculation"> | 478 | <sect2 id="Hardware_ECC_with_syndrome_calculation"> |
479 | <title>Hardware ECC with syndrome calculation</title> | 479 | <title>Hardware ECC with syndrome calculation</title> |
480 | <para> | 480 | <para> |
481 | Many hardware ECC implementations provide Reed-Solomon | 481 | Many hardware ECC implementations provide Reed-Solomon |
482 | codes and calculate an error syndrome on read. The syndrome | 482 | codes and calculate an error syndrome on read. The syndrome |
483 | must be converted to a standard Reed-Solomon syndrome | 483 | must be converted to a standard Reed-Solomon syndrome |
484 | before calling the error correction code in the generic | 484 | before calling the error correction code in the generic |
485 | Reed-Solomon library. | 485 | Reed-Solomon library. |
486 | </para> | 486 | </para> |
487 | <para> | 487 | <para> |
488 | The ECC bytes must be placed immidiately after the data | 488 | The ECC bytes must be placed immidiately after the data |
489 | bytes in order to make the syndrome generator work. This | 489 | bytes in order to make the syndrome generator work. This |
490 | is contrary to the usual layout used by software ECC. The | 490 | is contrary to the usual layout used by software ECC. The |
491 | seperation of data and out of band area is not longer | 491 | seperation of data and out of band area is not longer |
492 | possible. The nand driver code handles this layout and | 492 | possible. The nand driver code handles this layout and |
493 | the remaining free bytes in the oob area are managed by | 493 | the remaining free bytes in the oob area are managed by |
494 | the autoplacement code. Provide a matching oob-layout | 494 | the autoplacement code. Provide a matching oob-layout |
495 | in this case. See rts_from4.c and diskonchip.c for | 495 | in this case. See rts_from4.c and diskonchip.c for |
496 | implementation reference. In those cases we must also | 496 | implementation reference. In those cases we must also |
497 | use bad block tables on FLASH, because the ECC layout is | 497 | use bad block tables on FLASH, because the ECC layout is |
498 | interferring with the bad block marker positions. | 498 | interferring with the bad block marker positions. |
499 | See bad block table support for details. | 499 | See bad block table support for details. |
500 | </para> | 500 | </para> |
501 | </sect2> | 501 | </sect2> |
502 | </sect1> | 502 | </sect1> |
503 | <sect1 id="Bad_Block_table_support"> | 503 | <sect1 id="Bad_Block_table_support"> |
504 | <title>Bad block table support</title> | 504 | <title>Bad block table support</title> |
505 | <para> | 505 | <para> |
506 | Most NAND chips mark the bad blocks at a defined | 506 | Most NAND chips mark the bad blocks at a defined |
507 | position in the spare area. Those blocks must | 507 | position in the spare area. Those blocks must |
508 | not be erased under any circumstances as the bad | 508 | not be erased under any circumstances as the bad |
509 | block information would be lost. | 509 | block information would be lost. |
510 | It is possible to check the bad block mark each | 510 | It is possible to check the bad block mark each |
511 | time when the blocks are accessed by reading the | 511 | time when the blocks are accessed by reading the |
512 | spare area of the first page in the block. This | 512 | spare area of the first page in the block. This |
513 | is time consuming so a bad block table is used. | 513 | is time consuming so a bad block table is used. |
514 | </para> | 514 | </para> |
515 | <para> | 515 | <para> |
516 | The nand driver supports various types of bad block | 516 | The nand driver supports various types of bad block |
517 | tables. | 517 | tables. |
518 | <itemizedlist> | 518 | <itemizedlist> |
519 | <listitem><para>Per device</para><para> | 519 | <listitem><para>Per device</para><para> |
520 | The bad block table contains all bad block information | 520 | The bad block table contains all bad block information |
521 | of the device which can consist of multiple chips. | 521 | of the device which can consist of multiple chips. |
522 | </para> </listitem> | 522 | </para> </listitem> |
523 | <listitem><para>Per chip</para><para> | 523 | <listitem><para>Per chip</para><para> |
524 | A bad block table is used per chip and contains the | 524 | A bad block table is used per chip and contains the |
525 | bad block information for this particular chip. | 525 | bad block information for this particular chip. |
526 | </para> </listitem> | 526 | </para> </listitem> |
527 | <listitem><para>Fixed offset</para><para> | 527 | <listitem><para>Fixed offset</para><para> |
528 | The bad block table is located at a fixed offset | 528 | The bad block table is located at a fixed offset |
529 | in the chip (device). This applies to various | 529 | in the chip (device). This applies to various |
530 | DiskOnChip devices. | 530 | DiskOnChip devices. |
531 | </para> </listitem> | 531 | </para> </listitem> |
532 | <listitem><para>Automatic placed</para><para> | 532 | <listitem><para>Automatic placed</para><para> |
533 | The bad block table is automatically placed and | 533 | The bad block table is automatically placed and |
534 | detected either at the end or at the beginning | 534 | detected either at the end or at the beginning |
535 | of a chip (device) | 535 | of a chip (device) |
536 | </para> </listitem> | 536 | </para> </listitem> |
537 | <listitem><para>Mirrored tables</para><para> | 537 | <listitem><para>Mirrored tables</para><para> |
538 | The bad block table is mirrored on the chip (device) to | 538 | The bad block table is mirrored on the chip (device) to |
539 | allow updates of the bad block table without data loss. | 539 | allow updates of the bad block table without data loss. |
540 | </para> </listitem> | 540 | </para> </listitem> |
541 | </itemizedlist> | 541 | </itemizedlist> |
542 | </para> | 542 | </para> |
543 | <para> | 543 | <para> |
544 | nand_scan() calls the function nand_default_bbt(). | 544 | nand_scan() calls the function nand_default_bbt(). |
545 | nand_default_bbt() selects appropriate default | 545 | nand_default_bbt() selects appropriate default |
546 | bad block table desriptors depending on the chip information | 546 | bad block table desriptors depending on the chip information |
547 | which was retrieved by nand_scan(). | 547 | which was retrieved by nand_scan(). |
548 | </para> | 548 | </para> |
549 | <para> | 549 | <para> |
550 | The standard policy is scanning the device for bad | 550 | The standard policy is scanning the device for bad |
551 | blocks and build a ram based bad block table which | 551 | blocks and build a ram based bad block table which |
552 | allows faster access than always checking the | 552 | allows faster access than always checking the |
553 | bad block information on the flash chip itself. | 553 | bad block information on the flash chip itself. |
554 | </para> | 554 | </para> |
555 | <sect2 id="Flash_based_tables"> | 555 | <sect2 id="Flash_based_tables"> |
556 | <title>Flash based tables</title> | 556 | <title>Flash based tables</title> |
557 | <para> | 557 | <para> |
558 | It may be desired or neccecary to keep a bad block table in FLASH. | 558 | It may be desired or neccecary to keep a bad block table in FLASH. |
559 | For AG-AND chips this is mandatory, as they have no factory marked | 559 | For AG-AND chips this is mandatory, as they have no factory marked |
560 | bad blocks. They have factory marked good blocks. The marker pattern | 560 | bad blocks. They have factory marked good blocks. The marker pattern |
561 | is erased when the block is erased to be reused. So in case of | 561 | is erased when the block is erased to be reused. So in case of |
562 | powerloss before writing the pattern back to the chip this block | 562 | powerloss before writing the pattern back to the chip this block |
563 | would be lost and added to the bad blocks. Therefor we scan the | 563 | would be lost and added to the bad blocks. Therefor we scan the |
564 | chip(s) when we detect them the first time for good blocks and | 564 | chip(s) when we detect them the first time for good blocks and |
565 | store this information in a bad block table before erasing any | 565 | store this information in a bad block table before erasing any |
566 | of the blocks. | 566 | of the blocks. |
567 | </para> | 567 | </para> |
568 | <para> | 568 | <para> |
569 | The blocks in which the tables are stored are procteted against | 569 | The blocks in which the tables are stored are procteted against |
570 | accidental access by marking them bad in the memory bad block | 570 | accidental access by marking them bad in the memory bad block |
571 | table. The bad block table managment functions are allowed | 571 | table. The bad block table management functions are allowed |
572 | to circumvernt this protection. | 572 | to circumvernt this protection. |
573 | </para> | 573 | </para> |
574 | <para> | 574 | <para> |
575 | The simplest way to activate the FLASH based bad block table support | 575 | The simplest way to activate the FLASH based bad block table support |
576 | is to set the option NAND_USE_FLASH_BBT in the option field of | 576 | is to set the option NAND_USE_FLASH_BBT in the option field of |
577 | the nand chip structure before calling nand_scan(). For AG-AND | 577 | the nand chip structure before calling nand_scan(). For AG-AND |
578 | chips is this done by default. | 578 | chips is this done by default. |
579 | This activates the default FLASH based bad block table functionality | 579 | This activates the default FLASH based bad block table functionality |
580 | of the NAND driver. The default bad block table options are | 580 | of the NAND driver. The default bad block table options are |
581 | <itemizedlist> | 581 | <itemizedlist> |
582 | <listitem><para>Store bad block table per chip</para></listitem> | 582 | <listitem><para>Store bad block table per chip</para></listitem> |
583 | <listitem><para>Use 2 bits per block</para></listitem> | 583 | <listitem><para>Use 2 bits per block</para></listitem> |
584 | <listitem><para>Automatic placement at the end of the chip</para></listitem> | 584 | <listitem><para>Automatic placement at the end of the chip</para></listitem> |
585 | <listitem><para>Use mirrored tables with version numbers</para></listitem> | 585 | <listitem><para>Use mirrored tables with version numbers</para></listitem> |
586 | <listitem><para>Reserve 4 blocks at the end of the chip</para></listitem> | 586 | <listitem><para>Reserve 4 blocks at the end of the chip</para></listitem> |
587 | </itemizedlist> | 587 | </itemizedlist> |
588 | </para> | 588 | </para> |
589 | </sect2> | 589 | </sect2> |
590 | <sect2 id="User_defined_tables"> | 590 | <sect2 id="User_defined_tables"> |
591 | <title>User defined tables</title> | 591 | <title>User defined tables</title> |
592 | <para> | 592 | <para> |
593 | User defined tables are created by filling out a | 593 | User defined tables are created by filling out a |
594 | nand_bbt_descr structure and storing the pointer in the | 594 | nand_bbt_descr structure and storing the pointer in the |
595 | nand_chip structure member bbt_td before calling nand_scan(). | 595 | nand_chip structure member bbt_td before calling nand_scan(). |
596 | If a mirror table is neccecary a second structure must be | 596 | If a mirror table is neccecary a second structure must be |
597 | created and a pointer to this structure must be stored | 597 | created and a pointer to this structure must be stored |
598 | in bbt_md inside the nand_chip structure. If the bbt_md | 598 | in bbt_md inside the nand_chip structure. If the bbt_md |
599 | member is set to NULL then only the main table is used | 599 | member is set to NULL then only the main table is used |
600 | and no scan for the mirrored table is performed. | 600 | and no scan for the mirrored table is performed. |
601 | </para> | 601 | </para> |
602 | <para> | 602 | <para> |
603 | The most important field in the nand_bbt_descr structure | 603 | The most important field in the nand_bbt_descr structure |
604 | is the options field. The options define most of the | 604 | is the options field. The options define most of the |
605 | table properties. Use the predefined constants from | 605 | table properties. Use the predefined constants from |
606 | nand.h to define the options. | 606 | nand.h to define the options. |
607 | <itemizedlist> | 607 | <itemizedlist> |
608 | <listitem><para>Number of bits per block</para> | 608 | <listitem><para>Number of bits per block</para> |
609 | <para>The supported number of bits is 1, 2, 4, 8.</para></listitem> | 609 | <para>The supported number of bits is 1, 2, 4, 8.</para></listitem> |
610 | <listitem><para>Table per chip</para> | 610 | <listitem><para>Table per chip</para> |
611 | <para>Setting the constant NAND_BBT_PERCHIP selects that | 611 | <para>Setting the constant NAND_BBT_PERCHIP selects that |
612 | a bad block table is managed for each chip in a chip array. | 612 | a bad block table is managed for each chip in a chip array. |
613 | If this option is not set then a per device bad block table | 613 | If this option is not set then a per device bad block table |
614 | is used.</para></listitem> | 614 | is used.</para></listitem> |
615 | <listitem><para>Table location is absolute</para> | 615 | <listitem><para>Table location is absolute</para> |
616 | <para>Use the option constant NAND_BBT_ABSPAGE and | 616 | <para>Use the option constant NAND_BBT_ABSPAGE and |
617 | define the absolute page number where the bad block | 617 | define the absolute page number where the bad block |
618 | table starts in the field pages. If you have selected bad block | 618 | table starts in the field pages. If you have selected bad block |
619 | tables per chip and you have a multi chip array then the start page | 619 | tables per chip and you have a multi chip array then the start page |
620 | must be given for each chip in the chip array. Note: there is no scan | 620 | must be given for each chip in the chip array. Note: there is no scan |
621 | for a table ident pattern performed, so the fields | 621 | for a table ident pattern performed, so the fields |
622 | pattern, veroffs, offs, len can be left uninitialized</para></listitem> | 622 | pattern, veroffs, offs, len can be left uninitialized</para></listitem> |
623 | <listitem><para>Table location is automatically detected</para> | 623 | <listitem><para>Table location is automatically detected</para> |
624 | <para>The table can either be located in the first or the last good | 624 | <para>The table can either be located in the first or the last good |
625 | blocks of the chip (device). Set NAND_BBT_LASTBLOCK to place | 625 | blocks of the chip (device). Set NAND_BBT_LASTBLOCK to place |
626 | the bad block table at the end of the chip (device). The | 626 | the bad block table at the end of the chip (device). The |
627 | bad block tables are marked and identified by a pattern which | 627 | bad block tables are marked and identified by a pattern which |
628 | is stored in the spare area of the first page in the block which | 628 | is stored in the spare area of the first page in the block which |
629 | holds the bad block table. Store a pointer to the pattern | 629 | holds the bad block table. Store a pointer to the pattern |
630 | in the pattern field. Further the length of the pattern has to be | 630 | in the pattern field. Further the length of the pattern has to be |
631 | stored in len and the offset in the spare area must be given | 631 | stored in len and the offset in the spare area must be given |
632 | in the offs member of the nand_bbt_descr stucture. For mirrored | 632 | in the offs member of the nand_bbt_descr stucture. For mirrored |
633 | bad block tables different patterns are mandatory.</para></listitem> | 633 | bad block tables different patterns are mandatory.</para></listitem> |
634 | <listitem><para>Table creation</para> | 634 | <listitem><para>Table creation</para> |
635 | <para>Set the option NAND_BBT_CREATE to enable the table creation | 635 | <para>Set the option NAND_BBT_CREATE to enable the table creation |
636 | if no table can be found during the scan. Usually this is done only | 636 | if no table can be found during the scan. Usually this is done only |
637 | once if a new chip is found. </para></listitem> | 637 | once if a new chip is found. </para></listitem> |
638 | <listitem><para>Table write support</para> | 638 | <listitem><para>Table write support</para> |
639 | <para>Set the option NAND_BBT_WRITE to enable the table write support. | 639 | <para>Set the option NAND_BBT_WRITE to enable the table write support. |
640 | This allows the update of the bad block table(s) in case a block has | 640 | This allows the update of the bad block table(s) in case a block has |
641 | to be marked bad due to wear. The MTD interface function block_markbad | 641 | to be marked bad due to wear. The MTD interface function block_markbad |
642 | is calling the update function of the bad block table. If the write | 642 | is calling the update function of the bad block table. If the write |
643 | support is enabled then the table is updated on FLASH.</para> | 643 | support is enabled then the table is updated on FLASH.</para> |
644 | <para> | 644 | <para> |
645 | Note: Write support should only be enabled for mirrored tables with | 645 | Note: Write support should only be enabled for mirrored tables with |
646 | version control. | 646 | version control. |
647 | </para></listitem> | 647 | </para></listitem> |
648 | <listitem><para>Table version control</para> | 648 | <listitem><para>Table version control</para> |
649 | <para>Set the option NAND_BBT_VERSION to enable the table version control. | 649 | <para>Set the option NAND_BBT_VERSION to enable the table version control. |
650 | It's highly recommended to enable this for mirrored tables with write | 650 | It's highly recommended to enable this for mirrored tables with write |
651 | support. It makes sure that the risk of loosing the bad block | 651 | support. It makes sure that the risk of loosing the bad block |
652 | table information is reduced to the loss of the information about the | 652 | table information is reduced to the loss of the information about the |
653 | one worn out block which should be marked bad. The version is stored in | 653 | one worn out block which should be marked bad. The version is stored in |
654 | 4 consecutive bytes in the spare area of the device. The position of | 654 | 4 consecutive bytes in the spare area of the device. The position of |
655 | the version number is defined by the member veroffs in the bad block table | 655 | the version number is defined by the member veroffs in the bad block table |
656 | descriptor.</para></listitem> | 656 | descriptor.</para></listitem> |
657 | <listitem><para>Save block contents on write</para> | 657 | <listitem><para>Save block contents on write</para> |
658 | <para> | 658 | <para> |
659 | In case that the block which holds the bad block table does contain | 659 | In case that the block which holds the bad block table does contain |
660 | other useful information, set the option NAND_BBT_SAVECONTENT. When | 660 | other useful information, set the option NAND_BBT_SAVECONTENT. When |
661 | the bad block table is written then the whole block is read the bad | 661 | the bad block table is written then the whole block is read the bad |
662 | block table is updated and the block is erased and everything is | 662 | block table is updated and the block is erased and everything is |
663 | written back. If this option is not set only the bad block table | 663 | written back. If this option is not set only the bad block table |
664 | is written and everything else in the block is ignored and erased. | 664 | is written and everything else in the block is ignored and erased. |
665 | </para></listitem> | 665 | </para></listitem> |
666 | <listitem><para>Number of reserved blocks</para> | 666 | <listitem><para>Number of reserved blocks</para> |
667 | <para> | 667 | <para> |
668 | For automatic placement some blocks must be reserved for | 668 | For automatic placement some blocks must be reserved for |
669 | bad block table storage. The number of reserved blocks is defined | 669 | bad block table storage. The number of reserved blocks is defined |
670 | in the maxblocks member of the babd block table description structure. | 670 | in the maxblocks member of the babd block table description structure. |
671 | Reserving 4 blocks for mirrored tables should be a reasonable number. | 671 | Reserving 4 blocks for mirrored tables should be a reasonable number. |
672 | This also limits the number of blocks which are scanned for the bad | 672 | This also limits the number of blocks which are scanned for the bad |
673 | block table ident pattern. | 673 | block table ident pattern. |
674 | </para></listitem> | 674 | </para></listitem> |
675 | </itemizedlist> | 675 | </itemizedlist> |
676 | </para> | 676 | </para> |
677 | </sect2> | 677 | </sect2> |
678 | </sect1> | 678 | </sect1> |
679 | <sect1 id="Spare_area_placement"> | 679 | <sect1 id="Spare_area_placement"> |
680 | <title>Spare area (auto)placement</title> | 680 | <title>Spare area (auto)placement</title> |
681 | <para> | 681 | <para> |
682 | The nand driver implements different possibilities for | 682 | The nand driver implements different possibilities for |
683 | placement of filesystem data in the spare area, | 683 | placement of filesystem data in the spare area, |
684 | <itemizedlist> | 684 | <itemizedlist> |
685 | <listitem><para>Placement defined by fs driver</para></listitem> | 685 | <listitem><para>Placement defined by fs driver</para></listitem> |
686 | <listitem><para>Automatic placement</para></listitem> | 686 | <listitem><para>Automatic placement</para></listitem> |
687 | </itemizedlist> | 687 | </itemizedlist> |
688 | The default placement function is automatic placement. The | 688 | The default placement function is automatic placement. The |
689 | nand driver has built in default placement schemes for the | 689 | nand driver has built in default placement schemes for the |
690 | various chiptypes. If due to hardware ECC functionality the | 690 | various chiptypes. If due to hardware ECC functionality the |
691 | default placement does not fit then the board driver can | 691 | default placement does not fit then the board driver can |
692 | provide a own placement scheme. | 692 | provide a own placement scheme. |
693 | </para> | 693 | </para> |
694 | <para> | 694 | <para> |
695 | File system drivers can provide a own placement scheme which | 695 | File system drivers can provide a own placement scheme which |
696 | is used instead of the default placement scheme. | 696 | is used instead of the default placement scheme. |
697 | </para> | 697 | </para> |
698 | <para> | 698 | <para> |
699 | Placement schemes are defined by a nand_oobinfo structure | 699 | Placement schemes are defined by a nand_oobinfo structure |
700 | <programlisting> | 700 | <programlisting> |
701 | struct nand_oobinfo { | 701 | struct nand_oobinfo { |
702 | int useecc; | 702 | int useecc; |
703 | int eccbytes; | 703 | int eccbytes; |
704 | int eccpos[24]; | 704 | int eccpos[24]; |
705 | int oobfree[8][2]; | 705 | int oobfree[8][2]; |
706 | }; | 706 | }; |
707 | </programlisting> | 707 | </programlisting> |
708 | <itemizedlist> | 708 | <itemizedlist> |
709 | <listitem><para>useecc</para><para> | 709 | <listitem><para>useecc</para><para> |
710 | The useecc member controls the ecc and placement function. The header | 710 | The useecc member controls the ecc and placement function. The header |
711 | file include/mtd/mtd-abi.h contains constants to select ecc and | 711 | file include/mtd/mtd-abi.h contains constants to select ecc and |
712 | placement. MTD_NANDECC_OFF switches off the ecc complete. This is | 712 | placement. MTD_NANDECC_OFF switches off the ecc complete. This is |
713 | not recommended and available for testing and diagnosis only. | 713 | not recommended and available for testing and diagnosis only. |
714 | MTD_NANDECC_PLACE selects caller defined placement, MTD_NANDECC_AUTOPLACE | 714 | MTD_NANDECC_PLACE selects caller defined placement, MTD_NANDECC_AUTOPLACE |
715 | selects automatic placement. | 715 | selects automatic placement. |
716 | </para></listitem> | 716 | </para></listitem> |
717 | <listitem><para>eccbytes</para><para> | 717 | <listitem><para>eccbytes</para><para> |
718 | The eccbytes member defines the number of ecc bytes per page. | 718 | The eccbytes member defines the number of ecc bytes per page. |
719 | </para></listitem> | 719 | </para></listitem> |
720 | <listitem><para>eccpos</para><para> | 720 | <listitem><para>eccpos</para><para> |
721 | The eccpos array holds the byte offsets in the spare area where | 721 | The eccpos array holds the byte offsets in the spare area where |
722 | the ecc codes are placed. | 722 | the ecc codes are placed. |
723 | </para></listitem> | 723 | </para></listitem> |
724 | <listitem><para>oobfree</para><para> | 724 | <listitem><para>oobfree</para><para> |
725 | The oobfree array defines the areas in the spare area which can be | 725 | The oobfree array defines the areas in the spare area which can be |
726 | used for automatic placement. The information is given in the format | 726 | used for automatic placement. The information is given in the format |
727 | {offset, size}. offset defines the start of the usable area, size the | 727 | {offset, size}. offset defines the start of the usable area, size the |
728 | length in bytes. More than one area can be defined. The list is terminated | 728 | length in bytes. More than one area can be defined. The list is terminated |
729 | by an {0, 0} entry. | 729 | by an {0, 0} entry. |
730 | </para></listitem> | 730 | </para></listitem> |
731 | </itemizedlist> | 731 | </itemizedlist> |
732 | </para> | 732 | </para> |
733 | <sect2 id="Placement_defined_by_fs_driver"> | 733 | <sect2 id="Placement_defined_by_fs_driver"> |
734 | <title>Placement defined by fs driver</title> | 734 | <title>Placement defined by fs driver</title> |
735 | <para> | 735 | <para> |
736 | The calling function provides a pointer to a nand_oobinfo | 736 | The calling function provides a pointer to a nand_oobinfo |
737 | structure which defines the ecc placement. For writes the | 737 | structure which defines the ecc placement. For writes the |
738 | caller must provide a spare area buffer along with the | 738 | caller must provide a spare area buffer along with the |
739 | data buffer. The spare area buffer size is (number of pages) * | 739 | data buffer. The spare area buffer size is (number of pages) * |
740 | (size of spare area). For reads the buffer size is | 740 | (size of spare area). For reads the buffer size is |
741 | (number of pages) * ((size of spare area) + (number of ecc | 741 | (number of pages) * ((size of spare area) + (number of ecc |
742 | steps per page) * sizeof (int)). The driver stores the | 742 | steps per page) * sizeof (int)). The driver stores the |
743 | result of the ecc check for each tuple in the spare buffer. | 743 | result of the ecc check for each tuple in the spare buffer. |
744 | The storage sequence is | 744 | The storage sequence is |
745 | </para> | 745 | </para> |
746 | <para> | 746 | <para> |
747 | <spare data page 0><ecc result 0>...<ecc result n> | 747 | <spare data page 0><ecc result 0>...<ecc result n> |
748 | </para> | 748 | </para> |
749 | <para> | 749 | <para> |
750 | ... | 750 | ... |
751 | </para> | 751 | </para> |
752 | <para> | 752 | <para> |
753 | <spare data page n><ecc result 0>...<ecc result n> | 753 | <spare data page n><ecc result 0>...<ecc result n> |
754 | </para> | 754 | </para> |
755 | <para> | 755 | <para> |
756 | This is a legacy mode used by YAFFS1. | 756 | This is a legacy mode used by YAFFS1. |
757 | </para> | 757 | </para> |
758 | <para> | 758 | <para> |
759 | If the spare area buffer is NULL then only the ECC placement is | 759 | If the spare area buffer is NULL then only the ECC placement is |
760 | done according to the given scheme in the nand_oobinfo structure. | 760 | done according to the given scheme in the nand_oobinfo structure. |
761 | </para> | 761 | </para> |
762 | </sect2> | 762 | </sect2> |
763 | <sect2 id="Automatic_placement"> | 763 | <sect2 id="Automatic_placement"> |
764 | <title>Automatic placement</title> | 764 | <title>Automatic placement</title> |
765 | <para> | 765 | <para> |
766 | Automatic placement uses the built in defaults to place the | 766 | Automatic placement uses the built in defaults to place the |
767 | ecc bytes in the spare area. If filesystem data have to be stored / | 767 | ecc bytes in the spare area. If filesystem data have to be stored / |
768 | read into the spare area then the calling function must provide a | 768 | read into the spare area then the calling function must provide a |
769 | buffer. The buffer size per page is determined by the oobfree array in | 769 | buffer. The buffer size per page is determined by the oobfree array in |
770 | the nand_oobinfo structure. | 770 | the nand_oobinfo structure. |
771 | </para> | 771 | </para> |
772 | <para> | 772 | <para> |
773 | If the spare area buffer is NULL then only the ECC placement is | 773 | If the spare area buffer is NULL then only the ECC placement is |
774 | done according to the default builtin scheme. | 774 | done according to the default builtin scheme. |
775 | </para> | 775 | </para> |
776 | </sect2> | 776 | </sect2> |
777 | <sect2 id="User_space_placement_selection"> | 777 | <sect2 id="User_space_placement_selection"> |
778 | <title>User space placement selection</title> | 778 | <title>User space placement selection</title> |
779 | <para> | 779 | <para> |
780 | All non ecc functions like mtd->read and mtd->write use an internal | 780 | All non ecc functions like mtd->read and mtd->write use an internal |
781 | structure, which can be set by an ioctl. This structure is preset | 781 | structure, which can be set by an ioctl. This structure is preset |
782 | to the autoplacement default. | 782 | to the autoplacement default. |
783 | <programlisting> | 783 | <programlisting> |
784 | ioctl (fd, MEMSETOOBSEL, oobsel); | 784 | ioctl (fd, MEMSETOOBSEL, oobsel); |
785 | </programlisting> | 785 | </programlisting> |
786 | oobsel is a pointer to a user supplied structure of type | 786 | oobsel is a pointer to a user supplied structure of type |
787 | nand_oobconfig. The contents of this structure must match the | 787 | nand_oobconfig. The contents of this structure must match the |
788 | criteria of the filesystem, which will be used. See an example in utils/nandwrite.c. | 788 | criteria of the filesystem, which will be used. See an example in utils/nandwrite.c. |
789 | </para> | 789 | </para> |
790 | </sect2> | 790 | </sect2> |
791 | </sect1> | 791 | </sect1> |
792 | <sect1 id="Spare_area_autoplacement_default"> | 792 | <sect1 id="Spare_area_autoplacement_default"> |
793 | <title>Spare area autoplacement default schemes</title> | 793 | <title>Spare area autoplacement default schemes</title> |
794 | <sect2 id="pagesize_256"> | 794 | <sect2 id="pagesize_256"> |
795 | <title>256 byte pagesize</title> | 795 | <title>256 byte pagesize</title> |
796 | <informaltable><tgroup cols="3"><tbody> | 796 | <informaltable><tgroup cols="3"><tbody> |
797 | <row> | 797 | <row> |
798 | <entry>Offset</entry> | 798 | <entry>Offset</entry> |
799 | <entry>Content</entry> | 799 | <entry>Content</entry> |
800 | <entry>Comment</entry> | 800 | <entry>Comment</entry> |
801 | </row> | 801 | </row> |
802 | <row> | 802 | <row> |
803 | <entry>0x00</entry> | 803 | <entry>0x00</entry> |
804 | <entry>ECC byte 0</entry> | 804 | <entry>ECC byte 0</entry> |
805 | <entry>Error correction code byte 0</entry> | 805 | <entry>Error correction code byte 0</entry> |
806 | </row> | 806 | </row> |
807 | <row> | 807 | <row> |
808 | <entry>0x01</entry> | 808 | <entry>0x01</entry> |
809 | <entry>ECC byte 1</entry> | 809 | <entry>ECC byte 1</entry> |
810 | <entry>Error correction code byte 1</entry> | 810 | <entry>Error correction code byte 1</entry> |
811 | </row> | 811 | </row> |
812 | <row> | 812 | <row> |
813 | <entry>0x02</entry> | 813 | <entry>0x02</entry> |
814 | <entry>ECC byte 2</entry> | 814 | <entry>ECC byte 2</entry> |
815 | <entry>Error correction code byte 2</entry> | 815 | <entry>Error correction code byte 2</entry> |
816 | </row> | 816 | </row> |
817 | <row> | 817 | <row> |
818 | <entry>0x03</entry> | 818 | <entry>0x03</entry> |
819 | <entry>Autoplace 0</entry> | 819 | <entry>Autoplace 0</entry> |
820 | <entry></entry> | 820 | <entry></entry> |
821 | </row> | 821 | </row> |
822 | <row> | 822 | <row> |
823 | <entry>0x04</entry> | 823 | <entry>0x04</entry> |
824 | <entry>Autoplace 1</entry> | 824 | <entry>Autoplace 1</entry> |
825 | <entry></entry> | 825 | <entry></entry> |
826 | </row> | 826 | </row> |
827 | <row> | 827 | <row> |
828 | <entry>0x05</entry> | 828 | <entry>0x05</entry> |
829 | <entry>Bad block marker</entry> | 829 | <entry>Bad block marker</entry> |
830 | <entry>If any bit in this byte is zero, then this block is bad. | 830 | <entry>If any bit in this byte is zero, then this block is bad. |
831 | This applies only to the first page in a block. In the remaining | 831 | This applies only to the first page in a block. In the remaining |
832 | pages this byte is reserved</entry> | 832 | pages this byte is reserved</entry> |
833 | </row> | 833 | </row> |
834 | <row> | 834 | <row> |
835 | <entry>0x06</entry> | 835 | <entry>0x06</entry> |
836 | <entry>Autoplace 2</entry> | 836 | <entry>Autoplace 2</entry> |
837 | <entry></entry> | 837 | <entry></entry> |
838 | </row> | 838 | </row> |
839 | <row> | 839 | <row> |
840 | <entry>0x07</entry> | 840 | <entry>0x07</entry> |
841 | <entry>Autoplace 3</entry> | 841 | <entry>Autoplace 3</entry> |
842 | <entry></entry> | 842 | <entry></entry> |
843 | </row> | 843 | </row> |
844 | </tbody></tgroup></informaltable> | 844 | </tbody></tgroup></informaltable> |
845 | </sect2> | 845 | </sect2> |
846 | <sect2 id="pagesize_512"> | 846 | <sect2 id="pagesize_512"> |
847 | <title>512 byte pagesize</title> | 847 | <title>512 byte pagesize</title> |
848 | <informaltable><tgroup cols="3"><tbody> | 848 | <informaltable><tgroup cols="3"><tbody> |
849 | <row> | 849 | <row> |
850 | <entry>Offset</entry> | 850 | <entry>Offset</entry> |
851 | <entry>Content</entry> | 851 | <entry>Content</entry> |
852 | <entry>Comment</entry> | 852 | <entry>Comment</entry> |
853 | </row> | 853 | </row> |
854 | <row> | 854 | <row> |
855 | <entry>0x00</entry> | 855 | <entry>0x00</entry> |
856 | <entry>ECC byte 0</entry> | 856 | <entry>ECC byte 0</entry> |
857 | <entry>Error correction code byte 0 of the lower 256 Byte data in | 857 | <entry>Error correction code byte 0 of the lower 256 Byte data in |
858 | this page</entry> | 858 | this page</entry> |
859 | </row> | 859 | </row> |
860 | <row> | 860 | <row> |
861 | <entry>0x01</entry> | 861 | <entry>0x01</entry> |
862 | <entry>ECC byte 1</entry> | 862 | <entry>ECC byte 1</entry> |
863 | <entry>Error correction code byte 1 of the lower 256 Bytes of data | 863 | <entry>Error correction code byte 1 of the lower 256 Bytes of data |
864 | in this page</entry> | 864 | in this page</entry> |
865 | </row> | 865 | </row> |
866 | <row> | 866 | <row> |
867 | <entry>0x02</entry> | 867 | <entry>0x02</entry> |
868 | <entry>ECC byte 2</entry> | 868 | <entry>ECC byte 2</entry> |
869 | <entry>Error correction code byte 2 of the lower 256 Bytes of data | 869 | <entry>Error correction code byte 2 of the lower 256 Bytes of data |
870 | in this page</entry> | 870 | in this page</entry> |
871 | </row> | 871 | </row> |
872 | <row> | 872 | <row> |
873 | <entry>0x03</entry> | 873 | <entry>0x03</entry> |
874 | <entry>ECC byte 3</entry> | 874 | <entry>ECC byte 3</entry> |
875 | <entry>Error correction code byte 0 of the upper 256 Bytes of data | 875 | <entry>Error correction code byte 0 of the upper 256 Bytes of data |
876 | in this page</entry> | 876 | in this page</entry> |
877 | </row> | 877 | </row> |
878 | <row> | 878 | <row> |
879 | <entry>0x04</entry> | 879 | <entry>0x04</entry> |
880 | <entry>reserved</entry> | 880 | <entry>reserved</entry> |
881 | <entry>reserved</entry> | 881 | <entry>reserved</entry> |
882 | </row> | 882 | </row> |
883 | <row> | 883 | <row> |
884 | <entry>0x05</entry> | 884 | <entry>0x05</entry> |
885 | <entry>Bad block marker</entry> | 885 | <entry>Bad block marker</entry> |
886 | <entry>If any bit in this byte is zero, then this block is bad. | 886 | <entry>If any bit in this byte is zero, then this block is bad. |
887 | This applies only to the first page in a block. In the remaining | 887 | This applies only to the first page in a block. In the remaining |
888 | pages this byte is reserved</entry> | 888 | pages this byte is reserved</entry> |
889 | </row> | 889 | </row> |
890 | <row> | 890 | <row> |
891 | <entry>0x06</entry> | 891 | <entry>0x06</entry> |
892 | <entry>ECC byte 4</entry> | 892 | <entry>ECC byte 4</entry> |
893 | <entry>Error correction code byte 1 of the upper 256 Bytes of data | 893 | <entry>Error correction code byte 1 of the upper 256 Bytes of data |
894 | in this page</entry> | 894 | in this page</entry> |
895 | </row> | 895 | </row> |
896 | <row> | 896 | <row> |
897 | <entry>0x07</entry> | 897 | <entry>0x07</entry> |
898 | <entry>ECC byte 5</entry> | 898 | <entry>ECC byte 5</entry> |
899 | <entry>Error correction code byte 2 of the upper 256 Bytes of data | 899 | <entry>Error correction code byte 2 of the upper 256 Bytes of data |
900 | in this page</entry> | 900 | in this page</entry> |
901 | </row> | 901 | </row> |
902 | <row> | 902 | <row> |
903 | <entry>0x08 - 0x0F</entry> | 903 | <entry>0x08 - 0x0F</entry> |
904 | <entry>Autoplace 0 - 7</entry> | 904 | <entry>Autoplace 0 - 7</entry> |
905 | <entry></entry> | 905 | <entry></entry> |
906 | </row> | 906 | </row> |
907 | </tbody></tgroup></informaltable> | 907 | </tbody></tgroup></informaltable> |
908 | </sect2> | 908 | </sect2> |
909 | <sect2 id="pagesize_2048"> | 909 | <sect2 id="pagesize_2048"> |
910 | <title>2048 byte pagesize</title> | 910 | <title>2048 byte pagesize</title> |
911 | <informaltable><tgroup cols="3"><tbody> | 911 | <informaltable><tgroup cols="3"><tbody> |
912 | <row> | 912 | <row> |
913 | <entry>Offset</entry> | 913 | <entry>Offset</entry> |
914 | <entry>Content</entry> | 914 | <entry>Content</entry> |
915 | <entry>Comment</entry> | 915 | <entry>Comment</entry> |
916 | </row> | 916 | </row> |
917 | <row> | 917 | <row> |
918 | <entry>0x00</entry> | 918 | <entry>0x00</entry> |
919 | <entry>Bad block marker</entry> | 919 | <entry>Bad block marker</entry> |
920 | <entry>If any bit in this byte is zero, then this block is bad. | 920 | <entry>If any bit in this byte is zero, then this block is bad. |
921 | This applies only to the first page in a block. In the remaining | 921 | This applies only to the first page in a block. In the remaining |
922 | pages this byte is reserved</entry> | 922 | pages this byte is reserved</entry> |
923 | </row> | 923 | </row> |
924 | <row> | 924 | <row> |
925 | <entry>0x01</entry> | 925 | <entry>0x01</entry> |
926 | <entry>Reserved</entry> | 926 | <entry>Reserved</entry> |
927 | <entry>Reserved</entry> | 927 | <entry>Reserved</entry> |
928 | </row> | 928 | </row> |
929 | <row> | 929 | <row> |
930 | <entry>0x02-0x27</entry> | 930 | <entry>0x02-0x27</entry> |
931 | <entry>Autoplace 0 - 37</entry> | 931 | <entry>Autoplace 0 - 37</entry> |
932 | <entry></entry> | 932 | <entry></entry> |
933 | </row> | 933 | </row> |
934 | <row> | 934 | <row> |
935 | <entry>0x28</entry> | 935 | <entry>0x28</entry> |
936 | <entry>ECC byte 0</entry> | 936 | <entry>ECC byte 0</entry> |
937 | <entry>Error correction code byte 0 of the first 256 Byte data in | 937 | <entry>Error correction code byte 0 of the first 256 Byte data in |
938 | this page</entry> | 938 | this page</entry> |
939 | </row> | 939 | </row> |
940 | <row> | 940 | <row> |
941 | <entry>0x29</entry> | 941 | <entry>0x29</entry> |
942 | <entry>ECC byte 1</entry> | 942 | <entry>ECC byte 1</entry> |
943 | <entry>Error correction code byte 1 of the first 256 Bytes of data | 943 | <entry>Error correction code byte 1 of the first 256 Bytes of data |
944 | in this page</entry> | 944 | in this page</entry> |
945 | </row> | 945 | </row> |
946 | <row> | 946 | <row> |
947 | <entry>0x2A</entry> | 947 | <entry>0x2A</entry> |
948 | <entry>ECC byte 2</entry> | 948 | <entry>ECC byte 2</entry> |
949 | <entry>Error correction code byte 2 of the first 256 Bytes data in | 949 | <entry>Error correction code byte 2 of the first 256 Bytes data in |
950 | this page</entry> | 950 | this page</entry> |
951 | </row> | 951 | </row> |
952 | <row> | 952 | <row> |
953 | <entry>0x2B</entry> | 953 | <entry>0x2B</entry> |
954 | <entry>ECC byte 3</entry> | 954 | <entry>ECC byte 3</entry> |
955 | <entry>Error correction code byte 0 of the second 256 Bytes of data | 955 | <entry>Error correction code byte 0 of the second 256 Bytes of data |
956 | in this page</entry> | 956 | in this page</entry> |
957 | </row> | 957 | </row> |
958 | <row> | 958 | <row> |
959 | <entry>0x2C</entry> | 959 | <entry>0x2C</entry> |
960 | <entry>ECC byte 4</entry> | 960 | <entry>ECC byte 4</entry> |
961 | <entry>Error correction code byte 1 of the second 256 Bytes of data | 961 | <entry>Error correction code byte 1 of the second 256 Bytes of data |
962 | in this page</entry> | 962 | in this page</entry> |
963 | </row> | 963 | </row> |
964 | <row> | 964 | <row> |
965 | <entry>0x2D</entry> | 965 | <entry>0x2D</entry> |
966 | <entry>ECC byte 5</entry> | 966 | <entry>ECC byte 5</entry> |
967 | <entry>Error correction code byte 2 of the second 256 Bytes of data | 967 | <entry>Error correction code byte 2 of the second 256 Bytes of data |
968 | in this page</entry> | 968 | in this page</entry> |
969 | </row> | 969 | </row> |
970 | <row> | 970 | <row> |
971 | <entry>0x2E</entry> | 971 | <entry>0x2E</entry> |
972 | <entry>ECC byte 6</entry> | 972 | <entry>ECC byte 6</entry> |
973 | <entry>Error correction code byte 0 of the third 256 Bytes of data | 973 | <entry>Error correction code byte 0 of the third 256 Bytes of data |
974 | in this page</entry> | 974 | in this page</entry> |
975 | </row> | 975 | </row> |
976 | <row> | 976 | <row> |
977 | <entry>0x2F</entry> | 977 | <entry>0x2F</entry> |
978 | <entry>ECC byte 7</entry> | 978 | <entry>ECC byte 7</entry> |
979 | <entry>Error correction code byte 1 of the third 256 Bytes of data | 979 | <entry>Error correction code byte 1 of the third 256 Bytes of data |
980 | in this page</entry> | 980 | in this page</entry> |
981 | </row> | 981 | </row> |
982 | <row> | 982 | <row> |
983 | <entry>0x30</entry> | 983 | <entry>0x30</entry> |
984 | <entry>ECC byte 8</entry> | 984 | <entry>ECC byte 8</entry> |
985 | <entry>Error correction code byte 2 of the third 256 Bytes of data | 985 | <entry>Error correction code byte 2 of the third 256 Bytes of data |
986 | in this page</entry> | 986 | in this page</entry> |
987 | </row> | 987 | </row> |
988 | <row> | 988 | <row> |
989 | <entry>0x31</entry> | 989 | <entry>0x31</entry> |
990 | <entry>ECC byte 9</entry> | 990 | <entry>ECC byte 9</entry> |
991 | <entry>Error correction code byte 0 of the fourth 256 Bytes of data | 991 | <entry>Error correction code byte 0 of the fourth 256 Bytes of data |
992 | in this page</entry> | 992 | in this page</entry> |
993 | </row> | 993 | </row> |
994 | <row> | 994 | <row> |
995 | <entry>0x32</entry> | 995 | <entry>0x32</entry> |
996 | <entry>ECC byte 10</entry> | 996 | <entry>ECC byte 10</entry> |
997 | <entry>Error correction code byte 1 of the fourth 256 Bytes of data | 997 | <entry>Error correction code byte 1 of the fourth 256 Bytes of data |
998 | in this page</entry> | 998 | in this page</entry> |
999 | </row> | 999 | </row> |
1000 | <row> | 1000 | <row> |
1001 | <entry>0x33</entry> | 1001 | <entry>0x33</entry> |
1002 | <entry>ECC byte 11</entry> | 1002 | <entry>ECC byte 11</entry> |
1003 | <entry>Error correction code byte 2 of the fourth 256 Bytes of data | 1003 | <entry>Error correction code byte 2 of the fourth 256 Bytes of data |
1004 | in this page</entry> | 1004 | in this page</entry> |
1005 | </row> | 1005 | </row> |
1006 | <row> | 1006 | <row> |
1007 | <entry>0x34</entry> | 1007 | <entry>0x34</entry> |
1008 | <entry>ECC byte 12</entry> | 1008 | <entry>ECC byte 12</entry> |
1009 | <entry>Error correction code byte 0 of the fifth 256 Bytes of data | 1009 | <entry>Error correction code byte 0 of the fifth 256 Bytes of data |
1010 | in this page</entry> | 1010 | in this page</entry> |
1011 | </row> | 1011 | </row> |
1012 | <row> | 1012 | <row> |
1013 | <entry>0x35</entry> | 1013 | <entry>0x35</entry> |
1014 | <entry>ECC byte 13</entry> | 1014 | <entry>ECC byte 13</entry> |
1015 | <entry>Error correction code byte 1 of the fifth 256 Bytes of data | 1015 | <entry>Error correction code byte 1 of the fifth 256 Bytes of data |
1016 | in this page</entry> | 1016 | in this page</entry> |
1017 | </row> | 1017 | </row> |
1018 | <row> | 1018 | <row> |
1019 | <entry>0x36</entry> | 1019 | <entry>0x36</entry> |
1020 | <entry>ECC byte 14</entry> | 1020 | <entry>ECC byte 14</entry> |
1021 | <entry>Error correction code byte 2 of the fifth 256 Bytes of data | 1021 | <entry>Error correction code byte 2 of the fifth 256 Bytes of data |
1022 | in this page</entry> | 1022 | in this page</entry> |
1023 | </row> | 1023 | </row> |
1024 | <row> | 1024 | <row> |
1025 | <entry>0x37</entry> | 1025 | <entry>0x37</entry> |
1026 | <entry>ECC byte 15</entry> | 1026 | <entry>ECC byte 15</entry> |
1027 | <entry>Error correction code byte 0 of the sixt 256 Bytes of data | 1027 | <entry>Error correction code byte 0 of the sixt 256 Bytes of data |
1028 | in this page</entry> | 1028 | in this page</entry> |
1029 | </row> | 1029 | </row> |
1030 | <row> | 1030 | <row> |
1031 | <entry>0x38</entry> | 1031 | <entry>0x38</entry> |
1032 | <entry>ECC byte 16</entry> | 1032 | <entry>ECC byte 16</entry> |
1033 | <entry>Error correction code byte 1 of the sixt 256 Bytes of data | 1033 | <entry>Error correction code byte 1 of the sixt 256 Bytes of data |
1034 | in this page</entry> | 1034 | in this page</entry> |
1035 | </row> | 1035 | </row> |
1036 | <row> | 1036 | <row> |
1037 | <entry>0x39</entry> | 1037 | <entry>0x39</entry> |
1038 | <entry>ECC byte 17</entry> | 1038 | <entry>ECC byte 17</entry> |
1039 | <entry>Error correction code byte 2 of the sixt 256 Bytes of data | 1039 | <entry>Error correction code byte 2 of the sixt 256 Bytes of data |
1040 | in this page</entry> | 1040 | in this page</entry> |
1041 | </row> | 1041 | </row> |
1042 | <row> | 1042 | <row> |
1043 | <entry>0x3A</entry> | 1043 | <entry>0x3A</entry> |
1044 | <entry>ECC byte 18</entry> | 1044 | <entry>ECC byte 18</entry> |
1045 | <entry>Error correction code byte 0 of the seventh 256 Bytes of | 1045 | <entry>Error correction code byte 0 of the seventh 256 Bytes of |
1046 | data in this page</entry> | 1046 | data in this page</entry> |
1047 | </row> | 1047 | </row> |
1048 | <row> | 1048 | <row> |
1049 | <entry>0x3B</entry> | 1049 | <entry>0x3B</entry> |
1050 | <entry>ECC byte 19</entry> | 1050 | <entry>ECC byte 19</entry> |
1051 | <entry>Error correction code byte 1 of the seventh 256 Bytes of | 1051 | <entry>Error correction code byte 1 of the seventh 256 Bytes of |
1052 | data in this page</entry> | 1052 | data in this page</entry> |
1053 | </row> | 1053 | </row> |
1054 | <row> | 1054 | <row> |
1055 | <entry>0x3C</entry> | 1055 | <entry>0x3C</entry> |
1056 | <entry>ECC byte 20</entry> | 1056 | <entry>ECC byte 20</entry> |
1057 | <entry>Error correction code byte 2 of the seventh 256 Bytes of | 1057 | <entry>Error correction code byte 2 of the seventh 256 Bytes of |
1058 | data in this page</entry> | 1058 | data in this page</entry> |
1059 | </row> | 1059 | </row> |
1060 | <row> | 1060 | <row> |
1061 | <entry>0x3D</entry> | 1061 | <entry>0x3D</entry> |
1062 | <entry>ECC byte 21</entry> | 1062 | <entry>ECC byte 21</entry> |
1063 | <entry>Error correction code byte 0 of the eigth 256 Bytes of data | 1063 | <entry>Error correction code byte 0 of the eigth 256 Bytes of data |
1064 | in this page</entry> | 1064 | in this page</entry> |
1065 | </row> | 1065 | </row> |
1066 | <row> | 1066 | <row> |
1067 | <entry>0x3E</entry> | 1067 | <entry>0x3E</entry> |
1068 | <entry>ECC byte 22</entry> | 1068 | <entry>ECC byte 22</entry> |
1069 | <entry>Error correction code byte 1 of the eigth 256 Bytes of data | 1069 | <entry>Error correction code byte 1 of the eigth 256 Bytes of data |
1070 | in this page</entry> | 1070 | in this page</entry> |
1071 | </row> | 1071 | </row> |
1072 | <row> | 1072 | <row> |
1073 | <entry>0x3F</entry> | 1073 | <entry>0x3F</entry> |
1074 | <entry>ECC byte 23</entry> | 1074 | <entry>ECC byte 23</entry> |
1075 | <entry>Error correction code byte 2 of the eigth 256 Bytes of data | 1075 | <entry>Error correction code byte 2 of the eigth 256 Bytes of data |
1076 | in this page</entry> | 1076 | in this page</entry> |
1077 | </row> | 1077 | </row> |
1078 | </tbody></tgroup></informaltable> | 1078 | </tbody></tgroup></informaltable> |
1079 | </sect2> | 1079 | </sect2> |
1080 | </sect1> | 1080 | </sect1> |
1081 | </chapter> | 1081 | </chapter> |
1082 | 1082 | ||
1083 | <chapter id="filesystems"> | 1083 | <chapter id="filesystems"> |
1084 | <title>Filesystem support</title> | 1084 | <title>Filesystem support</title> |
1085 | <para> | 1085 | <para> |
1086 | The NAND driver provides all neccecary functions for a | 1086 | The NAND driver provides all neccecary functions for a |
1087 | filesystem via the MTD interface. | 1087 | filesystem via the MTD interface. |
1088 | </para> | 1088 | </para> |
1089 | <para> | 1089 | <para> |
1090 | Filesystems must be aware of the NAND pecularities and | 1090 | Filesystems must be aware of the NAND pecularities and |
1091 | restrictions. One major restrictions of NAND Flash is, that you cannot | 1091 | restrictions. One major restrictions of NAND Flash is, that you cannot |
1092 | write as often as you want to a page. The consecutive writes to a page, | 1092 | write as often as you want to a page. The consecutive writes to a page, |
1093 | before erasing it again, are restricted to 1-3 writes, depending on the | 1093 | before erasing it again, are restricted to 1-3 writes, depending on the |
1094 | manufacturers specifications. This applies similar to the spare area. | 1094 | manufacturers specifications. This applies similar to the spare area. |
1095 | </para> | 1095 | </para> |
1096 | <para> | 1096 | <para> |
1097 | Therefor NAND aware filesystems must either write in page size chunks | 1097 | Therefor NAND aware filesystems must either write in page size chunks |
1098 | or hold a writebuffer to collect smaller writes until they sum up to | 1098 | or hold a writebuffer to collect smaller writes until they sum up to |
1099 | pagesize. Available NAND aware filesystems: JFFS2, YAFFS. | 1099 | pagesize. Available NAND aware filesystems: JFFS2, YAFFS. |
1100 | </para> | 1100 | </para> |
1101 | <para> | 1101 | <para> |
1102 | The spare area usage to store filesystem data is controlled by | 1102 | The spare area usage to store filesystem data is controlled by |
1103 | the spare area placement functionality which is described in one | 1103 | the spare area placement functionality which is described in one |
1104 | of the earlier chapters. | 1104 | of the earlier chapters. |
1105 | </para> | 1105 | </para> |
1106 | </chapter> | 1106 | </chapter> |
1107 | <chapter id="tools"> | 1107 | <chapter id="tools"> |
1108 | <title>Tools</title> | 1108 | <title>Tools</title> |
1109 | <para> | 1109 | <para> |
1110 | The MTD project provides a couple of helpful tools to handle NAND Flash. | 1110 | The MTD project provides a couple of helpful tools to handle NAND Flash. |
1111 | <itemizedlist> | 1111 | <itemizedlist> |
1112 | <listitem><para>flasherase, flasheraseall: Erase and format FLASH partitions</para></listitem> | 1112 | <listitem><para>flasherase, flasheraseall: Erase and format FLASH partitions</para></listitem> |
1113 | <listitem><para>nandwrite: write filesystem images to NAND FLASH</para></listitem> | 1113 | <listitem><para>nandwrite: write filesystem images to NAND FLASH</para></listitem> |
1114 | <listitem><para>nanddump: dump the contents of a NAND FLASH partitions</para></listitem> | 1114 | <listitem><para>nanddump: dump the contents of a NAND FLASH partitions</para></listitem> |
1115 | </itemizedlist> | 1115 | </itemizedlist> |
1116 | </para> | 1116 | </para> |
1117 | <para> | 1117 | <para> |
1118 | These tools are aware of the NAND restrictions. Please use those tools | 1118 | These tools are aware of the NAND restrictions. Please use those tools |
1119 | instead of complaining about errors which are caused by non NAND aware | 1119 | instead of complaining about errors which are caused by non NAND aware |
1120 | access methods. | 1120 | access methods. |
1121 | </para> | 1121 | </para> |
1122 | </chapter> | 1122 | </chapter> |
1123 | 1123 | ||
1124 | <chapter id="defines"> | 1124 | <chapter id="defines"> |
1125 | <title>Constants</title> | 1125 | <title>Constants</title> |
1126 | <para> | 1126 | <para> |
1127 | This chapter describes the constants which might be relevant for a driver developer. | 1127 | This chapter describes the constants which might be relevant for a driver developer. |
1128 | </para> | 1128 | </para> |
1129 | <sect1 id="Chip_option_constants"> | 1129 | <sect1 id="Chip_option_constants"> |
1130 | <title>Chip option constants</title> | 1130 | <title>Chip option constants</title> |
1131 | <sect2 id="Constants_for_chip_id_table"> | 1131 | <sect2 id="Constants_for_chip_id_table"> |
1132 | <title>Constants for chip id table</title> | 1132 | <title>Constants for chip id table</title> |
1133 | <para> | 1133 | <para> |
1134 | These constants are defined in nand.h. They are ored together to describe | 1134 | These constants are defined in nand.h. They are ored together to describe |
1135 | the chip functionality. | 1135 | the chip functionality. |
1136 | <programlisting> | 1136 | <programlisting> |
1137 | /* Chip can not auto increment pages */ | 1137 | /* Chip can not auto increment pages */ |
1138 | #define NAND_NO_AUTOINCR 0x00000001 | 1138 | #define NAND_NO_AUTOINCR 0x00000001 |
1139 | /* Buswitdh is 16 bit */ | 1139 | /* Buswitdh is 16 bit */ |
1140 | #define NAND_BUSWIDTH_16 0x00000002 | 1140 | #define NAND_BUSWIDTH_16 0x00000002 |
1141 | /* Device supports partial programming without padding */ | 1141 | /* Device supports partial programming without padding */ |
1142 | #define NAND_NO_PADDING 0x00000004 | 1142 | #define NAND_NO_PADDING 0x00000004 |
1143 | /* Chip has cache program function */ | 1143 | /* Chip has cache program function */ |
1144 | #define NAND_CACHEPRG 0x00000008 | 1144 | #define NAND_CACHEPRG 0x00000008 |
1145 | /* Chip has copy back function */ | 1145 | /* Chip has copy back function */ |
1146 | #define NAND_COPYBACK 0x00000010 | 1146 | #define NAND_COPYBACK 0x00000010 |
1147 | /* AND Chip which has 4 banks and a confusing page / block | 1147 | /* AND Chip which has 4 banks and a confusing page / block |
1148 | * assignment. See Renesas datasheet for further information */ | 1148 | * assignment. See Renesas datasheet for further information */ |
1149 | #define NAND_IS_AND 0x00000020 | 1149 | #define NAND_IS_AND 0x00000020 |
1150 | /* Chip has a array of 4 pages which can be read without | 1150 | /* Chip has a array of 4 pages which can be read without |
1151 | * additional ready /busy waits */ | 1151 | * additional ready /busy waits */ |
1152 | #define NAND_4PAGE_ARRAY 0x00000040 | 1152 | #define NAND_4PAGE_ARRAY 0x00000040 |
1153 | </programlisting> | 1153 | </programlisting> |
1154 | </para> | 1154 | </para> |
1155 | </sect2> | 1155 | </sect2> |
1156 | <sect2 id="Constants_for_runtime_options"> | 1156 | <sect2 id="Constants_for_runtime_options"> |
1157 | <title>Constants for runtime options</title> | 1157 | <title>Constants for runtime options</title> |
1158 | <para> | 1158 | <para> |
1159 | These constants are defined in nand.h. They are ored together to describe | 1159 | These constants are defined in nand.h. They are ored together to describe |
1160 | the functionality. | 1160 | the functionality. |
1161 | <programlisting> | 1161 | <programlisting> |
1162 | /* Use a flash based bad block table. This option is parsed by the | 1162 | /* Use a flash based bad block table. This option is parsed by the |
1163 | * default bad block table function (nand_default_bbt). */ | 1163 | * default bad block table function (nand_default_bbt). */ |
1164 | #define NAND_USE_FLASH_BBT 0x00010000 | 1164 | #define NAND_USE_FLASH_BBT 0x00010000 |
1165 | /* The hw ecc generator provides a syndrome instead a ecc value on read | 1165 | /* The hw ecc generator provides a syndrome instead a ecc value on read |
1166 | * This can only work if we have the ecc bytes directly behind the | 1166 | * This can only work if we have the ecc bytes directly behind the |
1167 | * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */ | 1167 | * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */ |
1168 | #define NAND_HWECC_SYNDROME 0x00020000 | 1168 | #define NAND_HWECC_SYNDROME 0x00020000 |
1169 | </programlisting> | 1169 | </programlisting> |
1170 | </para> | 1170 | </para> |
1171 | </sect2> | 1171 | </sect2> |
1172 | </sect1> | 1172 | </sect1> |
1173 | 1173 | ||
1174 | <sect1 id="EEC_selection_constants"> | 1174 | <sect1 id="EEC_selection_constants"> |
1175 | <title>ECC selection constants</title> | 1175 | <title>ECC selection constants</title> |
1176 | <para> | 1176 | <para> |
1177 | Use these constants to select the ECC algorithm. | 1177 | Use these constants to select the ECC algorithm. |
1178 | <programlisting> | 1178 | <programlisting> |
1179 | /* No ECC. Usage is not recommended ! */ | 1179 | /* No ECC. Usage is not recommended ! */ |
1180 | #define NAND_ECC_NONE 0 | 1180 | #define NAND_ECC_NONE 0 |
1181 | /* Software ECC 3 byte ECC per 256 Byte data */ | 1181 | /* Software ECC 3 byte ECC per 256 Byte data */ |
1182 | #define NAND_ECC_SOFT 1 | 1182 | #define NAND_ECC_SOFT 1 |
1183 | /* Hardware ECC 3 byte ECC per 256 Byte data */ | 1183 | /* Hardware ECC 3 byte ECC per 256 Byte data */ |
1184 | #define NAND_ECC_HW3_256 2 | 1184 | #define NAND_ECC_HW3_256 2 |
1185 | /* Hardware ECC 3 byte ECC per 512 Byte data */ | 1185 | /* Hardware ECC 3 byte ECC per 512 Byte data */ |
1186 | #define NAND_ECC_HW3_512 3 | 1186 | #define NAND_ECC_HW3_512 3 |
1187 | /* Hardware ECC 6 byte ECC per 512 Byte data */ | 1187 | /* Hardware ECC 6 byte ECC per 512 Byte data */ |
1188 | #define NAND_ECC_HW6_512 4 | 1188 | #define NAND_ECC_HW6_512 4 |
1189 | /* Hardware ECC 6 byte ECC per 512 Byte data */ | 1189 | /* Hardware ECC 6 byte ECC per 512 Byte data */ |
1190 | #define NAND_ECC_HW8_512 6 | 1190 | #define NAND_ECC_HW8_512 6 |
1191 | </programlisting> | 1191 | </programlisting> |
1192 | </para> | 1192 | </para> |
1193 | </sect1> | 1193 | </sect1> |
1194 | 1194 | ||
1195 | <sect1 id="Hardware_control_related_constants"> | 1195 | <sect1 id="Hardware_control_related_constants"> |
1196 | <title>Hardware control related constants</title> | 1196 | <title>Hardware control related constants</title> |
1197 | <para> | 1197 | <para> |
1198 | These constants describe the requested hardware access function when | 1198 | These constants describe the requested hardware access function when |
1199 | the boardspecific hardware control function is called | 1199 | the boardspecific hardware control function is called |
1200 | <programlisting> | 1200 | <programlisting> |
1201 | /* Select the chip by setting nCE to low */ | 1201 | /* Select the chip by setting nCE to low */ |
1202 | #define NAND_CTL_SETNCE 1 | 1202 | #define NAND_CTL_SETNCE 1 |
1203 | /* Deselect the chip by setting nCE to high */ | 1203 | /* Deselect the chip by setting nCE to high */ |
1204 | #define NAND_CTL_CLRNCE 2 | 1204 | #define NAND_CTL_CLRNCE 2 |
1205 | /* Select the command latch by setting CLE to high */ | 1205 | /* Select the command latch by setting CLE to high */ |
1206 | #define NAND_CTL_SETCLE 3 | 1206 | #define NAND_CTL_SETCLE 3 |
1207 | /* Deselect the command latch by setting CLE to low */ | 1207 | /* Deselect the command latch by setting CLE to low */ |
1208 | #define NAND_CTL_CLRCLE 4 | 1208 | #define NAND_CTL_CLRCLE 4 |
1209 | /* Select the address latch by setting ALE to high */ | 1209 | /* Select the address latch by setting ALE to high */ |
1210 | #define NAND_CTL_SETALE 5 | 1210 | #define NAND_CTL_SETALE 5 |
1211 | /* Deselect the address latch by setting ALE to low */ | 1211 | /* Deselect the address latch by setting ALE to low */ |
1212 | #define NAND_CTL_CLRALE 6 | 1212 | #define NAND_CTL_CLRALE 6 |
1213 | /* Set write protection by setting WP to high. Not used! */ | 1213 | /* Set write protection by setting WP to high. Not used! */ |
1214 | #define NAND_CTL_SETWP 7 | 1214 | #define NAND_CTL_SETWP 7 |
1215 | /* Clear write protection by setting WP to low. Not used! */ | 1215 | /* Clear write protection by setting WP to low. Not used! */ |
1216 | #define NAND_CTL_CLRWP 8 | 1216 | #define NAND_CTL_CLRWP 8 |
1217 | </programlisting> | 1217 | </programlisting> |
1218 | </para> | 1218 | </para> |
1219 | </sect1> | 1219 | </sect1> |
1220 | 1220 | ||
1221 | <sect1 id="Bad_block_table_constants"> | 1221 | <sect1 id="Bad_block_table_constants"> |
1222 | <title>Bad block table related constants</title> | 1222 | <title>Bad block table related constants</title> |
1223 | <para> | 1223 | <para> |
1224 | These constants describe the options used for bad block | 1224 | These constants describe the options used for bad block |
1225 | table descriptors. | 1225 | table descriptors. |
1226 | <programlisting> | 1226 | <programlisting> |
1227 | /* Options for the bad block table descriptors */ | 1227 | /* Options for the bad block table descriptors */ |
1228 | 1228 | ||
1229 | /* The number of bits used per block in the bbt on the device */ | 1229 | /* The number of bits used per block in the bbt on the device */ |
1230 | #define NAND_BBT_NRBITS_MSK 0x0000000F | 1230 | #define NAND_BBT_NRBITS_MSK 0x0000000F |
1231 | #define NAND_BBT_1BIT 0x00000001 | 1231 | #define NAND_BBT_1BIT 0x00000001 |
1232 | #define NAND_BBT_2BIT 0x00000002 | 1232 | #define NAND_BBT_2BIT 0x00000002 |
1233 | #define NAND_BBT_4BIT 0x00000004 | 1233 | #define NAND_BBT_4BIT 0x00000004 |
1234 | #define NAND_BBT_8BIT 0x00000008 | 1234 | #define NAND_BBT_8BIT 0x00000008 |
1235 | /* The bad block table is in the last good block of the device */ | 1235 | /* The bad block table is in the last good block of the device */ |
1236 | #define NAND_BBT_LASTBLOCK 0x00000010 | 1236 | #define NAND_BBT_LASTBLOCK 0x00000010 |
1237 | /* The bbt is at the given page, else we must scan for the bbt */ | 1237 | /* The bbt is at the given page, else we must scan for the bbt */ |
1238 | #define NAND_BBT_ABSPAGE 0x00000020 | 1238 | #define NAND_BBT_ABSPAGE 0x00000020 |
1239 | /* The bbt is at the given page, else we must scan for the bbt */ | 1239 | /* The bbt is at the given page, else we must scan for the bbt */ |
1240 | #define NAND_BBT_SEARCH 0x00000040 | 1240 | #define NAND_BBT_SEARCH 0x00000040 |
1241 | /* bbt is stored per chip on multichip devices */ | 1241 | /* bbt is stored per chip on multichip devices */ |
1242 | #define NAND_BBT_PERCHIP 0x00000080 | 1242 | #define NAND_BBT_PERCHIP 0x00000080 |
1243 | /* bbt has a version counter at offset veroffs */ | 1243 | /* bbt has a version counter at offset veroffs */ |
1244 | #define NAND_BBT_VERSION 0x00000100 | 1244 | #define NAND_BBT_VERSION 0x00000100 |
1245 | /* Create a bbt if none axists */ | 1245 | /* Create a bbt if none axists */ |
1246 | #define NAND_BBT_CREATE 0x00000200 | 1246 | #define NAND_BBT_CREATE 0x00000200 |
1247 | /* Search good / bad pattern through all pages of a block */ | 1247 | /* Search good / bad pattern through all pages of a block */ |
1248 | #define NAND_BBT_SCANALLPAGES 0x00000400 | 1248 | #define NAND_BBT_SCANALLPAGES 0x00000400 |
1249 | /* Scan block empty during good / bad block scan */ | 1249 | /* Scan block empty during good / bad block scan */ |
1250 | #define NAND_BBT_SCANEMPTY 0x00000800 | 1250 | #define NAND_BBT_SCANEMPTY 0x00000800 |
1251 | /* Write bbt if neccecary */ | 1251 | /* Write bbt if neccecary */ |
1252 | #define NAND_BBT_WRITE 0x00001000 | 1252 | #define NAND_BBT_WRITE 0x00001000 |
1253 | /* Read and write back block contents when writing bbt */ | 1253 | /* Read and write back block contents when writing bbt */ |
1254 | #define NAND_BBT_SAVECONTENT 0x00002000 | 1254 | #define NAND_BBT_SAVECONTENT 0x00002000 |
1255 | </programlisting> | 1255 | </programlisting> |
1256 | </para> | 1256 | </para> |
1257 | </sect1> | 1257 | </sect1> |
1258 | 1258 | ||
1259 | </chapter> | 1259 | </chapter> |
1260 | 1260 | ||
1261 | <chapter id="structs"> | 1261 | <chapter id="structs"> |
1262 | <title>Structures</title> | 1262 | <title>Structures</title> |
1263 | <para> | 1263 | <para> |
1264 | This chapter contains the autogenerated documentation of the structures which are | 1264 | This chapter contains the autogenerated documentation of the structures which are |
1265 | used in the NAND driver and might be relevant for a driver developer. Each | 1265 | used in the NAND driver and might be relevant for a driver developer. Each |
1266 | struct member has a short description which is marked with an [XXX] identifier. | 1266 | struct member has a short description which is marked with an [XXX] identifier. |
1267 | See the chapter "Documentation hints" for an explanation. | 1267 | See the chapter "Documentation hints" for an explanation. |
1268 | </para> | 1268 | </para> |
1269 | !Iinclude/linux/mtd/nand.h | 1269 | !Iinclude/linux/mtd/nand.h |
1270 | </chapter> | 1270 | </chapter> |
1271 | 1271 | ||
1272 | <chapter id="pubfunctions"> | 1272 | <chapter id="pubfunctions"> |
1273 | <title>Public Functions Provided</title> | 1273 | <title>Public Functions Provided</title> |
1274 | <para> | 1274 | <para> |
1275 | This chapter contains the autogenerated documentation of the NAND kernel API functions | 1275 | This chapter contains the autogenerated documentation of the NAND kernel API functions |
1276 | which are exported. Each function has a short description which is marked with an [XXX] identifier. | 1276 | which are exported. Each function has a short description which is marked with an [XXX] identifier. |
1277 | See the chapter "Documentation hints" for an explanation. | 1277 | See the chapter "Documentation hints" for an explanation. |
1278 | </para> | 1278 | </para> |
1279 | !Edrivers/mtd/nand/nand_base.c | 1279 | !Edrivers/mtd/nand/nand_base.c |
1280 | !Edrivers/mtd/nand/nand_bbt.c | 1280 | !Edrivers/mtd/nand/nand_bbt.c |
1281 | !Edrivers/mtd/nand/nand_ecc.c | 1281 | !Edrivers/mtd/nand/nand_ecc.c |
1282 | </chapter> | 1282 | </chapter> |
1283 | 1283 | ||
1284 | <chapter id="intfunctions"> | 1284 | <chapter id="intfunctions"> |
1285 | <title>Internal Functions Provided</title> | 1285 | <title>Internal Functions Provided</title> |
1286 | <para> | 1286 | <para> |
1287 | This chapter contains the autogenerated documentation of the NAND driver internal functions. | 1287 | This chapter contains the autogenerated documentation of the NAND driver internal functions. |
1288 | Each function has a short description which is marked with an [XXX] identifier. | 1288 | Each function has a short description which is marked with an [XXX] identifier. |
1289 | See the chapter "Documentation hints" for an explanation. | 1289 | See the chapter "Documentation hints" for an explanation. |
1290 | The functions marked with [DEFAULT] might be relevant for a board driver developer. | 1290 | The functions marked with [DEFAULT] might be relevant for a board driver developer. |
1291 | </para> | 1291 | </para> |
1292 | !Idrivers/mtd/nand/nand_base.c | 1292 | !Idrivers/mtd/nand/nand_base.c |
1293 | !Idrivers/mtd/nand/nand_bbt.c | 1293 | !Idrivers/mtd/nand/nand_bbt.c |
1294 | <!-- No internal functions for kernel-doc: | 1294 | <!-- No internal functions for kernel-doc: |
1295 | X!Idrivers/mtd/nand/nand_ecc.c | 1295 | X!Idrivers/mtd/nand/nand_ecc.c |
1296 | --> | 1296 | --> |
1297 | </chapter> | 1297 | </chapter> |
1298 | 1298 | ||
1299 | <chapter id="credits"> | 1299 | <chapter id="credits"> |
1300 | <title>Credits</title> | 1300 | <title>Credits</title> |
1301 | <para> | 1301 | <para> |
1302 | The following people have contributed to the NAND driver: | 1302 | The following people have contributed to the NAND driver: |
1303 | <orderedlist> | 1303 | <orderedlist> |
1304 | <listitem><para>Steven J. Hill<email>sjhill@realitydiluted.com</email></para></listitem> | 1304 | <listitem><para>Steven J. Hill<email>sjhill@realitydiluted.com</email></para></listitem> |
1305 | <listitem><para>David Woodhouse<email>dwmw2@infradead.org</email></para></listitem> | 1305 | <listitem><para>David Woodhouse<email>dwmw2@infradead.org</email></para></listitem> |
1306 | <listitem><para>Thomas Gleixner<email>tglx@linutronix.de</email></para></listitem> | 1306 | <listitem><para>Thomas Gleixner<email>tglx@linutronix.de</email></para></listitem> |
1307 | </orderedlist> | 1307 | </orderedlist> |
1308 | A lot of users have provided bugfixes, improvements and helping hands for testing. | 1308 | A lot of users have provided bugfixes, improvements and helping hands for testing. |
1309 | Thanks a lot. | 1309 | Thanks a lot. |
1310 | </para> | 1310 | </para> |
1311 | <para> | 1311 | <para> |
1312 | The following people have contributed to this document: | 1312 | The following people have contributed to this document: |
1313 | <orderedlist> | 1313 | <orderedlist> |
1314 | <listitem><para>Thomas Gleixner<email>tglx@linutronix.de</email></para></listitem> | 1314 | <listitem><para>Thomas Gleixner<email>tglx@linutronix.de</email></para></listitem> |
1315 | </orderedlist> | 1315 | </orderedlist> |
1316 | </para> | 1316 | </para> |
1317 | </chapter> | 1317 | </chapter> |
1318 | </book> | 1318 | </book> |
1319 | 1319 |
Documentation/DocBook/scsi.tmpl
1 | <?xml version="1.0" encoding="UTF-8"?> | 1 | <?xml version="1.0" encoding="UTF-8"?> |
2 | <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" | 2 | <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" |
3 | "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []> | 3 | "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []> |
4 | 4 | ||
5 | <book id="scsimid"> | 5 | <book id="scsimid"> |
6 | <bookinfo> | 6 | <bookinfo> |
7 | <title>SCSI Interfaces Guide</title> | 7 | <title>SCSI Interfaces Guide</title> |
8 | 8 | ||
9 | <authorgroup> | 9 | <authorgroup> |
10 | <author> | 10 | <author> |
11 | <firstname>James</firstname> | 11 | <firstname>James</firstname> |
12 | <surname>Bottomley</surname> | 12 | <surname>Bottomley</surname> |
13 | <affiliation> | 13 | <affiliation> |
14 | <address> | 14 | <address> |
15 | <email>James.Bottomley@hansenpartnership.com</email> | 15 | <email>James.Bottomley@hansenpartnership.com</email> |
16 | </address> | 16 | </address> |
17 | </affiliation> | 17 | </affiliation> |
18 | </author> | 18 | </author> |
19 | 19 | ||
20 | <author> | 20 | <author> |
21 | <firstname>Rob</firstname> | 21 | <firstname>Rob</firstname> |
22 | <surname>Landley</surname> | 22 | <surname>Landley</surname> |
23 | <affiliation> | 23 | <affiliation> |
24 | <address> | 24 | <address> |
25 | <email>rob@landley.net</email> | 25 | <email>rob@landley.net</email> |
26 | </address> | 26 | </address> |
27 | </affiliation> | 27 | </affiliation> |
28 | </author> | 28 | </author> |
29 | 29 | ||
30 | </authorgroup> | 30 | </authorgroup> |
31 | 31 | ||
32 | <copyright> | 32 | <copyright> |
33 | <year>2007</year> | 33 | <year>2007</year> |
34 | <holder>Linux Foundation</holder> | 34 | <holder>Linux Foundation</holder> |
35 | </copyright> | 35 | </copyright> |
36 | 36 | ||
37 | <legalnotice> | 37 | <legalnotice> |
38 | <para> | 38 | <para> |
39 | This documentation is free software; you can redistribute | 39 | This documentation is free software; you can redistribute |
40 | it and/or modify it under the terms of the GNU General Public | 40 | it and/or modify it under the terms of the GNU General Public |
41 | License version 2. | 41 | License version 2. |
42 | </para> | 42 | </para> |
43 | 43 | ||
44 | <para> | 44 | <para> |
45 | This program is distributed in the hope that it will be | 45 | This program is distributed in the hope that it will be |
46 | useful, but WITHOUT ANY WARRANTY; without even the implied | 46 | useful, but WITHOUT ANY WARRANTY; without even the implied |
47 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 47 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
48 | For more details see the file COPYING in the source | 48 | For more details see the file COPYING in the source |
49 | distribution of Linux. | 49 | distribution of Linux. |
50 | </para> | 50 | </para> |
51 | </legalnotice> | 51 | </legalnotice> |
52 | </bookinfo> | 52 | </bookinfo> |
53 | 53 | ||
54 | <toc></toc> | 54 | <toc></toc> |
55 | 55 | ||
56 | <chapter id="intro"> | 56 | <chapter id="intro"> |
57 | <title>Introduction</title> | 57 | <title>Introduction</title> |
58 | <sect1 id="protocol_vs_bus"> | 58 | <sect1 id="protocol_vs_bus"> |
59 | <title>Protocol vs bus</title> | 59 | <title>Protocol vs bus</title> |
60 | <para> | 60 | <para> |
61 | Once upon a time, the Small Computer Systems Interface defined both | 61 | Once upon a time, the Small Computer Systems Interface defined both |
62 | a parallel I/O bus and a data protocol to connect a wide variety of | 62 | a parallel I/O bus and a data protocol to connect a wide variety of |
63 | peripherals (disk drives, tape drives, modems, printers, scanners, | 63 | peripherals (disk drives, tape drives, modems, printers, scanners, |
64 | optical drives, test equipment, and medical devices) to a host | 64 | optical drives, test equipment, and medical devices) to a host |
65 | computer. | 65 | computer. |
66 | </para> | 66 | </para> |
67 | <para> | 67 | <para> |
68 | Although the old parallel (fast/wide/ultra) SCSI bus has largely | 68 | Although the old parallel (fast/wide/ultra) SCSI bus has largely |
69 | fallen out of use, the SCSI command set is more widely used than ever | 69 | fallen out of use, the SCSI command set is more widely used than ever |
70 | to communicate with devices over a number of different busses. | 70 | to communicate with devices over a number of different busses. |
71 | </para> | 71 | </para> |
72 | <para> | 72 | <para> |
73 | The <ulink url='http://www.t10.org/scsi-3.htm'>SCSI protocol</ulink> | 73 | The <ulink url='http://www.t10.org/scsi-3.htm'>SCSI protocol</ulink> |
74 | is a big-endian peer-to-peer packet based protocol. SCSI commands | 74 | is a big-endian peer-to-peer packet based protocol. SCSI commands |
75 | are 6, 10, 12, or 16 bytes long, often followed by an associated data | 75 | are 6, 10, 12, or 16 bytes long, often followed by an associated data |
76 | payload. | 76 | payload. |
77 | </para> | 77 | </para> |
78 | <para> | 78 | <para> |
79 | SCSI commands can be transported over just about any kind of bus, and | 79 | SCSI commands can be transported over just about any kind of bus, and |
80 | are the default protocol for storage devices attached to USB, SATA, | 80 | are the default protocol for storage devices attached to USB, SATA, |
81 | SAS, Fibre Channel, FireWire, and ATAPI devices. SCSI packets are | 81 | SAS, Fibre Channel, FireWire, and ATAPI devices. SCSI packets are |
82 | also commonly exchanged over Infiniband, | 82 | also commonly exchanged over Infiniband, |
83 | <ulink url='http://i2o.shadowconnect.com/faq.php'>I20</ulink>, TCP/IP | 83 | <ulink url='http://i2o.shadowconnect.com/faq.php'>I20</ulink>, TCP/IP |
84 | (<ulink url='http://en.wikipedia.org/wiki/ISCSI'>iSCSI</ulink>), even | 84 | (<ulink url='http://en.wikipedia.org/wiki/ISCSI'>iSCSI</ulink>), even |
85 | <ulink url='http://cyberelk.net/tim/parport/parscsi.html'>Parallel | 85 | <ulink url='http://cyberelk.net/tim/parport/parscsi.html'>Parallel |
86 | ports</ulink>. | 86 | ports</ulink>. |
87 | </para> | 87 | </para> |
88 | </sect1> | 88 | </sect1> |
89 | <sect1 id="subsystem_design"> | 89 | <sect1 id="subsystem_design"> |
90 | <title>Design of the Linux SCSI subsystem</title> | 90 | <title>Design of the Linux SCSI subsystem</title> |
91 | <para> | 91 | <para> |
92 | The SCSI subsystem uses a three layer design, with upper, mid, and low | 92 | The SCSI subsystem uses a three layer design, with upper, mid, and low |
93 | layers. Every operation involving the SCSI subsystem (such as reading | 93 | layers. Every operation involving the SCSI subsystem (such as reading |
94 | a sector from a disk) uses one driver at each of the 3 levels: one | 94 | a sector from a disk) uses one driver at each of the 3 levels: one |
95 | upper layer driver, one lower layer driver, and the SCSI midlayer. | 95 | upper layer driver, one lower layer driver, and the SCSI midlayer. |
96 | </para> | 96 | </para> |
97 | <para> | 97 | <para> |
98 | The SCSI upper layer provides the interface between userspace and the | 98 | The SCSI upper layer provides the interface between userspace and the |
99 | kernel, in the form of block and char device nodes for I/O and | 99 | kernel, in the form of block and char device nodes for I/O and |
100 | ioctl(). The SCSI lower layer contains drivers for specific hardware | 100 | ioctl(). The SCSI lower layer contains drivers for specific hardware |
101 | devices. | 101 | devices. |
102 | </para> | 102 | </para> |
103 | <para> | 103 | <para> |
104 | In between is the SCSI mid-layer, analogous to a network routing | 104 | In between is the SCSI mid-layer, analogous to a network routing |
105 | layer such as the IPv4 stack. The SCSI mid-layer routes a packet | 105 | layer such as the IPv4 stack. The SCSI mid-layer routes a packet |
106 | based data protocol between the upper layer's /dev nodes and the | 106 | based data protocol between the upper layer's /dev nodes and the |
107 | corresponding devices in the lower layer. It manages command queues, | 107 | corresponding devices in the lower layer. It manages command queues, |
108 | provides error handling and power management functions, and responds | 108 | provides error handling and power management functions, and responds |
109 | to ioctl() requests. | 109 | to ioctl() requests. |
110 | </para> | 110 | </para> |
111 | </sect1> | 111 | </sect1> |
112 | </chapter> | 112 | </chapter> |
113 | 113 | ||
114 | <chapter id="upper_layer"> | 114 | <chapter id="upper_layer"> |
115 | <title>SCSI upper layer</title> | 115 | <title>SCSI upper layer</title> |
116 | <para> | 116 | <para> |
117 | The upper layer supports the user-kernel interface by providing | 117 | The upper layer supports the user-kernel interface by providing |
118 | device nodes. | 118 | device nodes. |
119 | </para> | 119 | </para> |
120 | <sect1 id="sd"> | 120 | <sect1 id="sd"> |
121 | <title>sd (SCSI Disk)</title> | 121 | <title>sd (SCSI Disk)</title> |
122 | <para>sd (sd_mod.o)</para> | 122 | <para>sd (sd_mod.o)</para> |
123 | <!-- !Idrivers/scsi/sd.c --> | 123 | <!-- !Idrivers/scsi/sd.c --> |
124 | </sect1> | 124 | </sect1> |
125 | <sect1 id="sr"> | 125 | <sect1 id="sr"> |
126 | <title>sr (SCSI CD-ROM)</title> | 126 | <title>sr (SCSI CD-ROM)</title> |
127 | <para>sr (sr_mod.o)</para> | 127 | <para>sr (sr_mod.o)</para> |
128 | </sect1> | 128 | </sect1> |
129 | <sect1 id="st"> | 129 | <sect1 id="st"> |
130 | <title>st (SCSI Tape)</title> | 130 | <title>st (SCSI Tape)</title> |
131 | <para>st (st.o)</para> | 131 | <para>st (st.o)</para> |
132 | </sect1> | 132 | </sect1> |
133 | <sect1 id="sg"> | 133 | <sect1 id="sg"> |
134 | <title>sg (SCSI Generic)</title> | 134 | <title>sg (SCSI Generic)</title> |
135 | <para>sg (sg.o)</para> | 135 | <para>sg (sg.o)</para> |
136 | </sect1> | 136 | </sect1> |
137 | <sect1 id="ch"> | 137 | <sect1 id="ch"> |
138 | <title>ch (SCSI Media Changer)</title> | 138 | <title>ch (SCSI Media Changer)</title> |
139 | <para>ch (ch.c)</para> | 139 | <para>ch (ch.c)</para> |
140 | </sect1> | 140 | </sect1> |
141 | </chapter> | 141 | </chapter> |
142 | 142 | ||
143 | <chapter id="mid_layer"> | 143 | <chapter id="mid_layer"> |
144 | <title>SCSI mid layer</title> | 144 | <title>SCSI mid layer</title> |
145 | 145 | ||
146 | <sect1 id="midlayer_implementation"> | 146 | <sect1 id="midlayer_implementation"> |
147 | <title>SCSI midlayer implementation</title> | 147 | <title>SCSI midlayer implementation</title> |
148 | <sect2 id="scsi_device.h"> | 148 | <sect2 id="scsi_device.h"> |
149 | <title>include/scsi/scsi_device.h</title> | 149 | <title>include/scsi/scsi_device.h</title> |
150 | <para> | 150 | <para> |
151 | </para> | 151 | </para> |
152 | !Iinclude/scsi/scsi_device.h | 152 | !Iinclude/scsi/scsi_device.h |
153 | </sect2> | 153 | </sect2> |
154 | 154 | ||
155 | <sect2 id="scsi.c"> | 155 | <sect2 id="scsi.c"> |
156 | <title>drivers/scsi/scsi.c</title> | 156 | <title>drivers/scsi/scsi.c</title> |
157 | <para>Main file for the SCSI midlayer.</para> | 157 | <para>Main file for the SCSI midlayer.</para> |
158 | !Edrivers/scsi/scsi.c | 158 | !Edrivers/scsi/scsi.c |
159 | </sect2> | 159 | </sect2> |
160 | <sect2 id="scsicam.c"> | 160 | <sect2 id="scsicam.c"> |
161 | <title>drivers/scsi/scsicam.c</title> | 161 | <title>drivers/scsi/scsicam.c</title> |
162 | <para> | 162 | <para> |
163 | <ulink url='http://www.t10.org/ftp/t10/drafts/cam/cam-r12b.pdf'>SCSI | 163 | <ulink url='http://www.t10.org/ftp/t10/drafts/cam/cam-r12b.pdf'>SCSI |
164 | Common Access Method</ulink> support functions, for use with | 164 | Common Access Method</ulink> support functions, for use with |
165 | HDIO_GETGEO, etc. | 165 | HDIO_GETGEO, etc. |
166 | </para> | 166 | </para> |
167 | !Edrivers/scsi/scsicam.c | 167 | !Edrivers/scsi/scsicam.c |
168 | </sect2> | 168 | </sect2> |
169 | <sect2 id="scsi_error.c"> | 169 | <sect2 id="scsi_error.c"> |
170 | <title>drivers/scsi/scsi_error.c</title> | 170 | <title>drivers/scsi/scsi_error.c</title> |
171 | <para>Common SCSI error/timeout handling routines.</para> | 171 | <para>Common SCSI error/timeout handling routines.</para> |
172 | !Edrivers/scsi/scsi_error.c | 172 | !Edrivers/scsi/scsi_error.c |
173 | </sect2> | 173 | </sect2> |
174 | <sect2 id="scsi_devinfo.c"> | 174 | <sect2 id="scsi_devinfo.c"> |
175 | <title>drivers/scsi/scsi_devinfo.c</title> | 175 | <title>drivers/scsi/scsi_devinfo.c</title> |
176 | <para> | 176 | <para> |
177 | Manage scsi_dev_info_list, which tracks blacklisted and whitelisted | 177 | Manage scsi_dev_info_list, which tracks blacklisted and whitelisted |
178 | devices. | 178 | devices. |
179 | </para> | 179 | </para> |
180 | !Idrivers/scsi/scsi_devinfo.c | 180 | !Idrivers/scsi/scsi_devinfo.c |
181 | </sect2> | 181 | </sect2> |
182 | <sect2 id="scsi_ioctl.c"> | 182 | <sect2 id="scsi_ioctl.c"> |
183 | <title>drivers/scsi/scsi_ioctl.c</title> | 183 | <title>drivers/scsi/scsi_ioctl.c</title> |
184 | <para> | 184 | <para> |
185 | Handle ioctl() calls for SCSI devices. | 185 | Handle ioctl() calls for SCSI devices. |
186 | </para> | 186 | </para> |
187 | !Edrivers/scsi/scsi_ioctl.c | 187 | !Edrivers/scsi/scsi_ioctl.c |
188 | </sect2> | 188 | </sect2> |
189 | <sect2 id="scsi_lib.c"> | 189 | <sect2 id="scsi_lib.c"> |
190 | <title>drivers/scsi/scsi_lib.c</title> | 190 | <title>drivers/scsi/scsi_lib.c</title> |
191 | <para> | 191 | <para> |
192 | SCSI queuing library. | 192 | SCSI queuing library. |
193 | </para> | 193 | </para> |
194 | !Edrivers/scsi/scsi_lib.c | 194 | !Edrivers/scsi/scsi_lib.c |
195 | </sect2> | 195 | </sect2> |
196 | <sect2 id="scsi_lib_dma.c"> | 196 | <sect2 id="scsi_lib_dma.c"> |
197 | <title>drivers/scsi/scsi_lib_dma.c</title> | 197 | <title>drivers/scsi/scsi_lib_dma.c</title> |
198 | <para> | 198 | <para> |
199 | SCSI library functions depending on DMA | 199 | SCSI library functions depending on DMA |
200 | (map and unmap scatter-gather lists). | 200 | (map and unmap scatter-gather lists). |
201 | </para> | 201 | </para> |
202 | !Edrivers/scsi/scsi_lib_dma.c | 202 | !Edrivers/scsi/scsi_lib_dma.c |
203 | </sect2> | 203 | </sect2> |
204 | <sect2 id="scsi_module.c"> | 204 | <sect2 id="scsi_module.c"> |
205 | <title>drivers/scsi/scsi_module.c</title> | 205 | <title>drivers/scsi/scsi_module.c</title> |
206 | <para> | 206 | <para> |
207 | The file drivers/scsi/scsi_module.c contains legacy support for | 207 | The file drivers/scsi/scsi_module.c contains legacy support for |
208 | old-style host templates. It should never be used by any new driver. | 208 | old-style host templates. It should never be used by any new driver. |
209 | </para> | 209 | </para> |
210 | </sect2> | 210 | </sect2> |
211 | <sect2 id="scsi_proc.c"> | 211 | <sect2 id="scsi_proc.c"> |
212 | <title>drivers/scsi/scsi_proc.c</title> | 212 | <title>drivers/scsi/scsi_proc.c</title> |
213 | <para> | 213 | <para> |
214 | The functions in this file provide an interface between | 214 | The functions in this file provide an interface between |
215 | the PROC file system and the SCSI device drivers | 215 | the PROC file system and the SCSI device drivers |
216 | It is mainly used for debugging, statistics and to pass | 216 | It is mainly used for debugging, statistics and to pass |
217 | information directly to the lowlevel driver. | 217 | information directly to the lowlevel driver. |
218 | 218 | ||
219 | I.E. plumbing to manage /proc/scsi/* | 219 | I.E. plumbing to manage /proc/scsi/* |
220 | </para> | 220 | </para> |
221 | !Idrivers/scsi/scsi_proc.c | 221 | !Idrivers/scsi/scsi_proc.c |
222 | </sect2> | 222 | </sect2> |
223 | <sect2 id="scsi_netlink.c"> | 223 | <sect2 id="scsi_netlink.c"> |
224 | <title>drivers/scsi/scsi_netlink.c</title> | 224 | <title>drivers/scsi/scsi_netlink.c</title> |
225 | <para> | 225 | <para> |
226 | Infrastructure to provide async events from transports to userspace | 226 | Infrastructure to provide async events from transports to userspace |
227 | via netlink, using a single NETLINK_SCSITRANSPORT protocol for all | 227 | via netlink, using a single NETLINK_SCSITRANSPORT protocol for all |
228 | transports. | 228 | transports. |
229 | 229 | ||
230 | See <ulink url='http://marc.info/?l=linux-scsi&m=115507374832500&w=2'>the | 230 | See <ulink url='http://marc.info/?l=linux-scsi&m=115507374832500&w=2'>the |
231 | original patch submission</ulink> for more details. | 231 | original patch submission</ulink> for more details. |
232 | </para> | 232 | </para> |
233 | !Idrivers/scsi/scsi_netlink.c | 233 | !Idrivers/scsi/scsi_netlink.c |
234 | </sect2> | 234 | </sect2> |
235 | <sect2 id="scsi_scan.c"> | 235 | <sect2 id="scsi_scan.c"> |
236 | <title>drivers/scsi/scsi_scan.c</title> | 236 | <title>drivers/scsi/scsi_scan.c</title> |
237 | <para> | 237 | <para> |
238 | Scan a host to determine which (if any) devices are attached. | 238 | Scan a host to determine which (if any) devices are attached. |
239 | 239 | ||
240 | The general scanning/probing algorithm is as follows, exceptions are | 240 | The general scanning/probing algorithm is as follows, exceptions are |
241 | made to it depending on device specific flags, compilation options, | 241 | made to it depending on device specific flags, compilation options, |
242 | and global variable (boot or module load time) settings. | 242 | and global variable (boot or module load time) settings. |
243 | 243 | ||
244 | A specific LUN is scanned via an INQUIRY command; if the LUN has a | 244 | A specific LUN is scanned via an INQUIRY command; if the LUN has a |
245 | device attached, a scsi_device is allocated and setup for it. | 245 | device attached, a scsi_device is allocated and setup for it. |
246 | 246 | ||
247 | For every id of every channel on the given host, start by scanning | 247 | For every id of every channel on the given host, start by scanning |
248 | LUN 0. Skip hosts that don't respond at all to a scan of LUN 0. | 248 | LUN 0. Skip hosts that don't respond at all to a scan of LUN 0. |
249 | Otherwise, if LUN 0 has a device attached, allocate and setup a | 249 | Otherwise, if LUN 0 has a device attached, allocate and setup a |
250 | scsi_device for it. If target is SCSI-3 or up, issue a REPORT LUN, | 250 | scsi_device for it. If target is SCSI-3 or up, issue a REPORT LUN, |
251 | and scan all of the LUNs returned by the REPORT LUN; else, | 251 | and scan all of the LUNs returned by the REPORT LUN; else, |
252 | sequentially scan LUNs up until some maximum is reached, or a LUN is | 252 | sequentially scan LUNs up until some maximum is reached, or a LUN is |
253 | seen that cannot have a device attached to it. | 253 | seen that cannot have a device attached to it. |
254 | </para> | 254 | </para> |
255 | !Idrivers/scsi/scsi_scan.c | 255 | !Idrivers/scsi/scsi_scan.c |
256 | </sect2> | 256 | </sect2> |
257 | <sect2 id="scsi_sysctl.c"> | 257 | <sect2 id="scsi_sysctl.c"> |
258 | <title>drivers/scsi/scsi_sysctl.c</title> | 258 | <title>drivers/scsi/scsi_sysctl.c</title> |
259 | <para> | 259 | <para> |
260 | Set up the sysctl entry: "/dev/scsi/logging_level" | 260 | Set up the sysctl entry: "/dev/scsi/logging_level" |
261 | (DEV_SCSI_LOGGING_LEVEL) which sets/returns scsi_logging_level. | 261 | (DEV_SCSI_LOGGING_LEVEL) which sets/returns scsi_logging_level. |
262 | </para> | 262 | </para> |
263 | </sect2> | 263 | </sect2> |
264 | <sect2 id="scsi_sysfs.c"> | 264 | <sect2 id="scsi_sysfs.c"> |
265 | <title>drivers/scsi/scsi_sysfs.c</title> | 265 | <title>drivers/scsi/scsi_sysfs.c</title> |
266 | <para> | 266 | <para> |
267 | SCSI sysfs interface routines. | 267 | SCSI sysfs interface routines. |
268 | </para> | 268 | </para> |
269 | !Edrivers/scsi/scsi_sysfs.c | 269 | !Edrivers/scsi/scsi_sysfs.c |
270 | </sect2> | 270 | </sect2> |
271 | <sect2 id="hosts.c"> | 271 | <sect2 id="hosts.c"> |
272 | <title>drivers/scsi/hosts.c</title> | 272 | <title>drivers/scsi/hosts.c</title> |
273 | <para> | 273 | <para> |
274 | mid to lowlevel SCSI driver interface | 274 | mid to lowlevel SCSI driver interface |
275 | </para> | 275 | </para> |
276 | !Edrivers/scsi/hosts.c | 276 | !Edrivers/scsi/hosts.c |
277 | </sect2> | 277 | </sect2> |
278 | <sect2 id="constants.c"> | 278 | <sect2 id="constants.c"> |
279 | <title>drivers/scsi/constants.c</title> | 279 | <title>drivers/scsi/constants.c</title> |
280 | <para> | 280 | <para> |
281 | mid to lowlevel SCSI driver interface | 281 | mid to lowlevel SCSI driver interface |
282 | </para> | 282 | </para> |
283 | !Edrivers/scsi/constants.c | 283 | !Edrivers/scsi/constants.c |
284 | </sect2> | 284 | </sect2> |
285 | </sect1> | 285 | </sect1> |
286 | 286 | ||
287 | <sect1 id="Transport_classes"> | 287 | <sect1 id="Transport_classes"> |
288 | <title>Transport classes</title> | 288 | <title>Transport classes</title> |
289 | <para> | 289 | <para> |
290 | Transport classes are service libraries for drivers in the SCSI | 290 | Transport classes are service libraries for drivers in the SCSI |
291 | lower layer, which expose transport attributes in sysfs. | 291 | lower layer, which expose transport attributes in sysfs. |
292 | </para> | 292 | </para> |
293 | <sect2 id="Fibre_Channel_transport"> | 293 | <sect2 id="Fibre_Channel_transport"> |
294 | <title>Fibre Channel transport</title> | 294 | <title>Fibre Channel transport</title> |
295 | <para> | 295 | <para> |
296 | The file drivers/scsi/scsi_transport_fc.c defines transport attributes | 296 | The file drivers/scsi/scsi_transport_fc.c defines transport attributes |
297 | for Fibre Channel. | 297 | for Fibre Channel. |
298 | </para> | 298 | </para> |
299 | !Edrivers/scsi/scsi_transport_fc.c | 299 | !Edrivers/scsi/scsi_transport_fc.c |
300 | </sect2> | 300 | </sect2> |
301 | <sect2 id="iSCSI_transport"> | 301 | <sect2 id="iSCSI_transport"> |
302 | <title>iSCSI transport class</title> | 302 | <title>iSCSI transport class</title> |
303 | <para> | 303 | <para> |
304 | The file drivers/scsi/scsi_transport_iscsi.c defines transport | 304 | The file drivers/scsi/scsi_transport_iscsi.c defines transport |
305 | attributes for the iSCSI class, which sends SCSI packets over TCP/IP | 305 | attributes for the iSCSI class, which sends SCSI packets over TCP/IP |
306 | connections. | 306 | connections. |
307 | </para> | 307 | </para> |
308 | !Edrivers/scsi/scsi_transport_iscsi.c | 308 | !Edrivers/scsi/scsi_transport_iscsi.c |
309 | </sect2> | 309 | </sect2> |
310 | <sect2 id="SAS_transport"> | 310 | <sect2 id="SAS_transport"> |
311 | <title>Serial Attached SCSI (SAS) transport class</title> | 311 | <title>Serial Attached SCSI (SAS) transport class</title> |
312 | <para> | 312 | <para> |
313 | The file drivers/scsi/scsi_transport_sas.c defines transport | 313 | The file drivers/scsi/scsi_transport_sas.c defines transport |
314 | attributes for Serial Attached SCSI, a variant of SATA aimed at | 314 | attributes for Serial Attached SCSI, a variant of SATA aimed at |
315 | large high-end systems. | 315 | large high-end systems. |
316 | </para> | 316 | </para> |
317 | <para> | 317 | <para> |
318 | The SAS transport class contains common code to deal with SAS HBAs, | 318 | The SAS transport class contains common code to deal with SAS HBAs, |
319 | an aproximated representation of SAS topologies in the driver model, | 319 | an aproximated representation of SAS topologies in the driver model, |
320 | and various sysfs attributes to expose these topologies and managment | 320 | and various sysfs attributes to expose these topologies and management |
321 | interfaces to userspace. | 321 | interfaces to userspace. |
322 | </para> | 322 | </para> |
323 | <para> | 323 | <para> |
324 | In addition to the basic SCSI core objects this transport class | 324 | In addition to the basic SCSI core objects this transport class |
325 | introduces two additional intermediate objects: The SAS PHY | 325 | introduces two additional intermediate objects: The SAS PHY |
326 | as represented by struct sas_phy defines an "outgoing" PHY on | 326 | as represented by struct sas_phy defines an "outgoing" PHY on |
327 | a SAS HBA or Expander, and the SAS remote PHY represented by | 327 | a SAS HBA or Expander, and the SAS remote PHY represented by |
328 | struct sas_rphy defines an "incoming" PHY on a SAS Expander or | 328 | struct sas_rphy defines an "incoming" PHY on a SAS Expander or |
329 | end device. Note that this is purely a software concept, the | 329 | end device. Note that this is purely a software concept, the |
330 | underlying hardware for a PHY and a remote PHY is the exactly | 330 | underlying hardware for a PHY and a remote PHY is the exactly |
331 | the same. | 331 | the same. |
332 | </para> | 332 | </para> |
333 | <para> | 333 | <para> |
334 | There is no concept of a SAS port in this code, users can see | 334 | There is no concept of a SAS port in this code, users can see |
335 | what PHYs form a wide port based on the port_identifier attribute, | 335 | what PHYs form a wide port based on the port_identifier attribute, |
336 | which is the same for all PHYs in a port. | 336 | which is the same for all PHYs in a port. |
337 | </para> | 337 | </para> |
338 | !Edrivers/scsi/scsi_transport_sas.c | 338 | !Edrivers/scsi/scsi_transport_sas.c |
339 | </sect2> | 339 | </sect2> |
340 | <sect2 id="SATA_transport"> | 340 | <sect2 id="SATA_transport"> |
341 | <title>SATA transport class</title> | 341 | <title>SATA transport class</title> |
342 | <para> | 342 | <para> |
343 | The SATA transport is handled by libata, which has its own book of | 343 | The SATA transport is handled by libata, which has its own book of |
344 | documentation in this directory. | 344 | documentation in this directory. |
345 | </para> | 345 | </para> |
346 | </sect2> | 346 | </sect2> |
347 | <sect2 id="SPI_transport"> | 347 | <sect2 id="SPI_transport"> |
348 | <title>Parallel SCSI (SPI) transport class</title> | 348 | <title>Parallel SCSI (SPI) transport class</title> |
349 | <para> | 349 | <para> |
350 | The file drivers/scsi/scsi_transport_spi.c defines transport | 350 | The file drivers/scsi/scsi_transport_spi.c defines transport |
351 | attributes for traditional (fast/wide/ultra) SCSI busses. | 351 | attributes for traditional (fast/wide/ultra) SCSI busses. |
352 | </para> | 352 | </para> |
353 | !Edrivers/scsi/scsi_transport_spi.c | 353 | !Edrivers/scsi/scsi_transport_spi.c |
354 | </sect2> | 354 | </sect2> |
355 | <sect2 id="SRP_transport"> | 355 | <sect2 id="SRP_transport"> |
356 | <title>SCSI RDMA (SRP) transport class</title> | 356 | <title>SCSI RDMA (SRP) transport class</title> |
357 | <para> | 357 | <para> |
358 | The file drivers/scsi/scsi_transport_srp.c defines transport | 358 | The file drivers/scsi/scsi_transport_srp.c defines transport |
359 | attributes for SCSI over Remote Direct Memory Access. | 359 | attributes for SCSI over Remote Direct Memory Access. |
360 | </para> | 360 | </para> |
361 | !Edrivers/scsi/scsi_transport_srp.c | 361 | !Edrivers/scsi/scsi_transport_srp.c |
362 | </sect2> | 362 | </sect2> |
363 | </sect1> | 363 | </sect1> |
364 | 364 | ||
365 | </chapter> | 365 | </chapter> |
366 | 366 | ||
367 | <chapter id="lower_layer"> | 367 | <chapter id="lower_layer"> |
368 | <title>SCSI lower layer</title> | 368 | <title>SCSI lower layer</title> |
369 | <sect1 id="hba_drivers"> | 369 | <sect1 id="hba_drivers"> |
370 | <title>Host Bus Adapter transport types</title> | 370 | <title>Host Bus Adapter transport types</title> |
371 | <para> | 371 | <para> |
372 | Many modern device controllers use the SCSI command set as a protocol to | 372 | Many modern device controllers use the SCSI command set as a protocol to |
373 | communicate with their devices through many different types of physical | 373 | communicate with their devices through many different types of physical |
374 | connections. | 374 | connections. |
375 | </para> | 375 | </para> |
376 | <para> | 376 | <para> |
377 | In SCSI language a bus capable of carrying SCSI commands is | 377 | In SCSI language a bus capable of carrying SCSI commands is |
378 | called a "transport", and a controller connecting to such a bus is | 378 | called a "transport", and a controller connecting to such a bus is |
379 | called a "host bus adapter" (HBA). | 379 | called a "host bus adapter" (HBA). |
380 | </para> | 380 | </para> |
381 | <sect2 id="scsi_debug.c"> | 381 | <sect2 id="scsi_debug.c"> |
382 | <title>Debug transport</title> | 382 | <title>Debug transport</title> |
383 | <para> | 383 | <para> |
384 | The file drivers/scsi/scsi_debug.c simulates a host adapter with a | 384 | The file drivers/scsi/scsi_debug.c simulates a host adapter with a |
385 | variable number of disks (or disk like devices) attached, sharing a | 385 | variable number of disks (or disk like devices) attached, sharing a |
386 | common amount of RAM. Does a lot of checking to make sure that we are | 386 | common amount of RAM. Does a lot of checking to make sure that we are |
387 | not getting blocks mixed up, and panics the kernel if anything out of | 387 | not getting blocks mixed up, and panics the kernel if anything out of |
388 | the ordinary is seen. | 388 | the ordinary is seen. |
389 | </para> | 389 | </para> |
390 | <para> | 390 | <para> |
391 | To be more realistic, the simulated devices have the transport | 391 | To be more realistic, the simulated devices have the transport |
392 | attributes of SAS disks. | 392 | attributes of SAS disks. |
393 | </para> | 393 | </para> |
394 | <para> | 394 | <para> |
395 | For documentation see | 395 | For documentation see |
396 | <ulink url='http://www.torque.net/sg/sdebug26.html'>http://www.torque.net/sg/sdebug26.html</ulink> | 396 | <ulink url='http://www.torque.net/sg/sdebug26.html'>http://www.torque.net/sg/sdebug26.html</ulink> |
397 | </para> | 397 | </para> |
398 | <!-- !Edrivers/scsi/scsi_debug.c --> | 398 | <!-- !Edrivers/scsi/scsi_debug.c --> |
399 | </sect2> | 399 | </sect2> |
400 | <sect2 id="todo"> | 400 | <sect2 id="todo"> |
401 | <title>todo</title> | 401 | <title>todo</title> |
402 | <para>Parallel (fast/wide/ultra) SCSI, USB, SATA, | 402 | <para>Parallel (fast/wide/ultra) SCSI, USB, SATA, |
403 | SAS, Fibre Channel, FireWire, ATAPI devices, Infiniband, | 403 | SAS, Fibre Channel, FireWire, ATAPI devices, Infiniband, |
404 | I20, iSCSI, Parallel ports, netlink... | 404 | I20, iSCSI, Parallel ports, netlink... |
405 | </para> | 405 | </para> |
406 | </sect2> | 406 | </sect2> |
407 | </sect1> | 407 | </sect1> |
408 | </chapter> | 408 | </chapter> |
409 | </book> | 409 | </book> |
410 | 410 |
Documentation/scsi/ChangeLog.megaraid
1 | Release Date : Thu Nov 16 15:32:35 EST 2006 - | 1 | Release Date : Thu Nov 16 15:32:35 EST 2006 - |
2 | Sumant Patro <sumant.patro@lsi.com> | 2 | Sumant Patro <sumant.patro@lsi.com> |
3 | Current Version : 2.20.5.1 (scsi module), 2.20.2.6 (cmm module) | 3 | Current Version : 2.20.5.1 (scsi module), 2.20.2.6 (cmm module) |
4 | Older Version : 2.20.4.9 (scsi module), 2.20.2.6 (cmm module) | 4 | Older Version : 2.20.4.9 (scsi module), 2.20.2.6 (cmm module) |
5 | 5 | ||
6 | 1. Changes in Initialization to fix kdump failure. | 6 | 1. Changes in Initialization to fix kdump failure. |
7 | Send SYNC command on loading. | 7 | Send SYNC command on loading. |
8 | This command clears the pending commands in the adapter | 8 | This command clears the pending commands in the adapter |
9 | and re-initialize its internal RAID structure. | 9 | and re-initialize its internal RAID structure. |
10 | Without this change, megaraid driver either panics or fails to | 10 | Without this change, megaraid driver either panics or fails to |
11 | initialize the adapter during kdump's second kernel boot | 11 | initialize the adapter during kdump's second kernel boot |
12 | if there are pending commands or interrupts from other devices | 12 | if there are pending commands or interrupts from other devices |
13 | sharing the same IRQ. | 13 | sharing the same IRQ. |
14 | 2. Authors email-id domain name changed from lsil.com to lsi.com. | 14 | 2. Authors email-id domain name changed from lsil.com to lsi.com. |
15 | Also modified the MODULE_AUTHOR to megaraidlinux@lsi.com | 15 | Also modified the MODULE_AUTHOR to megaraidlinux@lsi.com |
16 | 16 | ||
17 | Release Date : Fri May 19 09:31:45 EST 2006 - Seokmann Ju <sju@lsil.com> | 17 | Release Date : Fri May 19 09:31:45 EST 2006 - Seokmann Ju <sju@lsil.com> |
18 | Current Version : 2.20.4.9 (scsi module), 2.20.2.6 (cmm module) | 18 | Current Version : 2.20.4.9 (scsi module), 2.20.2.6 (cmm module) |
19 | Older Version : 2.20.4.8 (scsi module), 2.20.2.6 (cmm module) | 19 | Older Version : 2.20.4.8 (scsi module), 2.20.2.6 (cmm module) |
20 | 20 | ||
21 | 1. Fixed a bug in megaraid_init_mbox(). | 21 | 1. Fixed a bug in megaraid_init_mbox(). |
22 | Customer reported "garbage in file on x86_64 platform". | 22 | Customer reported "garbage in file on x86_64 platform". |
23 | Root Cause: the driver registered controllers as 64-bit DMA capable | 23 | Root Cause: the driver registered controllers as 64-bit DMA capable |
24 | for those which are not support it. | 24 | for those which are not support it. |
25 | Fix: Made change in the function inserting identification machanism | 25 | Fix: Made change in the function inserting identification machanism |
26 | identifying 64-bit DMA capable controllers. | 26 | identifying 64-bit DMA capable controllers. |
27 | 27 | ||
28 | > -----Original Message----- | 28 | > -----Original Message----- |
29 | > From: Vasily Averin [mailto:vvs@sw.ru] | 29 | > From: Vasily Averin [mailto:vvs@sw.ru] |
30 | > Sent: Thursday, May 04, 2006 2:49 PM | 30 | > Sent: Thursday, May 04, 2006 2:49 PM |
31 | > To: linux-scsi@vger.kernel.org; Kolli, Neela; Mukker, Atul; | 31 | > To: linux-scsi@vger.kernel.org; Kolli, Neela; Mukker, Atul; |
32 | > Ju, Seokmann; Bagalkote, Sreenivas; | 32 | > Ju, Seokmann; Bagalkote, Sreenivas; |
33 | > James.Bottomley@SteelEye.com; devel@openvz.org | 33 | > James.Bottomley@SteelEye.com; devel@openvz.org |
34 | > Subject: megaraid_mbox: garbage in file | 34 | > Subject: megaraid_mbox: garbage in file |
35 | > | 35 | > |
36 | > Hello all, | 36 | > Hello all, |
37 | > | 37 | > |
38 | > I've investigated customers claim on the unstable work of | 38 | > I've investigated customers claim on the unstable work of |
39 | > their node and found a | 39 | > their node and found a |
40 | > strange effect: reading from some files leads to the | 40 | > strange effect: reading from some files leads to the |
41 | > "attempt to access beyond end of device" messages. | 41 | > "attempt to access beyond end of device" messages. |
42 | > | 42 | > |
43 | > I've checked filesystem, memory on the node, motherboard BIOS | 43 | > I've checked filesystem, memory on the node, motherboard BIOS |
44 | > version, but it | 44 | > version, but it |
45 | > does not help and issue still has been reproduced by simple | 45 | > does not help and issue still has been reproduced by simple |
46 | > file reading. | 46 | > file reading. |
47 | > | 47 | > |
48 | > Reproducer is simple: | 48 | > Reproducer is simple: |
49 | > | 49 | > |
50 | > echo 0xffffffff >/proc/sys/dev/scsi/logging_level ; | 50 | > echo 0xffffffff >/proc/sys/dev/scsi/logging_level ; |
51 | > cat /vz/private/101/root/etc/ld.so.cache >/tmp/ttt ; | 51 | > cat /vz/private/101/root/etc/ld.so.cache >/tmp/ttt ; |
52 | > echo 0 >/proc/sys/dev/scsi/logging | 52 | > echo 0 >/proc/sys/dev/scsi/logging |
53 | > | 53 | > |
54 | > It leads to the following messages in dmesg | 54 | > It leads to the following messages in dmesg |
55 | > | 55 | > |
56 | > sd_init_command: disk=sda, block=871769260, count=26 | 56 | > sd_init_command: disk=sda, block=871769260, count=26 |
57 | > sda : block=871769260 | 57 | > sda : block=871769260 |
58 | > sda : reading 26/26 512 byte blocks. | 58 | > sda : reading 26/26 512 byte blocks. |
59 | > scsi_add_timer: scmd: f79ed980, time: 7500, (c02b1420) | 59 | > scsi_add_timer: scmd: f79ed980, time: 7500, (c02b1420) |
60 | > sd 0:1:0:0: send 0xf79ed980 sd 0:1:0:0: | 60 | > sd 0:1:0:0: send 0xf79ed980 sd 0:1:0:0: |
61 | > command: Read (10): 28 00 33 f6 24 ac 00 00 1a 00 | 61 | > command: Read (10): 28 00 33 f6 24 ac 00 00 1a 00 |
62 | > buffer = 0xf7cfb540, bufflen = 13312, done = 0xc0366b40, | 62 | > buffer = 0xf7cfb540, bufflen = 13312, done = 0xc0366b40, |
63 | > queuecommand 0xc0344010 | 63 | > queuecommand 0xc0344010 |
64 | > leaving scsi_dispatch_cmnd() | 64 | > leaving scsi_dispatch_cmnd() |
65 | > scsi_delete_timer: scmd: f79ed980, rtn: 1 | 65 | > scsi_delete_timer: scmd: f79ed980, rtn: 1 |
66 | > sd 0:1:0:0: done 0xf79ed980 SUCCESS 0 sd 0:1:0:0: | 66 | > sd 0:1:0:0: done 0xf79ed980 SUCCESS 0 sd 0:1:0:0: |
67 | > command: Read (10): 28 00 33 f6 24 ac 00 00 1a 00 | 67 | > command: Read (10): 28 00 33 f6 24 ac 00 00 1a 00 |
68 | > scsi host busy 1 failed 0 | 68 | > scsi host busy 1 failed 0 |
69 | > sd 0:1:0:0: Notifying upper driver of completion (result 0) | 69 | > sd 0:1:0:0: Notifying upper driver of completion (result 0) |
70 | > sd_rw_intr: sda: res=0x0 | 70 | > sd_rw_intr: sda: res=0x0 |
71 | > 26 sectors total, 13312 bytes done. | 71 | > 26 sectors total, 13312 bytes done. |
72 | > use_sg is 4 | 72 | > use_sg is 4 |
73 | > attempt to access beyond end of device | 73 | > attempt to access beyond end of device |
74 | > sda6: rw=0, want=1044134458, limit=951401367 | 74 | > sda6: rw=0, want=1044134458, limit=951401367 |
75 | > Buffer I/O error on device sda6, logical block 522067228 | 75 | > Buffer I/O error on device sda6, logical block 522067228 |
76 | > attempt to access beyond end of device | 76 | > attempt to access beyond end of device |
77 | 77 | ||
78 | 2. When INQUIRY with EVPD bit set issued to the MegaRAID controller, | 78 | 2. When INQUIRY with EVPD bit set issued to the MegaRAID controller, |
79 | system memory gets corrupted. | 79 | system memory gets corrupted. |
80 | Root Cause: MegaRAID F/W handle the INQUIRY with EVPD bit set | 80 | Root Cause: MegaRAID F/W handle the INQUIRY with EVPD bit set |
81 | incorrectly. | 81 | incorrectly. |
82 | Fix: MegaRAID F/W has fixed the problem and being process of release, | 82 | Fix: MegaRAID F/W has fixed the problem and being process of release, |
83 | soon. Meanwhile, driver will filter out the request. | 83 | soon. Meanwhile, driver will filter out the request. |
84 | 84 | ||
85 | 3. One of member in the data structure of the driver leads unaligne | 85 | 3. One of member in the data structure of the driver leads unaligne |
86 | issue on 64-bit platform. | 86 | issue on 64-bit platform. |
87 | Customer reporeted "kernel unaligned access addrss" issue when | 87 | Customer reporeted "kernel unaligned access addrss" issue when |
88 | application communicates with MegaRAID HBA driver. | 88 | application communicates with MegaRAID HBA driver. |
89 | Root Cause: in uioc_t structure, one of member had misaligned and it | 89 | Root Cause: in uioc_t structure, one of member had misaligned and it |
90 | led system to display the error message. | 90 | led system to display the error message. |
91 | Fix: A patch submitted to community from following folk. | 91 | Fix: A patch submitted to community from following folk. |
92 | 92 | ||
93 | > -----Original Message----- | 93 | > -----Original Message----- |
94 | > From: linux-scsi-owner@vger.kernel.org | 94 | > From: linux-scsi-owner@vger.kernel.org |
95 | > [mailto:linux-scsi-owner@vger.kernel.org] On Behalf Of Sakurai Hiroomi | 95 | > [mailto:linux-scsi-owner@vger.kernel.org] On Behalf Of Sakurai Hiroomi |
96 | > Sent: Wednesday, July 12, 2006 4:20 AM | 96 | > Sent: Wednesday, July 12, 2006 4:20 AM |
97 | > To: linux-scsi@vger.kernel.org; linux-kernel@vger.kernel.org | 97 | > To: linux-scsi@vger.kernel.org; linux-kernel@vger.kernel.org |
98 | > Subject: Re: Help: strange messages from kernel on IA64 platform | 98 | > Subject: Re: Help: strange messages from kernel on IA64 platform |
99 | > | 99 | > |
100 | > Hi, | 100 | > Hi, |
101 | > | 101 | > |
102 | > I saw same message. | 102 | > I saw same message. |
103 | > | 103 | > |
104 | > When GAM(Global Array Manager) is started, The following | 104 | > When GAM(Global Array Manager) is started, The following |
105 | > message output. | 105 | > message output. |
106 | > kernel: kernel unaligned access to 0xe0000001fe1080d4, | 106 | > kernel: kernel unaligned access to 0xe0000001fe1080d4, |
107 | > ip=0xa000000200053371 | 107 | > ip=0xa000000200053371 |
108 | > | 108 | > |
109 | > The uioc structure used by ioctl is defined by packed, | 109 | > The uioc structure used by ioctl is defined by packed, |
110 | > the allignment of each member are disturbed. | 110 | > the allignment of each member are disturbed. |
111 | > In a 64 bit structure, the allignment of member doesn't fit 64 bit | 111 | > In a 64 bit structure, the allignment of member doesn't fit 64 bit |
112 | > boundary. this causes this messages. | 112 | > boundary. this causes this messages. |
113 | > In a 32 bit structure, we don't see the message because the allinment | 113 | > In a 32 bit structure, we don't see the message because the allinment |
114 | > of member fit 32 bit boundary even if packed is specified. | 114 | > of member fit 32 bit boundary even if packed is specified. |
115 | > | 115 | > |
116 | > patch | 116 | > patch |
117 | > I Add 32 bit dummy member to fit 64 bit boundary. I tested. | 117 | > I Add 32 bit dummy member to fit 64 bit boundary. I tested. |
118 | > We confirmed this patch fix the problem by IA64 server. | 118 | > We confirmed this patch fix the problem by IA64 server. |
119 | > | 119 | > |
120 | > ************************************************************** | 120 | > ************************************************************** |
121 | > **************** | 121 | > **************** |
122 | > --- linux-2.6.9/drivers/scsi/megaraid/megaraid_ioctl.h.orig | 122 | > --- linux-2.6.9/drivers/scsi/megaraid/megaraid_ioctl.h.orig |
123 | > 2006-04-03 17:13:03.000000000 +0900 | 123 | > 2006-04-03 17:13:03.000000000 +0900 |
124 | > +++ linux-2.6.9/drivers/scsi/megaraid/megaraid_ioctl.h | 124 | > +++ linux-2.6.9/drivers/scsi/megaraid/megaraid_ioctl.h |
125 | > 2006-04-03 17:14:09.000000000 +0900 | 125 | > 2006-04-03 17:14:09.000000000 +0900 |
126 | > @@ -132,6 +132,10 @@ | 126 | > @@ -132,6 +132,10 @@ |
127 | > /* Driver Data: */ | 127 | > /* Driver Data: */ |
128 | > void __user * user_data; | 128 | > void __user * user_data; |
129 | > uint32_t user_data_len; | 129 | > uint32_t user_data_len; |
130 | > + | 130 | > + |
131 | > + /* 64bit alignment */ | 131 | > + /* 64bit alignment */ |
132 | > + uint32_t pad_0xBC; | 132 | > + uint32_t pad_0xBC; |
133 | > + | 133 | > + |
134 | > mraid_passthru_t __user *user_pthru; | 134 | > mraid_passthru_t __user *user_pthru; |
135 | > | 135 | > |
136 | > mraid_passthru_t *pthru32; | 136 | > mraid_passthru_t *pthru32; |
137 | > ************************************************************** | 137 | > ************************************************************** |
138 | > **************** | 138 | > **************** |
139 | 139 | ||
140 | Release Date : Mon Apr 11 12:27:22 EST 2006 - Seokmann Ju <sju@lsil.com> | 140 | Release Date : Mon Apr 11 12:27:22 EST 2006 - Seokmann Ju <sju@lsil.com> |
141 | Current Version : 2.20.4.8 (scsi module), 2.20.2.6 (cmm module) | 141 | Current Version : 2.20.4.8 (scsi module), 2.20.2.6 (cmm module) |
142 | Older Version : 2.20.4.7 (scsi module), 2.20.2.6 (cmm module) | 142 | Older Version : 2.20.4.7 (scsi module), 2.20.2.6 (cmm module) |
143 | 143 | ||
144 | 1. Fixed a bug in megaraid_reset_handler(). | 144 | 1. Fixed a bug in megaraid_reset_handler(). |
145 | Customer reported "Unable to handle kernel NULL pointer dereference | 145 | Customer reported "Unable to handle kernel NULL pointer dereference |
146 | at virtual address 00000000" when system goes to reset condition | 146 | at virtual address 00000000" when system goes to reset condition |
147 | for some reason. It happened randomly. | 147 | for some reason. It happened randomly. |
148 | Root Cause: in the megaraid_reset_handler(), there is possibility not | 148 | Root Cause: in the megaraid_reset_handler(), there is possibility not |
149 | returning pending packets in the pend_list if there are multiple | 149 | returning pending packets in the pend_list if there are multiple |
150 | pending packets. | 150 | pending packets. |
151 | Fix: Made the change in the driver so that it will return all packets | 151 | Fix: Made the change in the driver so that it will return all packets |
152 | in the pend_list. | 152 | in the pend_list. |
153 | 153 | ||
154 | 2. Added change request. | 154 | 2. Added change request. |
155 | As found in the following URL, rmb() only didn't help the | 155 | As found in the following URL, rmb() only didn't help the |
156 | problem. I had to increase the loop counter to 0xFFFFFF. (6 F's) | 156 | problem. I had to increase the loop counter to 0xFFFFFF. (6 F's) |
157 | http://marc.theaimsgroup.com/?l=linux-scsi&m=110971060502497&w=2 | 157 | http://marc.theaimsgroup.com/?l=linux-scsi&m=110971060502497&w=2 |
158 | 158 | ||
159 | I attached a patch for your reference, too. | 159 | I attached a patch for your reference, too. |
160 | Could you check and get this fix in your driver? | 160 | Could you check and get this fix in your driver? |
161 | 161 | ||
162 | Best Regards, | 162 | Best Regards, |
163 | Jun'ichi Nomura | 163 | Jun'ichi Nomura |
164 | 164 | ||
165 | Release Date : Fri Nov 11 12:27:22 EST 2005 - Seokmann Ju <sju@lsil.com> | 165 | Release Date : Fri Nov 11 12:27:22 EST 2005 - Seokmann Ju <sju@lsil.com> |
166 | Current Version : 2.20.4.7 (scsi module), 2.20.2.6 (cmm module) | 166 | Current Version : 2.20.4.7 (scsi module), 2.20.2.6 (cmm module) |
167 | Older Version : 2.20.4.6 (scsi module), 2.20.2.6 (cmm module) | 167 | Older Version : 2.20.4.6 (scsi module), 2.20.2.6 (cmm module) |
168 | 168 | ||
169 | 1. Sorted out PCI IDs to remove megaraid support overlaps. | 169 | 1. Sorted out PCI IDs to remove megaraid support overlaps. |
170 | Based on the patch from Daniel, sorted out PCI IDs along with | 170 | Based on the patch from Daniel, sorted out PCI IDs along with |
171 | charactor node name change from 'megadev' to 'megadev_legacy' to avoid | 171 | charactor node name change from 'megadev' to 'megadev_legacy' to avoid |
172 | conflict. | 172 | conflict. |
173 | --- | 173 | --- |
174 | Hopefully we'll be getting the build restriction zapped much sooner, | 174 | Hopefully we'll be getting the build restriction zapped much sooner, |
175 | but we should also be thinking about totally removing the hardware | 175 | but we should also be thinking about totally removing the hardware |
176 | support overlap in the megaraid drivers. | 176 | support overlap in the megaraid drivers. |
177 | 177 | ||
178 | This patch pencils in a date of Feb 06 for this, and performs some | 178 | This patch pencils in a date of Feb 06 for this, and performs some |
179 | printk abuse in hope that existing legacy users might pick up on what's | 179 | printk abuse in hope that existing legacy users might pick up on what's |
180 | going on. | 180 | going on. |
181 | 181 | ||
182 | Signed-off-by: Daniel Drake <dsd@gentoo.org> | 182 | Signed-off-by: Daniel Drake <dsd@gentoo.org> |
183 | --- | 183 | --- |
184 | 184 | ||
185 | 2. Fixed a issue: megaraid always fails to reset handler. | 185 | 2. Fixed a issue: megaraid always fails to reset handler. |
186 | --- | 186 | --- |
187 | I found that the megaraid driver always fails to reset the | 187 | I found that the megaraid driver always fails to reset the |
188 | adapter with the following message: | 188 | adapter with the following message: |
189 | megaraid: resetting the host... | 189 | megaraid: resetting the host... |
190 | megaraid mbox: reset sequence completed successfully | 190 | megaraid mbox: reset sequence completed successfully |
191 | megaraid: fast sync command timed out | 191 | megaraid: fast sync command timed out |
192 | megaraid: reservation reset failed | 192 | megaraid: reservation reset failed |
193 | when the "Cluster mode" of the adapter BIOS is enabled. | 193 | when the "Cluster mode" of the adapter BIOS is enabled. |
194 | So, whenever the reset occurs, the adapter goes to | 194 | So, whenever the reset occurs, the adapter goes to |
195 | offline and just become unavailable. | 195 | offline and just become unavailable. |
196 | 196 | ||
197 | Jun'ichi Nomura [mailto:jnomura@mtc.biglobe.ne.jp] | 197 | Jun'ichi Nomura [mailto:jnomura@mtc.biglobe.ne.jp] |
198 | --- | 198 | --- |
199 | 199 | ||
200 | Release Date : Mon Mar 07 12:27:22 EST 2005 - Seokmann Ju <sju@lsil.com> | 200 | Release Date : Mon Mar 07 12:27:22 EST 2005 - Seokmann Ju <sju@lsil.com> |
201 | Current Version : 2.20.4.6 (scsi module), 2.20.2.6 (cmm module) | 201 | Current Version : 2.20.4.6 (scsi module), 2.20.2.6 (cmm module) |
202 | Older Version : 2.20.4.5 (scsi module), 2.20.2.5 (cmm module) | 202 | Older Version : 2.20.4.5 (scsi module), 2.20.2.5 (cmm module) |
203 | 203 | ||
204 | 1. Added IOCTL backward compatibility. | 204 | 1. Added IOCTL backward compatibility. |
205 | Convert megaraid_mm driver to new compat_ioctl entry points. | 205 | Convert megaraid_mm driver to new compat_ioctl entry points. |
206 | I don't have easy access to hardware, so only compile tested. | 206 | I don't have easy access to hardware, so only compile tested. |
207 | - Signed-off-by:Andi Kleen <ak@muc.de> | 207 | - Signed-off-by:Andi Kleen <ak@muc.de> |
208 | 208 | ||
209 | 2. megaraid_mbox fix: wrong order of arguments in memset() | 209 | 2. megaraid_mbox fix: wrong order of arguments in memset() |
210 | That, BTW, shows why cross-builds are useful-the only indication of | 210 | That, BTW, shows why cross-builds are useful-the only indication of |
211 | problem had been a new warning showing up in sparse output on alpha | 211 | problem had been a new warning showing up in sparse output on alpha |
212 | build (number of exceeding 256 got truncated). | 212 | build (number of exceeding 256 got truncated). |
213 | - Signed-off-by: Al Viro | 213 | - Signed-off-by: Al Viro |
214 | <viro@parcelfarce.linux.theplanet.co.uk> | 214 | <viro@parcelfarce.linux.theplanet.co.uk> |
215 | 215 | ||
216 | 3. Convert pci_module_init to pci_register_driver | 216 | 3. Convert pci_module_init to pci_register_driver |
217 | Convert from pci_module_init to pci_register_driver | 217 | Convert from pci_module_init to pci_register_driver |
218 | (from:http://kerneljanitors.org/TODO) | 218 | (from:http://kerneljanitors.org/TODO) |
219 | - Signed-off-by: Domen Puncer <domen@coderock.org> | 219 | - Signed-off-by: Domen Puncer <domen@coderock.org> |
220 | 220 | ||
221 | 4. Use the pre defined DMA mask constants from dma-mapping.h | 221 | 4. Use the pre defined DMA mask constants from dma-mapping.h |
222 | Use the DMA_{64,32}BIT_MASK constants from dma-mapping.h when calling | 222 | Use the DMA_{64,32}BIT_MASK constants from dma-mapping.h when calling |
223 | pci_set_dma_mask() or pci_set_consistend_dma_mask(). See | 223 | pci_set_dma_mask() or pci_set_consistend_dma_mask(). See |
224 | http://marc.theaimsgroup.com/?t=108001993000001&r=1&w=2 for more | 224 | http://marc.theaimsgroup.com/?t=108001993000001&r=1&w=2 for more |
225 | details. | 225 | details. |
226 | Signed-off-by: Tobias Klauser <tklauser@nuerscht.ch> | 226 | Signed-off-by: Tobias Klauser <tklauser@nuerscht.ch> |
227 | Signed-off-by: Domen Puncer <domen@coderock.org> | 227 | Signed-off-by: Domen Puncer <domen@coderock.org> |
228 | 228 | ||
229 | 5. Remove SSID checking for Dobson, Lindsay, and Verde based products. | 229 | 5. Remove SSID checking for Dobson, Lindsay, and Verde based products. |
230 | Checking the SSVID/SSID for controllers which have Dobson, Lindsay, | 230 | Checking the SSVID/SSID for controllers which have Dobson, Lindsay, |
231 | and Verde is unnecessary because device ID has been assigned by LSI | 231 | and Verde is unnecessary because device ID has been assigned by LSI |
232 | and it is unique value. So, all controllers with these IOPs have to be | 232 | and it is unique value. So, all controllers with these IOPs have to be |
233 | supported by the driver regardless SSVID/SSID. | 233 | supported by the driver regardless SSVID/SSID. |
234 | 234 | ||
235 | 6. Date Thu, 27 Jan 2005 04:31:09 +0100 | 235 | 6. Date Thu, 27 Jan 2005 04:31:09 +0100 |
236 | From Herbert Poetzl <> | 236 | From Herbert Poetzl <> |
237 | Subject RFC: assert_spin_locked() for 2.6 | 237 | Subject RFC: assert_spin_locked() for 2.6 |
238 | 238 | ||
239 | Greetings! | 239 | Greetings! |
240 | 240 | ||
241 | overcautious programming will kill your kernel ;) | 241 | overcautious programming will kill your kernel ;) |
242 | ever thought about checking a spin_lock or even | 242 | ever thought about checking a spin_lock or even |
243 | asserting that it must be held (maybe just for | 243 | asserting that it must be held (maybe just for |
244 | spinlock debugging?) ... | 244 | spinlock debugging?) ... |
245 | 245 | ||
246 | there are several checks present in the kernel | 246 | there are several checks present in the kernel |
247 | where somebody does a variation on the following: | 247 | where somebody does a variation on the following: |
248 | 248 | ||
249 | BUG_ON(!spin_is_locked(&some_lock)); | 249 | BUG_ON(!spin_is_locked(&some_lock)); |
250 | 250 | ||
251 | so what's wrong about that? nothing, unless you | 251 | so what's wrong about that? nothing, unless you |
252 | compile the code with CONFIG_DEBUG_SPINLOCK but | 252 | compile the code with CONFIG_DEBUG_SPINLOCK but |
253 | without CONFIG_SMP ... in which case the BUG() | 253 | without CONFIG_SMP ... in which case the BUG() |
254 | will kill your kernel ... | 254 | will kill your kernel ... |
255 | 255 | ||
256 | maybe it's not advised to make such assertions, | 256 | maybe it's not advised to make such assertions, |
257 | but here is a solution which works for me ... | 257 | but here is a solution which works for me ... |
258 | (compile tested for sh, x86_64 and x86, boot/run | 258 | (compile tested for sh, x86_64 and x86, boot/run |
259 | tested for x86 only) | 259 | tested for x86 only) |
260 | 260 | ||
261 | best, | 261 | best, |
262 | Herbert | 262 | Herbert |
263 | 263 | ||
264 | - Herbert Poetzl <herbert@13thfloor.at>, Thu, 27 Jan 2005 | 264 | - Herbert Poetzl <herbert@13thfloor.at>, Thu, 27 Jan 2005 |
265 | 265 | ||
266 | Release Date : Thu Feb 03 12:27:22 EST 2005 - Seokmann Ju <sju@lsil.com> | 266 | Release Date : Thu Feb 03 12:27:22 EST 2005 - Seokmann Ju <sju@lsil.com> |
267 | Current Version : 2.20.4.5 (scsi module), 2.20.2.5 (cmm module) | 267 | Current Version : 2.20.4.5 (scsi module), 2.20.2.5 (cmm module) |
268 | Older Version : 2.20.4.4 (scsi module), 2.20.2.4 (cmm module) | 268 | Older Version : 2.20.4.4 (scsi module), 2.20.2.4 (cmm module) |
269 | 269 | ||
270 | 1. Modified name of two attributes in scsi_host_template. | 270 | 1. Modified name of two attributes in scsi_host_template. |
271 | On Wed, 2005-02-02 at 10:56 -0500, Ju, Seokmann wrote: | 271 | On Wed, 2005-02-02 at 10:56 -0500, Ju, Seokmann wrote: |
272 | > + .sdev_attrs = megaraid_device_attrs, | 272 | > + .sdev_attrs = megaraid_device_attrs, |
273 | > + .shost_attrs = megaraid_class_device_attrs, | 273 | > + .shost_attrs = megaraid_class_device_attrs, |
274 | 274 | ||
275 | These are, perhaps, slightly confusing names. | 275 | These are, perhaps, slightly confusing names. |
276 | The terms device and class_device have well defined meanings in the | 276 | The terms device and class_device have well defined meanings in the |
277 | generic device model, neither of which is what you mean here. | 277 | generic device model, neither of which is what you mean here. |
278 | Why not simply megaraid_sdev_attrs and megaraid_shost_attrs? | 278 | Why not simply megaraid_sdev_attrs and megaraid_shost_attrs? |
279 | 279 | ||
280 | Other than this, it looks fine to me too. | 280 | Other than this, it looks fine to me too. |
281 | 281 | ||
282 | Release Date : Thu Jan 27 00:01:03 EST 2005 - Atul Mukker <atulm@lsil.com> | 282 | Release Date : Thu Jan 27 00:01:03 EST 2005 - Atul Mukker <atulm@lsil.com> |
283 | Current Version : 2.20.4.4 (scsi module), 2.20.2.5 (cmm module) | 283 | Current Version : 2.20.4.4 (scsi module), 2.20.2.5 (cmm module) |
284 | Older Version : 2.20.4.3 (scsi module), 2.20.2.4 (cmm module) | 284 | Older Version : 2.20.4.3 (scsi module), 2.20.2.4 (cmm module) |
285 | 285 | ||
286 | 1. Bump up the version of scsi module due to its conflict. | 286 | 1. Bump up the version of scsi module due to its conflict. |
287 | 287 | ||
288 | Release Date : Thu Jan 21 00:01:03 EST 2005 - Atul Mukker <atulm@lsil.com> | 288 | Release Date : Thu Jan 21 00:01:03 EST 2005 - Atul Mukker <atulm@lsil.com> |
289 | Current Version : 2.20.4.3 (scsi module), 2.20.2.5 (cmm module) | 289 | Current Version : 2.20.4.3 (scsi module), 2.20.2.5 (cmm module) |
290 | Older Version : 2.20.4.2 (scsi module), 2.20.2.4 (cmm module) | 290 | Older Version : 2.20.4.2 (scsi module), 2.20.2.4 (cmm module) |
291 | 291 | ||
292 | 1. Remove driver ioctl for logical drive to scsi address translation and | 292 | 1. Remove driver ioctl for logical drive to scsi address translation and |
293 | replace with the sysfs attribute. To remove drives and change | 293 | replace with the sysfs attribute. To remove drives and change |
294 | capacity, application shall now use the device attribute to get the | 294 | capacity, application shall now use the device attribute to get the |
295 | logical drive number for a scsi device. For adding newly created | 295 | logical drive number for a scsi device. For adding newly created |
296 | logical drives, class device attribute would be required to uniquely | 296 | logical drives, class device attribute would be required to uniquely |
297 | identify each controller. | 297 | identify each controller. |
298 | - Atul Mukker <atulm@lsil.com> | 298 | - Atul Mukker <atulm@lsil.com> |
299 | 299 | ||
300 | "James, I've been thinking about this a little more, and you may be on | 300 | "James, I've been thinking about this a little more, and you may be on |
301 | to something here. Let each driver add files as such:" | 301 | to something here. Let each driver add files as such:" |
302 | 302 | ||
303 | - Matt Domsch <Matt_Domsch@dell.com>, 12.15.2004 | 303 | - Matt Domsch <Matt_Domsch@dell.com>, 12.15.2004 |
304 | linux-scsi mailing list | 304 | linux-scsi mailing list |
305 | 305 | ||
306 | 306 | ||
307 | "Then, if you simply publish your LD number as an extra parameter of | 307 | "Then, if you simply publish your LD number as an extra parameter of |
308 | the device, you can look through /sys to find it." | 308 | the device, you can look through /sys to find it." |
309 | 309 | ||
310 | - James Bottomley <James.Bottomley@SteelEye.com>, 01.03.2005 | 310 | - James Bottomley <James.Bottomley@SteelEye.com>, 01.03.2005 |
311 | linux-scsi mailing list | 311 | linux-scsi mailing list |
312 | 312 | ||
313 | 313 | ||
314 | "I don't see why not ... it's your driver, you can publish whatever | 314 | "I don't see why not ... it's your driver, you can publish whatever |
315 | extra information you need as scsi_device attributes; that was one of | 315 | extra information you need as scsi_device attributes; that was one of |
316 | the designs of the extensible attribute system." | 316 | the designs of the extensible attribute system." |
317 | 317 | ||
318 | - James Bottomley <James.Bottomley@SteelEye.com>, 01.06.2005 | 318 | - James Bottomley <James.Bottomley@SteelEye.com>, 01.06.2005 |
319 | linux-scsi mailing list | 319 | linux-scsi mailing list |
320 | 320 | ||
321 | 2. Add AMI megaraid support - Brian King <brking@charter.net> | 321 | 2. Add AMI megaraid support - Brian King <brking@charter.net> |
322 | PCI_VENDOR_ID_AMI, PCI_DEVICE_ID_AMI_MEGARAID3, | 322 | PCI_VENDOR_ID_AMI, PCI_DEVICE_ID_AMI_MEGARAID3, |
323 | PCI_VENDOR_ID_AMI, PCI_SUBSYS_ID_PERC3_DC, | 323 | PCI_VENDOR_ID_AMI, PCI_SUBSYS_ID_PERC3_DC, |
324 | 324 | ||
325 | 3. Make some code static - Adrian Bunk <bunk@stusta.de> | 325 | 3. Make some code static - Adrian Bunk <bunk@stusta.de> |
326 | Date: Mon, 15 Nov 2004 03:14:57 +0100 | 326 | Date: Mon, 15 Nov 2004 03:14:57 +0100 |
327 | 327 | ||
328 | The patch below makes some needlessly global code static. | 328 | The patch below makes some needlessly global code static. |
329 | -wait_queue_head_t wait_q; | 329 | -wait_queue_head_t wait_q; |
330 | +static wait_queue_head_t wait_q; | 330 | +static wait_queue_head_t wait_q; |
331 | 331 | ||
332 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | 332 | Signed-off-by: Adrian Bunk <bunk@stusta.de> |
333 | 333 | ||
334 | 4. Added NEC ROMB support - NEC MegaRAID PCI Express ROMB controller | 334 | 4. Added NEC ROMB support - NEC MegaRAID PCI Express ROMB controller |
335 | PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_MEGARAID_NEC_ROMB_2E, | 335 | PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_MEGARAID_NEC_ROMB_2E, |
336 | PCI_SUBSYS_ID_NEC, PCI_SUBSYS_ID_MEGARAID_NEC_ROMB_2E, | 336 | PCI_SUBSYS_ID_NEC, PCI_SUBSYS_ID_MEGARAID_NEC_ROMB_2E, |
337 | 337 | ||
338 | 5. Fixed Tape drive issue : For any Direct CDB command to physical device | 338 | 5. Fixed Tape drive issue : For any Direct CDB command to physical device |
339 | including tape, timeout value set by driver was 10 minutes. With this | 339 | including tape, timeout value set by driver was 10 minutes. With this |
340 | value, most of command will return within timeout. However, for those | 340 | value, most of command will return within timeout. However, for those |
341 | command like ERASE or FORMAT, it takes more than an hour depends on | 341 | command like ERASE or FORMAT, it takes more than an hour depends on |
342 | capacity of the device and the command could be terminated before it | 342 | capacity of the device and the command could be terminated before it |
343 | completes. | 343 | completes. |
344 | To address this issue, the 'timeout' field in the DCDB command will | 344 | To address this issue, the 'timeout' field in the DCDB command will |
345 | have NO TIMEOUT (i.e., 4) value as its timeout on DCDB command. | 345 | have NO TIMEOUT (i.e., 4) value as its timeout on DCDB command. |
346 | 346 | ||
347 | 347 | ||
348 | 348 | ||
349 | Release Date : Thu Dec 9 19:10:23 EST 2004 | 349 | Release Date : Thu Dec 9 19:10:23 EST 2004 |
350 | - Sreenivas Bagalkote <sreenib@lsil.com> | 350 | - Sreenivas Bagalkote <sreenib@lsil.com> |
351 | 351 | ||
352 | Current Version : 2.20.4.2 (scsi module), 2.20.2.4 (cmm module) | 352 | Current Version : 2.20.4.2 (scsi module), 2.20.2.4 (cmm module) |
353 | Older Version : 2.20.4.1 (scsi module), 2.20.2.3 (cmm module) | 353 | Older Version : 2.20.4.1 (scsi module), 2.20.2.3 (cmm module) |
354 | 354 | ||
355 | i. Introduced driver ioctl that returns scsi address for a given ld. | 355 | i. Introduced driver ioctl that returns scsi address for a given ld. |
356 | 356 | ||
357 | "Why can't the existing sysfs interfaces be used to do this?" | 357 | "Why can't the existing sysfs interfaces be used to do this?" |
358 | - Brian King (brking@us.ibm.com) | 358 | - Brian King (brking@us.ibm.com) |
359 | 359 | ||
360 | "I've looked into solving this another way, but I cannot see how | 360 | "I've looked into solving this another way, but I cannot see how |
361 | to get this driver-private mapping of logical drive number-> HCTL | 361 | to get this driver-private mapping of logical drive number-> HCTL |
362 | without putting code something like this into the driver." | 362 | without putting code something like this into the driver." |
363 | 363 | ||
364 | "...and by providing a mapping a function to userspace, the driver | 364 | "...and by providing a mapping a function to userspace, the driver |
365 | is free to change its mapping algorithm in the future if necessary .." | 365 | is free to change its mapping algorithm in the future if necessary .." |
366 | - Matt Domsch (Matt_Domsch@dell.com) | 366 | - Matt Domsch (Matt_Domsch@dell.com) |
367 | 367 | ||
368 | Release Date : Thu Dec 9 19:02:14 EST 2004 - Sreenivas Bagalkote <sreenib@lsil.com> | 368 | Release Date : Thu Dec 9 19:02:14 EST 2004 - Sreenivas Bagalkote <sreenib@lsil.com> |
369 | 369 | ||
370 | Current Version : 2.20.4.1 (scsi module), 2.20.2.3 (cmm module) | 370 | Current Version : 2.20.4.1 (scsi module), 2.20.2.3 (cmm module) |
371 | Older Version : 2.20.4.1 (scsi module), 2.20.2.2 (cmm module) | 371 | Older Version : 2.20.4.1 (scsi module), 2.20.2.2 (cmm module) |
372 | 372 | ||
373 | i. Fix a bug in kioc's dma buffer deallocation | 373 | i. Fix a bug in kioc's dma buffer deallocation |
374 | 374 | ||
375 | Release Date : Thu Nov 4 18:24:56 EST 2004 - Sreenivas Bagalkote <sreenib@lsil.com> | 375 | Release Date : Thu Nov 4 18:24:56 EST 2004 - Sreenivas Bagalkote <sreenib@lsil.com> |
376 | 376 | ||
377 | Current Version : 2.20.4.1 (scsi module), 2.20.2.2 (cmm module) | 377 | Current Version : 2.20.4.1 (scsi module), 2.20.2.2 (cmm module) |
378 | Older Version : 2.20.4.0 (scsi module), 2.20.2.1 (cmm module) | 378 | Older Version : 2.20.4.0 (scsi module), 2.20.2.1 (cmm module) |
379 | 379 | ||
380 | i. Handle IOCTL cmd timeouts more properly. | 380 | i. Handle IOCTL cmd timeouts more properly. |
381 | 381 | ||
382 | ii. pci_dma_sync_{sg,single}_for_cpu was introduced into megaraid_mbox | 382 | ii. pci_dma_sync_{sg,single}_for_cpu was introduced into megaraid_mbox |
383 | incorrectly (instead of _for_device). Changed to appropriate | 383 | incorrectly (instead of _for_device). Changed to appropriate |
384 | pci_dma_sync_{sg,single}_for_device. | 384 | pci_dma_sync_{sg,single}_for_device. |
385 | 385 | ||
386 | Release Date : Wed Oct 06 11:15:29 EDT 2004 - Sreenivas Bagalkote <sreenib@lsil.com> | 386 | Release Date : Wed Oct 06 11:15:29 EDT 2004 - Sreenivas Bagalkote <sreenib@lsil.com> |
387 | Current Version : 2.20.4.0 (scsi module), 2.20.2.1 (cmm module) | 387 | Current Version : 2.20.4.0 (scsi module), 2.20.2.1 (cmm module) |
388 | Older Version : 2.20.4.0 (scsi module), 2.20.2.0 (cmm module) | 388 | Older Version : 2.20.4.0 (scsi module), 2.20.2.0 (cmm module) |
389 | 389 | ||
390 | i. Remove CONFIG_COMPAT around register_ioctl32_conversion | 390 | i. Remove CONFIG_COMPAT around register_ioctl32_conversion |
391 | 391 | ||
392 | Release Date : Mon Sep 27 22:15:07 EDT 2004 - Atul Mukker <atulm@lsil.com> | 392 | Release Date : Mon Sep 27 22:15:07 EDT 2004 - Atul Mukker <atulm@lsil.com> |
393 | Current Version : 2.20.4.0 (scsi module), 2.20.2.0 (cmm module) | 393 | Current Version : 2.20.4.0 (scsi module), 2.20.2.0 (cmm module) |
394 | Older Version : 2.20.3.1 (scsi module), 2.20.2.0 (cmm module) | 394 | Older Version : 2.20.3.1 (scsi module), 2.20.2.0 (cmm module) |
395 | 395 | ||
396 | i. Fix data corruption. Because of a typo in the driver, the IO packets | 396 | i. Fix data corruption. Because of a typo in the driver, the IO packets |
397 | were wrongly shared by the ioctl path. This causes a whole IO command | 397 | were wrongly shared by the ioctl path. This causes a whole IO command |
398 | to be replaced by an incoming ioctl command. | 398 | to be replaced by an incoming ioctl command. |
399 | 399 | ||
400 | Release Date : Tue Aug 24 09:43:35 EDT 2004 - Atul Mukker <atulm@lsil.com> | 400 | Release Date : Tue Aug 24 09:43:35 EDT 2004 - Atul Mukker <atulm@lsil.com> |
401 | Current Version : 2.20.3.1 (scsi module), 2.20.2.0 (cmm module) | 401 | Current Version : 2.20.3.1 (scsi module), 2.20.2.0 (cmm module) |
402 | Older Version : 2.20.3.0 (scsi module), 2.20.2.0 (cmm module) | 402 | Older Version : 2.20.3.0 (scsi module), 2.20.2.0 (cmm module) |
403 | 403 | ||
404 | i. Function reordering so that inline functions are defined before they | 404 | i. Function reordering so that inline functions are defined before they |
405 | are actually used. It is now mandatory for GCC 3.4.1 (current stable) | 405 | are actually used. It is now mandatory for GCC 3.4.1 (current stable) |
406 | 406 | ||
407 | Declare some heavy-weight functions to be non-inlined, | 407 | Declare some heavy-weight functions to be non-inlined, |
408 | megaraid_mbox_build_cmd, megaraid_mbox_runpendq, | 408 | megaraid_mbox_build_cmd, megaraid_mbox_runpendq, |
409 | megaraid_mbox_prepare_pthru, megaraid_mbox_prepare_epthru, | 409 | megaraid_mbox_prepare_pthru, megaraid_mbox_prepare_epthru, |
410 | megaraid_busywait_mbox | 410 | megaraid_busywait_mbox |
411 | 411 | ||
412 | - Andrew Morton, 08.19.2004 | 412 | - Andrew Morton, 08.19.2004 |
413 | linux-scsi mailing list | 413 | linux-scsi mailing list |
414 | 414 | ||
415 | "Something else to clean up after inclusion: every instance of an | 415 | "Something else to clean up after inclusion: every instance of an |
416 | inline function is actually rendered as a full function call, because | 416 | inline function is actually rendered as a full function call, because |
417 | the function is always used before it is defined. Atul, please | 417 | the function is always used before it is defined. Atul, please |
418 | re-arrange the code to eliminate the need for most (all) of the | 418 | re-arrange the code to eliminate the need for most (all) of the |
419 | function prototypes at the top of each file, and define (not just | 419 | function prototypes at the top of each file, and define (not just |
420 | declare with a prototype) each inline function before its first use" | 420 | declare with a prototype) each inline function before its first use" |
421 | 421 | ||
422 | - Matt Domsch <Matt_Domsch@dell.com>, 07.27.2004 | 422 | - Matt Domsch <Matt_Domsch@dell.com>, 07.27.2004 |
423 | linux-scsi mailing list | 423 | linux-scsi mailing list |
424 | 424 | ||
425 | 425 | ||
426 | ii. Display elapsed time (countdown) while waiting for FW to boot. | 426 | ii. Display elapsed time (countdown) while waiting for FW to boot. |
427 | 427 | ||
428 | iii. Module compilation reorder in Makefile so that unresolved symbols do | 428 | iii. Module compilation reorder in Makefile so that unresolved symbols do |
429 | not occur when driver is compiled non-modular. | 429 | not occur when driver is compiled non-modular. |
430 | 430 | ||
431 | Patrick J. LoPresti <patl@users.sourceforge.net>, 8.22.2004 | 431 | Patrick J. LoPresti <patl@users.sourceforge.net>, 8.22.2004 |
432 | linux-scsi mailing list | 432 | linux-scsi mailing list |
433 | 433 | ||
434 | 434 | ||
435 | Release Date : Thu Aug 19 09:58:33 EDT 2004 - Atul Mukker <atulm@lsil.com> | 435 | Release Date : Thu Aug 19 09:58:33 EDT 2004 - Atul Mukker <atulm@lsil.com> |
436 | Current Version : 2.20.3.0 (scsi module), 2.20.2.0 (cmm module) | 436 | Current Version : 2.20.3.0 (scsi module), 2.20.2.0 (cmm module) |
437 | Older Version : 2.20.2.0 (scsi module), 2.20.1.0 (cmm module) | 437 | Older Version : 2.20.2.0 (scsi module), 2.20.1.0 (cmm module) |
438 | 438 | ||
439 | i. When copying the mailbox packets, copy only first 14 bytes (for 32-bit | 439 | i. When copying the mailbox packets, copy only first 14 bytes (for 32-bit |
440 | mailboxes) and only first 22 bytes (for 64-bit mailboxes). This is to | 440 | mailboxes) and only first 22 bytes (for 64-bit mailboxes). This is to |
441 | avoid getting the stale values for busy bit. We want to set the busy | 441 | avoid getting the stale values for busy bit. We want to set the busy |
442 | bit just before issuing command to the FW. | 442 | bit just before issuing command to the FW. |
443 | 443 | ||
444 | ii. In the reset handling, if the reseted command is not owned by the | 444 | ii. In the reset handling, if the reseted command is not owned by the |
445 | driver, do not (wrongly) print information for the "attached" driver | 445 | driver, do not (wrongly) print information for the "attached" driver |
446 | packet. | 446 | packet. |
447 | 447 | ||
448 | iii. Have extended wait when issuing command in synchronous mode. This is | 448 | iii. Have extended wait when issuing command in synchronous mode. This is |
449 | required for the cases where the option ROM is disabled and there is | 449 | required for the cases where the option ROM is disabled and there is |
450 | no BIOS to start the controller. The FW starts to boot after receiving | 450 | no BIOS to start the controller. The FW starts to boot after receiving |
451 | the first command from the driver. The current driver has 1 second | 451 | the first command from the driver. The current driver has 1 second |
452 | timeout for the synchronous commands, which is far less than what is | 452 | timeout for the synchronous commands, which is far less than what is |
453 | actually required. We now wait up to MBOX_RESET_TIME (180 seconds) for | 453 | actually required. We now wait up to MBOX_RESET_TIME (180 seconds) for |
454 | FW boot process. | 454 | FW boot process. |
455 | 455 | ||
456 | iv. In megaraid_mbox_product_info, clear the mailbox contents completely | 456 | iv. In megaraid_mbox_product_info, clear the mailbox contents completely |
457 | before preparing the command for inquiry3. This is to ensure that the | 457 | before preparing the command for inquiry3. This is to ensure that the |
458 | FW does not get junk values in the command. | 458 | FW does not get junk values in the command. |
459 | 459 | ||
460 | v. Do away with the redundant LSI_CONFIG_COMPAT redefinition for | 460 | v. Do away with the redundant LSI_CONFIG_COMPAT redefinition for |
461 | CONFIG_COMPAT. Replace <asm/ioctl32.h> with <linux/ioctl32.h> | 461 | CONFIG_COMPAT. Replace <asm/ioctl32.h> with <linux/ioctl32.h> |
462 | 462 | ||
463 | - James Bottomley <James.Bottomley@SteelEye.com>, 08.17.2004 | 463 | - James Bottomley <James.Bottomley@SteelEye.com>, 08.17.2004 |
464 | linux-scsi mailing list | 464 | linux-scsi mailing list |
465 | 465 | ||
466 | vi. Add support for 64-bit applications. Current drivers assume only | 466 | vi. Add support for 64-bit applications. Current drivers assume only |
467 | 32-bit applications, even on 64-bit platforms. Use the "data" and | 467 | 32-bit applications, even on 64-bit platforms. Use the "data" and |
468 | "buffer" fields of the mimd_t structure, instead of embedded 32-bit | 468 | "buffer" fields of the mimd_t structure, instead of embedded 32-bit |
469 | addresses in application mailbox and passthru structures. | 469 | addresses in application mailbox and passthru structures. |
470 | 470 | ||
471 | vii. Move the function declarations for the management module from | 471 | vii. Move the function declarations for the management module from |
472 | megaraid_mm.h to megaraid_mm.c | 472 | megaraid_mm.h to megaraid_mm.c |
473 | 473 | ||
474 | - Andrew Morton, 08.19.2004 | 474 | - Andrew Morton, 08.19.2004 |
475 | linux-scsi mailing list | 475 | linux-scsi mailing list |
476 | 476 | ||
477 | viii. Change default values for MEGARAID_NEWGEN, MEGARAID_MM, and | 477 | viii. Change default values for MEGARAID_NEWGEN, MEGARAID_MM, and |
478 | MEGARAID_MAILBOX to 'n' in Kconfig.megaraid | 478 | MEGARAID_MAILBOX to 'n' in Kconfig.megaraid |
479 | 479 | ||
480 | - Andrew Morton, 08.19.2004 | 480 | - Andrew Morton, 08.19.2004 |
481 | linux-scsi mailing list | 481 | linux-scsi mailing list |
482 | 482 | ||
483 | ix. replace udelay with msleep | 483 | ix. replace udelay with msleep |
484 | 484 | ||
485 | x. Typos corrected in comments and whitespace adjustments, explicit | 485 | x. Typos corrected in comments and whitespace adjustments, explicit |
486 | grouping of expressions. | 486 | grouping of expressions. |
487 | 487 | ||
488 | 488 | ||
489 | Release Date : Fri Jul 23 15:22:07 EDT 2004 - Atul Mukker <atulm@lsil.com> | 489 | Release Date : Fri Jul 23 15:22:07 EDT 2004 - Atul Mukker <atulm@lsil.com> |
490 | Current Version : 2.20.2.0 (scsi module), 2.20.1.0 (cmm module) | 490 | Current Version : 2.20.2.0 (scsi module), 2.20.1.0 (cmm module) |
491 | Older Version : 2.20.1.0 (scsi module), 2.20.0.0 (cmm module) | 491 | Older Version : 2.20.1.0 (scsi module), 2.20.0.0 (cmm module) |
492 | 492 | ||
493 | i. Add PCI ids for Acer ROMB 2E solution | 493 | i. Add PCI ids for Acer ROMB 2E solution |
494 | 494 | ||
495 | ii. Add PCI ids for I4 | 495 | ii. Add PCI ids for I4 |
496 | 496 | ||
497 | iii. Typo corrected for subsys id for megaraid sata 300-4x | 497 | iii. Typo corrected for subsys id for megaraid sata 300-4x |
498 | 498 | ||
499 | iv. Remove yield() while mailbox handshake in synchronous commands | 499 | iv. Remove yield() while mailbox handshake in synchronous commands |
500 | 500 | ||
501 | 501 | ||
502 | "My other main gripe is things like this: | 502 | "My other main gripe is things like this: |
503 | 503 | ||
504 | + // wait for maximum 1 second for status to post | 504 | + // wait for maximum 1 second for status to post |
505 | + for (i = 0; i < 40000; i++) { | 505 | + for (i = 0; i < 40000; i++) { |
506 | + if (mbox->numstatus != 0xFF) break; | 506 | + if (mbox->numstatus != 0xFF) break; |
507 | + udelay(25); yield(); | 507 | + udelay(25); yield(); |
508 | + } | 508 | + } |
509 | 509 | ||
510 | which litter the driver. Use of yield() in drivers is deprecated." | 510 | which litter the driver. Use of yield() in drivers is deprecated." |
511 | 511 | ||
512 | - James Bottomley <James.Bottomley@SteelEye.com>, 07.14.2004 | 512 | - James Bottomley <James.Bottomley@SteelEye.com>, 07.14.2004 |
513 | linux-scsi mailing list | 513 | linux-scsi mailing list |
514 | 514 | ||
515 | v. Remove redundant __megaraid_busywait_mbox routine | 515 | v. Remove redundant __megaraid_busywait_mbox routine |
516 | 516 | ||
517 | vi. Fix bug in the managment module, which causes a system lockup when the | 517 | vi. Fix bug in the management module, which causes a system lockup when the |
518 | IO module is loaded and then unloaded, followed by executing any | 518 | IO module is loaded and then unloaded, followed by executing any |
519 | management utility. The current version of management module does not | 519 | management utility. The current version of management module does not |
520 | handle the adapter unregister properly. | 520 | handle the adapter unregister properly. |
521 | 521 | ||
522 | Specifically, it still keeps a reference to the unregistered | 522 | Specifically, it still keeps a reference to the unregistered |
523 | controllers. To avoid this, the static array adapters has been | 523 | controllers. To avoid this, the static array adapters has been |
524 | replaced by a dynamic list, which gets updated every time an adapter | 524 | replaced by a dynamic list, which gets updated every time an adapter |
525 | is added or removed. | 525 | is added or removed. |
526 | 526 | ||
527 | Also, during unregistration of the IO module, the resources are | 527 | Also, during unregistration of the IO module, the resources are |
528 | now released in the exact reverse order of the allocation time | 528 | now released in the exact reverse order of the allocation time |
529 | sequence. | 529 | sequence. |
530 | 530 | ||
531 | 531 | ||
532 | Release Date : Fri Jun 25 18:58:43 EDT 2004 - Atul Mukker <atulm@lsil.com> | 532 | Release Date : Fri Jun 25 18:58:43 EDT 2004 - Atul Mukker <atulm@lsil.com> |
533 | Current Version : 2.20.1.0 | 533 | Current Version : 2.20.1.0 |
534 | Older Version : megaraid 2.20.0.1 | 534 | Older Version : megaraid 2.20.0.1 |
535 | 535 | ||
536 | i. Stale list pointer in adapter causes kernel panic when module | 536 | i. Stale list pointer in adapter causes kernel panic when module |
537 | megaraid_mbox is unloaded | 537 | megaraid_mbox is unloaded |
538 | 538 | ||
539 | 539 | ||
540 | Release Date : Thu Jun 24 20:37:11 EDT 2004 - Atul Mukker <atulm@lsil.com> | 540 | Release Date : Thu Jun 24 20:37:11 EDT 2004 - Atul Mukker <atulm@lsil.com> |
541 | Current Version : 2.20.0.1 | 541 | Current Version : 2.20.0.1 |
542 | Older Version : megaraid 2.20.0.00 | 542 | Older Version : megaraid 2.20.0.00 |
543 | 543 | ||
544 | i. Modules are not 'y' by default, but depend on current definition of | 544 | i. Modules are not 'y' by default, but depend on current definition of |
545 | SCSI & PCI. | 545 | SCSI & PCI. |
546 | 546 | ||
547 | ii. Redundant structure mraid_driver_t removed. | 547 | ii. Redundant structure mraid_driver_t removed. |
548 | 548 | ||
549 | iii. Miscellaneous indentation and goto/label fixes. | 549 | iii. Miscellaneous indentation and goto/label fixes. |
550 | - Christoph Hellwig <hch@infradead.org>, 06.24.2004 linux-scsi | 550 | - Christoph Hellwig <hch@infradead.org>, 06.24.2004 linux-scsi |
551 | 551 | ||
552 | iv. scsi_host_put(), do just before completing HBA shutdown. | 552 | iv. scsi_host_put(), do just before completing HBA shutdown. |
553 | 553 | ||
554 | 554 | ||
555 | 555 | ||
556 | Release Date : Mon Jun 21 19:53:54 EDT 2004 - Atul Mukker <atulm@lsil.com> | 556 | Release Date : Mon Jun 21 19:53:54 EDT 2004 - Atul Mukker <atulm@lsil.com> |
557 | Current Version : 2.20.0.0 | 557 | Current Version : 2.20.0.0 |
558 | Older Version : megaraid 2.20.0.rc2 and 2.00.3 | 558 | Older Version : megaraid 2.20.0.rc2 and 2.00.3 |
559 | 559 | ||
560 | i. Independent module to interact with userland applications and | 560 | i. Independent module to interact with userland applications and |
561 | multiplex command to low level RAID module(s). | 561 | multiplex command to low level RAID module(s). |
562 | 562 | ||
563 | "Shared code in a third module, a "library module", is an acceptable | 563 | "Shared code in a third module, a "library module", is an acceptable |
564 | solution. modprobe automatically loads dependent modules, so users | 564 | solution. modprobe automatically loads dependent modules, so users |
565 | running "modprobe driver1" or "modprobe driver2" would automatically | 565 | running "modprobe driver1" or "modprobe driver2" would automatically |
566 | load the shared library module." | 566 | load the shared library module." |
567 | 567 | ||
568 | - Jeff Garzik <jgarzik@pobox.com> 02.25.2004 LKML | 568 | - Jeff Garzik <jgarzik@pobox.com> 02.25.2004 LKML |
569 | 569 | ||
570 | "As Jeff hinted, if your userspace<->driver API is consistent between | 570 | "As Jeff hinted, if your userspace<->driver API is consistent between |
571 | your new MPT-based RAID controllers and your existing megaraid driver, | 571 | your new MPT-based RAID controllers and your existing megaraid driver, |
572 | then perhaps you need a single small helper module (lsiioctl or some | 572 | then perhaps you need a single small helper module (lsiioctl or some |
573 | better name), loaded by both mptraid and megaraid automatically, which | 573 | better name), loaded by both mptraid and megaraid automatically, which |
574 | handles registering the /dev/megaraid node dynamically. In this case, | 574 | handles registering the /dev/megaraid node dynamically. In this case, |
575 | both mptraid and megaraid would register with lsiioctl for each | 575 | both mptraid and megaraid would register with lsiioctl for each |
576 | adapter discovered, and lsiioctl would essentially be a switch, | 576 | adapter discovered, and lsiioctl would essentially be a switch, |
577 | redirecting userspace tool ioctls to the appropriate driver." | 577 | redirecting userspace tool ioctls to the appropriate driver." |
578 | 578 | ||
579 | - Matt Domsch <Matt_Domsch@dell.com> 02.25.2004 LKML | 579 | - Matt Domsch <Matt_Domsch@dell.com> 02.25.2004 LKML |
580 | 580 | ||
581 | ii. Remove C99 initializations from pci_device id. | 581 | ii. Remove C99 initializations from pci_device id. |
582 | 582 | ||
583 | "pci_id_table_g would be much more readable when not using C99 | 583 | "pci_id_table_g would be much more readable when not using C99 |
584 | initializers. | 584 | initializers. |
585 | PCI table doesn't change, there's lots of users that prefer the more | 585 | PCI table doesn't change, there's lots of users that prefer the more |
586 | readable variant. And it's really far less and much easier to grok | 586 | readable variant. And it's really far less and much easier to grok |
587 | lines without C99 initializers." | 587 | lines without C99 initializers." |
588 | 588 | ||
589 | - Christoph Hellwig <hch@infradead.org>, 05.28.2004 linux-scsi | 589 | - Christoph Hellwig <hch@infradead.org>, 05.28.2004 linux-scsi |
590 | 590 | ||
591 | iii. Many fixes as suggested by Christoph Hellwig <hch@infradead.org> on | 591 | iii. Many fixes as suggested by Christoph Hellwig <hch@infradead.org> on |
592 | linux-scsi, 05.28.2004 | 592 | linux-scsi, 05.28.2004 |
593 | 593 | ||
594 | iv. We now support up to 32 parallel ioctl commands instead of current 1. | 594 | iv. We now support up to 32 parallel ioctl commands instead of current 1. |
595 | There is a conscious effort to let memory allocation not fail for ioctl | 595 | There is a conscious effort to let memory allocation not fail for ioctl |
596 | commands. | 596 | commands. |
597 | 597 | ||
598 | v. Do away with internal memory management. Use pci_pool_(create|alloc) | 598 | v. Do away with internal memory management. Use pci_pool_(create|alloc) |
599 | instead. | 599 | instead. |
600 | 600 | ||
601 | vi. Kill tasklet when unloading the driver. | 601 | vi. Kill tasklet when unloading the driver. |
602 | 602 | ||
603 | vii. Do not use "host_lock', driver has fine-grain locks now to protect all | 603 | vii. Do not use "host_lock', driver has fine-grain locks now to protect all |
604 | data structures. | 604 | data structures. |
605 | 605 | ||
606 | viii. Optimize the build scatter-gather list routine. The callers already | 606 | viii. Optimize the build scatter-gather list routine. The callers already |
607 | know the data transfer address and length. | 607 | know the data transfer address and length. |
608 | 608 | ||
609 | ix. Better implementation of error handling and recovery. Driver now | 609 | ix. Better implementation of error handling and recovery. Driver now |
610 | performs extended errors recovery for instances like scsi cable pull. | 610 | performs extended errors recovery for instances like scsi cable pull. |
611 | 611 | ||
612 | x. Disassociate the management commands with an overlaid scsi command. | 612 | x. Disassociate the management commands with an overlaid scsi command. |
613 | Driver now treats the management packets as special packets and has a | 613 | Driver now treats the management packets as special packets and has a |
614 | dedicated callback routine. | 614 | dedicated callback routine. |
615 | 615 |
Documentation/sound/alsa/HD-Audio-Models.txt
1 | Model name Description | 1 | Model name Description |
2 | ---------- ----------- | 2 | ---------- ----------- |
3 | ALC880 | 3 | ALC880 |
4 | ====== | 4 | ====== |
5 | 3stack 3-jack in back and a headphone out | 5 | 3stack 3-jack in back and a headphone out |
6 | 3stack-digout 3-jack in back, a HP out and a SPDIF out | 6 | 3stack-digout 3-jack in back, a HP out and a SPDIF out |
7 | 5stack 5-jack in back, 2-jack in front | 7 | 5stack 5-jack in back, 2-jack in front |
8 | 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out | 8 | 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out |
9 | 6stack 6-jack in back, 2-jack in front | 9 | 6stack 6-jack in back, 2-jack in front |
10 | 6stack-digout 6-jack with a SPDIF out | 10 | 6stack-digout 6-jack with a SPDIF out |
11 | w810 3-jack | 11 | w810 3-jack |
12 | z71v 3-jack (HP shared SPDIF) | 12 | z71v 3-jack (HP shared SPDIF) |
13 | asus 3-jack (ASUS Mobo) | 13 | asus 3-jack (ASUS Mobo) |
14 | asus-w1v ASUS W1V | 14 | asus-w1v ASUS W1V |
15 | asus-dig ASUS with SPDIF out | 15 | asus-dig ASUS with SPDIF out |
16 | asus-dig2 ASUS with SPDIF out (using GPIO2) | 16 | asus-dig2 ASUS with SPDIF out (using GPIO2) |
17 | uniwill 3-jack | 17 | uniwill 3-jack |
18 | fujitsu Fujitsu Laptops (Pi1536) | 18 | fujitsu Fujitsu Laptops (Pi1536) |
19 | F1734 2-jack | 19 | F1734 2-jack |
20 | lg LG laptop (m1 express dual) | 20 | lg LG laptop (m1 express dual) |
21 | lg-lw LG LW20/LW25 laptop | 21 | lg-lw LG LW20/LW25 laptop |
22 | tcl TCL S700 | 22 | tcl TCL S700 |
23 | clevo Clevo laptops (m520G, m665n) | 23 | clevo Clevo laptops (m520G, m665n) |
24 | medion Medion Rim 2150 | 24 | medion Medion Rim 2150 |
25 | test for testing/debugging purpose, almost all controls can be | 25 | test for testing/debugging purpose, almost all controls can be |
26 | adjusted. Appearing only when compiled with | 26 | adjusted. Appearing only when compiled with |
27 | $CONFIG_SND_DEBUG=y | 27 | $CONFIG_SND_DEBUG=y |
28 | auto auto-config reading BIOS (default) | 28 | auto auto-config reading BIOS (default) |
29 | 29 | ||
30 | ALC260 | 30 | ALC260 |
31 | ====== | 31 | ====== |
32 | hp HP machines | 32 | hp HP machines |
33 | hp-3013 HP machines (3013-variant) | 33 | hp-3013 HP machines (3013-variant) |
34 | hp-dc7600 HP DC7600 | 34 | hp-dc7600 HP DC7600 |
35 | fujitsu Fujitsu S7020 | 35 | fujitsu Fujitsu S7020 |
36 | acer Acer TravelMate | 36 | acer Acer TravelMate |
37 | will Will laptops (PB V7900) | 37 | will Will laptops (PB V7900) |
38 | replacer Replacer 672V | 38 | replacer Replacer 672V |
39 | favorit100 Maxdata Favorit 100XS | 39 | favorit100 Maxdata Favorit 100XS |
40 | basic fixed pin assignment (old default model) | 40 | basic fixed pin assignment (old default model) |
41 | test for testing/debugging purpose, almost all controls can | 41 | test for testing/debugging purpose, almost all controls can |
42 | adjusted. Appearing only when compiled with | 42 | adjusted. Appearing only when compiled with |
43 | $CONFIG_SND_DEBUG=y | 43 | $CONFIG_SND_DEBUG=y |
44 | auto auto-config reading BIOS (default) | 44 | auto auto-config reading BIOS (default) |
45 | 45 | ||
46 | ALC262 | 46 | ALC262 |
47 | ====== | 47 | ====== |
48 | fujitsu Fujitsu Laptop | 48 | fujitsu Fujitsu Laptop |
49 | hp-bpc HP xw4400/6400/8400/9400 laptops | 49 | hp-bpc HP xw4400/6400/8400/9400 laptops |
50 | hp-bpc-d7000 HP BPC D7000 | 50 | hp-bpc-d7000 HP BPC D7000 |
51 | hp-tc-t5735 HP Thin Client T5735 | 51 | hp-tc-t5735 HP Thin Client T5735 |
52 | hp-rp5700 HP RP5700 | 52 | hp-rp5700 HP RP5700 |
53 | benq Benq ED8 | 53 | benq Benq ED8 |
54 | benq-t31 Benq T31 | 54 | benq-t31 Benq T31 |
55 | hippo Hippo (ATI) with jack detection, Sony UX-90s | 55 | hippo Hippo (ATI) with jack detection, Sony UX-90s |
56 | hippo_1 Hippo (Benq) with jack detection | 56 | hippo_1 Hippo (Benq) with jack detection |
57 | sony-assamd Sony ASSAMD | 57 | sony-assamd Sony ASSAMD |
58 | toshiba-s06 Toshiba S06 | 58 | toshiba-s06 Toshiba S06 |
59 | toshiba-rx1 Toshiba RX1 | 59 | toshiba-rx1 Toshiba RX1 |
60 | tyan Tyan Thunder n6650W (S2915-E) | 60 | tyan Tyan Thunder n6650W (S2915-E) |
61 | ultra Samsung Q1 Ultra Vista model | 61 | ultra Samsung Q1 Ultra Vista model |
62 | lenovo-3000 Lenovo 3000 y410 | 62 | lenovo-3000 Lenovo 3000 y410 |
63 | nec NEC Versa S9100 | 63 | nec NEC Versa S9100 |
64 | basic fixed pin assignment w/o SPDIF | 64 | basic fixed pin assignment w/o SPDIF |
65 | auto auto-config reading BIOS (default) | 65 | auto auto-config reading BIOS (default) |
66 | 66 | ||
67 | ALC267/268 | 67 | ALC267/268 |
68 | ========== | 68 | ========== |
69 | quanta-il1 Quanta IL1 mini-notebook | 69 | quanta-il1 Quanta IL1 mini-notebook |
70 | 3stack 3-stack model | 70 | 3stack 3-stack model |
71 | toshiba Toshiba A205 | 71 | toshiba Toshiba A205 |
72 | acer Acer laptops | 72 | acer Acer laptops |
73 | acer-dmic Acer laptops with digital-mic | 73 | acer-dmic Acer laptops with digital-mic |
74 | acer-aspire Acer Aspire One | 74 | acer-aspire Acer Aspire One |
75 | dell Dell OEM laptops (Vostro 1200) | 75 | dell Dell OEM laptops (Vostro 1200) |
76 | zepto Zepto laptops | 76 | zepto Zepto laptops |
77 | test for testing/debugging purpose, almost all controls can | 77 | test for testing/debugging purpose, almost all controls can |
78 | adjusted. Appearing only when compiled with | 78 | adjusted. Appearing only when compiled with |
79 | $CONFIG_SND_DEBUG=y | 79 | $CONFIG_SND_DEBUG=y |
80 | auto auto-config reading BIOS (default) | 80 | auto auto-config reading BIOS (default) |
81 | 81 | ||
82 | ALC269 | 82 | ALC269 |
83 | ====== | 83 | ====== |
84 | basic Basic preset | 84 | basic Basic preset |
85 | quanta Quanta FL1 | 85 | quanta Quanta FL1 |
86 | eeepc-p703 ASUS Eeepc P703 P900A | 86 | eeepc-p703 ASUS Eeepc P703 P900A |
87 | eeepc-p901 ASUS Eeepc P901 S101 | 87 | eeepc-p901 ASUS Eeepc P901 S101 |
88 | fujitsu FSC Amilo | 88 | fujitsu FSC Amilo |
89 | lifebook Fujitsu Lifebook S6420 | 89 | lifebook Fujitsu Lifebook S6420 |
90 | auto auto-config reading BIOS (default) | 90 | auto auto-config reading BIOS (default) |
91 | 91 | ||
92 | ALC662/663/272 | 92 | ALC662/663/272 |
93 | ============== | 93 | ============== |
94 | 3stack-dig 3-stack (2-channel) with SPDIF | 94 | 3stack-dig 3-stack (2-channel) with SPDIF |
95 | 3stack-6ch 3-stack (6-channel) | 95 | 3stack-6ch 3-stack (6-channel) |
96 | 3stack-6ch-dig 3-stack (6-channel) with SPDIF | 96 | 3stack-6ch-dig 3-stack (6-channel) with SPDIF |
97 | 6stack-dig 6-stack with SPDIF | 97 | 6stack-dig 6-stack with SPDIF |
98 | lenovo-101e Lenovo laptop | 98 | lenovo-101e Lenovo laptop |
99 | eeepc-p701 ASUS Eeepc P701 | 99 | eeepc-p701 ASUS Eeepc P701 |
100 | eeepc-ep20 ASUS Eeepc EP20 | 100 | eeepc-ep20 ASUS Eeepc EP20 |
101 | ecs ECS/Foxconn mobo | 101 | ecs ECS/Foxconn mobo |
102 | m51va ASUS M51VA | 102 | m51va ASUS M51VA |
103 | g71v ASUS G71V | 103 | g71v ASUS G71V |
104 | h13 ASUS H13 | 104 | h13 ASUS H13 |
105 | g50v ASUS G50V | 105 | g50v ASUS G50V |
106 | asus-mode1 ASUS | 106 | asus-mode1 ASUS |
107 | asus-mode2 ASUS | 107 | asus-mode2 ASUS |
108 | asus-mode3 ASUS | 108 | asus-mode3 ASUS |
109 | asus-mode4 ASUS | 109 | asus-mode4 ASUS |
110 | asus-mode5 ASUS | 110 | asus-mode5 ASUS |
111 | asus-mode6 ASUS | 111 | asus-mode6 ASUS |
112 | dell Dell with ALC272 | 112 | dell Dell with ALC272 |
113 | dell-zm1 Dell ZM1 with ALC272 | 113 | dell-zm1 Dell ZM1 with ALC272 |
114 | samsung-nc10 Samsung NC10 mini notebook | 114 | samsung-nc10 Samsung NC10 mini notebook |
115 | auto auto-config reading BIOS (default) | 115 | auto auto-config reading BIOS (default) |
116 | 116 | ||
117 | ALC882/883/885/888/889 | 117 | ALC882/883/885/888/889 |
118 | ====================== | 118 | ====================== |
119 | 3stack-dig 3-jack with SPDIF I/O | 119 | 3stack-dig 3-jack with SPDIF I/O |
120 | 6stack-dig 6-jack digital with SPDIF I/O | 120 | 6stack-dig 6-jack digital with SPDIF I/O |
121 | arima Arima W820Di1 | 121 | arima Arima W820Di1 |
122 | targa Targa T8, MSI-1049 T8 | 122 | targa Targa T8, MSI-1049 T8 |
123 | asus-a7j ASUS A7J | 123 | asus-a7j ASUS A7J |
124 | asus-a7m ASUS A7M | 124 | asus-a7m ASUS A7M |
125 | macpro MacPro support | 125 | macpro MacPro support |
126 | mb5 Macbook 5,1 | 126 | mb5 Macbook 5,1 |
127 | mbp3 Macbook Pro rev3 | 127 | mbp3 Macbook Pro rev3 |
128 | imac24 iMac 24'' with jack detection | 128 | imac24 iMac 24'' with jack detection |
129 | w2jc ASUS W2JC | 129 | w2jc ASUS W2JC |
130 | 3stack-2ch-dig 3-jack with SPDIF I/O (ALC883) | 130 | 3stack-2ch-dig 3-jack with SPDIF I/O (ALC883) |
131 | alc883-6stack-dig 6-jack digital with SPDIF I/O (ALC883) | 131 | alc883-6stack-dig 6-jack digital with SPDIF I/O (ALC883) |
132 | 3stack-6ch 3-jack 6-channel | 132 | 3stack-6ch 3-jack 6-channel |
133 | 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O | 133 | 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O |
134 | 6stack-dig-demo 6-jack digital for Intel demo board | 134 | 6stack-dig-demo 6-jack digital for Intel demo board |
135 | acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) | 135 | acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) |
136 | acer-aspire Acer Aspire 9810 | 136 | acer-aspire Acer Aspire 9810 |
137 | acer-aspire-4930g Acer Aspire 4930G | 137 | acer-aspire-4930g Acer Aspire 4930G |
138 | acer-aspire-6530g Acer Aspire 6530G | 138 | acer-aspire-6530g Acer Aspire 6530G |
139 | acer-aspire-7730g Acer Aspire 7730G | 139 | acer-aspire-7730g Acer Aspire 7730G |
140 | acer-aspire-8930g Acer Aspire 8930G | 140 | acer-aspire-8930g Acer Aspire 8930G |
141 | medion Medion Laptops | 141 | medion Medion Laptops |
142 | medion-md2 Medion MD2 | 142 | medion-md2 Medion MD2 |
143 | targa-dig Targa/MSI | 143 | targa-dig Targa/MSI |
144 | targa-2ch-dig Targa/MSI with 2-channel | 144 | targa-2ch-dig Targa/MSI with 2-channel |
145 | targa-8ch-dig Targa/MSI with 8-channel (MSI GX620) | 145 | targa-8ch-dig Targa/MSI with 8-channel (MSI GX620) |
146 | laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE) | 146 | laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE) |
147 | lenovo-101e Lenovo 101E | 147 | lenovo-101e Lenovo 101E |
148 | lenovo-nb0763 Lenovo NB0763 | 148 | lenovo-nb0763 Lenovo NB0763 |
149 | lenovo-ms7195-dig Lenovo MS7195 | 149 | lenovo-ms7195-dig Lenovo MS7195 |
150 | lenovo-sky Lenovo Sky | 150 | lenovo-sky Lenovo Sky |
151 | haier-w66 Haier W66 | 151 | haier-w66 Haier W66 |
152 | 3stack-hp HP machines with 3stack (Lucknow, Samba boards) | 152 | 3stack-hp HP machines with 3stack (Lucknow, Samba boards) |
153 | 6stack-dell Dell machines with 6stack (Inspiron 530) | 153 | 6stack-dell Dell machines with 6stack (Inspiron 530) |
154 | mitac Mitac 8252D | 154 | mitac Mitac 8252D |
155 | clevo-m540r Clevo M540R (6ch + digital) | 155 | clevo-m540r Clevo M540R (6ch + digital) |
156 | clevo-m720 Clevo M720 laptop series | 156 | clevo-m720 Clevo M720 laptop series |
157 | fujitsu-pi2515 Fujitsu AMILO Pi2515 | 157 | fujitsu-pi2515 Fujitsu AMILO Pi2515 |
158 | fujitsu-xa3530 Fujitsu AMILO XA3530 | 158 | fujitsu-xa3530 Fujitsu AMILO XA3530 |
159 | 3stack-6ch-intel Intel DG33* boards | 159 | 3stack-6ch-intel Intel DG33* boards |
160 | intel-alc889a Intel IbexPeak with ALC889A | 160 | intel-alc889a Intel IbexPeak with ALC889A |
161 | intel-x58 Intel DX58 with ALC889 | 161 | intel-x58 Intel DX58 with ALC889 |
162 | asus-p5q ASUS P5Q-EM boards | 162 | asus-p5q ASUS P5Q-EM boards |
163 | mb31 MacBook 3,1 | 163 | mb31 MacBook 3,1 |
164 | sony-vaio-tt Sony VAIO TT | 164 | sony-vaio-tt Sony VAIO TT |
165 | auto auto-config reading BIOS (default) | 165 | auto auto-config reading BIOS (default) |
166 | 166 | ||
167 | ALC861/660 | 167 | ALC861/660 |
168 | ========== | 168 | ========== |
169 | 3stack 3-jack | 169 | 3stack 3-jack |
170 | 3stack-dig 3-jack with SPDIF I/O | 170 | 3stack-dig 3-jack with SPDIF I/O |
171 | 6stack-dig 6-jack with SPDIF I/O | 171 | 6stack-dig 6-jack with SPDIF I/O |
172 | 3stack-660 3-jack (for ALC660) | 172 | 3stack-660 3-jack (for ALC660) |
173 | uniwill-m31 Uniwill M31 laptop | 173 | uniwill-m31 Uniwill M31 laptop |
174 | toshiba Toshiba laptop support | 174 | toshiba Toshiba laptop support |
175 | asus Asus laptop support | 175 | asus Asus laptop support |
176 | asus-laptop ASUS F2/F3 laptops | 176 | asus-laptop ASUS F2/F3 laptops |
177 | auto auto-config reading BIOS (default) | 177 | auto auto-config reading BIOS (default) |
178 | 178 | ||
179 | ALC861VD/660VD | 179 | ALC861VD/660VD |
180 | ============== | 180 | ============== |
181 | 3stack 3-jack | 181 | 3stack 3-jack |
182 | 3stack-dig 3-jack with SPDIF OUT | 182 | 3stack-dig 3-jack with SPDIF OUT |
183 | 6stack-dig 6-jack with SPDIF OUT | 183 | 6stack-dig 6-jack with SPDIF OUT |
184 | 3stack-660 3-jack (for ALC660VD) | 184 | 3stack-660 3-jack (for ALC660VD) |
185 | 3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD) | 185 | 3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD) |
186 | lenovo Lenovo 3000 C200 | 186 | lenovo Lenovo 3000 C200 |
187 | dallas Dallas laptops | 187 | dallas Dallas laptops |
188 | hp HP TX1000 | 188 | hp HP TX1000 |
189 | asus-v1s ASUS V1Sn | 189 | asus-v1s ASUS V1Sn |
190 | auto auto-config reading BIOS (default) | 190 | auto auto-config reading BIOS (default) |
191 | 191 | ||
192 | CMI9880 | 192 | CMI9880 |
193 | ======= | 193 | ======= |
194 | minimal 3-jack in back | 194 | minimal 3-jack in back |
195 | min_fp 3-jack in back, 2-jack in front | 195 | min_fp 3-jack in back, 2-jack in front |
196 | full 6-jack in back, 2-jack in front | 196 | full 6-jack in back, 2-jack in front |
197 | full_dig 6-jack in back, 2-jack in front, SPDIF I/O | 197 | full_dig 6-jack in back, 2-jack in front, SPDIF I/O |
198 | allout 5-jack in back, 2-jack in front, SPDIF out | 198 | allout 5-jack in back, 2-jack in front, SPDIF out |
199 | auto auto-config reading BIOS (default) | 199 | auto auto-config reading BIOS (default) |
200 | 200 | ||
201 | AD1882 / AD1882A | 201 | AD1882 / AD1882A |
202 | ================ | 202 | ================ |
203 | 3stack 3-stack mode (default) | 203 | 3stack 3-stack mode (default) |
204 | 6stack 6-stack mode | 204 | 6stack 6-stack mode |
205 | 205 | ||
206 | AD1884A / AD1883 / AD1984A / AD1984B | 206 | AD1884A / AD1883 / AD1984A / AD1984B |
207 | ==================================== | 207 | ==================================== |
208 | desktop 3-stack desktop (default) | 208 | desktop 3-stack desktop (default) |
209 | laptop laptop with HP jack sensing | 209 | laptop laptop with HP jack sensing |
210 | mobile mobile devices with HP jack sensing | 210 | mobile mobile devices with HP jack sensing |
211 | thinkpad Lenovo Thinkpad X300 | 211 | thinkpad Lenovo Thinkpad X300 |
212 | 212 | ||
213 | AD1884 | 213 | AD1884 |
214 | ====== | 214 | ====== |
215 | N/A | 215 | N/A |
216 | 216 | ||
217 | AD1981 | 217 | AD1981 |
218 | ====== | 218 | ====== |
219 | basic 3-jack (default) | 219 | basic 3-jack (default) |
220 | hp HP nx6320 | 220 | hp HP nx6320 |
221 | thinkpad Lenovo Thinkpad T60/X60/Z60 | 221 | thinkpad Lenovo Thinkpad T60/X60/Z60 |
222 | toshiba Toshiba U205 | 222 | toshiba Toshiba U205 |
223 | 223 | ||
224 | AD1983 | 224 | AD1983 |
225 | ====== | 225 | ====== |
226 | N/A | 226 | N/A |
227 | 227 | ||
228 | AD1984 | 228 | AD1984 |
229 | ====== | 229 | ====== |
230 | basic default configuration | 230 | basic default configuration |
231 | thinkpad Lenovo Thinkpad T61/X61 | 231 | thinkpad Lenovo Thinkpad T61/X61 |
232 | dell_desktop Dell T3400 | 232 | dell_desktop Dell T3400 |
233 | 233 | ||
234 | AD1986A | 234 | AD1986A |
235 | ======= | 235 | ======= |
236 | 6stack 6-jack, separate surrounds (default) | 236 | 6stack 6-jack, separate surrounds (default) |
237 | 3stack 3-stack, shared surrounds | 237 | 3stack 3-stack, shared surrounds |
238 | laptop 2-channel only (FSC V2060, Samsung M50) | 238 | laptop 2-channel only (FSC V2060, Samsung M50) |
239 | laptop-eapd 2-channel with EAPD (ASUS A6J) | 239 | laptop-eapd 2-channel with EAPD (ASUS A6J) |
240 | laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100) | 240 | laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100) |
241 | ultra 2-channel with EAPD (Samsung Ultra tablet PC) | 241 | ultra 2-channel with EAPD (Samsung Ultra tablet PC) |
242 | samsung 2-channel with EAPD (Samsung R65) | 242 | samsung 2-channel with EAPD (Samsung R65) |
243 | samsung-p50 2-channel with HP-automute (Samsung P50) | 243 | samsung-p50 2-channel with HP-automute (Samsung P50) |
244 | 244 | ||
245 | AD1988/AD1988B/AD1989A/AD1989B | 245 | AD1988/AD1988B/AD1989A/AD1989B |
246 | ============================== | 246 | ============================== |
247 | 6stack 6-jack | 247 | 6stack 6-jack |
248 | 6stack-dig ditto with SPDIF | 248 | 6stack-dig ditto with SPDIF |
249 | 3stack 3-jack | 249 | 3stack 3-jack |
250 | 3stack-dig ditto with SPDIF | 250 | 3stack-dig ditto with SPDIF |
251 | laptop 3-jack with hp-jack automute | 251 | laptop 3-jack with hp-jack automute |
252 | laptop-dig ditto with SPDIF | 252 | laptop-dig ditto with SPDIF |
253 | auto auto-config reading BIOS (default) | 253 | auto auto-config reading BIOS (default) |
254 | 254 | ||
255 | Conexant 5045 | 255 | Conexant 5045 |
256 | ============= | 256 | ============= |
257 | laptop-hpsense Laptop with HP sense (old model laptop) | 257 | laptop-hpsense Laptop with HP sense (old model laptop) |
258 | laptop-micsense Laptop with Mic sense (old model fujitsu) | 258 | laptop-micsense Laptop with Mic sense (old model fujitsu) |
259 | laptop-hpmicsense Laptop with HP and Mic senses | 259 | laptop-hpmicsense Laptop with HP and Mic senses |
260 | benq Benq R55E | 260 | benq Benq R55E |
261 | laptop-hp530 HP 530 laptop | 261 | laptop-hp530 HP 530 laptop |
262 | test for testing/debugging purpose, almost all controls | 262 | test for testing/debugging purpose, almost all controls |
263 | can be adjusted. Appearing only when compiled with | 263 | can be adjusted. Appearing only when compiled with |
264 | $CONFIG_SND_DEBUG=y | 264 | $CONFIG_SND_DEBUG=y |
265 | 265 | ||
266 | Conexant 5047 | 266 | Conexant 5047 |
267 | ============= | 267 | ============= |
268 | laptop Basic Laptop config | 268 | laptop Basic Laptop config |
269 | laptop-hp Laptop config for some HP models (subdevice 30A5) | 269 | laptop-hp Laptop config for some HP models (subdevice 30A5) |
270 | laptop-eapd Laptop config with EAPD support | 270 | laptop-eapd Laptop config with EAPD support |
271 | test for testing/debugging purpose, almost all controls | 271 | test for testing/debugging purpose, almost all controls |
272 | can be adjusted. Appearing only when compiled with | 272 | can be adjusted. Appearing only when compiled with |
273 | $CONFIG_SND_DEBUG=y | 273 | $CONFIG_SND_DEBUG=y |
274 | 274 | ||
275 | Conexant 5051 | 275 | Conexant 5051 |
276 | ============= | 276 | ============= |
277 | laptop Basic Laptop config (default) | 277 | laptop Basic Laptop config (default) |
278 | hp HP Spartan laptop | 278 | hp HP Spartan laptop |
279 | hp-dv6736 HP dv6736 | 279 | hp-dv6736 HP dv6736 |
280 | lenovo-x200 Lenovo X200 laptop | 280 | lenovo-x200 Lenovo X200 laptop |
281 | 281 | ||
282 | Conexant 5066 | 282 | Conexant 5066 |
283 | ============= | 283 | ============= |
284 | laptop Basic Laptop config (default) | 284 | laptop Basic Laptop config (default) |
285 | dell-laptop Dell laptops | 285 | dell-laptop Dell laptops |
286 | olpc-xo-1_5 OLPC XO 1.5 | 286 | olpc-xo-1_5 OLPC XO 1.5 |
287 | 287 | ||
288 | STAC9200 | 288 | STAC9200 |
289 | ======== | 289 | ======== |
290 | ref Reference board | 290 | ref Reference board |
291 | oqo OQO Model 2 | 291 | oqo OQO Model 2 |
292 | dell-d21 Dell (unknown) | 292 | dell-d21 Dell (unknown) |
293 | dell-d22 Dell (unknown) | 293 | dell-d22 Dell (unknown) |
294 | dell-d23 Dell (unknown) | 294 | dell-d23 Dell (unknown) |
295 | dell-m21 Dell Inspiron 630m, Dell Inspiron 640m | 295 | dell-m21 Dell Inspiron 630m, Dell Inspiron 640m |
296 | dell-m22 Dell Latitude D620, Dell Latitude D820 | 296 | dell-m22 Dell Latitude D620, Dell Latitude D820 |
297 | dell-m23 Dell XPS M1710, Dell Precision M90 | 297 | dell-m23 Dell XPS M1710, Dell Precision M90 |
298 | dell-m24 Dell Latitude 120L | 298 | dell-m24 Dell Latitude 120L |
299 | dell-m25 Dell Inspiron E1505n | 299 | dell-m25 Dell Inspiron E1505n |
300 | dell-m26 Dell Inspiron 1501 | 300 | dell-m26 Dell Inspiron 1501 |
301 | dell-m27 Dell Inspiron E1705/9400 | 301 | dell-m27 Dell Inspiron E1705/9400 |
302 | gateway-m4 Gateway laptops with EAPD control | 302 | gateway-m4 Gateway laptops with EAPD control |
303 | gateway-m4-2 Gateway laptops with EAPD control | 303 | gateway-m4-2 Gateway laptops with EAPD control |
304 | panasonic Panasonic CF-74 | 304 | panasonic Panasonic CF-74 |
305 | auto BIOS setup (default) | 305 | auto BIOS setup (default) |
306 | 306 | ||
307 | STAC9205/9254 | 307 | STAC9205/9254 |
308 | ============= | 308 | ============= |
309 | ref Reference board | 309 | ref Reference board |
310 | dell-m42 Dell (unknown) | 310 | dell-m42 Dell (unknown) |
311 | dell-m43 Dell Precision | 311 | dell-m43 Dell Precision |
312 | dell-m44 Dell Inspiron | 312 | dell-m44 Dell Inspiron |
313 | eapd Keep EAPD on (e.g. Gateway T1616) | 313 | eapd Keep EAPD on (e.g. Gateway T1616) |
314 | auto BIOS setup (default) | 314 | auto BIOS setup (default) |
315 | 315 | ||
316 | STAC9220/9221 | 316 | STAC9220/9221 |
317 | ============= | 317 | ============= |
318 | ref Reference board | 318 | ref Reference board |
319 | 3stack D945 3stack | 319 | 3stack D945 3stack |
320 | 5stack D945 5stack + SPDIF | 320 | 5stack D945 5stack + SPDIF |
321 | intel-mac-v1 Intel Mac Type 1 | 321 | intel-mac-v1 Intel Mac Type 1 |
322 | intel-mac-v2 Intel Mac Type 2 | 322 | intel-mac-v2 Intel Mac Type 2 |
323 | intel-mac-v3 Intel Mac Type 3 | 323 | intel-mac-v3 Intel Mac Type 3 |
324 | intel-mac-v4 Intel Mac Type 4 | 324 | intel-mac-v4 Intel Mac Type 4 |
325 | intel-mac-v5 Intel Mac Type 5 | 325 | intel-mac-v5 Intel Mac Type 5 |
326 | intel-mac-auto Intel Mac (detect type according to subsystem id) | 326 | intel-mac-auto Intel Mac (detect type according to subsystem id) |
327 | macmini Intel Mac Mini (equivalent with type 3) | 327 | macmini Intel Mac Mini (equivalent with type 3) |
328 | macbook Intel Mac Book (eq. type 5) | 328 | macbook Intel Mac Book (eq. type 5) |
329 | macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3) | 329 | macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3) |
330 | macbook-pro Intel Mac Book Pro 2nd generation (eq. type 3) | 330 | macbook-pro Intel Mac Book Pro 2nd generation (eq. type 3) |
331 | imac-intel Intel iMac (eq. type 2) | 331 | imac-intel Intel iMac (eq. type 2) |
332 | imac-intel-20 Intel iMac (newer version) (eq. type 3) | 332 | imac-intel-20 Intel iMac (newer version) (eq. type 3) |
333 | ecs202 ECS/PC chips | 333 | ecs202 ECS/PC chips |
334 | dell-d81 Dell (unknown) | 334 | dell-d81 Dell (unknown) |
335 | dell-d82 Dell (unknown) | 335 | dell-d82 Dell (unknown) |
336 | dell-m81 Dell (unknown) | 336 | dell-m81 Dell (unknown) |
337 | dell-m82 Dell XPS M1210 | 337 | dell-m82 Dell XPS M1210 |
338 | auto BIOS setup (default) | 338 | auto BIOS setup (default) |
339 | 339 | ||
340 | STAC9202/9250/9251 | 340 | STAC9202/9250/9251 |
341 | ================== | 341 | ================== |
342 | ref Reference board, base config | 342 | ref Reference board, base config |
343 | m1 Some Gateway MX series laptops (NX560XL) | 343 | m1 Some Gateway MX series laptops (NX560XL) |
344 | m1-2 Some Gateway MX series laptops (MX6453) | 344 | m1-2 Some Gateway MX series laptops (MX6453) |
345 | m2 Some Gateway MX series laptops (M255) | 345 | m2 Some Gateway MX series laptops (M255) |
346 | m2-2 Some Gateway MX series laptops | 346 | m2-2 Some Gateway MX series laptops |
347 | m3 Some Gateway MX series laptops | 347 | m3 Some Gateway MX series laptops |
348 | m5 Some Gateway MX series laptops (MP6954) | 348 | m5 Some Gateway MX series laptops (MP6954) |
349 | m6 Some Gateway NX series laptops | 349 | m6 Some Gateway NX series laptops |
350 | auto BIOS setup (default) | 350 | auto BIOS setup (default) |
351 | 351 | ||
352 | STAC9227/9228/9229/927x | 352 | STAC9227/9228/9229/927x |
353 | ======================= | 353 | ======================= |
354 | ref Reference board | 354 | ref Reference board |
355 | ref-no-jd Reference board without HP/Mic jack detection | 355 | ref-no-jd Reference board without HP/Mic jack detection |
356 | 3stack D965 3stack | 356 | 3stack D965 3stack |
357 | 5stack D965 5stack + SPDIF | 357 | 5stack D965 5stack + SPDIF |
358 | 5stack-no-fp D965 5stack without front panel | 358 | 5stack-no-fp D965 5stack without front panel |
359 | dell-3stack Dell Dimension E520 | 359 | dell-3stack Dell Dimension E520 |
360 | dell-bios Fixes with Dell BIOS setup | 360 | dell-bios Fixes with Dell BIOS setup |
361 | auto BIOS setup (default) | 361 | auto BIOS setup (default) |
362 | 362 | ||
363 | STAC92HD71B* | 363 | STAC92HD71B* |
364 | ============ | 364 | ============ |
365 | ref Reference board | 365 | ref Reference board |
366 | dell-m4-1 Dell desktops | 366 | dell-m4-1 Dell desktops |
367 | dell-m4-2 Dell desktops | 367 | dell-m4-2 Dell desktops |
368 | dell-m4-3 Dell desktops | 368 | dell-m4-3 Dell desktops |
369 | hp-m4 HP mini 1000 | 369 | hp-m4 HP mini 1000 |
370 | hp-dv5 HP dv series | 370 | hp-dv5 HP dv series |
371 | hp-hdx HP HDX series | 371 | hp-hdx HP HDX series |
372 | hp-dv4-1222nr HP dv4-1222nr (with LED support) | 372 | hp-dv4-1222nr HP dv4-1222nr (with LED support) |
373 | auto BIOS setup (default) | 373 | auto BIOS setup (default) |
374 | 374 | ||
375 | STAC92HD73* | 375 | STAC92HD73* |
376 | =========== | 376 | =========== |
377 | ref Reference board | 377 | ref Reference board |
378 | no-jd BIOS setup but without jack-detection | 378 | no-jd BIOS setup but without jack-detection |
379 | intel Intel DG45* mobos | 379 | intel Intel DG45* mobos |
380 | dell-m6-amic Dell desktops/laptops with analog mics | 380 | dell-m6-amic Dell desktops/laptops with analog mics |
381 | dell-m6-dmic Dell desktops/laptops with digital mics | 381 | dell-m6-dmic Dell desktops/laptops with digital mics |
382 | dell-m6 Dell desktops/laptops with both type of mics | 382 | dell-m6 Dell desktops/laptops with both type of mics |
383 | dell-eq Dell desktops/laptops | 383 | dell-eq Dell desktops/laptops |
384 | alienware Alienware M17x | 384 | alienware Alienware M17x |
385 | auto BIOS setup (default) | 385 | auto BIOS setup (default) |
386 | 386 | ||
387 | STAC92HD83* | 387 | STAC92HD83* |
388 | =========== | 388 | =========== |
389 | ref Reference board | 389 | ref Reference board |
390 | mic-ref Reference board with power managment for ports | 390 | mic-ref Reference board with power management for ports |
391 | dell-s14 Dell laptop | 391 | dell-s14 Dell laptop |
392 | auto BIOS setup (default) | 392 | auto BIOS setup (default) |
393 | 393 | ||
394 | STAC9872 | 394 | STAC9872 |
395 | ======== | 395 | ======== |
396 | vaio VAIO laptop without SPDIF | 396 | vaio VAIO laptop without SPDIF |
397 | auto BIOS setup (default) | 397 | auto BIOS setup (default) |
398 | 398 | ||
399 | Cirrus Logic CS4206/4207 | 399 | Cirrus Logic CS4206/4207 |
400 | ======================== | 400 | ======================== |
401 | mbp55 MacBook Pro 5,5 | 401 | mbp55 MacBook Pro 5,5 |
402 | auto BIOS setup (default) | 402 | auto BIOS setup (default) |
403 | 403 |
Documentation/trace/ftrace.txt
1 | ftrace - Function Tracer | 1 | ftrace - Function Tracer |
2 | ======================== | 2 | ======================== |
3 | 3 | ||
4 | Copyright 2008 Red Hat Inc. | 4 | Copyright 2008 Red Hat Inc. |
5 | Author: Steven Rostedt <srostedt@redhat.com> | 5 | Author: Steven Rostedt <srostedt@redhat.com> |
6 | License: The GNU Free Documentation License, Version 1.2 | 6 | License: The GNU Free Documentation License, Version 1.2 |
7 | (dual licensed under the GPL v2) | 7 | (dual licensed under the GPL v2) |
8 | Reviewers: Elias Oltmanns, Randy Dunlap, Andrew Morton, | 8 | Reviewers: Elias Oltmanns, Randy Dunlap, Andrew Morton, |
9 | John Kacur, and David Teigland. | 9 | John Kacur, and David Teigland. |
10 | Written for: 2.6.28-rc2 | 10 | Written for: 2.6.28-rc2 |
11 | 11 | ||
12 | Introduction | 12 | Introduction |
13 | ------------ | 13 | ------------ |
14 | 14 | ||
15 | Ftrace is an internal tracer designed to help out developers and | 15 | Ftrace is an internal tracer designed to help out developers and |
16 | designers of systems to find what is going on inside the kernel. | 16 | designers of systems to find what is going on inside the kernel. |
17 | It can be used for debugging or analyzing latencies and | 17 | It can be used for debugging or analyzing latencies and |
18 | performance issues that take place outside of user-space. | 18 | performance issues that take place outside of user-space. |
19 | 19 | ||
20 | Although ftrace is the function tracer, it also includes an | 20 | Although ftrace is the function tracer, it also includes an |
21 | infrastructure that allows for other types of tracing. Some of | 21 | infrastructure that allows for other types of tracing. Some of |
22 | the tracers that are currently in ftrace include a tracer to | 22 | the tracers that are currently in ftrace include a tracer to |
23 | trace context switches, the time it takes for a high priority | 23 | trace context switches, the time it takes for a high priority |
24 | task to run after it was woken up, the time interrupts are | 24 | task to run after it was woken up, the time interrupts are |
25 | disabled, and more (ftrace allows for tracer plugins, which | 25 | disabled, and more (ftrace allows for tracer plugins, which |
26 | means that the list of tracers can always grow). | 26 | means that the list of tracers can always grow). |
27 | 27 | ||
28 | 28 | ||
29 | Implementation Details | 29 | Implementation Details |
30 | ---------------------- | 30 | ---------------------- |
31 | 31 | ||
32 | See ftrace-design.txt for details for arch porters and such. | 32 | See ftrace-design.txt for details for arch porters and such. |
33 | 33 | ||
34 | 34 | ||
35 | The File System | 35 | The File System |
36 | --------------- | 36 | --------------- |
37 | 37 | ||
38 | Ftrace uses the debugfs file system to hold the control files as | 38 | Ftrace uses the debugfs file system to hold the control files as |
39 | well as the files to display output. | 39 | well as the files to display output. |
40 | 40 | ||
41 | When debugfs is configured into the kernel (which selecting any ftrace | 41 | When debugfs is configured into the kernel (which selecting any ftrace |
42 | option will do) the directory /sys/kernel/debug will be created. To mount | 42 | option will do) the directory /sys/kernel/debug will be created. To mount |
43 | this directory, you can add to your /etc/fstab file: | 43 | this directory, you can add to your /etc/fstab file: |
44 | 44 | ||
45 | debugfs /sys/kernel/debug debugfs defaults 0 0 | 45 | debugfs /sys/kernel/debug debugfs defaults 0 0 |
46 | 46 | ||
47 | Or you can mount it at run time with: | 47 | Or you can mount it at run time with: |
48 | 48 | ||
49 | mount -t debugfs nodev /sys/kernel/debug | 49 | mount -t debugfs nodev /sys/kernel/debug |
50 | 50 | ||
51 | For quicker access to that directory you may want to make a soft link to | 51 | For quicker access to that directory you may want to make a soft link to |
52 | it: | 52 | it: |
53 | 53 | ||
54 | ln -s /sys/kernel/debug /debug | 54 | ln -s /sys/kernel/debug /debug |
55 | 55 | ||
56 | Any selected ftrace option will also create a directory called tracing | 56 | Any selected ftrace option will also create a directory called tracing |
57 | within the debugfs. The rest of the document will assume that you are in | 57 | within the debugfs. The rest of the document will assume that you are in |
58 | the ftrace directory (cd /sys/kernel/debug/tracing) and will only concentrate | 58 | the ftrace directory (cd /sys/kernel/debug/tracing) and will only concentrate |
59 | on the files within that directory and not distract from the content with | 59 | on the files within that directory and not distract from the content with |
60 | the extended "/sys/kernel/debug/tracing" path name. | 60 | the extended "/sys/kernel/debug/tracing" path name. |
61 | 61 | ||
62 | That's it! (assuming that you have ftrace configured into your kernel) | 62 | That's it! (assuming that you have ftrace configured into your kernel) |
63 | 63 | ||
64 | After mounting the debugfs, you can see a directory called | 64 | After mounting the debugfs, you can see a directory called |
65 | "tracing". This directory contains the control and output files | 65 | "tracing". This directory contains the control and output files |
66 | of ftrace. Here is a list of some of the key files: | 66 | of ftrace. Here is a list of some of the key files: |
67 | 67 | ||
68 | 68 | ||
69 | Note: all time values are in microseconds. | 69 | Note: all time values are in microseconds. |
70 | 70 | ||
71 | current_tracer: | 71 | current_tracer: |
72 | 72 | ||
73 | This is used to set or display the current tracer | 73 | This is used to set or display the current tracer |
74 | that is configured. | 74 | that is configured. |
75 | 75 | ||
76 | available_tracers: | 76 | available_tracers: |
77 | 77 | ||
78 | This holds the different types of tracers that | 78 | This holds the different types of tracers that |
79 | have been compiled into the kernel. The | 79 | have been compiled into the kernel. The |
80 | tracers listed here can be configured by | 80 | tracers listed here can be configured by |
81 | echoing their name into current_tracer. | 81 | echoing their name into current_tracer. |
82 | 82 | ||
83 | tracing_enabled: | 83 | tracing_enabled: |
84 | 84 | ||
85 | This sets or displays whether the current_tracer | 85 | This sets or displays whether the current_tracer |
86 | is activated and tracing or not. Echo 0 into this | 86 | is activated and tracing or not. Echo 0 into this |
87 | file to disable the tracer or 1 to enable it. | 87 | file to disable the tracer or 1 to enable it. |
88 | 88 | ||
89 | trace: | 89 | trace: |
90 | 90 | ||
91 | This file holds the output of the trace in a human | 91 | This file holds the output of the trace in a human |
92 | readable format (described below). | 92 | readable format (described below). |
93 | 93 | ||
94 | trace_pipe: | 94 | trace_pipe: |
95 | 95 | ||
96 | The output is the same as the "trace" file but this | 96 | The output is the same as the "trace" file but this |
97 | file is meant to be streamed with live tracing. | 97 | file is meant to be streamed with live tracing. |
98 | Reads from this file will block until new data is | 98 | Reads from this file will block until new data is |
99 | retrieved. Unlike the "trace" file, this file is a | 99 | retrieved. Unlike the "trace" file, this file is a |
100 | consumer. This means reading from this file causes | 100 | consumer. This means reading from this file causes |
101 | sequential reads to display more current data. Once | 101 | sequential reads to display more current data. Once |
102 | data is read from this file, it is consumed, and | 102 | data is read from this file, it is consumed, and |
103 | will not be read again with a sequential read. The | 103 | will not be read again with a sequential read. The |
104 | "trace" file is static, and if the tracer is not | 104 | "trace" file is static, and if the tracer is not |
105 | adding more data,they will display the same | 105 | adding more data,they will display the same |
106 | information every time they are read. | 106 | information every time they are read. |
107 | 107 | ||
108 | trace_options: | 108 | trace_options: |
109 | 109 | ||
110 | This file lets the user control the amount of data | 110 | This file lets the user control the amount of data |
111 | that is displayed in one of the above output | 111 | that is displayed in one of the above output |
112 | files. | 112 | files. |
113 | 113 | ||
114 | tracing_max_latency: | 114 | tracing_max_latency: |
115 | 115 | ||
116 | Some of the tracers record the max latency. | 116 | Some of the tracers record the max latency. |
117 | For example, the time interrupts are disabled. | 117 | For example, the time interrupts are disabled. |
118 | This time is saved in this file. The max trace | 118 | This time is saved in this file. The max trace |
119 | will also be stored, and displayed by "trace". | 119 | will also be stored, and displayed by "trace". |
120 | A new max trace will only be recorded if the | 120 | A new max trace will only be recorded if the |
121 | latency is greater than the value in this | 121 | latency is greater than the value in this |
122 | file. (in microseconds) | 122 | file. (in microseconds) |
123 | 123 | ||
124 | buffer_size_kb: | 124 | buffer_size_kb: |
125 | 125 | ||
126 | This sets or displays the number of kilobytes each CPU | 126 | This sets or displays the number of kilobytes each CPU |
127 | buffer can hold. The tracer buffers are the same size | 127 | buffer can hold. The tracer buffers are the same size |
128 | for each CPU. The displayed number is the size of the | 128 | for each CPU. The displayed number is the size of the |
129 | CPU buffer and not total size of all buffers. The | 129 | CPU buffer and not total size of all buffers. The |
130 | trace buffers are allocated in pages (blocks of memory | 130 | trace buffers are allocated in pages (blocks of memory |
131 | that the kernel uses for allocation, usually 4 KB in size). | 131 | that the kernel uses for allocation, usually 4 KB in size). |
132 | If the last page allocated has room for more bytes | 132 | If the last page allocated has room for more bytes |
133 | than requested, the rest of the page will be used, | 133 | than requested, the rest of the page will be used, |
134 | making the actual allocation bigger than requested. | 134 | making the actual allocation bigger than requested. |
135 | ( Note, the size may not be a multiple of the page size | 135 | ( Note, the size may not be a multiple of the page size |
136 | due to buffer managment overhead. ) | 136 | due to buffer management overhead. ) |
137 | 137 | ||
138 | This can only be updated when the current_tracer | 138 | This can only be updated when the current_tracer |
139 | is set to "nop". | 139 | is set to "nop". |
140 | 140 | ||
141 | tracing_cpumask: | 141 | tracing_cpumask: |
142 | 142 | ||
143 | This is a mask that lets the user only trace | 143 | This is a mask that lets the user only trace |
144 | on specified CPUS. The format is a hex string | 144 | on specified CPUS. The format is a hex string |
145 | representing the CPUS. | 145 | representing the CPUS. |
146 | 146 | ||
147 | set_ftrace_filter: | 147 | set_ftrace_filter: |
148 | 148 | ||
149 | When dynamic ftrace is configured in (see the | 149 | When dynamic ftrace is configured in (see the |
150 | section below "dynamic ftrace"), the code is dynamically | 150 | section below "dynamic ftrace"), the code is dynamically |
151 | modified (code text rewrite) to disable calling of the | 151 | modified (code text rewrite) to disable calling of the |
152 | function profiler (mcount). This lets tracing be configured | 152 | function profiler (mcount). This lets tracing be configured |
153 | in with practically no overhead in performance. This also | 153 | in with practically no overhead in performance. This also |
154 | has a side effect of enabling or disabling specific functions | 154 | has a side effect of enabling or disabling specific functions |
155 | to be traced. Echoing names of functions into this file | 155 | to be traced. Echoing names of functions into this file |
156 | will limit the trace to only those functions. | 156 | will limit the trace to only those functions. |
157 | 157 | ||
158 | set_ftrace_notrace: | 158 | set_ftrace_notrace: |
159 | 159 | ||
160 | This has an effect opposite to that of | 160 | This has an effect opposite to that of |
161 | set_ftrace_filter. Any function that is added here will not | 161 | set_ftrace_filter. Any function that is added here will not |
162 | be traced. If a function exists in both set_ftrace_filter | 162 | be traced. If a function exists in both set_ftrace_filter |
163 | and set_ftrace_notrace, the function will _not_ be traced. | 163 | and set_ftrace_notrace, the function will _not_ be traced. |
164 | 164 | ||
165 | set_ftrace_pid: | 165 | set_ftrace_pid: |
166 | 166 | ||
167 | Have the function tracer only trace a single thread. | 167 | Have the function tracer only trace a single thread. |
168 | 168 | ||
169 | set_graph_function: | 169 | set_graph_function: |
170 | 170 | ||
171 | Set a "trigger" function where tracing should start | 171 | Set a "trigger" function where tracing should start |
172 | with the function graph tracer (See the section | 172 | with the function graph tracer (See the section |
173 | "dynamic ftrace" for more details). | 173 | "dynamic ftrace" for more details). |
174 | 174 | ||
175 | available_filter_functions: | 175 | available_filter_functions: |
176 | 176 | ||
177 | This lists the functions that ftrace | 177 | This lists the functions that ftrace |
178 | has processed and can trace. These are the function | 178 | has processed and can trace. These are the function |
179 | names that you can pass to "set_ftrace_filter" or | 179 | names that you can pass to "set_ftrace_filter" or |
180 | "set_ftrace_notrace". (See the section "dynamic ftrace" | 180 | "set_ftrace_notrace". (See the section "dynamic ftrace" |
181 | below for more details.) | 181 | below for more details.) |
182 | 182 | ||
183 | 183 | ||
184 | The Tracers | 184 | The Tracers |
185 | ----------- | 185 | ----------- |
186 | 186 | ||
187 | Here is the list of current tracers that may be configured. | 187 | Here is the list of current tracers that may be configured. |
188 | 188 | ||
189 | "function" | 189 | "function" |
190 | 190 | ||
191 | Function call tracer to trace all kernel functions. | 191 | Function call tracer to trace all kernel functions. |
192 | 192 | ||
193 | "function_graph" | 193 | "function_graph" |
194 | 194 | ||
195 | Similar to the function tracer except that the | 195 | Similar to the function tracer except that the |
196 | function tracer probes the functions on their entry | 196 | function tracer probes the functions on their entry |
197 | whereas the function graph tracer traces on both entry | 197 | whereas the function graph tracer traces on both entry |
198 | and exit of the functions. It then provides the ability | 198 | and exit of the functions. It then provides the ability |
199 | to draw a graph of function calls similar to C code | 199 | to draw a graph of function calls similar to C code |
200 | source. | 200 | source. |
201 | 201 | ||
202 | "sched_switch" | 202 | "sched_switch" |
203 | 203 | ||
204 | Traces the context switches and wakeups between tasks. | 204 | Traces the context switches and wakeups between tasks. |
205 | 205 | ||
206 | "irqsoff" | 206 | "irqsoff" |
207 | 207 | ||
208 | Traces the areas that disable interrupts and saves | 208 | Traces the areas that disable interrupts and saves |
209 | the trace with the longest max latency. | 209 | the trace with the longest max latency. |
210 | See tracing_max_latency. When a new max is recorded, | 210 | See tracing_max_latency. When a new max is recorded, |
211 | it replaces the old trace. It is best to view this | 211 | it replaces the old trace. It is best to view this |
212 | trace with the latency-format option enabled. | 212 | trace with the latency-format option enabled. |
213 | 213 | ||
214 | "preemptoff" | 214 | "preemptoff" |
215 | 215 | ||
216 | Similar to irqsoff but traces and records the amount of | 216 | Similar to irqsoff but traces and records the amount of |
217 | time for which preemption is disabled. | 217 | time for which preemption is disabled. |
218 | 218 | ||
219 | "preemptirqsoff" | 219 | "preemptirqsoff" |
220 | 220 | ||
221 | Similar to irqsoff and preemptoff, but traces and | 221 | Similar to irqsoff and preemptoff, but traces and |
222 | records the largest time for which irqs and/or preemption | 222 | records the largest time for which irqs and/or preemption |
223 | is disabled. | 223 | is disabled. |
224 | 224 | ||
225 | "wakeup" | 225 | "wakeup" |
226 | 226 | ||
227 | Traces and records the max latency that it takes for | 227 | Traces and records the max latency that it takes for |
228 | the highest priority task to get scheduled after | 228 | the highest priority task to get scheduled after |
229 | it has been woken up. | 229 | it has been woken up. |
230 | 230 | ||
231 | "hw-branch-tracer" | 231 | "hw-branch-tracer" |
232 | 232 | ||
233 | Uses the BTS CPU feature on x86 CPUs to traces all | 233 | Uses the BTS CPU feature on x86 CPUs to traces all |
234 | branches executed. | 234 | branches executed. |
235 | 235 | ||
236 | "nop" | 236 | "nop" |
237 | 237 | ||
238 | This is the "trace nothing" tracer. To remove all | 238 | This is the "trace nothing" tracer. To remove all |
239 | tracers from tracing simply echo "nop" into | 239 | tracers from tracing simply echo "nop" into |
240 | current_tracer. | 240 | current_tracer. |
241 | 241 | ||
242 | 242 | ||
243 | Examples of using the tracer | 243 | Examples of using the tracer |
244 | ---------------------------- | 244 | ---------------------------- |
245 | 245 | ||
246 | Here are typical examples of using the tracers when controlling | 246 | Here are typical examples of using the tracers when controlling |
247 | them only with the debugfs interface (without using any | 247 | them only with the debugfs interface (without using any |
248 | user-land utilities). | 248 | user-land utilities). |
249 | 249 | ||
250 | Output format: | 250 | Output format: |
251 | -------------- | 251 | -------------- |
252 | 252 | ||
253 | Here is an example of the output format of the file "trace" | 253 | Here is an example of the output format of the file "trace" |
254 | 254 | ||
255 | -------- | 255 | -------- |
256 | # tracer: function | 256 | # tracer: function |
257 | # | 257 | # |
258 | # TASK-PID CPU# TIMESTAMP FUNCTION | 258 | # TASK-PID CPU# TIMESTAMP FUNCTION |
259 | # | | | | | | 259 | # | | | | | |
260 | bash-4251 [01] 10152.583854: path_put <-path_walk | 260 | bash-4251 [01] 10152.583854: path_put <-path_walk |
261 | bash-4251 [01] 10152.583855: dput <-path_put | 261 | bash-4251 [01] 10152.583855: dput <-path_put |
262 | bash-4251 [01] 10152.583855: _atomic_dec_and_lock <-dput | 262 | bash-4251 [01] 10152.583855: _atomic_dec_and_lock <-dput |
263 | -------- | 263 | -------- |
264 | 264 | ||
265 | A header is printed with the tracer name that is represented by | 265 | A header is printed with the tracer name that is represented by |
266 | the trace. In this case the tracer is "function". Then a header | 266 | the trace. In this case the tracer is "function". Then a header |
267 | showing the format. Task name "bash", the task PID "4251", the | 267 | showing the format. Task name "bash", the task PID "4251", the |
268 | CPU that it was running on "01", the timestamp in <secs>.<usecs> | 268 | CPU that it was running on "01", the timestamp in <secs>.<usecs> |
269 | format, the function name that was traced "path_put" and the | 269 | format, the function name that was traced "path_put" and the |
270 | parent function that called this function "path_walk". The | 270 | parent function that called this function "path_walk". The |
271 | timestamp is the time at which the function was entered. | 271 | timestamp is the time at which the function was entered. |
272 | 272 | ||
273 | The sched_switch tracer also includes tracing of task wakeups | 273 | The sched_switch tracer also includes tracing of task wakeups |
274 | and context switches. | 274 | and context switches. |
275 | 275 | ||
276 | ksoftirqd/1-7 [01] 1453.070013: 7:115:R + 2916:115:S | 276 | ksoftirqd/1-7 [01] 1453.070013: 7:115:R + 2916:115:S |
277 | ksoftirqd/1-7 [01] 1453.070013: 7:115:R + 10:115:S | 277 | ksoftirqd/1-7 [01] 1453.070013: 7:115:R + 10:115:S |
278 | ksoftirqd/1-7 [01] 1453.070013: 7:115:R ==> 10:115:R | 278 | ksoftirqd/1-7 [01] 1453.070013: 7:115:R ==> 10:115:R |
279 | events/1-10 [01] 1453.070013: 10:115:S ==> 2916:115:R | 279 | events/1-10 [01] 1453.070013: 10:115:S ==> 2916:115:R |
280 | kondemand/1-2916 [01] 1453.070013: 2916:115:S ==> 7:115:R | 280 | kondemand/1-2916 [01] 1453.070013: 2916:115:S ==> 7:115:R |
281 | ksoftirqd/1-7 [01] 1453.070013: 7:115:S ==> 0:140:R | 281 | ksoftirqd/1-7 [01] 1453.070013: 7:115:S ==> 0:140:R |
282 | 282 | ||
283 | Wake ups are represented by a "+" and the context switches are | 283 | Wake ups are represented by a "+" and the context switches are |
284 | shown as "==>". The format is: | 284 | shown as "==>". The format is: |
285 | 285 | ||
286 | Context switches: | 286 | Context switches: |
287 | 287 | ||
288 | Previous task Next Task | 288 | Previous task Next Task |
289 | 289 | ||
290 | <pid>:<prio>:<state> ==> <pid>:<prio>:<state> | 290 | <pid>:<prio>:<state> ==> <pid>:<prio>:<state> |
291 | 291 | ||
292 | Wake ups: | 292 | Wake ups: |
293 | 293 | ||
294 | Current task Task waking up | 294 | Current task Task waking up |
295 | 295 | ||
296 | <pid>:<prio>:<state> + <pid>:<prio>:<state> | 296 | <pid>:<prio>:<state> + <pid>:<prio>:<state> |
297 | 297 | ||
298 | The prio is the internal kernel priority, which is the inverse | 298 | The prio is the internal kernel priority, which is the inverse |
299 | of the priority that is usually displayed by user-space tools. | 299 | of the priority that is usually displayed by user-space tools. |
300 | Zero represents the highest priority (99). Prio 100 starts the | 300 | Zero represents the highest priority (99). Prio 100 starts the |
301 | "nice" priorities with 100 being equal to nice -20 and 139 being | 301 | "nice" priorities with 100 being equal to nice -20 and 139 being |
302 | nice 19. The prio "140" is reserved for the idle task which is | 302 | nice 19. The prio "140" is reserved for the idle task which is |
303 | the lowest priority thread (pid 0). | 303 | the lowest priority thread (pid 0). |
304 | 304 | ||
305 | 305 | ||
306 | Latency trace format | 306 | Latency trace format |
307 | -------------------- | 307 | -------------------- |
308 | 308 | ||
309 | When the latency-format option is enabled, the trace file gives | 309 | When the latency-format option is enabled, the trace file gives |
310 | somewhat more information to see why a latency happened. | 310 | somewhat more information to see why a latency happened. |
311 | Here is a typical trace. | 311 | Here is a typical trace. |
312 | 312 | ||
313 | # tracer: irqsoff | 313 | # tracer: irqsoff |
314 | # | 314 | # |
315 | irqsoff latency trace v1.1.5 on 2.6.26-rc8 | 315 | irqsoff latency trace v1.1.5 on 2.6.26-rc8 |
316 | -------------------------------------------------------------------- | 316 | -------------------------------------------------------------------- |
317 | latency: 97 us, #3/3, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) | 317 | latency: 97 us, #3/3, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) |
318 | ----------------- | 318 | ----------------- |
319 | | task: swapper-0 (uid:0 nice:0 policy:0 rt_prio:0) | 319 | | task: swapper-0 (uid:0 nice:0 policy:0 rt_prio:0) |
320 | ----------------- | 320 | ----------------- |
321 | => started at: apic_timer_interrupt | 321 | => started at: apic_timer_interrupt |
322 | => ended at: do_softirq | 322 | => ended at: do_softirq |
323 | 323 | ||
324 | # _------=> CPU# | 324 | # _------=> CPU# |
325 | # / _-----=> irqs-off | 325 | # / _-----=> irqs-off |
326 | # | / _----=> need-resched | 326 | # | / _----=> need-resched |
327 | # || / _---=> hardirq/softirq | 327 | # || / _---=> hardirq/softirq |
328 | # ||| / _--=> preempt-depth | 328 | # ||| / _--=> preempt-depth |
329 | # |||| / | 329 | # |||| / |
330 | # ||||| delay | 330 | # ||||| delay |
331 | # cmd pid ||||| time | caller | 331 | # cmd pid ||||| time | caller |
332 | # \ / ||||| \ | / | 332 | # \ / ||||| \ | / |
333 | <idle>-0 0d..1 0us+: trace_hardirqs_off_thunk (apic_timer_interrupt) | 333 | <idle>-0 0d..1 0us+: trace_hardirqs_off_thunk (apic_timer_interrupt) |
334 | <idle>-0 0d.s. 97us : __do_softirq (do_softirq) | 334 | <idle>-0 0d.s. 97us : __do_softirq (do_softirq) |
335 | <idle>-0 0d.s1 98us : trace_hardirqs_on (do_softirq) | 335 | <idle>-0 0d.s1 98us : trace_hardirqs_on (do_softirq) |
336 | 336 | ||
337 | 337 | ||
338 | This shows that the current tracer is "irqsoff" tracing the time | 338 | This shows that the current tracer is "irqsoff" tracing the time |
339 | for which interrupts were disabled. It gives the trace version | 339 | for which interrupts were disabled. It gives the trace version |
340 | and the version of the kernel upon which this was executed on | 340 | and the version of the kernel upon which this was executed on |
341 | (2.6.26-rc8). Then it displays the max latency in microsecs (97 | 341 | (2.6.26-rc8). Then it displays the max latency in microsecs (97 |
342 | us). The number of trace entries displayed and the total number | 342 | us). The number of trace entries displayed and the total number |
343 | recorded (both are three: #3/3). The type of preemption that was | 343 | recorded (both are three: #3/3). The type of preemption that was |
344 | used (PREEMPT). VP, KP, SP, and HP are always zero and are | 344 | used (PREEMPT). VP, KP, SP, and HP are always zero and are |
345 | reserved for later use. #P is the number of online CPUS (#P:2). | 345 | reserved for later use. #P is the number of online CPUS (#P:2). |
346 | 346 | ||
347 | The task is the process that was running when the latency | 347 | The task is the process that was running when the latency |
348 | occurred. (swapper pid: 0). | 348 | occurred. (swapper pid: 0). |
349 | 349 | ||
350 | The start and stop (the functions in which the interrupts were | 350 | The start and stop (the functions in which the interrupts were |
351 | disabled and enabled respectively) that caused the latencies: | 351 | disabled and enabled respectively) that caused the latencies: |
352 | 352 | ||
353 | apic_timer_interrupt is where the interrupts were disabled. | 353 | apic_timer_interrupt is where the interrupts were disabled. |
354 | do_softirq is where they were enabled again. | 354 | do_softirq is where they were enabled again. |
355 | 355 | ||
356 | The next lines after the header are the trace itself. The header | 356 | The next lines after the header are the trace itself. The header |
357 | explains which is which. | 357 | explains which is which. |
358 | 358 | ||
359 | cmd: The name of the process in the trace. | 359 | cmd: The name of the process in the trace. |
360 | 360 | ||
361 | pid: The PID of that process. | 361 | pid: The PID of that process. |
362 | 362 | ||
363 | CPU#: The CPU which the process was running on. | 363 | CPU#: The CPU which the process was running on. |
364 | 364 | ||
365 | irqs-off: 'd' interrupts are disabled. '.' otherwise. | 365 | irqs-off: 'd' interrupts are disabled. '.' otherwise. |
366 | Note: If the architecture does not support a way to | 366 | Note: If the architecture does not support a way to |
367 | read the irq flags variable, an 'X' will always | 367 | read the irq flags variable, an 'X' will always |
368 | be printed here. | 368 | be printed here. |
369 | 369 | ||
370 | need-resched: 'N' task need_resched is set, '.' otherwise. | 370 | need-resched: 'N' task need_resched is set, '.' otherwise. |
371 | 371 | ||
372 | hardirq/softirq: | 372 | hardirq/softirq: |
373 | 'H' - hard irq occurred inside a softirq. | 373 | 'H' - hard irq occurred inside a softirq. |
374 | 'h' - hard irq is running | 374 | 'h' - hard irq is running |
375 | 's' - soft irq is running | 375 | 's' - soft irq is running |
376 | '.' - normal context. | 376 | '.' - normal context. |
377 | 377 | ||
378 | preempt-depth: The level of preempt_disabled | 378 | preempt-depth: The level of preempt_disabled |
379 | 379 | ||
380 | The above is mostly meaningful for kernel developers. | 380 | The above is mostly meaningful for kernel developers. |
381 | 381 | ||
382 | time: When the latency-format option is enabled, the trace file | 382 | time: When the latency-format option is enabled, the trace file |
383 | output includes a timestamp relative to the start of the | 383 | output includes a timestamp relative to the start of the |
384 | trace. This differs from the output when latency-format | 384 | trace. This differs from the output when latency-format |
385 | is disabled, which includes an absolute timestamp. | 385 | is disabled, which includes an absolute timestamp. |
386 | 386 | ||
387 | delay: This is just to help catch your eye a bit better. And | 387 | delay: This is just to help catch your eye a bit better. And |
388 | needs to be fixed to be only relative to the same CPU. | 388 | needs to be fixed to be only relative to the same CPU. |
389 | The marks are determined by the difference between this | 389 | The marks are determined by the difference between this |
390 | current trace and the next trace. | 390 | current trace and the next trace. |
391 | '!' - greater than preempt_mark_thresh (default 100) | 391 | '!' - greater than preempt_mark_thresh (default 100) |
392 | '+' - greater than 1 microsecond | 392 | '+' - greater than 1 microsecond |
393 | ' ' - less than or equal to 1 microsecond. | 393 | ' ' - less than or equal to 1 microsecond. |
394 | 394 | ||
395 | The rest is the same as the 'trace' file. | 395 | The rest is the same as the 'trace' file. |
396 | 396 | ||
397 | 397 | ||
398 | trace_options | 398 | trace_options |
399 | ------------- | 399 | ------------- |
400 | 400 | ||
401 | The trace_options file is used to control what gets printed in | 401 | The trace_options file is used to control what gets printed in |
402 | the trace output. To see what is available, simply cat the file: | 402 | the trace output. To see what is available, simply cat the file: |
403 | 403 | ||
404 | cat trace_options | 404 | cat trace_options |
405 | print-parent nosym-offset nosym-addr noverbose noraw nohex nobin \ | 405 | print-parent nosym-offset nosym-addr noverbose noraw nohex nobin \ |
406 | noblock nostacktrace nosched-tree nouserstacktrace nosym-userobj | 406 | noblock nostacktrace nosched-tree nouserstacktrace nosym-userobj |
407 | 407 | ||
408 | To disable one of the options, echo in the option prepended with | 408 | To disable one of the options, echo in the option prepended with |
409 | "no". | 409 | "no". |
410 | 410 | ||
411 | echo noprint-parent > trace_options | 411 | echo noprint-parent > trace_options |
412 | 412 | ||
413 | To enable an option, leave off the "no". | 413 | To enable an option, leave off the "no". |
414 | 414 | ||
415 | echo sym-offset > trace_options | 415 | echo sym-offset > trace_options |
416 | 416 | ||
417 | Here are the available options: | 417 | Here are the available options: |
418 | 418 | ||
419 | print-parent - On function traces, display the calling (parent) | 419 | print-parent - On function traces, display the calling (parent) |
420 | function as well as the function being traced. | 420 | function as well as the function being traced. |
421 | 421 | ||
422 | print-parent: | 422 | print-parent: |
423 | bash-4000 [01] 1477.606694: simple_strtoul <-strict_strtoul | 423 | bash-4000 [01] 1477.606694: simple_strtoul <-strict_strtoul |
424 | 424 | ||
425 | noprint-parent: | 425 | noprint-parent: |
426 | bash-4000 [01] 1477.606694: simple_strtoul | 426 | bash-4000 [01] 1477.606694: simple_strtoul |
427 | 427 | ||
428 | 428 | ||
429 | sym-offset - Display not only the function name, but also the | 429 | sym-offset - Display not only the function name, but also the |
430 | offset in the function. For example, instead of | 430 | offset in the function. For example, instead of |
431 | seeing just "ktime_get", you will see | 431 | seeing just "ktime_get", you will see |
432 | "ktime_get+0xb/0x20". | 432 | "ktime_get+0xb/0x20". |
433 | 433 | ||
434 | sym-offset: | 434 | sym-offset: |
435 | bash-4000 [01] 1477.606694: simple_strtoul+0x6/0xa0 | 435 | bash-4000 [01] 1477.606694: simple_strtoul+0x6/0xa0 |
436 | 436 | ||
437 | sym-addr - this will also display the function address as well | 437 | sym-addr - this will also display the function address as well |
438 | as the function name. | 438 | as the function name. |
439 | 439 | ||
440 | sym-addr: | 440 | sym-addr: |
441 | bash-4000 [01] 1477.606694: simple_strtoul <c0339346> | 441 | bash-4000 [01] 1477.606694: simple_strtoul <c0339346> |
442 | 442 | ||
443 | verbose - This deals with the trace file when the | 443 | verbose - This deals with the trace file when the |
444 | latency-format option is enabled. | 444 | latency-format option is enabled. |
445 | 445 | ||
446 | bash 4000 1 0 00000000 00010a95 [58127d26] 1720.415ms \ | 446 | bash 4000 1 0 00000000 00010a95 [58127d26] 1720.415ms \ |
447 | (+0.000ms): simple_strtoul (strict_strtoul) | 447 | (+0.000ms): simple_strtoul (strict_strtoul) |
448 | 448 | ||
449 | raw - This will display raw numbers. This option is best for | 449 | raw - This will display raw numbers. This option is best for |
450 | use with user applications that can translate the raw | 450 | use with user applications that can translate the raw |
451 | numbers better than having it done in the kernel. | 451 | numbers better than having it done in the kernel. |
452 | 452 | ||
453 | hex - Similar to raw, but the numbers will be in a hexadecimal | 453 | hex - Similar to raw, but the numbers will be in a hexadecimal |
454 | format. | 454 | format. |
455 | 455 | ||
456 | bin - This will print out the formats in raw binary. | 456 | bin - This will print out the formats in raw binary. |
457 | 457 | ||
458 | block - TBD (needs update) | 458 | block - TBD (needs update) |
459 | 459 | ||
460 | stacktrace - This is one of the options that changes the trace | 460 | stacktrace - This is one of the options that changes the trace |
461 | itself. When a trace is recorded, so is the stack | 461 | itself. When a trace is recorded, so is the stack |
462 | of functions. This allows for back traces of | 462 | of functions. This allows for back traces of |
463 | trace sites. | 463 | trace sites. |
464 | 464 | ||
465 | userstacktrace - This option changes the trace. It records a | 465 | userstacktrace - This option changes the trace. It records a |
466 | stacktrace of the current userspace thread. | 466 | stacktrace of the current userspace thread. |
467 | 467 | ||
468 | sym-userobj - when user stacktrace are enabled, look up which | 468 | sym-userobj - when user stacktrace are enabled, look up which |
469 | object the address belongs to, and print a | 469 | object the address belongs to, and print a |
470 | relative address. This is especially useful when | 470 | relative address. This is especially useful when |
471 | ASLR is on, otherwise you don't get a chance to | 471 | ASLR is on, otherwise you don't get a chance to |
472 | resolve the address to object/file/line after | 472 | resolve the address to object/file/line after |
473 | the app is no longer running | 473 | the app is no longer running |
474 | 474 | ||
475 | The lookup is performed when you read | 475 | The lookup is performed when you read |
476 | trace,trace_pipe. Example: | 476 | trace,trace_pipe. Example: |
477 | 477 | ||
478 | a.out-1623 [000] 40874.465068: /root/a.out[+0x480] <-/root/a.out[+0 | 478 | a.out-1623 [000] 40874.465068: /root/a.out[+0x480] <-/root/a.out[+0 |
479 | x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6] | 479 | x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6] |
480 | 480 | ||
481 | sched-tree - trace all tasks that are on the runqueue, at | 481 | sched-tree - trace all tasks that are on the runqueue, at |
482 | every scheduling event. Will add overhead if | 482 | every scheduling event. Will add overhead if |
483 | there's a lot of tasks running at once. | 483 | there's a lot of tasks running at once. |
484 | 484 | ||
485 | latency-format - This option changes the trace. When | 485 | latency-format - This option changes the trace. When |
486 | it is enabled, the trace displays | 486 | it is enabled, the trace displays |
487 | additional information about the | 487 | additional information about the |
488 | latencies, as described in "Latency | 488 | latencies, as described in "Latency |
489 | trace format". | 489 | trace format". |
490 | 490 | ||
491 | sched_switch | 491 | sched_switch |
492 | ------------ | 492 | ------------ |
493 | 493 | ||
494 | This tracer simply records schedule switches. Here is an example | 494 | This tracer simply records schedule switches. Here is an example |
495 | of how to use it. | 495 | of how to use it. |
496 | 496 | ||
497 | # echo sched_switch > current_tracer | 497 | # echo sched_switch > current_tracer |
498 | # echo 1 > tracing_enabled | 498 | # echo 1 > tracing_enabled |
499 | # sleep 1 | 499 | # sleep 1 |
500 | # echo 0 > tracing_enabled | 500 | # echo 0 > tracing_enabled |
501 | # cat trace | 501 | # cat trace |
502 | 502 | ||
503 | # tracer: sched_switch | 503 | # tracer: sched_switch |
504 | # | 504 | # |
505 | # TASK-PID CPU# TIMESTAMP FUNCTION | 505 | # TASK-PID CPU# TIMESTAMP FUNCTION |
506 | # | | | | | | 506 | # | | | | | |
507 | bash-3997 [01] 240.132281: 3997:120:R + 4055:120:R | 507 | bash-3997 [01] 240.132281: 3997:120:R + 4055:120:R |
508 | bash-3997 [01] 240.132284: 3997:120:R ==> 4055:120:R | 508 | bash-3997 [01] 240.132284: 3997:120:R ==> 4055:120:R |
509 | sleep-4055 [01] 240.132371: 4055:120:S ==> 3997:120:R | 509 | sleep-4055 [01] 240.132371: 4055:120:S ==> 3997:120:R |
510 | bash-3997 [01] 240.132454: 3997:120:R + 4055:120:S | 510 | bash-3997 [01] 240.132454: 3997:120:R + 4055:120:S |
511 | bash-3997 [01] 240.132457: 3997:120:R ==> 4055:120:R | 511 | bash-3997 [01] 240.132457: 3997:120:R ==> 4055:120:R |
512 | sleep-4055 [01] 240.132460: 4055:120:D ==> 3997:120:R | 512 | sleep-4055 [01] 240.132460: 4055:120:D ==> 3997:120:R |
513 | bash-3997 [01] 240.132463: 3997:120:R + 4055:120:D | 513 | bash-3997 [01] 240.132463: 3997:120:R + 4055:120:D |
514 | bash-3997 [01] 240.132465: 3997:120:R ==> 4055:120:R | 514 | bash-3997 [01] 240.132465: 3997:120:R ==> 4055:120:R |
515 | <idle>-0 [00] 240.132589: 0:140:R + 4:115:S | 515 | <idle>-0 [00] 240.132589: 0:140:R + 4:115:S |
516 | <idle>-0 [00] 240.132591: 0:140:R ==> 4:115:R | 516 | <idle>-0 [00] 240.132591: 0:140:R ==> 4:115:R |
517 | ksoftirqd/0-4 [00] 240.132595: 4:115:S ==> 0:140:R | 517 | ksoftirqd/0-4 [00] 240.132595: 4:115:S ==> 0:140:R |
518 | <idle>-0 [00] 240.132598: 0:140:R + 4:115:S | 518 | <idle>-0 [00] 240.132598: 0:140:R + 4:115:S |
519 | <idle>-0 [00] 240.132599: 0:140:R ==> 4:115:R | 519 | <idle>-0 [00] 240.132599: 0:140:R ==> 4:115:R |
520 | ksoftirqd/0-4 [00] 240.132603: 4:115:S ==> 0:140:R | 520 | ksoftirqd/0-4 [00] 240.132603: 4:115:S ==> 0:140:R |
521 | sleep-4055 [01] 240.133058: 4055:120:S ==> 3997:120:R | 521 | sleep-4055 [01] 240.133058: 4055:120:S ==> 3997:120:R |
522 | [...] | 522 | [...] |
523 | 523 | ||
524 | 524 | ||
525 | As we have discussed previously about this format, the header | 525 | As we have discussed previously about this format, the header |
526 | shows the name of the trace and points to the options. The | 526 | shows the name of the trace and points to the options. The |
527 | "FUNCTION" is a misnomer since here it represents the wake ups | 527 | "FUNCTION" is a misnomer since here it represents the wake ups |
528 | and context switches. | 528 | and context switches. |
529 | 529 | ||
530 | The sched_switch file only lists the wake ups (represented with | 530 | The sched_switch file only lists the wake ups (represented with |
531 | '+') and context switches ('==>') with the previous task or | 531 | '+') and context switches ('==>') with the previous task or |
532 | current task first followed by the next task or task waking up. | 532 | current task first followed by the next task or task waking up. |
533 | The format for both of these is PID:KERNEL-PRIO:TASK-STATE. | 533 | The format for both of these is PID:KERNEL-PRIO:TASK-STATE. |
534 | Remember that the KERNEL-PRIO is the inverse of the actual | 534 | Remember that the KERNEL-PRIO is the inverse of the actual |
535 | priority with zero (0) being the highest priority and the nice | 535 | priority with zero (0) being the highest priority and the nice |
536 | values starting at 100 (nice -20). Below is a quick chart to map | 536 | values starting at 100 (nice -20). Below is a quick chart to map |
537 | the kernel priority to user land priorities. | 537 | the kernel priority to user land priorities. |
538 | 538 | ||
539 | Kernel Space User Space | 539 | Kernel Space User Space |
540 | =============================================================== | 540 | =============================================================== |
541 | 0(high) to 98(low) user RT priority 99(high) to 1(low) | 541 | 0(high) to 98(low) user RT priority 99(high) to 1(low) |
542 | with SCHED_RR or SCHED_FIFO | 542 | with SCHED_RR or SCHED_FIFO |
543 | --------------------------------------------------------------- | 543 | --------------------------------------------------------------- |
544 | 99 sched_priority is not used in scheduling | 544 | 99 sched_priority is not used in scheduling |
545 | decisions(it must be specified as 0) | 545 | decisions(it must be specified as 0) |
546 | --------------------------------------------------------------- | 546 | --------------------------------------------------------------- |
547 | 100(high) to 139(low) user nice -20(high) to 19(low) | 547 | 100(high) to 139(low) user nice -20(high) to 19(low) |
548 | --------------------------------------------------------------- | 548 | --------------------------------------------------------------- |
549 | 140 idle task priority | 549 | 140 idle task priority |
550 | --------------------------------------------------------------- | 550 | --------------------------------------------------------------- |
551 | 551 | ||
552 | The task states are: | 552 | The task states are: |
553 | 553 | ||
554 | R - running : wants to run, may not actually be running | 554 | R - running : wants to run, may not actually be running |
555 | S - sleep : process is waiting to be woken up (handles signals) | 555 | S - sleep : process is waiting to be woken up (handles signals) |
556 | D - disk sleep (uninterruptible sleep) : process must be woken up | 556 | D - disk sleep (uninterruptible sleep) : process must be woken up |
557 | (ignores signals) | 557 | (ignores signals) |
558 | T - stopped : process suspended | 558 | T - stopped : process suspended |
559 | t - traced : process is being traced (with something like gdb) | 559 | t - traced : process is being traced (with something like gdb) |
560 | Z - zombie : process waiting to be cleaned up | 560 | Z - zombie : process waiting to be cleaned up |
561 | X - unknown | 561 | X - unknown |
562 | 562 | ||
563 | 563 | ||
564 | ftrace_enabled | 564 | ftrace_enabled |
565 | -------------- | 565 | -------------- |
566 | 566 | ||
567 | The following tracers (listed below) give different output | 567 | The following tracers (listed below) give different output |
568 | depending on whether or not the sysctl ftrace_enabled is set. To | 568 | depending on whether or not the sysctl ftrace_enabled is set. To |
569 | set ftrace_enabled, one can either use the sysctl function or | 569 | set ftrace_enabled, one can either use the sysctl function or |
570 | set it via the proc file system interface. | 570 | set it via the proc file system interface. |
571 | 571 | ||
572 | sysctl kernel.ftrace_enabled=1 | 572 | sysctl kernel.ftrace_enabled=1 |
573 | 573 | ||
574 | or | 574 | or |
575 | 575 | ||
576 | echo 1 > /proc/sys/kernel/ftrace_enabled | 576 | echo 1 > /proc/sys/kernel/ftrace_enabled |
577 | 577 | ||
578 | To disable ftrace_enabled simply replace the '1' with '0' in the | 578 | To disable ftrace_enabled simply replace the '1' with '0' in the |
579 | above commands. | 579 | above commands. |
580 | 580 | ||
581 | When ftrace_enabled is set the tracers will also record the | 581 | When ftrace_enabled is set the tracers will also record the |
582 | functions that are within the trace. The descriptions of the | 582 | functions that are within the trace. The descriptions of the |
583 | tracers will also show an example with ftrace enabled. | 583 | tracers will also show an example with ftrace enabled. |
584 | 584 | ||
585 | 585 | ||
586 | irqsoff | 586 | irqsoff |
587 | ------- | 587 | ------- |
588 | 588 | ||
589 | When interrupts are disabled, the CPU can not react to any other | 589 | When interrupts are disabled, the CPU can not react to any other |
590 | external event (besides NMIs and SMIs). This prevents the timer | 590 | external event (besides NMIs and SMIs). This prevents the timer |
591 | interrupt from triggering or the mouse interrupt from letting | 591 | interrupt from triggering or the mouse interrupt from letting |
592 | the kernel know of a new mouse event. The result is a latency | 592 | the kernel know of a new mouse event. The result is a latency |
593 | with the reaction time. | 593 | with the reaction time. |
594 | 594 | ||
595 | The irqsoff tracer tracks the time for which interrupts are | 595 | The irqsoff tracer tracks the time for which interrupts are |
596 | disabled. When a new maximum latency is hit, the tracer saves | 596 | disabled. When a new maximum latency is hit, the tracer saves |
597 | the trace leading up to that latency point so that every time a | 597 | the trace leading up to that latency point so that every time a |
598 | new maximum is reached, the old saved trace is discarded and the | 598 | new maximum is reached, the old saved trace is discarded and the |
599 | new trace is saved. | 599 | new trace is saved. |
600 | 600 | ||
601 | To reset the maximum, echo 0 into tracing_max_latency. Here is | 601 | To reset the maximum, echo 0 into tracing_max_latency. Here is |
602 | an example: | 602 | an example: |
603 | 603 | ||
604 | # echo irqsoff > current_tracer | 604 | # echo irqsoff > current_tracer |
605 | # echo latency-format > trace_options | 605 | # echo latency-format > trace_options |
606 | # echo 0 > tracing_max_latency | 606 | # echo 0 > tracing_max_latency |
607 | # echo 1 > tracing_enabled | 607 | # echo 1 > tracing_enabled |
608 | # ls -ltr | 608 | # ls -ltr |
609 | [...] | 609 | [...] |
610 | # echo 0 > tracing_enabled | 610 | # echo 0 > tracing_enabled |
611 | # cat trace | 611 | # cat trace |
612 | # tracer: irqsoff | 612 | # tracer: irqsoff |
613 | # | 613 | # |
614 | irqsoff latency trace v1.1.5 on 2.6.26 | 614 | irqsoff latency trace v1.1.5 on 2.6.26 |
615 | -------------------------------------------------------------------- | 615 | -------------------------------------------------------------------- |
616 | latency: 12 us, #3/3, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) | 616 | latency: 12 us, #3/3, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) |
617 | ----------------- | 617 | ----------------- |
618 | | task: bash-3730 (uid:0 nice:0 policy:0 rt_prio:0) | 618 | | task: bash-3730 (uid:0 nice:0 policy:0 rt_prio:0) |
619 | ----------------- | 619 | ----------------- |
620 | => started at: sys_setpgid | 620 | => started at: sys_setpgid |
621 | => ended at: sys_setpgid | 621 | => ended at: sys_setpgid |
622 | 622 | ||
623 | # _------=> CPU# | 623 | # _------=> CPU# |
624 | # / _-----=> irqs-off | 624 | # / _-----=> irqs-off |
625 | # | / _----=> need-resched | 625 | # | / _----=> need-resched |
626 | # || / _---=> hardirq/softirq | 626 | # || / _---=> hardirq/softirq |
627 | # ||| / _--=> preempt-depth | 627 | # ||| / _--=> preempt-depth |
628 | # |||| / | 628 | # |||| / |
629 | # ||||| delay | 629 | # ||||| delay |
630 | # cmd pid ||||| time | caller | 630 | # cmd pid ||||| time | caller |
631 | # \ / ||||| \ | / | 631 | # \ / ||||| \ | / |
632 | bash-3730 1d... 0us : _write_lock_irq (sys_setpgid) | 632 | bash-3730 1d... 0us : _write_lock_irq (sys_setpgid) |
633 | bash-3730 1d..1 1us+: _write_unlock_irq (sys_setpgid) | 633 | bash-3730 1d..1 1us+: _write_unlock_irq (sys_setpgid) |
634 | bash-3730 1d..2 14us : trace_hardirqs_on (sys_setpgid) | 634 | bash-3730 1d..2 14us : trace_hardirqs_on (sys_setpgid) |
635 | 635 | ||
636 | 636 | ||
637 | Here we see that that we had a latency of 12 microsecs (which is | 637 | Here we see that that we had a latency of 12 microsecs (which is |
638 | very good). The _write_lock_irq in sys_setpgid disabled | 638 | very good). The _write_lock_irq in sys_setpgid disabled |
639 | interrupts. The difference between the 12 and the displayed | 639 | interrupts. The difference between the 12 and the displayed |
640 | timestamp 14us occurred because the clock was incremented | 640 | timestamp 14us occurred because the clock was incremented |
641 | between the time of recording the max latency and the time of | 641 | between the time of recording the max latency and the time of |
642 | recording the function that had that latency. | 642 | recording the function that had that latency. |
643 | 643 | ||
644 | Note the above example had ftrace_enabled not set. If we set the | 644 | Note the above example had ftrace_enabled not set. If we set the |
645 | ftrace_enabled, we get a much larger output: | 645 | ftrace_enabled, we get a much larger output: |
646 | 646 | ||
647 | # tracer: irqsoff | 647 | # tracer: irqsoff |
648 | # | 648 | # |
649 | irqsoff latency trace v1.1.5 on 2.6.26-rc8 | 649 | irqsoff latency trace v1.1.5 on 2.6.26-rc8 |
650 | -------------------------------------------------------------------- | 650 | -------------------------------------------------------------------- |
651 | latency: 50 us, #101/101, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) | 651 | latency: 50 us, #101/101, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) |
652 | ----------------- | 652 | ----------------- |
653 | | task: ls-4339 (uid:0 nice:0 policy:0 rt_prio:0) | 653 | | task: ls-4339 (uid:0 nice:0 policy:0 rt_prio:0) |
654 | ----------------- | 654 | ----------------- |
655 | => started at: __alloc_pages_internal | 655 | => started at: __alloc_pages_internal |
656 | => ended at: __alloc_pages_internal | 656 | => ended at: __alloc_pages_internal |
657 | 657 | ||
658 | # _------=> CPU# | 658 | # _------=> CPU# |
659 | # / _-----=> irqs-off | 659 | # / _-----=> irqs-off |
660 | # | / _----=> need-resched | 660 | # | / _----=> need-resched |
661 | # || / _---=> hardirq/softirq | 661 | # || / _---=> hardirq/softirq |
662 | # ||| / _--=> preempt-depth | 662 | # ||| / _--=> preempt-depth |
663 | # |||| / | 663 | # |||| / |
664 | # ||||| delay | 664 | # ||||| delay |
665 | # cmd pid ||||| time | caller | 665 | # cmd pid ||||| time | caller |
666 | # \ / ||||| \ | / | 666 | # \ / ||||| \ | / |
667 | ls-4339 0...1 0us+: get_page_from_freelist (__alloc_pages_internal) | 667 | ls-4339 0...1 0us+: get_page_from_freelist (__alloc_pages_internal) |
668 | ls-4339 0d..1 3us : rmqueue_bulk (get_page_from_freelist) | 668 | ls-4339 0d..1 3us : rmqueue_bulk (get_page_from_freelist) |
669 | ls-4339 0d..1 3us : _spin_lock (rmqueue_bulk) | 669 | ls-4339 0d..1 3us : _spin_lock (rmqueue_bulk) |
670 | ls-4339 0d..1 4us : add_preempt_count (_spin_lock) | 670 | ls-4339 0d..1 4us : add_preempt_count (_spin_lock) |
671 | ls-4339 0d..2 4us : __rmqueue (rmqueue_bulk) | 671 | ls-4339 0d..2 4us : __rmqueue (rmqueue_bulk) |
672 | ls-4339 0d..2 5us : __rmqueue_smallest (__rmqueue) | 672 | ls-4339 0d..2 5us : __rmqueue_smallest (__rmqueue) |
673 | ls-4339 0d..2 5us : __mod_zone_page_state (__rmqueue_smallest) | 673 | ls-4339 0d..2 5us : __mod_zone_page_state (__rmqueue_smallest) |
674 | ls-4339 0d..2 6us : __rmqueue (rmqueue_bulk) | 674 | ls-4339 0d..2 6us : __rmqueue (rmqueue_bulk) |
675 | ls-4339 0d..2 6us : __rmqueue_smallest (__rmqueue) | 675 | ls-4339 0d..2 6us : __rmqueue_smallest (__rmqueue) |
676 | ls-4339 0d..2 7us : __mod_zone_page_state (__rmqueue_smallest) | 676 | ls-4339 0d..2 7us : __mod_zone_page_state (__rmqueue_smallest) |
677 | ls-4339 0d..2 7us : __rmqueue (rmqueue_bulk) | 677 | ls-4339 0d..2 7us : __rmqueue (rmqueue_bulk) |
678 | ls-4339 0d..2 8us : __rmqueue_smallest (__rmqueue) | 678 | ls-4339 0d..2 8us : __rmqueue_smallest (__rmqueue) |
679 | [...] | 679 | [...] |
680 | ls-4339 0d..2 46us : __rmqueue_smallest (__rmqueue) | 680 | ls-4339 0d..2 46us : __rmqueue_smallest (__rmqueue) |
681 | ls-4339 0d..2 47us : __mod_zone_page_state (__rmqueue_smallest) | 681 | ls-4339 0d..2 47us : __mod_zone_page_state (__rmqueue_smallest) |
682 | ls-4339 0d..2 47us : __rmqueue (rmqueue_bulk) | 682 | ls-4339 0d..2 47us : __rmqueue (rmqueue_bulk) |
683 | ls-4339 0d..2 48us : __rmqueue_smallest (__rmqueue) | 683 | ls-4339 0d..2 48us : __rmqueue_smallest (__rmqueue) |
684 | ls-4339 0d..2 48us : __mod_zone_page_state (__rmqueue_smallest) | 684 | ls-4339 0d..2 48us : __mod_zone_page_state (__rmqueue_smallest) |
685 | ls-4339 0d..2 49us : _spin_unlock (rmqueue_bulk) | 685 | ls-4339 0d..2 49us : _spin_unlock (rmqueue_bulk) |
686 | ls-4339 0d..2 49us : sub_preempt_count (_spin_unlock) | 686 | ls-4339 0d..2 49us : sub_preempt_count (_spin_unlock) |
687 | ls-4339 0d..1 50us : get_page_from_freelist (__alloc_pages_internal) | 687 | ls-4339 0d..1 50us : get_page_from_freelist (__alloc_pages_internal) |
688 | ls-4339 0d..2 51us : trace_hardirqs_on (__alloc_pages_internal) | 688 | ls-4339 0d..2 51us : trace_hardirqs_on (__alloc_pages_internal) |
689 | 689 | ||
690 | 690 | ||
691 | 691 | ||
692 | Here we traced a 50 microsecond latency. But we also see all the | 692 | Here we traced a 50 microsecond latency. But we also see all the |
693 | functions that were called during that time. Note that by | 693 | functions that were called during that time. Note that by |
694 | enabling function tracing, we incur an added overhead. This | 694 | enabling function tracing, we incur an added overhead. This |
695 | overhead may extend the latency times. But nevertheless, this | 695 | overhead may extend the latency times. But nevertheless, this |
696 | trace has provided some very helpful debugging information. | 696 | trace has provided some very helpful debugging information. |
697 | 697 | ||
698 | 698 | ||
699 | preemptoff | 699 | preemptoff |
700 | ---------- | 700 | ---------- |
701 | 701 | ||
702 | When preemption is disabled, we may be able to receive | 702 | When preemption is disabled, we may be able to receive |
703 | interrupts but the task cannot be preempted and a higher | 703 | interrupts but the task cannot be preempted and a higher |
704 | priority task must wait for preemption to be enabled again | 704 | priority task must wait for preemption to be enabled again |
705 | before it can preempt a lower priority task. | 705 | before it can preempt a lower priority task. |
706 | 706 | ||
707 | The preemptoff tracer traces the places that disable preemption. | 707 | The preemptoff tracer traces the places that disable preemption. |
708 | Like the irqsoff tracer, it records the maximum latency for | 708 | Like the irqsoff tracer, it records the maximum latency for |
709 | which preemption was disabled. The control of preemptoff tracer | 709 | which preemption was disabled. The control of preemptoff tracer |
710 | is much like the irqsoff tracer. | 710 | is much like the irqsoff tracer. |
711 | 711 | ||
712 | # echo preemptoff > current_tracer | 712 | # echo preemptoff > current_tracer |
713 | # echo latency-format > trace_options | 713 | # echo latency-format > trace_options |
714 | # echo 0 > tracing_max_latency | 714 | # echo 0 > tracing_max_latency |
715 | # echo 1 > tracing_enabled | 715 | # echo 1 > tracing_enabled |
716 | # ls -ltr | 716 | # ls -ltr |
717 | [...] | 717 | [...] |
718 | # echo 0 > tracing_enabled | 718 | # echo 0 > tracing_enabled |
719 | # cat trace | 719 | # cat trace |
720 | # tracer: preemptoff | 720 | # tracer: preemptoff |
721 | # | 721 | # |
722 | preemptoff latency trace v1.1.5 on 2.6.26-rc8 | 722 | preemptoff latency trace v1.1.5 on 2.6.26-rc8 |
723 | -------------------------------------------------------------------- | 723 | -------------------------------------------------------------------- |
724 | latency: 29 us, #3/3, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) | 724 | latency: 29 us, #3/3, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) |
725 | ----------------- | 725 | ----------------- |
726 | | task: sshd-4261 (uid:0 nice:0 policy:0 rt_prio:0) | 726 | | task: sshd-4261 (uid:0 nice:0 policy:0 rt_prio:0) |
727 | ----------------- | 727 | ----------------- |
728 | => started at: do_IRQ | 728 | => started at: do_IRQ |
729 | => ended at: __do_softirq | 729 | => ended at: __do_softirq |
730 | 730 | ||
731 | # _------=> CPU# | 731 | # _------=> CPU# |
732 | # / _-----=> irqs-off | 732 | # / _-----=> irqs-off |
733 | # | / _----=> need-resched | 733 | # | / _----=> need-resched |
734 | # || / _---=> hardirq/softirq | 734 | # || / _---=> hardirq/softirq |
735 | # ||| / _--=> preempt-depth | 735 | # ||| / _--=> preempt-depth |
736 | # |||| / | 736 | # |||| / |
737 | # ||||| delay | 737 | # ||||| delay |
738 | # cmd pid ||||| time | caller | 738 | # cmd pid ||||| time | caller |
739 | # \ / ||||| \ | / | 739 | # \ / ||||| \ | / |
740 | sshd-4261 0d.h. 0us+: irq_enter (do_IRQ) | 740 | sshd-4261 0d.h. 0us+: irq_enter (do_IRQ) |
741 | sshd-4261 0d.s. 29us : _local_bh_enable (__do_softirq) | 741 | sshd-4261 0d.s. 29us : _local_bh_enable (__do_softirq) |
742 | sshd-4261 0d.s1 30us : trace_preempt_on (__do_softirq) | 742 | sshd-4261 0d.s1 30us : trace_preempt_on (__do_softirq) |
743 | 743 | ||
744 | 744 | ||
745 | This has some more changes. Preemption was disabled when an | 745 | This has some more changes. Preemption was disabled when an |
746 | interrupt came in (notice the 'h'), and was enabled while doing | 746 | interrupt came in (notice the 'h'), and was enabled while doing |
747 | a softirq. (notice the 's'). But we also see that interrupts | 747 | a softirq. (notice the 's'). But we also see that interrupts |
748 | have been disabled when entering the preempt off section and | 748 | have been disabled when entering the preempt off section and |
749 | leaving it (the 'd'). We do not know if interrupts were enabled | 749 | leaving it (the 'd'). We do not know if interrupts were enabled |
750 | in the mean time. | 750 | in the mean time. |
751 | 751 | ||
752 | # tracer: preemptoff | 752 | # tracer: preemptoff |
753 | # | 753 | # |
754 | preemptoff latency trace v1.1.5 on 2.6.26-rc8 | 754 | preemptoff latency trace v1.1.5 on 2.6.26-rc8 |
755 | -------------------------------------------------------------------- | 755 | -------------------------------------------------------------------- |
756 | latency: 63 us, #87/87, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) | 756 | latency: 63 us, #87/87, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) |
757 | ----------------- | 757 | ----------------- |
758 | | task: sshd-4261 (uid:0 nice:0 policy:0 rt_prio:0) | 758 | | task: sshd-4261 (uid:0 nice:0 policy:0 rt_prio:0) |
759 | ----------------- | 759 | ----------------- |
760 | => started at: remove_wait_queue | 760 | => started at: remove_wait_queue |
761 | => ended at: __do_softirq | 761 | => ended at: __do_softirq |
762 | 762 | ||
763 | # _------=> CPU# | 763 | # _------=> CPU# |
764 | # / _-----=> irqs-off | 764 | # / _-----=> irqs-off |
765 | # | / _----=> need-resched | 765 | # | / _----=> need-resched |
766 | # || / _---=> hardirq/softirq | 766 | # || / _---=> hardirq/softirq |
767 | # ||| / _--=> preempt-depth | 767 | # ||| / _--=> preempt-depth |
768 | # |||| / | 768 | # |||| / |
769 | # ||||| delay | 769 | # ||||| delay |
770 | # cmd pid ||||| time | caller | 770 | # cmd pid ||||| time | caller |
771 | # \ / ||||| \ | / | 771 | # \ / ||||| \ | / |
772 | sshd-4261 0d..1 0us : _spin_lock_irqsave (remove_wait_queue) | 772 | sshd-4261 0d..1 0us : _spin_lock_irqsave (remove_wait_queue) |
773 | sshd-4261 0d..1 1us : _spin_unlock_irqrestore (remove_wait_queue) | 773 | sshd-4261 0d..1 1us : _spin_unlock_irqrestore (remove_wait_queue) |
774 | sshd-4261 0d..1 2us : do_IRQ (common_interrupt) | 774 | sshd-4261 0d..1 2us : do_IRQ (common_interrupt) |
775 | sshd-4261 0d..1 2us : irq_enter (do_IRQ) | 775 | sshd-4261 0d..1 2us : irq_enter (do_IRQ) |
776 | sshd-4261 0d..1 2us : idle_cpu (irq_enter) | 776 | sshd-4261 0d..1 2us : idle_cpu (irq_enter) |
777 | sshd-4261 0d..1 3us : add_preempt_count (irq_enter) | 777 | sshd-4261 0d..1 3us : add_preempt_count (irq_enter) |
778 | sshd-4261 0d.h1 3us : idle_cpu (irq_enter) | 778 | sshd-4261 0d.h1 3us : idle_cpu (irq_enter) |
779 | sshd-4261 0d.h. 4us : handle_fasteoi_irq (do_IRQ) | 779 | sshd-4261 0d.h. 4us : handle_fasteoi_irq (do_IRQ) |
780 | [...] | 780 | [...] |
781 | sshd-4261 0d.h. 12us : add_preempt_count (_spin_lock) | 781 | sshd-4261 0d.h. 12us : add_preempt_count (_spin_lock) |
782 | sshd-4261 0d.h1 12us : ack_ioapic_quirk_irq (handle_fasteoi_irq) | 782 | sshd-4261 0d.h1 12us : ack_ioapic_quirk_irq (handle_fasteoi_irq) |
783 | sshd-4261 0d.h1 13us : move_native_irq (ack_ioapic_quirk_irq) | 783 | sshd-4261 0d.h1 13us : move_native_irq (ack_ioapic_quirk_irq) |
784 | sshd-4261 0d.h1 13us : _spin_unlock (handle_fasteoi_irq) | 784 | sshd-4261 0d.h1 13us : _spin_unlock (handle_fasteoi_irq) |
785 | sshd-4261 0d.h1 14us : sub_preempt_count (_spin_unlock) | 785 | sshd-4261 0d.h1 14us : sub_preempt_count (_spin_unlock) |
786 | sshd-4261 0d.h1 14us : irq_exit (do_IRQ) | 786 | sshd-4261 0d.h1 14us : irq_exit (do_IRQ) |
787 | sshd-4261 0d.h1 15us : sub_preempt_count (irq_exit) | 787 | sshd-4261 0d.h1 15us : sub_preempt_count (irq_exit) |
788 | sshd-4261 0d..2 15us : do_softirq (irq_exit) | 788 | sshd-4261 0d..2 15us : do_softirq (irq_exit) |
789 | sshd-4261 0d... 15us : __do_softirq (do_softirq) | 789 | sshd-4261 0d... 15us : __do_softirq (do_softirq) |
790 | sshd-4261 0d... 16us : __local_bh_disable (__do_softirq) | 790 | sshd-4261 0d... 16us : __local_bh_disable (__do_softirq) |
791 | sshd-4261 0d... 16us+: add_preempt_count (__local_bh_disable) | 791 | sshd-4261 0d... 16us+: add_preempt_count (__local_bh_disable) |
792 | sshd-4261 0d.s4 20us : add_preempt_count (__local_bh_disable) | 792 | sshd-4261 0d.s4 20us : add_preempt_count (__local_bh_disable) |
793 | sshd-4261 0d.s4 21us : sub_preempt_count (local_bh_enable) | 793 | sshd-4261 0d.s4 21us : sub_preempt_count (local_bh_enable) |
794 | sshd-4261 0d.s5 21us : sub_preempt_count (local_bh_enable) | 794 | sshd-4261 0d.s5 21us : sub_preempt_count (local_bh_enable) |
795 | [...] | 795 | [...] |
796 | sshd-4261 0d.s6 41us : add_preempt_count (__local_bh_disable) | 796 | sshd-4261 0d.s6 41us : add_preempt_count (__local_bh_disable) |
797 | sshd-4261 0d.s6 42us : sub_preempt_count (local_bh_enable) | 797 | sshd-4261 0d.s6 42us : sub_preempt_count (local_bh_enable) |
798 | sshd-4261 0d.s7 42us : sub_preempt_count (local_bh_enable) | 798 | sshd-4261 0d.s7 42us : sub_preempt_count (local_bh_enable) |
799 | sshd-4261 0d.s5 43us : add_preempt_count (__local_bh_disable) | 799 | sshd-4261 0d.s5 43us : add_preempt_count (__local_bh_disable) |
800 | sshd-4261 0d.s5 43us : sub_preempt_count (local_bh_enable_ip) | 800 | sshd-4261 0d.s5 43us : sub_preempt_count (local_bh_enable_ip) |
801 | sshd-4261 0d.s6 44us : sub_preempt_count (local_bh_enable_ip) | 801 | sshd-4261 0d.s6 44us : sub_preempt_count (local_bh_enable_ip) |
802 | sshd-4261 0d.s5 44us : add_preempt_count (__local_bh_disable) | 802 | sshd-4261 0d.s5 44us : add_preempt_count (__local_bh_disable) |
803 | sshd-4261 0d.s5 45us : sub_preempt_count (local_bh_enable) | 803 | sshd-4261 0d.s5 45us : sub_preempt_count (local_bh_enable) |
804 | [...] | 804 | [...] |
805 | sshd-4261 0d.s. 63us : _local_bh_enable (__do_softirq) | 805 | sshd-4261 0d.s. 63us : _local_bh_enable (__do_softirq) |
806 | sshd-4261 0d.s1 64us : trace_preempt_on (__do_softirq) | 806 | sshd-4261 0d.s1 64us : trace_preempt_on (__do_softirq) |
807 | 807 | ||
808 | 808 | ||
809 | The above is an example of the preemptoff trace with | 809 | The above is an example of the preemptoff trace with |
810 | ftrace_enabled set. Here we see that interrupts were disabled | 810 | ftrace_enabled set. Here we see that interrupts were disabled |
811 | the entire time. The irq_enter code lets us know that we entered | 811 | the entire time. The irq_enter code lets us know that we entered |
812 | an interrupt 'h'. Before that, the functions being traced still | 812 | an interrupt 'h'. Before that, the functions being traced still |
813 | show that it is not in an interrupt, but we can see from the | 813 | show that it is not in an interrupt, but we can see from the |
814 | functions themselves that this is not the case. | 814 | functions themselves that this is not the case. |
815 | 815 | ||
816 | Notice that __do_softirq when called does not have a | 816 | Notice that __do_softirq when called does not have a |
817 | preempt_count. It may seem that we missed a preempt enabling. | 817 | preempt_count. It may seem that we missed a preempt enabling. |
818 | What really happened is that the preempt count is held on the | 818 | What really happened is that the preempt count is held on the |
819 | thread's stack and we switched to the softirq stack (4K stacks | 819 | thread's stack and we switched to the softirq stack (4K stacks |
820 | in effect). The code does not copy the preempt count, but | 820 | in effect). The code does not copy the preempt count, but |
821 | because interrupts are disabled, we do not need to worry about | 821 | because interrupts are disabled, we do not need to worry about |
822 | it. Having a tracer like this is good for letting people know | 822 | it. Having a tracer like this is good for letting people know |
823 | what really happens inside the kernel. | 823 | what really happens inside the kernel. |
824 | 824 | ||
825 | 825 | ||
826 | preemptirqsoff | 826 | preemptirqsoff |
827 | -------------- | 827 | -------------- |
828 | 828 | ||
829 | Knowing the locations that have interrupts disabled or | 829 | Knowing the locations that have interrupts disabled or |
830 | preemption disabled for the longest times is helpful. But | 830 | preemption disabled for the longest times is helpful. But |
831 | sometimes we would like to know when either preemption and/or | 831 | sometimes we would like to know when either preemption and/or |
832 | interrupts are disabled. | 832 | interrupts are disabled. |
833 | 833 | ||
834 | Consider the following code: | 834 | Consider the following code: |
835 | 835 | ||
836 | local_irq_disable(); | 836 | local_irq_disable(); |
837 | call_function_with_irqs_off(); | 837 | call_function_with_irqs_off(); |
838 | preempt_disable(); | 838 | preempt_disable(); |
839 | call_function_with_irqs_and_preemption_off(); | 839 | call_function_with_irqs_and_preemption_off(); |
840 | local_irq_enable(); | 840 | local_irq_enable(); |
841 | call_function_with_preemption_off(); | 841 | call_function_with_preemption_off(); |
842 | preempt_enable(); | 842 | preempt_enable(); |
843 | 843 | ||
844 | The irqsoff tracer will record the total length of | 844 | The irqsoff tracer will record the total length of |
845 | call_function_with_irqs_off() and | 845 | call_function_with_irqs_off() and |
846 | call_function_with_irqs_and_preemption_off(). | 846 | call_function_with_irqs_and_preemption_off(). |
847 | 847 | ||
848 | The preemptoff tracer will record the total length of | 848 | The preemptoff tracer will record the total length of |
849 | call_function_with_irqs_and_preemption_off() and | 849 | call_function_with_irqs_and_preemption_off() and |
850 | call_function_with_preemption_off(). | 850 | call_function_with_preemption_off(). |
851 | 851 | ||
852 | But neither will trace the time that interrupts and/or | 852 | But neither will trace the time that interrupts and/or |
853 | preemption is disabled. This total time is the time that we can | 853 | preemption is disabled. This total time is the time that we can |
854 | not schedule. To record this time, use the preemptirqsoff | 854 | not schedule. To record this time, use the preemptirqsoff |
855 | tracer. | 855 | tracer. |
856 | 856 | ||
857 | Again, using this trace is much like the irqsoff and preemptoff | 857 | Again, using this trace is much like the irqsoff and preemptoff |
858 | tracers. | 858 | tracers. |
859 | 859 | ||
860 | # echo preemptirqsoff > current_tracer | 860 | # echo preemptirqsoff > current_tracer |
861 | # echo latency-format > trace_options | 861 | # echo latency-format > trace_options |
862 | # echo 0 > tracing_max_latency | 862 | # echo 0 > tracing_max_latency |
863 | # echo 1 > tracing_enabled | 863 | # echo 1 > tracing_enabled |
864 | # ls -ltr | 864 | # ls -ltr |
865 | [...] | 865 | [...] |
866 | # echo 0 > tracing_enabled | 866 | # echo 0 > tracing_enabled |
867 | # cat trace | 867 | # cat trace |
868 | # tracer: preemptirqsoff | 868 | # tracer: preemptirqsoff |
869 | # | 869 | # |
870 | preemptirqsoff latency trace v1.1.5 on 2.6.26-rc8 | 870 | preemptirqsoff latency trace v1.1.5 on 2.6.26-rc8 |
871 | -------------------------------------------------------------------- | 871 | -------------------------------------------------------------------- |
872 | latency: 293 us, #3/3, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) | 872 | latency: 293 us, #3/3, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) |
873 | ----------------- | 873 | ----------------- |
874 | | task: ls-4860 (uid:0 nice:0 policy:0 rt_prio:0) | 874 | | task: ls-4860 (uid:0 nice:0 policy:0 rt_prio:0) |
875 | ----------------- | 875 | ----------------- |
876 | => started at: apic_timer_interrupt | 876 | => started at: apic_timer_interrupt |
877 | => ended at: __do_softirq | 877 | => ended at: __do_softirq |
878 | 878 | ||
879 | # _------=> CPU# | 879 | # _------=> CPU# |
880 | # / _-----=> irqs-off | 880 | # / _-----=> irqs-off |
881 | # | / _----=> need-resched | 881 | # | / _----=> need-resched |
882 | # || / _---=> hardirq/softirq | 882 | # || / _---=> hardirq/softirq |
883 | # ||| / _--=> preempt-depth | 883 | # ||| / _--=> preempt-depth |
884 | # |||| / | 884 | # |||| / |
885 | # ||||| delay | 885 | # ||||| delay |
886 | # cmd pid ||||| time | caller | 886 | # cmd pid ||||| time | caller |
887 | # \ / ||||| \ | / | 887 | # \ / ||||| \ | / |
888 | ls-4860 0d... 0us!: trace_hardirqs_off_thunk (apic_timer_interrupt) | 888 | ls-4860 0d... 0us!: trace_hardirqs_off_thunk (apic_timer_interrupt) |
889 | ls-4860 0d.s. 294us : _local_bh_enable (__do_softirq) | 889 | ls-4860 0d.s. 294us : _local_bh_enable (__do_softirq) |
890 | ls-4860 0d.s1 294us : trace_preempt_on (__do_softirq) | 890 | ls-4860 0d.s1 294us : trace_preempt_on (__do_softirq) |
891 | 891 | ||
892 | 892 | ||
893 | 893 | ||
894 | The trace_hardirqs_off_thunk is called from assembly on x86 when | 894 | The trace_hardirqs_off_thunk is called from assembly on x86 when |
895 | interrupts are disabled in the assembly code. Without the | 895 | interrupts are disabled in the assembly code. Without the |
896 | function tracing, we do not know if interrupts were enabled | 896 | function tracing, we do not know if interrupts were enabled |
897 | within the preemption points. We do see that it started with | 897 | within the preemption points. We do see that it started with |
898 | preemption enabled. | 898 | preemption enabled. |
899 | 899 | ||
900 | Here is a trace with ftrace_enabled set: | 900 | Here is a trace with ftrace_enabled set: |
901 | 901 | ||
902 | 902 | ||
903 | # tracer: preemptirqsoff | 903 | # tracer: preemptirqsoff |
904 | # | 904 | # |
905 | preemptirqsoff latency trace v1.1.5 on 2.6.26-rc8 | 905 | preemptirqsoff latency trace v1.1.5 on 2.6.26-rc8 |
906 | -------------------------------------------------------------------- | 906 | -------------------------------------------------------------------- |
907 | latency: 105 us, #183/183, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) | 907 | latency: 105 us, #183/183, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) |
908 | ----------------- | 908 | ----------------- |
909 | | task: sshd-4261 (uid:0 nice:0 policy:0 rt_prio:0) | 909 | | task: sshd-4261 (uid:0 nice:0 policy:0 rt_prio:0) |
910 | ----------------- | 910 | ----------------- |
911 | => started at: write_chan | 911 | => started at: write_chan |
912 | => ended at: __do_softirq | 912 | => ended at: __do_softirq |
913 | 913 | ||
914 | # _------=> CPU# | 914 | # _------=> CPU# |
915 | # / _-----=> irqs-off | 915 | # / _-----=> irqs-off |
916 | # | / _----=> need-resched | 916 | # | / _----=> need-resched |
917 | # || / _---=> hardirq/softirq | 917 | # || / _---=> hardirq/softirq |
918 | # ||| / _--=> preempt-depth | 918 | # ||| / _--=> preempt-depth |
919 | # |||| / | 919 | # |||| / |
920 | # ||||| delay | 920 | # ||||| delay |
921 | # cmd pid ||||| time | caller | 921 | # cmd pid ||||| time | caller |
922 | # \ / ||||| \ | / | 922 | # \ / ||||| \ | / |
923 | ls-4473 0.N.. 0us : preempt_schedule (write_chan) | 923 | ls-4473 0.N.. 0us : preempt_schedule (write_chan) |
924 | ls-4473 0dN.1 1us : _spin_lock (schedule) | 924 | ls-4473 0dN.1 1us : _spin_lock (schedule) |
925 | ls-4473 0dN.1 2us : add_preempt_count (_spin_lock) | 925 | ls-4473 0dN.1 2us : add_preempt_count (_spin_lock) |
926 | ls-4473 0d..2 2us : put_prev_task_fair (schedule) | 926 | ls-4473 0d..2 2us : put_prev_task_fair (schedule) |
927 | [...] | 927 | [...] |
928 | ls-4473 0d..2 13us : set_normalized_timespec (ktime_get_ts) | 928 | ls-4473 0d..2 13us : set_normalized_timespec (ktime_get_ts) |
929 | ls-4473 0d..2 13us : __switch_to (schedule) | 929 | ls-4473 0d..2 13us : __switch_to (schedule) |
930 | sshd-4261 0d..2 14us : finish_task_switch (schedule) | 930 | sshd-4261 0d..2 14us : finish_task_switch (schedule) |
931 | sshd-4261 0d..2 14us : _spin_unlock_irq (finish_task_switch) | 931 | sshd-4261 0d..2 14us : _spin_unlock_irq (finish_task_switch) |
932 | sshd-4261 0d..1 15us : add_preempt_count (_spin_lock_irqsave) | 932 | sshd-4261 0d..1 15us : add_preempt_count (_spin_lock_irqsave) |
933 | sshd-4261 0d..2 16us : _spin_unlock_irqrestore (hrtick_set) | 933 | sshd-4261 0d..2 16us : _spin_unlock_irqrestore (hrtick_set) |
934 | sshd-4261 0d..2 16us : do_IRQ (common_interrupt) | 934 | sshd-4261 0d..2 16us : do_IRQ (common_interrupt) |
935 | sshd-4261 0d..2 17us : irq_enter (do_IRQ) | 935 | sshd-4261 0d..2 17us : irq_enter (do_IRQ) |
936 | sshd-4261 0d..2 17us : idle_cpu (irq_enter) | 936 | sshd-4261 0d..2 17us : idle_cpu (irq_enter) |
937 | sshd-4261 0d..2 18us : add_preempt_count (irq_enter) | 937 | sshd-4261 0d..2 18us : add_preempt_count (irq_enter) |
938 | sshd-4261 0d.h2 18us : idle_cpu (irq_enter) | 938 | sshd-4261 0d.h2 18us : idle_cpu (irq_enter) |
939 | sshd-4261 0d.h. 18us : handle_fasteoi_irq (do_IRQ) | 939 | sshd-4261 0d.h. 18us : handle_fasteoi_irq (do_IRQ) |
940 | sshd-4261 0d.h. 19us : _spin_lock (handle_fasteoi_irq) | 940 | sshd-4261 0d.h. 19us : _spin_lock (handle_fasteoi_irq) |
941 | sshd-4261 0d.h. 19us : add_preempt_count (_spin_lock) | 941 | sshd-4261 0d.h. 19us : add_preempt_count (_spin_lock) |
942 | sshd-4261 0d.h1 20us : _spin_unlock (handle_fasteoi_irq) | 942 | sshd-4261 0d.h1 20us : _spin_unlock (handle_fasteoi_irq) |
943 | sshd-4261 0d.h1 20us : sub_preempt_count (_spin_unlock) | 943 | sshd-4261 0d.h1 20us : sub_preempt_count (_spin_unlock) |
944 | [...] | 944 | [...] |
945 | sshd-4261 0d.h1 28us : _spin_unlock (handle_fasteoi_irq) | 945 | sshd-4261 0d.h1 28us : _spin_unlock (handle_fasteoi_irq) |
946 | sshd-4261 0d.h1 29us : sub_preempt_count (_spin_unlock) | 946 | sshd-4261 0d.h1 29us : sub_preempt_count (_spin_unlock) |
947 | sshd-4261 0d.h2 29us : irq_exit (do_IRQ) | 947 | sshd-4261 0d.h2 29us : irq_exit (do_IRQ) |
948 | sshd-4261 0d.h2 29us : sub_preempt_count (irq_exit) | 948 | sshd-4261 0d.h2 29us : sub_preempt_count (irq_exit) |
949 | sshd-4261 0d..3 30us : do_softirq (irq_exit) | 949 | sshd-4261 0d..3 30us : do_softirq (irq_exit) |
950 | sshd-4261 0d... 30us : __do_softirq (do_softirq) | 950 | sshd-4261 0d... 30us : __do_softirq (do_softirq) |
951 | sshd-4261 0d... 31us : __local_bh_disable (__do_softirq) | 951 | sshd-4261 0d... 31us : __local_bh_disable (__do_softirq) |
952 | sshd-4261 0d... 31us+: add_preempt_count (__local_bh_disable) | 952 | sshd-4261 0d... 31us+: add_preempt_count (__local_bh_disable) |
953 | sshd-4261 0d.s4 34us : add_preempt_count (__local_bh_disable) | 953 | sshd-4261 0d.s4 34us : add_preempt_count (__local_bh_disable) |
954 | [...] | 954 | [...] |
955 | sshd-4261 0d.s3 43us : sub_preempt_count (local_bh_enable_ip) | 955 | sshd-4261 0d.s3 43us : sub_preempt_count (local_bh_enable_ip) |
956 | sshd-4261 0d.s4 44us : sub_preempt_count (local_bh_enable_ip) | 956 | sshd-4261 0d.s4 44us : sub_preempt_count (local_bh_enable_ip) |
957 | sshd-4261 0d.s3 44us : smp_apic_timer_interrupt (apic_timer_interrupt) | 957 | sshd-4261 0d.s3 44us : smp_apic_timer_interrupt (apic_timer_interrupt) |
958 | sshd-4261 0d.s3 45us : irq_enter (smp_apic_timer_interrupt) | 958 | sshd-4261 0d.s3 45us : irq_enter (smp_apic_timer_interrupt) |
959 | sshd-4261 0d.s3 45us : idle_cpu (irq_enter) | 959 | sshd-4261 0d.s3 45us : idle_cpu (irq_enter) |
960 | sshd-4261 0d.s3 46us : add_preempt_count (irq_enter) | 960 | sshd-4261 0d.s3 46us : add_preempt_count (irq_enter) |
961 | sshd-4261 0d.H3 46us : idle_cpu (irq_enter) | 961 | sshd-4261 0d.H3 46us : idle_cpu (irq_enter) |
962 | sshd-4261 0d.H3 47us : hrtimer_interrupt (smp_apic_timer_interrupt) | 962 | sshd-4261 0d.H3 47us : hrtimer_interrupt (smp_apic_timer_interrupt) |
963 | sshd-4261 0d.H3 47us : ktime_get (hrtimer_interrupt) | 963 | sshd-4261 0d.H3 47us : ktime_get (hrtimer_interrupt) |
964 | [...] | 964 | [...] |
965 | sshd-4261 0d.H3 81us : tick_program_event (hrtimer_interrupt) | 965 | sshd-4261 0d.H3 81us : tick_program_event (hrtimer_interrupt) |
966 | sshd-4261 0d.H3 82us : ktime_get (tick_program_event) | 966 | sshd-4261 0d.H3 82us : ktime_get (tick_program_event) |
967 | sshd-4261 0d.H3 82us : ktime_get_ts (ktime_get) | 967 | sshd-4261 0d.H3 82us : ktime_get_ts (ktime_get) |
968 | sshd-4261 0d.H3 83us : getnstimeofday (ktime_get_ts) | 968 | sshd-4261 0d.H3 83us : getnstimeofday (ktime_get_ts) |
969 | sshd-4261 0d.H3 83us : set_normalized_timespec (ktime_get_ts) | 969 | sshd-4261 0d.H3 83us : set_normalized_timespec (ktime_get_ts) |
970 | sshd-4261 0d.H3 84us : clockevents_program_event (tick_program_event) | 970 | sshd-4261 0d.H3 84us : clockevents_program_event (tick_program_event) |
971 | sshd-4261 0d.H3 84us : lapic_next_event (clockevents_program_event) | 971 | sshd-4261 0d.H3 84us : lapic_next_event (clockevents_program_event) |
972 | sshd-4261 0d.H3 85us : irq_exit (smp_apic_timer_interrupt) | 972 | sshd-4261 0d.H3 85us : irq_exit (smp_apic_timer_interrupt) |
973 | sshd-4261 0d.H3 85us : sub_preempt_count (irq_exit) | 973 | sshd-4261 0d.H3 85us : sub_preempt_count (irq_exit) |
974 | sshd-4261 0d.s4 86us : sub_preempt_count (irq_exit) | 974 | sshd-4261 0d.s4 86us : sub_preempt_count (irq_exit) |
975 | sshd-4261 0d.s3 86us : add_preempt_count (__local_bh_disable) | 975 | sshd-4261 0d.s3 86us : add_preempt_count (__local_bh_disable) |
976 | [...] | 976 | [...] |
977 | sshd-4261 0d.s1 98us : sub_preempt_count (net_rx_action) | 977 | sshd-4261 0d.s1 98us : sub_preempt_count (net_rx_action) |
978 | sshd-4261 0d.s. 99us : add_preempt_count (_spin_lock_irq) | 978 | sshd-4261 0d.s. 99us : add_preempt_count (_spin_lock_irq) |
979 | sshd-4261 0d.s1 99us+: _spin_unlock_irq (run_timer_softirq) | 979 | sshd-4261 0d.s1 99us+: _spin_unlock_irq (run_timer_softirq) |
980 | sshd-4261 0d.s. 104us : _local_bh_enable (__do_softirq) | 980 | sshd-4261 0d.s. 104us : _local_bh_enable (__do_softirq) |
981 | sshd-4261 0d.s. 104us : sub_preempt_count (_local_bh_enable) | 981 | sshd-4261 0d.s. 104us : sub_preempt_count (_local_bh_enable) |
982 | sshd-4261 0d.s. 105us : _local_bh_enable (__do_softirq) | 982 | sshd-4261 0d.s. 105us : _local_bh_enable (__do_softirq) |
983 | sshd-4261 0d.s1 105us : trace_preempt_on (__do_softirq) | 983 | sshd-4261 0d.s1 105us : trace_preempt_on (__do_softirq) |
984 | 984 | ||
985 | 985 | ||
986 | This is a very interesting trace. It started with the preemption | 986 | This is a very interesting trace. It started with the preemption |
987 | of the ls task. We see that the task had the "need_resched" bit | 987 | of the ls task. We see that the task had the "need_resched" bit |
988 | set via the 'N' in the trace. Interrupts were disabled before | 988 | set via the 'N' in the trace. Interrupts were disabled before |
989 | the spin_lock at the beginning of the trace. We see that a | 989 | the spin_lock at the beginning of the trace. We see that a |
990 | schedule took place to run sshd. When the interrupts were | 990 | schedule took place to run sshd. When the interrupts were |
991 | enabled, we took an interrupt. On return from the interrupt | 991 | enabled, we took an interrupt. On return from the interrupt |
992 | handler, the softirq ran. We took another interrupt while | 992 | handler, the softirq ran. We took another interrupt while |
993 | running the softirq as we see from the capital 'H'. | 993 | running the softirq as we see from the capital 'H'. |
994 | 994 | ||
995 | 995 | ||
996 | wakeup | 996 | wakeup |
997 | ------ | 997 | ------ |
998 | 998 | ||
999 | In a Real-Time environment it is very important to know the | 999 | In a Real-Time environment it is very important to know the |
1000 | wakeup time it takes for the highest priority task that is woken | 1000 | wakeup time it takes for the highest priority task that is woken |
1001 | up to the time that it executes. This is also known as "schedule | 1001 | up to the time that it executes. This is also known as "schedule |
1002 | latency". I stress the point that this is about RT tasks. It is | 1002 | latency". I stress the point that this is about RT tasks. It is |
1003 | also important to know the scheduling latency of non-RT tasks, | 1003 | also important to know the scheduling latency of non-RT tasks, |
1004 | but the average schedule latency is better for non-RT tasks. | 1004 | but the average schedule latency is better for non-RT tasks. |
1005 | Tools like LatencyTop are more appropriate for such | 1005 | Tools like LatencyTop are more appropriate for such |
1006 | measurements. | 1006 | measurements. |
1007 | 1007 | ||
1008 | Real-Time environments are interested in the worst case latency. | 1008 | Real-Time environments are interested in the worst case latency. |
1009 | That is the longest latency it takes for something to happen, | 1009 | That is the longest latency it takes for something to happen, |
1010 | and not the average. We can have a very fast scheduler that may | 1010 | and not the average. We can have a very fast scheduler that may |
1011 | only have a large latency once in a while, but that would not | 1011 | only have a large latency once in a while, but that would not |
1012 | work well with Real-Time tasks. The wakeup tracer was designed | 1012 | work well with Real-Time tasks. The wakeup tracer was designed |
1013 | to record the worst case wakeups of RT tasks. Non-RT tasks are | 1013 | to record the worst case wakeups of RT tasks. Non-RT tasks are |
1014 | not recorded because the tracer only records one worst case and | 1014 | not recorded because the tracer only records one worst case and |
1015 | tracing non-RT tasks that are unpredictable will overwrite the | 1015 | tracing non-RT tasks that are unpredictable will overwrite the |
1016 | worst case latency of RT tasks. | 1016 | worst case latency of RT tasks. |
1017 | 1017 | ||
1018 | Since this tracer only deals with RT tasks, we will run this | 1018 | Since this tracer only deals with RT tasks, we will run this |
1019 | slightly differently than we did with the previous tracers. | 1019 | slightly differently than we did with the previous tracers. |
1020 | Instead of performing an 'ls', we will run 'sleep 1' under | 1020 | Instead of performing an 'ls', we will run 'sleep 1' under |
1021 | 'chrt' which changes the priority of the task. | 1021 | 'chrt' which changes the priority of the task. |
1022 | 1022 | ||
1023 | # echo wakeup > current_tracer | 1023 | # echo wakeup > current_tracer |
1024 | # echo latency-format > trace_options | 1024 | # echo latency-format > trace_options |
1025 | # echo 0 > tracing_max_latency | 1025 | # echo 0 > tracing_max_latency |
1026 | # echo 1 > tracing_enabled | 1026 | # echo 1 > tracing_enabled |
1027 | # chrt -f 5 sleep 1 | 1027 | # chrt -f 5 sleep 1 |
1028 | # echo 0 > tracing_enabled | 1028 | # echo 0 > tracing_enabled |
1029 | # cat trace | 1029 | # cat trace |
1030 | # tracer: wakeup | 1030 | # tracer: wakeup |
1031 | # | 1031 | # |
1032 | wakeup latency trace v1.1.5 on 2.6.26-rc8 | 1032 | wakeup latency trace v1.1.5 on 2.6.26-rc8 |
1033 | -------------------------------------------------------------------- | 1033 | -------------------------------------------------------------------- |
1034 | latency: 4 us, #2/2, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) | 1034 | latency: 4 us, #2/2, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) |
1035 | ----------------- | 1035 | ----------------- |
1036 | | task: sleep-4901 (uid:0 nice:0 policy:1 rt_prio:5) | 1036 | | task: sleep-4901 (uid:0 nice:0 policy:1 rt_prio:5) |
1037 | ----------------- | 1037 | ----------------- |
1038 | 1038 | ||
1039 | # _------=> CPU# | 1039 | # _------=> CPU# |
1040 | # / _-----=> irqs-off | 1040 | # / _-----=> irqs-off |
1041 | # | / _----=> need-resched | 1041 | # | / _----=> need-resched |
1042 | # || / _---=> hardirq/softirq | 1042 | # || / _---=> hardirq/softirq |
1043 | # ||| / _--=> preempt-depth | 1043 | # ||| / _--=> preempt-depth |
1044 | # |||| / | 1044 | # |||| / |
1045 | # ||||| delay | 1045 | # ||||| delay |
1046 | # cmd pid ||||| time | caller | 1046 | # cmd pid ||||| time | caller |
1047 | # \ / ||||| \ | / | 1047 | # \ / ||||| \ | / |
1048 | <idle>-0 1d.h4 0us+: try_to_wake_up (wake_up_process) | 1048 | <idle>-0 1d.h4 0us+: try_to_wake_up (wake_up_process) |
1049 | <idle>-0 1d..4 4us : schedule (cpu_idle) | 1049 | <idle>-0 1d..4 4us : schedule (cpu_idle) |
1050 | 1050 | ||
1051 | 1051 | ||
1052 | Running this on an idle system, we see that it only took 4 | 1052 | Running this on an idle system, we see that it only took 4 |
1053 | microseconds to perform the task switch. Note, since the trace | 1053 | microseconds to perform the task switch. Note, since the trace |
1054 | marker in the schedule is before the actual "switch", we stop | 1054 | marker in the schedule is before the actual "switch", we stop |
1055 | the tracing when the recorded task is about to schedule in. This | 1055 | the tracing when the recorded task is about to schedule in. This |
1056 | may change if we add a new marker at the end of the scheduler. | 1056 | may change if we add a new marker at the end of the scheduler. |
1057 | 1057 | ||
1058 | Notice that the recorded task is 'sleep' with the PID of 4901 | 1058 | Notice that the recorded task is 'sleep' with the PID of 4901 |
1059 | and it has an rt_prio of 5. This priority is user-space priority | 1059 | and it has an rt_prio of 5. This priority is user-space priority |
1060 | and not the internal kernel priority. The policy is 1 for | 1060 | and not the internal kernel priority. The policy is 1 for |
1061 | SCHED_FIFO and 2 for SCHED_RR. | 1061 | SCHED_FIFO and 2 for SCHED_RR. |
1062 | 1062 | ||
1063 | Doing the same with chrt -r 5 and ftrace_enabled set. | 1063 | Doing the same with chrt -r 5 and ftrace_enabled set. |
1064 | 1064 | ||
1065 | # tracer: wakeup | 1065 | # tracer: wakeup |
1066 | # | 1066 | # |
1067 | wakeup latency trace v1.1.5 on 2.6.26-rc8 | 1067 | wakeup latency trace v1.1.5 on 2.6.26-rc8 |
1068 | -------------------------------------------------------------------- | 1068 | -------------------------------------------------------------------- |
1069 | latency: 50 us, #60/60, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) | 1069 | latency: 50 us, #60/60, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2) |
1070 | ----------------- | 1070 | ----------------- |
1071 | | task: sleep-4068 (uid:0 nice:0 policy:2 rt_prio:5) | 1071 | | task: sleep-4068 (uid:0 nice:0 policy:2 rt_prio:5) |
1072 | ----------------- | 1072 | ----------------- |
1073 | 1073 | ||
1074 | # _------=> CPU# | 1074 | # _------=> CPU# |
1075 | # / _-----=> irqs-off | 1075 | # / _-----=> irqs-off |
1076 | # | / _----=> need-resched | 1076 | # | / _----=> need-resched |
1077 | # || / _---=> hardirq/softirq | 1077 | # || / _---=> hardirq/softirq |
1078 | # ||| / _--=> preempt-depth | 1078 | # ||| / _--=> preempt-depth |
1079 | # |||| / | 1079 | # |||| / |
1080 | # ||||| delay | 1080 | # ||||| delay |
1081 | # cmd pid ||||| time | caller | 1081 | # cmd pid ||||| time | caller |
1082 | # \ / ||||| \ | / | 1082 | # \ / ||||| \ | / |
1083 | ksoftirq-7 1d.H3 0us : try_to_wake_up (wake_up_process) | 1083 | ksoftirq-7 1d.H3 0us : try_to_wake_up (wake_up_process) |
1084 | ksoftirq-7 1d.H4 1us : sub_preempt_count (marker_probe_cb) | 1084 | ksoftirq-7 1d.H4 1us : sub_preempt_count (marker_probe_cb) |
1085 | ksoftirq-7 1d.H3 2us : check_preempt_wakeup (try_to_wake_up) | 1085 | ksoftirq-7 1d.H3 2us : check_preempt_wakeup (try_to_wake_up) |
1086 | ksoftirq-7 1d.H3 3us : update_curr (check_preempt_wakeup) | 1086 | ksoftirq-7 1d.H3 3us : update_curr (check_preempt_wakeup) |
1087 | ksoftirq-7 1d.H3 4us : calc_delta_mine (update_curr) | 1087 | ksoftirq-7 1d.H3 4us : calc_delta_mine (update_curr) |
1088 | ksoftirq-7 1d.H3 5us : __resched_task (check_preempt_wakeup) | 1088 | ksoftirq-7 1d.H3 5us : __resched_task (check_preempt_wakeup) |
1089 | ksoftirq-7 1d.H3 6us : task_wake_up_rt (try_to_wake_up) | 1089 | ksoftirq-7 1d.H3 6us : task_wake_up_rt (try_to_wake_up) |
1090 | ksoftirq-7 1d.H3 7us : _spin_unlock_irqrestore (try_to_wake_up) | 1090 | ksoftirq-7 1d.H3 7us : _spin_unlock_irqrestore (try_to_wake_up) |
1091 | [...] | 1091 | [...] |
1092 | ksoftirq-7 1d.H2 17us : irq_exit (smp_apic_timer_interrupt) | 1092 | ksoftirq-7 1d.H2 17us : irq_exit (smp_apic_timer_interrupt) |
1093 | ksoftirq-7 1d.H2 18us : sub_preempt_count (irq_exit) | 1093 | ksoftirq-7 1d.H2 18us : sub_preempt_count (irq_exit) |
1094 | ksoftirq-7 1d.s3 19us : sub_preempt_count (irq_exit) | 1094 | ksoftirq-7 1d.s3 19us : sub_preempt_count (irq_exit) |
1095 | ksoftirq-7 1..s2 20us : rcu_process_callbacks (__do_softirq) | 1095 | ksoftirq-7 1..s2 20us : rcu_process_callbacks (__do_softirq) |
1096 | [...] | 1096 | [...] |
1097 | ksoftirq-7 1..s2 26us : __rcu_process_callbacks (rcu_process_callbacks) | 1097 | ksoftirq-7 1..s2 26us : __rcu_process_callbacks (rcu_process_callbacks) |
1098 | ksoftirq-7 1d.s2 27us : _local_bh_enable (__do_softirq) | 1098 | ksoftirq-7 1d.s2 27us : _local_bh_enable (__do_softirq) |
1099 | ksoftirq-7 1d.s2 28us : sub_preempt_count (_local_bh_enable) | 1099 | ksoftirq-7 1d.s2 28us : sub_preempt_count (_local_bh_enable) |
1100 | ksoftirq-7 1.N.3 29us : sub_preempt_count (ksoftirqd) | 1100 | ksoftirq-7 1.N.3 29us : sub_preempt_count (ksoftirqd) |
1101 | ksoftirq-7 1.N.2 30us : _cond_resched (ksoftirqd) | 1101 | ksoftirq-7 1.N.2 30us : _cond_resched (ksoftirqd) |
1102 | ksoftirq-7 1.N.2 31us : __cond_resched (_cond_resched) | 1102 | ksoftirq-7 1.N.2 31us : __cond_resched (_cond_resched) |
1103 | ksoftirq-7 1.N.2 32us : add_preempt_count (__cond_resched) | 1103 | ksoftirq-7 1.N.2 32us : add_preempt_count (__cond_resched) |
1104 | ksoftirq-7 1.N.2 33us : schedule (__cond_resched) | 1104 | ksoftirq-7 1.N.2 33us : schedule (__cond_resched) |
1105 | ksoftirq-7 1.N.2 33us : add_preempt_count (schedule) | 1105 | ksoftirq-7 1.N.2 33us : add_preempt_count (schedule) |
1106 | ksoftirq-7 1.N.3 34us : hrtick_clear (schedule) | 1106 | ksoftirq-7 1.N.3 34us : hrtick_clear (schedule) |
1107 | ksoftirq-7 1dN.3 35us : _spin_lock (schedule) | 1107 | ksoftirq-7 1dN.3 35us : _spin_lock (schedule) |
1108 | ksoftirq-7 1dN.3 36us : add_preempt_count (_spin_lock) | 1108 | ksoftirq-7 1dN.3 36us : add_preempt_count (_spin_lock) |
1109 | ksoftirq-7 1d..4 37us : put_prev_task_fair (schedule) | 1109 | ksoftirq-7 1d..4 37us : put_prev_task_fair (schedule) |
1110 | ksoftirq-7 1d..4 38us : update_curr (put_prev_task_fair) | 1110 | ksoftirq-7 1d..4 38us : update_curr (put_prev_task_fair) |
1111 | [...] | 1111 | [...] |
1112 | ksoftirq-7 1d..5 47us : _spin_trylock (tracing_record_cmdline) | 1112 | ksoftirq-7 1d..5 47us : _spin_trylock (tracing_record_cmdline) |
1113 | ksoftirq-7 1d..5 48us : add_preempt_count (_spin_trylock) | 1113 | ksoftirq-7 1d..5 48us : add_preempt_count (_spin_trylock) |
1114 | ksoftirq-7 1d..6 49us : _spin_unlock (tracing_record_cmdline) | 1114 | ksoftirq-7 1d..6 49us : _spin_unlock (tracing_record_cmdline) |
1115 | ksoftirq-7 1d..6 49us : sub_preempt_count (_spin_unlock) | 1115 | ksoftirq-7 1d..6 49us : sub_preempt_count (_spin_unlock) |
1116 | ksoftirq-7 1d..4 50us : schedule (__cond_resched) | 1116 | ksoftirq-7 1d..4 50us : schedule (__cond_resched) |
1117 | 1117 | ||
1118 | The interrupt went off while running ksoftirqd. This task runs | 1118 | The interrupt went off while running ksoftirqd. This task runs |
1119 | at SCHED_OTHER. Why did not we see the 'N' set early? This may | 1119 | at SCHED_OTHER. Why did not we see the 'N' set early? This may |
1120 | be a harmless bug with x86_32 and 4K stacks. On x86_32 with 4K | 1120 | be a harmless bug with x86_32 and 4K stacks. On x86_32 with 4K |
1121 | stacks configured, the interrupt and softirq run with their own | 1121 | stacks configured, the interrupt and softirq run with their own |
1122 | stack. Some information is held on the top of the task's stack | 1122 | stack. Some information is held on the top of the task's stack |
1123 | (need_resched and preempt_count are both stored there). The | 1123 | (need_resched and preempt_count are both stored there). The |
1124 | setting of the NEED_RESCHED bit is done directly to the task's | 1124 | setting of the NEED_RESCHED bit is done directly to the task's |
1125 | stack, but the reading of the NEED_RESCHED is done by looking at | 1125 | stack, but the reading of the NEED_RESCHED is done by looking at |
1126 | the current stack, which in this case is the stack for the hard | 1126 | the current stack, which in this case is the stack for the hard |
1127 | interrupt. This hides the fact that NEED_RESCHED has been set. | 1127 | interrupt. This hides the fact that NEED_RESCHED has been set. |
1128 | We do not see the 'N' until we switch back to the task's | 1128 | We do not see the 'N' until we switch back to the task's |
1129 | assigned stack. | 1129 | assigned stack. |
1130 | 1130 | ||
1131 | function | 1131 | function |
1132 | -------- | 1132 | -------- |
1133 | 1133 | ||
1134 | This tracer is the function tracer. Enabling the function tracer | 1134 | This tracer is the function tracer. Enabling the function tracer |
1135 | can be done from the debug file system. Make sure the | 1135 | can be done from the debug file system. Make sure the |
1136 | ftrace_enabled is set; otherwise this tracer is a nop. | 1136 | ftrace_enabled is set; otherwise this tracer is a nop. |
1137 | 1137 | ||
1138 | # sysctl kernel.ftrace_enabled=1 | 1138 | # sysctl kernel.ftrace_enabled=1 |
1139 | # echo function > current_tracer | 1139 | # echo function > current_tracer |
1140 | # echo 1 > tracing_enabled | 1140 | # echo 1 > tracing_enabled |
1141 | # usleep 1 | 1141 | # usleep 1 |
1142 | # echo 0 > tracing_enabled | 1142 | # echo 0 > tracing_enabled |
1143 | # cat trace | 1143 | # cat trace |
1144 | # tracer: function | 1144 | # tracer: function |
1145 | # | 1145 | # |
1146 | # TASK-PID CPU# TIMESTAMP FUNCTION | 1146 | # TASK-PID CPU# TIMESTAMP FUNCTION |
1147 | # | | | | | | 1147 | # | | | | | |
1148 | bash-4003 [00] 123.638713: finish_task_switch <-schedule | 1148 | bash-4003 [00] 123.638713: finish_task_switch <-schedule |
1149 | bash-4003 [00] 123.638714: _spin_unlock_irq <-finish_task_switch | 1149 | bash-4003 [00] 123.638714: _spin_unlock_irq <-finish_task_switch |
1150 | bash-4003 [00] 123.638714: sub_preempt_count <-_spin_unlock_irq | 1150 | bash-4003 [00] 123.638714: sub_preempt_count <-_spin_unlock_irq |
1151 | bash-4003 [00] 123.638715: hrtick_set <-schedule | 1151 | bash-4003 [00] 123.638715: hrtick_set <-schedule |
1152 | bash-4003 [00] 123.638715: _spin_lock_irqsave <-hrtick_set | 1152 | bash-4003 [00] 123.638715: _spin_lock_irqsave <-hrtick_set |
1153 | bash-4003 [00] 123.638716: add_preempt_count <-_spin_lock_irqsave | 1153 | bash-4003 [00] 123.638716: add_preempt_count <-_spin_lock_irqsave |
1154 | bash-4003 [00] 123.638716: _spin_unlock_irqrestore <-hrtick_set | 1154 | bash-4003 [00] 123.638716: _spin_unlock_irqrestore <-hrtick_set |
1155 | bash-4003 [00] 123.638717: sub_preempt_count <-_spin_unlock_irqrestore | 1155 | bash-4003 [00] 123.638717: sub_preempt_count <-_spin_unlock_irqrestore |
1156 | bash-4003 [00] 123.638717: hrtick_clear <-hrtick_set | 1156 | bash-4003 [00] 123.638717: hrtick_clear <-hrtick_set |
1157 | bash-4003 [00] 123.638718: sub_preempt_count <-schedule | 1157 | bash-4003 [00] 123.638718: sub_preempt_count <-schedule |
1158 | bash-4003 [00] 123.638718: sub_preempt_count <-preempt_schedule | 1158 | bash-4003 [00] 123.638718: sub_preempt_count <-preempt_schedule |
1159 | bash-4003 [00] 123.638719: wait_for_completion <-__stop_machine_run | 1159 | bash-4003 [00] 123.638719: wait_for_completion <-__stop_machine_run |
1160 | bash-4003 [00] 123.638719: wait_for_common <-wait_for_completion | 1160 | bash-4003 [00] 123.638719: wait_for_common <-wait_for_completion |
1161 | bash-4003 [00] 123.638720: _spin_lock_irq <-wait_for_common | 1161 | bash-4003 [00] 123.638720: _spin_lock_irq <-wait_for_common |
1162 | bash-4003 [00] 123.638720: add_preempt_count <-_spin_lock_irq | 1162 | bash-4003 [00] 123.638720: add_preempt_count <-_spin_lock_irq |
1163 | [...] | 1163 | [...] |
1164 | 1164 | ||
1165 | 1165 | ||
1166 | Note: function tracer uses ring buffers to store the above | 1166 | Note: function tracer uses ring buffers to store the above |
1167 | entries. The newest data may overwrite the oldest data. | 1167 | entries. The newest data may overwrite the oldest data. |
1168 | Sometimes using echo to stop the trace is not sufficient because | 1168 | Sometimes using echo to stop the trace is not sufficient because |
1169 | the tracing could have overwritten the data that you wanted to | 1169 | the tracing could have overwritten the data that you wanted to |
1170 | record. For this reason, it is sometimes better to disable | 1170 | record. For this reason, it is sometimes better to disable |
1171 | tracing directly from a program. This allows you to stop the | 1171 | tracing directly from a program. This allows you to stop the |
1172 | tracing at the point that you hit the part that you are | 1172 | tracing at the point that you hit the part that you are |
1173 | interested in. To disable the tracing directly from a C program, | 1173 | interested in. To disable the tracing directly from a C program, |
1174 | something like following code snippet can be used: | 1174 | something like following code snippet can be used: |
1175 | 1175 | ||
1176 | int trace_fd; | 1176 | int trace_fd; |
1177 | [...] | 1177 | [...] |
1178 | int main(int argc, char *argv[]) { | 1178 | int main(int argc, char *argv[]) { |
1179 | [...] | 1179 | [...] |
1180 | trace_fd = open(tracing_file("tracing_enabled"), O_WRONLY); | 1180 | trace_fd = open(tracing_file("tracing_enabled"), O_WRONLY); |
1181 | [...] | 1181 | [...] |
1182 | if (condition_hit()) { | 1182 | if (condition_hit()) { |
1183 | write(trace_fd, "0", 1); | 1183 | write(trace_fd, "0", 1); |
1184 | } | 1184 | } |
1185 | [...] | 1185 | [...] |
1186 | } | 1186 | } |
1187 | 1187 | ||
1188 | 1188 | ||
1189 | Single thread tracing | 1189 | Single thread tracing |
1190 | --------------------- | 1190 | --------------------- |
1191 | 1191 | ||
1192 | By writing into set_ftrace_pid you can trace a | 1192 | By writing into set_ftrace_pid you can trace a |
1193 | single thread. For example: | 1193 | single thread. For example: |
1194 | 1194 | ||
1195 | # cat set_ftrace_pid | 1195 | # cat set_ftrace_pid |
1196 | no pid | 1196 | no pid |
1197 | # echo 3111 > set_ftrace_pid | 1197 | # echo 3111 > set_ftrace_pid |
1198 | # cat set_ftrace_pid | 1198 | # cat set_ftrace_pid |
1199 | 3111 | 1199 | 3111 |
1200 | # echo function > current_tracer | 1200 | # echo function > current_tracer |
1201 | # cat trace | head | 1201 | # cat trace | head |
1202 | # tracer: function | 1202 | # tracer: function |
1203 | # | 1203 | # |
1204 | # TASK-PID CPU# TIMESTAMP FUNCTION | 1204 | # TASK-PID CPU# TIMESTAMP FUNCTION |
1205 | # | | | | | | 1205 | # | | | | | |
1206 | yum-updatesd-3111 [003] 1637.254676: finish_task_switch <-thread_return | 1206 | yum-updatesd-3111 [003] 1637.254676: finish_task_switch <-thread_return |
1207 | yum-updatesd-3111 [003] 1637.254681: hrtimer_cancel <-schedule_hrtimeout_range | 1207 | yum-updatesd-3111 [003] 1637.254681: hrtimer_cancel <-schedule_hrtimeout_range |
1208 | yum-updatesd-3111 [003] 1637.254682: hrtimer_try_to_cancel <-hrtimer_cancel | 1208 | yum-updatesd-3111 [003] 1637.254682: hrtimer_try_to_cancel <-hrtimer_cancel |
1209 | yum-updatesd-3111 [003] 1637.254683: lock_hrtimer_base <-hrtimer_try_to_cancel | 1209 | yum-updatesd-3111 [003] 1637.254683: lock_hrtimer_base <-hrtimer_try_to_cancel |
1210 | yum-updatesd-3111 [003] 1637.254685: fget_light <-do_sys_poll | 1210 | yum-updatesd-3111 [003] 1637.254685: fget_light <-do_sys_poll |
1211 | yum-updatesd-3111 [003] 1637.254686: pipe_poll <-do_sys_poll | 1211 | yum-updatesd-3111 [003] 1637.254686: pipe_poll <-do_sys_poll |
1212 | # echo -1 > set_ftrace_pid | 1212 | # echo -1 > set_ftrace_pid |
1213 | # cat trace |head | 1213 | # cat trace |head |
1214 | # tracer: function | 1214 | # tracer: function |
1215 | # | 1215 | # |
1216 | # TASK-PID CPU# TIMESTAMP FUNCTION | 1216 | # TASK-PID CPU# TIMESTAMP FUNCTION |
1217 | # | | | | | | 1217 | # | | | | | |
1218 | ##### CPU 3 buffer started #### | 1218 | ##### CPU 3 buffer started #### |
1219 | yum-updatesd-3111 [003] 1701.957688: free_poll_entry <-poll_freewait | 1219 | yum-updatesd-3111 [003] 1701.957688: free_poll_entry <-poll_freewait |
1220 | yum-updatesd-3111 [003] 1701.957689: remove_wait_queue <-free_poll_entry | 1220 | yum-updatesd-3111 [003] 1701.957689: remove_wait_queue <-free_poll_entry |
1221 | yum-updatesd-3111 [003] 1701.957691: fput <-free_poll_entry | 1221 | yum-updatesd-3111 [003] 1701.957691: fput <-free_poll_entry |
1222 | yum-updatesd-3111 [003] 1701.957692: audit_syscall_exit <-sysret_audit | 1222 | yum-updatesd-3111 [003] 1701.957692: audit_syscall_exit <-sysret_audit |
1223 | yum-updatesd-3111 [003] 1701.957693: path_put <-audit_syscall_exit | 1223 | yum-updatesd-3111 [003] 1701.957693: path_put <-audit_syscall_exit |
1224 | 1224 | ||
1225 | If you want to trace a function when executing, you could use | 1225 | If you want to trace a function when executing, you could use |
1226 | something like this simple program: | 1226 | something like this simple program: |
1227 | 1227 | ||
1228 | #include <stdio.h> | 1228 | #include <stdio.h> |
1229 | #include <stdlib.h> | 1229 | #include <stdlib.h> |
1230 | #include <sys/types.h> | 1230 | #include <sys/types.h> |
1231 | #include <sys/stat.h> | 1231 | #include <sys/stat.h> |
1232 | #include <fcntl.h> | 1232 | #include <fcntl.h> |
1233 | #include <unistd.h> | 1233 | #include <unistd.h> |
1234 | 1234 | ||
1235 | #define _STR(x) #x | 1235 | #define _STR(x) #x |
1236 | #define STR(x) _STR(x) | 1236 | #define STR(x) _STR(x) |
1237 | #define MAX_PATH 256 | 1237 | #define MAX_PATH 256 |
1238 | 1238 | ||
1239 | const char *find_debugfs(void) | 1239 | const char *find_debugfs(void) |
1240 | { | 1240 | { |
1241 | static char debugfs[MAX_PATH+1]; | 1241 | static char debugfs[MAX_PATH+1]; |
1242 | static int debugfs_found; | 1242 | static int debugfs_found; |
1243 | char type[100]; | 1243 | char type[100]; |
1244 | FILE *fp; | 1244 | FILE *fp; |
1245 | 1245 | ||
1246 | if (debugfs_found) | 1246 | if (debugfs_found) |
1247 | return debugfs; | 1247 | return debugfs; |
1248 | 1248 | ||
1249 | if ((fp = fopen("/proc/mounts","r")) == NULL) { | 1249 | if ((fp = fopen("/proc/mounts","r")) == NULL) { |
1250 | perror("/proc/mounts"); | 1250 | perror("/proc/mounts"); |
1251 | return NULL; | 1251 | return NULL; |
1252 | } | 1252 | } |
1253 | 1253 | ||
1254 | while (fscanf(fp, "%*s %" | 1254 | while (fscanf(fp, "%*s %" |
1255 | STR(MAX_PATH) | 1255 | STR(MAX_PATH) |
1256 | "s %99s %*s %*d %*d\n", | 1256 | "s %99s %*s %*d %*d\n", |
1257 | debugfs, type) == 2) { | 1257 | debugfs, type) == 2) { |
1258 | if (strcmp(type, "debugfs") == 0) | 1258 | if (strcmp(type, "debugfs") == 0) |
1259 | break; | 1259 | break; |
1260 | } | 1260 | } |
1261 | fclose(fp); | 1261 | fclose(fp); |
1262 | 1262 | ||
1263 | if (strcmp(type, "debugfs") != 0) { | 1263 | if (strcmp(type, "debugfs") != 0) { |
1264 | fprintf(stderr, "debugfs not mounted"); | 1264 | fprintf(stderr, "debugfs not mounted"); |
1265 | return NULL; | 1265 | return NULL; |
1266 | } | 1266 | } |
1267 | 1267 | ||
1268 | debugfs_found = 1; | 1268 | debugfs_found = 1; |
1269 | 1269 | ||
1270 | return debugfs; | 1270 | return debugfs; |
1271 | } | 1271 | } |
1272 | 1272 | ||
1273 | const char *tracing_file(const char *file_name) | 1273 | const char *tracing_file(const char *file_name) |
1274 | { | 1274 | { |
1275 | static char trace_file[MAX_PATH+1]; | 1275 | static char trace_file[MAX_PATH+1]; |
1276 | snprintf(trace_file, MAX_PATH, "%s/%s", find_debugfs(), file_name); | 1276 | snprintf(trace_file, MAX_PATH, "%s/%s", find_debugfs(), file_name); |
1277 | return trace_file; | 1277 | return trace_file; |
1278 | } | 1278 | } |
1279 | 1279 | ||
1280 | int main (int argc, char **argv) | 1280 | int main (int argc, char **argv) |
1281 | { | 1281 | { |
1282 | if (argc < 1) | 1282 | if (argc < 1) |
1283 | exit(-1); | 1283 | exit(-1); |
1284 | 1284 | ||
1285 | if (fork() > 0) { | 1285 | if (fork() > 0) { |
1286 | int fd, ffd; | 1286 | int fd, ffd; |
1287 | char line[64]; | 1287 | char line[64]; |
1288 | int s; | 1288 | int s; |
1289 | 1289 | ||
1290 | ffd = open(tracing_file("current_tracer"), O_WRONLY); | 1290 | ffd = open(tracing_file("current_tracer"), O_WRONLY); |
1291 | if (ffd < 0) | 1291 | if (ffd < 0) |
1292 | exit(-1); | 1292 | exit(-1); |
1293 | write(ffd, "nop", 3); | 1293 | write(ffd, "nop", 3); |
1294 | 1294 | ||
1295 | fd = open(tracing_file("set_ftrace_pid"), O_WRONLY); | 1295 | fd = open(tracing_file("set_ftrace_pid"), O_WRONLY); |
1296 | s = sprintf(line, "%d\n", getpid()); | 1296 | s = sprintf(line, "%d\n", getpid()); |
1297 | write(fd, line, s); | 1297 | write(fd, line, s); |
1298 | 1298 | ||
1299 | write(ffd, "function", 8); | 1299 | write(ffd, "function", 8); |
1300 | 1300 | ||
1301 | close(fd); | 1301 | close(fd); |
1302 | close(ffd); | 1302 | close(ffd); |
1303 | 1303 | ||
1304 | execvp(argv[1], argv+1); | 1304 | execvp(argv[1], argv+1); |
1305 | } | 1305 | } |
1306 | 1306 | ||
1307 | return 0; | 1307 | return 0; |
1308 | } | 1308 | } |
1309 | 1309 | ||
1310 | 1310 | ||
1311 | hw-branch-tracer (x86 only) | 1311 | hw-branch-tracer (x86 only) |
1312 | --------------------------- | 1312 | --------------------------- |
1313 | 1313 | ||
1314 | This tracer uses the x86 last branch tracing hardware feature to | 1314 | This tracer uses the x86 last branch tracing hardware feature to |
1315 | collect a branch trace on all cpus with relatively low overhead. | 1315 | collect a branch trace on all cpus with relatively low overhead. |
1316 | 1316 | ||
1317 | The tracer uses a fixed-size circular buffer per cpu and only | 1317 | The tracer uses a fixed-size circular buffer per cpu and only |
1318 | traces ring 0 branches. The trace file dumps that buffer in the | 1318 | traces ring 0 branches. The trace file dumps that buffer in the |
1319 | following format: | 1319 | following format: |
1320 | 1320 | ||
1321 | # tracer: hw-branch-tracer | 1321 | # tracer: hw-branch-tracer |
1322 | # | 1322 | # |
1323 | # CPU# TO <- FROM | 1323 | # CPU# TO <- FROM |
1324 | 0 scheduler_tick+0xb5/0x1bf <- task_tick_idle+0x5/0x6 | 1324 | 0 scheduler_tick+0xb5/0x1bf <- task_tick_idle+0x5/0x6 |
1325 | 2 run_posix_cpu_timers+0x2b/0x72a <- run_posix_cpu_timers+0x25/0x72a | 1325 | 2 run_posix_cpu_timers+0x2b/0x72a <- run_posix_cpu_timers+0x25/0x72a |
1326 | 0 scheduler_tick+0x139/0x1bf <- scheduler_tick+0xed/0x1bf | 1326 | 0 scheduler_tick+0x139/0x1bf <- scheduler_tick+0xed/0x1bf |
1327 | 0 scheduler_tick+0x17c/0x1bf <- scheduler_tick+0x148/0x1bf | 1327 | 0 scheduler_tick+0x17c/0x1bf <- scheduler_tick+0x148/0x1bf |
1328 | 2 run_posix_cpu_timers+0x9e/0x72a <- run_posix_cpu_timers+0x5e/0x72a | 1328 | 2 run_posix_cpu_timers+0x9e/0x72a <- run_posix_cpu_timers+0x5e/0x72a |
1329 | 0 scheduler_tick+0x1b6/0x1bf <- scheduler_tick+0x1aa/0x1bf | 1329 | 0 scheduler_tick+0x1b6/0x1bf <- scheduler_tick+0x1aa/0x1bf |
1330 | 1330 | ||
1331 | 1331 | ||
1332 | The tracer may be used to dump the trace for the oops'ing cpu on | 1332 | The tracer may be used to dump the trace for the oops'ing cpu on |
1333 | a kernel oops into the system log. To enable this, | 1333 | a kernel oops into the system log. To enable this, |
1334 | ftrace_dump_on_oops must be set. To set ftrace_dump_on_oops, one | 1334 | ftrace_dump_on_oops must be set. To set ftrace_dump_on_oops, one |
1335 | can either use the sysctl function or set it via the proc system | 1335 | can either use the sysctl function or set it via the proc system |
1336 | interface. | 1336 | interface. |
1337 | 1337 | ||
1338 | sysctl kernel.ftrace_dump_on_oops=1 | 1338 | sysctl kernel.ftrace_dump_on_oops=1 |
1339 | 1339 | ||
1340 | or | 1340 | or |
1341 | 1341 | ||
1342 | echo 1 > /proc/sys/kernel/ftrace_dump_on_oops | 1342 | echo 1 > /proc/sys/kernel/ftrace_dump_on_oops |
1343 | 1343 | ||
1344 | 1344 | ||
1345 | Here's an example of such a dump after a null pointer | 1345 | Here's an example of such a dump after a null pointer |
1346 | dereference in a kernel module: | 1346 | dereference in a kernel module: |
1347 | 1347 | ||
1348 | [57848.105921] BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 | 1348 | [57848.105921] BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 |
1349 | [57848.106019] IP: [<ffffffffa0000006>] open+0x6/0x14 [oops] | 1349 | [57848.106019] IP: [<ffffffffa0000006>] open+0x6/0x14 [oops] |
1350 | [57848.106019] PGD 2354e9067 PUD 2375e7067 PMD 0 | 1350 | [57848.106019] PGD 2354e9067 PUD 2375e7067 PMD 0 |
1351 | [57848.106019] Oops: 0002 [#1] SMP | 1351 | [57848.106019] Oops: 0002 [#1] SMP |
1352 | [57848.106019] last sysfs file: /sys/devices/pci0000:00/0000:00:1e.0/0000:20:05.0/local_cpus | 1352 | [57848.106019] last sysfs file: /sys/devices/pci0000:00/0000:00:1e.0/0000:20:05.0/local_cpus |
1353 | [57848.106019] Dumping ftrace buffer: | 1353 | [57848.106019] Dumping ftrace buffer: |
1354 | [57848.106019] --------------------------------- | 1354 | [57848.106019] --------------------------------- |
1355 | [...] | 1355 | [...] |
1356 | [57848.106019] 0 chrdev_open+0xe6/0x165 <- cdev_put+0x23/0x24 | 1356 | [57848.106019] 0 chrdev_open+0xe6/0x165 <- cdev_put+0x23/0x24 |
1357 | [57848.106019] 0 chrdev_open+0x117/0x165 <- chrdev_open+0xfa/0x165 | 1357 | [57848.106019] 0 chrdev_open+0x117/0x165 <- chrdev_open+0xfa/0x165 |
1358 | [57848.106019] 0 chrdev_open+0x120/0x165 <- chrdev_open+0x11c/0x165 | 1358 | [57848.106019] 0 chrdev_open+0x120/0x165 <- chrdev_open+0x11c/0x165 |
1359 | [57848.106019] 0 chrdev_open+0x134/0x165 <- chrdev_open+0x12b/0x165 | 1359 | [57848.106019] 0 chrdev_open+0x134/0x165 <- chrdev_open+0x12b/0x165 |
1360 | [57848.106019] 0 open+0x0/0x14 [oops] <- chrdev_open+0x144/0x165 | 1360 | [57848.106019] 0 open+0x0/0x14 [oops] <- chrdev_open+0x144/0x165 |
1361 | [57848.106019] 0 page_fault+0x0/0x30 <- open+0x6/0x14 [oops] | 1361 | [57848.106019] 0 page_fault+0x0/0x30 <- open+0x6/0x14 [oops] |
1362 | [57848.106019] 0 error_entry+0x0/0x5b <- page_fault+0x4/0x30 | 1362 | [57848.106019] 0 error_entry+0x0/0x5b <- page_fault+0x4/0x30 |
1363 | [57848.106019] 0 error_kernelspace+0x0/0x31 <- error_entry+0x59/0x5b | 1363 | [57848.106019] 0 error_kernelspace+0x0/0x31 <- error_entry+0x59/0x5b |
1364 | [57848.106019] 0 error_sti+0x0/0x1 <- error_kernelspace+0x2d/0x31 | 1364 | [57848.106019] 0 error_sti+0x0/0x1 <- error_kernelspace+0x2d/0x31 |
1365 | [57848.106019] 0 page_fault+0x9/0x30 <- error_sti+0x0/0x1 | 1365 | [57848.106019] 0 page_fault+0x9/0x30 <- error_sti+0x0/0x1 |
1366 | [57848.106019] 0 do_page_fault+0x0/0x881 <- page_fault+0x1a/0x30 | 1366 | [57848.106019] 0 do_page_fault+0x0/0x881 <- page_fault+0x1a/0x30 |
1367 | [...] | 1367 | [...] |
1368 | [57848.106019] 0 do_page_fault+0x66b/0x881 <- is_prefetch+0x1ee/0x1f2 | 1368 | [57848.106019] 0 do_page_fault+0x66b/0x881 <- is_prefetch+0x1ee/0x1f2 |
1369 | [57848.106019] 0 do_page_fault+0x6e0/0x881 <- do_page_fault+0x67a/0x881 | 1369 | [57848.106019] 0 do_page_fault+0x6e0/0x881 <- do_page_fault+0x67a/0x881 |
1370 | [57848.106019] 0 oops_begin+0x0/0x96 <- do_page_fault+0x6e0/0x881 | 1370 | [57848.106019] 0 oops_begin+0x0/0x96 <- do_page_fault+0x6e0/0x881 |
1371 | [57848.106019] 0 trace_hw_branch_oops+0x0/0x2d <- oops_begin+0x9/0x96 | 1371 | [57848.106019] 0 trace_hw_branch_oops+0x0/0x2d <- oops_begin+0x9/0x96 |
1372 | [...] | 1372 | [...] |
1373 | [57848.106019] 0 ds_suspend_bts+0x2a/0xe3 <- ds_suspend_bts+0x1a/0xe3 | 1373 | [57848.106019] 0 ds_suspend_bts+0x2a/0xe3 <- ds_suspend_bts+0x1a/0xe3 |
1374 | [57848.106019] --------------------------------- | 1374 | [57848.106019] --------------------------------- |
1375 | [57848.106019] CPU 0 | 1375 | [57848.106019] CPU 0 |
1376 | [57848.106019] Modules linked in: oops | 1376 | [57848.106019] Modules linked in: oops |
1377 | [57848.106019] Pid: 5542, comm: cat Tainted: G W 2.6.28 #23 | 1377 | [57848.106019] Pid: 5542, comm: cat Tainted: G W 2.6.28 #23 |
1378 | [57848.106019] RIP: 0010:[<ffffffffa0000006>] [<ffffffffa0000006>] open+0x6/0x14 [oops] | 1378 | [57848.106019] RIP: 0010:[<ffffffffa0000006>] [<ffffffffa0000006>] open+0x6/0x14 [oops] |
1379 | [57848.106019] RSP: 0018:ffff880235457d48 EFLAGS: 00010246 | 1379 | [57848.106019] RSP: 0018:ffff880235457d48 EFLAGS: 00010246 |
1380 | [...] | 1380 | [...] |
1381 | 1381 | ||
1382 | 1382 | ||
1383 | function graph tracer | 1383 | function graph tracer |
1384 | --------------------------- | 1384 | --------------------------- |
1385 | 1385 | ||
1386 | This tracer is similar to the function tracer except that it | 1386 | This tracer is similar to the function tracer except that it |
1387 | probes a function on its entry and its exit. This is done by | 1387 | probes a function on its entry and its exit. This is done by |
1388 | using a dynamically allocated stack of return addresses in each | 1388 | using a dynamically allocated stack of return addresses in each |
1389 | task_struct. On function entry the tracer overwrites the return | 1389 | task_struct. On function entry the tracer overwrites the return |
1390 | address of each function traced to set a custom probe. Thus the | 1390 | address of each function traced to set a custom probe. Thus the |
1391 | original return address is stored on the stack of return address | 1391 | original return address is stored on the stack of return address |
1392 | in the task_struct. | 1392 | in the task_struct. |
1393 | 1393 | ||
1394 | Probing on both ends of a function leads to special features | 1394 | Probing on both ends of a function leads to special features |
1395 | such as: | 1395 | such as: |
1396 | 1396 | ||
1397 | - measure of a function's time execution | 1397 | - measure of a function's time execution |
1398 | - having a reliable call stack to draw function calls graph | 1398 | - having a reliable call stack to draw function calls graph |
1399 | 1399 | ||
1400 | This tracer is useful in several situations: | 1400 | This tracer is useful in several situations: |
1401 | 1401 | ||
1402 | - you want to find the reason of a strange kernel behavior and | 1402 | - you want to find the reason of a strange kernel behavior and |
1403 | need to see what happens in detail on any areas (or specific | 1403 | need to see what happens in detail on any areas (or specific |
1404 | ones). | 1404 | ones). |
1405 | 1405 | ||
1406 | - you are experiencing weird latencies but it's difficult to | 1406 | - you are experiencing weird latencies but it's difficult to |
1407 | find its origin. | 1407 | find its origin. |
1408 | 1408 | ||
1409 | - you want to find quickly which path is taken by a specific | 1409 | - you want to find quickly which path is taken by a specific |
1410 | function | 1410 | function |
1411 | 1411 | ||
1412 | - you just want to peek inside a working kernel and want to see | 1412 | - you just want to peek inside a working kernel and want to see |
1413 | what happens there. | 1413 | what happens there. |
1414 | 1414 | ||
1415 | # tracer: function_graph | 1415 | # tracer: function_graph |
1416 | # | 1416 | # |
1417 | # CPU DURATION FUNCTION CALLS | 1417 | # CPU DURATION FUNCTION CALLS |
1418 | # | | | | | | | | 1418 | # | | | | | | | |
1419 | 1419 | ||
1420 | 0) | sys_open() { | 1420 | 0) | sys_open() { |
1421 | 0) | do_sys_open() { | 1421 | 0) | do_sys_open() { |
1422 | 0) | getname() { | 1422 | 0) | getname() { |
1423 | 0) | kmem_cache_alloc() { | 1423 | 0) | kmem_cache_alloc() { |
1424 | 0) 1.382 us | __might_sleep(); | 1424 | 0) 1.382 us | __might_sleep(); |
1425 | 0) 2.478 us | } | 1425 | 0) 2.478 us | } |
1426 | 0) | strncpy_from_user() { | 1426 | 0) | strncpy_from_user() { |
1427 | 0) | might_fault() { | 1427 | 0) | might_fault() { |
1428 | 0) 1.389 us | __might_sleep(); | 1428 | 0) 1.389 us | __might_sleep(); |
1429 | 0) 2.553 us | } | 1429 | 0) 2.553 us | } |
1430 | 0) 3.807 us | } | 1430 | 0) 3.807 us | } |
1431 | 0) 7.876 us | } | 1431 | 0) 7.876 us | } |
1432 | 0) | alloc_fd() { | 1432 | 0) | alloc_fd() { |
1433 | 0) 0.668 us | _spin_lock(); | 1433 | 0) 0.668 us | _spin_lock(); |
1434 | 0) 0.570 us | expand_files(); | 1434 | 0) 0.570 us | expand_files(); |
1435 | 0) 0.586 us | _spin_unlock(); | 1435 | 0) 0.586 us | _spin_unlock(); |
1436 | 1436 | ||
1437 | 1437 | ||
1438 | There are several columns that can be dynamically | 1438 | There are several columns that can be dynamically |
1439 | enabled/disabled. You can use every combination of options you | 1439 | enabled/disabled. You can use every combination of options you |
1440 | want, depending on your needs. | 1440 | want, depending on your needs. |
1441 | 1441 | ||
1442 | - The cpu number on which the function executed is default | 1442 | - The cpu number on which the function executed is default |
1443 | enabled. It is sometimes better to only trace one cpu (see | 1443 | enabled. It is sometimes better to only trace one cpu (see |
1444 | tracing_cpu_mask file) or you might sometimes see unordered | 1444 | tracing_cpu_mask file) or you might sometimes see unordered |
1445 | function calls while cpu tracing switch. | 1445 | function calls while cpu tracing switch. |
1446 | 1446 | ||
1447 | hide: echo nofuncgraph-cpu > trace_options | 1447 | hide: echo nofuncgraph-cpu > trace_options |
1448 | show: echo funcgraph-cpu > trace_options | 1448 | show: echo funcgraph-cpu > trace_options |
1449 | 1449 | ||
1450 | - The duration (function's time of execution) is displayed on | 1450 | - The duration (function's time of execution) is displayed on |
1451 | the closing bracket line of a function or on the same line | 1451 | the closing bracket line of a function or on the same line |
1452 | than the current function in case of a leaf one. It is default | 1452 | than the current function in case of a leaf one. It is default |
1453 | enabled. | 1453 | enabled. |
1454 | 1454 | ||
1455 | hide: echo nofuncgraph-duration > trace_options | 1455 | hide: echo nofuncgraph-duration > trace_options |
1456 | show: echo funcgraph-duration > trace_options | 1456 | show: echo funcgraph-duration > trace_options |
1457 | 1457 | ||
1458 | - The overhead field precedes the duration field in case of | 1458 | - The overhead field precedes the duration field in case of |
1459 | reached duration thresholds. | 1459 | reached duration thresholds. |
1460 | 1460 | ||
1461 | hide: echo nofuncgraph-overhead > trace_options | 1461 | hide: echo nofuncgraph-overhead > trace_options |
1462 | show: echo funcgraph-overhead > trace_options | 1462 | show: echo funcgraph-overhead > trace_options |
1463 | depends on: funcgraph-duration | 1463 | depends on: funcgraph-duration |
1464 | 1464 | ||
1465 | ie: | 1465 | ie: |
1466 | 1466 | ||
1467 | 0) | up_write() { | 1467 | 0) | up_write() { |
1468 | 0) 0.646 us | _spin_lock_irqsave(); | 1468 | 0) 0.646 us | _spin_lock_irqsave(); |
1469 | 0) 0.684 us | _spin_unlock_irqrestore(); | 1469 | 0) 0.684 us | _spin_unlock_irqrestore(); |
1470 | 0) 3.123 us | } | 1470 | 0) 3.123 us | } |
1471 | 0) 0.548 us | fput(); | 1471 | 0) 0.548 us | fput(); |
1472 | 0) + 58.628 us | } | 1472 | 0) + 58.628 us | } |
1473 | 1473 | ||
1474 | [...] | 1474 | [...] |
1475 | 1475 | ||
1476 | 0) | putname() { | 1476 | 0) | putname() { |
1477 | 0) | kmem_cache_free() { | 1477 | 0) | kmem_cache_free() { |
1478 | 0) 0.518 us | __phys_addr(); | 1478 | 0) 0.518 us | __phys_addr(); |
1479 | 0) 1.757 us | } | 1479 | 0) 1.757 us | } |
1480 | 0) 2.861 us | } | 1480 | 0) 2.861 us | } |
1481 | 0) ! 115.305 us | } | 1481 | 0) ! 115.305 us | } |
1482 | 0) ! 116.402 us | } | 1482 | 0) ! 116.402 us | } |
1483 | 1483 | ||
1484 | + means that the function exceeded 10 usecs. | 1484 | + means that the function exceeded 10 usecs. |
1485 | ! means that the function exceeded 100 usecs. | 1485 | ! means that the function exceeded 100 usecs. |
1486 | 1486 | ||
1487 | 1487 | ||
1488 | - The task/pid field displays the thread cmdline and pid which | 1488 | - The task/pid field displays the thread cmdline and pid which |
1489 | executed the function. It is default disabled. | 1489 | executed the function. It is default disabled. |
1490 | 1490 | ||
1491 | hide: echo nofuncgraph-proc > trace_options | 1491 | hide: echo nofuncgraph-proc > trace_options |
1492 | show: echo funcgraph-proc > trace_options | 1492 | show: echo funcgraph-proc > trace_options |
1493 | 1493 | ||
1494 | ie: | 1494 | ie: |
1495 | 1495 | ||
1496 | # tracer: function_graph | 1496 | # tracer: function_graph |
1497 | # | 1497 | # |
1498 | # CPU TASK/PID DURATION FUNCTION CALLS | 1498 | # CPU TASK/PID DURATION FUNCTION CALLS |
1499 | # | | | | | | | | | | 1499 | # | | | | | | | | | |
1500 | 0) sh-4802 | | d_free() { | 1500 | 0) sh-4802 | | d_free() { |
1501 | 0) sh-4802 | | call_rcu() { | 1501 | 0) sh-4802 | | call_rcu() { |
1502 | 0) sh-4802 | | __call_rcu() { | 1502 | 0) sh-4802 | | __call_rcu() { |
1503 | 0) sh-4802 | 0.616 us | rcu_process_gp_end(); | 1503 | 0) sh-4802 | 0.616 us | rcu_process_gp_end(); |
1504 | 0) sh-4802 | 0.586 us | check_for_new_grace_period(); | 1504 | 0) sh-4802 | 0.586 us | check_for_new_grace_period(); |
1505 | 0) sh-4802 | 2.899 us | } | 1505 | 0) sh-4802 | 2.899 us | } |
1506 | 0) sh-4802 | 4.040 us | } | 1506 | 0) sh-4802 | 4.040 us | } |
1507 | 0) sh-4802 | 5.151 us | } | 1507 | 0) sh-4802 | 5.151 us | } |
1508 | 0) sh-4802 | + 49.370 us | } | 1508 | 0) sh-4802 | + 49.370 us | } |
1509 | 1509 | ||
1510 | 1510 | ||
1511 | - The absolute time field is an absolute timestamp given by the | 1511 | - The absolute time field is an absolute timestamp given by the |
1512 | system clock since it started. A snapshot of this time is | 1512 | system clock since it started. A snapshot of this time is |
1513 | given on each entry/exit of functions | 1513 | given on each entry/exit of functions |
1514 | 1514 | ||
1515 | hide: echo nofuncgraph-abstime > trace_options | 1515 | hide: echo nofuncgraph-abstime > trace_options |
1516 | show: echo funcgraph-abstime > trace_options | 1516 | show: echo funcgraph-abstime > trace_options |
1517 | 1517 | ||
1518 | ie: | 1518 | ie: |
1519 | 1519 | ||
1520 | # | 1520 | # |
1521 | # TIME CPU DURATION FUNCTION CALLS | 1521 | # TIME CPU DURATION FUNCTION CALLS |
1522 | # | | | | | | | | | 1522 | # | | | | | | | | |
1523 | 360.774522 | 1) 0.541 us | } | 1523 | 360.774522 | 1) 0.541 us | } |
1524 | 360.774522 | 1) 4.663 us | } | 1524 | 360.774522 | 1) 4.663 us | } |
1525 | 360.774523 | 1) 0.541 us | __wake_up_bit(); | 1525 | 360.774523 | 1) 0.541 us | __wake_up_bit(); |
1526 | 360.774524 | 1) 6.796 us | } | 1526 | 360.774524 | 1) 6.796 us | } |
1527 | 360.774524 | 1) 7.952 us | } | 1527 | 360.774524 | 1) 7.952 us | } |
1528 | 360.774525 | 1) 9.063 us | } | 1528 | 360.774525 | 1) 9.063 us | } |
1529 | 360.774525 | 1) 0.615 us | journal_mark_dirty(); | 1529 | 360.774525 | 1) 0.615 us | journal_mark_dirty(); |
1530 | 360.774527 | 1) 0.578 us | __brelse(); | 1530 | 360.774527 | 1) 0.578 us | __brelse(); |
1531 | 360.774528 | 1) | reiserfs_prepare_for_journal() { | 1531 | 360.774528 | 1) | reiserfs_prepare_for_journal() { |
1532 | 360.774528 | 1) | unlock_buffer() { | 1532 | 360.774528 | 1) | unlock_buffer() { |
1533 | 360.774529 | 1) | wake_up_bit() { | 1533 | 360.774529 | 1) | wake_up_bit() { |
1534 | 360.774529 | 1) | bit_waitqueue() { | 1534 | 360.774529 | 1) | bit_waitqueue() { |
1535 | 360.774530 | 1) 0.594 us | __phys_addr(); | 1535 | 360.774530 | 1) 0.594 us | __phys_addr(); |
1536 | 1536 | ||
1537 | 1537 | ||
1538 | You can put some comments on specific functions by using | 1538 | You can put some comments on specific functions by using |
1539 | trace_printk() For example, if you want to put a comment inside | 1539 | trace_printk() For example, if you want to put a comment inside |
1540 | the __might_sleep() function, you just have to include | 1540 | the __might_sleep() function, you just have to include |
1541 | <linux/ftrace.h> and call trace_printk() inside __might_sleep() | 1541 | <linux/ftrace.h> and call trace_printk() inside __might_sleep() |
1542 | 1542 | ||
1543 | trace_printk("I'm a comment!\n") | 1543 | trace_printk("I'm a comment!\n") |
1544 | 1544 | ||
1545 | will produce: | 1545 | will produce: |
1546 | 1546 | ||
1547 | 1) | __might_sleep() { | 1547 | 1) | __might_sleep() { |
1548 | 1) | /* I'm a comment! */ | 1548 | 1) | /* I'm a comment! */ |
1549 | 1) 1.449 us | } | 1549 | 1) 1.449 us | } |
1550 | 1550 | ||
1551 | 1551 | ||
1552 | You might find other useful features for this tracer in the | 1552 | You might find other useful features for this tracer in the |
1553 | following "dynamic ftrace" section such as tracing only specific | 1553 | following "dynamic ftrace" section such as tracing only specific |
1554 | functions or tasks. | 1554 | functions or tasks. |
1555 | 1555 | ||
1556 | dynamic ftrace | 1556 | dynamic ftrace |
1557 | -------------- | 1557 | -------------- |
1558 | 1558 | ||
1559 | If CONFIG_DYNAMIC_FTRACE is set, the system will run with | 1559 | If CONFIG_DYNAMIC_FTRACE is set, the system will run with |
1560 | virtually no overhead when function tracing is disabled. The way | 1560 | virtually no overhead when function tracing is disabled. The way |
1561 | this works is the mcount function call (placed at the start of | 1561 | this works is the mcount function call (placed at the start of |
1562 | every kernel function, produced by the -pg switch in gcc), | 1562 | every kernel function, produced by the -pg switch in gcc), |
1563 | starts of pointing to a simple return. (Enabling FTRACE will | 1563 | starts of pointing to a simple return. (Enabling FTRACE will |
1564 | include the -pg switch in the compiling of the kernel.) | 1564 | include the -pg switch in the compiling of the kernel.) |
1565 | 1565 | ||
1566 | At compile time every C file object is run through the | 1566 | At compile time every C file object is run through the |
1567 | recordmcount.pl script (located in the scripts directory). This | 1567 | recordmcount.pl script (located in the scripts directory). This |
1568 | script will process the C object using objdump to find all the | 1568 | script will process the C object using objdump to find all the |
1569 | locations in the .text section that call mcount. (Note, only the | 1569 | locations in the .text section that call mcount. (Note, only the |
1570 | .text section is processed, since processing other sections like | 1570 | .text section is processed, since processing other sections like |
1571 | .init.text may cause races due to those sections being freed). | 1571 | .init.text may cause races due to those sections being freed). |
1572 | 1572 | ||
1573 | A new section called "__mcount_loc" is created that holds | 1573 | A new section called "__mcount_loc" is created that holds |
1574 | references to all the mcount call sites in the .text section. | 1574 | references to all the mcount call sites in the .text section. |
1575 | This section is compiled back into the original object. The | 1575 | This section is compiled back into the original object. The |
1576 | final linker will add all these references into a single table. | 1576 | final linker will add all these references into a single table. |
1577 | 1577 | ||
1578 | On boot up, before SMP is initialized, the dynamic ftrace code | 1578 | On boot up, before SMP is initialized, the dynamic ftrace code |
1579 | scans this table and updates all the locations into nops. It | 1579 | scans this table and updates all the locations into nops. It |
1580 | also records the locations, which are added to the | 1580 | also records the locations, which are added to the |
1581 | available_filter_functions list. Modules are processed as they | 1581 | available_filter_functions list. Modules are processed as they |
1582 | are loaded and before they are executed. When a module is | 1582 | are loaded and before they are executed. When a module is |
1583 | unloaded, it also removes its functions from the ftrace function | 1583 | unloaded, it also removes its functions from the ftrace function |
1584 | list. This is automatic in the module unload code, and the | 1584 | list. This is automatic in the module unload code, and the |
1585 | module author does not need to worry about it. | 1585 | module author does not need to worry about it. |
1586 | 1586 | ||
1587 | When tracing is enabled, kstop_machine is called to prevent | 1587 | When tracing is enabled, kstop_machine is called to prevent |
1588 | races with the CPUS executing code being modified (which can | 1588 | races with the CPUS executing code being modified (which can |
1589 | cause the CPU to do undesireable things), and the nops are | 1589 | cause the CPU to do undesireable things), and the nops are |
1590 | patched back to calls. But this time, they do not call mcount | 1590 | patched back to calls. But this time, they do not call mcount |
1591 | (which is just a function stub). They now call into the ftrace | 1591 | (which is just a function stub). They now call into the ftrace |
1592 | infrastructure. | 1592 | infrastructure. |
1593 | 1593 | ||
1594 | One special side-effect to the recording of the functions being | 1594 | One special side-effect to the recording of the functions being |
1595 | traced is that we can now selectively choose which functions we | 1595 | traced is that we can now selectively choose which functions we |
1596 | wish to trace and which ones we want the mcount calls to remain | 1596 | wish to trace and which ones we want the mcount calls to remain |
1597 | as nops. | 1597 | as nops. |
1598 | 1598 | ||
1599 | Two files are used, one for enabling and one for disabling the | 1599 | Two files are used, one for enabling and one for disabling the |
1600 | tracing of specified functions. They are: | 1600 | tracing of specified functions. They are: |
1601 | 1601 | ||
1602 | set_ftrace_filter | 1602 | set_ftrace_filter |
1603 | 1603 | ||
1604 | and | 1604 | and |
1605 | 1605 | ||
1606 | set_ftrace_notrace | 1606 | set_ftrace_notrace |
1607 | 1607 | ||
1608 | A list of available functions that you can add to these files is | 1608 | A list of available functions that you can add to these files is |
1609 | listed in: | 1609 | listed in: |
1610 | 1610 | ||
1611 | available_filter_functions | 1611 | available_filter_functions |
1612 | 1612 | ||
1613 | # cat available_filter_functions | 1613 | # cat available_filter_functions |
1614 | put_prev_task_idle | 1614 | put_prev_task_idle |
1615 | kmem_cache_create | 1615 | kmem_cache_create |
1616 | pick_next_task_rt | 1616 | pick_next_task_rt |
1617 | get_online_cpus | 1617 | get_online_cpus |
1618 | pick_next_task_fair | 1618 | pick_next_task_fair |
1619 | mutex_lock | 1619 | mutex_lock |
1620 | [...] | 1620 | [...] |
1621 | 1621 | ||
1622 | If I am only interested in sys_nanosleep and hrtimer_interrupt: | 1622 | If I am only interested in sys_nanosleep and hrtimer_interrupt: |
1623 | 1623 | ||
1624 | # echo sys_nanosleep hrtimer_interrupt \ | 1624 | # echo sys_nanosleep hrtimer_interrupt \ |
1625 | > set_ftrace_filter | 1625 | > set_ftrace_filter |
1626 | # echo ftrace > current_tracer | 1626 | # echo ftrace > current_tracer |
1627 | # echo 1 > tracing_enabled | 1627 | # echo 1 > tracing_enabled |
1628 | # usleep 1 | 1628 | # usleep 1 |
1629 | # echo 0 > tracing_enabled | 1629 | # echo 0 > tracing_enabled |
1630 | # cat trace | 1630 | # cat trace |
1631 | # tracer: ftrace | 1631 | # tracer: ftrace |
1632 | # | 1632 | # |
1633 | # TASK-PID CPU# TIMESTAMP FUNCTION | 1633 | # TASK-PID CPU# TIMESTAMP FUNCTION |
1634 | # | | | | | | 1634 | # | | | | | |
1635 | usleep-4134 [00] 1317.070017: hrtimer_interrupt <-smp_apic_timer_interrupt | 1635 | usleep-4134 [00] 1317.070017: hrtimer_interrupt <-smp_apic_timer_interrupt |
1636 | usleep-4134 [00] 1317.070111: sys_nanosleep <-syscall_call | 1636 | usleep-4134 [00] 1317.070111: sys_nanosleep <-syscall_call |
1637 | <idle>-0 [00] 1317.070115: hrtimer_interrupt <-smp_apic_timer_interrupt | 1637 | <idle>-0 [00] 1317.070115: hrtimer_interrupt <-smp_apic_timer_interrupt |
1638 | 1638 | ||
1639 | To see which functions are being traced, you can cat the file: | 1639 | To see which functions are being traced, you can cat the file: |
1640 | 1640 | ||
1641 | # cat set_ftrace_filter | 1641 | # cat set_ftrace_filter |
1642 | hrtimer_interrupt | 1642 | hrtimer_interrupt |
1643 | sys_nanosleep | 1643 | sys_nanosleep |
1644 | 1644 | ||
1645 | 1645 | ||
1646 | Perhaps this is not enough. The filters also allow simple wild | 1646 | Perhaps this is not enough. The filters also allow simple wild |
1647 | cards. Only the following are currently available | 1647 | cards. Only the following are currently available |
1648 | 1648 | ||
1649 | <match>* - will match functions that begin with <match> | 1649 | <match>* - will match functions that begin with <match> |
1650 | *<match> - will match functions that end with <match> | 1650 | *<match> - will match functions that end with <match> |
1651 | *<match>* - will match functions that have <match> in it | 1651 | *<match>* - will match functions that have <match> in it |
1652 | 1652 | ||
1653 | These are the only wild cards which are supported. | 1653 | These are the only wild cards which are supported. |
1654 | 1654 | ||
1655 | <match>*<match> will not work. | 1655 | <match>*<match> will not work. |
1656 | 1656 | ||
1657 | Note: It is better to use quotes to enclose the wild cards, | 1657 | Note: It is better to use quotes to enclose the wild cards, |
1658 | otherwise the shell may expand the parameters into names | 1658 | otherwise the shell may expand the parameters into names |
1659 | of files in the local directory. | 1659 | of files in the local directory. |
1660 | 1660 | ||
1661 | # echo 'hrtimer_*' > set_ftrace_filter | 1661 | # echo 'hrtimer_*' > set_ftrace_filter |
1662 | 1662 | ||
1663 | Produces: | 1663 | Produces: |
1664 | 1664 | ||
1665 | # tracer: ftrace | 1665 | # tracer: ftrace |
1666 | # | 1666 | # |
1667 | # TASK-PID CPU# TIMESTAMP FUNCTION | 1667 | # TASK-PID CPU# TIMESTAMP FUNCTION |
1668 | # | | | | | | 1668 | # | | | | | |
1669 | bash-4003 [00] 1480.611794: hrtimer_init <-copy_process | 1669 | bash-4003 [00] 1480.611794: hrtimer_init <-copy_process |
1670 | bash-4003 [00] 1480.611941: hrtimer_start <-hrtick_set | 1670 | bash-4003 [00] 1480.611941: hrtimer_start <-hrtick_set |
1671 | bash-4003 [00] 1480.611956: hrtimer_cancel <-hrtick_clear | 1671 | bash-4003 [00] 1480.611956: hrtimer_cancel <-hrtick_clear |
1672 | bash-4003 [00] 1480.611956: hrtimer_try_to_cancel <-hrtimer_cancel | 1672 | bash-4003 [00] 1480.611956: hrtimer_try_to_cancel <-hrtimer_cancel |
1673 | <idle>-0 [00] 1480.612019: hrtimer_get_next_event <-get_next_timer_interrupt | 1673 | <idle>-0 [00] 1480.612019: hrtimer_get_next_event <-get_next_timer_interrupt |
1674 | <idle>-0 [00] 1480.612025: hrtimer_get_next_event <-get_next_timer_interrupt | 1674 | <idle>-0 [00] 1480.612025: hrtimer_get_next_event <-get_next_timer_interrupt |
1675 | <idle>-0 [00] 1480.612032: hrtimer_get_next_event <-get_next_timer_interrupt | 1675 | <idle>-0 [00] 1480.612032: hrtimer_get_next_event <-get_next_timer_interrupt |
1676 | <idle>-0 [00] 1480.612037: hrtimer_get_next_event <-get_next_timer_interrupt | 1676 | <idle>-0 [00] 1480.612037: hrtimer_get_next_event <-get_next_timer_interrupt |
1677 | <idle>-0 [00] 1480.612382: hrtimer_get_next_event <-get_next_timer_interrupt | 1677 | <idle>-0 [00] 1480.612382: hrtimer_get_next_event <-get_next_timer_interrupt |
1678 | 1678 | ||
1679 | 1679 | ||
1680 | Notice that we lost the sys_nanosleep. | 1680 | Notice that we lost the sys_nanosleep. |
1681 | 1681 | ||
1682 | # cat set_ftrace_filter | 1682 | # cat set_ftrace_filter |
1683 | hrtimer_run_queues | 1683 | hrtimer_run_queues |
1684 | hrtimer_run_pending | 1684 | hrtimer_run_pending |
1685 | hrtimer_init | 1685 | hrtimer_init |
1686 | hrtimer_cancel | 1686 | hrtimer_cancel |
1687 | hrtimer_try_to_cancel | 1687 | hrtimer_try_to_cancel |
1688 | hrtimer_forward | 1688 | hrtimer_forward |
1689 | hrtimer_start | 1689 | hrtimer_start |
1690 | hrtimer_reprogram | 1690 | hrtimer_reprogram |
1691 | hrtimer_force_reprogram | 1691 | hrtimer_force_reprogram |
1692 | hrtimer_get_next_event | 1692 | hrtimer_get_next_event |
1693 | hrtimer_interrupt | 1693 | hrtimer_interrupt |
1694 | hrtimer_nanosleep | 1694 | hrtimer_nanosleep |
1695 | hrtimer_wakeup | 1695 | hrtimer_wakeup |
1696 | hrtimer_get_remaining | 1696 | hrtimer_get_remaining |
1697 | hrtimer_get_res | 1697 | hrtimer_get_res |
1698 | hrtimer_init_sleeper | 1698 | hrtimer_init_sleeper |
1699 | 1699 | ||
1700 | 1700 | ||
1701 | This is because the '>' and '>>' act just like they do in bash. | 1701 | This is because the '>' and '>>' act just like they do in bash. |
1702 | To rewrite the filters, use '>' | 1702 | To rewrite the filters, use '>' |
1703 | To append to the filters, use '>>' | 1703 | To append to the filters, use '>>' |
1704 | 1704 | ||
1705 | To clear out a filter so that all functions will be recorded | 1705 | To clear out a filter so that all functions will be recorded |
1706 | again: | 1706 | again: |
1707 | 1707 | ||
1708 | # echo > set_ftrace_filter | 1708 | # echo > set_ftrace_filter |
1709 | # cat set_ftrace_filter | 1709 | # cat set_ftrace_filter |
1710 | # | 1710 | # |
1711 | 1711 | ||
1712 | Again, now we want to append. | 1712 | Again, now we want to append. |
1713 | 1713 | ||
1714 | # echo sys_nanosleep > set_ftrace_filter | 1714 | # echo sys_nanosleep > set_ftrace_filter |
1715 | # cat set_ftrace_filter | 1715 | # cat set_ftrace_filter |
1716 | sys_nanosleep | 1716 | sys_nanosleep |
1717 | # echo 'hrtimer_*' >> set_ftrace_filter | 1717 | # echo 'hrtimer_*' >> set_ftrace_filter |
1718 | # cat set_ftrace_filter | 1718 | # cat set_ftrace_filter |
1719 | hrtimer_run_queues | 1719 | hrtimer_run_queues |
1720 | hrtimer_run_pending | 1720 | hrtimer_run_pending |
1721 | hrtimer_init | 1721 | hrtimer_init |
1722 | hrtimer_cancel | 1722 | hrtimer_cancel |
1723 | hrtimer_try_to_cancel | 1723 | hrtimer_try_to_cancel |
1724 | hrtimer_forward | 1724 | hrtimer_forward |
1725 | hrtimer_start | 1725 | hrtimer_start |
1726 | hrtimer_reprogram | 1726 | hrtimer_reprogram |
1727 | hrtimer_force_reprogram | 1727 | hrtimer_force_reprogram |
1728 | hrtimer_get_next_event | 1728 | hrtimer_get_next_event |
1729 | hrtimer_interrupt | 1729 | hrtimer_interrupt |
1730 | sys_nanosleep | 1730 | sys_nanosleep |
1731 | hrtimer_nanosleep | 1731 | hrtimer_nanosleep |
1732 | hrtimer_wakeup | 1732 | hrtimer_wakeup |
1733 | hrtimer_get_remaining | 1733 | hrtimer_get_remaining |
1734 | hrtimer_get_res | 1734 | hrtimer_get_res |
1735 | hrtimer_init_sleeper | 1735 | hrtimer_init_sleeper |
1736 | 1736 | ||
1737 | 1737 | ||
1738 | The set_ftrace_notrace prevents those functions from being | 1738 | The set_ftrace_notrace prevents those functions from being |
1739 | traced. | 1739 | traced. |
1740 | 1740 | ||
1741 | # echo '*preempt*' '*lock*' > set_ftrace_notrace | 1741 | # echo '*preempt*' '*lock*' > set_ftrace_notrace |
1742 | 1742 | ||
1743 | Produces: | 1743 | Produces: |
1744 | 1744 | ||
1745 | # tracer: ftrace | 1745 | # tracer: ftrace |
1746 | # | 1746 | # |
1747 | # TASK-PID CPU# TIMESTAMP FUNCTION | 1747 | # TASK-PID CPU# TIMESTAMP FUNCTION |
1748 | # | | | | | | 1748 | # | | | | | |
1749 | bash-4043 [01] 115.281644: finish_task_switch <-schedule | 1749 | bash-4043 [01] 115.281644: finish_task_switch <-schedule |
1750 | bash-4043 [01] 115.281645: hrtick_set <-schedule | 1750 | bash-4043 [01] 115.281645: hrtick_set <-schedule |
1751 | bash-4043 [01] 115.281645: hrtick_clear <-hrtick_set | 1751 | bash-4043 [01] 115.281645: hrtick_clear <-hrtick_set |
1752 | bash-4043 [01] 115.281646: wait_for_completion <-__stop_machine_run | 1752 | bash-4043 [01] 115.281646: wait_for_completion <-__stop_machine_run |
1753 | bash-4043 [01] 115.281647: wait_for_common <-wait_for_completion | 1753 | bash-4043 [01] 115.281647: wait_for_common <-wait_for_completion |
1754 | bash-4043 [01] 115.281647: kthread_stop <-stop_machine_run | 1754 | bash-4043 [01] 115.281647: kthread_stop <-stop_machine_run |
1755 | bash-4043 [01] 115.281648: init_waitqueue_head <-kthread_stop | 1755 | bash-4043 [01] 115.281648: init_waitqueue_head <-kthread_stop |
1756 | bash-4043 [01] 115.281648: wake_up_process <-kthread_stop | 1756 | bash-4043 [01] 115.281648: wake_up_process <-kthread_stop |
1757 | bash-4043 [01] 115.281649: try_to_wake_up <-wake_up_process | 1757 | bash-4043 [01] 115.281649: try_to_wake_up <-wake_up_process |
1758 | 1758 | ||
1759 | We can see that there's no more lock or preempt tracing. | 1759 | We can see that there's no more lock or preempt tracing. |
1760 | 1760 | ||
1761 | 1761 | ||
1762 | Dynamic ftrace with the function graph tracer | 1762 | Dynamic ftrace with the function graph tracer |
1763 | --------------------------------------------- | 1763 | --------------------------------------------- |
1764 | 1764 | ||
1765 | Although what has been explained above concerns both the | 1765 | Although what has been explained above concerns both the |
1766 | function tracer and the function-graph-tracer, there are some | 1766 | function tracer and the function-graph-tracer, there are some |
1767 | special features only available in the function-graph tracer. | 1767 | special features only available in the function-graph tracer. |
1768 | 1768 | ||
1769 | If you want to trace only one function and all of its children, | 1769 | If you want to trace only one function and all of its children, |
1770 | you just have to echo its name into set_graph_function: | 1770 | you just have to echo its name into set_graph_function: |
1771 | 1771 | ||
1772 | echo __do_fault > set_graph_function | 1772 | echo __do_fault > set_graph_function |
1773 | 1773 | ||
1774 | will produce the following "expanded" trace of the __do_fault() | 1774 | will produce the following "expanded" trace of the __do_fault() |
1775 | function: | 1775 | function: |
1776 | 1776 | ||
1777 | 0) | __do_fault() { | 1777 | 0) | __do_fault() { |
1778 | 0) | filemap_fault() { | 1778 | 0) | filemap_fault() { |
1779 | 0) | find_lock_page() { | 1779 | 0) | find_lock_page() { |
1780 | 0) 0.804 us | find_get_page(); | 1780 | 0) 0.804 us | find_get_page(); |
1781 | 0) | __might_sleep() { | 1781 | 0) | __might_sleep() { |
1782 | 0) 1.329 us | } | 1782 | 0) 1.329 us | } |
1783 | 0) 3.904 us | } | 1783 | 0) 3.904 us | } |
1784 | 0) 4.979 us | } | 1784 | 0) 4.979 us | } |
1785 | 0) 0.653 us | _spin_lock(); | 1785 | 0) 0.653 us | _spin_lock(); |
1786 | 0) 0.578 us | page_add_file_rmap(); | 1786 | 0) 0.578 us | page_add_file_rmap(); |
1787 | 0) 0.525 us | native_set_pte_at(); | 1787 | 0) 0.525 us | native_set_pte_at(); |
1788 | 0) 0.585 us | _spin_unlock(); | 1788 | 0) 0.585 us | _spin_unlock(); |
1789 | 0) | unlock_page() { | 1789 | 0) | unlock_page() { |
1790 | 0) 0.541 us | page_waitqueue(); | 1790 | 0) 0.541 us | page_waitqueue(); |
1791 | 0) 0.639 us | __wake_up_bit(); | 1791 | 0) 0.639 us | __wake_up_bit(); |
1792 | 0) 2.786 us | } | 1792 | 0) 2.786 us | } |
1793 | 0) + 14.237 us | } | 1793 | 0) + 14.237 us | } |
1794 | 0) | __do_fault() { | 1794 | 0) | __do_fault() { |
1795 | 0) | filemap_fault() { | 1795 | 0) | filemap_fault() { |
1796 | 0) | find_lock_page() { | 1796 | 0) | find_lock_page() { |
1797 | 0) 0.698 us | find_get_page(); | 1797 | 0) 0.698 us | find_get_page(); |
1798 | 0) | __might_sleep() { | 1798 | 0) | __might_sleep() { |
1799 | 0) 1.412 us | } | 1799 | 0) 1.412 us | } |
1800 | 0) 3.950 us | } | 1800 | 0) 3.950 us | } |
1801 | 0) 5.098 us | } | 1801 | 0) 5.098 us | } |
1802 | 0) 0.631 us | _spin_lock(); | 1802 | 0) 0.631 us | _spin_lock(); |
1803 | 0) 0.571 us | page_add_file_rmap(); | 1803 | 0) 0.571 us | page_add_file_rmap(); |
1804 | 0) 0.526 us | native_set_pte_at(); | 1804 | 0) 0.526 us | native_set_pte_at(); |
1805 | 0) 0.586 us | _spin_unlock(); | 1805 | 0) 0.586 us | _spin_unlock(); |
1806 | 0) | unlock_page() { | 1806 | 0) | unlock_page() { |
1807 | 0) 0.533 us | page_waitqueue(); | 1807 | 0) 0.533 us | page_waitqueue(); |
1808 | 0) 0.638 us | __wake_up_bit(); | 1808 | 0) 0.638 us | __wake_up_bit(); |
1809 | 0) 2.793 us | } | 1809 | 0) 2.793 us | } |
1810 | 0) + 14.012 us | } | 1810 | 0) + 14.012 us | } |
1811 | 1811 | ||
1812 | You can also expand several functions at once: | 1812 | You can also expand several functions at once: |
1813 | 1813 | ||
1814 | echo sys_open > set_graph_function | 1814 | echo sys_open > set_graph_function |
1815 | echo sys_close >> set_graph_function | 1815 | echo sys_close >> set_graph_function |
1816 | 1816 | ||
1817 | Now if you want to go back to trace all functions you can clear | 1817 | Now if you want to go back to trace all functions you can clear |
1818 | this special filter via: | 1818 | this special filter via: |
1819 | 1819 | ||
1820 | echo > set_graph_function | 1820 | echo > set_graph_function |
1821 | 1821 | ||
1822 | 1822 | ||
1823 | trace_pipe | 1823 | trace_pipe |
1824 | ---------- | 1824 | ---------- |
1825 | 1825 | ||
1826 | The trace_pipe outputs the same content as the trace file, but | 1826 | The trace_pipe outputs the same content as the trace file, but |
1827 | the effect on the tracing is different. Every read from | 1827 | the effect on the tracing is different. Every read from |
1828 | trace_pipe is consumed. This means that subsequent reads will be | 1828 | trace_pipe is consumed. This means that subsequent reads will be |
1829 | different. The trace is live. | 1829 | different. The trace is live. |
1830 | 1830 | ||
1831 | # echo function > current_tracer | 1831 | # echo function > current_tracer |
1832 | # cat trace_pipe > /tmp/trace.out & | 1832 | # cat trace_pipe > /tmp/trace.out & |
1833 | [1] 4153 | 1833 | [1] 4153 |
1834 | # echo 1 > tracing_enabled | 1834 | # echo 1 > tracing_enabled |
1835 | # usleep 1 | 1835 | # usleep 1 |
1836 | # echo 0 > tracing_enabled | 1836 | # echo 0 > tracing_enabled |
1837 | # cat trace | 1837 | # cat trace |
1838 | # tracer: function | 1838 | # tracer: function |
1839 | # | 1839 | # |
1840 | # TASK-PID CPU# TIMESTAMP FUNCTION | 1840 | # TASK-PID CPU# TIMESTAMP FUNCTION |
1841 | # | | | | | | 1841 | # | | | | | |
1842 | 1842 | ||
1843 | # | 1843 | # |
1844 | # cat /tmp/trace.out | 1844 | # cat /tmp/trace.out |
1845 | bash-4043 [00] 41.267106: finish_task_switch <-schedule | 1845 | bash-4043 [00] 41.267106: finish_task_switch <-schedule |
1846 | bash-4043 [00] 41.267106: hrtick_set <-schedule | 1846 | bash-4043 [00] 41.267106: hrtick_set <-schedule |
1847 | bash-4043 [00] 41.267107: hrtick_clear <-hrtick_set | 1847 | bash-4043 [00] 41.267107: hrtick_clear <-hrtick_set |
1848 | bash-4043 [00] 41.267108: wait_for_completion <-__stop_machine_run | 1848 | bash-4043 [00] 41.267108: wait_for_completion <-__stop_machine_run |
1849 | bash-4043 [00] 41.267108: wait_for_common <-wait_for_completion | 1849 | bash-4043 [00] 41.267108: wait_for_common <-wait_for_completion |
1850 | bash-4043 [00] 41.267109: kthread_stop <-stop_machine_run | 1850 | bash-4043 [00] 41.267109: kthread_stop <-stop_machine_run |
1851 | bash-4043 [00] 41.267109: init_waitqueue_head <-kthread_stop | 1851 | bash-4043 [00] 41.267109: init_waitqueue_head <-kthread_stop |
1852 | bash-4043 [00] 41.267110: wake_up_process <-kthread_stop | 1852 | bash-4043 [00] 41.267110: wake_up_process <-kthread_stop |
1853 | bash-4043 [00] 41.267110: try_to_wake_up <-wake_up_process | 1853 | bash-4043 [00] 41.267110: try_to_wake_up <-wake_up_process |
1854 | bash-4043 [00] 41.267111: select_task_rq_rt <-try_to_wake_up | 1854 | bash-4043 [00] 41.267111: select_task_rq_rt <-try_to_wake_up |
1855 | 1855 | ||
1856 | 1856 | ||
1857 | Note, reading the trace_pipe file will block until more input is | 1857 | Note, reading the trace_pipe file will block until more input is |
1858 | added. By changing the tracer, trace_pipe will issue an EOF. We | 1858 | added. By changing the tracer, trace_pipe will issue an EOF. We |
1859 | needed to set the function tracer _before_ we "cat" the | 1859 | needed to set the function tracer _before_ we "cat" the |
1860 | trace_pipe file. | 1860 | trace_pipe file. |
1861 | 1861 | ||
1862 | 1862 | ||
1863 | trace entries | 1863 | trace entries |
1864 | ------------- | 1864 | ------------- |
1865 | 1865 | ||
1866 | Having too much or not enough data can be troublesome in | 1866 | Having too much or not enough data can be troublesome in |
1867 | diagnosing an issue in the kernel. The file buffer_size_kb is | 1867 | diagnosing an issue in the kernel. The file buffer_size_kb is |
1868 | used to modify the size of the internal trace buffers. The | 1868 | used to modify the size of the internal trace buffers. The |
1869 | number listed is the number of entries that can be recorded per | 1869 | number listed is the number of entries that can be recorded per |
1870 | CPU. To know the full size, multiply the number of possible CPUS | 1870 | CPU. To know the full size, multiply the number of possible CPUS |
1871 | with the number of entries. | 1871 | with the number of entries. |
1872 | 1872 | ||
1873 | # cat buffer_size_kb | 1873 | # cat buffer_size_kb |
1874 | 1408 (units kilobytes) | 1874 | 1408 (units kilobytes) |
1875 | 1875 | ||
1876 | Note, to modify this, you must have tracing completely disabled. | 1876 | Note, to modify this, you must have tracing completely disabled. |
1877 | To do that, echo "nop" into the current_tracer. If the | 1877 | To do that, echo "nop" into the current_tracer. If the |
1878 | current_tracer is not set to "nop", an EINVAL error will be | 1878 | current_tracer is not set to "nop", an EINVAL error will be |
1879 | returned. | 1879 | returned. |
1880 | 1880 | ||
1881 | # echo nop > current_tracer | 1881 | # echo nop > current_tracer |
1882 | # echo 10000 > buffer_size_kb | 1882 | # echo 10000 > buffer_size_kb |
1883 | # cat buffer_size_kb | 1883 | # cat buffer_size_kb |
1884 | 10000 (units kilobytes) | 1884 | 10000 (units kilobytes) |
1885 | 1885 | ||
1886 | The number of pages which will be allocated is limited to a | 1886 | The number of pages which will be allocated is limited to a |
1887 | percentage of available memory. Allocating too much will produce | 1887 | percentage of available memory. Allocating too much will produce |
1888 | an error. | 1888 | an error. |
1889 | 1889 | ||
1890 | # echo 1000000000000 > buffer_size_kb | 1890 | # echo 1000000000000 > buffer_size_kb |
1891 | -bash: echo: write error: Cannot allocate memory | 1891 | -bash: echo: write error: Cannot allocate memory |
1892 | # cat buffer_size_kb | 1892 | # cat buffer_size_kb |
1893 | 85 | 1893 | 85 |
1894 | 1894 | ||
1895 | ----------- | 1895 | ----------- |
1896 | 1896 | ||
1897 | More details can be found in the source code, in the | 1897 | More details can be found in the source code, in the |
1898 | kernel/trace/*.c files. | 1898 | kernel/trace/*.c files. |
1899 | 1899 |
arch/arm/Makefile
1 | # | 1 | # |
2 | # arch/arm/Makefile | 2 | # arch/arm/Makefile |
3 | # | 3 | # |
4 | # This file is included by the global makefile so that you can add your own | 4 | # This file is included by the global makefile so that you can add your own |
5 | # architecture-specific flags and dependencies. | 5 | # architecture-specific flags and dependencies. |
6 | # | 6 | # |
7 | # This file is subject to the terms and conditions of the GNU General Public | 7 | # This file is subject to the terms and conditions of the GNU General Public |
8 | # License. See the file "COPYING" in the main directory of this archive | 8 | # License. See the file "COPYING" in the main directory of this archive |
9 | # for more details. | 9 | # for more details. |
10 | # | 10 | # |
11 | # Copyright (C) 1995-2001 by Russell King | 11 | # Copyright (C) 1995-2001 by Russell King |
12 | 12 | ||
13 | LDFLAGS_vmlinux :=-p --no-undefined -X | 13 | LDFLAGS_vmlinux :=-p --no-undefined -X |
14 | ifeq ($(CONFIG_CPU_ENDIAN_BE8),y) | 14 | ifeq ($(CONFIG_CPU_ENDIAN_BE8),y) |
15 | LDFLAGS_vmlinux += --be8 | 15 | LDFLAGS_vmlinux += --be8 |
16 | endif | 16 | endif |
17 | CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET) | 17 | CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET) |
18 | OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S | 18 | OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S |
19 | GZFLAGS :=-9 | 19 | GZFLAGS :=-9 |
20 | #KBUILD_CFLAGS +=-pipe | 20 | #KBUILD_CFLAGS +=-pipe |
21 | # Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb: | 21 | # Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb: |
22 | KBUILD_CFLAGS +=$(call cc-option,-marm,) | 22 | KBUILD_CFLAGS +=$(call cc-option,-marm,) |
23 | 23 | ||
24 | # Do not use arch/arm/defconfig - it's always outdated. | 24 | # Do not use arch/arm/defconfig - it's always outdated. |
25 | # Select a platform tht is kept up-to-date | 25 | # Select a platform tht is kept up-to-date |
26 | KBUILD_DEFCONFIG := versatile_defconfig | 26 | KBUILD_DEFCONFIG := versatile_defconfig |
27 | 27 | ||
28 | # defines filename extension depending memory manement type. | 28 | # defines filename extension depending memory management type. |
29 | ifeq ($(CONFIG_MMU),) | 29 | ifeq ($(CONFIG_MMU),) |
30 | MMUEXT := -nommu | 30 | MMUEXT := -nommu |
31 | endif | 31 | endif |
32 | 32 | ||
33 | ifeq ($(CONFIG_FRAME_POINTER),y) | 33 | ifeq ($(CONFIG_FRAME_POINTER),y) |
34 | KBUILD_CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog | 34 | KBUILD_CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog |
35 | endif | 35 | endif |
36 | 36 | ||
37 | ifeq ($(CONFIG_CPU_BIG_ENDIAN),y) | 37 | ifeq ($(CONFIG_CPU_BIG_ENDIAN),y) |
38 | KBUILD_CPPFLAGS += -mbig-endian | 38 | KBUILD_CPPFLAGS += -mbig-endian |
39 | AS += -EB | 39 | AS += -EB |
40 | LD += -EB | 40 | LD += -EB |
41 | else | 41 | else |
42 | KBUILD_CPPFLAGS += -mlittle-endian | 42 | KBUILD_CPPFLAGS += -mlittle-endian |
43 | AS += -EL | 43 | AS += -EL |
44 | LD += -EL | 44 | LD += -EL |
45 | endif | 45 | endif |
46 | 46 | ||
47 | comma = , | 47 | comma = , |
48 | 48 | ||
49 | # This selects which instruction set is used. | 49 | # This selects which instruction set is used. |
50 | # Note that GCC does not numerically define an architecture version | 50 | # Note that GCC does not numerically define an architecture version |
51 | # macro, but instead defines a whole series of macros which makes | 51 | # macro, but instead defines a whole series of macros which makes |
52 | # testing for a specific architecture or later rather impossible. | 52 | # testing for a specific architecture or later rather impossible. |
53 | arch-$(CONFIG_CPU_32v7) :=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a) | 53 | arch-$(CONFIG_CPU_32v7) :=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a) |
54 | arch-$(CONFIG_CPU_32v6) :=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6) | 54 | arch-$(CONFIG_CPU_32v6) :=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6) |
55 | # Only override the compiler option if ARMv6. The ARMv6K extensions are | 55 | # Only override the compiler option if ARMv6. The ARMv6K extensions are |
56 | # always available in ARMv7 | 56 | # always available in ARMv7 |
57 | ifeq ($(CONFIG_CPU_32v6),y) | 57 | ifeq ($(CONFIG_CPU_32v6),y) |
58 | arch-$(CONFIG_CPU_32v6K) :=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6k,-march=armv5t -Wa$(comma)-march=armv6k) | 58 | arch-$(CONFIG_CPU_32v6K) :=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6k,-march=armv5t -Wa$(comma)-march=armv6k) |
59 | endif | 59 | endif |
60 | arch-$(CONFIG_CPU_32v5) :=-D__LINUX_ARM_ARCH__=5 $(call cc-option,-march=armv5te,-march=armv4t) | 60 | arch-$(CONFIG_CPU_32v5) :=-D__LINUX_ARM_ARCH__=5 $(call cc-option,-march=armv5te,-march=armv4t) |
61 | arch-$(CONFIG_CPU_32v4T) :=-D__LINUX_ARM_ARCH__=4 -march=armv4t | 61 | arch-$(CONFIG_CPU_32v4T) :=-D__LINUX_ARM_ARCH__=4 -march=armv4t |
62 | arch-$(CONFIG_CPU_32v4) :=-D__LINUX_ARM_ARCH__=4 -march=armv4 | 62 | arch-$(CONFIG_CPU_32v4) :=-D__LINUX_ARM_ARCH__=4 -march=armv4 |
63 | arch-$(CONFIG_CPU_32v3) :=-D__LINUX_ARM_ARCH__=3 -march=armv3 | 63 | arch-$(CONFIG_CPU_32v3) :=-D__LINUX_ARM_ARCH__=3 -march=armv3 |
64 | 64 | ||
65 | # This selects how we optimise for the processor. | 65 | # This selects how we optimise for the processor. |
66 | tune-$(CONFIG_CPU_ARM610) :=-mtune=arm610 | 66 | tune-$(CONFIG_CPU_ARM610) :=-mtune=arm610 |
67 | tune-$(CONFIG_CPU_ARM710) :=-mtune=arm710 | 67 | tune-$(CONFIG_CPU_ARM710) :=-mtune=arm710 |
68 | tune-$(CONFIG_CPU_ARM7TDMI) :=-mtune=arm7tdmi | 68 | tune-$(CONFIG_CPU_ARM7TDMI) :=-mtune=arm7tdmi |
69 | tune-$(CONFIG_CPU_ARM720T) :=-mtune=arm7tdmi | 69 | tune-$(CONFIG_CPU_ARM720T) :=-mtune=arm7tdmi |
70 | tune-$(CONFIG_CPU_ARM740T) :=-mtune=arm7tdmi | 70 | tune-$(CONFIG_CPU_ARM740T) :=-mtune=arm7tdmi |
71 | tune-$(CONFIG_CPU_ARM9TDMI) :=-mtune=arm9tdmi | 71 | tune-$(CONFIG_CPU_ARM9TDMI) :=-mtune=arm9tdmi |
72 | tune-$(CONFIG_CPU_ARM940T) :=-mtune=arm9tdmi | 72 | tune-$(CONFIG_CPU_ARM940T) :=-mtune=arm9tdmi |
73 | tune-$(CONFIG_CPU_ARM946E) :=$(call cc-option,-mtune=arm9e,-mtune=arm9tdmi) | 73 | tune-$(CONFIG_CPU_ARM946E) :=$(call cc-option,-mtune=arm9e,-mtune=arm9tdmi) |
74 | tune-$(CONFIG_CPU_ARM920T) :=-mtune=arm9tdmi | 74 | tune-$(CONFIG_CPU_ARM920T) :=-mtune=arm9tdmi |
75 | tune-$(CONFIG_CPU_ARM922T) :=-mtune=arm9tdmi | 75 | tune-$(CONFIG_CPU_ARM922T) :=-mtune=arm9tdmi |
76 | tune-$(CONFIG_CPU_ARM925T) :=-mtune=arm9tdmi | 76 | tune-$(CONFIG_CPU_ARM925T) :=-mtune=arm9tdmi |
77 | tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi | 77 | tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi |
78 | tune-$(CONFIG_CPU_FA526) :=-mtune=arm9tdmi | 78 | tune-$(CONFIG_CPU_FA526) :=-mtune=arm9tdmi |
79 | tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 | 79 | tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 |
80 | tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 | 80 | tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 |
81 | tune-$(CONFIG_CPU_XSCALE) :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale | 81 | tune-$(CONFIG_CPU_XSCALE) :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale |
82 | tune-$(CONFIG_CPU_XSC3) :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale | 82 | tune-$(CONFIG_CPU_XSC3) :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale |
83 | tune-$(CONFIG_CPU_FEROCEON) :=$(call cc-option,-mtune=marvell-f,-mtune=xscale) | 83 | tune-$(CONFIG_CPU_FEROCEON) :=$(call cc-option,-mtune=marvell-f,-mtune=xscale) |
84 | tune-$(CONFIG_CPU_V6) :=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm) | 84 | tune-$(CONFIG_CPU_V6) :=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm) |
85 | 85 | ||
86 | ifeq ($(CONFIG_AEABI),y) | 86 | ifeq ($(CONFIG_AEABI),y) |
87 | CFLAGS_ABI :=-mabi=aapcs-linux -mno-thumb-interwork | 87 | CFLAGS_ABI :=-mabi=aapcs-linux -mno-thumb-interwork |
88 | else | 88 | else |
89 | CFLAGS_ABI :=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) $(call cc-option,-mno-thumb-interwork,) | 89 | CFLAGS_ABI :=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) $(call cc-option,-mno-thumb-interwork,) |
90 | endif | 90 | endif |
91 | 91 | ||
92 | ifeq ($(CONFIG_ARM_UNWIND),y) | 92 | ifeq ($(CONFIG_ARM_UNWIND),y) |
93 | CFLAGS_ABI +=-funwind-tables | 93 | CFLAGS_ABI +=-funwind-tables |
94 | endif | 94 | endif |
95 | 95 | ||
96 | ifeq ($(CONFIG_THUMB2_KERNEL),y) | 96 | ifeq ($(CONFIG_THUMB2_KERNEL),y) |
97 | AFLAGS_AUTOIT :=$(call as-option,-Wa$(comma)-mimplicit-it=thumb,-Wa$(comma)-mauto-it) | 97 | AFLAGS_AUTOIT :=$(call as-option,-Wa$(comma)-mimplicit-it=thumb,-Wa$(comma)-mauto-it) |
98 | AFLAGS_NOWARN :=$(call as-option,-Wa$(comma)-mno-warn-deprecated,-Wa$(comma)-W) | 98 | AFLAGS_NOWARN :=$(call as-option,-Wa$(comma)-mno-warn-deprecated,-Wa$(comma)-W) |
99 | CFLAGS_THUMB2 :=-mthumb $(AFLAGS_AUTOIT) $(AFLAGS_NOWARN) | 99 | CFLAGS_THUMB2 :=-mthumb $(AFLAGS_AUTOIT) $(AFLAGS_NOWARN) |
100 | AFLAGS_THUMB2 :=$(CFLAGS_THUMB2) -Wa$(comma)-mthumb | 100 | AFLAGS_THUMB2 :=$(CFLAGS_THUMB2) -Wa$(comma)-mthumb |
101 | endif | 101 | endif |
102 | 102 | ||
103 | # Need -Uarm for gcc < 3.x | 103 | # Need -Uarm for gcc < 3.x |
104 | KBUILD_CFLAGS +=$(CFLAGS_ABI) $(CFLAGS_THUMB2) $(arch-y) $(tune-y) $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) -msoft-float -Uarm | 104 | KBUILD_CFLAGS +=$(CFLAGS_ABI) $(CFLAGS_THUMB2) $(arch-y) $(tune-y) $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) -msoft-float -Uarm |
105 | KBUILD_AFLAGS +=$(CFLAGS_ABI) $(AFLAGS_THUMB2) $(arch-y) $(tune-y) -include asm/unified.h -msoft-float | 105 | KBUILD_AFLAGS +=$(CFLAGS_ABI) $(AFLAGS_THUMB2) $(arch-y) $(tune-y) -include asm/unified.h -msoft-float |
106 | 106 | ||
107 | CHECKFLAGS += -D__arm__ | 107 | CHECKFLAGS += -D__arm__ |
108 | 108 | ||
109 | #Default value | 109 | #Default value |
110 | head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o | 110 | head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o |
111 | textofs-y := 0x00008000 | 111 | textofs-y := 0x00008000 |
112 | textofs-$(CONFIG_ARCH_CLPS711X) := 0x00028000 | 112 | textofs-$(CONFIG_ARCH_CLPS711X) := 0x00028000 |
113 | # SA1111 DMA bug: we don't want the kernel to live in precious DMA-able memory | 113 | # SA1111 DMA bug: we don't want the kernel to live in precious DMA-able memory |
114 | ifeq ($(CONFIG_ARCH_SA1100),y) | 114 | ifeq ($(CONFIG_ARCH_SA1100),y) |
115 | textofs-$(CONFIG_SA1111) := 0x00208000 | 115 | textofs-$(CONFIG_SA1111) := 0x00208000 |
116 | endif | 116 | endif |
117 | 117 | ||
118 | # Machine directory name. This list is sorted alphanumerically | 118 | # Machine directory name. This list is sorted alphanumerically |
119 | # by CONFIG_* macro name. | 119 | # by CONFIG_* macro name. |
120 | machine-$(CONFIG_ARCH_AAEC2000) := aaec2000 | 120 | machine-$(CONFIG_ARCH_AAEC2000) := aaec2000 |
121 | machine-$(CONFIG_ARCH_AT91) := at91 | 121 | machine-$(CONFIG_ARCH_AT91) := at91 |
122 | machine-$(CONFIG_ARCH_BCMRING) := bcmring | 122 | machine-$(CONFIG_ARCH_BCMRING) := bcmring |
123 | machine-$(CONFIG_ARCH_CLPS711X) := clps711x | 123 | machine-$(CONFIG_ARCH_CLPS711X) := clps711x |
124 | machine-$(CONFIG_ARCH_DAVINCI) := davinci | 124 | machine-$(CONFIG_ARCH_DAVINCI) := davinci |
125 | machine-$(CONFIG_ARCH_EBSA110) := ebsa110 | 125 | machine-$(CONFIG_ARCH_EBSA110) := ebsa110 |
126 | machine-$(CONFIG_ARCH_EP93XX) := ep93xx | 126 | machine-$(CONFIG_ARCH_EP93XX) := ep93xx |
127 | machine-$(CONFIG_ARCH_GEMINI) := gemini | 127 | machine-$(CONFIG_ARCH_GEMINI) := gemini |
128 | machine-$(CONFIG_ARCH_H720X) := h720x | 128 | machine-$(CONFIG_ARCH_H720X) := h720x |
129 | machine-$(CONFIG_ARCH_INTEGRATOR) := integrator | 129 | machine-$(CONFIG_ARCH_INTEGRATOR) := integrator |
130 | machine-$(CONFIG_ARCH_IOP13XX) := iop13xx | 130 | machine-$(CONFIG_ARCH_IOP13XX) := iop13xx |
131 | machine-$(CONFIG_ARCH_IOP32X) := iop32x | 131 | machine-$(CONFIG_ARCH_IOP32X) := iop32x |
132 | machine-$(CONFIG_ARCH_IOP33X) := iop33x | 132 | machine-$(CONFIG_ARCH_IOP33X) := iop33x |
133 | machine-$(CONFIG_ARCH_IXP2000) := ixp2000 | 133 | machine-$(CONFIG_ARCH_IXP2000) := ixp2000 |
134 | machine-$(CONFIG_ARCH_IXP23XX) := ixp23xx | 134 | machine-$(CONFIG_ARCH_IXP23XX) := ixp23xx |
135 | machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx | 135 | machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx |
136 | machine-$(CONFIG_ARCH_KIRKWOOD) := kirkwood | 136 | machine-$(CONFIG_ARCH_KIRKWOOD) := kirkwood |
137 | machine-$(CONFIG_ARCH_KS8695) := ks8695 | 137 | machine-$(CONFIG_ARCH_KS8695) := ks8695 |
138 | machine-$(CONFIG_ARCH_L7200) := l7200 | 138 | machine-$(CONFIG_ARCH_L7200) := l7200 |
139 | machine-$(CONFIG_ARCH_LH7A40X) := lh7a40x | 139 | machine-$(CONFIG_ARCH_LH7A40X) := lh7a40x |
140 | machine-$(CONFIG_ARCH_LOKI) := loki | 140 | machine-$(CONFIG_ARCH_LOKI) := loki |
141 | machine-$(CONFIG_ARCH_MMP) := mmp | 141 | machine-$(CONFIG_ARCH_MMP) := mmp |
142 | machine-$(CONFIG_ARCH_MSM) := msm | 142 | machine-$(CONFIG_ARCH_MSM) := msm |
143 | machine-$(CONFIG_ARCH_MV78XX0) := mv78xx0 | 143 | machine-$(CONFIG_ARCH_MV78XX0) := mv78xx0 |
144 | machine-$(CONFIG_ARCH_MX1) := mx1 | 144 | machine-$(CONFIG_ARCH_MX1) := mx1 |
145 | machine-$(CONFIG_ARCH_MX2) := mx2 | 145 | machine-$(CONFIG_ARCH_MX2) := mx2 |
146 | machine-$(CONFIG_ARCH_MX25) := mx25 | 146 | machine-$(CONFIG_ARCH_MX25) := mx25 |
147 | machine-$(CONFIG_ARCH_MX3) := mx3 | 147 | machine-$(CONFIG_ARCH_MX3) := mx3 |
148 | machine-$(CONFIG_ARCH_NETX) := netx | 148 | machine-$(CONFIG_ARCH_NETX) := netx |
149 | machine-$(CONFIG_ARCH_NOMADIK) := nomadik | 149 | machine-$(CONFIG_ARCH_NOMADIK) := nomadik |
150 | machine-$(CONFIG_ARCH_NS9XXX) := ns9xxx | 150 | machine-$(CONFIG_ARCH_NS9XXX) := ns9xxx |
151 | machine-$(CONFIG_ARCH_OMAP1) := omap1 | 151 | machine-$(CONFIG_ARCH_OMAP1) := omap1 |
152 | machine-$(CONFIG_ARCH_OMAP2) := omap2 | 152 | machine-$(CONFIG_ARCH_OMAP2) := omap2 |
153 | machine-$(CONFIG_ARCH_OMAP3) := omap2 | 153 | machine-$(CONFIG_ARCH_OMAP3) := omap2 |
154 | machine-$(CONFIG_ARCH_OMAP4) := omap2 | 154 | machine-$(CONFIG_ARCH_OMAP4) := omap2 |
155 | machine-$(CONFIG_ARCH_ORION5X) := orion5x | 155 | machine-$(CONFIG_ARCH_ORION5X) := orion5x |
156 | machine-$(CONFIG_ARCH_PNX4008) := pnx4008 | 156 | machine-$(CONFIG_ARCH_PNX4008) := pnx4008 |
157 | machine-$(CONFIG_ARCH_PXA) := pxa | 157 | machine-$(CONFIG_ARCH_PXA) := pxa |
158 | machine-$(CONFIG_ARCH_REALVIEW) := realview | 158 | machine-$(CONFIG_ARCH_REALVIEW) := realview |
159 | machine-$(CONFIG_ARCH_RPC) := rpc | 159 | machine-$(CONFIG_ARCH_RPC) := rpc |
160 | machine-$(CONFIG_ARCH_S3C2410) := s3c2410 s3c2400 s3c2412 s3c2440 s3c2442 s3c2443 | 160 | machine-$(CONFIG_ARCH_S3C2410) := s3c2410 s3c2400 s3c2412 s3c2440 s3c2442 s3c2443 |
161 | machine-$(CONFIG_ARCH_S3C24A0) := s3c24a0 | 161 | machine-$(CONFIG_ARCH_S3C24A0) := s3c24a0 |
162 | machine-$(CONFIG_ARCH_S3C64XX) := s3c6400 s3c6410 | 162 | machine-$(CONFIG_ARCH_S3C64XX) := s3c6400 s3c6410 |
163 | machine-$(CONFIG_ARCH_S5PC1XX) := s5pc100 | 163 | machine-$(CONFIG_ARCH_S5PC1XX) := s5pc100 |
164 | machine-$(CONFIG_ARCH_SA1100) := sa1100 | 164 | machine-$(CONFIG_ARCH_SA1100) := sa1100 |
165 | machine-$(CONFIG_ARCH_SHARK) := shark | 165 | machine-$(CONFIG_ARCH_SHARK) := shark |
166 | machine-$(CONFIG_ARCH_STMP378X) := stmp378x | 166 | machine-$(CONFIG_ARCH_STMP378X) := stmp378x |
167 | machine-$(CONFIG_ARCH_STMP37XX) := stmp37xx | 167 | machine-$(CONFIG_ARCH_STMP37XX) := stmp37xx |
168 | machine-$(CONFIG_ARCH_U300) := u300 | 168 | machine-$(CONFIG_ARCH_U300) := u300 |
169 | machine-$(CONFIG_ARCH_VERSATILE) := versatile | 169 | machine-$(CONFIG_ARCH_VERSATILE) := versatile |
170 | machine-$(CONFIG_ARCH_W90X900) := w90x900 | 170 | machine-$(CONFIG_ARCH_W90X900) := w90x900 |
171 | machine-$(CONFIG_FOOTBRIDGE) := footbridge | 171 | machine-$(CONFIG_FOOTBRIDGE) := footbridge |
172 | machine-$(CONFIG_ARCH_MXC91231) := mxc91231 | 172 | machine-$(CONFIG_ARCH_MXC91231) := mxc91231 |
173 | 173 | ||
174 | # Platform directory name. This list is sorted alphanumerically | 174 | # Platform directory name. This list is sorted alphanumerically |
175 | # by CONFIG_* macro name. | 175 | # by CONFIG_* macro name. |
176 | plat-$(CONFIG_ARCH_MXC) := mxc | 176 | plat-$(CONFIG_ARCH_MXC) := mxc |
177 | plat-$(CONFIG_ARCH_OMAP) := omap | 177 | plat-$(CONFIG_ARCH_OMAP) := omap |
178 | plat-$(CONFIG_PLAT_IOP) := iop | 178 | plat-$(CONFIG_PLAT_IOP) := iop |
179 | plat-$(CONFIG_PLAT_ORION) := orion | 179 | plat-$(CONFIG_PLAT_ORION) := orion |
180 | plat-$(CONFIG_PLAT_PXA) := pxa | 180 | plat-$(CONFIG_PLAT_PXA) := pxa |
181 | plat-$(CONFIG_PLAT_S3C24XX) := s3c24xx s3c | 181 | plat-$(CONFIG_PLAT_S3C24XX) := s3c24xx s3c |
182 | plat-$(CONFIG_PLAT_S3C64XX) := s3c64xx s3c | 182 | plat-$(CONFIG_PLAT_S3C64XX) := s3c64xx s3c |
183 | plat-$(CONFIG_PLAT_S5PC1XX) := s5pc1xx s3c | 183 | plat-$(CONFIG_PLAT_S5PC1XX) := s5pc1xx s3c |
184 | plat-$(CONFIG_ARCH_STMP3XXX) := stmp3xxx | 184 | plat-$(CONFIG_ARCH_STMP3XXX) := stmp3xxx |
185 | 185 | ||
186 | ifeq ($(CONFIG_ARCH_EBSA110),y) | 186 | ifeq ($(CONFIG_ARCH_EBSA110),y) |
187 | # This is what happens if you forget the IOCS16 line. | 187 | # This is what happens if you forget the IOCS16 line. |
188 | # PCMCIA cards stop working. | 188 | # PCMCIA cards stop working. |
189 | CFLAGS_3c589_cs.o :=-DISA_SIXTEEN_BIT_PERIPHERAL | 189 | CFLAGS_3c589_cs.o :=-DISA_SIXTEEN_BIT_PERIPHERAL |
190 | export CFLAGS_3c589_cs.o | 190 | export CFLAGS_3c589_cs.o |
191 | endif | 191 | endif |
192 | 192 | ||
193 | # The byte offset of the kernel image in RAM from the start of RAM. | 193 | # The byte offset of the kernel image in RAM from the start of RAM. |
194 | TEXT_OFFSET := $(textofs-y) | 194 | TEXT_OFFSET := $(textofs-y) |
195 | 195 | ||
196 | # The first directory contains additional information for the boot setup code | 196 | # The first directory contains additional information for the boot setup code |
197 | ifneq ($(machine-y),) | 197 | ifneq ($(machine-y),) |
198 | MACHINE := arch/arm/mach-$(word 1,$(machine-y))/ | 198 | MACHINE := arch/arm/mach-$(word 1,$(machine-y))/ |
199 | else | 199 | else |
200 | MACHINE := | 200 | MACHINE := |
201 | endif | 201 | endif |
202 | 202 | ||
203 | machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y)) | 203 | machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y)) |
204 | platdirs := $(patsubst %,arch/arm/plat-%/,$(plat-y)) | 204 | platdirs := $(patsubst %,arch/arm/plat-%/,$(plat-y)) |
205 | 205 | ||
206 | ifeq ($(KBUILD_SRC),) | 206 | ifeq ($(KBUILD_SRC),) |
207 | KBUILD_CPPFLAGS += $(patsubst %,-I%include,$(machdirs) $(platdirs)) | 207 | KBUILD_CPPFLAGS += $(patsubst %,-I%include,$(machdirs) $(platdirs)) |
208 | else | 208 | else |
209 | KBUILD_CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(machdirs) $(platdirs)) | 209 | KBUILD_CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(machdirs) $(platdirs)) |
210 | endif | 210 | endif |
211 | 211 | ||
212 | export TEXT_OFFSET GZFLAGS MMUEXT | 212 | export TEXT_OFFSET GZFLAGS MMUEXT |
213 | 213 | ||
214 | # Do we have FASTFPE? | 214 | # Do we have FASTFPE? |
215 | FASTFPE :=arch/arm/fastfpe | 215 | FASTFPE :=arch/arm/fastfpe |
216 | ifeq ($(FASTFPE),$(wildcard $(FASTFPE))) | 216 | ifeq ($(FASTFPE),$(wildcard $(FASTFPE))) |
217 | FASTFPE_OBJ :=$(FASTFPE)/ | 217 | FASTFPE_OBJ :=$(FASTFPE)/ |
218 | endif | 218 | endif |
219 | 219 | ||
220 | # If we have a machine-specific directory, then include it in the build. | 220 | # If we have a machine-specific directory, then include it in the build. |
221 | core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ | 221 | core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ |
222 | core-y += $(machdirs) $(platdirs) | 222 | core-y += $(machdirs) $(platdirs) |
223 | core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ | 223 | core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ |
224 | core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) | 224 | core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) |
225 | core-$(CONFIG_VFP) += arch/arm/vfp/ | 225 | core-$(CONFIG_VFP) += arch/arm/vfp/ |
226 | 226 | ||
227 | drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/ | 227 | drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/ |
228 | 228 | ||
229 | libs-y := arch/arm/lib/ $(libs-y) | 229 | libs-y := arch/arm/lib/ $(libs-y) |
230 | 230 | ||
231 | # Default target when executing plain make | 231 | # Default target when executing plain make |
232 | ifeq ($(CONFIG_XIP_KERNEL),y) | 232 | ifeq ($(CONFIG_XIP_KERNEL),y) |
233 | KBUILD_IMAGE := xipImage | 233 | KBUILD_IMAGE := xipImage |
234 | else | 234 | else |
235 | KBUILD_IMAGE := zImage | 235 | KBUILD_IMAGE := zImage |
236 | endif | 236 | endif |
237 | 237 | ||
238 | all: $(KBUILD_IMAGE) | 238 | all: $(KBUILD_IMAGE) |
239 | 239 | ||
240 | boot := arch/arm/boot | 240 | boot := arch/arm/boot |
241 | 241 | ||
242 | # Update machine arch and proc symlinks if something which affects | 242 | # Update machine arch and proc symlinks if something which affects |
243 | # them changed. We use .arch to indicate when they were updated | 243 | # them changed. We use .arch to indicate when they were updated |
244 | # last, otherwise make uses the target directory mtime. | 244 | # last, otherwise make uses the target directory mtime. |
245 | 245 | ||
246 | archprepare: maketools | 246 | archprepare: maketools |
247 | 247 | ||
248 | PHONY += maketools FORCE | 248 | PHONY += maketools FORCE |
249 | maketools: include/linux/version.h FORCE | 249 | maketools: include/linux/version.h FORCE |
250 | $(Q)$(MAKE) $(build)=arch/arm/tools include/asm-arm/mach-types.h | 250 | $(Q)$(MAKE) $(build)=arch/arm/tools include/asm-arm/mach-types.h |
251 | 251 | ||
252 | # Convert bzImage to zImage | 252 | # Convert bzImage to zImage |
253 | bzImage: zImage | 253 | bzImage: zImage |
254 | 254 | ||
255 | zImage Image xipImage bootpImage uImage: vmlinux | 255 | zImage Image xipImage bootpImage uImage: vmlinux |
256 | $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ | 256 | $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ |
257 | 257 | ||
258 | zinstall install: vmlinux | 258 | zinstall install: vmlinux |
259 | $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@ | 259 | $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@ |
260 | 260 | ||
261 | CLEAN_FILES += include/asm-arm/mach-types.h \ | 261 | CLEAN_FILES += include/asm-arm/mach-types.h \ |
262 | include/asm-arm/arch include/asm-arm/.arch | 262 | include/asm-arm/arch include/asm-arm/.arch |
263 | 263 | ||
264 | # We use MRPROPER_FILES and CLEAN_FILES now | 264 | # We use MRPROPER_FILES and CLEAN_FILES now |
265 | archclean: | 265 | archclean: |
266 | $(Q)$(MAKE) $(clean)=$(boot) | 266 | $(Q)$(MAKE) $(clean)=$(boot) |
267 | 267 | ||
268 | # My testing targets (bypasses dependencies) | 268 | # My testing targets (bypasses dependencies) |
269 | bp:; $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/bootpImage | 269 | bp:; $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/bootpImage |
270 | i zi:; $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@ | 270 | i zi:; $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@ |
271 | 271 | ||
272 | 272 | ||
273 | define archhelp | 273 | define archhelp |
274 | echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)' | 274 | echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)' |
275 | echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)' | 275 | echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)' |
276 | echo '* xipImage - XIP kernel image, if configured (arch/$(ARCH)/boot/xipImage)' | 276 | echo '* xipImage - XIP kernel image, if configured (arch/$(ARCH)/boot/xipImage)' |
277 | echo ' uImage - U-Boot wrapped zImage' | 277 | echo ' uImage - U-Boot wrapped zImage' |
278 | echo ' bootpImage - Combined zImage and initial RAM disk' | 278 | echo ' bootpImage - Combined zImage and initial RAM disk' |
279 | echo ' (supply initrd image via make variable INITRD=<path>)' | 279 | echo ' (supply initrd image via make variable INITRD=<path>)' |
280 | echo ' install - Install uncompressed kernel' | 280 | echo ' install - Install uncompressed kernel' |
281 | echo ' zinstall - Install compressed kernel' | 281 | echo ' zinstall - Install compressed kernel' |
282 | echo ' Install using (your) ~/bin/installkernel or' | 282 | echo ' Install using (your) ~/bin/installkernel or' |
283 | echo ' (distribution) /sbin/installkernel or' | 283 | echo ' (distribution) /sbin/installkernel or' |
284 | echo ' install to $$(INSTALL_PATH) and run lilo' | 284 | echo ' install to $$(INSTALL_PATH) and run lilo' |
285 | endef | 285 | endef |
286 | 286 |
arch/frv/lib/cache.S
1 | /* cache.S: cache managment routines | 1 | /* cache.S: cache management routines |
2 | * | 2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
8 | * as published by the Free Software Foundation; either version | 8 | * as published by the Free Software Foundation; either version |
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <asm/spr-regs.h> | 12 | #include <asm/spr-regs.h> |
13 | #include <asm/cache.h> | 13 | #include <asm/cache.h> |
14 | 14 | ||
15 | .text | 15 | .text |
16 | .p2align 4 | 16 | .p2align 4 |
17 | 17 | ||
18 | ############################################################################### | 18 | ############################################################################### |
19 | # | 19 | # |
20 | # Write back a range of dcache | 20 | # Write back a range of dcache |
21 | # - void frv_dcache_writeback(unsigned long start [GR8], unsigned long size [GR9]) | 21 | # - void frv_dcache_writeback(unsigned long start [GR8], unsigned long size [GR9]) |
22 | # | 22 | # |
23 | ############################################################################### | 23 | ############################################################################### |
24 | .globl frv_dcache_writeback | 24 | .globl frv_dcache_writeback |
25 | .type frv_dcache_writeback,@function | 25 | .type frv_dcache_writeback,@function |
26 | frv_dcache_writeback: | 26 | frv_dcache_writeback: |
27 | andi gr8,~(L1_CACHE_BYTES-1),gr8 | 27 | andi gr8,~(L1_CACHE_BYTES-1),gr8 |
28 | 28 | ||
29 | 2: dcf @(gr8,gr0) | 29 | 2: dcf @(gr8,gr0) |
30 | addi gr8,#L1_CACHE_BYTES,gr8 | 30 | addi gr8,#L1_CACHE_BYTES,gr8 |
31 | cmp gr9,gr8,icc0 | 31 | cmp gr9,gr8,icc0 |
32 | bhi icc0,#2,2b | 32 | bhi icc0,#2,2b |
33 | 33 | ||
34 | membar | 34 | membar |
35 | bralr | 35 | bralr |
36 | .size frv_dcache_writeback, .-frv_dcache_writeback | 36 | .size frv_dcache_writeback, .-frv_dcache_writeback |
37 | 37 | ||
38 | ############################################################################## | 38 | ############################################################################## |
39 | # | 39 | # |
40 | # Invalidate a range of dcache and icache | 40 | # Invalidate a range of dcache and icache |
41 | # - void frv_cache_invalidate(unsigned long start [GR8], unsigned long end [GR9]); | 41 | # - void frv_cache_invalidate(unsigned long start [GR8], unsigned long end [GR9]); |
42 | # | 42 | # |
43 | ############################################################################### | 43 | ############################################################################### |
44 | .globl frv_cache_invalidate | 44 | .globl frv_cache_invalidate |
45 | .type frv_cache_invalidate,@function | 45 | .type frv_cache_invalidate,@function |
46 | frv_cache_invalidate: | 46 | frv_cache_invalidate: |
47 | andi gr8,~(L1_CACHE_BYTES-1),gr8 | 47 | andi gr8,~(L1_CACHE_BYTES-1),gr8 |
48 | 48 | ||
49 | 2: dci @(gr8,gr0) | 49 | 2: dci @(gr8,gr0) |
50 | ici @(gr8,gr0) | 50 | ici @(gr8,gr0) |
51 | addi gr8,#L1_CACHE_BYTES,gr8 | 51 | addi gr8,#L1_CACHE_BYTES,gr8 |
52 | cmp gr9,gr8,icc0 | 52 | cmp gr9,gr8,icc0 |
53 | bhi icc0,#2,2b | 53 | bhi icc0,#2,2b |
54 | 54 | ||
55 | membar | 55 | membar |
56 | bralr | 56 | bralr |
57 | .size frv_cache_invalidate, .-frv_cache_invalidate | 57 | .size frv_cache_invalidate, .-frv_cache_invalidate |
58 | 58 | ||
59 | ############################################################################## | 59 | ############################################################################## |
60 | # | 60 | # |
61 | # Invalidate a range of icache | 61 | # Invalidate a range of icache |
62 | # - void frv_icache_invalidate(unsigned long start [GR8], unsigned long end [GR9]); | 62 | # - void frv_icache_invalidate(unsigned long start [GR8], unsigned long end [GR9]); |
63 | # | 63 | # |
64 | ############################################################################### | 64 | ############################################################################### |
65 | .globl frv_icache_invalidate | 65 | .globl frv_icache_invalidate |
66 | .type frv_icache_invalidate,@function | 66 | .type frv_icache_invalidate,@function |
67 | frv_icache_invalidate: | 67 | frv_icache_invalidate: |
68 | andi gr8,~(L1_CACHE_BYTES-1),gr8 | 68 | andi gr8,~(L1_CACHE_BYTES-1),gr8 |
69 | 69 | ||
70 | 2: ici @(gr8,gr0) | 70 | 2: ici @(gr8,gr0) |
71 | addi gr8,#L1_CACHE_BYTES,gr8 | 71 | addi gr8,#L1_CACHE_BYTES,gr8 |
72 | cmp gr9,gr8,icc0 | 72 | cmp gr9,gr8,icc0 |
73 | bhi icc0,#2,2b | 73 | bhi icc0,#2,2b |
74 | 74 | ||
75 | membar | 75 | membar |
76 | bralr | 76 | bralr |
77 | .size frv_icache_invalidate, .-frv_icache_invalidate | 77 | .size frv_icache_invalidate, .-frv_icache_invalidate |
78 | 78 | ||
79 | ############################################################################### | 79 | ############################################################################### |
80 | # | 80 | # |
81 | # Write back and invalidate a range of dcache and icache | 81 | # Write back and invalidate a range of dcache and icache |
82 | # - void frv_cache_wback_inv(unsigned long start [GR8], unsigned long end [GR9]) | 82 | # - void frv_cache_wback_inv(unsigned long start [GR8], unsigned long end [GR9]) |
83 | # | 83 | # |
84 | ############################################################################### | 84 | ############################################################################### |
85 | .globl frv_cache_wback_inv | 85 | .globl frv_cache_wback_inv |
86 | .type frv_cache_wback_inv,@function | 86 | .type frv_cache_wback_inv,@function |
87 | frv_cache_wback_inv: | 87 | frv_cache_wback_inv: |
88 | andi gr8,~(L1_CACHE_BYTES-1),gr8 | 88 | andi gr8,~(L1_CACHE_BYTES-1),gr8 |
89 | 89 | ||
90 | 2: dcf @(gr8,gr0) | 90 | 2: dcf @(gr8,gr0) |
91 | ici @(gr8,gr0) | 91 | ici @(gr8,gr0) |
92 | addi gr8,#L1_CACHE_BYTES,gr8 | 92 | addi gr8,#L1_CACHE_BYTES,gr8 |
93 | cmp gr9,gr8,icc0 | 93 | cmp gr9,gr8,icc0 |
94 | bhi icc0,#2,2b | 94 | bhi icc0,#2,2b |
95 | 95 | ||
96 | membar | 96 | membar |
97 | bralr | 97 | bralr |
98 | .size frv_cache_wback_inv, .-frv_cache_wback_inv | 98 | .size frv_cache_wback_inv, .-frv_cache_wback_inv |
99 | 99 |
arch/mn10300/include/asm/cacheflush.h
1 | /* MN10300 Cache flushing | 1 | /* MN10300 Cache flushing |
2 | * | 2 | * |
3 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public Licence | 7 | * modify it under the terms of the GNU General Public Licence |
8 | * as published by the Free Software Foundation; either version | 8 | * as published by the Free Software Foundation; either version |
9 | * 2 of the Licence, or (at your option) any later version. | 9 | * 2 of the Licence, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | #ifndef _ASM_CACHEFLUSH_H | 11 | #ifndef _ASM_CACHEFLUSH_H |
12 | #define _ASM_CACHEFLUSH_H | 12 | #define _ASM_CACHEFLUSH_H |
13 | 13 | ||
14 | #ifndef __ASSEMBLY__ | 14 | #ifndef __ASSEMBLY__ |
15 | 15 | ||
16 | /* Keep includes the same across arches. */ | 16 | /* Keep includes the same across arches. */ |
17 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
18 | 18 | ||
19 | /* | 19 | /* |
20 | * virtually-indexed cache managment (our cache is physically indexed) | 20 | * virtually-indexed cache management (our cache is physically indexed) |
21 | */ | 21 | */ |
22 | #define flush_cache_all() do {} while (0) | 22 | #define flush_cache_all() do {} while (0) |
23 | #define flush_cache_mm(mm) do {} while (0) | 23 | #define flush_cache_mm(mm) do {} while (0) |
24 | #define flush_cache_dup_mm(mm) do {} while (0) | 24 | #define flush_cache_dup_mm(mm) do {} while (0) |
25 | #define flush_cache_range(mm, start, end) do {} while (0) | 25 | #define flush_cache_range(mm, start, end) do {} while (0) |
26 | #define flush_cache_page(vma, vmaddr, pfn) do {} while (0) | 26 | #define flush_cache_page(vma, vmaddr, pfn) do {} while (0) |
27 | #define flush_cache_vmap(start, end) do {} while (0) | 27 | #define flush_cache_vmap(start, end) do {} while (0) |
28 | #define flush_cache_vunmap(start, end) do {} while (0) | 28 | #define flush_cache_vunmap(start, end) do {} while (0) |
29 | #define flush_dcache_page(page) do {} while (0) | 29 | #define flush_dcache_page(page) do {} while (0) |
30 | #define flush_dcache_mmap_lock(mapping) do {} while (0) | 30 | #define flush_dcache_mmap_lock(mapping) do {} while (0) |
31 | #define flush_dcache_mmap_unlock(mapping) do {} while (0) | 31 | #define flush_dcache_mmap_unlock(mapping) do {} while (0) |
32 | 32 | ||
33 | /* | 33 | /* |
34 | * physically-indexed cache managment | 34 | * physically-indexed cache management |
35 | */ | 35 | */ |
36 | #ifndef CONFIG_MN10300_CACHE_DISABLED | 36 | #ifndef CONFIG_MN10300_CACHE_DISABLED |
37 | 37 | ||
38 | extern void flush_icache_range(unsigned long start, unsigned long end); | 38 | extern void flush_icache_range(unsigned long start, unsigned long end); |
39 | extern void flush_icache_page(struct vm_area_struct *vma, struct page *pg); | 39 | extern void flush_icache_page(struct vm_area_struct *vma, struct page *pg); |
40 | 40 | ||
41 | #else | 41 | #else |
42 | 42 | ||
43 | #define flush_icache_range(start, end) do {} while (0) | 43 | #define flush_icache_range(start, end) do {} while (0) |
44 | #define flush_icache_page(vma, pg) do {} while (0) | 44 | #define flush_icache_page(vma, pg) do {} while (0) |
45 | 45 | ||
46 | #endif | 46 | #endif |
47 | 47 | ||
48 | #define flush_icache_user_range(vma, pg, adr, len) \ | 48 | #define flush_icache_user_range(vma, pg, adr, len) \ |
49 | flush_icache_range(adr, adr + len) | 49 | flush_icache_range(adr, adr + len) |
50 | 50 | ||
51 | #define copy_to_user_page(vma, page, vaddr, dst, src, len) \ | 51 | #define copy_to_user_page(vma, page, vaddr, dst, src, len) \ |
52 | do { \ | 52 | do { \ |
53 | memcpy(dst, src, len); \ | 53 | memcpy(dst, src, len); \ |
54 | flush_icache_page(vma, page); \ | 54 | flush_icache_page(vma, page); \ |
55 | } while (0) | 55 | } while (0) |
56 | 56 | ||
57 | #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ | 57 | #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ |
58 | memcpy(dst, src, len) | 58 | memcpy(dst, src, len) |
59 | 59 | ||
60 | /* | 60 | /* |
61 | * primitive routines | 61 | * primitive routines |
62 | */ | 62 | */ |
63 | #ifndef CONFIG_MN10300_CACHE_DISABLED | 63 | #ifndef CONFIG_MN10300_CACHE_DISABLED |
64 | extern void mn10300_icache_inv(void); | 64 | extern void mn10300_icache_inv(void); |
65 | extern void mn10300_dcache_inv(void); | 65 | extern void mn10300_dcache_inv(void); |
66 | extern void mn10300_dcache_inv_page(unsigned start); | 66 | extern void mn10300_dcache_inv_page(unsigned start); |
67 | extern void mn10300_dcache_inv_range(unsigned start, unsigned end); | 67 | extern void mn10300_dcache_inv_range(unsigned start, unsigned end); |
68 | extern void mn10300_dcache_inv_range2(unsigned start, unsigned size); | 68 | extern void mn10300_dcache_inv_range2(unsigned start, unsigned size); |
69 | #ifdef CONFIG_MN10300_CACHE_WBACK | 69 | #ifdef CONFIG_MN10300_CACHE_WBACK |
70 | extern void mn10300_dcache_flush(void); | 70 | extern void mn10300_dcache_flush(void); |
71 | extern void mn10300_dcache_flush_page(unsigned start); | 71 | extern void mn10300_dcache_flush_page(unsigned start); |
72 | extern void mn10300_dcache_flush_range(unsigned start, unsigned end); | 72 | extern void mn10300_dcache_flush_range(unsigned start, unsigned end); |
73 | extern void mn10300_dcache_flush_range2(unsigned start, unsigned size); | 73 | extern void mn10300_dcache_flush_range2(unsigned start, unsigned size); |
74 | extern void mn10300_dcache_flush_inv(void); | 74 | extern void mn10300_dcache_flush_inv(void); |
75 | extern void mn10300_dcache_flush_inv_page(unsigned start); | 75 | extern void mn10300_dcache_flush_inv_page(unsigned start); |
76 | extern void mn10300_dcache_flush_inv_range(unsigned start, unsigned end); | 76 | extern void mn10300_dcache_flush_inv_range(unsigned start, unsigned end); |
77 | extern void mn10300_dcache_flush_inv_range2(unsigned start, unsigned size); | 77 | extern void mn10300_dcache_flush_inv_range2(unsigned start, unsigned size); |
78 | #else | 78 | #else |
79 | #define mn10300_dcache_flush() do {} while (0) | 79 | #define mn10300_dcache_flush() do {} while (0) |
80 | #define mn10300_dcache_flush_page(start) do {} while (0) | 80 | #define mn10300_dcache_flush_page(start) do {} while (0) |
81 | #define mn10300_dcache_flush_range(start, end) do {} while (0) | 81 | #define mn10300_dcache_flush_range(start, end) do {} while (0) |
82 | #define mn10300_dcache_flush_range2(start, size) do {} while (0) | 82 | #define mn10300_dcache_flush_range2(start, size) do {} while (0) |
83 | #define mn10300_dcache_flush_inv() mn10300_dcache_inv() | 83 | #define mn10300_dcache_flush_inv() mn10300_dcache_inv() |
84 | #define mn10300_dcache_flush_inv_page(start) \ | 84 | #define mn10300_dcache_flush_inv_page(start) \ |
85 | mn10300_dcache_inv_page((start)) | 85 | mn10300_dcache_inv_page((start)) |
86 | #define mn10300_dcache_flush_inv_range(start, end) \ | 86 | #define mn10300_dcache_flush_inv_range(start, end) \ |
87 | mn10300_dcache_inv_range((start), (end)) | 87 | mn10300_dcache_inv_range((start), (end)) |
88 | #define mn10300_dcache_flush_inv_range2(start, size) \ | 88 | #define mn10300_dcache_flush_inv_range2(start, size) \ |
89 | mn10300_dcache_inv_range2((start), (size)) | 89 | mn10300_dcache_inv_range2((start), (size)) |
90 | #endif /* CONFIG_MN10300_CACHE_WBACK */ | 90 | #endif /* CONFIG_MN10300_CACHE_WBACK */ |
91 | #else | 91 | #else |
92 | #define mn10300_icache_inv() do {} while (0) | 92 | #define mn10300_icache_inv() do {} while (0) |
93 | #define mn10300_dcache_inv() do {} while (0) | 93 | #define mn10300_dcache_inv() do {} while (0) |
94 | #define mn10300_dcache_inv_page(start) do {} while (0) | 94 | #define mn10300_dcache_inv_page(start) do {} while (0) |
95 | #define mn10300_dcache_inv_range(start, end) do {} while (0) | 95 | #define mn10300_dcache_inv_range(start, end) do {} while (0) |
96 | #define mn10300_dcache_inv_range2(start, size) do {} while (0) | 96 | #define mn10300_dcache_inv_range2(start, size) do {} while (0) |
97 | #define mn10300_dcache_flush() do {} while (0) | 97 | #define mn10300_dcache_flush() do {} while (0) |
98 | #define mn10300_dcache_flush_inv_page(start) do {} while (0) | 98 | #define mn10300_dcache_flush_inv_page(start) do {} while (0) |
99 | #define mn10300_dcache_flush_inv() do {} while (0) | 99 | #define mn10300_dcache_flush_inv() do {} while (0) |
100 | #define mn10300_dcache_flush_inv_range(start, end) do {} while (0) | 100 | #define mn10300_dcache_flush_inv_range(start, end) do {} while (0) |
101 | #define mn10300_dcache_flush_inv_range2(start, size) do {} while (0) | 101 | #define mn10300_dcache_flush_inv_range2(start, size) do {} while (0) |
102 | #define mn10300_dcache_flush_page(start) do {} while (0) | 102 | #define mn10300_dcache_flush_page(start) do {} while (0) |
103 | #define mn10300_dcache_flush_range(start, end) do {} while (0) | 103 | #define mn10300_dcache_flush_range(start, end) do {} while (0) |
104 | #define mn10300_dcache_flush_range2(start, size) do {} while (0) | 104 | #define mn10300_dcache_flush_range2(start, size) do {} while (0) |
105 | #endif /* CONFIG_MN10300_CACHE_DISABLED */ | 105 | #endif /* CONFIG_MN10300_CACHE_DISABLED */ |
106 | 106 | ||
107 | /* | 107 | /* |
108 | * internal debugging function | 108 | * internal debugging function |
109 | */ | 109 | */ |
110 | #ifdef CONFIG_DEBUG_PAGEALLOC | 110 | #ifdef CONFIG_DEBUG_PAGEALLOC |
111 | extern void kernel_map_pages(struct page *page, int numpages, int enable); | 111 | extern void kernel_map_pages(struct page *page, int numpages, int enable); |
112 | #endif | 112 | #endif |
113 | 113 | ||
114 | #endif /* __ASSEMBLY__ */ | 114 | #endif /* __ASSEMBLY__ */ |
115 | 115 | ||
116 | #endif /* _ASM_CACHEFLUSH_H */ | 116 | #endif /* _ASM_CACHEFLUSH_H */ |
117 | 117 |
drivers/media/dvb/siano/smscoreapi.c
1 | /* | 1 | /* |
2 | * Siano core API module | 2 | * Siano core API module |
3 | * | 3 | * |
4 | * This file contains implementation for the interface to sms core component | 4 | * This file contains implementation for the interface to sms core component |
5 | * | 5 | * |
6 | * author: Uri Shkolnik | 6 | * author: Uri Shkolnik |
7 | * | 7 | * |
8 | * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. | 8 | * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
12 | * published by the Free Software Foundation; | 12 | * published by the Free Software Foundation; |
13 | * | 13 | * |
14 | * Software distributed under the License is distributed on an "AS IS" | 14 | * Software distributed under the License is distributed on an "AS IS" |
15 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. | 15 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. |
16 | * | 16 | * |
17 | * See the GNU General Public License for more details. | 17 | * See the GNU General Public License for more details. |
18 | * | 18 | * |
19 | * You should have received a copy of the GNU General Public License | 19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, write to the Free Software | 20 | * along with this program; if not, write to the Free Software |
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/moduleparam.h> | 27 | #include <linux/moduleparam.h> |
28 | #include <linux/dma-mapping.h> | 28 | #include <linux/dma-mapping.h> |
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | #include <linux/io.h> | 30 | #include <linux/io.h> |
31 | 31 | ||
32 | #include <linux/firmware.h> | 32 | #include <linux/firmware.h> |
33 | #include <linux/wait.h> | 33 | #include <linux/wait.h> |
34 | #include <asm/byteorder.h> | 34 | #include <asm/byteorder.h> |
35 | 35 | ||
36 | #include "smscoreapi.h" | 36 | #include "smscoreapi.h" |
37 | #include "sms-cards.h" | 37 | #include "sms-cards.h" |
38 | #include "smsir.h" | 38 | #include "smsir.h" |
39 | #include "smsendian.h" | 39 | #include "smsendian.h" |
40 | 40 | ||
41 | static int sms_dbg; | 41 | static int sms_dbg; |
42 | module_param_named(debug, sms_dbg, int, 0644); | 42 | module_param_named(debug, sms_dbg, int, 0644); |
43 | MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); | 43 | MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); |
44 | 44 | ||
45 | struct smscore_device_notifyee_t { | 45 | struct smscore_device_notifyee_t { |
46 | struct list_head entry; | 46 | struct list_head entry; |
47 | hotplug_t hotplug; | 47 | hotplug_t hotplug; |
48 | }; | 48 | }; |
49 | 49 | ||
50 | struct smscore_idlist_t { | 50 | struct smscore_idlist_t { |
51 | struct list_head entry; | 51 | struct list_head entry; |
52 | int id; | 52 | int id; |
53 | int data_type; | 53 | int data_type; |
54 | }; | 54 | }; |
55 | 55 | ||
56 | struct smscore_client_t { | 56 | struct smscore_client_t { |
57 | struct list_head entry; | 57 | struct list_head entry; |
58 | struct smscore_device_t *coredev; | 58 | struct smscore_device_t *coredev; |
59 | void *context; | 59 | void *context; |
60 | struct list_head idlist; | 60 | struct list_head idlist; |
61 | onresponse_t onresponse_handler; | 61 | onresponse_t onresponse_handler; |
62 | onremove_t onremove_handler; | 62 | onremove_t onremove_handler; |
63 | }; | 63 | }; |
64 | 64 | ||
65 | void smscore_set_board_id(struct smscore_device_t *core, int id) | 65 | void smscore_set_board_id(struct smscore_device_t *core, int id) |
66 | { | 66 | { |
67 | core->board_id = id; | 67 | core->board_id = id; |
68 | } | 68 | } |
69 | 69 | ||
70 | int smscore_led_state(struct smscore_device_t *core, int led) | 70 | int smscore_led_state(struct smscore_device_t *core, int led) |
71 | { | 71 | { |
72 | if (led >= 0) | 72 | if (led >= 0) |
73 | core->led_state = led; | 73 | core->led_state = led; |
74 | return core->led_state; | 74 | return core->led_state; |
75 | } | 75 | } |
76 | EXPORT_SYMBOL_GPL(smscore_set_board_id); | 76 | EXPORT_SYMBOL_GPL(smscore_set_board_id); |
77 | 77 | ||
78 | int smscore_get_board_id(struct smscore_device_t *core) | 78 | int smscore_get_board_id(struct smscore_device_t *core) |
79 | { | 79 | { |
80 | return core->board_id; | 80 | return core->board_id; |
81 | } | 81 | } |
82 | EXPORT_SYMBOL_GPL(smscore_get_board_id); | 82 | EXPORT_SYMBOL_GPL(smscore_get_board_id); |
83 | 83 | ||
84 | struct smscore_registry_entry_t { | 84 | struct smscore_registry_entry_t { |
85 | struct list_head entry; | 85 | struct list_head entry; |
86 | char devpath[32]; | 86 | char devpath[32]; |
87 | int mode; | 87 | int mode; |
88 | enum sms_device_type_st type; | 88 | enum sms_device_type_st type; |
89 | }; | 89 | }; |
90 | 90 | ||
91 | static struct list_head g_smscore_notifyees; | 91 | static struct list_head g_smscore_notifyees; |
92 | static struct list_head g_smscore_devices; | 92 | static struct list_head g_smscore_devices; |
93 | static struct mutex g_smscore_deviceslock; | 93 | static struct mutex g_smscore_deviceslock; |
94 | 94 | ||
95 | static struct list_head g_smscore_registry; | 95 | static struct list_head g_smscore_registry; |
96 | static struct mutex g_smscore_registrylock; | 96 | static struct mutex g_smscore_registrylock; |
97 | 97 | ||
98 | static int default_mode = 4; | 98 | static int default_mode = 4; |
99 | 99 | ||
100 | module_param(default_mode, int, 0644); | 100 | module_param(default_mode, int, 0644); |
101 | MODULE_PARM_DESC(default_mode, "default firmware id (device mode)"); | 101 | MODULE_PARM_DESC(default_mode, "default firmware id (device mode)"); |
102 | 102 | ||
103 | static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) | 103 | static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) |
104 | { | 104 | { |
105 | struct smscore_registry_entry_t *entry; | 105 | struct smscore_registry_entry_t *entry; |
106 | struct list_head *next; | 106 | struct list_head *next; |
107 | 107 | ||
108 | kmutex_lock(&g_smscore_registrylock); | 108 | kmutex_lock(&g_smscore_registrylock); |
109 | for (next = g_smscore_registry.next; | 109 | for (next = g_smscore_registry.next; |
110 | next != &g_smscore_registry; | 110 | next != &g_smscore_registry; |
111 | next = next->next) { | 111 | next = next->next) { |
112 | entry = (struct smscore_registry_entry_t *) next; | 112 | entry = (struct smscore_registry_entry_t *) next; |
113 | if (!strcmp(entry->devpath, devpath)) { | 113 | if (!strcmp(entry->devpath, devpath)) { |
114 | kmutex_unlock(&g_smscore_registrylock); | 114 | kmutex_unlock(&g_smscore_registrylock); |
115 | return entry; | 115 | return entry; |
116 | } | 116 | } |
117 | } | 117 | } |
118 | entry = (struct smscore_registry_entry_t *) | 118 | entry = (struct smscore_registry_entry_t *) |
119 | kmalloc(sizeof(struct smscore_registry_entry_t), | 119 | kmalloc(sizeof(struct smscore_registry_entry_t), |
120 | GFP_KERNEL); | 120 | GFP_KERNEL); |
121 | if (entry) { | 121 | if (entry) { |
122 | entry->mode = default_mode; | 122 | entry->mode = default_mode; |
123 | strcpy(entry->devpath, devpath); | 123 | strcpy(entry->devpath, devpath); |
124 | list_add(&entry->entry, &g_smscore_registry); | 124 | list_add(&entry->entry, &g_smscore_registry); |
125 | } else | 125 | } else |
126 | sms_err("failed to create smscore_registry."); | 126 | sms_err("failed to create smscore_registry."); |
127 | kmutex_unlock(&g_smscore_registrylock); | 127 | kmutex_unlock(&g_smscore_registrylock); |
128 | return entry; | 128 | return entry; |
129 | } | 129 | } |
130 | 130 | ||
131 | int smscore_registry_getmode(char *devpath) | 131 | int smscore_registry_getmode(char *devpath) |
132 | { | 132 | { |
133 | struct smscore_registry_entry_t *entry; | 133 | struct smscore_registry_entry_t *entry; |
134 | 134 | ||
135 | entry = smscore_find_registry(devpath); | 135 | entry = smscore_find_registry(devpath); |
136 | if (entry) | 136 | if (entry) |
137 | return entry->mode; | 137 | return entry->mode; |
138 | else | 138 | else |
139 | sms_err("No registry found."); | 139 | sms_err("No registry found."); |
140 | 140 | ||
141 | return default_mode; | 141 | return default_mode; |
142 | } | 142 | } |
143 | EXPORT_SYMBOL_GPL(smscore_registry_getmode); | 143 | EXPORT_SYMBOL_GPL(smscore_registry_getmode); |
144 | 144 | ||
145 | static enum sms_device_type_st smscore_registry_gettype(char *devpath) | 145 | static enum sms_device_type_st smscore_registry_gettype(char *devpath) |
146 | { | 146 | { |
147 | struct smscore_registry_entry_t *entry; | 147 | struct smscore_registry_entry_t *entry; |
148 | 148 | ||
149 | entry = smscore_find_registry(devpath); | 149 | entry = smscore_find_registry(devpath); |
150 | if (entry) | 150 | if (entry) |
151 | return entry->type; | 151 | return entry->type; |
152 | else | 152 | else |
153 | sms_err("No registry found."); | 153 | sms_err("No registry found."); |
154 | 154 | ||
155 | return -1; | 155 | return -1; |
156 | } | 156 | } |
157 | 157 | ||
158 | void smscore_registry_setmode(char *devpath, int mode) | 158 | void smscore_registry_setmode(char *devpath, int mode) |
159 | { | 159 | { |
160 | struct smscore_registry_entry_t *entry; | 160 | struct smscore_registry_entry_t *entry; |
161 | 161 | ||
162 | entry = smscore_find_registry(devpath); | 162 | entry = smscore_find_registry(devpath); |
163 | if (entry) | 163 | if (entry) |
164 | entry->mode = mode; | 164 | entry->mode = mode; |
165 | else | 165 | else |
166 | sms_err("No registry found."); | 166 | sms_err("No registry found."); |
167 | } | 167 | } |
168 | 168 | ||
169 | static void smscore_registry_settype(char *devpath, | 169 | static void smscore_registry_settype(char *devpath, |
170 | enum sms_device_type_st type) | 170 | enum sms_device_type_st type) |
171 | { | 171 | { |
172 | struct smscore_registry_entry_t *entry; | 172 | struct smscore_registry_entry_t *entry; |
173 | 173 | ||
174 | entry = smscore_find_registry(devpath); | 174 | entry = smscore_find_registry(devpath); |
175 | if (entry) | 175 | if (entry) |
176 | entry->type = type; | 176 | entry->type = type; |
177 | else | 177 | else |
178 | sms_err("No registry found."); | 178 | sms_err("No registry found."); |
179 | } | 179 | } |
180 | 180 | ||
181 | 181 | ||
182 | static void list_add_locked(struct list_head *new, struct list_head *head, | 182 | static void list_add_locked(struct list_head *new, struct list_head *head, |
183 | spinlock_t *lock) | 183 | spinlock_t *lock) |
184 | { | 184 | { |
185 | unsigned long flags; | 185 | unsigned long flags; |
186 | 186 | ||
187 | spin_lock_irqsave(lock, flags); | 187 | spin_lock_irqsave(lock, flags); |
188 | 188 | ||
189 | list_add(new, head); | 189 | list_add(new, head); |
190 | 190 | ||
191 | spin_unlock_irqrestore(lock, flags); | 191 | spin_unlock_irqrestore(lock, flags); |
192 | } | 192 | } |
193 | 193 | ||
194 | /** | 194 | /** |
195 | * register a client callback that called when device plugged in/unplugged | 195 | * register a client callback that called when device plugged in/unplugged |
196 | * NOTE: if devices exist callback is called immediately for each device | 196 | * NOTE: if devices exist callback is called immediately for each device |
197 | * | 197 | * |
198 | * @param hotplug callback | 198 | * @param hotplug callback |
199 | * | 199 | * |
200 | * @return 0 on success, <0 on error. | 200 | * @return 0 on success, <0 on error. |
201 | */ | 201 | */ |
202 | int smscore_register_hotplug(hotplug_t hotplug) | 202 | int smscore_register_hotplug(hotplug_t hotplug) |
203 | { | 203 | { |
204 | struct smscore_device_notifyee_t *notifyee; | 204 | struct smscore_device_notifyee_t *notifyee; |
205 | struct list_head *next, *first; | 205 | struct list_head *next, *first; |
206 | int rc = 0; | 206 | int rc = 0; |
207 | 207 | ||
208 | kmutex_lock(&g_smscore_deviceslock); | 208 | kmutex_lock(&g_smscore_deviceslock); |
209 | 209 | ||
210 | notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t), | 210 | notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t), |
211 | GFP_KERNEL); | 211 | GFP_KERNEL); |
212 | if (notifyee) { | 212 | if (notifyee) { |
213 | /* now notify callback about existing devices */ | 213 | /* now notify callback about existing devices */ |
214 | first = &g_smscore_devices; | 214 | first = &g_smscore_devices; |
215 | for (next = first->next; | 215 | for (next = first->next; |
216 | next != first && !rc; | 216 | next != first && !rc; |
217 | next = next->next) { | 217 | next = next->next) { |
218 | struct smscore_device_t *coredev = | 218 | struct smscore_device_t *coredev = |
219 | (struct smscore_device_t *) next; | 219 | (struct smscore_device_t *) next; |
220 | rc = hotplug(coredev, coredev->device, 1); | 220 | rc = hotplug(coredev, coredev->device, 1); |
221 | } | 221 | } |
222 | 222 | ||
223 | if (rc >= 0) { | 223 | if (rc >= 0) { |
224 | notifyee->hotplug = hotplug; | 224 | notifyee->hotplug = hotplug; |
225 | list_add(¬ifyee->entry, &g_smscore_notifyees); | 225 | list_add(¬ifyee->entry, &g_smscore_notifyees); |
226 | } else | 226 | } else |
227 | kfree(notifyee); | 227 | kfree(notifyee); |
228 | } else | 228 | } else |
229 | rc = -ENOMEM; | 229 | rc = -ENOMEM; |
230 | 230 | ||
231 | kmutex_unlock(&g_smscore_deviceslock); | 231 | kmutex_unlock(&g_smscore_deviceslock); |
232 | 232 | ||
233 | return rc; | 233 | return rc; |
234 | } | 234 | } |
235 | EXPORT_SYMBOL_GPL(smscore_register_hotplug); | 235 | EXPORT_SYMBOL_GPL(smscore_register_hotplug); |
236 | 236 | ||
237 | /** | 237 | /** |
238 | * unregister a client callback that called when device plugged in/unplugged | 238 | * unregister a client callback that called when device plugged in/unplugged |
239 | * | 239 | * |
240 | * @param hotplug callback | 240 | * @param hotplug callback |
241 | * | 241 | * |
242 | */ | 242 | */ |
243 | void smscore_unregister_hotplug(hotplug_t hotplug) | 243 | void smscore_unregister_hotplug(hotplug_t hotplug) |
244 | { | 244 | { |
245 | struct list_head *next, *first; | 245 | struct list_head *next, *first; |
246 | 246 | ||
247 | kmutex_lock(&g_smscore_deviceslock); | 247 | kmutex_lock(&g_smscore_deviceslock); |
248 | 248 | ||
249 | first = &g_smscore_notifyees; | 249 | first = &g_smscore_notifyees; |
250 | 250 | ||
251 | for (next = first->next; next != first;) { | 251 | for (next = first->next; next != first;) { |
252 | struct smscore_device_notifyee_t *notifyee = | 252 | struct smscore_device_notifyee_t *notifyee = |
253 | (struct smscore_device_notifyee_t *) next; | 253 | (struct smscore_device_notifyee_t *) next; |
254 | next = next->next; | 254 | next = next->next; |
255 | 255 | ||
256 | if (notifyee->hotplug == hotplug) { | 256 | if (notifyee->hotplug == hotplug) { |
257 | list_del(¬ifyee->entry); | 257 | list_del(¬ifyee->entry); |
258 | kfree(notifyee); | 258 | kfree(notifyee); |
259 | } | 259 | } |
260 | } | 260 | } |
261 | 261 | ||
262 | kmutex_unlock(&g_smscore_deviceslock); | 262 | kmutex_unlock(&g_smscore_deviceslock); |
263 | } | 263 | } |
264 | EXPORT_SYMBOL_GPL(smscore_unregister_hotplug); | 264 | EXPORT_SYMBOL_GPL(smscore_unregister_hotplug); |
265 | 265 | ||
266 | static void smscore_notify_clients(struct smscore_device_t *coredev) | 266 | static void smscore_notify_clients(struct smscore_device_t *coredev) |
267 | { | 267 | { |
268 | struct smscore_client_t *client; | 268 | struct smscore_client_t *client; |
269 | 269 | ||
270 | /* the client must call smscore_unregister_client from remove handler */ | 270 | /* the client must call smscore_unregister_client from remove handler */ |
271 | while (!list_empty(&coredev->clients)) { | 271 | while (!list_empty(&coredev->clients)) { |
272 | client = (struct smscore_client_t *) coredev->clients.next; | 272 | client = (struct smscore_client_t *) coredev->clients.next; |
273 | client->onremove_handler(client->context); | 273 | client->onremove_handler(client->context); |
274 | } | 274 | } |
275 | } | 275 | } |
276 | 276 | ||
277 | static int smscore_notify_callbacks(struct smscore_device_t *coredev, | 277 | static int smscore_notify_callbacks(struct smscore_device_t *coredev, |
278 | struct device *device, int arrival) | 278 | struct device *device, int arrival) |
279 | { | 279 | { |
280 | struct list_head *next, *first; | 280 | struct list_head *next, *first; |
281 | int rc = 0; | 281 | int rc = 0; |
282 | 282 | ||
283 | /* note: must be called under g_deviceslock */ | 283 | /* note: must be called under g_deviceslock */ |
284 | 284 | ||
285 | first = &g_smscore_notifyees; | 285 | first = &g_smscore_notifyees; |
286 | 286 | ||
287 | for (next = first->next; next != first; next = next->next) { | 287 | for (next = first->next; next != first; next = next->next) { |
288 | rc = ((struct smscore_device_notifyee_t *) next)-> | 288 | rc = ((struct smscore_device_notifyee_t *) next)-> |
289 | hotplug(coredev, device, arrival); | 289 | hotplug(coredev, device, arrival); |
290 | if (rc < 0) | 290 | if (rc < 0) |
291 | break; | 291 | break; |
292 | } | 292 | } |
293 | 293 | ||
294 | return rc; | 294 | return rc; |
295 | } | 295 | } |
296 | 296 | ||
297 | static struct | 297 | static struct |
298 | smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, | 298 | smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, |
299 | dma_addr_t common_buffer_phys) | 299 | dma_addr_t common_buffer_phys) |
300 | { | 300 | { |
301 | struct smscore_buffer_t *cb = | 301 | struct smscore_buffer_t *cb = |
302 | kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL); | 302 | kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL); |
303 | if (!cb) { | 303 | if (!cb) { |
304 | sms_info("kmalloc(...) failed"); | 304 | sms_info("kmalloc(...) failed"); |
305 | return NULL; | 305 | return NULL; |
306 | } | 306 | } |
307 | 307 | ||
308 | cb->p = buffer; | 308 | cb->p = buffer; |
309 | cb->offset_in_common = buffer - (u8 *) common_buffer; | 309 | cb->offset_in_common = buffer - (u8 *) common_buffer; |
310 | cb->phys = common_buffer_phys + cb->offset_in_common; | 310 | cb->phys = common_buffer_phys + cb->offset_in_common; |
311 | 311 | ||
312 | return cb; | 312 | return cb; |
313 | } | 313 | } |
314 | 314 | ||
315 | /** | 315 | /** |
316 | * creates coredev object for a device, prepares buffers, | 316 | * creates coredev object for a device, prepares buffers, |
317 | * creates buffer mappings, notifies registered hotplugs about new device. | 317 | * creates buffer mappings, notifies registered hotplugs about new device. |
318 | * | 318 | * |
319 | * @param params device pointer to struct with device specific parameters | 319 | * @param params device pointer to struct with device specific parameters |
320 | * and handlers | 320 | * and handlers |
321 | * @param coredev pointer to a value that receives created coredev object | 321 | * @param coredev pointer to a value that receives created coredev object |
322 | * | 322 | * |
323 | * @return 0 on success, <0 on error. | 323 | * @return 0 on success, <0 on error. |
324 | */ | 324 | */ |
325 | int smscore_register_device(struct smsdevice_params_t *params, | 325 | int smscore_register_device(struct smsdevice_params_t *params, |
326 | struct smscore_device_t **coredev) | 326 | struct smscore_device_t **coredev) |
327 | { | 327 | { |
328 | struct smscore_device_t *dev; | 328 | struct smscore_device_t *dev; |
329 | u8 *buffer; | 329 | u8 *buffer; |
330 | 330 | ||
331 | dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL); | 331 | dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL); |
332 | if (!dev) { | 332 | if (!dev) { |
333 | sms_info("kzalloc(...) failed"); | 333 | sms_info("kzalloc(...) failed"); |
334 | return -ENOMEM; | 334 | return -ENOMEM; |
335 | } | 335 | } |
336 | 336 | ||
337 | /* init list entry so it could be safe in smscore_unregister_device */ | 337 | /* init list entry so it could be safe in smscore_unregister_device */ |
338 | INIT_LIST_HEAD(&dev->entry); | 338 | INIT_LIST_HEAD(&dev->entry); |
339 | 339 | ||
340 | /* init queues */ | 340 | /* init queues */ |
341 | INIT_LIST_HEAD(&dev->clients); | 341 | INIT_LIST_HEAD(&dev->clients); |
342 | INIT_LIST_HEAD(&dev->buffers); | 342 | INIT_LIST_HEAD(&dev->buffers); |
343 | 343 | ||
344 | /* init locks */ | 344 | /* init locks */ |
345 | spin_lock_init(&dev->clientslock); | 345 | spin_lock_init(&dev->clientslock); |
346 | spin_lock_init(&dev->bufferslock); | 346 | spin_lock_init(&dev->bufferslock); |
347 | 347 | ||
348 | /* init completion events */ | 348 | /* init completion events */ |
349 | init_completion(&dev->version_ex_done); | 349 | init_completion(&dev->version_ex_done); |
350 | init_completion(&dev->data_download_done); | 350 | init_completion(&dev->data_download_done); |
351 | init_completion(&dev->trigger_done); | 351 | init_completion(&dev->trigger_done); |
352 | init_completion(&dev->init_device_done); | 352 | init_completion(&dev->init_device_done); |
353 | init_completion(&dev->reload_start_done); | 353 | init_completion(&dev->reload_start_done); |
354 | init_completion(&dev->resume_done); | 354 | init_completion(&dev->resume_done); |
355 | init_completion(&dev->gpio_configuration_done); | 355 | init_completion(&dev->gpio_configuration_done); |
356 | init_completion(&dev->gpio_set_level_done); | 356 | init_completion(&dev->gpio_set_level_done); |
357 | init_completion(&dev->gpio_get_level_done); | 357 | init_completion(&dev->gpio_get_level_done); |
358 | init_completion(&dev->ir_init_done); | 358 | init_completion(&dev->ir_init_done); |
359 | 359 | ||
360 | /* Buffer management */ | 360 | /* Buffer management */ |
361 | init_waitqueue_head(&dev->buffer_mng_waitq); | 361 | init_waitqueue_head(&dev->buffer_mng_waitq); |
362 | 362 | ||
363 | /* alloc common buffer */ | 363 | /* alloc common buffer */ |
364 | dev->common_buffer_size = params->buffer_size * params->num_buffers; | 364 | dev->common_buffer_size = params->buffer_size * params->num_buffers; |
365 | dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size, | 365 | dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size, |
366 | &dev->common_buffer_phys, | 366 | &dev->common_buffer_phys, |
367 | GFP_KERNEL | GFP_DMA); | 367 | GFP_KERNEL | GFP_DMA); |
368 | if (!dev->common_buffer) { | 368 | if (!dev->common_buffer) { |
369 | smscore_unregister_device(dev); | 369 | smscore_unregister_device(dev); |
370 | return -ENOMEM; | 370 | return -ENOMEM; |
371 | } | 371 | } |
372 | 372 | ||
373 | /* prepare dma buffers */ | 373 | /* prepare dma buffers */ |
374 | for (buffer = dev->common_buffer; | 374 | for (buffer = dev->common_buffer; |
375 | dev->num_buffers < params->num_buffers; | 375 | dev->num_buffers < params->num_buffers; |
376 | dev->num_buffers++, buffer += params->buffer_size) { | 376 | dev->num_buffers++, buffer += params->buffer_size) { |
377 | struct smscore_buffer_t *cb = | 377 | struct smscore_buffer_t *cb = |
378 | smscore_createbuffer(buffer, dev->common_buffer, | 378 | smscore_createbuffer(buffer, dev->common_buffer, |
379 | dev->common_buffer_phys); | 379 | dev->common_buffer_phys); |
380 | if (!cb) { | 380 | if (!cb) { |
381 | smscore_unregister_device(dev); | 381 | smscore_unregister_device(dev); |
382 | return -ENOMEM; | 382 | return -ENOMEM; |
383 | } | 383 | } |
384 | 384 | ||
385 | smscore_putbuffer(dev, cb); | 385 | smscore_putbuffer(dev, cb); |
386 | } | 386 | } |
387 | 387 | ||
388 | sms_info("allocated %d buffers", dev->num_buffers); | 388 | sms_info("allocated %d buffers", dev->num_buffers); |
389 | 389 | ||
390 | dev->mode = DEVICE_MODE_NONE; | 390 | dev->mode = DEVICE_MODE_NONE; |
391 | dev->context = params->context; | 391 | dev->context = params->context; |
392 | dev->device = params->device; | 392 | dev->device = params->device; |
393 | dev->setmode_handler = params->setmode_handler; | 393 | dev->setmode_handler = params->setmode_handler; |
394 | dev->detectmode_handler = params->detectmode_handler; | 394 | dev->detectmode_handler = params->detectmode_handler; |
395 | dev->sendrequest_handler = params->sendrequest_handler; | 395 | dev->sendrequest_handler = params->sendrequest_handler; |
396 | dev->preload_handler = params->preload_handler; | 396 | dev->preload_handler = params->preload_handler; |
397 | dev->postload_handler = params->postload_handler; | 397 | dev->postload_handler = params->postload_handler; |
398 | 398 | ||
399 | dev->device_flags = params->flags; | 399 | dev->device_flags = params->flags; |
400 | strcpy(dev->devpath, params->devpath); | 400 | strcpy(dev->devpath, params->devpath); |
401 | 401 | ||
402 | smscore_registry_settype(dev->devpath, params->device_type); | 402 | smscore_registry_settype(dev->devpath, params->device_type); |
403 | 403 | ||
404 | /* add device to devices list */ | 404 | /* add device to devices list */ |
405 | kmutex_lock(&g_smscore_deviceslock); | 405 | kmutex_lock(&g_smscore_deviceslock); |
406 | list_add(&dev->entry, &g_smscore_devices); | 406 | list_add(&dev->entry, &g_smscore_devices); |
407 | kmutex_unlock(&g_smscore_deviceslock); | 407 | kmutex_unlock(&g_smscore_deviceslock); |
408 | 408 | ||
409 | *coredev = dev; | 409 | *coredev = dev; |
410 | 410 | ||
411 | sms_info("device %p created", dev); | 411 | sms_info("device %p created", dev); |
412 | 412 | ||
413 | return 0; | 413 | return 0; |
414 | } | 414 | } |
415 | EXPORT_SYMBOL_GPL(smscore_register_device); | 415 | EXPORT_SYMBOL_GPL(smscore_register_device); |
416 | 416 | ||
417 | 417 | ||
418 | static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, | 418 | static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, |
419 | void *buffer, size_t size, struct completion *completion) { | 419 | void *buffer, size_t size, struct completion *completion) { |
420 | int rc = coredev->sendrequest_handler(coredev->context, buffer, size); | 420 | int rc = coredev->sendrequest_handler(coredev->context, buffer, size); |
421 | if (rc < 0) { | 421 | if (rc < 0) { |
422 | sms_info("sendrequest returned error %d", rc); | 422 | sms_info("sendrequest returned error %d", rc); |
423 | return rc; | 423 | return rc; |
424 | } | 424 | } |
425 | 425 | ||
426 | return wait_for_completion_timeout(completion, | 426 | return wait_for_completion_timeout(completion, |
427 | msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ? | 427 | msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ? |
428 | 0 : -ETIME; | 428 | 0 : -ETIME; |
429 | } | 429 | } |
430 | 430 | ||
431 | /** | 431 | /** |
432 | * Starts & enables IR operations | 432 | * Starts & enables IR operations |
433 | * | 433 | * |
434 | * @return 0 on success, < 0 on error. | 434 | * @return 0 on success, < 0 on error. |
435 | */ | 435 | */ |
436 | static int smscore_init_ir(struct smscore_device_t *coredev) | 436 | static int smscore_init_ir(struct smscore_device_t *coredev) |
437 | { | 437 | { |
438 | int ir_io; | 438 | int ir_io; |
439 | int rc; | 439 | int rc; |
440 | void *buffer; | 440 | void *buffer; |
441 | 441 | ||
442 | coredev->ir.input_dev = NULL; | 442 | coredev->ir.input_dev = NULL; |
443 | ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir; | 443 | ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir; |
444 | if (ir_io) {/* only if IR port exist we use IR sub-module */ | 444 | if (ir_io) {/* only if IR port exist we use IR sub-module */ |
445 | sms_info("IR loading"); | 445 | sms_info("IR loading"); |
446 | rc = sms_ir_init(coredev); | 446 | rc = sms_ir_init(coredev); |
447 | 447 | ||
448 | if (rc != 0) | 448 | if (rc != 0) |
449 | sms_err("Error initialization DTV IR sub-module"); | 449 | sms_err("Error initialization DTV IR sub-module"); |
450 | else { | 450 | else { |
451 | buffer = kmalloc(sizeof(struct SmsMsgData_ST2) + | 451 | buffer = kmalloc(sizeof(struct SmsMsgData_ST2) + |
452 | SMS_DMA_ALIGNMENT, | 452 | SMS_DMA_ALIGNMENT, |
453 | GFP_KERNEL | GFP_DMA); | 453 | GFP_KERNEL | GFP_DMA); |
454 | if (buffer) { | 454 | if (buffer) { |
455 | struct SmsMsgData_ST2 *msg = | 455 | struct SmsMsgData_ST2 *msg = |
456 | (struct SmsMsgData_ST2 *) | 456 | (struct SmsMsgData_ST2 *) |
457 | SMS_ALIGN_ADDRESS(buffer); | 457 | SMS_ALIGN_ADDRESS(buffer); |
458 | 458 | ||
459 | SMS_INIT_MSG(&msg->xMsgHeader, | 459 | SMS_INIT_MSG(&msg->xMsgHeader, |
460 | MSG_SMS_START_IR_REQ, | 460 | MSG_SMS_START_IR_REQ, |
461 | sizeof(struct SmsMsgData_ST2)); | 461 | sizeof(struct SmsMsgData_ST2)); |
462 | msg->msgData[0] = coredev->ir.controller; | 462 | msg->msgData[0] = coredev->ir.controller; |
463 | msg->msgData[1] = coredev->ir.timeout; | 463 | msg->msgData[1] = coredev->ir.timeout; |
464 | 464 | ||
465 | smsendian_handle_tx_message( | 465 | smsendian_handle_tx_message( |
466 | (struct SmsMsgHdr_ST2 *)msg); | 466 | (struct SmsMsgHdr_ST2 *)msg); |
467 | rc = smscore_sendrequest_and_wait(coredev, msg, | 467 | rc = smscore_sendrequest_and_wait(coredev, msg, |
468 | msg->xMsgHeader. msgLength, | 468 | msg->xMsgHeader. msgLength, |
469 | &coredev->ir_init_done); | 469 | &coredev->ir_init_done); |
470 | 470 | ||
471 | kfree(buffer); | 471 | kfree(buffer); |
472 | } else | 472 | } else |
473 | sms_err | 473 | sms_err |
474 | ("Sending IR initialization message failed"); | 474 | ("Sending IR initialization message failed"); |
475 | } | 475 | } |
476 | } else | 476 | } else |
477 | sms_info("IR port has not been detected"); | 477 | sms_info("IR port has not been detected"); |
478 | 478 | ||
479 | return 0; | 479 | return 0; |
480 | } | 480 | } |
481 | 481 | ||
482 | /** | 482 | /** |
483 | * sets initial device mode and notifies client hotplugs that device is ready | 483 | * sets initial device mode and notifies client hotplugs that device is ready |
484 | * | 484 | * |
485 | * @param coredev pointer to a coredev object returned by | 485 | * @param coredev pointer to a coredev object returned by |
486 | * smscore_register_device | 486 | * smscore_register_device |
487 | * | 487 | * |
488 | * @return 0 on success, <0 on error. | 488 | * @return 0 on success, <0 on error. |
489 | */ | 489 | */ |
490 | int smscore_start_device(struct smscore_device_t *coredev) | 490 | int smscore_start_device(struct smscore_device_t *coredev) |
491 | { | 491 | { |
492 | int rc = smscore_set_device_mode( | 492 | int rc = smscore_set_device_mode( |
493 | coredev, smscore_registry_getmode(coredev->devpath)); | 493 | coredev, smscore_registry_getmode(coredev->devpath)); |
494 | if (rc < 0) { | 494 | if (rc < 0) { |
495 | sms_info("set device mode faile , rc %d", rc); | 495 | sms_info("set device mode faile , rc %d", rc); |
496 | return rc; | 496 | return rc; |
497 | } | 497 | } |
498 | 498 | ||
499 | kmutex_lock(&g_smscore_deviceslock); | 499 | kmutex_lock(&g_smscore_deviceslock); |
500 | 500 | ||
501 | rc = smscore_notify_callbacks(coredev, coredev->device, 1); | 501 | rc = smscore_notify_callbacks(coredev, coredev->device, 1); |
502 | smscore_init_ir(coredev); | 502 | smscore_init_ir(coredev); |
503 | 503 | ||
504 | sms_info("device %p started, rc %d", coredev, rc); | 504 | sms_info("device %p started, rc %d", coredev, rc); |
505 | 505 | ||
506 | kmutex_unlock(&g_smscore_deviceslock); | 506 | kmutex_unlock(&g_smscore_deviceslock); |
507 | 507 | ||
508 | return rc; | 508 | return rc; |
509 | } | 509 | } |
510 | EXPORT_SYMBOL_GPL(smscore_start_device); | 510 | EXPORT_SYMBOL_GPL(smscore_start_device); |
511 | 511 | ||
512 | 512 | ||
513 | static int smscore_load_firmware_family2(struct smscore_device_t *coredev, | 513 | static int smscore_load_firmware_family2(struct smscore_device_t *coredev, |
514 | void *buffer, size_t size) | 514 | void *buffer, size_t size) |
515 | { | 515 | { |
516 | struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer; | 516 | struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer; |
517 | struct SmsMsgHdr_ST *msg; | 517 | struct SmsMsgHdr_ST *msg; |
518 | u32 mem_address; | 518 | u32 mem_address; |
519 | u8 *payload = firmware->Payload; | 519 | u8 *payload = firmware->Payload; |
520 | int rc = 0; | 520 | int rc = 0; |
521 | firmware->StartAddress = le32_to_cpu(firmware->StartAddress); | 521 | firmware->StartAddress = le32_to_cpu(firmware->StartAddress); |
522 | firmware->Length = le32_to_cpu(firmware->Length); | 522 | firmware->Length = le32_to_cpu(firmware->Length); |
523 | 523 | ||
524 | mem_address = firmware->StartAddress; | 524 | mem_address = firmware->StartAddress; |
525 | 525 | ||
526 | sms_info("loading FW to addr 0x%x size %d", | 526 | sms_info("loading FW to addr 0x%x size %d", |
527 | mem_address, firmware->Length); | 527 | mem_address, firmware->Length); |
528 | if (coredev->preload_handler) { | 528 | if (coredev->preload_handler) { |
529 | rc = coredev->preload_handler(coredev->context); | 529 | rc = coredev->preload_handler(coredev->context); |
530 | if (rc < 0) | 530 | if (rc < 0) |
531 | return rc; | 531 | return rc; |
532 | } | 532 | } |
533 | 533 | ||
534 | /* PAGE_SIZE buffer shall be enough and dma aligned */ | 534 | /* PAGE_SIZE buffer shall be enough and dma aligned */ |
535 | msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA); | 535 | msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA); |
536 | if (!msg) | 536 | if (!msg) |
537 | return -ENOMEM; | 537 | return -ENOMEM; |
538 | 538 | ||
539 | if (coredev->mode != DEVICE_MODE_NONE) { | 539 | if (coredev->mode != DEVICE_MODE_NONE) { |
540 | sms_debug("sending reload command."); | 540 | sms_debug("sending reload command."); |
541 | SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ, | 541 | SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ, |
542 | sizeof(struct SmsMsgHdr_ST)); | 542 | sizeof(struct SmsMsgHdr_ST)); |
543 | rc = smscore_sendrequest_and_wait(coredev, msg, | 543 | rc = smscore_sendrequest_and_wait(coredev, msg, |
544 | msg->msgLength, | 544 | msg->msgLength, |
545 | &coredev->reload_start_done); | 545 | &coredev->reload_start_done); |
546 | mem_address = *(u32 *) &payload[20]; | 546 | mem_address = *(u32 *) &payload[20]; |
547 | } | 547 | } |
548 | 548 | ||
549 | while (size && rc >= 0) { | 549 | while (size && rc >= 0) { |
550 | struct SmsDataDownload_ST *DataMsg = | 550 | struct SmsDataDownload_ST *DataMsg = |
551 | (struct SmsDataDownload_ST *) msg; | 551 | (struct SmsDataDownload_ST *) msg; |
552 | int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE); | 552 | int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE); |
553 | 553 | ||
554 | SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ, | 554 | SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ, |
555 | (u16)(sizeof(struct SmsMsgHdr_ST) + | 555 | (u16)(sizeof(struct SmsMsgHdr_ST) + |
556 | sizeof(u32) + payload_size)); | 556 | sizeof(u32) + payload_size)); |
557 | 557 | ||
558 | DataMsg->MemAddr = mem_address; | 558 | DataMsg->MemAddr = mem_address; |
559 | memcpy(DataMsg->Payload, payload, payload_size); | 559 | memcpy(DataMsg->Payload, payload, payload_size); |
560 | 560 | ||
561 | if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) && | 561 | if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) && |
562 | (coredev->mode == DEVICE_MODE_NONE)) | 562 | (coredev->mode == DEVICE_MODE_NONE)) |
563 | rc = coredev->sendrequest_handler( | 563 | rc = coredev->sendrequest_handler( |
564 | coredev->context, DataMsg, | 564 | coredev->context, DataMsg, |
565 | DataMsg->xMsgHeader.msgLength); | 565 | DataMsg->xMsgHeader.msgLength); |
566 | else | 566 | else |
567 | rc = smscore_sendrequest_and_wait( | 567 | rc = smscore_sendrequest_and_wait( |
568 | coredev, DataMsg, | 568 | coredev, DataMsg, |
569 | DataMsg->xMsgHeader.msgLength, | 569 | DataMsg->xMsgHeader.msgLength, |
570 | &coredev->data_download_done); | 570 | &coredev->data_download_done); |
571 | 571 | ||
572 | payload += payload_size; | 572 | payload += payload_size; |
573 | size -= payload_size; | 573 | size -= payload_size; |
574 | mem_address += payload_size; | 574 | mem_address += payload_size; |
575 | } | 575 | } |
576 | 576 | ||
577 | if (rc >= 0) { | 577 | if (rc >= 0) { |
578 | if (coredev->mode == DEVICE_MODE_NONE) { | 578 | if (coredev->mode == DEVICE_MODE_NONE) { |
579 | struct SmsMsgData_ST *TriggerMsg = | 579 | struct SmsMsgData_ST *TriggerMsg = |
580 | (struct SmsMsgData_ST *) msg; | 580 | (struct SmsMsgData_ST *) msg; |
581 | 581 | ||
582 | SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, | 582 | SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, |
583 | sizeof(struct SmsMsgHdr_ST) + | 583 | sizeof(struct SmsMsgHdr_ST) + |
584 | sizeof(u32) * 5); | 584 | sizeof(u32) * 5); |
585 | 585 | ||
586 | TriggerMsg->msgData[0] = firmware->StartAddress; | 586 | TriggerMsg->msgData[0] = firmware->StartAddress; |
587 | /* Entry point */ | 587 | /* Entry point */ |
588 | TriggerMsg->msgData[1] = 5; /* Priority */ | 588 | TriggerMsg->msgData[1] = 5; /* Priority */ |
589 | TriggerMsg->msgData[2] = 0x200; /* Stack size */ | 589 | TriggerMsg->msgData[2] = 0x200; /* Stack size */ |
590 | TriggerMsg->msgData[3] = 0; /* Parameter */ | 590 | TriggerMsg->msgData[3] = 0; /* Parameter */ |
591 | TriggerMsg->msgData[4] = 4; /* Task ID */ | 591 | TriggerMsg->msgData[4] = 4; /* Task ID */ |
592 | 592 | ||
593 | if (coredev->device_flags & SMS_ROM_NO_RESPONSE) { | 593 | if (coredev->device_flags & SMS_ROM_NO_RESPONSE) { |
594 | rc = coredev->sendrequest_handler( | 594 | rc = coredev->sendrequest_handler( |
595 | coredev->context, TriggerMsg, | 595 | coredev->context, TriggerMsg, |
596 | TriggerMsg->xMsgHeader.msgLength); | 596 | TriggerMsg->xMsgHeader.msgLength); |
597 | msleep(100); | 597 | msleep(100); |
598 | } else | 598 | } else |
599 | rc = smscore_sendrequest_and_wait( | 599 | rc = smscore_sendrequest_and_wait( |
600 | coredev, TriggerMsg, | 600 | coredev, TriggerMsg, |
601 | TriggerMsg->xMsgHeader.msgLength, | 601 | TriggerMsg->xMsgHeader.msgLength, |
602 | &coredev->trigger_done); | 602 | &coredev->trigger_done); |
603 | } else { | 603 | } else { |
604 | SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ, | 604 | SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ, |
605 | sizeof(struct SmsMsgHdr_ST)); | 605 | sizeof(struct SmsMsgHdr_ST)); |
606 | 606 | ||
607 | rc = coredev->sendrequest_handler(coredev->context, | 607 | rc = coredev->sendrequest_handler(coredev->context, |
608 | msg, msg->msgLength); | 608 | msg, msg->msgLength); |
609 | } | 609 | } |
610 | msleep(500); | 610 | msleep(500); |
611 | } | 611 | } |
612 | 612 | ||
613 | sms_debug("rc=%d, postload=%p ", rc, | 613 | sms_debug("rc=%d, postload=%p ", rc, |
614 | coredev->postload_handler); | 614 | coredev->postload_handler); |
615 | 615 | ||
616 | kfree(msg); | 616 | kfree(msg); |
617 | 617 | ||
618 | return ((rc >= 0) && coredev->postload_handler) ? | 618 | return ((rc >= 0) && coredev->postload_handler) ? |
619 | coredev->postload_handler(coredev->context) : | 619 | coredev->postload_handler(coredev->context) : |
620 | rc; | 620 | rc; |
621 | } | 621 | } |
622 | 622 | ||
623 | /** | 623 | /** |
624 | * loads specified firmware into a buffer and calls device loadfirmware_handler | 624 | * loads specified firmware into a buffer and calls device loadfirmware_handler |
625 | * | 625 | * |
626 | * @param coredev pointer to a coredev object returned by | 626 | * @param coredev pointer to a coredev object returned by |
627 | * smscore_register_device | 627 | * smscore_register_device |
628 | * @param filename null-terminated string specifies firmware file name | 628 | * @param filename null-terminated string specifies firmware file name |
629 | * @param loadfirmware_handler device handler that loads firmware | 629 | * @param loadfirmware_handler device handler that loads firmware |
630 | * | 630 | * |
631 | * @return 0 on success, <0 on error. | 631 | * @return 0 on success, <0 on error. |
632 | */ | 632 | */ |
633 | static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, | 633 | static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, |
634 | char *filename, | 634 | char *filename, |
635 | loadfirmware_t loadfirmware_handler) | 635 | loadfirmware_t loadfirmware_handler) |
636 | { | 636 | { |
637 | int rc = -ENOENT; | 637 | int rc = -ENOENT; |
638 | const struct firmware *fw; | 638 | const struct firmware *fw; |
639 | u8 *fw_buffer; | 639 | u8 *fw_buffer; |
640 | 640 | ||
641 | if (loadfirmware_handler == NULL && !(coredev->device_flags & | 641 | if (loadfirmware_handler == NULL && !(coredev->device_flags & |
642 | SMS_DEVICE_FAMILY2)) | 642 | SMS_DEVICE_FAMILY2)) |
643 | return -EINVAL; | 643 | return -EINVAL; |
644 | 644 | ||
645 | rc = request_firmware(&fw, filename, coredev->device); | 645 | rc = request_firmware(&fw, filename, coredev->device); |
646 | if (rc < 0) { | 646 | if (rc < 0) { |
647 | sms_info("failed to open \"%s\"", filename); | 647 | sms_info("failed to open \"%s\"", filename); |
648 | return rc; | 648 | return rc; |
649 | } | 649 | } |
650 | sms_info("read FW %s, size=%zd", filename, fw->size); | 650 | sms_info("read FW %s, size=%zd", filename, fw->size); |
651 | fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT), | 651 | fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT), |
652 | GFP_KERNEL | GFP_DMA); | 652 | GFP_KERNEL | GFP_DMA); |
653 | if (fw_buffer) { | 653 | if (fw_buffer) { |
654 | memcpy(fw_buffer, fw->data, fw->size); | 654 | memcpy(fw_buffer, fw->data, fw->size); |
655 | 655 | ||
656 | rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ? | 656 | rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ? |
657 | smscore_load_firmware_family2(coredev, | 657 | smscore_load_firmware_family2(coredev, |
658 | fw_buffer, | 658 | fw_buffer, |
659 | fw->size) : | 659 | fw->size) : |
660 | loadfirmware_handler(coredev->context, | 660 | loadfirmware_handler(coredev->context, |
661 | fw_buffer, fw->size); | 661 | fw_buffer, fw->size); |
662 | 662 | ||
663 | kfree(fw_buffer); | 663 | kfree(fw_buffer); |
664 | } else { | 664 | } else { |
665 | sms_info("failed to allocate firmware buffer"); | 665 | sms_info("failed to allocate firmware buffer"); |
666 | rc = -ENOMEM; | 666 | rc = -ENOMEM; |
667 | } | 667 | } |
668 | 668 | ||
669 | release_firmware(fw); | 669 | release_firmware(fw); |
670 | 670 | ||
671 | return rc; | 671 | return rc; |
672 | } | 672 | } |
673 | 673 | ||
674 | /** | 674 | /** |
675 | * notifies all clients registered with the device, notifies hotplugs, | 675 | * notifies all clients registered with the device, notifies hotplugs, |
676 | * frees all buffers and coredev object | 676 | * frees all buffers and coredev object |
677 | * | 677 | * |
678 | * @param coredev pointer to a coredev object returned by | 678 | * @param coredev pointer to a coredev object returned by |
679 | * smscore_register_device | 679 | * smscore_register_device |
680 | * | 680 | * |
681 | * @return 0 on success, <0 on error. | 681 | * @return 0 on success, <0 on error. |
682 | */ | 682 | */ |
683 | void smscore_unregister_device(struct smscore_device_t *coredev) | 683 | void smscore_unregister_device(struct smscore_device_t *coredev) |
684 | { | 684 | { |
685 | struct smscore_buffer_t *cb; | 685 | struct smscore_buffer_t *cb; |
686 | int num_buffers = 0; | 686 | int num_buffers = 0; |
687 | int retry = 0; | 687 | int retry = 0; |
688 | 688 | ||
689 | kmutex_lock(&g_smscore_deviceslock); | 689 | kmutex_lock(&g_smscore_deviceslock); |
690 | 690 | ||
691 | /* Release input device (IR) resources */ | 691 | /* Release input device (IR) resources */ |
692 | sms_ir_exit(coredev); | 692 | sms_ir_exit(coredev); |
693 | 693 | ||
694 | smscore_notify_clients(coredev); | 694 | smscore_notify_clients(coredev); |
695 | smscore_notify_callbacks(coredev, NULL, 0); | 695 | smscore_notify_callbacks(coredev, NULL, 0); |
696 | 696 | ||
697 | /* at this point all buffers should be back | 697 | /* at this point all buffers should be back |
698 | * onresponse must no longer be called */ | 698 | * onresponse must no longer be called */ |
699 | 699 | ||
700 | while (1) { | 700 | while (1) { |
701 | while (!list_empty(&coredev->buffers)) { | 701 | while (!list_empty(&coredev->buffers)) { |
702 | cb = (struct smscore_buffer_t *) coredev->buffers.next; | 702 | cb = (struct smscore_buffer_t *) coredev->buffers.next; |
703 | list_del(&cb->entry); | 703 | list_del(&cb->entry); |
704 | kfree(cb); | 704 | kfree(cb); |
705 | num_buffers++; | 705 | num_buffers++; |
706 | } | 706 | } |
707 | if (num_buffers == coredev->num_buffers) | 707 | if (num_buffers == coredev->num_buffers) |
708 | break; | 708 | break; |
709 | if (++retry > 10) { | 709 | if (++retry > 10) { |
710 | sms_info("exiting although " | 710 | sms_info("exiting although " |
711 | "not all buffers released."); | 711 | "not all buffers released."); |
712 | break; | 712 | break; |
713 | } | 713 | } |
714 | 714 | ||
715 | sms_info("waiting for %d buffer(s)", | 715 | sms_info("waiting for %d buffer(s)", |
716 | coredev->num_buffers - num_buffers); | 716 | coredev->num_buffers - num_buffers); |
717 | msleep(100); | 717 | msleep(100); |
718 | } | 718 | } |
719 | 719 | ||
720 | sms_info("freed %d buffers", num_buffers); | 720 | sms_info("freed %d buffers", num_buffers); |
721 | 721 | ||
722 | if (coredev->common_buffer) | 722 | if (coredev->common_buffer) |
723 | dma_free_coherent(NULL, coredev->common_buffer_size, | 723 | dma_free_coherent(NULL, coredev->common_buffer_size, |
724 | coredev->common_buffer, coredev->common_buffer_phys); | 724 | coredev->common_buffer, coredev->common_buffer_phys); |
725 | 725 | ||
726 | if (coredev->fw_buf != NULL) | 726 | if (coredev->fw_buf != NULL) |
727 | kfree(coredev->fw_buf); | 727 | kfree(coredev->fw_buf); |
728 | 728 | ||
729 | list_del(&coredev->entry); | 729 | list_del(&coredev->entry); |
730 | kfree(coredev); | 730 | kfree(coredev); |
731 | 731 | ||
732 | kmutex_unlock(&g_smscore_deviceslock); | 732 | kmutex_unlock(&g_smscore_deviceslock); |
733 | 733 | ||
734 | sms_info("device %p destroyed", coredev); | 734 | sms_info("device %p destroyed", coredev); |
735 | } | 735 | } |
736 | EXPORT_SYMBOL_GPL(smscore_unregister_device); | 736 | EXPORT_SYMBOL_GPL(smscore_unregister_device); |
737 | 737 | ||
738 | static int smscore_detect_mode(struct smscore_device_t *coredev) | 738 | static int smscore_detect_mode(struct smscore_device_t *coredev) |
739 | { | 739 | { |
740 | void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT, | 740 | void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT, |
741 | GFP_KERNEL | GFP_DMA); | 741 | GFP_KERNEL | GFP_DMA); |
742 | struct SmsMsgHdr_ST *msg = | 742 | struct SmsMsgHdr_ST *msg = |
743 | (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer); | 743 | (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer); |
744 | int rc; | 744 | int rc; |
745 | 745 | ||
746 | if (!buffer) | 746 | if (!buffer) |
747 | return -ENOMEM; | 747 | return -ENOMEM; |
748 | 748 | ||
749 | SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ, | 749 | SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ, |
750 | sizeof(struct SmsMsgHdr_ST)); | 750 | sizeof(struct SmsMsgHdr_ST)); |
751 | 751 | ||
752 | rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength, | 752 | rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength, |
753 | &coredev->version_ex_done); | 753 | &coredev->version_ex_done); |
754 | if (rc == -ETIME) { | 754 | if (rc == -ETIME) { |
755 | sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try"); | 755 | sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try"); |
756 | 756 | ||
757 | if (wait_for_completion_timeout(&coredev->resume_done, | 757 | if (wait_for_completion_timeout(&coredev->resume_done, |
758 | msecs_to_jiffies(5000))) { | 758 | msecs_to_jiffies(5000))) { |
759 | rc = smscore_sendrequest_and_wait( | 759 | rc = smscore_sendrequest_and_wait( |
760 | coredev, msg, msg->msgLength, | 760 | coredev, msg, msg->msgLength, |
761 | &coredev->version_ex_done); | 761 | &coredev->version_ex_done); |
762 | if (rc < 0) | 762 | if (rc < 0) |
763 | sms_err("MSG_SMS_GET_VERSION_EX_REQ failed " | 763 | sms_err("MSG_SMS_GET_VERSION_EX_REQ failed " |
764 | "second try, rc %d", rc); | 764 | "second try, rc %d", rc); |
765 | } else | 765 | } else |
766 | rc = -ETIME; | 766 | rc = -ETIME; |
767 | } | 767 | } |
768 | 768 | ||
769 | kfree(buffer); | 769 | kfree(buffer); |
770 | 770 | ||
771 | return rc; | 771 | return rc; |
772 | } | 772 | } |
773 | 773 | ||
774 | static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = { | 774 | static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = { |
775 | /*Stellar NOVA A0 Nova B0 VEGA*/ | 775 | /*Stellar NOVA A0 Nova B0 VEGA*/ |
776 | /*DVBT*/ | 776 | /*DVBT*/ |
777 | {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, | 777 | {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, |
778 | /*DVBH*/ | 778 | /*DVBH*/ |
779 | {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, | 779 | {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, |
780 | /*TDMB*/ | 780 | /*TDMB*/ |
781 | {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"}, | 781 | {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"}, |
782 | /*DABIP*/ | 782 | /*DABIP*/ |
783 | {"none", "none", "none", "none"}, | 783 | {"none", "none", "none", "none"}, |
784 | /*BDA*/ | 784 | /*BDA*/ |
785 | {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, | 785 | {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, |
786 | /*ISDBT*/ | 786 | /*ISDBT*/ |
787 | {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, | 787 | {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, |
788 | /*ISDBTBDA*/ | 788 | /*ISDBTBDA*/ |
789 | {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, | 789 | {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, |
790 | /*CMMB*/ | 790 | /*CMMB*/ |
791 | {"none", "none", "none", "cmmb_vega_12mhz.inp"} | 791 | {"none", "none", "none", "cmmb_vega_12mhz.inp"} |
792 | }; | 792 | }; |
793 | 793 | ||
794 | static inline char *sms_get_fw_name(struct smscore_device_t *coredev, | 794 | static inline char *sms_get_fw_name(struct smscore_device_t *coredev, |
795 | int mode, enum sms_device_type_st type) | 795 | int mode, enum sms_device_type_st type) |
796 | { | 796 | { |
797 | char **fw = sms_get_board(smscore_get_board_id(coredev))->fw; | 797 | char **fw = sms_get_board(smscore_get_board_id(coredev))->fw; |
798 | return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type]; | 798 | return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type]; |
799 | } | 799 | } |
800 | 800 | ||
801 | /** | 801 | /** |
802 | * calls device handler to change mode of operation | 802 | * calls device handler to change mode of operation |
803 | * NOTE: stellar/usb may disconnect when changing mode | 803 | * NOTE: stellar/usb may disconnect when changing mode |
804 | * | 804 | * |
805 | * @param coredev pointer to a coredev object returned by | 805 | * @param coredev pointer to a coredev object returned by |
806 | * smscore_register_device | 806 | * smscore_register_device |
807 | * @param mode requested mode of operation | 807 | * @param mode requested mode of operation |
808 | * | 808 | * |
809 | * @return 0 on success, <0 on error. | 809 | * @return 0 on success, <0 on error. |
810 | */ | 810 | */ |
811 | int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) | 811 | int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) |
812 | { | 812 | { |
813 | void *buffer; | 813 | void *buffer; |
814 | int rc = 0; | 814 | int rc = 0; |
815 | enum sms_device_type_st type; | 815 | enum sms_device_type_st type; |
816 | 816 | ||
817 | sms_debug("set device mode to %d", mode); | 817 | sms_debug("set device mode to %d", mode); |
818 | if (coredev->device_flags & SMS_DEVICE_FAMILY2) { | 818 | if (coredev->device_flags & SMS_DEVICE_FAMILY2) { |
819 | if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) { | 819 | if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) { |
820 | sms_err("invalid mode specified %d", mode); | 820 | sms_err("invalid mode specified %d", mode); |
821 | return -EINVAL; | 821 | return -EINVAL; |
822 | } | 822 | } |
823 | 823 | ||
824 | smscore_registry_setmode(coredev->devpath, mode); | 824 | smscore_registry_setmode(coredev->devpath, mode); |
825 | 825 | ||
826 | if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) { | 826 | if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) { |
827 | rc = smscore_detect_mode(coredev); | 827 | rc = smscore_detect_mode(coredev); |
828 | if (rc < 0) { | 828 | if (rc < 0) { |
829 | sms_err("mode detect failed %d", rc); | 829 | sms_err("mode detect failed %d", rc); |
830 | return rc; | 830 | return rc; |
831 | } | 831 | } |
832 | } | 832 | } |
833 | 833 | ||
834 | if (coredev->mode == mode) { | 834 | if (coredev->mode == mode) { |
835 | sms_info("device mode %d already set", mode); | 835 | sms_info("device mode %d already set", mode); |
836 | return 0; | 836 | return 0; |
837 | } | 837 | } |
838 | 838 | ||
839 | if (!(coredev->modes_supported & (1 << mode))) { | 839 | if (!(coredev->modes_supported & (1 << mode))) { |
840 | char *fw_filename; | 840 | char *fw_filename; |
841 | 841 | ||
842 | type = smscore_registry_gettype(coredev->devpath); | 842 | type = smscore_registry_gettype(coredev->devpath); |
843 | fw_filename = sms_get_fw_name(coredev, mode, type); | 843 | fw_filename = sms_get_fw_name(coredev, mode, type); |
844 | 844 | ||
845 | rc = smscore_load_firmware_from_file(coredev, | 845 | rc = smscore_load_firmware_from_file(coredev, |
846 | fw_filename, NULL); | 846 | fw_filename, NULL); |
847 | if (rc < 0) { | 847 | if (rc < 0) { |
848 | sms_warn("error %d loading firmware: %s, " | 848 | sms_warn("error %d loading firmware: %s, " |
849 | "trying again with default firmware", | 849 | "trying again with default firmware", |
850 | rc, fw_filename); | 850 | rc, fw_filename); |
851 | 851 | ||
852 | /* try again with the default firmware */ | 852 | /* try again with the default firmware */ |
853 | fw_filename = smscore_fw_lkup[mode][type]; | 853 | fw_filename = smscore_fw_lkup[mode][type]; |
854 | rc = smscore_load_firmware_from_file(coredev, | 854 | rc = smscore_load_firmware_from_file(coredev, |
855 | fw_filename, NULL); | 855 | fw_filename, NULL); |
856 | 856 | ||
857 | if (rc < 0) { | 857 | if (rc < 0) { |
858 | sms_warn("error %d loading " | 858 | sms_warn("error %d loading " |
859 | "firmware: %s", rc, | 859 | "firmware: %s", rc, |
860 | fw_filename); | 860 | fw_filename); |
861 | return rc; | 861 | return rc; |
862 | } | 862 | } |
863 | } | 863 | } |
864 | sms_log("firmware download success: %s", fw_filename); | 864 | sms_log("firmware download success: %s", fw_filename); |
865 | } else | 865 | } else |
866 | sms_info("mode %d supported by running " | 866 | sms_info("mode %d supported by running " |
867 | "firmware", mode); | 867 | "firmware", mode); |
868 | 868 | ||
869 | buffer = kmalloc(sizeof(struct SmsMsgData_ST) + | 869 | buffer = kmalloc(sizeof(struct SmsMsgData_ST) + |
870 | SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); | 870 | SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); |
871 | if (buffer) { | 871 | if (buffer) { |
872 | struct SmsMsgData_ST *msg = | 872 | struct SmsMsgData_ST *msg = |
873 | (struct SmsMsgData_ST *) | 873 | (struct SmsMsgData_ST *) |
874 | SMS_ALIGN_ADDRESS(buffer); | 874 | SMS_ALIGN_ADDRESS(buffer); |
875 | 875 | ||
876 | SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, | 876 | SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, |
877 | sizeof(struct SmsMsgData_ST)); | 877 | sizeof(struct SmsMsgData_ST)); |
878 | msg->msgData[0] = mode; | 878 | msg->msgData[0] = mode; |
879 | 879 | ||
880 | rc = smscore_sendrequest_and_wait( | 880 | rc = smscore_sendrequest_and_wait( |
881 | coredev, msg, msg->xMsgHeader.msgLength, | 881 | coredev, msg, msg->xMsgHeader.msgLength, |
882 | &coredev->init_device_done); | 882 | &coredev->init_device_done); |
883 | 883 | ||
884 | kfree(buffer); | 884 | kfree(buffer); |
885 | } else { | 885 | } else { |
886 | sms_err("Could not allocate buffer for " | 886 | sms_err("Could not allocate buffer for " |
887 | "init device message."); | 887 | "init device message."); |
888 | rc = -ENOMEM; | 888 | rc = -ENOMEM; |
889 | } | 889 | } |
890 | } else { | 890 | } else { |
891 | if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { | 891 | if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { |
892 | sms_err("invalid mode specified %d", mode); | 892 | sms_err("invalid mode specified %d", mode); |
893 | return -EINVAL; | 893 | return -EINVAL; |
894 | } | 894 | } |
895 | 895 | ||
896 | smscore_registry_setmode(coredev->devpath, mode); | 896 | smscore_registry_setmode(coredev->devpath, mode); |
897 | 897 | ||
898 | if (coredev->detectmode_handler) | 898 | if (coredev->detectmode_handler) |
899 | coredev->detectmode_handler(coredev->context, | 899 | coredev->detectmode_handler(coredev->context, |
900 | &coredev->mode); | 900 | &coredev->mode); |
901 | 901 | ||
902 | if (coredev->mode != mode && coredev->setmode_handler) | 902 | if (coredev->mode != mode && coredev->setmode_handler) |
903 | rc = coredev->setmode_handler(coredev->context, mode); | 903 | rc = coredev->setmode_handler(coredev->context, mode); |
904 | } | 904 | } |
905 | 905 | ||
906 | if (rc >= 0) { | 906 | if (rc >= 0) { |
907 | coredev->mode = mode; | 907 | coredev->mode = mode; |
908 | coredev->device_flags &= ~SMS_DEVICE_NOT_READY; | 908 | coredev->device_flags &= ~SMS_DEVICE_NOT_READY; |
909 | } | 909 | } |
910 | 910 | ||
911 | if (rc < 0) | 911 | if (rc < 0) |
912 | sms_err("return error code %d.", rc); | 912 | sms_err("return error code %d.", rc); |
913 | return rc; | 913 | return rc; |
914 | } | 914 | } |
915 | 915 | ||
916 | /** | 916 | /** |
917 | * calls device handler to get current mode of operation | 917 | * calls device handler to get current mode of operation |
918 | * | 918 | * |
919 | * @param coredev pointer to a coredev object returned by | 919 | * @param coredev pointer to a coredev object returned by |
920 | * smscore_register_device | 920 | * smscore_register_device |
921 | * | 921 | * |
922 | * @return current mode | 922 | * @return current mode |
923 | */ | 923 | */ |
924 | int smscore_get_device_mode(struct smscore_device_t *coredev) | 924 | int smscore_get_device_mode(struct smscore_device_t *coredev) |
925 | { | 925 | { |
926 | return coredev->mode; | 926 | return coredev->mode; |
927 | } | 927 | } |
928 | EXPORT_SYMBOL_GPL(smscore_get_device_mode); | 928 | EXPORT_SYMBOL_GPL(smscore_get_device_mode); |
929 | 929 | ||
930 | /** | 930 | /** |
931 | * find client by response id & type within the clients list. | 931 | * find client by response id & type within the clients list. |
932 | * return client handle or NULL. | 932 | * return client handle or NULL. |
933 | * | 933 | * |
934 | * @param coredev pointer to a coredev object returned by | 934 | * @param coredev pointer to a coredev object returned by |
935 | * smscore_register_device | 935 | * smscore_register_device |
936 | * @param data_type client data type (SMS_DONT_CARE for all types) | 936 | * @param data_type client data type (SMS_DONT_CARE for all types) |
937 | * @param id client id (SMS_DONT_CARE for all id) | 937 | * @param id client id (SMS_DONT_CARE for all id) |
938 | * | 938 | * |
939 | */ | 939 | */ |
940 | static struct | 940 | static struct |
941 | smscore_client_t *smscore_find_client(struct smscore_device_t *coredev, | 941 | smscore_client_t *smscore_find_client(struct smscore_device_t *coredev, |
942 | int data_type, int id) | 942 | int data_type, int id) |
943 | { | 943 | { |
944 | struct smscore_client_t *client = NULL; | 944 | struct smscore_client_t *client = NULL; |
945 | struct list_head *next, *first; | 945 | struct list_head *next, *first; |
946 | unsigned long flags; | 946 | unsigned long flags; |
947 | struct list_head *firstid, *nextid; | 947 | struct list_head *firstid, *nextid; |
948 | 948 | ||
949 | 949 | ||
950 | spin_lock_irqsave(&coredev->clientslock, flags); | 950 | spin_lock_irqsave(&coredev->clientslock, flags); |
951 | first = &coredev->clients; | 951 | first = &coredev->clients; |
952 | for (next = first->next; | 952 | for (next = first->next; |
953 | (next != first) && !client; | 953 | (next != first) && !client; |
954 | next = next->next) { | 954 | next = next->next) { |
955 | firstid = &((struct smscore_client_t *)next)->idlist; | 955 | firstid = &((struct smscore_client_t *)next)->idlist; |
956 | for (nextid = firstid->next; | 956 | for (nextid = firstid->next; |
957 | nextid != firstid; | 957 | nextid != firstid; |
958 | nextid = nextid->next) { | 958 | nextid = nextid->next) { |
959 | if ((((struct smscore_idlist_t *)nextid)->id == id) && | 959 | if ((((struct smscore_idlist_t *)nextid)->id == id) && |
960 | (((struct smscore_idlist_t *)nextid)->data_type == data_type || | 960 | (((struct smscore_idlist_t *)nextid)->data_type == data_type || |
961 | (((struct smscore_idlist_t *)nextid)->data_type == 0))) { | 961 | (((struct smscore_idlist_t *)nextid)->data_type == 0))) { |
962 | client = (struct smscore_client_t *) next; | 962 | client = (struct smscore_client_t *) next; |
963 | break; | 963 | break; |
964 | } | 964 | } |
965 | } | 965 | } |
966 | } | 966 | } |
967 | spin_unlock_irqrestore(&coredev->clientslock, flags); | 967 | spin_unlock_irqrestore(&coredev->clientslock, flags); |
968 | return client; | 968 | return client; |
969 | } | 969 | } |
970 | 970 | ||
971 | /** | 971 | /** |
972 | * find client by response id/type, call clients onresponse handler | 972 | * find client by response id/type, call clients onresponse handler |
973 | * return buffer to pool on error | 973 | * return buffer to pool on error |
974 | * | 974 | * |
975 | * @param coredev pointer to a coredev object returned by | 975 | * @param coredev pointer to a coredev object returned by |
976 | * smscore_register_device | 976 | * smscore_register_device |
977 | * @param cb pointer to response buffer descriptor | 977 | * @param cb pointer to response buffer descriptor |
978 | * | 978 | * |
979 | */ | 979 | */ |
980 | void smscore_onresponse(struct smscore_device_t *coredev, | 980 | void smscore_onresponse(struct smscore_device_t *coredev, |
981 | struct smscore_buffer_t *cb) { | 981 | struct smscore_buffer_t *cb) { |
982 | struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p | 982 | struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p |
983 | + cb->offset); | 983 | + cb->offset); |
984 | struct smscore_client_t *client; | 984 | struct smscore_client_t *client; |
985 | int rc = -EBUSY; | 985 | int rc = -EBUSY; |
986 | static unsigned long last_sample_time; /* = 0; */ | 986 | static unsigned long last_sample_time; /* = 0; */ |
987 | static int data_total; /* = 0; */ | 987 | static int data_total; /* = 0; */ |
988 | unsigned long time_now = jiffies_to_msecs(jiffies); | 988 | unsigned long time_now = jiffies_to_msecs(jiffies); |
989 | 989 | ||
990 | if (!last_sample_time) | 990 | if (!last_sample_time) |
991 | last_sample_time = time_now; | 991 | last_sample_time = time_now; |
992 | 992 | ||
993 | if (time_now - last_sample_time > 10000) { | 993 | if (time_now - last_sample_time > 10000) { |
994 | sms_debug("\ndata rate %d bytes/secs", | 994 | sms_debug("\ndata rate %d bytes/secs", |
995 | (int)((data_total * 1000) / | 995 | (int)((data_total * 1000) / |
996 | (time_now - last_sample_time))); | 996 | (time_now - last_sample_time))); |
997 | 997 | ||
998 | last_sample_time = time_now; | 998 | last_sample_time = time_now; |
999 | data_total = 0; | 999 | data_total = 0; |
1000 | } | 1000 | } |
1001 | 1001 | ||
1002 | data_total += cb->size; | 1002 | data_total += cb->size; |
1003 | /* Do we need to re-route? */ | 1003 | /* Do we need to re-route? */ |
1004 | if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) || | 1004 | if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) || |
1005 | (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) { | 1005 | (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) { |
1006 | if (coredev->mode == DEVICE_MODE_DVBT_BDA) | 1006 | if (coredev->mode == DEVICE_MODE_DVBT_BDA) |
1007 | phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID; | 1007 | phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID; |
1008 | } | 1008 | } |
1009 | 1009 | ||
1010 | 1010 | ||
1011 | client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId); | 1011 | client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId); |
1012 | 1012 | ||
1013 | /* If no client registered for type & id, | 1013 | /* If no client registered for type & id, |
1014 | * check for control client where type is not registered */ | 1014 | * check for control client where type is not registered */ |
1015 | if (client) | 1015 | if (client) |
1016 | rc = client->onresponse_handler(client->context, cb); | 1016 | rc = client->onresponse_handler(client->context, cb); |
1017 | 1017 | ||
1018 | if (rc < 0) { | 1018 | if (rc < 0) { |
1019 | switch (phdr->msgType) { | 1019 | switch (phdr->msgType) { |
1020 | case MSG_SMS_GET_VERSION_EX_RES: | 1020 | case MSG_SMS_GET_VERSION_EX_RES: |
1021 | { | 1021 | { |
1022 | struct SmsVersionRes_ST *ver = | 1022 | struct SmsVersionRes_ST *ver = |
1023 | (struct SmsVersionRes_ST *) phdr; | 1023 | (struct SmsVersionRes_ST *) phdr; |
1024 | sms_debug("MSG_SMS_GET_VERSION_EX_RES " | 1024 | sms_debug("MSG_SMS_GET_VERSION_EX_RES " |
1025 | "id %d prots 0x%x ver %d.%d", | 1025 | "id %d prots 0x%x ver %d.%d", |
1026 | ver->FirmwareId, ver->SupportedProtocols, | 1026 | ver->FirmwareId, ver->SupportedProtocols, |
1027 | ver->RomVersionMajor, ver->RomVersionMinor); | 1027 | ver->RomVersionMajor, ver->RomVersionMinor); |
1028 | 1028 | ||
1029 | coredev->mode = ver->FirmwareId == 255 ? | 1029 | coredev->mode = ver->FirmwareId == 255 ? |
1030 | DEVICE_MODE_NONE : ver->FirmwareId; | 1030 | DEVICE_MODE_NONE : ver->FirmwareId; |
1031 | coredev->modes_supported = ver->SupportedProtocols; | 1031 | coredev->modes_supported = ver->SupportedProtocols; |
1032 | 1032 | ||
1033 | complete(&coredev->version_ex_done); | 1033 | complete(&coredev->version_ex_done); |
1034 | break; | 1034 | break; |
1035 | } | 1035 | } |
1036 | case MSG_SMS_INIT_DEVICE_RES: | 1036 | case MSG_SMS_INIT_DEVICE_RES: |
1037 | sms_debug("MSG_SMS_INIT_DEVICE_RES"); | 1037 | sms_debug("MSG_SMS_INIT_DEVICE_RES"); |
1038 | complete(&coredev->init_device_done); | 1038 | complete(&coredev->init_device_done); |
1039 | break; | 1039 | break; |
1040 | case MSG_SW_RELOAD_START_RES: | 1040 | case MSG_SW_RELOAD_START_RES: |
1041 | sms_debug("MSG_SW_RELOAD_START_RES"); | 1041 | sms_debug("MSG_SW_RELOAD_START_RES"); |
1042 | complete(&coredev->reload_start_done); | 1042 | complete(&coredev->reload_start_done); |
1043 | break; | 1043 | break; |
1044 | case MSG_SMS_DATA_DOWNLOAD_RES: | 1044 | case MSG_SMS_DATA_DOWNLOAD_RES: |
1045 | complete(&coredev->data_download_done); | 1045 | complete(&coredev->data_download_done); |
1046 | break; | 1046 | break; |
1047 | case MSG_SW_RELOAD_EXEC_RES: | 1047 | case MSG_SW_RELOAD_EXEC_RES: |
1048 | sms_debug("MSG_SW_RELOAD_EXEC_RES"); | 1048 | sms_debug("MSG_SW_RELOAD_EXEC_RES"); |
1049 | break; | 1049 | break; |
1050 | case MSG_SMS_SWDOWNLOAD_TRIGGER_RES: | 1050 | case MSG_SMS_SWDOWNLOAD_TRIGGER_RES: |
1051 | sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES"); | 1051 | sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES"); |
1052 | complete(&coredev->trigger_done); | 1052 | complete(&coredev->trigger_done); |
1053 | break; | 1053 | break; |
1054 | case MSG_SMS_SLEEP_RESUME_COMP_IND: | 1054 | case MSG_SMS_SLEEP_RESUME_COMP_IND: |
1055 | complete(&coredev->resume_done); | 1055 | complete(&coredev->resume_done); |
1056 | break; | 1056 | break; |
1057 | case MSG_SMS_GPIO_CONFIG_EX_RES: | 1057 | case MSG_SMS_GPIO_CONFIG_EX_RES: |
1058 | sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES"); | 1058 | sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES"); |
1059 | complete(&coredev->gpio_configuration_done); | 1059 | complete(&coredev->gpio_configuration_done); |
1060 | break; | 1060 | break; |
1061 | case MSG_SMS_GPIO_SET_LEVEL_RES: | 1061 | case MSG_SMS_GPIO_SET_LEVEL_RES: |
1062 | sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES"); | 1062 | sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES"); |
1063 | complete(&coredev->gpio_set_level_done); | 1063 | complete(&coredev->gpio_set_level_done); |
1064 | break; | 1064 | break; |
1065 | case MSG_SMS_GPIO_GET_LEVEL_RES: | 1065 | case MSG_SMS_GPIO_GET_LEVEL_RES: |
1066 | { | 1066 | { |
1067 | u32 *msgdata = (u32 *) phdr; | 1067 | u32 *msgdata = (u32 *) phdr; |
1068 | coredev->gpio_get_res = msgdata[1]; | 1068 | coredev->gpio_get_res = msgdata[1]; |
1069 | sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d", | 1069 | sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d", |
1070 | coredev->gpio_get_res); | 1070 | coredev->gpio_get_res); |
1071 | complete(&coredev->gpio_get_level_done); | 1071 | complete(&coredev->gpio_get_level_done); |
1072 | break; | 1072 | break; |
1073 | } | 1073 | } |
1074 | case MSG_SMS_START_IR_RES: | 1074 | case MSG_SMS_START_IR_RES: |
1075 | complete(&coredev->ir_init_done); | 1075 | complete(&coredev->ir_init_done); |
1076 | break; | 1076 | break; |
1077 | case MSG_SMS_IR_SAMPLES_IND: | 1077 | case MSG_SMS_IR_SAMPLES_IND: |
1078 | sms_ir_event(coredev, | 1078 | sms_ir_event(coredev, |
1079 | (const char *) | 1079 | (const char *) |
1080 | ((char *)phdr | 1080 | ((char *)phdr |
1081 | + sizeof(struct SmsMsgHdr_ST)), | 1081 | + sizeof(struct SmsMsgHdr_ST)), |
1082 | (int)phdr->msgLength | 1082 | (int)phdr->msgLength |
1083 | - sizeof(struct SmsMsgHdr_ST)); | 1083 | - sizeof(struct SmsMsgHdr_ST)); |
1084 | break; | 1084 | break; |
1085 | 1085 | ||
1086 | default: | 1086 | default: |
1087 | break; | 1087 | break; |
1088 | } | 1088 | } |
1089 | smscore_putbuffer(coredev, cb); | 1089 | smscore_putbuffer(coredev, cb); |
1090 | } | 1090 | } |
1091 | } | 1091 | } |
1092 | EXPORT_SYMBOL_GPL(smscore_onresponse); | 1092 | EXPORT_SYMBOL_GPL(smscore_onresponse); |
1093 | 1093 | ||
1094 | /** | 1094 | /** |
1095 | * return pointer to next free buffer descriptor from core pool | 1095 | * return pointer to next free buffer descriptor from core pool |
1096 | * | 1096 | * |
1097 | * @param coredev pointer to a coredev object returned by | 1097 | * @param coredev pointer to a coredev object returned by |
1098 | * smscore_register_device | 1098 | * smscore_register_device |
1099 | * | 1099 | * |
1100 | * @return pointer to descriptor on success, NULL on error. | 1100 | * @return pointer to descriptor on success, NULL on error. |
1101 | */ | 1101 | */ |
1102 | struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev) | 1102 | struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev) |
1103 | { | 1103 | { |
1104 | struct smscore_buffer_t *cb = NULL; | 1104 | struct smscore_buffer_t *cb = NULL; |
1105 | unsigned long flags; | 1105 | unsigned long flags; |
1106 | 1106 | ||
1107 | DEFINE_WAIT(wait); | 1107 | DEFINE_WAIT(wait); |
1108 | 1108 | ||
1109 | spin_lock_irqsave(&coredev->bufferslock, flags); | 1109 | spin_lock_irqsave(&coredev->bufferslock, flags); |
1110 | 1110 | ||
1111 | /* This function must return a valid buffer, since the buffer list is | 1111 | /* This function must return a valid buffer, since the buffer list is |
1112 | * finite, we check that there is an available buffer, if not, we wait | 1112 | * finite, we check that there is an available buffer, if not, we wait |
1113 | * until such buffer become available. | 1113 | * until such buffer become available. |
1114 | */ | 1114 | */ |
1115 | 1115 | ||
1116 | prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE); | 1116 | prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE); |
1117 | 1117 | ||
1118 | if (list_empty(&coredev->buffers)) | 1118 | if (list_empty(&coredev->buffers)) |
1119 | schedule(); | 1119 | schedule(); |
1120 | 1120 | ||
1121 | finish_wait(&coredev->buffer_mng_waitq, &wait); | 1121 | finish_wait(&coredev->buffer_mng_waitq, &wait); |
1122 | 1122 | ||
1123 | cb = (struct smscore_buffer_t *) coredev->buffers.next; | 1123 | cb = (struct smscore_buffer_t *) coredev->buffers.next; |
1124 | list_del(&cb->entry); | 1124 | list_del(&cb->entry); |
1125 | 1125 | ||
1126 | spin_unlock_irqrestore(&coredev->bufferslock, flags); | 1126 | spin_unlock_irqrestore(&coredev->bufferslock, flags); |
1127 | 1127 | ||
1128 | return cb; | 1128 | return cb; |
1129 | } | 1129 | } |
1130 | EXPORT_SYMBOL_GPL(smscore_getbuffer); | 1130 | EXPORT_SYMBOL_GPL(smscore_getbuffer); |
1131 | 1131 | ||
1132 | /** | 1132 | /** |
1133 | * return buffer descriptor to a pool | 1133 | * return buffer descriptor to a pool |
1134 | * | 1134 | * |
1135 | * @param coredev pointer to a coredev object returned by | 1135 | * @param coredev pointer to a coredev object returned by |
1136 | * smscore_register_device | 1136 | * smscore_register_device |
1137 | * @param cb pointer buffer descriptor | 1137 | * @param cb pointer buffer descriptor |
1138 | * | 1138 | * |
1139 | */ | 1139 | */ |
1140 | void smscore_putbuffer(struct smscore_device_t *coredev, | 1140 | void smscore_putbuffer(struct smscore_device_t *coredev, |
1141 | struct smscore_buffer_t *cb) { | 1141 | struct smscore_buffer_t *cb) { |
1142 | wake_up_interruptible(&coredev->buffer_mng_waitq); | 1142 | wake_up_interruptible(&coredev->buffer_mng_waitq); |
1143 | list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock); | 1143 | list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock); |
1144 | } | 1144 | } |
1145 | EXPORT_SYMBOL_GPL(smscore_putbuffer); | 1145 | EXPORT_SYMBOL_GPL(smscore_putbuffer); |
1146 | 1146 | ||
1147 | static int smscore_validate_client(struct smscore_device_t *coredev, | 1147 | static int smscore_validate_client(struct smscore_device_t *coredev, |
1148 | struct smscore_client_t *client, | 1148 | struct smscore_client_t *client, |
1149 | int data_type, int id) | 1149 | int data_type, int id) |
1150 | { | 1150 | { |
1151 | struct smscore_idlist_t *listentry; | 1151 | struct smscore_idlist_t *listentry; |
1152 | struct smscore_client_t *registered_client; | 1152 | struct smscore_client_t *registered_client; |
1153 | 1153 | ||
1154 | if (!client) { | 1154 | if (!client) { |
1155 | sms_err("bad parameter."); | 1155 | sms_err("bad parameter."); |
1156 | return -EFAULT; | 1156 | return -EFAULT; |
1157 | } | 1157 | } |
1158 | registered_client = smscore_find_client(coredev, data_type, id); | 1158 | registered_client = smscore_find_client(coredev, data_type, id); |
1159 | if (registered_client == client) | 1159 | if (registered_client == client) |
1160 | return 0; | 1160 | return 0; |
1161 | 1161 | ||
1162 | if (registered_client) { | 1162 | if (registered_client) { |
1163 | sms_err("The msg ID already registered to another client."); | 1163 | sms_err("The msg ID already registered to another client."); |
1164 | return -EEXIST; | 1164 | return -EEXIST; |
1165 | } | 1165 | } |
1166 | listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL); | 1166 | listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL); |
1167 | if (!listentry) { | 1167 | if (!listentry) { |
1168 | sms_err("Can't allocate memory for client id."); | 1168 | sms_err("Can't allocate memory for client id."); |
1169 | return -ENOMEM; | 1169 | return -ENOMEM; |
1170 | } | 1170 | } |
1171 | listentry->id = id; | 1171 | listentry->id = id; |
1172 | listentry->data_type = data_type; | 1172 | listentry->data_type = data_type; |
1173 | list_add_locked(&listentry->entry, &client->idlist, | 1173 | list_add_locked(&listentry->entry, &client->idlist, |
1174 | &coredev->clientslock); | 1174 | &coredev->clientslock); |
1175 | return 0; | 1175 | return 0; |
1176 | } | 1176 | } |
1177 | 1177 | ||
1178 | /** | 1178 | /** |
1179 | * creates smsclient object, check that id is taken by another client | 1179 | * creates smsclient object, check that id is taken by another client |
1180 | * | 1180 | * |
1181 | * @param coredev pointer to a coredev object from clients hotplug | 1181 | * @param coredev pointer to a coredev object from clients hotplug |
1182 | * @param initial_id all messages with this id would be sent to this client | 1182 | * @param initial_id all messages with this id would be sent to this client |
1183 | * @param data_type all messages of this type would be sent to this client | 1183 | * @param data_type all messages of this type would be sent to this client |
1184 | * @param onresponse_handler client handler that is called to | 1184 | * @param onresponse_handler client handler that is called to |
1185 | * process incoming messages | 1185 | * process incoming messages |
1186 | * @param onremove_handler client handler that is called when device is removed | 1186 | * @param onremove_handler client handler that is called when device is removed |
1187 | * @param context client-specific context | 1187 | * @param context client-specific context |
1188 | * @param client pointer to a value that receives created smsclient object | 1188 | * @param client pointer to a value that receives created smsclient object |
1189 | * | 1189 | * |
1190 | * @return 0 on success, <0 on error. | 1190 | * @return 0 on success, <0 on error. |
1191 | */ | 1191 | */ |
1192 | int smscore_register_client(struct smscore_device_t *coredev, | 1192 | int smscore_register_client(struct smscore_device_t *coredev, |
1193 | struct smsclient_params_t *params, | 1193 | struct smsclient_params_t *params, |
1194 | struct smscore_client_t **client) | 1194 | struct smscore_client_t **client) |
1195 | { | 1195 | { |
1196 | struct smscore_client_t *newclient; | 1196 | struct smscore_client_t *newclient; |
1197 | /* check that no other channel with same parameters exists */ | 1197 | /* check that no other channel with same parameters exists */ |
1198 | if (smscore_find_client(coredev, params->data_type, | 1198 | if (smscore_find_client(coredev, params->data_type, |
1199 | params->initial_id)) { | 1199 | params->initial_id)) { |
1200 | sms_err("Client already exist."); | 1200 | sms_err("Client already exist."); |
1201 | return -EEXIST; | 1201 | return -EEXIST; |
1202 | } | 1202 | } |
1203 | 1203 | ||
1204 | newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL); | 1204 | newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL); |
1205 | if (!newclient) { | 1205 | if (!newclient) { |
1206 | sms_err("Failed to allocate memory for client."); | 1206 | sms_err("Failed to allocate memory for client."); |
1207 | return -ENOMEM; | 1207 | return -ENOMEM; |
1208 | } | 1208 | } |
1209 | 1209 | ||
1210 | INIT_LIST_HEAD(&newclient->idlist); | 1210 | INIT_LIST_HEAD(&newclient->idlist); |
1211 | newclient->coredev = coredev; | 1211 | newclient->coredev = coredev; |
1212 | newclient->onresponse_handler = params->onresponse_handler; | 1212 | newclient->onresponse_handler = params->onresponse_handler; |
1213 | newclient->onremove_handler = params->onremove_handler; | 1213 | newclient->onremove_handler = params->onremove_handler; |
1214 | newclient->context = params->context; | 1214 | newclient->context = params->context; |
1215 | list_add_locked(&newclient->entry, &coredev->clients, | 1215 | list_add_locked(&newclient->entry, &coredev->clients, |
1216 | &coredev->clientslock); | 1216 | &coredev->clientslock); |
1217 | smscore_validate_client(coredev, newclient, params->data_type, | 1217 | smscore_validate_client(coredev, newclient, params->data_type, |
1218 | params->initial_id); | 1218 | params->initial_id); |
1219 | *client = newclient; | 1219 | *client = newclient; |
1220 | sms_debug("%p %d %d", params->context, params->data_type, | 1220 | sms_debug("%p %d %d", params->context, params->data_type, |
1221 | params->initial_id); | 1221 | params->initial_id); |
1222 | 1222 | ||
1223 | return 0; | 1223 | return 0; |
1224 | } | 1224 | } |
1225 | EXPORT_SYMBOL_GPL(smscore_register_client); | 1225 | EXPORT_SYMBOL_GPL(smscore_register_client); |
1226 | 1226 | ||
1227 | /** | 1227 | /** |
1228 | * frees smsclient object and all subclients associated with it | 1228 | * frees smsclient object and all subclients associated with it |
1229 | * | 1229 | * |
1230 | * @param client pointer to smsclient object returned by | 1230 | * @param client pointer to smsclient object returned by |
1231 | * smscore_register_client | 1231 | * smscore_register_client |
1232 | * | 1232 | * |
1233 | */ | 1233 | */ |
1234 | void smscore_unregister_client(struct smscore_client_t *client) | 1234 | void smscore_unregister_client(struct smscore_client_t *client) |
1235 | { | 1235 | { |
1236 | struct smscore_device_t *coredev = client->coredev; | 1236 | struct smscore_device_t *coredev = client->coredev; |
1237 | unsigned long flags; | 1237 | unsigned long flags; |
1238 | 1238 | ||
1239 | spin_lock_irqsave(&coredev->clientslock, flags); | 1239 | spin_lock_irqsave(&coredev->clientslock, flags); |
1240 | 1240 | ||
1241 | 1241 | ||
1242 | while (!list_empty(&client->idlist)) { | 1242 | while (!list_empty(&client->idlist)) { |
1243 | struct smscore_idlist_t *identry = | 1243 | struct smscore_idlist_t *identry = |
1244 | (struct smscore_idlist_t *) client->idlist.next; | 1244 | (struct smscore_idlist_t *) client->idlist.next; |
1245 | list_del(&identry->entry); | 1245 | list_del(&identry->entry); |
1246 | kfree(identry); | 1246 | kfree(identry); |
1247 | } | 1247 | } |
1248 | 1248 | ||
1249 | sms_info("%p", client->context); | 1249 | sms_info("%p", client->context); |
1250 | 1250 | ||
1251 | list_del(&client->entry); | 1251 | list_del(&client->entry); |
1252 | kfree(client); | 1252 | kfree(client); |
1253 | 1253 | ||
1254 | spin_unlock_irqrestore(&coredev->clientslock, flags); | 1254 | spin_unlock_irqrestore(&coredev->clientslock, flags); |
1255 | } | 1255 | } |
1256 | EXPORT_SYMBOL_GPL(smscore_unregister_client); | 1256 | EXPORT_SYMBOL_GPL(smscore_unregister_client); |
1257 | 1257 | ||
1258 | /** | 1258 | /** |
1259 | * verifies that source id is not taken by another client, | 1259 | * verifies that source id is not taken by another client, |
1260 | * calls device handler to send requests to the device | 1260 | * calls device handler to send requests to the device |
1261 | * | 1261 | * |
1262 | * @param client pointer to smsclient object returned by | 1262 | * @param client pointer to smsclient object returned by |
1263 | * smscore_register_client | 1263 | * smscore_register_client |
1264 | * @param buffer pointer to a request buffer | 1264 | * @param buffer pointer to a request buffer |
1265 | * @param size size (in bytes) of request buffer | 1265 | * @param size size (in bytes) of request buffer |
1266 | * | 1266 | * |
1267 | * @return 0 on success, <0 on error. | 1267 | * @return 0 on success, <0 on error. |
1268 | */ | 1268 | */ |
1269 | int smsclient_sendrequest(struct smscore_client_t *client, | 1269 | int smsclient_sendrequest(struct smscore_client_t *client, |
1270 | void *buffer, size_t size) | 1270 | void *buffer, size_t size) |
1271 | { | 1271 | { |
1272 | struct smscore_device_t *coredev; | 1272 | struct smscore_device_t *coredev; |
1273 | struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer; | 1273 | struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer; |
1274 | int rc; | 1274 | int rc; |
1275 | 1275 | ||
1276 | if (client == NULL) { | 1276 | if (client == NULL) { |
1277 | sms_err("Got NULL client"); | 1277 | sms_err("Got NULL client"); |
1278 | return -EINVAL; | 1278 | return -EINVAL; |
1279 | } | 1279 | } |
1280 | 1280 | ||
1281 | coredev = client->coredev; | 1281 | coredev = client->coredev; |
1282 | 1282 | ||
1283 | /* check that no other channel with same id exists */ | 1283 | /* check that no other channel with same id exists */ |
1284 | if (coredev == NULL) { | 1284 | if (coredev == NULL) { |
1285 | sms_err("Got NULL coredev"); | 1285 | sms_err("Got NULL coredev"); |
1286 | return -EINVAL; | 1286 | return -EINVAL; |
1287 | } | 1287 | } |
1288 | 1288 | ||
1289 | rc = smscore_validate_client(client->coredev, client, 0, | 1289 | rc = smscore_validate_client(client->coredev, client, 0, |
1290 | phdr->msgSrcId); | 1290 | phdr->msgSrcId); |
1291 | if (rc < 0) | 1291 | if (rc < 0) |
1292 | return rc; | 1292 | return rc; |
1293 | 1293 | ||
1294 | return coredev->sendrequest_handler(coredev->context, buffer, size); | 1294 | return coredev->sendrequest_handler(coredev->context, buffer, size); |
1295 | } | 1295 | } |
1296 | EXPORT_SYMBOL_GPL(smsclient_sendrequest); | 1296 | EXPORT_SYMBOL_GPL(smsclient_sendrequest); |
1297 | 1297 | ||
1298 | 1298 | ||
1299 | /* old GPIO managments implementation */ | 1299 | /* old GPIO managments implementation */ |
1300 | int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, | 1300 | int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, |
1301 | struct smscore_config_gpio *pinconfig) | 1301 | struct smscore_config_gpio *pinconfig) |
1302 | { | 1302 | { |
1303 | struct { | 1303 | struct { |
1304 | struct SmsMsgHdr_ST hdr; | 1304 | struct SmsMsgHdr_ST hdr; |
1305 | u32 data[6]; | 1305 | u32 data[6]; |
1306 | } msg; | 1306 | } msg; |
1307 | 1307 | ||
1308 | if (coredev->device_flags & SMS_DEVICE_FAMILY2) { | 1308 | if (coredev->device_flags & SMS_DEVICE_FAMILY2) { |
1309 | msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; | 1309 | msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; |
1310 | msg.hdr.msgDstId = HIF_TASK; | 1310 | msg.hdr.msgDstId = HIF_TASK; |
1311 | msg.hdr.msgFlags = 0; | 1311 | msg.hdr.msgFlags = 0; |
1312 | msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; | 1312 | msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; |
1313 | msg.hdr.msgLength = sizeof(msg); | 1313 | msg.hdr.msgLength = sizeof(msg); |
1314 | 1314 | ||
1315 | msg.data[0] = pin; | 1315 | msg.data[0] = pin; |
1316 | msg.data[1] = pinconfig->pullupdown; | 1316 | msg.data[1] = pinconfig->pullupdown; |
1317 | 1317 | ||
1318 | /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */ | 1318 | /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */ |
1319 | msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0; | 1319 | msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0; |
1320 | 1320 | ||
1321 | switch (pinconfig->outputdriving) { | 1321 | switch (pinconfig->outputdriving) { |
1322 | case SMS_GPIO_OUTPUTDRIVING_16mA: | 1322 | case SMS_GPIO_OUTPUTDRIVING_16mA: |
1323 | msg.data[3] = 7; /* Nova - 16mA */ | 1323 | msg.data[3] = 7; /* Nova - 16mA */ |
1324 | break; | 1324 | break; |
1325 | case SMS_GPIO_OUTPUTDRIVING_12mA: | 1325 | case SMS_GPIO_OUTPUTDRIVING_12mA: |
1326 | msg.data[3] = 5; /* Nova - 11mA */ | 1326 | msg.data[3] = 5; /* Nova - 11mA */ |
1327 | break; | 1327 | break; |
1328 | case SMS_GPIO_OUTPUTDRIVING_8mA: | 1328 | case SMS_GPIO_OUTPUTDRIVING_8mA: |
1329 | msg.data[3] = 3; /* Nova - 7mA */ | 1329 | msg.data[3] = 3; /* Nova - 7mA */ |
1330 | break; | 1330 | break; |
1331 | case SMS_GPIO_OUTPUTDRIVING_4mA: | 1331 | case SMS_GPIO_OUTPUTDRIVING_4mA: |
1332 | default: | 1332 | default: |
1333 | msg.data[3] = 2; /* Nova - 4mA */ | 1333 | msg.data[3] = 2; /* Nova - 4mA */ |
1334 | break; | 1334 | break; |
1335 | } | 1335 | } |
1336 | 1336 | ||
1337 | msg.data[4] = pinconfig->direction; | 1337 | msg.data[4] = pinconfig->direction; |
1338 | msg.data[5] = 0; | 1338 | msg.data[5] = 0; |
1339 | } else /* TODO: SMS_DEVICE_FAMILY1 */ | 1339 | } else /* TODO: SMS_DEVICE_FAMILY1 */ |
1340 | return -EINVAL; | 1340 | return -EINVAL; |
1341 | 1341 | ||
1342 | return coredev->sendrequest_handler(coredev->context, | 1342 | return coredev->sendrequest_handler(coredev->context, |
1343 | &msg, sizeof(msg)); | 1343 | &msg, sizeof(msg)); |
1344 | } | 1344 | } |
1345 | 1345 | ||
1346 | int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level) | 1346 | int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level) |
1347 | { | 1347 | { |
1348 | struct { | 1348 | struct { |
1349 | struct SmsMsgHdr_ST hdr; | 1349 | struct SmsMsgHdr_ST hdr; |
1350 | u32 data[3]; | 1350 | u32 data[3]; |
1351 | } msg; | 1351 | } msg; |
1352 | 1352 | ||
1353 | if (pin > MAX_GPIO_PIN_NUMBER) | 1353 | if (pin > MAX_GPIO_PIN_NUMBER) |
1354 | return -EINVAL; | 1354 | return -EINVAL; |
1355 | 1355 | ||
1356 | msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; | 1356 | msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; |
1357 | msg.hdr.msgDstId = HIF_TASK; | 1357 | msg.hdr.msgDstId = HIF_TASK; |
1358 | msg.hdr.msgFlags = 0; | 1358 | msg.hdr.msgFlags = 0; |
1359 | msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; | 1359 | msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; |
1360 | msg.hdr.msgLength = sizeof(msg); | 1360 | msg.hdr.msgLength = sizeof(msg); |
1361 | 1361 | ||
1362 | msg.data[0] = pin; | 1362 | msg.data[0] = pin; |
1363 | msg.data[1] = level ? 1 : 0; | 1363 | msg.data[1] = level ? 1 : 0; |
1364 | msg.data[2] = 0; | 1364 | msg.data[2] = 0; |
1365 | 1365 | ||
1366 | return coredev->sendrequest_handler(coredev->context, | 1366 | return coredev->sendrequest_handler(coredev->context, |
1367 | &msg, sizeof(msg)); | 1367 | &msg, sizeof(msg)); |
1368 | } | 1368 | } |
1369 | 1369 | ||
1370 | /* new GPIO managment implementation */ | 1370 | /* new GPIO management implementation */ |
1371 | static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum, | 1371 | static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum, |
1372 | u32 *pGroupNum, u32 *pGroupCfg) { | 1372 | u32 *pGroupNum, u32 *pGroupCfg) { |
1373 | 1373 | ||
1374 | *pGroupCfg = 1; | 1374 | *pGroupCfg = 1; |
1375 | 1375 | ||
1376 | if (PinNum >= 0 && PinNum <= 1) { | 1376 | if (PinNum >= 0 && PinNum <= 1) { |
1377 | *pTranslatedPinNum = 0; | 1377 | *pTranslatedPinNum = 0; |
1378 | *pGroupNum = 9; | 1378 | *pGroupNum = 9; |
1379 | *pGroupCfg = 2; | 1379 | *pGroupCfg = 2; |
1380 | } else if (PinNum >= 2 && PinNum <= 6) { | 1380 | } else if (PinNum >= 2 && PinNum <= 6) { |
1381 | *pTranslatedPinNum = 2; | 1381 | *pTranslatedPinNum = 2; |
1382 | *pGroupNum = 0; | 1382 | *pGroupNum = 0; |
1383 | *pGroupCfg = 2; | 1383 | *pGroupCfg = 2; |
1384 | } else if (PinNum >= 7 && PinNum <= 11) { | 1384 | } else if (PinNum >= 7 && PinNum <= 11) { |
1385 | *pTranslatedPinNum = 7; | 1385 | *pTranslatedPinNum = 7; |
1386 | *pGroupNum = 1; | 1386 | *pGroupNum = 1; |
1387 | } else if (PinNum >= 12 && PinNum <= 15) { | 1387 | } else if (PinNum >= 12 && PinNum <= 15) { |
1388 | *pTranslatedPinNum = 12; | 1388 | *pTranslatedPinNum = 12; |
1389 | *pGroupNum = 2; | 1389 | *pGroupNum = 2; |
1390 | *pGroupCfg = 3; | 1390 | *pGroupCfg = 3; |
1391 | } else if (PinNum == 16) { | 1391 | } else if (PinNum == 16) { |
1392 | *pTranslatedPinNum = 16; | 1392 | *pTranslatedPinNum = 16; |
1393 | *pGroupNum = 23; | 1393 | *pGroupNum = 23; |
1394 | } else if (PinNum >= 17 && PinNum <= 24) { | 1394 | } else if (PinNum >= 17 && PinNum <= 24) { |
1395 | *pTranslatedPinNum = 17; | 1395 | *pTranslatedPinNum = 17; |
1396 | *pGroupNum = 3; | 1396 | *pGroupNum = 3; |
1397 | } else if (PinNum == 25) { | 1397 | } else if (PinNum == 25) { |
1398 | *pTranslatedPinNum = 25; | 1398 | *pTranslatedPinNum = 25; |
1399 | *pGroupNum = 6; | 1399 | *pGroupNum = 6; |
1400 | } else if (PinNum >= 26 && PinNum <= 28) { | 1400 | } else if (PinNum >= 26 && PinNum <= 28) { |
1401 | *pTranslatedPinNum = 26; | 1401 | *pTranslatedPinNum = 26; |
1402 | *pGroupNum = 4; | 1402 | *pGroupNum = 4; |
1403 | } else if (PinNum == 29) { | 1403 | } else if (PinNum == 29) { |
1404 | *pTranslatedPinNum = 29; | 1404 | *pTranslatedPinNum = 29; |
1405 | *pGroupNum = 5; | 1405 | *pGroupNum = 5; |
1406 | *pGroupCfg = 2; | 1406 | *pGroupCfg = 2; |
1407 | } else if (PinNum == 30) { | 1407 | } else if (PinNum == 30) { |
1408 | *pTranslatedPinNum = 30; | 1408 | *pTranslatedPinNum = 30; |
1409 | *pGroupNum = 8; | 1409 | *pGroupNum = 8; |
1410 | } else if (PinNum == 31) { | 1410 | } else if (PinNum == 31) { |
1411 | *pTranslatedPinNum = 31; | 1411 | *pTranslatedPinNum = 31; |
1412 | *pGroupNum = 17; | 1412 | *pGroupNum = 17; |
1413 | } else | 1413 | } else |
1414 | return -1; | 1414 | return -1; |
1415 | 1415 | ||
1416 | *pGroupCfg <<= 24; | 1416 | *pGroupCfg <<= 24; |
1417 | 1417 | ||
1418 | return 0; | 1418 | return 0; |
1419 | } | 1419 | } |
1420 | 1420 | ||
1421 | int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, | 1421 | int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, |
1422 | struct smscore_gpio_config *pGpioConfig) { | 1422 | struct smscore_gpio_config *pGpioConfig) { |
1423 | 1423 | ||
1424 | u32 totalLen; | 1424 | u32 totalLen; |
1425 | u32 TranslatedPinNum = 0; | 1425 | u32 TranslatedPinNum = 0; |
1426 | u32 GroupNum = 0; | 1426 | u32 GroupNum = 0; |
1427 | u32 ElectricChar; | 1427 | u32 ElectricChar; |
1428 | u32 groupCfg; | 1428 | u32 groupCfg; |
1429 | void *buffer; | 1429 | void *buffer; |
1430 | int rc; | 1430 | int rc; |
1431 | 1431 | ||
1432 | struct SetGpioMsg { | 1432 | struct SetGpioMsg { |
1433 | struct SmsMsgHdr_ST xMsgHeader; | 1433 | struct SmsMsgHdr_ST xMsgHeader; |
1434 | u32 msgData[6]; | 1434 | u32 msgData[6]; |
1435 | } *pMsg; | 1435 | } *pMsg; |
1436 | 1436 | ||
1437 | 1437 | ||
1438 | if (PinNum > MAX_GPIO_PIN_NUMBER) | 1438 | if (PinNum > MAX_GPIO_PIN_NUMBER) |
1439 | return -EINVAL; | 1439 | return -EINVAL; |
1440 | 1440 | ||
1441 | if (pGpioConfig == NULL) | 1441 | if (pGpioConfig == NULL) |
1442 | return -EINVAL; | 1442 | return -EINVAL; |
1443 | 1443 | ||
1444 | totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6); | 1444 | totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6); |
1445 | 1445 | ||
1446 | buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, | 1446 | buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, |
1447 | GFP_KERNEL | GFP_DMA); | 1447 | GFP_KERNEL | GFP_DMA); |
1448 | if (!buffer) | 1448 | if (!buffer) |
1449 | return -ENOMEM; | 1449 | return -ENOMEM; |
1450 | 1450 | ||
1451 | pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); | 1451 | pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); |
1452 | 1452 | ||
1453 | pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; | 1453 | pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; |
1454 | pMsg->xMsgHeader.msgDstId = HIF_TASK; | 1454 | pMsg->xMsgHeader.msgDstId = HIF_TASK; |
1455 | pMsg->xMsgHeader.msgFlags = 0; | 1455 | pMsg->xMsgHeader.msgFlags = 0; |
1456 | pMsg->xMsgHeader.msgLength = (u16) totalLen; | 1456 | pMsg->xMsgHeader.msgLength = (u16) totalLen; |
1457 | pMsg->msgData[0] = PinNum; | 1457 | pMsg->msgData[0] = PinNum; |
1458 | 1458 | ||
1459 | if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) { | 1459 | if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) { |
1460 | pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ; | 1460 | pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ; |
1461 | if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum, | 1461 | if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum, |
1462 | &groupCfg) != 0) | 1462 | &groupCfg) != 0) |
1463 | return -EINVAL; | 1463 | return -EINVAL; |
1464 | 1464 | ||
1465 | pMsg->msgData[1] = TranslatedPinNum; | 1465 | pMsg->msgData[1] = TranslatedPinNum; |
1466 | pMsg->msgData[2] = GroupNum; | 1466 | pMsg->msgData[2] = GroupNum; |
1467 | ElectricChar = (pGpioConfig->PullUpDown) | 1467 | ElectricChar = (pGpioConfig->PullUpDown) |
1468 | | (pGpioConfig->InputCharacteristics << 2) | 1468 | | (pGpioConfig->InputCharacteristics << 2) |
1469 | | (pGpioConfig->OutputSlewRate << 3) | 1469 | | (pGpioConfig->OutputSlewRate << 3) |
1470 | | (pGpioConfig->OutputDriving << 4); | 1470 | | (pGpioConfig->OutputDriving << 4); |
1471 | pMsg->msgData[3] = ElectricChar; | 1471 | pMsg->msgData[3] = ElectricChar; |
1472 | pMsg->msgData[4] = pGpioConfig->Direction; | 1472 | pMsg->msgData[4] = pGpioConfig->Direction; |
1473 | pMsg->msgData[5] = groupCfg; | 1473 | pMsg->msgData[5] = groupCfg; |
1474 | } else { | 1474 | } else { |
1475 | pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; | 1475 | pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; |
1476 | pMsg->msgData[1] = pGpioConfig->PullUpDown; | 1476 | pMsg->msgData[1] = pGpioConfig->PullUpDown; |
1477 | pMsg->msgData[2] = pGpioConfig->OutputSlewRate; | 1477 | pMsg->msgData[2] = pGpioConfig->OutputSlewRate; |
1478 | pMsg->msgData[3] = pGpioConfig->OutputDriving; | 1478 | pMsg->msgData[3] = pGpioConfig->OutputDriving; |
1479 | pMsg->msgData[4] = pGpioConfig->Direction; | 1479 | pMsg->msgData[4] = pGpioConfig->Direction; |
1480 | pMsg->msgData[5] = 0; | 1480 | pMsg->msgData[5] = 0; |
1481 | } | 1481 | } |
1482 | 1482 | ||
1483 | smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); | 1483 | smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); |
1484 | rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, | 1484 | rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, |
1485 | &coredev->gpio_configuration_done); | 1485 | &coredev->gpio_configuration_done); |
1486 | 1486 | ||
1487 | if (rc != 0) { | 1487 | if (rc != 0) { |
1488 | if (rc == -ETIME) | 1488 | if (rc == -ETIME) |
1489 | sms_err("smscore_gpio_configure timeout"); | 1489 | sms_err("smscore_gpio_configure timeout"); |
1490 | else | 1490 | else |
1491 | sms_err("smscore_gpio_configure error"); | 1491 | sms_err("smscore_gpio_configure error"); |
1492 | } | 1492 | } |
1493 | kfree(buffer); | 1493 | kfree(buffer); |
1494 | 1494 | ||
1495 | return rc; | 1495 | return rc; |
1496 | } | 1496 | } |
1497 | 1497 | ||
1498 | int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, | 1498 | int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, |
1499 | u8 NewLevel) { | 1499 | u8 NewLevel) { |
1500 | 1500 | ||
1501 | u32 totalLen; | 1501 | u32 totalLen; |
1502 | int rc; | 1502 | int rc; |
1503 | void *buffer; | 1503 | void *buffer; |
1504 | 1504 | ||
1505 | struct SetGpioMsg { | 1505 | struct SetGpioMsg { |
1506 | struct SmsMsgHdr_ST xMsgHeader; | 1506 | struct SmsMsgHdr_ST xMsgHeader; |
1507 | u32 msgData[3]; /* keep it 3 ! */ | 1507 | u32 msgData[3]; /* keep it 3 ! */ |
1508 | } *pMsg; | 1508 | } *pMsg; |
1509 | 1509 | ||
1510 | if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER) || | 1510 | if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER) || |
1511 | (PinNum > MAX_GPIO_PIN_NUMBER)) | 1511 | (PinNum > MAX_GPIO_PIN_NUMBER)) |
1512 | return -EINVAL; | 1512 | return -EINVAL; |
1513 | 1513 | ||
1514 | totalLen = sizeof(struct SmsMsgHdr_ST) + | 1514 | totalLen = sizeof(struct SmsMsgHdr_ST) + |
1515 | (3 * sizeof(u32)); /* keep it 3 ! */ | 1515 | (3 * sizeof(u32)); /* keep it 3 ! */ |
1516 | 1516 | ||
1517 | buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, | 1517 | buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, |
1518 | GFP_KERNEL | GFP_DMA); | 1518 | GFP_KERNEL | GFP_DMA); |
1519 | if (!buffer) | 1519 | if (!buffer) |
1520 | return -ENOMEM; | 1520 | return -ENOMEM; |
1521 | 1521 | ||
1522 | pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); | 1522 | pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); |
1523 | 1523 | ||
1524 | pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; | 1524 | pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; |
1525 | pMsg->xMsgHeader.msgDstId = HIF_TASK; | 1525 | pMsg->xMsgHeader.msgDstId = HIF_TASK; |
1526 | pMsg->xMsgHeader.msgFlags = 0; | 1526 | pMsg->xMsgHeader.msgFlags = 0; |
1527 | pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; | 1527 | pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; |
1528 | pMsg->xMsgHeader.msgLength = (u16) totalLen; | 1528 | pMsg->xMsgHeader.msgLength = (u16) totalLen; |
1529 | pMsg->msgData[0] = PinNum; | 1529 | pMsg->msgData[0] = PinNum; |
1530 | pMsg->msgData[1] = NewLevel; | 1530 | pMsg->msgData[1] = NewLevel; |
1531 | 1531 | ||
1532 | /* Send message to SMS */ | 1532 | /* Send message to SMS */ |
1533 | smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); | 1533 | smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); |
1534 | rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, | 1534 | rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, |
1535 | &coredev->gpio_set_level_done); | 1535 | &coredev->gpio_set_level_done); |
1536 | 1536 | ||
1537 | if (rc != 0) { | 1537 | if (rc != 0) { |
1538 | if (rc == -ETIME) | 1538 | if (rc == -ETIME) |
1539 | sms_err("smscore_gpio_set_level timeout"); | 1539 | sms_err("smscore_gpio_set_level timeout"); |
1540 | else | 1540 | else |
1541 | sms_err("smscore_gpio_set_level error"); | 1541 | sms_err("smscore_gpio_set_level error"); |
1542 | } | 1542 | } |
1543 | kfree(buffer); | 1543 | kfree(buffer); |
1544 | 1544 | ||
1545 | return rc; | 1545 | return rc; |
1546 | } | 1546 | } |
1547 | 1547 | ||
1548 | int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, | 1548 | int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, |
1549 | u8 *level) { | 1549 | u8 *level) { |
1550 | 1550 | ||
1551 | u32 totalLen; | 1551 | u32 totalLen; |
1552 | int rc; | 1552 | int rc; |
1553 | void *buffer; | 1553 | void *buffer; |
1554 | 1554 | ||
1555 | struct SetGpioMsg { | 1555 | struct SetGpioMsg { |
1556 | struct SmsMsgHdr_ST xMsgHeader; | 1556 | struct SmsMsgHdr_ST xMsgHeader; |
1557 | u32 msgData[2]; | 1557 | u32 msgData[2]; |
1558 | } *pMsg; | 1558 | } *pMsg; |
1559 | 1559 | ||
1560 | 1560 | ||
1561 | if (PinNum > MAX_GPIO_PIN_NUMBER) | 1561 | if (PinNum > MAX_GPIO_PIN_NUMBER) |
1562 | return -EINVAL; | 1562 | return -EINVAL; |
1563 | 1563 | ||
1564 | totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32)); | 1564 | totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32)); |
1565 | 1565 | ||
1566 | buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, | 1566 | buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, |
1567 | GFP_KERNEL | GFP_DMA); | 1567 | GFP_KERNEL | GFP_DMA); |
1568 | if (!buffer) | 1568 | if (!buffer) |
1569 | return -ENOMEM; | 1569 | return -ENOMEM; |
1570 | 1570 | ||
1571 | pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); | 1571 | pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); |
1572 | 1572 | ||
1573 | pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; | 1573 | pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; |
1574 | pMsg->xMsgHeader.msgDstId = HIF_TASK; | 1574 | pMsg->xMsgHeader.msgDstId = HIF_TASK; |
1575 | pMsg->xMsgHeader.msgFlags = 0; | 1575 | pMsg->xMsgHeader.msgFlags = 0; |
1576 | pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ; | 1576 | pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ; |
1577 | pMsg->xMsgHeader.msgLength = (u16) totalLen; | 1577 | pMsg->xMsgHeader.msgLength = (u16) totalLen; |
1578 | pMsg->msgData[0] = PinNum; | 1578 | pMsg->msgData[0] = PinNum; |
1579 | pMsg->msgData[1] = 0; | 1579 | pMsg->msgData[1] = 0; |
1580 | 1580 | ||
1581 | /* Send message to SMS */ | 1581 | /* Send message to SMS */ |
1582 | smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); | 1582 | smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); |
1583 | rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, | 1583 | rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, |
1584 | &coredev->gpio_get_level_done); | 1584 | &coredev->gpio_get_level_done); |
1585 | 1585 | ||
1586 | if (rc != 0) { | 1586 | if (rc != 0) { |
1587 | if (rc == -ETIME) | 1587 | if (rc == -ETIME) |
1588 | sms_err("smscore_gpio_get_level timeout"); | 1588 | sms_err("smscore_gpio_get_level timeout"); |
1589 | else | 1589 | else |
1590 | sms_err("smscore_gpio_get_level error"); | 1590 | sms_err("smscore_gpio_get_level error"); |
1591 | } | 1591 | } |
1592 | kfree(buffer); | 1592 | kfree(buffer); |
1593 | 1593 | ||
1594 | /* Its a race between other gpio_get_level() and the copy of the single | 1594 | /* Its a race between other gpio_get_level() and the copy of the single |
1595 | * global 'coredev->gpio_get_res' to the function's variable 'level' | 1595 | * global 'coredev->gpio_get_res' to the function's variable 'level' |
1596 | */ | 1596 | */ |
1597 | *level = coredev->gpio_get_res; | 1597 | *level = coredev->gpio_get_res; |
1598 | 1598 | ||
1599 | return rc; | 1599 | return rc; |
1600 | } | 1600 | } |
1601 | 1601 | ||
1602 | static int __init smscore_module_init(void) | 1602 | static int __init smscore_module_init(void) |
1603 | { | 1603 | { |
1604 | int rc = 0; | 1604 | int rc = 0; |
1605 | 1605 | ||
1606 | INIT_LIST_HEAD(&g_smscore_notifyees); | 1606 | INIT_LIST_HEAD(&g_smscore_notifyees); |
1607 | INIT_LIST_HEAD(&g_smscore_devices); | 1607 | INIT_LIST_HEAD(&g_smscore_devices); |
1608 | kmutex_init(&g_smscore_deviceslock); | 1608 | kmutex_init(&g_smscore_deviceslock); |
1609 | 1609 | ||
1610 | INIT_LIST_HEAD(&g_smscore_registry); | 1610 | INIT_LIST_HEAD(&g_smscore_registry); |
1611 | kmutex_init(&g_smscore_registrylock); | 1611 | kmutex_init(&g_smscore_registrylock); |
1612 | 1612 | ||
1613 | return rc; | 1613 | return rc; |
1614 | } | 1614 | } |
1615 | 1615 | ||
1616 | static void __exit smscore_module_exit(void) | 1616 | static void __exit smscore_module_exit(void) |
1617 | { | 1617 | { |
1618 | kmutex_lock(&g_smscore_deviceslock); | 1618 | kmutex_lock(&g_smscore_deviceslock); |
1619 | while (!list_empty(&g_smscore_notifyees)) { | 1619 | while (!list_empty(&g_smscore_notifyees)) { |
1620 | struct smscore_device_notifyee_t *notifyee = | 1620 | struct smscore_device_notifyee_t *notifyee = |
1621 | (struct smscore_device_notifyee_t *) | 1621 | (struct smscore_device_notifyee_t *) |
1622 | g_smscore_notifyees.next; | 1622 | g_smscore_notifyees.next; |
1623 | 1623 | ||
1624 | list_del(¬ifyee->entry); | 1624 | list_del(¬ifyee->entry); |
1625 | kfree(notifyee); | 1625 | kfree(notifyee); |
1626 | } | 1626 | } |
1627 | kmutex_unlock(&g_smscore_deviceslock); | 1627 | kmutex_unlock(&g_smscore_deviceslock); |
1628 | 1628 | ||
1629 | kmutex_lock(&g_smscore_registrylock); | 1629 | kmutex_lock(&g_smscore_registrylock); |
1630 | while (!list_empty(&g_smscore_registry)) { | 1630 | while (!list_empty(&g_smscore_registry)) { |
1631 | struct smscore_registry_entry_t *entry = | 1631 | struct smscore_registry_entry_t *entry = |
1632 | (struct smscore_registry_entry_t *) | 1632 | (struct smscore_registry_entry_t *) |
1633 | g_smscore_registry.next; | 1633 | g_smscore_registry.next; |
1634 | 1634 | ||
1635 | list_del(&entry->entry); | 1635 | list_del(&entry->entry); |
1636 | kfree(entry); | 1636 | kfree(entry); |
1637 | } | 1637 | } |
1638 | kmutex_unlock(&g_smscore_registrylock); | 1638 | kmutex_unlock(&g_smscore_registrylock); |
1639 | 1639 | ||
1640 | sms_debug(""); | 1640 | sms_debug(""); |
1641 | } | 1641 | } |
1642 | 1642 | ||
1643 | module_init(smscore_module_init); | 1643 | module_init(smscore_module_init); |
1644 | module_exit(smscore_module_exit); | 1644 | module_exit(smscore_module_exit); |
1645 | 1645 | ||
1646 | MODULE_DESCRIPTION("Siano MDTV Core module"); | 1646 | MODULE_DESCRIPTION("Siano MDTV Core module"); |
1647 | MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); | 1647 | MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); |
1648 | MODULE_LICENSE("GPL"); | 1648 | MODULE_LICENSE("GPL"); |
1649 | 1649 |
drivers/media/dvb/siano/smscoreapi.h
1 | /**************************************************************** | 1 | /**************************************************************** |
2 | 2 | ||
3 | Siano Mobile Silicon, Inc. | 3 | Siano Mobile Silicon, Inc. |
4 | MDTV receiver kernel modules. | 4 | MDTV receiver kernel modules. |
5 | Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat | 5 | Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat |
6 | 6 | ||
7 | This program is free software: you can redistribute it and/or modify | 7 | This program is free software: you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by | 8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation, either version 2 of the License, or | 9 | the Free Software Foundation, either version 2 of the License, or |
10 | (at your option) any later version. | 10 | (at your option) any later version. |
11 | 11 | ||
12 | This program is distributed in the hope that it will be useful, | 12 | This program is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. | 15 | GNU General Public License for more details. |
16 | 16 | ||
17 | You should have received a copy of the GNU General Public License | 17 | You should have received a copy of the GNU General Public License |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 | ||
20 | ****************************************************************/ | 20 | ****************************************************************/ |
21 | 21 | ||
22 | #ifndef __SMS_CORE_API_H__ | 22 | #ifndef __SMS_CORE_API_H__ |
23 | #define __SMS_CORE_API_H__ | 23 | #define __SMS_CORE_API_H__ |
24 | 24 | ||
25 | #include <linux/version.h> | 25 | #include <linux/version.h> |
26 | #include <linux/device.h> | 26 | #include <linux/device.h> |
27 | #include <linux/list.h> | 27 | #include <linux/list.h> |
28 | #include <linux/mm.h> | 28 | #include <linux/mm.h> |
29 | #include <linux/scatterlist.h> | 29 | #include <linux/scatterlist.h> |
30 | #include <linux/types.h> | 30 | #include <linux/types.h> |
31 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
32 | #include <linux/wait.h> | 32 | #include <linux/wait.h> |
33 | #include <linux/timer.h> | 33 | #include <linux/timer.h> |
34 | 34 | ||
35 | #include <asm/page.h> | 35 | #include <asm/page.h> |
36 | 36 | ||
37 | #include "smsir.h" | 37 | #include "smsir.h" |
38 | 38 | ||
39 | #define kmutex_init(_p_) mutex_init(_p_) | 39 | #define kmutex_init(_p_) mutex_init(_p_) |
40 | #define kmutex_lock(_p_) mutex_lock(_p_) | 40 | #define kmutex_lock(_p_) mutex_lock(_p_) |
41 | #define kmutex_trylock(_p_) mutex_trylock(_p_) | 41 | #define kmutex_trylock(_p_) mutex_trylock(_p_) |
42 | #define kmutex_unlock(_p_) mutex_unlock(_p_) | 42 | #define kmutex_unlock(_p_) mutex_unlock(_p_) |
43 | 43 | ||
44 | #ifndef min | 44 | #ifndef min |
45 | #define min(a, b) (((a) < (b)) ? (a) : (b)) | 45 | #define min(a, b) (((a) < (b)) ? (a) : (b)) |
46 | #endif | 46 | #endif |
47 | 47 | ||
48 | #define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS (10000) | 48 | #define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS (10000) |
49 | #define SMS_ALLOC_ALIGNMENT 128 | 49 | #define SMS_ALLOC_ALIGNMENT 128 |
50 | #define SMS_DMA_ALIGNMENT 16 | 50 | #define SMS_DMA_ALIGNMENT 16 |
51 | #define SMS_ALIGN_ADDRESS(addr) \ | 51 | #define SMS_ALIGN_ADDRESS(addr) \ |
52 | ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1)) | 52 | ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1)) |
53 | 53 | ||
54 | #define SMS_DEVICE_FAMILY2 1 | 54 | #define SMS_DEVICE_FAMILY2 1 |
55 | #define SMS_ROM_NO_RESPONSE 2 | 55 | #define SMS_ROM_NO_RESPONSE 2 |
56 | #define SMS_DEVICE_NOT_READY 0x8000000 | 56 | #define SMS_DEVICE_NOT_READY 0x8000000 |
57 | 57 | ||
58 | enum sms_device_type_st { | 58 | enum sms_device_type_st { |
59 | SMS_STELLAR = 0, | 59 | SMS_STELLAR = 0, |
60 | SMS_NOVA_A0, | 60 | SMS_NOVA_A0, |
61 | SMS_NOVA_B0, | 61 | SMS_NOVA_B0, |
62 | SMS_VEGA, | 62 | SMS_VEGA, |
63 | SMS_NUM_OF_DEVICE_TYPES | 63 | SMS_NUM_OF_DEVICE_TYPES |
64 | }; | 64 | }; |
65 | 65 | ||
66 | struct smscore_device_t; | 66 | struct smscore_device_t; |
67 | struct smscore_client_t; | 67 | struct smscore_client_t; |
68 | struct smscore_buffer_t; | 68 | struct smscore_buffer_t; |
69 | 69 | ||
70 | typedef int (*hotplug_t)(struct smscore_device_t *coredev, | 70 | typedef int (*hotplug_t)(struct smscore_device_t *coredev, |
71 | struct device *device, int arrival); | 71 | struct device *device, int arrival); |
72 | 72 | ||
73 | typedef int (*setmode_t)(void *context, int mode); | 73 | typedef int (*setmode_t)(void *context, int mode); |
74 | typedef void (*detectmode_t)(void *context, int *mode); | 74 | typedef void (*detectmode_t)(void *context, int *mode); |
75 | typedef int (*sendrequest_t)(void *context, void *buffer, size_t size); | 75 | typedef int (*sendrequest_t)(void *context, void *buffer, size_t size); |
76 | typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size); | 76 | typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size); |
77 | typedef int (*preload_t)(void *context); | 77 | typedef int (*preload_t)(void *context); |
78 | typedef int (*postload_t)(void *context); | 78 | typedef int (*postload_t)(void *context); |
79 | 79 | ||
80 | typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb); | 80 | typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb); |
81 | typedef void (*onremove_t)(void *context); | 81 | typedef void (*onremove_t)(void *context); |
82 | 82 | ||
83 | struct smscore_buffer_t { | 83 | struct smscore_buffer_t { |
84 | /* public members, once passed to clients can be changed freely */ | 84 | /* public members, once passed to clients can be changed freely */ |
85 | struct list_head entry; | 85 | struct list_head entry; |
86 | int size; | 86 | int size; |
87 | int offset; | 87 | int offset; |
88 | 88 | ||
89 | /* private members, read-only for clients */ | 89 | /* private members, read-only for clients */ |
90 | void *p; | 90 | void *p; |
91 | dma_addr_t phys; | 91 | dma_addr_t phys; |
92 | unsigned long offset_in_common; | 92 | unsigned long offset_in_common; |
93 | }; | 93 | }; |
94 | 94 | ||
95 | struct smsdevice_params_t { | 95 | struct smsdevice_params_t { |
96 | struct device *device; | 96 | struct device *device; |
97 | 97 | ||
98 | int buffer_size; | 98 | int buffer_size; |
99 | int num_buffers; | 99 | int num_buffers; |
100 | 100 | ||
101 | char devpath[32]; | 101 | char devpath[32]; |
102 | unsigned long flags; | 102 | unsigned long flags; |
103 | 103 | ||
104 | setmode_t setmode_handler; | 104 | setmode_t setmode_handler; |
105 | detectmode_t detectmode_handler; | 105 | detectmode_t detectmode_handler; |
106 | sendrequest_t sendrequest_handler; | 106 | sendrequest_t sendrequest_handler; |
107 | preload_t preload_handler; | 107 | preload_t preload_handler; |
108 | postload_t postload_handler; | 108 | postload_t postload_handler; |
109 | 109 | ||
110 | void *context; | 110 | void *context; |
111 | enum sms_device_type_st device_type; | 111 | enum sms_device_type_st device_type; |
112 | }; | 112 | }; |
113 | 113 | ||
114 | struct smsclient_params_t { | 114 | struct smsclient_params_t { |
115 | int initial_id; | 115 | int initial_id; |
116 | int data_type; | 116 | int data_type; |
117 | onresponse_t onresponse_handler; | 117 | onresponse_t onresponse_handler; |
118 | onremove_t onremove_handler; | 118 | onremove_t onremove_handler; |
119 | void *context; | 119 | void *context; |
120 | }; | 120 | }; |
121 | 121 | ||
122 | struct smscore_device_t { | 122 | struct smscore_device_t { |
123 | struct list_head entry; | 123 | struct list_head entry; |
124 | 124 | ||
125 | struct list_head clients; | 125 | struct list_head clients; |
126 | struct list_head subclients; | 126 | struct list_head subclients; |
127 | spinlock_t clientslock; | 127 | spinlock_t clientslock; |
128 | 128 | ||
129 | struct list_head buffers; | 129 | struct list_head buffers; |
130 | spinlock_t bufferslock; | 130 | spinlock_t bufferslock; |
131 | int num_buffers; | 131 | int num_buffers; |
132 | 132 | ||
133 | void *common_buffer; | 133 | void *common_buffer; |
134 | int common_buffer_size; | 134 | int common_buffer_size; |
135 | dma_addr_t common_buffer_phys; | 135 | dma_addr_t common_buffer_phys; |
136 | 136 | ||
137 | void *context; | 137 | void *context; |
138 | struct device *device; | 138 | struct device *device; |
139 | 139 | ||
140 | char devpath[32]; | 140 | char devpath[32]; |
141 | unsigned long device_flags; | 141 | unsigned long device_flags; |
142 | 142 | ||
143 | setmode_t setmode_handler; | 143 | setmode_t setmode_handler; |
144 | detectmode_t detectmode_handler; | 144 | detectmode_t detectmode_handler; |
145 | sendrequest_t sendrequest_handler; | 145 | sendrequest_t sendrequest_handler; |
146 | preload_t preload_handler; | 146 | preload_t preload_handler; |
147 | postload_t postload_handler; | 147 | postload_t postload_handler; |
148 | 148 | ||
149 | int mode, modes_supported; | 149 | int mode, modes_supported; |
150 | 150 | ||
151 | /* host <--> device messages */ | 151 | /* host <--> device messages */ |
152 | struct completion version_ex_done, data_download_done, trigger_done; | 152 | struct completion version_ex_done, data_download_done, trigger_done; |
153 | struct completion init_device_done, reload_start_done, resume_done; | 153 | struct completion init_device_done, reload_start_done, resume_done; |
154 | struct completion gpio_configuration_done, gpio_set_level_done; | 154 | struct completion gpio_configuration_done, gpio_set_level_done; |
155 | struct completion gpio_get_level_done, ir_init_done; | 155 | struct completion gpio_get_level_done, ir_init_done; |
156 | 156 | ||
157 | /* Buffer management */ | 157 | /* Buffer management */ |
158 | wait_queue_head_t buffer_mng_waitq; | 158 | wait_queue_head_t buffer_mng_waitq; |
159 | 159 | ||
160 | /* GPIO */ | 160 | /* GPIO */ |
161 | int gpio_get_res; | 161 | int gpio_get_res; |
162 | 162 | ||
163 | /* Target hardware board */ | 163 | /* Target hardware board */ |
164 | int board_id; | 164 | int board_id; |
165 | 165 | ||
166 | /* Firmware */ | 166 | /* Firmware */ |
167 | u8 *fw_buf; | 167 | u8 *fw_buf; |
168 | u32 fw_buf_size; | 168 | u32 fw_buf_size; |
169 | 169 | ||
170 | /* Infrared (IR) */ | 170 | /* Infrared (IR) */ |
171 | struct ir_t ir; | 171 | struct ir_t ir; |
172 | 172 | ||
173 | int led_state; | 173 | int led_state; |
174 | }; | 174 | }; |
175 | 175 | ||
176 | /* GPIO definitions for antenna frequency domain control (SMS8021) */ | 176 | /* GPIO definitions for antenna frequency domain control (SMS8021) */ |
177 | #define SMS_ANTENNA_GPIO_0 1 | 177 | #define SMS_ANTENNA_GPIO_0 1 |
178 | #define SMS_ANTENNA_GPIO_1 0 | 178 | #define SMS_ANTENNA_GPIO_1 0 |
179 | 179 | ||
180 | #define BW_8_MHZ 0 | 180 | #define BW_8_MHZ 0 |
181 | #define BW_7_MHZ 1 | 181 | #define BW_7_MHZ 1 |
182 | #define BW_6_MHZ 2 | 182 | #define BW_6_MHZ 2 |
183 | #define BW_5_MHZ 3 | 183 | #define BW_5_MHZ 3 |
184 | #define BW_ISDBT_1SEG 4 | 184 | #define BW_ISDBT_1SEG 4 |
185 | #define BW_ISDBT_3SEG 5 | 185 | #define BW_ISDBT_3SEG 5 |
186 | 186 | ||
187 | #define MSG_HDR_FLAG_SPLIT_MSG 4 | 187 | #define MSG_HDR_FLAG_SPLIT_MSG 4 |
188 | 188 | ||
189 | #define MAX_GPIO_PIN_NUMBER 31 | 189 | #define MAX_GPIO_PIN_NUMBER 31 |
190 | 190 | ||
191 | #define HIF_TASK 11 | 191 | #define HIF_TASK 11 |
192 | #define SMS_HOST_LIB 150 | 192 | #define SMS_HOST_LIB 150 |
193 | #define DVBT_BDA_CONTROL_MSG_ID 201 | 193 | #define DVBT_BDA_CONTROL_MSG_ID 201 |
194 | 194 | ||
195 | #define SMS_MAX_PAYLOAD_SIZE 240 | 195 | #define SMS_MAX_PAYLOAD_SIZE 240 |
196 | #define SMS_TUNE_TIMEOUT 500 | 196 | #define SMS_TUNE_TIMEOUT 500 |
197 | 197 | ||
198 | #define MSG_SMS_GPIO_CONFIG_REQ 507 | 198 | #define MSG_SMS_GPIO_CONFIG_REQ 507 |
199 | #define MSG_SMS_GPIO_CONFIG_RES 508 | 199 | #define MSG_SMS_GPIO_CONFIG_RES 508 |
200 | #define MSG_SMS_GPIO_SET_LEVEL_REQ 509 | 200 | #define MSG_SMS_GPIO_SET_LEVEL_REQ 509 |
201 | #define MSG_SMS_GPIO_SET_LEVEL_RES 510 | 201 | #define MSG_SMS_GPIO_SET_LEVEL_RES 510 |
202 | #define MSG_SMS_GPIO_GET_LEVEL_REQ 511 | 202 | #define MSG_SMS_GPIO_GET_LEVEL_REQ 511 |
203 | #define MSG_SMS_GPIO_GET_LEVEL_RES 512 | 203 | #define MSG_SMS_GPIO_GET_LEVEL_RES 512 |
204 | #define MSG_SMS_RF_TUNE_REQ 561 | 204 | #define MSG_SMS_RF_TUNE_REQ 561 |
205 | #define MSG_SMS_RF_TUNE_RES 562 | 205 | #define MSG_SMS_RF_TUNE_RES 562 |
206 | #define MSG_SMS_INIT_DEVICE_REQ 578 | 206 | #define MSG_SMS_INIT_DEVICE_REQ 578 |
207 | #define MSG_SMS_INIT_DEVICE_RES 579 | 207 | #define MSG_SMS_INIT_DEVICE_RES 579 |
208 | #define MSG_SMS_ADD_PID_FILTER_REQ 601 | 208 | #define MSG_SMS_ADD_PID_FILTER_REQ 601 |
209 | #define MSG_SMS_ADD_PID_FILTER_RES 602 | 209 | #define MSG_SMS_ADD_PID_FILTER_RES 602 |
210 | #define MSG_SMS_REMOVE_PID_FILTER_REQ 603 | 210 | #define MSG_SMS_REMOVE_PID_FILTER_REQ 603 |
211 | #define MSG_SMS_REMOVE_PID_FILTER_RES 604 | 211 | #define MSG_SMS_REMOVE_PID_FILTER_RES 604 |
212 | #define MSG_SMS_DAB_CHANNEL 607 | 212 | #define MSG_SMS_DAB_CHANNEL 607 |
213 | #define MSG_SMS_GET_PID_FILTER_LIST_REQ 608 | 213 | #define MSG_SMS_GET_PID_FILTER_LIST_REQ 608 |
214 | #define MSG_SMS_GET_PID_FILTER_LIST_RES 609 | 214 | #define MSG_SMS_GET_PID_FILTER_LIST_RES 609 |
215 | #define MSG_SMS_HO_PER_SLICES_IND 630 | 215 | #define MSG_SMS_HO_PER_SLICES_IND 630 |
216 | #define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651 | 216 | #define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651 |
217 | #define MSG_SMS_SET_ANTENNA_CONFIG_RES 652 | 217 | #define MSG_SMS_SET_ANTENNA_CONFIG_RES 652 |
218 | #define MSG_SMS_SLEEP_RESUME_COMP_IND 655 | 218 | #define MSG_SMS_SLEEP_RESUME_COMP_IND 655 |
219 | #define MSG_SMS_DATA_DOWNLOAD_REQ 660 | 219 | #define MSG_SMS_DATA_DOWNLOAD_REQ 660 |
220 | #define MSG_SMS_DATA_DOWNLOAD_RES 661 | 220 | #define MSG_SMS_DATA_DOWNLOAD_RES 661 |
221 | #define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664 | 221 | #define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664 |
222 | #define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665 | 222 | #define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665 |
223 | #define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666 | 223 | #define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666 |
224 | #define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667 | 224 | #define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667 |
225 | #define MSG_SMS_GET_VERSION_EX_REQ 668 | 225 | #define MSG_SMS_GET_VERSION_EX_REQ 668 |
226 | #define MSG_SMS_GET_VERSION_EX_RES 669 | 226 | #define MSG_SMS_GET_VERSION_EX_RES 669 |
227 | #define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670 | 227 | #define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670 |
228 | #define MSG_SMS_I2C_SET_FREQ_REQ 685 | 228 | #define MSG_SMS_I2C_SET_FREQ_REQ 685 |
229 | #define MSG_SMS_GENERIC_I2C_REQ 687 | 229 | #define MSG_SMS_GENERIC_I2C_REQ 687 |
230 | #define MSG_SMS_GENERIC_I2C_RES 688 | 230 | #define MSG_SMS_GENERIC_I2C_RES 688 |
231 | #define MSG_SMS_DVBT_BDA_DATA 693 | 231 | #define MSG_SMS_DVBT_BDA_DATA 693 |
232 | #define MSG_SW_RELOAD_REQ 697 | 232 | #define MSG_SW_RELOAD_REQ 697 |
233 | #define MSG_SMS_DATA_MSG 699 | 233 | #define MSG_SMS_DATA_MSG 699 |
234 | #define MSG_SW_RELOAD_START_REQ 702 | 234 | #define MSG_SW_RELOAD_START_REQ 702 |
235 | #define MSG_SW_RELOAD_START_RES 703 | 235 | #define MSG_SW_RELOAD_START_RES 703 |
236 | #define MSG_SW_RELOAD_EXEC_REQ 704 | 236 | #define MSG_SW_RELOAD_EXEC_REQ 704 |
237 | #define MSG_SW_RELOAD_EXEC_RES 705 | 237 | #define MSG_SW_RELOAD_EXEC_RES 705 |
238 | #define MSG_SMS_SPI_INT_LINE_SET_REQ 710 | 238 | #define MSG_SMS_SPI_INT_LINE_SET_REQ 710 |
239 | #define MSG_SMS_GPIO_CONFIG_EX_REQ 712 | 239 | #define MSG_SMS_GPIO_CONFIG_EX_REQ 712 |
240 | #define MSG_SMS_GPIO_CONFIG_EX_RES 713 | 240 | #define MSG_SMS_GPIO_CONFIG_EX_RES 713 |
241 | #define MSG_SMS_ISDBT_TUNE_REQ 776 | 241 | #define MSG_SMS_ISDBT_TUNE_REQ 776 |
242 | #define MSG_SMS_ISDBT_TUNE_RES 777 | 242 | #define MSG_SMS_ISDBT_TUNE_RES 777 |
243 | #define MSG_SMS_TRANSMISSION_IND 782 | 243 | #define MSG_SMS_TRANSMISSION_IND 782 |
244 | #define MSG_SMS_START_IR_REQ 800 | 244 | #define MSG_SMS_START_IR_REQ 800 |
245 | #define MSG_SMS_START_IR_RES 801 | 245 | #define MSG_SMS_START_IR_RES 801 |
246 | #define MSG_SMS_IR_SAMPLES_IND 802 | 246 | #define MSG_SMS_IR_SAMPLES_IND 802 |
247 | #define MSG_SMS_SIGNAL_DETECTED_IND 827 | 247 | #define MSG_SMS_SIGNAL_DETECTED_IND 827 |
248 | #define MSG_SMS_NO_SIGNAL_IND 828 | 248 | #define MSG_SMS_NO_SIGNAL_IND 828 |
249 | 249 | ||
250 | #define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \ | 250 | #define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \ |
251 | (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \ | 251 | (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \ |
252 | (ptr)->msgLength = len; (ptr)->msgFlags = 0; \ | 252 | (ptr)->msgLength = len; (ptr)->msgFlags = 0; \ |
253 | } while (0) | 253 | } while (0) |
254 | 254 | ||
255 | #define SMS_INIT_MSG(ptr, type, len) \ | 255 | #define SMS_INIT_MSG(ptr, type, len) \ |
256 | SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len) | 256 | SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len) |
257 | 257 | ||
258 | enum SMS_DVB3_EVENTS { | 258 | enum SMS_DVB3_EVENTS { |
259 | DVB3_EVENT_INIT = 0, | 259 | DVB3_EVENT_INIT = 0, |
260 | DVB3_EVENT_SLEEP, | 260 | DVB3_EVENT_SLEEP, |
261 | DVB3_EVENT_HOTPLUG, | 261 | DVB3_EVENT_HOTPLUG, |
262 | DVB3_EVENT_FE_LOCK, | 262 | DVB3_EVENT_FE_LOCK, |
263 | DVB3_EVENT_FE_UNLOCK, | 263 | DVB3_EVENT_FE_UNLOCK, |
264 | DVB3_EVENT_UNC_OK, | 264 | DVB3_EVENT_UNC_OK, |
265 | DVB3_EVENT_UNC_ERR | 265 | DVB3_EVENT_UNC_ERR |
266 | }; | 266 | }; |
267 | 267 | ||
268 | enum SMS_DEVICE_MODE { | 268 | enum SMS_DEVICE_MODE { |
269 | DEVICE_MODE_NONE = -1, | 269 | DEVICE_MODE_NONE = -1, |
270 | DEVICE_MODE_DVBT = 0, | 270 | DEVICE_MODE_DVBT = 0, |
271 | DEVICE_MODE_DVBH, | 271 | DEVICE_MODE_DVBH, |
272 | DEVICE_MODE_DAB_TDMB, | 272 | DEVICE_MODE_DAB_TDMB, |
273 | DEVICE_MODE_DAB_TDMB_DABIP, | 273 | DEVICE_MODE_DAB_TDMB_DABIP, |
274 | DEVICE_MODE_DVBT_BDA, | 274 | DEVICE_MODE_DVBT_BDA, |
275 | DEVICE_MODE_ISDBT, | 275 | DEVICE_MODE_ISDBT, |
276 | DEVICE_MODE_ISDBT_BDA, | 276 | DEVICE_MODE_ISDBT_BDA, |
277 | DEVICE_MODE_CMMB, | 277 | DEVICE_MODE_CMMB, |
278 | DEVICE_MODE_RAW_TUNER, | 278 | DEVICE_MODE_RAW_TUNER, |
279 | DEVICE_MODE_MAX, | 279 | DEVICE_MODE_MAX, |
280 | }; | 280 | }; |
281 | 281 | ||
282 | struct SmsMsgHdr_ST { | 282 | struct SmsMsgHdr_ST { |
283 | u16 msgType; | 283 | u16 msgType; |
284 | u8 msgSrcId; | 284 | u8 msgSrcId; |
285 | u8 msgDstId; | 285 | u8 msgDstId; |
286 | u16 msgLength; /* Length of entire message, including header */ | 286 | u16 msgLength; /* Length of entire message, including header */ |
287 | u16 msgFlags; | 287 | u16 msgFlags; |
288 | }; | 288 | }; |
289 | 289 | ||
290 | struct SmsMsgData_ST { | 290 | struct SmsMsgData_ST { |
291 | struct SmsMsgHdr_ST xMsgHeader; | 291 | struct SmsMsgHdr_ST xMsgHeader; |
292 | u32 msgData[1]; | 292 | u32 msgData[1]; |
293 | }; | 293 | }; |
294 | 294 | ||
295 | struct SmsMsgData_ST2 { | 295 | struct SmsMsgData_ST2 { |
296 | struct SmsMsgHdr_ST xMsgHeader; | 296 | struct SmsMsgHdr_ST xMsgHeader; |
297 | u32 msgData[2]; | 297 | u32 msgData[2]; |
298 | }; | 298 | }; |
299 | 299 | ||
300 | struct SmsDataDownload_ST { | 300 | struct SmsDataDownload_ST { |
301 | struct SmsMsgHdr_ST xMsgHeader; | 301 | struct SmsMsgHdr_ST xMsgHeader; |
302 | u32 MemAddr; | 302 | u32 MemAddr; |
303 | u8 Payload[SMS_MAX_PAYLOAD_SIZE]; | 303 | u8 Payload[SMS_MAX_PAYLOAD_SIZE]; |
304 | }; | 304 | }; |
305 | 305 | ||
306 | struct SmsVersionRes_ST { | 306 | struct SmsVersionRes_ST { |
307 | struct SmsMsgHdr_ST xMsgHeader; | 307 | struct SmsMsgHdr_ST xMsgHeader; |
308 | 308 | ||
309 | u16 ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */ | 309 | u16 ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */ |
310 | u8 Step; /* 0 - Step A */ | 310 | u8 Step; /* 0 - Step A */ |
311 | u8 MetalFix; /* 0 - Metal 0 */ | 311 | u8 MetalFix; /* 0 - Metal 0 */ |
312 | 312 | ||
313 | /* FirmwareId 0xFF if ROM, otherwise the | 313 | /* FirmwareId 0xFF if ROM, otherwise the |
314 | * value indicated by SMSHOSTLIB_DEVICE_MODES_E */ | 314 | * value indicated by SMSHOSTLIB_DEVICE_MODES_E */ |
315 | u8 FirmwareId; | 315 | u8 FirmwareId; |
316 | /* SupportedProtocols Bitwise OR combination of | 316 | /* SupportedProtocols Bitwise OR combination of |
317 | * supported protocols */ | 317 | * supported protocols */ |
318 | u8 SupportedProtocols; | 318 | u8 SupportedProtocols; |
319 | 319 | ||
320 | u8 VersionMajor; | 320 | u8 VersionMajor; |
321 | u8 VersionMinor; | 321 | u8 VersionMinor; |
322 | u8 VersionPatch; | 322 | u8 VersionPatch; |
323 | u8 VersionFieldPatch; | 323 | u8 VersionFieldPatch; |
324 | 324 | ||
325 | u8 RomVersionMajor; | 325 | u8 RomVersionMajor; |
326 | u8 RomVersionMinor; | 326 | u8 RomVersionMinor; |
327 | u8 RomVersionPatch; | 327 | u8 RomVersionPatch; |
328 | u8 RomVersionFieldPatch; | 328 | u8 RomVersionFieldPatch; |
329 | 329 | ||
330 | u8 TextLabel[34]; | 330 | u8 TextLabel[34]; |
331 | }; | 331 | }; |
332 | 332 | ||
333 | struct SmsFirmware_ST { | 333 | struct SmsFirmware_ST { |
334 | u32 CheckSum; | 334 | u32 CheckSum; |
335 | u32 Length; | 335 | u32 Length; |
336 | u32 StartAddress; | 336 | u32 StartAddress; |
337 | u8 Payload[1]; | 337 | u8 Payload[1]; |
338 | }; | 338 | }; |
339 | 339 | ||
340 | /* Statistics information returned as response for | 340 | /* Statistics information returned as response for |
341 | * SmsHostApiGetStatistics_Req */ | 341 | * SmsHostApiGetStatistics_Req */ |
342 | struct SMSHOSTLIB_STATISTICS_S { | 342 | struct SMSHOSTLIB_STATISTICS_S { |
343 | u32 Reserved; /* Reserved */ | 343 | u32 Reserved; /* Reserved */ |
344 | 344 | ||
345 | /* Common parameters */ | 345 | /* Common parameters */ |
346 | u32 IsRfLocked; /* 0 - not locked, 1 - locked */ | 346 | u32 IsRfLocked; /* 0 - not locked, 1 - locked */ |
347 | u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ | 347 | u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ |
348 | u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ | 348 | u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ |
349 | 349 | ||
350 | /* Reception quality */ | 350 | /* Reception quality */ |
351 | s32 SNR; /* dB */ | 351 | s32 SNR; /* dB */ |
352 | u32 BER; /* Post Viterbi BER [1E-5] */ | 352 | u32 BER; /* Post Viterbi BER [1E-5] */ |
353 | u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */ | 353 | u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */ |
354 | u32 TS_PER; /* Transport stream PER, | 354 | u32 TS_PER; /* Transport stream PER, |
355 | 0xFFFFFFFF indicate N/A, valid only for DVB-T/H */ | 355 | 0xFFFFFFFF indicate N/A, valid only for DVB-T/H */ |
356 | u32 MFER; /* DVB-H frame error rate in percentage, | 356 | u32 MFER; /* DVB-H frame error rate in percentage, |
357 | 0xFFFFFFFF indicate N/A, valid only for DVB-H */ | 357 | 0xFFFFFFFF indicate N/A, valid only for DVB-H */ |
358 | s32 RSSI; /* dBm */ | 358 | s32 RSSI; /* dBm */ |
359 | s32 InBandPwr; /* In band power in dBM */ | 359 | s32 InBandPwr; /* In band power in dBM */ |
360 | s32 CarrierOffset; /* Carrier Offset in bin/1024 */ | 360 | s32 CarrierOffset; /* Carrier Offset in bin/1024 */ |
361 | 361 | ||
362 | /* Transmission parameters */ | 362 | /* Transmission parameters */ |
363 | u32 Frequency; /* Frequency in Hz */ | 363 | u32 Frequency; /* Frequency in Hz */ |
364 | u32 Bandwidth; /* Bandwidth in MHz, valid only for DVB-T/H */ | 364 | u32 Bandwidth; /* Bandwidth in MHz, valid only for DVB-T/H */ |
365 | u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4, | 365 | u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4, |
366 | for DVB-T/H FFT mode carriers in Kilos */ | 366 | for DVB-T/H FFT mode carriers in Kilos */ |
367 | u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET, | 367 | u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET, |
368 | valid only for DVB-T/H */ | 368 | valid only for DVB-T/H */ |
369 | u32 GuardInterval; /* Guard Interval from | 369 | u32 GuardInterval; /* Guard Interval from |
370 | SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */ | 370 | SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */ |
371 | u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, | 371 | u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, |
372 | valid only for DVB-T/H */ | 372 | valid only for DVB-T/H */ |
373 | u32 LPCodeRate; /* Low Priority Code Rate from | 373 | u32 LPCodeRate; /* Low Priority Code Rate from |
374 | SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */ | 374 | SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */ |
375 | u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET, | 375 | u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET, |
376 | valid only for DVB-T/H */ | 376 | valid only for DVB-T/H */ |
377 | u32 Constellation; /* Constellation from | 377 | u32 Constellation; /* Constellation from |
378 | SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */ | 378 | SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */ |
379 | 379 | ||
380 | /* Burst parameters, valid only for DVB-H */ | 380 | /* Burst parameters, valid only for DVB-H */ |
381 | u32 BurstSize; /* Current burst size in bytes, | 381 | u32 BurstSize; /* Current burst size in bytes, |
382 | valid only for DVB-H */ | 382 | valid only for DVB-H */ |
383 | u32 BurstDuration; /* Current burst duration in mSec, | 383 | u32 BurstDuration; /* Current burst duration in mSec, |
384 | valid only for DVB-H */ | 384 | valid only for DVB-H */ |
385 | u32 BurstCycleTime; /* Current burst cycle time in mSec, | 385 | u32 BurstCycleTime; /* Current burst cycle time in mSec, |
386 | valid only for DVB-H */ | 386 | valid only for DVB-H */ |
387 | u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec, | 387 | u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec, |
388 | as calculated by demodulator, valid only for DVB-H */ | 388 | as calculated by demodulator, valid only for DVB-H */ |
389 | u32 NumOfRows; /* Number of rows in MPE table, | 389 | u32 NumOfRows; /* Number of rows in MPE table, |
390 | valid only for DVB-H */ | 390 | valid only for DVB-H */ |
391 | u32 NumOfPaddCols; /* Number of padding columns in MPE table, | 391 | u32 NumOfPaddCols; /* Number of padding columns in MPE table, |
392 | valid only for DVB-H */ | 392 | valid only for DVB-H */ |
393 | u32 NumOfPunctCols; /* Number of puncturing columns in MPE table, | 393 | u32 NumOfPunctCols; /* Number of puncturing columns in MPE table, |
394 | valid only for DVB-H */ | 394 | valid only for DVB-H */ |
395 | u32 ErrorTSPackets; /* Number of erroneous | 395 | u32 ErrorTSPackets; /* Number of erroneous |
396 | transport-stream packets */ | 396 | transport-stream packets */ |
397 | u32 TotalTSPackets; /* Total number of transport-stream packets */ | 397 | u32 TotalTSPackets; /* Total number of transport-stream packets */ |
398 | u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include | 398 | u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include |
399 | errors after MPE RS decoding */ | 399 | errors after MPE RS decoding */ |
400 | u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors | 400 | u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors |
401 | after MPE RS decoding */ | 401 | after MPE RS decoding */ |
402 | u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were | 402 | u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were |
403 | corrected by MPE RS decoding */ | 403 | corrected by MPE RS decoding */ |
404 | /* Common params */ | 404 | /* Common params */ |
405 | u32 BERErrorCount; /* Number of errornous SYNC bits. */ | 405 | u32 BERErrorCount; /* Number of errornous SYNC bits. */ |
406 | u32 BERBitCount; /* Total number of SYNC bits. */ | 406 | u32 BERBitCount; /* Total number of SYNC bits. */ |
407 | 407 | ||
408 | /* Interface information */ | 408 | /* Interface information */ |
409 | u32 SmsToHostTxErrors; /* Total number of transmission errors. */ | 409 | u32 SmsToHostTxErrors; /* Total number of transmission errors. */ |
410 | 410 | ||
411 | /* DAB/T-DMB */ | 411 | /* DAB/T-DMB */ |
412 | u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ | 412 | u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ |
413 | 413 | ||
414 | /* DVB-H TPS parameters */ | 414 | /* DVB-H TPS parameters */ |
415 | u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; | 415 | u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; |
416 | if set to 0xFFFFFFFF cell_id not yet recovered */ | 416 | if set to 0xFFFFFFFF cell_id not yet recovered */ |
417 | u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - | 417 | u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - |
418 | Time Slicing indicator, bit 0 - MPE-FEC indicator */ | 418 | Time Slicing indicator, bit 0 - MPE-FEC indicator */ |
419 | u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - | 419 | u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - |
420 | Time Slicing indicator, bit 0 - MPE-FEC indicator */ | 420 | Time Slicing indicator, bit 0 - MPE-FEC indicator */ |
421 | 421 | ||
422 | u32 NumMPEReceived; /* DVB-H, Num MPE section received */ | 422 | u32 NumMPEReceived; /* DVB-H, Num MPE section received */ |
423 | 423 | ||
424 | u32 ReservedFields[10]; /* Reserved */ | 424 | u32 ReservedFields[10]; /* Reserved */ |
425 | }; | 425 | }; |
426 | 426 | ||
427 | struct PID_STATISTICS_DATA_S { | 427 | struct PID_STATISTICS_DATA_S { |
428 | struct PID_BURST_S { | 428 | struct PID_BURST_S { |
429 | u32 size; | 429 | u32 size; |
430 | u32 padding_cols; | 430 | u32 padding_cols; |
431 | u32 punct_cols; | 431 | u32 punct_cols; |
432 | u32 duration; | 432 | u32 duration; |
433 | u32 cycle; | 433 | u32 cycle; |
434 | u32 calc_cycle; | 434 | u32 calc_cycle; |
435 | } burst; | 435 | } burst; |
436 | 436 | ||
437 | u32 tot_tbl_cnt; | 437 | u32 tot_tbl_cnt; |
438 | u32 invalid_tbl_cnt; | 438 | u32 invalid_tbl_cnt; |
439 | u32 tot_cor_tbl; | 439 | u32 tot_cor_tbl; |
440 | }; | 440 | }; |
441 | 441 | ||
442 | struct PID_DATA_S { | 442 | struct PID_DATA_S { |
443 | u32 pid; | 443 | u32 pid; |
444 | u32 num_rows; | 444 | u32 num_rows; |
445 | struct PID_STATISTICS_DATA_S pid_statistics; | 445 | struct PID_STATISTICS_DATA_S pid_statistics; |
446 | }; | 446 | }; |
447 | 447 | ||
448 | #define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1) | 448 | #define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1) |
449 | #define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth) | 449 | #define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth) |
450 | #define CORRECT_STAT_TRANSMISSON_MODE(_stat) \ | 450 | #define CORRECT_STAT_TRANSMISSON_MODE(_stat) \ |
451 | if (_stat.TransmissionMode == 0) \ | 451 | if (_stat.TransmissionMode == 0) \ |
452 | _stat.TransmissionMode = 2; \ | 452 | _stat.TransmissionMode = 2; \ |
453 | else if (_stat.TransmissionMode == 1) \ | 453 | else if (_stat.TransmissionMode == 1) \ |
454 | _stat.TransmissionMode = 8; \ | 454 | _stat.TransmissionMode = 8; \ |
455 | else \ | 455 | else \ |
456 | _stat.TransmissionMode = 4; | 456 | _stat.TransmissionMode = 4; |
457 | 457 | ||
458 | struct TRANSMISSION_STATISTICS_S { | 458 | struct TRANSMISSION_STATISTICS_S { |
459 | u32 Frequency; /* Frequency in Hz */ | 459 | u32 Frequency; /* Frequency in Hz */ |
460 | u32 Bandwidth; /* Bandwidth in MHz */ | 460 | u32 Bandwidth; /* Bandwidth in MHz */ |
461 | u32 TransmissionMode; /* FFT mode carriers in Kilos */ | 461 | u32 TransmissionMode; /* FFT mode carriers in Kilos */ |
462 | u32 GuardInterval; /* Guard Interval from | 462 | u32 GuardInterval; /* Guard Interval from |
463 | SMSHOSTLIB_GUARD_INTERVALS_ET */ | 463 | SMSHOSTLIB_GUARD_INTERVALS_ET */ |
464 | u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */ | 464 | u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */ |
465 | u32 LPCodeRate; /* Low Priority Code Rate from | 465 | u32 LPCodeRate; /* Low Priority Code Rate from |
466 | SMSHOSTLIB_CODE_RATE_ET */ | 466 | SMSHOSTLIB_CODE_RATE_ET */ |
467 | u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */ | 467 | u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */ |
468 | u32 Constellation; /* Constellation from | 468 | u32 Constellation; /* Constellation from |
469 | SMSHOSTLIB_CONSTELLATION_ET */ | 469 | SMSHOSTLIB_CONSTELLATION_ET */ |
470 | 470 | ||
471 | /* DVB-H TPS parameters */ | 471 | /* DVB-H TPS parameters */ |
472 | u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; | 472 | u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; |
473 | if set to 0xFFFFFFFF cell_id not yet recovered */ | 473 | if set to 0xFFFFFFFF cell_id not yet recovered */ |
474 | u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - | 474 | u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - |
475 | Time Slicing indicator, bit 0 - MPE-FEC indicator */ | 475 | Time Slicing indicator, bit 0 - MPE-FEC indicator */ |
476 | u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - | 476 | u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - |
477 | Time Slicing indicator, bit 0 - MPE-FEC indicator */ | 477 | Time Slicing indicator, bit 0 - MPE-FEC indicator */ |
478 | u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ | 478 | u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ |
479 | }; | 479 | }; |
480 | 480 | ||
481 | struct RECEPTION_STATISTICS_S { | 481 | struct RECEPTION_STATISTICS_S { |
482 | u32 IsRfLocked; /* 0 - not locked, 1 - locked */ | 482 | u32 IsRfLocked; /* 0 - not locked, 1 - locked */ |
483 | u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ | 483 | u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ |
484 | u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ | 484 | u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ |
485 | 485 | ||
486 | u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ | 486 | u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ |
487 | s32 SNR; /* dB */ | 487 | s32 SNR; /* dB */ |
488 | u32 BER; /* Post Viterbi BER [1E-5] */ | 488 | u32 BER; /* Post Viterbi BER [1E-5] */ |
489 | u32 BERErrorCount; /* Number of erronous SYNC bits. */ | 489 | u32 BERErrorCount; /* Number of erronous SYNC bits. */ |
490 | u32 BERBitCount; /* Total number of SYNC bits. */ | 490 | u32 BERBitCount; /* Total number of SYNC bits. */ |
491 | u32 TS_PER; /* Transport stream PER, | 491 | u32 TS_PER; /* Transport stream PER, |
492 | 0xFFFFFFFF indicate N/A */ | 492 | 0xFFFFFFFF indicate N/A */ |
493 | u32 MFER; /* DVB-H frame error rate in percentage, | 493 | u32 MFER; /* DVB-H frame error rate in percentage, |
494 | 0xFFFFFFFF indicate N/A, valid only for DVB-H */ | 494 | 0xFFFFFFFF indicate N/A, valid only for DVB-H */ |
495 | s32 RSSI; /* dBm */ | 495 | s32 RSSI; /* dBm */ |
496 | s32 InBandPwr; /* In band power in dBM */ | 496 | s32 InBandPwr; /* In band power in dBM */ |
497 | s32 CarrierOffset; /* Carrier Offset in bin/1024 */ | 497 | s32 CarrierOffset; /* Carrier Offset in bin/1024 */ |
498 | u32 ErrorTSPackets; /* Number of erroneous | 498 | u32 ErrorTSPackets; /* Number of erroneous |
499 | transport-stream packets */ | 499 | transport-stream packets */ |
500 | u32 TotalTSPackets; /* Total number of transport-stream packets */ | 500 | u32 TotalTSPackets; /* Total number of transport-stream packets */ |
501 | 501 | ||
502 | s32 MRC_SNR; /* dB */ | 502 | s32 MRC_SNR; /* dB */ |
503 | s32 MRC_RSSI; /* dBm */ | 503 | s32 MRC_RSSI; /* dBm */ |
504 | s32 MRC_InBandPwr; /* In band power in dBM */ | 504 | s32 MRC_InBandPwr; /* In band power in dBM */ |
505 | }; | 505 | }; |
506 | 506 | ||
507 | 507 | ||
508 | /* Statistics information returned as response for | 508 | /* Statistics information returned as response for |
509 | * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */ | 509 | * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */ |
510 | struct SMSHOSTLIB_STATISTICS_DVB_S { | 510 | struct SMSHOSTLIB_STATISTICS_DVB_S { |
511 | /* Reception */ | 511 | /* Reception */ |
512 | struct RECEPTION_STATISTICS_S ReceptionData; | 512 | struct RECEPTION_STATISTICS_S ReceptionData; |
513 | 513 | ||
514 | /* Transmission parameters */ | 514 | /* Transmission parameters */ |
515 | struct TRANSMISSION_STATISTICS_S TransmissionData; | 515 | struct TRANSMISSION_STATISTICS_S TransmissionData; |
516 | 516 | ||
517 | /* Burst parameters, valid only for DVB-H */ | 517 | /* Burst parameters, valid only for DVB-H */ |
518 | #define SRVM_MAX_PID_FILTERS 8 | 518 | #define SRVM_MAX_PID_FILTERS 8 |
519 | struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS]; | 519 | struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS]; |
520 | }; | 520 | }; |
521 | 521 | ||
522 | struct SRVM_SIGNAL_STATUS_S { | 522 | struct SRVM_SIGNAL_STATUS_S { |
523 | u32 result; | 523 | u32 result; |
524 | u32 snr; | 524 | u32 snr; |
525 | u32 tsPackets; | 525 | u32 tsPackets; |
526 | u32 etsPackets; | 526 | u32 etsPackets; |
527 | u32 constellation; | 527 | u32 constellation; |
528 | u32 hpCode; | 528 | u32 hpCode; |
529 | u32 tpsSrvIndLP; | 529 | u32 tpsSrvIndLP; |
530 | u32 tpsSrvIndHP; | 530 | u32 tpsSrvIndHP; |
531 | u32 cellId; | 531 | u32 cellId; |
532 | u32 reason; | 532 | u32 reason; |
533 | 533 | ||
534 | s32 inBandPower; | 534 | s32 inBandPower; |
535 | u32 requestId; | 535 | u32 requestId; |
536 | }; | 536 | }; |
537 | 537 | ||
538 | struct SMSHOSTLIB_I2C_REQ_ST { | 538 | struct SMSHOSTLIB_I2C_REQ_ST { |
539 | u32 DeviceAddress; /* I2c device address */ | 539 | u32 DeviceAddress; /* I2c device address */ |
540 | u32 WriteCount; /* number of bytes to write */ | 540 | u32 WriteCount; /* number of bytes to write */ |
541 | u32 ReadCount; /* number of bytes to read */ | 541 | u32 ReadCount; /* number of bytes to read */ |
542 | u8 Data[1]; | 542 | u8 Data[1]; |
543 | }; | 543 | }; |
544 | 544 | ||
545 | struct SMSHOSTLIB_I2C_RES_ST { | 545 | struct SMSHOSTLIB_I2C_RES_ST { |
546 | u32 Status; /* non-zero value in case of failure */ | 546 | u32 Status; /* non-zero value in case of failure */ |
547 | u32 ReadCount; /* number of bytes read */ | 547 | u32 ReadCount; /* number of bytes read */ |
548 | u8 Data[1]; | 548 | u8 Data[1]; |
549 | }; | 549 | }; |
550 | 550 | ||
551 | 551 | ||
552 | struct smscore_config_gpio { | 552 | struct smscore_config_gpio { |
553 | #define SMS_GPIO_DIRECTION_INPUT 0 | 553 | #define SMS_GPIO_DIRECTION_INPUT 0 |
554 | #define SMS_GPIO_DIRECTION_OUTPUT 1 | 554 | #define SMS_GPIO_DIRECTION_OUTPUT 1 |
555 | u8 direction; | 555 | u8 direction; |
556 | 556 | ||
557 | #define SMS_GPIO_PULLUPDOWN_NONE 0 | 557 | #define SMS_GPIO_PULLUPDOWN_NONE 0 |
558 | #define SMS_GPIO_PULLUPDOWN_PULLDOWN 1 | 558 | #define SMS_GPIO_PULLUPDOWN_PULLDOWN 1 |
559 | #define SMS_GPIO_PULLUPDOWN_PULLUP 2 | 559 | #define SMS_GPIO_PULLUPDOWN_PULLUP 2 |
560 | #define SMS_GPIO_PULLUPDOWN_KEEPER 3 | 560 | #define SMS_GPIO_PULLUPDOWN_KEEPER 3 |
561 | u8 pullupdown; | 561 | u8 pullupdown; |
562 | 562 | ||
563 | #define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL 0 | 563 | #define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL 0 |
564 | #define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1 | 564 | #define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1 |
565 | u8 inputcharacteristics; | 565 | u8 inputcharacteristics; |
566 | 566 | ||
567 | #define SMS_GPIO_OUTPUTSLEWRATE_FAST 0 | 567 | #define SMS_GPIO_OUTPUTSLEWRATE_FAST 0 |
568 | #define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1 | 568 | #define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1 |
569 | u8 outputslewrate; | 569 | u8 outputslewrate; |
570 | 570 | ||
571 | #define SMS_GPIO_OUTPUTDRIVING_4mA 0 | 571 | #define SMS_GPIO_OUTPUTDRIVING_4mA 0 |
572 | #define SMS_GPIO_OUTPUTDRIVING_8mA 1 | 572 | #define SMS_GPIO_OUTPUTDRIVING_8mA 1 |
573 | #define SMS_GPIO_OUTPUTDRIVING_12mA 2 | 573 | #define SMS_GPIO_OUTPUTDRIVING_12mA 2 |
574 | #define SMS_GPIO_OUTPUTDRIVING_16mA 3 | 574 | #define SMS_GPIO_OUTPUTDRIVING_16mA 3 |
575 | u8 outputdriving; | 575 | u8 outputdriving; |
576 | }; | 576 | }; |
577 | 577 | ||
578 | struct smscore_gpio_config { | 578 | struct smscore_gpio_config { |
579 | #define SMS_GPIO_DIRECTION_INPUT 0 | 579 | #define SMS_GPIO_DIRECTION_INPUT 0 |
580 | #define SMS_GPIO_DIRECTION_OUTPUT 1 | 580 | #define SMS_GPIO_DIRECTION_OUTPUT 1 |
581 | u8 Direction; | 581 | u8 Direction; |
582 | 582 | ||
583 | #define SMS_GPIO_PULL_UP_DOWN_NONE 0 | 583 | #define SMS_GPIO_PULL_UP_DOWN_NONE 0 |
584 | #define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1 | 584 | #define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1 |
585 | #define SMS_GPIO_PULL_UP_DOWN_PULLUP 2 | 585 | #define SMS_GPIO_PULL_UP_DOWN_PULLUP 2 |
586 | #define SMS_GPIO_PULL_UP_DOWN_KEEPER 3 | 586 | #define SMS_GPIO_PULL_UP_DOWN_KEEPER 3 |
587 | u8 PullUpDown; | 587 | u8 PullUpDown; |
588 | 588 | ||
589 | #define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL 0 | 589 | #define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL 0 |
590 | #define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1 | 590 | #define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1 |
591 | u8 InputCharacteristics; | 591 | u8 InputCharacteristics; |
592 | 592 | ||
593 | #define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW 1 /* 10xx */ | 593 | #define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW 1 /* 10xx */ |
594 | #define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0 /* 10xx */ | 594 | #define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0 /* 10xx */ |
595 | 595 | ||
596 | 596 | ||
597 | #define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0 /* 11xx */ | 597 | #define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0 /* 11xx */ |
598 | #define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1 /* 11xx */ | 598 | #define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1 /* 11xx */ |
599 | #define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2 /* 11xx */ | 599 | #define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2 /* 11xx */ |
600 | #define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3 /* 11xx */ | 600 | #define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3 /* 11xx */ |
601 | u8 OutputSlewRate; | 601 | u8 OutputSlewRate; |
602 | 602 | ||
603 | #define SMS_GPIO_OUTPUT_DRIVING_S_4mA 0 /* 10xx */ | 603 | #define SMS_GPIO_OUTPUT_DRIVING_S_4mA 0 /* 10xx */ |
604 | #define SMS_GPIO_OUTPUT_DRIVING_S_8mA 1 /* 10xx */ | 604 | #define SMS_GPIO_OUTPUT_DRIVING_S_8mA 1 /* 10xx */ |
605 | #define SMS_GPIO_OUTPUT_DRIVING_S_12mA 2 /* 10xx */ | 605 | #define SMS_GPIO_OUTPUT_DRIVING_S_12mA 2 /* 10xx */ |
606 | #define SMS_GPIO_OUTPUT_DRIVING_S_16mA 3 /* 10xx */ | 606 | #define SMS_GPIO_OUTPUT_DRIVING_S_16mA 3 /* 10xx */ |
607 | 607 | ||
608 | #define SMS_GPIO_OUTPUT_DRIVING_1_5mA 0 /* 11xx */ | 608 | #define SMS_GPIO_OUTPUT_DRIVING_1_5mA 0 /* 11xx */ |
609 | #define SMS_GPIO_OUTPUT_DRIVING_2_8mA 1 /* 11xx */ | 609 | #define SMS_GPIO_OUTPUT_DRIVING_2_8mA 1 /* 11xx */ |
610 | #define SMS_GPIO_OUTPUT_DRIVING_4mA 2 /* 11xx */ | 610 | #define SMS_GPIO_OUTPUT_DRIVING_4mA 2 /* 11xx */ |
611 | #define SMS_GPIO_OUTPUT_DRIVING_7mA 3 /* 11xx */ | 611 | #define SMS_GPIO_OUTPUT_DRIVING_7mA 3 /* 11xx */ |
612 | #define SMS_GPIO_OUTPUT_DRIVING_10mA 4 /* 11xx */ | 612 | #define SMS_GPIO_OUTPUT_DRIVING_10mA 4 /* 11xx */ |
613 | #define SMS_GPIO_OUTPUT_DRIVING_11mA 5 /* 11xx */ | 613 | #define SMS_GPIO_OUTPUT_DRIVING_11mA 5 /* 11xx */ |
614 | #define SMS_GPIO_OUTPUT_DRIVING_14mA 6 /* 11xx */ | 614 | #define SMS_GPIO_OUTPUT_DRIVING_14mA 6 /* 11xx */ |
615 | #define SMS_GPIO_OUTPUT_DRIVING_16mA 7 /* 11xx */ | 615 | #define SMS_GPIO_OUTPUT_DRIVING_16mA 7 /* 11xx */ |
616 | u8 OutputDriving; | 616 | u8 OutputDriving; |
617 | }; | 617 | }; |
618 | 618 | ||
619 | extern void smscore_registry_setmode(char *devpath, int mode); | 619 | extern void smscore_registry_setmode(char *devpath, int mode); |
620 | extern int smscore_registry_getmode(char *devpath); | 620 | extern int smscore_registry_getmode(char *devpath); |
621 | 621 | ||
622 | extern int smscore_register_hotplug(hotplug_t hotplug); | 622 | extern int smscore_register_hotplug(hotplug_t hotplug); |
623 | extern void smscore_unregister_hotplug(hotplug_t hotplug); | 623 | extern void smscore_unregister_hotplug(hotplug_t hotplug); |
624 | 624 | ||
625 | extern int smscore_register_device(struct smsdevice_params_t *params, | 625 | extern int smscore_register_device(struct smsdevice_params_t *params, |
626 | struct smscore_device_t **coredev); | 626 | struct smscore_device_t **coredev); |
627 | extern void smscore_unregister_device(struct smscore_device_t *coredev); | 627 | extern void smscore_unregister_device(struct smscore_device_t *coredev); |
628 | 628 | ||
629 | extern int smscore_start_device(struct smscore_device_t *coredev); | 629 | extern int smscore_start_device(struct smscore_device_t *coredev); |
630 | extern int smscore_load_firmware(struct smscore_device_t *coredev, | 630 | extern int smscore_load_firmware(struct smscore_device_t *coredev, |
631 | char *filename, | 631 | char *filename, |
632 | loadfirmware_t loadfirmware_handler); | 632 | loadfirmware_t loadfirmware_handler); |
633 | 633 | ||
634 | extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode); | 634 | extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode); |
635 | extern int smscore_get_device_mode(struct smscore_device_t *coredev); | 635 | extern int smscore_get_device_mode(struct smscore_device_t *coredev); |
636 | 636 | ||
637 | extern int smscore_register_client(struct smscore_device_t *coredev, | 637 | extern int smscore_register_client(struct smscore_device_t *coredev, |
638 | struct smsclient_params_t *params, | 638 | struct smsclient_params_t *params, |
639 | struct smscore_client_t **client); | 639 | struct smscore_client_t **client); |
640 | extern void smscore_unregister_client(struct smscore_client_t *client); | 640 | extern void smscore_unregister_client(struct smscore_client_t *client); |
641 | 641 | ||
642 | extern int smsclient_sendrequest(struct smscore_client_t *client, | 642 | extern int smsclient_sendrequest(struct smscore_client_t *client, |
643 | void *buffer, size_t size); | 643 | void *buffer, size_t size); |
644 | extern void smscore_onresponse(struct smscore_device_t *coredev, | 644 | extern void smscore_onresponse(struct smscore_device_t *coredev, |
645 | struct smscore_buffer_t *cb); | 645 | struct smscore_buffer_t *cb); |
646 | 646 | ||
647 | extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev); | 647 | extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev); |
648 | extern int smscore_map_common_buffer(struct smscore_device_t *coredev, | 648 | extern int smscore_map_common_buffer(struct smscore_device_t *coredev, |
649 | struct vm_area_struct *vma); | 649 | struct vm_area_struct *vma); |
650 | extern int smscore_get_fw_filename(struct smscore_device_t *coredev, | 650 | extern int smscore_get_fw_filename(struct smscore_device_t *coredev, |
651 | int mode, char *filename); | 651 | int mode, char *filename); |
652 | extern int smscore_send_fw_file(struct smscore_device_t *coredev, | 652 | extern int smscore_send_fw_file(struct smscore_device_t *coredev, |
653 | u8 *ufwbuf, int size); | 653 | u8 *ufwbuf, int size); |
654 | 654 | ||
655 | extern | 655 | extern |
656 | struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev); | 656 | struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev); |
657 | extern void smscore_putbuffer(struct smscore_device_t *coredev, | 657 | extern void smscore_putbuffer(struct smscore_device_t *coredev, |
658 | struct smscore_buffer_t *cb); | 658 | struct smscore_buffer_t *cb); |
659 | 659 | ||
660 | /* old GPIO managment */ | 660 | /* old GPIO management */ |
661 | int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, | 661 | int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, |
662 | struct smscore_config_gpio *pinconfig); | 662 | struct smscore_config_gpio *pinconfig); |
663 | int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level); | 663 | int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level); |
664 | 664 | ||
665 | /* new GPIO managment */ | 665 | /* new GPIO management */ |
666 | extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, | 666 | extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, |
667 | struct smscore_gpio_config *pGpioConfig); | 667 | struct smscore_gpio_config *pGpioConfig); |
668 | extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, | 668 | extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, |
669 | u8 NewLevel); | 669 | u8 NewLevel); |
670 | extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, | 670 | extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, |
671 | u8 *level); | 671 | u8 *level); |
672 | 672 | ||
673 | void smscore_set_board_id(struct smscore_device_t *core, int id); | 673 | void smscore_set_board_id(struct smscore_device_t *core, int id); |
674 | int smscore_get_board_id(struct smscore_device_t *core); | 674 | int smscore_get_board_id(struct smscore_device_t *core); |
675 | 675 | ||
676 | int smscore_led_state(struct smscore_device_t *core, int led); | 676 | int smscore_led_state(struct smscore_device_t *core, int led); |
677 | 677 | ||
678 | 678 | ||
679 | /* ------------------------------------------------------------------------ */ | 679 | /* ------------------------------------------------------------------------ */ |
680 | 680 | ||
681 | #define DBG_INFO 1 | 681 | #define DBG_INFO 1 |
682 | #define DBG_ADV 2 | 682 | #define DBG_ADV 2 |
683 | 683 | ||
684 | #define sms_printk(kern, fmt, arg...) \ | 684 | #define sms_printk(kern, fmt, arg...) \ |
685 | printk(kern "%s: " fmt "\n", __func__, ##arg) | 685 | printk(kern "%s: " fmt "\n", __func__, ##arg) |
686 | 686 | ||
687 | #define dprintk(kern, lvl, fmt, arg...) do {\ | 687 | #define dprintk(kern, lvl, fmt, arg...) do {\ |
688 | if (sms_dbg & lvl) \ | 688 | if (sms_dbg & lvl) \ |
689 | sms_printk(kern, fmt, ##arg); } while (0) | 689 | sms_printk(kern, fmt, ##arg); } while (0) |
690 | 690 | ||
691 | #define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg) | 691 | #define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg) |
692 | #define sms_err(fmt, arg...) \ | 692 | #define sms_err(fmt, arg...) \ |
693 | sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg) | 693 | sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg) |
694 | #define sms_warn(fmt, arg...) sms_printk(KERN_WARNING, fmt, ##arg) | 694 | #define sms_warn(fmt, arg...) sms_printk(KERN_WARNING, fmt, ##arg) |
695 | #define sms_info(fmt, arg...) \ | 695 | #define sms_info(fmt, arg...) \ |
696 | dprintk(KERN_INFO, DBG_INFO, fmt, ##arg) | 696 | dprintk(KERN_INFO, DBG_INFO, fmt, ##arg) |
697 | #define sms_debug(fmt, arg...) \ | 697 | #define sms_debug(fmt, arg...) \ |
698 | dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg) | 698 | dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg) |
699 | 699 | ||
700 | 700 | ||
701 | #endif /* __SMS_CORE_API_H__ */ | 701 | #endif /* __SMS_CORE_API_H__ */ |
702 | 702 |
drivers/media/radio/radio-mr800.c
1 | /* | 1 | /* |
2 | * A driver for the AverMedia MR 800 USB FM radio. This device plugs | 2 | * A driver for the AverMedia MR 800 USB FM radio. This device plugs |
3 | * into both the USB and an analog audio input, so this thing | 3 | * into both the USB and an analog audio input, so this thing |
4 | * only deals with initialization and frequency setting, the | 4 | * only deals with initialization and frequency setting, the |
5 | * audio data has to be handled by a sound driver. | 5 | * audio data has to be handled by a sound driver. |
6 | * | 6 | * |
7 | * Copyright (c) 2008 Alexey Klimov <klimov.linux@gmail.com> | 7 | * Copyright (c) 2008 Alexey Klimov <klimov.linux@gmail.com> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
11 | * the Free Software Foundation; either version 2 of the License, or | 11 | * the Free Software Foundation; either version 2 of the License, or |
12 | * (at your option) any later version. | 12 | * (at your option) any later version. |
13 | * | 13 | * |
14 | * This program is distributed in the hope that it will be useful, | 14 | * This program is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | * GNU General Public License for more details. | 17 | * GNU General Public License for more details. |
18 | * | 18 | * |
19 | * You should have received a copy of the GNU General Public License | 19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, write to the Free Software | 20 | * along with this program; if not, write to the Free Software |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * Big thanks to authors and contributors of dsbr100.c and radio-si470x.c | 25 | * Big thanks to authors and contributors of dsbr100.c and radio-si470x.c |
26 | * | 26 | * |
27 | * When work was looked pretty good, i discover this: | 27 | * When work was looked pretty good, i discover this: |
28 | * http://av-usbradio.sourceforge.net/index.php | 28 | * http://av-usbradio.sourceforge.net/index.php |
29 | * http://sourceforge.net/projects/av-usbradio/ | 29 | * http://sourceforge.net/projects/av-usbradio/ |
30 | * Latest release of theirs project was in 2005. | 30 | * Latest release of theirs project was in 2005. |
31 | * Probably, this driver could be improved trough using their | 31 | * Probably, this driver could be improved trough using their |
32 | * achievements (specifications given). | 32 | * achievements (specifications given). |
33 | * Also, Faidon Liambotis <paravoid@debian.org> wrote nice driver for this radio | 33 | * Also, Faidon Liambotis <paravoid@debian.org> wrote nice driver for this radio |
34 | * in 2007. He allowed to use his driver to improve current mr800 radio driver. | 34 | * in 2007. He allowed to use his driver to improve current mr800 radio driver. |
35 | * http://kerneltrap.org/mailarchive/linux-usb-devel/2007/10/11/342492 | 35 | * http://kerneltrap.org/mailarchive/linux-usb-devel/2007/10/11/342492 |
36 | * | 36 | * |
37 | * Version 0.01: First working version. | 37 | * Version 0.01: First working version. |
38 | * It's required to blacklist AverMedia USB Radio | 38 | * It's required to blacklist AverMedia USB Radio |
39 | * in usbhid/hid-quirks.c | 39 | * in usbhid/hid-quirks.c |
40 | * Version 0.10: A lot of cleanups and fixes: unpluging the device, | 40 | * Version 0.10: A lot of cleanups and fixes: unpluging the device, |
41 | * few mutex locks were added, codinstyle issues, etc. | 41 | * few mutex locks were added, codinstyle issues, etc. |
42 | * Added stereo support. Thanks to | 42 | * Added stereo support. Thanks to |
43 | * Douglas Schilling Landgraf <dougsland@gmail.com> and | 43 | * Douglas Schilling Landgraf <dougsland@gmail.com> and |
44 | * David Ellingsworth <david@identd.dyndns.org> | 44 | * David Ellingsworth <david@identd.dyndns.org> |
45 | * for discussion, help and support. | 45 | * for discussion, help and support. |
46 | * Version 0.11: Converted to v4l2_device. | 46 | * Version 0.11: Converted to v4l2_device. |
47 | * | 47 | * |
48 | * Many things to do: | 48 | * Many things to do: |
49 | * - Correct power managment of device (suspend & resume) | 49 | * - Correct power management of device (suspend & resume) |
50 | * - Add code for scanning and smooth tuning | 50 | * - Add code for scanning and smooth tuning |
51 | * - Add code for sensitivity value | 51 | * - Add code for sensitivity value |
52 | * - Correct mistakes | 52 | * - Correct mistakes |
53 | * - In Japan another FREQ_MIN and FREQ_MAX | 53 | * - In Japan another FREQ_MIN and FREQ_MAX |
54 | */ | 54 | */ |
55 | 55 | ||
56 | /* kernel includes */ | 56 | /* kernel includes */ |
57 | #include <linux/kernel.h> | 57 | #include <linux/kernel.h> |
58 | #include <linux/module.h> | 58 | #include <linux/module.h> |
59 | #include <linux/init.h> | 59 | #include <linux/init.h> |
60 | #include <linux/slab.h> | 60 | #include <linux/slab.h> |
61 | #include <linux/smp_lock.h> | 61 | #include <linux/smp_lock.h> |
62 | #include <linux/input.h> | 62 | #include <linux/input.h> |
63 | #include <linux/videodev2.h> | 63 | #include <linux/videodev2.h> |
64 | #include <media/v4l2-device.h> | 64 | #include <media/v4l2-device.h> |
65 | #include <media/v4l2-ioctl.h> | 65 | #include <media/v4l2-ioctl.h> |
66 | #include <linux/usb.h> | 66 | #include <linux/usb.h> |
67 | #include <linux/version.h> /* for KERNEL_VERSION MACRO */ | 67 | #include <linux/version.h> /* for KERNEL_VERSION MACRO */ |
68 | #include <linux/mutex.h> | 68 | #include <linux/mutex.h> |
69 | 69 | ||
70 | /* driver and module definitions */ | 70 | /* driver and module definitions */ |
71 | #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>" | 71 | #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>" |
72 | #define DRIVER_DESC "AverMedia MR 800 USB FM radio driver" | 72 | #define DRIVER_DESC "AverMedia MR 800 USB FM radio driver" |
73 | #define DRIVER_VERSION "0.11" | 73 | #define DRIVER_VERSION "0.11" |
74 | #define RADIO_VERSION KERNEL_VERSION(0, 1, 1) | 74 | #define RADIO_VERSION KERNEL_VERSION(0, 1, 1) |
75 | 75 | ||
76 | MODULE_AUTHOR(DRIVER_AUTHOR); | 76 | MODULE_AUTHOR(DRIVER_AUTHOR); |
77 | MODULE_DESCRIPTION(DRIVER_DESC); | 77 | MODULE_DESCRIPTION(DRIVER_DESC); |
78 | MODULE_LICENSE("GPL"); | 78 | MODULE_LICENSE("GPL"); |
79 | 79 | ||
80 | #define USB_AMRADIO_VENDOR 0x07ca | 80 | #define USB_AMRADIO_VENDOR 0x07ca |
81 | #define USB_AMRADIO_PRODUCT 0xb800 | 81 | #define USB_AMRADIO_PRODUCT 0xb800 |
82 | 82 | ||
83 | /* dev_warn macro with driver name */ | 83 | /* dev_warn macro with driver name */ |
84 | #define MR800_DRIVER_NAME "radio-mr800" | 84 | #define MR800_DRIVER_NAME "radio-mr800" |
85 | #define amradio_dev_warn(dev, fmt, arg...) \ | 85 | #define amradio_dev_warn(dev, fmt, arg...) \ |
86 | dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg) | 86 | dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg) |
87 | 87 | ||
88 | /* Probably USB_TIMEOUT should be modified in module parameter */ | 88 | /* Probably USB_TIMEOUT should be modified in module parameter */ |
89 | #define BUFFER_LENGTH 8 | 89 | #define BUFFER_LENGTH 8 |
90 | #define USB_TIMEOUT 500 | 90 | #define USB_TIMEOUT 500 |
91 | 91 | ||
92 | /* Frequency limits in MHz -- these are European values. For Japanese | 92 | /* Frequency limits in MHz -- these are European values. For Japanese |
93 | devices, that would be 76 and 91. */ | 93 | devices, that would be 76 and 91. */ |
94 | #define FREQ_MIN 87.5 | 94 | #define FREQ_MIN 87.5 |
95 | #define FREQ_MAX 108.0 | 95 | #define FREQ_MAX 108.0 |
96 | #define FREQ_MUL 16000 | 96 | #define FREQ_MUL 16000 |
97 | 97 | ||
98 | /* | 98 | /* |
99 | * Commands that device should understand | 99 | * Commands that device should understand |
100 | * List isnt full and will be updated with implementation of new functions | 100 | * List isnt full and will be updated with implementation of new functions |
101 | */ | 101 | */ |
102 | #define AMRADIO_SET_FREQ 0xa4 | 102 | #define AMRADIO_SET_FREQ 0xa4 |
103 | #define AMRADIO_SET_MUTE 0xab | 103 | #define AMRADIO_SET_MUTE 0xab |
104 | #define AMRADIO_SET_MONO 0xae | 104 | #define AMRADIO_SET_MONO 0xae |
105 | 105 | ||
106 | /* Comfortable defines for amradio_set_mute */ | 106 | /* Comfortable defines for amradio_set_mute */ |
107 | #define AMRADIO_START 0x00 | 107 | #define AMRADIO_START 0x00 |
108 | #define AMRADIO_STOP 0x01 | 108 | #define AMRADIO_STOP 0x01 |
109 | 109 | ||
110 | /* Comfortable defines for amradio_set_stereo */ | 110 | /* Comfortable defines for amradio_set_stereo */ |
111 | #define WANT_STEREO 0x00 | 111 | #define WANT_STEREO 0x00 |
112 | #define WANT_MONO 0x01 | 112 | #define WANT_MONO 0x01 |
113 | 113 | ||
114 | /* module parameter */ | 114 | /* module parameter */ |
115 | static int radio_nr = -1; | 115 | static int radio_nr = -1; |
116 | module_param(radio_nr, int, 0); | 116 | module_param(radio_nr, int, 0); |
117 | MODULE_PARM_DESC(radio_nr, "Radio Nr"); | 117 | MODULE_PARM_DESC(radio_nr, "Radio Nr"); |
118 | 118 | ||
119 | static int usb_amradio_probe(struct usb_interface *intf, | 119 | static int usb_amradio_probe(struct usb_interface *intf, |
120 | const struct usb_device_id *id); | 120 | const struct usb_device_id *id); |
121 | static void usb_amradio_disconnect(struct usb_interface *intf); | 121 | static void usb_amradio_disconnect(struct usb_interface *intf); |
122 | static int usb_amradio_open(struct file *file); | 122 | static int usb_amradio_open(struct file *file); |
123 | static int usb_amradio_close(struct file *file); | 123 | static int usb_amradio_close(struct file *file); |
124 | static int usb_amradio_suspend(struct usb_interface *intf, | 124 | static int usb_amradio_suspend(struct usb_interface *intf, |
125 | pm_message_t message); | 125 | pm_message_t message); |
126 | static int usb_amradio_resume(struct usb_interface *intf); | 126 | static int usb_amradio_resume(struct usb_interface *intf); |
127 | 127 | ||
128 | /* Data for one (physical) device */ | 128 | /* Data for one (physical) device */ |
129 | struct amradio_device { | 129 | struct amradio_device { |
130 | /* reference to USB and video device */ | 130 | /* reference to USB and video device */ |
131 | struct usb_device *usbdev; | 131 | struct usb_device *usbdev; |
132 | struct video_device *videodev; | 132 | struct video_device *videodev; |
133 | struct v4l2_device v4l2_dev; | 133 | struct v4l2_device v4l2_dev; |
134 | 134 | ||
135 | unsigned char *buffer; | 135 | unsigned char *buffer; |
136 | struct mutex lock; /* buffer locking */ | 136 | struct mutex lock; /* buffer locking */ |
137 | int curfreq; | 137 | int curfreq; |
138 | int stereo; | 138 | int stereo; |
139 | int users; | 139 | int users; |
140 | int removed; | 140 | int removed; |
141 | int muted; | 141 | int muted; |
142 | }; | 142 | }; |
143 | 143 | ||
144 | /* USB Device ID List */ | 144 | /* USB Device ID List */ |
145 | static struct usb_device_id usb_amradio_device_table[] = { | 145 | static struct usb_device_id usb_amradio_device_table[] = { |
146 | {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT, | 146 | {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT, |
147 | USB_CLASS_HID, 0, 0) }, | 147 | USB_CLASS_HID, 0, 0) }, |
148 | { } /* Terminating entry */ | 148 | { } /* Terminating entry */ |
149 | }; | 149 | }; |
150 | 150 | ||
151 | MODULE_DEVICE_TABLE(usb, usb_amradio_device_table); | 151 | MODULE_DEVICE_TABLE(usb, usb_amradio_device_table); |
152 | 152 | ||
153 | /* USB subsystem interface */ | 153 | /* USB subsystem interface */ |
154 | static struct usb_driver usb_amradio_driver = { | 154 | static struct usb_driver usb_amradio_driver = { |
155 | .name = MR800_DRIVER_NAME, | 155 | .name = MR800_DRIVER_NAME, |
156 | .probe = usb_amradio_probe, | 156 | .probe = usb_amradio_probe, |
157 | .disconnect = usb_amradio_disconnect, | 157 | .disconnect = usb_amradio_disconnect, |
158 | .suspend = usb_amradio_suspend, | 158 | .suspend = usb_amradio_suspend, |
159 | .resume = usb_amradio_resume, | 159 | .resume = usb_amradio_resume, |
160 | .reset_resume = usb_amradio_resume, | 160 | .reset_resume = usb_amradio_resume, |
161 | .id_table = usb_amradio_device_table, | 161 | .id_table = usb_amradio_device_table, |
162 | .supports_autosuspend = 0, | 162 | .supports_autosuspend = 0, |
163 | }; | 163 | }; |
164 | 164 | ||
165 | /* switch on/off the radio. Send 8 bytes to device */ | 165 | /* switch on/off the radio. Send 8 bytes to device */ |
166 | static int amradio_set_mute(struct amradio_device *radio, char argument) | 166 | static int amradio_set_mute(struct amradio_device *radio, char argument) |
167 | { | 167 | { |
168 | int retval; | 168 | int retval; |
169 | int size; | 169 | int size; |
170 | 170 | ||
171 | /* safety check */ | 171 | /* safety check */ |
172 | if (radio->removed) | 172 | if (radio->removed) |
173 | return -EIO; | 173 | return -EIO; |
174 | 174 | ||
175 | mutex_lock(&radio->lock); | 175 | mutex_lock(&radio->lock); |
176 | 176 | ||
177 | radio->buffer[0] = 0x00; | 177 | radio->buffer[0] = 0x00; |
178 | radio->buffer[1] = 0x55; | 178 | radio->buffer[1] = 0x55; |
179 | radio->buffer[2] = 0xaa; | 179 | radio->buffer[2] = 0xaa; |
180 | radio->buffer[3] = 0x00; | 180 | radio->buffer[3] = 0x00; |
181 | radio->buffer[4] = AMRADIO_SET_MUTE; | 181 | radio->buffer[4] = AMRADIO_SET_MUTE; |
182 | radio->buffer[5] = argument; | 182 | radio->buffer[5] = argument; |
183 | radio->buffer[6] = 0x00; | 183 | radio->buffer[6] = 0x00; |
184 | radio->buffer[7] = 0x00; | 184 | radio->buffer[7] = 0x00; |
185 | 185 | ||
186 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), | 186 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), |
187 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); | 187 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); |
188 | 188 | ||
189 | if (retval < 0 || size != BUFFER_LENGTH) { | 189 | if (retval < 0 || size != BUFFER_LENGTH) { |
190 | mutex_unlock(&radio->lock); | 190 | mutex_unlock(&radio->lock); |
191 | return retval; | 191 | return retval; |
192 | } | 192 | } |
193 | 193 | ||
194 | radio->muted = argument; | 194 | radio->muted = argument; |
195 | 195 | ||
196 | mutex_unlock(&radio->lock); | 196 | mutex_unlock(&radio->lock); |
197 | 197 | ||
198 | return retval; | 198 | return retval; |
199 | } | 199 | } |
200 | 200 | ||
201 | /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ | 201 | /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ |
202 | static int amradio_setfreq(struct amradio_device *radio, int freq) | 202 | static int amradio_setfreq(struct amradio_device *radio, int freq) |
203 | { | 203 | { |
204 | int retval; | 204 | int retval; |
205 | int size; | 205 | int size; |
206 | unsigned short freq_send = 0x10 + (freq >> 3) / 25; | 206 | unsigned short freq_send = 0x10 + (freq >> 3) / 25; |
207 | 207 | ||
208 | /* safety check */ | 208 | /* safety check */ |
209 | if (radio->removed) | 209 | if (radio->removed) |
210 | return -EIO; | 210 | return -EIO; |
211 | 211 | ||
212 | mutex_lock(&radio->lock); | 212 | mutex_lock(&radio->lock); |
213 | 213 | ||
214 | radio->buffer[0] = 0x00; | 214 | radio->buffer[0] = 0x00; |
215 | radio->buffer[1] = 0x55; | 215 | radio->buffer[1] = 0x55; |
216 | radio->buffer[2] = 0xaa; | 216 | radio->buffer[2] = 0xaa; |
217 | radio->buffer[3] = 0x03; | 217 | radio->buffer[3] = 0x03; |
218 | radio->buffer[4] = AMRADIO_SET_FREQ; | 218 | radio->buffer[4] = AMRADIO_SET_FREQ; |
219 | radio->buffer[5] = 0x00; | 219 | radio->buffer[5] = 0x00; |
220 | radio->buffer[6] = 0x00; | 220 | radio->buffer[6] = 0x00; |
221 | radio->buffer[7] = 0x08; | 221 | radio->buffer[7] = 0x08; |
222 | 222 | ||
223 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), | 223 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), |
224 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); | 224 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); |
225 | 225 | ||
226 | if (retval < 0 || size != BUFFER_LENGTH) { | 226 | if (retval < 0 || size != BUFFER_LENGTH) { |
227 | mutex_unlock(&radio->lock); | 227 | mutex_unlock(&radio->lock); |
228 | return retval; | 228 | return retval; |
229 | } | 229 | } |
230 | 230 | ||
231 | /* frequency is calculated from freq_send and placed in first 2 bytes */ | 231 | /* frequency is calculated from freq_send and placed in first 2 bytes */ |
232 | radio->buffer[0] = (freq_send >> 8) & 0xff; | 232 | radio->buffer[0] = (freq_send >> 8) & 0xff; |
233 | radio->buffer[1] = freq_send & 0xff; | 233 | radio->buffer[1] = freq_send & 0xff; |
234 | radio->buffer[2] = 0x01; | 234 | radio->buffer[2] = 0x01; |
235 | radio->buffer[3] = 0x00; | 235 | radio->buffer[3] = 0x00; |
236 | radio->buffer[4] = 0x00; | 236 | radio->buffer[4] = 0x00; |
237 | /* 5 and 6 bytes of buffer already = 0x00 */ | 237 | /* 5 and 6 bytes of buffer already = 0x00 */ |
238 | radio->buffer[7] = 0x00; | 238 | radio->buffer[7] = 0x00; |
239 | 239 | ||
240 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), | 240 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), |
241 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); | 241 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); |
242 | 242 | ||
243 | if (retval < 0 || size != BUFFER_LENGTH) { | 243 | if (retval < 0 || size != BUFFER_LENGTH) { |
244 | mutex_unlock(&radio->lock); | 244 | mutex_unlock(&radio->lock); |
245 | return retval; | 245 | return retval; |
246 | } | 246 | } |
247 | 247 | ||
248 | mutex_unlock(&radio->lock); | 248 | mutex_unlock(&radio->lock); |
249 | 249 | ||
250 | return retval; | 250 | return retval; |
251 | } | 251 | } |
252 | 252 | ||
253 | static int amradio_set_stereo(struct amradio_device *radio, char argument) | 253 | static int amradio_set_stereo(struct amradio_device *radio, char argument) |
254 | { | 254 | { |
255 | int retval; | 255 | int retval; |
256 | int size; | 256 | int size; |
257 | 257 | ||
258 | /* safety check */ | 258 | /* safety check */ |
259 | if (radio->removed) | 259 | if (radio->removed) |
260 | return -EIO; | 260 | return -EIO; |
261 | 261 | ||
262 | mutex_lock(&radio->lock); | 262 | mutex_lock(&radio->lock); |
263 | 263 | ||
264 | radio->buffer[0] = 0x00; | 264 | radio->buffer[0] = 0x00; |
265 | radio->buffer[1] = 0x55; | 265 | radio->buffer[1] = 0x55; |
266 | radio->buffer[2] = 0xaa; | 266 | radio->buffer[2] = 0xaa; |
267 | radio->buffer[3] = 0x00; | 267 | radio->buffer[3] = 0x00; |
268 | radio->buffer[4] = AMRADIO_SET_MONO; | 268 | radio->buffer[4] = AMRADIO_SET_MONO; |
269 | radio->buffer[5] = argument; | 269 | radio->buffer[5] = argument; |
270 | radio->buffer[6] = 0x00; | 270 | radio->buffer[6] = 0x00; |
271 | radio->buffer[7] = 0x00; | 271 | radio->buffer[7] = 0x00; |
272 | 272 | ||
273 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), | 273 | retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), |
274 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); | 274 | (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); |
275 | 275 | ||
276 | if (retval < 0 || size != BUFFER_LENGTH) { | 276 | if (retval < 0 || size != BUFFER_LENGTH) { |
277 | radio->stereo = -1; | 277 | radio->stereo = -1; |
278 | mutex_unlock(&radio->lock); | 278 | mutex_unlock(&radio->lock); |
279 | return retval; | 279 | return retval; |
280 | } | 280 | } |
281 | 281 | ||
282 | radio->stereo = 1; | 282 | radio->stereo = 1; |
283 | 283 | ||
284 | mutex_unlock(&radio->lock); | 284 | mutex_unlock(&radio->lock); |
285 | 285 | ||
286 | return retval; | 286 | return retval; |
287 | } | 287 | } |
288 | 288 | ||
289 | /* Handle unplugging the device. | 289 | /* Handle unplugging the device. |
290 | * We call video_unregister_device in any case. | 290 | * We call video_unregister_device in any case. |
291 | * The last function called in this procedure is | 291 | * The last function called in this procedure is |
292 | * usb_amradio_device_release. | 292 | * usb_amradio_device_release. |
293 | */ | 293 | */ |
294 | static void usb_amradio_disconnect(struct usb_interface *intf) | 294 | static void usb_amradio_disconnect(struct usb_interface *intf) |
295 | { | 295 | { |
296 | struct amradio_device *radio = usb_get_intfdata(intf); | 296 | struct amradio_device *radio = usb_get_intfdata(intf); |
297 | 297 | ||
298 | mutex_lock(&radio->lock); | 298 | mutex_lock(&radio->lock); |
299 | radio->removed = 1; | 299 | radio->removed = 1; |
300 | mutex_unlock(&radio->lock); | 300 | mutex_unlock(&radio->lock); |
301 | 301 | ||
302 | usb_set_intfdata(intf, NULL); | 302 | usb_set_intfdata(intf, NULL); |
303 | video_unregister_device(radio->videodev); | 303 | video_unregister_device(radio->videodev); |
304 | v4l2_device_disconnect(&radio->v4l2_dev); | 304 | v4l2_device_disconnect(&radio->v4l2_dev); |
305 | } | 305 | } |
306 | 306 | ||
307 | /* vidioc_querycap - query device capabilities */ | 307 | /* vidioc_querycap - query device capabilities */ |
308 | static int vidioc_querycap(struct file *file, void *priv, | 308 | static int vidioc_querycap(struct file *file, void *priv, |
309 | struct v4l2_capability *v) | 309 | struct v4l2_capability *v) |
310 | { | 310 | { |
311 | struct amradio_device *radio = video_drvdata(file); | 311 | struct amradio_device *radio = video_drvdata(file); |
312 | 312 | ||
313 | strlcpy(v->driver, "radio-mr800", sizeof(v->driver)); | 313 | strlcpy(v->driver, "radio-mr800", sizeof(v->driver)); |
314 | strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card)); | 314 | strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card)); |
315 | usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); | 315 | usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); |
316 | v->version = RADIO_VERSION; | 316 | v->version = RADIO_VERSION; |
317 | v->capabilities = V4L2_CAP_TUNER; | 317 | v->capabilities = V4L2_CAP_TUNER; |
318 | return 0; | 318 | return 0; |
319 | } | 319 | } |
320 | 320 | ||
321 | /* vidioc_g_tuner - get tuner attributes */ | 321 | /* vidioc_g_tuner - get tuner attributes */ |
322 | static int vidioc_g_tuner(struct file *file, void *priv, | 322 | static int vidioc_g_tuner(struct file *file, void *priv, |
323 | struct v4l2_tuner *v) | 323 | struct v4l2_tuner *v) |
324 | { | 324 | { |
325 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 325 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
326 | int retval; | 326 | int retval; |
327 | 327 | ||
328 | /* safety check */ | 328 | /* safety check */ |
329 | if (radio->removed) | 329 | if (radio->removed) |
330 | return -EIO; | 330 | return -EIO; |
331 | 331 | ||
332 | if (v->index > 0) | 332 | if (v->index > 0) |
333 | return -EINVAL; | 333 | return -EINVAL; |
334 | 334 | ||
335 | /* TODO: Add function which look is signal stereo or not | 335 | /* TODO: Add function which look is signal stereo or not |
336 | * amradio_getstat(radio); | 336 | * amradio_getstat(radio); |
337 | */ | 337 | */ |
338 | 338 | ||
339 | /* we call amradio_set_stereo to set radio->stereo | 339 | /* we call amradio_set_stereo to set radio->stereo |
340 | * Honestly, amradio_getstat should cover this in future and | 340 | * Honestly, amradio_getstat should cover this in future and |
341 | * amradio_set_stereo shouldn't be here | 341 | * amradio_set_stereo shouldn't be here |
342 | */ | 342 | */ |
343 | retval = amradio_set_stereo(radio, WANT_STEREO); | 343 | retval = amradio_set_stereo(radio, WANT_STEREO); |
344 | if (retval < 0) | 344 | if (retval < 0) |
345 | amradio_dev_warn(&radio->videodev->dev, | 345 | amradio_dev_warn(&radio->videodev->dev, |
346 | "set stereo failed\n"); | 346 | "set stereo failed\n"); |
347 | 347 | ||
348 | strcpy(v->name, "FM"); | 348 | strcpy(v->name, "FM"); |
349 | v->type = V4L2_TUNER_RADIO; | 349 | v->type = V4L2_TUNER_RADIO; |
350 | v->rangelow = FREQ_MIN * FREQ_MUL; | 350 | v->rangelow = FREQ_MIN * FREQ_MUL; |
351 | v->rangehigh = FREQ_MAX * FREQ_MUL; | 351 | v->rangehigh = FREQ_MAX * FREQ_MUL; |
352 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | 352 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; |
353 | v->capability = V4L2_TUNER_CAP_LOW; | 353 | v->capability = V4L2_TUNER_CAP_LOW; |
354 | if (radio->stereo) | 354 | if (radio->stereo) |
355 | v->audmode = V4L2_TUNER_MODE_STEREO; | 355 | v->audmode = V4L2_TUNER_MODE_STEREO; |
356 | else | 356 | else |
357 | v->audmode = V4L2_TUNER_MODE_MONO; | 357 | v->audmode = V4L2_TUNER_MODE_MONO; |
358 | v->signal = 0xffff; /* Can't get the signal strength, sad.. */ | 358 | v->signal = 0xffff; /* Can't get the signal strength, sad.. */ |
359 | v->afc = 0; /* Don't know what is this */ | 359 | v->afc = 0; /* Don't know what is this */ |
360 | return 0; | 360 | return 0; |
361 | } | 361 | } |
362 | 362 | ||
363 | /* vidioc_s_tuner - set tuner attributes */ | 363 | /* vidioc_s_tuner - set tuner attributes */ |
364 | static int vidioc_s_tuner(struct file *file, void *priv, | 364 | static int vidioc_s_tuner(struct file *file, void *priv, |
365 | struct v4l2_tuner *v) | 365 | struct v4l2_tuner *v) |
366 | { | 366 | { |
367 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 367 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
368 | int retval; | 368 | int retval; |
369 | 369 | ||
370 | /* safety check */ | 370 | /* safety check */ |
371 | if (radio->removed) | 371 | if (radio->removed) |
372 | return -EIO; | 372 | return -EIO; |
373 | 373 | ||
374 | if (v->index > 0) | 374 | if (v->index > 0) |
375 | return -EINVAL; | 375 | return -EINVAL; |
376 | 376 | ||
377 | /* mono/stereo selector */ | 377 | /* mono/stereo selector */ |
378 | switch (v->audmode) { | 378 | switch (v->audmode) { |
379 | case V4L2_TUNER_MODE_MONO: | 379 | case V4L2_TUNER_MODE_MONO: |
380 | retval = amradio_set_stereo(radio, WANT_MONO); | 380 | retval = amradio_set_stereo(radio, WANT_MONO); |
381 | if (retval < 0) | 381 | if (retval < 0) |
382 | amradio_dev_warn(&radio->videodev->dev, | 382 | amradio_dev_warn(&radio->videodev->dev, |
383 | "set mono failed\n"); | 383 | "set mono failed\n"); |
384 | break; | 384 | break; |
385 | case V4L2_TUNER_MODE_STEREO: | 385 | case V4L2_TUNER_MODE_STEREO: |
386 | retval = amradio_set_stereo(radio, WANT_STEREO); | 386 | retval = amradio_set_stereo(radio, WANT_STEREO); |
387 | if (retval < 0) | 387 | if (retval < 0) |
388 | amradio_dev_warn(&radio->videodev->dev, | 388 | amradio_dev_warn(&radio->videodev->dev, |
389 | "set stereo failed\n"); | 389 | "set stereo failed\n"); |
390 | break; | 390 | break; |
391 | default: | 391 | default: |
392 | return -EINVAL; | 392 | return -EINVAL; |
393 | } | 393 | } |
394 | 394 | ||
395 | return 0; | 395 | return 0; |
396 | } | 396 | } |
397 | 397 | ||
398 | /* vidioc_s_frequency - set tuner radio frequency */ | 398 | /* vidioc_s_frequency - set tuner radio frequency */ |
399 | static int vidioc_s_frequency(struct file *file, void *priv, | 399 | static int vidioc_s_frequency(struct file *file, void *priv, |
400 | struct v4l2_frequency *f) | 400 | struct v4l2_frequency *f) |
401 | { | 401 | { |
402 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 402 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
403 | int retval; | 403 | int retval; |
404 | 404 | ||
405 | /* safety check */ | 405 | /* safety check */ |
406 | if (radio->removed) | 406 | if (radio->removed) |
407 | return -EIO; | 407 | return -EIO; |
408 | 408 | ||
409 | mutex_lock(&radio->lock); | 409 | mutex_lock(&radio->lock); |
410 | radio->curfreq = f->frequency; | 410 | radio->curfreq = f->frequency; |
411 | mutex_unlock(&radio->lock); | 411 | mutex_unlock(&radio->lock); |
412 | 412 | ||
413 | retval = amradio_setfreq(radio, radio->curfreq); | 413 | retval = amradio_setfreq(radio, radio->curfreq); |
414 | if (retval < 0) | 414 | if (retval < 0) |
415 | amradio_dev_warn(&radio->videodev->dev, | 415 | amradio_dev_warn(&radio->videodev->dev, |
416 | "set frequency failed\n"); | 416 | "set frequency failed\n"); |
417 | return 0; | 417 | return 0; |
418 | } | 418 | } |
419 | 419 | ||
420 | /* vidioc_g_frequency - get tuner radio frequency */ | 420 | /* vidioc_g_frequency - get tuner radio frequency */ |
421 | static int vidioc_g_frequency(struct file *file, void *priv, | 421 | static int vidioc_g_frequency(struct file *file, void *priv, |
422 | struct v4l2_frequency *f) | 422 | struct v4l2_frequency *f) |
423 | { | 423 | { |
424 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 424 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
425 | 425 | ||
426 | /* safety check */ | 426 | /* safety check */ |
427 | if (radio->removed) | 427 | if (radio->removed) |
428 | return -EIO; | 428 | return -EIO; |
429 | 429 | ||
430 | f->type = V4L2_TUNER_RADIO; | 430 | f->type = V4L2_TUNER_RADIO; |
431 | f->frequency = radio->curfreq; | 431 | f->frequency = radio->curfreq; |
432 | return 0; | 432 | return 0; |
433 | } | 433 | } |
434 | 434 | ||
435 | /* vidioc_queryctrl - enumerate control items */ | 435 | /* vidioc_queryctrl - enumerate control items */ |
436 | static int vidioc_queryctrl(struct file *file, void *priv, | 436 | static int vidioc_queryctrl(struct file *file, void *priv, |
437 | struct v4l2_queryctrl *qc) | 437 | struct v4l2_queryctrl *qc) |
438 | { | 438 | { |
439 | switch (qc->id) { | 439 | switch (qc->id) { |
440 | case V4L2_CID_AUDIO_MUTE: | 440 | case V4L2_CID_AUDIO_MUTE: |
441 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | 441 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); |
442 | } | 442 | } |
443 | 443 | ||
444 | return -EINVAL; | 444 | return -EINVAL; |
445 | } | 445 | } |
446 | 446 | ||
447 | /* vidioc_g_ctrl - get the value of a control */ | 447 | /* vidioc_g_ctrl - get the value of a control */ |
448 | static int vidioc_g_ctrl(struct file *file, void *priv, | 448 | static int vidioc_g_ctrl(struct file *file, void *priv, |
449 | struct v4l2_control *ctrl) | 449 | struct v4l2_control *ctrl) |
450 | { | 450 | { |
451 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 451 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
452 | 452 | ||
453 | /* safety check */ | 453 | /* safety check */ |
454 | if (radio->removed) | 454 | if (radio->removed) |
455 | return -EIO; | 455 | return -EIO; |
456 | 456 | ||
457 | switch (ctrl->id) { | 457 | switch (ctrl->id) { |
458 | case V4L2_CID_AUDIO_MUTE: | 458 | case V4L2_CID_AUDIO_MUTE: |
459 | ctrl->value = radio->muted; | 459 | ctrl->value = radio->muted; |
460 | return 0; | 460 | return 0; |
461 | } | 461 | } |
462 | return -EINVAL; | 462 | return -EINVAL; |
463 | } | 463 | } |
464 | 464 | ||
465 | /* vidioc_s_ctrl - set the value of a control */ | 465 | /* vidioc_s_ctrl - set the value of a control */ |
466 | static int vidioc_s_ctrl(struct file *file, void *priv, | 466 | static int vidioc_s_ctrl(struct file *file, void *priv, |
467 | struct v4l2_control *ctrl) | 467 | struct v4l2_control *ctrl) |
468 | { | 468 | { |
469 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 469 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
470 | int retval; | 470 | int retval; |
471 | 471 | ||
472 | /* safety check */ | 472 | /* safety check */ |
473 | if (radio->removed) | 473 | if (radio->removed) |
474 | return -EIO; | 474 | return -EIO; |
475 | 475 | ||
476 | switch (ctrl->id) { | 476 | switch (ctrl->id) { |
477 | case V4L2_CID_AUDIO_MUTE: | 477 | case V4L2_CID_AUDIO_MUTE: |
478 | if (ctrl->value) { | 478 | if (ctrl->value) { |
479 | retval = amradio_set_mute(radio, AMRADIO_STOP); | 479 | retval = amradio_set_mute(radio, AMRADIO_STOP); |
480 | if (retval < 0) { | 480 | if (retval < 0) { |
481 | amradio_dev_warn(&radio->videodev->dev, | 481 | amradio_dev_warn(&radio->videodev->dev, |
482 | "amradio_stop failed\n"); | 482 | "amradio_stop failed\n"); |
483 | return -1; | 483 | return -1; |
484 | } | 484 | } |
485 | } else { | 485 | } else { |
486 | retval = amradio_set_mute(radio, AMRADIO_START); | 486 | retval = amradio_set_mute(radio, AMRADIO_START); |
487 | if (retval < 0) { | 487 | if (retval < 0) { |
488 | amradio_dev_warn(&radio->videodev->dev, | 488 | amradio_dev_warn(&radio->videodev->dev, |
489 | "amradio_start failed\n"); | 489 | "amradio_start failed\n"); |
490 | return -1; | 490 | return -1; |
491 | } | 491 | } |
492 | } | 492 | } |
493 | return 0; | 493 | return 0; |
494 | } | 494 | } |
495 | return -EINVAL; | 495 | return -EINVAL; |
496 | } | 496 | } |
497 | 497 | ||
498 | /* vidioc_g_audio - get audio attributes */ | 498 | /* vidioc_g_audio - get audio attributes */ |
499 | static int vidioc_g_audio(struct file *file, void *priv, | 499 | static int vidioc_g_audio(struct file *file, void *priv, |
500 | struct v4l2_audio *a) | 500 | struct v4l2_audio *a) |
501 | { | 501 | { |
502 | if (a->index > 1) | 502 | if (a->index > 1) |
503 | return -EINVAL; | 503 | return -EINVAL; |
504 | 504 | ||
505 | strcpy(a->name, "Radio"); | 505 | strcpy(a->name, "Radio"); |
506 | a->capability = V4L2_AUDCAP_STEREO; | 506 | a->capability = V4L2_AUDCAP_STEREO; |
507 | return 0; | 507 | return 0; |
508 | } | 508 | } |
509 | 509 | ||
510 | /* vidioc_s_audio - set audio attributes */ | 510 | /* vidioc_s_audio - set audio attributes */ |
511 | static int vidioc_s_audio(struct file *file, void *priv, | 511 | static int vidioc_s_audio(struct file *file, void *priv, |
512 | struct v4l2_audio *a) | 512 | struct v4l2_audio *a) |
513 | { | 513 | { |
514 | if (a->index != 0) | 514 | if (a->index != 0) |
515 | return -EINVAL; | 515 | return -EINVAL; |
516 | return 0; | 516 | return 0; |
517 | } | 517 | } |
518 | 518 | ||
519 | /* vidioc_g_input - get input */ | 519 | /* vidioc_g_input - get input */ |
520 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | 520 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) |
521 | { | 521 | { |
522 | *i = 0; | 522 | *i = 0; |
523 | return 0; | 523 | return 0; |
524 | } | 524 | } |
525 | 525 | ||
526 | /* vidioc_s_input - set input */ | 526 | /* vidioc_s_input - set input */ |
527 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | 527 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) |
528 | { | 528 | { |
529 | if (i != 0) | 529 | if (i != 0) |
530 | return -EINVAL; | 530 | return -EINVAL; |
531 | return 0; | 531 | return 0; |
532 | } | 532 | } |
533 | 533 | ||
534 | /* open device - amradio_start() and amradio_setfreq() */ | 534 | /* open device - amradio_start() and amradio_setfreq() */ |
535 | static int usb_amradio_open(struct file *file) | 535 | static int usb_amradio_open(struct file *file) |
536 | { | 536 | { |
537 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 537 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
538 | int retval; | 538 | int retval; |
539 | 539 | ||
540 | lock_kernel(); | 540 | lock_kernel(); |
541 | 541 | ||
542 | radio->users = 1; | 542 | radio->users = 1; |
543 | radio->muted = 1; | 543 | radio->muted = 1; |
544 | 544 | ||
545 | retval = amradio_set_mute(radio, AMRADIO_START); | 545 | retval = amradio_set_mute(radio, AMRADIO_START); |
546 | if (retval < 0) { | 546 | if (retval < 0) { |
547 | amradio_dev_warn(&radio->videodev->dev, | 547 | amradio_dev_warn(&radio->videodev->dev, |
548 | "radio did not start up properly\n"); | 548 | "radio did not start up properly\n"); |
549 | radio->users = 0; | 549 | radio->users = 0; |
550 | unlock_kernel(); | 550 | unlock_kernel(); |
551 | return -EIO; | 551 | return -EIO; |
552 | } | 552 | } |
553 | 553 | ||
554 | retval = amradio_set_stereo(radio, WANT_STEREO); | 554 | retval = amradio_set_stereo(radio, WANT_STEREO); |
555 | if (retval < 0) | 555 | if (retval < 0) |
556 | amradio_dev_warn(&radio->videodev->dev, | 556 | amradio_dev_warn(&radio->videodev->dev, |
557 | "set stereo failed\n"); | 557 | "set stereo failed\n"); |
558 | 558 | ||
559 | retval = amradio_setfreq(radio, radio->curfreq); | 559 | retval = amradio_setfreq(radio, radio->curfreq); |
560 | if (retval < 0) | 560 | if (retval < 0) |
561 | amradio_dev_warn(&radio->videodev->dev, | 561 | amradio_dev_warn(&radio->videodev->dev, |
562 | "set frequency failed\n"); | 562 | "set frequency failed\n"); |
563 | 563 | ||
564 | unlock_kernel(); | 564 | unlock_kernel(); |
565 | return 0; | 565 | return 0; |
566 | } | 566 | } |
567 | 567 | ||
568 | /*close device */ | 568 | /*close device */ |
569 | static int usb_amradio_close(struct file *file) | 569 | static int usb_amradio_close(struct file *file) |
570 | { | 570 | { |
571 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); | 571 | struct amradio_device *radio = video_get_drvdata(video_devdata(file)); |
572 | int retval; | 572 | int retval; |
573 | 573 | ||
574 | if (!radio) | 574 | if (!radio) |
575 | return -ENODEV; | 575 | return -ENODEV; |
576 | 576 | ||
577 | mutex_lock(&radio->lock); | 577 | mutex_lock(&radio->lock); |
578 | radio->users = 0; | 578 | radio->users = 0; |
579 | mutex_unlock(&radio->lock); | 579 | mutex_unlock(&radio->lock); |
580 | 580 | ||
581 | if (!radio->removed) { | 581 | if (!radio->removed) { |
582 | retval = amradio_set_mute(radio, AMRADIO_STOP); | 582 | retval = amradio_set_mute(radio, AMRADIO_STOP); |
583 | if (retval < 0) | 583 | if (retval < 0) |
584 | amradio_dev_warn(&radio->videodev->dev, | 584 | amradio_dev_warn(&radio->videodev->dev, |
585 | "amradio_stop failed\n"); | 585 | "amradio_stop failed\n"); |
586 | } | 586 | } |
587 | 587 | ||
588 | return 0; | 588 | return 0; |
589 | } | 589 | } |
590 | 590 | ||
591 | /* Suspend device - stop device. Need to be checked and fixed */ | 591 | /* Suspend device - stop device. Need to be checked and fixed */ |
592 | static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) | 592 | static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) |
593 | { | 593 | { |
594 | struct amradio_device *radio = usb_get_intfdata(intf); | 594 | struct amradio_device *radio = usb_get_intfdata(intf); |
595 | int retval; | 595 | int retval; |
596 | 596 | ||
597 | retval = amradio_set_mute(radio, AMRADIO_STOP); | 597 | retval = amradio_set_mute(radio, AMRADIO_STOP); |
598 | if (retval < 0) | 598 | if (retval < 0) |
599 | dev_warn(&intf->dev, "amradio_stop failed\n"); | 599 | dev_warn(&intf->dev, "amradio_stop failed\n"); |
600 | 600 | ||
601 | dev_info(&intf->dev, "going into suspend..\n"); | 601 | dev_info(&intf->dev, "going into suspend..\n"); |
602 | 602 | ||
603 | return 0; | 603 | return 0; |
604 | } | 604 | } |
605 | 605 | ||
606 | /* Resume device - start device. Need to be checked and fixed */ | 606 | /* Resume device - start device. Need to be checked and fixed */ |
607 | static int usb_amradio_resume(struct usb_interface *intf) | 607 | static int usb_amradio_resume(struct usb_interface *intf) |
608 | { | 608 | { |
609 | struct amradio_device *radio = usb_get_intfdata(intf); | 609 | struct amradio_device *radio = usb_get_intfdata(intf); |
610 | int retval; | 610 | int retval; |
611 | 611 | ||
612 | retval = amradio_set_mute(radio, AMRADIO_START); | 612 | retval = amradio_set_mute(radio, AMRADIO_START); |
613 | if (retval < 0) | 613 | if (retval < 0) |
614 | dev_warn(&intf->dev, "amradio_start failed\n"); | 614 | dev_warn(&intf->dev, "amradio_start failed\n"); |
615 | 615 | ||
616 | dev_info(&intf->dev, "coming out of suspend..\n"); | 616 | dev_info(&intf->dev, "coming out of suspend..\n"); |
617 | 617 | ||
618 | return 0; | 618 | return 0; |
619 | } | 619 | } |
620 | 620 | ||
621 | /* File system interface */ | 621 | /* File system interface */ |
622 | static const struct v4l2_file_operations usb_amradio_fops = { | 622 | static const struct v4l2_file_operations usb_amradio_fops = { |
623 | .owner = THIS_MODULE, | 623 | .owner = THIS_MODULE, |
624 | .open = usb_amradio_open, | 624 | .open = usb_amradio_open, |
625 | .release = usb_amradio_close, | 625 | .release = usb_amradio_close, |
626 | .ioctl = video_ioctl2, | 626 | .ioctl = video_ioctl2, |
627 | }; | 627 | }; |
628 | 628 | ||
629 | static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = { | 629 | static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = { |
630 | .vidioc_querycap = vidioc_querycap, | 630 | .vidioc_querycap = vidioc_querycap, |
631 | .vidioc_g_tuner = vidioc_g_tuner, | 631 | .vidioc_g_tuner = vidioc_g_tuner, |
632 | .vidioc_s_tuner = vidioc_s_tuner, | 632 | .vidioc_s_tuner = vidioc_s_tuner, |
633 | .vidioc_g_frequency = vidioc_g_frequency, | 633 | .vidioc_g_frequency = vidioc_g_frequency, |
634 | .vidioc_s_frequency = vidioc_s_frequency, | 634 | .vidioc_s_frequency = vidioc_s_frequency, |
635 | .vidioc_queryctrl = vidioc_queryctrl, | 635 | .vidioc_queryctrl = vidioc_queryctrl, |
636 | .vidioc_g_ctrl = vidioc_g_ctrl, | 636 | .vidioc_g_ctrl = vidioc_g_ctrl, |
637 | .vidioc_s_ctrl = vidioc_s_ctrl, | 637 | .vidioc_s_ctrl = vidioc_s_ctrl, |
638 | .vidioc_g_audio = vidioc_g_audio, | 638 | .vidioc_g_audio = vidioc_g_audio, |
639 | .vidioc_s_audio = vidioc_s_audio, | 639 | .vidioc_s_audio = vidioc_s_audio, |
640 | .vidioc_g_input = vidioc_g_input, | 640 | .vidioc_g_input = vidioc_g_input, |
641 | .vidioc_s_input = vidioc_s_input, | 641 | .vidioc_s_input = vidioc_s_input, |
642 | }; | 642 | }; |
643 | 643 | ||
644 | static void usb_amradio_video_device_release(struct video_device *videodev) | 644 | static void usb_amradio_video_device_release(struct video_device *videodev) |
645 | { | 645 | { |
646 | struct amradio_device *radio = video_get_drvdata(videodev); | 646 | struct amradio_device *radio = video_get_drvdata(videodev); |
647 | 647 | ||
648 | /* we call v4l to free radio->videodev */ | 648 | /* we call v4l to free radio->videodev */ |
649 | video_device_release(videodev); | 649 | video_device_release(videodev); |
650 | 650 | ||
651 | v4l2_device_unregister(&radio->v4l2_dev); | 651 | v4l2_device_unregister(&radio->v4l2_dev); |
652 | 652 | ||
653 | /* free rest memory */ | 653 | /* free rest memory */ |
654 | kfree(radio->buffer); | 654 | kfree(radio->buffer); |
655 | kfree(radio); | 655 | kfree(radio); |
656 | } | 656 | } |
657 | 657 | ||
658 | /* check if the device is present and register with v4l and usb if it is */ | 658 | /* check if the device is present and register with v4l and usb if it is */ |
659 | static int usb_amradio_probe(struct usb_interface *intf, | 659 | static int usb_amradio_probe(struct usb_interface *intf, |
660 | const struct usb_device_id *id) | 660 | const struct usb_device_id *id) |
661 | { | 661 | { |
662 | struct amradio_device *radio; | 662 | struct amradio_device *radio; |
663 | struct v4l2_device *v4l2_dev; | 663 | struct v4l2_device *v4l2_dev; |
664 | int retval; | 664 | int retval; |
665 | 665 | ||
666 | radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL); | 666 | radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL); |
667 | 667 | ||
668 | if (!radio) { | 668 | if (!radio) { |
669 | dev_err(&intf->dev, "kmalloc for amradio_device failed\n"); | 669 | dev_err(&intf->dev, "kmalloc for amradio_device failed\n"); |
670 | return -ENOMEM; | 670 | return -ENOMEM; |
671 | } | 671 | } |
672 | 672 | ||
673 | radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); | 673 | radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); |
674 | 674 | ||
675 | if (!radio->buffer) { | 675 | if (!radio->buffer) { |
676 | dev_err(&intf->dev, "kmalloc for radio->buffer failed\n"); | 676 | dev_err(&intf->dev, "kmalloc for radio->buffer failed\n"); |
677 | kfree(radio); | 677 | kfree(radio); |
678 | return -ENOMEM; | 678 | return -ENOMEM; |
679 | } | 679 | } |
680 | 680 | ||
681 | v4l2_dev = &radio->v4l2_dev; | 681 | v4l2_dev = &radio->v4l2_dev; |
682 | retval = v4l2_device_register(&intf->dev, v4l2_dev); | 682 | retval = v4l2_device_register(&intf->dev, v4l2_dev); |
683 | if (retval < 0) { | 683 | if (retval < 0) { |
684 | dev_err(&intf->dev, "couldn't register v4l2_device\n"); | 684 | dev_err(&intf->dev, "couldn't register v4l2_device\n"); |
685 | kfree(radio->buffer); | 685 | kfree(radio->buffer); |
686 | kfree(radio); | 686 | kfree(radio); |
687 | return retval; | 687 | return retval; |
688 | } | 688 | } |
689 | 689 | ||
690 | radio->videodev = video_device_alloc(); | 690 | radio->videodev = video_device_alloc(); |
691 | 691 | ||
692 | if (!radio->videodev) { | 692 | if (!radio->videodev) { |
693 | dev_err(&intf->dev, "video_device_alloc failed\n"); | 693 | dev_err(&intf->dev, "video_device_alloc failed\n"); |
694 | kfree(radio->buffer); | 694 | kfree(radio->buffer); |
695 | kfree(radio); | 695 | kfree(radio); |
696 | return -ENOMEM; | 696 | return -ENOMEM; |
697 | } | 697 | } |
698 | 698 | ||
699 | strlcpy(radio->videodev->name, v4l2_dev->name, sizeof(radio->videodev->name)); | 699 | strlcpy(radio->videodev->name, v4l2_dev->name, sizeof(radio->videodev->name)); |
700 | radio->videodev->v4l2_dev = v4l2_dev; | 700 | radio->videodev->v4l2_dev = v4l2_dev; |
701 | radio->videodev->fops = &usb_amradio_fops; | 701 | radio->videodev->fops = &usb_amradio_fops; |
702 | radio->videodev->ioctl_ops = &usb_amradio_ioctl_ops; | 702 | radio->videodev->ioctl_ops = &usb_amradio_ioctl_ops; |
703 | radio->videodev->release = usb_amradio_video_device_release; | 703 | radio->videodev->release = usb_amradio_video_device_release; |
704 | 704 | ||
705 | radio->removed = 0; | 705 | radio->removed = 0; |
706 | radio->users = 0; | 706 | radio->users = 0; |
707 | radio->usbdev = interface_to_usbdev(intf); | 707 | radio->usbdev = interface_to_usbdev(intf); |
708 | radio->curfreq = 95.16 * FREQ_MUL; | 708 | radio->curfreq = 95.16 * FREQ_MUL; |
709 | radio->stereo = -1; | 709 | radio->stereo = -1; |
710 | 710 | ||
711 | mutex_init(&radio->lock); | 711 | mutex_init(&radio->lock); |
712 | 712 | ||
713 | video_set_drvdata(radio->videodev, radio); | 713 | video_set_drvdata(radio->videodev, radio); |
714 | 714 | ||
715 | retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); | 715 | retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); |
716 | if (retval < 0) { | 716 | if (retval < 0) { |
717 | dev_err(&intf->dev, "could not register video device\n"); | 717 | dev_err(&intf->dev, "could not register video device\n"); |
718 | video_device_release(radio->videodev); | 718 | video_device_release(radio->videodev); |
719 | v4l2_device_unregister(v4l2_dev); | 719 | v4l2_device_unregister(v4l2_dev); |
720 | kfree(radio->buffer); | 720 | kfree(radio->buffer); |
721 | kfree(radio); | 721 | kfree(radio); |
722 | return -EIO; | 722 | return -EIO; |
723 | } | 723 | } |
724 | 724 | ||
725 | usb_set_intfdata(intf, radio); | 725 | usb_set_intfdata(intf, radio); |
726 | return 0; | 726 | return 0; |
727 | } | 727 | } |
728 | 728 | ||
729 | static int __init amradio_init(void) | 729 | static int __init amradio_init(void) |
730 | { | 730 | { |
731 | int retval = usb_register(&usb_amradio_driver); | 731 | int retval = usb_register(&usb_amradio_driver); |
732 | 732 | ||
733 | pr_info(KBUILD_MODNAME | 733 | pr_info(KBUILD_MODNAME |
734 | ": version " DRIVER_VERSION " " DRIVER_DESC "\n"); | 734 | ": version " DRIVER_VERSION " " DRIVER_DESC "\n"); |
735 | 735 | ||
736 | if (retval) | 736 | if (retval) |
737 | pr_err(KBUILD_MODNAME | 737 | pr_err(KBUILD_MODNAME |
738 | ": usb_register failed. Error number %d\n", retval); | 738 | ": usb_register failed. Error number %d\n", retval); |
739 | 739 | ||
740 | return retval; | 740 | return retval; |
741 | } | 741 | } |
742 | 742 | ||
743 | static void __exit amradio_exit(void) | 743 | static void __exit amradio_exit(void) |
744 | { | 744 | { |
745 | usb_deregister(&usb_amradio_driver); | 745 | usb_deregister(&usb_amradio_driver); |
746 | } | 746 | } |
747 | 747 | ||
748 | module_init(amradio_init); | 748 | module_init(amradio_init); |
749 | module_exit(amradio_exit); | 749 | module_exit(amradio_exit); |
750 | 750 | ||
751 | 751 |
drivers/message/fusion/mptbase.c
1 | /* | 1 | /* |
2 | * linux/drivers/message/fusion/mptbase.c | 2 | * linux/drivers/message/fusion/mptbase.c |
3 | * This is the Fusion MPT base driver which supports multiple | 3 | * This is the Fusion MPT base driver which supports multiple |
4 | * (SCSI + LAN) specialized protocol drivers. | 4 | * (SCSI + LAN) specialized protocol drivers. |
5 | * For use with LSI PCI chip/adapter(s) | 5 | * For use with LSI PCI chip/adapter(s) |
6 | * running LSI Fusion MPT (Message Passing Technology) firmware. | 6 | * running LSI Fusion MPT (Message Passing Technology) firmware. |
7 | * | 7 | * |
8 | * Copyright (c) 1999-2008 LSI Corporation | 8 | * Copyright (c) 1999-2008 LSI Corporation |
9 | * (mailto:DL-MPTFusionLinux@lsi.com) | 9 | * (mailto:DL-MPTFusionLinux@lsi.com) |
10 | * | 10 | * |
11 | */ | 11 | */ |
12 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 12 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
13 | /* | 13 | /* |
14 | This program is free software; you can redistribute it and/or modify | 14 | This program is free software; you can redistribute it and/or modify |
15 | it under the terms of the GNU General Public License as published by | 15 | it under the terms of the GNU General Public License as published by |
16 | the Free Software Foundation; version 2 of the License. | 16 | the Free Software Foundation; version 2 of the License. |
17 | 17 | ||
18 | This program is distributed in the hope that it will be useful, | 18 | This program is distributed in the hope that it will be useful, |
19 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | GNU General Public License for more details. | 21 | GNU General Public License for more details. |
22 | 22 | ||
23 | NO WARRANTY | 23 | NO WARRANTY |
24 | THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR | 24 | THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR |
25 | CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT | 25 | CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT |
26 | LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, | 26 | LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, |
27 | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is | 27 | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is |
28 | solely responsible for determining the appropriateness of using and | 28 | solely responsible for determining the appropriateness of using and |
29 | distributing the Program and assumes all risks associated with its | 29 | distributing the Program and assumes all risks associated with its |
30 | exercise of rights under this Agreement, including but not limited to | 30 | exercise of rights under this Agreement, including but not limited to |
31 | the risks and costs of program errors, damage to or loss of data, | 31 | the risks and costs of program errors, damage to or loss of data, |
32 | programs or equipment, and unavailability or interruption of operations. | 32 | programs or equipment, and unavailability or interruption of operations. |
33 | 33 | ||
34 | DISCLAIMER OF LIABILITY | 34 | DISCLAIMER OF LIABILITY |
35 | NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY | 35 | NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY |
36 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 36 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
37 | DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND | 37 | DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND |
38 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | 38 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR |
39 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | 39 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
40 | USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED | 40 | USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED |
41 | HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES | 41 | HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES |
42 | 42 | ||
43 | You should have received a copy of the GNU General Public License | 43 | You should have received a copy of the GNU General Public License |
44 | along with this program; if not, write to the Free Software | 44 | along with this program; if not, write to the Free Software |
45 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 45 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
46 | */ | 46 | */ |
47 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 47 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
48 | 48 | ||
49 | #include <linux/kernel.h> | 49 | #include <linux/kernel.h> |
50 | #include <linux/module.h> | 50 | #include <linux/module.h> |
51 | #include <linux/errno.h> | 51 | #include <linux/errno.h> |
52 | #include <linux/init.h> | 52 | #include <linux/init.h> |
53 | #include <linux/slab.h> | 53 | #include <linux/slab.h> |
54 | #include <linux/types.h> | 54 | #include <linux/types.h> |
55 | #include <linux/pci.h> | 55 | #include <linux/pci.h> |
56 | #include <linux/kdev_t.h> | 56 | #include <linux/kdev_t.h> |
57 | #include <linux/blkdev.h> | 57 | #include <linux/blkdev.h> |
58 | #include <linux/delay.h> | 58 | #include <linux/delay.h> |
59 | #include <linux/interrupt.h> /* needed for in_interrupt() proto */ | 59 | #include <linux/interrupt.h> /* needed for in_interrupt() proto */ |
60 | #include <linux/dma-mapping.h> | 60 | #include <linux/dma-mapping.h> |
61 | #include <asm/io.h> | 61 | #include <asm/io.h> |
62 | #ifdef CONFIG_MTRR | 62 | #ifdef CONFIG_MTRR |
63 | #include <asm/mtrr.h> | 63 | #include <asm/mtrr.h> |
64 | #endif | 64 | #endif |
65 | 65 | ||
66 | #include "mptbase.h" | 66 | #include "mptbase.h" |
67 | #include "lsi/mpi_log_fc.h" | 67 | #include "lsi/mpi_log_fc.h" |
68 | 68 | ||
69 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 69 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
70 | #define my_NAME "Fusion MPT base driver" | 70 | #define my_NAME "Fusion MPT base driver" |
71 | #define my_VERSION MPT_LINUX_VERSION_COMMON | 71 | #define my_VERSION MPT_LINUX_VERSION_COMMON |
72 | #define MYNAM "mptbase" | 72 | #define MYNAM "mptbase" |
73 | 73 | ||
74 | MODULE_AUTHOR(MODULEAUTHOR); | 74 | MODULE_AUTHOR(MODULEAUTHOR); |
75 | MODULE_DESCRIPTION(my_NAME); | 75 | MODULE_DESCRIPTION(my_NAME); |
76 | MODULE_LICENSE("GPL"); | 76 | MODULE_LICENSE("GPL"); |
77 | MODULE_VERSION(my_VERSION); | 77 | MODULE_VERSION(my_VERSION); |
78 | 78 | ||
79 | /* | 79 | /* |
80 | * cmd line parameters | 80 | * cmd line parameters |
81 | */ | 81 | */ |
82 | 82 | ||
83 | static int mpt_msi_enable_spi; | 83 | static int mpt_msi_enable_spi; |
84 | module_param(mpt_msi_enable_spi, int, 0); | 84 | module_param(mpt_msi_enable_spi, int, 0); |
85 | MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI \ | 85 | MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI \ |
86 | controllers (default=0)"); | 86 | controllers (default=0)"); |
87 | 87 | ||
88 | static int mpt_msi_enable_fc; | 88 | static int mpt_msi_enable_fc; |
89 | module_param(mpt_msi_enable_fc, int, 0); | 89 | module_param(mpt_msi_enable_fc, int, 0); |
90 | MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \ | 90 | MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \ |
91 | controllers (default=0)"); | 91 | controllers (default=0)"); |
92 | 92 | ||
93 | static int mpt_msi_enable_sas; | 93 | static int mpt_msi_enable_sas; |
94 | module_param(mpt_msi_enable_sas, int, 0); | 94 | module_param(mpt_msi_enable_sas, int, 0); |
95 | MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \ | 95 | MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \ |
96 | controllers (default=0)"); | 96 | controllers (default=0)"); |
97 | 97 | ||
98 | 98 | ||
99 | static int mpt_channel_mapping; | 99 | static int mpt_channel_mapping; |
100 | module_param(mpt_channel_mapping, int, 0); | 100 | module_param(mpt_channel_mapping, int, 0); |
101 | MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)"); | 101 | MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)"); |
102 | 102 | ||
103 | static int mpt_debug_level; | 103 | static int mpt_debug_level; |
104 | static int mpt_set_debug_level(const char *val, struct kernel_param *kp); | 104 | static int mpt_set_debug_level(const char *val, struct kernel_param *kp); |
105 | module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int, | 105 | module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int, |
106 | &mpt_debug_level, 0600); | 106 | &mpt_debug_level, 0600); |
107 | MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h \ | 107 | MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h \ |
108 | - (default=0)"); | 108 | - (default=0)"); |
109 | 109 | ||
110 | int mpt_fwfault_debug; | 110 | int mpt_fwfault_debug; |
111 | EXPORT_SYMBOL(mpt_fwfault_debug); | 111 | EXPORT_SYMBOL(mpt_fwfault_debug); |
112 | module_param_call(mpt_fwfault_debug, param_set_int, param_get_int, | 112 | module_param_call(mpt_fwfault_debug, param_set_int, param_get_int, |
113 | &mpt_fwfault_debug, 0600); | 113 | &mpt_fwfault_debug, 0600); |
114 | MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault" | 114 | MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault" |
115 | " and halt Firmware on fault - (default=0)"); | 115 | " and halt Firmware on fault - (default=0)"); |
116 | 116 | ||
117 | 117 | ||
118 | 118 | ||
119 | #ifdef MFCNT | 119 | #ifdef MFCNT |
120 | static int mfcounter = 0; | 120 | static int mfcounter = 0; |
121 | #define PRINT_MF_COUNT 20000 | 121 | #define PRINT_MF_COUNT 20000 |
122 | #endif | 122 | #endif |
123 | 123 | ||
124 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 124 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
125 | /* | 125 | /* |
126 | * Public data... | 126 | * Public data... |
127 | */ | 127 | */ |
128 | 128 | ||
129 | static struct proc_dir_entry *mpt_proc_root_dir; | 129 | static struct proc_dir_entry *mpt_proc_root_dir; |
130 | 130 | ||
131 | #define WHOINIT_UNKNOWN 0xAA | 131 | #define WHOINIT_UNKNOWN 0xAA |
132 | 132 | ||
133 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 133 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
134 | /* | 134 | /* |
135 | * Private data... | 135 | * Private data... |
136 | */ | 136 | */ |
137 | /* Adapter link list */ | 137 | /* Adapter link list */ |
138 | LIST_HEAD(ioc_list); | 138 | LIST_HEAD(ioc_list); |
139 | /* Callback lookup table */ | 139 | /* Callback lookup table */ |
140 | static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS]; | 140 | static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS]; |
141 | /* Protocol driver class lookup table */ | 141 | /* Protocol driver class lookup table */ |
142 | static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS]; | 142 | static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS]; |
143 | /* Event handler lookup table */ | 143 | /* Event handler lookup table */ |
144 | static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS]; | 144 | static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS]; |
145 | /* Reset handler lookup table */ | 145 | /* Reset handler lookup table */ |
146 | static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS]; | 146 | static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS]; |
147 | static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS]; | 147 | static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS]; |
148 | 148 | ||
149 | 149 | ||
150 | /* | 150 | /* |
151 | * Driver Callback Index's | 151 | * Driver Callback Index's |
152 | */ | 152 | */ |
153 | static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS; | 153 | static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS; |
154 | static u8 last_drv_idx; | 154 | static u8 last_drv_idx; |
155 | 155 | ||
156 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 156 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
157 | /* | 157 | /* |
158 | * Forward protos... | 158 | * Forward protos... |
159 | */ | 159 | */ |
160 | static irqreturn_t mpt_interrupt(int irq, void *bus_id); | 160 | static irqreturn_t mpt_interrupt(int irq, void *bus_id); |
161 | static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, | 161 | static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, |
162 | MPT_FRAME_HDR *reply); | 162 | MPT_FRAME_HDR *reply); |
163 | static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, | 163 | static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, |
164 | u32 *req, int replyBytes, u16 *u16reply, int maxwait, | 164 | u32 *req, int replyBytes, u16 *u16reply, int maxwait, |
165 | int sleepFlag); | 165 | int sleepFlag); |
166 | static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag); | 166 | static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag); |
167 | static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev); | 167 | static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev); |
168 | static void mpt_adapter_disable(MPT_ADAPTER *ioc); | 168 | static void mpt_adapter_disable(MPT_ADAPTER *ioc); |
169 | static void mpt_adapter_dispose(MPT_ADAPTER *ioc); | 169 | static void mpt_adapter_dispose(MPT_ADAPTER *ioc); |
170 | 170 | ||
171 | static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc); | 171 | static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc); |
172 | static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag); | 172 | static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag); |
173 | static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason); | 173 | static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason); |
174 | static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag); | 174 | static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag); |
175 | static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag); | 175 | static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag); |
176 | static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag); | 176 | static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag); |
177 | static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag); | 177 | static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag); |
178 | static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag); | 178 | static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag); |
179 | static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag); | 179 | static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag); |
180 | static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag); | 180 | static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag); |
181 | static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag); | 181 | static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag); |
182 | static int PrimeIocFifos(MPT_ADAPTER *ioc); | 182 | static int PrimeIocFifos(MPT_ADAPTER *ioc); |
183 | static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag); | 183 | static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag); |
184 | static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag); | 184 | static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag); |
185 | static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag); | 185 | static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag); |
186 | static int GetLanConfigPages(MPT_ADAPTER *ioc); | 186 | static int GetLanConfigPages(MPT_ADAPTER *ioc); |
187 | static int GetIoUnitPage2(MPT_ADAPTER *ioc); | 187 | static int GetIoUnitPage2(MPT_ADAPTER *ioc); |
188 | int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode); | 188 | int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode); |
189 | static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum); | 189 | static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum); |
190 | static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum); | 190 | static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum); |
191 | static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc); | 191 | static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc); |
192 | static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc); | 192 | static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc); |
193 | static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc); | 193 | static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc); |
194 | static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, | 194 | static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, |
195 | int sleepFlag); | 195 | int sleepFlag); |
196 | static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp); | 196 | static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp); |
197 | static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag); | 197 | static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag); |
198 | static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init); | 198 | static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init); |
199 | 199 | ||
200 | #ifdef CONFIG_PROC_FS | 200 | #ifdef CONFIG_PROC_FS |
201 | static int procmpt_summary_read(char *buf, char **start, off_t offset, | 201 | static int procmpt_summary_read(char *buf, char **start, off_t offset, |
202 | int request, int *eof, void *data); | 202 | int request, int *eof, void *data); |
203 | static int procmpt_version_read(char *buf, char **start, off_t offset, | 203 | static int procmpt_version_read(char *buf, char **start, off_t offset, |
204 | int request, int *eof, void *data); | 204 | int request, int *eof, void *data); |
205 | static int procmpt_iocinfo_read(char *buf, char **start, off_t offset, | 205 | static int procmpt_iocinfo_read(char *buf, char **start, off_t offset, |
206 | int request, int *eof, void *data); | 206 | int request, int *eof, void *data); |
207 | #endif | 207 | #endif |
208 | static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc); | 208 | static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc); |
209 | 209 | ||
210 | static int ProcessEventNotification(MPT_ADAPTER *ioc, | 210 | static int ProcessEventNotification(MPT_ADAPTER *ioc, |
211 | EventNotificationReply_t *evReply, int *evHandlers); | 211 | EventNotificationReply_t *evReply, int *evHandlers); |
212 | static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf); | 212 | static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf); |
213 | static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info); | 213 | static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info); |
214 | static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info); | 214 | static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info); |
215 | static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info); | 215 | static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info); |
216 | static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc); | 216 | static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc); |
217 | static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc); | 217 | static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc); |
218 | 218 | ||
219 | /* module entry point */ | 219 | /* module entry point */ |
220 | static int __init fusion_init (void); | 220 | static int __init fusion_init (void); |
221 | static void __exit fusion_exit (void); | 221 | static void __exit fusion_exit (void); |
222 | 222 | ||
223 | #define CHIPREG_READ32(addr) readl_relaxed(addr) | 223 | #define CHIPREG_READ32(addr) readl_relaxed(addr) |
224 | #define CHIPREG_READ32_dmasync(addr) readl(addr) | 224 | #define CHIPREG_READ32_dmasync(addr) readl(addr) |
225 | #define CHIPREG_WRITE32(addr,val) writel(val, addr) | 225 | #define CHIPREG_WRITE32(addr,val) writel(val, addr) |
226 | #define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr) | 226 | #define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr) |
227 | #define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr) | 227 | #define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr) |
228 | 228 | ||
229 | static void | 229 | static void |
230 | pci_disable_io_access(struct pci_dev *pdev) | 230 | pci_disable_io_access(struct pci_dev *pdev) |
231 | { | 231 | { |
232 | u16 command_reg; | 232 | u16 command_reg; |
233 | 233 | ||
234 | pci_read_config_word(pdev, PCI_COMMAND, &command_reg); | 234 | pci_read_config_word(pdev, PCI_COMMAND, &command_reg); |
235 | command_reg &= ~1; | 235 | command_reg &= ~1; |
236 | pci_write_config_word(pdev, PCI_COMMAND, command_reg); | 236 | pci_write_config_word(pdev, PCI_COMMAND, command_reg); |
237 | } | 237 | } |
238 | 238 | ||
239 | static void | 239 | static void |
240 | pci_enable_io_access(struct pci_dev *pdev) | 240 | pci_enable_io_access(struct pci_dev *pdev) |
241 | { | 241 | { |
242 | u16 command_reg; | 242 | u16 command_reg; |
243 | 243 | ||
244 | pci_read_config_word(pdev, PCI_COMMAND, &command_reg); | 244 | pci_read_config_word(pdev, PCI_COMMAND, &command_reg); |
245 | command_reg |= 1; | 245 | command_reg |= 1; |
246 | pci_write_config_word(pdev, PCI_COMMAND, command_reg); | 246 | pci_write_config_word(pdev, PCI_COMMAND, command_reg); |
247 | } | 247 | } |
248 | 248 | ||
249 | static int mpt_set_debug_level(const char *val, struct kernel_param *kp) | 249 | static int mpt_set_debug_level(const char *val, struct kernel_param *kp) |
250 | { | 250 | { |
251 | int ret = param_set_int(val, kp); | 251 | int ret = param_set_int(val, kp); |
252 | MPT_ADAPTER *ioc; | 252 | MPT_ADAPTER *ioc; |
253 | 253 | ||
254 | if (ret) | 254 | if (ret) |
255 | return ret; | 255 | return ret; |
256 | 256 | ||
257 | list_for_each_entry(ioc, &ioc_list, list) | 257 | list_for_each_entry(ioc, &ioc_list, list) |
258 | ioc->debug_level = mpt_debug_level; | 258 | ioc->debug_level = mpt_debug_level; |
259 | return 0; | 259 | return 0; |
260 | } | 260 | } |
261 | 261 | ||
262 | /** | 262 | /** |
263 | * mpt_get_cb_idx - obtain cb_idx for registered driver | 263 | * mpt_get_cb_idx - obtain cb_idx for registered driver |
264 | * @dclass: class driver enum | 264 | * @dclass: class driver enum |
265 | * | 265 | * |
266 | * Returns cb_idx, or zero means it wasn't found | 266 | * Returns cb_idx, or zero means it wasn't found |
267 | **/ | 267 | **/ |
268 | static u8 | 268 | static u8 |
269 | mpt_get_cb_idx(MPT_DRIVER_CLASS dclass) | 269 | mpt_get_cb_idx(MPT_DRIVER_CLASS dclass) |
270 | { | 270 | { |
271 | u8 cb_idx; | 271 | u8 cb_idx; |
272 | 272 | ||
273 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) | 273 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) |
274 | if (MptDriverClass[cb_idx] == dclass) | 274 | if (MptDriverClass[cb_idx] == dclass) |
275 | return cb_idx; | 275 | return cb_idx; |
276 | return 0; | 276 | return 0; |
277 | } | 277 | } |
278 | 278 | ||
279 | /** | 279 | /** |
280 | * mpt_is_discovery_complete - determine if discovery has completed | 280 | * mpt_is_discovery_complete - determine if discovery has completed |
281 | * @ioc: per adatper instance | 281 | * @ioc: per adatper instance |
282 | * | 282 | * |
283 | * Returns 1 when discovery completed, else zero. | 283 | * Returns 1 when discovery completed, else zero. |
284 | */ | 284 | */ |
285 | static int | 285 | static int |
286 | mpt_is_discovery_complete(MPT_ADAPTER *ioc) | 286 | mpt_is_discovery_complete(MPT_ADAPTER *ioc) |
287 | { | 287 | { |
288 | ConfigExtendedPageHeader_t hdr; | 288 | ConfigExtendedPageHeader_t hdr; |
289 | CONFIGPARMS cfg; | 289 | CONFIGPARMS cfg; |
290 | SasIOUnitPage0_t *buffer; | 290 | SasIOUnitPage0_t *buffer; |
291 | dma_addr_t dma_handle; | 291 | dma_addr_t dma_handle; |
292 | int rc = 0; | 292 | int rc = 0; |
293 | 293 | ||
294 | memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t)); | 294 | memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t)); |
295 | memset(&cfg, 0, sizeof(CONFIGPARMS)); | 295 | memset(&cfg, 0, sizeof(CONFIGPARMS)); |
296 | hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; | 296 | hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; |
297 | hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; | 297 | hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; |
298 | hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; | 298 | hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; |
299 | cfg.cfghdr.ehdr = &hdr; | 299 | cfg.cfghdr.ehdr = &hdr; |
300 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 300 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
301 | 301 | ||
302 | if ((mpt_config(ioc, &cfg))) | 302 | if ((mpt_config(ioc, &cfg))) |
303 | goto out; | 303 | goto out; |
304 | if (!hdr.ExtPageLength) | 304 | if (!hdr.ExtPageLength) |
305 | goto out; | 305 | goto out; |
306 | 306 | ||
307 | buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, | 307 | buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, |
308 | &dma_handle); | 308 | &dma_handle); |
309 | if (!buffer) | 309 | if (!buffer) |
310 | goto out; | 310 | goto out; |
311 | 311 | ||
312 | cfg.physAddr = dma_handle; | 312 | cfg.physAddr = dma_handle; |
313 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | 313 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
314 | 314 | ||
315 | if ((mpt_config(ioc, &cfg))) | 315 | if ((mpt_config(ioc, &cfg))) |
316 | goto out_free_consistent; | 316 | goto out_free_consistent; |
317 | 317 | ||
318 | if (!(buffer->PhyData[0].PortFlags & | 318 | if (!(buffer->PhyData[0].PortFlags & |
319 | MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS)) | 319 | MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS)) |
320 | rc = 1; | 320 | rc = 1; |
321 | 321 | ||
322 | out_free_consistent: | 322 | out_free_consistent: |
323 | pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, | 323 | pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, |
324 | buffer, dma_handle); | 324 | buffer, dma_handle); |
325 | out: | 325 | out: |
326 | return rc; | 326 | return rc; |
327 | } | 327 | } |
328 | 328 | ||
329 | /** | 329 | /** |
330 | * mpt_fault_reset_work - work performed on workq after ioc fault | 330 | * mpt_fault_reset_work - work performed on workq after ioc fault |
331 | * @work: input argument, used to derive ioc | 331 | * @work: input argument, used to derive ioc |
332 | * | 332 | * |
333 | **/ | 333 | **/ |
334 | static void | 334 | static void |
335 | mpt_fault_reset_work(struct work_struct *work) | 335 | mpt_fault_reset_work(struct work_struct *work) |
336 | { | 336 | { |
337 | MPT_ADAPTER *ioc = | 337 | MPT_ADAPTER *ioc = |
338 | container_of(work, MPT_ADAPTER, fault_reset_work.work); | 338 | container_of(work, MPT_ADAPTER, fault_reset_work.work); |
339 | u32 ioc_raw_state; | 339 | u32 ioc_raw_state; |
340 | int rc; | 340 | int rc; |
341 | unsigned long flags; | 341 | unsigned long flags; |
342 | 342 | ||
343 | if (ioc->ioc_reset_in_progress || !ioc->active) | 343 | if (ioc->ioc_reset_in_progress || !ioc->active) |
344 | goto out; | 344 | goto out; |
345 | 345 | ||
346 | ioc_raw_state = mpt_GetIocState(ioc, 0); | 346 | ioc_raw_state = mpt_GetIocState(ioc, 0); |
347 | if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { | 347 | if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { |
348 | printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n", | 348 | printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n", |
349 | ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); | 349 | ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); |
350 | printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", | 350 | printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", |
351 | ioc->name, __func__); | 351 | ioc->name, __func__); |
352 | rc = mpt_HardResetHandler(ioc, CAN_SLEEP); | 352 | rc = mpt_HardResetHandler(ioc, CAN_SLEEP); |
353 | printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name, | 353 | printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name, |
354 | __func__, (rc == 0) ? "success" : "failed"); | 354 | __func__, (rc == 0) ? "success" : "failed"); |
355 | ioc_raw_state = mpt_GetIocState(ioc, 0); | 355 | ioc_raw_state = mpt_GetIocState(ioc, 0); |
356 | if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) | 356 | if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) |
357 | printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after " | 357 | printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after " |
358 | "reset (%04xh)\n", ioc->name, ioc_raw_state & | 358 | "reset (%04xh)\n", ioc->name, ioc_raw_state & |
359 | MPI_DOORBELL_DATA_MASK); | 359 | MPI_DOORBELL_DATA_MASK); |
360 | } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) { | 360 | } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) { |
361 | if ((mpt_is_discovery_complete(ioc))) { | 361 | if ((mpt_is_discovery_complete(ioc))) { |
362 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing " | 362 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing " |
363 | "discovery_quiesce_io flag\n", ioc->name)); | 363 | "discovery_quiesce_io flag\n", ioc->name)); |
364 | ioc->sas_discovery_quiesce_io = 0; | 364 | ioc->sas_discovery_quiesce_io = 0; |
365 | } | 365 | } |
366 | } | 366 | } |
367 | 367 | ||
368 | out: | 368 | out: |
369 | /* | 369 | /* |
370 | * Take turns polling alternate controller | 370 | * Take turns polling alternate controller |
371 | */ | 371 | */ |
372 | if (ioc->alt_ioc) | 372 | if (ioc->alt_ioc) |
373 | ioc = ioc->alt_ioc; | 373 | ioc = ioc->alt_ioc; |
374 | 374 | ||
375 | /* rearm the timer */ | 375 | /* rearm the timer */ |
376 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); | 376 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); |
377 | if (ioc->reset_work_q) | 377 | if (ioc->reset_work_q) |
378 | queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, | 378 | queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, |
379 | msecs_to_jiffies(MPT_POLLING_INTERVAL)); | 379 | msecs_to_jiffies(MPT_POLLING_INTERVAL)); |
380 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | 380 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); |
381 | } | 381 | } |
382 | 382 | ||
383 | 383 | ||
384 | /* | 384 | /* |
385 | * Process turbo (context) reply... | 385 | * Process turbo (context) reply... |
386 | */ | 386 | */ |
387 | static void | 387 | static void |
388 | mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa) | 388 | mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa) |
389 | { | 389 | { |
390 | MPT_FRAME_HDR *mf = NULL; | 390 | MPT_FRAME_HDR *mf = NULL; |
391 | MPT_FRAME_HDR *mr = NULL; | 391 | MPT_FRAME_HDR *mr = NULL; |
392 | u16 req_idx = 0; | 392 | u16 req_idx = 0; |
393 | u8 cb_idx; | 393 | u8 cb_idx; |
394 | 394 | ||
395 | dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n", | 395 | dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n", |
396 | ioc->name, pa)); | 396 | ioc->name, pa)); |
397 | 397 | ||
398 | switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) { | 398 | switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) { |
399 | case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT: | 399 | case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT: |
400 | req_idx = pa & 0x0000FFFF; | 400 | req_idx = pa & 0x0000FFFF; |
401 | cb_idx = (pa & 0x00FF0000) >> 16; | 401 | cb_idx = (pa & 0x00FF0000) >> 16; |
402 | mf = MPT_INDEX_2_MFPTR(ioc, req_idx); | 402 | mf = MPT_INDEX_2_MFPTR(ioc, req_idx); |
403 | break; | 403 | break; |
404 | case MPI_CONTEXT_REPLY_TYPE_LAN: | 404 | case MPI_CONTEXT_REPLY_TYPE_LAN: |
405 | cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER); | 405 | cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER); |
406 | /* | 406 | /* |
407 | * Blind set of mf to NULL here was fatal | 407 | * Blind set of mf to NULL here was fatal |
408 | * after lan_reply says "freeme" | 408 | * after lan_reply says "freeme" |
409 | * Fix sort of combined with an optimization here; | 409 | * Fix sort of combined with an optimization here; |
410 | * added explicit check for case where lan_reply | 410 | * added explicit check for case where lan_reply |
411 | * was just returning 1 and doing nothing else. | 411 | * was just returning 1 and doing nothing else. |
412 | * For this case skip the callback, but set up | 412 | * For this case skip the callback, but set up |
413 | * proper mf value first here:-) | 413 | * proper mf value first here:-) |
414 | */ | 414 | */ |
415 | if ((pa & 0x58000000) == 0x58000000) { | 415 | if ((pa & 0x58000000) == 0x58000000) { |
416 | req_idx = pa & 0x0000FFFF; | 416 | req_idx = pa & 0x0000FFFF; |
417 | mf = MPT_INDEX_2_MFPTR(ioc, req_idx); | 417 | mf = MPT_INDEX_2_MFPTR(ioc, req_idx); |
418 | mpt_free_msg_frame(ioc, mf); | 418 | mpt_free_msg_frame(ioc, mf); |
419 | mb(); | 419 | mb(); |
420 | return; | 420 | return; |
421 | break; | 421 | break; |
422 | } | 422 | } |
423 | mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); | 423 | mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); |
424 | break; | 424 | break; |
425 | case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET: | 425 | case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET: |
426 | cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER); | 426 | cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER); |
427 | mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); | 427 | mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); |
428 | break; | 428 | break; |
429 | default: | 429 | default: |
430 | cb_idx = 0; | 430 | cb_idx = 0; |
431 | BUG(); | 431 | BUG(); |
432 | } | 432 | } |
433 | 433 | ||
434 | /* Check for (valid) IO callback! */ | 434 | /* Check for (valid) IO callback! */ |
435 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || | 435 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || |
436 | MptCallbacks[cb_idx] == NULL) { | 436 | MptCallbacks[cb_idx] == NULL) { |
437 | printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", | 437 | printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", |
438 | __func__, ioc->name, cb_idx); | 438 | __func__, ioc->name, cb_idx); |
439 | goto out; | 439 | goto out; |
440 | } | 440 | } |
441 | 441 | ||
442 | if (MptCallbacks[cb_idx](ioc, mf, mr)) | 442 | if (MptCallbacks[cb_idx](ioc, mf, mr)) |
443 | mpt_free_msg_frame(ioc, mf); | 443 | mpt_free_msg_frame(ioc, mf); |
444 | out: | 444 | out: |
445 | mb(); | 445 | mb(); |
446 | } | 446 | } |
447 | 447 | ||
448 | static void | 448 | static void |
449 | mpt_reply(MPT_ADAPTER *ioc, u32 pa) | 449 | mpt_reply(MPT_ADAPTER *ioc, u32 pa) |
450 | { | 450 | { |
451 | MPT_FRAME_HDR *mf; | 451 | MPT_FRAME_HDR *mf; |
452 | MPT_FRAME_HDR *mr; | 452 | MPT_FRAME_HDR *mr; |
453 | u16 req_idx; | 453 | u16 req_idx; |
454 | u8 cb_idx; | 454 | u8 cb_idx; |
455 | int freeme; | 455 | int freeme; |
456 | 456 | ||
457 | u32 reply_dma_low; | 457 | u32 reply_dma_low; |
458 | u16 ioc_stat; | 458 | u16 ioc_stat; |
459 | 459 | ||
460 | /* non-TURBO reply! Hmmm, something may be up... | 460 | /* non-TURBO reply! Hmmm, something may be up... |
461 | * Newest turbo reply mechanism; get address | 461 | * Newest turbo reply mechanism; get address |
462 | * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)! | 462 | * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)! |
463 | */ | 463 | */ |
464 | 464 | ||
465 | /* Map DMA address of reply header to cpu address. | 465 | /* Map DMA address of reply header to cpu address. |
466 | * pa is 32 bits - but the dma address may be 32 or 64 bits | 466 | * pa is 32 bits - but the dma address may be 32 or 64 bits |
467 | * get offset based only only the low addresses | 467 | * get offset based only only the low addresses |
468 | */ | 468 | */ |
469 | 469 | ||
470 | reply_dma_low = (pa <<= 1); | 470 | reply_dma_low = (pa <<= 1); |
471 | mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames + | 471 | mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames + |
472 | (reply_dma_low - ioc->reply_frames_low_dma)); | 472 | (reply_dma_low - ioc->reply_frames_low_dma)); |
473 | 473 | ||
474 | req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx); | 474 | req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx); |
475 | cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx; | 475 | cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx; |
476 | mf = MPT_INDEX_2_MFPTR(ioc, req_idx); | 476 | mf = MPT_INDEX_2_MFPTR(ioc, req_idx); |
477 | 477 | ||
478 | dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n", | 478 | dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n", |
479 | ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function)); | 479 | ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function)); |
480 | DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr); | 480 | DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr); |
481 | 481 | ||
482 | /* Check/log IOC log info | 482 | /* Check/log IOC log info |
483 | */ | 483 | */ |
484 | ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus); | 484 | ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus); |
485 | if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { | 485 | if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { |
486 | u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo); | 486 | u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo); |
487 | if (ioc->bus_type == FC) | 487 | if (ioc->bus_type == FC) |
488 | mpt_fc_log_info(ioc, log_info); | 488 | mpt_fc_log_info(ioc, log_info); |
489 | else if (ioc->bus_type == SPI) | 489 | else if (ioc->bus_type == SPI) |
490 | mpt_spi_log_info(ioc, log_info); | 490 | mpt_spi_log_info(ioc, log_info); |
491 | else if (ioc->bus_type == SAS) | 491 | else if (ioc->bus_type == SAS) |
492 | mpt_sas_log_info(ioc, log_info); | 492 | mpt_sas_log_info(ioc, log_info); |
493 | } | 493 | } |
494 | 494 | ||
495 | if (ioc_stat & MPI_IOCSTATUS_MASK) | 495 | if (ioc_stat & MPI_IOCSTATUS_MASK) |
496 | mpt_iocstatus_info(ioc, (u32)ioc_stat, mf); | 496 | mpt_iocstatus_info(ioc, (u32)ioc_stat, mf); |
497 | 497 | ||
498 | /* Check for (valid) IO callback! */ | 498 | /* Check for (valid) IO callback! */ |
499 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || | 499 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || |
500 | MptCallbacks[cb_idx] == NULL) { | 500 | MptCallbacks[cb_idx] == NULL) { |
501 | printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", | 501 | printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", |
502 | __func__, ioc->name, cb_idx); | 502 | __func__, ioc->name, cb_idx); |
503 | freeme = 0; | 503 | freeme = 0; |
504 | goto out; | 504 | goto out; |
505 | } | 505 | } |
506 | 506 | ||
507 | freeme = MptCallbacks[cb_idx](ioc, mf, mr); | 507 | freeme = MptCallbacks[cb_idx](ioc, mf, mr); |
508 | 508 | ||
509 | out: | 509 | out: |
510 | /* Flush (non-TURBO) reply with a WRITE! */ | 510 | /* Flush (non-TURBO) reply with a WRITE! */ |
511 | CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa); | 511 | CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa); |
512 | 512 | ||
513 | if (freeme) | 513 | if (freeme) |
514 | mpt_free_msg_frame(ioc, mf); | 514 | mpt_free_msg_frame(ioc, mf); |
515 | mb(); | 515 | mb(); |
516 | } | 516 | } |
517 | 517 | ||
518 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 518 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
519 | /** | 519 | /** |
520 | * mpt_interrupt - MPT adapter (IOC) specific interrupt handler. | 520 | * mpt_interrupt - MPT adapter (IOC) specific interrupt handler. |
521 | * @irq: irq number (not used) | 521 | * @irq: irq number (not used) |
522 | * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure | 522 | * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure |
523 | * | 523 | * |
524 | * This routine is registered via the request_irq() kernel API call, | 524 | * This routine is registered via the request_irq() kernel API call, |
525 | * and handles all interrupts generated from a specific MPT adapter | 525 | * and handles all interrupts generated from a specific MPT adapter |
526 | * (also referred to as a IO Controller or IOC). | 526 | * (also referred to as a IO Controller or IOC). |
527 | * This routine must clear the interrupt from the adapter and does | 527 | * This routine must clear the interrupt from the adapter and does |
528 | * so by reading the reply FIFO. Multiple replies may be processed | 528 | * so by reading the reply FIFO. Multiple replies may be processed |
529 | * per single call to this routine. | 529 | * per single call to this routine. |
530 | * | 530 | * |
531 | * This routine handles register-level access of the adapter but | 531 | * This routine handles register-level access of the adapter but |
532 | * dispatches (calls) a protocol-specific callback routine to handle | 532 | * dispatches (calls) a protocol-specific callback routine to handle |
533 | * the protocol-specific details of the MPT request completion. | 533 | * the protocol-specific details of the MPT request completion. |
534 | */ | 534 | */ |
535 | static irqreturn_t | 535 | static irqreturn_t |
536 | mpt_interrupt(int irq, void *bus_id) | 536 | mpt_interrupt(int irq, void *bus_id) |
537 | { | 537 | { |
538 | MPT_ADAPTER *ioc = bus_id; | 538 | MPT_ADAPTER *ioc = bus_id; |
539 | u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); | 539 | u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); |
540 | 540 | ||
541 | if (pa == 0xFFFFFFFF) | 541 | if (pa == 0xFFFFFFFF) |
542 | return IRQ_NONE; | 542 | return IRQ_NONE; |
543 | 543 | ||
544 | /* | 544 | /* |
545 | * Drain the reply FIFO! | 545 | * Drain the reply FIFO! |
546 | */ | 546 | */ |
547 | do { | 547 | do { |
548 | if (pa & MPI_ADDRESS_REPLY_A_BIT) | 548 | if (pa & MPI_ADDRESS_REPLY_A_BIT) |
549 | mpt_reply(ioc, pa); | 549 | mpt_reply(ioc, pa); |
550 | else | 550 | else |
551 | mpt_turbo_reply(ioc, pa); | 551 | mpt_turbo_reply(ioc, pa); |
552 | pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); | 552 | pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); |
553 | } while (pa != 0xFFFFFFFF); | 553 | } while (pa != 0xFFFFFFFF); |
554 | 554 | ||
555 | return IRQ_HANDLED; | 555 | return IRQ_HANDLED; |
556 | } | 556 | } |
557 | 557 | ||
558 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 558 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
559 | /** | 559 | /** |
560 | * mptbase_reply - MPT base driver's callback routine | 560 | * mptbase_reply - MPT base driver's callback routine |
561 | * @ioc: Pointer to MPT_ADAPTER structure | 561 | * @ioc: Pointer to MPT_ADAPTER structure |
562 | * @req: Pointer to original MPT request frame | 562 | * @req: Pointer to original MPT request frame |
563 | * @reply: Pointer to MPT reply frame (NULL if TurboReply) | 563 | * @reply: Pointer to MPT reply frame (NULL if TurboReply) |
564 | * | 564 | * |
565 | * MPT base driver's callback routine; all base driver | 565 | * MPT base driver's callback routine; all base driver |
566 | * "internal" request/reply processing is routed here. | 566 | * "internal" request/reply processing is routed here. |
567 | * Currently used for EventNotification and EventAck handling. | 567 | * Currently used for EventNotification and EventAck handling. |
568 | * | 568 | * |
569 | * Returns 1 indicating original alloc'd request frame ptr | 569 | * Returns 1 indicating original alloc'd request frame ptr |
570 | * should be freed, or 0 if it shouldn't. | 570 | * should be freed, or 0 if it shouldn't. |
571 | */ | 571 | */ |
572 | static int | 572 | static int |
573 | mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) | 573 | mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) |
574 | { | 574 | { |
575 | EventNotificationReply_t *pEventReply; | 575 | EventNotificationReply_t *pEventReply; |
576 | u8 event; | 576 | u8 event; |
577 | int evHandlers; | 577 | int evHandlers; |
578 | int freereq = 1; | 578 | int freereq = 1; |
579 | 579 | ||
580 | switch (reply->u.hdr.Function) { | 580 | switch (reply->u.hdr.Function) { |
581 | case MPI_FUNCTION_EVENT_NOTIFICATION: | 581 | case MPI_FUNCTION_EVENT_NOTIFICATION: |
582 | pEventReply = (EventNotificationReply_t *)reply; | 582 | pEventReply = (EventNotificationReply_t *)reply; |
583 | evHandlers = 0; | 583 | evHandlers = 0; |
584 | ProcessEventNotification(ioc, pEventReply, &evHandlers); | 584 | ProcessEventNotification(ioc, pEventReply, &evHandlers); |
585 | event = le32_to_cpu(pEventReply->Event) & 0xFF; | 585 | event = le32_to_cpu(pEventReply->Event) & 0xFF; |
586 | if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) | 586 | if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) |
587 | freereq = 0; | 587 | freereq = 0; |
588 | if (event != MPI_EVENT_EVENT_CHANGE) | 588 | if (event != MPI_EVENT_EVENT_CHANGE) |
589 | break; | 589 | break; |
590 | case MPI_FUNCTION_CONFIG: | 590 | case MPI_FUNCTION_CONFIG: |
591 | case MPI_FUNCTION_SAS_IO_UNIT_CONTROL: | 591 | case MPI_FUNCTION_SAS_IO_UNIT_CONTROL: |
592 | ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; | 592 | ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; |
593 | if (reply) { | 593 | if (reply) { |
594 | ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID; | 594 | ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID; |
595 | memcpy(ioc->mptbase_cmds.reply, reply, | 595 | memcpy(ioc->mptbase_cmds.reply, reply, |
596 | min(MPT_DEFAULT_FRAME_SIZE, | 596 | min(MPT_DEFAULT_FRAME_SIZE, |
597 | 4 * reply->u.reply.MsgLength)); | 597 | 4 * reply->u.reply.MsgLength)); |
598 | } | 598 | } |
599 | if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { | 599 | if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { |
600 | ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING; | 600 | ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING; |
601 | complete(&ioc->mptbase_cmds.done); | 601 | complete(&ioc->mptbase_cmds.done); |
602 | } else | 602 | } else |
603 | freereq = 0; | 603 | freereq = 0; |
604 | if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF) | 604 | if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF) |
605 | freereq = 1; | 605 | freereq = 1; |
606 | break; | 606 | break; |
607 | case MPI_FUNCTION_EVENT_ACK: | 607 | case MPI_FUNCTION_EVENT_ACK: |
608 | devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 608 | devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
609 | "EventAck reply received\n", ioc->name)); | 609 | "EventAck reply received\n", ioc->name)); |
610 | break; | 610 | break; |
611 | default: | 611 | default: |
612 | printk(MYIOC_s_ERR_FMT | 612 | printk(MYIOC_s_ERR_FMT |
613 | "Unexpected msg function (=%02Xh) reply received!\n", | 613 | "Unexpected msg function (=%02Xh) reply received!\n", |
614 | ioc->name, reply->u.hdr.Function); | 614 | ioc->name, reply->u.hdr.Function); |
615 | break; | 615 | break; |
616 | } | 616 | } |
617 | 617 | ||
618 | /* | 618 | /* |
619 | * Conditionally tell caller to free the original | 619 | * Conditionally tell caller to free the original |
620 | * EventNotification/EventAck/unexpected request frame! | 620 | * EventNotification/EventAck/unexpected request frame! |
621 | */ | 621 | */ |
622 | return freereq; | 622 | return freereq; |
623 | } | 623 | } |
624 | 624 | ||
625 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 625 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
626 | /** | 626 | /** |
627 | * mpt_register - Register protocol-specific main callback handler. | 627 | * mpt_register - Register protocol-specific main callback handler. |
628 | * @cbfunc: callback function pointer | 628 | * @cbfunc: callback function pointer |
629 | * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value) | 629 | * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value) |
630 | * | 630 | * |
631 | * This routine is called by a protocol-specific driver (SCSI host, | 631 | * This routine is called by a protocol-specific driver (SCSI host, |
632 | * LAN, SCSI target) to register its reply callback routine. Each | 632 | * LAN, SCSI target) to register its reply callback routine. Each |
633 | * protocol-specific driver must do this before it will be able to | 633 | * protocol-specific driver must do this before it will be able to |
634 | * use any IOC resources, such as obtaining request frames. | 634 | * use any IOC resources, such as obtaining request frames. |
635 | * | 635 | * |
636 | * NOTES: The SCSI protocol driver currently calls this routine thrice | 636 | * NOTES: The SCSI protocol driver currently calls this routine thrice |
637 | * in order to register separate callbacks; one for "normal" SCSI IO; | 637 | * in order to register separate callbacks; one for "normal" SCSI IO; |
638 | * one for MptScsiTaskMgmt requests; one for Scan/DV requests. | 638 | * one for MptScsiTaskMgmt requests; one for Scan/DV requests. |
639 | * | 639 | * |
640 | * Returns u8 valued "handle" in the range (and S.O.D. order) | 640 | * Returns u8 valued "handle" in the range (and S.O.D. order) |
641 | * {N,...,7,6,5,...,1} if successful. | 641 | * {N,...,7,6,5,...,1} if successful. |
642 | * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be | 642 | * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be |
643 | * considered an error by the caller. | 643 | * considered an error by the caller. |
644 | */ | 644 | */ |
645 | u8 | 645 | u8 |
646 | mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) | 646 | mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) |
647 | { | 647 | { |
648 | u8 cb_idx; | 648 | u8 cb_idx; |
649 | last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS; | 649 | last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS; |
650 | 650 | ||
651 | /* | 651 | /* |
652 | * Search for empty callback slot in this order: {N,...,7,6,5,...,1} | 652 | * Search for empty callback slot in this order: {N,...,7,6,5,...,1} |
653 | * (slot/handle 0 is reserved!) | 653 | * (slot/handle 0 is reserved!) |
654 | */ | 654 | */ |
655 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { | 655 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { |
656 | if (MptCallbacks[cb_idx] == NULL) { | 656 | if (MptCallbacks[cb_idx] == NULL) { |
657 | MptCallbacks[cb_idx] = cbfunc; | 657 | MptCallbacks[cb_idx] = cbfunc; |
658 | MptDriverClass[cb_idx] = dclass; | 658 | MptDriverClass[cb_idx] = dclass; |
659 | MptEvHandlers[cb_idx] = NULL; | 659 | MptEvHandlers[cb_idx] = NULL; |
660 | last_drv_idx = cb_idx; | 660 | last_drv_idx = cb_idx; |
661 | break; | 661 | break; |
662 | } | 662 | } |
663 | } | 663 | } |
664 | 664 | ||
665 | return last_drv_idx; | 665 | return last_drv_idx; |
666 | } | 666 | } |
667 | 667 | ||
668 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 668 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
669 | /** | 669 | /** |
670 | * mpt_deregister - Deregister a protocol drivers resources. | 670 | * mpt_deregister - Deregister a protocol drivers resources. |
671 | * @cb_idx: previously registered callback handle | 671 | * @cb_idx: previously registered callback handle |
672 | * | 672 | * |
673 | * Each protocol-specific driver should call this routine when its | 673 | * Each protocol-specific driver should call this routine when its |
674 | * module is unloaded. | 674 | * module is unloaded. |
675 | */ | 675 | */ |
676 | void | 676 | void |
677 | mpt_deregister(u8 cb_idx) | 677 | mpt_deregister(u8 cb_idx) |
678 | { | 678 | { |
679 | if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) { | 679 | if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) { |
680 | MptCallbacks[cb_idx] = NULL; | 680 | MptCallbacks[cb_idx] = NULL; |
681 | MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER; | 681 | MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER; |
682 | MptEvHandlers[cb_idx] = NULL; | 682 | MptEvHandlers[cb_idx] = NULL; |
683 | 683 | ||
684 | last_drv_idx++; | 684 | last_drv_idx++; |
685 | } | 685 | } |
686 | } | 686 | } |
687 | 687 | ||
688 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 688 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
689 | /** | 689 | /** |
690 | * mpt_event_register - Register protocol-specific event callback handler. | 690 | * mpt_event_register - Register protocol-specific event callback handler. |
691 | * @cb_idx: previously registered (via mpt_register) callback handle | 691 | * @cb_idx: previously registered (via mpt_register) callback handle |
692 | * @ev_cbfunc: callback function | 692 | * @ev_cbfunc: callback function |
693 | * | 693 | * |
694 | * This routine can be called by one or more protocol-specific drivers | 694 | * This routine can be called by one or more protocol-specific drivers |
695 | * if/when they choose to be notified of MPT events. | 695 | * if/when they choose to be notified of MPT events. |
696 | * | 696 | * |
697 | * Returns 0 for success. | 697 | * Returns 0 for success. |
698 | */ | 698 | */ |
699 | int | 699 | int |
700 | mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc) | 700 | mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc) |
701 | { | 701 | { |
702 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) | 702 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) |
703 | return -1; | 703 | return -1; |
704 | 704 | ||
705 | MptEvHandlers[cb_idx] = ev_cbfunc; | 705 | MptEvHandlers[cb_idx] = ev_cbfunc; |
706 | return 0; | 706 | return 0; |
707 | } | 707 | } |
708 | 708 | ||
709 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 709 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
710 | /** | 710 | /** |
711 | * mpt_event_deregister - Deregister protocol-specific event callback handler | 711 | * mpt_event_deregister - Deregister protocol-specific event callback handler |
712 | * @cb_idx: previously registered callback handle | 712 | * @cb_idx: previously registered callback handle |
713 | * | 713 | * |
714 | * Each protocol-specific driver should call this routine | 714 | * Each protocol-specific driver should call this routine |
715 | * when it does not (or can no longer) handle events, | 715 | * when it does not (or can no longer) handle events, |
716 | * or when its module is unloaded. | 716 | * or when its module is unloaded. |
717 | */ | 717 | */ |
718 | void | 718 | void |
719 | mpt_event_deregister(u8 cb_idx) | 719 | mpt_event_deregister(u8 cb_idx) |
720 | { | 720 | { |
721 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) | 721 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) |
722 | return; | 722 | return; |
723 | 723 | ||
724 | MptEvHandlers[cb_idx] = NULL; | 724 | MptEvHandlers[cb_idx] = NULL; |
725 | } | 725 | } |
726 | 726 | ||
727 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 727 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
728 | /** | 728 | /** |
729 | * mpt_reset_register - Register protocol-specific IOC reset handler. | 729 | * mpt_reset_register - Register protocol-specific IOC reset handler. |
730 | * @cb_idx: previously registered (via mpt_register) callback handle | 730 | * @cb_idx: previously registered (via mpt_register) callback handle |
731 | * @reset_func: reset function | 731 | * @reset_func: reset function |
732 | * | 732 | * |
733 | * This routine can be called by one or more protocol-specific drivers | 733 | * This routine can be called by one or more protocol-specific drivers |
734 | * if/when they choose to be notified of IOC resets. | 734 | * if/when they choose to be notified of IOC resets. |
735 | * | 735 | * |
736 | * Returns 0 for success. | 736 | * Returns 0 for success. |
737 | */ | 737 | */ |
738 | int | 738 | int |
739 | mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func) | 739 | mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func) |
740 | { | 740 | { |
741 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) | 741 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) |
742 | return -1; | 742 | return -1; |
743 | 743 | ||
744 | MptResetHandlers[cb_idx] = reset_func; | 744 | MptResetHandlers[cb_idx] = reset_func; |
745 | return 0; | 745 | return 0; |
746 | } | 746 | } |
747 | 747 | ||
748 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 748 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
749 | /** | 749 | /** |
750 | * mpt_reset_deregister - Deregister protocol-specific IOC reset handler. | 750 | * mpt_reset_deregister - Deregister protocol-specific IOC reset handler. |
751 | * @cb_idx: previously registered callback handle | 751 | * @cb_idx: previously registered callback handle |
752 | * | 752 | * |
753 | * Each protocol-specific driver should call this routine | 753 | * Each protocol-specific driver should call this routine |
754 | * when it does not (or can no longer) handle IOC reset handling, | 754 | * when it does not (or can no longer) handle IOC reset handling, |
755 | * or when its module is unloaded. | 755 | * or when its module is unloaded. |
756 | */ | 756 | */ |
757 | void | 757 | void |
758 | mpt_reset_deregister(u8 cb_idx) | 758 | mpt_reset_deregister(u8 cb_idx) |
759 | { | 759 | { |
760 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) | 760 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) |
761 | return; | 761 | return; |
762 | 762 | ||
763 | MptResetHandlers[cb_idx] = NULL; | 763 | MptResetHandlers[cb_idx] = NULL; |
764 | } | 764 | } |
765 | 765 | ||
766 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 766 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
767 | /** | 767 | /** |
768 | * mpt_device_driver_register - Register device driver hooks | 768 | * mpt_device_driver_register - Register device driver hooks |
769 | * @dd_cbfunc: driver callbacks struct | 769 | * @dd_cbfunc: driver callbacks struct |
770 | * @cb_idx: MPT protocol driver index | 770 | * @cb_idx: MPT protocol driver index |
771 | */ | 771 | */ |
772 | int | 772 | int |
773 | mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx) | 773 | mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx) |
774 | { | 774 | { |
775 | MPT_ADAPTER *ioc; | 775 | MPT_ADAPTER *ioc; |
776 | const struct pci_device_id *id; | 776 | const struct pci_device_id *id; |
777 | 777 | ||
778 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) | 778 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) |
779 | return -EINVAL; | 779 | return -EINVAL; |
780 | 780 | ||
781 | MptDeviceDriverHandlers[cb_idx] = dd_cbfunc; | 781 | MptDeviceDriverHandlers[cb_idx] = dd_cbfunc; |
782 | 782 | ||
783 | /* call per pci device probe entry point */ | 783 | /* call per pci device probe entry point */ |
784 | list_for_each_entry(ioc, &ioc_list, list) { | 784 | list_for_each_entry(ioc, &ioc_list, list) { |
785 | id = ioc->pcidev->driver ? | 785 | id = ioc->pcidev->driver ? |
786 | ioc->pcidev->driver->id_table : NULL; | 786 | ioc->pcidev->driver->id_table : NULL; |
787 | if (dd_cbfunc->probe) | 787 | if (dd_cbfunc->probe) |
788 | dd_cbfunc->probe(ioc->pcidev, id); | 788 | dd_cbfunc->probe(ioc->pcidev, id); |
789 | } | 789 | } |
790 | 790 | ||
791 | return 0; | 791 | return 0; |
792 | } | 792 | } |
793 | 793 | ||
794 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 794 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
795 | /** | 795 | /** |
796 | * mpt_device_driver_deregister - DeRegister device driver hooks | 796 | * mpt_device_driver_deregister - DeRegister device driver hooks |
797 | * @cb_idx: MPT protocol driver index | 797 | * @cb_idx: MPT protocol driver index |
798 | */ | 798 | */ |
799 | void | 799 | void |
800 | mpt_device_driver_deregister(u8 cb_idx) | 800 | mpt_device_driver_deregister(u8 cb_idx) |
801 | { | 801 | { |
802 | struct mpt_pci_driver *dd_cbfunc; | 802 | struct mpt_pci_driver *dd_cbfunc; |
803 | MPT_ADAPTER *ioc; | 803 | MPT_ADAPTER *ioc; |
804 | 804 | ||
805 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) | 805 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) |
806 | return; | 806 | return; |
807 | 807 | ||
808 | dd_cbfunc = MptDeviceDriverHandlers[cb_idx]; | 808 | dd_cbfunc = MptDeviceDriverHandlers[cb_idx]; |
809 | 809 | ||
810 | list_for_each_entry(ioc, &ioc_list, list) { | 810 | list_for_each_entry(ioc, &ioc_list, list) { |
811 | if (dd_cbfunc->remove) | 811 | if (dd_cbfunc->remove) |
812 | dd_cbfunc->remove(ioc->pcidev); | 812 | dd_cbfunc->remove(ioc->pcidev); |
813 | } | 813 | } |
814 | 814 | ||
815 | MptDeviceDriverHandlers[cb_idx] = NULL; | 815 | MptDeviceDriverHandlers[cb_idx] = NULL; |
816 | } | 816 | } |
817 | 817 | ||
818 | 818 | ||
819 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 819 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
820 | /** | 820 | /** |
821 | * mpt_get_msg_frame - Obtain an MPT request frame from the pool | 821 | * mpt_get_msg_frame - Obtain an MPT request frame from the pool |
822 | * @cb_idx: Handle of registered MPT protocol driver | 822 | * @cb_idx: Handle of registered MPT protocol driver |
823 | * @ioc: Pointer to MPT adapter structure | 823 | * @ioc: Pointer to MPT adapter structure |
824 | * | 824 | * |
825 | * Obtain an MPT request frame from the pool (of 1024) that are | 825 | * Obtain an MPT request frame from the pool (of 1024) that are |
826 | * allocated per MPT adapter. | 826 | * allocated per MPT adapter. |
827 | * | 827 | * |
828 | * Returns pointer to a MPT request frame or %NULL if none are available | 828 | * Returns pointer to a MPT request frame or %NULL if none are available |
829 | * or IOC is not active. | 829 | * or IOC is not active. |
830 | */ | 830 | */ |
831 | MPT_FRAME_HDR* | 831 | MPT_FRAME_HDR* |
832 | mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc) | 832 | mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc) |
833 | { | 833 | { |
834 | MPT_FRAME_HDR *mf; | 834 | MPT_FRAME_HDR *mf; |
835 | unsigned long flags; | 835 | unsigned long flags; |
836 | u16 req_idx; /* Request index */ | 836 | u16 req_idx; /* Request index */ |
837 | 837 | ||
838 | /* validate handle and ioc identifier */ | 838 | /* validate handle and ioc identifier */ |
839 | 839 | ||
840 | #ifdef MFCNT | 840 | #ifdef MFCNT |
841 | if (!ioc->active) | 841 | if (!ioc->active) |
842 | printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame " | 842 | printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame " |
843 | "returning NULL!\n", ioc->name); | 843 | "returning NULL!\n", ioc->name); |
844 | #endif | 844 | #endif |
845 | 845 | ||
846 | /* If interrupts are not attached, do not return a request frame */ | 846 | /* If interrupts are not attached, do not return a request frame */ |
847 | if (!ioc->active) | 847 | if (!ioc->active) |
848 | return NULL; | 848 | return NULL; |
849 | 849 | ||
850 | spin_lock_irqsave(&ioc->FreeQlock, flags); | 850 | spin_lock_irqsave(&ioc->FreeQlock, flags); |
851 | if (!list_empty(&ioc->FreeQ)) { | 851 | if (!list_empty(&ioc->FreeQ)) { |
852 | int req_offset; | 852 | int req_offset; |
853 | 853 | ||
854 | mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR, | 854 | mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR, |
855 | u.frame.linkage.list); | 855 | u.frame.linkage.list); |
856 | list_del(&mf->u.frame.linkage.list); | 856 | list_del(&mf->u.frame.linkage.list); |
857 | mf->u.frame.linkage.arg1 = 0; | 857 | mf->u.frame.linkage.arg1 = 0; |
858 | mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */ | 858 | mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */ |
859 | req_offset = (u8 *)mf - (u8 *)ioc->req_frames; | 859 | req_offset = (u8 *)mf - (u8 *)ioc->req_frames; |
860 | /* u16! */ | 860 | /* u16! */ |
861 | req_idx = req_offset / ioc->req_sz; | 861 | req_idx = req_offset / ioc->req_sz; |
862 | mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); | 862 | mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); |
863 | mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; | 863 | mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; |
864 | /* Default, will be changed if necessary in SG generation */ | 864 | /* Default, will be changed if necessary in SG generation */ |
865 | ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; | 865 | ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; |
866 | #ifdef MFCNT | 866 | #ifdef MFCNT |
867 | ioc->mfcnt++; | 867 | ioc->mfcnt++; |
868 | #endif | 868 | #endif |
869 | } | 869 | } |
870 | else | 870 | else |
871 | mf = NULL; | 871 | mf = NULL; |
872 | spin_unlock_irqrestore(&ioc->FreeQlock, flags); | 872 | spin_unlock_irqrestore(&ioc->FreeQlock, flags); |
873 | 873 | ||
874 | #ifdef MFCNT | 874 | #ifdef MFCNT |
875 | if (mf == NULL) | 875 | if (mf == NULL) |
876 | printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! " | 876 | printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! " |
877 | "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt, | 877 | "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt, |
878 | ioc->req_depth); | 878 | ioc->req_depth); |
879 | mfcounter++; | 879 | mfcounter++; |
880 | if (mfcounter == PRINT_MF_COUNT) | 880 | if (mfcounter == PRINT_MF_COUNT) |
881 | printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name, | 881 | printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name, |
882 | ioc->mfcnt, ioc->req_depth); | 882 | ioc->mfcnt, ioc->req_depth); |
883 | #endif | 883 | #endif |
884 | 884 | ||
885 | dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n", | 885 | dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n", |
886 | ioc->name, cb_idx, ioc->id, mf)); | 886 | ioc->name, cb_idx, ioc->id, mf)); |
887 | return mf; | 887 | return mf; |
888 | } | 888 | } |
889 | 889 | ||
890 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 890 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
891 | /** | 891 | /** |
892 | * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC | 892 | * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC |
893 | * @cb_idx: Handle of registered MPT protocol driver | 893 | * @cb_idx: Handle of registered MPT protocol driver |
894 | * @ioc: Pointer to MPT adapter structure | 894 | * @ioc: Pointer to MPT adapter structure |
895 | * @mf: Pointer to MPT request frame | 895 | * @mf: Pointer to MPT request frame |
896 | * | 896 | * |
897 | * This routine posts an MPT request frame to the request post FIFO of a | 897 | * This routine posts an MPT request frame to the request post FIFO of a |
898 | * specific MPT adapter. | 898 | * specific MPT adapter. |
899 | */ | 899 | */ |
900 | void | 900 | void |
901 | mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) | 901 | mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) |
902 | { | 902 | { |
903 | u32 mf_dma_addr; | 903 | u32 mf_dma_addr; |
904 | int req_offset; | 904 | int req_offset; |
905 | u16 req_idx; /* Request index */ | 905 | u16 req_idx; /* Request index */ |
906 | 906 | ||
907 | /* ensure values are reset properly! */ | 907 | /* ensure values are reset properly! */ |
908 | mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */ | 908 | mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */ |
909 | req_offset = (u8 *)mf - (u8 *)ioc->req_frames; | 909 | req_offset = (u8 *)mf - (u8 *)ioc->req_frames; |
910 | /* u16! */ | 910 | /* u16! */ |
911 | req_idx = req_offset / ioc->req_sz; | 911 | req_idx = req_offset / ioc->req_sz; |
912 | mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); | 912 | mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); |
913 | mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; | 913 | mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; |
914 | 914 | ||
915 | DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf); | 915 | DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf); |
916 | 916 | ||
917 | mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx]; | 917 | mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx]; |
918 | dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d " | 918 | dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d " |
919 | "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, | 919 | "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, |
920 | ioc->RequestNB[req_idx])); | 920 | ioc->RequestNB[req_idx])); |
921 | CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr); | 921 | CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr); |
922 | } | 922 | } |
923 | 923 | ||
924 | /** | 924 | /** |
925 | * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame | 925 | * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame |
926 | * @cb_idx: Handle of registered MPT protocol driver | 926 | * @cb_idx: Handle of registered MPT protocol driver |
927 | * @ioc: Pointer to MPT adapter structure | 927 | * @ioc: Pointer to MPT adapter structure |
928 | * @mf: Pointer to MPT request frame | 928 | * @mf: Pointer to MPT request frame |
929 | * | 929 | * |
930 | * Send a protocol-specific MPT request frame to an IOC using | 930 | * Send a protocol-specific MPT request frame to an IOC using |
931 | * hi-priority request queue. | 931 | * hi-priority request queue. |
932 | * | 932 | * |
933 | * This routine posts an MPT request frame to the request post FIFO of a | 933 | * This routine posts an MPT request frame to the request post FIFO of a |
934 | * specific MPT adapter. | 934 | * specific MPT adapter. |
935 | **/ | 935 | **/ |
936 | void | 936 | void |
937 | mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) | 937 | mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) |
938 | { | 938 | { |
939 | u32 mf_dma_addr; | 939 | u32 mf_dma_addr; |
940 | int req_offset; | 940 | int req_offset; |
941 | u16 req_idx; /* Request index */ | 941 | u16 req_idx; /* Request index */ |
942 | 942 | ||
943 | /* ensure values are reset properly! */ | 943 | /* ensure values are reset properly! */ |
944 | mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; | 944 | mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; |
945 | req_offset = (u8 *)mf - (u8 *)ioc->req_frames; | 945 | req_offset = (u8 *)mf - (u8 *)ioc->req_frames; |
946 | req_idx = req_offset / ioc->req_sz; | 946 | req_idx = req_offset / ioc->req_sz; |
947 | mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); | 947 | mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); |
948 | mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; | 948 | mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; |
949 | 949 | ||
950 | DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf); | 950 | DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf); |
951 | 951 | ||
952 | mf_dma_addr = (ioc->req_frames_low_dma + req_offset); | 952 | mf_dma_addr = (ioc->req_frames_low_dma + req_offset); |
953 | dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n", | 953 | dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n", |
954 | ioc->name, mf_dma_addr, req_idx)); | 954 | ioc->name, mf_dma_addr, req_idx)); |
955 | CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr); | 955 | CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr); |
956 | } | 956 | } |
957 | 957 | ||
958 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 958 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
959 | /** | 959 | /** |
960 | * mpt_free_msg_frame - Place MPT request frame back on FreeQ. | 960 | * mpt_free_msg_frame - Place MPT request frame back on FreeQ. |
961 | * @ioc: Pointer to MPT adapter structure | 961 | * @ioc: Pointer to MPT adapter structure |
962 | * @mf: Pointer to MPT request frame | 962 | * @mf: Pointer to MPT request frame |
963 | * | 963 | * |
964 | * This routine places a MPT request frame back on the MPT adapter's | 964 | * This routine places a MPT request frame back on the MPT adapter's |
965 | * FreeQ. | 965 | * FreeQ. |
966 | */ | 966 | */ |
967 | void | 967 | void |
968 | mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) | 968 | mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) |
969 | { | 969 | { |
970 | unsigned long flags; | 970 | unsigned long flags; |
971 | 971 | ||
972 | /* Put Request back on FreeQ! */ | 972 | /* Put Request back on FreeQ! */ |
973 | spin_lock_irqsave(&ioc->FreeQlock, flags); | 973 | spin_lock_irqsave(&ioc->FreeQlock, flags); |
974 | if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf) | 974 | if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf) |
975 | goto out; | 975 | goto out; |
976 | /* signature to know if this mf is freed */ | 976 | /* signature to know if this mf is freed */ |
977 | mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf); | 977 | mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf); |
978 | list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ); | 978 | list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ); |
979 | #ifdef MFCNT | 979 | #ifdef MFCNT |
980 | ioc->mfcnt--; | 980 | ioc->mfcnt--; |
981 | #endif | 981 | #endif |
982 | out: | 982 | out: |
983 | spin_unlock_irqrestore(&ioc->FreeQlock, flags); | 983 | spin_unlock_irqrestore(&ioc->FreeQlock, flags); |
984 | } | 984 | } |
985 | 985 | ||
986 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 986 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
987 | /** | 987 | /** |
988 | * mpt_add_sge - Place a simple 32 bit SGE at address pAddr. | 988 | * mpt_add_sge - Place a simple 32 bit SGE at address pAddr. |
989 | * @pAddr: virtual address for SGE | 989 | * @pAddr: virtual address for SGE |
990 | * @flagslength: SGE flags and data transfer length | 990 | * @flagslength: SGE flags and data transfer length |
991 | * @dma_addr: Physical address | 991 | * @dma_addr: Physical address |
992 | * | 992 | * |
993 | * This routine places a MPT request frame back on the MPT adapter's | 993 | * This routine places a MPT request frame back on the MPT adapter's |
994 | * FreeQ. | 994 | * FreeQ. |
995 | */ | 995 | */ |
996 | static void | 996 | static void |
997 | mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr) | 997 | mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr) |
998 | { | 998 | { |
999 | SGESimple32_t *pSge = (SGESimple32_t *) pAddr; | 999 | SGESimple32_t *pSge = (SGESimple32_t *) pAddr; |
1000 | pSge->FlagsLength = cpu_to_le32(flagslength); | 1000 | pSge->FlagsLength = cpu_to_le32(flagslength); |
1001 | pSge->Address = cpu_to_le32(dma_addr); | 1001 | pSge->Address = cpu_to_le32(dma_addr); |
1002 | } | 1002 | } |
1003 | 1003 | ||
1004 | /** | 1004 | /** |
1005 | * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr. | 1005 | * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr. |
1006 | * @pAddr: virtual address for SGE | 1006 | * @pAddr: virtual address for SGE |
1007 | * @flagslength: SGE flags and data transfer length | 1007 | * @flagslength: SGE flags and data transfer length |
1008 | * @dma_addr: Physical address | 1008 | * @dma_addr: Physical address |
1009 | * | 1009 | * |
1010 | * This routine places a MPT request frame back on the MPT adapter's | 1010 | * This routine places a MPT request frame back on the MPT adapter's |
1011 | * FreeQ. | 1011 | * FreeQ. |
1012 | **/ | 1012 | **/ |
1013 | static void | 1013 | static void |
1014 | mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr) | 1014 | mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr) |
1015 | { | 1015 | { |
1016 | SGESimple64_t *pSge = (SGESimple64_t *) pAddr; | 1016 | SGESimple64_t *pSge = (SGESimple64_t *) pAddr; |
1017 | pSge->Address.Low = cpu_to_le32 | 1017 | pSge->Address.Low = cpu_to_le32 |
1018 | (lower_32_bits(dma_addr)); | 1018 | (lower_32_bits(dma_addr)); |
1019 | pSge->Address.High = cpu_to_le32 | 1019 | pSge->Address.High = cpu_to_le32 |
1020 | (upper_32_bits(dma_addr)); | 1020 | (upper_32_bits(dma_addr)); |
1021 | pSge->FlagsLength = cpu_to_le32 | 1021 | pSge->FlagsLength = cpu_to_le32 |
1022 | ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); | 1022 | ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); |
1023 | } | 1023 | } |
1024 | 1024 | ||
1025 | /** | 1025 | /** |
1026 | * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround). | 1026 | * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround). |
1027 | * @pAddr: virtual address for SGE | 1027 | * @pAddr: virtual address for SGE |
1028 | * @flagslength: SGE flags and data transfer length | 1028 | * @flagslength: SGE flags and data transfer length |
1029 | * @dma_addr: Physical address | 1029 | * @dma_addr: Physical address |
1030 | * | 1030 | * |
1031 | * This routine places a MPT request frame back on the MPT adapter's | 1031 | * This routine places a MPT request frame back on the MPT adapter's |
1032 | * FreeQ. | 1032 | * FreeQ. |
1033 | **/ | 1033 | **/ |
1034 | static void | 1034 | static void |
1035 | mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr) | 1035 | mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr) |
1036 | { | 1036 | { |
1037 | SGESimple64_t *pSge = (SGESimple64_t *) pAddr; | 1037 | SGESimple64_t *pSge = (SGESimple64_t *) pAddr; |
1038 | u32 tmp; | 1038 | u32 tmp; |
1039 | 1039 | ||
1040 | pSge->Address.Low = cpu_to_le32 | 1040 | pSge->Address.Low = cpu_to_le32 |
1041 | (lower_32_bits(dma_addr)); | 1041 | (lower_32_bits(dma_addr)); |
1042 | tmp = (u32)(upper_32_bits(dma_addr)); | 1042 | tmp = (u32)(upper_32_bits(dma_addr)); |
1043 | 1043 | ||
1044 | /* | 1044 | /* |
1045 | * 1078 errata workaround for the 36GB limitation | 1045 | * 1078 errata workaround for the 36GB limitation |
1046 | */ | 1046 | */ |
1047 | if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) { | 1047 | if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) { |
1048 | flagslength |= | 1048 | flagslength |= |
1049 | MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS); | 1049 | MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS); |
1050 | tmp |= (1<<31); | 1050 | tmp |= (1<<31); |
1051 | if (mpt_debug_level & MPT_DEBUG_36GB_MEM) | 1051 | if (mpt_debug_level & MPT_DEBUG_36GB_MEM) |
1052 | printk(KERN_DEBUG "1078 P0M2 addressing for " | 1052 | printk(KERN_DEBUG "1078 P0M2 addressing for " |
1053 | "addr = 0x%llx len = %d\n", | 1053 | "addr = 0x%llx len = %d\n", |
1054 | (unsigned long long)dma_addr, | 1054 | (unsigned long long)dma_addr, |
1055 | MPI_SGE_LENGTH(flagslength)); | 1055 | MPI_SGE_LENGTH(flagslength)); |
1056 | } | 1056 | } |
1057 | 1057 | ||
1058 | pSge->Address.High = cpu_to_le32(tmp); | 1058 | pSge->Address.High = cpu_to_le32(tmp); |
1059 | pSge->FlagsLength = cpu_to_le32( | 1059 | pSge->FlagsLength = cpu_to_le32( |
1060 | (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); | 1060 | (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); |
1061 | } | 1061 | } |
1062 | 1062 | ||
1063 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 1063 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
1064 | /** | 1064 | /** |
1065 | * mpt_add_chain - Place a 32 bit chain SGE at address pAddr. | 1065 | * mpt_add_chain - Place a 32 bit chain SGE at address pAddr. |
1066 | * @pAddr: virtual address for SGE | 1066 | * @pAddr: virtual address for SGE |
1067 | * @next: nextChainOffset value (u32's) | 1067 | * @next: nextChainOffset value (u32's) |
1068 | * @length: length of next SGL segment | 1068 | * @length: length of next SGL segment |
1069 | * @dma_addr: Physical address | 1069 | * @dma_addr: Physical address |
1070 | * | 1070 | * |
1071 | */ | 1071 | */ |
1072 | static void | 1072 | static void |
1073 | mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr) | 1073 | mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr) |
1074 | { | 1074 | { |
1075 | SGEChain32_t *pChain = (SGEChain32_t *) pAddr; | 1075 | SGEChain32_t *pChain = (SGEChain32_t *) pAddr; |
1076 | pChain->Length = cpu_to_le16(length); | 1076 | pChain->Length = cpu_to_le16(length); |
1077 | pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT; | 1077 | pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT; |
1078 | pChain->NextChainOffset = next; | 1078 | pChain->NextChainOffset = next; |
1079 | pChain->Address = cpu_to_le32(dma_addr); | 1079 | pChain->Address = cpu_to_le32(dma_addr); |
1080 | } | 1080 | } |
1081 | 1081 | ||
1082 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 1082 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
1083 | /** | 1083 | /** |
1084 | * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr. | 1084 | * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr. |
1085 | * @pAddr: virtual address for SGE | 1085 | * @pAddr: virtual address for SGE |
1086 | * @next: nextChainOffset value (u32's) | 1086 | * @next: nextChainOffset value (u32's) |
1087 | * @length: length of next SGL segment | 1087 | * @length: length of next SGL segment |
1088 | * @dma_addr: Physical address | 1088 | * @dma_addr: Physical address |
1089 | * | 1089 | * |
1090 | */ | 1090 | */ |
1091 | static void | 1091 | static void |
1092 | mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr) | 1092 | mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr) |
1093 | { | 1093 | { |
1094 | SGEChain64_t *pChain = (SGEChain64_t *) pAddr; | 1094 | SGEChain64_t *pChain = (SGEChain64_t *) pAddr; |
1095 | u32 tmp = dma_addr & 0xFFFFFFFF; | 1095 | u32 tmp = dma_addr & 0xFFFFFFFF; |
1096 | 1096 | ||
1097 | pChain->Length = cpu_to_le16(length); | 1097 | pChain->Length = cpu_to_le16(length); |
1098 | pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT | | 1098 | pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT | |
1099 | MPI_SGE_FLAGS_64_BIT_ADDRESSING); | 1099 | MPI_SGE_FLAGS_64_BIT_ADDRESSING); |
1100 | 1100 | ||
1101 | pChain->NextChainOffset = next; | 1101 | pChain->NextChainOffset = next; |
1102 | 1102 | ||
1103 | pChain->Address.Low = cpu_to_le32(tmp); | 1103 | pChain->Address.Low = cpu_to_le32(tmp); |
1104 | tmp = (u32)(upper_32_bits(dma_addr)); | 1104 | tmp = (u32)(upper_32_bits(dma_addr)); |
1105 | pChain->Address.High = cpu_to_le32(tmp); | 1105 | pChain->Address.High = cpu_to_le32(tmp); |
1106 | } | 1106 | } |
1107 | 1107 | ||
1108 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 1108 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
1109 | /** | 1109 | /** |
1110 | * mpt_send_handshake_request - Send MPT request via doorbell handshake method. | 1110 | * mpt_send_handshake_request - Send MPT request via doorbell handshake method. |
1111 | * @cb_idx: Handle of registered MPT protocol driver | 1111 | * @cb_idx: Handle of registered MPT protocol driver |
1112 | * @ioc: Pointer to MPT adapter structure | 1112 | * @ioc: Pointer to MPT adapter structure |
1113 | * @reqBytes: Size of the request in bytes | 1113 | * @reqBytes: Size of the request in bytes |
1114 | * @req: Pointer to MPT request frame | 1114 | * @req: Pointer to MPT request frame |
1115 | * @sleepFlag: Use schedule if CAN_SLEEP else use udelay. | 1115 | * @sleepFlag: Use schedule if CAN_SLEEP else use udelay. |
1116 | * | 1116 | * |
1117 | * This routine is used exclusively to send MptScsiTaskMgmt | 1117 | * This routine is used exclusively to send MptScsiTaskMgmt |
1118 | * requests since they are required to be sent via doorbell handshake. | 1118 | * requests since they are required to be sent via doorbell handshake. |
1119 | * | 1119 | * |
1120 | * NOTE: It is the callers responsibility to byte-swap fields in the | 1120 | * NOTE: It is the callers responsibility to byte-swap fields in the |
1121 | * request which are greater than 1 byte in size. | 1121 | * request which are greater than 1 byte in size. |
1122 | * | 1122 | * |
1123 | * Returns 0 for success, non-zero for failure. | 1123 | * Returns 0 for success, non-zero for failure. |
1124 | */ | 1124 | */ |
1125 | int | 1125 | int |
1126 | mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag) | 1126 | mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag) |
1127 | { | 1127 | { |
1128 | int r = 0; | 1128 | int r = 0; |
1129 | u8 *req_as_bytes; | 1129 | u8 *req_as_bytes; |
1130 | int ii; | 1130 | int ii; |
1131 | 1131 | ||
1132 | /* State is known to be good upon entering | 1132 | /* State is known to be good upon entering |
1133 | * this function so issue the bus reset | 1133 | * this function so issue the bus reset |
1134 | * request. | 1134 | * request. |
1135 | */ | 1135 | */ |
1136 | 1136 | ||
1137 | /* | 1137 | /* |
1138 | * Emulate what mpt_put_msg_frame() does /wrt to sanity | 1138 | * Emulate what mpt_put_msg_frame() does /wrt to sanity |
1139 | * setting cb_idx/req_idx. But ONLY if this request | 1139 | * setting cb_idx/req_idx. But ONLY if this request |
1140 | * is in proper (pre-alloc'd) request buffer range... | 1140 | * is in proper (pre-alloc'd) request buffer range... |
1141 | */ | 1141 | */ |
1142 | ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req); | 1142 | ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req); |
1143 | if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) { | 1143 | if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) { |
1144 | MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req; | 1144 | MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req; |
1145 | mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii); | 1145 | mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii); |
1146 | mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; | 1146 | mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; |
1147 | } | 1147 | } |
1148 | 1148 | ||
1149 | /* Make sure there are no doorbells */ | 1149 | /* Make sure there are no doorbells */ |
1150 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); | 1150 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); |
1151 | 1151 | ||
1152 | CHIPREG_WRITE32(&ioc->chip->Doorbell, | 1152 | CHIPREG_WRITE32(&ioc->chip->Doorbell, |
1153 | ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) | | 1153 | ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) | |
1154 | ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT))); | 1154 | ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT))); |
1155 | 1155 | ||
1156 | /* Wait for IOC doorbell int */ | 1156 | /* Wait for IOC doorbell int */ |
1157 | if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) { | 1157 | if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) { |
1158 | return ii; | 1158 | return ii; |
1159 | } | 1159 | } |
1160 | 1160 | ||
1161 | /* Read doorbell and check for active bit */ | 1161 | /* Read doorbell and check for active bit */ |
1162 | if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) | 1162 | if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) |
1163 | return -5; | 1163 | return -5; |
1164 | 1164 | ||
1165 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n", | 1165 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n", |
1166 | ioc->name, ii)); | 1166 | ioc->name, ii)); |
1167 | 1167 | ||
1168 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); | 1168 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); |
1169 | 1169 | ||
1170 | if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { | 1170 | if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { |
1171 | return -2; | 1171 | return -2; |
1172 | } | 1172 | } |
1173 | 1173 | ||
1174 | /* Send request via doorbell handshake */ | 1174 | /* Send request via doorbell handshake */ |
1175 | req_as_bytes = (u8 *) req; | 1175 | req_as_bytes = (u8 *) req; |
1176 | for (ii = 0; ii < reqBytes/4; ii++) { | 1176 | for (ii = 0; ii < reqBytes/4; ii++) { |
1177 | u32 word; | 1177 | u32 word; |
1178 | 1178 | ||
1179 | word = ((req_as_bytes[(ii*4) + 0] << 0) | | 1179 | word = ((req_as_bytes[(ii*4) + 0] << 0) | |
1180 | (req_as_bytes[(ii*4) + 1] << 8) | | 1180 | (req_as_bytes[(ii*4) + 1] << 8) | |
1181 | (req_as_bytes[(ii*4) + 2] << 16) | | 1181 | (req_as_bytes[(ii*4) + 2] << 16) | |
1182 | (req_as_bytes[(ii*4) + 3] << 24)); | 1182 | (req_as_bytes[(ii*4) + 3] << 24)); |
1183 | CHIPREG_WRITE32(&ioc->chip->Doorbell, word); | 1183 | CHIPREG_WRITE32(&ioc->chip->Doorbell, word); |
1184 | if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { | 1184 | if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { |
1185 | r = -3; | 1185 | r = -3; |
1186 | break; | 1186 | break; |
1187 | } | 1187 | } |
1188 | } | 1188 | } |
1189 | 1189 | ||
1190 | if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0) | 1190 | if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0) |
1191 | r = 0; | 1191 | r = 0; |
1192 | else | 1192 | else |
1193 | r = -4; | 1193 | r = -4; |
1194 | 1194 | ||
1195 | /* Make sure there are no doorbells */ | 1195 | /* Make sure there are no doorbells */ |
1196 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); | 1196 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); |
1197 | 1197 | ||
1198 | return r; | 1198 | return r; |
1199 | } | 1199 | } |
1200 | 1200 | ||
1201 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 1201 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
1202 | /** | 1202 | /** |
1203 | * mpt_host_page_access_control - control the IOC's Host Page Buffer access | 1203 | * mpt_host_page_access_control - control the IOC's Host Page Buffer access |
1204 | * @ioc: Pointer to MPT adapter structure | 1204 | * @ioc: Pointer to MPT adapter structure |
1205 | * @access_control_value: define bits below | 1205 | * @access_control_value: define bits below |
1206 | * @sleepFlag: Specifies whether the process can sleep | 1206 | * @sleepFlag: Specifies whether the process can sleep |
1207 | * | 1207 | * |
1208 | * Provides mechanism for the host driver to control the IOC's | 1208 | * Provides mechanism for the host driver to control the IOC's |
1209 | * Host Page Buffer access. | 1209 | * Host Page Buffer access. |
1210 | * | 1210 | * |
1211 | * Access Control Value - bits[15:12] | 1211 | * Access Control Value - bits[15:12] |
1212 | * 0h Reserved | 1212 | * 0h Reserved |
1213 | * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS } | 1213 | * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS } |
1214 | * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS } | 1214 | * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS } |
1215 | * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER } | 1215 | * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER } |
1216 | * | 1216 | * |
1217 | * Returns 0 for success, non-zero for failure. | 1217 | * Returns 0 for success, non-zero for failure. |
1218 | */ | 1218 | */ |
1219 | 1219 | ||
1220 | static int | 1220 | static int |
1221 | mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag) | 1221 | mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag) |
1222 | { | 1222 | { |
1223 | int r = 0; | 1223 | int r = 0; |
1224 | 1224 | ||
1225 | /* return if in use */ | 1225 | /* return if in use */ |
1226 | if (CHIPREG_READ32(&ioc->chip->Doorbell) | 1226 | if (CHIPREG_READ32(&ioc->chip->Doorbell) |
1227 | & MPI_DOORBELL_ACTIVE) | 1227 | & MPI_DOORBELL_ACTIVE) |
1228 | return -1; | 1228 | return -1; |
1229 | 1229 | ||
1230 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); | 1230 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); |
1231 | 1231 | ||
1232 | CHIPREG_WRITE32(&ioc->chip->Doorbell, | 1232 | CHIPREG_WRITE32(&ioc->chip->Doorbell, |
1233 | ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL | 1233 | ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL |
1234 | <<MPI_DOORBELL_FUNCTION_SHIFT) | | 1234 | <<MPI_DOORBELL_FUNCTION_SHIFT) | |
1235 | (access_control_value<<12))); | 1235 | (access_control_value<<12))); |
1236 | 1236 | ||
1237 | /* Wait for IOC to clear Doorbell Status bit */ | 1237 | /* Wait for IOC to clear Doorbell Status bit */ |
1238 | if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { | 1238 | if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { |
1239 | return -2; | 1239 | return -2; |
1240 | }else | 1240 | }else |
1241 | return 0; | 1241 | return 0; |
1242 | } | 1242 | } |
1243 | 1243 | ||
1244 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 1244 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
1245 | /** | 1245 | /** |
1246 | * mpt_host_page_alloc - allocate system memory for the fw | 1246 | * mpt_host_page_alloc - allocate system memory for the fw |
1247 | * @ioc: Pointer to pointer to IOC adapter | 1247 | * @ioc: Pointer to pointer to IOC adapter |
1248 | * @ioc_init: Pointer to ioc init config page | 1248 | * @ioc_init: Pointer to ioc init config page |
1249 | * | 1249 | * |
1250 | * If we already allocated memory in past, then resend the same pointer. | 1250 | * If we already allocated memory in past, then resend the same pointer. |
1251 | * Returns 0 for success, non-zero for failure. | 1251 | * Returns 0 for success, non-zero for failure. |
1252 | */ | 1252 | */ |
1253 | static int | 1253 | static int |
1254 | mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init) | 1254 | mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init) |
1255 | { | 1255 | { |
1256 | char *psge; | 1256 | char *psge; |
1257 | int flags_length; | 1257 | int flags_length; |
1258 | u32 host_page_buffer_sz=0; | 1258 | u32 host_page_buffer_sz=0; |
1259 | 1259 | ||
1260 | if(!ioc->HostPageBuffer) { | 1260 | if(!ioc->HostPageBuffer) { |
1261 | 1261 | ||
1262 | host_page_buffer_sz = | 1262 | host_page_buffer_sz = |
1263 | le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF; | 1263 | le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF; |
1264 | 1264 | ||
1265 | if(!host_page_buffer_sz) | 1265 | if(!host_page_buffer_sz) |
1266 | return 0; /* fw doesn't need any host buffers */ | 1266 | return 0; /* fw doesn't need any host buffers */ |
1267 | 1267 | ||
1268 | /* spin till we get enough memory */ | 1268 | /* spin till we get enough memory */ |
1269 | while(host_page_buffer_sz > 0) { | 1269 | while(host_page_buffer_sz > 0) { |
1270 | 1270 | ||
1271 | if((ioc->HostPageBuffer = pci_alloc_consistent( | 1271 | if((ioc->HostPageBuffer = pci_alloc_consistent( |
1272 | ioc->pcidev, | 1272 | ioc->pcidev, |
1273 | host_page_buffer_sz, | 1273 | host_page_buffer_sz, |
1274 | &ioc->HostPageBuffer_dma)) != NULL) { | 1274 | &ioc->HostPageBuffer_dma)) != NULL) { |
1275 | 1275 | ||
1276 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 1276 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
1277 | "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n", | 1277 | "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n", |
1278 | ioc->name, ioc->HostPageBuffer, | 1278 | ioc->name, ioc->HostPageBuffer, |
1279 | (u32)ioc->HostPageBuffer_dma, | 1279 | (u32)ioc->HostPageBuffer_dma, |
1280 | host_page_buffer_sz)); | 1280 | host_page_buffer_sz)); |
1281 | ioc->alloc_total += host_page_buffer_sz; | 1281 | ioc->alloc_total += host_page_buffer_sz; |
1282 | ioc->HostPageBuffer_sz = host_page_buffer_sz; | 1282 | ioc->HostPageBuffer_sz = host_page_buffer_sz; |
1283 | break; | 1283 | break; |
1284 | } | 1284 | } |
1285 | 1285 | ||
1286 | host_page_buffer_sz -= (4*1024); | 1286 | host_page_buffer_sz -= (4*1024); |
1287 | } | 1287 | } |
1288 | } | 1288 | } |
1289 | 1289 | ||
1290 | if(!ioc->HostPageBuffer) { | 1290 | if(!ioc->HostPageBuffer) { |
1291 | printk(MYIOC_s_ERR_FMT | 1291 | printk(MYIOC_s_ERR_FMT |
1292 | "Failed to alloc memory for host_page_buffer!\n", | 1292 | "Failed to alloc memory for host_page_buffer!\n", |
1293 | ioc->name); | 1293 | ioc->name); |
1294 | return -999; | 1294 | return -999; |
1295 | } | 1295 | } |
1296 | 1296 | ||
1297 | psge = (char *)&ioc_init->HostPageBufferSGE; | 1297 | psge = (char *)&ioc_init->HostPageBufferSGE; |
1298 | flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT | | 1298 | flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT | |
1299 | MPI_SGE_FLAGS_SYSTEM_ADDRESS | | 1299 | MPI_SGE_FLAGS_SYSTEM_ADDRESS | |
1300 | MPI_SGE_FLAGS_HOST_TO_IOC | | 1300 | MPI_SGE_FLAGS_HOST_TO_IOC | |
1301 | MPI_SGE_FLAGS_END_OF_BUFFER; | 1301 | MPI_SGE_FLAGS_END_OF_BUFFER; |
1302 | flags_length = flags_length << MPI_SGE_FLAGS_SHIFT; | 1302 | flags_length = flags_length << MPI_SGE_FLAGS_SHIFT; |
1303 | flags_length |= ioc->HostPageBuffer_sz; | 1303 | flags_length |= ioc->HostPageBuffer_sz; |
1304 | ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma); | 1304 | ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma); |
1305 | ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE; | 1305 | ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE; |
1306 | 1306 | ||
1307 | return 0; | 1307 | return 0; |
1308 | } | 1308 | } |
1309 | 1309 | ||
1310 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 1310 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
1311 | /** | 1311 | /** |
1312 | * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure. | 1312 | * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure. |
1313 | * @iocid: IOC unique identifier (integer) | 1313 | * @iocid: IOC unique identifier (integer) |
1314 | * @iocpp: Pointer to pointer to IOC adapter | 1314 | * @iocpp: Pointer to pointer to IOC adapter |
1315 | * | 1315 | * |
1316 | * Given a unique IOC identifier, set pointer to the associated MPT | 1316 | * Given a unique IOC identifier, set pointer to the associated MPT |
1317 | * adapter structure. | 1317 | * adapter structure. |
1318 | * | 1318 | * |
1319 | * Returns iocid and sets iocpp if iocid is found. | 1319 | * Returns iocid and sets iocpp if iocid is found. |
1320 | * Returns -1 if iocid is not found. | 1320 | * Returns -1 if iocid is not found. |
1321 | */ | 1321 | */ |
1322 | int | 1322 | int |
1323 | mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp) | 1323 | mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp) |
1324 | { | 1324 | { |
1325 | MPT_ADAPTER *ioc; | 1325 | MPT_ADAPTER *ioc; |
1326 | 1326 | ||
1327 | list_for_each_entry(ioc,&ioc_list,list) { | 1327 | list_for_each_entry(ioc,&ioc_list,list) { |
1328 | if (ioc->id == iocid) { | 1328 | if (ioc->id == iocid) { |
1329 | *iocpp =ioc; | 1329 | *iocpp =ioc; |
1330 | return iocid; | 1330 | return iocid; |
1331 | } | 1331 | } |
1332 | } | 1332 | } |
1333 | 1333 | ||
1334 | *iocpp = NULL; | 1334 | *iocpp = NULL; |
1335 | return -1; | 1335 | return -1; |
1336 | } | 1336 | } |
1337 | 1337 | ||
1338 | /** | 1338 | /** |
1339 | * mpt_get_product_name - returns product string | 1339 | * mpt_get_product_name - returns product string |
1340 | * @vendor: pci vendor id | 1340 | * @vendor: pci vendor id |
1341 | * @device: pci device id | 1341 | * @device: pci device id |
1342 | * @revision: pci revision id | 1342 | * @revision: pci revision id |
1343 | * @prod_name: string returned | 1343 | * @prod_name: string returned |
1344 | * | 1344 | * |
1345 | * Returns product string displayed when driver loads, | 1345 | * Returns product string displayed when driver loads, |
1346 | * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product | 1346 | * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product |
1347 | * | 1347 | * |
1348 | **/ | 1348 | **/ |
1349 | static void | 1349 | static void |
1350 | mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name) | 1350 | mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name) |
1351 | { | 1351 | { |
1352 | char *product_str = NULL; | 1352 | char *product_str = NULL; |
1353 | 1353 | ||
1354 | if (vendor == PCI_VENDOR_ID_BROCADE) { | 1354 | if (vendor == PCI_VENDOR_ID_BROCADE) { |
1355 | switch (device) | 1355 | switch (device) |
1356 | { | 1356 | { |
1357 | case MPI_MANUFACTPAGE_DEVICEID_FC949E: | 1357 | case MPI_MANUFACTPAGE_DEVICEID_FC949E: |
1358 | switch (revision) | 1358 | switch (revision) |
1359 | { | 1359 | { |
1360 | case 0x00: | 1360 | case 0x00: |
1361 | product_str = "BRE040 A0"; | 1361 | product_str = "BRE040 A0"; |
1362 | break; | 1362 | break; |
1363 | case 0x01: | 1363 | case 0x01: |
1364 | product_str = "BRE040 A1"; | 1364 | product_str = "BRE040 A1"; |
1365 | break; | 1365 | break; |
1366 | default: | 1366 | default: |
1367 | product_str = "BRE040"; | 1367 | product_str = "BRE040"; |
1368 | break; | 1368 | break; |
1369 | } | 1369 | } |
1370 | break; | 1370 | break; |
1371 | } | 1371 | } |
1372 | goto out; | 1372 | goto out; |
1373 | } | 1373 | } |
1374 | 1374 | ||
1375 | switch (device) | 1375 | switch (device) |
1376 | { | 1376 | { |
1377 | case MPI_MANUFACTPAGE_DEVICEID_FC909: | 1377 | case MPI_MANUFACTPAGE_DEVICEID_FC909: |
1378 | product_str = "LSIFC909 B1"; | 1378 | product_str = "LSIFC909 B1"; |
1379 | break; | 1379 | break; |
1380 | case MPI_MANUFACTPAGE_DEVICEID_FC919: | 1380 | case MPI_MANUFACTPAGE_DEVICEID_FC919: |
1381 | product_str = "LSIFC919 B0"; | 1381 | product_str = "LSIFC919 B0"; |
1382 | break; | 1382 | break; |
1383 | case MPI_MANUFACTPAGE_DEVICEID_FC929: | 1383 | case MPI_MANUFACTPAGE_DEVICEID_FC929: |
1384 | product_str = "LSIFC929 B0"; | 1384 | product_str = "LSIFC929 B0"; |
1385 | break; | 1385 | break; |
1386 | case MPI_MANUFACTPAGE_DEVICEID_FC919X: | 1386 | case MPI_MANUFACTPAGE_DEVICEID_FC919X: |
1387 | if (revision < 0x80) | 1387 | if (revision < 0x80) |
1388 | product_str = "LSIFC919X A0"; | 1388 | product_str = "LSIFC919X A0"; |
1389 | else | 1389 | else |
1390 | product_str = "LSIFC919XL A1"; | 1390 | product_str = "LSIFC919XL A1"; |
1391 | break; | 1391 | break; |
1392 | case MPI_MANUFACTPAGE_DEVICEID_FC929X: | 1392 | case MPI_MANUFACTPAGE_DEVICEID_FC929X: |
1393 | if (revision < 0x80) | 1393 | if (revision < 0x80) |
1394 | product_str = "LSIFC929X A0"; | 1394 | product_str = "LSIFC929X A0"; |
1395 | else | 1395 | else |
1396 | product_str = "LSIFC929XL A1"; | 1396 | product_str = "LSIFC929XL A1"; |
1397 | break; | 1397 | break; |
1398 | case MPI_MANUFACTPAGE_DEVICEID_FC939X: | 1398 | case MPI_MANUFACTPAGE_DEVICEID_FC939X: |
1399 | product_str = "LSIFC939X A1"; | 1399 | product_str = "LSIFC939X A1"; |
1400 | break; | 1400 | break; |
1401 | case MPI_MANUFACTPAGE_DEVICEID_FC949X: | 1401 | case MPI_MANUFACTPAGE_DEVICEID_FC949X: |
1402 | product_str = "LSIFC949X A1"; | 1402 | product_str = "LSIFC949X A1"; |
1403 | break; | 1403 | break; |
1404 | case MPI_MANUFACTPAGE_DEVICEID_FC949E: | 1404 | case MPI_MANUFACTPAGE_DEVICEID_FC949E: |
1405 | switch (revision) | 1405 | switch (revision) |
1406 | { | 1406 | { |
1407 | case 0x00: | 1407 | case 0x00: |
1408 | product_str = "LSIFC949E A0"; | 1408 | product_str = "LSIFC949E A0"; |
1409 | break; | 1409 | break; |
1410 | case 0x01: | 1410 | case 0x01: |
1411 | product_str = "LSIFC949E A1"; | 1411 | product_str = "LSIFC949E A1"; |
1412 | break; | 1412 | break; |
1413 | default: | 1413 | default: |
1414 | product_str = "LSIFC949E"; | 1414 | product_str = "LSIFC949E"; |
1415 | break; | 1415 | break; |
1416 | } | 1416 | } |
1417 | break; | 1417 | break; |
1418 | case MPI_MANUFACTPAGE_DEVID_53C1030: | 1418 | case MPI_MANUFACTPAGE_DEVID_53C1030: |
1419 | switch (revision) | 1419 | switch (revision) |
1420 | { | 1420 | { |
1421 | case 0x00: | 1421 | case 0x00: |
1422 | product_str = "LSI53C1030 A0"; | 1422 | product_str = "LSI53C1030 A0"; |
1423 | break; | 1423 | break; |
1424 | case 0x01: | 1424 | case 0x01: |
1425 | product_str = "LSI53C1030 B0"; | 1425 | product_str = "LSI53C1030 B0"; |
1426 | break; | 1426 | break; |
1427 | case 0x03: | 1427 | case 0x03: |
1428 | product_str = "LSI53C1030 B1"; | 1428 | product_str = "LSI53C1030 B1"; |
1429 | break; | 1429 | break; |
1430 | case 0x07: | 1430 | case 0x07: |
1431 | product_str = "LSI53C1030 B2"; | 1431 | product_str = "LSI53C1030 B2"; |
1432 | break; | 1432 | break; |
1433 | case 0x08: | 1433 | case 0x08: |
1434 | product_str = "LSI53C1030 C0"; | 1434 | product_str = "LSI53C1030 C0"; |
1435 | break; | 1435 | break; |
1436 | case 0x80: | 1436 | case 0x80: |
1437 | product_str = "LSI53C1030T A0"; | 1437 | product_str = "LSI53C1030T A0"; |
1438 | break; | 1438 | break; |
1439 | case 0x83: | 1439 | case 0x83: |
1440 | product_str = "LSI53C1030T A2"; | 1440 | product_str = "LSI53C1030T A2"; |
1441 | break; | 1441 | break; |
1442 | case 0x87: | 1442 | case 0x87: |
1443 | product_str = "LSI53C1030T A3"; | 1443 | product_str = "LSI53C1030T A3"; |
1444 | break; | 1444 | break; |
1445 | case 0xc1: | 1445 | case 0xc1: |
1446 | product_str = "LSI53C1020A A1"; | 1446 | product_str = "LSI53C1020A A1"; |
1447 | break; | 1447 | break; |
1448 | default: | 1448 | default: |
1449 | product_str = "LSI53C1030"; | 1449 | product_str = "LSI53C1030"; |
1450 | break; | 1450 | break; |
1451 | } | 1451 | } |
1452 | break; | 1452 | break; |
1453 | case MPI_MANUFACTPAGE_DEVID_1030_53C1035: | 1453 | case MPI_MANUFACTPAGE_DEVID_1030_53C1035: |
1454 | switch (revision) | 1454 | switch (revision) |
1455 | { | 1455 | { |
1456 | case 0x03: | 1456 | case 0x03: |
1457 | product_str = "LSI53C1035 A2"; | 1457 | product_str = "LSI53C1035 A2"; |
1458 | break; | 1458 | break; |
1459 | case 0x04: | 1459 | case 0x04: |
1460 | product_str = "LSI53C1035 B0"; | 1460 | product_str = "LSI53C1035 B0"; |
1461 | break; | 1461 | break; |
1462 | default: | 1462 | default: |
1463 | product_str = "LSI53C1035"; | 1463 | product_str = "LSI53C1035"; |
1464 | break; | 1464 | break; |
1465 | } | 1465 | } |
1466 | break; | 1466 | break; |
1467 | case MPI_MANUFACTPAGE_DEVID_SAS1064: | 1467 | case MPI_MANUFACTPAGE_DEVID_SAS1064: |
1468 | switch (revision) | 1468 | switch (revision) |
1469 | { | 1469 | { |
1470 | case 0x00: | 1470 | case 0x00: |
1471 | product_str = "LSISAS1064 A1"; | 1471 | product_str = "LSISAS1064 A1"; |
1472 | break; | 1472 | break; |
1473 | case 0x01: | 1473 | case 0x01: |
1474 | product_str = "LSISAS1064 A2"; | 1474 | product_str = "LSISAS1064 A2"; |
1475 | break; | 1475 | break; |
1476 | case 0x02: | 1476 | case 0x02: |
1477 | product_str = "LSISAS1064 A3"; | 1477 | product_str = "LSISAS1064 A3"; |
1478 | break; | 1478 | break; |
1479 | case 0x03: | 1479 | case 0x03: |
1480 | product_str = "LSISAS1064 A4"; | 1480 | product_str = "LSISAS1064 A4"; |
1481 | break; | 1481 | break; |
1482 | default: | 1482 | default: |
1483 | product_str = "LSISAS1064"; | 1483 | product_str = "LSISAS1064"; |
1484 | break; | 1484 | break; |
1485 | } | 1485 | } |
1486 | break; | 1486 | break; |
1487 | case MPI_MANUFACTPAGE_DEVID_SAS1064E: | 1487 | case MPI_MANUFACTPAGE_DEVID_SAS1064E: |
1488 | switch (revision) | 1488 | switch (revision) |
1489 | { | 1489 | { |
1490 | case 0x00: | 1490 | case 0x00: |
1491 | product_str = "LSISAS1064E A0"; | 1491 | product_str = "LSISAS1064E A0"; |
1492 | break; | 1492 | break; |
1493 | case 0x01: | 1493 | case 0x01: |
1494 | product_str = "LSISAS1064E B0"; | 1494 | product_str = "LSISAS1064E B0"; |
1495 | break; | 1495 | break; |
1496 | case 0x02: | 1496 | case 0x02: |
1497 | product_str = "LSISAS1064E B1"; | 1497 | product_str = "LSISAS1064E B1"; |
1498 | break; | 1498 | break; |
1499 | case 0x04: | 1499 | case 0x04: |
1500 | product_str = "LSISAS1064E B2"; | 1500 | product_str = "LSISAS1064E B2"; |
1501 | break; | 1501 | break; |
1502 | case 0x08: | 1502 | case 0x08: |
1503 | product_str = "LSISAS1064E B3"; | 1503 | product_str = "LSISAS1064E B3"; |
1504 | break; | 1504 | break; |
1505 | default: | 1505 | default: |
1506 | product_str = "LSISAS1064E"; | 1506 | product_str = "LSISAS1064E"; |
1507 | break; | 1507 | break; |
1508 | } | 1508 | } |
1509 | break; | 1509 | break; |
1510 | case MPI_MANUFACTPAGE_DEVID_SAS1068: | 1510 | case MPI_MANUFACTPAGE_DEVID_SAS1068: |
1511 | switch (revision) | 1511 | switch (revision) |
1512 | { | 1512 | { |
1513 | case 0x00: | 1513 | case 0x00: |
1514 | product_str = "LSISAS1068 A0"; | 1514 | product_str = "LSISAS1068 A0"; |
1515 | break; | 1515 | break; |
1516 | case 0x01: | 1516 | case 0x01: |
1517 | product_str = "LSISAS1068 B0"; | 1517 | product_str = "LSISAS1068 B0"; |
1518 | break; | 1518 | break; |
1519 | case 0x02: | 1519 | case 0x02: |
1520 | product_str = "LSISAS1068 B1"; | 1520 | product_str = "LSISAS1068 B1"; |
1521 | break; | 1521 | break; |
1522 | default: | 1522 | default: |
1523 | product_str = "LSISAS1068"; | 1523 | product_str = "LSISAS1068"; |
1524 | break; | 1524 | break; |
1525 | } | 1525 | } |
1526 | break; | 1526 | break; |
1527 | case MPI_MANUFACTPAGE_DEVID_SAS1068E: | 1527 | case MPI_MANUFACTPAGE_DEVID_SAS1068E: |
1528 | switch (revision) | 1528 | switch (revision) |
1529 | { | 1529 | { |
1530 | case 0x00: | 1530 | case 0x00: |
1531 | product_str = "LSISAS1068E A0"; | 1531 | product_str = "LSISAS1068E A0"; |
1532 | break; | 1532 | break; |
1533 | case 0x01: | 1533 | case 0x01: |
1534 | product_str = "LSISAS1068E B0"; | 1534 | product_str = "LSISAS1068E B0"; |
1535 | break; | 1535 | break; |
1536 | case 0x02: | 1536 | case 0x02: |
1537 | product_str = "LSISAS1068E B1"; | 1537 | product_str = "LSISAS1068E B1"; |
1538 | break; | 1538 | break; |
1539 | case 0x04: | 1539 | case 0x04: |
1540 | product_str = "LSISAS1068E B2"; | 1540 | product_str = "LSISAS1068E B2"; |
1541 | break; | 1541 | break; |
1542 | case 0x08: | 1542 | case 0x08: |
1543 | product_str = "LSISAS1068E B3"; | 1543 | product_str = "LSISAS1068E B3"; |
1544 | break; | 1544 | break; |
1545 | default: | 1545 | default: |
1546 | product_str = "LSISAS1068E"; | 1546 | product_str = "LSISAS1068E"; |
1547 | break; | 1547 | break; |
1548 | } | 1548 | } |
1549 | break; | 1549 | break; |
1550 | case MPI_MANUFACTPAGE_DEVID_SAS1078: | 1550 | case MPI_MANUFACTPAGE_DEVID_SAS1078: |
1551 | switch (revision) | 1551 | switch (revision) |
1552 | { | 1552 | { |
1553 | case 0x00: | 1553 | case 0x00: |
1554 | product_str = "LSISAS1078 A0"; | 1554 | product_str = "LSISAS1078 A0"; |
1555 | break; | 1555 | break; |
1556 | case 0x01: | 1556 | case 0x01: |
1557 | product_str = "LSISAS1078 B0"; | 1557 | product_str = "LSISAS1078 B0"; |
1558 | break; | 1558 | break; |
1559 | case 0x02: | 1559 | case 0x02: |
1560 | product_str = "LSISAS1078 C0"; | 1560 | product_str = "LSISAS1078 C0"; |
1561 | break; | 1561 | break; |
1562 | case 0x03: | 1562 | case 0x03: |
1563 | product_str = "LSISAS1078 C1"; | 1563 | product_str = "LSISAS1078 C1"; |
1564 | break; | 1564 | break; |
1565 | case 0x04: | 1565 | case 0x04: |
1566 | product_str = "LSISAS1078 C2"; | 1566 | product_str = "LSISAS1078 C2"; |
1567 | break; | 1567 | break; |
1568 | default: | 1568 | default: |
1569 | product_str = "LSISAS1078"; | 1569 | product_str = "LSISAS1078"; |
1570 | break; | 1570 | break; |
1571 | } | 1571 | } |
1572 | break; | 1572 | break; |
1573 | } | 1573 | } |
1574 | 1574 | ||
1575 | out: | 1575 | out: |
1576 | if (product_str) | 1576 | if (product_str) |
1577 | sprintf(prod_name, "%s", product_str); | 1577 | sprintf(prod_name, "%s", product_str); |
1578 | } | 1578 | } |
1579 | 1579 | ||
1580 | /** | 1580 | /** |
1581 | * mpt_mapresources - map in memory mapped io | 1581 | * mpt_mapresources - map in memory mapped io |
1582 | * @ioc: Pointer to pointer to IOC adapter | 1582 | * @ioc: Pointer to pointer to IOC adapter |
1583 | * | 1583 | * |
1584 | **/ | 1584 | **/ |
1585 | static int | 1585 | static int |
1586 | mpt_mapresources(MPT_ADAPTER *ioc) | 1586 | mpt_mapresources(MPT_ADAPTER *ioc) |
1587 | { | 1587 | { |
1588 | u8 __iomem *mem; | 1588 | u8 __iomem *mem; |
1589 | int ii; | 1589 | int ii; |
1590 | unsigned long mem_phys; | 1590 | unsigned long mem_phys; |
1591 | unsigned long port; | 1591 | unsigned long port; |
1592 | u32 msize; | 1592 | u32 msize; |
1593 | u32 psize; | 1593 | u32 psize; |
1594 | u8 revision; | 1594 | u8 revision; |
1595 | int r = -ENODEV; | 1595 | int r = -ENODEV; |
1596 | struct pci_dev *pdev; | 1596 | struct pci_dev *pdev; |
1597 | 1597 | ||
1598 | pdev = ioc->pcidev; | 1598 | pdev = ioc->pcidev; |
1599 | ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); | 1599 | ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); |
1600 | if (pci_enable_device_mem(pdev)) { | 1600 | if (pci_enable_device_mem(pdev)) { |
1601 | printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() " | 1601 | printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() " |
1602 | "failed\n", ioc->name); | 1602 | "failed\n", ioc->name); |
1603 | return r; | 1603 | return r; |
1604 | } | 1604 | } |
1605 | if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) { | 1605 | if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) { |
1606 | printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with " | 1606 | printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with " |
1607 | "MEM failed\n", ioc->name); | 1607 | "MEM failed\n", ioc->name); |
1608 | return r; | 1608 | return r; |
1609 | } | 1609 | } |
1610 | 1610 | ||
1611 | pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); | 1611 | pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); |
1612 | 1612 | ||
1613 | if (sizeof(dma_addr_t) > 4) { | 1613 | if (sizeof(dma_addr_t) > 4) { |
1614 | const uint64_t required_mask = dma_get_required_mask | 1614 | const uint64_t required_mask = dma_get_required_mask |
1615 | (&pdev->dev); | 1615 | (&pdev->dev); |
1616 | if (required_mask > DMA_BIT_MASK(32) | 1616 | if (required_mask > DMA_BIT_MASK(32) |
1617 | && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) | 1617 | && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) |
1618 | && !pci_set_consistent_dma_mask(pdev, | 1618 | && !pci_set_consistent_dma_mask(pdev, |
1619 | DMA_BIT_MASK(64))) { | 1619 | DMA_BIT_MASK(64))) { |
1620 | ioc->dma_mask = DMA_BIT_MASK(64); | 1620 | ioc->dma_mask = DMA_BIT_MASK(64); |
1621 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT | 1621 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT |
1622 | ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", | 1622 | ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", |
1623 | ioc->name)); | 1623 | ioc->name)); |
1624 | } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) | 1624 | } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) |
1625 | && !pci_set_consistent_dma_mask(pdev, | 1625 | && !pci_set_consistent_dma_mask(pdev, |
1626 | DMA_BIT_MASK(32))) { | 1626 | DMA_BIT_MASK(32))) { |
1627 | ioc->dma_mask = DMA_BIT_MASK(32); | 1627 | ioc->dma_mask = DMA_BIT_MASK(32); |
1628 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT | 1628 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT |
1629 | ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", | 1629 | ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", |
1630 | ioc->name)); | 1630 | ioc->name)); |
1631 | } else { | 1631 | } else { |
1632 | printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", | 1632 | printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", |
1633 | ioc->name, pci_name(pdev)); | 1633 | ioc->name, pci_name(pdev)); |
1634 | return r; | 1634 | return r; |
1635 | } | 1635 | } |
1636 | } else { | 1636 | } else { |
1637 | if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) | 1637 | if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) |
1638 | && !pci_set_consistent_dma_mask(pdev, | 1638 | && !pci_set_consistent_dma_mask(pdev, |
1639 | DMA_BIT_MASK(32))) { | 1639 | DMA_BIT_MASK(32))) { |
1640 | ioc->dma_mask = DMA_BIT_MASK(32); | 1640 | ioc->dma_mask = DMA_BIT_MASK(32); |
1641 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT | 1641 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT |
1642 | ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", | 1642 | ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", |
1643 | ioc->name)); | 1643 | ioc->name)); |
1644 | } else { | 1644 | } else { |
1645 | printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", | 1645 | printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", |
1646 | ioc->name, pci_name(pdev)); | 1646 | ioc->name, pci_name(pdev)); |
1647 | return r; | 1647 | return r; |
1648 | } | 1648 | } |
1649 | } | 1649 | } |
1650 | 1650 | ||
1651 | mem_phys = msize = 0; | 1651 | mem_phys = msize = 0; |
1652 | port = psize = 0; | 1652 | port = psize = 0; |
1653 | for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) { | 1653 | for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) { |
1654 | if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) { | 1654 | if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) { |
1655 | if (psize) | 1655 | if (psize) |
1656 | continue; | 1656 | continue; |
1657 | /* Get I/O space! */ | 1657 | /* Get I/O space! */ |
1658 | port = pci_resource_start(pdev, ii); | 1658 | port = pci_resource_start(pdev, ii); |
1659 | psize = pci_resource_len(pdev, ii); | 1659 | psize = pci_resource_len(pdev, ii); |
1660 | } else { | 1660 | } else { |
1661 | if (msize) | 1661 | if (msize) |
1662 | continue; | 1662 | continue; |
1663 | /* Get memmap */ | 1663 | /* Get memmap */ |
1664 | mem_phys = pci_resource_start(pdev, ii); | 1664 | mem_phys = pci_resource_start(pdev, ii); |
1665 | msize = pci_resource_len(pdev, ii); | 1665 | msize = pci_resource_len(pdev, ii); |
1666 | } | 1666 | } |
1667 | } | 1667 | } |
1668 | ioc->mem_size = msize; | 1668 | ioc->mem_size = msize; |
1669 | 1669 | ||
1670 | mem = NULL; | 1670 | mem = NULL; |
1671 | /* Get logical ptr for PciMem0 space */ | 1671 | /* Get logical ptr for PciMem0 space */ |
1672 | /*mem = ioremap(mem_phys, msize);*/ | 1672 | /*mem = ioremap(mem_phys, msize);*/ |
1673 | mem = ioremap(mem_phys, msize); | 1673 | mem = ioremap(mem_phys, msize); |
1674 | if (mem == NULL) { | 1674 | if (mem == NULL) { |
1675 | printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter" | 1675 | printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter" |
1676 | " memory!\n", ioc->name); | 1676 | " memory!\n", ioc->name); |
1677 | return -EINVAL; | 1677 | return -EINVAL; |
1678 | } | 1678 | } |
1679 | ioc->memmap = mem; | 1679 | ioc->memmap = mem; |
1680 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", | 1680 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", |
1681 | ioc->name, mem, mem_phys)); | 1681 | ioc->name, mem, mem_phys)); |
1682 | 1682 | ||
1683 | ioc->mem_phys = mem_phys; | 1683 | ioc->mem_phys = mem_phys; |
1684 | ioc->chip = (SYSIF_REGS __iomem *)mem; | 1684 | ioc->chip = (SYSIF_REGS __iomem *)mem; |
1685 | 1685 | ||
1686 | /* Save Port IO values in case we need to do downloadboot */ | 1686 | /* Save Port IO values in case we need to do downloadboot */ |
1687 | ioc->pio_mem_phys = port; | 1687 | ioc->pio_mem_phys = port; |
1688 | ioc->pio_chip = (SYSIF_REGS __iomem *)port; | 1688 | ioc->pio_chip = (SYSIF_REGS __iomem *)port; |
1689 | 1689 | ||
1690 | return 0; | 1690 | return 0; |
1691 | } | 1691 | } |
1692 | 1692 | ||
1693 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 1693 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
1694 | /** | 1694 | /** |
1695 | * mpt_attach - Install a PCI intelligent MPT adapter. | 1695 | * mpt_attach - Install a PCI intelligent MPT adapter. |
1696 | * @pdev: Pointer to pci_dev structure | 1696 | * @pdev: Pointer to pci_dev structure |
1697 | * @id: PCI device ID information | 1697 | * @id: PCI device ID information |
1698 | * | 1698 | * |
1699 | * This routine performs all the steps necessary to bring the IOC of | 1699 | * This routine performs all the steps necessary to bring the IOC of |
1700 | * a MPT adapter to a OPERATIONAL state. This includes registering | 1700 | * a MPT adapter to a OPERATIONAL state. This includes registering |
1701 | * memory regions, registering the interrupt, and allocating request | 1701 | * memory regions, registering the interrupt, and allocating request |
1702 | * and reply memory pools. | 1702 | * and reply memory pools. |
1703 | * | 1703 | * |
1704 | * This routine also pre-fetches the LAN MAC address of a Fibre Channel | 1704 | * This routine also pre-fetches the LAN MAC address of a Fibre Channel |
1705 | * MPT adapter. | 1705 | * MPT adapter. |
1706 | * | 1706 | * |
1707 | * Returns 0 for success, non-zero for failure. | 1707 | * Returns 0 for success, non-zero for failure. |
1708 | * | 1708 | * |
1709 | * TODO: Add support for polled controllers | 1709 | * TODO: Add support for polled controllers |
1710 | */ | 1710 | */ |
1711 | int | 1711 | int |
1712 | mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) | 1712 | mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) |
1713 | { | 1713 | { |
1714 | MPT_ADAPTER *ioc; | 1714 | MPT_ADAPTER *ioc; |
1715 | u8 cb_idx; | 1715 | u8 cb_idx; |
1716 | int r = -ENODEV; | 1716 | int r = -ENODEV; |
1717 | u8 revision; | 1717 | u8 revision; |
1718 | u8 pcixcmd; | 1718 | u8 pcixcmd; |
1719 | static int mpt_ids = 0; | 1719 | static int mpt_ids = 0; |
1720 | #ifdef CONFIG_PROC_FS | 1720 | #ifdef CONFIG_PROC_FS |
1721 | struct proc_dir_entry *dent, *ent; | 1721 | struct proc_dir_entry *dent, *ent; |
1722 | #endif | 1722 | #endif |
1723 | 1723 | ||
1724 | ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC); | 1724 | ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC); |
1725 | if (ioc == NULL) { | 1725 | if (ioc == NULL) { |
1726 | printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); | 1726 | printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); |
1727 | return -ENOMEM; | 1727 | return -ENOMEM; |
1728 | } | 1728 | } |
1729 | 1729 | ||
1730 | ioc->id = mpt_ids++; | 1730 | ioc->id = mpt_ids++; |
1731 | sprintf(ioc->name, "ioc%d", ioc->id); | 1731 | sprintf(ioc->name, "ioc%d", ioc->id); |
1732 | dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n")); | 1732 | dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n")); |
1733 | 1733 | ||
1734 | /* | 1734 | /* |
1735 | * set initial debug level | 1735 | * set initial debug level |
1736 | * (refer to mptdebug.h) | 1736 | * (refer to mptdebug.h) |
1737 | * | 1737 | * |
1738 | */ | 1738 | */ |
1739 | ioc->debug_level = mpt_debug_level; | 1739 | ioc->debug_level = mpt_debug_level; |
1740 | if (mpt_debug_level) | 1740 | if (mpt_debug_level) |
1741 | printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level); | 1741 | printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level); |
1742 | 1742 | ||
1743 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name)); | 1743 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name)); |
1744 | 1744 | ||
1745 | ioc->pcidev = pdev; | 1745 | ioc->pcidev = pdev; |
1746 | if (mpt_mapresources(ioc)) { | 1746 | if (mpt_mapresources(ioc)) { |
1747 | kfree(ioc); | 1747 | kfree(ioc); |
1748 | return r; | 1748 | return r; |
1749 | } | 1749 | } |
1750 | 1750 | ||
1751 | /* | 1751 | /* |
1752 | * Setting up proper handlers for scatter gather handling | 1752 | * Setting up proper handlers for scatter gather handling |
1753 | */ | 1753 | */ |
1754 | if (ioc->dma_mask == DMA_BIT_MASK(64)) { | 1754 | if (ioc->dma_mask == DMA_BIT_MASK(64)) { |
1755 | if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) | 1755 | if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) |
1756 | ioc->add_sge = &mpt_add_sge_64bit_1078; | 1756 | ioc->add_sge = &mpt_add_sge_64bit_1078; |
1757 | else | 1757 | else |
1758 | ioc->add_sge = &mpt_add_sge_64bit; | 1758 | ioc->add_sge = &mpt_add_sge_64bit; |
1759 | ioc->add_chain = &mpt_add_chain_64bit; | 1759 | ioc->add_chain = &mpt_add_chain_64bit; |
1760 | ioc->sg_addr_size = 8; | 1760 | ioc->sg_addr_size = 8; |
1761 | } else { | 1761 | } else { |
1762 | ioc->add_sge = &mpt_add_sge; | 1762 | ioc->add_sge = &mpt_add_sge; |
1763 | ioc->add_chain = &mpt_add_chain; | 1763 | ioc->add_chain = &mpt_add_chain; |
1764 | ioc->sg_addr_size = 4; | 1764 | ioc->sg_addr_size = 4; |
1765 | } | 1765 | } |
1766 | ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size; | 1766 | ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size; |
1767 | 1767 | ||
1768 | ioc->alloc_total = sizeof(MPT_ADAPTER); | 1768 | ioc->alloc_total = sizeof(MPT_ADAPTER); |
1769 | ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ | 1769 | ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ |
1770 | ioc->reply_sz = MPT_REPLY_FRAME_SIZE; | 1770 | ioc->reply_sz = MPT_REPLY_FRAME_SIZE; |
1771 | 1771 | ||
1772 | ioc->pcidev = pdev; | 1772 | ioc->pcidev = pdev; |
1773 | 1773 | ||
1774 | spin_lock_init(&ioc->taskmgmt_lock); | 1774 | spin_lock_init(&ioc->taskmgmt_lock); |
1775 | mutex_init(&ioc->internal_cmds.mutex); | 1775 | mutex_init(&ioc->internal_cmds.mutex); |
1776 | init_completion(&ioc->internal_cmds.done); | 1776 | init_completion(&ioc->internal_cmds.done); |
1777 | mutex_init(&ioc->mptbase_cmds.mutex); | 1777 | mutex_init(&ioc->mptbase_cmds.mutex); |
1778 | init_completion(&ioc->mptbase_cmds.done); | 1778 | init_completion(&ioc->mptbase_cmds.done); |
1779 | mutex_init(&ioc->taskmgmt_cmds.mutex); | 1779 | mutex_init(&ioc->taskmgmt_cmds.mutex); |
1780 | init_completion(&ioc->taskmgmt_cmds.done); | 1780 | init_completion(&ioc->taskmgmt_cmds.done); |
1781 | 1781 | ||
1782 | /* Initialize the event logging. | 1782 | /* Initialize the event logging. |
1783 | */ | 1783 | */ |
1784 | ioc->eventTypes = 0; /* None */ | 1784 | ioc->eventTypes = 0; /* None */ |
1785 | ioc->eventContext = 0; | 1785 | ioc->eventContext = 0; |
1786 | ioc->eventLogSize = 0; | 1786 | ioc->eventLogSize = 0; |
1787 | ioc->events = NULL; | 1787 | ioc->events = NULL; |
1788 | 1788 | ||
1789 | #ifdef MFCNT | 1789 | #ifdef MFCNT |
1790 | ioc->mfcnt = 0; | 1790 | ioc->mfcnt = 0; |
1791 | #endif | 1791 | #endif |
1792 | 1792 | ||
1793 | ioc->sh = NULL; | 1793 | ioc->sh = NULL; |
1794 | ioc->cached_fw = NULL; | 1794 | ioc->cached_fw = NULL; |
1795 | 1795 | ||
1796 | /* Initilize SCSI Config Data structure | 1796 | /* Initilize SCSI Config Data structure |
1797 | */ | 1797 | */ |
1798 | memset(&ioc->spi_data, 0, sizeof(SpiCfgData)); | 1798 | memset(&ioc->spi_data, 0, sizeof(SpiCfgData)); |
1799 | 1799 | ||
1800 | /* Initialize the fc rport list head. | 1800 | /* Initialize the fc rport list head. |
1801 | */ | 1801 | */ |
1802 | INIT_LIST_HEAD(&ioc->fc_rports); | 1802 | INIT_LIST_HEAD(&ioc->fc_rports); |
1803 | 1803 | ||
1804 | /* Find lookup slot. */ | 1804 | /* Find lookup slot. */ |
1805 | INIT_LIST_HEAD(&ioc->list); | 1805 | INIT_LIST_HEAD(&ioc->list); |
1806 | 1806 | ||
1807 | 1807 | ||
1808 | /* Initialize workqueue */ | 1808 | /* Initialize workqueue */ |
1809 | INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work); | 1809 | INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work); |
1810 | 1810 | ||
1811 | snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN, | 1811 | snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN, |
1812 | "mpt_poll_%d", ioc->id); | 1812 | "mpt_poll_%d", ioc->id); |
1813 | ioc->reset_work_q = | 1813 | ioc->reset_work_q = |
1814 | create_singlethread_workqueue(ioc->reset_work_q_name); | 1814 | create_singlethread_workqueue(ioc->reset_work_q_name); |
1815 | if (!ioc->reset_work_q) { | 1815 | if (!ioc->reset_work_q) { |
1816 | printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n", | 1816 | printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n", |
1817 | ioc->name); | 1817 | ioc->name); |
1818 | pci_release_selected_regions(pdev, ioc->bars); | 1818 | pci_release_selected_regions(pdev, ioc->bars); |
1819 | kfree(ioc); | 1819 | kfree(ioc); |
1820 | return -ENOMEM; | 1820 | return -ENOMEM; |
1821 | } | 1821 | } |
1822 | 1822 | ||
1823 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n", | 1823 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n", |
1824 | ioc->name, &ioc->facts, &ioc->pfacts[0])); | 1824 | ioc->name, &ioc->facts, &ioc->pfacts[0])); |
1825 | 1825 | ||
1826 | pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); | 1826 | pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); |
1827 | mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name); | 1827 | mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name); |
1828 | 1828 | ||
1829 | switch (pdev->device) | 1829 | switch (pdev->device) |
1830 | { | 1830 | { |
1831 | case MPI_MANUFACTPAGE_DEVICEID_FC939X: | 1831 | case MPI_MANUFACTPAGE_DEVICEID_FC939X: |
1832 | case MPI_MANUFACTPAGE_DEVICEID_FC949X: | 1832 | case MPI_MANUFACTPAGE_DEVICEID_FC949X: |
1833 | ioc->errata_flag_1064 = 1; | 1833 | ioc->errata_flag_1064 = 1; |
1834 | case MPI_MANUFACTPAGE_DEVICEID_FC909: | 1834 | case MPI_MANUFACTPAGE_DEVICEID_FC909: |
1835 | case MPI_MANUFACTPAGE_DEVICEID_FC929: | 1835 | case MPI_MANUFACTPAGE_DEVICEID_FC929: |
1836 | case MPI_MANUFACTPAGE_DEVICEID_FC919: | 1836 | case MPI_MANUFACTPAGE_DEVICEID_FC919: |
1837 | case MPI_MANUFACTPAGE_DEVICEID_FC949E: | 1837 | case MPI_MANUFACTPAGE_DEVICEID_FC949E: |
1838 | ioc->bus_type = FC; | 1838 | ioc->bus_type = FC; |
1839 | break; | 1839 | break; |
1840 | 1840 | ||
1841 | case MPI_MANUFACTPAGE_DEVICEID_FC929X: | 1841 | case MPI_MANUFACTPAGE_DEVICEID_FC929X: |
1842 | if (revision < XL_929) { | 1842 | if (revision < XL_929) { |
1843 | /* 929X Chip Fix. Set Split transactions level | 1843 | /* 929X Chip Fix. Set Split transactions level |
1844 | * for PCIX. Set MOST bits to zero. | 1844 | * for PCIX. Set MOST bits to zero. |
1845 | */ | 1845 | */ |
1846 | pci_read_config_byte(pdev, 0x6a, &pcixcmd); | 1846 | pci_read_config_byte(pdev, 0x6a, &pcixcmd); |
1847 | pcixcmd &= 0x8F; | 1847 | pcixcmd &= 0x8F; |
1848 | pci_write_config_byte(pdev, 0x6a, pcixcmd); | 1848 | pci_write_config_byte(pdev, 0x6a, pcixcmd); |
1849 | } else { | 1849 | } else { |
1850 | /* 929XL Chip Fix. Set MMRBC to 0x08. | 1850 | /* 929XL Chip Fix. Set MMRBC to 0x08. |
1851 | */ | 1851 | */ |
1852 | pci_read_config_byte(pdev, 0x6a, &pcixcmd); | 1852 | pci_read_config_byte(pdev, 0x6a, &pcixcmd); |
1853 | pcixcmd |= 0x08; | 1853 | pcixcmd |= 0x08; |
1854 | pci_write_config_byte(pdev, 0x6a, pcixcmd); | 1854 | pci_write_config_byte(pdev, 0x6a, pcixcmd); |
1855 | } | 1855 | } |
1856 | ioc->bus_type = FC; | 1856 | ioc->bus_type = FC; |
1857 | break; | 1857 | break; |
1858 | 1858 | ||
1859 | case MPI_MANUFACTPAGE_DEVICEID_FC919X: | 1859 | case MPI_MANUFACTPAGE_DEVICEID_FC919X: |
1860 | /* 919X Chip Fix. Set Split transactions level | 1860 | /* 919X Chip Fix. Set Split transactions level |
1861 | * for PCIX. Set MOST bits to zero. | 1861 | * for PCIX. Set MOST bits to zero. |
1862 | */ | 1862 | */ |
1863 | pci_read_config_byte(pdev, 0x6a, &pcixcmd); | 1863 | pci_read_config_byte(pdev, 0x6a, &pcixcmd); |
1864 | pcixcmd &= 0x8F; | 1864 | pcixcmd &= 0x8F; |
1865 | pci_write_config_byte(pdev, 0x6a, pcixcmd); | 1865 | pci_write_config_byte(pdev, 0x6a, pcixcmd); |
1866 | ioc->bus_type = FC; | 1866 | ioc->bus_type = FC; |
1867 | break; | 1867 | break; |
1868 | 1868 | ||
1869 | case MPI_MANUFACTPAGE_DEVID_53C1030: | 1869 | case MPI_MANUFACTPAGE_DEVID_53C1030: |
1870 | /* 1030 Chip Fix. Disable Split transactions | 1870 | /* 1030 Chip Fix. Disable Split transactions |
1871 | * for PCIX. Set MOST bits to zero if Rev < C0( = 8). | 1871 | * for PCIX. Set MOST bits to zero if Rev < C0( = 8). |
1872 | */ | 1872 | */ |
1873 | if (revision < C0_1030) { | 1873 | if (revision < C0_1030) { |
1874 | pci_read_config_byte(pdev, 0x6a, &pcixcmd); | 1874 | pci_read_config_byte(pdev, 0x6a, &pcixcmd); |
1875 | pcixcmd &= 0x8F; | 1875 | pcixcmd &= 0x8F; |
1876 | pci_write_config_byte(pdev, 0x6a, pcixcmd); | 1876 | pci_write_config_byte(pdev, 0x6a, pcixcmd); |
1877 | } | 1877 | } |
1878 | 1878 | ||
1879 | case MPI_MANUFACTPAGE_DEVID_1030_53C1035: | 1879 | case MPI_MANUFACTPAGE_DEVID_1030_53C1035: |
1880 | ioc->bus_type = SPI; | 1880 | ioc->bus_type = SPI; |
1881 | break; | 1881 | break; |
1882 | 1882 | ||
1883 | case MPI_MANUFACTPAGE_DEVID_SAS1064: | 1883 | case MPI_MANUFACTPAGE_DEVID_SAS1064: |
1884 | case MPI_MANUFACTPAGE_DEVID_SAS1068: | 1884 | case MPI_MANUFACTPAGE_DEVID_SAS1068: |
1885 | ioc->errata_flag_1064 = 1; | 1885 | ioc->errata_flag_1064 = 1; |
1886 | ioc->bus_type = SAS; | 1886 | ioc->bus_type = SAS; |
1887 | break; | 1887 | break; |
1888 | 1888 | ||
1889 | case MPI_MANUFACTPAGE_DEVID_SAS1064E: | 1889 | case MPI_MANUFACTPAGE_DEVID_SAS1064E: |
1890 | case MPI_MANUFACTPAGE_DEVID_SAS1068E: | 1890 | case MPI_MANUFACTPAGE_DEVID_SAS1068E: |
1891 | case MPI_MANUFACTPAGE_DEVID_SAS1078: | 1891 | case MPI_MANUFACTPAGE_DEVID_SAS1078: |
1892 | ioc->bus_type = SAS; | 1892 | ioc->bus_type = SAS; |
1893 | break; | 1893 | break; |
1894 | } | 1894 | } |
1895 | 1895 | ||
1896 | 1896 | ||
1897 | switch (ioc->bus_type) { | 1897 | switch (ioc->bus_type) { |
1898 | 1898 | ||
1899 | case SAS: | 1899 | case SAS: |
1900 | ioc->msi_enable = mpt_msi_enable_sas; | 1900 | ioc->msi_enable = mpt_msi_enable_sas; |
1901 | break; | 1901 | break; |
1902 | 1902 | ||
1903 | case SPI: | 1903 | case SPI: |
1904 | ioc->msi_enable = mpt_msi_enable_spi; | 1904 | ioc->msi_enable = mpt_msi_enable_spi; |
1905 | break; | 1905 | break; |
1906 | 1906 | ||
1907 | case FC: | 1907 | case FC: |
1908 | ioc->msi_enable = mpt_msi_enable_fc; | 1908 | ioc->msi_enable = mpt_msi_enable_fc; |
1909 | break; | 1909 | break; |
1910 | 1910 | ||
1911 | default: | 1911 | default: |
1912 | ioc->msi_enable = 0; | 1912 | ioc->msi_enable = 0; |
1913 | break; | 1913 | break; |
1914 | } | 1914 | } |
1915 | if (ioc->errata_flag_1064) | 1915 | if (ioc->errata_flag_1064) |
1916 | pci_disable_io_access(pdev); | 1916 | pci_disable_io_access(pdev); |
1917 | 1917 | ||
1918 | spin_lock_init(&ioc->FreeQlock); | 1918 | spin_lock_init(&ioc->FreeQlock); |
1919 | 1919 | ||
1920 | /* Disable all! */ | 1920 | /* Disable all! */ |
1921 | CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); | 1921 | CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); |
1922 | ioc->active = 0; | 1922 | ioc->active = 0; |
1923 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); | 1923 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); |
1924 | 1924 | ||
1925 | /* Set IOC ptr in the pcidev's driver data. */ | 1925 | /* Set IOC ptr in the pcidev's driver data. */ |
1926 | pci_set_drvdata(ioc->pcidev, ioc); | 1926 | pci_set_drvdata(ioc->pcidev, ioc); |
1927 | 1927 | ||
1928 | /* Set lookup ptr. */ | 1928 | /* Set lookup ptr. */ |
1929 | list_add_tail(&ioc->list, &ioc_list); | 1929 | list_add_tail(&ioc->list, &ioc_list); |
1930 | 1930 | ||
1931 | /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets. | 1931 | /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets. |
1932 | */ | 1932 | */ |
1933 | mpt_detect_bound_ports(ioc, pdev); | 1933 | mpt_detect_bound_ports(ioc, pdev); |
1934 | 1934 | ||
1935 | INIT_LIST_HEAD(&ioc->fw_event_list); | 1935 | INIT_LIST_HEAD(&ioc->fw_event_list); |
1936 | spin_lock_init(&ioc->fw_event_lock); | 1936 | spin_lock_init(&ioc->fw_event_lock); |
1937 | snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id); | 1937 | snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id); |
1938 | ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name); | 1938 | ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name); |
1939 | 1939 | ||
1940 | if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, | 1940 | if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, |
1941 | CAN_SLEEP)) != 0){ | 1941 | CAN_SLEEP)) != 0){ |
1942 | printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n", | 1942 | printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n", |
1943 | ioc->name, r); | 1943 | ioc->name, r); |
1944 | 1944 | ||
1945 | list_del(&ioc->list); | 1945 | list_del(&ioc->list); |
1946 | if (ioc->alt_ioc) | 1946 | if (ioc->alt_ioc) |
1947 | ioc->alt_ioc->alt_ioc = NULL; | 1947 | ioc->alt_ioc->alt_ioc = NULL; |
1948 | iounmap(ioc->memmap); | 1948 | iounmap(ioc->memmap); |
1949 | if (r != -5) | 1949 | if (r != -5) |
1950 | pci_release_selected_regions(pdev, ioc->bars); | 1950 | pci_release_selected_regions(pdev, ioc->bars); |
1951 | 1951 | ||
1952 | destroy_workqueue(ioc->reset_work_q); | 1952 | destroy_workqueue(ioc->reset_work_q); |
1953 | ioc->reset_work_q = NULL; | 1953 | ioc->reset_work_q = NULL; |
1954 | 1954 | ||
1955 | kfree(ioc); | 1955 | kfree(ioc); |
1956 | pci_set_drvdata(pdev, NULL); | 1956 | pci_set_drvdata(pdev, NULL); |
1957 | return r; | 1957 | return r; |
1958 | } | 1958 | } |
1959 | 1959 | ||
1960 | /* call per device driver probe entry point */ | 1960 | /* call per device driver probe entry point */ |
1961 | for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { | 1961 | for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { |
1962 | if(MptDeviceDriverHandlers[cb_idx] && | 1962 | if(MptDeviceDriverHandlers[cb_idx] && |
1963 | MptDeviceDriverHandlers[cb_idx]->probe) { | 1963 | MptDeviceDriverHandlers[cb_idx]->probe) { |
1964 | MptDeviceDriverHandlers[cb_idx]->probe(pdev,id); | 1964 | MptDeviceDriverHandlers[cb_idx]->probe(pdev,id); |
1965 | } | 1965 | } |
1966 | } | 1966 | } |
1967 | 1967 | ||
1968 | #ifdef CONFIG_PROC_FS | 1968 | #ifdef CONFIG_PROC_FS |
1969 | /* | 1969 | /* |
1970 | * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter. | 1970 | * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter. |
1971 | */ | 1971 | */ |
1972 | dent = proc_mkdir(ioc->name, mpt_proc_root_dir); | 1972 | dent = proc_mkdir(ioc->name, mpt_proc_root_dir); |
1973 | if (dent) { | 1973 | if (dent) { |
1974 | ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent); | 1974 | ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent); |
1975 | if (ent) { | 1975 | if (ent) { |
1976 | ent->read_proc = procmpt_iocinfo_read; | 1976 | ent->read_proc = procmpt_iocinfo_read; |
1977 | ent->data = ioc; | 1977 | ent->data = ioc; |
1978 | } | 1978 | } |
1979 | ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent); | 1979 | ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent); |
1980 | if (ent) { | 1980 | if (ent) { |
1981 | ent->read_proc = procmpt_summary_read; | 1981 | ent->read_proc = procmpt_summary_read; |
1982 | ent->data = ioc; | 1982 | ent->data = ioc; |
1983 | } | 1983 | } |
1984 | } | 1984 | } |
1985 | #endif | 1985 | #endif |
1986 | 1986 | ||
1987 | if (!ioc->alt_ioc) | 1987 | if (!ioc->alt_ioc) |
1988 | queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, | 1988 | queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, |
1989 | msecs_to_jiffies(MPT_POLLING_INTERVAL)); | 1989 | msecs_to_jiffies(MPT_POLLING_INTERVAL)); |
1990 | 1990 | ||
1991 | return 0; | 1991 | return 0; |
1992 | } | 1992 | } |
1993 | 1993 | ||
1994 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 1994 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
1995 | /** | 1995 | /** |
1996 | * mpt_detach - Remove a PCI intelligent MPT adapter. | 1996 | * mpt_detach - Remove a PCI intelligent MPT adapter. |
1997 | * @pdev: Pointer to pci_dev structure | 1997 | * @pdev: Pointer to pci_dev structure |
1998 | */ | 1998 | */ |
1999 | 1999 | ||
2000 | void | 2000 | void |
2001 | mpt_detach(struct pci_dev *pdev) | 2001 | mpt_detach(struct pci_dev *pdev) |
2002 | { | 2002 | { |
2003 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); | 2003 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); |
2004 | char pname[32]; | 2004 | char pname[32]; |
2005 | u8 cb_idx; | 2005 | u8 cb_idx; |
2006 | unsigned long flags; | 2006 | unsigned long flags; |
2007 | struct workqueue_struct *wq; | 2007 | struct workqueue_struct *wq; |
2008 | 2008 | ||
2009 | /* | 2009 | /* |
2010 | * Stop polling ioc for fault condition | 2010 | * Stop polling ioc for fault condition |
2011 | */ | 2011 | */ |
2012 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); | 2012 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); |
2013 | wq = ioc->reset_work_q; | 2013 | wq = ioc->reset_work_q; |
2014 | ioc->reset_work_q = NULL; | 2014 | ioc->reset_work_q = NULL; |
2015 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | 2015 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); |
2016 | cancel_delayed_work(&ioc->fault_reset_work); | 2016 | cancel_delayed_work(&ioc->fault_reset_work); |
2017 | destroy_workqueue(wq); | 2017 | destroy_workqueue(wq); |
2018 | 2018 | ||
2019 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | 2019 | spin_lock_irqsave(&ioc->fw_event_lock, flags); |
2020 | wq = ioc->fw_event_q; | 2020 | wq = ioc->fw_event_q; |
2021 | ioc->fw_event_q = NULL; | 2021 | ioc->fw_event_q = NULL; |
2022 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | 2022 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); |
2023 | destroy_workqueue(wq); | 2023 | destroy_workqueue(wq); |
2024 | 2024 | ||
2025 | sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name); | 2025 | sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name); |
2026 | remove_proc_entry(pname, NULL); | 2026 | remove_proc_entry(pname, NULL); |
2027 | sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name); | 2027 | sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name); |
2028 | remove_proc_entry(pname, NULL); | 2028 | remove_proc_entry(pname, NULL); |
2029 | sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); | 2029 | sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); |
2030 | remove_proc_entry(pname, NULL); | 2030 | remove_proc_entry(pname, NULL); |
2031 | 2031 | ||
2032 | /* call per device driver remove entry point */ | 2032 | /* call per device driver remove entry point */ |
2033 | for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { | 2033 | for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { |
2034 | if(MptDeviceDriverHandlers[cb_idx] && | 2034 | if(MptDeviceDriverHandlers[cb_idx] && |
2035 | MptDeviceDriverHandlers[cb_idx]->remove) { | 2035 | MptDeviceDriverHandlers[cb_idx]->remove) { |
2036 | MptDeviceDriverHandlers[cb_idx]->remove(pdev); | 2036 | MptDeviceDriverHandlers[cb_idx]->remove(pdev); |
2037 | } | 2037 | } |
2038 | } | 2038 | } |
2039 | 2039 | ||
2040 | /* Disable interrupts! */ | 2040 | /* Disable interrupts! */ |
2041 | CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); | 2041 | CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); |
2042 | 2042 | ||
2043 | ioc->active = 0; | 2043 | ioc->active = 0; |
2044 | synchronize_irq(pdev->irq); | 2044 | synchronize_irq(pdev->irq); |
2045 | 2045 | ||
2046 | /* Clear any lingering interrupt */ | 2046 | /* Clear any lingering interrupt */ |
2047 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); | 2047 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); |
2048 | 2048 | ||
2049 | CHIPREG_READ32(&ioc->chip->IntStatus); | 2049 | CHIPREG_READ32(&ioc->chip->IntStatus); |
2050 | 2050 | ||
2051 | mpt_adapter_dispose(ioc); | 2051 | mpt_adapter_dispose(ioc); |
2052 | 2052 | ||
2053 | pci_set_drvdata(pdev, NULL); | 2053 | pci_set_drvdata(pdev, NULL); |
2054 | } | 2054 | } |
2055 | 2055 | ||
2056 | /************************************************************************** | 2056 | /************************************************************************** |
2057 | * Power Management | 2057 | * Power Management |
2058 | */ | 2058 | */ |
2059 | #ifdef CONFIG_PM | 2059 | #ifdef CONFIG_PM |
2060 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 2060 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
2061 | /** | 2061 | /** |
2062 | * mpt_suspend - Fusion MPT base driver suspend routine. | 2062 | * mpt_suspend - Fusion MPT base driver suspend routine. |
2063 | * @pdev: Pointer to pci_dev structure | 2063 | * @pdev: Pointer to pci_dev structure |
2064 | * @state: new state to enter | 2064 | * @state: new state to enter |
2065 | */ | 2065 | */ |
2066 | int | 2066 | int |
2067 | mpt_suspend(struct pci_dev *pdev, pm_message_t state) | 2067 | mpt_suspend(struct pci_dev *pdev, pm_message_t state) |
2068 | { | 2068 | { |
2069 | u32 device_state; | 2069 | u32 device_state; |
2070 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); | 2070 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); |
2071 | 2071 | ||
2072 | device_state = pci_choose_state(pdev, state); | 2072 | device_state = pci_choose_state(pdev, state); |
2073 | printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering " | 2073 | printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering " |
2074 | "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev), | 2074 | "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev), |
2075 | device_state); | 2075 | device_state); |
2076 | 2076 | ||
2077 | /* put ioc into READY_STATE */ | 2077 | /* put ioc into READY_STATE */ |
2078 | if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) { | 2078 | if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) { |
2079 | printk(MYIOC_s_ERR_FMT | 2079 | printk(MYIOC_s_ERR_FMT |
2080 | "pci-suspend: IOC msg unit reset failed!\n", ioc->name); | 2080 | "pci-suspend: IOC msg unit reset failed!\n", ioc->name); |
2081 | } | 2081 | } |
2082 | 2082 | ||
2083 | /* disable interrupts */ | 2083 | /* disable interrupts */ |
2084 | CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); | 2084 | CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); |
2085 | ioc->active = 0; | 2085 | ioc->active = 0; |
2086 | 2086 | ||
2087 | /* Clear any lingering interrupt */ | 2087 | /* Clear any lingering interrupt */ |
2088 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); | 2088 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); |
2089 | 2089 | ||
2090 | free_irq(ioc->pci_irq, ioc); | 2090 | free_irq(ioc->pci_irq, ioc); |
2091 | if (ioc->msi_enable) | 2091 | if (ioc->msi_enable) |
2092 | pci_disable_msi(ioc->pcidev); | 2092 | pci_disable_msi(ioc->pcidev); |
2093 | ioc->pci_irq = -1; | 2093 | ioc->pci_irq = -1; |
2094 | pci_save_state(pdev); | 2094 | pci_save_state(pdev); |
2095 | pci_disable_device(pdev); | 2095 | pci_disable_device(pdev); |
2096 | pci_release_selected_regions(pdev, ioc->bars); | 2096 | pci_release_selected_regions(pdev, ioc->bars); |
2097 | pci_set_power_state(pdev, device_state); | 2097 | pci_set_power_state(pdev, device_state); |
2098 | return 0; | 2098 | return 0; |
2099 | } | 2099 | } |
2100 | 2100 | ||
2101 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 2101 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
2102 | /** | 2102 | /** |
2103 | * mpt_resume - Fusion MPT base driver resume routine. | 2103 | * mpt_resume - Fusion MPT base driver resume routine. |
2104 | * @pdev: Pointer to pci_dev structure | 2104 | * @pdev: Pointer to pci_dev structure |
2105 | */ | 2105 | */ |
2106 | int | 2106 | int |
2107 | mpt_resume(struct pci_dev *pdev) | 2107 | mpt_resume(struct pci_dev *pdev) |
2108 | { | 2108 | { |
2109 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); | 2109 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); |
2110 | u32 device_state = pdev->current_state; | 2110 | u32 device_state = pdev->current_state; |
2111 | int recovery_state; | 2111 | int recovery_state; |
2112 | int err; | 2112 | int err; |
2113 | 2113 | ||
2114 | printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous " | 2114 | printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous " |
2115 | "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev), | 2115 | "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev), |
2116 | device_state); | 2116 | device_state); |
2117 | 2117 | ||
2118 | pci_set_power_state(pdev, PCI_D0); | 2118 | pci_set_power_state(pdev, PCI_D0); |
2119 | pci_enable_wake(pdev, PCI_D0, 0); | 2119 | pci_enable_wake(pdev, PCI_D0, 0); |
2120 | pci_restore_state(pdev); | 2120 | pci_restore_state(pdev); |
2121 | ioc->pcidev = pdev; | 2121 | ioc->pcidev = pdev; |
2122 | err = mpt_mapresources(ioc); | 2122 | err = mpt_mapresources(ioc); |
2123 | if (err) | 2123 | if (err) |
2124 | return err; | 2124 | return err; |
2125 | 2125 | ||
2126 | if (ioc->dma_mask == DMA_BIT_MASK(64)) { | 2126 | if (ioc->dma_mask == DMA_BIT_MASK(64)) { |
2127 | if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) | 2127 | if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) |
2128 | ioc->add_sge = &mpt_add_sge_64bit_1078; | 2128 | ioc->add_sge = &mpt_add_sge_64bit_1078; |
2129 | else | 2129 | else |
2130 | ioc->add_sge = &mpt_add_sge_64bit; | 2130 | ioc->add_sge = &mpt_add_sge_64bit; |
2131 | ioc->add_chain = &mpt_add_chain_64bit; | 2131 | ioc->add_chain = &mpt_add_chain_64bit; |
2132 | ioc->sg_addr_size = 8; | 2132 | ioc->sg_addr_size = 8; |
2133 | } else { | 2133 | } else { |
2134 | 2134 | ||
2135 | ioc->add_sge = &mpt_add_sge; | 2135 | ioc->add_sge = &mpt_add_sge; |
2136 | ioc->add_chain = &mpt_add_chain; | 2136 | ioc->add_chain = &mpt_add_chain; |
2137 | ioc->sg_addr_size = 4; | 2137 | ioc->sg_addr_size = 4; |
2138 | } | 2138 | } |
2139 | ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size; | 2139 | ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size; |
2140 | 2140 | ||
2141 | printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n", | 2141 | printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n", |
2142 | ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT), | 2142 | ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT), |
2143 | CHIPREG_READ32(&ioc->chip->Doorbell)); | 2143 | CHIPREG_READ32(&ioc->chip->Doorbell)); |
2144 | 2144 | ||
2145 | /* | 2145 | /* |
2146 | * Errata workaround for SAS pci express: | 2146 | * Errata workaround for SAS pci express: |
2147 | * Upon returning to the D0 state, the contents of the doorbell will be | 2147 | * Upon returning to the D0 state, the contents of the doorbell will be |
2148 | * stale data, and this will incorrectly signal to the host driver that | 2148 | * stale data, and this will incorrectly signal to the host driver that |
2149 | * the firmware is ready to process mpt commands. The workaround is | 2149 | * the firmware is ready to process mpt commands. The workaround is |
2150 | * to issue a diagnostic reset. | 2150 | * to issue a diagnostic reset. |
2151 | */ | 2151 | */ |
2152 | if (ioc->bus_type == SAS && (pdev->device == | 2152 | if (ioc->bus_type == SAS && (pdev->device == |
2153 | MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device == | 2153 | MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device == |
2154 | MPI_MANUFACTPAGE_DEVID_SAS1064E)) { | 2154 | MPI_MANUFACTPAGE_DEVID_SAS1064E)) { |
2155 | if (KickStart(ioc, 1, CAN_SLEEP) < 0) { | 2155 | if (KickStart(ioc, 1, CAN_SLEEP) < 0) { |
2156 | printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n", | 2156 | printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n", |
2157 | ioc->name); | 2157 | ioc->name); |
2158 | goto out; | 2158 | goto out; |
2159 | } | 2159 | } |
2160 | } | 2160 | } |
2161 | 2161 | ||
2162 | /* bring ioc to operational state */ | 2162 | /* bring ioc to operational state */ |
2163 | printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name); | 2163 | printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name); |
2164 | recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, | 2164 | recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, |
2165 | CAN_SLEEP); | 2165 | CAN_SLEEP); |
2166 | if (recovery_state != 0) | 2166 | if (recovery_state != 0) |
2167 | printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, " | 2167 | printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, " |
2168 | "error:[%x]\n", ioc->name, recovery_state); | 2168 | "error:[%x]\n", ioc->name, recovery_state); |
2169 | else | 2169 | else |
2170 | printk(MYIOC_s_INFO_FMT | 2170 | printk(MYIOC_s_INFO_FMT |
2171 | "pci-resume: success\n", ioc->name); | 2171 | "pci-resume: success\n", ioc->name); |
2172 | out: | 2172 | out: |
2173 | return 0; | 2173 | return 0; |
2174 | 2174 | ||
2175 | } | 2175 | } |
2176 | #endif | 2176 | #endif |
2177 | 2177 | ||
2178 | static int | 2178 | static int |
2179 | mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase) | 2179 | mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase) |
2180 | { | 2180 | { |
2181 | if ((MptDriverClass[index] == MPTSPI_DRIVER && | 2181 | if ((MptDriverClass[index] == MPTSPI_DRIVER && |
2182 | ioc->bus_type != SPI) || | 2182 | ioc->bus_type != SPI) || |
2183 | (MptDriverClass[index] == MPTFC_DRIVER && | 2183 | (MptDriverClass[index] == MPTFC_DRIVER && |
2184 | ioc->bus_type != FC) || | 2184 | ioc->bus_type != FC) || |
2185 | (MptDriverClass[index] == MPTSAS_DRIVER && | 2185 | (MptDriverClass[index] == MPTSAS_DRIVER && |
2186 | ioc->bus_type != SAS)) | 2186 | ioc->bus_type != SAS)) |
2187 | /* make sure we only call the relevant reset handler | 2187 | /* make sure we only call the relevant reset handler |
2188 | * for the bus */ | 2188 | * for the bus */ |
2189 | return 0; | 2189 | return 0; |
2190 | return (MptResetHandlers[index])(ioc, reset_phase); | 2190 | return (MptResetHandlers[index])(ioc, reset_phase); |
2191 | } | 2191 | } |
2192 | 2192 | ||
2193 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 2193 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
2194 | /** | 2194 | /** |
2195 | * mpt_do_ioc_recovery - Initialize or recover MPT adapter. | 2195 | * mpt_do_ioc_recovery - Initialize or recover MPT adapter. |
2196 | * @ioc: Pointer to MPT adapter structure | 2196 | * @ioc: Pointer to MPT adapter structure |
2197 | * @reason: Event word / reason | 2197 | * @reason: Event word / reason |
2198 | * @sleepFlag: Use schedule if CAN_SLEEP else use udelay. | 2198 | * @sleepFlag: Use schedule if CAN_SLEEP else use udelay. |
2199 | * | 2199 | * |
2200 | * This routine performs all the steps necessary to bring the IOC | 2200 | * This routine performs all the steps necessary to bring the IOC |
2201 | * to a OPERATIONAL state. | 2201 | * to a OPERATIONAL state. |
2202 | * | 2202 | * |
2203 | * This routine also pre-fetches the LAN MAC address of a Fibre Channel | 2203 | * This routine also pre-fetches the LAN MAC address of a Fibre Channel |
2204 | * MPT adapter. | 2204 | * MPT adapter. |
2205 | * | 2205 | * |
2206 | * Returns: | 2206 | * Returns: |
2207 | * 0 for success | 2207 | * 0 for success |
2208 | * -1 if failed to get board READY | 2208 | * -1 if failed to get board READY |
2209 | * -2 if READY but IOCFacts Failed | 2209 | * -2 if READY but IOCFacts Failed |
2210 | * -3 if READY but PrimeIOCFifos Failed | 2210 | * -3 if READY but PrimeIOCFifos Failed |
2211 | * -4 if READY but IOCInit Failed | 2211 | * -4 if READY but IOCInit Failed |
2212 | * -5 if failed to enable_device and/or request_selected_regions | 2212 | * -5 if failed to enable_device and/or request_selected_regions |
2213 | * -6 if failed to upload firmware | 2213 | * -6 if failed to upload firmware |
2214 | */ | 2214 | */ |
2215 | static int | 2215 | static int |
2216 | mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) | 2216 | mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) |
2217 | { | 2217 | { |
2218 | int hard_reset_done = 0; | 2218 | int hard_reset_done = 0; |
2219 | int alt_ioc_ready = 0; | 2219 | int alt_ioc_ready = 0; |
2220 | int hard; | 2220 | int hard; |
2221 | int rc=0; | 2221 | int rc=0; |
2222 | int ii; | 2222 | int ii; |
2223 | int ret = 0; | 2223 | int ret = 0; |
2224 | int reset_alt_ioc_active = 0; | 2224 | int reset_alt_ioc_active = 0; |
2225 | int irq_allocated = 0; | 2225 | int irq_allocated = 0; |
2226 | u8 *a; | 2226 | u8 *a; |
2227 | 2227 | ||
2228 | printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name, | 2228 | printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name, |
2229 | reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery"); | 2229 | reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery"); |
2230 | 2230 | ||
2231 | /* Disable reply interrupts (also blocks FreeQ) */ | 2231 | /* Disable reply interrupts (also blocks FreeQ) */ |
2232 | CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); | 2232 | CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); |
2233 | ioc->active = 0; | 2233 | ioc->active = 0; |
2234 | 2234 | ||
2235 | if (ioc->alt_ioc) { | 2235 | if (ioc->alt_ioc) { |
2236 | if (ioc->alt_ioc->active || | 2236 | if (ioc->alt_ioc->active || |
2237 | reason == MPT_HOSTEVENT_IOC_RECOVER) { | 2237 | reason == MPT_HOSTEVENT_IOC_RECOVER) { |
2238 | reset_alt_ioc_active = 1; | 2238 | reset_alt_ioc_active = 1; |
2239 | /* Disable alt-IOC's reply interrupts | 2239 | /* Disable alt-IOC's reply interrupts |
2240 | * (and FreeQ) for a bit | 2240 | * (and FreeQ) for a bit |
2241 | **/ | 2241 | **/ |
2242 | CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, | 2242 | CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, |
2243 | 0xFFFFFFFF); | 2243 | 0xFFFFFFFF); |
2244 | ioc->alt_ioc->active = 0; | 2244 | ioc->alt_ioc->active = 0; |
2245 | } | 2245 | } |
2246 | } | 2246 | } |
2247 | 2247 | ||
2248 | hard = 1; | 2248 | hard = 1; |
2249 | if (reason == MPT_HOSTEVENT_IOC_BRINGUP) | 2249 | if (reason == MPT_HOSTEVENT_IOC_BRINGUP) |
2250 | hard = 0; | 2250 | hard = 0; |
2251 | 2251 | ||
2252 | if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) { | 2252 | if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) { |
2253 | if (hard_reset_done == -4) { | 2253 | if (hard_reset_done == -4) { |
2254 | printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n", | 2254 | printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n", |
2255 | ioc->name); | 2255 | ioc->name); |
2256 | 2256 | ||
2257 | if (reset_alt_ioc_active && ioc->alt_ioc) { | 2257 | if (reset_alt_ioc_active && ioc->alt_ioc) { |
2258 | /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */ | 2258 | /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */ |
2259 | dprintk(ioc, printk(MYIOC_s_INFO_FMT | 2259 | dprintk(ioc, printk(MYIOC_s_INFO_FMT |
2260 | "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name)); | 2260 | "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name)); |
2261 | CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); | 2261 | CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); |
2262 | ioc->alt_ioc->active = 1; | 2262 | ioc->alt_ioc->active = 1; |
2263 | } | 2263 | } |
2264 | 2264 | ||
2265 | } else { | 2265 | } else { |
2266 | printk(MYIOC_s_WARN_FMT | 2266 | printk(MYIOC_s_WARN_FMT |
2267 | "NOT READY WARNING!\n", ioc->name); | 2267 | "NOT READY WARNING!\n", ioc->name); |
2268 | } | 2268 | } |
2269 | ret = -1; | 2269 | ret = -1; |
2270 | goto out; | 2270 | goto out; |
2271 | } | 2271 | } |
2272 | 2272 | ||
2273 | /* hard_reset_done = 0 if a soft reset was performed | 2273 | /* hard_reset_done = 0 if a soft reset was performed |
2274 | * and 1 if a hard reset was performed. | 2274 | * and 1 if a hard reset was performed. |
2275 | */ | 2275 | */ |
2276 | if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) { | 2276 | if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) { |
2277 | if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) | 2277 | if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) |
2278 | alt_ioc_ready = 1; | 2278 | alt_ioc_ready = 1; |
2279 | else | 2279 | else |
2280 | printk(MYIOC_s_WARN_FMT | 2280 | printk(MYIOC_s_WARN_FMT |
2281 | ": alt-ioc Not ready WARNING!\n", | 2281 | ": alt-ioc Not ready WARNING!\n", |
2282 | ioc->alt_ioc->name); | 2282 | ioc->alt_ioc->name); |
2283 | } | 2283 | } |
2284 | 2284 | ||
2285 | for (ii=0; ii<5; ii++) { | 2285 | for (ii=0; ii<5; ii++) { |
2286 | /* Get IOC facts! Allow 5 retries */ | 2286 | /* Get IOC facts! Allow 5 retries */ |
2287 | if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0) | 2287 | if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0) |
2288 | break; | 2288 | break; |
2289 | } | 2289 | } |
2290 | 2290 | ||
2291 | 2291 | ||
2292 | if (ii == 5) { | 2292 | if (ii == 5) { |
2293 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 2293 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
2294 | "Retry IocFacts failed rc=%x\n", ioc->name, rc)); | 2294 | "Retry IocFacts failed rc=%x\n", ioc->name, rc)); |
2295 | ret = -2; | 2295 | ret = -2; |
2296 | } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { | 2296 | } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { |
2297 | MptDisplayIocCapabilities(ioc); | 2297 | MptDisplayIocCapabilities(ioc); |
2298 | } | 2298 | } |
2299 | 2299 | ||
2300 | if (alt_ioc_ready) { | 2300 | if (alt_ioc_ready) { |
2301 | if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { | 2301 | if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { |
2302 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 2302 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
2303 | "Initial Alt IocFacts failed rc=%x\n", | 2303 | "Initial Alt IocFacts failed rc=%x\n", |
2304 | ioc->name, rc)); | 2304 | ioc->name, rc)); |
2305 | /* Retry - alt IOC was initialized once | 2305 | /* Retry - alt IOC was initialized once |
2306 | */ | 2306 | */ |
2307 | rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); | 2307 | rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); |
2308 | } | 2308 | } |
2309 | if (rc) { | 2309 | if (rc) { |
2310 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 2310 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
2311 | "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc)); | 2311 | "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc)); |
2312 | alt_ioc_ready = 0; | 2312 | alt_ioc_ready = 0; |
2313 | reset_alt_ioc_active = 0; | 2313 | reset_alt_ioc_active = 0; |
2314 | } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { | 2314 | } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { |
2315 | MptDisplayIocCapabilities(ioc->alt_ioc); | 2315 | MptDisplayIocCapabilities(ioc->alt_ioc); |
2316 | } | 2316 | } |
2317 | } | 2317 | } |
2318 | 2318 | ||
2319 | if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) && | 2319 | if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) && |
2320 | (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) { | 2320 | (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) { |
2321 | pci_release_selected_regions(ioc->pcidev, ioc->bars); | 2321 | pci_release_selected_regions(ioc->pcidev, ioc->bars); |
2322 | ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM | | 2322 | ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM | |
2323 | IORESOURCE_IO); | 2323 | IORESOURCE_IO); |
2324 | if (pci_enable_device(ioc->pcidev)) | 2324 | if (pci_enable_device(ioc->pcidev)) |
2325 | return -5; | 2325 | return -5; |
2326 | if (pci_request_selected_regions(ioc->pcidev, ioc->bars, | 2326 | if (pci_request_selected_regions(ioc->pcidev, ioc->bars, |
2327 | "mpt")) | 2327 | "mpt")) |
2328 | return -5; | 2328 | return -5; |
2329 | } | 2329 | } |
2330 | 2330 | ||
2331 | /* | 2331 | /* |
2332 | * Device is reset now. It must have de-asserted the interrupt line | 2332 | * Device is reset now. It must have de-asserted the interrupt line |
2333 | * (if it was asserted) and it should be safe to register for the | 2333 | * (if it was asserted) and it should be safe to register for the |
2334 | * interrupt now. | 2334 | * interrupt now. |
2335 | */ | 2335 | */ |
2336 | if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { | 2336 | if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { |
2337 | ioc->pci_irq = -1; | 2337 | ioc->pci_irq = -1; |
2338 | if (ioc->pcidev->irq) { | 2338 | if (ioc->pcidev->irq) { |
2339 | if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev)) | 2339 | if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev)) |
2340 | printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n", | 2340 | printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n", |
2341 | ioc->name); | 2341 | ioc->name); |
2342 | else | 2342 | else |
2343 | ioc->msi_enable = 0; | 2343 | ioc->msi_enable = 0; |
2344 | rc = request_irq(ioc->pcidev->irq, mpt_interrupt, | 2344 | rc = request_irq(ioc->pcidev->irq, mpt_interrupt, |
2345 | IRQF_SHARED, ioc->name, ioc); | 2345 | IRQF_SHARED, ioc->name, ioc); |
2346 | if (rc < 0) { | 2346 | if (rc < 0) { |
2347 | printk(MYIOC_s_ERR_FMT "Unable to allocate " | 2347 | printk(MYIOC_s_ERR_FMT "Unable to allocate " |
2348 | "interrupt %d!\n", | 2348 | "interrupt %d!\n", |
2349 | ioc->name, ioc->pcidev->irq); | 2349 | ioc->name, ioc->pcidev->irq); |
2350 | if (ioc->msi_enable) | 2350 | if (ioc->msi_enable) |
2351 | pci_disable_msi(ioc->pcidev); | 2351 | pci_disable_msi(ioc->pcidev); |
2352 | ret = -EBUSY; | 2352 | ret = -EBUSY; |
2353 | goto out; | 2353 | goto out; |
2354 | } | 2354 | } |
2355 | irq_allocated = 1; | 2355 | irq_allocated = 1; |
2356 | ioc->pci_irq = ioc->pcidev->irq; | 2356 | ioc->pci_irq = ioc->pcidev->irq; |
2357 | pci_set_master(ioc->pcidev); /* ?? */ | 2357 | pci_set_master(ioc->pcidev); /* ?? */ |
2358 | pci_set_drvdata(ioc->pcidev, ioc); | 2358 | pci_set_drvdata(ioc->pcidev, ioc); |
2359 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT | 2359 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT |
2360 | "installed at interrupt %d\n", ioc->name, | 2360 | "installed at interrupt %d\n", ioc->name, |
2361 | ioc->pcidev->irq)); | 2361 | ioc->pcidev->irq)); |
2362 | } | 2362 | } |
2363 | } | 2363 | } |
2364 | 2364 | ||
2365 | /* Prime reply & request queues! | 2365 | /* Prime reply & request queues! |
2366 | * (mucho alloc's) Must be done prior to | 2366 | * (mucho alloc's) Must be done prior to |
2367 | * init as upper addresses are needed for init. | 2367 | * init as upper addresses are needed for init. |
2368 | * If fails, continue with alt-ioc processing | 2368 | * If fails, continue with alt-ioc processing |
2369 | */ | 2369 | */ |
2370 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n", | 2370 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n", |
2371 | ioc->name)); | 2371 | ioc->name)); |
2372 | if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0)) | 2372 | if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0)) |
2373 | ret = -3; | 2373 | ret = -3; |
2374 | 2374 | ||
2375 | /* May need to check/upload firmware & data here! | 2375 | /* May need to check/upload firmware & data here! |
2376 | * If fails, continue with alt-ioc processing | 2376 | * If fails, continue with alt-ioc processing |
2377 | */ | 2377 | */ |
2378 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n", | 2378 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n", |
2379 | ioc->name)); | 2379 | ioc->name)); |
2380 | if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0)) | 2380 | if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0)) |
2381 | ret = -4; | 2381 | ret = -4; |
2382 | // NEW! | 2382 | // NEW! |
2383 | if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) { | 2383 | if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) { |
2384 | printk(MYIOC_s_WARN_FMT | 2384 | printk(MYIOC_s_WARN_FMT |
2385 | ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n", | 2385 | ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n", |
2386 | ioc->alt_ioc->name, rc); | 2386 | ioc->alt_ioc->name, rc); |
2387 | alt_ioc_ready = 0; | 2387 | alt_ioc_ready = 0; |
2388 | reset_alt_ioc_active = 0; | 2388 | reset_alt_ioc_active = 0; |
2389 | } | 2389 | } |
2390 | 2390 | ||
2391 | if (alt_ioc_ready) { | 2391 | if (alt_ioc_ready) { |
2392 | if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { | 2392 | if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { |
2393 | alt_ioc_ready = 0; | 2393 | alt_ioc_ready = 0; |
2394 | reset_alt_ioc_active = 0; | 2394 | reset_alt_ioc_active = 0; |
2395 | printk(MYIOC_s_WARN_FMT | 2395 | printk(MYIOC_s_WARN_FMT |
2396 | ": alt-ioc: (%d) init failure WARNING!\n", | 2396 | ": alt-ioc: (%d) init failure WARNING!\n", |
2397 | ioc->alt_ioc->name, rc); | 2397 | ioc->alt_ioc->name, rc); |
2398 | } | 2398 | } |
2399 | } | 2399 | } |
2400 | 2400 | ||
2401 | if (reason == MPT_HOSTEVENT_IOC_BRINGUP){ | 2401 | if (reason == MPT_HOSTEVENT_IOC_BRINGUP){ |
2402 | if (ioc->upload_fw) { | 2402 | if (ioc->upload_fw) { |
2403 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 2403 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
2404 | "firmware upload required!\n", ioc->name)); | 2404 | "firmware upload required!\n", ioc->name)); |
2405 | 2405 | ||
2406 | /* Controller is not operational, cannot do upload | 2406 | /* Controller is not operational, cannot do upload |
2407 | */ | 2407 | */ |
2408 | if (ret == 0) { | 2408 | if (ret == 0) { |
2409 | rc = mpt_do_upload(ioc, sleepFlag); | 2409 | rc = mpt_do_upload(ioc, sleepFlag); |
2410 | if (rc == 0) { | 2410 | if (rc == 0) { |
2411 | if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { | 2411 | if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { |
2412 | /* | 2412 | /* |
2413 | * Maintain only one pointer to FW memory | 2413 | * Maintain only one pointer to FW memory |
2414 | * so there will not be two attempt to | 2414 | * so there will not be two attempt to |
2415 | * downloadboot onboard dual function | 2415 | * downloadboot onboard dual function |
2416 | * chips (mpt_adapter_disable, | 2416 | * chips (mpt_adapter_disable, |
2417 | * mpt_diag_reset) | 2417 | * mpt_diag_reset) |
2418 | */ | 2418 | */ |
2419 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 2419 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
2420 | "mpt_upload: alt_%s has cached_fw=%p \n", | 2420 | "mpt_upload: alt_%s has cached_fw=%p \n", |
2421 | ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw)); | 2421 | ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw)); |
2422 | ioc->cached_fw = NULL; | 2422 | ioc->cached_fw = NULL; |
2423 | } | 2423 | } |
2424 | } else { | 2424 | } else { |
2425 | printk(MYIOC_s_WARN_FMT | 2425 | printk(MYIOC_s_WARN_FMT |
2426 | "firmware upload failure!\n", ioc->name); | 2426 | "firmware upload failure!\n", ioc->name); |
2427 | ret = -6; | 2427 | ret = -6; |
2428 | } | 2428 | } |
2429 | } | 2429 | } |
2430 | } | 2430 | } |
2431 | } | 2431 | } |
2432 | 2432 | ||
2433 | /* Enable MPT base driver management of EventNotification | 2433 | /* Enable MPT base driver management of EventNotification |
2434 | * and EventAck handling. | 2434 | * and EventAck handling. |
2435 | */ | 2435 | */ |
2436 | if ((ret == 0) && (!ioc->facts.EventState)) { | 2436 | if ((ret == 0) && (!ioc->facts.EventState)) { |
2437 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT | 2437 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT |
2438 | "SendEventNotification\n", | 2438 | "SendEventNotification\n", |
2439 | ioc->name)); | 2439 | ioc->name)); |
2440 | ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */ | 2440 | ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */ |
2441 | } | 2441 | } |
2442 | 2442 | ||
2443 | if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) | 2443 | if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) |
2444 | rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag); | 2444 | rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag); |
2445 | 2445 | ||
2446 | if (ret == 0) { | 2446 | if (ret == 0) { |
2447 | /* Enable! (reply interrupt) */ | 2447 | /* Enable! (reply interrupt) */ |
2448 | CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); | 2448 | CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); |
2449 | ioc->active = 1; | 2449 | ioc->active = 1; |
2450 | } | 2450 | } |
2451 | if (rc == 0) { /* alt ioc */ | 2451 | if (rc == 0) { /* alt ioc */ |
2452 | if (reset_alt_ioc_active && ioc->alt_ioc) { | 2452 | if (reset_alt_ioc_active && ioc->alt_ioc) { |
2453 | /* (re)Enable alt-IOC! (reply interrupt) */ | 2453 | /* (re)Enable alt-IOC! (reply interrupt) */ |
2454 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc" | 2454 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc" |
2455 | "reply irq re-enabled\n", | 2455 | "reply irq re-enabled\n", |
2456 | ioc->alt_ioc->name)); | 2456 | ioc->alt_ioc->name)); |
2457 | CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, | 2457 | CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, |
2458 | MPI_HIM_DIM); | 2458 | MPI_HIM_DIM); |
2459 | ioc->alt_ioc->active = 1; | 2459 | ioc->alt_ioc->active = 1; |
2460 | } | 2460 | } |
2461 | } | 2461 | } |
2462 | 2462 | ||
2463 | 2463 | ||
2464 | /* Add additional "reason" check before call to GetLanConfigPages | 2464 | /* Add additional "reason" check before call to GetLanConfigPages |
2465 | * (combined with GetIoUnitPage2 call). This prevents a somewhat | 2465 | * (combined with GetIoUnitPage2 call). This prevents a somewhat |
2466 | * recursive scenario; GetLanConfigPages times out, timer expired | 2466 | * recursive scenario; GetLanConfigPages times out, timer expired |
2467 | * routine calls HardResetHandler, which calls into here again, | 2467 | * routine calls HardResetHandler, which calls into here again, |
2468 | * and we try GetLanConfigPages again... | 2468 | * and we try GetLanConfigPages again... |
2469 | */ | 2469 | */ |
2470 | if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { | 2470 | if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { |
2471 | 2471 | ||
2472 | /* | 2472 | /* |
2473 | * Initalize link list for inactive raid volumes. | 2473 | * Initalize link list for inactive raid volumes. |
2474 | */ | 2474 | */ |
2475 | mutex_init(&ioc->raid_data.inactive_list_mutex); | 2475 | mutex_init(&ioc->raid_data.inactive_list_mutex); |
2476 | INIT_LIST_HEAD(&ioc->raid_data.inactive_list); | 2476 | INIT_LIST_HEAD(&ioc->raid_data.inactive_list); |
2477 | 2477 | ||
2478 | switch (ioc->bus_type) { | 2478 | switch (ioc->bus_type) { |
2479 | 2479 | ||
2480 | case SAS: | 2480 | case SAS: |
2481 | /* clear persistency table */ | 2481 | /* clear persistency table */ |
2482 | if(ioc->facts.IOCExceptions & | 2482 | if(ioc->facts.IOCExceptions & |
2483 | MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) { | 2483 | MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) { |
2484 | ret = mptbase_sas_persist_operation(ioc, | 2484 | ret = mptbase_sas_persist_operation(ioc, |
2485 | MPI_SAS_OP_CLEAR_NOT_PRESENT); | 2485 | MPI_SAS_OP_CLEAR_NOT_PRESENT); |
2486 | if(ret != 0) | 2486 | if(ret != 0) |
2487 | goto out; | 2487 | goto out; |
2488 | } | 2488 | } |
2489 | 2489 | ||
2490 | /* Find IM volumes | 2490 | /* Find IM volumes |
2491 | */ | 2491 | */ |
2492 | mpt_findImVolumes(ioc); | 2492 | mpt_findImVolumes(ioc); |
2493 | 2493 | ||
2494 | /* Check, and possibly reset, the coalescing value | 2494 | /* Check, and possibly reset, the coalescing value |
2495 | */ | 2495 | */ |
2496 | mpt_read_ioc_pg_1(ioc); | 2496 | mpt_read_ioc_pg_1(ioc); |
2497 | 2497 | ||
2498 | break; | 2498 | break; |
2499 | 2499 | ||
2500 | case FC: | 2500 | case FC: |
2501 | if ((ioc->pfacts[0].ProtocolFlags & | 2501 | if ((ioc->pfacts[0].ProtocolFlags & |
2502 | MPI_PORTFACTS_PROTOCOL_LAN) && | 2502 | MPI_PORTFACTS_PROTOCOL_LAN) && |
2503 | (ioc->lan_cnfg_page0.Header.PageLength == 0)) { | 2503 | (ioc->lan_cnfg_page0.Header.PageLength == 0)) { |
2504 | /* | 2504 | /* |
2505 | * Pre-fetch the ports LAN MAC address! | 2505 | * Pre-fetch the ports LAN MAC address! |
2506 | * (LANPage1_t stuff) | 2506 | * (LANPage1_t stuff) |
2507 | */ | 2507 | */ |
2508 | (void) GetLanConfigPages(ioc); | 2508 | (void) GetLanConfigPages(ioc); |
2509 | a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; | 2509 | a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; |
2510 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 2510 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
2511 | "LanAddr = %02X:%02X:%02X" | 2511 | "LanAddr = %02X:%02X:%02X" |
2512 | ":%02X:%02X:%02X\n", | 2512 | ":%02X:%02X:%02X\n", |
2513 | ioc->name, a[5], a[4], | 2513 | ioc->name, a[5], a[4], |
2514 | a[3], a[2], a[1], a[0])); | 2514 | a[3], a[2], a[1], a[0])); |
2515 | } | 2515 | } |
2516 | break; | 2516 | break; |
2517 | 2517 | ||
2518 | case SPI: | 2518 | case SPI: |
2519 | /* Get NVRAM and adapter maximums from SPP 0 and 2 | 2519 | /* Get NVRAM and adapter maximums from SPP 0 and 2 |
2520 | */ | 2520 | */ |
2521 | mpt_GetScsiPortSettings(ioc, 0); | 2521 | mpt_GetScsiPortSettings(ioc, 0); |
2522 | 2522 | ||
2523 | /* Get version and length of SDP 1 | 2523 | /* Get version and length of SDP 1 |
2524 | */ | 2524 | */ |
2525 | mpt_readScsiDevicePageHeaders(ioc, 0); | 2525 | mpt_readScsiDevicePageHeaders(ioc, 0); |
2526 | 2526 | ||
2527 | /* Find IM volumes | 2527 | /* Find IM volumes |
2528 | */ | 2528 | */ |
2529 | if (ioc->facts.MsgVersion >= MPI_VERSION_01_02) | 2529 | if (ioc->facts.MsgVersion >= MPI_VERSION_01_02) |
2530 | mpt_findImVolumes(ioc); | 2530 | mpt_findImVolumes(ioc); |
2531 | 2531 | ||
2532 | /* Check, and possibly reset, the coalescing value | 2532 | /* Check, and possibly reset, the coalescing value |
2533 | */ | 2533 | */ |
2534 | mpt_read_ioc_pg_1(ioc); | 2534 | mpt_read_ioc_pg_1(ioc); |
2535 | 2535 | ||
2536 | mpt_read_ioc_pg_4(ioc); | 2536 | mpt_read_ioc_pg_4(ioc); |
2537 | 2537 | ||
2538 | break; | 2538 | break; |
2539 | } | 2539 | } |
2540 | 2540 | ||
2541 | GetIoUnitPage2(ioc); | 2541 | GetIoUnitPage2(ioc); |
2542 | mpt_get_manufacturing_pg_0(ioc); | 2542 | mpt_get_manufacturing_pg_0(ioc); |
2543 | } | 2543 | } |
2544 | 2544 | ||
2545 | out: | 2545 | out: |
2546 | if ((ret != 0) && irq_allocated) { | 2546 | if ((ret != 0) && irq_allocated) { |
2547 | free_irq(ioc->pci_irq, ioc); | 2547 | free_irq(ioc->pci_irq, ioc); |
2548 | if (ioc->msi_enable) | 2548 | if (ioc->msi_enable) |
2549 | pci_disable_msi(ioc->pcidev); | 2549 | pci_disable_msi(ioc->pcidev); |
2550 | } | 2550 | } |
2551 | return ret; | 2551 | return ret; |
2552 | } | 2552 | } |
2553 | 2553 | ||
2554 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 2554 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
2555 | /** | 2555 | /** |
2556 | * mpt_detect_bound_ports - Search for matching PCI bus/dev_function | 2556 | * mpt_detect_bound_ports - Search for matching PCI bus/dev_function |
2557 | * @ioc: Pointer to MPT adapter structure | 2557 | * @ioc: Pointer to MPT adapter structure |
2558 | * @pdev: Pointer to (struct pci_dev) structure | 2558 | * @pdev: Pointer to (struct pci_dev) structure |
2559 | * | 2559 | * |
2560 | * Search for PCI bus/dev_function which matches | 2560 | * Search for PCI bus/dev_function which matches |
2561 | * PCI bus/dev_function (+/-1) for newly discovered 929, | 2561 | * PCI bus/dev_function (+/-1) for newly discovered 929, |
2562 | * 929X, 1030 or 1035. | 2562 | * 929X, 1030 or 1035. |
2563 | * | 2563 | * |
2564 | * If match on PCI dev_function +/-1 is found, bind the two MPT adapters | 2564 | * If match on PCI dev_function +/-1 is found, bind the two MPT adapters |
2565 | * using alt_ioc pointer fields in their %MPT_ADAPTER structures. | 2565 | * using alt_ioc pointer fields in their %MPT_ADAPTER structures. |
2566 | */ | 2566 | */ |
2567 | static void | 2567 | static void |
2568 | mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) | 2568 | mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) |
2569 | { | 2569 | { |
2570 | struct pci_dev *peer=NULL; | 2570 | struct pci_dev *peer=NULL; |
2571 | unsigned int slot = PCI_SLOT(pdev->devfn); | 2571 | unsigned int slot = PCI_SLOT(pdev->devfn); |
2572 | unsigned int func = PCI_FUNC(pdev->devfn); | 2572 | unsigned int func = PCI_FUNC(pdev->devfn); |
2573 | MPT_ADAPTER *ioc_srch; | 2573 | MPT_ADAPTER *ioc_srch; |
2574 | 2574 | ||
2575 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x," | 2575 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x," |
2576 | " searching for devfn match on %x or %x\n", | 2576 | " searching for devfn match on %x or %x\n", |
2577 | ioc->name, pci_name(pdev), pdev->bus->number, | 2577 | ioc->name, pci_name(pdev), pdev->bus->number, |
2578 | pdev->devfn, func-1, func+1)); | 2578 | pdev->devfn, func-1, func+1)); |
2579 | 2579 | ||
2580 | peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1)); | 2580 | peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1)); |
2581 | if (!peer) { | 2581 | if (!peer) { |
2582 | peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1)); | 2582 | peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1)); |
2583 | if (!peer) | 2583 | if (!peer) |
2584 | return; | 2584 | return; |
2585 | } | 2585 | } |
2586 | 2586 | ||
2587 | list_for_each_entry(ioc_srch, &ioc_list, list) { | 2587 | list_for_each_entry(ioc_srch, &ioc_list, list) { |
2588 | struct pci_dev *_pcidev = ioc_srch->pcidev; | 2588 | struct pci_dev *_pcidev = ioc_srch->pcidev; |
2589 | if (_pcidev == peer) { | 2589 | if (_pcidev == peer) { |
2590 | /* Paranoia checks */ | 2590 | /* Paranoia checks */ |
2591 | if (ioc->alt_ioc != NULL) { | 2591 | if (ioc->alt_ioc != NULL) { |
2592 | printk(MYIOC_s_WARN_FMT | 2592 | printk(MYIOC_s_WARN_FMT |
2593 | "Oops, already bound (%s <==> %s)!\n", | 2593 | "Oops, already bound (%s <==> %s)!\n", |
2594 | ioc->name, ioc->name, ioc->alt_ioc->name); | 2594 | ioc->name, ioc->name, ioc->alt_ioc->name); |
2595 | break; | 2595 | break; |
2596 | } else if (ioc_srch->alt_ioc != NULL) { | 2596 | } else if (ioc_srch->alt_ioc != NULL) { |
2597 | printk(MYIOC_s_WARN_FMT | 2597 | printk(MYIOC_s_WARN_FMT |
2598 | "Oops, already bound (%s <==> %s)!\n", | 2598 | "Oops, already bound (%s <==> %s)!\n", |
2599 | ioc_srch->name, ioc_srch->name, | 2599 | ioc_srch->name, ioc_srch->name, |
2600 | ioc_srch->alt_ioc->name); | 2600 | ioc_srch->alt_ioc->name); |
2601 | break; | 2601 | break; |
2602 | } | 2602 | } |
2603 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 2603 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
2604 | "FOUND! binding %s <==> %s\n", | 2604 | "FOUND! binding %s <==> %s\n", |
2605 | ioc->name, ioc->name, ioc_srch->name)); | 2605 | ioc->name, ioc->name, ioc_srch->name)); |
2606 | ioc_srch->alt_ioc = ioc; | 2606 | ioc_srch->alt_ioc = ioc; |
2607 | ioc->alt_ioc = ioc_srch; | 2607 | ioc->alt_ioc = ioc_srch; |
2608 | } | 2608 | } |
2609 | } | 2609 | } |
2610 | pci_dev_put(peer); | 2610 | pci_dev_put(peer); |
2611 | } | 2611 | } |
2612 | 2612 | ||
2613 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 2613 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
2614 | /** | 2614 | /** |
2615 | * mpt_adapter_disable - Disable misbehaving MPT adapter. | 2615 | * mpt_adapter_disable - Disable misbehaving MPT adapter. |
2616 | * @ioc: Pointer to MPT adapter structure | 2616 | * @ioc: Pointer to MPT adapter structure |
2617 | */ | 2617 | */ |
2618 | static void | 2618 | static void |
2619 | mpt_adapter_disable(MPT_ADAPTER *ioc) | 2619 | mpt_adapter_disable(MPT_ADAPTER *ioc) |
2620 | { | 2620 | { |
2621 | int sz; | 2621 | int sz; |
2622 | int ret; | 2622 | int ret; |
2623 | 2623 | ||
2624 | if (ioc->cached_fw != NULL) { | 2624 | if (ioc->cached_fw != NULL) { |
2625 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 2625 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
2626 | "%s: Pushing FW onto adapter\n", __func__, ioc->name)); | 2626 | "%s: Pushing FW onto adapter\n", __func__, ioc->name)); |
2627 | if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *) | 2627 | if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *) |
2628 | ioc->cached_fw, CAN_SLEEP)) < 0) { | 2628 | ioc->cached_fw, CAN_SLEEP)) < 0) { |
2629 | printk(MYIOC_s_WARN_FMT | 2629 | printk(MYIOC_s_WARN_FMT |
2630 | ": firmware downloadboot failure (%d)!\n", | 2630 | ": firmware downloadboot failure (%d)!\n", |
2631 | ioc->name, ret); | 2631 | ioc->name, ret); |
2632 | } | 2632 | } |
2633 | } | 2633 | } |
2634 | 2634 | ||
2635 | /* | 2635 | /* |
2636 | * Put the controller into ready state (if its not already) | 2636 | * Put the controller into ready state (if its not already) |
2637 | */ | 2637 | */ |
2638 | if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) { | 2638 | if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) { |
2639 | if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, | 2639 | if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, |
2640 | CAN_SLEEP)) { | 2640 | CAN_SLEEP)) { |
2641 | if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) | 2641 | if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) |
2642 | printk(MYIOC_s_ERR_FMT "%s: IOC msg unit " | 2642 | printk(MYIOC_s_ERR_FMT "%s: IOC msg unit " |
2643 | "reset failed to put ioc in ready state!\n", | 2643 | "reset failed to put ioc in ready state!\n", |
2644 | ioc->name, __func__); | 2644 | ioc->name, __func__); |
2645 | } else | 2645 | } else |
2646 | printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset " | 2646 | printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset " |
2647 | "failed!\n", ioc->name, __func__); | 2647 | "failed!\n", ioc->name, __func__); |
2648 | } | 2648 | } |
2649 | 2649 | ||
2650 | 2650 | ||
2651 | /* Disable adapter interrupts! */ | 2651 | /* Disable adapter interrupts! */ |
2652 | synchronize_irq(ioc->pcidev->irq); | 2652 | synchronize_irq(ioc->pcidev->irq); |
2653 | CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); | 2653 | CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); |
2654 | ioc->active = 0; | 2654 | ioc->active = 0; |
2655 | 2655 | ||
2656 | /* Clear any lingering interrupt */ | 2656 | /* Clear any lingering interrupt */ |
2657 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); | 2657 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); |
2658 | CHIPREG_READ32(&ioc->chip->IntStatus); | 2658 | CHIPREG_READ32(&ioc->chip->IntStatus); |
2659 | 2659 | ||
2660 | if (ioc->alloc != NULL) { | 2660 | if (ioc->alloc != NULL) { |
2661 | sz = ioc->alloc_sz; | 2661 | sz = ioc->alloc_sz; |
2662 | dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n", | 2662 | dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n", |
2663 | ioc->name, ioc->alloc, ioc->alloc_sz)); | 2663 | ioc->name, ioc->alloc, ioc->alloc_sz)); |
2664 | pci_free_consistent(ioc->pcidev, sz, | 2664 | pci_free_consistent(ioc->pcidev, sz, |
2665 | ioc->alloc, ioc->alloc_dma); | 2665 | ioc->alloc, ioc->alloc_dma); |
2666 | ioc->reply_frames = NULL; | 2666 | ioc->reply_frames = NULL; |
2667 | ioc->req_frames = NULL; | 2667 | ioc->req_frames = NULL; |
2668 | ioc->alloc = NULL; | 2668 | ioc->alloc = NULL; |
2669 | ioc->alloc_total -= sz; | 2669 | ioc->alloc_total -= sz; |
2670 | } | 2670 | } |
2671 | 2671 | ||
2672 | if (ioc->sense_buf_pool != NULL) { | 2672 | if (ioc->sense_buf_pool != NULL) { |
2673 | sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); | 2673 | sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); |
2674 | pci_free_consistent(ioc->pcidev, sz, | 2674 | pci_free_consistent(ioc->pcidev, sz, |
2675 | ioc->sense_buf_pool, ioc->sense_buf_pool_dma); | 2675 | ioc->sense_buf_pool, ioc->sense_buf_pool_dma); |
2676 | ioc->sense_buf_pool = NULL; | 2676 | ioc->sense_buf_pool = NULL; |
2677 | ioc->alloc_total -= sz; | 2677 | ioc->alloc_total -= sz; |
2678 | } | 2678 | } |
2679 | 2679 | ||
2680 | if (ioc->events != NULL){ | 2680 | if (ioc->events != NULL){ |
2681 | sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); | 2681 | sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); |
2682 | kfree(ioc->events); | 2682 | kfree(ioc->events); |
2683 | ioc->events = NULL; | 2683 | ioc->events = NULL; |
2684 | ioc->alloc_total -= sz; | 2684 | ioc->alloc_total -= sz; |
2685 | } | 2685 | } |
2686 | 2686 | ||
2687 | mpt_free_fw_memory(ioc); | 2687 | mpt_free_fw_memory(ioc); |
2688 | 2688 | ||
2689 | kfree(ioc->spi_data.nvram); | 2689 | kfree(ioc->spi_data.nvram); |
2690 | mpt_inactive_raid_list_free(ioc); | 2690 | mpt_inactive_raid_list_free(ioc); |
2691 | kfree(ioc->raid_data.pIocPg2); | 2691 | kfree(ioc->raid_data.pIocPg2); |
2692 | kfree(ioc->raid_data.pIocPg3); | 2692 | kfree(ioc->raid_data.pIocPg3); |
2693 | ioc->spi_data.nvram = NULL; | 2693 | ioc->spi_data.nvram = NULL; |
2694 | ioc->raid_data.pIocPg3 = NULL; | 2694 | ioc->raid_data.pIocPg3 = NULL; |
2695 | 2695 | ||
2696 | if (ioc->spi_data.pIocPg4 != NULL) { | 2696 | if (ioc->spi_data.pIocPg4 != NULL) { |
2697 | sz = ioc->spi_data.IocPg4Sz; | 2697 | sz = ioc->spi_data.IocPg4Sz; |
2698 | pci_free_consistent(ioc->pcidev, sz, | 2698 | pci_free_consistent(ioc->pcidev, sz, |
2699 | ioc->spi_data.pIocPg4, | 2699 | ioc->spi_data.pIocPg4, |
2700 | ioc->spi_data.IocPg4_dma); | 2700 | ioc->spi_data.IocPg4_dma); |
2701 | ioc->spi_data.pIocPg4 = NULL; | 2701 | ioc->spi_data.pIocPg4 = NULL; |
2702 | ioc->alloc_total -= sz; | 2702 | ioc->alloc_total -= sz; |
2703 | } | 2703 | } |
2704 | 2704 | ||
2705 | if (ioc->ReqToChain != NULL) { | 2705 | if (ioc->ReqToChain != NULL) { |
2706 | kfree(ioc->ReqToChain); | 2706 | kfree(ioc->ReqToChain); |
2707 | kfree(ioc->RequestNB); | 2707 | kfree(ioc->RequestNB); |
2708 | ioc->ReqToChain = NULL; | 2708 | ioc->ReqToChain = NULL; |
2709 | } | 2709 | } |
2710 | 2710 | ||
2711 | kfree(ioc->ChainToChain); | 2711 | kfree(ioc->ChainToChain); |
2712 | ioc->ChainToChain = NULL; | 2712 | ioc->ChainToChain = NULL; |
2713 | 2713 | ||
2714 | if (ioc->HostPageBuffer != NULL) { | 2714 | if (ioc->HostPageBuffer != NULL) { |
2715 | if((ret = mpt_host_page_access_control(ioc, | 2715 | if((ret = mpt_host_page_access_control(ioc, |
2716 | MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) { | 2716 | MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) { |
2717 | printk(MYIOC_s_ERR_FMT | 2717 | printk(MYIOC_s_ERR_FMT |
2718 | ": %s: host page buffers free failed (%d)!\n", | 2718 | ": %s: host page buffers free failed (%d)!\n", |
2719 | ioc->name, __func__, ret); | 2719 | ioc->name, __func__, ret); |
2720 | } | 2720 | } |
2721 | dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 2721 | dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
2722 | "HostPageBuffer free @ %p, sz=%d bytes\n", | 2722 | "HostPageBuffer free @ %p, sz=%d bytes\n", |
2723 | ioc->name, ioc->HostPageBuffer, | 2723 | ioc->name, ioc->HostPageBuffer, |
2724 | ioc->HostPageBuffer_sz)); | 2724 | ioc->HostPageBuffer_sz)); |
2725 | pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz, | 2725 | pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz, |
2726 | ioc->HostPageBuffer, ioc->HostPageBuffer_dma); | 2726 | ioc->HostPageBuffer, ioc->HostPageBuffer_dma); |
2727 | ioc->HostPageBuffer = NULL; | 2727 | ioc->HostPageBuffer = NULL; |
2728 | ioc->HostPageBuffer_sz = 0; | 2728 | ioc->HostPageBuffer_sz = 0; |
2729 | ioc->alloc_total -= ioc->HostPageBuffer_sz; | 2729 | ioc->alloc_total -= ioc->HostPageBuffer_sz; |
2730 | } | 2730 | } |
2731 | 2731 | ||
2732 | pci_set_drvdata(ioc->pcidev, NULL); | 2732 | pci_set_drvdata(ioc->pcidev, NULL); |
2733 | } | 2733 | } |
2734 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 2734 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
2735 | /** | 2735 | /** |
2736 | * mpt_adapter_dispose - Free all resources associated with an MPT adapter | 2736 | * mpt_adapter_dispose - Free all resources associated with an MPT adapter |
2737 | * @ioc: Pointer to MPT adapter structure | 2737 | * @ioc: Pointer to MPT adapter structure |
2738 | * | 2738 | * |
2739 | * This routine unregisters h/w resources and frees all alloc'd memory | 2739 | * This routine unregisters h/w resources and frees all alloc'd memory |
2740 | * associated with a MPT adapter structure. | 2740 | * associated with a MPT adapter structure. |
2741 | */ | 2741 | */ |
2742 | static void | 2742 | static void |
2743 | mpt_adapter_dispose(MPT_ADAPTER *ioc) | 2743 | mpt_adapter_dispose(MPT_ADAPTER *ioc) |
2744 | { | 2744 | { |
2745 | int sz_first, sz_last; | 2745 | int sz_first, sz_last; |
2746 | 2746 | ||
2747 | if (ioc == NULL) | 2747 | if (ioc == NULL) |
2748 | return; | 2748 | return; |
2749 | 2749 | ||
2750 | sz_first = ioc->alloc_total; | 2750 | sz_first = ioc->alloc_total; |
2751 | 2751 | ||
2752 | mpt_adapter_disable(ioc); | 2752 | mpt_adapter_disable(ioc); |
2753 | 2753 | ||
2754 | if (ioc->pci_irq != -1) { | 2754 | if (ioc->pci_irq != -1) { |
2755 | free_irq(ioc->pci_irq, ioc); | 2755 | free_irq(ioc->pci_irq, ioc); |
2756 | if (ioc->msi_enable) | 2756 | if (ioc->msi_enable) |
2757 | pci_disable_msi(ioc->pcidev); | 2757 | pci_disable_msi(ioc->pcidev); |
2758 | ioc->pci_irq = -1; | 2758 | ioc->pci_irq = -1; |
2759 | } | 2759 | } |
2760 | 2760 | ||
2761 | if (ioc->memmap != NULL) { | 2761 | if (ioc->memmap != NULL) { |
2762 | iounmap(ioc->memmap); | 2762 | iounmap(ioc->memmap); |
2763 | ioc->memmap = NULL; | 2763 | ioc->memmap = NULL; |
2764 | } | 2764 | } |
2765 | 2765 | ||
2766 | pci_disable_device(ioc->pcidev); | 2766 | pci_disable_device(ioc->pcidev); |
2767 | pci_release_selected_regions(ioc->pcidev, ioc->bars); | 2767 | pci_release_selected_regions(ioc->pcidev, ioc->bars); |
2768 | 2768 | ||
2769 | #if defined(CONFIG_MTRR) && 0 | 2769 | #if defined(CONFIG_MTRR) && 0 |
2770 | if (ioc->mtrr_reg > 0) { | 2770 | if (ioc->mtrr_reg > 0) { |
2771 | mtrr_del(ioc->mtrr_reg, 0, 0); | 2771 | mtrr_del(ioc->mtrr_reg, 0, 0); |
2772 | dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name)); | 2772 | dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name)); |
2773 | } | 2773 | } |
2774 | #endif | 2774 | #endif |
2775 | 2775 | ||
2776 | /* Zap the adapter lookup ptr! */ | 2776 | /* Zap the adapter lookup ptr! */ |
2777 | list_del(&ioc->list); | 2777 | list_del(&ioc->list); |
2778 | 2778 | ||
2779 | sz_last = ioc->alloc_total; | 2779 | sz_last = ioc->alloc_total; |
2780 | dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n", | 2780 | dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n", |
2781 | ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first)); | 2781 | ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first)); |
2782 | 2782 | ||
2783 | if (ioc->alt_ioc) | 2783 | if (ioc->alt_ioc) |
2784 | ioc->alt_ioc->alt_ioc = NULL; | 2784 | ioc->alt_ioc->alt_ioc = NULL; |
2785 | 2785 | ||
2786 | kfree(ioc); | 2786 | kfree(ioc); |
2787 | } | 2787 | } |
2788 | 2788 | ||
2789 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 2789 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
2790 | /** | 2790 | /** |
2791 | * MptDisplayIocCapabilities - Disply IOC's capabilities. | 2791 | * MptDisplayIocCapabilities - Disply IOC's capabilities. |
2792 | * @ioc: Pointer to MPT adapter structure | 2792 | * @ioc: Pointer to MPT adapter structure |
2793 | */ | 2793 | */ |
2794 | static void | 2794 | static void |
2795 | MptDisplayIocCapabilities(MPT_ADAPTER *ioc) | 2795 | MptDisplayIocCapabilities(MPT_ADAPTER *ioc) |
2796 | { | 2796 | { |
2797 | int i = 0; | 2797 | int i = 0; |
2798 | 2798 | ||
2799 | printk(KERN_INFO "%s: ", ioc->name); | 2799 | printk(KERN_INFO "%s: ", ioc->name); |
2800 | if (ioc->prod_name) | 2800 | if (ioc->prod_name) |
2801 | printk("%s: ", ioc->prod_name); | 2801 | printk("%s: ", ioc->prod_name); |
2802 | printk("Capabilities={"); | 2802 | printk("Capabilities={"); |
2803 | 2803 | ||
2804 | if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) { | 2804 | if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) { |
2805 | printk("Initiator"); | 2805 | printk("Initiator"); |
2806 | i++; | 2806 | i++; |
2807 | } | 2807 | } |
2808 | 2808 | ||
2809 | if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) { | 2809 | if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) { |
2810 | printk("%sTarget", i ? "," : ""); | 2810 | printk("%sTarget", i ? "," : ""); |
2811 | i++; | 2811 | i++; |
2812 | } | 2812 | } |
2813 | 2813 | ||
2814 | if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { | 2814 | if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { |
2815 | printk("%sLAN", i ? "," : ""); | 2815 | printk("%sLAN", i ? "," : ""); |
2816 | i++; | 2816 | i++; |
2817 | } | 2817 | } |
2818 | 2818 | ||
2819 | #if 0 | 2819 | #if 0 |
2820 | /* | 2820 | /* |
2821 | * This would probably evoke more questions than it's worth | 2821 | * This would probably evoke more questions than it's worth |
2822 | */ | 2822 | */ |
2823 | if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) { | 2823 | if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) { |
2824 | printk("%sLogBusAddr", i ? "," : ""); | 2824 | printk("%sLogBusAddr", i ? "," : ""); |
2825 | i++; | 2825 | i++; |
2826 | } | 2826 | } |
2827 | #endif | 2827 | #endif |
2828 | 2828 | ||
2829 | printk("}\n"); | 2829 | printk("}\n"); |
2830 | } | 2830 | } |
2831 | 2831 | ||
2832 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 2832 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
2833 | /** | 2833 | /** |
2834 | * MakeIocReady - Get IOC to a READY state, using KickStart if needed. | 2834 | * MakeIocReady - Get IOC to a READY state, using KickStart if needed. |
2835 | * @ioc: Pointer to MPT_ADAPTER structure | 2835 | * @ioc: Pointer to MPT_ADAPTER structure |
2836 | * @force: Force hard KickStart of IOC | 2836 | * @force: Force hard KickStart of IOC |
2837 | * @sleepFlag: Specifies whether the process can sleep | 2837 | * @sleepFlag: Specifies whether the process can sleep |
2838 | * | 2838 | * |
2839 | * Returns: | 2839 | * Returns: |
2840 | * 1 - DIAG reset and READY | 2840 | * 1 - DIAG reset and READY |
2841 | * 0 - READY initially OR soft reset and READY | 2841 | * 0 - READY initially OR soft reset and READY |
2842 | * -1 - Any failure on KickStart | 2842 | * -1 - Any failure on KickStart |
2843 | * -2 - Msg Unit Reset Failed | 2843 | * -2 - Msg Unit Reset Failed |
2844 | * -3 - IO Unit Reset Failed | 2844 | * -3 - IO Unit Reset Failed |
2845 | * -4 - IOC owned by a PEER | 2845 | * -4 - IOC owned by a PEER |
2846 | */ | 2846 | */ |
2847 | static int | 2847 | static int |
2848 | MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) | 2848 | MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) |
2849 | { | 2849 | { |
2850 | u32 ioc_state; | 2850 | u32 ioc_state; |
2851 | int statefault = 0; | 2851 | int statefault = 0; |
2852 | int cntdn; | 2852 | int cntdn; |
2853 | int hard_reset_done = 0; | 2853 | int hard_reset_done = 0; |
2854 | int r; | 2854 | int r; |
2855 | int ii; | 2855 | int ii; |
2856 | int whoinit; | 2856 | int whoinit; |
2857 | 2857 | ||
2858 | /* Get current [raw] IOC state */ | 2858 | /* Get current [raw] IOC state */ |
2859 | ioc_state = mpt_GetIocState(ioc, 0); | 2859 | ioc_state = mpt_GetIocState(ioc, 0); |
2860 | dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state)); | 2860 | dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state)); |
2861 | 2861 | ||
2862 | /* | 2862 | /* |
2863 | * Check to see if IOC got left/stuck in doorbell handshake | 2863 | * Check to see if IOC got left/stuck in doorbell handshake |
2864 | * grip of death. If so, hard reset the IOC. | 2864 | * grip of death. If so, hard reset the IOC. |
2865 | */ | 2865 | */ |
2866 | if (ioc_state & MPI_DOORBELL_ACTIVE) { | 2866 | if (ioc_state & MPI_DOORBELL_ACTIVE) { |
2867 | statefault = 1; | 2867 | statefault = 1; |
2868 | printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n", | 2868 | printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n", |
2869 | ioc->name); | 2869 | ioc->name); |
2870 | } | 2870 | } |
2871 | 2871 | ||
2872 | /* Is it already READY? */ | 2872 | /* Is it already READY? */ |
2873 | if (!statefault && | 2873 | if (!statefault && |
2874 | ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) { | 2874 | ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) { |
2875 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT | 2875 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT |
2876 | "IOC is in READY state\n", ioc->name)); | 2876 | "IOC is in READY state\n", ioc->name)); |
2877 | return 0; | 2877 | return 0; |
2878 | } | 2878 | } |
2879 | 2879 | ||
2880 | /* | 2880 | /* |
2881 | * Check to see if IOC is in FAULT state. | 2881 | * Check to see if IOC is in FAULT state. |
2882 | */ | 2882 | */ |
2883 | if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { | 2883 | if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { |
2884 | statefault = 2; | 2884 | statefault = 2; |
2885 | printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n", | 2885 | printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n", |
2886 | ioc->name); | 2886 | ioc->name); |
2887 | printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n", | 2887 | printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n", |
2888 | ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK); | 2888 | ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK); |
2889 | } | 2889 | } |
2890 | 2890 | ||
2891 | /* | 2891 | /* |
2892 | * Hmmm... Did it get left operational? | 2892 | * Hmmm... Did it get left operational? |
2893 | */ | 2893 | */ |
2894 | if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) { | 2894 | if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) { |
2895 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n", | 2895 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n", |
2896 | ioc->name)); | 2896 | ioc->name)); |
2897 | 2897 | ||
2898 | /* Check WhoInit. | 2898 | /* Check WhoInit. |
2899 | * If PCI Peer, exit. | 2899 | * If PCI Peer, exit. |
2900 | * Else, if no fault conditions are present, issue a MessageUnitReset | 2900 | * Else, if no fault conditions are present, issue a MessageUnitReset |
2901 | * Else, fall through to KickStart case | 2901 | * Else, fall through to KickStart case |
2902 | */ | 2902 | */ |
2903 | whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT; | 2903 | whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT; |
2904 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT | 2904 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT |
2905 | "whoinit 0x%x statefault %d force %d\n", | 2905 | "whoinit 0x%x statefault %d force %d\n", |
2906 | ioc->name, whoinit, statefault, force)); | 2906 | ioc->name, whoinit, statefault, force)); |
2907 | if (whoinit == MPI_WHOINIT_PCI_PEER) | 2907 | if (whoinit == MPI_WHOINIT_PCI_PEER) |
2908 | return -4; | 2908 | return -4; |
2909 | else { | 2909 | else { |
2910 | if ((statefault == 0 ) && (force == 0)) { | 2910 | if ((statefault == 0 ) && (force == 0)) { |
2911 | if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0) | 2911 | if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0) |
2912 | return 0; | 2912 | return 0; |
2913 | } | 2913 | } |
2914 | statefault = 3; | 2914 | statefault = 3; |
2915 | } | 2915 | } |
2916 | } | 2916 | } |
2917 | 2917 | ||
2918 | hard_reset_done = KickStart(ioc, statefault||force, sleepFlag); | 2918 | hard_reset_done = KickStart(ioc, statefault||force, sleepFlag); |
2919 | if (hard_reset_done < 0) | 2919 | if (hard_reset_done < 0) |
2920 | return -1; | 2920 | return -1; |
2921 | 2921 | ||
2922 | /* | 2922 | /* |
2923 | * Loop here waiting for IOC to come READY. | 2923 | * Loop here waiting for IOC to come READY. |
2924 | */ | 2924 | */ |
2925 | ii = 0; | 2925 | ii = 0; |
2926 | cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */ | 2926 | cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */ |
2927 | 2927 | ||
2928 | while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) { | 2928 | while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) { |
2929 | if (ioc_state == MPI_IOC_STATE_OPERATIONAL) { | 2929 | if (ioc_state == MPI_IOC_STATE_OPERATIONAL) { |
2930 | /* | 2930 | /* |
2931 | * BIOS or previous driver load left IOC in OP state. | 2931 | * BIOS or previous driver load left IOC in OP state. |
2932 | * Reset messaging FIFOs. | 2932 | * Reset messaging FIFOs. |
2933 | */ | 2933 | */ |
2934 | if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) { | 2934 | if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) { |
2935 | printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name); | 2935 | printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name); |
2936 | return -2; | 2936 | return -2; |
2937 | } | 2937 | } |
2938 | } else if (ioc_state == MPI_IOC_STATE_RESET) { | 2938 | } else if (ioc_state == MPI_IOC_STATE_RESET) { |
2939 | /* | 2939 | /* |
2940 | * Something is wrong. Try to get IOC back | 2940 | * Something is wrong. Try to get IOC back |
2941 | * to a known state. | 2941 | * to a known state. |
2942 | */ | 2942 | */ |
2943 | if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) { | 2943 | if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) { |
2944 | printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name); | 2944 | printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name); |
2945 | return -3; | 2945 | return -3; |
2946 | } | 2946 | } |
2947 | } | 2947 | } |
2948 | 2948 | ||
2949 | ii++; cntdn--; | 2949 | ii++; cntdn--; |
2950 | if (!cntdn) { | 2950 | if (!cntdn) { |
2951 | printk(MYIOC_s_ERR_FMT | 2951 | printk(MYIOC_s_ERR_FMT |
2952 | "Wait IOC_READY state (0x%x) timeout(%d)!\n", | 2952 | "Wait IOC_READY state (0x%x) timeout(%d)!\n", |
2953 | ioc->name, ioc_state, (int)((ii+5)/HZ)); | 2953 | ioc->name, ioc_state, (int)((ii+5)/HZ)); |
2954 | return -ETIME; | 2954 | return -ETIME; |
2955 | } | 2955 | } |
2956 | 2956 | ||
2957 | if (sleepFlag == CAN_SLEEP) { | 2957 | if (sleepFlag == CAN_SLEEP) { |
2958 | msleep(1); | 2958 | msleep(1); |
2959 | } else { | 2959 | } else { |
2960 | mdelay (1); /* 1 msec delay */ | 2960 | mdelay (1); /* 1 msec delay */ |
2961 | } | 2961 | } |
2962 | 2962 | ||
2963 | } | 2963 | } |
2964 | 2964 | ||
2965 | if (statefault < 3) { | 2965 | if (statefault < 3) { |
2966 | printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name, | 2966 | printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name, |
2967 | statefault == 1 ? "stuck handshake" : "IOC FAULT"); | 2967 | statefault == 1 ? "stuck handshake" : "IOC FAULT"); |
2968 | } | 2968 | } |
2969 | 2969 | ||
2970 | return hard_reset_done; | 2970 | return hard_reset_done; |
2971 | } | 2971 | } |
2972 | 2972 | ||
2973 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 2973 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
2974 | /** | 2974 | /** |
2975 | * mpt_GetIocState - Get the current state of a MPT adapter. | 2975 | * mpt_GetIocState - Get the current state of a MPT adapter. |
2976 | * @ioc: Pointer to MPT_ADAPTER structure | 2976 | * @ioc: Pointer to MPT_ADAPTER structure |
2977 | * @cooked: Request raw or cooked IOC state | 2977 | * @cooked: Request raw or cooked IOC state |
2978 | * | 2978 | * |
2979 | * Returns all IOC Doorbell register bits if cooked==0, else just the | 2979 | * Returns all IOC Doorbell register bits if cooked==0, else just the |
2980 | * Doorbell bits in MPI_IOC_STATE_MASK. | 2980 | * Doorbell bits in MPI_IOC_STATE_MASK. |
2981 | */ | 2981 | */ |
2982 | u32 | 2982 | u32 |
2983 | mpt_GetIocState(MPT_ADAPTER *ioc, int cooked) | 2983 | mpt_GetIocState(MPT_ADAPTER *ioc, int cooked) |
2984 | { | 2984 | { |
2985 | u32 s, sc; | 2985 | u32 s, sc; |
2986 | 2986 | ||
2987 | /* Get! */ | 2987 | /* Get! */ |
2988 | s = CHIPREG_READ32(&ioc->chip->Doorbell); | 2988 | s = CHIPREG_READ32(&ioc->chip->Doorbell); |
2989 | sc = s & MPI_IOC_STATE_MASK; | 2989 | sc = s & MPI_IOC_STATE_MASK; |
2990 | 2990 | ||
2991 | /* Save! */ | 2991 | /* Save! */ |
2992 | ioc->last_state = sc; | 2992 | ioc->last_state = sc; |
2993 | 2993 | ||
2994 | return cooked ? sc : s; | 2994 | return cooked ? sc : s; |
2995 | } | 2995 | } |
2996 | 2996 | ||
2997 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 2997 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
2998 | /** | 2998 | /** |
2999 | * GetIocFacts - Send IOCFacts request to MPT adapter. | 2999 | * GetIocFacts - Send IOCFacts request to MPT adapter. |
3000 | * @ioc: Pointer to MPT_ADAPTER structure | 3000 | * @ioc: Pointer to MPT_ADAPTER structure |
3001 | * @sleepFlag: Specifies whether the process can sleep | 3001 | * @sleepFlag: Specifies whether the process can sleep |
3002 | * @reason: If recovery, only update facts. | 3002 | * @reason: If recovery, only update facts. |
3003 | * | 3003 | * |
3004 | * Returns 0 for success, non-zero for failure. | 3004 | * Returns 0 for success, non-zero for failure. |
3005 | */ | 3005 | */ |
3006 | static int | 3006 | static int |
3007 | GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) | 3007 | GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) |
3008 | { | 3008 | { |
3009 | IOCFacts_t get_facts; | 3009 | IOCFacts_t get_facts; |
3010 | IOCFactsReply_t *facts; | 3010 | IOCFactsReply_t *facts; |
3011 | int r; | 3011 | int r; |
3012 | int req_sz; | 3012 | int req_sz; |
3013 | int reply_sz; | 3013 | int reply_sz; |
3014 | int sz; | 3014 | int sz; |
3015 | u32 status, vv; | 3015 | u32 status, vv; |
3016 | u8 shiftFactor=1; | 3016 | u8 shiftFactor=1; |
3017 | 3017 | ||
3018 | /* IOC *must* NOT be in RESET state! */ | 3018 | /* IOC *must* NOT be in RESET state! */ |
3019 | if (ioc->last_state == MPI_IOC_STATE_RESET) { | 3019 | if (ioc->last_state == MPI_IOC_STATE_RESET) { |
3020 | printk(KERN_ERR MYNAM | 3020 | printk(KERN_ERR MYNAM |
3021 | ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n", | 3021 | ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n", |
3022 | ioc->name, ioc->last_state); | 3022 | ioc->name, ioc->last_state); |
3023 | return -44; | 3023 | return -44; |
3024 | } | 3024 | } |
3025 | 3025 | ||
3026 | facts = &ioc->facts; | 3026 | facts = &ioc->facts; |
3027 | 3027 | ||
3028 | /* Destination (reply area)... */ | 3028 | /* Destination (reply area)... */ |
3029 | reply_sz = sizeof(*facts); | 3029 | reply_sz = sizeof(*facts); |
3030 | memset(facts, 0, reply_sz); | 3030 | memset(facts, 0, reply_sz); |
3031 | 3031 | ||
3032 | /* Request area (get_facts on the stack right now!) */ | 3032 | /* Request area (get_facts on the stack right now!) */ |
3033 | req_sz = sizeof(get_facts); | 3033 | req_sz = sizeof(get_facts); |
3034 | memset(&get_facts, 0, req_sz); | 3034 | memset(&get_facts, 0, req_sz); |
3035 | 3035 | ||
3036 | get_facts.Function = MPI_FUNCTION_IOC_FACTS; | 3036 | get_facts.Function = MPI_FUNCTION_IOC_FACTS; |
3037 | /* Assert: All other get_facts fields are zero! */ | 3037 | /* Assert: All other get_facts fields are zero! */ |
3038 | 3038 | ||
3039 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 3039 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
3040 | "Sending get IocFacts request req_sz=%d reply_sz=%d\n", | 3040 | "Sending get IocFacts request req_sz=%d reply_sz=%d\n", |
3041 | ioc->name, req_sz, reply_sz)); | 3041 | ioc->name, req_sz, reply_sz)); |
3042 | 3042 | ||
3043 | /* No non-zero fields in the get_facts request are greater than | 3043 | /* No non-zero fields in the get_facts request are greater than |
3044 | * 1 byte in size, so we can just fire it off as is. | 3044 | * 1 byte in size, so we can just fire it off as is. |
3045 | */ | 3045 | */ |
3046 | r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts, | 3046 | r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts, |
3047 | reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag); | 3047 | reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag); |
3048 | if (r != 0) | 3048 | if (r != 0) |
3049 | return r; | 3049 | return r; |
3050 | 3050 | ||
3051 | /* | 3051 | /* |
3052 | * Now byte swap (GRRR) the necessary fields before any further | 3052 | * Now byte swap (GRRR) the necessary fields before any further |
3053 | * inspection of reply contents. | 3053 | * inspection of reply contents. |
3054 | * | 3054 | * |
3055 | * But need to do some sanity checks on MsgLength (byte) field | 3055 | * But need to do some sanity checks on MsgLength (byte) field |
3056 | * to make sure we don't zero IOC's req_sz! | 3056 | * to make sure we don't zero IOC's req_sz! |
3057 | */ | 3057 | */ |
3058 | /* Did we get a valid reply? */ | 3058 | /* Did we get a valid reply? */ |
3059 | if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) { | 3059 | if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) { |
3060 | if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { | 3060 | if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { |
3061 | /* | 3061 | /* |
3062 | * If not been here, done that, save off first WhoInit value | 3062 | * If not been here, done that, save off first WhoInit value |
3063 | */ | 3063 | */ |
3064 | if (ioc->FirstWhoInit == WHOINIT_UNKNOWN) | 3064 | if (ioc->FirstWhoInit == WHOINIT_UNKNOWN) |
3065 | ioc->FirstWhoInit = facts->WhoInit; | 3065 | ioc->FirstWhoInit = facts->WhoInit; |
3066 | } | 3066 | } |
3067 | 3067 | ||
3068 | facts->MsgVersion = le16_to_cpu(facts->MsgVersion); | 3068 | facts->MsgVersion = le16_to_cpu(facts->MsgVersion); |
3069 | facts->MsgContext = le32_to_cpu(facts->MsgContext); | 3069 | facts->MsgContext = le32_to_cpu(facts->MsgContext); |
3070 | facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions); | 3070 | facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions); |
3071 | facts->IOCStatus = le16_to_cpu(facts->IOCStatus); | 3071 | facts->IOCStatus = le16_to_cpu(facts->IOCStatus); |
3072 | facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo); | 3072 | facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo); |
3073 | status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK; | 3073 | status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK; |
3074 | /* CHECKME! IOCStatus, IOCLogInfo */ | 3074 | /* CHECKME! IOCStatus, IOCLogInfo */ |
3075 | 3075 | ||
3076 | facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth); | 3076 | facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth); |
3077 | facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize); | 3077 | facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize); |
3078 | 3078 | ||
3079 | /* | 3079 | /* |
3080 | * FC f/w version changed between 1.1 and 1.2 | 3080 | * FC f/w version changed between 1.1 and 1.2 |
3081 | * Old: u16{Major(4),Minor(4),SubMinor(8)} | 3081 | * Old: u16{Major(4),Minor(4),SubMinor(8)} |
3082 | * New: u32{Major(8),Minor(8),Unit(8),Dev(8)} | 3082 | * New: u32{Major(8),Minor(8),Unit(8),Dev(8)} |
3083 | */ | 3083 | */ |
3084 | if (facts->MsgVersion < MPI_VERSION_01_02) { | 3084 | if (facts->MsgVersion < MPI_VERSION_01_02) { |
3085 | /* | 3085 | /* |
3086 | * Handle old FC f/w style, convert to new... | 3086 | * Handle old FC f/w style, convert to new... |
3087 | */ | 3087 | */ |
3088 | u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion); | 3088 | u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion); |
3089 | facts->FWVersion.Word = | 3089 | facts->FWVersion.Word = |
3090 | ((oldv<<12) & 0xFF000000) | | 3090 | ((oldv<<12) & 0xFF000000) | |
3091 | ((oldv<<8) & 0x000FFF00); | 3091 | ((oldv<<8) & 0x000FFF00); |
3092 | } else | 3092 | } else |
3093 | facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word); | 3093 | facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word); |
3094 | 3094 | ||
3095 | facts->ProductID = le16_to_cpu(facts->ProductID); | 3095 | facts->ProductID = le16_to_cpu(facts->ProductID); |
3096 | 3096 | ||
3097 | if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK) | 3097 | if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK) |
3098 | > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) | 3098 | > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) |
3099 | ioc->ir_firmware = 1; | 3099 | ioc->ir_firmware = 1; |
3100 | 3100 | ||
3101 | facts->CurrentHostMfaHighAddr = | 3101 | facts->CurrentHostMfaHighAddr = |
3102 | le32_to_cpu(facts->CurrentHostMfaHighAddr); | 3102 | le32_to_cpu(facts->CurrentHostMfaHighAddr); |
3103 | facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits); | 3103 | facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits); |
3104 | facts->CurrentSenseBufferHighAddr = | 3104 | facts->CurrentSenseBufferHighAddr = |
3105 | le32_to_cpu(facts->CurrentSenseBufferHighAddr); | 3105 | le32_to_cpu(facts->CurrentSenseBufferHighAddr); |
3106 | facts->CurReplyFrameSize = | 3106 | facts->CurReplyFrameSize = |
3107 | le16_to_cpu(facts->CurReplyFrameSize); | 3107 | le16_to_cpu(facts->CurReplyFrameSize); |
3108 | facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities); | 3108 | facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities); |
3109 | 3109 | ||
3110 | /* | 3110 | /* |
3111 | * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx | 3111 | * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx |
3112 | * Older MPI-1.00.xx struct had 13 dwords, and enlarged | 3112 | * Older MPI-1.00.xx struct had 13 dwords, and enlarged |
3113 | * to 14 in MPI-1.01.0x. | 3113 | * to 14 in MPI-1.01.0x. |
3114 | */ | 3114 | */ |
3115 | if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 && | 3115 | if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 && |
3116 | facts->MsgVersion > MPI_VERSION_01_00) { | 3116 | facts->MsgVersion > MPI_VERSION_01_00) { |
3117 | facts->FWImageSize = le32_to_cpu(facts->FWImageSize); | 3117 | facts->FWImageSize = le32_to_cpu(facts->FWImageSize); |
3118 | } | 3118 | } |
3119 | 3119 | ||
3120 | sz = facts->FWImageSize; | 3120 | sz = facts->FWImageSize; |
3121 | if ( sz & 0x01 ) | 3121 | if ( sz & 0x01 ) |
3122 | sz += 1; | 3122 | sz += 1; |
3123 | if ( sz & 0x02 ) | 3123 | if ( sz & 0x02 ) |
3124 | sz += 2; | 3124 | sz += 2; |
3125 | facts->FWImageSize = sz; | 3125 | facts->FWImageSize = sz; |
3126 | 3126 | ||
3127 | if (!facts->RequestFrameSize) { | 3127 | if (!facts->RequestFrameSize) { |
3128 | /* Something is wrong! */ | 3128 | /* Something is wrong! */ |
3129 | printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n", | 3129 | printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n", |
3130 | ioc->name); | 3130 | ioc->name); |
3131 | return -55; | 3131 | return -55; |
3132 | } | 3132 | } |
3133 | 3133 | ||
3134 | r = sz = facts->BlockSize; | 3134 | r = sz = facts->BlockSize; |
3135 | vv = ((63 / (sz * 4)) + 1) & 0x03; | 3135 | vv = ((63 / (sz * 4)) + 1) & 0x03; |
3136 | ioc->NB_for_64_byte_frame = vv; | 3136 | ioc->NB_for_64_byte_frame = vv; |
3137 | while ( sz ) | 3137 | while ( sz ) |
3138 | { | 3138 | { |
3139 | shiftFactor++; | 3139 | shiftFactor++; |
3140 | sz = sz >> 1; | 3140 | sz = sz >> 1; |
3141 | } | 3141 | } |
3142 | ioc->NBShiftFactor = shiftFactor; | 3142 | ioc->NBShiftFactor = shiftFactor; |
3143 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 3143 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
3144 | "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n", | 3144 | "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n", |
3145 | ioc->name, vv, shiftFactor, r)); | 3145 | ioc->name, vv, shiftFactor, r)); |
3146 | 3146 | ||
3147 | if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { | 3147 | if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { |
3148 | /* | 3148 | /* |
3149 | * Set values for this IOC's request & reply frame sizes, | 3149 | * Set values for this IOC's request & reply frame sizes, |
3150 | * and request & reply queue depths... | 3150 | * and request & reply queue depths... |
3151 | */ | 3151 | */ |
3152 | ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4); | 3152 | ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4); |
3153 | ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits); | 3153 | ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits); |
3154 | ioc->reply_sz = MPT_REPLY_FRAME_SIZE; | 3154 | ioc->reply_sz = MPT_REPLY_FRAME_SIZE; |
3155 | ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth); | 3155 | ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth); |
3156 | 3156 | ||
3157 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n", | 3157 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n", |
3158 | ioc->name, ioc->reply_sz, ioc->reply_depth)); | 3158 | ioc->name, ioc->reply_sz, ioc->reply_depth)); |
3159 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n", | 3159 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n", |
3160 | ioc->name, ioc->req_sz, ioc->req_depth)); | 3160 | ioc->name, ioc->req_sz, ioc->req_depth)); |
3161 | 3161 | ||
3162 | /* Get port facts! */ | 3162 | /* Get port facts! */ |
3163 | if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 ) | 3163 | if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 ) |
3164 | return r; | 3164 | return r; |
3165 | } | 3165 | } |
3166 | } else { | 3166 | } else { |
3167 | printk(MYIOC_s_ERR_FMT | 3167 | printk(MYIOC_s_ERR_FMT |
3168 | "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n", | 3168 | "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n", |
3169 | ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t, | 3169 | ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t, |
3170 | RequestFrameSize)/sizeof(u32))); | 3170 | RequestFrameSize)/sizeof(u32))); |
3171 | return -66; | 3171 | return -66; |
3172 | } | 3172 | } |
3173 | 3173 | ||
3174 | return 0; | 3174 | return 0; |
3175 | } | 3175 | } |
3176 | 3176 | ||
3177 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 3177 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
3178 | /** | 3178 | /** |
3179 | * GetPortFacts - Send PortFacts request to MPT adapter. | 3179 | * GetPortFacts - Send PortFacts request to MPT adapter. |
3180 | * @ioc: Pointer to MPT_ADAPTER structure | 3180 | * @ioc: Pointer to MPT_ADAPTER structure |
3181 | * @portnum: Port number | 3181 | * @portnum: Port number |
3182 | * @sleepFlag: Specifies whether the process can sleep | 3182 | * @sleepFlag: Specifies whether the process can sleep |
3183 | * | 3183 | * |
3184 | * Returns 0 for success, non-zero for failure. | 3184 | * Returns 0 for success, non-zero for failure. |
3185 | */ | 3185 | */ |
3186 | static int | 3186 | static int |
3187 | GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag) | 3187 | GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag) |
3188 | { | 3188 | { |
3189 | PortFacts_t get_pfacts; | 3189 | PortFacts_t get_pfacts; |
3190 | PortFactsReply_t *pfacts; | 3190 | PortFactsReply_t *pfacts; |
3191 | int ii; | 3191 | int ii; |
3192 | int req_sz; | 3192 | int req_sz; |
3193 | int reply_sz; | 3193 | int reply_sz; |
3194 | int max_id; | 3194 | int max_id; |
3195 | 3195 | ||
3196 | /* IOC *must* NOT be in RESET state! */ | 3196 | /* IOC *must* NOT be in RESET state! */ |
3197 | if (ioc->last_state == MPI_IOC_STATE_RESET) { | 3197 | if (ioc->last_state == MPI_IOC_STATE_RESET) { |
3198 | printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n", | 3198 | printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n", |
3199 | ioc->name, ioc->last_state ); | 3199 | ioc->name, ioc->last_state ); |
3200 | return -4; | 3200 | return -4; |
3201 | } | 3201 | } |
3202 | 3202 | ||
3203 | pfacts = &ioc->pfacts[portnum]; | 3203 | pfacts = &ioc->pfacts[portnum]; |
3204 | 3204 | ||
3205 | /* Destination (reply area)... */ | 3205 | /* Destination (reply area)... */ |
3206 | reply_sz = sizeof(*pfacts); | 3206 | reply_sz = sizeof(*pfacts); |
3207 | memset(pfacts, 0, reply_sz); | 3207 | memset(pfacts, 0, reply_sz); |
3208 | 3208 | ||
3209 | /* Request area (get_pfacts on the stack right now!) */ | 3209 | /* Request area (get_pfacts on the stack right now!) */ |
3210 | req_sz = sizeof(get_pfacts); | 3210 | req_sz = sizeof(get_pfacts); |
3211 | memset(&get_pfacts, 0, req_sz); | 3211 | memset(&get_pfacts, 0, req_sz); |
3212 | 3212 | ||
3213 | get_pfacts.Function = MPI_FUNCTION_PORT_FACTS; | 3213 | get_pfacts.Function = MPI_FUNCTION_PORT_FACTS; |
3214 | get_pfacts.PortNumber = portnum; | 3214 | get_pfacts.PortNumber = portnum; |
3215 | /* Assert: All other get_pfacts fields are zero! */ | 3215 | /* Assert: All other get_pfacts fields are zero! */ |
3216 | 3216 | ||
3217 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n", | 3217 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n", |
3218 | ioc->name, portnum)); | 3218 | ioc->name, portnum)); |
3219 | 3219 | ||
3220 | /* No non-zero fields in the get_pfacts request are greater than | 3220 | /* No non-zero fields in the get_pfacts request are greater than |
3221 | * 1 byte in size, so we can just fire it off as is. | 3221 | * 1 byte in size, so we can just fire it off as is. |
3222 | */ | 3222 | */ |
3223 | ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts, | 3223 | ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts, |
3224 | reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag); | 3224 | reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag); |
3225 | if (ii != 0) | 3225 | if (ii != 0) |
3226 | return ii; | 3226 | return ii; |
3227 | 3227 | ||
3228 | /* Did we get a valid reply? */ | 3228 | /* Did we get a valid reply? */ |
3229 | 3229 | ||
3230 | /* Now byte swap the necessary fields in the response. */ | 3230 | /* Now byte swap the necessary fields in the response. */ |
3231 | pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext); | 3231 | pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext); |
3232 | pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus); | 3232 | pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus); |
3233 | pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo); | 3233 | pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo); |
3234 | pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices); | 3234 | pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices); |
3235 | pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID); | 3235 | pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID); |
3236 | pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags); | 3236 | pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags); |
3237 | pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers); | 3237 | pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers); |
3238 | pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs); | 3238 | pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs); |
3239 | pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets); | 3239 | pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets); |
3240 | 3240 | ||
3241 | max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID : | 3241 | max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID : |
3242 | pfacts->MaxDevices; | 3242 | pfacts->MaxDevices; |
3243 | ioc->devices_per_bus = (max_id > 255) ? 256 : max_id; | 3243 | ioc->devices_per_bus = (max_id > 255) ? 256 : max_id; |
3244 | ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256; | 3244 | ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256; |
3245 | 3245 | ||
3246 | /* | 3246 | /* |
3247 | * Place all the devices on channels | 3247 | * Place all the devices on channels |
3248 | * | 3248 | * |
3249 | * (for debuging) | 3249 | * (for debuging) |
3250 | */ | 3250 | */ |
3251 | if (mpt_channel_mapping) { | 3251 | if (mpt_channel_mapping) { |
3252 | ioc->devices_per_bus = 1; | 3252 | ioc->devices_per_bus = 1; |
3253 | ioc->number_of_buses = (max_id > 255) ? 255 : max_id; | 3253 | ioc->number_of_buses = (max_id > 255) ? 255 : max_id; |
3254 | } | 3254 | } |
3255 | 3255 | ||
3256 | return 0; | 3256 | return 0; |
3257 | } | 3257 | } |
3258 | 3258 | ||
3259 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 3259 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
3260 | /** | 3260 | /** |
3261 | * SendIocInit - Send IOCInit request to MPT adapter. | 3261 | * SendIocInit - Send IOCInit request to MPT adapter. |
3262 | * @ioc: Pointer to MPT_ADAPTER structure | 3262 | * @ioc: Pointer to MPT_ADAPTER structure |
3263 | * @sleepFlag: Specifies whether the process can sleep | 3263 | * @sleepFlag: Specifies whether the process can sleep |
3264 | * | 3264 | * |
3265 | * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state. | 3265 | * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state. |
3266 | * | 3266 | * |
3267 | * Returns 0 for success, non-zero for failure. | 3267 | * Returns 0 for success, non-zero for failure. |
3268 | */ | 3268 | */ |
3269 | static int | 3269 | static int |
3270 | SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) | 3270 | SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) |
3271 | { | 3271 | { |
3272 | IOCInit_t ioc_init; | 3272 | IOCInit_t ioc_init; |
3273 | MPIDefaultReply_t init_reply; | 3273 | MPIDefaultReply_t init_reply; |
3274 | u32 state; | 3274 | u32 state; |
3275 | int r; | 3275 | int r; |
3276 | int count; | 3276 | int count; |
3277 | int cntdn; | 3277 | int cntdn; |
3278 | 3278 | ||
3279 | memset(&ioc_init, 0, sizeof(ioc_init)); | 3279 | memset(&ioc_init, 0, sizeof(ioc_init)); |
3280 | memset(&init_reply, 0, sizeof(init_reply)); | 3280 | memset(&init_reply, 0, sizeof(init_reply)); |
3281 | 3281 | ||
3282 | ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER; | 3282 | ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER; |
3283 | ioc_init.Function = MPI_FUNCTION_IOC_INIT; | 3283 | ioc_init.Function = MPI_FUNCTION_IOC_INIT; |
3284 | 3284 | ||
3285 | /* If we are in a recovery mode and we uploaded the FW image, | 3285 | /* If we are in a recovery mode and we uploaded the FW image, |
3286 | * then this pointer is not NULL. Skip the upload a second time. | 3286 | * then this pointer is not NULL. Skip the upload a second time. |
3287 | * Set this flag if cached_fw set for either IOC. | 3287 | * Set this flag if cached_fw set for either IOC. |
3288 | */ | 3288 | */ |
3289 | if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) | 3289 | if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) |
3290 | ioc->upload_fw = 1; | 3290 | ioc->upload_fw = 1; |
3291 | else | 3291 | else |
3292 | ioc->upload_fw = 0; | 3292 | ioc->upload_fw = 0; |
3293 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n", | 3293 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n", |
3294 | ioc->name, ioc->upload_fw, ioc->facts.Flags)); | 3294 | ioc->name, ioc->upload_fw, ioc->facts.Flags)); |
3295 | 3295 | ||
3296 | ioc_init.MaxDevices = (U8)ioc->devices_per_bus; | 3296 | ioc_init.MaxDevices = (U8)ioc->devices_per_bus; |
3297 | ioc_init.MaxBuses = (U8)ioc->number_of_buses; | 3297 | ioc_init.MaxBuses = (U8)ioc->number_of_buses; |
3298 | 3298 | ||
3299 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n", | 3299 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n", |
3300 | ioc->name, ioc->facts.MsgVersion)); | 3300 | ioc->name, ioc->facts.MsgVersion)); |
3301 | if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) { | 3301 | if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) { |
3302 | // set MsgVersion and HeaderVersion host driver was built with | 3302 | // set MsgVersion and HeaderVersion host driver was built with |
3303 | ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION); | 3303 | ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION); |
3304 | ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION); | 3304 | ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION); |
3305 | 3305 | ||
3306 | if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) { | 3306 | if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) { |
3307 | ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE; | 3307 | ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE; |
3308 | } else if(mpt_host_page_alloc(ioc, &ioc_init)) | 3308 | } else if(mpt_host_page_alloc(ioc, &ioc_init)) |
3309 | return -99; | 3309 | return -99; |
3310 | } | 3310 | } |
3311 | ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ | 3311 | ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ |
3312 | 3312 | ||
3313 | if (ioc->sg_addr_size == sizeof(u64)) { | 3313 | if (ioc->sg_addr_size == sizeof(u64)) { |
3314 | /* Save the upper 32-bits of the request | 3314 | /* Save the upper 32-bits of the request |
3315 | * (reply) and sense buffers. | 3315 | * (reply) and sense buffers. |
3316 | */ | 3316 | */ |
3317 | ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32)); | 3317 | ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32)); |
3318 | ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32)); | 3318 | ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32)); |
3319 | } else { | 3319 | } else { |
3320 | /* Force 32-bit addressing */ | 3320 | /* Force 32-bit addressing */ |
3321 | ioc_init.HostMfaHighAddr = cpu_to_le32(0); | 3321 | ioc_init.HostMfaHighAddr = cpu_to_le32(0); |
3322 | ioc_init.SenseBufferHighAddr = cpu_to_le32(0); | 3322 | ioc_init.SenseBufferHighAddr = cpu_to_le32(0); |
3323 | } | 3323 | } |
3324 | 3324 | ||
3325 | ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr; | 3325 | ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr; |
3326 | ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr; | 3326 | ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr; |
3327 | ioc->facts.MaxDevices = ioc_init.MaxDevices; | 3327 | ioc->facts.MaxDevices = ioc_init.MaxDevices; |
3328 | ioc->facts.MaxBuses = ioc_init.MaxBuses; | 3328 | ioc->facts.MaxBuses = ioc_init.MaxBuses; |
3329 | 3329 | ||
3330 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n", | 3330 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n", |
3331 | ioc->name, &ioc_init)); | 3331 | ioc->name, &ioc_init)); |
3332 | 3332 | ||
3333 | r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init, | 3333 | r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init, |
3334 | sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag); | 3334 | sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag); |
3335 | if (r != 0) { | 3335 | if (r != 0) { |
3336 | printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r); | 3336 | printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r); |
3337 | return r; | 3337 | return r; |
3338 | } | 3338 | } |
3339 | 3339 | ||
3340 | /* No need to byte swap the multibyte fields in the reply | 3340 | /* No need to byte swap the multibyte fields in the reply |
3341 | * since we don't even look at its contents. | 3341 | * since we don't even look at its contents. |
3342 | */ | 3342 | */ |
3343 | 3343 | ||
3344 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n", | 3344 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n", |
3345 | ioc->name, &ioc_init)); | 3345 | ioc->name, &ioc_init)); |
3346 | 3346 | ||
3347 | if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) { | 3347 | if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) { |
3348 | printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r); | 3348 | printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r); |
3349 | return r; | 3349 | return r; |
3350 | } | 3350 | } |
3351 | 3351 | ||
3352 | /* YIKES! SUPER IMPORTANT!!! | 3352 | /* YIKES! SUPER IMPORTANT!!! |
3353 | * Poll IocState until _OPERATIONAL while IOC is doing | 3353 | * Poll IocState until _OPERATIONAL while IOC is doing |
3354 | * LoopInit and TargetDiscovery! | 3354 | * LoopInit and TargetDiscovery! |
3355 | */ | 3355 | */ |
3356 | count = 0; | 3356 | count = 0; |
3357 | cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */ | 3357 | cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */ |
3358 | state = mpt_GetIocState(ioc, 1); | 3358 | state = mpt_GetIocState(ioc, 1); |
3359 | while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) { | 3359 | while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) { |
3360 | if (sleepFlag == CAN_SLEEP) { | 3360 | if (sleepFlag == CAN_SLEEP) { |
3361 | msleep(1); | 3361 | msleep(1); |
3362 | } else { | 3362 | } else { |
3363 | mdelay(1); | 3363 | mdelay(1); |
3364 | } | 3364 | } |
3365 | 3365 | ||
3366 | if (!cntdn) { | 3366 | if (!cntdn) { |
3367 | printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n", | 3367 | printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n", |
3368 | ioc->name, (int)((count+5)/HZ)); | 3368 | ioc->name, (int)((count+5)/HZ)); |
3369 | return -9; | 3369 | return -9; |
3370 | } | 3370 | } |
3371 | 3371 | ||
3372 | state = mpt_GetIocState(ioc, 1); | 3372 | state = mpt_GetIocState(ioc, 1); |
3373 | count++; | 3373 | count++; |
3374 | } | 3374 | } |
3375 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n", | 3375 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n", |
3376 | ioc->name, count)); | 3376 | ioc->name, count)); |
3377 | 3377 | ||
3378 | ioc->aen_event_read_flag=0; | 3378 | ioc->aen_event_read_flag=0; |
3379 | return r; | 3379 | return r; |
3380 | } | 3380 | } |
3381 | 3381 | ||
3382 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 3382 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
3383 | /** | 3383 | /** |
3384 | * SendPortEnable - Send PortEnable request to MPT adapter port. | 3384 | * SendPortEnable - Send PortEnable request to MPT adapter port. |
3385 | * @ioc: Pointer to MPT_ADAPTER structure | 3385 | * @ioc: Pointer to MPT_ADAPTER structure |
3386 | * @portnum: Port number to enable | 3386 | * @portnum: Port number to enable |
3387 | * @sleepFlag: Specifies whether the process can sleep | 3387 | * @sleepFlag: Specifies whether the process can sleep |
3388 | * | 3388 | * |
3389 | * Send PortEnable to bring IOC to OPERATIONAL state. | 3389 | * Send PortEnable to bring IOC to OPERATIONAL state. |
3390 | * | 3390 | * |
3391 | * Returns 0 for success, non-zero for failure. | 3391 | * Returns 0 for success, non-zero for failure. |
3392 | */ | 3392 | */ |
3393 | static int | 3393 | static int |
3394 | SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) | 3394 | SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) |
3395 | { | 3395 | { |
3396 | PortEnable_t port_enable; | 3396 | PortEnable_t port_enable; |
3397 | MPIDefaultReply_t reply_buf; | 3397 | MPIDefaultReply_t reply_buf; |
3398 | int rc; | 3398 | int rc; |
3399 | int req_sz; | 3399 | int req_sz; |
3400 | int reply_sz; | 3400 | int reply_sz; |
3401 | 3401 | ||
3402 | /* Destination... */ | 3402 | /* Destination... */ |
3403 | reply_sz = sizeof(MPIDefaultReply_t); | 3403 | reply_sz = sizeof(MPIDefaultReply_t); |
3404 | memset(&reply_buf, 0, reply_sz); | 3404 | memset(&reply_buf, 0, reply_sz); |
3405 | 3405 | ||
3406 | req_sz = sizeof(PortEnable_t); | 3406 | req_sz = sizeof(PortEnable_t); |
3407 | memset(&port_enable, 0, req_sz); | 3407 | memset(&port_enable, 0, req_sz); |
3408 | 3408 | ||
3409 | port_enable.Function = MPI_FUNCTION_PORT_ENABLE; | 3409 | port_enable.Function = MPI_FUNCTION_PORT_ENABLE; |
3410 | port_enable.PortNumber = portnum; | 3410 | port_enable.PortNumber = portnum; |
3411 | /* port_enable.ChainOffset = 0; */ | 3411 | /* port_enable.ChainOffset = 0; */ |
3412 | /* port_enable.MsgFlags = 0; */ | 3412 | /* port_enable.MsgFlags = 0; */ |
3413 | /* port_enable.MsgContext = 0; */ | 3413 | /* port_enable.MsgContext = 0; */ |
3414 | 3414 | ||
3415 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n", | 3415 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n", |
3416 | ioc->name, portnum, &port_enable)); | 3416 | ioc->name, portnum, &port_enable)); |
3417 | 3417 | ||
3418 | /* RAID FW may take a long time to enable | 3418 | /* RAID FW may take a long time to enable |
3419 | */ | 3419 | */ |
3420 | if (ioc->ir_firmware || ioc->bus_type == SAS) { | 3420 | if (ioc->ir_firmware || ioc->bus_type == SAS) { |
3421 | rc = mpt_handshake_req_reply_wait(ioc, req_sz, | 3421 | rc = mpt_handshake_req_reply_wait(ioc, req_sz, |
3422 | (u32*)&port_enable, reply_sz, (u16*)&reply_buf, | 3422 | (u32*)&port_enable, reply_sz, (u16*)&reply_buf, |
3423 | 300 /*seconds*/, sleepFlag); | 3423 | 300 /*seconds*/, sleepFlag); |
3424 | } else { | 3424 | } else { |
3425 | rc = mpt_handshake_req_reply_wait(ioc, req_sz, | 3425 | rc = mpt_handshake_req_reply_wait(ioc, req_sz, |
3426 | (u32*)&port_enable, reply_sz, (u16*)&reply_buf, | 3426 | (u32*)&port_enable, reply_sz, (u16*)&reply_buf, |
3427 | 30 /*seconds*/, sleepFlag); | 3427 | 30 /*seconds*/, sleepFlag); |
3428 | } | 3428 | } |
3429 | return rc; | 3429 | return rc; |
3430 | } | 3430 | } |
3431 | 3431 | ||
3432 | /** | 3432 | /** |
3433 | * mpt_alloc_fw_memory - allocate firmware memory | 3433 | * mpt_alloc_fw_memory - allocate firmware memory |
3434 | * @ioc: Pointer to MPT_ADAPTER structure | 3434 | * @ioc: Pointer to MPT_ADAPTER structure |
3435 | * @size: total FW bytes | 3435 | * @size: total FW bytes |
3436 | * | 3436 | * |
3437 | * If memory has already been allocated, the same (cached) value | 3437 | * If memory has already been allocated, the same (cached) value |
3438 | * is returned. | 3438 | * is returned. |
3439 | * | 3439 | * |
3440 | * Return 0 if successfull, or non-zero for failure | 3440 | * Return 0 if successfull, or non-zero for failure |
3441 | **/ | 3441 | **/ |
3442 | int | 3442 | int |
3443 | mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size) | 3443 | mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size) |
3444 | { | 3444 | { |
3445 | int rc; | 3445 | int rc; |
3446 | 3446 | ||
3447 | if (ioc->cached_fw) { | 3447 | if (ioc->cached_fw) { |
3448 | rc = 0; /* use already allocated memory */ | 3448 | rc = 0; /* use already allocated memory */ |
3449 | goto out; | 3449 | goto out; |
3450 | } | 3450 | } |
3451 | else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { | 3451 | else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { |
3452 | ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */ | 3452 | ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */ |
3453 | ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma; | 3453 | ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma; |
3454 | rc = 0; | 3454 | rc = 0; |
3455 | goto out; | 3455 | goto out; |
3456 | } | 3456 | } |
3457 | ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma); | 3457 | ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma); |
3458 | if (!ioc->cached_fw) { | 3458 | if (!ioc->cached_fw) { |
3459 | printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n", | 3459 | printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n", |
3460 | ioc->name); | 3460 | ioc->name); |
3461 | rc = -1; | 3461 | rc = -1; |
3462 | } else { | 3462 | } else { |
3463 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n", | 3463 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n", |
3464 | ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size)); | 3464 | ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size)); |
3465 | ioc->alloc_total += size; | 3465 | ioc->alloc_total += size; |
3466 | rc = 0; | 3466 | rc = 0; |
3467 | } | 3467 | } |
3468 | out: | 3468 | out: |
3469 | return rc; | 3469 | return rc; |
3470 | } | 3470 | } |
3471 | 3471 | ||
3472 | /** | 3472 | /** |
3473 | * mpt_free_fw_memory - free firmware memory | 3473 | * mpt_free_fw_memory - free firmware memory |
3474 | * @ioc: Pointer to MPT_ADAPTER structure | 3474 | * @ioc: Pointer to MPT_ADAPTER structure |
3475 | * | 3475 | * |
3476 | * If alt_img is NULL, delete from ioc structure. | 3476 | * If alt_img is NULL, delete from ioc structure. |
3477 | * Else, delete a secondary image in same format. | 3477 | * Else, delete a secondary image in same format. |
3478 | **/ | 3478 | **/ |
3479 | void | 3479 | void |
3480 | mpt_free_fw_memory(MPT_ADAPTER *ioc) | 3480 | mpt_free_fw_memory(MPT_ADAPTER *ioc) |
3481 | { | 3481 | { |
3482 | int sz; | 3482 | int sz; |
3483 | 3483 | ||
3484 | if (!ioc->cached_fw) | 3484 | if (!ioc->cached_fw) |
3485 | return; | 3485 | return; |
3486 | 3486 | ||
3487 | sz = ioc->facts.FWImageSize; | 3487 | sz = ioc->facts.FWImageSize; |
3488 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n", | 3488 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n", |
3489 | ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); | 3489 | ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); |
3490 | pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma); | 3490 | pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma); |
3491 | ioc->alloc_total -= sz; | 3491 | ioc->alloc_total -= sz; |
3492 | ioc->cached_fw = NULL; | 3492 | ioc->cached_fw = NULL; |
3493 | } | 3493 | } |
3494 | 3494 | ||
3495 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 3495 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
3496 | /** | 3496 | /** |
3497 | * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port. | 3497 | * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port. |
3498 | * @ioc: Pointer to MPT_ADAPTER structure | 3498 | * @ioc: Pointer to MPT_ADAPTER structure |
3499 | * @sleepFlag: Specifies whether the process can sleep | 3499 | * @sleepFlag: Specifies whether the process can sleep |
3500 | * | 3500 | * |
3501 | * Returns 0 for success, >0 for handshake failure | 3501 | * Returns 0 for success, >0 for handshake failure |
3502 | * <0 for fw upload failure. | 3502 | * <0 for fw upload failure. |
3503 | * | 3503 | * |
3504 | * Remark: If bound IOC and a successful FWUpload was performed | 3504 | * Remark: If bound IOC and a successful FWUpload was performed |
3505 | * on the bound IOC, the second image is discarded | 3505 | * on the bound IOC, the second image is discarded |
3506 | * and memory is free'd. Both channels must upload to prevent | 3506 | * and memory is free'd. Both channels must upload to prevent |
3507 | * IOC from running in degraded mode. | 3507 | * IOC from running in degraded mode. |
3508 | */ | 3508 | */ |
3509 | static int | 3509 | static int |
3510 | mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) | 3510 | mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) |
3511 | { | 3511 | { |
3512 | u8 reply[sizeof(FWUploadReply_t)]; | 3512 | u8 reply[sizeof(FWUploadReply_t)]; |
3513 | FWUpload_t *prequest; | 3513 | FWUpload_t *prequest; |
3514 | FWUploadReply_t *preply; | 3514 | FWUploadReply_t *preply; |
3515 | FWUploadTCSGE_t *ptcsge; | 3515 | FWUploadTCSGE_t *ptcsge; |
3516 | u32 flagsLength; | 3516 | u32 flagsLength; |
3517 | int ii, sz, reply_sz; | 3517 | int ii, sz, reply_sz; |
3518 | int cmdStatus; | 3518 | int cmdStatus; |
3519 | int request_size; | 3519 | int request_size; |
3520 | /* If the image size is 0, we are done. | 3520 | /* If the image size is 0, we are done. |
3521 | */ | 3521 | */ |
3522 | if ((sz = ioc->facts.FWImageSize) == 0) | 3522 | if ((sz = ioc->facts.FWImageSize) == 0) |
3523 | return 0; | 3523 | return 0; |
3524 | 3524 | ||
3525 | if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0) | 3525 | if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0) |
3526 | return -ENOMEM; | 3526 | return -ENOMEM; |
3527 | 3527 | ||
3528 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n", | 3528 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n", |
3529 | ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); | 3529 | ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); |
3530 | 3530 | ||
3531 | prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) : | 3531 | prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) : |
3532 | kzalloc(ioc->req_sz, GFP_KERNEL); | 3532 | kzalloc(ioc->req_sz, GFP_KERNEL); |
3533 | if (!prequest) { | 3533 | if (!prequest) { |
3534 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed " | 3534 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed " |
3535 | "while allocating memory \n", ioc->name)); | 3535 | "while allocating memory \n", ioc->name)); |
3536 | mpt_free_fw_memory(ioc); | 3536 | mpt_free_fw_memory(ioc); |
3537 | return -ENOMEM; | 3537 | return -ENOMEM; |
3538 | } | 3538 | } |
3539 | 3539 | ||
3540 | preply = (FWUploadReply_t *)&reply; | 3540 | preply = (FWUploadReply_t *)&reply; |
3541 | 3541 | ||
3542 | reply_sz = sizeof(reply); | 3542 | reply_sz = sizeof(reply); |
3543 | memset(preply, 0, reply_sz); | 3543 | memset(preply, 0, reply_sz); |
3544 | 3544 | ||
3545 | prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM; | 3545 | prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM; |
3546 | prequest->Function = MPI_FUNCTION_FW_UPLOAD; | 3546 | prequest->Function = MPI_FUNCTION_FW_UPLOAD; |
3547 | 3547 | ||
3548 | ptcsge = (FWUploadTCSGE_t *) &prequest->SGL; | 3548 | ptcsge = (FWUploadTCSGE_t *) &prequest->SGL; |
3549 | ptcsge->DetailsLength = 12; | 3549 | ptcsge->DetailsLength = 12; |
3550 | ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT; | 3550 | ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT; |
3551 | ptcsge->ImageSize = cpu_to_le32(sz); | 3551 | ptcsge->ImageSize = cpu_to_le32(sz); |
3552 | ptcsge++; | 3552 | ptcsge++; |
3553 | 3553 | ||
3554 | flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz; | 3554 | flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz; |
3555 | ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma); | 3555 | ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma); |
3556 | request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) + | 3556 | request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) + |
3557 | ioc->SGE_size; | 3557 | ioc->SGE_size; |
3558 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload " | 3558 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload " |
3559 | " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest, | 3559 | " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest, |
3560 | ioc->facts.FWImageSize, request_size)); | 3560 | ioc->facts.FWImageSize, request_size)); |
3561 | DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest); | 3561 | DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest); |
3562 | 3562 | ||
3563 | ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest, | 3563 | ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest, |
3564 | reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag); | 3564 | reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag); |
3565 | 3565 | ||
3566 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed " | 3566 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed " |
3567 | "rc=%x \n", ioc->name, ii)); | 3567 | "rc=%x \n", ioc->name, ii)); |
3568 | 3568 | ||
3569 | cmdStatus = -EFAULT; | 3569 | cmdStatus = -EFAULT; |
3570 | if (ii == 0) { | 3570 | if (ii == 0) { |
3571 | /* Handshake transfer was complete and successful. | 3571 | /* Handshake transfer was complete and successful. |
3572 | * Check the Reply Frame. | 3572 | * Check the Reply Frame. |
3573 | */ | 3573 | */ |
3574 | int status; | 3574 | int status; |
3575 | status = le16_to_cpu(preply->IOCStatus) & | 3575 | status = le16_to_cpu(preply->IOCStatus) & |
3576 | MPI_IOCSTATUS_MASK; | 3576 | MPI_IOCSTATUS_MASK; |
3577 | if (status == MPI_IOCSTATUS_SUCCESS && | 3577 | if (status == MPI_IOCSTATUS_SUCCESS && |
3578 | ioc->facts.FWImageSize == | 3578 | ioc->facts.FWImageSize == |
3579 | le32_to_cpu(preply->ActualImageSize)) | 3579 | le32_to_cpu(preply->ActualImageSize)) |
3580 | cmdStatus = 0; | 3580 | cmdStatus = 0; |
3581 | } | 3581 | } |
3582 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n", | 3582 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n", |
3583 | ioc->name, cmdStatus)); | 3583 | ioc->name, cmdStatus)); |
3584 | 3584 | ||
3585 | 3585 | ||
3586 | if (cmdStatus) { | 3586 | if (cmdStatus) { |
3587 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, " | 3587 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, " |
3588 | "freeing image \n", ioc->name)); | 3588 | "freeing image \n", ioc->name)); |
3589 | mpt_free_fw_memory(ioc); | 3589 | mpt_free_fw_memory(ioc); |
3590 | } | 3590 | } |
3591 | kfree(prequest); | 3591 | kfree(prequest); |
3592 | 3592 | ||
3593 | return cmdStatus; | 3593 | return cmdStatus; |
3594 | } | 3594 | } |
3595 | 3595 | ||
3596 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 3596 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
3597 | /** | 3597 | /** |
3598 | * mpt_downloadboot - DownloadBoot code | 3598 | * mpt_downloadboot - DownloadBoot code |
3599 | * @ioc: Pointer to MPT_ADAPTER structure | 3599 | * @ioc: Pointer to MPT_ADAPTER structure |
3600 | * @pFwHeader: Pointer to firmware header info | 3600 | * @pFwHeader: Pointer to firmware header info |
3601 | * @sleepFlag: Specifies whether the process can sleep | 3601 | * @sleepFlag: Specifies whether the process can sleep |
3602 | * | 3602 | * |
3603 | * FwDownloadBoot requires Programmed IO access. | 3603 | * FwDownloadBoot requires Programmed IO access. |
3604 | * | 3604 | * |
3605 | * Returns 0 for success | 3605 | * Returns 0 for success |
3606 | * -1 FW Image size is 0 | 3606 | * -1 FW Image size is 0 |
3607 | * -2 No valid cached_fw Pointer | 3607 | * -2 No valid cached_fw Pointer |
3608 | * <0 for fw upload failure. | 3608 | * <0 for fw upload failure. |
3609 | */ | 3609 | */ |
3610 | static int | 3610 | static int |
3611 | mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag) | 3611 | mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag) |
3612 | { | 3612 | { |
3613 | MpiExtImageHeader_t *pExtImage; | 3613 | MpiExtImageHeader_t *pExtImage; |
3614 | u32 fwSize; | 3614 | u32 fwSize; |
3615 | u32 diag0val; | 3615 | u32 diag0val; |
3616 | int count; | 3616 | int count; |
3617 | u32 *ptrFw; | 3617 | u32 *ptrFw; |
3618 | u32 diagRwData; | 3618 | u32 diagRwData; |
3619 | u32 nextImage; | 3619 | u32 nextImage; |
3620 | u32 load_addr; | 3620 | u32 load_addr; |
3621 | u32 ioc_state=0; | 3621 | u32 ioc_state=0; |
3622 | 3622 | ||
3623 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n", | 3623 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n", |
3624 | ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader)); | 3624 | ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader)); |
3625 | 3625 | ||
3626 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); | 3626 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); |
3627 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); | 3627 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); |
3628 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); | 3628 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); |
3629 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); | 3629 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); |
3630 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); | 3630 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); |
3631 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); | 3631 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); |
3632 | 3632 | ||
3633 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM)); | 3633 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM)); |
3634 | 3634 | ||
3635 | /* wait 1 msec */ | 3635 | /* wait 1 msec */ |
3636 | if (sleepFlag == CAN_SLEEP) { | 3636 | if (sleepFlag == CAN_SLEEP) { |
3637 | msleep(1); | 3637 | msleep(1); |
3638 | } else { | 3638 | } else { |
3639 | mdelay (1); | 3639 | mdelay (1); |
3640 | } | 3640 | } |
3641 | 3641 | ||
3642 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); | 3642 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); |
3643 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); | 3643 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); |
3644 | 3644 | ||
3645 | for (count = 0; count < 30; count ++) { | 3645 | for (count = 0; count < 30; count ++) { |
3646 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); | 3646 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); |
3647 | if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) { | 3647 | if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) { |
3648 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n", | 3648 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n", |
3649 | ioc->name, count)); | 3649 | ioc->name, count)); |
3650 | break; | 3650 | break; |
3651 | } | 3651 | } |
3652 | /* wait .1 sec */ | 3652 | /* wait .1 sec */ |
3653 | if (sleepFlag == CAN_SLEEP) { | 3653 | if (sleepFlag == CAN_SLEEP) { |
3654 | msleep (100); | 3654 | msleep (100); |
3655 | } else { | 3655 | } else { |
3656 | mdelay (100); | 3656 | mdelay (100); |
3657 | } | 3657 | } |
3658 | } | 3658 | } |
3659 | 3659 | ||
3660 | if ( count == 30 ) { | 3660 | if ( count == 30 ) { |
3661 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! " | 3661 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! " |
3662 | "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n", | 3662 | "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n", |
3663 | ioc->name, diag0val)); | 3663 | ioc->name, diag0val)); |
3664 | return -3; | 3664 | return -3; |
3665 | } | 3665 | } |
3666 | 3666 | ||
3667 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); | 3667 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); |
3668 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); | 3668 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); |
3669 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); | 3669 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); |
3670 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); | 3670 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); |
3671 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); | 3671 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); |
3672 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); | 3672 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); |
3673 | 3673 | ||
3674 | /* Set the DiagRwEn and Disable ARM bits */ | 3674 | /* Set the DiagRwEn and Disable ARM bits */ |
3675 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM)); | 3675 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM)); |
3676 | 3676 | ||
3677 | fwSize = (pFwHeader->ImageSize + 3)/4; | 3677 | fwSize = (pFwHeader->ImageSize + 3)/4; |
3678 | ptrFw = (u32 *) pFwHeader; | 3678 | ptrFw = (u32 *) pFwHeader; |
3679 | 3679 | ||
3680 | /* Write the LoadStartAddress to the DiagRw Address Register | 3680 | /* Write the LoadStartAddress to the DiagRw Address Register |
3681 | * using Programmed IO | 3681 | * using Programmed IO |
3682 | */ | 3682 | */ |
3683 | if (ioc->errata_flag_1064) | 3683 | if (ioc->errata_flag_1064) |
3684 | pci_enable_io_access(ioc->pcidev); | 3684 | pci_enable_io_access(ioc->pcidev); |
3685 | 3685 | ||
3686 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress); | 3686 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress); |
3687 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n", | 3687 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n", |
3688 | ioc->name, pFwHeader->LoadStartAddress)); | 3688 | ioc->name, pFwHeader->LoadStartAddress)); |
3689 | 3689 | ||
3690 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n", | 3690 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n", |
3691 | ioc->name, fwSize*4, ptrFw)); | 3691 | ioc->name, fwSize*4, ptrFw)); |
3692 | while (fwSize--) { | 3692 | while (fwSize--) { |
3693 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++); | 3693 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++); |
3694 | } | 3694 | } |
3695 | 3695 | ||
3696 | nextImage = pFwHeader->NextImageHeaderOffset; | 3696 | nextImage = pFwHeader->NextImageHeaderOffset; |
3697 | while (nextImage) { | 3697 | while (nextImage) { |
3698 | pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage); | 3698 | pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage); |
3699 | 3699 | ||
3700 | load_addr = pExtImage->LoadStartAddress; | 3700 | load_addr = pExtImage->LoadStartAddress; |
3701 | 3701 | ||
3702 | fwSize = (pExtImage->ImageSize + 3) >> 2; | 3702 | fwSize = (pExtImage->ImageSize + 3) >> 2; |
3703 | ptrFw = (u32 *)pExtImage; | 3703 | ptrFw = (u32 *)pExtImage; |
3704 | 3704 | ||
3705 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n", | 3705 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n", |
3706 | ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr)); | 3706 | ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr)); |
3707 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr); | 3707 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr); |
3708 | 3708 | ||
3709 | while (fwSize--) { | 3709 | while (fwSize--) { |
3710 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++); | 3710 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++); |
3711 | } | 3711 | } |
3712 | nextImage = pExtImage->NextImageHeaderOffset; | 3712 | nextImage = pExtImage->NextImageHeaderOffset; |
3713 | } | 3713 | } |
3714 | 3714 | ||
3715 | /* Write the IopResetVectorRegAddr */ | 3715 | /* Write the IopResetVectorRegAddr */ |
3716 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr)); | 3716 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr)); |
3717 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr); | 3717 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr); |
3718 | 3718 | ||
3719 | /* Write the IopResetVectorValue */ | 3719 | /* Write the IopResetVectorValue */ |
3720 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue)); | 3720 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue)); |
3721 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue); | 3721 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue); |
3722 | 3722 | ||
3723 | /* Clear the internal flash bad bit - autoincrementing register, | 3723 | /* Clear the internal flash bad bit - autoincrementing register, |
3724 | * so must do two writes. | 3724 | * so must do two writes. |
3725 | */ | 3725 | */ |
3726 | if (ioc->bus_type == SPI) { | 3726 | if (ioc->bus_type == SPI) { |
3727 | /* | 3727 | /* |
3728 | * 1030 and 1035 H/W errata, workaround to access | 3728 | * 1030 and 1035 H/W errata, workaround to access |
3729 | * the ClearFlashBadSignatureBit | 3729 | * the ClearFlashBadSignatureBit |
3730 | */ | 3730 | */ |
3731 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); | 3731 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); |
3732 | diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData); | 3732 | diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData); |
3733 | diagRwData |= 0x40000000; | 3733 | diagRwData |= 0x40000000; |
3734 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); | 3734 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); |
3735 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData); | 3735 | CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData); |
3736 | 3736 | ||
3737 | } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ { | 3737 | } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ { |
3738 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); | 3738 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); |
3739 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | | 3739 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | |
3740 | MPI_DIAG_CLEAR_FLASH_BAD_SIG); | 3740 | MPI_DIAG_CLEAR_FLASH_BAD_SIG); |
3741 | 3741 | ||
3742 | /* wait 1 msec */ | 3742 | /* wait 1 msec */ |
3743 | if (sleepFlag == CAN_SLEEP) { | 3743 | if (sleepFlag == CAN_SLEEP) { |
3744 | msleep (1); | 3744 | msleep (1); |
3745 | } else { | 3745 | } else { |
3746 | mdelay (1); | 3746 | mdelay (1); |
3747 | } | 3747 | } |
3748 | } | 3748 | } |
3749 | 3749 | ||
3750 | if (ioc->errata_flag_1064) | 3750 | if (ioc->errata_flag_1064) |
3751 | pci_disable_io_access(ioc->pcidev); | 3751 | pci_disable_io_access(ioc->pcidev); |
3752 | 3752 | ||
3753 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); | 3753 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); |
3754 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, " | 3754 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, " |
3755 | "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n", | 3755 | "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n", |
3756 | ioc->name, diag0val)); | 3756 | ioc->name, diag0val)); |
3757 | diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE); | 3757 | diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE); |
3758 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n", | 3758 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n", |
3759 | ioc->name, diag0val)); | 3759 | ioc->name, diag0val)); |
3760 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); | 3760 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); |
3761 | 3761 | ||
3762 | /* Write 0xFF to reset the sequencer */ | 3762 | /* Write 0xFF to reset the sequencer */ |
3763 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); | 3763 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); |
3764 | 3764 | ||
3765 | if (ioc->bus_type == SAS) { | 3765 | if (ioc->bus_type == SAS) { |
3766 | ioc_state = mpt_GetIocState(ioc, 0); | 3766 | ioc_state = mpt_GetIocState(ioc, 0); |
3767 | if ( (GetIocFacts(ioc, sleepFlag, | 3767 | if ( (GetIocFacts(ioc, sleepFlag, |
3768 | MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) { | 3768 | MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) { |
3769 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n", | 3769 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n", |
3770 | ioc->name, ioc_state)); | 3770 | ioc->name, ioc_state)); |
3771 | return -EFAULT; | 3771 | return -EFAULT; |
3772 | } | 3772 | } |
3773 | } | 3773 | } |
3774 | 3774 | ||
3775 | for (count=0; count<HZ*20; count++) { | 3775 | for (count=0; count<HZ*20; count++) { |
3776 | if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) { | 3776 | if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) { |
3777 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 3777 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
3778 | "downloadboot successful! (count=%d) IocState=%x\n", | 3778 | "downloadboot successful! (count=%d) IocState=%x\n", |
3779 | ioc->name, count, ioc_state)); | 3779 | ioc->name, count, ioc_state)); |
3780 | if (ioc->bus_type == SAS) { | 3780 | if (ioc->bus_type == SAS) { |
3781 | return 0; | 3781 | return 0; |
3782 | } | 3782 | } |
3783 | if ((SendIocInit(ioc, sleepFlag)) != 0) { | 3783 | if ((SendIocInit(ioc, sleepFlag)) != 0) { |
3784 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 3784 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
3785 | "downloadboot: SendIocInit failed\n", | 3785 | "downloadboot: SendIocInit failed\n", |
3786 | ioc->name)); | 3786 | ioc->name)); |
3787 | return -EFAULT; | 3787 | return -EFAULT; |
3788 | } | 3788 | } |
3789 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 3789 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
3790 | "downloadboot: SendIocInit successful\n", | 3790 | "downloadboot: SendIocInit successful\n", |
3791 | ioc->name)); | 3791 | ioc->name)); |
3792 | return 0; | 3792 | return 0; |
3793 | } | 3793 | } |
3794 | if (sleepFlag == CAN_SLEEP) { | 3794 | if (sleepFlag == CAN_SLEEP) { |
3795 | msleep (10); | 3795 | msleep (10); |
3796 | } else { | 3796 | } else { |
3797 | mdelay (10); | 3797 | mdelay (10); |
3798 | } | 3798 | } |
3799 | } | 3799 | } |
3800 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 3800 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
3801 | "downloadboot failed! IocState=%x\n",ioc->name, ioc_state)); | 3801 | "downloadboot failed! IocState=%x\n",ioc->name, ioc_state)); |
3802 | return -EFAULT; | 3802 | return -EFAULT; |
3803 | } | 3803 | } |
3804 | 3804 | ||
3805 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 3805 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
3806 | /** | 3806 | /** |
3807 | * KickStart - Perform hard reset of MPT adapter. | 3807 | * KickStart - Perform hard reset of MPT adapter. |
3808 | * @ioc: Pointer to MPT_ADAPTER structure | 3808 | * @ioc: Pointer to MPT_ADAPTER structure |
3809 | * @force: Force hard reset | 3809 | * @force: Force hard reset |
3810 | * @sleepFlag: Specifies whether the process can sleep | 3810 | * @sleepFlag: Specifies whether the process can sleep |
3811 | * | 3811 | * |
3812 | * This routine places MPT adapter in diagnostic mode via the | 3812 | * This routine places MPT adapter in diagnostic mode via the |
3813 | * WriteSequence register, and then performs a hard reset of adapter | 3813 | * WriteSequence register, and then performs a hard reset of adapter |
3814 | * via the Diagnostic register. | 3814 | * via the Diagnostic register. |
3815 | * | 3815 | * |
3816 | * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread) | 3816 | * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread) |
3817 | * or NO_SLEEP (interrupt thread, use mdelay) | 3817 | * or NO_SLEEP (interrupt thread, use mdelay) |
3818 | * force - 1 if doorbell active, board fault state | 3818 | * force - 1 if doorbell active, board fault state |
3819 | * board operational, IOC_RECOVERY or | 3819 | * board operational, IOC_RECOVERY or |
3820 | * IOC_BRINGUP and there is an alt_ioc. | 3820 | * IOC_BRINGUP and there is an alt_ioc. |
3821 | * 0 else | 3821 | * 0 else |
3822 | * | 3822 | * |
3823 | * Returns: | 3823 | * Returns: |
3824 | * 1 - hard reset, READY | 3824 | * 1 - hard reset, READY |
3825 | * 0 - no reset due to History bit, READY | 3825 | * 0 - no reset due to History bit, READY |
3826 | * -1 - no reset due to History bit but not READY | 3826 | * -1 - no reset due to History bit but not READY |
3827 | * OR reset but failed to come READY | 3827 | * OR reset but failed to come READY |
3828 | * -2 - no reset, could not enter DIAG mode | 3828 | * -2 - no reset, could not enter DIAG mode |
3829 | * -3 - reset but bad FW bit | 3829 | * -3 - reset but bad FW bit |
3830 | */ | 3830 | */ |
3831 | static int | 3831 | static int |
3832 | KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) | 3832 | KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) |
3833 | { | 3833 | { |
3834 | int hard_reset_done = 0; | 3834 | int hard_reset_done = 0; |
3835 | u32 ioc_state=0; | 3835 | u32 ioc_state=0; |
3836 | int cnt,cntdn; | 3836 | int cnt,cntdn; |
3837 | 3837 | ||
3838 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name)); | 3838 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name)); |
3839 | if (ioc->bus_type == SPI) { | 3839 | if (ioc->bus_type == SPI) { |
3840 | /* Always issue a Msg Unit Reset first. This will clear some | 3840 | /* Always issue a Msg Unit Reset first. This will clear some |
3841 | * SCSI bus hang conditions. | 3841 | * SCSI bus hang conditions. |
3842 | */ | 3842 | */ |
3843 | SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag); | 3843 | SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag); |
3844 | 3844 | ||
3845 | if (sleepFlag == CAN_SLEEP) { | 3845 | if (sleepFlag == CAN_SLEEP) { |
3846 | msleep (1000); | 3846 | msleep (1000); |
3847 | } else { | 3847 | } else { |
3848 | mdelay (1000); | 3848 | mdelay (1000); |
3849 | } | 3849 | } |
3850 | } | 3850 | } |
3851 | 3851 | ||
3852 | hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag); | 3852 | hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag); |
3853 | if (hard_reset_done < 0) | 3853 | if (hard_reset_done < 0) |
3854 | return hard_reset_done; | 3854 | return hard_reset_done; |
3855 | 3855 | ||
3856 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n", | 3856 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n", |
3857 | ioc->name)); | 3857 | ioc->name)); |
3858 | 3858 | ||
3859 | cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */ | 3859 | cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */ |
3860 | for (cnt=0; cnt<cntdn; cnt++) { | 3860 | for (cnt=0; cnt<cntdn; cnt++) { |
3861 | ioc_state = mpt_GetIocState(ioc, 1); | 3861 | ioc_state = mpt_GetIocState(ioc, 1); |
3862 | if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) { | 3862 | if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) { |
3863 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n", | 3863 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n", |
3864 | ioc->name, cnt)); | 3864 | ioc->name, cnt)); |
3865 | return hard_reset_done; | 3865 | return hard_reset_done; |
3866 | } | 3866 | } |
3867 | if (sleepFlag == CAN_SLEEP) { | 3867 | if (sleepFlag == CAN_SLEEP) { |
3868 | msleep (10); | 3868 | msleep (10); |
3869 | } else { | 3869 | } else { |
3870 | mdelay (10); | 3870 | mdelay (10); |
3871 | } | 3871 | } |
3872 | } | 3872 | } |
3873 | 3873 | ||
3874 | dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n", | 3874 | dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n", |
3875 | ioc->name, mpt_GetIocState(ioc, 0))); | 3875 | ioc->name, mpt_GetIocState(ioc, 0))); |
3876 | return -1; | 3876 | return -1; |
3877 | } | 3877 | } |
3878 | 3878 | ||
3879 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 3879 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
3880 | /** | 3880 | /** |
3881 | * mpt_diag_reset - Perform hard reset of the adapter. | 3881 | * mpt_diag_reset - Perform hard reset of the adapter. |
3882 | * @ioc: Pointer to MPT_ADAPTER structure | 3882 | * @ioc: Pointer to MPT_ADAPTER structure |
3883 | * @ignore: Set if to honor and clear to ignore | 3883 | * @ignore: Set if to honor and clear to ignore |
3884 | * the reset history bit | 3884 | * the reset history bit |
3885 | * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread, | 3885 | * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread, |
3886 | * else set to NO_SLEEP (use mdelay instead) | 3886 | * else set to NO_SLEEP (use mdelay instead) |
3887 | * | 3887 | * |
3888 | * This routine places the adapter in diagnostic mode via the | 3888 | * This routine places the adapter in diagnostic mode via the |
3889 | * WriteSequence register and then performs a hard reset of adapter | 3889 | * WriteSequence register and then performs a hard reset of adapter |
3890 | * via the Diagnostic register. Adapter should be in ready state | 3890 | * via the Diagnostic register. Adapter should be in ready state |
3891 | * upon successful completion. | 3891 | * upon successful completion. |
3892 | * | 3892 | * |
3893 | * Returns: 1 hard reset successful | 3893 | * Returns: 1 hard reset successful |
3894 | * 0 no reset performed because reset history bit set | 3894 | * 0 no reset performed because reset history bit set |
3895 | * -2 enabling diagnostic mode failed | 3895 | * -2 enabling diagnostic mode failed |
3896 | * -3 diagnostic reset failed | 3896 | * -3 diagnostic reset failed |
3897 | */ | 3897 | */ |
3898 | static int | 3898 | static int |
3899 | mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) | 3899 | mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) |
3900 | { | 3900 | { |
3901 | u32 diag0val; | 3901 | u32 diag0val; |
3902 | u32 doorbell; | 3902 | u32 doorbell; |
3903 | int hard_reset_done = 0; | 3903 | int hard_reset_done = 0; |
3904 | int count = 0; | 3904 | int count = 0; |
3905 | u32 diag1val = 0; | 3905 | u32 diag1val = 0; |
3906 | MpiFwHeader_t *cached_fw; /* Pointer to FW */ | 3906 | MpiFwHeader_t *cached_fw; /* Pointer to FW */ |
3907 | u8 cb_idx; | 3907 | u8 cb_idx; |
3908 | 3908 | ||
3909 | /* Clear any existing interrupts */ | 3909 | /* Clear any existing interrupts */ |
3910 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); | 3910 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); |
3911 | 3911 | ||
3912 | if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { | 3912 | if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { |
3913 | 3913 | ||
3914 | if (!ignore) | 3914 | if (!ignore) |
3915 | return 0; | 3915 | return 0; |
3916 | 3916 | ||
3917 | drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset " | 3917 | drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset " |
3918 | "address=%p\n", ioc->name, __func__, | 3918 | "address=%p\n", ioc->name, __func__, |
3919 | &ioc->chip->Doorbell, &ioc->chip->Reset_1078)); | 3919 | &ioc->chip->Doorbell, &ioc->chip->Reset_1078)); |
3920 | CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07); | 3920 | CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07); |
3921 | if (sleepFlag == CAN_SLEEP) | 3921 | if (sleepFlag == CAN_SLEEP) |
3922 | msleep(1); | 3922 | msleep(1); |
3923 | else | 3923 | else |
3924 | mdelay(1); | 3924 | mdelay(1); |
3925 | 3925 | ||
3926 | /* | 3926 | /* |
3927 | * Call each currently registered protocol IOC reset handler | 3927 | * Call each currently registered protocol IOC reset handler |
3928 | * with pre-reset indication. | 3928 | * with pre-reset indication. |
3929 | * NOTE: If we're doing _IOC_BRINGUP, there can be no | 3929 | * NOTE: If we're doing _IOC_BRINGUP, there can be no |
3930 | * MptResetHandlers[] registered yet. | 3930 | * MptResetHandlers[] registered yet. |
3931 | */ | 3931 | */ |
3932 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { | 3932 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { |
3933 | if (MptResetHandlers[cb_idx]) | 3933 | if (MptResetHandlers[cb_idx]) |
3934 | (*(MptResetHandlers[cb_idx]))(ioc, | 3934 | (*(MptResetHandlers[cb_idx]))(ioc, |
3935 | MPT_IOC_PRE_RESET); | 3935 | MPT_IOC_PRE_RESET); |
3936 | } | 3936 | } |
3937 | 3937 | ||
3938 | for (count = 0; count < 60; count ++) { | 3938 | for (count = 0; count < 60; count ++) { |
3939 | doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); | 3939 | doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); |
3940 | doorbell &= MPI_IOC_STATE_MASK; | 3940 | doorbell &= MPI_IOC_STATE_MASK; |
3941 | 3941 | ||
3942 | drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 3942 | drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
3943 | "looking for READY STATE: doorbell=%x" | 3943 | "looking for READY STATE: doorbell=%x" |
3944 | " count=%d\n", | 3944 | " count=%d\n", |
3945 | ioc->name, doorbell, count)); | 3945 | ioc->name, doorbell, count)); |
3946 | 3946 | ||
3947 | if (doorbell == MPI_IOC_STATE_READY) { | 3947 | if (doorbell == MPI_IOC_STATE_READY) { |
3948 | return 1; | 3948 | return 1; |
3949 | } | 3949 | } |
3950 | 3950 | ||
3951 | /* wait 1 sec */ | 3951 | /* wait 1 sec */ |
3952 | if (sleepFlag == CAN_SLEEP) | 3952 | if (sleepFlag == CAN_SLEEP) |
3953 | msleep(1000); | 3953 | msleep(1000); |
3954 | else | 3954 | else |
3955 | mdelay(1000); | 3955 | mdelay(1000); |
3956 | } | 3956 | } |
3957 | return -1; | 3957 | return -1; |
3958 | } | 3958 | } |
3959 | 3959 | ||
3960 | /* Use "Diagnostic reset" method! (only thing available!) */ | 3960 | /* Use "Diagnostic reset" method! (only thing available!) */ |
3961 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); | 3961 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); |
3962 | 3962 | ||
3963 | if (ioc->debug_level & MPT_DEBUG) { | 3963 | if (ioc->debug_level & MPT_DEBUG) { |
3964 | if (ioc->alt_ioc) | 3964 | if (ioc->alt_ioc) |
3965 | diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); | 3965 | diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); |
3966 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n", | 3966 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n", |
3967 | ioc->name, diag0val, diag1val)); | 3967 | ioc->name, diag0val, diag1val)); |
3968 | } | 3968 | } |
3969 | 3969 | ||
3970 | /* Do the reset if we are told to ignore the reset history | 3970 | /* Do the reset if we are told to ignore the reset history |
3971 | * or if the reset history is 0 | 3971 | * or if the reset history is 0 |
3972 | */ | 3972 | */ |
3973 | if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) { | 3973 | if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) { |
3974 | while ((diag0val & MPI_DIAG_DRWE) == 0) { | 3974 | while ((diag0val & MPI_DIAG_DRWE) == 0) { |
3975 | /* Write magic sequence to WriteSequence register | 3975 | /* Write magic sequence to WriteSequence register |
3976 | * Loop until in diagnostic mode | 3976 | * Loop until in diagnostic mode |
3977 | */ | 3977 | */ |
3978 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); | 3978 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); |
3979 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); | 3979 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); |
3980 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); | 3980 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); |
3981 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); | 3981 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); |
3982 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); | 3982 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); |
3983 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); | 3983 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); |
3984 | 3984 | ||
3985 | /* wait 100 msec */ | 3985 | /* wait 100 msec */ |
3986 | if (sleepFlag == CAN_SLEEP) { | 3986 | if (sleepFlag == CAN_SLEEP) { |
3987 | msleep (100); | 3987 | msleep (100); |
3988 | } else { | 3988 | } else { |
3989 | mdelay (100); | 3989 | mdelay (100); |
3990 | } | 3990 | } |
3991 | 3991 | ||
3992 | count++; | 3992 | count++; |
3993 | if (count > 20) { | 3993 | if (count > 20) { |
3994 | printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n", | 3994 | printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n", |
3995 | ioc->name, diag0val); | 3995 | ioc->name, diag0val); |
3996 | return -2; | 3996 | return -2; |
3997 | 3997 | ||
3998 | } | 3998 | } |
3999 | 3999 | ||
4000 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); | 4000 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); |
4001 | 4001 | ||
4002 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n", | 4002 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n", |
4003 | ioc->name, diag0val)); | 4003 | ioc->name, diag0val)); |
4004 | } | 4004 | } |
4005 | 4005 | ||
4006 | if (ioc->debug_level & MPT_DEBUG) { | 4006 | if (ioc->debug_level & MPT_DEBUG) { |
4007 | if (ioc->alt_ioc) | 4007 | if (ioc->alt_ioc) |
4008 | diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); | 4008 | diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); |
4009 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n", | 4009 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n", |
4010 | ioc->name, diag0val, diag1val)); | 4010 | ioc->name, diag0val, diag1val)); |
4011 | } | 4011 | } |
4012 | /* | 4012 | /* |
4013 | * Disable the ARM (Bug fix) | 4013 | * Disable the ARM (Bug fix) |
4014 | * | 4014 | * |
4015 | */ | 4015 | */ |
4016 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM); | 4016 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM); |
4017 | mdelay(1); | 4017 | mdelay(1); |
4018 | 4018 | ||
4019 | /* | 4019 | /* |
4020 | * Now hit the reset bit in the Diagnostic register | 4020 | * Now hit the reset bit in the Diagnostic register |
4021 | * (THE BIG HAMMER!) (Clears DRWE bit). | 4021 | * (THE BIG HAMMER!) (Clears DRWE bit). |
4022 | */ | 4022 | */ |
4023 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); | 4023 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); |
4024 | hard_reset_done = 1; | 4024 | hard_reset_done = 1; |
4025 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n", | 4025 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n", |
4026 | ioc->name)); | 4026 | ioc->name)); |
4027 | 4027 | ||
4028 | /* | 4028 | /* |
4029 | * Call each currently registered protocol IOC reset handler | 4029 | * Call each currently registered protocol IOC reset handler |
4030 | * with pre-reset indication. | 4030 | * with pre-reset indication. |
4031 | * NOTE: If we're doing _IOC_BRINGUP, there can be no | 4031 | * NOTE: If we're doing _IOC_BRINGUP, there can be no |
4032 | * MptResetHandlers[] registered yet. | 4032 | * MptResetHandlers[] registered yet. |
4033 | */ | 4033 | */ |
4034 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { | 4034 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { |
4035 | if (MptResetHandlers[cb_idx]) { | 4035 | if (MptResetHandlers[cb_idx]) { |
4036 | mpt_signal_reset(cb_idx, | 4036 | mpt_signal_reset(cb_idx, |
4037 | ioc, MPT_IOC_PRE_RESET); | 4037 | ioc, MPT_IOC_PRE_RESET); |
4038 | if (ioc->alt_ioc) { | 4038 | if (ioc->alt_ioc) { |
4039 | mpt_signal_reset(cb_idx, | 4039 | mpt_signal_reset(cb_idx, |
4040 | ioc->alt_ioc, MPT_IOC_PRE_RESET); | 4040 | ioc->alt_ioc, MPT_IOC_PRE_RESET); |
4041 | } | 4041 | } |
4042 | } | 4042 | } |
4043 | } | 4043 | } |
4044 | 4044 | ||
4045 | if (ioc->cached_fw) | 4045 | if (ioc->cached_fw) |
4046 | cached_fw = (MpiFwHeader_t *)ioc->cached_fw; | 4046 | cached_fw = (MpiFwHeader_t *)ioc->cached_fw; |
4047 | else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) | 4047 | else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) |
4048 | cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw; | 4048 | cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw; |
4049 | else | 4049 | else |
4050 | cached_fw = NULL; | 4050 | cached_fw = NULL; |
4051 | if (cached_fw) { | 4051 | if (cached_fw) { |
4052 | /* If the DownloadBoot operation fails, the | 4052 | /* If the DownloadBoot operation fails, the |
4053 | * IOC will be left unusable. This is a fatal error | 4053 | * IOC will be left unusable. This is a fatal error |
4054 | * case. _diag_reset will return < 0 | 4054 | * case. _diag_reset will return < 0 |
4055 | */ | 4055 | */ |
4056 | for (count = 0; count < 30; count ++) { | 4056 | for (count = 0; count < 30; count ++) { |
4057 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); | 4057 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); |
4058 | if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) { | 4058 | if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) { |
4059 | break; | 4059 | break; |
4060 | } | 4060 | } |
4061 | 4061 | ||
4062 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n", | 4062 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n", |
4063 | ioc->name, diag0val, count)); | 4063 | ioc->name, diag0val, count)); |
4064 | /* wait 1 sec */ | 4064 | /* wait 1 sec */ |
4065 | if (sleepFlag == CAN_SLEEP) { | 4065 | if (sleepFlag == CAN_SLEEP) { |
4066 | msleep (1000); | 4066 | msleep (1000); |
4067 | } else { | 4067 | } else { |
4068 | mdelay (1000); | 4068 | mdelay (1000); |
4069 | } | 4069 | } |
4070 | } | 4070 | } |
4071 | if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) { | 4071 | if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) { |
4072 | printk(MYIOC_s_WARN_FMT | 4072 | printk(MYIOC_s_WARN_FMT |
4073 | "firmware downloadboot failure (%d)!\n", ioc->name, count); | 4073 | "firmware downloadboot failure (%d)!\n", ioc->name, count); |
4074 | } | 4074 | } |
4075 | 4075 | ||
4076 | } else { | 4076 | } else { |
4077 | /* Wait for FW to reload and for board | 4077 | /* Wait for FW to reload and for board |
4078 | * to go to the READY state. | 4078 | * to go to the READY state. |
4079 | * Maximum wait is 60 seconds. | 4079 | * Maximum wait is 60 seconds. |
4080 | * If fail, no error will check again | 4080 | * If fail, no error will check again |
4081 | * with calling program. | 4081 | * with calling program. |
4082 | */ | 4082 | */ |
4083 | for (count = 0; count < 60; count ++) { | 4083 | for (count = 0; count < 60; count ++) { |
4084 | doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); | 4084 | doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); |
4085 | doorbell &= MPI_IOC_STATE_MASK; | 4085 | doorbell &= MPI_IOC_STATE_MASK; |
4086 | 4086 | ||
4087 | drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 4087 | drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
4088 | "looking for READY STATE: doorbell=%x" | 4088 | "looking for READY STATE: doorbell=%x" |
4089 | " count=%d\n", ioc->name, doorbell, count)); | 4089 | " count=%d\n", ioc->name, doorbell, count)); |
4090 | 4090 | ||
4091 | if (doorbell == MPI_IOC_STATE_READY) { | 4091 | if (doorbell == MPI_IOC_STATE_READY) { |
4092 | break; | 4092 | break; |
4093 | } | 4093 | } |
4094 | 4094 | ||
4095 | /* wait 1 sec */ | 4095 | /* wait 1 sec */ |
4096 | if (sleepFlag == CAN_SLEEP) { | 4096 | if (sleepFlag == CAN_SLEEP) { |
4097 | msleep (1000); | 4097 | msleep (1000); |
4098 | } else { | 4098 | } else { |
4099 | mdelay (1000); | 4099 | mdelay (1000); |
4100 | } | 4100 | } |
4101 | } | 4101 | } |
4102 | 4102 | ||
4103 | if (doorbell != MPI_IOC_STATE_READY) | 4103 | if (doorbell != MPI_IOC_STATE_READY) |
4104 | printk(MYIOC_s_ERR_FMT "Failed to come READY " | 4104 | printk(MYIOC_s_ERR_FMT "Failed to come READY " |
4105 | "after reset! IocState=%x", ioc->name, | 4105 | "after reset! IocState=%x", ioc->name, |
4106 | doorbell); | 4106 | doorbell); |
4107 | } | 4107 | } |
4108 | } | 4108 | } |
4109 | 4109 | ||
4110 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); | 4110 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); |
4111 | if (ioc->debug_level & MPT_DEBUG) { | 4111 | if (ioc->debug_level & MPT_DEBUG) { |
4112 | if (ioc->alt_ioc) | 4112 | if (ioc->alt_ioc) |
4113 | diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); | 4113 | diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); |
4114 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n", | 4114 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n", |
4115 | ioc->name, diag0val, diag1val)); | 4115 | ioc->name, diag0val, diag1val)); |
4116 | } | 4116 | } |
4117 | 4117 | ||
4118 | /* Clear RESET_HISTORY bit! Place board in the | 4118 | /* Clear RESET_HISTORY bit! Place board in the |
4119 | * diagnostic mode to update the diag register. | 4119 | * diagnostic mode to update the diag register. |
4120 | */ | 4120 | */ |
4121 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); | 4121 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); |
4122 | count = 0; | 4122 | count = 0; |
4123 | while ((diag0val & MPI_DIAG_DRWE) == 0) { | 4123 | while ((diag0val & MPI_DIAG_DRWE) == 0) { |
4124 | /* Write magic sequence to WriteSequence register | 4124 | /* Write magic sequence to WriteSequence register |
4125 | * Loop until in diagnostic mode | 4125 | * Loop until in diagnostic mode |
4126 | */ | 4126 | */ |
4127 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); | 4127 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); |
4128 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); | 4128 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); |
4129 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); | 4129 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); |
4130 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); | 4130 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); |
4131 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); | 4131 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); |
4132 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); | 4132 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); |
4133 | 4133 | ||
4134 | /* wait 100 msec */ | 4134 | /* wait 100 msec */ |
4135 | if (sleepFlag == CAN_SLEEP) { | 4135 | if (sleepFlag == CAN_SLEEP) { |
4136 | msleep (100); | 4136 | msleep (100); |
4137 | } else { | 4137 | } else { |
4138 | mdelay (100); | 4138 | mdelay (100); |
4139 | } | 4139 | } |
4140 | 4140 | ||
4141 | count++; | 4141 | count++; |
4142 | if (count > 20) { | 4142 | if (count > 20) { |
4143 | printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n", | 4143 | printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n", |
4144 | ioc->name, diag0val); | 4144 | ioc->name, diag0val); |
4145 | break; | 4145 | break; |
4146 | } | 4146 | } |
4147 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); | 4147 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); |
4148 | } | 4148 | } |
4149 | diag0val &= ~MPI_DIAG_RESET_HISTORY; | 4149 | diag0val &= ~MPI_DIAG_RESET_HISTORY; |
4150 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); | 4150 | CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); |
4151 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); | 4151 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); |
4152 | if (diag0val & MPI_DIAG_RESET_HISTORY) { | 4152 | if (diag0val & MPI_DIAG_RESET_HISTORY) { |
4153 | printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n", | 4153 | printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n", |
4154 | ioc->name); | 4154 | ioc->name); |
4155 | } | 4155 | } |
4156 | 4156 | ||
4157 | /* Disable Diagnostic Mode | 4157 | /* Disable Diagnostic Mode |
4158 | */ | 4158 | */ |
4159 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF); | 4159 | CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF); |
4160 | 4160 | ||
4161 | /* Check FW reload status flags. | 4161 | /* Check FW reload status flags. |
4162 | */ | 4162 | */ |
4163 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); | 4163 | diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); |
4164 | if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) { | 4164 | if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) { |
4165 | printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n", | 4165 | printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n", |
4166 | ioc->name, diag0val); | 4166 | ioc->name, diag0val); |
4167 | return -3; | 4167 | return -3; |
4168 | } | 4168 | } |
4169 | 4169 | ||
4170 | if (ioc->debug_level & MPT_DEBUG) { | 4170 | if (ioc->debug_level & MPT_DEBUG) { |
4171 | if (ioc->alt_ioc) | 4171 | if (ioc->alt_ioc) |
4172 | diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); | 4172 | diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); |
4173 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n", | 4173 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n", |
4174 | ioc->name, diag0val, diag1val)); | 4174 | ioc->name, diag0val, diag1val)); |
4175 | } | 4175 | } |
4176 | 4176 | ||
4177 | /* | 4177 | /* |
4178 | * Reset flag that says we've enabled event notification | 4178 | * Reset flag that says we've enabled event notification |
4179 | */ | 4179 | */ |
4180 | ioc->facts.EventState = 0; | 4180 | ioc->facts.EventState = 0; |
4181 | 4181 | ||
4182 | if (ioc->alt_ioc) | 4182 | if (ioc->alt_ioc) |
4183 | ioc->alt_ioc->facts.EventState = 0; | 4183 | ioc->alt_ioc->facts.EventState = 0; |
4184 | 4184 | ||
4185 | return hard_reset_done; | 4185 | return hard_reset_done; |
4186 | } | 4186 | } |
4187 | 4187 | ||
4188 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 4188 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
4189 | /** | 4189 | /** |
4190 | * SendIocReset - Send IOCReset request to MPT adapter. | 4190 | * SendIocReset - Send IOCReset request to MPT adapter. |
4191 | * @ioc: Pointer to MPT_ADAPTER structure | 4191 | * @ioc: Pointer to MPT_ADAPTER structure |
4192 | * @reset_type: reset type, expected values are | 4192 | * @reset_type: reset type, expected values are |
4193 | * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET | 4193 | * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET |
4194 | * @sleepFlag: Specifies whether the process can sleep | 4194 | * @sleepFlag: Specifies whether the process can sleep |
4195 | * | 4195 | * |
4196 | * Send IOCReset request to the MPT adapter. | 4196 | * Send IOCReset request to the MPT adapter. |
4197 | * | 4197 | * |
4198 | * Returns 0 for success, non-zero for failure. | 4198 | * Returns 0 for success, non-zero for failure. |
4199 | */ | 4199 | */ |
4200 | static int | 4200 | static int |
4201 | SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) | 4201 | SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) |
4202 | { | 4202 | { |
4203 | int r; | 4203 | int r; |
4204 | u32 state; | 4204 | u32 state; |
4205 | int cntdn, count; | 4205 | int cntdn, count; |
4206 | 4206 | ||
4207 | drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n", | 4207 | drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n", |
4208 | ioc->name, reset_type)); | 4208 | ioc->name, reset_type)); |
4209 | CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT); | 4209 | CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT); |
4210 | if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) | 4210 | if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) |
4211 | return r; | 4211 | return r; |
4212 | 4212 | ||
4213 | /* FW ACK'd request, wait for READY state | 4213 | /* FW ACK'd request, wait for READY state |
4214 | */ | 4214 | */ |
4215 | count = 0; | 4215 | count = 0; |
4216 | cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */ | 4216 | cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */ |
4217 | 4217 | ||
4218 | while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) { | 4218 | while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) { |
4219 | cntdn--; | 4219 | cntdn--; |
4220 | count++; | 4220 | count++; |
4221 | if (!cntdn) { | 4221 | if (!cntdn) { |
4222 | if (sleepFlag != CAN_SLEEP) | 4222 | if (sleepFlag != CAN_SLEEP) |
4223 | count *= 10; | 4223 | count *= 10; |
4224 | 4224 | ||
4225 | printk(MYIOC_s_ERR_FMT | 4225 | printk(MYIOC_s_ERR_FMT |
4226 | "Wait IOC_READY state (0x%x) timeout(%d)!\n", | 4226 | "Wait IOC_READY state (0x%x) timeout(%d)!\n", |
4227 | ioc->name, state, (int)((count+5)/HZ)); | 4227 | ioc->name, state, (int)((count+5)/HZ)); |
4228 | return -ETIME; | 4228 | return -ETIME; |
4229 | } | 4229 | } |
4230 | 4230 | ||
4231 | if (sleepFlag == CAN_SLEEP) { | 4231 | if (sleepFlag == CAN_SLEEP) { |
4232 | msleep(1); | 4232 | msleep(1); |
4233 | } else { | 4233 | } else { |
4234 | mdelay (1); /* 1 msec delay */ | 4234 | mdelay (1); /* 1 msec delay */ |
4235 | } | 4235 | } |
4236 | } | 4236 | } |
4237 | 4237 | ||
4238 | /* TODO! | 4238 | /* TODO! |
4239 | * Cleanup all event stuff for this IOC; re-issue EventNotification | 4239 | * Cleanup all event stuff for this IOC; re-issue EventNotification |
4240 | * request if needed. | 4240 | * request if needed. |
4241 | */ | 4241 | */ |
4242 | if (ioc->facts.Function) | 4242 | if (ioc->facts.Function) |
4243 | ioc->facts.EventState = 0; | 4243 | ioc->facts.EventState = 0; |
4244 | 4244 | ||
4245 | return 0; | 4245 | return 0; |
4246 | } | 4246 | } |
4247 | 4247 | ||
4248 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 4248 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
4249 | /** | 4249 | /** |
4250 | * initChainBuffers - Allocate memory for and initialize chain buffers | 4250 | * initChainBuffers - Allocate memory for and initialize chain buffers |
4251 | * @ioc: Pointer to MPT_ADAPTER structure | 4251 | * @ioc: Pointer to MPT_ADAPTER structure |
4252 | * | 4252 | * |
4253 | * Allocates memory for and initializes chain buffers, | 4253 | * Allocates memory for and initializes chain buffers, |
4254 | * chain buffer control arrays and spinlock. | 4254 | * chain buffer control arrays and spinlock. |
4255 | */ | 4255 | */ |
4256 | static int | 4256 | static int |
4257 | initChainBuffers(MPT_ADAPTER *ioc) | 4257 | initChainBuffers(MPT_ADAPTER *ioc) |
4258 | { | 4258 | { |
4259 | u8 *mem; | 4259 | u8 *mem; |
4260 | int sz, ii, num_chain; | 4260 | int sz, ii, num_chain; |
4261 | int scale, num_sge, numSGE; | 4261 | int scale, num_sge, numSGE; |
4262 | 4262 | ||
4263 | /* ReqToChain size must equal the req_depth | 4263 | /* ReqToChain size must equal the req_depth |
4264 | * index = req_idx | 4264 | * index = req_idx |
4265 | */ | 4265 | */ |
4266 | if (ioc->ReqToChain == NULL) { | 4266 | if (ioc->ReqToChain == NULL) { |
4267 | sz = ioc->req_depth * sizeof(int); | 4267 | sz = ioc->req_depth * sizeof(int); |
4268 | mem = kmalloc(sz, GFP_ATOMIC); | 4268 | mem = kmalloc(sz, GFP_ATOMIC); |
4269 | if (mem == NULL) | 4269 | if (mem == NULL) |
4270 | return -1; | 4270 | return -1; |
4271 | 4271 | ||
4272 | ioc->ReqToChain = (int *) mem; | 4272 | ioc->ReqToChain = (int *) mem; |
4273 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n", | 4273 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n", |
4274 | ioc->name, mem, sz)); | 4274 | ioc->name, mem, sz)); |
4275 | mem = kmalloc(sz, GFP_ATOMIC); | 4275 | mem = kmalloc(sz, GFP_ATOMIC); |
4276 | if (mem == NULL) | 4276 | if (mem == NULL) |
4277 | return -1; | 4277 | return -1; |
4278 | 4278 | ||
4279 | ioc->RequestNB = (int *) mem; | 4279 | ioc->RequestNB = (int *) mem; |
4280 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n", | 4280 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n", |
4281 | ioc->name, mem, sz)); | 4281 | ioc->name, mem, sz)); |
4282 | } | 4282 | } |
4283 | for (ii = 0; ii < ioc->req_depth; ii++) { | 4283 | for (ii = 0; ii < ioc->req_depth; ii++) { |
4284 | ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN; | 4284 | ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN; |
4285 | } | 4285 | } |
4286 | 4286 | ||
4287 | /* ChainToChain size must equal the total number | 4287 | /* ChainToChain size must equal the total number |
4288 | * of chain buffers to be allocated. | 4288 | * of chain buffers to be allocated. |
4289 | * index = chain_idx | 4289 | * index = chain_idx |
4290 | * | 4290 | * |
4291 | * Calculate the number of chain buffers needed(plus 1) per I/O | 4291 | * Calculate the number of chain buffers needed(plus 1) per I/O |
4292 | * then multiply the maximum number of simultaneous cmds | 4292 | * then multiply the maximum number of simultaneous cmds |
4293 | * | 4293 | * |
4294 | * num_sge = num sge in request frame + last chain buffer | 4294 | * num_sge = num sge in request frame + last chain buffer |
4295 | * scale = num sge per chain buffer if no chain element | 4295 | * scale = num sge per chain buffer if no chain element |
4296 | */ | 4296 | */ |
4297 | scale = ioc->req_sz / ioc->SGE_size; | 4297 | scale = ioc->req_sz / ioc->SGE_size; |
4298 | if (ioc->sg_addr_size == sizeof(u64)) | 4298 | if (ioc->sg_addr_size == sizeof(u64)) |
4299 | num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size; | 4299 | num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size; |
4300 | else | 4300 | else |
4301 | num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size; | 4301 | num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size; |
4302 | 4302 | ||
4303 | if (ioc->sg_addr_size == sizeof(u64)) { | 4303 | if (ioc->sg_addr_size == sizeof(u64)) { |
4304 | numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + | 4304 | numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + |
4305 | (ioc->req_sz - 60) / ioc->SGE_size; | 4305 | (ioc->req_sz - 60) / ioc->SGE_size; |
4306 | } else { | 4306 | } else { |
4307 | numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + | 4307 | numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + |
4308 | scale + (ioc->req_sz - 64) / ioc->SGE_size; | 4308 | scale + (ioc->req_sz - 64) / ioc->SGE_size; |
4309 | } | 4309 | } |
4310 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n", | 4310 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n", |
4311 | ioc->name, num_sge, numSGE)); | 4311 | ioc->name, num_sge, numSGE)); |
4312 | 4312 | ||
4313 | if (ioc->bus_type == FC) { | 4313 | if (ioc->bus_type == FC) { |
4314 | if (numSGE > MPT_SCSI_FC_SG_DEPTH) | 4314 | if (numSGE > MPT_SCSI_FC_SG_DEPTH) |
4315 | numSGE = MPT_SCSI_FC_SG_DEPTH; | 4315 | numSGE = MPT_SCSI_FC_SG_DEPTH; |
4316 | } else { | 4316 | } else { |
4317 | if (numSGE > MPT_SCSI_SG_DEPTH) | 4317 | if (numSGE > MPT_SCSI_SG_DEPTH) |
4318 | numSGE = MPT_SCSI_SG_DEPTH; | 4318 | numSGE = MPT_SCSI_SG_DEPTH; |
4319 | } | 4319 | } |
4320 | 4320 | ||
4321 | num_chain = 1; | 4321 | num_chain = 1; |
4322 | while (numSGE - num_sge > 0) { | 4322 | while (numSGE - num_sge > 0) { |
4323 | num_chain++; | 4323 | num_chain++; |
4324 | num_sge += (scale - 1); | 4324 | num_sge += (scale - 1); |
4325 | } | 4325 | } |
4326 | num_chain++; | 4326 | num_chain++; |
4327 | 4327 | ||
4328 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n", | 4328 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n", |
4329 | ioc->name, numSGE, num_sge, num_chain)); | 4329 | ioc->name, numSGE, num_sge, num_chain)); |
4330 | 4330 | ||
4331 | if (ioc->bus_type == SPI) | 4331 | if (ioc->bus_type == SPI) |
4332 | num_chain *= MPT_SCSI_CAN_QUEUE; | 4332 | num_chain *= MPT_SCSI_CAN_QUEUE; |
4333 | else | 4333 | else |
4334 | num_chain *= MPT_FC_CAN_QUEUE; | 4334 | num_chain *= MPT_FC_CAN_QUEUE; |
4335 | 4335 | ||
4336 | ioc->num_chain = num_chain; | 4336 | ioc->num_chain = num_chain; |
4337 | 4337 | ||
4338 | sz = num_chain * sizeof(int); | 4338 | sz = num_chain * sizeof(int); |
4339 | if (ioc->ChainToChain == NULL) { | 4339 | if (ioc->ChainToChain == NULL) { |
4340 | mem = kmalloc(sz, GFP_ATOMIC); | 4340 | mem = kmalloc(sz, GFP_ATOMIC); |
4341 | if (mem == NULL) | 4341 | if (mem == NULL) |
4342 | return -1; | 4342 | return -1; |
4343 | 4343 | ||
4344 | ioc->ChainToChain = (int *) mem; | 4344 | ioc->ChainToChain = (int *) mem; |
4345 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n", | 4345 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n", |
4346 | ioc->name, mem, sz)); | 4346 | ioc->name, mem, sz)); |
4347 | } else { | 4347 | } else { |
4348 | mem = (u8 *) ioc->ChainToChain; | 4348 | mem = (u8 *) ioc->ChainToChain; |
4349 | } | 4349 | } |
4350 | memset(mem, 0xFF, sz); | 4350 | memset(mem, 0xFF, sz); |
4351 | return num_chain; | 4351 | return num_chain; |
4352 | } | 4352 | } |
4353 | 4353 | ||
4354 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 4354 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
4355 | /** | 4355 | /** |
4356 | * PrimeIocFifos - Initialize IOC request and reply FIFOs. | 4356 | * PrimeIocFifos - Initialize IOC request and reply FIFOs. |
4357 | * @ioc: Pointer to MPT_ADAPTER structure | 4357 | * @ioc: Pointer to MPT_ADAPTER structure |
4358 | * | 4358 | * |
4359 | * This routine allocates memory for the MPT reply and request frame | 4359 | * This routine allocates memory for the MPT reply and request frame |
4360 | * pools (if necessary), and primes the IOC reply FIFO with | 4360 | * pools (if necessary), and primes the IOC reply FIFO with |
4361 | * reply frames. | 4361 | * reply frames. |
4362 | * | 4362 | * |
4363 | * Returns 0 for success, non-zero for failure. | 4363 | * Returns 0 for success, non-zero for failure. |
4364 | */ | 4364 | */ |
4365 | static int | 4365 | static int |
4366 | PrimeIocFifos(MPT_ADAPTER *ioc) | 4366 | PrimeIocFifos(MPT_ADAPTER *ioc) |
4367 | { | 4367 | { |
4368 | MPT_FRAME_HDR *mf; | 4368 | MPT_FRAME_HDR *mf; |
4369 | unsigned long flags; | 4369 | unsigned long flags; |
4370 | dma_addr_t alloc_dma; | 4370 | dma_addr_t alloc_dma; |
4371 | u8 *mem; | 4371 | u8 *mem; |
4372 | int i, reply_sz, sz, total_size, num_chain; | 4372 | int i, reply_sz, sz, total_size, num_chain; |
4373 | u64 dma_mask; | 4373 | u64 dma_mask; |
4374 | 4374 | ||
4375 | dma_mask = 0; | 4375 | dma_mask = 0; |
4376 | 4376 | ||
4377 | /* Prime reply FIFO... */ | 4377 | /* Prime reply FIFO... */ |
4378 | 4378 | ||
4379 | if (ioc->reply_frames == NULL) { | 4379 | if (ioc->reply_frames == NULL) { |
4380 | if ( (num_chain = initChainBuffers(ioc)) < 0) | 4380 | if ( (num_chain = initChainBuffers(ioc)) < 0) |
4381 | return -1; | 4381 | return -1; |
4382 | /* | 4382 | /* |
4383 | * 1078 errata workaround for the 36GB limitation | 4383 | * 1078 errata workaround for the 36GB limitation |
4384 | */ | 4384 | */ |
4385 | if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 && | 4385 | if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 && |
4386 | ioc->dma_mask > DMA_BIT_MASK(35)) { | 4386 | ioc->dma_mask > DMA_BIT_MASK(35)) { |
4387 | if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32)) | 4387 | if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32)) |
4388 | && !pci_set_consistent_dma_mask(ioc->pcidev, | 4388 | && !pci_set_consistent_dma_mask(ioc->pcidev, |
4389 | DMA_BIT_MASK(32))) { | 4389 | DMA_BIT_MASK(32))) { |
4390 | dma_mask = DMA_BIT_MASK(35); | 4390 | dma_mask = DMA_BIT_MASK(35); |
4391 | d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 4391 | d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
4392 | "setting 35 bit addressing for " | 4392 | "setting 35 bit addressing for " |
4393 | "Request/Reply/Chain and Sense Buffers\n", | 4393 | "Request/Reply/Chain and Sense Buffers\n", |
4394 | ioc->name)); | 4394 | ioc->name)); |
4395 | } else { | 4395 | } else { |
4396 | /*Reseting DMA mask to 64 bit*/ | 4396 | /*Reseting DMA mask to 64 bit*/ |
4397 | pci_set_dma_mask(ioc->pcidev, | 4397 | pci_set_dma_mask(ioc->pcidev, |
4398 | DMA_BIT_MASK(64)); | 4398 | DMA_BIT_MASK(64)); |
4399 | pci_set_consistent_dma_mask(ioc->pcidev, | 4399 | pci_set_consistent_dma_mask(ioc->pcidev, |
4400 | DMA_BIT_MASK(64)); | 4400 | DMA_BIT_MASK(64)); |
4401 | 4401 | ||
4402 | printk(MYIOC_s_ERR_FMT | 4402 | printk(MYIOC_s_ERR_FMT |
4403 | "failed setting 35 bit addressing for " | 4403 | "failed setting 35 bit addressing for " |
4404 | "Request/Reply/Chain and Sense Buffers\n", | 4404 | "Request/Reply/Chain and Sense Buffers\n", |
4405 | ioc->name); | 4405 | ioc->name); |
4406 | return -1; | 4406 | return -1; |
4407 | } | 4407 | } |
4408 | } | 4408 | } |
4409 | 4409 | ||
4410 | total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth); | 4410 | total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth); |
4411 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n", | 4411 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n", |
4412 | ioc->name, ioc->reply_sz, ioc->reply_depth)); | 4412 | ioc->name, ioc->reply_sz, ioc->reply_depth)); |
4413 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n", | 4413 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n", |
4414 | ioc->name, reply_sz, reply_sz)); | 4414 | ioc->name, reply_sz, reply_sz)); |
4415 | 4415 | ||
4416 | sz = (ioc->req_sz * ioc->req_depth); | 4416 | sz = (ioc->req_sz * ioc->req_depth); |
4417 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n", | 4417 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n", |
4418 | ioc->name, ioc->req_sz, ioc->req_depth)); | 4418 | ioc->name, ioc->req_sz, ioc->req_depth)); |
4419 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n", | 4419 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n", |
4420 | ioc->name, sz, sz)); | 4420 | ioc->name, sz, sz)); |
4421 | total_size += sz; | 4421 | total_size += sz; |
4422 | 4422 | ||
4423 | sz = num_chain * ioc->req_sz; /* chain buffer pool size */ | 4423 | sz = num_chain * ioc->req_sz; /* chain buffer pool size */ |
4424 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n", | 4424 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n", |
4425 | ioc->name, ioc->req_sz, num_chain)); | 4425 | ioc->name, ioc->req_sz, num_chain)); |
4426 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n", | 4426 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n", |
4427 | ioc->name, sz, sz, num_chain)); | 4427 | ioc->name, sz, sz, num_chain)); |
4428 | 4428 | ||
4429 | total_size += sz; | 4429 | total_size += sz; |
4430 | mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma); | 4430 | mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma); |
4431 | if (mem == NULL) { | 4431 | if (mem == NULL) { |
4432 | printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n", | 4432 | printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n", |
4433 | ioc->name); | 4433 | ioc->name); |
4434 | goto out_fail; | 4434 | goto out_fail; |
4435 | } | 4435 | } |
4436 | 4436 | ||
4437 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n", | 4437 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n", |
4438 | ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size)); | 4438 | ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size)); |
4439 | 4439 | ||
4440 | memset(mem, 0, total_size); | 4440 | memset(mem, 0, total_size); |
4441 | ioc->alloc_total += total_size; | 4441 | ioc->alloc_total += total_size; |
4442 | ioc->alloc = mem; | 4442 | ioc->alloc = mem; |
4443 | ioc->alloc_dma = alloc_dma; | 4443 | ioc->alloc_dma = alloc_dma; |
4444 | ioc->alloc_sz = total_size; | 4444 | ioc->alloc_sz = total_size; |
4445 | ioc->reply_frames = (MPT_FRAME_HDR *) mem; | 4445 | ioc->reply_frames = (MPT_FRAME_HDR *) mem; |
4446 | ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); | 4446 | ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); |
4447 | 4447 | ||
4448 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n", | 4448 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n", |
4449 | ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); | 4449 | ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); |
4450 | 4450 | ||
4451 | alloc_dma += reply_sz; | 4451 | alloc_dma += reply_sz; |
4452 | mem += reply_sz; | 4452 | mem += reply_sz; |
4453 | 4453 | ||
4454 | /* Request FIFO - WE manage this! */ | 4454 | /* Request FIFO - WE manage this! */ |
4455 | 4455 | ||
4456 | ioc->req_frames = (MPT_FRAME_HDR *) mem; | 4456 | ioc->req_frames = (MPT_FRAME_HDR *) mem; |
4457 | ioc->req_frames_dma = alloc_dma; | 4457 | ioc->req_frames_dma = alloc_dma; |
4458 | 4458 | ||
4459 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n", | 4459 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n", |
4460 | ioc->name, mem, (void *)(ulong)alloc_dma)); | 4460 | ioc->name, mem, (void *)(ulong)alloc_dma)); |
4461 | 4461 | ||
4462 | ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); | 4462 | ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); |
4463 | 4463 | ||
4464 | #if defined(CONFIG_MTRR) && 0 | 4464 | #if defined(CONFIG_MTRR) && 0 |
4465 | /* | 4465 | /* |
4466 | * Enable Write Combining MTRR for IOC's memory region. | 4466 | * Enable Write Combining MTRR for IOC's memory region. |
4467 | * (at least as much as we can; "size and base must be | 4467 | * (at least as much as we can; "size and base must be |
4468 | * multiples of 4 kiB" | 4468 | * multiples of 4 kiB" |
4469 | */ | 4469 | */ |
4470 | ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma, | 4470 | ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma, |
4471 | sz, | 4471 | sz, |
4472 | MTRR_TYPE_WRCOMB, 1); | 4472 | MTRR_TYPE_WRCOMB, 1); |
4473 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n", | 4473 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n", |
4474 | ioc->name, ioc->req_frames_dma, sz)); | 4474 | ioc->name, ioc->req_frames_dma, sz)); |
4475 | #endif | 4475 | #endif |
4476 | 4476 | ||
4477 | for (i = 0; i < ioc->req_depth; i++) { | 4477 | for (i = 0; i < ioc->req_depth; i++) { |
4478 | alloc_dma += ioc->req_sz; | 4478 | alloc_dma += ioc->req_sz; |
4479 | mem += ioc->req_sz; | 4479 | mem += ioc->req_sz; |
4480 | } | 4480 | } |
4481 | 4481 | ||
4482 | ioc->ChainBuffer = mem; | 4482 | ioc->ChainBuffer = mem; |
4483 | ioc->ChainBufferDMA = alloc_dma; | 4483 | ioc->ChainBufferDMA = alloc_dma; |
4484 | 4484 | ||
4485 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n", | 4485 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n", |
4486 | ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA)); | 4486 | ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA)); |
4487 | 4487 | ||
4488 | /* Initialize the free chain Q. | 4488 | /* Initialize the free chain Q. |
4489 | */ | 4489 | */ |
4490 | 4490 | ||
4491 | INIT_LIST_HEAD(&ioc->FreeChainQ); | 4491 | INIT_LIST_HEAD(&ioc->FreeChainQ); |
4492 | 4492 | ||
4493 | /* Post the chain buffers to the FreeChainQ. | 4493 | /* Post the chain buffers to the FreeChainQ. |
4494 | */ | 4494 | */ |
4495 | mem = (u8 *)ioc->ChainBuffer; | 4495 | mem = (u8 *)ioc->ChainBuffer; |
4496 | for (i=0; i < num_chain; i++) { | 4496 | for (i=0; i < num_chain; i++) { |
4497 | mf = (MPT_FRAME_HDR *) mem; | 4497 | mf = (MPT_FRAME_HDR *) mem; |
4498 | list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ); | 4498 | list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ); |
4499 | mem += ioc->req_sz; | 4499 | mem += ioc->req_sz; |
4500 | } | 4500 | } |
4501 | 4501 | ||
4502 | /* Initialize Request frames linked list | 4502 | /* Initialize Request frames linked list |
4503 | */ | 4503 | */ |
4504 | alloc_dma = ioc->req_frames_dma; | 4504 | alloc_dma = ioc->req_frames_dma; |
4505 | mem = (u8 *) ioc->req_frames; | 4505 | mem = (u8 *) ioc->req_frames; |
4506 | 4506 | ||
4507 | spin_lock_irqsave(&ioc->FreeQlock, flags); | 4507 | spin_lock_irqsave(&ioc->FreeQlock, flags); |
4508 | INIT_LIST_HEAD(&ioc->FreeQ); | 4508 | INIT_LIST_HEAD(&ioc->FreeQ); |
4509 | for (i = 0; i < ioc->req_depth; i++) { | 4509 | for (i = 0; i < ioc->req_depth; i++) { |
4510 | mf = (MPT_FRAME_HDR *) mem; | 4510 | mf = (MPT_FRAME_HDR *) mem; |
4511 | 4511 | ||
4512 | /* Queue REQUESTs *internally*! */ | 4512 | /* Queue REQUESTs *internally*! */ |
4513 | list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ); | 4513 | list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ); |
4514 | 4514 | ||
4515 | mem += ioc->req_sz; | 4515 | mem += ioc->req_sz; |
4516 | } | 4516 | } |
4517 | spin_unlock_irqrestore(&ioc->FreeQlock, flags); | 4517 | spin_unlock_irqrestore(&ioc->FreeQlock, flags); |
4518 | 4518 | ||
4519 | sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); | 4519 | sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); |
4520 | ioc->sense_buf_pool = | 4520 | ioc->sense_buf_pool = |
4521 | pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma); | 4521 | pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma); |
4522 | if (ioc->sense_buf_pool == NULL) { | 4522 | if (ioc->sense_buf_pool == NULL) { |
4523 | printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n", | 4523 | printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n", |
4524 | ioc->name); | 4524 | ioc->name); |
4525 | goto out_fail; | 4525 | goto out_fail; |
4526 | } | 4526 | } |
4527 | 4527 | ||
4528 | ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF); | 4528 | ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF); |
4529 | ioc->alloc_total += sz; | 4529 | ioc->alloc_total += sz; |
4530 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n", | 4530 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n", |
4531 | ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma)); | 4531 | ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma)); |
4532 | 4532 | ||
4533 | } | 4533 | } |
4534 | 4534 | ||
4535 | /* Post Reply frames to FIFO | 4535 | /* Post Reply frames to FIFO |
4536 | */ | 4536 | */ |
4537 | alloc_dma = ioc->alloc_dma; | 4537 | alloc_dma = ioc->alloc_dma; |
4538 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n", | 4538 | dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n", |
4539 | ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); | 4539 | ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); |
4540 | 4540 | ||
4541 | for (i = 0; i < ioc->reply_depth; i++) { | 4541 | for (i = 0; i < ioc->reply_depth; i++) { |
4542 | /* Write each address to the IOC! */ | 4542 | /* Write each address to the IOC! */ |
4543 | CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma); | 4543 | CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma); |
4544 | alloc_dma += ioc->reply_sz; | 4544 | alloc_dma += ioc->reply_sz; |
4545 | } | 4545 | } |
4546 | 4546 | ||
4547 | if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev, | 4547 | if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev, |
4548 | ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev, | 4548 | ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev, |
4549 | ioc->dma_mask)) | 4549 | ioc->dma_mask)) |
4550 | d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 4550 | d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
4551 | "restoring 64 bit addressing\n", ioc->name)); | 4551 | "restoring 64 bit addressing\n", ioc->name)); |
4552 | 4552 | ||
4553 | return 0; | 4553 | return 0; |
4554 | 4554 | ||
4555 | out_fail: | 4555 | out_fail: |
4556 | 4556 | ||
4557 | if (ioc->alloc != NULL) { | 4557 | if (ioc->alloc != NULL) { |
4558 | sz = ioc->alloc_sz; | 4558 | sz = ioc->alloc_sz; |
4559 | pci_free_consistent(ioc->pcidev, | 4559 | pci_free_consistent(ioc->pcidev, |
4560 | sz, | 4560 | sz, |
4561 | ioc->alloc, ioc->alloc_dma); | 4561 | ioc->alloc, ioc->alloc_dma); |
4562 | ioc->reply_frames = NULL; | 4562 | ioc->reply_frames = NULL; |
4563 | ioc->req_frames = NULL; | 4563 | ioc->req_frames = NULL; |
4564 | ioc->alloc_total -= sz; | 4564 | ioc->alloc_total -= sz; |
4565 | } | 4565 | } |
4566 | if (ioc->sense_buf_pool != NULL) { | 4566 | if (ioc->sense_buf_pool != NULL) { |
4567 | sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); | 4567 | sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); |
4568 | pci_free_consistent(ioc->pcidev, | 4568 | pci_free_consistent(ioc->pcidev, |
4569 | sz, | 4569 | sz, |
4570 | ioc->sense_buf_pool, ioc->sense_buf_pool_dma); | 4570 | ioc->sense_buf_pool, ioc->sense_buf_pool_dma); |
4571 | ioc->sense_buf_pool = NULL; | 4571 | ioc->sense_buf_pool = NULL; |
4572 | } | 4572 | } |
4573 | 4573 | ||
4574 | if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev, | 4574 | if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev, |
4575 | DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev, | 4575 | DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev, |
4576 | DMA_BIT_MASK(64))) | 4576 | DMA_BIT_MASK(64))) |
4577 | d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 4577 | d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
4578 | "restoring 64 bit addressing\n", ioc->name)); | 4578 | "restoring 64 bit addressing\n", ioc->name)); |
4579 | 4579 | ||
4580 | return -1; | 4580 | return -1; |
4581 | } | 4581 | } |
4582 | 4582 | ||
4583 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 4583 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
4584 | /** | 4584 | /** |
4585 | * mpt_handshake_req_reply_wait - Send MPT request to and receive reply | 4585 | * mpt_handshake_req_reply_wait - Send MPT request to and receive reply |
4586 | * from IOC via doorbell handshake method. | 4586 | * from IOC via doorbell handshake method. |
4587 | * @ioc: Pointer to MPT_ADAPTER structure | 4587 | * @ioc: Pointer to MPT_ADAPTER structure |
4588 | * @reqBytes: Size of the request in bytes | 4588 | * @reqBytes: Size of the request in bytes |
4589 | * @req: Pointer to MPT request frame | 4589 | * @req: Pointer to MPT request frame |
4590 | * @replyBytes: Expected size of the reply in bytes | 4590 | * @replyBytes: Expected size of the reply in bytes |
4591 | * @u16reply: Pointer to area where reply should be written | 4591 | * @u16reply: Pointer to area where reply should be written |
4592 | * @maxwait: Max wait time for a reply (in seconds) | 4592 | * @maxwait: Max wait time for a reply (in seconds) |
4593 | * @sleepFlag: Specifies whether the process can sleep | 4593 | * @sleepFlag: Specifies whether the process can sleep |
4594 | * | 4594 | * |
4595 | * NOTES: It is the callers responsibility to byte-swap fields in the | 4595 | * NOTES: It is the callers responsibility to byte-swap fields in the |
4596 | * request which are greater than 1 byte in size. It is also the | 4596 | * request which are greater than 1 byte in size. It is also the |
4597 | * callers responsibility to byte-swap response fields which are | 4597 | * callers responsibility to byte-swap response fields which are |
4598 | * greater than 1 byte in size. | 4598 | * greater than 1 byte in size. |
4599 | * | 4599 | * |
4600 | * Returns 0 for success, non-zero for failure. | 4600 | * Returns 0 for success, non-zero for failure. |
4601 | */ | 4601 | */ |
4602 | static int | 4602 | static int |
4603 | mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, | 4603 | mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, |
4604 | int replyBytes, u16 *u16reply, int maxwait, int sleepFlag) | 4604 | int replyBytes, u16 *u16reply, int maxwait, int sleepFlag) |
4605 | { | 4605 | { |
4606 | MPIDefaultReply_t *mptReply; | 4606 | MPIDefaultReply_t *mptReply; |
4607 | int failcnt = 0; | 4607 | int failcnt = 0; |
4608 | int t; | 4608 | int t; |
4609 | 4609 | ||
4610 | /* | 4610 | /* |
4611 | * Get ready to cache a handshake reply | 4611 | * Get ready to cache a handshake reply |
4612 | */ | 4612 | */ |
4613 | ioc->hs_reply_idx = 0; | 4613 | ioc->hs_reply_idx = 0; |
4614 | mptReply = (MPIDefaultReply_t *) ioc->hs_reply; | 4614 | mptReply = (MPIDefaultReply_t *) ioc->hs_reply; |
4615 | mptReply->MsgLength = 0; | 4615 | mptReply->MsgLength = 0; |
4616 | 4616 | ||
4617 | /* | 4617 | /* |
4618 | * Make sure there are no doorbells (WRITE 0 to IntStatus reg), | 4618 | * Make sure there are no doorbells (WRITE 0 to IntStatus reg), |
4619 | * then tell IOC that we want to handshake a request of N words. | 4619 | * then tell IOC that we want to handshake a request of N words. |
4620 | * (WRITE u32val to Doorbell reg). | 4620 | * (WRITE u32val to Doorbell reg). |
4621 | */ | 4621 | */ |
4622 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); | 4622 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); |
4623 | CHIPREG_WRITE32(&ioc->chip->Doorbell, | 4623 | CHIPREG_WRITE32(&ioc->chip->Doorbell, |
4624 | ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) | | 4624 | ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) | |
4625 | ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT))); | 4625 | ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT))); |
4626 | 4626 | ||
4627 | /* | 4627 | /* |
4628 | * Wait for IOC's doorbell handshake int | 4628 | * Wait for IOC's doorbell handshake int |
4629 | */ | 4629 | */ |
4630 | if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) | 4630 | if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) |
4631 | failcnt++; | 4631 | failcnt++; |
4632 | 4632 | ||
4633 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n", | 4633 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n", |
4634 | ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); | 4634 | ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); |
4635 | 4635 | ||
4636 | /* Read doorbell and check for active bit */ | 4636 | /* Read doorbell and check for active bit */ |
4637 | if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) | 4637 | if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) |
4638 | return -1; | 4638 | return -1; |
4639 | 4639 | ||
4640 | /* | 4640 | /* |
4641 | * Clear doorbell int (WRITE 0 to IntStatus reg), | 4641 | * Clear doorbell int (WRITE 0 to IntStatus reg), |
4642 | * then wait for IOC to ACKnowledge that it's ready for | 4642 | * then wait for IOC to ACKnowledge that it's ready for |
4643 | * our handshake request. | 4643 | * our handshake request. |
4644 | */ | 4644 | */ |
4645 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); | 4645 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); |
4646 | if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) | 4646 | if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) |
4647 | failcnt++; | 4647 | failcnt++; |
4648 | 4648 | ||
4649 | if (!failcnt) { | 4649 | if (!failcnt) { |
4650 | int ii; | 4650 | int ii; |
4651 | u8 *req_as_bytes = (u8 *) req; | 4651 | u8 *req_as_bytes = (u8 *) req; |
4652 | 4652 | ||
4653 | /* | 4653 | /* |
4654 | * Stuff request words via doorbell handshake, | 4654 | * Stuff request words via doorbell handshake, |
4655 | * with ACK from IOC for each. | 4655 | * with ACK from IOC for each. |
4656 | */ | 4656 | */ |
4657 | for (ii = 0; !failcnt && ii < reqBytes/4; ii++) { | 4657 | for (ii = 0; !failcnt && ii < reqBytes/4; ii++) { |
4658 | u32 word = ((req_as_bytes[(ii*4) + 0] << 0) | | 4658 | u32 word = ((req_as_bytes[(ii*4) + 0] << 0) | |
4659 | (req_as_bytes[(ii*4) + 1] << 8) | | 4659 | (req_as_bytes[(ii*4) + 1] << 8) | |
4660 | (req_as_bytes[(ii*4) + 2] << 16) | | 4660 | (req_as_bytes[(ii*4) + 2] << 16) | |
4661 | (req_as_bytes[(ii*4) + 3] << 24)); | 4661 | (req_as_bytes[(ii*4) + 3] << 24)); |
4662 | 4662 | ||
4663 | CHIPREG_WRITE32(&ioc->chip->Doorbell, word); | 4663 | CHIPREG_WRITE32(&ioc->chip->Doorbell, word); |
4664 | if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) | 4664 | if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) |
4665 | failcnt++; | 4665 | failcnt++; |
4666 | } | 4666 | } |
4667 | 4667 | ||
4668 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req)); | 4668 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req)); |
4669 | DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req); | 4669 | DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req); |
4670 | 4670 | ||
4671 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n", | 4671 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n", |
4672 | ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : "")); | 4672 | ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : "")); |
4673 | 4673 | ||
4674 | /* | 4674 | /* |
4675 | * Wait for completion of doorbell handshake reply from the IOC | 4675 | * Wait for completion of doorbell handshake reply from the IOC |
4676 | */ | 4676 | */ |
4677 | if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0) | 4677 | if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0) |
4678 | failcnt++; | 4678 | failcnt++; |
4679 | 4679 | ||
4680 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n", | 4680 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n", |
4681 | ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : "")); | 4681 | ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : "")); |
4682 | 4682 | ||
4683 | /* | 4683 | /* |
4684 | * Copy out the cached reply... | 4684 | * Copy out the cached reply... |
4685 | */ | 4685 | */ |
4686 | for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++) | 4686 | for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++) |
4687 | u16reply[ii] = ioc->hs_reply[ii]; | 4687 | u16reply[ii] = ioc->hs_reply[ii]; |
4688 | } else { | 4688 | } else { |
4689 | return -99; | 4689 | return -99; |
4690 | } | 4690 | } |
4691 | 4691 | ||
4692 | return -failcnt; | 4692 | return -failcnt; |
4693 | } | 4693 | } |
4694 | 4694 | ||
4695 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 4695 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
4696 | /** | 4696 | /** |
4697 | * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge | 4697 | * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge |
4698 | * @ioc: Pointer to MPT_ADAPTER structure | 4698 | * @ioc: Pointer to MPT_ADAPTER structure |
4699 | * @howlong: How long to wait (in seconds) | 4699 | * @howlong: How long to wait (in seconds) |
4700 | * @sleepFlag: Specifies whether the process can sleep | 4700 | * @sleepFlag: Specifies whether the process can sleep |
4701 | * | 4701 | * |
4702 | * This routine waits (up to ~2 seconds max) for IOC doorbell | 4702 | * This routine waits (up to ~2 seconds max) for IOC doorbell |
4703 | * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS | 4703 | * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS |
4704 | * bit in its IntStatus register being clear. | 4704 | * bit in its IntStatus register being clear. |
4705 | * | 4705 | * |
4706 | * Returns a negative value on failure, else wait loop count. | 4706 | * Returns a negative value on failure, else wait loop count. |
4707 | */ | 4707 | */ |
4708 | static int | 4708 | static int |
4709 | WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag) | 4709 | WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag) |
4710 | { | 4710 | { |
4711 | int cntdn; | 4711 | int cntdn; |
4712 | int count = 0; | 4712 | int count = 0; |
4713 | u32 intstat=0; | 4713 | u32 intstat=0; |
4714 | 4714 | ||
4715 | cntdn = 1000 * howlong; | 4715 | cntdn = 1000 * howlong; |
4716 | 4716 | ||
4717 | if (sleepFlag == CAN_SLEEP) { | 4717 | if (sleepFlag == CAN_SLEEP) { |
4718 | while (--cntdn) { | 4718 | while (--cntdn) { |
4719 | msleep (1); | 4719 | msleep (1); |
4720 | intstat = CHIPREG_READ32(&ioc->chip->IntStatus); | 4720 | intstat = CHIPREG_READ32(&ioc->chip->IntStatus); |
4721 | if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) | 4721 | if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) |
4722 | break; | 4722 | break; |
4723 | count++; | 4723 | count++; |
4724 | } | 4724 | } |
4725 | } else { | 4725 | } else { |
4726 | while (--cntdn) { | 4726 | while (--cntdn) { |
4727 | udelay (1000); | 4727 | udelay (1000); |
4728 | intstat = CHIPREG_READ32(&ioc->chip->IntStatus); | 4728 | intstat = CHIPREG_READ32(&ioc->chip->IntStatus); |
4729 | if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) | 4729 | if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) |
4730 | break; | 4730 | break; |
4731 | count++; | 4731 | count++; |
4732 | } | 4732 | } |
4733 | } | 4733 | } |
4734 | 4734 | ||
4735 | if (cntdn) { | 4735 | if (cntdn) { |
4736 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n", | 4736 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n", |
4737 | ioc->name, count)); | 4737 | ioc->name, count)); |
4738 | return count; | 4738 | return count; |
4739 | } | 4739 | } |
4740 | 4740 | ||
4741 | printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n", | 4741 | printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n", |
4742 | ioc->name, count, intstat); | 4742 | ioc->name, count, intstat); |
4743 | return -1; | 4743 | return -1; |
4744 | } | 4744 | } |
4745 | 4745 | ||
4746 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 4746 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
4747 | /** | 4747 | /** |
4748 | * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit | 4748 | * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit |
4749 | * @ioc: Pointer to MPT_ADAPTER structure | 4749 | * @ioc: Pointer to MPT_ADAPTER structure |
4750 | * @howlong: How long to wait (in seconds) | 4750 | * @howlong: How long to wait (in seconds) |
4751 | * @sleepFlag: Specifies whether the process can sleep | 4751 | * @sleepFlag: Specifies whether the process can sleep |
4752 | * | 4752 | * |
4753 | * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt | 4753 | * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt |
4754 | * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register. | 4754 | * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register. |
4755 | * | 4755 | * |
4756 | * Returns a negative value on failure, else wait loop count. | 4756 | * Returns a negative value on failure, else wait loop count. |
4757 | */ | 4757 | */ |
4758 | static int | 4758 | static int |
4759 | WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag) | 4759 | WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag) |
4760 | { | 4760 | { |
4761 | int cntdn; | 4761 | int cntdn; |
4762 | int count = 0; | 4762 | int count = 0; |
4763 | u32 intstat=0; | 4763 | u32 intstat=0; |
4764 | 4764 | ||
4765 | cntdn = 1000 * howlong; | 4765 | cntdn = 1000 * howlong; |
4766 | if (sleepFlag == CAN_SLEEP) { | 4766 | if (sleepFlag == CAN_SLEEP) { |
4767 | while (--cntdn) { | 4767 | while (--cntdn) { |
4768 | intstat = CHIPREG_READ32(&ioc->chip->IntStatus); | 4768 | intstat = CHIPREG_READ32(&ioc->chip->IntStatus); |
4769 | if (intstat & MPI_HIS_DOORBELL_INTERRUPT) | 4769 | if (intstat & MPI_HIS_DOORBELL_INTERRUPT) |
4770 | break; | 4770 | break; |
4771 | msleep(1); | 4771 | msleep(1); |
4772 | count++; | 4772 | count++; |
4773 | } | 4773 | } |
4774 | } else { | 4774 | } else { |
4775 | while (--cntdn) { | 4775 | while (--cntdn) { |
4776 | intstat = CHIPREG_READ32(&ioc->chip->IntStatus); | 4776 | intstat = CHIPREG_READ32(&ioc->chip->IntStatus); |
4777 | if (intstat & MPI_HIS_DOORBELL_INTERRUPT) | 4777 | if (intstat & MPI_HIS_DOORBELL_INTERRUPT) |
4778 | break; | 4778 | break; |
4779 | udelay (1000); | 4779 | udelay (1000); |
4780 | count++; | 4780 | count++; |
4781 | } | 4781 | } |
4782 | } | 4782 | } |
4783 | 4783 | ||
4784 | if (cntdn) { | 4784 | if (cntdn) { |
4785 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n", | 4785 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n", |
4786 | ioc->name, count, howlong)); | 4786 | ioc->name, count, howlong)); |
4787 | return count; | 4787 | return count; |
4788 | } | 4788 | } |
4789 | 4789 | ||
4790 | printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n", | 4790 | printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n", |
4791 | ioc->name, count, intstat); | 4791 | ioc->name, count, intstat); |
4792 | return -1; | 4792 | return -1; |
4793 | } | 4793 | } |
4794 | 4794 | ||
4795 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 4795 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
4796 | /** | 4796 | /** |
4797 | * WaitForDoorbellReply - Wait for and capture an IOC handshake reply. | 4797 | * WaitForDoorbellReply - Wait for and capture an IOC handshake reply. |
4798 | * @ioc: Pointer to MPT_ADAPTER structure | 4798 | * @ioc: Pointer to MPT_ADAPTER structure |
4799 | * @howlong: How long to wait (in seconds) | 4799 | * @howlong: How long to wait (in seconds) |
4800 | * @sleepFlag: Specifies whether the process can sleep | 4800 | * @sleepFlag: Specifies whether the process can sleep |
4801 | * | 4801 | * |
4802 | * This routine polls the IOC for a handshake reply, 16 bits at a time. | 4802 | * This routine polls the IOC for a handshake reply, 16 bits at a time. |
4803 | * Reply is cached to IOC private area large enough to hold a maximum | 4803 | * Reply is cached to IOC private area large enough to hold a maximum |
4804 | * of 128 bytes of reply data. | 4804 | * of 128 bytes of reply data. |
4805 | * | 4805 | * |
4806 | * Returns a negative value on failure, else size of reply in WORDS. | 4806 | * Returns a negative value on failure, else size of reply in WORDS. |
4807 | */ | 4807 | */ |
4808 | static int | 4808 | static int |
4809 | WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag) | 4809 | WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag) |
4810 | { | 4810 | { |
4811 | int u16cnt = 0; | 4811 | int u16cnt = 0; |
4812 | int failcnt = 0; | 4812 | int failcnt = 0; |
4813 | int t; | 4813 | int t; |
4814 | u16 *hs_reply = ioc->hs_reply; | 4814 | u16 *hs_reply = ioc->hs_reply; |
4815 | volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply; | 4815 | volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply; |
4816 | u16 hword; | 4816 | u16 hword; |
4817 | 4817 | ||
4818 | hs_reply[0] = hs_reply[1] = hs_reply[7] = 0; | 4818 | hs_reply[0] = hs_reply[1] = hs_reply[7] = 0; |
4819 | 4819 | ||
4820 | /* | 4820 | /* |
4821 | * Get first two u16's so we can look at IOC's intended reply MsgLength | 4821 | * Get first two u16's so we can look at IOC's intended reply MsgLength |
4822 | */ | 4822 | */ |
4823 | u16cnt=0; | 4823 | u16cnt=0; |
4824 | if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) { | 4824 | if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) { |
4825 | failcnt++; | 4825 | failcnt++; |
4826 | } else { | 4826 | } else { |
4827 | hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); | 4827 | hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); |
4828 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); | 4828 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); |
4829 | if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) | 4829 | if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) |
4830 | failcnt++; | 4830 | failcnt++; |
4831 | else { | 4831 | else { |
4832 | hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); | 4832 | hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); |
4833 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); | 4833 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); |
4834 | } | 4834 | } |
4835 | } | 4835 | } |
4836 | 4836 | ||
4837 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n", | 4837 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n", |
4838 | ioc->name, t, le32_to_cpu(*(u32 *)hs_reply), | 4838 | ioc->name, t, le32_to_cpu(*(u32 *)hs_reply), |
4839 | failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); | 4839 | failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); |
4840 | 4840 | ||
4841 | /* | 4841 | /* |
4842 | * If no error (and IOC said MsgLength is > 0), piece together | 4842 | * If no error (and IOC said MsgLength is > 0), piece together |
4843 | * reply 16 bits at a time. | 4843 | * reply 16 bits at a time. |
4844 | */ | 4844 | */ |
4845 | for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) { | 4845 | for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) { |
4846 | if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) | 4846 | if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) |
4847 | failcnt++; | 4847 | failcnt++; |
4848 | hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); | 4848 | hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); |
4849 | /* don't overflow our IOC hs_reply[] buffer! */ | 4849 | /* don't overflow our IOC hs_reply[] buffer! */ |
4850 | if (u16cnt < ARRAY_SIZE(ioc->hs_reply)) | 4850 | if (u16cnt < ARRAY_SIZE(ioc->hs_reply)) |
4851 | hs_reply[u16cnt] = hword; | 4851 | hs_reply[u16cnt] = hword; |
4852 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); | 4852 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); |
4853 | } | 4853 | } |
4854 | 4854 | ||
4855 | if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) | 4855 | if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) |
4856 | failcnt++; | 4856 | failcnt++; |
4857 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); | 4857 | CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); |
4858 | 4858 | ||
4859 | if (failcnt) { | 4859 | if (failcnt) { |
4860 | printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n", | 4860 | printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n", |
4861 | ioc->name); | 4861 | ioc->name); |
4862 | return -failcnt; | 4862 | return -failcnt; |
4863 | } | 4863 | } |
4864 | #if 0 | 4864 | #if 0 |
4865 | else if (u16cnt != (2 * mptReply->MsgLength)) { | 4865 | else if (u16cnt != (2 * mptReply->MsgLength)) { |
4866 | return -101; | 4866 | return -101; |
4867 | } | 4867 | } |
4868 | else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { | 4868 | else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { |
4869 | return -102; | 4869 | return -102; |
4870 | } | 4870 | } |
4871 | #endif | 4871 | #endif |
4872 | 4872 | ||
4873 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name)); | 4873 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name)); |
4874 | DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply); | 4874 | DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply); |
4875 | 4875 | ||
4876 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n", | 4876 | dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n", |
4877 | ioc->name, t, u16cnt/2)); | 4877 | ioc->name, t, u16cnt/2)); |
4878 | return u16cnt/2; | 4878 | return u16cnt/2; |
4879 | } | 4879 | } |
4880 | 4880 | ||
4881 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 4881 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
4882 | /** | 4882 | /** |
4883 | * GetLanConfigPages - Fetch LANConfig pages. | 4883 | * GetLanConfigPages - Fetch LANConfig pages. |
4884 | * @ioc: Pointer to MPT_ADAPTER structure | 4884 | * @ioc: Pointer to MPT_ADAPTER structure |
4885 | * | 4885 | * |
4886 | * Return: 0 for success | 4886 | * Return: 0 for success |
4887 | * -ENOMEM if no memory available | 4887 | * -ENOMEM if no memory available |
4888 | * -EPERM if not allowed due to ISR context | 4888 | * -EPERM if not allowed due to ISR context |
4889 | * -EAGAIN if no msg frames currently available | 4889 | * -EAGAIN if no msg frames currently available |
4890 | * -EFAULT for non-successful reply or no reply (timeout) | 4890 | * -EFAULT for non-successful reply or no reply (timeout) |
4891 | */ | 4891 | */ |
4892 | static int | 4892 | static int |
4893 | GetLanConfigPages(MPT_ADAPTER *ioc) | 4893 | GetLanConfigPages(MPT_ADAPTER *ioc) |
4894 | { | 4894 | { |
4895 | ConfigPageHeader_t hdr; | 4895 | ConfigPageHeader_t hdr; |
4896 | CONFIGPARMS cfg; | 4896 | CONFIGPARMS cfg; |
4897 | LANPage0_t *ppage0_alloc; | 4897 | LANPage0_t *ppage0_alloc; |
4898 | dma_addr_t page0_dma; | 4898 | dma_addr_t page0_dma; |
4899 | LANPage1_t *ppage1_alloc; | 4899 | LANPage1_t *ppage1_alloc; |
4900 | dma_addr_t page1_dma; | 4900 | dma_addr_t page1_dma; |
4901 | int rc = 0; | 4901 | int rc = 0; |
4902 | int data_sz; | 4902 | int data_sz; |
4903 | int copy_sz; | 4903 | int copy_sz; |
4904 | 4904 | ||
4905 | /* Get LAN Page 0 header */ | 4905 | /* Get LAN Page 0 header */ |
4906 | hdr.PageVersion = 0; | 4906 | hdr.PageVersion = 0; |
4907 | hdr.PageLength = 0; | 4907 | hdr.PageLength = 0; |
4908 | hdr.PageNumber = 0; | 4908 | hdr.PageNumber = 0; |
4909 | hdr.PageType = MPI_CONFIG_PAGETYPE_LAN; | 4909 | hdr.PageType = MPI_CONFIG_PAGETYPE_LAN; |
4910 | cfg.cfghdr.hdr = &hdr; | 4910 | cfg.cfghdr.hdr = &hdr; |
4911 | cfg.physAddr = -1; | 4911 | cfg.physAddr = -1; |
4912 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 4912 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
4913 | cfg.dir = 0; | 4913 | cfg.dir = 0; |
4914 | cfg.pageAddr = 0; | 4914 | cfg.pageAddr = 0; |
4915 | cfg.timeout = 0; | 4915 | cfg.timeout = 0; |
4916 | 4916 | ||
4917 | if ((rc = mpt_config(ioc, &cfg)) != 0) | 4917 | if ((rc = mpt_config(ioc, &cfg)) != 0) |
4918 | return rc; | 4918 | return rc; |
4919 | 4919 | ||
4920 | if (hdr.PageLength > 0) { | 4920 | if (hdr.PageLength > 0) { |
4921 | data_sz = hdr.PageLength * 4; | 4921 | data_sz = hdr.PageLength * 4; |
4922 | ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma); | 4922 | ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma); |
4923 | rc = -ENOMEM; | 4923 | rc = -ENOMEM; |
4924 | if (ppage0_alloc) { | 4924 | if (ppage0_alloc) { |
4925 | memset((u8 *)ppage0_alloc, 0, data_sz); | 4925 | memset((u8 *)ppage0_alloc, 0, data_sz); |
4926 | cfg.physAddr = page0_dma; | 4926 | cfg.physAddr = page0_dma; |
4927 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | 4927 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
4928 | 4928 | ||
4929 | if ((rc = mpt_config(ioc, &cfg)) == 0) { | 4929 | if ((rc = mpt_config(ioc, &cfg)) == 0) { |
4930 | /* save the data */ | 4930 | /* save the data */ |
4931 | copy_sz = min_t(int, sizeof(LANPage0_t), data_sz); | 4931 | copy_sz = min_t(int, sizeof(LANPage0_t), data_sz); |
4932 | memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz); | 4932 | memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz); |
4933 | 4933 | ||
4934 | } | 4934 | } |
4935 | 4935 | ||
4936 | pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma); | 4936 | pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma); |
4937 | 4937 | ||
4938 | /* FIXME! | 4938 | /* FIXME! |
4939 | * Normalize endianness of structure data, | 4939 | * Normalize endianness of structure data, |
4940 | * by byte-swapping all > 1 byte fields! | 4940 | * by byte-swapping all > 1 byte fields! |
4941 | */ | 4941 | */ |
4942 | 4942 | ||
4943 | } | 4943 | } |
4944 | 4944 | ||
4945 | if (rc) | 4945 | if (rc) |
4946 | return rc; | 4946 | return rc; |
4947 | } | 4947 | } |
4948 | 4948 | ||
4949 | /* Get LAN Page 1 header */ | 4949 | /* Get LAN Page 1 header */ |
4950 | hdr.PageVersion = 0; | 4950 | hdr.PageVersion = 0; |
4951 | hdr.PageLength = 0; | 4951 | hdr.PageLength = 0; |
4952 | hdr.PageNumber = 1; | 4952 | hdr.PageNumber = 1; |
4953 | hdr.PageType = MPI_CONFIG_PAGETYPE_LAN; | 4953 | hdr.PageType = MPI_CONFIG_PAGETYPE_LAN; |
4954 | cfg.cfghdr.hdr = &hdr; | 4954 | cfg.cfghdr.hdr = &hdr; |
4955 | cfg.physAddr = -1; | 4955 | cfg.physAddr = -1; |
4956 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 4956 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
4957 | cfg.dir = 0; | 4957 | cfg.dir = 0; |
4958 | cfg.pageAddr = 0; | 4958 | cfg.pageAddr = 0; |
4959 | 4959 | ||
4960 | if ((rc = mpt_config(ioc, &cfg)) != 0) | 4960 | if ((rc = mpt_config(ioc, &cfg)) != 0) |
4961 | return rc; | 4961 | return rc; |
4962 | 4962 | ||
4963 | if (hdr.PageLength == 0) | 4963 | if (hdr.PageLength == 0) |
4964 | return 0; | 4964 | return 0; |
4965 | 4965 | ||
4966 | data_sz = hdr.PageLength * 4; | 4966 | data_sz = hdr.PageLength * 4; |
4967 | rc = -ENOMEM; | 4967 | rc = -ENOMEM; |
4968 | ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma); | 4968 | ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma); |
4969 | if (ppage1_alloc) { | 4969 | if (ppage1_alloc) { |
4970 | memset((u8 *)ppage1_alloc, 0, data_sz); | 4970 | memset((u8 *)ppage1_alloc, 0, data_sz); |
4971 | cfg.physAddr = page1_dma; | 4971 | cfg.physAddr = page1_dma; |
4972 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | 4972 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
4973 | 4973 | ||
4974 | if ((rc = mpt_config(ioc, &cfg)) == 0) { | 4974 | if ((rc = mpt_config(ioc, &cfg)) == 0) { |
4975 | /* save the data */ | 4975 | /* save the data */ |
4976 | copy_sz = min_t(int, sizeof(LANPage1_t), data_sz); | 4976 | copy_sz = min_t(int, sizeof(LANPage1_t), data_sz); |
4977 | memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz); | 4977 | memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz); |
4978 | } | 4978 | } |
4979 | 4979 | ||
4980 | pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma); | 4980 | pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma); |
4981 | 4981 | ||
4982 | /* FIXME! | 4982 | /* FIXME! |
4983 | * Normalize endianness of structure data, | 4983 | * Normalize endianness of structure data, |
4984 | * by byte-swapping all > 1 byte fields! | 4984 | * by byte-swapping all > 1 byte fields! |
4985 | */ | 4985 | */ |
4986 | 4986 | ||
4987 | } | 4987 | } |
4988 | 4988 | ||
4989 | return rc; | 4989 | return rc; |
4990 | } | 4990 | } |
4991 | 4991 | ||
4992 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 4992 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
4993 | /** | 4993 | /** |
4994 | * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table | 4994 | * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table |
4995 | * @ioc: Pointer to MPT_ADAPTER structure | 4995 | * @ioc: Pointer to MPT_ADAPTER structure |
4996 | * @persist_opcode: see below | 4996 | * @persist_opcode: see below |
4997 | * | 4997 | * |
4998 | * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for | 4998 | * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for |
4999 | * devices not currently present. | 4999 | * devices not currently present. |
5000 | * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings | 5000 | * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings |
5001 | * | 5001 | * |
5002 | * NOTE: Don't use not this function during interrupt time. | 5002 | * NOTE: Don't use not this function during interrupt time. |
5003 | * | 5003 | * |
5004 | * Returns 0 for success, non-zero error | 5004 | * Returns 0 for success, non-zero error |
5005 | */ | 5005 | */ |
5006 | 5006 | ||
5007 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 5007 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
5008 | int | 5008 | int |
5009 | mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) | 5009 | mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) |
5010 | { | 5010 | { |
5011 | SasIoUnitControlRequest_t *sasIoUnitCntrReq; | 5011 | SasIoUnitControlRequest_t *sasIoUnitCntrReq; |
5012 | SasIoUnitControlReply_t *sasIoUnitCntrReply; | 5012 | SasIoUnitControlReply_t *sasIoUnitCntrReply; |
5013 | MPT_FRAME_HDR *mf = NULL; | 5013 | MPT_FRAME_HDR *mf = NULL; |
5014 | MPIHeader_t *mpi_hdr; | 5014 | MPIHeader_t *mpi_hdr; |
5015 | int ret = 0; | 5015 | int ret = 0; |
5016 | unsigned long timeleft; | 5016 | unsigned long timeleft; |
5017 | 5017 | ||
5018 | mutex_lock(&ioc->mptbase_cmds.mutex); | 5018 | mutex_lock(&ioc->mptbase_cmds.mutex); |
5019 | 5019 | ||
5020 | /* init the internal cmd struct */ | 5020 | /* init the internal cmd struct */ |
5021 | memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE); | 5021 | memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE); |
5022 | INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status) | 5022 | INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status) |
5023 | 5023 | ||
5024 | /* insure garbage is not sent to fw */ | 5024 | /* insure garbage is not sent to fw */ |
5025 | switch(persist_opcode) { | 5025 | switch(persist_opcode) { |
5026 | 5026 | ||
5027 | case MPI_SAS_OP_CLEAR_NOT_PRESENT: | 5027 | case MPI_SAS_OP_CLEAR_NOT_PRESENT: |
5028 | case MPI_SAS_OP_CLEAR_ALL_PERSISTENT: | 5028 | case MPI_SAS_OP_CLEAR_ALL_PERSISTENT: |
5029 | break; | 5029 | break; |
5030 | 5030 | ||
5031 | default: | 5031 | default: |
5032 | ret = -1; | 5032 | ret = -1; |
5033 | goto out; | 5033 | goto out; |
5034 | } | 5034 | } |
5035 | 5035 | ||
5036 | printk(KERN_DEBUG "%s: persist_opcode=%x\n", | 5036 | printk(KERN_DEBUG "%s: persist_opcode=%x\n", |
5037 | __func__, persist_opcode); | 5037 | __func__, persist_opcode); |
5038 | 5038 | ||
5039 | /* Get a MF for this command. | 5039 | /* Get a MF for this command. |
5040 | */ | 5040 | */ |
5041 | if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { | 5041 | if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { |
5042 | printk(KERN_DEBUG "%s: no msg frames!\n", __func__); | 5042 | printk(KERN_DEBUG "%s: no msg frames!\n", __func__); |
5043 | ret = -1; | 5043 | ret = -1; |
5044 | goto out; | 5044 | goto out; |
5045 | } | 5045 | } |
5046 | 5046 | ||
5047 | mpi_hdr = (MPIHeader_t *) mf; | 5047 | mpi_hdr = (MPIHeader_t *) mf; |
5048 | sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf; | 5048 | sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf; |
5049 | memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t)); | 5049 | memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t)); |
5050 | sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; | 5050 | sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; |
5051 | sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext; | 5051 | sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext; |
5052 | sasIoUnitCntrReq->Operation = persist_opcode; | 5052 | sasIoUnitCntrReq->Operation = persist_opcode; |
5053 | 5053 | ||
5054 | mpt_put_msg_frame(mpt_base_index, ioc, mf); | 5054 | mpt_put_msg_frame(mpt_base_index, ioc, mf); |
5055 | timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ); | 5055 | timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ); |
5056 | if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { | 5056 | if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { |
5057 | ret = -ETIME; | 5057 | ret = -ETIME; |
5058 | printk(KERN_DEBUG "%s: failed\n", __func__); | 5058 | printk(KERN_DEBUG "%s: failed\n", __func__); |
5059 | if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) | 5059 | if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) |
5060 | goto out; | 5060 | goto out; |
5061 | if (!timeleft) { | 5061 | if (!timeleft) { |
5062 | printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n", | 5062 | printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n", |
5063 | ioc->name, __func__); | 5063 | ioc->name, __func__); |
5064 | mpt_HardResetHandler(ioc, CAN_SLEEP); | 5064 | mpt_HardResetHandler(ioc, CAN_SLEEP); |
5065 | mpt_free_msg_frame(ioc, mf); | 5065 | mpt_free_msg_frame(ioc, mf); |
5066 | } | 5066 | } |
5067 | goto out; | 5067 | goto out; |
5068 | } | 5068 | } |
5069 | 5069 | ||
5070 | if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { | 5070 | if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { |
5071 | ret = -1; | 5071 | ret = -1; |
5072 | goto out; | 5072 | goto out; |
5073 | } | 5073 | } |
5074 | 5074 | ||
5075 | sasIoUnitCntrReply = | 5075 | sasIoUnitCntrReply = |
5076 | (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply; | 5076 | (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply; |
5077 | if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) { | 5077 | if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) { |
5078 | printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", | 5078 | printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", |
5079 | __func__, sasIoUnitCntrReply->IOCStatus, | 5079 | __func__, sasIoUnitCntrReply->IOCStatus, |
5080 | sasIoUnitCntrReply->IOCLogInfo); | 5080 | sasIoUnitCntrReply->IOCLogInfo); |
5081 | printk(KERN_DEBUG "%s: failed\n", __func__); | 5081 | printk(KERN_DEBUG "%s: failed\n", __func__); |
5082 | ret = -1; | 5082 | ret = -1; |
5083 | } else | 5083 | } else |
5084 | printk(KERN_DEBUG "%s: success\n", __func__); | 5084 | printk(KERN_DEBUG "%s: success\n", __func__); |
5085 | out: | 5085 | out: |
5086 | 5086 | ||
5087 | CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) | 5087 | CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) |
5088 | mutex_unlock(&ioc->mptbase_cmds.mutex); | 5088 | mutex_unlock(&ioc->mptbase_cmds.mutex); |
5089 | return ret; | 5089 | return ret; |
5090 | } | 5090 | } |
5091 | 5091 | ||
5092 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 5092 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
5093 | 5093 | ||
5094 | static void | 5094 | static void |
5095 | mptbase_raid_process_event_data(MPT_ADAPTER *ioc, | 5095 | mptbase_raid_process_event_data(MPT_ADAPTER *ioc, |
5096 | MpiEventDataRaid_t * pRaidEventData) | 5096 | MpiEventDataRaid_t * pRaidEventData) |
5097 | { | 5097 | { |
5098 | int volume; | 5098 | int volume; |
5099 | int reason; | 5099 | int reason; |
5100 | int disk; | 5100 | int disk; |
5101 | int status; | 5101 | int status; |
5102 | int flags; | 5102 | int flags; |
5103 | int state; | 5103 | int state; |
5104 | 5104 | ||
5105 | volume = pRaidEventData->VolumeID; | 5105 | volume = pRaidEventData->VolumeID; |
5106 | reason = pRaidEventData->ReasonCode; | 5106 | reason = pRaidEventData->ReasonCode; |
5107 | disk = pRaidEventData->PhysDiskNum; | 5107 | disk = pRaidEventData->PhysDiskNum; |
5108 | status = le32_to_cpu(pRaidEventData->SettingsStatus); | 5108 | status = le32_to_cpu(pRaidEventData->SettingsStatus); |
5109 | flags = (status >> 0) & 0xff; | 5109 | flags = (status >> 0) & 0xff; |
5110 | state = (status >> 8) & 0xff; | 5110 | state = (status >> 8) & 0xff; |
5111 | 5111 | ||
5112 | if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) { | 5112 | if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) { |
5113 | return; | 5113 | return; |
5114 | } | 5114 | } |
5115 | 5115 | ||
5116 | if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED && | 5116 | if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED && |
5117 | reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) || | 5117 | reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) || |
5118 | (reason == MPI_EVENT_RAID_RC_SMART_DATA)) { | 5118 | (reason == MPI_EVENT_RAID_RC_SMART_DATA)) { |
5119 | printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n", | 5119 | printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n", |
5120 | ioc->name, disk, volume); | 5120 | ioc->name, disk, volume); |
5121 | } else { | 5121 | } else { |
5122 | printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n", | 5122 | printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n", |
5123 | ioc->name, volume); | 5123 | ioc->name, volume); |
5124 | } | 5124 | } |
5125 | 5125 | ||
5126 | switch(reason) { | 5126 | switch(reason) { |
5127 | case MPI_EVENT_RAID_RC_VOLUME_CREATED: | 5127 | case MPI_EVENT_RAID_RC_VOLUME_CREATED: |
5128 | printk(MYIOC_s_INFO_FMT " volume has been created\n", | 5128 | printk(MYIOC_s_INFO_FMT " volume has been created\n", |
5129 | ioc->name); | 5129 | ioc->name); |
5130 | break; | 5130 | break; |
5131 | 5131 | ||
5132 | case MPI_EVENT_RAID_RC_VOLUME_DELETED: | 5132 | case MPI_EVENT_RAID_RC_VOLUME_DELETED: |
5133 | 5133 | ||
5134 | printk(MYIOC_s_INFO_FMT " volume has been deleted\n", | 5134 | printk(MYIOC_s_INFO_FMT " volume has been deleted\n", |
5135 | ioc->name); | 5135 | ioc->name); |
5136 | break; | 5136 | break; |
5137 | 5137 | ||
5138 | case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED: | 5138 | case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED: |
5139 | printk(MYIOC_s_INFO_FMT " volume settings have been changed\n", | 5139 | printk(MYIOC_s_INFO_FMT " volume settings have been changed\n", |
5140 | ioc->name); | 5140 | ioc->name); |
5141 | break; | 5141 | break; |
5142 | 5142 | ||
5143 | case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: | 5143 | case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: |
5144 | printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n", | 5144 | printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n", |
5145 | ioc->name, | 5145 | ioc->name, |
5146 | state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL | 5146 | state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL |
5147 | ? "optimal" | 5147 | ? "optimal" |
5148 | : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED | 5148 | : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED |
5149 | ? "degraded" | 5149 | ? "degraded" |
5150 | : state == MPI_RAIDVOL0_STATUS_STATE_FAILED | 5150 | : state == MPI_RAIDVOL0_STATUS_STATE_FAILED |
5151 | ? "failed" | 5151 | ? "failed" |
5152 | : "state unknown", | 5152 | : "state unknown", |
5153 | flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED | 5153 | flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED |
5154 | ? ", enabled" : "", | 5154 | ? ", enabled" : "", |
5155 | flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED | 5155 | flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED |
5156 | ? ", quiesced" : "", | 5156 | ? ", quiesced" : "", |
5157 | flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS | 5157 | flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS |
5158 | ? ", resync in progress" : "" ); | 5158 | ? ", resync in progress" : "" ); |
5159 | break; | 5159 | break; |
5160 | 5160 | ||
5161 | case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED: | 5161 | case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED: |
5162 | printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n", | 5162 | printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n", |
5163 | ioc->name, disk); | 5163 | ioc->name, disk); |
5164 | break; | 5164 | break; |
5165 | 5165 | ||
5166 | case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: | 5166 | case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: |
5167 | printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n", | 5167 | printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n", |
5168 | ioc->name); | 5168 | ioc->name); |
5169 | break; | 5169 | break; |
5170 | 5170 | ||
5171 | case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: | 5171 | case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: |
5172 | printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n", | 5172 | printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n", |
5173 | ioc->name); | 5173 | ioc->name); |
5174 | break; | 5174 | break; |
5175 | 5175 | ||
5176 | case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED: | 5176 | case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED: |
5177 | printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n", | 5177 | printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n", |
5178 | ioc->name); | 5178 | ioc->name); |
5179 | break; | 5179 | break; |
5180 | 5180 | ||
5181 | case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: | 5181 | case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: |
5182 | printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n", | 5182 | printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n", |
5183 | ioc->name, | 5183 | ioc->name, |
5184 | state == MPI_PHYSDISK0_STATUS_ONLINE | 5184 | state == MPI_PHYSDISK0_STATUS_ONLINE |
5185 | ? "online" | 5185 | ? "online" |
5186 | : state == MPI_PHYSDISK0_STATUS_MISSING | 5186 | : state == MPI_PHYSDISK0_STATUS_MISSING |
5187 | ? "missing" | 5187 | ? "missing" |
5188 | : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE | 5188 | : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE |
5189 | ? "not compatible" | 5189 | ? "not compatible" |
5190 | : state == MPI_PHYSDISK0_STATUS_FAILED | 5190 | : state == MPI_PHYSDISK0_STATUS_FAILED |
5191 | ? "failed" | 5191 | ? "failed" |
5192 | : state == MPI_PHYSDISK0_STATUS_INITIALIZING | 5192 | : state == MPI_PHYSDISK0_STATUS_INITIALIZING |
5193 | ? "initializing" | 5193 | ? "initializing" |
5194 | : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED | 5194 | : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED |
5195 | ? "offline requested" | 5195 | ? "offline requested" |
5196 | : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED | 5196 | : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED |
5197 | ? "failed requested" | 5197 | ? "failed requested" |
5198 | : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE | 5198 | : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE |
5199 | ? "offline" | 5199 | ? "offline" |
5200 | : "state unknown", | 5200 | : "state unknown", |
5201 | flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC | 5201 | flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC |
5202 | ? ", out of sync" : "", | 5202 | ? ", out of sync" : "", |
5203 | flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED | 5203 | flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED |
5204 | ? ", quiesced" : "" ); | 5204 | ? ", quiesced" : "" ); |
5205 | break; | 5205 | break; |
5206 | 5206 | ||
5207 | case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED: | 5207 | case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED: |
5208 | printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n", | 5208 | printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n", |
5209 | ioc->name, disk); | 5209 | ioc->name, disk); |
5210 | break; | 5210 | break; |
5211 | 5211 | ||
5212 | case MPI_EVENT_RAID_RC_SMART_DATA: | 5212 | case MPI_EVENT_RAID_RC_SMART_DATA: |
5213 | printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n", | 5213 | printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n", |
5214 | ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ); | 5214 | ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ); |
5215 | break; | 5215 | break; |
5216 | 5216 | ||
5217 | case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED: | 5217 | case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED: |
5218 | printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n", | 5218 | printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n", |
5219 | ioc->name, disk); | 5219 | ioc->name, disk); |
5220 | break; | 5220 | break; |
5221 | } | 5221 | } |
5222 | } | 5222 | } |
5223 | 5223 | ||
5224 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 5224 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
5225 | /** | 5225 | /** |
5226 | * GetIoUnitPage2 - Retrieve BIOS version and boot order information. | 5226 | * GetIoUnitPage2 - Retrieve BIOS version and boot order information. |
5227 | * @ioc: Pointer to MPT_ADAPTER structure | 5227 | * @ioc: Pointer to MPT_ADAPTER structure |
5228 | * | 5228 | * |
5229 | * Returns: 0 for success | 5229 | * Returns: 0 for success |
5230 | * -ENOMEM if no memory available | 5230 | * -ENOMEM if no memory available |
5231 | * -EPERM if not allowed due to ISR context | 5231 | * -EPERM if not allowed due to ISR context |
5232 | * -EAGAIN if no msg frames currently available | 5232 | * -EAGAIN if no msg frames currently available |
5233 | * -EFAULT for non-successful reply or no reply (timeout) | 5233 | * -EFAULT for non-successful reply or no reply (timeout) |
5234 | */ | 5234 | */ |
5235 | static int | 5235 | static int |
5236 | GetIoUnitPage2(MPT_ADAPTER *ioc) | 5236 | GetIoUnitPage2(MPT_ADAPTER *ioc) |
5237 | { | 5237 | { |
5238 | ConfigPageHeader_t hdr; | 5238 | ConfigPageHeader_t hdr; |
5239 | CONFIGPARMS cfg; | 5239 | CONFIGPARMS cfg; |
5240 | IOUnitPage2_t *ppage_alloc; | 5240 | IOUnitPage2_t *ppage_alloc; |
5241 | dma_addr_t page_dma; | 5241 | dma_addr_t page_dma; |
5242 | int data_sz; | 5242 | int data_sz; |
5243 | int rc; | 5243 | int rc; |
5244 | 5244 | ||
5245 | /* Get the page header */ | 5245 | /* Get the page header */ |
5246 | hdr.PageVersion = 0; | 5246 | hdr.PageVersion = 0; |
5247 | hdr.PageLength = 0; | 5247 | hdr.PageLength = 0; |
5248 | hdr.PageNumber = 2; | 5248 | hdr.PageNumber = 2; |
5249 | hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT; | 5249 | hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT; |
5250 | cfg.cfghdr.hdr = &hdr; | 5250 | cfg.cfghdr.hdr = &hdr; |
5251 | cfg.physAddr = -1; | 5251 | cfg.physAddr = -1; |
5252 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 5252 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
5253 | cfg.dir = 0; | 5253 | cfg.dir = 0; |
5254 | cfg.pageAddr = 0; | 5254 | cfg.pageAddr = 0; |
5255 | cfg.timeout = 0; | 5255 | cfg.timeout = 0; |
5256 | 5256 | ||
5257 | if ((rc = mpt_config(ioc, &cfg)) != 0) | 5257 | if ((rc = mpt_config(ioc, &cfg)) != 0) |
5258 | return rc; | 5258 | return rc; |
5259 | 5259 | ||
5260 | if (hdr.PageLength == 0) | 5260 | if (hdr.PageLength == 0) |
5261 | return 0; | 5261 | return 0; |
5262 | 5262 | ||
5263 | /* Read the config page */ | 5263 | /* Read the config page */ |
5264 | data_sz = hdr.PageLength * 4; | 5264 | data_sz = hdr.PageLength * 4; |
5265 | rc = -ENOMEM; | 5265 | rc = -ENOMEM; |
5266 | ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma); | 5266 | ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma); |
5267 | if (ppage_alloc) { | 5267 | if (ppage_alloc) { |
5268 | memset((u8 *)ppage_alloc, 0, data_sz); | 5268 | memset((u8 *)ppage_alloc, 0, data_sz); |
5269 | cfg.physAddr = page_dma; | 5269 | cfg.physAddr = page_dma; |
5270 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | 5270 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
5271 | 5271 | ||
5272 | /* If Good, save data */ | 5272 | /* If Good, save data */ |
5273 | if ((rc = mpt_config(ioc, &cfg)) == 0) | 5273 | if ((rc = mpt_config(ioc, &cfg)) == 0) |
5274 | ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion); | 5274 | ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion); |
5275 | 5275 | ||
5276 | pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma); | 5276 | pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma); |
5277 | } | 5277 | } |
5278 | 5278 | ||
5279 | return rc; | 5279 | return rc; |
5280 | } | 5280 | } |
5281 | 5281 | ||
5282 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 5282 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
5283 | /** | 5283 | /** |
5284 | * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2 | 5284 | * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2 |
5285 | * @ioc: Pointer to a Adapter Strucutre | 5285 | * @ioc: Pointer to a Adapter Strucutre |
5286 | * @portnum: IOC port number | 5286 | * @portnum: IOC port number |
5287 | * | 5287 | * |
5288 | * Return: -EFAULT if read of config page header fails | 5288 | * Return: -EFAULT if read of config page header fails |
5289 | * or if no nvram | 5289 | * or if no nvram |
5290 | * If read of SCSI Port Page 0 fails, | 5290 | * If read of SCSI Port Page 0 fails, |
5291 | * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF) | 5291 | * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF) |
5292 | * Adapter settings: async, narrow | 5292 | * Adapter settings: async, narrow |
5293 | * Return 1 | 5293 | * Return 1 |
5294 | * If read of SCSI Port Page 2 fails, | 5294 | * If read of SCSI Port Page 2 fails, |
5295 | * Adapter settings valid | 5295 | * Adapter settings valid |
5296 | * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF) | 5296 | * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF) |
5297 | * Return 1 | 5297 | * Return 1 |
5298 | * Else | 5298 | * Else |
5299 | * Both valid | 5299 | * Both valid |
5300 | * Return 0 | 5300 | * Return 0 |
5301 | * CHECK - what type of locking mechanisms should be used???? | 5301 | * CHECK - what type of locking mechanisms should be used???? |
5302 | */ | 5302 | */ |
5303 | static int | 5303 | static int |
5304 | mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) | 5304 | mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) |
5305 | { | 5305 | { |
5306 | u8 *pbuf; | 5306 | u8 *pbuf; |
5307 | dma_addr_t buf_dma; | 5307 | dma_addr_t buf_dma; |
5308 | CONFIGPARMS cfg; | 5308 | CONFIGPARMS cfg; |
5309 | ConfigPageHeader_t header; | 5309 | ConfigPageHeader_t header; |
5310 | int ii; | 5310 | int ii; |
5311 | int data, rc = 0; | 5311 | int data, rc = 0; |
5312 | 5312 | ||
5313 | /* Allocate memory | 5313 | /* Allocate memory |
5314 | */ | 5314 | */ |
5315 | if (!ioc->spi_data.nvram) { | 5315 | if (!ioc->spi_data.nvram) { |
5316 | int sz; | 5316 | int sz; |
5317 | u8 *mem; | 5317 | u8 *mem; |
5318 | sz = MPT_MAX_SCSI_DEVICES * sizeof(int); | 5318 | sz = MPT_MAX_SCSI_DEVICES * sizeof(int); |
5319 | mem = kmalloc(sz, GFP_ATOMIC); | 5319 | mem = kmalloc(sz, GFP_ATOMIC); |
5320 | if (mem == NULL) | 5320 | if (mem == NULL) |
5321 | return -EFAULT; | 5321 | return -EFAULT; |
5322 | 5322 | ||
5323 | ioc->spi_data.nvram = (int *) mem; | 5323 | ioc->spi_data.nvram = (int *) mem; |
5324 | 5324 | ||
5325 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n", | 5325 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n", |
5326 | ioc->name, ioc->spi_data.nvram, sz)); | 5326 | ioc->name, ioc->spi_data.nvram, sz)); |
5327 | } | 5327 | } |
5328 | 5328 | ||
5329 | /* Invalidate NVRAM information | 5329 | /* Invalidate NVRAM information |
5330 | */ | 5330 | */ |
5331 | for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { | 5331 | for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { |
5332 | ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID; | 5332 | ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID; |
5333 | } | 5333 | } |
5334 | 5334 | ||
5335 | /* Read SPP0 header, allocate memory, then read page. | 5335 | /* Read SPP0 header, allocate memory, then read page. |
5336 | */ | 5336 | */ |
5337 | header.PageVersion = 0; | 5337 | header.PageVersion = 0; |
5338 | header.PageLength = 0; | 5338 | header.PageLength = 0; |
5339 | header.PageNumber = 0; | 5339 | header.PageNumber = 0; |
5340 | header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT; | 5340 | header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT; |
5341 | cfg.cfghdr.hdr = &header; | 5341 | cfg.cfghdr.hdr = &header; |
5342 | cfg.physAddr = -1; | 5342 | cfg.physAddr = -1; |
5343 | cfg.pageAddr = portnum; | 5343 | cfg.pageAddr = portnum; |
5344 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 5344 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
5345 | cfg.dir = 0; | 5345 | cfg.dir = 0; |
5346 | cfg.timeout = 0; /* use default */ | 5346 | cfg.timeout = 0; /* use default */ |
5347 | if (mpt_config(ioc, &cfg) != 0) | 5347 | if (mpt_config(ioc, &cfg) != 0) |
5348 | return -EFAULT; | 5348 | return -EFAULT; |
5349 | 5349 | ||
5350 | if (header.PageLength > 0) { | 5350 | if (header.PageLength > 0) { |
5351 | pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma); | 5351 | pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma); |
5352 | if (pbuf) { | 5352 | if (pbuf) { |
5353 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | 5353 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
5354 | cfg.physAddr = buf_dma; | 5354 | cfg.physAddr = buf_dma; |
5355 | if (mpt_config(ioc, &cfg) != 0) { | 5355 | if (mpt_config(ioc, &cfg) != 0) { |
5356 | ioc->spi_data.maxBusWidth = MPT_NARROW; | 5356 | ioc->spi_data.maxBusWidth = MPT_NARROW; |
5357 | ioc->spi_data.maxSyncOffset = 0; | 5357 | ioc->spi_data.maxSyncOffset = 0; |
5358 | ioc->spi_data.minSyncFactor = MPT_ASYNC; | 5358 | ioc->spi_data.minSyncFactor = MPT_ASYNC; |
5359 | ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN; | 5359 | ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN; |
5360 | rc = 1; | 5360 | rc = 1; |
5361 | ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 5361 | ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
5362 | "Unable to read PortPage0 minSyncFactor=%x\n", | 5362 | "Unable to read PortPage0 minSyncFactor=%x\n", |
5363 | ioc->name, ioc->spi_data.minSyncFactor)); | 5363 | ioc->name, ioc->spi_data.minSyncFactor)); |
5364 | } else { | 5364 | } else { |
5365 | /* Save the Port Page 0 data | 5365 | /* Save the Port Page 0 data |
5366 | */ | 5366 | */ |
5367 | SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf; | 5367 | SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf; |
5368 | pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities); | 5368 | pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities); |
5369 | pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface); | 5369 | pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface); |
5370 | 5370 | ||
5371 | if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) { | 5371 | if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) { |
5372 | ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS; | 5372 | ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS; |
5373 | ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 5373 | ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
5374 | "noQas due to Capabilities=%x\n", | 5374 | "noQas due to Capabilities=%x\n", |
5375 | ioc->name, pPP0->Capabilities)); | 5375 | ioc->name, pPP0->Capabilities)); |
5376 | } | 5376 | } |
5377 | ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0; | 5377 | ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0; |
5378 | data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK; | 5378 | data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK; |
5379 | if (data) { | 5379 | if (data) { |
5380 | ioc->spi_data.maxSyncOffset = (u8) (data >> 16); | 5380 | ioc->spi_data.maxSyncOffset = (u8) (data >> 16); |
5381 | data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK; | 5381 | data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK; |
5382 | ioc->spi_data.minSyncFactor = (u8) (data >> 8); | 5382 | ioc->spi_data.minSyncFactor = (u8) (data >> 8); |
5383 | ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 5383 | ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
5384 | "PortPage0 minSyncFactor=%x\n", | 5384 | "PortPage0 minSyncFactor=%x\n", |
5385 | ioc->name, ioc->spi_data.minSyncFactor)); | 5385 | ioc->name, ioc->spi_data.minSyncFactor)); |
5386 | } else { | 5386 | } else { |
5387 | ioc->spi_data.maxSyncOffset = 0; | 5387 | ioc->spi_data.maxSyncOffset = 0; |
5388 | ioc->spi_data.minSyncFactor = MPT_ASYNC; | 5388 | ioc->spi_data.minSyncFactor = MPT_ASYNC; |
5389 | } | 5389 | } |
5390 | 5390 | ||
5391 | ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK; | 5391 | ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK; |
5392 | 5392 | ||
5393 | /* Update the minSyncFactor based on bus type. | 5393 | /* Update the minSyncFactor based on bus type. |
5394 | */ | 5394 | */ |
5395 | if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) || | 5395 | if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) || |
5396 | (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) { | 5396 | (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) { |
5397 | 5397 | ||
5398 | if (ioc->spi_data.minSyncFactor < MPT_ULTRA) { | 5398 | if (ioc->spi_data.minSyncFactor < MPT_ULTRA) { |
5399 | ioc->spi_data.minSyncFactor = MPT_ULTRA; | 5399 | ioc->spi_data.minSyncFactor = MPT_ULTRA; |
5400 | ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 5400 | ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
5401 | "HVD or SE detected, minSyncFactor=%x\n", | 5401 | "HVD or SE detected, minSyncFactor=%x\n", |
5402 | ioc->name, ioc->spi_data.minSyncFactor)); | 5402 | ioc->name, ioc->spi_data.minSyncFactor)); |
5403 | } | 5403 | } |
5404 | } | 5404 | } |
5405 | } | 5405 | } |
5406 | if (pbuf) { | 5406 | if (pbuf) { |
5407 | pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma); | 5407 | pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma); |
5408 | } | 5408 | } |
5409 | } | 5409 | } |
5410 | } | 5410 | } |
5411 | 5411 | ||
5412 | /* SCSI Port Page 2 - Read the header then the page. | 5412 | /* SCSI Port Page 2 - Read the header then the page. |
5413 | */ | 5413 | */ |
5414 | header.PageVersion = 0; | 5414 | header.PageVersion = 0; |
5415 | header.PageLength = 0; | 5415 | header.PageLength = 0; |
5416 | header.PageNumber = 2; | 5416 | header.PageNumber = 2; |
5417 | header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT; | 5417 | header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT; |
5418 | cfg.cfghdr.hdr = &header; | 5418 | cfg.cfghdr.hdr = &header; |
5419 | cfg.physAddr = -1; | 5419 | cfg.physAddr = -1; |
5420 | cfg.pageAddr = portnum; | 5420 | cfg.pageAddr = portnum; |
5421 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 5421 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
5422 | cfg.dir = 0; | 5422 | cfg.dir = 0; |
5423 | if (mpt_config(ioc, &cfg) != 0) | 5423 | if (mpt_config(ioc, &cfg) != 0) |
5424 | return -EFAULT; | 5424 | return -EFAULT; |
5425 | 5425 | ||
5426 | if (header.PageLength > 0) { | 5426 | if (header.PageLength > 0) { |
5427 | /* Allocate memory and read SCSI Port Page 2 | 5427 | /* Allocate memory and read SCSI Port Page 2 |
5428 | */ | 5428 | */ |
5429 | pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma); | 5429 | pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma); |
5430 | if (pbuf) { | 5430 | if (pbuf) { |
5431 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM; | 5431 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM; |
5432 | cfg.physAddr = buf_dma; | 5432 | cfg.physAddr = buf_dma; |
5433 | if (mpt_config(ioc, &cfg) != 0) { | 5433 | if (mpt_config(ioc, &cfg) != 0) { |
5434 | /* Nvram data is left with INVALID mark | 5434 | /* Nvram data is left with INVALID mark |
5435 | */ | 5435 | */ |
5436 | rc = 1; | 5436 | rc = 1; |
5437 | } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) { | 5437 | } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) { |
5438 | 5438 | ||
5439 | /* This is an ATTO adapter, read Page2 accordingly | 5439 | /* This is an ATTO adapter, read Page2 accordingly |
5440 | */ | 5440 | */ |
5441 | ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf; | 5441 | ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf; |
5442 | ATTODeviceInfo_t *pdevice = NULL; | 5442 | ATTODeviceInfo_t *pdevice = NULL; |
5443 | u16 ATTOFlags; | 5443 | u16 ATTOFlags; |
5444 | 5444 | ||
5445 | /* Save the Port Page 2 data | 5445 | /* Save the Port Page 2 data |
5446 | * (reformat into a 32bit quantity) | 5446 | * (reformat into a 32bit quantity) |
5447 | */ | 5447 | */ |
5448 | for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { | 5448 | for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { |
5449 | pdevice = &pPP2->DeviceSettings[ii]; | 5449 | pdevice = &pPP2->DeviceSettings[ii]; |
5450 | ATTOFlags = le16_to_cpu(pdevice->ATTOFlags); | 5450 | ATTOFlags = le16_to_cpu(pdevice->ATTOFlags); |
5451 | data = 0; | 5451 | data = 0; |
5452 | 5452 | ||
5453 | /* Translate ATTO device flags to LSI format | 5453 | /* Translate ATTO device flags to LSI format |
5454 | */ | 5454 | */ |
5455 | if (ATTOFlags & ATTOFLAG_DISC) | 5455 | if (ATTOFlags & ATTOFLAG_DISC) |
5456 | data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE); | 5456 | data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE); |
5457 | if (ATTOFlags & ATTOFLAG_ID_ENB) | 5457 | if (ATTOFlags & ATTOFLAG_ID_ENB) |
5458 | data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE); | 5458 | data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE); |
5459 | if (ATTOFlags & ATTOFLAG_LUN_ENB) | 5459 | if (ATTOFlags & ATTOFLAG_LUN_ENB) |
5460 | data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE); | 5460 | data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE); |
5461 | if (ATTOFlags & ATTOFLAG_TAGGED) | 5461 | if (ATTOFlags & ATTOFLAG_TAGGED) |
5462 | data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE); | 5462 | data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE); |
5463 | if (!(ATTOFlags & ATTOFLAG_WIDE_ENB)) | 5463 | if (!(ATTOFlags & ATTOFLAG_WIDE_ENB)) |
5464 | data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE); | 5464 | data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE); |
5465 | 5465 | ||
5466 | data = (data << 16) | (pdevice->Period << 8) | 10; | 5466 | data = (data << 16) | (pdevice->Period << 8) | 10; |
5467 | ioc->spi_data.nvram[ii] = data; | 5467 | ioc->spi_data.nvram[ii] = data; |
5468 | } | 5468 | } |
5469 | } else { | 5469 | } else { |
5470 | SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf; | 5470 | SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf; |
5471 | MpiDeviceInfo_t *pdevice = NULL; | 5471 | MpiDeviceInfo_t *pdevice = NULL; |
5472 | 5472 | ||
5473 | /* | 5473 | /* |
5474 | * Save "Set to Avoid SCSI Bus Resets" flag | 5474 | * Save "Set to Avoid SCSI Bus Resets" flag |
5475 | */ | 5475 | */ |
5476 | ioc->spi_data.bus_reset = | 5476 | ioc->spi_data.bus_reset = |
5477 | (le32_to_cpu(pPP2->PortFlags) & | 5477 | (le32_to_cpu(pPP2->PortFlags) & |
5478 | MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ? | 5478 | MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ? |
5479 | 0 : 1 ; | 5479 | 0 : 1 ; |
5480 | 5480 | ||
5481 | /* Save the Port Page 2 data | 5481 | /* Save the Port Page 2 data |
5482 | * (reformat into a 32bit quantity) | 5482 | * (reformat into a 32bit quantity) |
5483 | */ | 5483 | */ |
5484 | data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK; | 5484 | data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK; |
5485 | ioc->spi_data.PortFlags = data; | 5485 | ioc->spi_data.PortFlags = data; |
5486 | for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { | 5486 | for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { |
5487 | pdevice = &pPP2->DeviceSettings[ii]; | 5487 | pdevice = &pPP2->DeviceSettings[ii]; |
5488 | data = (le16_to_cpu(pdevice->DeviceFlags) << 16) | | 5488 | data = (le16_to_cpu(pdevice->DeviceFlags) << 16) | |
5489 | (pdevice->SyncFactor << 8) | pdevice->Timeout; | 5489 | (pdevice->SyncFactor << 8) | pdevice->Timeout; |
5490 | ioc->spi_data.nvram[ii] = data; | 5490 | ioc->spi_data.nvram[ii] = data; |
5491 | } | 5491 | } |
5492 | } | 5492 | } |
5493 | 5493 | ||
5494 | pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma); | 5494 | pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma); |
5495 | } | 5495 | } |
5496 | } | 5496 | } |
5497 | 5497 | ||
5498 | /* Update Adapter limits with those from NVRAM | 5498 | /* Update Adapter limits with those from NVRAM |
5499 | * Comment: Don't need to do this. Target performance | 5499 | * Comment: Don't need to do this. Target performance |
5500 | * parameters will never exceed the adapters limits. | 5500 | * parameters will never exceed the adapters limits. |
5501 | */ | 5501 | */ |
5502 | 5502 | ||
5503 | return rc; | 5503 | return rc; |
5504 | } | 5504 | } |
5505 | 5505 | ||
5506 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 5506 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
5507 | /** | 5507 | /** |
5508 | * mpt_readScsiDevicePageHeaders - save version and length of SDP1 | 5508 | * mpt_readScsiDevicePageHeaders - save version and length of SDP1 |
5509 | * @ioc: Pointer to a Adapter Strucutre | 5509 | * @ioc: Pointer to a Adapter Strucutre |
5510 | * @portnum: IOC port number | 5510 | * @portnum: IOC port number |
5511 | * | 5511 | * |
5512 | * Return: -EFAULT if read of config page header fails | 5512 | * Return: -EFAULT if read of config page header fails |
5513 | * or 0 if success. | 5513 | * or 0 if success. |
5514 | */ | 5514 | */ |
5515 | static int | 5515 | static int |
5516 | mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) | 5516 | mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) |
5517 | { | 5517 | { |
5518 | CONFIGPARMS cfg; | 5518 | CONFIGPARMS cfg; |
5519 | ConfigPageHeader_t header; | 5519 | ConfigPageHeader_t header; |
5520 | 5520 | ||
5521 | /* Read the SCSI Device Page 1 header | 5521 | /* Read the SCSI Device Page 1 header |
5522 | */ | 5522 | */ |
5523 | header.PageVersion = 0; | 5523 | header.PageVersion = 0; |
5524 | header.PageLength = 0; | 5524 | header.PageLength = 0; |
5525 | header.PageNumber = 1; | 5525 | header.PageNumber = 1; |
5526 | header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; | 5526 | header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; |
5527 | cfg.cfghdr.hdr = &header; | 5527 | cfg.cfghdr.hdr = &header; |
5528 | cfg.physAddr = -1; | 5528 | cfg.physAddr = -1; |
5529 | cfg.pageAddr = portnum; | 5529 | cfg.pageAddr = portnum; |
5530 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 5530 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
5531 | cfg.dir = 0; | 5531 | cfg.dir = 0; |
5532 | cfg.timeout = 0; | 5532 | cfg.timeout = 0; |
5533 | if (mpt_config(ioc, &cfg) != 0) | 5533 | if (mpt_config(ioc, &cfg) != 0) |
5534 | return -EFAULT; | 5534 | return -EFAULT; |
5535 | 5535 | ||
5536 | ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion; | 5536 | ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion; |
5537 | ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength; | 5537 | ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength; |
5538 | 5538 | ||
5539 | header.PageVersion = 0; | 5539 | header.PageVersion = 0; |
5540 | header.PageLength = 0; | 5540 | header.PageLength = 0; |
5541 | header.PageNumber = 0; | 5541 | header.PageNumber = 0; |
5542 | header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; | 5542 | header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; |
5543 | if (mpt_config(ioc, &cfg) != 0) | 5543 | if (mpt_config(ioc, &cfg) != 0) |
5544 | return -EFAULT; | 5544 | return -EFAULT; |
5545 | 5545 | ||
5546 | ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion; | 5546 | ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion; |
5547 | ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength; | 5547 | ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength; |
5548 | 5548 | ||
5549 | dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n", | 5549 | dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n", |
5550 | ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length)); | 5550 | ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length)); |
5551 | 5551 | ||
5552 | dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n", | 5552 | dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n", |
5553 | ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length)); | 5553 | ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length)); |
5554 | return 0; | 5554 | return 0; |
5555 | } | 5555 | } |
5556 | 5556 | ||
5557 | /** | 5557 | /** |
5558 | * mpt_inactive_raid_list_free - This clears this link list. | 5558 | * mpt_inactive_raid_list_free - This clears this link list. |
5559 | * @ioc : pointer to per adapter structure | 5559 | * @ioc : pointer to per adapter structure |
5560 | **/ | 5560 | **/ |
5561 | static void | 5561 | static void |
5562 | mpt_inactive_raid_list_free(MPT_ADAPTER *ioc) | 5562 | mpt_inactive_raid_list_free(MPT_ADAPTER *ioc) |
5563 | { | 5563 | { |
5564 | struct inactive_raid_component_info *component_info, *pNext; | 5564 | struct inactive_raid_component_info *component_info, *pNext; |
5565 | 5565 | ||
5566 | if (list_empty(&ioc->raid_data.inactive_list)) | 5566 | if (list_empty(&ioc->raid_data.inactive_list)) |
5567 | return; | 5567 | return; |
5568 | 5568 | ||
5569 | mutex_lock(&ioc->raid_data.inactive_list_mutex); | 5569 | mutex_lock(&ioc->raid_data.inactive_list_mutex); |
5570 | list_for_each_entry_safe(component_info, pNext, | 5570 | list_for_each_entry_safe(component_info, pNext, |
5571 | &ioc->raid_data.inactive_list, list) { | 5571 | &ioc->raid_data.inactive_list, list) { |
5572 | list_del(&component_info->list); | 5572 | list_del(&component_info->list); |
5573 | kfree(component_info); | 5573 | kfree(component_info); |
5574 | } | 5574 | } |
5575 | mutex_unlock(&ioc->raid_data.inactive_list_mutex); | 5575 | mutex_unlock(&ioc->raid_data.inactive_list_mutex); |
5576 | } | 5576 | } |
5577 | 5577 | ||
5578 | /** | 5578 | /** |
5579 | * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume | 5579 | * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume |
5580 | * | 5580 | * |
5581 | * @ioc : pointer to per adapter structure | 5581 | * @ioc : pointer to per adapter structure |
5582 | * @channel : volume channel | 5582 | * @channel : volume channel |
5583 | * @id : volume target id | 5583 | * @id : volume target id |
5584 | **/ | 5584 | **/ |
5585 | static void | 5585 | static void |
5586 | mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id) | 5586 | mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id) |
5587 | { | 5587 | { |
5588 | CONFIGPARMS cfg; | 5588 | CONFIGPARMS cfg; |
5589 | ConfigPageHeader_t hdr; | 5589 | ConfigPageHeader_t hdr; |
5590 | dma_addr_t dma_handle; | 5590 | dma_addr_t dma_handle; |
5591 | pRaidVolumePage0_t buffer = NULL; | 5591 | pRaidVolumePage0_t buffer = NULL; |
5592 | int i; | 5592 | int i; |
5593 | RaidPhysDiskPage0_t phys_disk; | 5593 | RaidPhysDiskPage0_t phys_disk; |
5594 | struct inactive_raid_component_info *component_info; | 5594 | struct inactive_raid_component_info *component_info; |
5595 | int handle_inactive_volumes; | 5595 | int handle_inactive_volumes; |
5596 | 5596 | ||
5597 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); | 5597 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); |
5598 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); | 5598 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); |
5599 | hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; | 5599 | hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; |
5600 | cfg.pageAddr = (channel << 8) + id; | 5600 | cfg.pageAddr = (channel << 8) + id; |
5601 | cfg.cfghdr.hdr = &hdr; | 5601 | cfg.cfghdr.hdr = &hdr; |
5602 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 5602 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
5603 | 5603 | ||
5604 | if (mpt_config(ioc, &cfg) != 0) | 5604 | if (mpt_config(ioc, &cfg) != 0) |
5605 | goto out; | 5605 | goto out; |
5606 | 5606 | ||
5607 | if (!hdr.PageLength) | 5607 | if (!hdr.PageLength) |
5608 | goto out; | 5608 | goto out; |
5609 | 5609 | ||
5610 | buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, | 5610 | buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, |
5611 | &dma_handle); | 5611 | &dma_handle); |
5612 | 5612 | ||
5613 | if (!buffer) | 5613 | if (!buffer) |
5614 | goto out; | 5614 | goto out; |
5615 | 5615 | ||
5616 | cfg.physAddr = dma_handle; | 5616 | cfg.physAddr = dma_handle; |
5617 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | 5617 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
5618 | 5618 | ||
5619 | if (mpt_config(ioc, &cfg) != 0) | 5619 | if (mpt_config(ioc, &cfg) != 0) |
5620 | goto out; | 5620 | goto out; |
5621 | 5621 | ||
5622 | if (!buffer->NumPhysDisks) | 5622 | if (!buffer->NumPhysDisks) |
5623 | goto out; | 5623 | goto out; |
5624 | 5624 | ||
5625 | handle_inactive_volumes = | 5625 | handle_inactive_volumes = |
5626 | (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE || | 5626 | (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE || |
5627 | (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 || | 5627 | (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 || |
5628 | buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED || | 5628 | buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED || |
5629 | buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0; | 5629 | buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0; |
5630 | 5630 | ||
5631 | if (!handle_inactive_volumes) | 5631 | if (!handle_inactive_volumes) |
5632 | goto out; | 5632 | goto out; |
5633 | 5633 | ||
5634 | mutex_lock(&ioc->raid_data.inactive_list_mutex); | 5634 | mutex_lock(&ioc->raid_data.inactive_list_mutex); |
5635 | for (i = 0; i < buffer->NumPhysDisks; i++) { | 5635 | for (i = 0; i < buffer->NumPhysDisks; i++) { |
5636 | if(mpt_raid_phys_disk_pg0(ioc, | 5636 | if(mpt_raid_phys_disk_pg0(ioc, |
5637 | buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) | 5637 | buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) |
5638 | continue; | 5638 | continue; |
5639 | 5639 | ||
5640 | if ((component_info = kmalloc(sizeof (*component_info), | 5640 | if ((component_info = kmalloc(sizeof (*component_info), |
5641 | GFP_KERNEL)) == NULL) | 5641 | GFP_KERNEL)) == NULL) |
5642 | continue; | 5642 | continue; |
5643 | 5643 | ||
5644 | component_info->volumeID = id; | 5644 | component_info->volumeID = id; |
5645 | component_info->volumeBus = channel; | 5645 | component_info->volumeBus = channel; |
5646 | component_info->d.PhysDiskNum = phys_disk.PhysDiskNum; | 5646 | component_info->d.PhysDiskNum = phys_disk.PhysDiskNum; |
5647 | component_info->d.PhysDiskBus = phys_disk.PhysDiskBus; | 5647 | component_info->d.PhysDiskBus = phys_disk.PhysDiskBus; |
5648 | component_info->d.PhysDiskID = phys_disk.PhysDiskID; | 5648 | component_info->d.PhysDiskID = phys_disk.PhysDiskID; |
5649 | component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC; | 5649 | component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC; |
5650 | 5650 | ||
5651 | list_add_tail(&component_info->list, | 5651 | list_add_tail(&component_info->list, |
5652 | &ioc->raid_data.inactive_list); | 5652 | &ioc->raid_data.inactive_list); |
5653 | } | 5653 | } |
5654 | mutex_unlock(&ioc->raid_data.inactive_list_mutex); | 5654 | mutex_unlock(&ioc->raid_data.inactive_list_mutex); |
5655 | 5655 | ||
5656 | out: | 5656 | out: |
5657 | if (buffer) | 5657 | if (buffer) |
5658 | pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, | 5658 | pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, |
5659 | dma_handle); | 5659 | dma_handle); |
5660 | } | 5660 | } |
5661 | 5661 | ||
5662 | /** | 5662 | /** |
5663 | * mpt_raid_phys_disk_pg0 - returns phys disk page zero | 5663 | * mpt_raid_phys_disk_pg0 - returns phys disk page zero |
5664 | * @ioc: Pointer to a Adapter Structure | 5664 | * @ioc: Pointer to a Adapter Structure |
5665 | * @phys_disk_num: io unit unique phys disk num generated by the ioc | 5665 | * @phys_disk_num: io unit unique phys disk num generated by the ioc |
5666 | * @phys_disk: requested payload data returned | 5666 | * @phys_disk: requested payload data returned |
5667 | * | 5667 | * |
5668 | * Return: | 5668 | * Return: |
5669 | * 0 on success | 5669 | * 0 on success |
5670 | * -EFAULT if read of config page header fails or data pointer not NULL | 5670 | * -EFAULT if read of config page header fails or data pointer not NULL |
5671 | * -ENOMEM if pci_alloc failed | 5671 | * -ENOMEM if pci_alloc failed |
5672 | **/ | 5672 | **/ |
5673 | int | 5673 | int |
5674 | mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, | 5674 | mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, |
5675 | RaidPhysDiskPage0_t *phys_disk) | 5675 | RaidPhysDiskPage0_t *phys_disk) |
5676 | { | 5676 | { |
5677 | CONFIGPARMS cfg; | 5677 | CONFIGPARMS cfg; |
5678 | ConfigPageHeader_t hdr; | 5678 | ConfigPageHeader_t hdr; |
5679 | dma_addr_t dma_handle; | 5679 | dma_addr_t dma_handle; |
5680 | pRaidPhysDiskPage0_t buffer = NULL; | 5680 | pRaidPhysDiskPage0_t buffer = NULL; |
5681 | int rc; | 5681 | int rc; |
5682 | 5682 | ||
5683 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); | 5683 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); |
5684 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); | 5684 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); |
5685 | memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t)); | 5685 | memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t)); |
5686 | 5686 | ||
5687 | hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION; | 5687 | hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION; |
5688 | hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; | 5688 | hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; |
5689 | cfg.cfghdr.hdr = &hdr; | 5689 | cfg.cfghdr.hdr = &hdr; |
5690 | cfg.physAddr = -1; | 5690 | cfg.physAddr = -1; |
5691 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 5691 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
5692 | 5692 | ||
5693 | if (mpt_config(ioc, &cfg) != 0) { | 5693 | if (mpt_config(ioc, &cfg) != 0) { |
5694 | rc = -EFAULT; | 5694 | rc = -EFAULT; |
5695 | goto out; | 5695 | goto out; |
5696 | } | 5696 | } |
5697 | 5697 | ||
5698 | if (!hdr.PageLength) { | 5698 | if (!hdr.PageLength) { |
5699 | rc = -EFAULT; | 5699 | rc = -EFAULT; |
5700 | goto out; | 5700 | goto out; |
5701 | } | 5701 | } |
5702 | 5702 | ||
5703 | buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, | 5703 | buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, |
5704 | &dma_handle); | 5704 | &dma_handle); |
5705 | 5705 | ||
5706 | if (!buffer) { | 5706 | if (!buffer) { |
5707 | rc = -ENOMEM; | 5707 | rc = -ENOMEM; |
5708 | goto out; | 5708 | goto out; |
5709 | } | 5709 | } |
5710 | 5710 | ||
5711 | cfg.physAddr = dma_handle; | 5711 | cfg.physAddr = dma_handle; |
5712 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | 5712 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
5713 | cfg.pageAddr = phys_disk_num; | 5713 | cfg.pageAddr = phys_disk_num; |
5714 | 5714 | ||
5715 | if (mpt_config(ioc, &cfg) != 0) { | 5715 | if (mpt_config(ioc, &cfg) != 0) { |
5716 | rc = -EFAULT; | 5716 | rc = -EFAULT; |
5717 | goto out; | 5717 | goto out; |
5718 | } | 5718 | } |
5719 | 5719 | ||
5720 | rc = 0; | 5720 | rc = 0; |
5721 | memcpy(phys_disk, buffer, sizeof(*buffer)); | 5721 | memcpy(phys_disk, buffer, sizeof(*buffer)); |
5722 | phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA); | 5722 | phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA); |
5723 | 5723 | ||
5724 | out: | 5724 | out: |
5725 | 5725 | ||
5726 | if (buffer) | 5726 | if (buffer) |
5727 | pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, | 5727 | pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, |
5728 | dma_handle); | 5728 | dma_handle); |
5729 | 5729 | ||
5730 | return rc; | 5730 | return rc; |
5731 | } | 5731 | } |
5732 | 5732 | ||
5733 | /** | 5733 | /** |
5734 | * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num | 5734 | * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num |
5735 | * @ioc: Pointer to a Adapter Structure | 5735 | * @ioc: Pointer to a Adapter Structure |
5736 | * @phys_disk_num: io unit unique phys disk num generated by the ioc | 5736 | * @phys_disk_num: io unit unique phys disk num generated by the ioc |
5737 | * | 5737 | * |
5738 | * Return: | 5738 | * Return: |
5739 | * returns number paths | 5739 | * returns number paths |
5740 | **/ | 5740 | **/ |
5741 | int | 5741 | int |
5742 | mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num) | 5742 | mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num) |
5743 | { | 5743 | { |
5744 | CONFIGPARMS cfg; | 5744 | CONFIGPARMS cfg; |
5745 | ConfigPageHeader_t hdr; | 5745 | ConfigPageHeader_t hdr; |
5746 | dma_addr_t dma_handle; | 5746 | dma_addr_t dma_handle; |
5747 | pRaidPhysDiskPage1_t buffer = NULL; | 5747 | pRaidPhysDiskPage1_t buffer = NULL; |
5748 | int rc; | 5748 | int rc; |
5749 | 5749 | ||
5750 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); | 5750 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); |
5751 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); | 5751 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); |
5752 | 5752 | ||
5753 | hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION; | 5753 | hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION; |
5754 | hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; | 5754 | hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; |
5755 | hdr.PageNumber = 1; | 5755 | hdr.PageNumber = 1; |
5756 | cfg.cfghdr.hdr = &hdr; | 5756 | cfg.cfghdr.hdr = &hdr; |
5757 | cfg.physAddr = -1; | 5757 | cfg.physAddr = -1; |
5758 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 5758 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
5759 | 5759 | ||
5760 | if (mpt_config(ioc, &cfg) != 0) { | 5760 | if (mpt_config(ioc, &cfg) != 0) { |
5761 | rc = 0; | 5761 | rc = 0; |
5762 | goto out; | 5762 | goto out; |
5763 | } | 5763 | } |
5764 | 5764 | ||
5765 | if (!hdr.PageLength) { | 5765 | if (!hdr.PageLength) { |
5766 | rc = 0; | 5766 | rc = 0; |
5767 | goto out; | 5767 | goto out; |
5768 | } | 5768 | } |
5769 | 5769 | ||
5770 | buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, | 5770 | buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, |
5771 | &dma_handle); | 5771 | &dma_handle); |
5772 | 5772 | ||
5773 | if (!buffer) { | 5773 | if (!buffer) { |
5774 | rc = 0; | 5774 | rc = 0; |
5775 | goto out; | 5775 | goto out; |
5776 | } | 5776 | } |
5777 | 5777 | ||
5778 | cfg.physAddr = dma_handle; | 5778 | cfg.physAddr = dma_handle; |
5779 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | 5779 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
5780 | cfg.pageAddr = phys_disk_num; | 5780 | cfg.pageAddr = phys_disk_num; |
5781 | 5781 | ||
5782 | if (mpt_config(ioc, &cfg) != 0) { | 5782 | if (mpt_config(ioc, &cfg) != 0) { |
5783 | rc = 0; | 5783 | rc = 0; |
5784 | goto out; | 5784 | goto out; |
5785 | } | 5785 | } |
5786 | 5786 | ||
5787 | rc = buffer->NumPhysDiskPaths; | 5787 | rc = buffer->NumPhysDiskPaths; |
5788 | out: | 5788 | out: |
5789 | 5789 | ||
5790 | if (buffer) | 5790 | if (buffer) |
5791 | pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, | 5791 | pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, |
5792 | dma_handle); | 5792 | dma_handle); |
5793 | 5793 | ||
5794 | return rc; | 5794 | return rc; |
5795 | } | 5795 | } |
5796 | EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths); | 5796 | EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths); |
5797 | 5797 | ||
5798 | /** | 5798 | /** |
5799 | * mpt_raid_phys_disk_pg1 - returns phys disk page 1 | 5799 | * mpt_raid_phys_disk_pg1 - returns phys disk page 1 |
5800 | * @ioc: Pointer to a Adapter Structure | 5800 | * @ioc: Pointer to a Adapter Structure |
5801 | * @phys_disk_num: io unit unique phys disk num generated by the ioc | 5801 | * @phys_disk_num: io unit unique phys disk num generated by the ioc |
5802 | * @phys_disk: requested payload data returned | 5802 | * @phys_disk: requested payload data returned |
5803 | * | 5803 | * |
5804 | * Return: | 5804 | * Return: |
5805 | * 0 on success | 5805 | * 0 on success |
5806 | * -EFAULT if read of config page header fails or data pointer not NULL | 5806 | * -EFAULT if read of config page header fails or data pointer not NULL |
5807 | * -ENOMEM if pci_alloc failed | 5807 | * -ENOMEM if pci_alloc failed |
5808 | **/ | 5808 | **/ |
5809 | int | 5809 | int |
5810 | mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, | 5810 | mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, |
5811 | RaidPhysDiskPage1_t *phys_disk) | 5811 | RaidPhysDiskPage1_t *phys_disk) |
5812 | { | 5812 | { |
5813 | CONFIGPARMS cfg; | 5813 | CONFIGPARMS cfg; |
5814 | ConfigPageHeader_t hdr; | 5814 | ConfigPageHeader_t hdr; |
5815 | dma_addr_t dma_handle; | 5815 | dma_addr_t dma_handle; |
5816 | pRaidPhysDiskPage1_t buffer = NULL; | 5816 | pRaidPhysDiskPage1_t buffer = NULL; |
5817 | int rc; | 5817 | int rc; |
5818 | int i; | 5818 | int i; |
5819 | __le64 sas_address; | 5819 | __le64 sas_address; |
5820 | 5820 | ||
5821 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); | 5821 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); |
5822 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); | 5822 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); |
5823 | rc = 0; | 5823 | rc = 0; |
5824 | 5824 | ||
5825 | hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION; | 5825 | hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION; |
5826 | hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; | 5826 | hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; |
5827 | hdr.PageNumber = 1; | 5827 | hdr.PageNumber = 1; |
5828 | cfg.cfghdr.hdr = &hdr; | 5828 | cfg.cfghdr.hdr = &hdr; |
5829 | cfg.physAddr = -1; | 5829 | cfg.physAddr = -1; |
5830 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 5830 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
5831 | 5831 | ||
5832 | if (mpt_config(ioc, &cfg) != 0) { | 5832 | if (mpt_config(ioc, &cfg) != 0) { |
5833 | rc = -EFAULT; | 5833 | rc = -EFAULT; |
5834 | goto out; | 5834 | goto out; |
5835 | } | 5835 | } |
5836 | 5836 | ||
5837 | if (!hdr.PageLength) { | 5837 | if (!hdr.PageLength) { |
5838 | rc = -EFAULT; | 5838 | rc = -EFAULT; |
5839 | goto out; | 5839 | goto out; |
5840 | } | 5840 | } |
5841 | 5841 | ||
5842 | buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, | 5842 | buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, |
5843 | &dma_handle); | 5843 | &dma_handle); |
5844 | 5844 | ||
5845 | if (!buffer) { | 5845 | if (!buffer) { |
5846 | rc = -ENOMEM; | 5846 | rc = -ENOMEM; |
5847 | goto out; | 5847 | goto out; |
5848 | } | 5848 | } |
5849 | 5849 | ||
5850 | cfg.physAddr = dma_handle; | 5850 | cfg.physAddr = dma_handle; |
5851 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | 5851 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
5852 | cfg.pageAddr = phys_disk_num; | 5852 | cfg.pageAddr = phys_disk_num; |
5853 | 5853 | ||
5854 | if (mpt_config(ioc, &cfg) != 0) { | 5854 | if (mpt_config(ioc, &cfg) != 0) { |
5855 | rc = -EFAULT; | 5855 | rc = -EFAULT; |
5856 | goto out; | 5856 | goto out; |
5857 | } | 5857 | } |
5858 | 5858 | ||
5859 | phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths; | 5859 | phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths; |
5860 | phys_disk->PhysDiskNum = phys_disk_num; | 5860 | phys_disk->PhysDiskNum = phys_disk_num; |
5861 | for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) { | 5861 | for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) { |
5862 | phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID; | 5862 | phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID; |
5863 | phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus; | 5863 | phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus; |
5864 | phys_disk->Path[i].OwnerIdentifier = | 5864 | phys_disk->Path[i].OwnerIdentifier = |
5865 | buffer->Path[i].OwnerIdentifier; | 5865 | buffer->Path[i].OwnerIdentifier; |
5866 | phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags); | 5866 | phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags); |
5867 | memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64)); | 5867 | memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64)); |
5868 | sas_address = le64_to_cpu(sas_address); | 5868 | sas_address = le64_to_cpu(sas_address); |
5869 | memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64)); | 5869 | memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64)); |
5870 | memcpy(&sas_address, | 5870 | memcpy(&sas_address, |
5871 | &buffer->Path[i].OwnerWWID, sizeof(__le64)); | 5871 | &buffer->Path[i].OwnerWWID, sizeof(__le64)); |
5872 | sas_address = le64_to_cpu(sas_address); | 5872 | sas_address = le64_to_cpu(sas_address); |
5873 | memcpy(&phys_disk->Path[i].OwnerWWID, | 5873 | memcpy(&phys_disk->Path[i].OwnerWWID, |
5874 | &sas_address, sizeof(__le64)); | 5874 | &sas_address, sizeof(__le64)); |
5875 | } | 5875 | } |
5876 | 5876 | ||
5877 | out: | 5877 | out: |
5878 | 5878 | ||
5879 | if (buffer) | 5879 | if (buffer) |
5880 | pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, | 5880 | pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, |
5881 | dma_handle); | 5881 | dma_handle); |
5882 | 5882 | ||
5883 | return rc; | 5883 | return rc; |
5884 | } | 5884 | } |
5885 | EXPORT_SYMBOL(mpt_raid_phys_disk_pg1); | 5885 | EXPORT_SYMBOL(mpt_raid_phys_disk_pg1); |
5886 | 5886 | ||
5887 | 5887 | ||
5888 | /** | 5888 | /** |
5889 | * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes | 5889 | * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes |
5890 | * @ioc: Pointer to a Adapter Strucutre | 5890 | * @ioc: Pointer to a Adapter Strucutre |
5891 | * | 5891 | * |
5892 | * Return: | 5892 | * Return: |
5893 | * 0 on success | 5893 | * 0 on success |
5894 | * -EFAULT if read of config page header fails or data pointer not NULL | 5894 | * -EFAULT if read of config page header fails or data pointer not NULL |
5895 | * -ENOMEM if pci_alloc failed | 5895 | * -ENOMEM if pci_alloc failed |
5896 | **/ | 5896 | **/ |
5897 | int | 5897 | int |
5898 | mpt_findImVolumes(MPT_ADAPTER *ioc) | 5898 | mpt_findImVolumes(MPT_ADAPTER *ioc) |
5899 | { | 5899 | { |
5900 | IOCPage2_t *pIoc2; | 5900 | IOCPage2_t *pIoc2; |
5901 | u8 *mem; | 5901 | u8 *mem; |
5902 | dma_addr_t ioc2_dma; | 5902 | dma_addr_t ioc2_dma; |
5903 | CONFIGPARMS cfg; | 5903 | CONFIGPARMS cfg; |
5904 | ConfigPageHeader_t header; | 5904 | ConfigPageHeader_t header; |
5905 | int rc = 0; | 5905 | int rc = 0; |
5906 | int iocpage2sz; | 5906 | int iocpage2sz; |
5907 | int i; | 5907 | int i; |
5908 | 5908 | ||
5909 | if (!ioc->ir_firmware) | 5909 | if (!ioc->ir_firmware) |
5910 | return 0; | 5910 | return 0; |
5911 | 5911 | ||
5912 | /* Free the old page | 5912 | /* Free the old page |
5913 | */ | 5913 | */ |
5914 | kfree(ioc->raid_data.pIocPg2); | 5914 | kfree(ioc->raid_data.pIocPg2); |
5915 | ioc->raid_data.pIocPg2 = NULL; | 5915 | ioc->raid_data.pIocPg2 = NULL; |
5916 | mpt_inactive_raid_list_free(ioc); | 5916 | mpt_inactive_raid_list_free(ioc); |
5917 | 5917 | ||
5918 | /* Read IOCP2 header then the page. | 5918 | /* Read IOCP2 header then the page. |
5919 | */ | 5919 | */ |
5920 | header.PageVersion = 0; | 5920 | header.PageVersion = 0; |
5921 | header.PageLength = 0; | 5921 | header.PageLength = 0; |
5922 | header.PageNumber = 2; | 5922 | header.PageNumber = 2; |
5923 | header.PageType = MPI_CONFIG_PAGETYPE_IOC; | 5923 | header.PageType = MPI_CONFIG_PAGETYPE_IOC; |
5924 | cfg.cfghdr.hdr = &header; | 5924 | cfg.cfghdr.hdr = &header; |
5925 | cfg.physAddr = -1; | 5925 | cfg.physAddr = -1; |
5926 | cfg.pageAddr = 0; | 5926 | cfg.pageAddr = 0; |
5927 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 5927 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
5928 | cfg.dir = 0; | 5928 | cfg.dir = 0; |
5929 | cfg.timeout = 0; | 5929 | cfg.timeout = 0; |
5930 | if (mpt_config(ioc, &cfg) != 0) | 5930 | if (mpt_config(ioc, &cfg) != 0) |
5931 | return -EFAULT; | 5931 | return -EFAULT; |
5932 | 5932 | ||
5933 | if (header.PageLength == 0) | 5933 | if (header.PageLength == 0) |
5934 | return -EFAULT; | 5934 | return -EFAULT; |
5935 | 5935 | ||
5936 | iocpage2sz = header.PageLength * 4; | 5936 | iocpage2sz = header.PageLength * 4; |
5937 | pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma); | 5937 | pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma); |
5938 | if (!pIoc2) | 5938 | if (!pIoc2) |
5939 | return -ENOMEM; | 5939 | return -ENOMEM; |
5940 | 5940 | ||
5941 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | 5941 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
5942 | cfg.physAddr = ioc2_dma; | 5942 | cfg.physAddr = ioc2_dma; |
5943 | if (mpt_config(ioc, &cfg) != 0) | 5943 | if (mpt_config(ioc, &cfg) != 0) |
5944 | goto out; | 5944 | goto out; |
5945 | 5945 | ||
5946 | mem = kmalloc(iocpage2sz, GFP_KERNEL); | 5946 | mem = kmalloc(iocpage2sz, GFP_KERNEL); |
5947 | if (!mem) | 5947 | if (!mem) |
5948 | goto out; | 5948 | goto out; |
5949 | 5949 | ||
5950 | memcpy(mem, (u8 *)pIoc2, iocpage2sz); | 5950 | memcpy(mem, (u8 *)pIoc2, iocpage2sz); |
5951 | ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem; | 5951 | ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem; |
5952 | 5952 | ||
5953 | mpt_read_ioc_pg_3(ioc); | 5953 | mpt_read_ioc_pg_3(ioc); |
5954 | 5954 | ||
5955 | for (i = 0; i < pIoc2->NumActiveVolumes ; i++) | 5955 | for (i = 0; i < pIoc2->NumActiveVolumes ; i++) |
5956 | mpt_inactive_raid_volumes(ioc, | 5956 | mpt_inactive_raid_volumes(ioc, |
5957 | pIoc2->RaidVolume[i].VolumeBus, | 5957 | pIoc2->RaidVolume[i].VolumeBus, |
5958 | pIoc2->RaidVolume[i].VolumeID); | 5958 | pIoc2->RaidVolume[i].VolumeID); |
5959 | 5959 | ||
5960 | out: | 5960 | out: |
5961 | pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma); | 5961 | pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma); |
5962 | 5962 | ||
5963 | return rc; | 5963 | return rc; |
5964 | } | 5964 | } |
5965 | 5965 | ||
5966 | static int | 5966 | static int |
5967 | mpt_read_ioc_pg_3(MPT_ADAPTER *ioc) | 5967 | mpt_read_ioc_pg_3(MPT_ADAPTER *ioc) |
5968 | { | 5968 | { |
5969 | IOCPage3_t *pIoc3; | 5969 | IOCPage3_t *pIoc3; |
5970 | u8 *mem; | 5970 | u8 *mem; |
5971 | CONFIGPARMS cfg; | 5971 | CONFIGPARMS cfg; |
5972 | ConfigPageHeader_t header; | 5972 | ConfigPageHeader_t header; |
5973 | dma_addr_t ioc3_dma; | 5973 | dma_addr_t ioc3_dma; |
5974 | int iocpage3sz = 0; | 5974 | int iocpage3sz = 0; |
5975 | 5975 | ||
5976 | /* Free the old page | 5976 | /* Free the old page |
5977 | */ | 5977 | */ |
5978 | kfree(ioc->raid_data.pIocPg3); | 5978 | kfree(ioc->raid_data.pIocPg3); |
5979 | ioc->raid_data.pIocPg3 = NULL; | 5979 | ioc->raid_data.pIocPg3 = NULL; |
5980 | 5980 | ||
5981 | /* There is at least one physical disk. | 5981 | /* There is at least one physical disk. |
5982 | * Read and save IOC Page 3 | 5982 | * Read and save IOC Page 3 |
5983 | */ | 5983 | */ |
5984 | header.PageVersion = 0; | 5984 | header.PageVersion = 0; |
5985 | header.PageLength = 0; | 5985 | header.PageLength = 0; |
5986 | header.PageNumber = 3; | 5986 | header.PageNumber = 3; |
5987 | header.PageType = MPI_CONFIG_PAGETYPE_IOC; | 5987 | header.PageType = MPI_CONFIG_PAGETYPE_IOC; |
5988 | cfg.cfghdr.hdr = &header; | 5988 | cfg.cfghdr.hdr = &header; |
5989 | cfg.physAddr = -1; | 5989 | cfg.physAddr = -1; |
5990 | cfg.pageAddr = 0; | 5990 | cfg.pageAddr = 0; |
5991 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 5991 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
5992 | cfg.dir = 0; | 5992 | cfg.dir = 0; |
5993 | cfg.timeout = 0; | 5993 | cfg.timeout = 0; |
5994 | if (mpt_config(ioc, &cfg) != 0) | 5994 | if (mpt_config(ioc, &cfg) != 0) |
5995 | return 0; | 5995 | return 0; |
5996 | 5996 | ||
5997 | if (header.PageLength == 0) | 5997 | if (header.PageLength == 0) |
5998 | return 0; | 5998 | return 0; |
5999 | 5999 | ||
6000 | /* Read Header good, alloc memory | 6000 | /* Read Header good, alloc memory |
6001 | */ | 6001 | */ |
6002 | iocpage3sz = header.PageLength * 4; | 6002 | iocpage3sz = header.PageLength * 4; |
6003 | pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma); | 6003 | pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma); |
6004 | if (!pIoc3) | 6004 | if (!pIoc3) |
6005 | return 0; | 6005 | return 0; |
6006 | 6006 | ||
6007 | /* Read the Page and save the data | 6007 | /* Read the Page and save the data |
6008 | * into malloc'd memory. | 6008 | * into malloc'd memory. |
6009 | */ | 6009 | */ |
6010 | cfg.physAddr = ioc3_dma; | 6010 | cfg.physAddr = ioc3_dma; |
6011 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | 6011 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
6012 | if (mpt_config(ioc, &cfg) == 0) { | 6012 | if (mpt_config(ioc, &cfg) == 0) { |
6013 | mem = kmalloc(iocpage3sz, GFP_KERNEL); | 6013 | mem = kmalloc(iocpage3sz, GFP_KERNEL); |
6014 | if (mem) { | 6014 | if (mem) { |
6015 | memcpy(mem, (u8 *)pIoc3, iocpage3sz); | 6015 | memcpy(mem, (u8 *)pIoc3, iocpage3sz); |
6016 | ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem; | 6016 | ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem; |
6017 | } | 6017 | } |
6018 | } | 6018 | } |
6019 | 6019 | ||
6020 | pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma); | 6020 | pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma); |
6021 | 6021 | ||
6022 | return 0; | 6022 | return 0; |
6023 | } | 6023 | } |
6024 | 6024 | ||
6025 | static void | 6025 | static void |
6026 | mpt_read_ioc_pg_4(MPT_ADAPTER *ioc) | 6026 | mpt_read_ioc_pg_4(MPT_ADAPTER *ioc) |
6027 | { | 6027 | { |
6028 | IOCPage4_t *pIoc4; | 6028 | IOCPage4_t *pIoc4; |
6029 | CONFIGPARMS cfg; | 6029 | CONFIGPARMS cfg; |
6030 | ConfigPageHeader_t header; | 6030 | ConfigPageHeader_t header; |
6031 | dma_addr_t ioc4_dma; | 6031 | dma_addr_t ioc4_dma; |
6032 | int iocpage4sz; | 6032 | int iocpage4sz; |
6033 | 6033 | ||
6034 | /* Read and save IOC Page 4 | 6034 | /* Read and save IOC Page 4 |
6035 | */ | 6035 | */ |
6036 | header.PageVersion = 0; | 6036 | header.PageVersion = 0; |
6037 | header.PageLength = 0; | 6037 | header.PageLength = 0; |
6038 | header.PageNumber = 4; | 6038 | header.PageNumber = 4; |
6039 | header.PageType = MPI_CONFIG_PAGETYPE_IOC; | 6039 | header.PageType = MPI_CONFIG_PAGETYPE_IOC; |
6040 | cfg.cfghdr.hdr = &header; | 6040 | cfg.cfghdr.hdr = &header; |
6041 | cfg.physAddr = -1; | 6041 | cfg.physAddr = -1; |
6042 | cfg.pageAddr = 0; | 6042 | cfg.pageAddr = 0; |
6043 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 6043 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
6044 | cfg.dir = 0; | 6044 | cfg.dir = 0; |
6045 | cfg.timeout = 0; | 6045 | cfg.timeout = 0; |
6046 | if (mpt_config(ioc, &cfg) != 0) | 6046 | if (mpt_config(ioc, &cfg) != 0) |
6047 | return; | 6047 | return; |
6048 | 6048 | ||
6049 | if (header.PageLength == 0) | 6049 | if (header.PageLength == 0) |
6050 | return; | 6050 | return; |
6051 | 6051 | ||
6052 | if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) { | 6052 | if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) { |
6053 | iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */ | 6053 | iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */ |
6054 | pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma); | 6054 | pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma); |
6055 | if (!pIoc4) | 6055 | if (!pIoc4) |
6056 | return; | 6056 | return; |
6057 | ioc->alloc_total += iocpage4sz; | 6057 | ioc->alloc_total += iocpage4sz; |
6058 | } else { | 6058 | } else { |
6059 | ioc4_dma = ioc->spi_data.IocPg4_dma; | 6059 | ioc4_dma = ioc->spi_data.IocPg4_dma; |
6060 | iocpage4sz = ioc->spi_data.IocPg4Sz; | 6060 | iocpage4sz = ioc->spi_data.IocPg4Sz; |
6061 | } | 6061 | } |
6062 | 6062 | ||
6063 | /* Read the Page into dma memory. | 6063 | /* Read the Page into dma memory. |
6064 | */ | 6064 | */ |
6065 | cfg.physAddr = ioc4_dma; | 6065 | cfg.physAddr = ioc4_dma; |
6066 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | 6066 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
6067 | if (mpt_config(ioc, &cfg) == 0) { | 6067 | if (mpt_config(ioc, &cfg) == 0) { |
6068 | ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4; | 6068 | ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4; |
6069 | ioc->spi_data.IocPg4_dma = ioc4_dma; | 6069 | ioc->spi_data.IocPg4_dma = ioc4_dma; |
6070 | ioc->spi_data.IocPg4Sz = iocpage4sz; | 6070 | ioc->spi_data.IocPg4Sz = iocpage4sz; |
6071 | } else { | 6071 | } else { |
6072 | pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma); | 6072 | pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma); |
6073 | ioc->spi_data.pIocPg4 = NULL; | 6073 | ioc->spi_data.pIocPg4 = NULL; |
6074 | ioc->alloc_total -= iocpage4sz; | 6074 | ioc->alloc_total -= iocpage4sz; |
6075 | } | 6075 | } |
6076 | } | 6076 | } |
6077 | 6077 | ||
6078 | static void | 6078 | static void |
6079 | mpt_read_ioc_pg_1(MPT_ADAPTER *ioc) | 6079 | mpt_read_ioc_pg_1(MPT_ADAPTER *ioc) |
6080 | { | 6080 | { |
6081 | IOCPage1_t *pIoc1; | 6081 | IOCPage1_t *pIoc1; |
6082 | CONFIGPARMS cfg; | 6082 | CONFIGPARMS cfg; |
6083 | ConfigPageHeader_t header; | 6083 | ConfigPageHeader_t header; |
6084 | dma_addr_t ioc1_dma; | 6084 | dma_addr_t ioc1_dma; |
6085 | int iocpage1sz = 0; | 6085 | int iocpage1sz = 0; |
6086 | u32 tmp; | 6086 | u32 tmp; |
6087 | 6087 | ||
6088 | /* Check the Coalescing Timeout in IOC Page 1 | 6088 | /* Check the Coalescing Timeout in IOC Page 1 |
6089 | */ | 6089 | */ |
6090 | header.PageVersion = 0; | 6090 | header.PageVersion = 0; |
6091 | header.PageLength = 0; | 6091 | header.PageLength = 0; |
6092 | header.PageNumber = 1; | 6092 | header.PageNumber = 1; |
6093 | header.PageType = MPI_CONFIG_PAGETYPE_IOC; | 6093 | header.PageType = MPI_CONFIG_PAGETYPE_IOC; |
6094 | cfg.cfghdr.hdr = &header; | 6094 | cfg.cfghdr.hdr = &header; |
6095 | cfg.physAddr = -1; | 6095 | cfg.physAddr = -1; |
6096 | cfg.pageAddr = 0; | 6096 | cfg.pageAddr = 0; |
6097 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 6097 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
6098 | cfg.dir = 0; | 6098 | cfg.dir = 0; |
6099 | cfg.timeout = 0; | 6099 | cfg.timeout = 0; |
6100 | if (mpt_config(ioc, &cfg) != 0) | 6100 | if (mpt_config(ioc, &cfg) != 0) |
6101 | return; | 6101 | return; |
6102 | 6102 | ||
6103 | if (header.PageLength == 0) | 6103 | if (header.PageLength == 0) |
6104 | return; | 6104 | return; |
6105 | 6105 | ||
6106 | /* Read Header good, alloc memory | 6106 | /* Read Header good, alloc memory |
6107 | */ | 6107 | */ |
6108 | iocpage1sz = header.PageLength * 4; | 6108 | iocpage1sz = header.PageLength * 4; |
6109 | pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma); | 6109 | pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma); |
6110 | if (!pIoc1) | 6110 | if (!pIoc1) |
6111 | return; | 6111 | return; |
6112 | 6112 | ||
6113 | /* Read the Page and check coalescing timeout | 6113 | /* Read the Page and check coalescing timeout |
6114 | */ | 6114 | */ |
6115 | cfg.physAddr = ioc1_dma; | 6115 | cfg.physAddr = ioc1_dma; |
6116 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | 6116 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
6117 | if (mpt_config(ioc, &cfg) == 0) { | 6117 | if (mpt_config(ioc, &cfg) == 0) { |
6118 | 6118 | ||
6119 | tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING; | 6119 | tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING; |
6120 | if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) { | 6120 | if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) { |
6121 | tmp = le32_to_cpu(pIoc1->CoalescingTimeout); | 6121 | tmp = le32_to_cpu(pIoc1->CoalescingTimeout); |
6122 | 6122 | ||
6123 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n", | 6123 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n", |
6124 | ioc->name, tmp)); | 6124 | ioc->name, tmp)); |
6125 | 6125 | ||
6126 | if (tmp > MPT_COALESCING_TIMEOUT) { | 6126 | if (tmp > MPT_COALESCING_TIMEOUT) { |
6127 | pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT); | 6127 | pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT); |
6128 | 6128 | ||
6129 | /* Write NVRAM and current | 6129 | /* Write NVRAM and current |
6130 | */ | 6130 | */ |
6131 | cfg.dir = 1; | 6131 | cfg.dir = 1; |
6132 | cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; | 6132 | cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; |
6133 | if (mpt_config(ioc, &cfg) == 0) { | 6133 | if (mpt_config(ioc, &cfg) == 0) { |
6134 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n", | 6134 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n", |
6135 | ioc->name, MPT_COALESCING_TIMEOUT)); | 6135 | ioc->name, MPT_COALESCING_TIMEOUT)); |
6136 | 6136 | ||
6137 | cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM; | 6137 | cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM; |
6138 | if (mpt_config(ioc, &cfg) == 0) { | 6138 | if (mpt_config(ioc, &cfg) == 0) { |
6139 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 6139 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
6140 | "Reset NVRAM Coalescing Timeout to = %d\n", | 6140 | "Reset NVRAM Coalescing Timeout to = %d\n", |
6141 | ioc->name, MPT_COALESCING_TIMEOUT)); | 6141 | ioc->name, MPT_COALESCING_TIMEOUT)); |
6142 | } else { | 6142 | } else { |
6143 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 6143 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
6144 | "Reset NVRAM Coalescing Timeout Failed\n", | 6144 | "Reset NVRAM Coalescing Timeout Failed\n", |
6145 | ioc->name)); | 6145 | ioc->name)); |
6146 | } | 6146 | } |
6147 | 6147 | ||
6148 | } else { | 6148 | } else { |
6149 | dprintk(ioc, printk(MYIOC_s_WARN_FMT | 6149 | dprintk(ioc, printk(MYIOC_s_WARN_FMT |
6150 | "Reset of Current Coalescing Timeout Failed!\n", | 6150 | "Reset of Current Coalescing Timeout Failed!\n", |
6151 | ioc->name)); | 6151 | ioc->name)); |
6152 | } | 6152 | } |
6153 | } | 6153 | } |
6154 | 6154 | ||
6155 | } else { | 6155 | } else { |
6156 | dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name)); | 6156 | dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name)); |
6157 | } | 6157 | } |
6158 | } | 6158 | } |
6159 | 6159 | ||
6160 | pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma); | 6160 | pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma); |
6161 | 6161 | ||
6162 | return; | 6162 | return; |
6163 | } | 6163 | } |
6164 | 6164 | ||
6165 | static void | 6165 | static void |
6166 | mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc) | 6166 | mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc) |
6167 | { | 6167 | { |
6168 | CONFIGPARMS cfg; | 6168 | CONFIGPARMS cfg; |
6169 | ConfigPageHeader_t hdr; | 6169 | ConfigPageHeader_t hdr; |
6170 | dma_addr_t buf_dma; | 6170 | dma_addr_t buf_dma; |
6171 | ManufacturingPage0_t *pbuf = NULL; | 6171 | ManufacturingPage0_t *pbuf = NULL; |
6172 | 6172 | ||
6173 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); | 6173 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); |
6174 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); | 6174 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); |
6175 | 6175 | ||
6176 | hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING; | 6176 | hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING; |
6177 | cfg.cfghdr.hdr = &hdr; | 6177 | cfg.cfghdr.hdr = &hdr; |
6178 | cfg.physAddr = -1; | 6178 | cfg.physAddr = -1; |
6179 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | 6179 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
6180 | cfg.timeout = 10; | 6180 | cfg.timeout = 10; |
6181 | 6181 | ||
6182 | if (mpt_config(ioc, &cfg) != 0) | 6182 | if (mpt_config(ioc, &cfg) != 0) |
6183 | goto out; | 6183 | goto out; |
6184 | 6184 | ||
6185 | if (!cfg.cfghdr.hdr->PageLength) | 6185 | if (!cfg.cfghdr.hdr->PageLength) |
6186 | goto out; | 6186 | goto out; |
6187 | 6187 | ||
6188 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | 6188 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
6189 | pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma); | 6189 | pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma); |
6190 | if (!pbuf) | 6190 | if (!pbuf) |
6191 | goto out; | 6191 | goto out; |
6192 | 6192 | ||
6193 | cfg.physAddr = buf_dma; | 6193 | cfg.physAddr = buf_dma; |
6194 | 6194 | ||
6195 | if (mpt_config(ioc, &cfg) != 0) | 6195 | if (mpt_config(ioc, &cfg) != 0) |
6196 | goto out; | 6196 | goto out; |
6197 | 6197 | ||
6198 | memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name)); | 6198 | memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name)); |
6199 | memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly)); | 6199 | memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly)); |
6200 | memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer)); | 6200 | memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer)); |
6201 | 6201 | ||
6202 | out: | 6202 | out: |
6203 | 6203 | ||
6204 | if (pbuf) | 6204 | if (pbuf) |
6205 | pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma); | 6205 | pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma); |
6206 | } | 6206 | } |
6207 | 6207 | ||
6208 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 6208 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
6209 | /** | 6209 | /** |
6210 | * SendEventNotification - Send EventNotification (on or off) request to adapter | 6210 | * SendEventNotification - Send EventNotification (on or off) request to adapter |
6211 | * @ioc: Pointer to MPT_ADAPTER structure | 6211 | * @ioc: Pointer to MPT_ADAPTER structure |
6212 | * @EvSwitch: Event switch flags | 6212 | * @EvSwitch: Event switch flags |
6213 | * @sleepFlag: Specifies whether the process can sleep | 6213 | * @sleepFlag: Specifies whether the process can sleep |
6214 | */ | 6214 | */ |
6215 | static int | 6215 | static int |
6216 | SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag) | 6216 | SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag) |
6217 | { | 6217 | { |
6218 | EventNotification_t evn; | 6218 | EventNotification_t evn; |
6219 | MPIDefaultReply_t reply_buf; | 6219 | MPIDefaultReply_t reply_buf; |
6220 | 6220 | ||
6221 | memset(&evn, 0, sizeof(EventNotification_t)); | 6221 | memset(&evn, 0, sizeof(EventNotification_t)); |
6222 | memset(&reply_buf, 0, sizeof(MPIDefaultReply_t)); | 6222 | memset(&reply_buf, 0, sizeof(MPIDefaultReply_t)); |
6223 | 6223 | ||
6224 | evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION; | 6224 | evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION; |
6225 | evn.Switch = EvSwitch; | 6225 | evn.Switch = EvSwitch; |
6226 | evn.MsgContext = cpu_to_le32(mpt_base_index << 16); | 6226 | evn.MsgContext = cpu_to_le32(mpt_base_index << 16); |
6227 | 6227 | ||
6228 | devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 6228 | devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
6229 | "Sending EventNotification (%d) request %p\n", | 6229 | "Sending EventNotification (%d) request %p\n", |
6230 | ioc->name, EvSwitch, &evn)); | 6230 | ioc->name, EvSwitch, &evn)); |
6231 | 6231 | ||
6232 | return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t), | 6232 | return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t), |
6233 | (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30, | 6233 | (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30, |
6234 | sleepFlag); | 6234 | sleepFlag); |
6235 | } | 6235 | } |
6236 | 6236 | ||
6237 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 6237 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
6238 | /** | 6238 | /** |
6239 | * SendEventAck - Send EventAck request to MPT adapter. | 6239 | * SendEventAck - Send EventAck request to MPT adapter. |
6240 | * @ioc: Pointer to MPT_ADAPTER structure | 6240 | * @ioc: Pointer to MPT_ADAPTER structure |
6241 | * @evnp: Pointer to original EventNotification request | 6241 | * @evnp: Pointer to original EventNotification request |
6242 | */ | 6242 | */ |
6243 | static int | 6243 | static int |
6244 | SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) | 6244 | SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) |
6245 | { | 6245 | { |
6246 | EventAck_t *pAck; | 6246 | EventAck_t *pAck; |
6247 | 6247 | ||
6248 | if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { | 6248 | if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { |
6249 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", | 6249 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", |
6250 | ioc->name, __func__)); | 6250 | ioc->name, __func__)); |
6251 | return -1; | 6251 | return -1; |
6252 | } | 6252 | } |
6253 | 6253 | ||
6254 | devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name)); | 6254 | devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name)); |
6255 | 6255 | ||
6256 | pAck->Function = MPI_FUNCTION_EVENT_ACK; | 6256 | pAck->Function = MPI_FUNCTION_EVENT_ACK; |
6257 | pAck->ChainOffset = 0; | 6257 | pAck->ChainOffset = 0; |
6258 | pAck->Reserved[0] = pAck->Reserved[1] = 0; | 6258 | pAck->Reserved[0] = pAck->Reserved[1] = 0; |
6259 | pAck->MsgFlags = 0; | 6259 | pAck->MsgFlags = 0; |
6260 | pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0; | 6260 | pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0; |
6261 | pAck->Event = evnp->Event; | 6261 | pAck->Event = evnp->Event; |
6262 | pAck->EventContext = evnp->EventContext; | 6262 | pAck->EventContext = evnp->EventContext; |
6263 | 6263 | ||
6264 | mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck); | 6264 | mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck); |
6265 | 6265 | ||
6266 | return 0; | 6266 | return 0; |
6267 | } | 6267 | } |
6268 | 6268 | ||
6269 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 6269 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
6270 | /** | 6270 | /** |
6271 | * mpt_config - Generic function to issue config message | 6271 | * mpt_config - Generic function to issue config message |
6272 | * @ioc: Pointer to an adapter structure | 6272 | * @ioc: Pointer to an adapter structure |
6273 | * @pCfg: Pointer to a configuration structure. Struct contains | 6273 | * @pCfg: Pointer to a configuration structure. Struct contains |
6274 | * action, page address, direction, physical address | 6274 | * action, page address, direction, physical address |
6275 | * and pointer to a configuration page header | 6275 | * and pointer to a configuration page header |
6276 | * Page header is updated. | 6276 | * Page header is updated. |
6277 | * | 6277 | * |
6278 | * Returns 0 for success | 6278 | * Returns 0 for success |
6279 | * -EPERM if not allowed due to ISR context | 6279 | * -EPERM if not allowed due to ISR context |
6280 | * -EAGAIN if no msg frames currently available | 6280 | * -EAGAIN if no msg frames currently available |
6281 | * -EFAULT for non-successful reply or no reply (timeout) | 6281 | * -EFAULT for non-successful reply or no reply (timeout) |
6282 | */ | 6282 | */ |
6283 | int | 6283 | int |
6284 | mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) | 6284 | mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) |
6285 | { | 6285 | { |
6286 | Config_t *pReq; | 6286 | Config_t *pReq; |
6287 | ConfigReply_t *pReply; | 6287 | ConfigReply_t *pReply; |
6288 | ConfigExtendedPageHeader_t *pExtHdr = NULL; | 6288 | ConfigExtendedPageHeader_t *pExtHdr = NULL; |
6289 | MPT_FRAME_HDR *mf; | 6289 | MPT_FRAME_HDR *mf; |
6290 | int ii; | 6290 | int ii; |
6291 | int flagsLength; | 6291 | int flagsLength; |
6292 | long timeout; | 6292 | long timeout; |
6293 | int ret; | 6293 | int ret; |
6294 | u8 page_type = 0, extend_page; | 6294 | u8 page_type = 0, extend_page; |
6295 | unsigned long timeleft; | 6295 | unsigned long timeleft; |
6296 | unsigned long flags; | 6296 | unsigned long flags; |
6297 | int in_isr; | 6297 | int in_isr; |
6298 | u8 issue_hard_reset = 0; | 6298 | u8 issue_hard_reset = 0; |
6299 | u8 retry_count = 0; | 6299 | u8 retry_count = 0; |
6300 | 6300 | ||
6301 | /* Prevent calling wait_event() (below), if caller happens | 6301 | /* Prevent calling wait_event() (below), if caller happens |
6302 | * to be in ISR context, because that is fatal! | 6302 | * to be in ISR context, because that is fatal! |
6303 | */ | 6303 | */ |
6304 | in_isr = in_interrupt(); | 6304 | in_isr = in_interrupt(); |
6305 | if (in_isr) { | 6305 | if (in_isr) { |
6306 | dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n", | 6306 | dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n", |
6307 | ioc->name)); | 6307 | ioc->name)); |
6308 | return -EPERM; | 6308 | return -EPERM; |
6309 | } | 6309 | } |
6310 | 6310 | ||
6311 | /* don't send a config page during diag reset */ | 6311 | /* don't send a config page during diag reset */ |
6312 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); | 6312 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); |
6313 | if (ioc->ioc_reset_in_progress) { | 6313 | if (ioc->ioc_reset_in_progress) { |
6314 | dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 6314 | dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
6315 | "%s: busy with host reset\n", ioc->name, __func__)); | 6315 | "%s: busy with host reset\n", ioc->name, __func__)); |
6316 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | 6316 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); |
6317 | return -EBUSY; | 6317 | return -EBUSY; |
6318 | } | 6318 | } |
6319 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | 6319 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); |
6320 | 6320 | ||
6321 | /* don't send if no chance of success */ | 6321 | /* don't send if no chance of success */ |
6322 | if (!ioc->active || | 6322 | if (!ioc->active || |
6323 | mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) { | 6323 | mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) { |
6324 | dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 6324 | dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
6325 | "%s: ioc not operational, %d, %xh\n", | 6325 | "%s: ioc not operational, %d, %xh\n", |
6326 | ioc->name, __func__, ioc->active, | 6326 | ioc->name, __func__, ioc->active, |
6327 | mpt_GetIocState(ioc, 0))); | 6327 | mpt_GetIocState(ioc, 0))); |
6328 | return -EFAULT; | 6328 | return -EFAULT; |
6329 | } | 6329 | } |
6330 | 6330 | ||
6331 | retry_config: | 6331 | retry_config: |
6332 | mutex_lock(&ioc->mptbase_cmds.mutex); | 6332 | mutex_lock(&ioc->mptbase_cmds.mutex); |
6333 | /* init the internal cmd struct */ | 6333 | /* init the internal cmd struct */ |
6334 | memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE); | 6334 | memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE); |
6335 | INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status) | 6335 | INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status) |
6336 | 6336 | ||
6337 | /* Get and Populate a free Frame | 6337 | /* Get and Populate a free Frame |
6338 | */ | 6338 | */ |
6339 | if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { | 6339 | if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { |
6340 | dcprintk(ioc, printk(MYIOC_s_WARN_FMT | 6340 | dcprintk(ioc, printk(MYIOC_s_WARN_FMT |
6341 | "mpt_config: no msg frames!\n", ioc->name)); | 6341 | "mpt_config: no msg frames!\n", ioc->name)); |
6342 | ret = -EAGAIN; | 6342 | ret = -EAGAIN; |
6343 | goto out; | 6343 | goto out; |
6344 | } | 6344 | } |
6345 | 6345 | ||
6346 | pReq = (Config_t *)mf; | 6346 | pReq = (Config_t *)mf; |
6347 | pReq->Action = pCfg->action; | 6347 | pReq->Action = pCfg->action; |
6348 | pReq->Reserved = 0; | 6348 | pReq->Reserved = 0; |
6349 | pReq->ChainOffset = 0; | 6349 | pReq->ChainOffset = 0; |
6350 | pReq->Function = MPI_FUNCTION_CONFIG; | 6350 | pReq->Function = MPI_FUNCTION_CONFIG; |
6351 | 6351 | ||
6352 | /* Assume page type is not extended and clear "reserved" fields. */ | 6352 | /* Assume page type is not extended and clear "reserved" fields. */ |
6353 | pReq->ExtPageLength = 0; | 6353 | pReq->ExtPageLength = 0; |
6354 | pReq->ExtPageType = 0; | 6354 | pReq->ExtPageType = 0; |
6355 | pReq->MsgFlags = 0; | 6355 | pReq->MsgFlags = 0; |
6356 | 6356 | ||
6357 | for (ii=0; ii < 8; ii++) | 6357 | for (ii=0; ii < 8; ii++) |
6358 | pReq->Reserved2[ii] = 0; | 6358 | pReq->Reserved2[ii] = 0; |
6359 | 6359 | ||
6360 | pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion; | 6360 | pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion; |
6361 | pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength; | 6361 | pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength; |
6362 | pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber; | 6362 | pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber; |
6363 | pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); | 6363 | pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); |
6364 | 6364 | ||
6365 | if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) { | 6365 | if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) { |
6366 | pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr; | 6366 | pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr; |
6367 | pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength); | 6367 | pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength); |
6368 | pReq->ExtPageType = pExtHdr->ExtPageType; | 6368 | pReq->ExtPageType = pExtHdr->ExtPageType; |
6369 | pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; | 6369 | pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; |
6370 | 6370 | ||
6371 | /* Page Length must be treated as a reserved field for the | 6371 | /* Page Length must be treated as a reserved field for the |
6372 | * extended header. | 6372 | * extended header. |
6373 | */ | 6373 | */ |
6374 | pReq->Header.PageLength = 0; | 6374 | pReq->Header.PageLength = 0; |
6375 | } | 6375 | } |
6376 | 6376 | ||
6377 | pReq->PageAddress = cpu_to_le32(pCfg->pageAddr); | 6377 | pReq->PageAddress = cpu_to_le32(pCfg->pageAddr); |
6378 | 6378 | ||
6379 | /* Add a SGE to the config request. | 6379 | /* Add a SGE to the config request. |
6380 | */ | 6380 | */ |
6381 | if (pCfg->dir) | 6381 | if (pCfg->dir) |
6382 | flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; | 6382 | flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; |
6383 | else | 6383 | else |
6384 | flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; | 6384 | flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; |
6385 | 6385 | ||
6386 | if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == | 6386 | if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == |
6387 | MPI_CONFIG_PAGETYPE_EXTENDED) { | 6387 | MPI_CONFIG_PAGETYPE_EXTENDED) { |
6388 | flagsLength |= pExtHdr->ExtPageLength * 4; | 6388 | flagsLength |= pExtHdr->ExtPageLength * 4; |
6389 | page_type = pReq->ExtPageType; | 6389 | page_type = pReq->ExtPageType; |
6390 | extend_page = 1; | 6390 | extend_page = 1; |
6391 | } else { | 6391 | } else { |
6392 | flagsLength |= pCfg->cfghdr.hdr->PageLength * 4; | 6392 | flagsLength |= pCfg->cfghdr.hdr->PageLength * 4; |
6393 | page_type = pReq->Header.PageType; | 6393 | page_type = pReq->Header.PageType; |
6394 | extend_page = 0; | 6394 | extend_page = 0; |
6395 | } | 6395 | } |
6396 | 6396 | ||
6397 | dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 6397 | dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
6398 | "Sending Config request type 0x%x, page 0x%x and action %d\n", | 6398 | "Sending Config request type 0x%x, page 0x%x and action %d\n", |
6399 | ioc->name, page_type, pReq->Header.PageNumber, pReq->Action)); | 6399 | ioc->name, page_type, pReq->Header.PageNumber, pReq->Action)); |
6400 | 6400 | ||
6401 | ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); | 6401 | ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); |
6402 | timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout; | 6402 | timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout; |
6403 | mpt_put_msg_frame(mpt_base_index, ioc, mf); | 6403 | mpt_put_msg_frame(mpt_base_index, ioc, mf); |
6404 | timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, | 6404 | timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, |
6405 | timeout); | 6405 | timeout); |
6406 | if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { | 6406 | if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { |
6407 | ret = -ETIME; | 6407 | ret = -ETIME; |
6408 | dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 6408 | dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
6409 | "Failed Sending Config request type 0x%x, page 0x%x," | 6409 | "Failed Sending Config request type 0x%x, page 0x%x," |
6410 | " action %d, status %xh, time left %ld\n\n", | 6410 | " action %d, status %xh, time left %ld\n\n", |
6411 | ioc->name, page_type, pReq->Header.PageNumber, | 6411 | ioc->name, page_type, pReq->Header.PageNumber, |
6412 | pReq->Action, ioc->mptbase_cmds.status, timeleft)); | 6412 | pReq->Action, ioc->mptbase_cmds.status, timeleft)); |
6413 | if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) | 6413 | if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) |
6414 | goto out; | 6414 | goto out; |
6415 | if (!timeleft) | 6415 | if (!timeleft) |
6416 | issue_hard_reset = 1; | 6416 | issue_hard_reset = 1; |
6417 | goto out; | 6417 | goto out; |
6418 | } | 6418 | } |
6419 | 6419 | ||
6420 | if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { | 6420 | if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { |
6421 | ret = -1; | 6421 | ret = -1; |
6422 | goto out; | 6422 | goto out; |
6423 | } | 6423 | } |
6424 | pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply; | 6424 | pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply; |
6425 | ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; | 6425 | ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; |
6426 | if (ret == MPI_IOCSTATUS_SUCCESS) { | 6426 | if (ret == MPI_IOCSTATUS_SUCCESS) { |
6427 | if (extend_page) { | 6427 | if (extend_page) { |
6428 | pCfg->cfghdr.ehdr->ExtPageLength = | 6428 | pCfg->cfghdr.ehdr->ExtPageLength = |
6429 | le16_to_cpu(pReply->ExtPageLength); | 6429 | le16_to_cpu(pReply->ExtPageLength); |
6430 | pCfg->cfghdr.ehdr->ExtPageType = | 6430 | pCfg->cfghdr.ehdr->ExtPageType = |
6431 | pReply->ExtPageType; | 6431 | pReply->ExtPageType; |
6432 | } | 6432 | } |
6433 | pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion; | 6433 | pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion; |
6434 | pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength; | 6434 | pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength; |
6435 | pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber; | 6435 | pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber; |
6436 | pCfg->cfghdr.hdr->PageType = pReply->Header.PageType; | 6436 | pCfg->cfghdr.hdr->PageType = pReply->Header.PageType; |
6437 | 6437 | ||
6438 | } | 6438 | } |
6439 | 6439 | ||
6440 | if (retry_count) | 6440 | if (retry_count) |
6441 | printk(MYIOC_s_INFO_FMT "Retry completed " | 6441 | printk(MYIOC_s_INFO_FMT "Retry completed " |
6442 | "ret=0x%x timeleft=%ld\n", | 6442 | "ret=0x%x timeleft=%ld\n", |
6443 | ioc->name, ret, timeleft); | 6443 | ioc->name, ret, timeleft); |
6444 | 6444 | ||
6445 | dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n", | 6445 | dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n", |
6446 | ret, le32_to_cpu(pReply->IOCLogInfo))); | 6446 | ret, le32_to_cpu(pReply->IOCLogInfo))); |
6447 | 6447 | ||
6448 | out: | 6448 | out: |
6449 | 6449 | ||
6450 | CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) | 6450 | CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) |
6451 | mutex_unlock(&ioc->mptbase_cmds.mutex); | 6451 | mutex_unlock(&ioc->mptbase_cmds.mutex); |
6452 | if (issue_hard_reset) { | 6452 | if (issue_hard_reset) { |
6453 | issue_hard_reset = 0; | 6453 | issue_hard_reset = 0; |
6454 | printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", | 6454 | printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", |
6455 | ioc->name, __func__); | 6455 | ioc->name, __func__); |
6456 | mpt_HardResetHandler(ioc, CAN_SLEEP); | 6456 | mpt_HardResetHandler(ioc, CAN_SLEEP); |
6457 | mpt_free_msg_frame(ioc, mf); | 6457 | mpt_free_msg_frame(ioc, mf); |
6458 | /* attempt one retry for a timed out command */ | 6458 | /* attempt one retry for a timed out command */ |
6459 | if (!retry_count) { | 6459 | if (!retry_count) { |
6460 | printk(MYIOC_s_INFO_FMT | 6460 | printk(MYIOC_s_INFO_FMT |
6461 | "Attempting Retry Config request" | 6461 | "Attempting Retry Config request" |
6462 | " type 0x%x, page 0x%x," | 6462 | " type 0x%x, page 0x%x," |
6463 | " action %d\n", ioc->name, page_type, | 6463 | " action %d\n", ioc->name, page_type, |
6464 | pCfg->cfghdr.hdr->PageNumber, pCfg->action); | 6464 | pCfg->cfghdr.hdr->PageNumber, pCfg->action); |
6465 | retry_count++; | 6465 | retry_count++; |
6466 | goto retry_config; | 6466 | goto retry_config; |
6467 | } | 6467 | } |
6468 | } | 6468 | } |
6469 | return ret; | 6469 | return ret; |
6470 | 6470 | ||
6471 | } | 6471 | } |
6472 | 6472 | ||
6473 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 6473 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
6474 | /** | 6474 | /** |
6475 | * mpt_ioc_reset - Base cleanup for hard reset | 6475 | * mpt_ioc_reset - Base cleanup for hard reset |
6476 | * @ioc: Pointer to the adapter structure | 6476 | * @ioc: Pointer to the adapter structure |
6477 | * @reset_phase: Indicates pre- or post-reset functionality | 6477 | * @reset_phase: Indicates pre- or post-reset functionality |
6478 | * | 6478 | * |
6479 | * Remark: Frees resources with internally generated commands. | 6479 | * Remark: Frees resources with internally generated commands. |
6480 | */ | 6480 | */ |
6481 | static int | 6481 | static int |
6482 | mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) | 6482 | mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) |
6483 | { | 6483 | { |
6484 | switch (reset_phase) { | 6484 | switch (reset_phase) { |
6485 | case MPT_IOC_SETUP_RESET: | 6485 | case MPT_IOC_SETUP_RESET: |
6486 | ioc->taskmgmt_quiesce_io = 1; | 6486 | ioc->taskmgmt_quiesce_io = 1; |
6487 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 6487 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
6488 | "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); | 6488 | "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); |
6489 | break; | 6489 | break; |
6490 | case MPT_IOC_PRE_RESET: | 6490 | case MPT_IOC_PRE_RESET: |
6491 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 6491 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
6492 | "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); | 6492 | "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); |
6493 | break; | 6493 | break; |
6494 | case MPT_IOC_POST_RESET: | 6494 | case MPT_IOC_POST_RESET: |
6495 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 6495 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
6496 | "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); | 6496 | "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); |
6497 | /* wake up mptbase_cmds */ | 6497 | /* wake up mptbase_cmds */ |
6498 | if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { | 6498 | if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { |
6499 | ioc->mptbase_cmds.status |= | 6499 | ioc->mptbase_cmds.status |= |
6500 | MPT_MGMT_STATUS_DID_IOCRESET; | 6500 | MPT_MGMT_STATUS_DID_IOCRESET; |
6501 | complete(&ioc->mptbase_cmds.done); | 6501 | complete(&ioc->mptbase_cmds.done); |
6502 | } | 6502 | } |
6503 | /* wake up taskmgmt_cmds */ | 6503 | /* wake up taskmgmt_cmds */ |
6504 | if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { | 6504 | if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { |
6505 | ioc->taskmgmt_cmds.status |= | 6505 | ioc->taskmgmt_cmds.status |= |
6506 | MPT_MGMT_STATUS_DID_IOCRESET; | 6506 | MPT_MGMT_STATUS_DID_IOCRESET; |
6507 | complete(&ioc->taskmgmt_cmds.done); | 6507 | complete(&ioc->taskmgmt_cmds.done); |
6508 | } | 6508 | } |
6509 | break; | 6509 | break; |
6510 | default: | 6510 | default: |
6511 | break; | 6511 | break; |
6512 | } | 6512 | } |
6513 | 6513 | ||
6514 | return 1; /* currently means nothing really */ | 6514 | return 1; /* currently means nothing really */ |
6515 | } | 6515 | } |
6516 | 6516 | ||
6517 | 6517 | ||
6518 | #ifdef CONFIG_PROC_FS /* { */ | 6518 | #ifdef CONFIG_PROC_FS /* { */ |
6519 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 6519 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
6520 | /* | 6520 | /* |
6521 | * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff... | 6521 | * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff... |
6522 | */ | 6522 | */ |
6523 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 6523 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
6524 | /** | 6524 | /** |
6525 | * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries. | 6525 | * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries. |
6526 | * | 6526 | * |
6527 | * Returns 0 for success, non-zero for failure. | 6527 | * Returns 0 for success, non-zero for failure. |
6528 | */ | 6528 | */ |
6529 | static int | 6529 | static int |
6530 | procmpt_create(void) | 6530 | procmpt_create(void) |
6531 | { | 6531 | { |
6532 | struct proc_dir_entry *ent; | 6532 | struct proc_dir_entry *ent; |
6533 | 6533 | ||
6534 | mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL); | 6534 | mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL); |
6535 | if (mpt_proc_root_dir == NULL) | 6535 | if (mpt_proc_root_dir == NULL) |
6536 | return -ENOTDIR; | 6536 | return -ENOTDIR; |
6537 | 6537 | ||
6538 | ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir); | 6538 | ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir); |
6539 | if (ent) | 6539 | if (ent) |
6540 | ent->read_proc = procmpt_summary_read; | 6540 | ent->read_proc = procmpt_summary_read; |
6541 | 6541 | ||
6542 | ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir); | 6542 | ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir); |
6543 | if (ent) | 6543 | if (ent) |
6544 | ent->read_proc = procmpt_version_read; | 6544 | ent->read_proc = procmpt_version_read; |
6545 | 6545 | ||
6546 | return 0; | 6546 | return 0; |
6547 | } | 6547 | } |
6548 | 6548 | ||
6549 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 6549 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
6550 | /** | 6550 | /** |
6551 | * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries. | 6551 | * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries. |
6552 | * | 6552 | * |
6553 | * Returns 0 for success, non-zero for failure. | 6553 | * Returns 0 for success, non-zero for failure. |
6554 | */ | 6554 | */ |
6555 | static void | 6555 | static void |
6556 | procmpt_destroy(void) | 6556 | procmpt_destroy(void) |
6557 | { | 6557 | { |
6558 | remove_proc_entry("version", mpt_proc_root_dir); | 6558 | remove_proc_entry("version", mpt_proc_root_dir); |
6559 | remove_proc_entry("summary", mpt_proc_root_dir); | 6559 | remove_proc_entry("summary", mpt_proc_root_dir); |
6560 | remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL); | 6560 | remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL); |
6561 | } | 6561 | } |
6562 | 6562 | ||
6563 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 6563 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
6564 | /** | 6564 | /** |
6565 | * procmpt_summary_read - Handle read request of a summary file | 6565 | * procmpt_summary_read - Handle read request of a summary file |
6566 | * @buf: Pointer to area to write information | 6566 | * @buf: Pointer to area to write information |
6567 | * @start: Pointer to start pointer | 6567 | * @start: Pointer to start pointer |
6568 | * @offset: Offset to start writing | 6568 | * @offset: Offset to start writing |
6569 | * @request: Amount of read data requested | 6569 | * @request: Amount of read data requested |
6570 | * @eof: Pointer to EOF integer | 6570 | * @eof: Pointer to EOF integer |
6571 | * @data: Pointer | 6571 | * @data: Pointer |
6572 | * | 6572 | * |
6573 | * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary. | 6573 | * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary. |
6574 | * Returns number of characters written to process performing the read. | 6574 | * Returns number of characters written to process performing the read. |
6575 | */ | 6575 | */ |
6576 | static int | 6576 | static int |
6577 | procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) | 6577 | procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) |
6578 | { | 6578 | { |
6579 | MPT_ADAPTER *ioc; | 6579 | MPT_ADAPTER *ioc; |
6580 | char *out = buf; | 6580 | char *out = buf; |
6581 | int len; | 6581 | int len; |
6582 | 6582 | ||
6583 | if (data) { | 6583 | if (data) { |
6584 | int more = 0; | 6584 | int more = 0; |
6585 | 6585 | ||
6586 | ioc = data; | 6586 | ioc = data; |
6587 | mpt_print_ioc_summary(ioc, out, &more, 0, 1); | 6587 | mpt_print_ioc_summary(ioc, out, &more, 0, 1); |
6588 | 6588 | ||
6589 | out += more; | 6589 | out += more; |
6590 | } else { | 6590 | } else { |
6591 | list_for_each_entry(ioc, &ioc_list, list) { | 6591 | list_for_each_entry(ioc, &ioc_list, list) { |
6592 | int more = 0; | 6592 | int more = 0; |
6593 | 6593 | ||
6594 | mpt_print_ioc_summary(ioc, out, &more, 0, 1); | 6594 | mpt_print_ioc_summary(ioc, out, &more, 0, 1); |
6595 | 6595 | ||
6596 | out += more; | 6596 | out += more; |
6597 | if ((out-buf) >= request) | 6597 | if ((out-buf) >= request) |
6598 | break; | 6598 | break; |
6599 | } | 6599 | } |
6600 | } | 6600 | } |
6601 | 6601 | ||
6602 | len = out - buf; | 6602 | len = out - buf; |
6603 | 6603 | ||
6604 | MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); | 6604 | MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); |
6605 | } | 6605 | } |
6606 | 6606 | ||
6607 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 6607 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
6608 | /** | 6608 | /** |
6609 | * procmpt_version_read - Handle read request from /proc/mpt/version. | 6609 | * procmpt_version_read - Handle read request from /proc/mpt/version. |
6610 | * @buf: Pointer to area to write information | 6610 | * @buf: Pointer to area to write information |
6611 | * @start: Pointer to start pointer | 6611 | * @start: Pointer to start pointer |
6612 | * @offset: Offset to start writing | 6612 | * @offset: Offset to start writing |
6613 | * @request: Amount of read data requested | 6613 | * @request: Amount of read data requested |
6614 | * @eof: Pointer to EOF integer | 6614 | * @eof: Pointer to EOF integer |
6615 | * @data: Pointer | 6615 | * @data: Pointer |
6616 | * | 6616 | * |
6617 | * Returns number of characters written to process performing the read. | 6617 | * Returns number of characters written to process performing the read. |
6618 | */ | 6618 | */ |
6619 | static int | 6619 | static int |
6620 | procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) | 6620 | procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) |
6621 | { | 6621 | { |
6622 | u8 cb_idx; | 6622 | u8 cb_idx; |
6623 | int scsi, fc, sas, lan, ctl, targ, dmp; | 6623 | int scsi, fc, sas, lan, ctl, targ, dmp; |
6624 | char *drvname; | 6624 | char *drvname; |
6625 | int len; | 6625 | int len; |
6626 | 6626 | ||
6627 | len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON); | 6627 | len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON); |
6628 | len += sprintf(buf+len, " Fusion MPT base driver\n"); | 6628 | len += sprintf(buf+len, " Fusion MPT base driver\n"); |
6629 | 6629 | ||
6630 | scsi = fc = sas = lan = ctl = targ = dmp = 0; | 6630 | scsi = fc = sas = lan = ctl = targ = dmp = 0; |
6631 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { | 6631 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { |
6632 | drvname = NULL; | 6632 | drvname = NULL; |
6633 | if (MptCallbacks[cb_idx]) { | 6633 | if (MptCallbacks[cb_idx]) { |
6634 | switch (MptDriverClass[cb_idx]) { | 6634 | switch (MptDriverClass[cb_idx]) { |
6635 | case MPTSPI_DRIVER: | 6635 | case MPTSPI_DRIVER: |
6636 | if (!scsi++) drvname = "SPI host"; | 6636 | if (!scsi++) drvname = "SPI host"; |
6637 | break; | 6637 | break; |
6638 | case MPTFC_DRIVER: | 6638 | case MPTFC_DRIVER: |
6639 | if (!fc++) drvname = "FC host"; | 6639 | if (!fc++) drvname = "FC host"; |
6640 | break; | 6640 | break; |
6641 | case MPTSAS_DRIVER: | 6641 | case MPTSAS_DRIVER: |
6642 | if (!sas++) drvname = "SAS host"; | 6642 | if (!sas++) drvname = "SAS host"; |
6643 | break; | 6643 | break; |
6644 | case MPTLAN_DRIVER: | 6644 | case MPTLAN_DRIVER: |
6645 | if (!lan++) drvname = "LAN"; | 6645 | if (!lan++) drvname = "LAN"; |
6646 | break; | 6646 | break; |
6647 | case MPTSTM_DRIVER: | 6647 | case MPTSTM_DRIVER: |
6648 | if (!targ++) drvname = "SCSI target"; | 6648 | if (!targ++) drvname = "SCSI target"; |
6649 | break; | 6649 | break; |
6650 | case MPTCTL_DRIVER: | 6650 | case MPTCTL_DRIVER: |
6651 | if (!ctl++) drvname = "ioctl"; | 6651 | if (!ctl++) drvname = "ioctl"; |
6652 | break; | 6652 | break; |
6653 | } | 6653 | } |
6654 | 6654 | ||
6655 | if (drvname) | 6655 | if (drvname) |
6656 | len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname); | 6656 | len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname); |
6657 | } | 6657 | } |
6658 | } | 6658 | } |
6659 | 6659 | ||
6660 | MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); | 6660 | MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); |
6661 | } | 6661 | } |
6662 | 6662 | ||
6663 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 6663 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
6664 | /** | 6664 | /** |
6665 | * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info. | 6665 | * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info. |
6666 | * @buf: Pointer to area to write information | 6666 | * @buf: Pointer to area to write information |
6667 | * @start: Pointer to start pointer | 6667 | * @start: Pointer to start pointer |
6668 | * @offset: Offset to start writing | 6668 | * @offset: Offset to start writing |
6669 | * @request: Amount of read data requested | 6669 | * @request: Amount of read data requested |
6670 | * @eof: Pointer to EOF integer | 6670 | * @eof: Pointer to EOF integer |
6671 | * @data: Pointer | 6671 | * @data: Pointer |
6672 | * | 6672 | * |
6673 | * Returns number of characters written to process performing the read. | 6673 | * Returns number of characters written to process performing the read. |
6674 | */ | 6674 | */ |
6675 | static int | 6675 | static int |
6676 | procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) | 6676 | procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) |
6677 | { | 6677 | { |
6678 | MPT_ADAPTER *ioc = data; | 6678 | MPT_ADAPTER *ioc = data; |
6679 | int len; | 6679 | int len; |
6680 | char expVer[32]; | 6680 | char expVer[32]; |
6681 | int sz; | 6681 | int sz; |
6682 | int p; | 6682 | int p; |
6683 | 6683 | ||
6684 | mpt_get_fw_exp_ver(expVer, ioc); | 6684 | mpt_get_fw_exp_ver(expVer, ioc); |
6685 | 6685 | ||
6686 | len = sprintf(buf, "%s:", ioc->name); | 6686 | len = sprintf(buf, "%s:", ioc->name); |
6687 | if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) | 6687 | if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) |
6688 | len += sprintf(buf+len, " (f/w download boot flag set)"); | 6688 | len += sprintf(buf+len, " (f/w download boot flag set)"); |
6689 | // if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL) | 6689 | // if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL) |
6690 | // len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!"); | 6690 | // len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!"); |
6691 | 6691 | ||
6692 | len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n", | 6692 | len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n", |
6693 | ioc->facts.ProductID, | 6693 | ioc->facts.ProductID, |
6694 | ioc->prod_name); | 6694 | ioc->prod_name); |
6695 | len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer); | 6695 | len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer); |
6696 | if (ioc->facts.FWImageSize) | 6696 | if (ioc->facts.FWImageSize) |
6697 | len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize); | 6697 | len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize); |
6698 | len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion); | 6698 | len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion); |
6699 | len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit); | 6699 | len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit); |
6700 | len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState); | 6700 | len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState); |
6701 | 6701 | ||
6702 | len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n", | 6702 | len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n", |
6703 | ioc->facts.CurrentHostMfaHighAddr); | 6703 | ioc->facts.CurrentHostMfaHighAddr); |
6704 | len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n", | 6704 | len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n", |
6705 | ioc->facts.CurrentSenseBufferHighAddr); | 6705 | ioc->facts.CurrentSenseBufferHighAddr); |
6706 | 6706 | ||
6707 | len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth); | 6707 | len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth); |
6708 | len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize); | 6708 | len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize); |
6709 | 6709 | ||
6710 | len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n", | 6710 | len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n", |
6711 | (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma); | 6711 | (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma); |
6712 | /* | 6712 | /* |
6713 | * Rounding UP to nearest 4-kB boundary here... | 6713 | * Rounding UP to nearest 4-kB boundary here... |
6714 | */ | 6714 | */ |
6715 | sz = (ioc->req_sz * ioc->req_depth) + 128; | 6715 | sz = (ioc->req_sz * ioc->req_depth) + 128; |
6716 | sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; | 6716 | sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; |
6717 | len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n", | 6717 | len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n", |
6718 | ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz); | 6718 | ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz); |
6719 | len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n", | 6719 | len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n", |
6720 | 4*ioc->facts.RequestFrameSize, | 6720 | 4*ioc->facts.RequestFrameSize, |
6721 | ioc->facts.GlobalCredits); | 6721 | ioc->facts.GlobalCredits); |
6722 | 6722 | ||
6723 | len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n", | 6723 | len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n", |
6724 | (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma); | 6724 | (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma); |
6725 | sz = (ioc->reply_sz * ioc->reply_depth) + 128; | 6725 | sz = (ioc->reply_sz * ioc->reply_depth) + 128; |
6726 | len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n", | 6726 | len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n", |
6727 | ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz); | 6727 | ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz); |
6728 | len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n", | 6728 | len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n", |
6729 | ioc->facts.CurReplyFrameSize, | 6729 | ioc->facts.CurReplyFrameSize, |
6730 | ioc->facts.ReplyQueueDepth); | 6730 | ioc->facts.ReplyQueueDepth); |
6731 | 6731 | ||
6732 | len += sprintf(buf+len, " MaxDevices = %d\n", | 6732 | len += sprintf(buf+len, " MaxDevices = %d\n", |
6733 | (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices); | 6733 | (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices); |
6734 | len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses); | 6734 | len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses); |
6735 | 6735 | ||
6736 | /* per-port info */ | 6736 | /* per-port info */ |
6737 | for (p=0; p < ioc->facts.NumberOfPorts; p++) { | 6737 | for (p=0; p < ioc->facts.NumberOfPorts; p++) { |
6738 | len += sprintf(buf+len, " PortNumber = %d (of %d)\n", | 6738 | len += sprintf(buf+len, " PortNumber = %d (of %d)\n", |
6739 | p+1, | 6739 | p+1, |
6740 | ioc->facts.NumberOfPorts); | 6740 | ioc->facts.NumberOfPorts); |
6741 | if (ioc->bus_type == FC) { | 6741 | if (ioc->bus_type == FC) { |
6742 | if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { | 6742 | if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { |
6743 | u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; | 6743 | u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; |
6744 | len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", | 6744 | len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", |
6745 | a[5], a[4], a[3], a[2], a[1], a[0]); | 6745 | a[5], a[4], a[3], a[2], a[1], a[0]); |
6746 | } | 6746 | } |
6747 | len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n", | 6747 | len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n", |
6748 | ioc->fc_port_page0[p].WWNN.High, | 6748 | ioc->fc_port_page0[p].WWNN.High, |
6749 | ioc->fc_port_page0[p].WWNN.Low, | 6749 | ioc->fc_port_page0[p].WWNN.Low, |
6750 | ioc->fc_port_page0[p].WWPN.High, | 6750 | ioc->fc_port_page0[p].WWPN.High, |
6751 | ioc->fc_port_page0[p].WWPN.Low); | 6751 | ioc->fc_port_page0[p].WWPN.Low); |
6752 | } | 6752 | } |
6753 | } | 6753 | } |
6754 | 6754 | ||
6755 | MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); | 6755 | MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); |
6756 | } | 6756 | } |
6757 | 6757 | ||
6758 | #endif /* CONFIG_PROC_FS } */ | 6758 | #endif /* CONFIG_PROC_FS } */ |
6759 | 6759 | ||
6760 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 6760 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
6761 | static void | 6761 | static void |
6762 | mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc) | 6762 | mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc) |
6763 | { | 6763 | { |
6764 | buf[0] ='\0'; | 6764 | buf[0] ='\0'; |
6765 | if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) { | 6765 | if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) { |
6766 | sprintf(buf, " (Exp %02d%02d)", | 6766 | sprintf(buf, " (Exp %02d%02d)", |
6767 | (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */ | 6767 | (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */ |
6768 | (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */ | 6768 | (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */ |
6769 | 6769 | ||
6770 | /* insider hack! */ | 6770 | /* insider hack! */ |
6771 | if ((ioc->facts.FWVersion.Word >> 8) & 0x80) | 6771 | if ((ioc->facts.FWVersion.Word >> 8) & 0x80) |
6772 | strcat(buf, " [MDBG]"); | 6772 | strcat(buf, " [MDBG]"); |
6773 | } | 6773 | } |
6774 | } | 6774 | } |
6775 | 6775 | ||
6776 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 6776 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
6777 | /** | 6777 | /** |
6778 | * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer. | 6778 | * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer. |
6779 | * @ioc: Pointer to MPT_ADAPTER structure | 6779 | * @ioc: Pointer to MPT_ADAPTER structure |
6780 | * @buffer: Pointer to buffer where IOC summary info should be written | 6780 | * @buffer: Pointer to buffer where IOC summary info should be written |
6781 | * @size: Pointer to number of bytes we wrote (set by this routine) | 6781 | * @size: Pointer to number of bytes we wrote (set by this routine) |
6782 | * @len: Offset at which to start writing in buffer | 6782 | * @len: Offset at which to start writing in buffer |
6783 | * @showlan: Display LAN stuff? | 6783 | * @showlan: Display LAN stuff? |
6784 | * | 6784 | * |
6785 | * This routine writes (english readable) ASCII text, which represents | 6785 | * This routine writes (english readable) ASCII text, which represents |
6786 | * a summary of IOC information, to a buffer. | 6786 | * a summary of IOC information, to a buffer. |
6787 | */ | 6787 | */ |
6788 | void | 6788 | void |
6789 | mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan) | 6789 | mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan) |
6790 | { | 6790 | { |
6791 | char expVer[32]; | 6791 | char expVer[32]; |
6792 | int y; | 6792 | int y; |
6793 | 6793 | ||
6794 | mpt_get_fw_exp_ver(expVer, ioc); | 6794 | mpt_get_fw_exp_ver(expVer, ioc); |
6795 | 6795 | ||
6796 | /* | 6796 | /* |
6797 | * Shorter summary of attached ioc's... | 6797 | * Shorter summary of attached ioc's... |
6798 | */ | 6798 | */ |
6799 | y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d", | 6799 | y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d", |
6800 | ioc->name, | 6800 | ioc->name, |
6801 | ioc->prod_name, | 6801 | ioc->prod_name, |
6802 | MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */ | 6802 | MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */ |
6803 | ioc->facts.FWVersion.Word, | 6803 | ioc->facts.FWVersion.Word, |
6804 | expVer, | 6804 | expVer, |
6805 | ioc->facts.NumberOfPorts, | 6805 | ioc->facts.NumberOfPorts, |
6806 | ioc->req_depth); | 6806 | ioc->req_depth); |
6807 | 6807 | ||
6808 | if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) { | 6808 | if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) { |
6809 | u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; | 6809 | u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; |
6810 | y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X", | 6810 | y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X", |
6811 | a[5], a[4], a[3], a[2], a[1], a[0]); | 6811 | a[5], a[4], a[3], a[2], a[1], a[0]); |
6812 | } | 6812 | } |
6813 | 6813 | ||
6814 | y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq); | 6814 | y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq); |
6815 | 6815 | ||
6816 | if (!ioc->active) | 6816 | if (!ioc->active) |
6817 | y += sprintf(buffer+len+y, " (disabled)"); | 6817 | y += sprintf(buffer+len+y, " (disabled)"); |
6818 | 6818 | ||
6819 | y += sprintf(buffer+len+y, "\n"); | 6819 | y += sprintf(buffer+len+y, "\n"); |
6820 | 6820 | ||
6821 | *size = y; | 6821 | *size = y; |
6822 | } | 6822 | } |
6823 | /** | 6823 | /** |
6824 | * mpt_set_taskmgmt_in_progress_flag - set flags associated with task managment | 6824 | * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management |
6825 | * @ioc: Pointer to MPT_ADAPTER structure | 6825 | * @ioc: Pointer to MPT_ADAPTER structure |
6826 | * | 6826 | * |
6827 | * Returns 0 for SUCCESS or -1 if FAILED. | 6827 | * Returns 0 for SUCCESS or -1 if FAILED. |
6828 | * | 6828 | * |
6829 | * If -1 is return, then it was not possible to set the flags | 6829 | * If -1 is return, then it was not possible to set the flags |
6830 | **/ | 6830 | **/ |
6831 | int | 6831 | int |
6832 | mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc) | 6832 | mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc) |
6833 | { | 6833 | { |
6834 | unsigned long flags; | 6834 | unsigned long flags; |
6835 | int retval; | 6835 | int retval; |
6836 | 6836 | ||
6837 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); | 6837 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); |
6838 | if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress || | 6838 | if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress || |
6839 | (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) { | 6839 | (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) { |
6840 | retval = -1; | 6840 | retval = -1; |
6841 | goto out; | 6841 | goto out; |
6842 | } | 6842 | } |
6843 | retval = 0; | 6843 | retval = 0; |
6844 | ioc->taskmgmt_in_progress = 1; | 6844 | ioc->taskmgmt_in_progress = 1; |
6845 | ioc->taskmgmt_quiesce_io = 1; | 6845 | ioc->taskmgmt_quiesce_io = 1; |
6846 | if (ioc->alt_ioc) { | 6846 | if (ioc->alt_ioc) { |
6847 | ioc->alt_ioc->taskmgmt_in_progress = 1; | 6847 | ioc->alt_ioc->taskmgmt_in_progress = 1; |
6848 | ioc->alt_ioc->taskmgmt_quiesce_io = 1; | 6848 | ioc->alt_ioc->taskmgmt_quiesce_io = 1; |
6849 | } | 6849 | } |
6850 | out: | 6850 | out: |
6851 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | 6851 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); |
6852 | return retval; | 6852 | return retval; |
6853 | } | 6853 | } |
6854 | EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag); | 6854 | EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag); |
6855 | 6855 | ||
6856 | /** | 6856 | /** |
6857 | * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment | 6857 | * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management |
6858 | * @ioc: Pointer to MPT_ADAPTER structure | 6858 | * @ioc: Pointer to MPT_ADAPTER structure |
6859 | * | 6859 | * |
6860 | **/ | 6860 | **/ |
6861 | void | 6861 | void |
6862 | mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc) | 6862 | mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc) |
6863 | { | 6863 | { |
6864 | unsigned long flags; | 6864 | unsigned long flags; |
6865 | 6865 | ||
6866 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); | 6866 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); |
6867 | ioc->taskmgmt_in_progress = 0; | 6867 | ioc->taskmgmt_in_progress = 0; |
6868 | ioc->taskmgmt_quiesce_io = 0; | 6868 | ioc->taskmgmt_quiesce_io = 0; |
6869 | if (ioc->alt_ioc) { | 6869 | if (ioc->alt_ioc) { |
6870 | ioc->alt_ioc->taskmgmt_in_progress = 0; | 6870 | ioc->alt_ioc->taskmgmt_in_progress = 0; |
6871 | ioc->alt_ioc->taskmgmt_quiesce_io = 0; | 6871 | ioc->alt_ioc->taskmgmt_quiesce_io = 0; |
6872 | } | 6872 | } |
6873 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | 6873 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); |
6874 | } | 6874 | } |
6875 | EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag); | 6875 | EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag); |
6876 | 6876 | ||
6877 | 6877 | ||
6878 | /** | 6878 | /** |
6879 | * mpt_halt_firmware - Halts the firmware if it is operational and panic | 6879 | * mpt_halt_firmware - Halts the firmware if it is operational and panic |
6880 | * the kernel | 6880 | * the kernel |
6881 | * @ioc: Pointer to MPT_ADAPTER structure | 6881 | * @ioc: Pointer to MPT_ADAPTER structure |
6882 | * | 6882 | * |
6883 | **/ | 6883 | **/ |
6884 | void | 6884 | void |
6885 | mpt_halt_firmware(MPT_ADAPTER *ioc) | 6885 | mpt_halt_firmware(MPT_ADAPTER *ioc) |
6886 | { | 6886 | { |
6887 | u32 ioc_raw_state; | 6887 | u32 ioc_raw_state; |
6888 | 6888 | ||
6889 | ioc_raw_state = mpt_GetIocState(ioc, 0); | 6889 | ioc_raw_state = mpt_GetIocState(ioc, 0); |
6890 | 6890 | ||
6891 | if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { | 6891 | if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { |
6892 | printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n", | 6892 | printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n", |
6893 | ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); | 6893 | ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); |
6894 | panic("%s: IOC Fault (%04xh)!!!\n", ioc->name, | 6894 | panic("%s: IOC Fault (%04xh)!!!\n", ioc->name, |
6895 | ioc_raw_state & MPI_DOORBELL_DATA_MASK); | 6895 | ioc_raw_state & MPI_DOORBELL_DATA_MASK); |
6896 | } else { | 6896 | } else { |
6897 | CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00); | 6897 | CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00); |
6898 | panic("%s: Firmware is halted due to command timeout\n", | 6898 | panic("%s: Firmware is halted due to command timeout\n", |
6899 | ioc->name); | 6899 | ioc->name); |
6900 | } | 6900 | } |
6901 | } | 6901 | } |
6902 | EXPORT_SYMBOL(mpt_halt_firmware); | 6902 | EXPORT_SYMBOL(mpt_halt_firmware); |
6903 | 6903 | ||
6904 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 6904 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
6905 | /* | 6905 | /* |
6906 | * Reset Handling | 6906 | * Reset Handling |
6907 | */ | 6907 | */ |
6908 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 6908 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
6909 | /** | 6909 | /** |
6910 | * mpt_HardResetHandler - Generic reset handler | 6910 | * mpt_HardResetHandler - Generic reset handler |
6911 | * @ioc: Pointer to MPT_ADAPTER structure | 6911 | * @ioc: Pointer to MPT_ADAPTER structure |
6912 | * @sleepFlag: Indicates if sleep or schedule must be called. | 6912 | * @sleepFlag: Indicates if sleep or schedule must be called. |
6913 | * | 6913 | * |
6914 | * Issues SCSI Task Management call based on input arg values. | 6914 | * Issues SCSI Task Management call based on input arg values. |
6915 | * If TaskMgmt fails, returns associated SCSI request. | 6915 | * If TaskMgmt fails, returns associated SCSI request. |
6916 | * | 6916 | * |
6917 | * Remark: _HardResetHandler can be invoked from an interrupt thread (timer) | 6917 | * Remark: _HardResetHandler can be invoked from an interrupt thread (timer) |
6918 | * or a non-interrupt thread. In the former, must not call schedule(). | 6918 | * or a non-interrupt thread. In the former, must not call schedule(). |
6919 | * | 6919 | * |
6920 | * Note: A return of -1 is a FATAL error case, as it means a | 6920 | * Note: A return of -1 is a FATAL error case, as it means a |
6921 | * FW reload/initialization failed. | 6921 | * FW reload/initialization failed. |
6922 | * | 6922 | * |
6923 | * Returns 0 for SUCCESS or -1 if FAILED. | 6923 | * Returns 0 for SUCCESS or -1 if FAILED. |
6924 | */ | 6924 | */ |
6925 | int | 6925 | int |
6926 | mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) | 6926 | mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) |
6927 | { | 6927 | { |
6928 | int rc; | 6928 | int rc; |
6929 | u8 cb_idx; | 6929 | u8 cb_idx; |
6930 | unsigned long flags; | 6930 | unsigned long flags; |
6931 | unsigned long time_count; | 6931 | unsigned long time_count; |
6932 | 6932 | ||
6933 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name)); | 6933 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name)); |
6934 | #ifdef MFCNT | 6934 | #ifdef MFCNT |
6935 | printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name); | 6935 | printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name); |
6936 | printk("MF count 0x%x !\n", ioc->mfcnt); | 6936 | printk("MF count 0x%x !\n", ioc->mfcnt); |
6937 | #endif | 6937 | #endif |
6938 | if (mpt_fwfault_debug) | 6938 | if (mpt_fwfault_debug) |
6939 | mpt_halt_firmware(ioc); | 6939 | mpt_halt_firmware(ioc); |
6940 | 6940 | ||
6941 | /* Reset the adapter. Prevent more than 1 call to | 6941 | /* Reset the adapter. Prevent more than 1 call to |
6942 | * mpt_do_ioc_recovery at any instant in time. | 6942 | * mpt_do_ioc_recovery at any instant in time. |
6943 | */ | 6943 | */ |
6944 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); | 6944 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); |
6945 | if (ioc->ioc_reset_in_progress) { | 6945 | if (ioc->ioc_reset_in_progress) { |
6946 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | 6946 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); |
6947 | return 0; | 6947 | return 0; |
6948 | } | 6948 | } |
6949 | ioc->ioc_reset_in_progress = 1; | 6949 | ioc->ioc_reset_in_progress = 1; |
6950 | if (ioc->alt_ioc) | 6950 | if (ioc->alt_ioc) |
6951 | ioc->alt_ioc->ioc_reset_in_progress = 1; | 6951 | ioc->alt_ioc->ioc_reset_in_progress = 1; |
6952 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | 6952 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); |
6953 | 6953 | ||
6954 | 6954 | ||
6955 | /* The SCSI driver needs to adjust timeouts on all current | 6955 | /* The SCSI driver needs to adjust timeouts on all current |
6956 | * commands prior to the diagnostic reset being issued. | 6956 | * commands prior to the diagnostic reset being issued. |
6957 | * Prevents timeouts occurring during a diagnostic reset...very bad. | 6957 | * Prevents timeouts occurring during a diagnostic reset...very bad. |
6958 | * For all other protocol drivers, this is a no-op. | 6958 | * For all other protocol drivers, this is a no-op. |
6959 | */ | 6959 | */ |
6960 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { | 6960 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { |
6961 | if (MptResetHandlers[cb_idx]) { | 6961 | if (MptResetHandlers[cb_idx]) { |
6962 | mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); | 6962 | mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); |
6963 | if (ioc->alt_ioc) | 6963 | if (ioc->alt_ioc) |
6964 | mpt_signal_reset(cb_idx, ioc->alt_ioc, | 6964 | mpt_signal_reset(cb_idx, ioc->alt_ioc, |
6965 | MPT_IOC_SETUP_RESET); | 6965 | MPT_IOC_SETUP_RESET); |
6966 | } | 6966 | } |
6967 | } | 6967 | } |
6968 | 6968 | ||
6969 | time_count = jiffies; | 6969 | time_count = jiffies; |
6970 | rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag); | 6970 | rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag); |
6971 | if (rc != 0) { | 6971 | if (rc != 0) { |
6972 | printk(KERN_WARNING MYNAM | 6972 | printk(KERN_WARNING MYNAM |
6973 | ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name); | 6973 | ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name); |
6974 | } else { | 6974 | } else { |
6975 | if (ioc->hard_resets < -1) | 6975 | if (ioc->hard_resets < -1) |
6976 | ioc->hard_resets++; | 6976 | ioc->hard_resets++; |
6977 | } | 6977 | } |
6978 | 6978 | ||
6979 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); | 6979 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); |
6980 | ioc->ioc_reset_in_progress = 0; | 6980 | ioc->ioc_reset_in_progress = 0; |
6981 | ioc->taskmgmt_quiesce_io = 0; | 6981 | ioc->taskmgmt_quiesce_io = 0; |
6982 | ioc->taskmgmt_in_progress = 0; | 6982 | ioc->taskmgmt_in_progress = 0; |
6983 | if (ioc->alt_ioc) { | 6983 | if (ioc->alt_ioc) { |
6984 | ioc->alt_ioc->ioc_reset_in_progress = 0; | 6984 | ioc->alt_ioc->ioc_reset_in_progress = 0; |
6985 | ioc->alt_ioc->taskmgmt_quiesce_io = 0; | 6985 | ioc->alt_ioc->taskmgmt_quiesce_io = 0; |
6986 | ioc->alt_ioc->taskmgmt_in_progress = 0; | 6986 | ioc->alt_ioc->taskmgmt_in_progress = 0; |
6987 | } | 6987 | } |
6988 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | 6988 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); |
6989 | 6989 | ||
6990 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { | 6990 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { |
6991 | if (MptResetHandlers[cb_idx]) { | 6991 | if (MptResetHandlers[cb_idx]) { |
6992 | mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); | 6992 | mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); |
6993 | if (ioc->alt_ioc) | 6993 | if (ioc->alt_ioc) |
6994 | mpt_signal_reset(cb_idx, | 6994 | mpt_signal_reset(cb_idx, |
6995 | ioc->alt_ioc, MPT_IOC_POST_RESET); | 6995 | ioc->alt_ioc, MPT_IOC_POST_RESET); |
6996 | } | 6996 | } |
6997 | } | 6997 | } |
6998 | 6998 | ||
6999 | dtmprintk(ioc, | 6999 | dtmprintk(ioc, |
7000 | printk(MYIOC_s_DEBUG_FMT | 7000 | printk(MYIOC_s_DEBUG_FMT |
7001 | "HardResetHandler: completed (%d seconds): %s\n", ioc->name, | 7001 | "HardResetHandler: completed (%d seconds): %s\n", ioc->name, |
7002 | jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ? | 7002 | jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ? |
7003 | "SUCCESS" : "FAILED"))); | 7003 | "SUCCESS" : "FAILED"))); |
7004 | 7004 | ||
7005 | return rc; | 7005 | return rc; |
7006 | } | 7006 | } |
7007 | 7007 | ||
7008 | #ifdef CONFIG_FUSION_LOGGING | 7008 | #ifdef CONFIG_FUSION_LOGGING |
7009 | static void | 7009 | static void |
7010 | mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply) | 7010 | mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply) |
7011 | { | 7011 | { |
7012 | char *ds = NULL; | 7012 | char *ds = NULL; |
7013 | u32 evData0; | 7013 | u32 evData0; |
7014 | int ii; | 7014 | int ii; |
7015 | u8 event; | 7015 | u8 event; |
7016 | char *evStr = ioc->evStr; | 7016 | char *evStr = ioc->evStr; |
7017 | 7017 | ||
7018 | event = le32_to_cpu(pEventReply->Event) & 0xFF; | 7018 | event = le32_to_cpu(pEventReply->Event) & 0xFF; |
7019 | evData0 = le32_to_cpu(pEventReply->Data[0]); | 7019 | evData0 = le32_to_cpu(pEventReply->Data[0]); |
7020 | 7020 | ||
7021 | switch(event) { | 7021 | switch(event) { |
7022 | case MPI_EVENT_NONE: | 7022 | case MPI_EVENT_NONE: |
7023 | ds = "None"; | 7023 | ds = "None"; |
7024 | break; | 7024 | break; |
7025 | case MPI_EVENT_LOG_DATA: | 7025 | case MPI_EVENT_LOG_DATA: |
7026 | ds = "Log Data"; | 7026 | ds = "Log Data"; |
7027 | break; | 7027 | break; |
7028 | case MPI_EVENT_STATE_CHANGE: | 7028 | case MPI_EVENT_STATE_CHANGE: |
7029 | ds = "State Change"; | 7029 | ds = "State Change"; |
7030 | break; | 7030 | break; |
7031 | case MPI_EVENT_UNIT_ATTENTION: | 7031 | case MPI_EVENT_UNIT_ATTENTION: |
7032 | ds = "Unit Attention"; | 7032 | ds = "Unit Attention"; |
7033 | break; | 7033 | break; |
7034 | case MPI_EVENT_IOC_BUS_RESET: | 7034 | case MPI_EVENT_IOC_BUS_RESET: |
7035 | ds = "IOC Bus Reset"; | 7035 | ds = "IOC Bus Reset"; |
7036 | break; | 7036 | break; |
7037 | case MPI_EVENT_EXT_BUS_RESET: | 7037 | case MPI_EVENT_EXT_BUS_RESET: |
7038 | ds = "External Bus Reset"; | 7038 | ds = "External Bus Reset"; |
7039 | break; | 7039 | break; |
7040 | case MPI_EVENT_RESCAN: | 7040 | case MPI_EVENT_RESCAN: |
7041 | ds = "Bus Rescan Event"; | 7041 | ds = "Bus Rescan Event"; |
7042 | break; | 7042 | break; |
7043 | case MPI_EVENT_LINK_STATUS_CHANGE: | 7043 | case MPI_EVENT_LINK_STATUS_CHANGE: |
7044 | if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE) | 7044 | if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE) |
7045 | ds = "Link Status(FAILURE) Change"; | 7045 | ds = "Link Status(FAILURE) Change"; |
7046 | else | 7046 | else |
7047 | ds = "Link Status(ACTIVE) Change"; | 7047 | ds = "Link Status(ACTIVE) Change"; |
7048 | break; | 7048 | break; |
7049 | case MPI_EVENT_LOOP_STATE_CHANGE: | 7049 | case MPI_EVENT_LOOP_STATE_CHANGE: |
7050 | if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP) | 7050 | if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP) |
7051 | ds = "Loop State(LIP) Change"; | 7051 | ds = "Loop State(LIP) Change"; |
7052 | else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE) | 7052 | else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE) |
7053 | ds = "Loop State(LPE) Change"; | 7053 | ds = "Loop State(LPE) Change"; |
7054 | else | 7054 | else |
7055 | ds = "Loop State(LPB) Change"; | 7055 | ds = "Loop State(LPB) Change"; |
7056 | break; | 7056 | break; |
7057 | case MPI_EVENT_LOGOUT: | 7057 | case MPI_EVENT_LOGOUT: |
7058 | ds = "Logout"; | 7058 | ds = "Logout"; |
7059 | break; | 7059 | break; |
7060 | case MPI_EVENT_EVENT_CHANGE: | 7060 | case MPI_EVENT_EVENT_CHANGE: |
7061 | if (evData0) | 7061 | if (evData0) |
7062 | ds = "Events ON"; | 7062 | ds = "Events ON"; |
7063 | else | 7063 | else |
7064 | ds = "Events OFF"; | 7064 | ds = "Events OFF"; |
7065 | break; | 7065 | break; |
7066 | case MPI_EVENT_INTEGRATED_RAID: | 7066 | case MPI_EVENT_INTEGRATED_RAID: |
7067 | { | 7067 | { |
7068 | u8 ReasonCode = (u8)(evData0 >> 16); | 7068 | u8 ReasonCode = (u8)(evData0 >> 16); |
7069 | switch (ReasonCode) { | 7069 | switch (ReasonCode) { |
7070 | case MPI_EVENT_RAID_RC_VOLUME_CREATED : | 7070 | case MPI_EVENT_RAID_RC_VOLUME_CREATED : |
7071 | ds = "Integrated Raid: Volume Created"; | 7071 | ds = "Integrated Raid: Volume Created"; |
7072 | break; | 7072 | break; |
7073 | case MPI_EVENT_RAID_RC_VOLUME_DELETED : | 7073 | case MPI_EVENT_RAID_RC_VOLUME_DELETED : |
7074 | ds = "Integrated Raid: Volume Deleted"; | 7074 | ds = "Integrated Raid: Volume Deleted"; |
7075 | break; | 7075 | break; |
7076 | case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED : | 7076 | case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED : |
7077 | ds = "Integrated Raid: Volume Settings Changed"; | 7077 | ds = "Integrated Raid: Volume Settings Changed"; |
7078 | break; | 7078 | break; |
7079 | case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED : | 7079 | case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED : |
7080 | ds = "Integrated Raid: Volume Status Changed"; | 7080 | ds = "Integrated Raid: Volume Status Changed"; |
7081 | break; | 7081 | break; |
7082 | case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED : | 7082 | case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED : |
7083 | ds = "Integrated Raid: Volume Physdisk Changed"; | 7083 | ds = "Integrated Raid: Volume Physdisk Changed"; |
7084 | break; | 7084 | break; |
7085 | case MPI_EVENT_RAID_RC_PHYSDISK_CREATED : | 7085 | case MPI_EVENT_RAID_RC_PHYSDISK_CREATED : |
7086 | ds = "Integrated Raid: Physdisk Created"; | 7086 | ds = "Integrated Raid: Physdisk Created"; |
7087 | break; | 7087 | break; |
7088 | case MPI_EVENT_RAID_RC_PHYSDISK_DELETED : | 7088 | case MPI_EVENT_RAID_RC_PHYSDISK_DELETED : |
7089 | ds = "Integrated Raid: Physdisk Deleted"; | 7089 | ds = "Integrated Raid: Physdisk Deleted"; |
7090 | break; | 7090 | break; |
7091 | case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED : | 7091 | case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED : |
7092 | ds = "Integrated Raid: Physdisk Settings Changed"; | 7092 | ds = "Integrated Raid: Physdisk Settings Changed"; |
7093 | break; | 7093 | break; |
7094 | case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED : | 7094 | case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED : |
7095 | ds = "Integrated Raid: Physdisk Status Changed"; | 7095 | ds = "Integrated Raid: Physdisk Status Changed"; |
7096 | break; | 7096 | break; |
7097 | case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED : | 7097 | case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED : |
7098 | ds = "Integrated Raid: Domain Validation Needed"; | 7098 | ds = "Integrated Raid: Domain Validation Needed"; |
7099 | break; | 7099 | break; |
7100 | case MPI_EVENT_RAID_RC_SMART_DATA : | 7100 | case MPI_EVENT_RAID_RC_SMART_DATA : |
7101 | ds = "Integrated Raid; Smart Data"; | 7101 | ds = "Integrated Raid; Smart Data"; |
7102 | break; | 7102 | break; |
7103 | case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED : | 7103 | case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED : |
7104 | ds = "Integrated Raid: Replace Action Started"; | 7104 | ds = "Integrated Raid: Replace Action Started"; |
7105 | break; | 7105 | break; |
7106 | default: | 7106 | default: |
7107 | ds = "Integrated Raid"; | 7107 | ds = "Integrated Raid"; |
7108 | break; | 7108 | break; |
7109 | } | 7109 | } |
7110 | break; | 7110 | break; |
7111 | } | 7111 | } |
7112 | case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE: | 7112 | case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE: |
7113 | ds = "SCSI Device Status Change"; | 7113 | ds = "SCSI Device Status Change"; |
7114 | break; | 7114 | break; |
7115 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: | 7115 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: |
7116 | { | 7116 | { |
7117 | u8 id = (u8)(evData0); | 7117 | u8 id = (u8)(evData0); |
7118 | u8 channel = (u8)(evData0 >> 8); | 7118 | u8 channel = (u8)(evData0 >> 8); |
7119 | u8 ReasonCode = (u8)(evData0 >> 16); | 7119 | u8 ReasonCode = (u8)(evData0 >> 16); |
7120 | switch (ReasonCode) { | 7120 | switch (ReasonCode) { |
7121 | case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: | 7121 | case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: |
7122 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7122 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7123 | "SAS Device Status Change: Added: " | 7123 | "SAS Device Status Change: Added: " |
7124 | "id=%d channel=%d", id, channel); | 7124 | "id=%d channel=%d", id, channel); |
7125 | break; | 7125 | break; |
7126 | case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: | 7126 | case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: |
7127 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7127 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7128 | "SAS Device Status Change: Deleted: " | 7128 | "SAS Device Status Change: Deleted: " |
7129 | "id=%d channel=%d", id, channel); | 7129 | "id=%d channel=%d", id, channel); |
7130 | break; | 7130 | break; |
7131 | case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: | 7131 | case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: |
7132 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7132 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7133 | "SAS Device Status Change: SMART Data: " | 7133 | "SAS Device Status Change: SMART Data: " |
7134 | "id=%d channel=%d", id, channel); | 7134 | "id=%d channel=%d", id, channel); |
7135 | break; | 7135 | break; |
7136 | case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: | 7136 | case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: |
7137 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7137 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7138 | "SAS Device Status Change: No Persistancy: " | 7138 | "SAS Device Status Change: No Persistancy: " |
7139 | "id=%d channel=%d", id, channel); | 7139 | "id=%d channel=%d", id, channel); |
7140 | break; | 7140 | break; |
7141 | case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: | 7141 | case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: |
7142 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7142 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7143 | "SAS Device Status Change: Unsupported Device " | 7143 | "SAS Device Status Change: Unsupported Device " |
7144 | "Discovered : id=%d channel=%d", id, channel); | 7144 | "Discovered : id=%d channel=%d", id, channel); |
7145 | break; | 7145 | break; |
7146 | case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: | 7146 | case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: |
7147 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7147 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7148 | "SAS Device Status Change: Internal Device " | 7148 | "SAS Device Status Change: Internal Device " |
7149 | "Reset : id=%d channel=%d", id, channel); | 7149 | "Reset : id=%d channel=%d", id, channel); |
7150 | break; | 7150 | break; |
7151 | case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: | 7151 | case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: |
7152 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7152 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7153 | "SAS Device Status Change: Internal Task " | 7153 | "SAS Device Status Change: Internal Task " |
7154 | "Abort : id=%d channel=%d", id, channel); | 7154 | "Abort : id=%d channel=%d", id, channel); |
7155 | break; | 7155 | break; |
7156 | case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: | 7156 | case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: |
7157 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7157 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7158 | "SAS Device Status Change: Internal Abort " | 7158 | "SAS Device Status Change: Internal Abort " |
7159 | "Task Set : id=%d channel=%d", id, channel); | 7159 | "Task Set : id=%d channel=%d", id, channel); |
7160 | break; | 7160 | break; |
7161 | case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: | 7161 | case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: |
7162 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7162 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7163 | "SAS Device Status Change: Internal Clear " | 7163 | "SAS Device Status Change: Internal Clear " |
7164 | "Task Set : id=%d channel=%d", id, channel); | 7164 | "Task Set : id=%d channel=%d", id, channel); |
7165 | break; | 7165 | break; |
7166 | case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: | 7166 | case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: |
7167 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7167 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7168 | "SAS Device Status Change: Internal Query " | 7168 | "SAS Device Status Change: Internal Query " |
7169 | "Task : id=%d channel=%d", id, channel); | 7169 | "Task : id=%d channel=%d", id, channel); |
7170 | break; | 7170 | break; |
7171 | default: | 7171 | default: |
7172 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7172 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7173 | "SAS Device Status Change: Unknown: " | 7173 | "SAS Device Status Change: Unknown: " |
7174 | "id=%d channel=%d", id, channel); | 7174 | "id=%d channel=%d", id, channel); |
7175 | break; | 7175 | break; |
7176 | } | 7176 | } |
7177 | break; | 7177 | break; |
7178 | } | 7178 | } |
7179 | case MPI_EVENT_ON_BUS_TIMER_EXPIRED: | 7179 | case MPI_EVENT_ON_BUS_TIMER_EXPIRED: |
7180 | ds = "Bus Timer Expired"; | 7180 | ds = "Bus Timer Expired"; |
7181 | break; | 7181 | break; |
7182 | case MPI_EVENT_QUEUE_FULL: | 7182 | case MPI_EVENT_QUEUE_FULL: |
7183 | { | 7183 | { |
7184 | u16 curr_depth = (u16)(evData0 >> 16); | 7184 | u16 curr_depth = (u16)(evData0 >> 16); |
7185 | u8 channel = (u8)(evData0 >> 8); | 7185 | u8 channel = (u8)(evData0 >> 8); |
7186 | u8 id = (u8)(evData0); | 7186 | u8 id = (u8)(evData0); |
7187 | 7187 | ||
7188 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7188 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7189 | "Queue Full: channel=%d id=%d depth=%d", | 7189 | "Queue Full: channel=%d id=%d depth=%d", |
7190 | channel, id, curr_depth); | 7190 | channel, id, curr_depth); |
7191 | break; | 7191 | break; |
7192 | } | 7192 | } |
7193 | case MPI_EVENT_SAS_SES: | 7193 | case MPI_EVENT_SAS_SES: |
7194 | ds = "SAS SES Event"; | 7194 | ds = "SAS SES Event"; |
7195 | break; | 7195 | break; |
7196 | case MPI_EVENT_PERSISTENT_TABLE_FULL: | 7196 | case MPI_EVENT_PERSISTENT_TABLE_FULL: |
7197 | ds = "Persistent Table Full"; | 7197 | ds = "Persistent Table Full"; |
7198 | break; | 7198 | break; |
7199 | case MPI_EVENT_SAS_PHY_LINK_STATUS: | 7199 | case MPI_EVENT_SAS_PHY_LINK_STATUS: |
7200 | { | 7200 | { |
7201 | u8 LinkRates = (u8)(evData0 >> 8); | 7201 | u8 LinkRates = (u8)(evData0 >> 8); |
7202 | u8 PhyNumber = (u8)(evData0); | 7202 | u8 PhyNumber = (u8)(evData0); |
7203 | LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >> | 7203 | LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >> |
7204 | MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT; | 7204 | MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT; |
7205 | switch (LinkRates) { | 7205 | switch (LinkRates) { |
7206 | case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN: | 7206 | case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN: |
7207 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7207 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7208 | "SAS PHY Link Status: Phy=%d:" | 7208 | "SAS PHY Link Status: Phy=%d:" |
7209 | " Rate Unknown",PhyNumber); | 7209 | " Rate Unknown",PhyNumber); |
7210 | break; | 7210 | break; |
7211 | case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED: | 7211 | case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED: |
7212 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7212 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7213 | "SAS PHY Link Status: Phy=%d:" | 7213 | "SAS PHY Link Status: Phy=%d:" |
7214 | " Phy Disabled",PhyNumber); | 7214 | " Phy Disabled",PhyNumber); |
7215 | break; | 7215 | break; |
7216 | case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION: | 7216 | case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION: |
7217 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7217 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7218 | "SAS PHY Link Status: Phy=%d:" | 7218 | "SAS PHY Link Status: Phy=%d:" |
7219 | " Failed Speed Nego",PhyNumber); | 7219 | " Failed Speed Nego",PhyNumber); |
7220 | break; | 7220 | break; |
7221 | case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE: | 7221 | case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE: |
7222 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7222 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7223 | "SAS PHY Link Status: Phy=%d:" | 7223 | "SAS PHY Link Status: Phy=%d:" |
7224 | " Sata OOB Completed",PhyNumber); | 7224 | " Sata OOB Completed",PhyNumber); |
7225 | break; | 7225 | break; |
7226 | case MPI_EVENT_SAS_PLS_LR_RATE_1_5: | 7226 | case MPI_EVENT_SAS_PLS_LR_RATE_1_5: |
7227 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7227 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7228 | "SAS PHY Link Status: Phy=%d:" | 7228 | "SAS PHY Link Status: Phy=%d:" |
7229 | " Rate 1.5 Gbps",PhyNumber); | 7229 | " Rate 1.5 Gbps",PhyNumber); |
7230 | break; | 7230 | break; |
7231 | case MPI_EVENT_SAS_PLS_LR_RATE_3_0: | 7231 | case MPI_EVENT_SAS_PLS_LR_RATE_3_0: |
7232 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7232 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7233 | "SAS PHY Link Status: Phy=%d:" | 7233 | "SAS PHY Link Status: Phy=%d:" |
7234 | " Rate 3.0 Gpbs",PhyNumber); | 7234 | " Rate 3.0 Gpbs",PhyNumber); |
7235 | break; | 7235 | break; |
7236 | default: | 7236 | default: |
7237 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7237 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7238 | "SAS PHY Link Status: Phy=%d", PhyNumber); | 7238 | "SAS PHY Link Status: Phy=%d", PhyNumber); |
7239 | break; | 7239 | break; |
7240 | } | 7240 | } |
7241 | break; | 7241 | break; |
7242 | } | 7242 | } |
7243 | case MPI_EVENT_SAS_DISCOVERY_ERROR: | 7243 | case MPI_EVENT_SAS_DISCOVERY_ERROR: |
7244 | ds = "SAS Discovery Error"; | 7244 | ds = "SAS Discovery Error"; |
7245 | break; | 7245 | break; |
7246 | case MPI_EVENT_IR_RESYNC_UPDATE: | 7246 | case MPI_EVENT_IR_RESYNC_UPDATE: |
7247 | { | 7247 | { |
7248 | u8 resync_complete = (u8)(evData0 >> 16); | 7248 | u8 resync_complete = (u8)(evData0 >> 16); |
7249 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7249 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7250 | "IR Resync Update: Complete = %d:",resync_complete); | 7250 | "IR Resync Update: Complete = %d:",resync_complete); |
7251 | break; | 7251 | break; |
7252 | } | 7252 | } |
7253 | case MPI_EVENT_IR2: | 7253 | case MPI_EVENT_IR2: |
7254 | { | 7254 | { |
7255 | u8 id = (u8)(evData0); | 7255 | u8 id = (u8)(evData0); |
7256 | u8 channel = (u8)(evData0 >> 8); | 7256 | u8 channel = (u8)(evData0 >> 8); |
7257 | u8 phys_num = (u8)(evData0 >> 24); | 7257 | u8 phys_num = (u8)(evData0 >> 24); |
7258 | u8 ReasonCode = (u8)(evData0 >> 16); | 7258 | u8 ReasonCode = (u8)(evData0 >> 16); |
7259 | 7259 | ||
7260 | switch (ReasonCode) { | 7260 | switch (ReasonCode) { |
7261 | case MPI_EVENT_IR2_RC_LD_STATE_CHANGED: | 7261 | case MPI_EVENT_IR2_RC_LD_STATE_CHANGED: |
7262 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7262 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7263 | "IR2: LD State Changed: " | 7263 | "IR2: LD State Changed: " |
7264 | "id=%d channel=%d phys_num=%d", | 7264 | "id=%d channel=%d phys_num=%d", |
7265 | id, channel, phys_num); | 7265 | id, channel, phys_num); |
7266 | break; | 7266 | break; |
7267 | case MPI_EVENT_IR2_RC_PD_STATE_CHANGED: | 7267 | case MPI_EVENT_IR2_RC_PD_STATE_CHANGED: |
7268 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7268 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7269 | "IR2: PD State Changed " | 7269 | "IR2: PD State Changed " |
7270 | "id=%d channel=%d phys_num=%d", | 7270 | "id=%d channel=%d phys_num=%d", |
7271 | id, channel, phys_num); | 7271 | id, channel, phys_num); |
7272 | break; | 7272 | break; |
7273 | case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL: | 7273 | case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL: |
7274 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7274 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7275 | "IR2: Bad Block Table Full: " | 7275 | "IR2: Bad Block Table Full: " |
7276 | "id=%d channel=%d phys_num=%d", | 7276 | "id=%d channel=%d phys_num=%d", |
7277 | id, channel, phys_num); | 7277 | id, channel, phys_num); |
7278 | break; | 7278 | break; |
7279 | case MPI_EVENT_IR2_RC_PD_INSERTED: | 7279 | case MPI_EVENT_IR2_RC_PD_INSERTED: |
7280 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7280 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7281 | "IR2: PD Inserted: " | 7281 | "IR2: PD Inserted: " |
7282 | "id=%d channel=%d phys_num=%d", | 7282 | "id=%d channel=%d phys_num=%d", |
7283 | id, channel, phys_num); | 7283 | id, channel, phys_num); |
7284 | break; | 7284 | break; |
7285 | case MPI_EVENT_IR2_RC_PD_REMOVED: | 7285 | case MPI_EVENT_IR2_RC_PD_REMOVED: |
7286 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7286 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7287 | "IR2: PD Removed: " | 7287 | "IR2: PD Removed: " |
7288 | "id=%d channel=%d phys_num=%d", | 7288 | "id=%d channel=%d phys_num=%d", |
7289 | id, channel, phys_num); | 7289 | id, channel, phys_num); |
7290 | break; | 7290 | break; |
7291 | case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: | 7291 | case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: |
7292 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7292 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7293 | "IR2: Foreign CFG Detected: " | 7293 | "IR2: Foreign CFG Detected: " |
7294 | "id=%d channel=%d phys_num=%d", | 7294 | "id=%d channel=%d phys_num=%d", |
7295 | id, channel, phys_num); | 7295 | id, channel, phys_num); |
7296 | break; | 7296 | break; |
7297 | case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR: | 7297 | case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR: |
7298 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7298 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7299 | "IR2: Rebuild Medium Error: " | 7299 | "IR2: Rebuild Medium Error: " |
7300 | "id=%d channel=%d phys_num=%d", | 7300 | "id=%d channel=%d phys_num=%d", |
7301 | id, channel, phys_num); | 7301 | id, channel, phys_num); |
7302 | break; | 7302 | break; |
7303 | case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: | 7303 | case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: |
7304 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7304 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7305 | "IR2: Dual Port Added: " | 7305 | "IR2: Dual Port Added: " |
7306 | "id=%d channel=%d phys_num=%d", | 7306 | "id=%d channel=%d phys_num=%d", |
7307 | id, channel, phys_num); | 7307 | id, channel, phys_num); |
7308 | break; | 7308 | break; |
7309 | case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: | 7309 | case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: |
7310 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7310 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7311 | "IR2: Dual Port Removed: " | 7311 | "IR2: Dual Port Removed: " |
7312 | "id=%d channel=%d phys_num=%d", | 7312 | "id=%d channel=%d phys_num=%d", |
7313 | id, channel, phys_num); | 7313 | id, channel, phys_num); |
7314 | break; | 7314 | break; |
7315 | default: | 7315 | default: |
7316 | ds = "IR2"; | 7316 | ds = "IR2"; |
7317 | break; | 7317 | break; |
7318 | } | 7318 | } |
7319 | break; | 7319 | break; |
7320 | } | 7320 | } |
7321 | case MPI_EVENT_SAS_DISCOVERY: | 7321 | case MPI_EVENT_SAS_DISCOVERY: |
7322 | { | 7322 | { |
7323 | if (evData0) | 7323 | if (evData0) |
7324 | ds = "SAS Discovery: Start"; | 7324 | ds = "SAS Discovery: Start"; |
7325 | else | 7325 | else |
7326 | ds = "SAS Discovery: Stop"; | 7326 | ds = "SAS Discovery: Stop"; |
7327 | break; | 7327 | break; |
7328 | } | 7328 | } |
7329 | case MPI_EVENT_LOG_ENTRY_ADDED: | 7329 | case MPI_EVENT_LOG_ENTRY_ADDED: |
7330 | ds = "SAS Log Entry Added"; | 7330 | ds = "SAS Log Entry Added"; |
7331 | break; | 7331 | break; |
7332 | 7332 | ||
7333 | case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: | 7333 | case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: |
7334 | { | 7334 | { |
7335 | u8 phy_num = (u8)(evData0); | 7335 | u8 phy_num = (u8)(evData0); |
7336 | u8 port_num = (u8)(evData0 >> 8); | 7336 | u8 port_num = (u8)(evData0 >> 8); |
7337 | u8 port_width = (u8)(evData0 >> 16); | 7337 | u8 port_width = (u8)(evData0 >> 16); |
7338 | u8 primative = (u8)(evData0 >> 24); | 7338 | u8 primative = (u8)(evData0 >> 24); |
7339 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7339 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7340 | "SAS Broadcase Primative: phy=%d port=%d " | 7340 | "SAS Broadcase Primative: phy=%d port=%d " |
7341 | "width=%d primative=0x%02x", | 7341 | "width=%d primative=0x%02x", |
7342 | phy_num, port_num, port_width, primative); | 7342 | phy_num, port_num, port_width, primative); |
7343 | break; | 7343 | break; |
7344 | } | 7344 | } |
7345 | 7345 | ||
7346 | case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: | 7346 | case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: |
7347 | { | 7347 | { |
7348 | u8 reason = (u8)(evData0); | 7348 | u8 reason = (u8)(evData0); |
7349 | 7349 | ||
7350 | switch (reason) { | 7350 | switch (reason) { |
7351 | case MPI_EVENT_SAS_INIT_RC_ADDED: | 7351 | case MPI_EVENT_SAS_INIT_RC_ADDED: |
7352 | ds = "SAS Initiator Status Change: Added"; | 7352 | ds = "SAS Initiator Status Change: Added"; |
7353 | break; | 7353 | break; |
7354 | case MPI_EVENT_SAS_INIT_RC_REMOVED: | 7354 | case MPI_EVENT_SAS_INIT_RC_REMOVED: |
7355 | ds = "SAS Initiator Status Change: Deleted"; | 7355 | ds = "SAS Initiator Status Change: Deleted"; |
7356 | break; | 7356 | break; |
7357 | default: | 7357 | default: |
7358 | ds = "SAS Initiator Status Change"; | 7358 | ds = "SAS Initiator Status Change"; |
7359 | break; | 7359 | break; |
7360 | } | 7360 | } |
7361 | break; | 7361 | break; |
7362 | } | 7362 | } |
7363 | 7363 | ||
7364 | case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW: | 7364 | case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW: |
7365 | { | 7365 | { |
7366 | u8 max_init = (u8)(evData0); | 7366 | u8 max_init = (u8)(evData0); |
7367 | u8 current_init = (u8)(evData0 >> 8); | 7367 | u8 current_init = (u8)(evData0 >> 8); |
7368 | 7368 | ||
7369 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7369 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7370 | "SAS Initiator Device Table Overflow: max initiators=%02d " | 7370 | "SAS Initiator Device Table Overflow: max initiators=%02d " |
7371 | "current initators=%02d", | 7371 | "current initators=%02d", |
7372 | max_init, current_init); | 7372 | max_init, current_init); |
7373 | break; | 7373 | break; |
7374 | } | 7374 | } |
7375 | case MPI_EVENT_SAS_SMP_ERROR: | 7375 | case MPI_EVENT_SAS_SMP_ERROR: |
7376 | { | 7376 | { |
7377 | u8 status = (u8)(evData0); | 7377 | u8 status = (u8)(evData0); |
7378 | u8 port_num = (u8)(evData0 >> 8); | 7378 | u8 port_num = (u8)(evData0 >> 8); |
7379 | u8 result = (u8)(evData0 >> 16); | 7379 | u8 result = (u8)(evData0 >> 16); |
7380 | 7380 | ||
7381 | if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID) | 7381 | if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID) |
7382 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7382 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7383 | "SAS SMP Error: port=%d result=0x%02x", | 7383 | "SAS SMP Error: port=%d result=0x%02x", |
7384 | port_num, result); | 7384 | port_num, result); |
7385 | else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR) | 7385 | else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR) |
7386 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7386 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7387 | "SAS SMP Error: port=%d : CRC Error", | 7387 | "SAS SMP Error: port=%d : CRC Error", |
7388 | port_num); | 7388 | port_num); |
7389 | else if (status == MPI_EVENT_SAS_SMP_TIMEOUT) | 7389 | else if (status == MPI_EVENT_SAS_SMP_TIMEOUT) |
7390 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7390 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7391 | "SAS SMP Error: port=%d : Timeout", | 7391 | "SAS SMP Error: port=%d : Timeout", |
7392 | port_num); | 7392 | port_num); |
7393 | else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION) | 7393 | else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION) |
7394 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7394 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7395 | "SAS SMP Error: port=%d : No Destination", | 7395 | "SAS SMP Error: port=%d : No Destination", |
7396 | port_num); | 7396 | port_num); |
7397 | else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION) | 7397 | else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION) |
7398 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7398 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7399 | "SAS SMP Error: port=%d : Bad Destination", | 7399 | "SAS SMP Error: port=%d : Bad Destination", |
7400 | port_num); | 7400 | port_num); |
7401 | else | 7401 | else |
7402 | snprintf(evStr, EVENT_DESCR_STR_SZ, | 7402 | snprintf(evStr, EVENT_DESCR_STR_SZ, |
7403 | "SAS SMP Error: port=%d : status=0x%02x", | 7403 | "SAS SMP Error: port=%d : status=0x%02x", |
7404 | port_num, status); | 7404 | port_num, status); |
7405 | break; | 7405 | break; |
7406 | } | 7406 | } |
7407 | 7407 | ||
7408 | case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: | 7408 | case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: |
7409 | { | 7409 | { |
7410 | u8 reason = (u8)(evData0); | 7410 | u8 reason = (u8)(evData0); |
7411 | 7411 | ||
7412 | switch (reason) { | 7412 | switch (reason) { |
7413 | case MPI_EVENT_SAS_EXP_RC_ADDED: | 7413 | case MPI_EVENT_SAS_EXP_RC_ADDED: |
7414 | ds = "Expander Status Change: Added"; | 7414 | ds = "Expander Status Change: Added"; |
7415 | break; | 7415 | break; |
7416 | case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING: | 7416 | case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING: |
7417 | ds = "Expander Status Change: Deleted"; | 7417 | ds = "Expander Status Change: Deleted"; |
7418 | break; | 7418 | break; |
7419 | default: | 7419 | default: |
7420 | ds = "Expander Status Change"; | 7420 | ds = "Expander Status Change"; |
7421 | break; | 7421 | break; |
7422 | } | 7422 | } |
7423 | break; | 7423 | break; |
7424 | } | 7424 | } |
7425 | 7425 | ||
7426 | /* | 7426 | /* |
7427 | * MPT base "custom" events may be added here... | 7427 | * MPT base "custom" events may be added here... |
7428 | */ | 7428 | */ |
7429 | default: | 7429 | default: |
7430 | ds = "Unknown"; | 7430 | ds = "Unknown"; |
7431 | break; | 7431 | break; |
7432 | } | 7432 | } |
7433 | if (ds) | 7433 | if (ds) |
7434 | strncpy(evStr, ds, EVENT_DESCR_STR_SZ); | 7434 | strncpy(evStr, ds, EVENT_DESCR_STR_SZ); |
7435 | 7435 | ||
7436 | 7436 | ||
7437 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 7437 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
7438 | "MPT event:(%02Xh) : %s\n", | 7438 | "MPT event:(%02Xh) : %s\n", |
7439 | ioc->name, event, evStr)); | 7439 | ioc->name, event, evStr)); |
7440 | 7440 | ||
7441 | devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM | 7441 | devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM |
7442 | ": Event data:\n")); | 7442 | ": Event data:\n")); |
7443 | for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++) | 7443 | for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++) |
7444 | devtverboseprintk(ioc, printk(" %08x", | 7444 | devtverboseprintk(ioc, printk(" %08x", |
7445 | le32_to_cpu(pEventReply->Data[ii]))); | 7445 | le32_to_cpu(pEventReply->Data[ii]))); |
7446 | devtverboseprintk(ioc, printk(KERN_DEBUG "\n")); | 7446 | devtverboseprintk(ioc, printk(KERN_DEBUG "\n")); |
7447 | } | 7447 | } |
7448 | #endif | 7448 | #endif |
7449 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 7449 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
7450 | /** | 7450 | /** |
7451 | * ProcessEventNotification - Route EventNotificationReply to all event handlers | 7451 | * ProcessEventNotification - Route EventNotificationReply to all event handlers |
7452 | * @ioc: Pointer to MPT_ADAPTER structure | 7452 | * @ioc: Pointer to MPT_ADAPTER structure |
7453 | * @pEventReply: Pointer to EventNotification reply frame | 7453 | * @pEventReply: Pointer to EventNotification reply frame |
7454 | * @evHandlers: Pointer to integer, number of event handlers | 7454 | * @evHandlers: Pointer to integer, number of event handlers |
7455 | * | 7455 | * |
7456 | * Routes a received EventNotificationReply to all currently registered | 7456 | * Routes a received EventNotificationReply to all currently registered |
7457 | * event handlers. | 7457 | * event handlers. |
7458 | * Returns sum of event handlers return values. | 7458 | * Returns sum of event handlers return values. |
7459 | */ | 7459 | */ |
7460 | static int | 7460 | static int |
7461 | ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers) | 7461 | ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers) |
7462 | { | 7462 | { |
7463 | u16 evDataLen; | 7463 | u16 evDataLen; |
7464 | u32 evData0 = 0; | 7464 | u32 evData0 = 0; |
7465 | int ii; | 7465 | int ii; |
7466 | u8 cb_idx; | 7466 | u8 cb_idx; |
7467 | int r = 0; | 7467 | int r = 0; |
7468 | int handlers = 0; | 7468 | int handlers = 0; |
7469 | u8 event; | 7469 | u8 event; |
7470 | 7470 | ||
7471 | /* | 7471 | /* |
7472 | * Do platform normalization of values | 7472 | * Do platform normalization of values |
7473 | */ | 7473 | */ |
7474 | event = le32_to_cpu(pEventReply->Event) & 0xFF; | 7474 | event = le32_to_cpu(pEventReply->Event) & 0xFF; |
7475 | evDataLen = le16_to_cpu(pEventReply->EventDataLength); | 7475 | evDataLen = le16_to_cpu(pEventReply->EventDataLength); |
7476 | if (evDataLen) { | 7476 | if (evDataLen) { |
7477 | evData0 = le32_to_cpu(pEventReply->Data[0]); | 7477 | evData0 = le32_to_cpu(pEventReply->Data[0]); |
7478 | } | 7478 | } |
7479 | 7479 | ||
7480 | #ifdef CONFIG_FUSION_LOGGING | 7480 | #ifdef CONFIG_FUSION_LOGGING |
7481 | if (evDataLen) | 7481 | if (evDataLen) |
7482 | mpt_display_event_info(ioc, pEventReply); | 7482 | mpt_display_event_info(ioc, pEventReply); |
7483 | #endif | 7483 | #endif |
7484 | 7484 | ||
7485 | /* | 7485 | /* |
7486 | * Do general / base driver event processing | 7486 | * Do general / base driver event processing |
7487 | */ | 7487 | */ |
7488 | switch(event) { | 7488 | switch(event) { |
7489 | case MPI_EVENT_EVENT_CHANGE: /* 0A */ | 7489 | case MPI_EVENT_EVENT_CHANGE: /* 0A */ |
7490 | if (evDataLen) { | 7490 | if (evDataLen) { |
7491 | u8 evState = evData0 & 0xFF; | 7491 | u8 evState = evData0 & 0xFF; |
7492 | 7492 | ||
7493 | /* CHECKME! What if evState unexpectedly says OFF (0)? */ | 7493 | /* CHECKME! What if evState unexpectedly says OFF (0)? */ |
7494 | 7494 | ||
7495 | /* Update EventState field in cached IocFacts */ | 7495 | /* Update EventState field in cached IocFacts */ |
7496 | if (ioc->facts.Function) { | 7496 | if (ioc->facts.Function) { |
7497 | ioc->facts.EventState = evState; | 7497 | ioc->facts.EventState = evState; |
7498 | } | 7498 | } |
7499 | } | 7499 | } |
7500 | break; | 7500 | break; |
7501 | case MPI_EVENT_INTEGRATED_RAID: | 7501 | case MPI_EVENT_INTEGRATED_RAID: |
7502 | mptbase_raid_process_event_data(ioc, | 7502 | mptbase_raid_process_event_data(ioc, |
7503 | (MpiEventDataRaid_t *)pEventReply->Data); | 7503 | (MpiEventDataRaid_t *)pEventReply->Data); |
7504 | break; | 7504 | break; |
7505 | default: | 7505 | default: |
7506 | break; | 7506 | break; |
7507 | } | 7507 | } |
7508 | 7508 | ||
7509 | /* | 7509 | /* |
7510 | * Should this event be logged? Events are written sequentially. | 7510 | * Should this event be logged? Events are written sequentially. |
7511 | * When buffer is full, start again at the top. | 7511 | * When buffer is full, start again at the top. |
7512 | */ | 7512 | */ |
7513 | if (ioc->events && (ioc->eventTypes & ( 1 << event))) { | 7513 | if (ioc->events && (ioc->eventTypes & ( 1 << event))) { |
7514 | int idx; | 7514 | int idx; |
7515 | 7515 | ||
7516 | idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE; | 7516 | idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE; |
7517 | 7517 | ||
7518 | ioc->events[idx].event = event; | 7518 | ioc->events[idx].event = event; |
7519 | ioc->events[idx].eventContext = ioc->eventContext; | 7519 | ioc->events[idx].eventContext = ioc->eventContext; |
7520 | 7520 | ||
7521 | for (ii = 0; ii < 2; ii++) { | 7521 | for (ii = 0; ii < 2; ii++) { |
7522 | if (ii < evDataLen) | 7522 | if (ii < evDataLen) |
7523 | ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]); | 7523 | ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]); |
7524 | else | 7524 | else |
7525 | ioc->events[idx].data[ii] = 0; | 7525 | ioc->events[idx].data[ii] = 0; |
7526 | } | 7526 | } |
7527 | 7527 | ||
7528 | ioc->eventContext++; | 7528 | ioc->eventContext++; |
7529 | } | 7529 | } |
7530 | 7530 | ||
7531 | 7531 | ||
7532 | /* | 7532 | /* |
7533 | * Call each currently registered protocol event handler. | 7533 | * Call each currently registered protocol event handler. |
7534 | */ | 7534 | */ |
7535 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { | 7535 | for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { |
7536 | if (MptEvHandlers[cb_idx]) { | 7536 | if (MptEvHandlers[cb_idx]) { |
7537 | devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 7537 | devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
7538 | "Routing Event to event handler #%d\n", | 7538 | "Routing Event to event handler #%d\n", |
7539 | ioc->name, cb_idx)); | 7539 | ioc->name, cb_idx)); |
7540 | r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply); | 7540 | r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply); |
7541 | handlers++; | 7541 | handlers++; |
7542 | } | 7542 | } |
7543 | } | 7543 | } |
7544 | /* FIXME? Examine results here? */ | 7544 | /* FIXME? Examine results here? */ |
7545 | 7545 | ||
7546 | /* | 7546 | /* |
7547 | * If needed, send (a single) EventAck. | 7547 | * If needed, send (a single) EventAck. |
7548 | */ | 7548 | */ |
7549 | if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) { | 7549 | if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) { |
7550 | devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 7550 | devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
7551 | "EventAck required\n",ioc->name)); | 7551 | "EventAck required\n",ioc->name)); |
7552 | if ((ii = SendEventAck(ioc, pEventReply)) != 0) { | 7552 | if ((ii = SendEventAck(ioc, pEventReply)) != 0) { |
7553 | devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n", | 7553 | devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n", |
7554 | ioc->name, ii)); | 7554 | ioc->name, ii)); |
7555 | } | 7555 | } |
7556 | } | 7556 | } |
7557 | 7557 | ||
7558 | *evHandlers = handlers; | 7558 | *evHandlers = handlers; |
7559 | return r; | 7559 | return r; |
7560 | } | 7560 | } |
7561 | 7561 | ||
7562 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 7562 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
7563 | /** | 7563 | /** |
7564 | * mpt_fc_log_info - Log information returned from Fibre Channel IOC. | 7564 | * mpt_fc_log_info - Log information returned from Fibre Channel IOC. |
7565 | * @ioc: Pointer to MPT_ADAPTER structure | 7565 | * @ioc: Pointer to MPT_ADAPTER structure |
7566 | * @log_info: U32 LogInfo reply word from the IOC | 7566 | * @log_info: U32 LogInfo reply word from the IOC |
7567 | * | 7567 | * |
7568 | * Refer to lsi/mpi_log_fc.h. | 7568 | * Refer to lsi/mpi_log_fc.h. |
7569 | */ | 7569 | */ |
7570 | static void | 7570 | static void |
7571 | mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info) | 7571 | mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info) |
7572 | { | 7572 | { |
7573 | char *desc = "unknown"; | 7573 | char *desc = "unknown"; |
7574 | 7574 | ||
7575 | switch (log_info & 0xFF000000) { | 7575 | switch (log_info & 0xFF000000) { |
7576 | case MPI_IOCLOGINFO_FC_INIT_BASE: | 7576 | case MPI_IOCLOGINFO_FC_INIT_BASE: |
7577 | desc = "FCP Initiator"; | 7577 | desc = "FCP Initiator"; |
7578 | break; | 7578 | break; |
7579 | case MPI_IOCLOGINFO_FC_TARGET_BASE: | 7579 | case MPI_IOCLOGINFO_FC_TARGET_BASE: |
7580 | desc = "FCP Target"; | 7580 | desc = "FCP Target"; |
7581 | break; | 7581 | break; |
7582 | case MPI_IOCLOGINFO_FC_LAN_BASE: | 7582 | case MPI_IOCLOGINFO_FC_LAN_BASE: |
7583 | desc = "LAN"; | 7583 | desc = "LAN"; |
7584 | break; | 7584 | break; |
7585 | case MPI_IOCLOGINFO_FC_MSG_BASE: | 7585 | case MPI_IOCLOGINFO_FC_MSG_BASE: |
7586 | desc = "MPI Message Layer"; | 7586 | desc = "MPI Message Layer"; |
7587 | break; | 7587 | break; |
7588 | case MPI_IOCLOGINFO_FC_LINK_BASE: | 7588 | case MPI_IOCLOGINFO_FC_LINK_BASE: |
7589 | desc = "FC Link"; | 7589 | desc = "FC Link"; |
7590 | break; | 7590 | break; |
7591 | case MPI_IOCLOGINFO_FC_CTX_BASE: | 7591 | case MPI_IOCLOGINFO_FC_CTX_BASE: |
7592 | desc = "Context Manager"; | 7592 | desc = "Context Manager"; |
7593 | break; | 7593 | break; |
7594 | case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET: | 7594 | case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET: |
7595 | desc = "Invalid Field Offset"; | 7595 | desc = "Invalid Field Offset"; |
7596 | break; | 7596 | break; |
7597 | case MPI_IOCLOGINFO_FC_STATE_CHANGE: | 7597 | case MPI_IOCLOGINFO_FC_STATE_CHANGE: |
7598 | desc = "State Change Info"; | 7598 | desc = "State Change Info"; |
7599 | break; | 7599 | break; |
7600 | } | 7600 | } |
7601 | 7601 | ||
7602 | printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n", | 7602 | printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n", |
7603 | ioc->name, log_info, desc, (log_info & 0xFFFFFF)); | 7603 | ioc->name, log_info, desc, (log_info & 0xFFFFFF)); |
7604 | } | 7604 | } |
7605 | 7605 | ||
7606 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 7606 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
7607 | /** | 7607 | /** |
7608 | * mpt_spi_log_info - Log information returned from SCSI Parallel IOC. | 7608 | * mpt_spi_log_info - Log information returned from SCSI Parallel IOC. |
7609 | * @ioc: Pointer to MPT_ADAPTER structure | 7609 | * @ioc: Pointer to MPT_ADAPTER structure |
7610 | * @log_info: U32 LogInfo word from the IOC | 7610 | * @log_info: U32 LogInfo word from the IOC |
7611 | * | 7611 | * |
7612 | * Refer to lsi/sp_log.h. | 7612 | * Refer to lsi/sp_log.h. |
7613 | */ | 7613 | */ |
7614 | static void | 7614 | static void |
7615 | mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) | 7615 | mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) |
7616 | { | 7616 | { |
7617 | u32 info = log_info & 0x00FF0000; | 7617 | u32 info = log_info & 0x00FF0000; |
7618 | char *desc = "unknown"; | 7618 | char *desc = "unknown"; |
7619 | 7619 | ||
7620 | switch (info) { | 7620 | switch (info) { |
7621 | case 0x00010000: | 7621 | case 0x00010000: |
7622 | desc = "bug! MID not found"; | 7622 | desc = "bug! MID not found"; |
7623 | break; | 7623 | break; |
7624 | 7624 | ||
7625 | case 0x00020000: | 7625 | case 0x00020000: |
7626 | desc = "Parity Error"; | 7626 | desc = "Parity Error"; |
7627 | break; | 7627 | break; |
7628 | 7628 | ||
7629 | case 0x00030000: | 7629 | case 0x00030000: |
7630 | desc = "ASYNC Outbound Overrun"; | 7630 | desc = "ASYNC Outbound Overrun"; |
7631 | break; | 7631 | break; |
7632 | 7632 | ||
7633 | case 0x00040000: | 7633 | case 0x00040000: |
7634 | desc = "SYNC Offset Error"; | 7634 | desc = "SYNC Offset Error"; |
7635 | break; | 7635 | break; |
7636 | 7636 | ||
7637 | case 0x00050000: | 7637 | case 0x00050000: |
7638 | desc = "BM Change"; | 7638 | desc = "BM Change"; |
7639 | break; | 7639 | break; |
7640 | 7640 | ||
7641 | case 0x00060000: | 7641 | case 0x00060000: |
7642 | desc = "Msg In Overflow"; | 7642 | desc = "Msg In Overflow"; |
7643 | break; | 7643 | break; |
7644 | 7644 | ||
7645 | case 0x00070000: | 7645 | case 0x00070000: |
7646 | desc = "DMA Error"; | 7646 | desc = "DMA Error"; |
7647 | break; | 7647 | break; |
7648 | 7648 | ||
7649 | case 0x00080000: | 7649 | case 0x00080000: |
7650 | desc = "Outbound DMA Overrun"; | 7650 | desc = "Outbound DMA Overrun"; |
7651 | break; | 7651 | break; |
7652 | 7652 | ||
7653 | case 0x00090000: | 7653 | case 0x00090000: |
7654 | desc = "Task Management"; | 7654 | desc = "Task Management"; |
7655 | break; | 7655 | break; |
7656 | 7656 | ||
7657 | case 0x000A0000: | 7657 | case 0x000A0000: |
7658 | desc = "Device Problem"; | 7658 | desc = "Device Problem"; |
7659 | break; | 7659 | break; |
7660 | 7660 | ||
7661 | case 0x000B0000: | 7661 | case 0x000B0000: |
7662 | desc = "Invalid Phase Change"; | 7662 | desc = "Invalid Phase Change"; |
7663 | break; | 7663 | break; |
7664 | 7664 | ||
7665 | case 0x000C0000: | 7665 | case 0x000C0000: |
7666 | desc = "Untagged Table Size"; | 7666 | desc = "Untagged Table Size"; |
7667 | break; | 7667 | break; |
7668 | 7668 | ||
7669 | } | 7669 | } |
7670 | 7670 | ||
7671 | printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc); | 7671 | printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc); |
7672 | } | 7672 | } |
7673 | 7673 | ||
7674 | /* strings for sas loginfo */ | 7674 | /* strings for sas loginfo */ |
7675 | static char *originator_str[] = { | 7675 | static char *originator_str[] = { |
7676 | "IOP", /* 00h */ | 7676 | "IOP", /* 00h */ |
7677 | "PL", /* 01h */ | 7677 | "PL", /* 01h */ |
7678 | "IR" /* 02h */ | 7678 | "IR" /* 02h */ |
7679 | }; | 7679 | }; |
7680 | static char *iop_code_str[] = { | 7680 | static char *iop_code_str[] = { |
7681 | NULL, /* 00h */ | 7681 | NULL, /* 00h */ |
7682 | "Invalid SAS Address", /* 01h */ | 7682 | "Invalid SAS Address", /* 01h */ |
7683 | NULL, /* 02h */ | 7683 | NULL, /* 02h */ |
7684 | "Invalid Page", /* 03h */ | 7684 | "Invalid Page", /* 03h */ |
7685 | "Diag Message Error", /* 04h */ | 7685 | "Diag Message Error", /* 04h */ |
7686 | "Task Terminated", /* 05h */ | 7686 | "Task Terminated", /* 05h */ |
7687 | "Enclosure Management", /* 06h */ | 7687 | "Enclosure Management", /* 06h */ |
7688 | "Target Mode" /* 07h */ | 7688 | "Target Mode" /* 07h */ |
7689 | }; | 7689 | }; |
7690 | static char *pl_code_str[] = { | 7690 | static char *pl_code_str[] = { |
7691 | NULL, /* 00h */ | 7691 | NULL, /* 00h */ |
7692 | "Open Failure", /* 01h */ | 7692 | "Open Failure", /* 01h */ |
7693 | "Invalid Scatter Gather List", /* 02h */ | 7693 | "Invalid Scatter Gather List", /* 02h */ |
7694 | "Wrong Relative Offset or Frame Length", /* 03h */ | 7694 | "Wrong Relative Offset or Frame Length", /* 03h */ |
7695 | "Frame Transfer Error", /* 04h */ | 7695 | "Frame Transfer Error", /* 04h */ |
7696 | "Transmit Frame Connected Low", /* 05h */ | 7696 | "Transmit Frame Connected Low", /* 05h */ |
7697 | "SATA Non-NCQ RW Error Bit Set", /* 06h */ | 7697 | "SATA Non-NCQ RW Error Bit Set", /* 06h */ |
7698 | "SATA Read Log Receive Data Error", /* 07h */ | 7698 | "SATA Read Log Receive Data Error", /* 07h */ |
7699 | "SATA NCQ Fail All Commands After Error", /* 08h */ | 7699 | "SATA NCQ Fail All Commands After Error", /* 08h */ |
7700 | "SATA Error in Receive Set Device Bit FIS", /* 09h */ | 7700 | "SATA Error in Receive Set Device Bit FIS", /* 09h */ |
7701 | "Receive Frame Invalid Message", /* 0Ah */ | 7701 | "Receive Frame Invalid Message", /* 0Ah */ |
7702 | "Receive Context Message Valid Error", /* 0Bh */ | 7702 | "Receive Context Message Valid Error", /* 0Bh */ |
7703 | "Receive Frame Current Frame Error", /* 0Ch */ | 7703 | "Receive Frame Current Frame Error", /* 0Ch */ |
7704 | "SATA Link Down", /* 0Dh */ | 7704 | "SATA Link Down", /* 0Dh */ |
7705 | "Discovery SATA Init W IOS", /* 0Eh */ | 7705 | "Discovery SATA Init W IOS", /* 0Eh */ |
7706 | "Config Invalid Page", /* 0Fh */ | 7706 | "Config Invalid Page", /* 0Fh */ |
7707 | "Discovery SATA Init Timeout", /* 10h */ | 7707 | "Discovery SATA Init Timeout", /* 10h */ |
7708 | "Reset", /* 11h */ | 7708 | "Reset", /* 11h */ |
7709 | "Abort", /* 12h */ | 7709 | "Abort", /* 12h */ |
7710 | "IO Not Yet Executed", /* 13h */ | 7710 | "IO Not Yet Executed", /* 13h */ |
7711 | "IO Executed", /* 14h */ | 7711 | "IO Executed", /* 14h */ |
7712 | "Persistent Reservation Out Not Affiliation " | 7712 | "Persistent Reservation Out Not Affiliation " |
7713 | "Owner", /* 15h */ | 7713 | "Owner", /* 15h */ |
7714 | "Open Transmit DMA Abort", /* 16h */ | 7714 | "Open Transmit DMA Abort", /* 16h */ |
7715 | "IO Device Missing Delay Retry", /* 17h */ | 7715 | "IO Device Missing Delay Retry", /* 17h */ |
7716 | "IO Cancelled Due to Recieve Error", /* 18h */ | 7716 | "IO Cancelled Due to Recieve Error", /* 18h */ |
7717 | NULL, /* 19h */ | 7717 | NULL, /* 19h */ |
7718 | NULL, /* 1Ah */ | 7718 | NULL, /* 1Ah */ |
7719 | NULL, /* 1Bh */ | 7719 | NULL, /* 1Bh */ |
7720 | NULL, /* 1Ch */ | 7720 | NULL, /* 1Ch */ |
7721 | NULL, /* 1Dh */ | 7721 | NULL, /* 1Dh */ |
7722 | NULL, /* 1Eh */ | 7722 | NULL, /* 1Eh */ |
7723 | NULL, /* 1Fh */ | 7723 | NULL, /* 1Fh */ |
7724 | "Enclosure Management" /* 20h */ | 7724 | "Enclosure Management" /* 20h */ |
7725 | }; | 7725 | }; |
7726 | static char *ir_code_str[] = { | 7726 | static char *ir_code_str[] = { |
7727 | "Raid Action Error", /* 00h */ | 7727 | "Raid Action Error", /* 00h */ |
7728 | NULL, /* 00h */ | 7728 | NULL, /* 00h */ |
7729 | NULL, /* 01h */ | 7729 | NULL, /* 01h */ |
7730 | NULL, /* 02h */ | 7730 | NULL, /* 02h */ |
7731 | NULL, /* 03h */ | 7731 | NULL, /* 03h */ |
7732 | NULL, /* 04h */ | 7732 | NULL, /* 04h */ |
7733 | NULL, /* 05h */ | 7733 | NULL, /* 05h */ |
7734 | NULL, /* 06h */ | 7734 | NULL, /* 06h */ |
7735 | NULL /* 07h */ | 7735 | NULL /* 07h */ |
7736 | }; | 7736 | }; |
7737 | static char *raid_sub_code_str[] = { | 7737 | static char *raid_sub_code_str[] = { |
7738 | NULL, /* 00h */ | 7738 | NULL, /* 00h */ |
7739 | "Volume Creation Failed: Data Passed too " | 7739 | "Volume Creation Failed: Data Passed too " |
7740 | "Large", /* 01h */ | 7740 | "Large", /* 01h */ |
7741 | "Volume Creation Failed: Duplicate Volumes " | 7741 | "Volume Creation Failed: Duplicate Volumes " |
7742 | "Attempted", /* 02h */ | 7742 | "Attempted", /* 02h */ |
7743 | "Volume Creation Failed: Max Number " | 7743 | "Volume Creation Failed: Max Number " |
7744 | "Supported Volumes Exceeded", /* 03h */ | 7744 | "Supported Volumes Exceeded", /* 03h */ |
7745 | "Volume Creation Failed: DMA Error", /* 04h */ | 7745 | "Volume Creation Failed: DMA Error", /* 04h */ |
7746 | "Volume Creation Failed: Invalid Volume Type", /* 05h */ | 7746 | "Volume Creation Failed: Invalid Volume Type", /* 05h */ |
7747 | "Volume Creation Failed: Error Reading " | 7747 | "Volume Creation Failed: Error Reading " |
7748 | "MFG Page 4", /* 06h */ | 7748 | "MFG Page 4", /* 06h */ |
7749 | "Volume Creation Failed: Creating Internal " | 7749 | "Volume Creation Failed: Creating Internal " |
7750 | "Structures", /* 07h */ | 7750 | "Structures", /* 07h */ |
7751 | NULL, /* 08h */ | 7751 | NULL, /* 08h */ |
7752 | NULL, /* 09h */ | 7752 | NULL, /* 09h */ |
7753 | NULL, /* 0Ah */ | 7753 | NULL, /* 0Ah */ |
7754 | NULL, /* 0Bh */ | 7754 | NULL, /* 0Bh */ |
7755 | NULL, /* 0Ch */ | 7755 | NULL, /* 0Ch */ |
7756 | NULL, /* 0Dh */ | 7756 | NULL, /* 0Dh */ |
7757 | NULL, /* 0Eh */ | 7757 | NULL, /* 0Eh */ |
7758 | NULL, /* 0Fh */ | 7758 | NULL, /* 0Fh */ |
7759 | "Activation failed: Already Active Volume", /* 10h */ | 7759 | "Activation failed: Already Active Volume", /* 10h */ |
7760 | "Activation failed: Unsupported Volume Type", /* 11h */ | 7760 | "Activation failed: Unsupported Volume Type", /* 11h */ |
7761 | "Activation failed: Too Many Active Volumes", /* 12h */ | 7761 | "Activation failed: Too Many Active Volumes", /* 12h */ |
7762 | "Activation failed: Volume ID in Use", /* 13h */ | 7762 | "Activation failed: Volume ID in Use", /* 13h */ |
7763 | "Activation failed: Reported Failure", /* 14h */ | 7763 | "Activation failed: Reported Failure", /* 14h */ |
7764 | "Activation failed: Importing a Volume", /* 15h */ | 7764 | "Activation failed: Importing a Volume", /* 15h */ |
7765 | NULL, /* 16h */ | 7765 | NULL, /* 16h */ |
7766 | NULL, /* 17h */ | 7766 | NULL, /* 17h */ |
7767 | NULL, /* 18h */ | 7767 | NULL, /* 18h */ |
7768 | NULL, /* 19h */ | 7768 | NULL, /* 19h */ |
7769 | NULL, /* 1Ah */ | 7769 | NULL, /* 1Ah */ |
7770 | NULL, /* 1Bh */ | 7770 | NULL, /* 1Bh */ |
7771 | NULL, /* 1Ch */ | 7771 | NULL, /* 1Ch */ |
7772 | NULL, /* 1Dh */ | 7772 | NULL, /* 1Dh */ |
7773 | NULL, /* 1Eh */ | 7773 | NULL, /* 1Eh */ |
7774 | NULL, /* 1Fh */ | 7774 | NULL, /* 1Fh */ |
7775 | "Phys Disk failed: Too Many Phys Disks", /* 20h */ | 7775 | "Phys Disk failed: Too Many Phys Disks", /* 20h */ |
7776 | "Phys Disk failed: Data Passed too Large", /* 21h */ | 7776 | "Phys Disk failed: Data Passed too Large", /* 21h */ |
7777 | "Phys Disk failed: DMA Error", /* 22h */ | 7777 | "Phys Disk failed: DMA Error", /* 22h */ |
7778 | "Phys Disk failed: Invalid <channel:id>", /* 23h */ | 7778 | "Phys Disk failed: Invalid <channel:id>", /* 23h */ |
7779 | "Phys Disk failed: Creating Phys Disk Config " | 7779 | "Phys Disk failed: Creating Phys Disk Config " |
7780 | "Page", /* 24h */ | 7780 | "Page", /* 24h */ |
7781 | NULL, /* 25h */ | 7781 | NULL, /* 25h */ |
7782 | NULL, /* 26h */ | 7782 | NULL, /* 26h */ |
7783 | NULL, /* 27h */ | 7783 | NULL, /* 27h */ |
7784 | NULL, /* 28h */ | 7784 | NULL, /* 28h */ |
7785 | NULL, /* 29h */ | 7785 | NULL, /* 29h */ |
7786 | NULL, /* 2Ah */ | 7786 | NULL, /* 2Ah */ |
7787 | NULL, /* 2Bh */ | 7787 | NULL, /* 2Bh */ |
7788 | NULL, /* 2Ch */ | 7788 | NULL, /* 2Ch */ |
7789 | NULL, /* 2Dh */ | 7789 | NULL, /* 2Dh */ |
7790 | NULL, /* 2Eh */ | 7790 | NULL, /* 2Eh */ |
7791 | NULL, /* 2Fh */ | 7791 | NULL, /* 2Fh */ |
7792 | "Compatibility Error: IR Disabled", /* 30h */ | 7792 | "Compatibility Error: IR Disabled", /* 30h */ |
7793 | "Compatibility Error: Inquiry Comand Failed", /* 31h */ | 7793 | "Compatibility Error: Inquiry Comand Failed", /* 31h */ |
7794 | "Compatibility Error: Device not Direct Access " | 7794 | "Compatibility Error: Device not Direct Access " |
7795 | "Device ", /* 32h */ | 7795 | "Device ", /* 32h */ |
7796 | "Compatibility Error: Removable Device Found", /* 33h */ | 7796 | "Compatibility Error: Removable Device Found", /* 33h */ |
7797 | "Compatibility Error: Device SCSI Version not " | 7797 | "Compatibility Error: Device SCSI Version not " |
7798 | "2 or Higher", /* 34h */ | 7798 | "2 or Higher", /* 34h */ |
7799 | "Compatibility Error: SATA Device, 48 BIT LBA " | 7799 | "Compatibility Error: SATA Device, 48 BIT LBA " |
7800 | "not Supported", /* 35h */ | 7800 | "not Supported", /* 35h */ |
7801 | "Compatibility Error: Device doesn't have " | 7801 | "Compatibility Error: Device doesn't have " |
7802 | "512 Byte Block Sizes", /* 36h */ | 7802 | "512 Byte Block Sizes", /* 36h */ |
7803 | "Compatibility Error: Volume Type Check Failed", /* 37h */ | 7803 | "Compatibility Error: Volume Type Check Failed", /* 37h */ |
7804 | "Compatibility Error: Volume Type is " | 7804 | "Compatibility Error: Volume Type is " |
7805 | "Unsupported by FW", /* 38h */ | 7805 | "Unsupported by FW", /* 38h */ |
7806 | "Compatibility Error: Disk Drive too Small for " | 7806 | "Compatibility Error: Disk Drive too Small for " |
7807 | "use in Volume", /* 39h */ | 7807 | "use in Volume", /* 39h */ |
7808 | "Compatibility Error: Phys Disk for Create " | 7808 | "Compatibility Error: Phys Disk for Create " |
7809 | "Volume not Found", /* 3Ah */ | 7809 | "Volume not Found", /* 3Ah */ |
7810 | "Compatibility Error: Too Many or too Few " | 7810 | "Compatibility Error: Too Many or too Few " |
7811 | "Disks for Volume Type", /* 3Bh */ | 7811 | "Disks for Volume Type", /* 3Bh */ |
7812 | "Compatibility Error: Disk stripe Sizes " | 7812 | "Compatibility Error: Disk stripe Sizes " |
7813 | "Must be 64KB", /* 3Ch */ | 7813 | "Must be 64KB", /* 3Ch */ |
7814 | "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */ | 7814 | "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */ |
7815 | }; | 7815 | }; |
7816 | 7816 | ||
7817 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 7817 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
7818 | /** | 7818 | /** |
7819 | * mpt_sas_log_info - Log information returned from SAS IOC. | 7819 | * mpt_sas_log_info - Log information returned from SAS IOC. |
7820 | * @ioc: Pointer to MPT_ADAPTER structure | 7820 | * @ioc: Pointer to MPT_ADAPTER structure |
7821 | * @log_info: U32 LogInfo reply word from the IOC | 7821 | * @log_info: U32 LogInfo reply word from the IOC |
7822 | * | 7822 | * |
7823 | * Refer to lsi/mpi_log_sas.h. | 7823 | * Refer to lsi/mpi_log_sas.h. |
7824 | **/ | 7824 | **/ |
7825 | static void | 7825 | static void |
7826 | mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info) | 7826 | mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info) |
7827 | { | 7827 | { |
7828 | union loginfo_type { | 7828 | union loginfo_type { |
7829 | u32 loginfo; | 7829 | u32 loginfo; |
7830 | struct { | 7830 | struct { |
7831 | u32 subcode:16; | 7831 | u32 subcode:16; |
7832 | u32 code:8; | 7832 | u32 code:8; |
7833 | u32 originator:4; | 7833 | u32 originator:4; |
7834 | u32 bus_type:4; | 7834 | u32 bus_type:4; |
7835 | }dw; | 7835 | }dw; |
7836 | }; | 7836 | }; |
7837 | union loginfo_type sas_loginfo; | 7837 | union loginfo_type sas_loginfo; |
7838 | char *originator_desc = NULL; | 7838 | char *originator_desc = NULL; |
7839 | char *code_desc = NULL; | 7839 | char *code_desc = NULL; |
7840 | char *sub_code_desc = NULL; | 7840 | char *sub_code_desc = NULL; |
7841 | 7841 | ||
7842 | sas_loginfo.loginfo = log_info; | 7842 | sas_loginfo.loginfo = log_info; |
7843 | if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) && | 7843 | if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) && |
7844 | (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str))) | 7844 | (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str))) |
7845 | return; | 7845 | return; |
7846 | 7846 | ||
7847 | originator_desc = originator_str[sas_loginfo.dw.originator]; | 7847 | originator_desc = originator_str[sas_loginfo.dw.originator]; |
7848 | 7848 | ||
7849 | switch (sas_loginfo.dw.originator) { | 7849 | switch (sas_loginfo.dw.originator) { |
7850 | 7850 | ||
7851 | case 0: /* IOP */ | 7851 | case 0: /* IOP */ |
7852 | if (sas_loginfo.dw.code < | 7852 | if (sas_loginfo.dw.code < |
7853 | ARRAY_SIZE(iop_code_str)) | 7853 | ARRAY_SIZE(iop_code_str)) |
7854 | code_desc = iop_code_str[sas_loginfo.dw.code]; | 7854 | code_desc = iop_code_str[sas_loginfo.dw.code]; |
7855 | break; | 7855 | break; |
7856 | case 1: /* PL */ | 7856 | case 1: /* PL */ |
7857 | if (sas_loginfo.dw.code < | 7857 | if (sas_loginfo.dw.code < |
7858 | ARRAY_SIZE(pl_code_str)) | 7858 | ARRAY_SIZE(pl_code_str)) |
7859 | code_desc = pl_code_str[sas_loginfo.dw.code]; | 7859 | code_desc = pl_code_str[sas_loginfo.dw.code]; |
7860 | break; | 7860 | break; |
7861 | case 2: /* IR */ | 7861 | case 2: /* IR */ |
7862 | if (sas_loginfo.dw.code >= | 7862 | if (sas_loginfo.dw.code >= |
7863 | ARRAY_SIZE(ir_code_str)) | 7863 | ARRAY_SIZE(ir_code_str)) |
7864 | break; | 7864 | break; |
7865 | code_desc = ir_code_str[sas_loginfo.dw.code]; | 7865 | code_desc = ir_code_str[sas_loginfo.dw.code]; |
7866 | if (sas_loginfo.dw.subcode >= | 7866 | if (sas_loginfo.dw.subcode >= |
7867 | ARRAY_SIZE(raid_sub_code_str)) | 7867 | ARRAY_SIZE(raid_sub_code_str)) |
7868 | break; | 7868 | break; |
7869 | if (sas_loginfo.dw.code == 0) | 7869 | if (sas_loginfo.dw.code == 0) |
7870 | sub_code_desc = | 7870 | sub_code_desc = |
7871 | raid_sub_code_str[sas_loginfo.dw.subcode]; | 7871 | raid_sub_code_str[sas_loginfo.dw.subcode]; |
7872 | break; | 7872 | break; |
7873 | default: | 7873 | default: |
7874 | return; | 7874 | return; |
7875 | } | 7875 | } |
7876 | 7876 | ||
7877 | if (sub_code_desc != NULL) | 7877 | if (sub_code_desc != NULL) |
7878 | printk(MYIOC_s_INFO_FMT | 7878 | printk(MYIOC_s_INFO_FMT |
7879 | "LogInfo(0x%08x): Originator={%s}, Code={%s}," | 7879 | "LogInfo(0x%08x): Originator={%s}, Code={%s}," |
7880 | " SubCode={%s}\n", | 7880 | " SubCode={%s}\n", |
7881 | ioc->name, log_info, originator_desc, code_desc, | 7881 | ioc->name, log_info, originator_desc, code_desc, |
7882 | sub_code_desc); | 7882 | sub_code_desc); |
7883 | else if (code_desc != NULL) | 7883 | else if (code_desc != NULL) |
7884 | printk(MYIOC_s_INFO_FMT | 7884 | printk(MYIOC_s_INFO_FMT |
7885 | "LogInfo(0x%08x): Originator={%s}, Code={%s}," | 7885 | "LogInfo(0x%08x): Originator={%s}, Code={%s}," |
7886 | " SubCode(0x%04x)\n", | 7886 | " SubCode(0x%04x)\n", |
7887 | ioc->name, log_info, originator_desc, code_desc, | 7887 | ioc->name, log_info, originator_desc, code_desc, |
7888 | sas_loginfo.dw.subcode); | 7888 | sas_loginfo.dw.subcode); |
7889 | else | 7889 | else |
7890 | printk(MYIOC_s_INFO_FMT | 7890 | printk(MYIOC_s_INFO_FMT |
7891 | "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x)," | 7891 | "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x)," |
7892 | " SubCode(0x%04x)\n", | 7892 | " SubCode(0x%04x)\n", |
7893 | ioc->name, log_info, originator_desc, | 7893 | ioc->name, log_info, originator_desc, |
7894 | sas_loginfo.dw.code, sas_loginfo.dw.subcode); | 7894 | sas_loginfo.dw.code, sas_loginfo.dw.subcode); |
7895 | } | 7895 | } |
7896 | 7896 | ||
7897 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 7897 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
7898 | /** | 7898 | /** |
7899 | * mpt_iocstatus_info_config - IOCSTATUS information for config pages | 7899 | * mpt_iocstatus_info_config - IOCSTATUS information for config pages |
7900 | * @ioc: Pointer to MPT_ADAPTER structure | 7900 | * @ioc: Pointer to MPT_ADAPTER structure |
7901 | * @ioc_status: U32 IOCStatus word from IOC | 7901 | * @ioc_status: U32 IOCStatus word from IOC |
7902 | * @mf: Pointer to MPT request frame | 7902 | * @mf: Pointer to MPT request frame |
7903 | * | 7903 | * |
7904 | * Refer to lsi/mpi.h. | 7904 | * Refer to lsi/mpi.h. |
7905 | **/ | 7905 | **/ |
7906 | static void | 7906 | static void |
7907 | mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) | 7907 | mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) |
7908 | { | 7908 | { |
7909 | Config_t *pReq = (Config_t *)mf; | 7909 | Config_t *pReq = (Config_t *)mf; |
7910 | char extend_desc[EVENT_DESCR_STR_SZ]; | 7910 | char extend_desc[EVENT_DESCR_STR_SZ]; |
7911 | char *desc = NULL; | 7911 | char *desc = NULL; |
7912 | u32 form; | 7912 | u32 form; |
7913 | u8 page_type; | 7913 | u8 page_type; |
7914 | 7914 | ||
7915 | if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED) | 7915 | if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED) |
7916 | page_type = pReq->ExtPageType; | 7916 | page_type = pReq->ExtPageType; |
7917 | else | 7917 | else |
7918 | page_type = pReq->Header.PageType; | 7918 | page_type = pReq->Header.PageType; |
7919 | 7919 | ||
7920 | /* | 7920 | /* |
7921 | * ignore invalid page messages for GET_NEXT_HANDLE | 7921 | * ignore invalid page messages for GET_NEXT_HANDLE |
7922 | */ | 7922 | */ |
7923 | form = le32_to_cpu(pReq->PageAddress); | 7923 | form = le32_to_cpu(pReq->PageAddress); |
7924 | if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { | 7924 | if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { |
7925 | if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE || | 7925 | if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE || |
7926 | page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER || | 7926 | page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER || |
7927 | page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) { | 7927 | page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) { |
7928 | if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) == | 7928 | if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) == |
7929 | MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) | 7929 | MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) |
7930 | return; | 7930 | return; |
7931 | } | 7931 | } |
7932 | if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE) | 7932 | if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE) |
7933 | if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) == | 7933 | if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) == |
7934 | MPI_FC_DEVICE_PGAD_FORM_NEXT_DID) | 7934 | MPI_FC_DEVICE_PGAD_FORM_NEXT_DID) |
7935 | return; | 7935 | return; |
7936 | } | 7936 | } |
7937 | 7937 | ||
7938 | snprintf(extend_desc, EVENT_DESCR_STR_SZ, | 7938 | snprintf(extend_desc, EVENT_DESCR_STR_SZ, |
7939 | "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh", | 7939 | "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh", |
7940 | page_type, pReq->Header.PageNumber, pReq->Action, form); | 7940 | page_type, pReq->Header.PageNumber, pReq->Action, form); |
7941 | 7941 | ||
7942 | switch (ioc_status) { | 7942 | switch (ioc_status) { |
7943 | 7943 | ||
7944 | case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */ | 7944 | case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */ |
7945 | desc = "Config Page Invalid Action"; | 7945 | desc = "Config Page Invalid Action"; |
7946 | break; | 7946 | break; |
7947 | 7947 | ||
7948 | case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */ | 7948 | case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */ |
7949 | desc = "Config Page Invalid Type"; | 7949 | desc = "Config Page Invalid Type"; |
7950 | break; | 7950 | break; |
7951 | 7951 | ||
7952 | case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */ | 7952 | case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */ |
7953 | desc = "Config Page Invalid Page"; | 7953 | desc = "Config Page Invalid Page"; |
7954 | break; | 7954 | break; |
7955 | 7955 | ||
7956 | case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */ | 7956 | case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */ |
7957 | desc = "Config Page Invalid Data"; | 7957 | desc = "Config Page Invalid Data"; |
7958 | break; | 7958 | break; |
7959 | 7959 | ||
7960 | case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */ | 7960 | case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */ |
7961 | desc = "Config Page No Defaults"; | 7961 | desc = "Config Page No Defaults"; |
7962 | break; | 7962 | break; |
7963 | 7963 | ||
7964 | case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */ | 7964 | case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */ |
7965 | desc = "Config Page Can't Commit"; | 7965 | desc = "Config Page Can't Commit"; |
7966 | break; | 7966 | break; |
7967 | } | 7967 | } |
7968 | 7968 | ||
7969 | if (!desc) | 7969 | if (!desc) |
7970 | return; | 7970 | return; |
7971 | 7971 | ||
7972 | dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n", | 7972 | dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n", |
7973 | ioc->name, ioc_status, desc, extend_desc)); | 7973 | ioc->name, ioc_status, desc, extend_desc)); |
7974 | } | 7974 | } |
7975 | 7975 | ||
7976 | /** | 7976 | /** |
7977 | * mpt_iocstatus_info - IOCSTATUS information returned from IOC. | 7977 | * mpt_iocstatus_info - IOCSTATUS information returned from IOC. |
7978 | * @ioc: Pointer to MPT_ADAPTER structure | 7978 | * @ioc: Pointer to MPT_ADAPTER structure |
7979 | * @ioc_status: U32 IOCStatus word from IOC | 7979 | * @ioc_status: U32 IOCStatus word from IOC |
7980 | * @mf: Pointer to MPT request frame | 7980 | * @mf: Pointer to MPT request frame |
7981 | * | 7981 | * |
7982 | * Refer to lsi/mpi.h. | 7982 | * Refer to lsi/mpi.h. |
7983 | **/ | 7983 | **/ |
7984 | static void | 7984 | static void |
7985 | mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) | 7985 | mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) |
7986 | { | 7986 | { |
7987 | u32 status = ioc_status & MPI_IOCSTATUS_MASK; | 7987 | u32 status = ioc_status & MPI_IOCSTATUS_MASK; |
7988 | char *desc = NULL; | 7988 | char *desc = NULL; |
7989 | 7989 | ||
7990 | switch (status) { | 7990 | switch (status) { |
7991 | 7991 | ||
7992 | /****************************************************************************/ | 7992 | /****************************************************************************/ |
7993 | /* Common IOCStatus values for all replies */ | 7993 | /* Common IOCStatus values for all replies */ |
7994 | /****************************************************************************/ | 7994 | /****************************************************************************/ |
7995 | 7995 | ||
7996 | case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */ | 7996 | case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */ |
7997 | desc = "Invalid Function"; | 7997 | desc = "Invalid Function"; |
7998 | break; | 7998 | break; |
7999 | 7999 | ||
8000 | case MPI_IOCSTATUS_BUSY: /* 0x0002 */ | 8000 | case MPI_IOCSTATUS_BUSY: /* 0x0002 */ |
8001 | desc = "Busy"; | 8001 | desc = "Busy"; |
8002 | break; | 8002 | break; |
8003 | 8003 | ||
8004 | case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */ | 8004 | case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */ |
8005 | desc = "Invalid SGL"; | 8005 | desc = "Invalid SGL"; |
8006 | break; | 8006 | break; |
8007 | 8007 | ||
8008 | case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */ | 8008 | case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */ |
8009 | desc = "Internal Error"; | 8009 | desc = "Internal Error"; |
8010 | break; | 8010 | break; |
8011 | 8011 | ||
8012 | case MPI_IOCSTATUS_RESERVED: /* 0x0005 */ | 8012 | case MPI_IOCSTATUS_RESERVED: /* 0x0005 */ |
8013 | desc = "Reserved"; | 8013 | desc = "Reserved"; |
8014 | break; | 8014 | break; |
8015 | 8015 | ||
8016 | case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ | 8016 | case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ |
8017 | desc = "Insufficient Resources"; | 8017 | desc = "Insufficient Resources"; |
8018 | break; | 8018 | break; |
8019 | 8019 | ||
8020 | case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */ | 8020 | case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */ |
8021 | desc = "Invalid Field"; | 8021 | desc = "Invalid Field"; |
8022 | break; | 8022 | break; |
8023 | 8023 | ||
8024 | case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */ | 8024 | case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */ |
8025 | desc = "Invalid State"; | 8025 | desc = "Invalid State"; |
8026 | break; | 8026 | break; |
8027 | 8027 | ||
8028 | /****************************************************************************/ | 8028 | /****************************************************************************/ |
8029 | /* Config IOCStatus values */ | 8029 | /* Config IOCStatus values */ |
8030 | /****************************************************************************/ | 8030 | /****************************************************************************/ |
8031 | 8031 | ||
8032 | case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */ | 8032 | case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */ |
8033 | case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */ | 8033 | case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */ |
8034 | case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */ | 8034 | case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */ |
8035 | case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */ | 8035 | case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */ |
8036 | case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */ | 8036 | case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */ |
8037 | case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */ | 8037 | case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */ |
8038 | mpt_iocstatus_info_config(ioc, status, mf); | 8038 | mpt_iocstatus_info_config(ioc, status, mf); |
8039 | break; | 8039 | break; |
8040 | 8040 | ||
8041 | /****************************************************************************/ | 8041 | /****************************************************************************/ |
8042 | /* SCSIIO Reply (SPI, FCP, SAS) initiator values */ | 8042 | /* SCSIIO Reply (SPI, FCP, SAS) initiator values */ |
8043 | /* */ | 8043 | /* */ |
8044 | /* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */ | 8044 | /* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */ |
8045 | /* */ | 8045 | /* */ |
8046 | /****************************************************************************/ | 8046 | /****************************************************************************/ |
8047 | 8047 | ||
8048 | case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ | 8048 | case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ |
8049 | case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ | 8049 | case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ |
8050 | case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ | 8050 | case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ |
8051 | case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */ | 8051 | case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */ |
8052 | case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ | 8052 | case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ |
8053 | case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */ | 8053 | case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */ |
8054 | case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ | 8054 | case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ |
8055 | case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ | 8055 | case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ |
8056 | case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ | 8056 | case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ |
8057 | case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ | 8057 | case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ |
8058 | case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */ | 8058 | case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */ |
8059 | case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ | 8059 | case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ |
8060 | case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ | 8060 | case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ |
8061 | break; | 8061 | break; |
8062 | 8062 | ||
8063 | /****************************************************************************/ | 8063 | /****************************************************************************/ |
8064 | /* SCSI Target values */ | 8064 | /* SCSI Target values */ |
8065 | /****************************************************************************/ | 8065 | /****************************************************************************/ |
8066 | 8066 | ||
8067 | case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */ | 8067 | case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */ |
8068 | desc = "Target: Priority IO"; | 8068 | desc = "Target: Priority IO"; |
8069 | break; | 8069 | break; |
8070 | 8070 | ||
8071 | case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */ | 8071 | case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */ |
8072 | desc = "Target: Invalid Port"; | 8072 | desc = "Target: Invalid Port"; |
8073 | break; | 8073 | break; |
8074 | 8074 | ||
8075 | case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */ | 8075 | case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */ |
8076 | desc = "Target Invalid IO Index:"; | 8076 | desc = "Target Invalid IO Index:"; |
8077 | break; | 8077 | break; |
8078 | 8078 | ||
8079 | case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */ | 8079 | case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */ |
8080 | desc = "Target: Aborted"; | 8080 | desc = "Target: Aborted"; |
8081 | break; | 8081 | break; |
8082 | 8082 | ||
8083 | case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */ | 8083 | case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */ |
8084 | desc = "Target: No Conn Retryable"; | 8084 | desc = "Target: No Conn Retryable"; |
8085 | break; | 8085 | break; |
8086 | 8086 | ||
8087 | case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */ | 8087 | case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */ |
8088 | desc = "Target: No Connection"; | 8088 | desc = "Target: No Connection"; |
8089 | break; | 8089 | break; |
8090 | 8090 | ||
8091 | case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */ | 8091 | case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */ |
8092 | desc = "Target: Transfer Count Mismatch"; | 8092 | desc = "Target: Transfer Count Mismatch"; |
8093 | break; | 8093 | break; |
8094 | 8094 | ||
8095 | case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */ | 8095 | case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */ |
8096 | desc = "Target: STS Data not Sent"; | 8096 | desc = "Target: STS Data not Sent"; |
8097 | break; | 8097 | break; |
8098 | 8098 | ||
8099 | case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */ | 8099 | case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */ |
8100 | desc = "Target: Data Offset Error"; | 8100 | desc = "Target: Data Offset Error"; |
8101 | break; | 8101 | break; |
8102 | 8102 | ||
8103 | case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */ | 8103 | case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */ |
8104 | desc = "Target: Too Much Write Data"; | 8104 | desc = "Target: Too Much Write Data"; |
8105 | break; | 8105 | break; |
8106 | 8106 | ||
8107 | case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */ | 8107 | case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */ |
8108 | desc = "Target: IU Too Short"; | 8108 | desc = "Target: IU Too Short"; |
8109 | break; | 8109 | break; |
8110 | 8110 | ||
8111 | case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */ | 8111 | case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */ |
8112 | desc = "Target: ACK NAK Timeout"; | 8112 | desc = "Target: ACK NAK Timeout"; |
8113 | break; | 8113 | break; |
8114 | 8114 | ||
8115 | case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */ | 8115 | case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */ |
8116 | desc = "Target: Nak Received"; | 8116 | desc = "Target: Nak Received"; |
8117 | break; | 8117 | break; |
8118 | 8118 | ||
8119 | /****************************************************************************/ | 8119 | /****************************************************************************/ |
8120 | /* Fibre Channel Direct Access values */ | 8120 | /* Fibre Channel Direct Access values */ |
8121 | /****************************************************************************/ | 8121 | /****************************************************************************/ |
8122 | 8122 | ||
8123 | case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */ | 8123 | case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */ |
8124 | desc = "FC: Aborted"; | 8124 | desc = "FC: Aborted"; |
8125 | break; | 8125 | break; |
8126 | 8126 | ||
8127 | case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */ | 8127 | case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */ |
8128 | desc = "FC: RX ID Invalid"; | 8128 | desc = "FC: RX ID Invalid"; |
8129 | break; | 8129 | break; |
8130 | 8130 | ||
8131 | case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */ | 8131 | case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */ |
8132 | desc = "FC: DID Invalid"; | 8132 | desc = "FC: DID Invalid"; |
8133 | break; | 8133 | break; |
8134 | 8134 | ||
8135 | case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */ | 8135 | case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */ |
8136 | desc = "FC: Node Logged Out"; | 8136 | desc = "FC: Node Logged Out"; |
8137 | break; | 8137 | break; |
8138 | 8138 | ||
8139 | case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */ | 8139 | case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */ |
8140 | desc = "FC: Exchange Canceled"; | 8140 | desc = "FC: Exchange Canceled"; |
8141 | break; | 8141 | break; |
8142 | 8142 | ||
8143 | /****************************************************************************/ | 8143 | /****************************************************************************/ |
8144 | /* LAN values */ | 8144 | /* LAN values */ |
8145 | /****************************************************************************/ | 8145 | /****************************************************************************/ |
8146 | 8146 | ||
8147 | case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */ | 8147 | case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */ |
8148 | desc = "LAN: Device not Found"; | 8148 | desc = "LAN: Device not Found"; |
8149 | break; | 8149 | break; |
8150 | 8150 | ||
8151 | case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */ | 8151 | case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */ |
8152 | desc = "LAN: Device Failure"; | 8152 | desc = "LAN: Device Failure"; |
8153 | break; | 8153 | break; |
8154 | 8154 | ||
8155 | case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */ | 8155 | case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */ |
8156 | desc = "LAN: Transmit Error"; | 8156 | desc = "LAN: Transmit Error"; |
8157 | break; | 8157 | break; |
8158 | 8158 | ||
8159 | case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */ | 8159 | case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */ |
8160 | desc = "LAN: Transmit Aborted"; | 8160 | desc = "LAN: Transmit Aborted"; |
8161 | break; | 8161 | break; |
8162 | 8162 | ||
8163 | case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */ | 8163 | case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */ |
8164 | desc = "LAN: Receive Error"; | 8164 | desc = "LAN: Receive Error"; |
8165 | break; | 8165 | break; |
8166 | 8166 | ||
8167 | case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */ | 8167 | case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */ |
8168 | desc = "LAN: Receive Aborted"; | 8168 | desc = "LAN: Receive Aborted"; |
8169 | break; | 8169 | break; |
8170 | 8170 | ||
8171 | case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */ | 8171 | case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */ |
8172 | desc = "LAN: Partial Packet"; | 8172 | desc = "LAN: Partial Packet"; |
8173 | break; | 8173 | break; |
8174 | 8174 | ||
8175 | case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */ | 8175 | case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */ |
8176 | desc = "LAN: Canceled"; | 8176 | desc = "LAN: Canceled"; |
8177 | break; | 8177 | break; |
8178 | 8178 | ||
8179 | /****************************************************************************/ | 8179 | /****************************************************************************/ |
8180 | /* Serial Attached SCSI values */ | 8180 | /* Serial Attached SCSI values */ |
8181 | /****************************************************************************/ | 8181 | /****************************************************************************/ |
8182 | 8182 | ||
8183 | case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */ | 8183 | case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */ |
8184 | desc = "SAS: SMP Request Failed"; | 8184 | desc = "SAS: SMP Request Failed"; |
8185 | break; | 8185 | break; |
8186 | 8186 | ||
8187 | case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */ | 8187 | case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */ |
8188 | desc = "SAS: SMP Data Overrun"; | 8188 | desc = "SAS: SMP Data Overrun"; |
8189 | break; | 8189 | break; |
8190 | 8190 | ||
8191 | default: | 8191 | default: |
8192 | desc = "Others"; | 8192 | desc = "Others"; |
8193 | break; | 8193 | break; |
8194 | } | 8194 | } |
8195 | 8195 | ||
8196 | if (!desc) | 8196 | if (!desc) |
8197 | return; | 8197 | return; |
8198 | 8198 | ||
8199 | dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n", | 8199 | dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n", |
8200 | ioc->name, status, desc)); | 8200 | ioc->name, status, desc)); |
8201 | } | 8201 | } |
8202 | 8202 | ||
8203 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 8203 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
8204 | EXPORT_SYMBOL(mpt_attach); | 8204 | EXPORT_SYMBOL(mpt_attach); |
8205 | EXPORT_SYMBOL(mpt_detach); | 8205 | EXPORT_SYMBOL(mpt_detach); |
8206 | #ifdef CONFIG_PM | 8206 | #ifdef CONFIG_PM |
8207 | EXPORT_SYMBOL(mpt_resume); | 8207 | EXPORT_SYMBOL(mpt_resume); |
8208 | EXPORT_SYMBOL(mpt_suspend); | 8208 | EXPORT_SYMBOL(mpt_suspend); |
8209 | #endif | 8209 | #endif |
8210 | EXPORT_SYMBOL(ioc_list); | 8210 | EXPORT_SYMBOL(ioc_list); |
8211 | EXPORT_SYMBOL(mpt_register); | 8211 | EXPORT_SYMBOL(mpt_register); |
8212 | EXPORT_SYMBOL(mpt_deregister); | 8212 | EXPORT_SYMBOL(mpt_deregister); |
8213 | EXPORT_SYMBOL(mpt_event_register); | 8213 | EXPORT_SYMBOL(mpt_event_register); |
8214 | EXPORT_SYMBOL(mpt_event_deregister); | 8214 | EXPORT_SYMBOL(mpt_event_deregister); |
8215 | EXPORT_SYMBOL(mpt_reset_register); | 8215 | EXPORT_SYMBOL(mpt_reset_register); |
8216 | EXPORT_SYMBOL(mpt_reset_deregister); | 8216 | EXPORT_SYMBOL(mpt_reset_deregister); |
8217 | EXPORT_SYMBOL(mpt_device_driver_register); | 8217 | EXPORT_SYMBOL(mpt_device_driver_register); |
8218 | EXPORT_SYMBOL(mpt_device_driver_deregister); | 8218 | EXPORT_SYMBOL(mpt_device_driver_deregister); |
8219 | EXPORT_SYMBOL(mpt_get_msg_frame); | 8219 | EXPORT_SYMBOL(mpt_get_msg_frame); |
8220 | EXPORT_SYMBOL(mpt_put_msg_frame); | 8220 | EXPORT_SYMBOL(mpt_put_msg_frame); |
8221 | EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri); | 8221 | EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri); |
8222 | EXPORT_SYMBOL(mpt_free_msg_frame); | 8222 | EXPORT_SYMBOL(mpt_free_msg_frame); |
8223 | EXPORT_SYMBOL(mpt_send_handshake_request); | 8223 | EXPORT_SYMBOL(mpt_send_handshake_request); |
8224 | EXPORT_SYMBOL(mpt_verify_adapter); | 8224 | EXPORT_SYMBOL(mpt_verify_adapter); |
8225 | EXPORT_SYMBOL(mpt_GetIocState); | 8225 | EXPORT_SYMBOL(mpt_GetIocState); |
8226 | EXPORT_SYMBOL(mpt_print_ioc_summary); | 8226 | EXPORT_SYMBOL(mpt_print_ioc_summary); |
8227 | EXPORT_SYMBOL(mpt_HardResetHandler); | 8227 | EXPORT_SYMBOL(mpt_HardResetHandler); |
8228 | EXPORT_SYMBOL(mpt_config); | 8228 | EXPORT_SYMBOL(mpt_config); |
8229 | EXPORT_SYMBOL(mpt_findImVolumes); | 8229 | EXPORT_SYMBOL(mpt_findImVolumes); |
8230 | EXPORT_SYMBOL(mpt_alloc_fw_memory); | 8230 | EXPORT_SYMBOL(mpt_alloc_fw_memory); |
8231 | EXPORT_SYMBOL(mpt_free_fw_memory); | 8231 | EXPORT_SYMBOL(mpt_free_fw_memory); |
8232 | EXPORT_SYMBOL(mptbase_sas_persist_operation); | 8232 | EXPORT_SYMBOL(mptbase_sas_persist_operation); |
8233 | EXPORT_SYMBOL(mpt_raid_phys_disk_pg0); | 8233 | EXPORT_SYMBOL(mpt_raid_phys_disk_pg0); |
8234 | 8234 | ||
8235 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 8235 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
8236 | /** | 8236 | /** |
8237 | * fusion_init - Fusion MPT base driver initialization routine. | 8237 | * fusion_init - Fusion MPT base driver initialization routine. |
8238 | * | 8238 | * |
8239 | * Returns 0 for success, non-zero for failure. | 8239 | * Returns 0 for success, non-zero for failure. |
8240 | */ | 8240 | */ |
8241 | static int __init | 8241 | static int __init |
8242 | fusion_init(void) | 8242 | fusion_init(void) |
8243 | { | 8243 | { |
8244 | u8 cb_idx; | 8244 | u8 cb_idx; |
8245 | 8245 | ||
8246 | show_mptmod_ver(my_NAME, my_VERSION); | 8246 | show_mptmod_ver(my_NAME, my_VERSION); |
8247 | printk(KERN_INFO COPYRIGHT "\n"); | 8247 | printk(KERN_INFO COPYRIGHT "\n"); |
8248 | 8248 | ||
8249 | for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { | 8249 | for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { |
8250 | MptCallbacks[cb_idx] = NULL; | 8250 | MptCallbacks[cb_idx] = NULL; |
8251 | MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER; | 8251 | MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER; |
8252 | MptEvHandlers[cb_idx] = NULL; | 8252 | MptEvHandlers[cb_idx] = NULL; |
8253 | MptResetHandlers[cb_idx] = NULL; | 8253 | MptResetHandlers[cb_idx] = NULL; |
8254 | } | 8254 | } |
8255 | 8255 | ||
8256 | /* Register ourselves (mptbase) in order to facilitate | 8256 | /* Register ourselves (mptbase) in order to facilitate |
8257 | * EventNotification handling. | 8257 | * EventNotification handling. |
8258 | */ | 8258 | */ |
8259 | mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER); | 8259 | mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER); |
8260 | 8260 | ||
8261 | /* Register for hard reset handling callbacks. | 8261 | /* Register for hard reset handling callbacks. |
8262 | */ | 8262 | */ |
8263 | mpt_reset_register(mpt_base_index, mpt_ioc_reset); | 8263 | mpt_reset_register(mpt_base_index, mpt_ioc_reset); |
8264 | 8264 | ||
8265 | #ifdef CONFIG_PROC_FS | 8265 | #ifdef CONFIG_PROC_FS |
8266 | (void) procmpt_create(); | 8266 | (void) procmpt_create(); |
8267 | #endif | 8267 | #endif |
8268 | return 0; | 8268 | return 0; |
8269 | } | 8269 | } |
8270 | 8270 | ||
8271 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 8271 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
8272 | /** | 8272 | /** |
8273 | * fusion_exit - Perform driver unload cleanup. | 8273 | * fusion_exit - Perform driver unload cleanup. |
8274 | * | 8274 | * |
8275 | * This routine frees all resources associated with each MPT adapter | 8275 | * This routine frees all resources associated with each MPT adapter |
8276 | * and removes all %MPT_PROCFS_MPTBASEDIR entries. | 8276 | * and removes all %MPT_PROCFS_MPTBASEDIR entries. |
8277 | */ | 8277 | */ |
8278 | static void __exit | 8278 | static void __exit |
8279 | fusion_exit(void) | 8279 | fusion_exit(void) |
8280 | { | 8280 | { |
8281 | 8281 | ||
8282 | mpt_reset_deregister(mpt_base_index); | 8282 | mpt_reset_deregister(mpt_base_index); |
8283 | 8283 | ||
8284 | #ifdef CONFIG_PROC_FS | 8284 | #ifdef CONFIG_PROC_FS |
8285 | procmpt_destroy(); | 8285 | procmpt_destroy(); |
8286 | #endif | 8286 | #endif |
8287 | } | 8287 | } |
8288 | 8288 | ||
8289 | module_init(fusion_init); | 8289 | module_init(fusion_init); |
8290 | module_exit(fusion_exit); | 8290 | module_exit(fusion_exit); |
8291 | 8291 |
drivers/net/macb.c
1 | /* | 1 | /* |
2 | * Atmel MACB Ethernet Controller driver | 2 | * Atmel MACB Ethernet Controller driver |
3 | * | 3 | * |
4 | * Copyright (C) 2004-2006 Atmel Corporation | 4 | * Copyright (C) 2004-2006 Atmel Corporation |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/clk.h> | 11 | #include <linux/clk.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/moduleparam.h> | 13 | #include <linux/moduleparam.h> |
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/netdevice.h> | 18 | #include <linux/netdevice.h> |
19 | #include <linux/etherdevice.h> | 19 | #include <linux/etherdevice.h> |
20 | #include <linux/dma-mapping.h> | 20 | #include <linux/dma-mapping.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/phy.h> | 22 | #include <linux/phy.h> |
23 | 23 | ||
24 | #include <mach/board.h> | 24 | #include <mach/board.h> |
25 | #include <mach/cpu.h> | 25 | #include <mach/cpu.h> |
26 | 26 | ||
27 | #include "macb.h" | 27 | #include "macb.h" |
28 | 28 | ||
29 | #define RX_BUFFER_SIZE 128 | 29 | #define RX_BUFFER_SIZE 128 |
30 | #define RX_RING_SIZE 512 | 30 | #define RX_RING_SIZE 512 |
31 | #define RX_RING_BYTES (sizeof(struct dma_desc) * RX_RING_SIZE) | 31 | #define RX_RING_BYTES (sizeof(struct dma_desc) * RX_RING_SIZE) |
32 | 32 | ||
33 | /* Make the IP header word-aligned (the ethernet header is 14 bytes) */ | 33 | /* Make the IP header word-aligned (the ethernet header is 14 bytes) */ |
34 | #define RX_OFFSET 2 | 34 | #define RX_OFFSET 2 |
35 | 35 | ||
36 | #define TX_RING_SIZE 128 | 36 | #define TX_RING_SIZE 128 |
37 | #define DEF_TX_RING_PENDING (TX_RING_SIZE - 1) | 37 | #define DEF_TX_RING_PENDING (TX_RING_SIZE - 1) |
38 | #define TX_RING_BYTES (sizeof(struct dma_desc) * TX_RING_SIZE) | 38 | #define TX_RING_BYTES (sizeof(struct dma_desc) * TX_RING_SIZE) |
39 | 39 | ||
40 | #define TX_RING_GAP(bp) \ | 40 | #define TX_RING_GAP(bp) \ |
41 | (TX_RING_SIZE - (bp)->tx_pending) | 41 | (TX_RING_SIZE - (bp)->tx_pending) |
42 | #define TX_BUFFS_AVAIL(bp) \ | 42 | #define TX_BUFFS_AVAIL(bp) \ |
43 | (((bp)->tx_tail <= (bp)->tx_head) ? \ | 43 | (((bp)->tx_tail <= (bp)->tx_head) ? \ |
44 | (bp)->tx_tail + (bp)->tx_pending - (bp)->tx_head : \ | 44 | (bp)->tx_tail + (bp)->tx_pending - (bp)->tx_head : \ |
45 | (bp)->tx_tail - (bp)->tx_head - TX_RING_GAP(bp)) | 45 | (bp)->tx_tail - (bp)->tx_head - TX_RING_GAP(bp)) |
46 | #define NEXT_TX(n) (((n) + 1) & (TX_RING_SIZE - 1)) | 46 | #define NEXT_TX(n) (((n) + 1) & (TX_RING_SIZE - 1)) |
47 | 47 | ||
48 | #define NEXT_RX(n) (((n) + 1) & (RX_RING_SIZE - 1)) | 48 | #define NEXT_RX(n) (((n) + 1) & (RX_RING_SIZE - 1)) |
49 | 49 | ||
50 | /* minimum number of free TX descriptors before waking up TX process */ | 50 | /* minimum number of free TX descriptors before waking up TX process */ |
51 | #define MACB_TX_WAKEUP_THRESH (TX_RING_SIZE / 4) | 51 | #define MACB_TX_WAKEUP_THRESH (TX_RING_SIZE / 4) |
52 | 52 | ||
53 | #define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \ | 53 | #define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \ |
54 | | MACB_BIT(ISR_ROVR)) | 54 | | MACB_BIT(ISR_ROVR)) |
55 | 55 | ||
56 | static void __macb_set_hwaddr(struct macb *bp) | 56 | static void __macb_set_hwaddr(struct macb *bp) |
57 | { | 57 | { |
58 | u32 bottom; | 58 | u32 bottom; |
59 | u16 top; | 59 | u16 top; |
60 | 60 | ||
61 | bottom = cpu_to_le32(*((u32 *)bp->dev->dev_addr)); | 61 | bottom = cpu_to_le32(*((u32 *)bp->dev->dev_addr)); |
62 | macb_writel(bp, SA1B, bottom); | 62 | macb_writel(bp, SA1B, bottom); |
63 | top = cpu_to_le16(*((u16 *)(bp->dev->dev_addr + 4))); | 63 | top = cpu_to_le16(*((u16 *)(bp->dev->dev_addr + 4))); |
64 | macb_writel(bp, SA1T, top); | 64 | macb_writel(bp, SA1T, top); |
65 | } | 65 | } |
66 | 66 | ||
67 | static void __init macb_get_hwaddr(struct macb *bp) | 67 | static void __init macb_get_hwaddr(struct macb *bp) |
68 | { | 68 | { |
69 | u32 bottom; | 69 | u32 bottom; |
70 | u16 top; | 70 | u16 top; |
71 | u8 addr[6]; | 71 | u8 addr[6]; |
72 | 72 | ||
73 | bottom = macb_readl(bp, SA1B); | 73 | bottom = macb_readl(bp, SA1B); |
74 | top = macb_readl(bp, SA1T); | 74 | top = macb_readl(bp, SA1T); |
75 | 75 | ||
76 | addr[0] = bottom & 0xff; | 76 | addr[0] = bottom & 0xff; |
77 | addr[1] = (bottom >> 8) & 0xff; | 77 | addr[1] = (bottom >> 8) & 0xff; |
78 | addr[2] = (bottom >> 16) & 0xff; | 78 | addr[2] = (bottom >> 16) & 0xff; |
79 | addr[3] = (bottom >> 24) & 0xff; | 79 | addr[3] = (bottom >> 24) & 0xff; |
80 | addr[4] = top & 0xff; | 80 | addr[4] = top & 0xff; |
81 | addr[5] = (top >> 8) & 0xff; | 81 | addr[5] = (top >> 8) & 0xff; |
82 | 82 | ||
83 | if (is_valid_ether_addr(addr)) { | 83 | if (is_valid_ether_addr(addr)) { |
84 | memcpy(bp->dev->dev_addr, addr, sizeof(addr)); | 84 | memcpy(bp->dev->dev_addr, addr, sizeof(addr)); |
85 | } else { | 85 | } else { |
86 | dev_info(&bp->pdev->dev, "invalid hw address, using random\n"); | 86 | dev_info(&bp->pdev->dev, "invalid hw address, using random\n"); |
87 | random_ether_addr(bp->dev->dev_addr); | 87 | random_ether_addr(bp->dev->dev_addr); |
88 | } | 88 | } |
89 | } | 89 | } |
90 | 90 | ||
91 | static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum) | 91 | static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum) |
92 | { | 92 | { |
93 | struct macb *bp = bus->priv; | 93 | struct macb *bp = bus->priv; |
94 | int value; | 94 | int value; |
95 | 95 | ||
96 | macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) | 96 | macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
97 | | MACB_BF(RW, MACB_MAN_READ) | 97 | | MACB_BF(RW, MACB_MAN_READ) |
98 | | MACB_BF(PHYA, mii_id) | 98 | | MACB_BF(PHYA, mii_id) |
99 | | MACB_BF(REGA, regnum) | 99 | | MACB_BF(REGA, regnum) |
100 | | MACB_BF(CODE, MACB_MAN_CODE))); | 100 | | MACB_BF(CODE, MACB_MAN_CODE))); |
101 | 101 | ||
102 | /* wait for end of transfer */ | 102 | /* wait for end of transfer */ |
103 | while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR))) | 103 | while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR))) |
104 | cpu_relax(); | 104 | cpu_relax(); |
105 | 105 | ||
106 | value = MACB_BFEXT(DATA, macb_readl(bp, MAN)); | 106 | value = MACB_BFEXT(DATA, macb_readl(bp, MAN)); |
107 | 107 | ||
108 | return value; | 108 | return value; |
109 | } | 109 | } |
110 | 110 | ||
111 | static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum, | 111 | static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum, |
112 | u16 value) | 112 | u16 value) |
113 | { | 113 | { |
114 | struct macb *bp = bus->priv; | 114 | struct macb *bp = bus->priv; |
115 | 115 | ||
116 | macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) | 116 | macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) |
117 | | MACB_BF(RW, MACB_MAN_WRITE) | 117 | | MACB_BF(RW, MACB_MAN_WRITE) |
118 | | MACB_BF(PHYA, mii_id) | 118 | | MACB_BF(PHYA, mii_id) |
119 | | MACB_BF(REGA, regnum) | 119 | | MACB_BF(REGA, regnum) |
120 | | MACB_BF(CODE, MACB_MAN_CODE) | 120 | | MACB_BF(CODE, MACB_MAN_CODE) |
121 | | MACB_BF(DATA, value))); | 121 | | MACB_BF(DATA, value))); |
122 | 122 | ||
123 | /* wait for end of transfer */ | 123 | /* wait for end of transfer */ |
124 | while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR))) | 124 | while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR))) |
125 | cpu_relax(); | 125 | cpu_relax(); |
126 | 126 | ||
127 | return 0; | 127 | return 0; |
128 | } | 128 | } |
129 | 129 | ||
130 | static int macb_mdio_reset(struct mii_bus *bus) | 130 | static int macb_mdio_reset(struct mii_bus *bus) |
131 | { | 131 | { |
132 | return 0; | 132 | return 0; |
133 | } | 133 | } |
134 | 134 | ||
135 | static void macb_handle_link_change(struct net_device *dev) | 135 | static void macb_handle_link_change(struct net_device *dev) |
136 | { | 136 | { |
137 | struct macb *bp = netdev_priv(dev); | 137 | struct macb *bp = netdev_priv(dev); |
138 | struct phy_device *phydev = bp->phy_dev; | 138 | struct phy_device *phydev = bp->phy_dev; |
139 | unsigned long flags; | 139 | unsigned long flags; |
140 | 140 | ||
141 | int status_change = 0; | 141 | int status_change = 0; |
142 | 142 | ||
143 | spin_lock_irqsave(&bp->lock, flags); | 143 | spin_lock_irqsave(&bp->lock, flags); |
144 | 144 | ||
145 | if (phydev->link) { | 145 | if (phydev->link) { |
146 | if ((bp->speed != phydev->speed) || | 146 | if ((bp->speed != phydev->speed) || |
147 | (bp->duplex != phydev->duplex)) { | 147 | (bp->duplex != phydev->duplex)) { |
148 | u32 reg; | 148 | u32 reg; |
149 | 149 | ||
150 | reg = macb_readl(bp, NCFGR); | 150 | reg = macb_readl(bp, NCFGR); |
151 | reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); | 151 | reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); |
152 | 152 | ||
153 | if (phydev->duplex) | 153 | if (phydev->duplex) |
154 | reg |= MACB_BIT(FD); | 154 | reg |= MACB_BIT(FD); |
155 | if (phydev->speed == SPEED_100) | 155 | if (phydev->speed == SPEED_100) |
156 | reg |= MACB_BIT(SPD); | 156 | reg |= MACB_BIT(SPD); |
157 | 157 | ||
158 | macb_writel(bp, NCFGR, reg); | 158 | macb_writel(bp, NCFGR, reg); |
159 | 159 | ||
160 | bp->speed = phydev->speed; | 160 | bp->speed = phydev->speed; |
161 | bp->duplex = phydev->duplex; | 161 | bp->duplex = phydev->duplex; |
162 | status_change = 1; | 162 | status_change = 1; |
163 | } | 163 | } |
164 | } | 164 | } |
165 | 165 | ||
166 | if (phydev->link != bp->link) { | 166 | if (phydev->link != bp->link) { |
167 | if (!phydev->link) { | 167 | if (!phydev->link) { |
168 | bp->speed = 0; | 168 | bp->speed = 0; |
169 | bp->duplex = -1; | 169 | bp->duplex = -1; |
170 | } | 170 | } |
171 | bp->link = phydev->link; | 171 | bp->link = phydev->link; |
172 | 172 | ||
173 | status_change = 1; | 173 | status_change = 1; |
174 | } | 174 | } |
175 | 175 | ||
176 | spin_unlock_irqrestore(&bp->lock, flags); | 176 | spin_unlock_irqrestore(&bp->lock, flags); |
177 | 177 | ||
178 | if (status_change) { | 178 | if (status_change) { |
179 | if (phydev->link) | 179 | if (phydev->link) |
180 | printk(KERN_INFO "%s: link up (%d/%s)\n", | 180 | printk(KERN_INFO "%s: link up (%d/%s)\n", |
181 | dev->name, phydev->speed, | 181 | dev->name, phydev->speed, |
182 | DUPLEX_FULL == phydev->duplex ? "Full":"Half"); | 182 | DUPLEX_FULL == phydev->duplex ? "Full":"Half"); |
183 | else | 183 | else |
184 | printk(KERN_INFO "%s: link down\n", dev->name); | 184 | printk(KERN_INFO "%s: link down\n", dev->name); |
185 | } | 185 | } |
186 | } | 186 | } |
187 | 187 | ||
188 | /* based on au1000_eth. c*/ | 188 | /* based on au1000_eth. c*/ |
189 | static int macb_mii_probe(struct net_device *dev) | 189 | static int macb_mii_probe(struct net_device *dev) |
190 | { | 190 | { |
191 | struct macb *bp = netdev_priv(dev); | 191 | struct macb *bp = netdev_priv(dev); |
192 | struct phy_device *phydev = NULL; | 192 | struct phy_device *phydev = NULL; |
193 | struct eth_platform_data *pdata; | 193 | struct eth_platform_data *pdata; |
194 | int phy_addr; | 194 | int phy_addr; |
195 | 195 | ||
196 | /* find the first phy */ | 196 | /* find the first phy */ |
197 | for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { | 197 | for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { |
198 | if (bp->mii_bus->phy_map[phy_addr]) { | 198 | if (bp->mii_bus->phy_map[phy_addr]) { |
199 | phydev = bp->mii_bus->phy_map[phy_addr]; | 199 | phydev = bp->mii_bus->phy_map[phy_addr]; |
200 | break; | 200 | break; |
201 | } | 201 | } |
202 | } | 202 | } |
203 | 203 | ||
204 | if (!phydev) { | 204 | if (!phydev) { |
205 | printk (KERN_ERR "%s: no PHY found\n", dev->name); | 205 | printk (KERN_ERR "%s: no PHY found\n", dev->name); |
206 | return -1; | 206 | return -1; |
207 | } | 207 | } |
208 | 208 | ||
209 | pdata = bp->pdev->dev.platform_data; | 209 | pdata = bp->pdev->dev.platform_data; |
210 | /* TODO : add pin_irq */ | 210 | /* TODO : add pin_irq */ |
211 | 211 | ||
212 | /* attach the mac to the phy */ | 212 | /* attach the mac to the phy */ |
213 | if (pdata && pdata->is_rmii) { | 213 | if (pdata && pdata->is_rmii) { |
214 | phydev = phy_connect(dev, dev_name(&phydev->dev), | 214 | phydev = phy_connect(dev, dev_name(&phydev->dev), |
215 | &macb_handle_link_change, 0, PHY_INTERFACE_MODE_RMII); | 215 | &macb_handle_link_change, 0, PHY_INTERFACE_MODE_RMII); |
216 | } else { | 216 | } else { |
217 | phydev = phy_connect(dev, dev_name(&phydev->dev), | 217 | phydev = phy_connect(dev, dev_name(&phydev->dev), |
218 | &macb_handle_link_change, 0, PHY_INTERFACE_MODE_MII); | 218 | &macb_handle_link_change, 0, PHY_INTERFACE_MODE_MII); |
219 | } | 219 | } |
220 | 220 | ||
221 | if (IS_ERR(phydev)) { | 221 | if (IS_ERR(phydev)) { |
222 | printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); | 222 | printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); |
223 | return PTR_ERR(phydev); | 223 | return PTR_ERR(phydev); |
224 | } | 224 | } |
225 | 225 | ||
226 | /* mask with MAC supported features */ | 226 | /* mask with MAC supported features */ |
227 | phydev->supported &= PHY_BASIC_FEATURES; | 227 | phydev->supported &= PHY_BASIC_FEATURES; |
228 | 228 | ||
229 | phydev->advertising = phydev->supported; | 229 | phydev->advertising = phydev->supported; |
230 | 230 | ||
231 | bp->link = 0; | 231 | bp->link = 0; |
232 | bp->speed = 0; | 232 | bp->speed = 0; |
233 | bp->duplex = -1; | 233 | bp->duplex = -1; |
234 | bp->phy_dev = phydev; | 234 | bp->phy_dev = phydev; |
235 | 235 | ||
236 | return 0; | 236 | return 0; |
237 | } | 237 | } |
238 | 238 | ||
239 | static int macb_mii_init(struct macb *bp) | 239 | static int macb_mii_init(struct macb *bp) |
240 | { | 240 | { |
241 | struct eth_platform_data *pdata; | 241 | struct eth_platform_data *pdata; |
242 | int err = -ENXIO, i; | 242 | int err = -ENXIO, i; |
243 | 243 | ||
244 | /* Enable managment port */ | 244 | /* Enable management port */ |
245 | macb_writel(bp, NCR, MACB_BIT(MPE)); | 245 | macb_writel(bp, NCR, MACB_BIT(MPE)); |
246 | 246 | ||
247 | bp->mii_bus = mdiobus_alloc(); | 247 | bp->mii_bus = mdiobus_alloc(); |
248 | if (bp->mii_bus == NULL) { | 248 | if (bp->mii_bus == NULL) { |
249 | err = -ENOMEM; | 249 | err = -ENOMEM; |
250 | goto err_out; | 250 | goto err_out; |
251 | } | 251 | } |
252 | 252 | ||
253 | bp->mii_bus->name = "MACB_mii_bus"; | 253 | bp->mii_bus->name = "MACB_mii_bus"; |
254 | bp->mii_bus->read = &macb_mdio_read; | 254 | bp->mii_bus->read = &macb_mdio_read; |
255 | bp->mii_bus->write = &macb_mdio_write; | 255 | bp->mii_bus->write = &macb_mdio_write; |
256 | bp->mii_bus->reset = &macb_mdio_reset; | 256 | bp->mii_bus->reset = &macb_mdio_reset; |
257 | snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", bp->pdev->id); | 257 | snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", bp->pdev->id); |
258 | bp->mii_bus->priv = bp; | 258 | bp->mii_bus->priv = bp; |
259 | bp->mii_bus->parent = &bp->dev->dev; | 259 | bp->mii_bus->parent = &bp->dev->dev; |
260 | pdata = bp->pdev->dev.platform_data; | 260 | pdata = bp->pdev->dev.platform_data; |
261 | 261 | ||
262 | if (pdata) | 262 | if (pdata) |
263 | bp->mii_bus->phy_mask = pdata->phy_mask; | 263 | bp->mii_bus->phy_mask = pdata->phy_mask; |
264 | 264 | ||
265 | bp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); | 265 | bp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); |
266 | if (!bp->mii_bus->irq) { | 266 | if (!bp->mii_bus->irq) { |
267 | err = -ENOMEM; | 267 | err = -ENOMEM; |
268 | goto err_out_free_mdiobus; | 268 | goto err_out_free_mdiobus; |
269 | } | 269 | } |
270 | 270 | ||
271 | for (i = 0; i < PHY_MAX_ADDR; i++) | 271 | for (i = 0; i < PHY_MAX_ADDR; i++) |
272 | bp->mii_bus->irq[i] = PHY_POLL; | 272 | bp->mii_bus->irq[i] = PHY_POLL; |
273 | 273 | ||
274 | platform_set_drvdata(bp->dev, bp->mii_bus); | 274 | platform_set_drvdata(bp->dev, bp->mii_bus); |
275 | 275 | ||
276 | if (mdiobus_register(bp->mii_bus)) | 276 | if (mdiobus_register(bp->mii_bus)) |
277 | goto err_out_free_mdio_irq; | 277 | goto err_out_free_mdio_irq; |
278 | 278 | ||
279 | if (macb_mii_probe(bp->dev) != 0) { | 279 | if (macb_mii_probe(bp->dev) != 0) { |
280 | goto err_out_unregister_bus; | 280 | goto err_out_unregister_bus; |
281 | } | 281 | } |
282 | 282 | ||
283 | return 0; | 283 | return 0; |
284 | 284 | ||
285 | err_out_unregister_bus: | 285 | err_out_unregister_bus: |
286 | mdiobus_unregister(bp->mii_bus); | 286 | mdiobus_unregister(bp->mii_bus); |
287 | err_out_free_mdio_irq: | 287 | err_out_free_mdio_irq: |
288 | kfree(bp->mii_bus->irq); | 288 | kfree(bp->mii_bus->irq); |
289 | err_out_free_mdiobus: | 289 | err_out_free_mdiobus: |
290 | mdiobus_free(bp->mii_bus); | 290 | mdiobus_free(bp->mii_bus); |
291 | err_out: | 291 | err_out: |
292 | return err; | 292 | return err; |
293 | } | 293 | } |
294 | 294 | ||
295 | static void macb_update_stats(struct macb *bp) | 295 | static void macb_update_stats(struct macb *bp) |
296 | { | 296 | { |
297 | u32 __iomem *reg = bp->regs + MACB_PFR; | 297 | u32 __iomem *reg = bp->regs + MACB_PFR; |
298 | u32 *p = &bp->hw_stats.rx_pause_frames; | 298 | u32 *p = &bp->hw_stats.rx_pause_frames; |
299 | u32 *end = &bp->hw_stats.tx_pause_frames + 1; | 299 | u32 *end = &bp->hw_stats.tx_pause_frames + 1; |
300 | 300 | ||
301 | WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4); | 301 | WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4); |
302 | 302 | ||
303 | for(; p < end; p++, reg++) | 303 | for(; p < end; p++, reg++) |
304 | *p += __raw_readl(reg); | 304 | *p += __raw_readl(reg); |
305 | } | 305 | } |
306 | 306 | ||
307 | static void macb_tx(struct macb *bp) | 307 | static void macb_tx(struct macb *bp) |
308 | { | 308 | { |
309 | unsigned int tail; | 309 | unsigned int tail; |
310 | unsigned int head; | 310 | unsigned int head; |
311 | u32 status; | 311 | u32 status; |
312 | 312 | ||
313 | status = macb_readl(bp, TSR); | 313 | status = macb_readl(bp, TSR); |
314 | macb_writel(bp, TSR, status); | 314 | macb_writel(bp, TSR, status); |
315 | 315 | ||
316 | dev_dbg(&bp->pdev->dev, "macb_tx status = %02lx\n", | 316 | dev_dbg(&bp->pdev->dev, "macb_tx status = %02lx\n", |
317 | (unsigned long)status); | 317 | (unsigned long)status); |
318 | 318 | ||
319 | if (status & (MACB_BIT(UND) | MACB_BIT(TSR_RLE))) { | 319 | if (status & (MACB_BIT(UND) | MACB_BIT(TSR_RLE))) { |
320 | int i; | 320 | int i; |
321 | printk(KERN_ERR "%s: TX %s, resetting buffers\n", | 321 | printk(KERN_ERR "%s: TX %s, resetting buffers\n", |
322 | bp->dev->name, status & MACB_BIT(UND) ? | 322 | bp->dev->name, status & MACB_BIT(UND) ? |
323 | "underrun" : "retry limit exceeded"); | 323 | "underrun" : "retry limit exceeded"); |
324 | 324 | ||
325 | /* Transfer ongoing, disable transmitter, to avoid confusion */ | 325 | /* Transfer ongoing, disable transmitter, to avoid confusion */ |
326 | if (status & MACB_BIT(TGO)) | 326 | if (status & MACB_BIT(TGO)) |
327 | macb_writel(bp, NCR, macb_readl(bp, NCR) & ~MACB_BIT(TE)); | 327 | macb_writel(bp, NCR, macb_readl(bp, NCR) & ~MACB_BIT(TE)); |
328 | 328 | ||
329 | head = bp->tx_head; | 329 | head = bp->tx_head; |
330 | 330 | ||
331 | /*Mark all the buffer as used to avoid sending a lost buffer*/ | 331 | /*Mark all the buffer as used to avoid sending a lost buffer*/ |
332 | for (i = 0; i < TX_RING_SIZE; i++) | 332 | for (i = 0; i < TX_RING_SIZE; i++) |
333 | bp->tx_ring[i].ctrl = MACB_BIT(TX_USED); | 333 | bp->tx_ring[i].ctrl = MACB_BIT(TX_USED); |
334 | 334 | ||
335 | /* free transmit buffer in upper layer*/ | 335 | /* free transmit buffer in upper layer*/ |
336 | for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) { | 336 | for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) { |
337 | struct ring_info *rp = &bp->tx_skb[tail]; | 337 | struct ring_info *rp = &bp->tx_skb[tail]; |
338 | struct sk_buff *skb = rp->skb; | 338 | struct sk_buff *skb = rp->skb; |
339 | 339 | ||
340 | BUG_ON(skb == NULL); | 340 | BUG_ON(skb == NULL); |
341 | 341 | ||
342 | rmb(); | 342 | rmb(); |
343 | 343 | ||
344 | dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len, | 344 | dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len, |
345 | DMA_TO_DEVICE); | 345 | DMA_TO_DEVICE); |
346 | rp->skb = NULL; | 346 | rp->skb = NULL; |
347 | dev_kfree_skb_irq(skb); | 347 | dev_kfree_skb_irq(skb); |
348 | } | 348 | } |
349 | 349 | ||
350 | bp->tx_head = bp->tx_tail = 0; | 350 | bp->tx_head = bp->tx_tail = 0; |
351 | 351 | ||
352 | /* Enable the transmitter again */ | 352 | /* Enable the transmitter again */ |
353 | if (status & MACB_BIT(TGO)) | 353 | if (status & MACB_BIT(TGO)) |
354 | macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TE)); | 354 | macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TE)); |
355 | } | 355 | } |
356 | 356 | ||
357 | if (!(status & MACB_BIT(COMP))) | 357 | if (!(status & MACB_BIT(COMP))) |
358 | /* | 358 | /* |
359 | * This may happen when a buffer becomes complete | 359 | * This may happen when a buffer becomes complete |
360 | * between reading the ISR and scanning the | 360 | * between reading the ISR and scanning the |
361 | * descriptors. Nothing to worry about. | 361 | * descriptors. Nothing to worry about. |
362 | */ | 362 | */ |
363 | return; | 363 | return; |
364 | 364 | ||
365 | head = bp->tx_head; | 365 | head = bp->tx_head; |
366 | for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) { | 366 | for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) { |
367 | struct ring_info *rp = &bp->tx_skb[tail]; | 367 | struct ring_info *rp = &bp->tx_skb[tail]; |
368 | struct sk_buff *skb = rp->skb; | 368 | struct sk_buff *skb = rp->skb; |
369 | u32 bufstat; | 369 | u32 bufstat; |
370 | 370 | ||
371 | BUG_ON(skb == NULL); | 371 | BUG_ON(skb == NULL); |
372 | 372 | ||
373 | rmb(); | 373 | rmb(); |
374 | bufstat = bp->tx_ring[tail].ctrl; | 374 | bufstat = bp->tx_ring[tail].ctrl; |
375 | 375 | ||
376 | if (!(bufstat & MACB_BIT(TX_USED))) | 376 | if (!(bufstat & MACB_BIT(TX_USED))) |
377 | break; | 377 | break; |
378 | 378 | ||
379 | dev_dbg(&bp->pdev->dev, "skb %u (data %p) TX complete\n", | 379 | dev_dbg(&bp->pdev->dev, "skb %u (data %p) TX complete\n", |
380 | tail, skb->data); | 380 | tail, skb->data); |
381 | dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len, | 381 | dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len, |
382 | DMA_TO_DEVICE); | 382 | DMA_TO_DEVICE); |
383 | bp->stats.tx_packets++; | 383 | bp->stats.tx_packets++; |
384 | bp->stats.tx_bytes += skb->len; | 384 | bp->stats.tx_bytes += skb->len; |
385 | rp->skb = NULL; | 385 | rp->skb = NULL; |
386 | dev_kfree_skb_irq(skb); | 386 | dev_kfree_skb_irq(skb); |
387 | } | 387 | } |
388 | 388 | ||
389 | bp->tx_tail = tail; | 389 | bp->tx_tail = tail; |
390 | if (netif_queue_stopped(bp->dev) && | 390 | if (netif_queue_stopped(bp->dev) && |
391 | TX_BUFFS_AVAIL(bp) > MACB_TX_WAKEUP_THRESH) | 391 | TX_BUFFS_AVAIL(bp) > MACB_TX_WAKEUP_THRESH) |
392 | netif_wake_queue(bp->dev); | 392 | netif_wake_queue(bp->dev); |
393 | } | 393 | } |
394 | 394 | ||
395 | static int macb_rx_frame(struct macb *bp, unsigned int first_frag, | 395 | static int macb_rx_frame(struct macb *bp, unsigned int first_frag, |
396 | unsigned int last_frag) | 396 | unsigned int last_frag) |
397 | { | 397 | { |
398 | unsigned int len; | 398 | unsigned int len; |
399 | unsigned int frag; | 399 | unsigned int frag; |
400 | unsigned int offset = 0; | 400 | unsigned int offset = 0; |
401 | struct sk_buff *skb; | 401 | struct sk_buff *skb; |
402 | 402 | ||
403 | len = MACB_BFEXT(RX_FRMLEN, bp->rx_ring[last_frag].ctrl); | 403 | len = MACB_BFEXT(RX_FRMLEN, bp->rx_ring[last_frag].ctrl); |
404 | 404 | ||
405 | dev_dbg(&bp->pdev->dev, "macb_rx_frame frags %u - %u (len %u)\n", | 405 | dev_dbg(&bp->pdev->dev, "macb_rx_frame frags %u - %u (len %u)\n", |
406 | first_frag, last_frag, len); | 406 | first_frag, last_frag, len); |
407 | 407 | ||
408 | skb = dev_alloc_skb(len + RX_OFFSET); | 408 | skb = dev_alloc_skb(len + RX_OFFSET); |
409 | if (!skb) { | 409 | if (!skb) { |
410 | bp->stats.rx_dropped++; | 410 | bp->stats.rx_dropped++; |
411 | for (frag = first_frag; ; frag = NEXT_RX(frag)) { | 411 | for (frag = first_frag; ; frag = NEXT_RX(frag)) { |
412 | bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED); | 412 | bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED); |
413 | if (frag == last_frag) | 413 | if (frag == last_frag) |
414 | break; | 414 | break; |
415 | } | 415 | } |
416 | wmb(); | 416 | wmb(); |
417 | return 1; | 417 | return 1; |
418 | } | 418 | } |
419 | 419 | ||
420 | skb_reserve(skb, RX_OFFSET); | 420 | skb_reserve(skb, RX_OFFSET); |
421 | skb->ip_summed = CHECKSUM_NONE; | 421 | skb->ip_summed = CHECKSUM_NONE; |
422 | skb_put(skb, len); | 422 | skb_put(skb, len); |
423 | 423 | ||
424 | for (frag = first_frag; ; frag = NEXT_RX(frag)) { | 424 | for (frag = first_frag; ; frag = NEXT_RX(frag)) { |
425 | unsigned int frag_len = RX_BUFFER_SIZE; | 425 | unsigned int frag_len = RX_BUFFER_SIZE; |
426 | 426 | ||
427 | if (offset + frag_len > len) { | 427 | if (offset + frag_len > len) { |
428 | BUG_ON(frag != last_frag); | 428 | BUG_ON(frag != last_frag); |
429 | frag_len = len - offset; | 429 | frag_len = len - offset; |
430 | } | 430 | } |
431 | skb_copy_to_linear_data_offset(skb, offset, | 431 | skb_copy_to_linear_data_offset(skb, offset, |
432 | (bp->rx_buffers + | 432 | (bp->rx_buffers + |
433 | (RX_BUFFER_SIZE * frag)), | 433 | (RX_BUFFER_SIZE * frag)), |
434 | frag_len); | 434 | frag_len); |
435 | offset += RX_BUFFER_SIZE; | 435 | offset += RX_BUFFER_SIZE; |
436 | bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED); | 436 | bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED); |
437 | wmb(); | 437 | wmb(); |
438 | 438 | ||
439 | if (frag == last_frag) | 439 | if (frag == last_frag) |
440 | break; | 440 | break; |
441 | } | 441 | } |
442 | 442 | ||
443 | skb->protocol = eth_type_trans(skb, bp->dev); | 443 | skb->protocol = eth_type_trans(skb, bp->dev); |
444 | 444 | ||
445 | bp->stats.rx_packets++; | 445 | bp->stats.rx_packets++; |
446 | bp->stats.rx_bytes += len; | 446 | bp->stats.rx_bytes += len; |
447 | dev_dbg(&bp->pdev->dev, "received skb of length %u, csum: %08x\n", | 447 | dev_dbg(&bp->pdev->dev, "received skb of length %u, csum: %08x\n", |
448 | skb->len, skb->csum); | 448 | skb->len, skb->csum); |
449 | netif_receive_skb(skb); | 449 | netif_receive_skb(skb); |
450 | 450 | ||
451 | return 0; | 451 | return 0; |
452 | } | 452 | } |
453 | 453 | ||
454 | /* Mark DMA descriptors from begin up to and not including end as unused */ | 454 | /* Mark DMA descriptors from begin up to and not including end as unused */ |
455 | static void discard_partial_frame(struct macb *bp, unsigned int begin, | 455 | static void discard_partial_frame(struct macb *bp, unsigned int begin, |
456 | unsigned int end) | 456 | unsigned int end) |
457 | { | 457 | { |
458 | unsigned int frag; | 458 | unsigned int frag; |
459 | 459 | ||
460 | for (frag = begin; frag != end; frag = NEXT_RX(frag)) | 460 | for (frag = begin; frag != end; frag = NEXT_RX(frag)) |
461 | bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED); | 461 | bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED); |
462 | wmb(); | 462 | wmb(); |
463 | 463 | ||
464 | /* | 464 | /* |
465 | * When this happens, the hardware stats registers for | 465 | * When this happens, the hardware stats registers for |
466 | * whatever caused this is updated, so we don't have to record | 466 | * whatever caused this is updated, so we don't have to record |
467 | * anything. | 467 | * anything. |
468 | */ | 468 | */ |
469 | } | 469 | } |
470 | 470 | ||
471 | static int macb_rx(struct macb *bp, int budget) | 471 | static int macb_rx(struct macb *bp, int budget) |
472 | { | 472 | { |
473 | int received = 0; | 473 | int received = 0; |
474 | unsigned int tail = bp->rx_tail; | 474 | unsigned int tail = bp->rx_tail; |
475 | int first_frag = -1; | 475 | int first_frag = -1; |
476 | 476 | ||
477 | for (; budget > 0; tail = NEXT_RX(tail)) { | 477 | for (; budget > 0; tail = NEXT_RX(tail)) { |
478 | u32 addr, ctrl; | 478 | u32 addr, ctrl; |
479 | 479 | ||
480 | rmb(); | 480 | rmb(); |
481 | addr = bp->rx_ring[tail].addr; | 481 | addr = bp->rx_ring[tail].addr; |
482 | ctrl = bp->rx_ring[tail].ctrl; | 482 | ctrl = bp->rx_ring[tail].ctrl; |
483 | 483 | ||
484 | if (!(addr & MACB_BIT(RX_USED))) | 484 | if (!(addr & MACB_BIT(RX_USED))) |
485 | break; | 485 | break; |
486 | 486 | ||
487 | if (ctrl & MACB_BIT(RX_SOF)) { | 487 | if (ctrl & MACB_BIT(RX_SOF)) { |
488 | if (first_frag != -1) | 488 | if (first_frag != -1) |
489 | discard_partial_frame(bp, first_frag, tail); | 489 | discard_partial_frame(bp, first_frag, tail); |
490 | first_frag = tail; | 490 | first_frag = tail; |
491 | } | 491 | } |
492 | 492 | ||
493 | if (ctrl & MACB_BIT(RX_EOF)) { | 493 | if (ctrl & MACB_BIT(RX_EOF)) { |
494 | int dropped; | 494 | int dropped; |
495 | BUG_ON(first_frag == -1); | 495 | BUG_ON(first_frag == -1); |
496 | 496 | ||
497 | dropped = macb_rx_frame(bp, first_frag, tail); | 497 | dropped = macb_rx_frame(bp, first_frag, tail); |
498 | first_frag = -1; | 498 | first_frag = -1; |
499 | if (!dropped) { | 499 | if (!dropped) { |
500 | received++; | 500 | received++; |
501 | budget--; | 501 | budget--; |
502 | } | 502 | } |
503 | } | 503 | } |
504 | } | 504 | } |
505 | 505 | ||
506 | if (first_frag != -1) | 506 | if (first_frag != -1) |
507 | bp->rx_tail = first_frag; | 507 | bp->rx_tail = first_frag; |
508 | else | 508 | else |
509 | bp->rx_tail = tail; | 509 | bp->rx_tail = tail; |
510 | 510 | ||
511 | return received; | 511 | return received; |
512 | } | 512 | } |
513 | 513 | ||
514 | static int macb_poll(struct napi_struct *napi, int budget) | 514 | static int macb_poll(struct napi_struct *napi, int budget) |
515 | { | 515 | { |
516 | struct macb *bp = container_of(napi, struct macb, napi); | 516 | struct macb *bp = container_of(napi, struct macb, napi); |
517 | int work_done; | 517 | int work_done; |
518 | u32 status; | 518 | u32 status; |
519 | 519 | ||
520 | status = macb_readl(bp, RSR); | 520 | status = macb_readl(bp, RSR); |
521 | macb_writel(bp, RSR, status); | 521 | macb_writel(bp, RSR, status); |
522 | 522 | ||
523 | work_done = 0; | 523 | work_done = 0; |
524 | 524 | ||
525 | dev_dbg(&bp->pdev->dev, "poll: status = %08lx, budget = %d\n", | 525 | dev_dbg(&bp->pdev->dev, "poll: status = %08lx, budget = %d\n", |
526 | (unsigned long)status, budget); | 526 | (unsigned long)status, budget); |
527 | 527 | ||
528 | work_done = macb_rx(bp, budget); | 528 | work_done = macb_rx(bp, budget); |
529 | if (work_done < budget) | 529 | if (work_done < budget) |
530 | napi_complete(napi); | 530 | napi_complete(napi); |
531 | 531 | ||
532 | /* | 532 | /* |
533 | * We've done what we can to clean the buffers. Make sure we | 533 | * We've done what we can to clean the buffers. Make sure we |
534 | * get notified when new packets arrive. | 534 | * get notified when new packets arrive. |
535 | */ | 535 | */ |
536 | macb_writel(bp, IER, MACB_RX_INT_FLAGS); | 536 | macb_writel(bp, IER, MACB_RX_INT_FLAGS); |
537 | 537 | ||
538 | /* TODO: Handle errors */ | 538 | /* TODO: Handle errors */ |
539 | 539 | ||
540 | return work_done; | 540 | return work_done; |
541 | } | 541 | } |
542 | 542 | ||
543 | static irqreturn_t macb_interrupt(int irq, void *dev_id) | 543 | static irqreturn_t macb_interrupt(int irq, void *dev_id) |
544 | { | 544 | { |
545 | struct net_device *dev = dev_id; | 545 | struct net_device *dev = dev_id; |
546 | struct macb *bp = netdev_priv(dev); | 546 | struct macb *bp = netdev_priv(dev); |
547 | u32 status; | 547 | u32 status; |
548 | 548 | ||
549 | status = macb_readl(bp, ISR); | 549 | status = macb_readl(bp, ISR); |
550 | 550 | ||
551 | if (unlikely(!status)) | 551 | if (unlikely(!status)) |
552 | return IRQ_NONE; | 552 | return IRQ_NONE; |
553 | 553 | ||
554 | spin_lock(&bp->lock); | 554 | spin_lock(&bp->lock); |
555 | 555 | ||
556 | while (status) { | 556 | while (status) { |
557 | /* close possible race with dev_close */ | 557 | /* close possible race with dev_close */ |
558 | if (unlikely(!netif_running(dev))) { | 558 | if (unlikely(!netif_running(dev))) { |
559 | macb_writel(bp, IDR, ~0UL); | 559 | macb_writel(bp, IDR, ~0UL); |
560 | break; | 560 | break; |
561 | } | 561 | } |
562 | 562 | ||
563 | if (status & MACB_RX_INT_FLAGS) { | 563 | if (status & MACB_RX_INT_FLAGS) { |
564 | if (napi_schedule_prep(&bp->napi)) { | 564 | if (napi_schedule_prep(&bp->napi)) { |
565 | /* | 565 | /* |
566 | * There's no point taking any more interrupts | 566 | * There's no point taking any more interrupts |
567 | * until we have processed the buffers | 567 | * until we have processed the buffers |
568 | */ | 568 | */ |
569 | macb_writel(bp, IDR, MACB_RX_INT_FLAGS); | 569 | macb_writel(bp, IDR, MACB_RX_INT_FLAGS); |
570 | dev_dbg(&bp->pdev->dev, | 570 | dev_dbg(&bp->pdev->dev, |
571 | "scheduling RX softirq\n"); | 571 | "scheduling RX softirq\n"); |
572 | __napi_schedule(&bp->napi); | 572 | __napi_schedule(&bp->napi); |
573 | } | 573 | } |
574 | } | 574 | } |
575 | 575 | ||
576 | if (status & (MACB_BIT(TCOMP) | MACB_BIT(ISR_TUND) | | 576 | if (status & (MACB_BIT(TCOMP) | MACB_BIT(ISR_TUND) | |
577 | MACB_BIT(ISR_RLE))) | 577 | MACB_BIT(ISR_RLE))) |
578 | macb_tx(bp); | 578 | macb_tx(bp); |
579 | 579 | ||
580 | /* | 580 | /* |
581 | * Link change detection isn't possible with RMII, so we'll | 581 | * Link change detection isn't possible with RMII, so we'll |
582 | * add that if/when we get our hands on a full-blown MII PHY. | 582 | * add that if/when we get our hands on a full-blown MII PHY. |
583 | */ | 583 | */ |
584 | 584 | ||
585 | if (status & MACB_BIT(HRESP)) { | 585 | if (status & MACB_BIT(HRESP)) { |
586 | /* | 586 | /* |
587 | * TODO: Reset the hardware, and maybe move the printk | 587 | * TODO: Reset the hardware, and maybe move the printk |
588 | * to a lower-priority context as well (work queue?) | 588 | * to a lower-priority context as well (work queue?) |
589 | */ | 589 | */ |
590 | printk(KERN_ERR "%s: DMA bus error: HRESP not OK\n", | 590 | printk(KERN_ERR "%s: DMA bus error: HRESP not OK\n", |
591 | dev->name); | 591 | dev->name); |
592 | } | 592 | } |
593 | 593 | ||
594 | status = macb_readl(bp, ISR); | 594 | status = macb_readl(bp, ISR); |
595 | } | 595 | } |
596 | 596 | ||
597 | spin_unlock(&bp->lock); | 597 | spin_unlock(&bp->lock); |
598 | 598 | ||
599 | return IRQ_HANDLED; | 599 | return IRQ_HANDLED; |
600 | } | 600 | } |
601 | 601 | ||
602 | #ifdef CONFIG_NET_POLL_CONTROLLER | 602 | #ifdef CONFIG_NET_POLL_CONTROLLER |
603 | /* | 603 | /* |
604 | * Polling receive - used by netconsole and other diagnostic tools | 604 | * Polling receive - used by netconsole and other diagnostic tools |
605 | * to allow network i/o with interrupts disabled. | 605 | * to allow network i/o with interrupts disabled. |
606 | */ | 606 | */ |
607 | static void macb_poll_controller(struct net_device *dev) | 607 | static void macb_poll_controller(struct net_device *dev) |
608 | { | 608 | { |
609 | unsigned long flags; | 609 | unsigned long flags; |
610 | 610 | ||
611 | local_irq_save(flags); | 611 | local_irq_save(flags); |
612 | macb_interrupt(dev->irq, dev); | 612 | macb_interrupt(dev->irq, dev); |
613 | local_irq_restore(flags); | 613 | local_irq_restore(flags); |
614 | } | 614 | } |
615 | #endif | 615 | #endif |
616 | 616 | ||
617 | static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) | 617 | static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) |
618 | { | 618 | { |
619 | struct macb *bp = netdev_priv(dev); | 619 | struct macb *bp = netdev_priv(dev); |
620 | dma_addr_t mapping; | 620 | dma_addr_t mapping; |
621 | unsigned int len, entry; | 621 | unsigned int len, entry; |
622 | u32 ctrl; | 622 | u32 ctrl; |
623 | unsigned long flags; | 623 | unsigned long flags; |
624 | 624 | ||
625 | #ifdef DEBUG | 625 | #ifdef DEBUG |
626 | int i; | 626 | int i; |
627 | dev_dbg(&bp->pdev->dev, | 627 | dev_dbg(&bp->pdev->dev, |
628 | "start_xmit: len %u head %p data %p tail %p end %p\n", | 628 | "start_xmit: len %u head %p data %p tail %p end %p\n", |
629 | skb->len, skb->head, skb->data, | 629 | skb->len, skb->head, skb->data, |
630 | skb_tail_pointer(skb), skb_end_pointer(skb)); | 630 | skb_tail_pointer(skb), skb_end_pointer(skb)); |
631 | dev_dbg(&bp->pdev->dev, | 631 | dev_dbg(&bp->pdev->dev, |
632 | "data:"); | 632 | "data:"); |
633 | for (i = 0; i < 16; i++) | 633 | for (i = 0; i < 16; i++) |
634 | printk(" %02x", (unsigned int)skb->data[i]); | 634 | printk(" %02x", (unsigned int)skb->data[i]); |
635 | printk("\n"); | 635 | printk("\n"); |
636 | #endif | 636 | #endif |
637 | 637 | ||
638 | len = skb->len; | 638 | len = skb->len; |
639 | spin_lock_irqsave(&bp->lock, flags); | 639 | spin_lock_irqsave(&bp->lock, flags); |
640 | 640 | ||
641 | /* This is a hard error, log it. */ | 641 | /* This is a hard error, log it. */ |
642 | if (TX_BUFFS_AVAIL(bp) < 1) { | 642 | if (TX_BUFFS_AVAIL(bp) < 1) { |
643 | netif_stop_queue(dev); | 643 | netif_stop_queue(dev); |
644 | spin_unlock_irqrestore(&bp->lock, flags); | 644 | spin_unlock_irqrestore(&bp->lock, flags); |
645 | dev_err(&bp->pdev->dev, | 645 | dev_err(&bp->pdev->dev, |
646 | "BUG! Tx Ring full when queue awake!\n"); | 646 | "BUG! Tx Ring full when queue awake!\n"); |
647 | dev_dbg(&bp->pdev->dev, "tx_head = %u, tx_tail = %u\n", | 647 | dev_dbg(&bp->pdev->dev, "tx_head = %u, tx_tail = %u\n", |
648 | bp->tx_head, bp->tx_tail); | 648 | bp->tx_head, bp->tx_tail); |
649 | return NETDEV_TX_BUSY; | 649 | return NETDEV_TX_BUSY; |
650 | } | 650 | } |
651 | 651 | ||
652 | entry = bp->tx_head; | 652 | entry = bp->tx_head; |
653 | dev_dbg(&bp->pdev->dev, "Allocated ring entry %u\n", entry); | 653 | dev_dbg(&bp->pdev->dev, "Allocated ring entry %u\n", entry); |
654 | mapping = dma_map_single(&bp->pdev->dev, skb->data, | 654 | mapping = dma_map_single(&bp->pdev->dev, skb->data, |
655 | len, DMA_TO_DEVICE); | 655 | len, DMA_TO_DEVICE); |
656 | bp->tx_skb[entry].skb = skb; | 656 | bp->tx_skb[entry].skb = skb; |
657 | bp->tx_skb[entry].mapping = mapping; | 657 | bp->tx_skb[entry].mapping = mapping; |
658 | dev_dbg(&bp->pdev->dev, "Mapped skb data %p to DMA addr %08lx\n", | 658 | dev_dbg(&bp->pdev->dev, "Mapped skb data %p to DMA addr %08lx\n", |
659 | skb->data, (unsigned long)mapping); | 659 | skb->data, (unsigned long)mapping); |
660 | 660 | ||
661 | ctrl = MACB_BF(TX_FRMLEN, len); | 661 | ctrl = MACB_BF(TX_FRMLEN, len); |
662 | ctrl |= MACB_BIT(TX_LAST); | 662 | ctrl |= MACB_BIT(TX_LAST); |
663 | if (entry == (TX_RING_SIZE - 1)) | 663 | if (entry == (TX_RING_SIZE - 1)) |
664 | ctrl |= MACB_BIT(TX_WRAP); | 664 | ctrl |= MACB_BIT(TX_WRAP); |
665 | 665 | ||
666 | bp->tx_ring[entry].addr = mapping; | 666 | bp->tx_ring[entry].addr = mapping; |
667 | bp->tx_ring[entry].ctrl = ctrl; | 667 | bp->tx_ring[entry].ctrl = ctrl; |
668 | wmb(); | 668 | wmb(); |
669 | 669 | ||
670 | entry = NEXT_TX(entry); | 670 | entry = NEXT_TX(entry); |
671 | bp->tx_head = entry; | 671 | bp->tx_head = entry; |
672 | 672 | ||
673 | macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); | 673 | macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); |
674 | 674 | ||
675 | if (TX_BUFFS_AVAIL(bp) < 1) | 675 | if (TX_BUFFS_AVAIL(bp) < 1) |
676 | netif_stop_queue(dev); | 676 | netif_stop_queue(dev); |
677 | 677 | ||
678 | spin_unlock_irqrestore(&bp->lock, flags); | 678 | spin_unlock_irqrestore(&bp->lock, flags); |
679 | 679 | ||
680 | dev->trans_start = jiffies; | 680 | dev->trans_start = jiffies; |
681 | 681 | ||
682 | return NETDEV_TX_OK; | 682 | return NETDEV_TX_OK; |
683 | } | 683 | } |
684 | 684 | ||
685 | static void macb_free_consistent(struct macb *bp) | 685 | static void macb_free_consistent(struct macb *bp) |
686 | { | 686 | { |
687 | if (bp->tx_skb) { | 687 | if (bp->tx_skb) { |
688 | kfree(bp->tx_skb); | 688 | kfree(bp->tx_skb); |
689 | bp->tx_skb = NULL; | 689 | bp->tx_skb = NULL; |
690 | } | 690 | } |
691 | if (bp->rx_ring) { | 691 | if (bp->rx_ring) { |
692 | dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES, | 692 | dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES, |
693 | bp->rx_ring, bp->rx_ring_dma); | 693 | bp->rx_ring, bp->rx_ring_dma); |
694 | bp->rx_ring = NULL; | 694 | bp->rx_ring = NULL; |
695 | } | 695 | } |
696 | if (bp->tx_ring) { | 696 | if (bp->tx_ring) { |
697 | dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES, | 697 | dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES, |
698 | bp->tx_ring, bp->tx_ring_dma); | 698 | bp->tx_ring, bp->tx_ring_dma); |
699 | bp->tx_ring = NULL; | 699 | bp->tx_ring = NULL; |
700 | } | 700 | } |
701 | if (bp->rx_buffers) { | 701 | if (bp->rx_buffers) { |
702 | dma_free_coherent(&bp->pdev->dev, | 702 | dma_free_coherent(&bp->pdev->dev, |
703 | RX_RING_SIZE * RX_BUFFER_SIZE, | 703 | RX_RING_SIZE * RX_BUFFER_SIZE, |
704 | bp->rx_buffers, bp->rx_buffers_dma); | 704 | bp->rx_buffers, bp->rx_buffers_dma); |
705 | bp->rx_buffers = NULL; | 705 | bp->rx_buffers = NULL; |
706 | } | 706 | } |
707 | } | 707 | } |
708 | 708 | ||
709 | static int macb_alloc_consistent(struct macb *bp) | 709 | static int macb_alloc_consistent(struct macb *bp) |
710 | { | 710 | { |
711 | int size; | 711 | int size; |
712 | 712 | ||
713 | size = TX_RING_SIZE * sizeof(struct ring_info); | 713 | size = TX_RING_SIZE * sizeof(struct ring_info); |
714 | bp->tx_skb = kmalloc(size, GFP_KERNEL); | 714 | bp->tx_skb = kmalloc(size, GFP_KERNEL); |
715 | if (!bp->tx_skb) | 715 | if (!bp->tx_skb) |
716 | goto out_err; | 716 | goto out_err; |
717 | 717 | ||
718 | size = RX_RING_BYTES; | 718 | size = RX_RING_BYTES; |
719 | bp->rx_ring = dma_alloc_coherent(&bp->pdev->dev, size, | 719 | bp->rx_ring = dma_alloc_coherent(&bp->pdev->dev, size, |
720 | &bp->rx_ring_dma, GFP_KERNEL); | 720 | &bp->rx_ring_dma, GFP_KERNEL); |
721 | if (!bp->rx_ring) | 721 | if (!bp->rx_ring) |
722 | goto out_err; | 722 | goto out_err; |
723 | dev_dbg(&bp->pdev->dev, | 723 | dev_dbg(&bp->pdev->dev, |
724 | "Allocated RX ring of %d bytes at %08lx (mapped %p)\n", | 724 | "Allocated RX ring of %d bytes at %08lx (mapped %p)\n", |
725 | size, (unsigned long)bp->rx_ring_dma, bp->rx_ring); | 725 | size, (unsigned long)bp->rx_ring_dma, bp->rx_ring); |
726 | 726 | ||
727 | size = TX_RING_BYTES; | 727 | size = TX_RING_BYTES; |
728 | bp->tx_ring = dma_alloc_coherent(&bp->pdev->dev, size, | 728 | bp->tx_ring = dma_alloc_coherent(&bp->pdev->dev, size, |
729 | &bp->tx_ring_dma, GFP_KERNEL); | 729 | &bp->tx_ring_dma, GFP_KERNEL); |
730 | if (!bp->tx_ring) | 730 | if (!bp->tx_ring) |
731 | goto out_err; | 731 | goto out_err; |
732 | dev_dbg(&bp->pdev->dev, | 732 | dev_dbg(&bp->pdev->dev, |
733 | "Allocated TX ring of %d bytes at %08lx (mapped %p)\n", | 733 | "Allocated TX ring of %d bytes at %08lx (mapped %p)\n", |
734 | size, (unsigned long)bp->tx_ring_dma, bp->tx_ring); | 734 | size, (unsigned long)bp->tx_ring_dma, bp->tx_ring); |
735 | 735 | ||
736 | size = RX_RING_SIZE * RX_BUFFER_SIZE; | 736 | size = RX_RING_SIZE * RX_BUFFER_SIZE; |
737 | bp->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size, | 737 | bp->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size, |
738 | &bp->rx_buffers_dma, GFP_KERNEL); | 738 | &bp->rx_buffers_dma, GFP_KERNEL); |
739 | if (!bp->rx_buffers) | 739 | if (!bp->rx_buffers) |
740 | goto out_err; | 740 | goto out_err; |
741 | dev_dbg(&bp->pdev->dev, | 741 | dev_dbg(&bp->pdev->dev, |
742 | "Allocated RX buffers of %d bytes at %08lx (mapped %p)\n", | 742 | "Allocated RX buffers of %d bytes at %08lx (mapped %p)\n", |
743 | size, (unsigned long)bp->rx_buffers_dma, bp->rx_buffers); | 743 | size, (unsigned long)bp->rx_buffers_dma, bp->rx_buffers); |
744 | 744 | ||
745 | return 0; | 745 | return 0; |
746 | 746 | ||
747 | out_err: | 747 | out_err: |
748 | macb_free_consistent(bp); | 748 | macb_free_consistent(bp); |
749 | return -ENOMEM; | 749 | return -ENOMEM; |
750 | } | 750 | } |
751 | 751 | ||
752 | static void macb_init_rings(struct macb *bp) | 752 | static void macb_init_rings(struct macb *bp) |
753 | { | 753 | { |
754 | int i; | 754 | int i; |
755 | dma_addr_t addr; | 755 | dma_addr_t addr; |
756 | 756 | ||
757 | addr = bp->rx_buffers_dma; | 757 | addr = bp->rx_buffers_dma; |
758 | for (i = 0; i < RX_RING_SIZE; i++) { | 758 | for (i = 0; i < RX_RING_SIZE; i++) { |
759 | bp->rx_ring[i].addr = addr; | 759 | bp->rx_ring[i].addr = addr; |
760 | bp->rx_ring[i].ctrl = 0; | 760 | bp->rx_ring[i].ctrl = 0; |
761 | addr += RX_BUFFER_SIZE; | 761 | addr += RX_BUFFER_SIZE; |
762 | } | 762 | } |
763 | bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP); | 763 | bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP); |
764 | 764 | ||
765 | for (i = 0; i < TX_RING_SIZE; i++) { | 765 | for (i = 0; i < TX_RING_SIZE; i++) { |
766 | bp->tx_ring[i].addr = 0; | 766 | bp->tx_ring[i].addr = 0; |
767 | bp->tx_ring[i].ctrl = MACB_BIT(TX_USED); | 767 | bp->tx_ring[i].ctrl = MACB_BIT(TX_USED); |
768 | } | 768 | } |
769 | bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP); | 769 | bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP); |
770 | 770 | ||
771 | bp->rx_tail = bp->tx_head = bp->tx_tail = 0; | 771 | bp->rx_tail = bp->tx_head = bp->tx_tail = 0; |
772 | } | 772 | } |
773 | 773 | ||
774 | static void macb_reset_hw(struct macb *bp) | 774 | static void macb_reset_hw(struct macb *bp) |
775 | { | 775 | { |
776 | /* Make sure we have the write buffer for ourselves */ | 776 | /* Make sure we have the write buffer for ourselves */ |
777 | wmb(); | 777 | wmb(); |
778 | 778 | ||
779 | /* | 779 | /* |
780 | * Disable RX and TX (XXX: Should we halt the transmission | 780 | * Disable RX and TX (XXX: Should we halt the transmission |
781 | * more gracefully?) | 781 | * more gracefully?) |
782 | */ | 782 | */ |
783 | macb_writel(bp, NCR, 0); | 783 | macb_writel(bp, NCR, 0); |
784 | 784 | ||
785 | /* Clear the stats registers (XXX: Update stats first?) */ | 785 | /* Clear the stats registers (XXX: Update stats first?) */ |
786 | macb_writel(bp, NCR, MACB_BIT(CLRSTAT)); | 786 | macb_writel(bp, NCR, MACB_BIT(CLRSTAT)); |
787 | 787 | ||
788 | /* Clear all status flags */ | 788 | /* Clear all status flags */ |
789 | macb_writel(bp, TSR, ~0UL); | 789 | macb_writel(bp, TSR, ~0UL); |
790 | macb_writel(bp, RSR, ~0UL); | 790 | macb_writel(bp, RSR, ~0UL); |
791 | 791 | ||
792 | /* Disable all interrupts */ | 792 | /* Disable all interrupts */ |
793 | macb_writel(bp, IDR, ~0UL); | 793 | macb_writel(bp, IDR, ~0UL); |
794 | macb_readl(bp, ISR); | 794 | macb_readl(bp, ISR); |
795 | } | 795 | } |
796 | 796 | ||
797 | static void macb_init_hw(struct macb *bp) | 797 | static void macb_init_hw(struct macb *bp) |
798 | { | 798 | { |
799 | u32 config; | 799 | u32 config; |
800 | 800 | ||
801 | macb_reset_hw(bp); | 801 | macb_reset_hw(bp); |
802 | __macb_set_hwaddr(bp); | 802 | __macb_set_hwaddr(bp); |
803 | 803 | ||
804 | config = macb_readl(bp, NCFGR) & MACB_BF(CLK, -1L); | 804 | config = macb_readl(bp, NCFGR) & MACB_BF(CLK, -1L); |
805 | config |= MACB_BIT(PAE); /* PAuse Enable */ | 805 | config |= MACB_BIT(PAE); /* PAuse Enable */ |
806 | config |= MACB_BIT(DRFCS); /* Discard Rx FCS */ | 806 | config |= MACB_BIT(DRFCS); /* Discard Rx FCS */ |
807 | if (bp->dev->flags & IFF_PROMISC) | 807 | if (bp->dev->flags & IFF_PROMISC) |
808 | config |= MACB_BIT(CAF); /* Copy All Frames */ | 808 | config |= MACB_BIT(CAF); /* Copy All Frames */ |
809 | if (!(bp->dev->flags & IFF_BROADCAST)) | 809 | if (!(bp->dev->flags & IFF_BROADCAST)) |
810 | config |= MACB_BIT(NBC); /* No BroadCast */ | 810 | config |= MACB_BIT(NBC); /* No BroadCast */ |
811 | macb_writel(bp, NCFGR, config); | 811 | macb_writel(bp, NCFGR, config); |
812 | 812 | ||
813 | /* Initialize TX and RX buffers */ | 813 | /* Initialize TX and RX buffers */ |
814 | macb_writel(bp, RBQP, bp->rx_ring_dma); | 814 | macb_writel(bp, RBQP, bp->rx_ring_dma); |
815 | macb_writel(bp, TBQP, bp->tx_ring_dma); | 815 | macb_writel(bp, TBQP, bp->tx_ring_dma); |
816 | 816 | ||
817 | /* Enable TX and RX */ | 817 | /* Enable TX and RX */ |
818 | macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE) | MACB_BIT(MPE)); | 818 | macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE) | MACB_BIT(MPE)); |
819 | 819 | ||
820 | /* Enable interrupts */ | 820 | /* Enable interrupts */ |
821 | macb_writel(bp, IER, (MACB_BIT(RCOMP) | 821 | macb_writel(bp, IER, (MACB_BIT(RCOMP) |
822 | | MACB_BIT(RXUBR) | 822 | | MACB_BIT(RXUBR) |
823 | | MACB_BIT(ISR_TUND) | 823 | | MACB_BIT(ISR_TUND) |
824 | | MACB_BIT(ISR_RLE) | 824 | | MACB_BIT(ISR_RLE) |
825 | | MACB_BIT(TXERR) | 825 | | MACB_BIT(TXERR) |
826 | | MACB_BIT(TCOMP) | 826 | | MACB_BIT(TCOMP) |
827 | | MACB_BIT(ISR_ROVR) | 827 | | MACB_BIT(ISR_ROVR) |
828 | | MACB_BIT(HRESP))); | 828 | | MACB_BIT(HRESP))); |
829 | 829 | ||
830 | } | 830 | } |
831 | 831 | ||
832 | /* | 832 | /* |
833 | * The hash address register is 64 bits long and takes up two | 833 | * The hash address register is 64 bits long and takes up two |
834 | * locations in the memory map. The least significant bits are stored | 834 | * locations in the memory map. The least significant bits are stored |
835 | * in EMAC_HSL and the most significant bits in EMAC_HSH. | 835 | * in EMAC_HSL and the most significant bits in EMAC_HSH. |
836 | * | 836 | * |
837 | * The unicast hash enable and the multicast hash enable bits in the | 837 | * The unicast hash enable and the multicast hash enable bits in the |
838 | * network configuration register enable the reception of hash matched | 838 | * network configuration register enable the reception of hash matched |
839 | * frames. The destination address is reduced to a 6 bit index into | 839 | * frames. The destination address is reduced to a 6 bit index into |
840 | * the 64 bit hash register using the following hash function. The | 840 | * the 64 bit hash register using the following hash function. The |
841 | * hash function is an exclusive or of every sixth bit of the | 841 | * hash function is an exclusive or of every sixth bit of the |
842 | * destination address. | 842 | * destination address. |
843 | * | 843 | * |
844 | * hi[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47] | 844 | * hi[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47] |
845 | * hi[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46] | 845 | * hi[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46] |
846 | * hi[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45] | 846 | * hi[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45] |
847 | * hi[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44] | 847 | * hi[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44] |
848 | * hi[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43] | 848 | * hi[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43] |
849 | * hi[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42] | 849 | * hi[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42] |
850 | * | 850 | * |
851 | * da[0] represents the least significant bit of the first byte | 851 | * da[0] represents the least significant bit of the first byte |
852 | * received, that is, the multicast/unicast indicator, and da[47] | 852 | * received, that is, the multicast/unicast indicator, and da[47] |
853 | * represents the most significant bit of the last byte received. If | 853 | * represents the most significant bit of the last byte received. If |
854 | * the hash index, hi[n], points to a bit that is set in the hash | 854 | * the hash index, hi[n], points to a bit that is set in the hash |
855 | * register then the frame will be matched according to whether the | 855 | * register then the frame will be matched according to whether the |
856 | * frame is multicast or unicast. A multicast match will be signalled | 856 | * frame is multicast or unicast. A multicast match will be signalled |
857 | * if the multicast hash enable bit is set, da[0] is 1 and the hash | 857 | * if the multicast hash enable bit is set, da[0] is 1 and the hash |
858 | * index points to a bit set in the hash register. A unicast match | 858 | * index points to a bit set in the hash register. A unicast match |
859 | * will be signalled if the unicast hash enable bit is set, da[0] is 0 | 859 | * will be signalled if the unicast hash enable bit is set, da[0] is 0 |
860 | * and the hash index points to a bit set in the hash register. To | 860 | * and the hash index points to a bit set in the hash register. To |
861 | * receive all multicast frames, the hash register should be set with | 861 | * receive all multicast frames, the hash register should be set with |
862 | * all ones and the multicast hash enable bit should be set in the | 862 | * all ones and the multicast hash enable bit should be set in the |
863 | * network configuration register. | 863 | * network configuration register. |
864 | */ | 864 | */ |
865 | 865 | ||
866 | static inline int hash_bit_value(int bitnr, __u8 *addr) | 866 | static inline int hash_bit_value(int bitnr, __u8 *addr) |
867 | { | 867 | { |
868 | if (addr[bitnr / 8] & (1 << (bitnr % 8))) | 868 | if (addr[bitnr / 8] & (1 << (bitnr % 8))) |
869 | return 1; | 869 | return 1; |
870 | return 0; | 870 | return 0; |
871 | } | 871 | } |
872 | 872 | ||
873 | /* | 873 | /* |
874 | * Return the hash index value for the specified address. | 874 | * Return the hash index value for the specified address. |
875 | */ | 875 | */ |
876 | static int hash_get_index(__u8 *addr) | 876 | static int hash_get_index(__u8 *addr) |
877 | { | 877 | { |
878 | int i, j, bitval; | 878 | int i, j, bitval; |
879 | int hash_index = 0; | 879 | int hash_index = 0; |
880 | 880 | ||
881 | for (j = 0; j < 6; j++) { | 881 | for (j = 0; j < 6; j++) { |
882 | for (i = 0, bitval = 0; i < 8; i++) | 882 | for (i = 0, bitval = 0; i < 8; i++) |
883 | bitval ^= hash_bit_value(i*6 + j, addr); | 883 | bitval ^= hash_bit_value(i*6 + j, addr); |
884 | 884 | ||
885 | hash_index |= (bitval << j); | 885 | hash_index |= (bitval << j); |
886 | } | 886 | } |
887 | 887 | ||
888 | return hash_index; | 888 | return hash_index; |
889 | } | 889 | } |
890 | 890 | ||
891 | /* | 891 | /* |
892 | * Add multicast addresses to the internal multicast-hash table. | 892 | * Add multicast addresses to the internal multicast-hash table. |
893 | */ | 893 | */ |
894 | static void macb_sethashtable(struct net_device *dev) | 894 | static void macb_sethashtable(struct net_device *dev) |
895 | { | 895 | { |
896 | struct dev_mc_list *curr; | 896 | struct dev_mc_list *curr; |
897 | unsigned long mc_filter[2]; | 897 | unsigned long mc_filter[2]; |
898 | unsigned int i, bitnr; | 898 | unsigned int i, bitnr; |
899 | struct macb *bp = netdev_priv(dev); | 899 | struct macb *bp = netdev_priv(dev); |
900 | 900 | ||
901 | mc_filter[0] = mc_filter[1] = 0; | 901 | mc_filter[0] = mc_filter[1] = 0; |
902 | 902 | ||
903 | curr = dev->mc_list; | 903 | curr = dev->mc_list; |
904 | for (i = 0; i < dev->mc_count; i++, curr = curr->next) { | 904 | for (i = 0; i < dev->mc_count; i++, curr = curr->next) { |
905 | if (!curr) break; /* unexpected end of list */ | 905 | if (!curr) break; /* unexpected end of list */ |
906 | 906 | ||
907 | bitnr = hash_get_index(curr->dmi_addr); | 907 | bitnr = hash_get_index(curr->dmi_addr); |
908 | mc_filter[bitnr >> 5] |= 1 << (bitnr & 31); | 908 | mc_filter[bitnr >> 5] |= 1 << (bitnr & 31); |
909 | } | 909 | } |
910 | 910 | ||
911 | macb_writel(bp, HRB, mc_filter[0]); | 911 | macb_writel(bp, HRB, mc_filter[0]); |
912 | macb_writel(bp, HRT, mc_filter[1]); | 912 | macb_writel(bp, HRT, mc_filter[1]); |
913 | } | 913 | } |
914 | 914 | ||
915 | /* | 915 | /* |
916 | * Enable/Disable promiscuous and multicast modes. | 916 | * Enable/Disable promiscuous and multicast modes. |
917 | */ | 917 | */ |
918 | static void macb_set_rx_mode(struct net_device *dev) | 918 | static void macb_set_rx_mode(struct net_device *dev) |
919 | { | 919 | { |
920 | unsigned long cfg; | 920 | unsigned long cfg; |
921 | struct macb *bp = netdev_priv(dev); | 921 | struct macb *bp = netdev_priv(dev); |
922 | 922 | ||
923 | cfg = macb_readl(bp, NCFGR); | 923 | cfg = macb_readl(bp, NCFGR); |
924 | 924 | ||
925 | if (dev->flags & IFF_PROMISC) | 925 | if (dev->flags & IFF_PROMISC) |
926 | /* Enable promiscuous mode */ | 926 | /* Enable promiscuous mode */ |
927 | cfg |= MACB_BIT(CAF); | 927 | cfg |= MACB_BIT(CAF); |
928 | else if (dev->flags & (~IFF_PROMISC)) | 928 | else if (dev->flags & (~IFF_PROMISC)) |
929 | /* Disable promiscuous mode */ | 929 | /* Disable promiscuous mode */ |
930 | cfg &= ~MACB_BIT(CAF); | 930 | cfg &= ~MACB_BIT(CAF); |
931 | 931 | ||
932 | if (dev->flags & IFF_ALLMULTI) { | 932 | if (dev->flags & IFF_ALLMULTI) { |
933 | /* Enable all multicast mode */ | 933 | /* Enable all multicast mode */ |
934 | macb_writel(bp, HRB, -1); | 934 | macb_writel(bp, HRB, -1); |
935 | macb_writel(bp, HRT, -1); | 935 | macb_writel(bp, HRT, -1); |
936 | cfg |= MACB_BIT(NCFGR_MTI); | 936 | cfg |= MACB_BIT(NCFGR_MTI); |
937 | } else if (dev->mc_count > 0) { | 937 | } else if (dev->mc_count > 0) { |
938 | /* Enable specific multicasts */ | 938 | /* Enable specific multicasts */ |
939 | macb_sethashtable(dev); | 939 | macb_sethashtable(dev); |
940 | cfg |= MACB_BIT(NCFGR_MTI); | 940 | cfg |= MACB_BIT(NCFGR_MTI); |
941 | } else if (dev->flags & (~IFF_ALLMULTI)) { | 941 | } else if (dev->flags & (~IFF_ALLMULTI)) { |
942 | /* Disable all multicast mode */ | 942 | /* Disable all multicast mode */ |
943 | macb_writel(bp, HRB, 0); | 943 | macb_writel(bp, HRB, 0); |
944 | macb_writel(bp, HRT, 0); | 944 | macb_writel(bp, HRT, 0); |
945 | cfg &= ~MACB_BIT(NCFGR_MTI); | 945 | cfg &= ~MACB_BIT(NCFGR_MTI); |
946 | } | 946 | } |
947 | 947 | ||
948 | macb_writel(bp, NCFGR, cfg); | 948 | macb_writel(bp, NCFGR, cfg); |
949 | } | 949 | } |
950 | 950 | ||
951 | static int macb_open(struct net_device *dev) | 951 | static int macb_open(struct net_device *dev) |
952 | { | 952 | { |
953 | struct macb *bp = netdev_priv(dev); | 953 | struct macb *bp = netdev_priv(dev); |
954 | int err; | 954 | int err; |
955 | 955 | ||
956 | dev_dbg(&bp->pdev->dev, "open\n"); | 956 | dev_dbg(&bp->pdev->dev, "open\n"); |
957 | 957 | ||
958 | /* if the phy is not yet register, retry later*/ | 958 | /* if the phy is not yet register, retry later*/ |
959 | if (!bp->phy_dev) | 959 | if (!bp->phy_dev) |
960 | return -EAGAIN; | 960 | return -EAGAIN; |
961 | 961 | ||
962 | if (!is_valid_ether_addr(dev->dev_addr)) | 962 | if (!is_valid_ether_addr(dev->dev_addr)) |
963 | return -EADDRNOTAVAIL; | 963 | return -EADDRNOTAVAIL; |
964 | 964 | ||
965 | err = macb_alloc_consistent(bp); | 965 | err = macb_alloc_consistent(bp); |
966 | if (err) { | 966 | if (err) { |
967 | printk(KERN_ERR | 967 | printk(KERN_ERR |
968 | "%s: Unable to allocate DMA memory (error %d)\n", | 968 | "%s: Unable to allocate DMA memory (error %d)\n", |
969 | dev->name, err); | 969 | dev->name, err); |
970 | return err; | 970 | return err; |
971 | } | 971 | } |
972 | 972 | ||
973 | napi_enable(&bp->napi); | 973 | napi_enable(&bp->napi); |
974 | 974 | ||
975 | macb_init_rings(bp); | 975 | macb_init_rings(bp); |
976 | macb_init_hw(bp); | 976 | macb_init_hw(bp); |
977 | 977 | ||
978 | /* schedule a link state check */ | 978 | /* schedule a link state check */ |
979 | phy_start(bp->phy_dev); | 979 | phy_start(bp->phy_dev); |
980 | 980 | ||
981 | netif_start_queue(dev); | 981 | netif_start_queue(dev); |
982 | 982 | ||
983 | return 0; | 983 | return 0; |
984 | } | 984 | } |
985 | 985 | ||
986 | static int macb_close(struct net_device *dev) | 986 | static int macb_close(struct net_device *dev) |
987 | { | 987 | { |
988 | struct macb *bp = netdev_priv(dev); | 988 | struct macb *bp = netdev_priv(dev); |
989 | unsigned long flags; | 989 | unsigned long flags; |
990 | 990 | ||
991 | netif_stop_queue(dev); | 991 | netif_stop_queue(dev); |
992 | napi_disable(&bp->napi); | 992 | napi_disable(&bp->napi); |
993 | 993 | ||
994 | if (bp->phy_dev) | 994 | if (bp->phy_dev) |
995 | phy_stop(bp->phy_dev); | 995 | phy_stop(bp->phy_dev); |
996 | 996 | ||
997 | spin_lock_irqsave(&bp->lock, flags); | 997 | spin_lock_irqsave(&bp->lock, flags); |
998 | macb_reset_hw(bp); | 998 | macb_reset_hw(bp); |
999 | netif_carrier_off(dev); | 999 | netif_carrier_off(dev); |
1000 | spin_unlock_irqrestore(&bp->lock, flags); | 1000 | spin_unlock_irqrestore(&bp->lock, flags); |
1001 | 1001 | ||
1002 | macb_free_consistent(bp); | 1002 | macb_free_consistent(bp); |
1003 | 1003 | ||
1004 | return 0; | 1004 | return 0; |
1005 | } | 1005 | } |
1006 | 1006 | ||
1007 | static struct net_device_stats *macb_get_stats(struct net_device *dev) | 1007 | static struct net_device_stats *macb_get_stats(struct net_device *dev) |
1008 | { | 1008 | { |
1009 | struct macb *bp = netdev_priv(dev); | 1009 | struct macb *bp = netdev_priv(dev); |
1010 | struct net_device_stats *nstat = &bp->stats; | 1010 | struct net_device_stats *nstat = &bp->stats; |
1011 | struct macb_stats *hwstat = &bp->hw_stats; | 1011 | struct macb_stats *hwstat = &bp->hw_stats; |
1012 | 1012 | ||
1013 | /* read stats from hardware */ | 1013 | /* read stats from hardware */ |
1014 | macb_update_stats(bp); | 1014 | macb_update_stats(bp); |
1015 | 1015 | ||
1016 | /* Convert HW stats into netdevice stats */ | 1016 | /* Convert HW stats into netdevice stats */ |
1017 | nstat->rx_errors = (hwstat->rx_fcs_errors + | 1017 | nstat->rx_errors = (hwstat->rx_fcs_errors + |
1018 | hwstat->rx_align_errors + | 1018 | hwstat->rx_align_errors + |
1019 | hwstat->rx_resource_errors + | 1019 | hwstat->rx_resource_errors + |
1020 | hwstat->rx_overruns + | 1020 | hwstat->rx_overruns + |
1021 | hwstat->rx_oversize_pkts + | 1021 | hwstat->rx_oversize_pkts + |
1022 | hwstat->rx_jabbers + | 1022 | hwstat->rx_jabbers + |
1023 | hwstat->rx_undersize_pkts + | 1023 | hwstat->rx_undersize_pkts + |
1024 | hwstat->sqe_test_errors + | 1024 | hwstat->sqe_test_errors + |
1025 | hwstat->rx_length_mismatch); | 1025 | hwstat->rx_length_mismatch); |
1026 | nstat->tx_errors = (hwstat->tx_late_cols + | 1026 | nstat->tx_errors = (hwstat->tx_late_cols + |
1027 | hwstat->tx_excessive_cols + | 1027 | hwstat->tx_excessive_cols + |
1028 | hwstat->tx_underruns + | 1028 | hwstat->tx_underruns + |
1029 | hwstat->tx_carrier_errors); | 1029 | hwstat->tx_carrier_errors); |
1030 | nstat->collisions = (hwstat->tx_single_cols + | 1030 | nstat->collisions = (hwstat->tx_single_cols + |
1031 | hwstat->tx_multiple_cols + | 1031 | hwstat->tx_multiple_cols + |
1032 | hwstat->tx_excessive_cols); | 1032 | hwstat->tx_excessive_cols); |
1033 | nstat->rx_length_errors = (hwstat->rx_oversize_pkts + | 1033 | nstat->rx_length_errors = (hwstat->rx_oversize_pkts + |
1034 | hwstat->rx_jabbers + | 1034 | hwstat->rx_jabbers + |
1035 | hwstat->rx_undersize_pkts + | 1035 | hwstat->rx_undersize_pkts + |
1036 | hwstat->rx_length_mismatch); | 1036 | hwstat->rx_length_mismatch); |
1037 | nstat->rx_over_errors = hwstat->rx_resource_errors; | 1037 | nstat->rx_over_errors = hwstat->rx_resource_errors; |
1038 | nstat->rx_crc_errors = hwstat->rx_fcs_errors; | 1038 | nstat->rx_crc_errors = hwstat->rx_fcs_errors; |
1039 | nstat->rx_frame_errors = hwstat->rx_align_errors; | 1039 | nstat->rx_frame_errors = hwstat->rx_align_errors; |
1040 | nstat->rx_fifo_errors = hwstat->rx_overruns; | 1040 | nstat->rx_fifo_errors = hwstat->rx_overruns; |
1041 | /* XXX: What does "missed" mean? */ | 1041 | /* XXX: What does "missed" mean? */ |
1042 | nstat->tx_aborted_errors = hwstat->tx_excessive_cols; | 1042 | nstat->tx_aborted_errors = hwstat->tx_excessive_cols; |
1043 | nstat->tx_carrier_errors = hwstat->tx_carrier_errors; | 1043 | nstat->tx_carrier_errors = hwstat->tx_carrier_errors; |
1044 | nstat->tx_fifo_errors = hwstat->tx_underruns; | 1044 | nstat->tx_fifo_errors = hwstat->tx_underruns; |
1045 | /* Don't know about heartbeat or window errors... */ | 1045 | /* Don't know about heartbeat or window errors... */ |
1046 | 1046 | ||
1047 | return nstat; | 1047 | return nstat; |
1048 | } | 1048 | } |
1049 | 1049 | ||
1050 | static int macb_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 1050 | static int macb_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
1051 | { | 1051 | { |
1052 | struct macb *bp = netdev_priv(dev); | 1052 | struct macb *bp = netdev_priv(dev); |
1053 | struct phy_device *phydev = bp->phy_dev; | 1053 | struct phy_device *phydev = bp->phy_dev; |
1054 | 1054 | ||
1055 | if (!phydev) | 1055 | if (!phydev) |
1056 | return -ENODEV; | 1056 | return -ENODEV; |
1057 | 1057 | ||
1058 | return phy_ethtool_gset(phydev, cmd); | 1058 | return phy_ethtool_gset(phydev, cmd); |
1059 | } | 1059 | } |
1060 | 1060 | ||
1061 | static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 1061 | static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
1062 | { | 1062 | { |
1063 | struct macb *bp = netdev_priv(dev); | 1063 | struct macb *bp = netdev_priv(dev); |
1064 | struct phy_device *phydev = bp->phy_dev; | 1064 | struct phy_device *phydev = bp->phy_dev; |
1065 | 1065 | ||
1066 | if (!phydev) | 1066 | if (!phydev) |
1067 | return -ENODEV; | 1067 | return -ENODEV; |
1068 | 1068 | ||
1069 | return phy_ethtool_sset(phydev, cmd); | 1069 | return phy_ethtool_sset(phydev, cmd); |
1070 | } | 1070 | } |
1071 | 1071 | ||
1072 | static void macb_get_drvinfo(struct net_device *dev, | 1072 | static void macb_get_drvinfo(struct net_device *dev, |
1073 | struct ethtool_drvinfo *info) | 1073 | struct ethtool_drvinfo *info) |
1074 | { | 1074 | { |
1075 | struct macb *bp = netdev_priv(dev); | 1075 | struct macb *bp = netdev_priv(dev); |
1076 | 1076 | ||
1077 | strcpy(info->driver, bp->pdev->dev.driver->name); | 1077 | strcpy(info->driver, bp->pdev->dev.driver->name); |
1078 | strcpy(info->version, "$Revision: 1.14 $"); | 1078 | strcpy(info->version, "$Revision: 1.14 $"); |
1079 | strcpy(info->bus_info, dev_name(&bp->pdev->dev)); | 1079 | strcpy(info->bus_info, dev_name(&bp->pdev->dev)); |
1080 | } | 1080 | } |
1081 | 1081 | ||
1082 | static const struct ethtool_ops macb_ethtool_ops = { | 1082 | static const struct ethtool_ops macb_ethtool_ops = { |
1083 | .get_settings = macb_get_settings, | 1083 | .get_settings = macb_get_settings, |
1084 | .set_settings = macb_set_settings, | 1084 | .set_settings = macb_set_settings, |
1085 | .get_drvinfo = macb_get_drvinfo, | 1085 | .get_drvinfo = macb_get_drvinfo, |
1086 | .get_link = ethtool_op_get_link, | 1086 | .get_link = ethtool_op_get_link, |
1087 | }; | 1087 | }; |
1088 | 1088 | ||
1089 | static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | 1089 | static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
1090 | { | 1090 | { |
1091 | struct macb *bp = netdev_priv(dev); | 1091 | struct macb *bp = netdev_priv(dev); |
1092 | struct phy_device *phydev = bp->phy_dev; | 1092 | struct phy_device *phydev = bp->phy_dev; |
1093 | 1093 | ||
1094 | if (!netif_running(dev)) | 1094 | if (!netif_running(dev)) |
1095 | return -EINVAL; | 1095 | return -EINVAL; |
1096 | 1096 | ||
1097 | if (!phydev) | 1097 | if (!phydev) |
1098 | return -ENODEV; | 1098 | return -ENODEV; |
1099 | 1099 | ||
1100 | return phy_mii_ioctl(phydev, if_mii(rq), cmd); | 1100 | return phy_mii_ioctl(phydev, if_mii(rq), cmd); |
1101 | } | 1101 | } |
1102 | 1102 | ||
1103 | static const struct net_device_ops macb_netdev_ops = { | 1103 | static const struct net_device_ops macb_netdev_ops = { |
1104 | .ndo_open = macb_open, | 1104 | .ndo_open = macb_open, |
1105 | .ndo_stop = macb_close, | 1105 | .ndo_stop = macb_close, |
1106 | .ndo_start_xmit = macb_start_xmit, | 1106 | .ndo_start_xmit = macb_start_xmit, |
1107 | .ndo_set_multicast_list = macb_set_rx_mode, | 1107 | .ndo_set_multicast_list = macb_set_rx_mode, |
1108 | .ndo_get_stats = macb_get_stats, | 1108 | .ndo_get_stats = macb_get_stats, |
1109 | .ndo_do_ioctl = macb_ioctl, | 1109 | .ndo_do_ioctl = macb_ioctl, |
1110 | .ndo_validate_addr = eth_validate_addr, | 1110 | .ndo_validate_addr = eth_validate_addr, |
1111 | .ndo_change_mtu = eth_change_mtu, | 1111 | .ndo_change_mtu = eth_change_mtu, |
1112 | .ndo_set_mac_address = eth_mac_addr, | 1112 | .ndo_set_mac_address = eth_mac_addr, |
1113 | #ifdef CONFIG_NET_POLL_CONTROLLER | 1113 | #ifdef CONFIG_NET_POLL_CONTROLLER |
1114 | .ndo_poll_controller = macb_poll_controller, | 1114 | .ndo_poll_controller = macb_poll_controller, |
1115 | #endif | 1115 | #endif |
1116 | }; | 1116 | }; |
1117 | 1117 | ||
1118 | static int __init macb_probe(struct platform_device *pdev) | 1118 | static int __init macb_probe(struct platform_device *pdev) |
1119 | { | 1119 | { |
1120 | struct eth_platform_data *pdata; | 1120 | struct eth_platform_data *pdata; |
1121 | struct resource *regs; | 1121 | struct resource *regs; |
1122 | struct net_device *dev; | 1122 | struct net_device *dev; |
1123 | struct macb *bp; | 1123 | struct macb *bp; |
1124 | struct phy_device *phydev; | 1124 | struct phy_device *phydev; |
1125 | unsigned long pclk_hz; | 1125 | unsigned long pclk_hz; |
1126 | u32 config; | 1126 | u32 config; |
1127 | int err = -ENXIO; | 1127 | int err = -ENXIO; |
1128 | 1128 | ||
1129 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1129 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1130 | if (!regs) { | 1130 | if (!regs) { |
1131 | dev_err(&pdev->dev, "no mmio resource defined\n"); | 1131 | dev_err(&pdev->dev, "no mmio resource defined\n"); |
1132 | goto err_out; | 1132 | goto err_out; |
1133 | } | 1133 | } |
1134 | 1134 | ||
1135 | err = -ENOMEM; | 1135 | err = -ENOMEM; |
1136 | dev = alloc_etherdev(sizeof(*bp)); | 1136 | dev = alloc_etherdev(sizeof(*bp)); |
1137 | if (!dev) { | 1137 | if (!dev) { |
1138 | dev_err(&pdev->dev, "etherdev alloc failed, aborting.\n"); | 1138 | dev_err(&pdev->dev, "etherdev alloc failed, aborting.\n"); |
1139 | goto err_out; | 1139 | goto err_out; |
1140 | } | 1140 | } |
1141 | 1141 | ||
1142 | SET_NETDEV_DEV(dev, &pdev->dev); | 1142 | SET_NETDEV_DEV(dev, &pdev->dev); |
1143 | 1143 | ||
1144 | /* TODO: Actually, we have some interesting features... */ | 1144 | /* TODO: Actually, we have some interesting features... */ |
1145 | dev->features |= 0; | 1145 | dev->features |= 0; |
1146 | 1146 | ||
1147 | bp = netdev_priv(dev); | 1147 | bp = netdev_priv(dev); |
1148 | bp->pdev = pdev; | 1148 | bp->pdev = pdev; |
1149 | bp->dev = dev; | 1149 | bp->dev = dev; |
1150 | 1150 | ||
1151 | spin_lock_init(&bp->lock); | 1151 | spin_lock_init(&bp->lock); |
1152 | 1152 | ||
1153 | #if defined(CONFIG_ARCH_AT91) | 1153 | #if defined(CONFIG_ARCH_AT91) |
1154 | bp->pclk = clk_get(&pdev->dev, "macb_clk"); | 1154 | bp->pclk = clk_get(&pdev->dev, "macb_clk"); |
1155 | if (IS_ERR(bp->pclk)) { | 1155 | if (IS_ERR(bp->pclk)) { |
1156 | dev_err(&pdev->dev, "failed to get macb_clk\n"); | 1156 | dev_err(&pdev->dev, "failed to get macb_clk\n"); |
1157 | goto err_out_free_dev; | 1157 | goto err_out_free_dev; |
1158 | } | 1158 | } |
1159 | clk_enable(bp->pclk); | 1159 | clk_enable(bp->pclk); |
1160 | #else | 1160 | #else |
1161 | bp->pclk = clk_get(&pdev->dev, "pclk"); | 1161 | bp->pclk = clk_get(&pdev->dev, "pclk"); |
1162 | if (IS_ERR(bp->pclk)) { | 1162 | if (IS_ERR(bp->pclk)) { |
1163 | dev_err(&pdev->dev, "failed to get pclk\n"); | 1163 | dev_err(&pdev->dev, "failed to get pclk\n"); |
1164 | goto err_out_free_dev; | 1164 | goto err_out_free_dev; |
1165 | } | 1165 | } |
1166 | bp->hclk = clk_get(&pdev->dev, "hclk"); | 1166 | bp->hclk = clk_get(&pdev->dev, "hclk"); |
1167 | if (IS_ERR(bp->hclk)) { | 1167 | if (IS_ERR(bp->hclk)) { |
1168 | dev_err(&pdev->dev, "failed to get hclk\n"); | 1168 | dev_err(&pdev->dev, "failed to get hclk\n"); |
1169 | goto err_out_put_pclk; | 1169 | goto err_out_put_pclk; |
1170 | } | 1170 | } |
1171 | 1171 | ||
1172 | clk_enable(bp->pclk); | 1172 | clk_enable(bp->pclk); |
1173 | clk_enable(bp->hclk); | 1173 | clk_enable(bp->hclk); |
1174 | #endif | 1174 | #endif |
1175 | 1175 | ||
1176 | bp->regs = ioremap(regs->start, regs->end - regs->start + 1); | 1176 | bp->regs = ioremap(regs->start, regs->end - regs->start + 1); |
1177 | if (!bp->regs) { | 1177 | if (!bp->regs) { |
1178 | dev_err(&pdev->dev, "failed to map registers, aborting.\n"); | 1178 | dev_err(&pdev->dev, "failed to map registers, aborting.\n"); |
1179 | err = -ENOMEM; | 1179 | err = -ENOMEM; |
1180 | goto err_out_disable_clocks; | 1180 | goto err_out_disable_clocks; |
1181 | } | 1181 | } |
1182 | 1182 | ||
1183 | dev->irq = platform_get_irq(pdev, 0); | 1183 | dev->irq = platform_get_irq(pdev, 0); |
1184 | err = request_irq(dev->irq, macb_interrupt, IRQF_SAMPLE_RANDOM, | 1184 | err = request_irq(dev->irq, macb_interrupt, IRQF_SAMPLE_RANDOM, |
1185 | dev->name, dev); | 1185 | dev->name, dev); |
1186 | if (err) { | 1186 | if (err) { |
1187 | printk(KERN_ERR | 1187 | printk(KERN_ERR |
1188 | "%s: Unable to request IRQ %d (error %d)\n", | 1188 | "%s: Unable to request IRQ %d (error %d)\n", |
1189 | dev->name, dev->irq, err); | 1189 | dev->name, dev->irq, err); |
1190 | goto err_out_iounmap; | 1190 | goto err_out_iounmap; |
1191 | } | 1191 | } |
1192 | 1192 | ||
1193 | dev->netdev_ops = &macb_netdev_ops; | 1193 | dev->netdev_ops = &macb_netdev_ops; |
1194 | netif_napi_add(dev, &bp->napi, macb_poll, 64); | 1194 | netif_napi_add(dev, &bp->napi, macb_poll, 64); |
1195 | dev->ethtool_ops = &macb_ethtool_ops; | 1195 | dev->ethtool_ops = &macb_ethtool_ops; |
1196 | 1196 | ||
1197 | dev->base_addr = regs->start; | 1197 | dev->base_addr = regs->start; |
1198 | 1198 | ||
1199 | /* Set MII management clock divider */ | 1199 | /* Set MII management clock divider */ |
1200 | pclk_hz = clk_get_rate(bp->pclk); | 1200 | pclk_hz = clk_get_rate(bp->pclk); |
1201 | if (pclk_hz <= 20000000) | 1201 | if (pclk_hz <= 20000000) |
1202 | config = MACB_BF(CLK, MACB_CLK_DIV8); | 1202 | config = MACB_BF(CLK, MACB_CLK_DIV8); |
1203 | else if (pclk_hz <= 40000000) | 1203 | else if (pclk_hz <= 40000000) |
1204 | config = MACB_BF(CLK, MACB_CLK_DIV16); | 1204 | config = MACB_BF(CLK, MACB_CLK_DIV16); |
1205 | else if (pclk_hz <= 80000000) | 1205 | else if (pclk_hz <= 80000000) |
1206 | config = MACB_BF(CLK, MACB_CLK_DIV32); | 1206 | config = MACB_BF(CLK, MACB_CLK_DIV32); |
1207 | else | 1207 | else |
1208 | config = MACB_BF(CLK, MACB_CLK_DIV64); | 1208 | config = MACB_BF(CLK, MACB_CLK_DIV64); |
1209 | macb_writel(bp, NCFGR, config); | 1209 | macb_writel(bp, NCFGR, config); |
1210 | 1210 | ||
1211 | macb_get_hwaddr(bp); | 1211 | macb_get_hwaddr(bp); |
1212 | pdata = pdev->dev.platform_data; | 1212 | pdata = pdev->dev.platform_data; |
1213 | 1213 | ||
1214 | if (pdata && pdata->is_rmii) | 1214 | if (pdata && pdata->is_rmii) |
1215 | #if defined(CONFIG_ARCH_AT91) | 1215 | #if defined(CONFIG_ARCH_AT91) |
1216 | macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) ); | 1216 | macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) ); |
1217 | #else | 1217 | #else |
1218 | macb_writel(bp, USRIO, 0); | 1218 | macb_writel(bp, USRIO, 0); |
1219 | #endif | 1219 | #endif |
1220 | else | 1220 | else |
1221 | #if defined(CONFIG_ARCH_AT91) | 1221 | #if defined(CONFIG_ARCH_AT91) |
1222 | macb_writel(bp, USRIO, MACB_BIT(CLKEN)); | 1222 | macb_writel(bp, USRIO, MACB_BIT(CLKEN)); |
1223 | #else | 1223 | #else |
1224 | macb_writel(bp, USRIO, MACB_BIT(MII)); | 1224 | macb_writel(bp, USRIO, MACB_BIT(MII)); |
1225 | #endif | 1225 | #endif |
1226 | 1226 | ||
1227 | bp->tx_pending = DEF_TX_RING_PENDING; | 1227 | bp->tx_pending = DEF_TX_RING_PENDING; |
1228 | 1228 | ||
1229 | err = register_netdev(dev); | 1229 | err = register_netdev(dev); |
1230 | if (err) { | 1230 | if (err) { |
1231 | dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); | 1231 | dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); |
1232 | goto err_out_free_irq; | 1232 | goto err_out_free_irq; |
1233 | } | 1233 | } |
1234 | 1234 | ||
1235 | if (macb_mii_init(bp) != 0) { | 1235 | if (macb_mii_init(bp) != 0) { |
1236 | goto err_out_unregister_netdev; | 1236 | goto err_out_unregister_netdev; |
1237 | } | 1237 | } |
1238 | 1238 | ||
1239 | platform_set_drvdata(pdev, dev); | 1239 | platform_set_drvdata(pdev, dev); |
1240 | 1240 | ||
1241 | printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d (%pM)\n", | 1241 | printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d (%pM)\n", |
1242 | dev->name, dev->base_addr, dev->irq, dev->dev_addr); | 1242 | dev->name, dev->base_addr, dev->irq, dev->dev_addr); |
1243 | 1243 | ||
1244 | phydev = bp->phy_dev; | 1244 | phydev = bp->phy_dev; |
1245 | printk(KERN_INFO "%s: attached PHY driver [%s] " | 1245 | printk(KERN_INFO "%s: attached PHY driver [%s] " |
1246 | "(mii_bus:phy_addr=%s, irq=%d)\n", dev->name, | 1246 | "(mii_bus:phy_addr=%s, irq=%d)\n", dev->name, |
1247 | phydev->drv->name, dev_name(&phydev->dev), phydev->irq); | 1247 | phydev->drv->name, dev_name(&phydev->dev), phydev->irq); |
1248 | 1248 | ||
1249 | return 0; | 1249 | return 0; |
1250 | 1250 | ||
1251 | err_out_unregister_netdev: | 1251 | err_out_unregister_netdev: |
1252 | unregister_netdev(dev); | 1252 | unregister_netdev(dev); |
1253 | err_out_free_irq: | 1253 | err_out_free_irq: |
1254 | free_irq(dev->irq, dev); | 1254 | free_irq(dev->irq, dev); |
1255 | err_out_iounmap: | 1255 | err_out_iounmap: |
1256 | iounmap(bp->regs); | 1256 | iounmap(bp->regs); |
1257 | err_out_disable_clocks: | 1257 | err_out_disable_clocks: |
1258 | #ifndef CONFIG_ARCH_AT91 | 1258 | #ifndef CONFIG_ARCH_AT91 |
1259 | clk_disable(bp->hclk); | 1259 | clk_disable(bp->hclk); |
1260 | clk_put(bp->hclk); | 1260 | clk_put(bp->hclk); |
1261 | #endif | 1261 | #endif |
1262 | clk_disable(bp->pclk); | 1262 | clk_disable(bp->pclk); |
1263 | #ifndef CONFIG_ARCH_AT91 | 1263 | #ifndef CONFIG_ARCH_AT91 |
1264 | err_out_put_pclk: | 1264 | err_out_put_pclk: |
1265 | #endif | 1265 | #endif |
1266 | clk_put(bp->pclk); | 1266 | clk_put(bp->pclk); |
1267 | err_out_free_dev: | 1267 | err_out_free_dev: |
1268 | free_netdev(dev); | 1268 | free_netdev(dev); |
1269 | err_out: | 1269 | err_out: |
1270 | platform_set_drvdata(pdev, NULL); | 1270 | platform_set_drvdata(pdev, NULL); |
1271 | return err; | 1271 | return err; |
1272 | } | 1272 | } |
1273 | 1273 | ||
1274 | static int __exit macb_remove(struct platform_device *pdev) | 1274 | static int __exit macb_remove(struct platform_device *pdev) |
1275 | { | 1275 | { |
1276 | struct net_device *dev; | 1276 | struct net_device *dev; |
1277 | struct macb *bp; | 1277 | struct macb *bp; |
1278 | 1278 | ||
1279 | dev = platform_get_drvdata(pdev); | 1279 | dev = platform_get_drvdata(pdev); |
1280 | 1280 | ||
1281 | if (dev) { | 1281 | if (dev) { |
1282 | bp = netdev_priv(dev); | 1282 | bp = netdev_priv(dev); |
1283 | if (bp->phy_dev) | 1283 | if (bp->phy_dev) |
1284 | phy_disconnect(bp->phy_dev); | 1284 | phy_disconnect(bp->phy_dev); |
1285 | mdiobus_unregister(bp->mii_bus); | 1285 | mdiobus_unregister(bp->mii_bus); |
1286 | kfree(bp->mii_bus->irq); | 1286 | kfree(bp->mii_bus->irq); |
1287 | mdiobus_free(bp->mii_bus); | 1287 | mdiobus_free(bp->mii_bus); |
1288 | unregister_netdev(dev); | 1288 | unregister_netdev(dev); |
1289 | free_irq(dev->irq, dev); | 1289 | free_irq(dev->irq, dev); |
1290 | iounmap(bp->regs); | 1290 | iounmap(bp->regs); |
1291 | #ifndef CONFIG_ARCH_AT91 | 1291 | #ifndef CONFIG_ARCH_AT91 |
1292 | clk_disable(bp->hclk); | 1292 | clk_disable(bp->hclk); |
1293 | clk_put(bp->hclk); | 1293 | clk_put(bp->hclk); |
1294 | #endif | 1294 | #endif |
1295 | clk_disable(bp->pclk); | 1295 | clk_disable(bp->pclk); |
1296 | clk_put(bp->pclk); | 1296 | clk_put(bp->pclk); |
1297 | free_netdev(dev); | 1297 | free_netdev(dev); |
1298 | platform_set_drvdata(pdev, NULL); | 1298 | platform_set_drvdata(pdev, NULL); |
1299 | } | 1299 | } |
1300 | 1300 | ||
1301 | return 0; | 1301 | return 0; |
1302 | } | 1302 | } |
1303 | 1303 | ||
1304 | #ifdef CONFIG_PM | 1304 | #ifdef CONFIG_PM |
1305 | static int macb_suspend(struct platform_device *pdev, pm_message_t state) | 1305 | static int macb_suspend(struct platform_device *pdev, pm_message_t state) |
1306 | { | 1306 | { |
1307 | struct net_device *netdev = platform_get_drvdata(pdev); | 1307 | struct net_device *netdev = platform_get_drvdata(pdev); |
1308 | struct macb *bp = netdev_priv(netdev); | 1308 | struct macb *bp = netdev_priv(netdev); |
1309 | 1309 | ||
1310 | netif_device_detach(netdev); | 1310 | netif_device_detach(netdev); |
1311 | 1311 | ||
1312 | #ifndef CONFIG_ARCH_AT91 | 1312 | #ifndef CONFIG_ARCH_AT91 |
1313 | clk_disable(bp->hclk); | 1313 | clk_disable(bp->hclk); |
1314 | #endif | 1314 | #endif |
1315 | clk_disable(bp->pclk); | 1315 | clk_disable(bp->pclk); |
1316 | 1316 | ||
1317 | return 0; | 1317 | return 0; |
1318 | } | 1318 | } |
1319 | 1319 | ||
1320 | static int macb_resume(struct platform_device *pdev) | 1320 | static int macb_resume(struct platform_device *pdev) |
1321 | { | 1321 | { |
1322 | struct net_device *netdev = platform_get_drvdata(pdev); | 1322 | struct net_device *netdev = platform_get_drvdata(pdev); |
1323 | struct macb *bp = netdev_priv(netdev); | 1323 | struct macb *bp = netdev_priv(netdev); |
1324 | 1324 | ||
1325 | clk_enable(bp->pclk); | 1325 | clk_enable(bp->pclk); |
1326 | #ifndef CONFIG_ARCH_AT91 | 1326 | #ifndef CONFIG_ARCH_AT91 |
1327 | clk_enable(bp->hclk); | 1327 | clk_enable(bp->hclk); |
1328 | #endif | 1328 | #endif |
1329 | 1329 | ||
1330 | netif_device_attach(netdev); | 1330 | netif_device_attach(netdev); |
1331 | 1331 | ||
1332 | return 0; | 1332 | return 0; |
1333 | } | 1333 | } |
1334 | #else | 1334 | #else |
1335 | #define macb_suspend NULL | 1335 | #define macb_suspend NULL |
1336 | #define macb_resume NULL | 1336 | #define macb_resume NULL |
1337 | #endif | 1337 | #endif |
1338 | 1338 | ||
1339 | static struct platform_driver macb_driver = { | 1339 | static struct platform_driver macb_driver = { |
1340 | .remove = __exit_p(macb_remove), | 1340 | .remove = __exit_p(macb_remove), |
1341 | .suspend = macb_suspend, | 1341 | .suspend = macb_suspend, |
1342 | .resume = macb_resume, | 1342 | .resume = macb_resume, |
1343 | .driver = { | 1343 | .driver = { |
1344 | .name = "macb", | 1344 | .name = "macb", |
1345 | .owner = THIS_MODULE, | 1345 | .owner = THIS_MODULE, |
1346 | }, | 1346 | }, |
1347 | }; | 1347 | }; |
1348 | 1348 | ||
1349 | static int __init macb_init(void) | 1349 | static int __init macb_init(void) |
1350 | { | 1350 | { |
1351 | return platform_driver_probe(&macb_driver, macb_probe); | 1351 | return platform_driver_probe(&macb_driver, macb_probe); |
1352 | } | 1352 | } |
1353 | 1353 | ||
1354 | static void __exit macb_exit(void) | 1354 | static void __exit macb_exit(void) |
1355 | { | 1355 | { |
1356 | platform_driver_unregister(&macb_driver); | 1356 | platform_driver_unregister(&macb_driver); |
1357 | } | 1357 | } |
1358 | 1358 | ||
1359 | module_init(macb_init); | 1359 | module_init(macb_init); |
1360 | module_exit(macb_exit); | 1360 | module_exit(macb_exit); |
1361 | 1361 | ||
1362 | MODULE_LICENSE("GPL"); | 1362 | MODULE_LICENSE("GPL"); |
1363 | MODULE_DESCRIPTION("Atmel MACB Ethernet driver"); | 1363 | MODULE_DESCRIPTION("Atmel MACB Ethernet driver"); |
1364 | MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>"); | 1364 | MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>"); |
1365 | MODULE_ALIAS("platform:macb"); | 1365 | MODULE_ALIAS("platform:macb"); |
1366 | 1366 |
drivers/net/wireless/ath/ath5k/reg.h
1 | /* | 1 | /* |
2 | * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> | 2 | * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> |
3 | * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> | 3 | * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> |
4 | * Copyright (c) 2007-2008 Michael Taylor <mike.taylor@apprion.com> | 4 | * Copyright (c) 2007-2008 Michael Taylor <mike.taylor@apprion.com> |
5 | * | 5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any | 6 | * Permission to use, copy, modify, and distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above | 7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. | 8 | * copyright notice and this permission notice appear in all copies. |
9 | * | 9 | * |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | * | 17 | * |
18 | */ | 18 | */ |
19 | 19 | ||
20 | /* | 20 | /* |
21 | * Register values for Atheros 5210/5211/5212 cards from OpenBSD's ar5k | 21 | * Register values for Atheros 5210/5211/5212 cards from OpenBSD's ar5k |
22 | * maintained by Reyk Floeter | 22 | * maintained by Reyk Floeter |
23 | * | 23 | * |
24 | * I tried to document those registers by looking at ar5k code, some | 24 | * I tried to document those registers by looking at ar5k code, some |
25 | * 802.11 (802.11e mostly) papers and by reading various public available | 25 | * 802.11 (802.11e mostly) papers and by reading various public available |
26 | * Atheros presentations and papers like these: | 26 | * Atheros presentations and papers like these: |
27 | * | 27 | * |
28 | * 5210 - http://nova.stanford.edu/~bbaas/ps/isscc2002_slides.pdf | 28 | * 5210 - http://nova.stanford.edu/~bbaas/ps/isscc2002_slides.pdf |
29 | * http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf | 29 | * http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf |
30 | * | 30 | * |
31 | * 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf | 31 | * 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf |
32 | * | 32 | * |
33 | * This file also contains register values found on a memory dump of | 33 | * This file also contains register values found on a memory dump of |
34 | * Atheros's ART program (Atheros Radio Test), on ath9k, on legacy-hal | 34 | * Atheros's ART program (Atheros Radio Test), on ath9k, on legacy-hal |
35 | * released by Atheros and on various debug messages found on the net. | 35 | * released by Atheros and on various debug messages found on the net. |
36 | */ | 36 | */ |
37 | 37 | ||
38 | 38 | ||
39 | 39 | ||
40 | /*====MAC DMA REGISTERS====*/ | 40 | /*====MAC DMA REGISTERS====*/ |
41 | 41 | ||
42 | /* | 42 | /* |
43 | * AR5210-Specific TXDP registers | 43 | * AR5210-Specific TXDP registers |
44 | * 5210 has only 2 transmit queues so no DCU/QCU, just | 44 | * 5210 has only 2 transmit queues so no DCU/QCU, just |
45 | * 2 transmit descriptor pointers... | 45 | * 2 transmit descriptor pointers... |
46 | */ | 46 | */ |
47 | #define AR5K_NOQCU_TXDP0 0x0000 /* Queue 0 - data */ | 47 | #define AR5K_NOQCU_TXDP0 0x0000 /* Queue 0 - data */ |
48 | #define AR5K_NOQCU_TXDP1 0x0004 /* Queue 1 - beacons */ | 48 | #define AR5K_NOQCU_TXDP1 0x0004 /* Queue 1 - beacons */ |
49 | 49 | ||
50 | /* | 50 | /* |
51 | * Mac Control Register | 51 | * Mac Control Register |
52 | */ | 52 | */ |
53 | #define AR5K_CR 0x0008 /* Register Address */ | 53 | #define AR5K_CR 0x0008 /* Register Address */ |
54 | #define AR5K_CR_TXE0 0x00000001 /* TX Enable for queue 0 on 5210 */ | 54 | #define AR5K_CR_TXE0 0x00000001 /* TX Enable for queue 0 on 5210 */ |
55 | #define AR5K_CR_TXE1 0x00000002 /* TX Enable for queue 1 on 5210 */ | 55 | #define AR5K_CR_TXE1 0x00000002 /* TX Enable for queue 1 on 5210 */ |
56 | #define AR5K_CR_RXE 0x00000004 /* RX Enable */ | 56 | #define AR5K_CR_RXE 0x00000004 /* RX Enable */ |
57 | #define AR5K_CR_TXD0 0x00000008 /* TX Disable for queue 0 on 5210 */ | 57 | #define AR5K_CR_TXD0 0x00000008 /* TX Disable for queue 0 on 5210 */ |
58 | #define AR5K_CR_TXD1 0x00000010 /* TX Disable for queue 1 on 5210 */ | 58 | #define AR5K_CR_TXD1 0x00000010 /* TX Disable for queue 1 on 5210 */ |
59 | #define AR5K_CR_RXD 0x00000020 /* RX Disable */ | 59 | #define AR5K_CR_RXD 0x00000020 /* RX Disable */ |
60 | #define AR5K_CR_SWI 0x00000040 /* Software Interrupt */ | 60 | #define AR5K_CR_SWI 0x00000040 /* Software Interrupt */ |
61 | 61 | ||
62 | /* | 62 | /* |
63 | * RX Descriptor Pointer register | 63 | * RX Descriptor Pointer register |
64 | */ | 64 | */ |
65 | #define AR5K_RXDP 0x000c | 65 | #define AR5K_RXDP 0x000c |
66 | 66 | ||
67 | /* | 67 | /* |
68 | * Configuration and status register | 68 | * Configuration and status register |
69 | */ | 69 | */ |
70 | #define AR5K_CFG 0x0014 /* Register Address */ | 70 | #define AR5K_CFG 0x0014 /* Register Address */ |
71 | #define AR5K_CFG_SWTD 0x00000001 /* Byte-swap TX descriptor (for big endian archs) */ | 71 | #define AR5K_CFG_SWTD 0x00000001 /* Byte-swap TX descriptor (for big endian archs) */ |
72 | #define AR5K_CFG_SWTB 0x00000002 /* Byte-swap TX buffer */ | 72 | #define AR5K_CFG_SWTB 0x00000002 /* Byte-swap TX buffer */ |
73 | #define AR5K_CFG_SWRD 0x00000004 /* Byte-swap RX descriptor */ | 73 | #define AR5K_CFG_SWRD 0x00000004 /* Byte-swap RX descriptor */ |
74 | #define AR5K_CFG_SWRB 0x00000008 /* Byte-swap RX buffer */ | 74 | #define AR5K_CFG_SWRB 0x00000008 /* Byte-swap RX buffer */ |
75 | #define AR5K_CFG_SWRG 0x00000010 /* Byte-swap Register access */ | 75 | #define AR5K_CFG_SWRG 0x00000010 /* Byte-swap Register access */ |
76 | #define AR5K_CFG_IBSS 0x00000020 /* 0-BSS, 1-IBSS [5211+] */ | 76 | #define AR5K_CFG_IBSS 0x00000020 /* 0-BSS, 1-IBSS [5211+] */ |
77 | #define AR5K_CFG_PHY_OK 0x00000100 /* [5211+] */ | 77 | #define AR5K_CFG_PHY_OK 0x00000100 /* [5211+] */ |
78 | #define AR5K_CFG_EEBS 0x00000200 /* EEPROM is busy */ | 78 | #define AR5K_CFG_EEBS 0x00000200 /* EEPROM is busy */ |
79 | #define AR5K_CFG_CLKGD 0x00000400 /* Clock gated (Disable dynamic clock) */ | 79 | #define AR5K_CFG_CLKGD 0x00000400 /* Clock gated (Disable dynamic clock) */ |
80 | #define AR5K_CFG_TXCNT 0x00007800 /* Tx frame count (?) [5210] */ | 80 | #define AR5K_CFG_TXCNT 0x00007800 /* Tx frame count (?) [5210] */ |
81 | #define AR5K_CFG_TXCNT_S 11 | 81 | #define AR5K_CFG_TXCNT_S 11 |
82 | #define AR5K_CFG_TXFSTAT 0x00008000 /* Tx frame status (?) [5210] */ | 82 | #define AR5K_CFG_TXFSTAT 0x00008000 /* Tx frame status (?) [5210] */ |
83 | #define AR5K_CFG_TXFSTRT 0x00010000 /* [5210] */ | 83 | #define AR5K_CFG_TXFSTRT 0x00010000 /* [5210] */ |
84 | #define AR5K_CFG_PCI_THRES 0x00060000 /* PCI Master req q threshold [5211+] */ | 84 | #define AR5K_CFG_PCI_THRES 0x00060000 /* PCI Master req q threshold [5211+] */ |
85 | #define AR5K_CFG_PCI_THRES_S 17 | 85 | #define AR5K_CFG_PCI_THRES_S 17 |
86 | 86 | ||
87 | /* | 87 | /* |
88 | * Interrupt enable register | 88 | * Interrupt enable register |
89 | */ | 89 | */ |
90 | #define AR5K_IER 0x0024 /* Register Address */ | 90 | #define AR5K_IER 0x0024 /* Register Address */ |
91 | #define AR5K_IER_DISABLE 0x00000000 /* Disable card interrupts */ | 91 | #define AR5K_IER_DISABLE 0x00000000 /* Disable card interrupts */ |
92 | #define AR5K_IER_ENABLE 0x00000001 /* Enable card interrupts */ | 92 | #define AR5K_IER_ENABLE 0x00000001 /* Enable card interrupts */ |
93 | 93 | ||
94 | 94 | ||
95 | /* | 95 | /* |
96 | * 0x0028 is Beacon Control Register on 5210 | 96 | * 0x0028 is Beacon Control Register on 5210 |
97 | * and first RTS duration register on 5211 | 97 | * and first RTS duration register on 5211 |
98 | */ | 98 | */ |
99 | 99 | ||
100 | /* | 100 | /* |
101 | * Beacon control register [5210] | 101 | * Beacon control register [5210] |
102 | */ | 102 | */ |
103 | #define AR5K_BCR 0x0028 /* Register Address */ | 103 | #define AR5K_BCR 0x0028 /* Register Address */ |
104 | #define AR5K_BCR_AP 0x00000000 /* AP mode */ | 104 | #define AR5K_BCR_AP 0x00000000 /* AP mode */ |
105 | #define AR5K_BCR_ADHOC 0x00000001 /* Ad-Hoc mode */ | 105 | #define AR5K_BCR_ADHOC 0x00000001 /* Ad-Hoc mode */ |
106 | #define AR5K_BCR_BDMAE 0x00000002 /* DMA enable */ | 106 | #define AR5K_BCR_BDMAE 0x00000002 /* DMA enable */ |
107 | #define AR5K_BCR_TQ1FV 0x00000004 /* Use Queue1 for CAB traffic */ | 107 | #define AR5K_BCR_TQ1FV 0x00000004 /* Use Queue1 for CAB traffic */ |
108 | #define AR5K_BCR_TQ1V 0x00000008 /* Use Queue1 for Beacon traffic */ | 108 | #define AR5K_BCR_TQ1V 0x00000008 /* Use Queue1 for Beacon traffic */ |
109 | #define AR5K_BCR_BCGET 0x00000010 | 109 | #define AR5K_BCR_BCGET 0x00000010 |
110 | 110 | ||
111 | /* | 111 | /* |
112 | * First RTS duration register [5211] | 112 | * First RTS duration register [5211] |
113 | */ | 113 | */ |
114 | #define AR5K_RTSD0 0x0028 /* Register Address */ | 114 | #define AR5K_RTSD0 0x0028 /* Register Address */ |
115 | #define AR5K_RTSD0_6 0x000000ff /* 6Mb RTS duration mask (?) */ | 115 | #define AR5K_RTSD0_6 0x000000ff /* 6Mb RTS duration mask (?) */ |
116 | #define AR5K_RTSD0_6_S 0 /* 6Mb RTS duration shift (?) */ | 116 | #define AR5K_RTSD0_6_S 0 /* 6Mb RTS duration shift (?) */ |
117 | #define AR5K_RTSD0_9 0x0000ff00 /* 9Mb*/ | 117 | #define AR5K_RTSD0_9 0x0000ff00 /* 9Mb*/ |
118 | #define AR5K_RTSD0_9_S 8 | 118 | #define AR5K_RTSD0_9_S 8 |
119 | #define AR5K_RTSD0_12 0x00ff0000 /* 12Mb*/ | 119 | #define AR5K_RTSD0_12 0x00ff0000 /* 12Mb*/ |
120 | #define AR5K_RTSD0_12_S 16 | 120 | #define AR5K_RTSD0_12_S 16 |
121 | #define AR5K_RTSD0_18 0xff000000 /* 16Mb*/ | 121 | #define AR5K_RTSD0_18 0xff000000 /* 16Mb*/ |
122 | #define AR5K_RTSD0_18_S 24 | 122 | #define AR5K_RTSD0_18_S 24 |
123 | 123 | ||
124 | 124 | ||
125 | /* | 125 | /* |
126 | * 0x002c is Beacon Status Register on 5210 | 126 | * 0x002c is Beacon Status Register on 5210 |
127 | * and second RTS duration register on 5211 | 127 | * and second RTS duration register on 5211 |
128 | */ | 128 | */ |
129 | 129 | ||
130 | /* | 130 | /* |
131 | * Beacon status register [5210] | 131 | * Beacon status register [5210] |
132 | * | 132 | * |
133 | * As i can see in ar5k_ar5210_tx_start Reyk uses some of the values of BCR | 133 | * As i can see in ar5k_ar5210_tx_start Reyk uses some of the values of BCR |
134 | * for this register, so i guess TQ1V,TQ1FV and BDMAE have the same meaning | 134 | * for this register, so i guess TQ1V,TQ1FV and BDMAE have the same meaning |
135 | * here and SNP/SNAP means "snapshot" (so this register gets synced with BCR). | 135 | * here and SNP/SNAP means "snapshot" (so this register gets synced with BCR). |
136 | * So SNAPPEDBCRVALID sould also stand for "snapped BCR -values- valid", so i | 136 | * So SNAPPEDBCRVALID sould also stand for "snapped BCR -values- valid", so i |
137 | * renamed it to SNAPSHOTSVALID to make more sense. I realy have no idea what | 137 | * renamed it to SNAPSHOTSVALID to make more sense. I realy have no idea what |
138 | * else can it be. I also renamed SNPBCMD to SNPADHOC to match BCR. | 138 | * else can it be. I also renamed SNPBCMD to SNPADHOC to match BCR. |
139 | */ | 139 | */ |
140 | #define AR5K_BSR 0x002c /* Register Address */ | 140 | #define AR5K_BSR 0x002c /* Register Address */ |
141 | #define AR5K_BSR_BDLYSW 0x00000001 /* SW Beacon delay (?) */ | 141 | #define AR5K_BSR_BDLYSW 0x00000001 /* SW Beacon delay (?) */ |
142 | #define AR5K_BSR_BDLYDMA 0x00000002 /* DMA Beacon delay (?) */ | 142 | #define AR5K_BSR_BDLYDMA 0x00000002 /* DMA Beacon delay (?) */ |
143 | #define AR5K_BSR_TXQ1F 0x00000004 /* Beacon queue (1) finished */ | 143 | #define AR5K_BSR_TXQ1F 0x00000004 /* Beacon queue (1) finished */ |
144 | #define AR5K_BSR_ATIMDLY 0x00000008 /* ATIM delay (?) */ | 144 | #define AR5K_BSR_ATIMDLY 0x00000008 /* ATIM delay (?) */ |
145 | #define AR5K_BSR_SNPADHOC 0x00000100 /* Ad-hoc mode set (?) */ | 145 | #define AR5K_BSR_SNPADHOC 0x00000100 /* Ad-hoc mode set (?) */ |
146 | #define AR5K_BSR_SNPBDMAE 0x00000200 /* Beacon DMA enabled (?) */ | 146 | #define AR5K_BSR_SNPBDMAE 0x00000200 /* Beacon DMA enabled (?) */ |
147 | #define AR5K_BSR_SNPTQ1FV 0x00000400 /* Queue1 is used for CAB traffic (?) */ | 147 | #define AR5K_BSR_SNPTQ1FV 0x00000400 /* Queue1 is used for CAB traffic (?) */ |
148 | #define AR5K_BSR_SNPTQ1V 0x00000800 /* Queue1 is used for Beacon traffic (?) */ | 148 | #define AR5K_BSR_SNPTQ1V 0x00000800 /* Queue1 is used for Beacon traffic (?) */ |
149 | #define AR5K_BSR_SNAPSHOTSVALID 0x00001000 /* BCR snapshots are valid (?) */ | 149 | #define AR5K_BSR_SNAPSHOTSVALID 0x00001000 /* BCR snapshots are valid (?) */ |
150 | #define AR5K_BSR_SWBA_CNT 0x00ff0000 | 150 | #define AR5K_BSR_SWBA_CNT 0x00ff0000 |
151 | 151 | ||
152 | /* | 152 | /* |
153 | * Second RTS duration register [5211] | 153 | * Second RTS duration register [5211] |
154 | */ | 154 | */ |
155 | #define AR5K_RTSD1 0x002c /* Register Address */ | 155 | #define AR5K_RTSD1 0x002c /* Register Address */ |
156 | #define AR5K_RTSD1_24 0x000000ff /* 24Mb */ | 156 | #define AR5K_RTSD1_24 0x000000ff /* 24Mb */ |
157 | #define AR5K_RTSD1_24_S 0 | 157 | #define AR5K_RTSD1_24_S 0 |
158 | #define AR5K_RTSD1_36 0x0000ff00 /* 36Mb */ | 158 | #define AR5K_RTSD1_36 0x0000ff00 /* 36Mb */ |
159 | #define AR5K_RTSD1_36_S 8 | 159 | #define AR5K_RTSD1_36_S 8 |
160 | #define AR5K_RTSD1_48 0x00ff0000 /* 48Mb */ | 160 | #define AR5K_RTSD1_48 0x00ff0000 /* 48Mb */ |
161 | #define AR5K_RTSD1_48_S 16 | 161 | #define AR5K_RTSD1_48_S 16 |
162 | #define AR5K_RTSD1_54 0xff000000 /* 54Mb */ | 162 | #define AR5K_RTSD1_54 0xff000000 /* 54Mb */ |
163 | #define AR5K_RTSD1_54_S 24 | 163 | #define AR5K_RTSD1_54_S 24 |
164 | 164 | ||
165 | 165 | ||
166 | /* | 166 | /* |
167 | * Transmit configuration register | 167 | * Transmit configuration register |
168 | */ | 168 | */ |
169 | #define AR5K_TXCFG 0x0030 /* Register Address */ | 169 | #define AR5K_TXCFG 0x0030 /* Register Address */ |
170 | #define AR5K_TXCFG_SDMAMR 0x00000007 /* DMA size (read) */ | 170 | #define AR5K_TXCFG_SDMAMR 0x00000007 /* DMA size (read) */ |
171 | #define AR5K_TXCFG_SDMAMR_S 0 | 171 | #define AR5K_TXCFG_SDMAMR_S 0 |
172 | #define AR5K_TXCFG_B_MODE 0x00000008 /* Set b mode for 5111 (enable 2111) */ | 172 | #define AR5K_TXCFG_B_MODE 0x00000008 /* Set b mode for 5111 (enable 2111) */ |
173 | #define AR5K_TXCFG_TXFSTP 0x00000008 /* TX DMA full Stop [5210] */ | 173 | #define AR5K_TXCFG_TXFSTP 0x00000008 /* TX DMA full Stop [5210] */ |
174 | #define AR5K_TXCFG_TXFULL 0x000003f0 /* TX Triger level mask */ | 174 | #define AR5K_TXCFG_TXFULL 0x000003f0 /* TX Triger level mask */ |
175 | #define AR5K_TXCFG_TXFULL_S 4 | 175 | #define AR5K_TXCFG_TXFULL_S 4 |
176 | #define AR5K_TXCFG_TXFULL_0B 0x00000000 | 176 | #define AR5K_TXCFG_TXFULL_0B 0x00000000 |
177 | #define AR5K_TXCFG_TXFULL_64B 0x00000010 | 177 | #define AR5K_TXCFG_TXFULL_64B 0x00000010 |
178 | #define AR5K_TXCFG_TXFULL_128B 0x00000020 | 178 | #define AR5K_TXCFG_TXFULL_128B 0x00000020 |
179 | #define AR5K_TXCFG_TXFULL_192B 0x00000030 | 179 | #define AR5K_TXCFG_TXFULL_192B 0x00000030 |
180 | #define AR5K_TXCFG_TXFULL_256B 0x00000040 | 180 | #define AR5K_TXCFG_TXFULL_256B 0x00000040 |
181 | #define AR5K_TXCFG_TXCONT_EN 0x00000080 | 181 | #define AR5K_TXCFG_TXCONT_EN 0x00000080 |
182 | #define AR5K_TXCFG_DMASIZE 0x00000100 /* Flag for passing DMA size [5210] */ | 182 | #define AR5K_TXCFG_DMASIZE 0x00000100 /* Flag for passing DMA size [5210] */ |
183 | #define AR5K_TXCFG_JUMBO_DESC_EN 0x00000400 /* Enable jumbo tx descriptors [5211+] */ | 183 | #define AR5K_TXCFG_JUMBO_DESC_EN 0x00000400 /* Enable jumbo tx descriptors [5211+] */ |
184 | #define AR5K_TXCFG_ADHOC_BCN_ATIM 0x00000800 /* Adhoc Beacon ATIM Policy */ | 184 | #define AR5K_TXCFG_ADHOC_BCN_ATIM 0x00000800 /* Adhoc Beacon ATIM Policy */ |
185 | #define AR5K_TXCFG_ATIM_WINDOW_DEF_DIS 0x00001000 /* Disable ATIM window defer [5211+] */ | 185 | #define AR5K_TXCFG_ATIM_WINDOW_DEF_DIS 0x00001000 /* Disable ATIM window defer [5211+] */ |
186 | #define AR5K_TXCFG_RTSRND 0x00001000 /* [5211+] */ | 186 | #define AR5K_TXCFG_RTSRND 0x00001000 /* [5211+] */ |
187 | #define AR5K_TXCFG_FRMPAD_DIS 0x00002000 /* [5211+] */ | 187 | #define AR5K_TXCFG_FRMPAD_DIS 0x00002000 /* [5211+] */ |
188 | #define AR5K_TXCFG_RDY_CBR_DIS 0x00004000 /* Ready time CBR disable [5211+] */ | 188 | #define AR5K_TXCFG_RDY_CBR_DIS 0x00004000 /* Ready time CBR disable [5211+] */ |
189 | #define AR5K_TXCFG_JUMBO_FRM_MODE 0x00008000 /* Jumbo frame mode [5211+] */ | 189 | #define AR5K_TXCFG_JUMBO_FRM_MODE 0x00008000 /* Jumbo frame mode [5211+] */ |
190 | #define AR5K_TXCFG_DCU_DBL_BUF_DIS 0x00008000 /* Disable double buffering on DCU */ | 190 | #define AR5K_TXCFG_DCU_DBL_BUF_DIS 0x00008000 /* Disable double buffering on DCU */ |
191 | #define AR5K_TXCFG_DCU_CACHING_DIS 0x00010000 /* Disable DCU caching */ | 191 | #define AR5K_TXCFG_DCU_CACHING_DIS 0x00010000 /* Disable DCU caching */ |
192 | 192 | ||
193 | /* | 193 | /* |
194 | * Receive configuration register | 194 | * Receive configuration register |
195 | */ | 195 | */ |
196 | #define AR5K_RXCFG 0x0034 /* Register Address */ | 196 | #define AR5K_RXCFG 0x0034 /* Register Address */ |
197 | #define AR5K_RXCFG_SDMAMW 0x00000007 /* DMA size (write) */ | 197 | #define AR5K_RXCFG_SDMAMW 0x00000007 /* DMA size (write) */ |
198 | #define AR5K_RXCFG_SDMAMW_S 0 | 198 | #define AR5K_RXCFG_SDMAMW_S 0 |
199 | #define AR5K_RXCFG_ZLFDMA 0x00000008 /* Enable Zero-length frame DMA */ | 199 | #define AR5K_RXCFG_ZLFDMA 0x00000008 /* Enable Zero-length frame DMA */ |
200 | #define AR5K_RXCFG_DEF_ANTENNA 0x00000010 /* Default antenna (?) */ | 200 | #define AR5K_RXCFG_DEF_ANTENNA 0x00000010 /* Default antenna (?) */ |
201 | #define AR5K_RXCFG_JUMBO_RXE 0x00000020 /* Enable jumbo rx descriptors [5211+] */ | 201 | #define AR5K_RXCFG_JUMBO_RXE 0x00000020 /* Enable jumbo rx descriptors [5211+] */ |
202 | #define AR5K_RXCFG_JUMBO_WRAP 0x00000040 /* Wrap jumbo frames [5211+] */ | 202 | #define AR5K_RXCFG_JUMBO_WRAP 0x00000040 /* Wrap jumbo frames [5211+] */ |
203 | #define AR5K_RXCFG_SLE_ENTRY 0x00000080 /* Sleep entry policy */ | 203 | #define AR5K_RXCFG_SLE_ENTRY 0x00000080 /* Sleep entry policy */ |
204 | 204 | ||
205 | /* | 205 | /* |
206 | * Receive jumbo descriptor last address register | 206 | * Receive jumbo descriptor last address register |
207 | * Only found in 5211 (?) | 207 | * Only found in 5211 (?) |
208 | */ | 208 | */ |
209 | #define AR5K_RXJLA 0x0038 | 209 | #define AR5K_RXJLA 0x0038 |
210 | 210 | ||
211 | /* | 211 | /* |
212 | * MIB control register | 212 | * MIB control register |
213 | */ | 213 | */ |
214 | #define AR5K_MIBC 0x0040 /* Register Address */ | 214 | #define AR5K_MIBC 0x0040 /* Register Address */ |
215 | #define AR5K_MIBC_COW 0x00000001 /* Warn test indicator */ | 215 | #define AR5K_MIBC_COW 0x00000001 /* Warn test indicator */ |
216 | #define AR5K_MIBC_FMC 0x00000002 /* Freeze MIB Counters */ | 216 | #define AR5K_MIBC_FMC 0x00000002 /* Freeze MIB Counters */ |
217 | #define AR5K_MIBC_CMC 0x00000004 /* Clean MIB Counters */ | 217 | #define AR5K_MIBC_CMC 0x00000004 /* Clean MIB Counters */ |
218 | #define AR5K_MIBC_MCS 0x00000008 /* MIB counter strobe */ | 218 | #define AR5K_MIBC_MCS 0x00000008 /* MIB counter strobe */ |
219 | 219 | ||
220 | /* | 220 | /* |
221 | * Timeout prescale register | 221 | * Timeout prescale register |
222 | */ | 222 | */ |
223 | #define AR5K_TOPS 0x0044 | 223 | #define AR5K_TOPS 0x0044 |
224 | #define AR5K_TOPS_M 0x0000ffff | 224 | #define AR5K_TOPS_M 0x0000ffff |
225 | 225 | ||
226 | /* | 226 | /* |
227 | * Receive timeout register (no frame received) | 227 | * Receive timeout register (no frame received) |
228 | */ | 228 | */ |
229 | #define AR5K_RXNOFRM 0x0048 | 229 | #define AR5K_RXNOFRM 0x0048 |
230 | #define AR5K_RXNOFRM_M 0x000003ff | 230 | #define AR5K_RXNOFRM_M 0x000003ff |
231 | 231 | ||
232 | /* | 232 | /* |
233 | * Transmit timeout register (no frame sent) | 233 | * Transmit timeout register (no frame sent) |
234 | */ | 234 | */ |
235 | #define AR5K_TXNOFRM 0x004c | 235 | #define AR5K_TXNOFRM 0x004c |
236 | #define AR5K_TXNOFRM_M 0x000003ff | 236 | #define AR5K_TXNOFRM_M 0x000003ff |
237 | #define AR5K_TXNOFRM_QCU 0x000ffc00 | 237 | #define AR5K_TXNOFRM_QCU 0x000ffc00 |
238 | #define AR5K_TXNOFRM_QCU_S 10 | 238 | #define AR5K_TXNOFRM_QCU_S 10 |
239 | 239 | ||
240 | /* | 240 | /* |
241 | * Receive frame gap timeout register | 241 | * Receive frame gap timeout register |
242 | */ | 242 | */ |
243 | #define AR5K_RPGTO 0x0050 | 243 | #define AR5K_RPGTO 0x0050 |
244 | #define AR5K_RPGTO_M 0x000003ff | 244 | #define AR5K_RPGTO_M 0x000003ff |
245 | 245 | ||
246 | /* | 246 | /* |
247 | * Receive frame count limit register | 247 | * Receive frame count limit register |
248 | */ | 248 | */ |
249 | #define AR5K_RFCNT 0x0054 | 249 | #define AR5K_RFCNT 0x0054 |
250 | #define AR5K_RFCNT_M 0x0000001f /* [5211+] (?) */ | 250 | #define AR5K_RFCNT_M 0x0000001f /* [5211+] (?) */ |
251 | #define AR5K_RFCNT_RFCL 0x0000000f /* [5210] */ | 251 | #define AR5K_RFCNT_RFCL 0x0000000f /* [5210] */ |
252 | 252 | ||
253 | /* | 253 | /* |
254 | * Misc settings register | 254 | * Misc settings register |
255 | * (reserved0-3) | 255 | * (reserved0-3) |
256 | */ | 256 | */ |
257 | #define AR5K_MISC 0x0058 /* Register Address */ | 257 | #define AR5K_MISC 0x0058 /* Register Address */ |
258 | #define AR5K_MISC_DMA_OBS_M 0x000001e0 | 258 | #define AR5K_MISC_DMA_OBS_M 0x000001e0 |
259 | #define AR5K_MISC_DMA_OBS_S 5 | 259 | #define AR5K_MISC_DMA_OBS_S 5 |
260 | #define AR5K_MISC_MISC_OBS_M 0x00000e00 | 260 | #define AR5K_MISC_MISC_OBS_M 0x00000e00 |
261 | #define AR5K_MISC_MISC_OBS_S 9 | 261 | #define AR5K_MISC_MISC_OBS_S 9 |
262 | #define AR5K_MISC_MAC_OBS_LSB_M 0x00007000 | 262 | #define AR5K_MISC_MAC_OBS_LSB_M 0x00007000 |
263 | #define AR5K_MISC_MAC_OBS_LSB_S 12 | 263 | #define AR5K_MISC_MAC_OBS_LSB_S 12 |
264 | #define AR5K_MISC_MAC_OBS_MSB_M 0x00038000 | 264 | #define AR5K_MISC_MAC_OBS_MSB_M 0x00038000 |
265 | #define AR5K_MISC_MAC_OBS_MSB_S 15 | 265 | #define AR5K_MISC_MAC_OBS_MSB_S 15 |
266 | #define AR5K_MISC_LED_DECAY 0x001c0000 /* [5210] */ | 266 | #define AR5K_MISC_LED_DECAY 0x001c0000 /* [5210] */ |
267 | #define AR5K_MISC_LED_BLINK 0x00e00000 /* [5210] */ | 267 | #define AR5K_MISC_LED_BLINK 0x00e00000 /* [5210] */ |
268 | 268 | ||
269 | /* | 269 | /* |
270 | * QCU/DCU clock gating register (5311) | 270 | * QCU/DCU clock gating register (5311) |
271 | * (reserved4-5) | 271 | * (reserved4-5) |
272 | */ | 272 | */ |
273 | #define AR5K_QCUDCU_CLKGT 0x005c /* Register Address (?) */ | 273 | #define AR5K_QCUDCU_CLKGT 0x005c /* Register Address (?) */ |
274 | #define AR5K_QCUDCU_CLKGT_QCU 0x0000ffff /* Mask for QCU clock */ | 274 | #define AR5K_QCUDCU_CLKGT_QCU 0x0000ffff /* Mask for QCU clock */ |
275 | #define AR5K_QCUDCU_CLKGT_DCU 0x07ff0000 /* Mask for DCU clock */ | 275 | #define AR5K_QCUDCU_CLKGT_DCU 0x07ff0000 /* Mask for DCU clock */ |
276 | 276 | ||
277 | /* | 277 | /* |
278 | * Interrupt Status Registers | 278 | * Interrupt Status Registers |
279 | * | 279 | * |
280 | * For 5210 there is only one status register but for | 280 | * For 5210 there is only one status register but for |
281 | * 5211/5212 we have one primary and 4 secondary registers. | 281 | * 5211/5212 we have one primary and 4 secondary registers. |
282 | * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212. | 282 | * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212. |
283 | * Most of these bits are common for all chipsets. | 283 | * Most of these bits are common for all chipsets. |
284 | */ | 284 | */ |
285 | #define AR5K_ISR 0x001c /* Register Address [5210] */ | 285 | #define AR5K_ISR 0x001c /* Register Address [5210] */ |
286 | #define AR5K_PISR 0x0080 /* Register Address [5211+] */ | 286 | #define AR5K_PISR 0x0080 /* Register Address [5211+] */ |
287 | #define AR5K_ISR_RXOK 0x00000001 /* Frame successfuly recieved */ | 287 | #define AR5K_ISR_RXOK 0x00000001 /* Frame successfuly recieved */ |
288 | #define AR5K_ISR_RXDESC 0x00000002 /* RX descriptor request */ | 288 | #define AR5K_ISR_RXDESC 0x00000002 /* RX descriptor request */ |
289 | #define AR5K_ISR_RXERR 0x00000004 /* Receive error */ | 289 | #define AR5K_ISR_RXERR 0x00000004 /* Receive error */ |
290 | #define AR5K_ISR_RXNOFRM 0x00000008 /* No frame received (receive timeout) */ | 290 | #define AR5K_ISR_RXNOFRM 0x00000008 /* No frame received (receive timeout) */ |
291 | #define AR5K_ISR_RXEOL 0x00000010 /* Empty RX descriptor */ | 291 | #define AR5K_ISR_RXEOL 0x00000010 /* Empty RX descriptor */ |
292 | #define AR5K_ISR_RXORN 0x00000020 /* Receive FIFO overrun */ | 292 | #define AR5K_ISR_RXORN 0x00000020 /* Receive FIFO overrun */ |
293 | #define AR5K_ISR_TXOK 0x00000040 /* Frame successfuly transmited */ | 293 | #define AR5K_ISR_TXOK 0x00000040 /* Frame successfuly transmited */ |
294 | #define AR5K_ISR_TXDESC 0x00000080 /* TX descriptor request */ | 294 | #define AR5K_ISR_TXDESC 0x00000080 /* TX descriptor request */ |
295 | #define AR5K_ISR_TXERR 0x00000100 /* Transmit error */ | 295 | #define AR5K_ISR_TXERR 0x00000100 /* Transmit error */ |
296 | #define AR5K_ISR_TXNOFRM 0x00000200 /* No frame transmited (transmit timeout) */ | 296 | #define AR5K_ISR_TXNOFRM 0x00000200 /* No frame transmited (transmit timeout) */ |
297 | #define AR5K_ISR_TXEOL 0x00000400 /* Empty TX descriptor */ | 297 | #define AR5K_ISR_TXEOL 0x00000400 /* Empty TX descriptor */ |
298 | #define AR5K_ISR_TXURN 0x00000800 /* Transmit FIFO underrun */ | 298 | #define AR5K_ISR_TXURN 0x00000800 /* Transmit FIFO underrun */ |
299 | #define AR5K_ISR_MIB 0x00001000 /* Update MIB counters */ | 299 | #define AR5K_ISR_MIB 0x00001000 /* Update MIB counters */ |
300 | #define AR5K_ISR_SWI 0x00002000 /* Software interrupt */ | 300 | #define AR5K_ISR_SWI 0x00002000 /* Software interrupt */ |
301 | #define AR5K_ISR_RXPHY 0x00004000 /* PHY error */ | 301 | #define AR5K_ISR_RXPHY 0x00004000 /* PHY error */ |
302 | #define AR5K_ISR_RXKCM 0x00008000 /* RX Key cache miss */ | 302 | #define AR5K_ISR_RXKCM 0x00008000 /* RX Key cache miss */ |
303 | #define AR5K_ISR_SWBA 0x00010000 /* Software beacon alert */ | 303 | #define AR5K_ISR_SWBA 0x00010000 /* Software beacon alert */ |
304 | #define AR5K_ISR_BRSSI 0x00020000 /* Beacon rssi below threshold (?) */ | 304 | #define AR5K_ISR_BRSSI 0x00020000 /* Beacon rssi below threshold (?) */ |
305 | #define AR5K_ISR_BMISS 0x00040000 /* Beacon missed */ | 305 | #define AR5K_ISR_BMISS 0x00040000 /* Beacon missed */ |
306 | #define AR5K_ISR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ | 306 | #define AR5K_ISR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ |
307 | #define AR5K_ISR_BNR 0x00100000 /* Beacon not ready [5211+] */ | 307 | #define AR5K_ISR_BNR 0x00100000 /* Beacon not ready [5211+] */ |
308 | #define AR5K_ISR_MCABT 0x00100000 /* Master Cycle Abort [5210] */ | 308 | #define AR5K_ISR_MCABT 0x00100000 /* Master Cycle Abort [5210] */ |
309 | #define AR5K_ISR_RXCHIRP 0x00200000 /* CHIRP Received [5212+] */ | 309 | #define AR5K_ISR_RXCHIRP 0x00200000 /* CHIRP Received [5212+] */ |
310 | #define AR5K_ISR_SSERR 0x00200000 /* Signaled System Error [5210] */ | 310 | #define AR5K_ISR_SSERR 0x00200000 /* Signaled System Error [5210] */ |
311 | #define AR5K_ISR_DPERR 0x00400000 /* Det par Error (?) [5210] */ | 311 | #define AR5K_ISR_DPERR 0x00400000 /* Det par Error (?) [5210] */ |
312 | #define AR5K_ISR_RXDOPPLER 0x00400000 /* Doppler chirp received [5212+] */ | 312 | #define AR5K_ISR_RXDOPPLER 0x00400000 /* Doppler chirp received [5212+] */ |
313 | #define AR5K_ISR_TIM 0x00800000 /* [5211+] */ | 313 | #define AR5K_ISR_TIM 0x00800000 /* [5211+] */ |
314 | #define AR5K_ISR_BCNMISC 0x00800000 /* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT, | 314 | #define AR5K_ISR_BCNMISC 0x00800000 /* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT, |
315 | CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */ | 315 | CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */ |
316 | #define AR5K_ISR_GPIO 0x01000000 /* GPIO (rf kill) */ | 316 | #define AR5K_ISR_GPIO 0x01000000 /* GPIO (rf kill) */ |
317 | #define AR5K_ISR_QCBRORN 0x02000000 /* QCU CBR overrun [5211+] */ | 317 | #define AR5K_ISR_QCBRORN 0x02000000 /* QCU CBR overrun [5211+] */ |
318 | #define AR5K_ISR_QCBRURN 0x04000000 /* QCU CBR underrun [5211+] */ | 318 | #define AR5K_ISR_QCBRURN 0x04000000 /* QCU CBR underrun [5211+] */ |
319 | #define AR5K_ISR_QTRIG 0x08000000 /* QCU scheduling trigger [5211+] */ | 319 | #define AR5K_ISR_QTRIG 0x08000000 /* QCU scheduling trigger [5211+] */ |
320 | 320 | ||
321 | /* | 321 | /* |
322 | * Secondary status registers [5211+] (0 - 4) | 322 | * Secondary status registers [5211+] (0 - 4) |
323 | * | 323 | * |
324 | * These give the status for each QCU, only QCUs 0-9 are | 324 | * These give the status for each QCU, only QCUs 0-9 are |
325 | * represented. | 325 | * represented. |
326 | */ | 326 | */ |
327 | #define AR5K_SISR0 0x0084 /* Register Address [5211+] */ | 327 | #define AR5K_SISR0 0x0084 /* Register Address [5211+] */ |
328 | #define AR5K_SISR0_QCU_TXOK 0x000003ff /* Mask for QCU_TXOK */ | 328 | #define AR5K_SISR0_QCU_TXOK 0x000003ff /* Mask for QCU_TXOK */ |
329 | #define AR5K_SISR0_QCU_TXOK_S 0 | 329 | #define AR5K_SISR0_QCU_TXOK_S 0 |
330 | #define AR5K_SISR0_QCU_TXDESC 0x03ff0000 /* Mask for QCU_TXDESC */ | 330 | #define AR5K_SISR0_QCU_TXDESC 0x03ff0000 /* Mask for QCU_TXDESC */ |
331 | #define AR5K_SISR0_QCU_TXDESC_S 16 | 331 | #define AR5K_SISR0_QCU_TXDESC_S 16 |
332 | 332 | ||
333 | #define AR5K_SISR1 0x0088 /* Register Address [5211+] */ | 333 | #define AR5K_SISR1 0x0088 /* Register Address [5211+] */ |
334 | #define AR5K_SISR1_QCU_TXERR 0x000003ff /* Mask for QCU_TXERR */ | 334 | #define AR5K_SISR1_QCU_TXERR 0x000003ff /* Mask for QCU_TXERR */ |
335 | #define AR5K_SISR1_QCU_TXERR_S 0 | 335 | #define AR5K_SISR1_QCU_TXERR_S 0 |
336 | #define AR5K_SISR1_QCU_TXEOL 0x03ff0000 /* Mask for QCU_TXEOL */ | 336 | #define AR5K_SISR1_QCU_TXEOL 0x03ff0000 /* Mask for QCU_TXEOL */ |
337 | #define AR5K_SISR1_QCU_TXEOL_S 16 | 337 | #define AR5K_SISR1_QCU_TXEOL_S 16 |
338 | 338 | ||
339 | #define AR5K_SISR2 0x008c /* Register Address [5211+] */ | 339 | #define AR5K_SISR2 0x008c /* Register Address [5211+] */ |
340 | #define AR5K_SISR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ | 340 | #define AR5K_SISR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ |
341 | #define AR5K_SISR2_QCU_TXURN_S 0 | 341 | #define AR5K_SISR2_QCU_TXURN_S 0 |
342 | #define AR5K_SISR2_MCABT 0x00010000 /* Master Cycle Abort */ | 342 | #define AR5K_SISR2_MCABT 0x00010000 /* Master Cycle Abort */ |
343 | #define AR5K_SISR2_SSERR 0x00020000 /* Signaled System Error */ | 343 | #define AR5K_SISR2_SSERR 0x00020000 /* Signaled System Error */ |
344 | #define AR5K_SISR2_DPERR 0x00040000 /* Bus parity error */ | 344 | #define AR5K_SISR2_DPERR 0x00040000 /* Bus parity error */ |
345 | #define AR5K_SISR2_TIM 0x01000000 /* [5212+] */ | 345 | #define AR5K_SISR2_TIM 0x01000000 /* [5212+] */ |
346 | #define AR5K_SISR2_CAB_END 0x02000000 /* [5212+] */ | 346 | #define AR5K_SISR2_CAB_END 0x02000000 /* [5212+] */ |
347 | #define AR5K_SISR2_DTIM_SYNC 0x04000000 /* DTIM sync lost [5212+] */ | 347 | #define AR5K_SISR2_DTIM_SYNC 0x04000000 /* DTIM sync lost [5212+] */ |
348 | #define AR5K_SISR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */ | 348 | #define AR5K_SISR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */ |
349 | #define AR5K_SISR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */ | 349 | #define AR5K_SISR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */ |
350 | #define AR5K_SISR2_DTIM 0x20000000 /* [5212+] */ | 350 | #define AR5K_SISR2_DTIM 0x20000000 /* [5212+] */ |
351 | #define AR5K_SISR2_TSFOOR 0x80000000 /* TSF OOR (?) */ | 351 | #define AR5K_SISR2_TSFOOR 0x80000000 /* TSF OOR (?) */ |
352 | 352 | ||
353 | #define AR5K_SISR3 0x0090 /* Register Address [5211+] */ | 353 | #define AR5K_SISR3 0x0090 /* Register Address [5211+] */ |
354 | #define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ | 354 | #define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ |
355 | #define AR5K_SISR3_QCBRORN_S 0 | 355 | #define AR5K_SISR3_QCBRORN_S 0 |
356 | #define AR5K_SISR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ | 356 | #define AR5K_SISR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ |
357 | #define AR5K_SISR3_QCBRURN_S 16 | 357 | #define AR5K_SISR3_QCBRURN_S 16 |
358 | 358 | ||
359 | #define AR5K_SISR4 0x0094 /* Register Address [5211+] */ | 359 | #define AR5K_SISR4 0x0094 /* Register Address [5211+] */ |
360 | #define AR5K_SISR4_QTRIG 0x000003ff /* Mask for QTRIG */ | 360 | #define AR5K_SISR4_QTRIG 0x000003ff /* Mask for QTRIG */ |
361 | #define AR5K_SISR4_QTRIG_S 0 | 361 | #define AR5K_SISR4_QTRIG_S 0 |
362 | 362 | ||
363 | /* | 363 | /* |
364 | * Shadow read-and-clear interrupt status registers [5211+] | 364 | * Shadow read-and-clear interrupt status registers [5211+] |
365 | */ | 365 | */ |
366 | #define AR5K_RAC_PISR 0x00c0 /* Read and clear PISR */ | 366 | #define AR5K_RAC_PISR 0x00c0 /* Read and clear PISR */ |
367 | #define AR5K_RAC_SISR0 0x00c4 /* Read and clear SISR0 */ | 367 | #define AR5K_RAC_SISR0 0x00c4 /* Read and clear SISR0 */ |
368 | #define AR5K_RAC_SISR1 0x00c8 /* Read and clear SISR1 */ | 368 | #define AR5K_RAC_SISR1 0x00c8 /* Read and clear SISR1 */ |
369 | #define AR5K_RAC_SISR2 0x00cc /* Read and clear SISR2 */ | 369 | #define AR5K_RAC_SISR2 0x00cc /* Read and clear SISR2 */ |
370 | #define AR5K_RAC_SISR3 0x00d0 /* Read and clear SISR3 */ | 370 | #define AR5K_RAC_SISR3 0x00d0 /* Read and clear SISR3 */ |
371 | #define AR5K_RAC_SISR4 0x00d4 /* Read and clear SISR4 */ | 371 | #define AR5K_RAC_SISR4 0x00d4 /* Read and clear SISR4 */ |
372 | 372 | ||
373 | /* | 373 | /* |
374 | * Interrupt Mask Registers | 374 | * Interrupt Mask Registers |
375 | * | 375 | * |
376 | * As whith ISRs 5210 has one IMR (AR5K_IMR) and 5211/5212 has one primary | 376 | * As whith ISRs 5210 has one IMR (AR5K_IMR) and 5211/5212 has one primary |
377 | * (AR5K_PIMR) and 4 secondary IMRs (AR5K_SIMRx). Note that ISR/IMR flags match. | 377 | * (AR5K_PIMR) and 4 secondary IMRs (AR5K_SIMRx). Note that ISR/IMR flags match. |
378 | */ | 378 | */ |
379 | #define AR5K_IMR 0x0020 /* Register Address [5210] */ | 379 | #define AR5K_IMR 0x0020 /* Register Address [5210] */ |
380 | #define AR5K_PIMR 0x00a0 /* Register Address [5211+] */ | 380 | #define AR5K_PIMR 0x00a0 /* Register Address [5211+] */ |
381 | #define AR5K_IMR_RXOK 0x00000001 /* Frame successfuly recieved*/ | 381 | #define AR5K_IMR_RXOK 0x00000001 /* Frame successfuly recieved*/ |
382 | #define AR5K_IMR_RXDESC 0x00000002 /* RX descriptor request*/ | 382 | #define AR5K_IMR_RXDESC 0x00000002 /* RX descriptor request*/ |
383 | #define AR5K_IMR_RXERR 0x00000004 /* Receive error*/ | 383 | #define AR5K_IMR_RXERR 0x00000004 /* Receive error*/ |
384 | #define AR5K_IMR_RXNOFRM 0x00000008 /* No frame received (receive timeout)*/ | 384 | #define AR5K_IMR_RXNOFRM 0x00000008 /* No frame received (receive timeout)*/ |
385 | #define AR5K_IMR_RXEOL 0x00000010 /* Empty RX descriptor*/ | 385 | #define AR5K_IMR_RXEOL 0x00000010 /* Empty RX descriptor*/ |
386 | #define AR5K_IMR_RXORN 0x00000020 /* Receive FIFO overrun*/ | 386 | #define AR5K_IMR_RXORN 0x00000020 /* Receive FIFO overrun*/ |
387 | #define AR5K_IMR_TXOK 0x00000040 /* Frame successfuly transmited*/ | 387 | #define AR5K_IMR_TXOK 0x00000040 /* Frame successfuly transmited*/ |
388 | #define AR5K_IMR_TXDESC 0x00000080 /* TX descriptor request*/ | 388 | #define AR5K_IMR_TXDESC 0x00000080 /* TX descriptor request*/ |
389 | #define AR5K_IMR_TXERR 0x00000100 /* Transmit error*/ | 389 | #define AR5K_IMR_TXERR 0x00000100 /* Transmit error*/ |
390 | #define AR5K_IMR_TXNOFRM 0x00000200 /* No frame transmited (transmit timeout)*/ | 390 | #define AR5K_IMR_TXNOFRM 0x00000200 /* No frame transmited (transmit timeout)*/ |
391 | #define AR5K_IMR_TXEOL 0x00000400 /* Empty TX descriptor*/ | 391 | #define AR5K_IMR_TXEOL 0x00000400 /* Empty TX descriptor*/ |
392 | #define AR5K_IMR_TXURN 0x00000800 /* Transmit FIFO underrun*/ | 392 | #define AR5K_IMR_TXURN 0x00000800 /* Transmit FIFO underrun*/ |
393 | #define AR5K_IMR_MIB 0x00001000 /* Update MIB counters*/ | 393 | #define AR5K_IMR_MIB 0x00001000 /* Update MIB counters*/ |
394 | #define AR5K_IMR_SWI 0x00002000 /* Software interrupt */ | 394 | #define AR5K_IMR_SWI 0x00002000 /* Software interrupt */ |
395 | #define AR5K_IMR_RXPHY 0x00004000 /* PHY error*/ | 395 | #define AR5K_IMR_RXPHY 0x00004000 /* PHY error*/ |
396 | #define AR5K_IMR_RXKCM 0x00008000 /* RX Key cache miss */ | 396 | #define AR5K_IMR_RXKCM 0x00008000 /* RX Key cache miss */ |
397 | #define AR5K_IMR_SWBA 0x00010000 /* Software beacon alert*/ | 397 | #define AR5K_IMR_SWBA 0x00010000 /* Software beacon alert*/ |
398 | #define AR5K_IMR_BRSSI 0x00020000 /* Beacon rssi below threshold (?) */ | 398 | #define AR5K_IMR_BRSSI 0x00020000 /* Beacon rssi below threshold (?) */ |
399 | #define AR5K_IMR_BMISS 0x00040000 /* Beacon missed*/ | 399 | #define AR5K_IMR_BMISS 0x00040000 /* Beacon missed*/ |
400 | #define AR5K_IMR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ | 400 | #define AR5K_IMR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ |
401 | #define AR5K_IMR_BNR 0x00100000 /* Beacon not ready [5211+] */ | 401 | #define AR5K_IMR_BNR 0x00100000 /* Beacon not ready [5211+] */ |
402 | #define AR5K_IMR_MCABT 0x00100000 /* Master Cycle Abort [5210] */ | 402 | #define AR5K_IMR_MCABT 0x00100000 /* Master Cycle Abort [5210] */ |
403 | #define AR5K_IMR_RXCHIRP 0x00200000 /* CHIRP Received [5212+]*/ | 403 | #define AR5K_IMR_RXCHIRP 0x00200000 /* CHIRP Received [5212+]*/ |
404 | #define AR5K_IMR_SSERR 0x00200000 /* Signaled System Error [5210] */ | 404 | #define AR5K_IMR_SSERR 0x00200000 /* Signaled System Error [5210] */ |
405 | #define AR5K_IMR_DPERR 0x00400000 /* Det par Error (?) [5210] */ | 405 | #define AR5K_IMR_DPERR 0x00400000 /* Det par Error (?) [5210] */ |
406 | #define AR5K_IMR_RXDOPPLER 0x00400000 /* Doppler chirp received [5212+] */ | 406 | #define AR5K_IMR_RXDOPPLER 0x00400000 /* Doppler chirp received [5212+] */ |
407 | #define AR5K_IMR_TIM 0x00800000 /* [5211+] */ | 407 | #define AR5K_IMR_TIM 0x00800000 /* [5211+] */ |
408 | #define AR5K_IMR_BCNMISC 0x00800000 /* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT, | 408 | #define AR5K_IMR_BCNMISC 0x00800000 /* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT, |
409 | CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */ | 409 | CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */ |
410 | #define AR5K_IMR_GPIO 0x01000000 /* GPIO (rf kill)*/ | 410 | #define AR5K_IMR_GPIO 0x01000000 /* GPIO (rf kill)*/ |
411 | #define AR5K_IMR_QCBRORN 0x02000000 /* QCU CBR overrun (?) [5211+] */ | 411 | #define AR5K_IMR_QCBRORN 0x02000000 /* QCU CBR overrun (?) [5211+] */ |
412 | #define AR5K_IMR_QCBRURN 0x04000000 /* QCU CBR underrun (?) [5211+] */ | 412 | #define AR5K_IMR_QCBRURN 0x04000000 /* QCU CBR underrun (?) [5211+] */ |
413 | #define AR5K_IMR_QTRIG 0x08000000 /* QCU scheduling trigger [5211+] */ | 413 | #define AR5K_IMR_QTRIG 0x08000000 /* QCU scheduling trigger [5211+] */ |
414 | 414 | ||
415 | /* | 415 | /* |
416 | * Secondary interrupt mask registers [5211+] (0 - 4) | 416 | * Secondary interrupt mask registers [5211+] (0 - 4) |
417 | */ | 417 | */ |
418 | #define AR5K_SIMR0 0x00a4 /* Register Address [5211+] */ | 418 | #define AR5K_SIMR0 0x00a4 /* Register Address [5211+] */ |
419 | #define AR5K_SIMR0_QCU_TXOK 0x000003ff /* Mask for QCU_TXOK */ | 419 | #define AR5K_SIMR0_QCU_TXOK 0x000003ff /* Mask for QCU_TXOK */ |
420 | #define AR5K_SIMR0_QCU_TXOK_S 0 | 420 | #define AR5K_SIMR0_QCU_TXOK_S 0 |
421 | #define AR5K_SIMR0_QCU_TXDESC 0x03ff0000 /* Mask for QCU_TXDESC */ | 421 | #define AR5K_SIMR0_QCU_TXDESC 0x03ff0000 /* Mask for QCU_TXDESC */ |
422 | #define AR5K_SIMR0_QCU_TXDESC_S 16 | 422 | #define AR5K_SIMR0_QCU_TXDESC_S 16 |
423 | 423 | ||
424 | #define AR5K_SIMR1 0x00a8 /* Register Address [5211+] */ | 424 | #define AR5K_SIMR1 0x00a8 /* Register Address [5211+] */ |
425 | #define AR5K_SIMR1_QCU_TXERR 0x000003ff /* Mask for QCU_TXERR */ | 425 | #define AR5K_SIMR1_QCU_TXERR 0x000003ff /* Mask for QCU_TXERR */ |
426 | #define AR5K_SIMR1_QCU_TXERR_S 0 | 426 | #define AR5K_SIMR1_QCU_TXERR_S 0 |
427 | #define AR5K_SIMR1_QCU_TXEOL 0x03ff0000 /* Mask for QCU_TXEOL */ | 427 | #define AR5K_SIMR1_QCU_TXEOL 0x03ff0000 /* Mask for QCU_TXEOL */ |
428 | #define AR5K_SIMR1_QCU_TXEOL_S 16 | 428 | #define AR5K_SIMR1_QCU_TXEOL_S 16 |
429 | 429 | ||
430 | #define AR5K_SIMR2 0x00ac /* Register Address [5211+] */ | 430 | #define AR5K_SIMR2 0x00ac /* Register Address [5211+] */ |
431 | #define AR5K_SIMR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ | 431 | #define AR5K_SIMR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ |
432 | #define AR5K_SIMR2_QCU_TXURN_S 0 | 432 | #define AR5K_SIMR2_QCU_TXURN_S 0 |
433 | #define AR5K_SIMR2_MCABT 0x00010000 /* Master Cycle Abort */ | 433 | #define AR5K_SIMR2_MCABT 0x00010000 /* Master Cycle Abort */ |
434 | #define AR5K_SIMR2_SSERR 0x00020000 /* Signaled System Error */ | 434 | #define AR5K_SIMR2_SSERR 0x00020000 /* Signaled System Error */ |
435 | #define AR5K_SIMR2_DPERR 0x00040000 /* Bus parity error */ | 435 | #define AR5K_SIMR2_DPERR 0x00040000 /* Bus parity error */ |
436 | #define AR5K_SIMR2_TIM 0x01000000 /* [5212+] */ | 436 | #define AR5K_SIMR2_TIM 0x01000000 /* [5212+] */ |
437 | #define AR5K_SIMR2_CAB_END 0x02000000 /* [5212+] */ | 437 | #define AR5K_SIMR2_CAB_END 0x02000000 /* [5212+] */ |
438 | #define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* DTIM Sync lost [5212+] */ | 438 | #define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* DTIM Sync lost [5212+] */ |
439 | #define AR5K_SIMR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */ | 439 | #define AR5K_SIMR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */ |
440 | #define AR5K_SIMR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */ | 440 | #define AR5K_SIMR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */ |
441 | #define AR5K_SIMR2_DTIM 0x20000000 /* [5212+] */ | 441 | #define AR5K_SIMR2_DTIM 0x20000000 /* [5212+] */ |
442 | #define AR5K_SIMR2_TSFOOR 0x80000000 /* TSF OOR (?) */ | 442 | #define AR5K_SIMR2_TSFOOR 0x80000000 /* TSF OOR (?) */ |
443 | 443 | ||
444 | #define AR5K_SIMR3 0x00b0 /* Register Address [5211+] */ | 444 | #define AR5K_SIMR3 0x00b0 /* Register Address [5211+] */ |
445 | #define AR5K_SIMR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ | 445 | #define AR5K_SIMR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ |
446 | #define AR5K_SIMR3_QCBRORN_S 0 | 446 | #define AR5K_SIMR3_QCBRORN_S 0 |
447 | #define AR5K_SIMR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ | 447 | #define AR5K_SIMR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ |
448 | #define AR5K_SIMR3_QCBRURN_S 16 | 448 | #define AR5K_SIMR3_QCBRURN_S 16 |
449 | 449 | ||
450 | #define AR5K_SIMR4 0x00b4 /* Register Address [5211+] */ | 450 | #define AR5K_SIMR4 0x00b4 /* Register Address [5211+] */ |
451 | #define AR5K_SIMR4_QTRIG 0x000003ff /* Mask for QTRIG */ | 451 | #define AR5K_SIMR4_QTRIG 0x000003ff /* Mask for QTRIG */ |
452 | #define AR5K_SIMR4_QTRIG_S 0 | 452 | #define AR5K_SIMR4_QTRIG_S 0 |
453 | 453 | ||
454 | /* | 454 | /* |
455 | * DMA Debug registers 0-7 | 455 | * DMA Debug registers 0-7 |
456 | * 0xe0 - 0xfc | 456 | * 0xe0 - 0xfc |
457 | */ | 457 | */ |
458 | 458 | ||
459 | /* | 459 | /* |
460 | * Decompression mask registers [5212+] | 460 | * Decompression mask registers [5212+] |
461 | */ | 461 | */ |
462 | #define AR5K_DCM_ADDR 0x0400 /*Decompression mask address (index) */ | 462 | #define AR5K_DCM_ADDR 0x0400 /*Decompression mask address (index) */ |
463 | #define AR5K_DCM_DATA 0x0404 /*Decompression mask data */ | 463 | #define AR5K_DCM_DATA 0x0404 /*Decompression mask data */ |
464 | 464 | ||
465 | /* | 465 | /* |
466 | * Wake On Wireless pattern control register [5212+] | 466 | * Wake On Wireless pattern control register [5212+] |
467 | */ | 467 | */ |
468 | #define AR5K_WOW_PCFG 0x0410 /* Register Address */ | 468 | #define AR5K_WOW_PCFG 0x0410 /* Register Address */ |
469 | #define AR5K_WOW_PCFG_PAT_MATCH_EN 0x00000001 /* Pattern match enable */ | 469 | #define AR5K_WOW_PCFG_PAT_MATCH_EN 0x00000001 /* Pattern match enable */ |
470 | #define AR5K_WOW_PCFG_LONG_FRAME_POL 0x00000002 /* Long frame policy */ | 470 | #define AR5K_WOW_PCFG_LONG_FRAME_POL 0x00000002 /* Long frame policy */ |
471 | #define AR5K_WOW_PCFG_WOBMISS 0x00000004 /* Wake on bea(con) miss (?) */ | 471 | #define AR5K_WOW_PCFG_WOBMISS 0x00000004 /* Wake on bea(con) miss (?) */ |
472 | #define AR5K_WOW_PCFG_PAT_0_EN 0x00000100 /* Enable pattern 0 */ | 472 | #define AR5K_WOW_PCFG_PAT_0_EN 0x00000100 /* Enable pattern 0 */ |
473 | #define AR5K_WOW_PCFG_PAT_1_EN 0x00000200 /* Enable pattern 1 */ | 473 | #define AR5K_WOW_PCFG_PAT_1_EN 0x00000200 /* Enable pattern 1 */ |
474 | #define AR5K_WOW_PCFG_PAT_2_EN 0x00000400 /* Enable pattern 2 */ | 474 | #define AR5K_WOW_PCFG_PAT_2_EN 0x00000400 /* Enable pattern 2 */ |
475 | #define AR5K_WOW_PCFG_PAT_3_EN 0x00000800 /* Enable pattern 3 */ | 475 | #define AR5K_WOW_PCFG_PAT_3_EN 0x00000800 /* Enable pattern 3 */ |
476 | #define AR5K_WOW_PCFG_PAT_4_EN 0x00001000 /* Enable pattern 4 */ | 476 | #define AR5K_WOW_PCFG_PAT_4_EN 0x00001000 /* Enable pattern 4 */ |
477 | #define AR5K_WOW_PCFG_PAT_5_EN 0x00002000 /* Enable pattern 5 */ | 477 | #define AR5K_WOW_PCFG_PAT_5_EN 0x00002000 /* Enable pattern 5 */ |
478 | 478 | ||
479 | /* | 479 | /* |
480 | * Wake On Wireless pattern index register (?) [5212+] | 480 | * Wake On Wireless pattern index register (?) [5212+] |
481 | */ | 481 | */ |
482 | #define AR5K_WOW_PAT_IDX 0x0414 | 482 | #define AR5K_WOW_PAT_IDX 0x0414 |
483 | 483 | ||
484 | /* | 484 | /* |
485 | * Wake On Wireless pattern data register [5212+] | 485 | * Wake On Wireless pattern data register [5212+] |
486 | */ | 486 | */ |
487 | #define AR5K_WOW_PAT_DATA 0x0418 /* Register Address */ | 487 | #define AR5K_WOW_PAT_DATA 0x0418 /* Register Address */ |
488 | #define AR5K_WOW_PAT_DATA_0_3_V 0x00000001 /* Pattern 0, 3 value */ | 488 | #define AR5K_WOW_PAT_DATA_0_3_V 0x00000001 /* Pattern 0, 3 value */ |
489 | #define AR5K_WOW_PAT_DATA_1_4_V 0x00000100 /* Pattern 1, 4 value */ | 489 | #define AR5K_WOW_PAT_DATA_1_4_V 0x00000100 /* Pattern 1, 4 value */ |
490 | #define AR5K_WOW_PAT_DATA_2_5_V 0x00010000 /* Pattern 2, 5 value */ | 490 | #define AR5K_WOW_PAT_DATA_2_5_V 0x00010000 /* Pattern 2, 5 value */ |
491 | #define AR5K_WOW_PAT_DATA_0_3_M 0x01000000 /* Pattern 0, 3 mask */ | 491 | #define AR5K_WOW_PAT_DATA_0_3_M 0x01000000 /* Pattern 0, 3 mask */ |
492 | #define AR5K_WOW_PAT_DATA_1_4_M 0x04000000 /* Pattern 1, 4 mask */ | 492 | #define AR5K_WOW_PAT_DATA_1_4_M 0x04000000 /* Pattern 1, 4 mask */ |
493 | #define AR5K_WOW_PAT_DATA_2_5_M 0x10000000 /* Pattern 2, 5 mask */ | 493 | #define AR5K_WOW_PAT_DATA_2_5_M 0x10000000 /* Pattern 2, 5 mask */ |
494 | 494 | ||
495 | /* | 495 | /* |
496 | * Decompression configuration registers [5212+] | 496 | * Decompression configuration registers [5212+] |
497 | */ | 497 | */ |
498 | #define AR5K_DCCFG 0x0420 /* Register Address */ | 498 | #define AR5K_DCCFG 0x0420 /* Register Address */ |
499 | #define AR5K_DCCFG_GLOBAL_EN 0x00000001 /* Enable decompression on all queues */ | 499 | #define AR5K_DCCFG_GLOBAL_EN 0x00000001 /* Enable decompression on all queues */ |
500 | #define AR5K_DCCFG_BYPASS_EN 0x00000002 /* Bypass decompression */ | 500 | #define AR5K_DCCFG_BYPASS_EN 0x00000002 /* Bypass decompression */ |
501 | #define AR5K_DCCFG_BCAST_EN 0x00000004 /* Enable decompression for bcast frames */ | 501 | #define AR5K_DCCFG_BCAST_EN 0x00000004 /* Enable decompression for bcast frames */ |
502 | #define AR5K_DCCFG_MCAST_EN 0x00000008 /* Enable decompression for mcast frames */ | 502 | #define AR5K_DCCFG_MCAST_EN 0x00000008 /* Enable decompression for mcast frames */ |
503 | 503 | ||
504 | /* | 504 | /* |
505 | * Compression configuration registers [5212+] | 505 | * Compression configuration registers [5212+] |
506 | */ | 506 | */ |
507 | #define AR5K_CCFG 0x0600 /* Register Address */ | 507 | #define AR5K_CCFG 0x0600 /* Register Address */ |
508 | #define AR5K_CCFG_WINDOW_SIZE 0x00000007 /* Compression window size */ | 508 | #define AR5K_CCFG_WINDOW_SIZE 0x00000007 /* Compression window size */ |
509 | #define AR5K_CCFG_CPC_EN 0x00000008 /* Enable performance counters */ | 509 | #define AR5K_CCFG_CPC_EN 0x00000008 /* Enable performance counters */ |
510 | 510 | ||
511 | #define AR5K_CCFG_CCU 0x0604 /* Register Address */ | 511 | #define AR5K_CCFG_CCU 0x0604 /* Register Address */ |
512 | #define AR5K_CCFG_CCU_CUP_EN 0x00000001 /* CCU Catchup enable */ | 512 | #define AR5K_CCFG_CCU_CUP_EN 0x00000001 /* CCU Catchup enable */ |
513 | #define AR5K_CCFG_CCU_CREDIT 0x00000002 /* CCU Credit (field) */ | 513 | #define AR5K_CCFG_CCU_CREDIT 0x00000002 /* CCU Credit (field) */ |
514 | #define AR5K_CCFG_CCU_CD_THRES 0x00000080 /* CCU Cyc(lic?) debt threshold (field) */ | 514 | #define AR5K_CCFG_CCU_CD_THRES 0x00000080 /* CCU Cyc(lic?) debt threshold (field) */ |
515 | #define AR5K_CCFG_CCU_CUP_LCNT 0x00010000 /* CCU Catchup lit(?) count */ | 515 | #define AR5K_CCFG_CCU_CUP_LCNT 0x00010000 /* CCU Catchup lit(?) count */ |
516 | #define AR5K_CCFG_CCU_INIT 0x00100200 /* Initial value during reset */ | 516 | #define AR5K_CCFG_CCU_INIT 0x00100200 /* Initial value during reset */ |
517 | 517 | ||
518 | /* | 518 | /* |
519 | * Compression performance counter registers [5212+] | 519 | * Compression performance counter registers [5212+] |
520 | */ | 520 | */ |
521 | #define AR5K_CPC0 0x0610 /* Compression performance counter 0 */ | 521 | #define AR5K_CPC0 0x0610 /* Compression performance counter 0 */ |
522 | #define AR5K_CPC1 0x0614 /* Compression performance counter 1*/ | 522 | #define AR5K_CPC1 0x0614 /* Compression performance counter 1*/ |
523 | #define AR5K_CPC2 0x0618 /* Compression performance counter 2 */ | 523 | #define AR5K_CPC2 0x0618 /* Compression performance counter 2 */ |
524 | #define AR5K_CPC3 0x061c /* Compression performance counter 3 */ | 524 | #define AR5K_CPC3 0x061c /* Compression performance counter 3 */ |
525 | #define AR5K_CPCOVF 0x0620 /* Compression performance overflow */ | 525 | #define AR5K_CPCOVF 0x0620 /* Compression performance overflow */ |
526 | 526 | ||
527 | 527 | ||
528 | /* | 528 | /* |
529 | * Queue control unit (QCU) registers [5211+] | 529 | * Queue control unit (QCU) registers [5211+] |
530 | * | 530 | * |
531 | * Card has 12 TX Queues but i see that only 0-9 are used (?) | 531 | * Card has 12 TX Queues but i see that only 0-9 are used (?) |
532 | * both in binary HAL (see ah.h) and ar5k. Each queue has it's own | 532 | * both in binary HAL (see ah.h) and ar5k. Each queue has it's own |
533 | * TXDP at addresses 0x0800 - 0x082c, a CBR (Constant Bit Rate) | 533 | * TXDP at addresses 0x0800 - 0x082c, a CBR (Constant Bit Rate) |
534 | * configuration register (0x08c0 - 0x08ec), a ready time configuration | 534 | * configuration register (0x08c0 - 0x08ec), a ready time configuration |
535 | * register (0x0900 - 0x092c), a misc configuration register (0x09c0 - | 535 | * register (0x0900 - 0x092c), a misc configuration register (0x09c0 - |
536 | * 0x09ec) and a status register (0x0a00 - 0x0a2c). We also have some | 536 | * 0x09ec) and a status register (0x0a00 - 0x0a2c). We also have some |
537 | * global registers, QCU transmit enable/disable and "one shot arm (?)" | 537 | * global registers, QCU transmit enable/disable and "one shot arm (?)" |
538 | * set/clear, which contain status for all queues (we shift by 1 for each | 538 | * set/clear, which contain status for all queues (we shift by 1 for each |
539 | * queue). To access these registers easily we define some macros here | 539 | * queue). To access these registers easily we define some macros here |
540 | * that are used inside HAL. For more infos check out *_tx_queue functs. | 540 | * that are used inside HAL. For more infos check out *_tx_queue functs. |
541 | */ | 541 | */ |
542 | 542 | ||
543 | /* | 543 | /* |
544 | * Generic QCU Register access macros | 544 | * Generic QCU Register access macros |
545 | */ | 545 | */ |
546 | #define AR5K_QUEUE_REG(_r, _q) (((_q) << 2) + _r) | 546 | #define AR5K_QUEUE_REG(_r, _q) (((_q) << 2) + _r) |
547 | #define AR5K_QCU_GLOBAL_READ(_r, _q) (AR5K_REG_READ(_r) & (1 << _q)) | 547 | #define AR5K_QCU_GLOBAL_READ(_r, _q) (AR5K_REG_READ(_r) & (1 << _q)) |
548 | #define AR5K_QCU_GLOBAL_WRITE(_r, _q) AR5K_REG_WRITE(_r, (1 << _q)) | 548 | #define AR5K_QCU_GLOBAL_WRITE(_r, _q) AR5K_REG_WRITE(_r, (1 << _q)) |
549 | 549 | ||
550 | /* | 550 | /* |
551 | * QCU Transmit descriptor pointer registers | 551 | * QCU Transmit descriptor pointer registers |
552 | */ | 552 | */ |
553 | #define AR5K_QCU_TXDP_BASE 0x0800 /* Register Address - Queue0 TXDP */ | 553 | #define AR5K_QCU_TXDP_BASE 0x0800 /* Register Address - Queue0 TXDP */ |
554 | #define AR5K_QUEUE_TXDP(_q) AR5K_QUEUE_REG(AR5K_QCU_TXDP_BASE, _q) | 554 | #define AR5K_QUEUE_TXDP(_q) AR5K_QUEUE_REG(AR5K_QCU_TXDP_BASE, _q) |
555 | 555 | ||
556 | /* | 556 | /* |
557 | * QCU Transmit enable register | 557 | * QCU Transmit enable register |
558 | */ | 558 | */ |
559 | #define AR5K_QCU_TXE 0x0840 | 559 | #define AR5K_QCU_TXE 0x0840 |
560 | #define AR5K_ENABLE_QUEUE(_q) AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXE, _q) | 560 | #define AR5K_ENABLE_QUEUE(_q) AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXE, _q) |
561 | #define AR5K_QUEUE_ENABLED(_q) AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXE, _q) | 561 | #define AR5K_QUEUE_ENABLED(_q) AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXE, _q) |
562 | 562 | ||
563 | /* | 563 | /* |
564 | * QCU Transmit disable register | 564 | * QCU Transmit disable register |
565 | */ | 565 | */ |
566 | #define AR5K_QCU_TXD 0x0880 | 566 | #define AR5K_QCU_TXD 0x0880 |
567 | #define AR5K_DISABLE_QUEUE(_q) AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXD, _q) | 567 | #define AR5K_DISABLE_QUEUE(_q) AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXD, _q) |
568 | #define AR5K_QUEUE_DISABLED(_q) AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXD, _q) | 568 | #define AR5K_QUEUE_DISABLED(_q) AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXD, _q) |
569 | 569 | ||
570 | /* | 570 | /* |
571 | * QCU Constant Bit Rate configuration registers | 571 | * QCU Constant Bit Rate configuration registers |
572 | */ | 572 | */ |
573 | #define AR5K_QCU_CBRCFG_BASE 0x08c0 /* Register Address - Queue0 CBRCFG */ | 573 | #define AR5K_QCU_CBRCFG_BASE 0x08c0 /* Register Address - Queue0 CBRCFG */ |
574 | #define AR5K_QCU_CBRCFG_INTVAL 0x00ffffff /* CBR Interval mask */ | 574 | #define AR5K_QCU_CBRCFG_INTVAL 0x00ffffff /* CBR Interval mask */ |
575 | #define AR5K_QCU_CBRCFG_INTVAL_S 0 | 575 | #define AR5K_QCU_CBRCFG_INTVAL_S 0 |
576 | #define AR5K_QCU_CBRCFG_ORN_THRES 0xff000000 /* CBR overrun threshold mask */ | 576 | #define AR5K_QCU_CBRCFG_ORN_THRES 0xff000000 /* CBR overrun threshold mask */ |
577 | #define AR5K_QCU_CBRCFG_ORN_THRES_S 24 | 577 | #define AR5K_QCU_CBRCFG_ORN_THRES_S 24 |
578 | #define AR5K_QUEUE_CBRCFG(_q) AR5K_QUEUE_REG(AR5K_QCU_CBRCFG_BASE, _q) | 578 | #define AR5K_QUEUE_CBRCFG(_q) AR5K_QUEUE_REG(AR5K_QCU_CBRCFG_BASE, _q) |
579 | 579 | ||
580 | /* | 580 | /* |
581 | * QCU Ready time configuration registers | 581 | * QCU Ready time configuration registers |
582 | */ | 582 | */ |
583 | #define AR5K_QCU_RDYTIMECFG_BASE 0x0900 /* Register Address - Queue0 RDYTIMECFG */ | 583 | #define AR5K_QCU_RDYTIMECFG_BASE 0x0900 /* Register Address - Queue0 RDYTIMECFG */ |
584 | #define AR5K_QCU_RDYTIMECFG_INTVAL 0x00ffffff /* Ready time interval mask */ | 584 | #define AR5K_QCU_RDYTIMECFG_INTVAL 0x00ffffff /* Ready time interval mask */ |
585 | #define AR5K_QCU_RDYTIMECFG_INTVAL_S 0 | 585 | #define AR5K_QCU_RDYTIMECFG_INTVAL_S 0 |
586 | #define AR5K_QCU_RDYTIMECFG_ENABLE 0x01000000 /* Ready time enable mask */ | 586 | #define AR5K_QCU_RDYTIMECFG_ENABLE 0x01000000 /* Ready time enable mask */ |
587 | #define AR5K_QUEUE_RDYTIMECFG(_q) AR5K_QUEUE_REG(AR5K_QCU_RDYTIMECFG_BASE, _q) | 587 | #define AR5K_QUEUE_RDYTIMECFG(_q) AR5K_QUEUE_REG(AR5K_QCU_RDYTIMECFG_BASE, _q) |
588 | 588 | ||
589 | /* | 589 | /* |
590 | * QCU one shot arm set registers | 590 | * QCU one shot arm set registers |
591 | */ | 591 | */ |
592 | #define AR5K_QCU_ONESHOTARM_SET 0x0940 /* Register Address -QCU "one shot arm set (?)" */ | 592 | #define AR5K_QCU_ONESHOTARM_SET 0x0940 /* Register Address -QCU "one shot arm set (?)" */ |
593 | #define AR5K_QCU_ONESHOTARM_SET_M 0x0000ffff | 593 | #define AR5K_QCU_ONESHOTARM_SET_M 0x0000ffff |
594 | 594 | ||
595 | /* | 595 | /* |
596 | * QCU one shot arm clear registers | 596 | * QCU one shot arm clear registers |
597 | */ | 597 | */ |
598 | #define AR5K_QCU_ONESHOTARM_CLEAR 0x0980 /* Register Address -QCU "one shot arm clear (?)" */ | 598 | #define AR5K_QCU_ONESHOTARM_CLEAR 0x0980 /* Register Address -QCU "one shot arm clear (?)" */ |
599 | #define AR5K_QCU_ONESHOTARM_CLEAR_M 0x0000ffff | 599 | #define AR5K_QCU_ONESHOTARM_CLEAR_M 0x0000ffff |
600 | 600 | ||
601 | /* | 601 | /* |
602 | * QCU misc registers | 602 | * QCU misc registers |
603 | */ | 603 | */ |
604 | #define AR5K_QCU_MISC_BASE 0x09c0 /* Register Address -Queue0 MISC */ | 604 | #define AR5K_QCU_MISC_BASE 0x09c0 /* Register Address -Queue0 MISC */ |
605 | #define AR5K_QCU_MISC_FRSHED_M 0x0000000f /* Frame sheduling mask */ | 605 | #define AR5K_QCU_MISC_FRSHED_M 0x0000000f /* Frame sheduling mask */ |
606 | #define AR5K_QCU_MISC_FRSHED_ASAP 0 /* ASAP */ | 606 | #define AR5K_QCU_MISC_FRSHED_ASAP 0 /* ASAP */ |
607 | #define AR5K_QCU_MISC_FRSHED_CBR 1 /* Constant Bit Rate */ | 607 | #define AR5K_QCU_MISC_FRSHED_CBR 1 /* Constant Bit Rate */ |
608 | #define AR5K_QCU_MISC_FRSHED_DBA_GT 2 /* DMA Beacon alert gated */ | 608 | #define AR5K_QCU_MISC_FRSHED_DBA_GT 2 /* DMA Beacon alert gated */ |
609 | #define AR5K_QCU_MISC_FRSHED_TIM_GT 3 /* TIMT gated */ | 609 | #define AR5K_QCU_MISC_FRSHED_TIM_GT 3 /* TIMT gated */ |
610 | #define AR5K_QCU_MISC_FRSHED_BCN_SENT_GT 4 /* Beacon sent gated */ | 610 | #define AR5K_QCU_MISC_FRSHED_BCN_SENT_GT 4 /* Beacon sent gated */ |
611 | #define AR5K_QCU_MISC_ONESHOT_ENABLE 0x00000010 /* Oneshot enable */ | 611 | #define AR5K_QCU_MISC_ONESHOT_ENABLE 0x00000010 /* Oneshot enable */ |
612 | #define AR5K_QCU_MISC_CBREXP_DIS 0x00000020 /* Disable CBR expired counter (normal queue) */ | 612 | #define AR5K_QCU_MISC_CBREXP_DIS 0x00000020 /* Disable CBR expired counter (normal queue) */ |
613 | #define AR5K_QCU_MISC_CBREXP_BCN_DIS 0x00000040 /* Disable CBR expired counter (beacon queue) */ | 613 | #define AR5K_QCU_MISC_CBREXP_BCN_DIS 0x00000040 /* Disable CBR expired counter (beacon queue) */ |
614 | #define AR5K_QCU_MISC_BCN_ENABLE 0x00000080 /* Enable Beacon use */ | 614 | #define AR5K_QCU_MISC_BCN_ENABLE 0x00000080 /* Enable Beacon use */ |
615 | #define AR5K_QCU_MISC_CBR_THRES_ENABLE 0x00000100 /* CBR expired threshold enabled */ | 615 | #define AR5K_QCU_MISC_CBR_THRES_ENABLE 0x00000100 /* CBR expired threshold enabled */ |
616 | #define AR5K_QCU_MISC_RDY_VEOL_POLICY 0x00000200 /* TXE reset when RDYTIME expired or VEOL */ | 616 | #define AR5K_QCU_MISC_RDY_VEOL_POLICY 0x00000200 /* TXE reset when RDYTIME expired or VEOL */ |
617 | #define AR5K_QCU_MISC_CBR_RESET_CNT 0x00000400 /* CBR threshold (counter) reset */ | 617 | #define AR5K_QCU_MISC_CBR_RESET_CNT 0x00000400 /* CBR threshold (counter) reset */ |
618 | #define AR5K_QCU_MISC_DCU_EARLY 0x00000800 /* DCU early termination */ | 618 | #define AR5K_QCU_MISC_DCU_EARLY 0x00000800 /* DCU early termination */ |
619 | #define AR5K_QCU_MISC_DCU_CMP_EN 0x00001000 /* Enable frame compression */ | 619 | #define AR5K_QCU_MISC_DCU_CMP_EN 0x00001000 /* Enable frame compression */ |
620 | #define AR5K_QUEUE_MISC(_q) AR5K_QUEUE_REG(AR5K_QCU_MISC_BASE, _q) | 620 | #define AR5K_QUEUE_MISC(_q) AR5K_QUEUE_REG(AR5K_QCU_MISC_BASE, _q) |
621 | 621 | ||
622 | 622 | ||
623 | /* | 623 | /* |
624 | * QCU status registers | 624 | * QCU status registers |
625 | */ | 625 | */ |
626 | #define AR5K_QCU_STS_BASE 0x0a00 /* Register Address - Queue0 STS */ | 626 | #define AR5K_QCU_STS_BASE 0x0a00 /* Register Address - Queue0 STS */ |
627 | #define AR5K_QCU_STS_FRMPENDCNT 0x00000003 /* Frames pending counter */ | 627 | #define AR5K_QCU_STS_FRMPENDCNT 0x00000003 /* Frames pending counter */ |
628 | #define AR5K_QCU_STS_CBREXPCNT 0x0000ff00 /* CBR expired counter */ | 628 | #define AR5K_QCU_STS_CBREXPCNT 0x0000ff00 /* CBR expired counter */ |
629 | #define AR5K_QUEUE_STATUS(_q) AR5K_QUEUE_REG(AR5K_QCU_STS_BASE, _q) | 629 | #define AR5K_QUEUE_STATUS(_q) AR5K_QUEUE_REG(AR5K_QCU_STS_BASE, _q) |
630 | 630 | ||
631 | /* | 631 | /* |
632 | * QCU ready time shutdown register | 632 | * QCU ready time shutdown register |
633 | */ | 633 | */ |
634 | #define AR5K_QCU_RDYTIMESHDN 0x0a40 | 634 | #define AR5K_QCU_RDYTIMESHDN 0x0a40 |
635 | #define AR5K_QCU_RDYTIMESHDN_M 0x000003ff | 635 | #define AR5K_QCU_RDYTIMESHDN_M 0x000003ff |
636 | 636 | ||
637 | /* | 637 | /* |
638 | * QCU compression buffer base registers [5212+] | 638 | * QCU compression buffer base registers [5212+] |
639 | */ | 639 | */ |
640 | #define AR5K_QCU_CBB_SELECT 0x0b00 | 640 | #define AR5K_QCU_CBB_SELECT 0x0b00 |
641 | #define AR5K_QCU_CBB_ADDR 0x0b04 | 641 | #define AR5K_QCU_CBB_ADDR 0x0b04 |
642 | #define AR5K_QCU_CBB_ADDR_S 9 | 642 | #define AR5K_QCU_CBB_ADDR_S 9 |
643 | 643 | ||
644 | /* | 644 | /* |
645 | * QCU compression buffer configuration register [5212+] | 645 | * QCU compression buffer configuration register [5212+] |
646 | * (buffer size) | 646 | * (buffer size) |
647 | */ | 647 | */ |
648 | #define AR5K_QCU_CBCFG 0x0b08 | 648 | #define AR5K_QCU_CBCFG 0x0b08 |
649 | 649 | ||
650 | 650 | ||
651 | 651 | ||
652 | /* | 652 | /* |
653 | * Distributed Coordination Function (DCF) control unit (DCU) | 653 | * Distributed Coordination Function (DCF) control unit (DCU) |
654 | * registers [5211+] | 654 | * registers [5211+] |
655 | * | 655 | * |
656 | * These registers control the various characteristics of each queue | 656 | * These registers control the various characteristics of each queue |
657 | * for 802.11e (WME) combatibility so they go together with | 657 | * for 802.11e (WME) combatibility so they go together with |
658 | * QCU registers in pairs. For each queue we have a QCU mask register, | 658 | * QCU registers in pairs. For each queue we have a QCU mask register, |
659 | * (0x1000 - 0x102c), a local-IFS settings register (0x1040 - 0x106c), | 659 | * (0x1000 - 0x102c), a local-IFS settings register (0x1040 - 0x106c), |
660 | * a retry limit register (0x1080 - 0x10ac), a channel time register | 660 | * a retry limit register (0x1080 - 0x10ac), a channel time register |
661 | * (0x10c0 - 0x10ec), a misc-settings register (0x1100 - 0x112c) and | 661 | * (0x10c0 - 0x10ec), a misc-settings register (0x1100 - 0x112c) and |
662 | * a sequence number register (0x1140 - 0x116c). It seems that "global" | 662 | * a sequence number register (0x1140 - 0x116c). It seems that "global" |
663 | * registers here afect all queues (see use of DCU_GBL_IFS_SLOT in ar5k). | 663 | * registers here afect all queues (see use of DCU_GBL_IFS_SLOT in ar5k). |
664 | * We use the same macros here for easier register access. | 664 | * We use the same macros here for easier register access. |
665 | * | 665 | * |
666 | */ | 666 | */ |
667 | 667 | ||
668 | /* | 668 | /* |
669 | * DCU QCU mask registers | 669 | * DCU QCU mask registers |
670 | */ | 670 | */ |
671 | #define AR5K_DCU_QCUMASK_BASE 0x1000 /* Register Address -Queue0 DCU_QCUMASK */ | 671 | #define AR5K_DCU_QCUMASK_BASE 0x1000 /* Register Address -Queue0 DCU_QCUMASK */ |
672 | #define AR5K_DCU_QCUMASK_M 0x000003ff | 672 | #define AR5K_DCU_QCUMASK_M 0x000003ff |
673 | #define AR5K_QUEUE_QCUMASK(_q) AR5K_QUEUE_REG(AR5K_DCU_QCUMASK_BASE, _q) | 673 | #define AR5K_QUEUE_QCUMASK(_q) AR5K_QUEUE_REG(AR5K_DCU_QCUMASK_BASE, _q) |
674 | 674 | ||
675 | /* | 675 | /* |
676 | * DCU local Inter Frame Space settings register | 676 | * DCU local Inter Frame Space settings register |
677 | */ | 677 | */ |
678 | #define AR5K_DCU_LCL_IFS_BASE 0x1040 /* Register Address -Queue0 DCU_LCL_IFS */ | 678 | #define AR5K_DCU_LCL_IFS_BASE 0x1040 /* Register Address -Queue0 DCU_LCL_IFS */ |
679 | #define AR5K_DCU_LCL_IFS_CW_MIN 0x000003ff /* Minimum Contention Window */ | 679 | #define AR5K_DCU_LCL_IFS_CW_MIN 0x000003ff /* Minimum Contention Window */ |
680 | #define AR5K_DCU_LCL_IFS_CW_MIN_S 0 | 680 | #define AR5K_DCU_LCL_IFS_CW_MIN_S 0 |
681 | #define AR5K_DCU_LCL_IFS_CW_MAX 0x000ffc00 /* Maximum Contention Window */ | 681 | #define AR5K_DCU_LCL_IFS_CW_MAX 0x000ffc00 /* Maximum Contention Window */ |
682 | #define AR5K_DCU_LCL_IFS_CW_MAX_S 10 | 682 | #define AR5K_DCU_LCL_IFS_CW_MAX_S 10 |
683 | #define AR5K_DCU_LCL_IFS_AIFS 0x0ff00000 /* Arbitrated Interframe Space */ | 683 | #define AR5K_DCU_LCL_IFS_AIFS 0x0ff00000 /* Arbitrated Interframe Space */ |
684 | #define AR5K_DCU_LCL_IFS_AIFS_S 20 | 684 | #define AR5K_DCU_LCL_IFS_AIFS_S 20 |
685 | #define AR5K_DCU_LCL_IFS_AIFS_MAX 0xfc /* Anything above that can cause DCU to hang */ | 685 | #define AR5K_DCU_LCL_IFS_AIFS_MAX 0xfc /* Anything above that can cause DCU to hang */ |
686 | #define AR5K_QUEUE_DFS_LOCAL_IFS(_q) AR5K_QUEUE_REG(AR5K_DCU_LCL_IFS_BASE, _q) | 686 | #define AR5K_QUEUE_DFS_LOCAL_IFS(_q) AR5K_QUEUE_REG(AR5K_DCU_LCL_IFS_BASE, _q) |
687 | 687 | ||
688 | /* | 688 | /* |
689 | * DCU retry limit registers | 689 | * DCU retry limit registers |
690 | */ | 690 | */ |
691 | #define AR5K_DCU_RETRY_LMT_BASE 0x1080 /* Register Address -Queue0 DCU_RETRY_LMT */ | 691 | #define AR5K_DCU_RETRY_LMT_BASE 0x1080 /* Register Address -Queue0 DCU_RETRY_LMT */ |
692 | #define AR5K_DCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */ | 692 | #define AR5K_DCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */ |
693 | #define AR5K_DCU_RETRY_LMT_SH_RETRY_S 0 | 693 | #define AR5K_DCU_RETRY_LMT_SH_RETRY_S 0 |
694 | #define AR5K_DCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry limit mask */ | 694 | #define AR5K_DCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry limit mask */ |
695 | #define AR5K_DCU_RETRY_LMT_LG_RETRY_S 4 | 695 | #define AR5K_DCU_RETRY_LMT_LG_RETRY_S 4 |
696 | #define AR5K_DCU_RETRY_LMT_SSH_RETRY 0x00003f00 /* Station short retry limit mask (?) */ | 696 | #define AR5K_DCU_RETRY_LMT_SSH_RETRY 0x00003f00 /* Station short retry limit mask (?) */ |
697 | #define AR5K_DCU_RETRY_LMT_SSH_RETRY_S 8 | 697 | #define AR5K_DCU_RETRY_LMT_SSH_RETRY_S 8 |
698 | #define AR5K_DCU_RETRY_LMT_SLG_RETRY 0x000fc000 /* Station long retry limit mask (?) */ | 698 | #define AR5K_DCU_RETRY_LMT_SLG_RETRY 0x000fc000 /* Station long retry limit mask (?) */ |
699 | #define AR5K_DCU_RETRY_LMT_SLG_RETRY_S 14 | 699 | #define AR5K_DCU_RETRY_LMT_SLG_RETRY_S 14 |
700 | #define AR5K_QUEUE_DFS_RETRY_LIMIT(_q) AR5K_QUEUE_REG(AR5K_DCU_RETRY_LMT_BASE, _q) | 700 | #define AR5K_QUEUE_DFS_RETRY_LIMIT(_q) AR5K_QUEUE_REG(AR5K_DCU_RETRY_LMT_BASE, _q) |
701 | 701 | ||
702 | /* | 702 | /* |
703 | * DCU channel time registers | 703 | * DCU channel time registers |
704 | */ | 704 | */ |
705 | #define AR5K_DCU_CHAN_TIME_BASE 0x10c0 /* Register Address -Queue0 DCU_CHAN_TIME */ | 705 | #define AR5K_DCU_CHAN_TIME_BASE 0x10c0 /* Register Address -Queue0 DCU_CHAN_TIME */ |
706 | #define AR5K_DCU_CHAN_TIME_DUR 0x000fffff /* Channel time duration */ | 706 | #define AR5K_DCU_CHAN_TIME_DUR 0x000fffff /* Channel time duration */ |
707 | #define AR5K_DCU_CHAN_TIME_DUR_S 0 | 707 | #define AR5K_DCU_CHAN_TIME_DUR_S 0 |
708 | #define AR5K_DCU_CHAN_TIME_ENABLE 0x00100000 /* Enable channel time */ | 708 | #define AR5K_DCU_CHAN_TIME_ENABLE 0x00100000 /* Enable channel time */ |
709 | #define AR5K_QUEUE_DFS_CHANNEL_TIME(_q) AR5K_QUEUE_REG(AR5K_DCU_CHAN_TIME_BASE, _q) | 709 | #define AR5K_QUEUE_DFS_CHANNEL_TIME(_q) AR5K_QUEUE_REG(AR5K_DCU_CHAN_TIME_BASE, _q) |
710 | 710 | ||
711 | /* | 711 | /* |
712 | * DCU misc registers [5211+] | 712 | * DCU misc registers [5211+] |
713 | * | 713 | * |
714 | * Note: Arbiter lockout control controls the | 714 | * Note: Arbiter lockout control controls the |
715 | * behaviour on low priority queues when we have multiple queues | 715 | * behaviour on low priority queues when we have multiple queues |
716 | * with pending frames. Intra-frame lockout means we wait until | 716 | * with pending frames. Intra-frame lockout means we wait until |
717 | * the queue's current frame transmits (with post frame backoff and bursting) | 717 | * the queue's current frame transmits (with post frame backoff and bursting) |
718 | * before we transmit anything else and global lockout means we | 718 | * before we transmit anything else and global lockout means we |
719 | * wait for the whole queue to finish before higher priority queues | 719 | * wait for the whole queue to finish before higher priority queues |
720 | * can transmit (this is used on beacon and CAB queues). | 720 | * can transmit (this is used on beacon and CAB queues). |
721 | * No lockout means there is no special handling. | 721 | * No lockout means there is no special handling. |
722 | */ | 722 | */ |
723 | #define AR5K_DCU_MISC_BASE 0x1100 /* Register Address -Queue0 DCU_MISC */ | 723 | #define AR5K_DCU_MISC_BASE 0x1100 /* Register Address -Queue0 DCU_MISC */ |
724 | #define AR5K_DCU_MISC_BACKOFF 0x0000003f /* Mask for backoff threshold */ | 724 | #define AR5K_DCU_MISC_BACKOFF 0x0000003f /* Mask for backoff threshold */ |
725 | #define AR5K_DCU_MISC_ETS_RTS_POL 0x00000040 /* End of transmission series | 725 | #define AR5K_DCU_MISC_ETS_RTS_POL 0x00000040 /* End of transmission series |
726 | station RTS/data failure count | 726 | station RTS/data failure count |
727 | reset policy (?) */ | 727 | reset policy (?) */ |
728 | #define AR5K_DCU_MISC_ETS_CW_POL 0x00000080 /* End of transmission series | 728 | #define AR5K_DCU_MISC_ETS_CW_POL 0x00000080 /* End of transmission series |
729 | CW reset policy */ | 729 | CW reset policy */ |
730 | #define AR5K_DCU_MISC_FRAG_WAIT 0x00000100 /* Wait for next fragment */ | 730 | #define AR5K_DCU_MISC_FRAG_WAIT 0x00000100 /* Wait for next fragment */ |
731 | #define AR5K_DCU_MISC_BACKOFF_FRAG 0x00000200 /* Enable backoff while bursting */ | 731 | #define AR5K_DCU_MISC_BACKOFF_FRAG 0x00000200 /* Enable backoff while bursting */ |
732 | #define AR5K_DCU_MISC_HCFPOLL_ENABLE 0x00000800 /* CF - Poll enable */ | 732 | #define AR5K_DCU_MISC_HCFPOLL_ENABLE 0x00000800 /* CF - Poll enable */ |
733 | #define AR5K_DCU_MISC_BACKOFF_PERSIST 0x00001000 /* Persistent backoff */ | 733 | #define AR5K_DCU_MISC_BACKOFF_PERSIST 0x00001000 /* Persistent backoff */ |
734 | #define AR5K_DCU_MISC_FRMPRFTCH_ENABLE 0x00002000 /* Enable frame pre-fetch */ | 734 | #define AR5K_DCU_MISC_FRMPRFTCH_ENABLE 0x00002000 /* Enable frame pre-fetch */ |
735 | #define AR5K_DCU_MISC_VIRTCOL 0x0000c000 /* Mask for Virtual Collision (?) */ | 735 | #define AR5K_DCU_MISC_VIRTCOL 0x0000c000 /* Mask for Virtual Collision (?) */ |
736 | #define AR5K_DCU_MISC_VIRTCOL_NORMAL 0 | 736 | #define AR5K_DCU_MISC_VIRTCOL_NORMAL 0 |
737 | #define AR5K_DCU_MISC_VIRTCOL_IGNORE 1 | 737 | #define AR5K_DCU_MISC_VIRTCOL_IGNORE 1 |
738 | #define AR5K_DCU_MISC_BCN_ENABLE 0x00010000 /* Enable Beacon use */ | 738 | #define AR5K_DCU_MISC_BCN_ENABLE 0x00010000 /* Enable Beacon use */ |
739 | #define AR5K_DCU_MISC_ARBLOCK_CTL 0x00060000 /* Arbiter lockout control mask */ | 739 | #define AR5K_DCU_MISC_ARBLOCK_CTL 0x00060000 /* Arbiter lockout control mask */ |
740 | #define AR5K_DCU_MISC_ARBLOCK_CTL_S 17 | 740 | #define AR5K_DCU_MISC_ARBLOCK_CTL_S 17 |
741 | #define AR5K_DCU_MISC_ARBLOCK_CTL_NONE 0 /* No arbiter lockout */ | 741 | #define AR5K_DCU_MISC_ARBLOCK_CTL_NONE 0 /* No arbiter lockout */ |
742 | #define AR5K_DCU_MISC_ARBLOCK_CTL_INTFRM 1 /* Intra-frame lockout */ | 742 | #define AR5K_DCU_MISC_ARBLOCK_CTL_INTFRM 1 /* Intra-frame lockout */ |
743 | #define AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL 2 /* Global lockout */ | 743 | #define AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL 2 /* Global lockout */ |
744 | #define AR5K_DCU_MISC_ARBLOCK_IGNORE 0x00080000 /* Ignore Arbiter lockout */ | 744 | #define AR5K_DCU_MISC_ARBLOCK_IGNORE 0x00080000 /* Ignore Arbiter lockout */ |
745 | #define AR5K_DCU_MISC_SEQ_NUM_INCR_DIS 0x00100000 /* Disable sequence number increment */ | 745 | #define AR5K_DCU_MISC_SEQ_NUM_INCR_DIS 0x00100000 /* Disable sequence number increment */ |
746 | #define AR5K_DCU_MISC_POST_FR_BKOFF_DIS 0x00200000 /* Disable post-frame backoff */ | 746 | #define AR5K_DCU_MISC_POST_FR_BKOFF_DIS 0x00200000 /* Disable post-frame backoff */ |
747 | #define AR5K_DCU_MISC_VIRT_COLL_POLICY 0x00400000 /* Virtual Collision cw policy */ | 747 | #define AR5K_DCU_MISC_VIRT_COLL_POLICY 0x00400000 /* Virtual Collision cw policy */ |
748 | #define AR5K_DCU_MISC_BLOWN_IFS_POLICY 0x00800000 /* Blown IFS policy (?) */ | 748 | #define AR5K_DCU_MISC_BLOWN_IFS_POLICY 0x00800000 /* Blown IFS policy (?) */ |
749 | #define AR5K_DCU_MISC_SEQNUM_CTL 0x01000000 /* Sequence number control (?) */ | 749 | #define AR5K_DCU_MISC_SEQNUM_CTL 0x01000000 /* Sequence number control (?) */ |
750 | #define AR5K_QUEUE_DFS_MISC(_q) AR5K_QUEUE_REG(AR5K_DCU_MISC_BASE, _q) | 750 | #define AR5K_QUEUE_DFS_MISC(_q) AR5K_QUEUE_REG(AR5K_DCU_MISC_BASE, _q) |
751 | 751 | ||
752 | /* | 752 | /* |
753 | * DCU frame sequence number registers | 753 | * DCU frame sequence number registers |
754 | */ | 754 | */ |
755 | #define AR5K_DCU_SEQNUM_BASE 0x1140 | 755 | #define AR5K_DCU_SEQNUM_BASE 0x1140 |
756 | #define AR5K_DCU_SEQNUM_M 0x00000fff | 756 | #define AR5K_DCU_SEQNUM_M 0x00000fff |
757 | #define AR5K_QUEUE_DCU_SEQNUM(_q) AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q) | 757 | #define AR5K_QUEUE_DCU_SEQNUM(_q) AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q) |
758 | 758 | ||
759 | /* | 759 | /* |
760 | * DCU global IFS SIFS register | 760 | * DCU global IFS SIFS register |
761 | */ | 761 | */ |
762 | #define AR5K_DCU_GBL_IFS_SIFS 0x1030 | 762 | #define AR5K_DCU_GBL_IFS_SIFS 0x1030 |
763 | #define AR5K_DCU_GBL_IFS_SIFS_M 0x0000ffff | 763 | #define AR5K_DCU_GBL_IFS_SIFS_M 0x0000ffff |
764 | 764 | ||
765 | /* | 765 | /* |
766 | * DCU global IFS slot interval register | 766 | * DCU global IFS slot interval register |
767 | */ | 767 | */ |
768 | #define AR5K_DCU_GBL_IFS_SLOT 0x1070 | 768 | #define AR5K_DCU_GBL_IFS_SLOT 0x1070 |
769 | #define AR5K_DCU_GBL_IFS_SLOT_M 0x0000ffff | 769 | #define AR5K_DCU_GBL_IFS_SLOT_M 0x0000ffff |
770 | 770 | ||
771 | /* | 771 | /* |
772 | * DCU global IFS EIFS register | 772 | * DCU global IFS EIFS register |
773 | */ | 773 | */ |
774 | #define AR5K_DCU_GBL_IFS_EIFS 0x10b0 | 774 | #define AR5K_DCU_GBL_IFS_EIFS 0x10b0 |
775 | #define AR5K_DCU_GBL_IFS_EIFS_M 0x0000ffff | 775 | #define AR5K_DCU_GBL_IFS_EIFS_M 0x0000ffff |
776 | 776 | ||
777 | /* | 777 | /* |
778 | * DCU global IFS misc register | 778 | * DCU global IFS misc register |
779 | * | 779 | * |
780 | * LFSR stands for Linear Feedback Shift Register | 780 | * LFSR stands for Linear Feedback Shift Register |
781 | * and it's used for generating pseudo-random | 781 | * and it's used for generating pseudo-random |
782 | * number sequences. | 782 | * number sequences. |
783 | * | 783 | * |
784 | * (If i understand corectly, random numbers are | 784 | * (If i understand corectly, random numbers are |
785 | * used for idle sensing -multiplied with cwmin/max etc-) | 785 | * used for idle sensing -multiplied with cwmin/max etc-) |
786 | */ | 786 | */ |
787 | #define AR5K_DCU_GBL_IFS_MISC 0x10f0 /* Register Address */ | 787 | #define AR5K_DCU_GBL_IFS_MISC 0x10f0 /* Register Address */ |
788 | #define AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE 0x00000007 /* LFSR Slice Select */ | 788 | #define AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE 0x00000007 /* LFSR Slice Select */ |
789 | #define AR5K_DCU_GBL_IFS_MISC_TURBO_MODE 0x00000008 /* Turbo mode */ | 789 | #define AR5K_DCU_GBL_IFS_MISC_TURBO_MODE 0x00000008 /* Turbo mode */ |
790 | #define AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC 0x000003f0 /* SIFS Duration mask */ | 790 | #define AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC 0x000003f0 /* SIFS Duration mask */ |
791 | #define AR5K_DCU_GBL_IFS_MISC_USEC_DUR 0x000ffc00 /* USEC Duration mask */ | 791 | #define AR5K_DCU_GBL_IFS_MISC_USEC_DUR 0x000ffc00 /* USEC Duration mask */ |
792 | #define AR5K_DCU_GBL_IFS_MISC_USEC_DUR_S 10 | 792 | #define AR5K_DCU_GBL_IFS_MISC_USEC_DUR_S 10 |
793 | #define AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY 0x00300000 /* DCU Arbiter delay mask */ | 793 | #define AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY 0x00300000 /* DCU Arbiter delay mask */ |
794 | #define AR5K_DCU_GBL_IFS_MISC_SIFS_CNT_RST 0x00400000 /* SIFS cnt reset policy (?) */ | 794 | #define AR5K_DCU_GBL_IFS_MISC_SIFS_CNT_RST 0x00400000 /* SIFS cnt reset policy (?) */ |
795 | #define AR5K_DCU_GBL_IFS_MISC_AIFS_CNT_RST 0x00800000 /* AIFS cnt reset policy (?) */ | 795 | #define AR5K_DCU_GBL_IFS_MISC_AIFS_CNT_RST 0x00800000 /* AIFS cnt reset policy (?) */ |
796 | #define AR5K_DCU_GBL_IFS_MISC_RND_LFSR_SL_DIS 0x01000000 /* Disable random LFSR slice */ | 796 | #define AR5K_DCU_GBL_IFS_MISC_RND_LFSR_SL_DIS 0x01000000 /* Disable random LFSR slice */ |
797 | 797 | ||
798 | /* | 798 | /* |
799 | * DCU frame prefetch control register | 799 | * DCU frame prefetch control register |
800 | */ | 800 | */ |
801 | #define AR5K_DCU_FP 0x1230 /* Register Address */ | 801 | #define AR5K_DCU_FP 0x1230 /* Register Address */ |
802 | #define AR5K_DCU_FP_NOBURST_DCU_EN 0x00000001 /* Enable non-burst prefetch on DCU (?) */ | 802 | #define AR5K_DCU_FP_NOBURST_DCU_EN 0x00000001 /* Enable non-burst prefetch on DCU (?) */ |
803 | #define AR5K_DCU_FP_NOBURST_EN 0x00000010 /* Enable non-burst prefetch (?) */ | 803 | #define AR5K_DCU_FP_NOBURST_EN 0x00000010 /* Enable non-burst prefetch (?) */ |
804 | #define AR5K_DCU_FP_BURST_DCU_EN 0x00000020 /* Enable burst prefetch on DCU (?) */ | 804 | #define AR5K_DCU_FP_BURST_DCU_EN 0x00000020 /* Enable burst prefetch on DCU (?) */ |
805 | 805 | ||
806 | /* | 806 | /* |
807 | * DCU transmit pause control/status register | 807 | * DCU transmit pause control/status register |
808 | */ | 808 | */ |
809 | #define AR5K_DCU_TXP 0x1270 /* Register Address */ | 809 | #define AR5K_DCU_TXP 0x1270 /* Register Address */ |
810 | #define AR5K_DCU_TXP_M 0x000003ff /* Tx pause mask */ | 810 | #define AR5K_DCU_TXP_M 0x000003ff /* Tx pause mask */ |
811 | #define AR5K_DCU_TXP_STATUS 0x00010000 /* Tx pause status */ | 811 | #define AR5K_DCU_TXP_STATUS 0x00010000 /* Tx pause status */ |
812 | 812 | ||
813 | /* | 813 | /* |
814 | * DCU transmit filter table 0 (32 entries) | 814 | * DCU transmit filter table 0 (32 entries) |
815 | * each entry contains a 32bit slice of the | 815 | * each entry contains a 32bit slice of the |
816 | * 128bit tx filter for each DCU (4 slices per DCU) | 816 | * 128bit tx filter for each DCU (4 slices per DCU) |
817 | */ | 817 | */ |
818 | #define AR5K_DCU_TX_FILTER_0_BASE 0x1038 | 818 | #define AR5K_DCU_TX_FILTER_0_BASE 0x1038 |
819 | #define AR5K_DCU_TX_FILTER_0(_n) (AR5K_DCU_TX_FILTER_0_BASE + (_n * 64)) | 819 | #define AR5K_DCU_TX_FILTER_0(_n) (AR5K_DCU_TX_FILTER_0_BASE + (_n * 64)) |
820 | 820 | ||
821 | /* | 821 | /* |
822 | * DCU transmit filter table 1 (16 entries) | 822 | * DCU transmit filter table 1 (16 entries) |
823 | */ | 823 | */ |
824 | #define AR5K_DCU_TX_FILTER_1_BASE 0x103c | 824 | #define AR5K_DCU_TX_FILTER_1_BASE 0x103c |
825 | #define AR5K_DCU_TX_FILTER_1(_n) (AR5K_DCU_TX_FILTER_1_BASE + (_n * 64)) | 825 | #define AR5K_DCU_TX_FILTER_1(_n) (AR5K_DCU_TX_FILTER_1_BASE + (_n * 64)) |
826 | 826 | ||
827 | /* | 827 | /* |
828 | * DCU clear transmit filter register | 828 | * DCU clear transmit filter register |
829 | */ | 829 | */ |
830 | #define AR5K_DCU_TX_FILTER_CLR 0x143c | 830 | #define AR5K_DCU_TX_FILTER_CLR 0x143c |
831 | 831 | ||
832 | /* | 832 | /* |
833 | * DCU set transmit filter register | 833 | * DCU set transmit filter register |
834 | */ | 834 | */ |
835 | #define AR5K_DCU_TX_FILTER_SET 0x147c | 835 | #define AR5K_DCU_TX_FILTER_SET 0x147c |
836 | 836 | ||
837 | /* | 837 | /* |
838 | * Reset control register | 838 | * Reset control register |
839 | */ | 839 | */ |
840 | #define AR5K_RESET_CTL 0x4000 /* Register Address */ | 840 | #define AR5K_RESET_CTL 0x4000 /* Register Address */ |
841 | #define AR5K_RESET_CTL_PCU 0x00000001 /* Protocol Control Unit reset */ | 841 | #define AR5K_RESET_CTL_PCU 0x00000001 /* Protocol Control Unit reset */ |
842 | #define AR5K_RESET_CTL_DMA 0x00000002 /* DMA (Rx/Tx) reset [5210] */ | 842 | #define AR5K_RESET_CTL_DMA 0x00000002 /* DMA (Rx/Tx) reset [5210] */ |
843 | #define AR5K_RESET_CTL_BASEBAND 0x00000002 /* Baseband reset [5211+] */ | 843 | #define AR5K_RESET_CTL_BASEBAND 0x00000002 /* Baseband reset [5211+] */ |
844 | #define AR5K_RESET_CTL_MAC 0x00000004 /* MAC reset (PCU+Baseband ?) [5210] */ | 844 | #define AR5K_RESET_CTL_MAC 0x00000004 /* MAC reset (PCU+Baseband ?) [5210] */ |
845 | #define AR5K_RESET_CTL_PHY 0x00000008 /* PHY reset [5210] */ | 845 | #define AR5K_RESET_CTL_PHY 0x00000008 /* PHY reset [5210] */ |
846 | #define AR5K_RESET_CTL_PCI 0x00000010 /* PCI Core reset (interrupts etc) */ | 846 | #define AR5K_RESET_CTL_PCI 0x00000010 /* PCI Core reset (interrupts etc) */ |
847 | 847 | ||
848 | /* | 848 | /* |
849 | * Sleep control register | 849 | * Sleep control register |
850 | */ | 850 | */ |
851 | #define AR5K_SLEEP_CTL 0x4004 /* Register Address */ | 851 | #define AR5K_SLEEP_CTL 0x4004 /* Register Address */ |
852 | #define AR5K_SLEEP_CTL_SLDUR 0x0000ffff /* Sleep duration mask */ | 852 | #define AR5K_SLEEP_CTL_SLDUR 0x0000ffff /* Sleep duration mask */ |
853 | #define AR5K_SLEEP_CTL_SLDUR_S 0 | 853 | #define AR5K_SLEEP_CTL_SLDUR_S 0 |
854 | #define AR5K_SLEEP_CTL_SLE 0x00030000 /* Sleep enable mask */ | 854 | #define AR5K_SLEEP_CTL_SLE 0x00030000 /* Sleep enable mask */ |
855 | #define AR5K_SLEEP_CTL_SLE_S 16 | 855 | #define AR5K_SLEEP_CTL_SLE_S 16 |
856 | #define AR5K_SLEEP_CTL_SLE_WAKE 0x00000000 /* Force chip awake */ | 856 | #define AR5K_SLEEP_CTL_SLE_WAKE 0x00000000 /* Force chip awake */ |
857 | #define AR5K_SLEEP_CTL_SLE_SLP 0x00010000 /* Force chip sleep */ | 857 | #define AR5K_SLEEP_CTL_SLE_SLP 0x00010000 /* Force chip sleep */ |
858 | #define AR5K_SLEEP_CTL_SLE_ALLOW 0x00020000 /* Normal sleep policy */ | 858 | #define AR5K_SLEEP_CTL_SLE_ALLOW 0x00020000 /* Normal sleep policy */ |
859 | #define AR5K_SLEEP_CTL_SLE_UNITS 0x00000008 /* [5211+] */ | 859 | #define AR5K_SLEEP_CTL_SLE_UNITS 0x00000008 /* [5211+] */ |
860 | #define AR5K_SLEEP_CTL_DUR_TIM_POL 0x00040000 /* Sleep duration timing policy */ | 860 | #define AR5K_SLEEP_CTL_DUR_TIM_POL 0x00040000 /* Sleep duration timing policy */ |
861 | #define AR5K_SLEEP_CTL_DUR_WRITE_POL 0x00080000 /* Sleep duration write policy */ | 861 | #define AR5K_SLEEP_CTL_DUR_WRITE_POL 0x00080000 /* Sleep duration write policy */ |
862 | #define AR5K_SLEEP_CTL_SLE_POL 0x00100000 /* Sleep policy mode */ | 862 | #define AR5K_SLEEP_CTL_SLE_POL 0x00100000 /* Sleep policy mode */ |
863 | 863 | ||
864 | /* | 864 | /* |
865 | * Interrupt pending register | 865 | * Interrupt pending register |
866 | */ | 866 | */ |
867 | #define AR5K_INTPEND 0x4008 | 867 | #define AR5K_INTPEND 0x4008 |
868 | #define AR5K_INTPEND_M 0x00000001 | 868 | #define AR5K_INTPEND_M 0x00000001 |
869 | 869 | ||
870 | /* | 870 | /* |
871 | * Sleep force register | 871 | * Sleep force register |
872 | */ | 872 | */ |
873 | #define AR5K_SFR 0x400c | 873 | #define AR5K_SFR 0x400c |
874 | #define AR5K_SFR_EN 0x00000001 | 874 | #define AR5K_SFR_EN 0x00000001 |
875 | 875 | ||
876 | /* | 876 | /* |
877 | * PCI configuration register | 877 | * PCI configuration register |
878 | * TODO: Fix LED stuff | 878 | * TODO: Fix LED stuff |
879 | */ | 879 | */ |
880 | #define AR5K_PCICFG 0x4010 /* Register Address */ | 880 | #define AR5K_PCICFG 0x4010 /* Register Address */ |
881 | #define AR5K_PCICFG_EEAE 0x00000001 /* Eeprom access enable [5210] */ | 881 | #define AR5K_PCICFG_EEAE 0x00000001 /* Eeprom access enable [5210] */ |
882 | #define AR5K_PCICFG_SLEEP_CLOCK_EN 0x00000002 /* Enable sleep clock */ | 882 | #define AR5K_PCICFG_SLEEP_CLOCK_EN 0x00000002 /* Enable sleep clock */ |
883 | #define AR5K_PCICFG_CLKRUNEN 0x00000004 /* CLKRUN enable [5211+] */ | 883 | #define AR5K_PCICFG_CLKRUNEN 0x00000004 /* CLKRUN enable [5211+] */ |
884 | #define AR5K_PCICFG_EESIZE 0x00000018 /* Mask for EEPROM size [5211+] */ | 884 | #define AR5K_PCICFG_EESIZE 0x00000018 /* Mask for EEPROM size [5211+] */ |
885 | #define AR5K_PCICFG_EESIZE_S 3 | 885 | #define AR5K_PCICFG_EESIZE_S 3 |
886 | #define AR5K_PCICFG_EESIZE_4K 0 /* 4K */ | 886 | #define AR5K_PCICFG_EESIZE_4K 0 /* 4K */ |
887 | #define AR5K_PCICFG_EESIZE_8K 1 /* 8K */ | 887 | #define AR5K_PCICFG_EESIZE_8K 1 /* 8K */ |
888 | #define AR5K_PCICFG_EESIZE_16K 2 /* 16K */ | 888 | #define AR5K_PCICFG_EESIZE_16K 2 /* 16K */ |
889 | #define AR5K_PCICFG_EESIZE_FAIL 3 /* Failed to get size [5211+] */ | 889 | #define AR5K_PCICFG_EESIZE_FAIL 3 /* Failed to get size [5211+] */ |
890 | #define AR5K_PCICFG_LED 0x00000060 /* Led status [5211+] */ | 890 | #define AR5K_PCICFG_LED 0x00000060 /* Led status [5211+] */ |
891 | #define AR5K_PCICFG_LED_NONE 0x00000000 /* Default [5211+] */ | 891 | #define AR5K_PCICFG_LED_NONE 0x00000000 /* Default [5211+] */ |
892 | #define AR5K_PCICFG_LED_PEND 0x00000020 /* Scan / Auth pending */ | 892 | #define AR5K_PCICFG_LED_PEND 0x00000020 /* Scan / Auth pending */ |
893 | #define AR5K_PCICFG_LED_ASSOC 0x00000040 /* Associated */ | 893 | #define AR5K_PCICFG_LED_ASSOC 0x00000040 /* Associated */ |
894 | #define AR5K_PCICFG_BUS_SEL 0x00000380 /* Mask for "bus select" [5211+] (?) */ | 894 | #define AR5K_PCICFG_BUS_SEL 0x00000380 /* Mask for "bus select" [5211+] (?) */ |
895 | #define AR5K_PCICFG_CBEFIX_DIS 0x00000400 /* Disable CBE fix */ | 895 | #define AR5K_PCICFG_CBEFIX_DIS 0x00000400 /* Disable CBE fix */ |
896 | #define AR5K_PCICFG_SL_INTEN 0x00000800 /* Enable interrupts when asleep */ | 896 | #define AR5K_PCICFG_SL_INTEN 0x00000800 /* Enable interrupts when asleep */ |
897 | #define AR5K_PCICFG_LED_BCTL 0x00001000 /* Led blink (?) [5210] */ | 897 | #define AR5K_PCICFG_LED_BCTL 0x00001000 /* Led blink (?) [5210] */ |
898 | #define AR5K_PCICFG_RETRY_FIX 0x00001000 /* Enable pci core retry fix */ | 898 | #define AR5K_PCICFG_RETRY_FIX 0x00001000 /* Enable pci core retry fix */ |
899 | #define AR5K_PCICFG_SL_INPEN 0x00002000 /* Sleep even whith pending interrupts*/ | 899 | #define AR5K_PCICFG_SL_INPEN 0x00002000 /* Sleep even whith pending interrupts*/ |
900 | #define AR5K_PCICFG_SPWR_DN 0x00010000 /* Mask for power status */ | 900 | #define AR5K_PCICFG_SPWR_DN 0x00010000 /* Mask for power status */ |
901 | #define AR5K_PCICFG_LEDMODE 0x000e0000 /* Ledmode [5211+] */ | 901 | #define AR5K_PCICFG_LEDMODE 0x000e0000 /* Ledmode [5211+] */ |
902 | #define AR5K_PCICFG_LEDMODE_PROP 0x00000000 /* Blink on standard traffic [5211+] */ | 902 | #define AR5K_PCICFG_LEDMODE_PROP 0x00000000 /* Blink on standard traffic [5211+] */ |
903 | #define AR5K_PCICFG_LEDMODE_PROM 0x00020000 /* Default mode (blink on any traffic) [5211+] */ | 903 | #define AR5K_PCICFG_LEDMODE_PROM 0x00020000 /* Default mode (blink on any traffic) [5211+] */ |
904 | #define AR5K_PCICFG_LEDMODE_PWR 0x00040000 /* Some other blinking mode (?) [5211+] */ | 904 | #define AR5K_PCICFG_LEDMODE_PWR 0x00040000 /* Some other blinking mode (?) [5211+] */ |
905 | #define AR5K_PCICFG_LEDMODE_RAND 0x00060000 /* Random blinking (?) [5211+] */ | 905 | #define AR5K_PCICFG_LEDMODE_RAND 0x00060000 /* Random blinking (?) [5211+] */ |
906 | #define AR5K_PCICFG_LEDBLINK 0x00700000 /* Led blink rate */ | 906 | #define AR5K_PCICFG_LEDBLINK 0x00700000 /* Led blink rate */ |
907 | #define AR5K_PCICFG_LEDBLINK_S 20 | 907 | #define AR5K_PCICFG_LEDBLINK_S 20 |
908 | #define AR5K_PCICFG_LEDSLOW 0x00800000 /* Slowest led blink rate [5211+] */ | 908 | #define AR5K_PCICFG_LEDSLOW 0x00800000 /* Slowest led blink rate [5211+] */ |
909 | #define AR5K_PCICFG_LEDSTATE \ | 909 | #define AR5K_PCICFG_LEDSTATE \ |
910 | (AR5K_PCICFG_LED | AR5K_PCICFG_LEDMODE | \ | 910 | (AR5K_PCICFG_LED | AR5K_PCICFG_LEDMODE | \ |
911 | AR5K_PCICFG_LEDBLINK | AR5K_PCICFG_LEDSLOW) | 911 | AR5K_PCICFG_LEDBLINK | AR5K_PCICFG_LEDSLOW) |
912 | #define AR5K_PCICFG_SLEEP_CLOCK_RATE 0x03000000 /* Sleep clock rate */ | 912 | #define AR5K_PCICFG_SLEEP_CLOCK_RATE 0x03000000 /* Sleep clock rate */ |
913 | #define AR5K_PCICFG_SLEEP_CLOCK_RATE_S 24 | 913 | #define AR5K_PCICFG_SLEEP_CLOCK_RATE_S 24 |
914 | 914 | ||
915 | /* | 915 | /* |
916 | * "General Purpose Input/Output" (GPIO) control register | 916 | * "General Purpose Input/Output" (GPIO) control register |
917 | * | 917 | * |
918 | * I'm not sure about this but after looking at the code | 918 | * I'm not sure about this but after looking at the code |
919 | * for all chipsets here is what i got. | 919 | * for all chipsets here is what i got. |
920 | * | 920 | * |
921 | * We have 6 GPIOs (pins), each GPIO has 4 modes (2 bits) | 921 | * We have 6 GPIOs (pins), each GPIO has 4 modes (2 bits) |
922 | * Mode 0 -> always input | 922 | * Mode 0 -> always input |
923 | * Mode 1 -> output when GPIODO for this GPIO is set to 0 | 923 | * Mode 1 -> output when GPIODO for this GPIO is set to 0 |
924 | * Mode 2 -> output when GPIODO for this GPIO is set to 1 | 924 | * Mode 2 -> output when GPIODO for this GPIO is set to 1 |
925 | * Mode 3 -> always output | 925 | * Mode 3 -> always output |
926 | * | 926 | * |
927 | * For more infos check out get_gpio/set_gpio and | 927 | * For more infos check out get_gpio/set_gpio and |
928 | * set_gpio_input/set_gpio_output functs. | 928 | * set_gpio_input/set_gpio_output functs. |
929 | * For more infos on gpio interrupt check out set_gpio_intr. | 929 | * For more infos on gpio interrupt check out set_gpio_intr. |
930 | */ | 930 | */ |
931 | #define AR5K_NUM_GPIO 6 | 931 | #define AR5K_NUM_GPIO 6 |
932 | 932 | ||
933 | #define AR5K_GPIOCR 0x4014 /* Register Address */ | 933 | #define AR5K_GPIOCR 0x4014 /* Register Address */ |
934 | #define AR5K_GPIOCR_INT_ENA 0x00008000 /* Enable GPIO interrupt */ | 934 | #define AR5K_GPIOCR_INT_ENA 0x00008000 /* Enable GPIO interrupt */ |
935 | #define AR5K_GPIOCR_INT_SELL 0x00000000 /* Generate interrupt when pin is low */ | 935 | #define AR5K_GPIOCR_INT_SELL 0x00000000 /* Generate interrupt when pin is low */ |
936 | #define AR5K_GPIOCR_INT_SELH 0x00010000 /* Generate interrupt when pin is high */ | 936 | #define AR5K_GPIOCR_INT_SELH 0x00010000 /* Generate interrupt when pin is high */ |
937 | #define AR5K_GPIOCR_IN(n) (0 << ((n) * 2)) /* Mode 0 for pin n */ | 937 | #define AR5K_GPIOCR_IN(n) (0 << ((n) * 2)) /* Mode 0 for pin n */ |
938 | #define AR5K_GPIOCR_OUT0(n) (1 << ((n) * 2)) /* Mode 1 for pin n */ | 938 | #define AR5K_GPIOCR_OUT0(n) (1 << ((n) * 2)) /* Mode 1 for pin n */ |
939 | #define AR5K_GPIOCR_OUT1(n) (2 << ((n) * 2)) /* Mode 2 for pin n */ | 939 | #define AR5K_GPIOCR_OUT1(n) (2 << ((n) * 2)) /* Mode 2 for pin n */ |
940 | #define AR5K_GPIOCR_OUT(n) (3 << ((n) * 2)) /* Mode 3 for pin n */ | 940 | #define AR5K_GPIOCR_OUT(n) (3 << ((n) * 2)) /* Mode 3 for pin n */ |
941 | #define AR5K_GPIOCR_INT_SEL(n) ((n) << 12) /* Interrupt for GPIO pin n */ | 941 | #define AR5K_GPIOCR_INT_SEL(n) ((n) << 12) /* Interrupt for GPIO pin n */ |
942 | 942 | ||
943 | /* | 943 | /* |
944 | * "General Purpose Input/Output" (GPIO) data output register | 944 | * "General Purpose Input/Output" (GPIO) data output register |
945 | */ | 945 | */ |
946 | #define AR5K_GPIODO 0x4018 | 946 | #define AR5K_GPIODO 0x4018 |
947 | 947 | ||
948 | /* | 948 | /* |
949 | * "General Purpose Input/Output" (GPIO) data input register | 949 | * "General Purpose Input/Output" (GPIO) data input register |
950 | */ | 950 | */ |
951 | #define AR5K_GPIODI 0x401c | 951 | #define AR5K_GPIODI 0x401c |
952 | #define AR5K_GPIODI_M 0x0000002f | 952 | #define AR5K_GPIODI_M 0x0000002f |
953 | 953 | ||
954 | /* | 954 | /* |
955 | * Silicon revision register | 955 | * Silicon revision register |
956 | */ | 956 | */ |
957 | #define AR5K_SREV 0x4020 /* Register Address */ | 957 | #define AR5K_SREV 0x4020 /* Register Address */ |
958 | #define AR5K_SREV_REV 0x0000000f /* Mask for revision */ | 958 | #define AR5K_SREV_REV 0x0000000f /* Mask for revision */ |
959 | #define AR5K_SREV_REV_S 0 | 959 | #define AR5K_SREV_REV_S 0 |
960 | #define AR5K_SREV_VER 0x000000ff /* Mask for version */ | 960 | #define AR5K_SREV_VER 0x000000ff /* Mask for version */ |
961 | #define AR5K_SREV_VER_S 4 | 961 | #define AR5K_SREV_VER_S 4 |
962 | 962 | ||
963 | /* | 963 | /* |
964 | * TXE write posting register | 964 | * TXE write posting register |
965 | */ | 965 | */ |
966 | #define AR5K_TXEPOST 0x4028 | 966 | #define AR5K_TXEPOST 0x4028 |
967 | 967 | ||
968 | /* | 968 | /* |
969 | * QCU sleep mask | 969 | * QCU sleep mask |
970 | */ | 970 | */ |
971 | #define AR5K_QCU_SLEEP_MASK 0x402c | 971 | #define AR5K_QCU_SLEEP_MASK 0x402c |
972 | 972 | ||
973 | /* 0x4068 is compression buffer configuration | 973 | /* 0x4068 is compression buffer configuration |
974 | * register on 5414 and pm configuration register | 974 | * register on 5414 and pm configuration register |
975 | * on 5424 and newer pci-e chips. */ | 975 | * on 5424 and newer pci-e chips. */ |
976 | 976 | ||
977 | /* | 977 | /* |
978 | * Compression buffer configuration | 978 | * Compression buffer configuration |
979 | * register (enable/disable) [5414] | 979 | * register (enable/disable) [5414] |
980 | */ | 980 | */ |
981 | #define AR5K_5414_CBCFG 0x4068 | 981 | #define AR5K_5414_CBCFG 0x4068 |
982 | #define AR5K_5414_CBCFG_BUF_DIS 0x10 /* Disable buffer */ | 982 | #define AR5K_5414_CBCFG_BUF_DIS 0x10 /* Disable buffer */ |
983 | 983 | ||
984 | /* | 984 | /* |
985 | * PCI-E Power managment configuration | 985 | * PCI-E Power management configuration |
986 | * and status register [5424+] | 986 | * and status register [5424+] |
987 | */ | 987 | */ |
988 | #define AR5K_PCIE_PM_CTL 0x4068 /* Register address */ | 988 | #define AR5K_PCIE_PM_CTL 0x4068 /* Register address */ |
989 | /* Only 5424 */ | 989 | /* Only 5424 */ |
990 | #define AR5K_PCIE_PM_CTL_L1_WHEN_D2 0x00000001 /* enable PCIe core enter L1 | 990 | #define AR5K_PCIE_PM_CTL_L1_WHEN_D2 0x00000001 /* enable PCIe core enter L1 |
991 | when d2_sleep_en is asserted */ | 991 | when d2_sleep_en is asserted */ |
992 | #define AR5K_PCIE_PM_CTL_L0_L0S_CLEAR 0x00000002 /* Clear L0 and L0S counters */ | 992 | #define AR5K_PCIE_PM_CTL_L0_L0S_CLEAR 0x00000002 /* Clear L0 and L0S counters */ |
993 | #define AR5K_PCIE_PM_CTL_L0_L0S_EN 0x00000004 /* Start L0 nd L0S counters */ | 993 | #define AR5K_PCIE_PM_CTL_L0_L0S_EN 0x00000004 /* Start L0 nd L0S counters */ |
994 | #define AR5K_PCIE_PM_CTL_LDRESET_EN 0x00000008 /* Enable reset when link goes | 994 | #define AR5K_PCIE_PM_CTL_LDRESET_EN 0x00000008 /* Enable reset when link goes |
995 | down */ | 995 | down */ |
996 | /* Wake On Wireless */ | 996 | /* Wake On Wireless */ |
997 | #define AR5K_PCIE_PM_CTL_PME_EN 0x00000010 /* PME Enable */ | 997 | #define AR5K_PCIE_PM_CTL_PME_EN 0x00000010 /* PME Enable */ |
998 | #define AR5K_PCIE_PM_CTL_AUX_PWR_DET 0x00000020 /* Aux power detect */ | 998 | #define AR5K_PCIE_PM_CTL_AUX_PWR_DET 0x00000020 /* Aux power detect */ |
999 | #define AR5K_PCIE_PM_CTL_PME_CLEAR 0x00000040 /* Clear PME */ | 999 | #define AR5K_PCIE_PM_CTL_PME_CLEAR 0x00000040 /* Clear PME */ |
1000 | #define AR5K_PCIE_PM_CTL_PSM_D0 0x00000080 | 1000 | #define AR5K_PCIE_PM_CTL_PSM_D0 0x00000080 |
1001 | #define AR5K_PCIE_PM_CTL_PSM_D1 0x00000100 | 1001 | #define AR5K_PCIE_PM_CTL_PSM_D1 0x00000100 |
1002 | #define AR5K_PCIE_PM_CTL_PSM_D2 0x00000200 | 1002 | #define AR5K_PCIE_PM_CTL_PSM_D2 0x00000200 |
1003 | #define AR5K_PCIE_PM_CTL_PSM_D3 0x00000400 | 1003 | #define AR5K_PCIE_PM_CTL_PSM_D3 0x00000400 |
1004 | 1004 | ||
1005 | /* | 1005 | /* |
1006 | * PCI-E Workaround enable register | 1006 | * PCI-E Workaround enable register |
1007 | */ | 1007 | */ |
1008 | #define AR5K_PCIE_WAEN 0x407c | 1008 | #define AR5K_PCIE_WAEN 0x407c |
1009 | 1009 | ||
1010 | /* | 1010 | /* |
1011 | * PCI-E Serializer/Desirializer | 1011 | * PCI-E Serializer/Desirializer |
1012 | * registers | 1012 | * registers |
1013 | */ | 1013 | */ |
1014 | #define AR5K_PCIE_SERDES 0x4080 | 1014 | #define AR5K_PCIE_SERDES 0x4080 |
1015 | #define AR5K_PCIE_SERDES_RESET 0x4084 | 1015 | #define AR5K_PCIE_SERDES_RESET 0x4084 |
1016 | 1016 | ||
1017 | /*====EEPROM REGISTERS====*/ | 1017 | /*====EEPROM REGISTERS====*/ |
1018 | 1018 | ||
1019 | /* | 1019 | /* |
1020 | * EEPROM access registers | 1020 | * EEPROM access registers |
1021 | * | 1021 | * |
1022 | * Here we got a difference between 5210/5211-12 | 1022 | * Here we got a difference between 5210/5211-12 |
1023 | * read data register for 5210 is at 0x6800 and | 1023 | * read data register for 5210 is at 0x6800 and |
1024 | * status register is at 0x6c00. There is also | 1024 | * status register is at 0x6c00. There is also |
1025 | * no eeprom command register on 5210 and the | 1025 | * no eeprom command register on 5210 and the |
1026 | * offsets are different. | 1026 | * offsets are different. |
1027 | * | 1027 | * |
1028 | * To read eeprom data for a specific offset: | 1028 | * To read eeprom data for a specific offset: |
1029 | * 5210 - enable eeprom access (AR5K_PCICFG_EEAE) | 1029 | * 5210 - enable eeprom access (AR5K_PCICFG_EEAE) |
1030 | * read AR5K_EEPROM_BASE +(4 * offset) | 1030 | * read AR5K_EEPROM_BASE +(4 * offset) |
1031 | * check the eeprom status register | 1031 | * check the eeprom status register |
1032 | * and read eeprom data register. | 1032 | * and read eeprom data register. |
1033 | * | 1033 | * |
1034 | * 5211 - write offset to AR5K_EEPROM_BASE | 1034 | * 5211 - write offset to AR5K_EEPROM_BASE |
1035 | * 5212 write AR5K_EEPROM_CMD_READ on AR5K_EEPROM_CMD | 1035 | * 5212 write AR5K_EEPROM_CMD_READ on AR5K_EEPROM_CMD |
1036 | * check the eeprom status register | 1036 | * check the eeprom status register |
1037 | * and read eeprom data register. | 1037 | * and read eeprom data register. |
1038 | * | 1038 | * |
1039 | * To write eeprom data for a specific offset: | 1039 | * To write eeprom data for a specific offset: |
1040 | * 5210 - enable eeprom access (AR5K_PCICFG_EEAE) | 1040 | * 5210 - enable eeprom access (AR5K_PCICFG_EEAE) |
1041 | * write data to AR5K_EEPROM_BASE +(4 * offset) | 1041 | * write data to AR5K_EEPROM_BASE +(4 * offset) |
1042 | * check the eeprom status register | 1042 | * check the eeprom status register |
1043 | * 5211 - write AR5K_EEPROM_CMD_RESET on AR5K_EEPROM_CMD | 1043 | * 5211 - write AR5K_EEPROM_CMD_RESET on AR5K_EEPROM_CMD |
1044 | * 5212 write offset to AR5K_EEPROM_BASE | 1044 | * 5212 write offset to AR5K_EEPROM_BASE |
1045 | * write data to data register | 1045 | * write data to data register |
1046 | * write AR5K_EEPROM_CMD_WRITE on AR5K_EEPROM_CMD | 1046 | * write AR5K_EEPROM_CMD_WRITE on AR5K_EEPROM_CMD |
1047 | * check the eeprom status register | 1047 | * check the eeprom status register |
1048 | * | 1048 | * |
1049 | * For more infos check eeprom_* functs and the ar5k.c | 1049 | * For more infos check eeprom_* functs and the ar5k.c |
1050 | * file posted in madwifi-devel mailing list. | 1050 | * file posted in madwifi-devel mailing list. |
1051 | * http://sourceforge.net/mailarchive/message.php?msg_id=8966525 | 1051 | * http://sourceforge.net/mailarchive/message.php?msg_id=8966525 |
1052 | * | 1052 | * |
1053 | */ | 1053 | */ |
1054 | #define AR5K_EEPROM_BASE 0x6000 | 1054 | #define AR5K_EEPROM_BASE 0x6000 |
1055 | 1055 | ||
1056 | /* | 1056 | /* |
1057 | * EEPROM data register | 1057 | * EEPROM data register |
1058 | */ | 1058 | */ |
1059 | #define AR5K_EEPROM_DATA_5211 0x6004 | 1059 | #define AR5K_EEPROM_DATA_5211 0x6004 |
1060 | #define AR5K_EEPROM_DATA_5210 0x6800 | 1060 | #define AR5K_EEPROM_DATA_5210 0x6800 |
1061 | #define AR5K_EEPROM_DATA (ah->ah_version == AR5K_AR5210 ? \ | 1061 | #define AR5K_EEPROM_DATA (ah->ah_version == AR5K_AR5210 ? \ |
1062 | AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211) | 1062 | AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211) |
1063 | 1063 | ||
1064 | /* | 1064 | /* |
1065 | * EEPROM command register | 1065 | * EEPROM command register |
1066 | */ | 1066 | */ |
1067 | #define AR5K_EEPROM_CMD 0x6008 /* Register Addres */ | 1067 | #define AR5K_EEPROM_CMD 0x6008 /* Register Addres */ |
1068 | #define AR5K_EEPROM_CMD_READ 0x00000001 /* EEPROM read */ | 1068 | #define AR5K_EEPROM_CMD_READ 0x00000001 /* EEPROM read */ |
1069 | #define AR5K_EEPROM_CMD_WRITE 0x00000002 /* EEPROM write */ | 1069 | #define AR5K_EEPROM_CMD_WRITE 0x00000002 /* EEPROM write */ |
1070 | #define AR5K_EEPROM_CMD_RESET 0x00000004 /* EEPROM reset */ | 1070 | #define AR5K_EEPROM_CMD_RESET 0x00000004 /* EEPROM reset */ |
1071 | 1071 | ||
1072 | /* | 1072 | /* |
1073 | * EEPROM status register | 1073 | * EEPROM status register |
1074 | */ | 1074 | */ |
1075 | #define AR5K_EEPROM_STAT_5210 0x6c00 /* Register Address [5210] */ | 1075 | #define AR5K_EEPROM_STAT_5210 0x6c00 /* Register Address [5210] */ |
1076 | #define AR5K_EEPROM_STAT_5211 0x600c /* Register Address [5211+] */ | 1076 | #define AR5K_EEPROM_STAT_5211 0x600c /* Register Address [5211+] */ |
1077 | #define AR5K_EEPROM_STATUS (ah->ah_version == AR5K_AR5210 ? \ | 1077 | #define AR5K_EEPROM_STATUS (ah->ah_version == AR5K_AR5210 ? \ |
1078 | AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211) | 1078 | AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211) |
1079 | #define AR5K_EEPROM_STAT_RDERR 0x00000001 /* EEPROM read failed */ | 1079 | #define AR5K_EEPROM_STAT_RDERR 0x00000001 /* EEPROM read failed */ |
1080 | #define AR5K_EEPROM_STAT_RDDONE 0x00000002 /* EEPROM read successful */ | 1080 | #define AR5K_EEPROM_STAT_RDDONE 0x00000002 /* EEPROM read successful */ |
1081 | #define AR5K_EEPROM_STAT_WRERR 0x00000004 /* EEPROM write failed */ | 1081 | #define AR5K_EEPROM_STAT_WRERR 0x00000004 /* EEPROM write failed */ |
1082 | #define AR5K_EEPROM_STAT_WRDONE 0x00000008 /* EEPROM write successful */ | 1082 | #define AR5K_EEPROM_STAT_WRDONE 0x00000008 /* EEPROM write successful */ |
1083 | 1083 | ||
1084 | /* | 1084 | /* |
1085 | * EEPROM config register | 1085 | * EEPROM config register |
1086 | */ | 1086 | */ |
1087 | #define AR5K_EEPROM_CFG 0x6010 /* Register Addres */ | 1087 | #define AR5K_EEPROM_CFG 0x6010 /* Register Addres */ |
1088 | #define AR5K_EEPROM_CFG_SIZE 0x00000003 /* Size determination override */ | 1088 | #define AR5K_EEPROM_CFG_SIZE 0x00000003 /* Size determination override */ |
1089 | #define AR5K_EEPROM_CFG_SIZE_AUTO 0 | 1089 | #define AR5K_EEPROM_CFG_SIZE_AUTO 0 |
1090 | #define AR5K_EEPROM_CFG_SIZE_4KBIT 1 | 1090 | #define AR5K_EEPROM_CFG_SIZE_4KBIT 1 |
1091 | #define AR5K_EEPROM_CFG_SIZE_8KBIT 2 | 1091 | #define AR5K_EEPROM_CFG_SIZE_8KBIT 2 |
1092 | #define AR5K_EEPROM_CFG_SIZE_16KBIT 3 | 1092 | #define AR5K_EEPROM_CFG_SIZE_16KBIT 3 |
1093 | #define AR5K_EEPROM_CFG_WR_WAIT_DIS 0x00000004 /* Disable write wait */ | 1093 | #define AR5K_EEPROM_CFG_WR_WAIT_DIS 0x00000004 /* Disable write wait */ |
1094 | #define AR5K_EEPROM_CFG_CLK_RATE 0x00000018 /* Clock rate */ | 1094 | #define AR5K_EEPROM_CFG_CLK_RATE 0x00000018 /* Clock rate */ |
1095 | #define AR5K_EEPROM_CFG_CLK_RATE_S 3 | 1095 | #define AR5K_EEPROM_CFG_CLK_RATE_S 3 |
1096 | #define AR5K_EEPROM_CFG_CLK_RATE_156KHZ 0 | 1096 | #define AR5K_EEPROM_CFG_CLK_RATE_156KHZ 0 |
1097 | #define AR5K_EEPROM_CFG_CLK_RATE_312KHZ 1 | 1097 | #define AR5K_EEPROM_CFG_CLK_RATE_312KHZ 1 |
1098 | #define AR5K_EEPROM_CFG_CLK_RATE_625KHZ 2 | 1098 | #define AR5K_EEPROM_CFG_CLK_RATE_625KHZ 2 |
1099 | #define AR5K_EEPROM_CFG_PROT_KEY 0x00ffff00 /* Protection key */ | 1099 | #define AR5K_EEPROM_CFG_PROT_KEY 0x00ffff00 /* Protection key */ |
1100 | #define AR5K_EEPROM_CFG_PROT_KEY_S 8 | 1100 | #define AR5K_EEPROM_CFG_PROT_KEY_S 8 |
1101 | #define AR5K_EEPROM_CFG_LIND_EN 0x01000000 /* Enable length indicator (?) */ | 1101 | #define AR5K_EEPROM_CFG_LIND_EN 0x01000000 /* Enable length indicator (?) */ |
1102 | 1102 | ||
1103 | 1103 | ||
1104 | /* | 1104 | /* |
1105 | * TODO: Wake On Wireless registers | 1105 | * TODO: Wake On Wireless registers |
1106 | * Range 0x7000 - 0x7ce0 | 1106 | * Range 0x7000 - 0x7ce0 |
1107 | */ | 1107 | */ |
1108 | 1108 | ||
1109 | /* | 1109 | /* |
1110 | * Protocol Control Unit (PCU) registers | 1110 | * Protocol Control Unit (PCU) registers |
1111 | */ | 1111 | */ |
1112 | /* | 1112 | /* |
1113 | * Used for checking initial register writes | 1113 | * Used for checking initial register writes |
1114 | * during channel reset (see reset func) | 1114 | * during channel reset (see reset func) |
1115 | */ | 1115 | */ |
1116 | #define AR5K_PCU_MIN 0x8000 | 1116 | #define AR5K_PCU_MIN 0x8000 |
1117 | #define AR5K_PCU_MAX 0x8fff | 1117 | #define AR5K_PCU_MAX 0x8fff |
1118 | 1118 | ||
1119 | /* | 1119 | /* |
1120 | * First station id register (Lower 32 bits of MAC address) | 1120 | * First station id register (Lower 32 bits of MAC address) |
1121 | */ | 1121 | */ |
1122 | #define AR5K_STA_ID0 0x8000 | 1122 | #define AR5K_STA_ID0 0x8000 |
1123 | #define AR5K_STA_ID0_ARRD_L32 0xffffffff | 1123 | #define AR5K_STA_ID0_ARRD_L32 0xffffffff |
1124 | 1124 | ||
1125 | /* | 1125 | /* |
1126 | * Second station id register (Upper 16 bits of MAC address + PCU settings) | 1126 | * Second station id register (Upper 16 bits of MAC address + PCU settings) |
1127 | */ | 1127 | */ |
1128 | #define AR5K_STA_ID1 0x8004 /* Register Address */ | 1128 | #define AR5K_STA_ID1 0x8004 /* Register Address */ |
1129 | #define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC addres */ | 1129 | #define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC addres */ |
1130 | #define AR5K_STA_ID1_AP 0x00010000 /* Set AP mode */ | 1130 | #define AR5K_STA_ID1_AP 0x00010000 /* Set AP mode */ |
1131 | #define AR5K_STA_ID1_ADHOC 0x00020000 /* Set Ad-Hoc mode */ | 1131 | #define AR5K_STA_ID1_ADHOC 0x00020000 /* Set Ad-Hoc mode */ |
1132 | #define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting */ | 1132 | #define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting */ |
1133 | #define AR5K_STA_ID1_NO_KEYSRCH 0x00080000 /* No key search */ | 1133 | #define AR5K_STA_ID1_NO_KEYSRCH 0x00080000 /* No key search */ |
1134 | #define AR5K_STA_ID1_NO_PSPOLL 0x00100000 /* No power save polling [5210] */ | 1134 | #define AR5K_STA_ID1_NO_PSPOLL 0x00100000 /* No power save polling [5210] */ |
1135 | #define AR5K_STA_ID1_PCF_5211 0x00100000 /* Enable PCF on [5211+] */ | 1135 | #define AR5K_STA_ID1_PCF_5211 0x00100000 /* Enable PCF on [5211+] */ |
1136 | #define AR5K_STA_ID1_PCF_5210 0x00200000 /* Enable PCF on [5210]*/ | 1136 | #define AR5K_STA_ID1_PCF_5210 0x00200000 /* Enable PCF on [5210]*/ |
1137 | #define AR5K_STA_ID1_PCF (ah->ah_version == AR5K_AR5210 ? \ | 1137 | #define AR5K_STA_ID1_PCF (ah->ah_version == AR5K_AR5210 ? \ |
1138 | AR5K_STA_ID1_PCF_5210 : AR5K_STA_ID1_PCF_5211) | 1138 | AR5K_STA_ID1_PCF_5210 : AR5K_STA_ID1_PCF_5211) |
1139 | #define AR5K_STA_ID1_DEFAULT_ANTENNA 0x00200000 /* Use default antenna */ | 1139 | #define AR5K_STA_ID1_DEFAULT_ANTENNA 0x00200000 /* Use default antenna */ |
1140 | #define AR5K_STA_ID1_DESC_ANTENNA 0x00400000 /* Update antenna from descriptor */ | 1140 | #define AR5K_STA_ID1_DESC_ANTENNA 0x00400000 /* Update antenna from descriptor */ |
1141 | #define AR5K_STA_ID1_RTS_DEF_ANTENNA 0x00800000 /* Use default antenna for RTS */ | 1141 | #define AR5K_STA_ID1_RTS_DEF_ANTENNA 0x00800000 /* Use default antenna for RTS */ |
1142 | #define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mbit/s for ACK/CTS */ | 1142 | #define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mbit/s for ACK/CTS */ |
1143 | #define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate for ACK/CTS [5211+] */ | 1143 | #define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate for ACK/CTS [5211+] */ |
1144 | #define AR5K_STA_ID1_SELFGEN_DEF_ANT 0x04000000 /* Use def. antenna for self generated frames */ | 1144 | #define AR5K_STA_ID1_SELFGEN_DEF_ANT 0x04000000 /* Use def. antenna for self generated frames */ |
1145 | #define AR5K_STA_ID1_CRYPT_MIC_EN 0x08000000 /* Enable MIC */ | 1145 | #define AR5K_STA_ID1_CRYPT_MIC_EN 0x08000000 /* Enable MIC */ |
1146 | #define AR5K_STA_ID1_KEYSRCH_MODE 0x10000000 /* Look up key when key id != 0 */ | 1146 | #define AR5K_STA_ID1_KEYSRCH_MODE 0x10000000 /* Look up key when key id != 0 */ |
1147 | #define AR5K_STA_ID1_PRESERVE_SEQ_NUM 0x20000000 /* Preserve sequence number */ | 1147 | #define AR5K_STA_ID1_PRESERVE_SEQ_NUM 0x20000000 /* Preserve sequence number */ |
1148 | #define AR5K_STA_ID1_CBCIV_ENDIAN 0x40000000 /* ??? */ | 1148 | #define AR5K_STA_ID1_CBCIV_ENDIAN 0x40000000 /* ??? */ |
1149 | #define AR5K_STA_ID1_KEYSRCH_MCAST 0x80000000 /* Do key cache search for mcast frames */ | 1149 | #define AR5K_STA_ID1_KEYSRCH_MCAST 0x80000000 /* Do key cache search for mcast frames */ |
1150 | 1150 | ||
1151 | #define AR5K_STA_ID1_ANTENNA_SETTINGS (AR5K_STA_ID1_DEFAULT_ANTENNA | \ | 1151 | #define AR5K_STA_ID1_ANTENNA_SETTINGS (AR5K_STA_ID1_DEFAULT_ANTENNA | \ |
1152 | AR5K_STA_ID1_DESC_ANTENNA | \ | 1152 | AR5K_STA_ID1_DESC_ANTENNA | \ |
1153 | AR5K_STA_ID1_RTS_DEF_ANTENNA | \ | 1153 | AR5K_STA_ID1_RTS_DEF_ANTENNA | \ |
1154 | AR5K_STA_ID1_SELFGEN_DEF_ANT) | 1154 | AR5K_STA_ID1_SELFGEN_DEF_ANT) |
1155 | 1155 | ||
1156 | /* | 1156 | /* |
1157 | * First BSSID register (MAC address, lower 32bits) | 1157 | * First BSSID register (MAC address, lower 32bits) |
1158 | */ | 1158 | */ |
1159 | #define AR5K_BSS_ID0 0x8008 | 1159 | #define AR5K_BSS_ID0 0x8008 |
1160 | 1160 | ||
1161 | /* | 1161 | /* |
1162 | * Second BSSID register (MAC address in upper 16 bits) | 1162 | * Second BSSID register (MAC address in upper 16 bits) |
1163 | * | 1163 | * |
1164 | * AID: Association ID | 1164 | * AID: Association ID |
1165 | */ | 1165 | */ |
1166 | #define AR5K_BSS_ID1 0x800c | 1166 | #define AR5K_BSS_ID1 0x800c |
1167 | #define AR5K_BSS_ID1_AID 0xffff0000 | 1167 | #define AR5K_BSS_ID1_AID 0xffff0000 |
1168 | #define AR5K_BSS_ID1_AID_S 16 | 1168 | #define AR5K_BSS_ID1_AID_S 16 |
1169 | 1169 | ||
1170 | /* | 1170 | /* |
1171 | * Backoff slot time register | 1171 | * Backoff slot time register |
1172 | */ | 1172 | */ |
1173 | #define AR5K_SLOT_TIME 0x8010 | 1173 | #define AR5K_SLOT_TIME 0x8010 |
1174 | 1174 | ||
1175 | /* | 1175 | /* |
1176 | * ACK/CTS timeout register | 1176 | * ACK/CTS timeout register |
1177 | */ | 1177 | */ |
1178 | #define AR5K_TIME_OUT 0x8014 /* Register Address */ | 1178 | #define AR5K_TIME_OUT 0x8014 /* Register Address */ |
1179 | #define AR5K_TIME_OUT_ACK 0x00001fff /* ACK timeout mask */ | 1179 | #define AR5K_TIME_OUT_ACK 0x00001fff /* ACK timeout mask */ |
1180 | #define AR5K_TIME_OUT_ACK_S 0 | 1180 | #define AR5K_TIME_OUT_ACK_S 0 |
1181 | #define AR5K_TIME_OUT_CTS 0x1fff0000 /* CTS timeout mask */ | 1181 | #define AR5K_TIME_OUT_CTS 0x1fff0000 /* CTS timeout mask */ |
1182 | #define AR5K_TIME_OUT_CTS_S 16 | 1182 | #define AR5K_TIME_OUT_CTS_S 16 |
1183 | 1183 | ||
1184 | /* | 1184 | /* |
1185 | * RSSI threshold register | 1185 | * RSSI threshold register |
1186 | */ | 1186 | */ |
1187 | #define AR5K_RSSI_THR 0x8018 /* Register Address */ | 1187 | #define AR5K_RSSI_THR 0x8018 /* Register Address */ |
1188 | #define AR5K_RSSI_THR_M 0x000000ff /* Mask for RSSI threshold [5211+] */ | 1188 | #define AR5K_RSSI_THR_M 0x000000ff /* Mask for RSSI threshold [5211+] */ |
1189 | #define AR5K_RSSI_THR_BMISS_5210 0x00000700 /* Mask for Beacon Missed threshold [5210] */ | 1189 | #define AR5K_RSSI_THR_BMISS_5210 0x00000700 /* Mask for Beacon Missed threshold [5210] */ |
1190 | #define AR5K_RSSI_THR_BMISS_5210_S 8 | 1190 | #define AR5K_RSSI_THR_BMISS_5210_S 8 |
1191 | #define AR5K_RSSI_THR_BMISS_5211 0x0000ff00 /* Mask for Beacon Missed threshold [5211+] */ | 1191 | #define AR5K_RSSI_THR_BMISS_5211 0x0000ff00 /* Mask for Beacon Missed threshold [5211+] */ |
1192 | #define AR5K_RSSI_THR_BMISS_5211_S 8 | 1192 | #define AR5K_RSSI_THR_BMISS_5211_S 8 |
1193 | #define AR5K_RSSI_THR_BMISS (ah->ah_version == AR5K_AR5210 ? \ | 1193 | #define AR5K_RSSI_THR_BMISS (ah->ah_version == AR5K_AR5210 ? \ |
1194 | AR5K_RSSI_THR_BMISS_5210 : AR5K_RSSI_THR_BMISS_5211) | 1194 | AR5K_RSSI_THR_BMISS_5210 : AR5K_RSSI_THR_BMISS_5211) |
1195 | #define AR5K_RSSI_THR_BMISS_S 8 | 1195 | #define AR5K_RSSI_THR_BMISS_S 8 |
1196 | 1196 | ||
1197 | /* | 1197 | /* |
1198 | * 5210 has more PCU registers because there is no QCU/DCU | 1198 | * 5210 has more PCU registers because there is no QCU/DCU |
1199 | * so queue parameters are set here, this way a lot common | 1199 | * so queue parameters are set here, this way a lot common |
1200 | * registers have different address for 5210. To make things | 1200 | * registers have different address for 5210. To make things |
1201 | * easier we define a macro based on ah->ah_version for common | 1201 | * easier we define a macro based on ah->ah_version for common |
1202 | * registers with different addresses and common flags. | 1202 | * registers with different addresses and common flags. |
1203 | */ | 1203 | */ |
1204 | 1204 | ||
1205 | /* | 1205 | /* |
1206 | * Retry limit register | 1206 | * Retry limit register |
1207 | * | 1207 | * |
1208 | * Retry limit register for 5210 (no QCU/DCU so it's done in PCU) | 1208 | * Retry limit register for 5210 (no QCU/DCU so it's done in PCU) |
1209 | */ | 1209 | */ |
1210 | #define AR5K_NODCU_RETRY_LMT 0x801c /* Register Address */ | 1210 | #define AR5K_NODCU_RETRY_LMT 0x801c /* Register Address */ |
1211 | #define AR5K_NODCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */ | 1211 | #define AR5K_NODCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */ |
1212 | #define AR5K_NODCU_RETRY_LMT_SH_RETRY_S 0 | 1212 | #define AR5K_NODCU_RETRY_LMT_SH_RETRY_S 0 |
1213 | #define AR5K_NODCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry mask */ | 1213 | #define AR5K_NODCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry mask */ |
1214 | #define AR5K_NODCU_RETRY_LMT_LG_RETRY_S 4 | 1214 | #define AR5K_NODCU_RETRY_LMT_LG_RETRY_S 4 |
1215 | #define AR5K_NODCU_RETRY_LMT_SSH_RETRY 0x00003f00 /* Station short retry limit mask */ | 1215 | #define AR5K_NODCU_RETRY_LMT_SSH_RETRY 0x00003f00 /* Station short retry limit mask */ |
1216 | #define AR5K_NODCU_RETRY_LMT_SSH_RETRY_S 8 | 1216 | #define AR5K_NODCU_RETRY_LMT_SSH_RETRY_S 8 |
1217 | #define AR5K_NODCU_RETRY_LMT_SLG_RETRY 0x000fc000 /* Station long retry limit mask */ | 1217 | #define AR5K_NODCU_RETRY_LMT_SLG_RETRY 0x000fc000 /* Station long retry limit mask */ |
1218 | #define AR5K_NODCU_RETRY_LMT_SLG_RETRY_S 14 | 1218 | #define AR5K_NODCU_RETRY_LMT_SLG_RETRY_S 14 |
1219 | #define AR5K_NODCU_RETRY_LMT_CW_MIN 0x3ff00000 /* Minimum contention window mask */ | 1219 | #define AR5K_NODCU_RETRY_LMT_CW_MIN 0x3ff00000 /* Minimum contention window mask */ |
1220 | #define AR5K_NODCU_RETRY_LMT_CW_MIN_S 20 | 1220 | #define AR5K_NODCU_RETRY_LMT_CW_MIN_S 20 |
1221 | 1221 | ||
1222 | /* | 1222 | /* |
1223 | * Transmit latency register | 1223 | * Transmit latency register |
1224 | */ | 1224 | */ |
1225 | #define AR5K_USEC_5210 0x8020 /* Register Address [5210] */ | 1225 | #define AR5K_USEC_5210 0x8020 /* Register Address [5210] */ |
1226 | #define AR5K_USEC_5211 0x801c /* Register Address [5211+] */ | 1226 | #define AR5K_USEC_5211 0x801c /* Register Address [5211+] */ |
1227 | #define AR5K_USEC (ah->ah_version == AR5K_AR5210 ? \ | 1227 | #define AR5K_USEC (ah->ah_version == AR5K_AR5210 ? \ |
1228 | AR5K_USEC_5210 : AR5K_USEC_5211) | 1228 | AR5K_USEC_5210 : AR5K_USEC_5211) |
1229 | #define AR5K_USEC_1 0x0000007f /* clock cycles for 1us */ | 1229 | #define AR5K_USEC_1 0x0000007f /* clock cycles for 1us */ |
1230 | #define AR5K_USEC_1_S 0 | 1230 | #define AR5K_USEC_1_S 0 |
1231 | #define AR5K_USEC_32 0x00003f80 /* clock cycles for 1us while on 32Mhz clock */ | 1231 | #define AR5K_USEC_32 0x00003f80 /* clock cycles for 1us while on 32Mhz clock */ |
1232 | #define AR5K_USEC_32_S 7 | 1232 | #define AR5K_USEC_32_S 7 |
1233 | #define AR5K_USEC_TX_LATENCY_5211 0x007fc000 | 1233 | #define AR5K_USEC_TX_LATENCY_5211 0x007fc000 |
1234 | #define AR5K_USEC_TX_LATENCY_5211_S 14 | 1234 | #define AR5K_USEC_TX_LATENCY_5211_S 14 |
1235 | #define AR5K_USEC_RX_LATENCY_5211 0x1f800000 | 1235 | #define AR5K_USEC_RX_LATENCY_5211 0x1f800000 |
1236 | #define AR5K_USEC_RX_LATENCY_5211_S 23 | 1236 | #define AR5K_USEC_RX_LATENCY_5211_S 23 |
1237 | #define AR5K_USEC_TX_LATENCY_5210 0x000fc000 /* also for 5311 */ | 1237 | #define AR5K_USEC_TX_LATENCY_5210 0x000fc000 /* also for 5311 */ |
1238 | #define AR5K_USEC_TX_LATENCY_5210_S 14 | 1238 | #define AR5K_USEC_TX_LATENCY_5210_S 14 |
1239 | #define AR5K_USEC_RX_LATENCY_5210 0x03f00000 /* also for 5311 */ | 1239 | #define AR5K_USEC_RX_LATENCY_5210 0x03f00000 /* also for 5311 */ |
1240 | #define AR5K_USEC_RX_LATENCY_5210_S 20 | 1240 | #define AR5K_USEC_RX_LATENCY_5210_S 20 |
1241 | 1241 | ||
1242 | /* | 1242 | /* |
1243 | * PCU beacon control register | 1243 | * PCU beacon control register |
1244 | */ | 1244 | */ |
1245 | #define AR5K_BEACON_5210 0x8024 /*Register Address [5210] */ | 1245 | #define AR5K_BEACON_5210 0x8024 /*Register Address [5210] */ |
1246 | #define AR5K_BEACON_5211 0x8020 /*Register Address [5211+] */ | 1246 | #define AR5K_BEACON_5211 0x8020 /*Register Address [5211+] */ |
1247 | #define AR5K_BEACON (ah->ah_version == AR5K_AR5210 ? \ | 1247 | #define AR5K_BEACON (ah->ah_version == AR5K_AR5210 ? \ |
1248 | AR5K_BEACON_5210 : AR5K_BEACON_5211) | 1248 | AR5K_BEACON_5210 : AR5K_BEACON_5211) |
1249 | #define AR5K_BEACON_PERIOD 0x0000ffff /* Mask for beacon period */ | 1249 | #define AR5K_BEACON_PERIOD 0x0000ffff /* Mask for beacon period */ |
1250 | #define AR5K_BEACON_PERIOD_S 0 | 1250 | #define AR5K_BEACON_PERIOD_S 0 |
1251 | #define AR5K_BEACON_TIM 0x007f0000 /* Mask for TIM offset */ | 1251 | #define AR5K_BEACON_TIM 0x007f0000 /* Mask for TIM offset */ |
1252 | #define AR5K_BEACON_TIM_S 16 | 1252 | #define AR5K_BEACON_TIM_S 16 |
1253 | #define AR5K_BEACON_ENABLE 0x00800000 /* Enable beacons */ | 1253 | #define AR5K_BEACON_ENABLE 0x00800000 /* Enable beacons */ |
1254 | #define AR5K_BEACON_RESET_TSF 0x01000000 /* Force TSF reset */ | 1254 | #define AR5K_BEACON_RESET_TSF 0x01000000 /* Force TSF reset */ |
1255 | 1255 | ||
1256 | /* | 1256 | /* |
1257 | * CFP period register | 1257 | * CFP period register |
1258 | */ | 1258 | */ |
1259 | #define AR5K_CFP_PERIOD_5210 0x8028 | 1259 | #define AR5K_CFP_PERIOD_5210 0x8028 |
1260 | #define AR5K_CFP_PERIOD_5211 0x8024 | 1260 | #define AR5K_CFP_PERIOD_5211 0x8024 |
1261 | #define AR5K_CFP_PERIOD (ah->ah_version == AR5K_AR5210 ? \ | 1261 | #define AR5K_CFP_PERIOD (ah->ah_version == AR5K_AR5210 ? \ |
1262 | AR5K_CFP_PERIOD_5210 : AR5K_CFP_PERIOD_5211) | 1262 | AR5K_CFP_PERIOD_5210 : AR5K_CFP_PERIOD_5211) |
1263 | 1263 | ||
1264 | /* | 1264 | /* |
1265 | * Next beacon time register | 1265 | * Next beacon time register |
1266 | */ | 1266 | */ |
1267 | #define AR5K_TIMER0_5210 0x802c | 1267 | #define AR5K_TIMER0_5210 0x802c |
1268 | #define AR5K_TIMER0_5211 0x8028 | 1268 | #define AR5K_TIMER0_5211 0x8028 |
1269 | #define AR5K_TIMER0 (ah->ah_version == AR5K_AR5210 ? \ | 1269 | #define AR5K_TIMER0 (ah->ah_version == AR5K_AR5210 ? \ |
1270 | AR5K_TIMER0_5210 : AR5K_TIMER0_5211) | 1270 | AR5K_TIMER0_5210 : AR5K_TIMER0_5211) |
1271 | 1271 | ||
1272 | /* | 1272 | /* |
1273 | * Next DMA beacon alert register | 1273 | * Next DMA beacon alert register |
1274 | */ | 1274 | */ |
1275 | #define AR5K_TIMER1_5210 0x8030 | 1275 | #define AR5K_TIMER1_5210 0x8030 |
1276 | #define AR5K_TIMER1_5211 0x802c | 1276 | #define AR5K_TIMER1_5211 0x802c |
1277 | #define AR5K_TIMER1 (ah->ah_version == AR5K_AR5210 ? \ | 1277 | #define AR5K_TIMER1 (ah->ah_version == AR5K_AR5210 ? \ |
1278 | AR5K_TIMER1_5210 : AR5K_TIMER1_5211) | 1278 | AR5K_TIMER1_5210 : AR5K_TIMER1_5211) |
1279 | 1279 | ||
1280 | /* | 1280 | /* |
1281 | * Next software beacon alert register | 1281 | * Next software beacon alert register |
1282 | */ | 1282 | */ |
1283 | #define AR5K_TIMER2_5210 0x8034 | 1283 | #define AR5K_TIMER2_5210 0x8034 |
1284 | #define AR5K_TIMER2_5211 0x8030 | 1284 | #define AR5K_TIMER2_5211 0x8030 |
1285 | #define AR5K_TIMER2 (ah->ah_version == AR5K_AR5210 ? \ | 1285 | #define AR5K_TIMER2 (ah->ah_version == AR5K_AR5210 ? \ |
1286 | AR5K_TIMER2_5210 : AR5K_TIMER2_5211) | 1286 | AR5K_TIMER2_5210 : AR5K_TIMER2_5211) |
1287 | 1287 | ||
1288 | /* | 1288 | /* |
1289 | * Next ATIM window time register | 1289 | * Next ATIM window time register |
1290 | */ | 1290 | */ |
1291 | #define AR5K_TIMER3_5210 0x8038 | 1291 | #define AR5K_TIMER3_5210 0x8038 |
1292 | #define AR5K_TIMER3_5211 0x8034 | 1292 | #define AR5K_TIMER3_5211 0x8034 |
1293 | #define AR5K_TIMER3 (ah->ah_version == AR5K_AR5210 ? \ | 1293 | #define AR5K_TIMER3 (ah->ah_version == AR5K_AR5210 ? \ |
1294 | AR5K_TIMER3_5210 : AR5K_TIMER3_5211) | 1294 | AR5K_TIMER3_5210 : AR5K_TIMER3_5211) |
1295 | 1295 | ||
1296 | 1296 | ||
1297 | /* | 1297 | /* |
1298 | * 5210 First inter frame spacing register (IFS) | 1298 | * 5210 First inter frame spacing register (IFS) |
1299 | */ | 1299 | */ |
1300 | #define AR5K_IFS0 0x8040 | 1300 | #define AR5K_IFS0 0x8040 |
1301 | #define AR5K_IFS0_SIFS 0x000007ff | 1301 | #define AR5K_IFS0_SIFS 0x000007ff |
1302 | #define AR5K_IFS0_SIFS_S 0 | 1302 | #define AR5K_IFS0_SIFS_S 0 |
1303 | #define AR5K_IFS0_DIFS 0x007ff800 | 1303 | #define AR5K_IFS0_DIFS 0x007ff800 |
1304 | #define AR5K_IFS0_DIFS_S 11 | 1304 | #define AR5K_IFS0_DIFS_S 11 |
1305 | 1305 | ||
1306 | /* | 1306 | /* |
1307 | * 5210 Second inter frame spacing register (IFS) | 1307 | * 5210 Second inter frame spacing register (IFS) |
1308 | */ | 1308 | */ |
1309 | #define AR5K_IFS1 0x8044 | 1309 | #define AR5K_IFS1 0x8044 |
1310 | #define AR5K_IFS1_PIFS 0x00000fff | 1310 | #define AR5K_IFS1_PIFS 0x00000fff |
1311 | #define AR5K_IFS1_PIFS_S 0 | 1311 | #define AR5K_IFS1_PIFS_S 0 |
1312 | #define AR5K_IFS1_EIFS 0x03fff000 | 1312 | #define AR5K_IFS1_EIFS 0x03fff000 |
1313 | #define AR5K_IFS1_EIFS_S 12 | 1313 | #define AR5K_IFS1_EIFS_S 12 |
1314 | #define AR5K_IFS1_CS_EN 0x04000000 | 1314 | #define AR5K_IFS1_CS_EN 0x04000000 |
1315 | 1315 | ||
1316 | 1316 | ||
1317 | /* | 1317 | /* |
1318 | * CFP duration register | 1318 | * CFP duration register |
1319 | */ | 1319 | */ |
1320 | #define AR5K_CFP_DUR_5210 0x8048 | 1320 | #define AR5K_CFP_DUR_5210 0x8048 |
1321 | #define AR5K_CFP_DUR_5211 0x8038 | 1321 | #define AR5K_CFP_DUR_5211 0x8038 |
1322 | #define AR5K_CFP_DUR (ah->ah_version == AR5K_AR5210 ? \ | 1322 | #define AR5K_CFP_DUR (ah->ah_version == AR5K_AR5210 ? \ |
1323 | AR5K_CFP_DUR_5210 : AR5K_CFP_DUR_5211) | 1323 | AR5K_CFP_DUR_5210 : AR5K_CFP_DUR_5211) |
1324 | 1324 | ||
1325 | /* | 1325 | /* |
1326 | * Receive filter register | 1326 | * Receive filter register |
1327 | */ | 1327 | */ |
1328 | #define AR5K_RX_FILTER_5210 0x804c /* Register Address [5210] */ | 1328 | #define AR5K_RX_FILTER_5210 0x804c /* Register Address [5210] */ |
1329 | #define AR5K_RX_FILTER_5211 0x803c /* Register Address [5211+] */ | 1329 | #define AR5K_RX_FILTER_5211 0x803c /* Register Address [5211+] */ |
1330 | #define AR5K_RX_FILTER (ah->ah_version == AR5K_AR5210 ? \ | 1330 | #define AR5K_RX_FILTER (ah->ah_version == AR5K_AR5210 ? \ |
1331 | AR5K_RX_FILTER_5210 : AR5K_RX_FILTER_5211) | 1331 | AR5K_RX_FILTER_5210 : AR5K_RX_FILTER_5211) |
1332 | #define AR5K_RX_FILTER_UCAST 0x00000001 /* Don't filter unicast frames */ | 1332 | #define AR5K_RX_FILTER_UCAST 0x00000001 /* Don't filter unicast frames */ |
1333 | #define AR5K_RX_FILTER_MCAST 0x00000002 /* Don't filter multicast frames */ | 1333 | #define AR5K_RX_FILTER_MCAST 0x00000002 /* Don't filter multicast frames */ |
1334 | #define AR5K_RX_FILTER_BCAST 0x00000004 /* Don't filter broadcast frames */ | 1334 | #define AR5K_RX_FILTER_BCAST 0x00000004 /* Don't filter broadcast frames */ |
1335 | #define AR5K_RX_FILTER_CONTROL 0x00000008 /* Don't filter control frames */ | 1335 | #define AR5K_RX_FILTER_CONTROL 0x00000008 /* Don't filter control frames */ |
1336 | #define AR5K_RX_FILTER_BEACON 0x00000010 /* Don't filter beacon frames */ | 1336 | #define AR5K_RX_FILTER_BEACON 0x00000010 /* Don't filter beacon frames */ |
1337 | #define AR5K_RX_FILTER_PROM 0x00000020 /* Set promiscuous mode */ | 1337 | #define AR5K_RX_FILTER_PROM 0x00000020 /* Set promiscuous mode */ |
1338 | #define AR5K_RX_FILTER_XRPOLL 0x00000040 /* Don't filter XR poll frame [5212+] */ | 1338 | #define AR5K_RX_FILTER_XRPOLL 0x00000040 /* Don't filter XR poll frame [5212+] */ |
1339 | #define AR5K_RX_FILTER_PROBEREQ 0x00000080 /* Don't filter probe requests [5212+] */ | 1339 | #define AR5K_RX_FILTER_PROBEREQ 0x00000080 /* Don't filter probe requests [5212+] */ |
1340 | #define AR5K_RX_FILTER_PHYERR_5212 0x00000100 /* Don't filter phy errors [5212+] */ | 1340 | #define AR5K_RX_FILTER_PHYERR_5212 0x00000100 /* Don't filter phy errors [5212+] */ |
1341 | #define AR5K_RX_FILTER_RADARERR_5212 0x00000200 /* Don't filter phy radar errors [5212+] */ | 1341 | #define AR5K_RX_FILTER_RADARERR_5212 0x00000200 /* Don't filter phy radar errors [5212+] */ |
1342 | #define AR5K_RX_FILTER_PHYERR_5211 0x00000040 /* [5211] */ | 1342 | #define AR5K_RX_FILTER_PHYERR_5211 0x00000040 /* [5211] */ |
1343 | #define AR5K_RX_FILTER_RADARERR_5211 0x00000080 /* [5211] */ | 1343 | #define AR5K_RX_FILTER_RADARERR_5211 0x00000080 /* [5211] */ |
1344 | #define AR5K_RX_FILTER_PHYERR \ | 1344 | #define AR5K_RX_FILTER_PHYERR \ |
1345 | ((ah->ah_version == AR5K_AR5211 ? \ | 1345 | ((ah->ah_version == AR5K_AR5211 ? \ |
1346 | AR5K_RX_FILTER_PHYERR_5211 : AR5K_RX_FILTER_PHYERR_5212)) | 1346 | AR5K_RX_FILTER_PHYERR_5211 : AR5K_RX_FILTER_PHYERR_5212)) |
1347 | #define AR5K_RX_FILTER_RADARERR \ | 1347 | #define AR5K_RX_FILTER_RADARERR \ |
1348 | ((ah->ah_version == AR5K_AR5211 ? \ | 1348 | ((ah->ah_version == AR5K_AR5211 ? \ |
1349 | AR5K_RX_FILTER_RADARERR_5211 : AR5K_RX_FILTER_RADARERR_5212)) | 1349 | AR5K_RX_FILTER_RADARERR_5211 : AR5K_RX_FILTER_RADARERR_5212)) |
1350 | 1350 | ||
1351 | /* | 1351 | /* |
1352 | * Multicast filter register (lower 32 bits) | 1352 | * Multicast filter register (lower 32 bits) |
1353 | */ | 1353 | */ |
1354 | #define AR5K_MCAST_FILTER0_5210 0x8050 | 1354 | #define AR5K_MCAST_FILTER0_5210 0x8050 |
1355 | #define AR5K_MCAST_FILTER0_5211 0x8040 | 1355 | #define AR5K_MCAST_FILTER0_5211 0x8040 |
1356 | #define AR5K_MCAST_FILTER0 (ah->ah_version == AR5K_AR5210 ? \ | 1356 | #define AR5K_MCAST_FILTER0 (ah->ah_version == AR5K_AR5210 ? \ |
1357 | AR5K_MCAST_FILTER0_5210 : AR5K_MCAST_FILTER0_5211) | 1357 | AR5K_MCAST_FILTER0_5210 : AR5K_MCAST_FILTER0_5211) |
1358 | 1358 | ||
1359 | /* | 1359 | /* |
1360 | * Multicast filter register (higher 16 bits) | 1360 | * Multicast filter register (higher 16 bits) |
1361 | */ | 1361 | */ |
1362 | #define AR5K_MCAST_FILTER1_5210 0x8054 | 1362 | #define AR5K_MCAST_FILTER1_5210 0x8054 |
1363 | #define AR5K_MCAST_FILTER1_5211 0x8044 | 1363 | #define AR5K_MCAST_FILTER1_5211 0x8044 |
1364 | #define AR5K_MCAST_FILTER1 (ah->ah_version == AR5K_AR5210 ? \ | 1364 | #define AR5K_MCAST_FILTER1 (ah->ah_version == AR5K_AR5210 ? \ |
1365 | AR5K_MCAST_FILTER1_5210 : AR5K_MCAST_FILTER1_5211) | 1365 | AR5K_MCAST_FILTER1_5210 : AR5K_MCAST_FILTER1_5211) |
1366 | 1366 | ||
1367 | 1367 | ||
1368 | /* | 1368 | /* |
1369 | * Transmit mask register (lower 32 bits) [5210] | 1369 | * Transmit mask register (lower 32 bits) [5210] |
1370 | */ | 1370 | */ |
1371 | #define AR5K_TX_MASK0 0x8058 | 1371 | #define AR5K_TX_MASK0 0x8058 |
1372 | 1372 | ||
1373 | /* | 1373 | /* |
1374 | * Transmit mask register (higher 16 bits) [5210] | 1374 | * Transmit mask register (higher 16 bits) [5210] |
1375 | */ | 1375 | */ |
1376 | #define AR5K_TX_MASK1 0x805c | 1376 | #define AR5K_TX_MASK1 0x805c |
1377 | 1377 | ||
1378 | /* | 1378 | /* |
1379 | * Clear transmit mask [5210] | 1379 | * Clear transmit mask [5210] |
1380 | */ | 1380 | */ |
1381 | #define AR5K_CLR_TMASK 0x8060 | 1381 | #define AR5K_CLR_TMASK 0x8060 |
1382 | 1382 | ||
1383 | /* | 1383 | /* |
1384 | * Trigger level register (before transmission) [5210] | 1384 | * Trigger level register (before transmission) [5210] |
1385 | */ | 1385 | */ |
1386 | #define AR5K_TRIG_LVL 0x8064 | 1386 | #define AR5K_TRIG_LVL 0x8064 |
1387 | 1387 | ||
1388 | 1388 | ||
1389 | /* | 1389 | /* |
1390 | * PCU control register | 1390 | * PCU control register |
1391 | * | 1391 | * |
1392 | * Only DIS_RX is used in the code, the rest i guess are | 1392 | * Only DIS_RX is used in the code, the rest i guess are |
1393 | * for tweaking/diagnostics. | 1393 | * for tweaking/diagnostics. |
1394 | */ | 1394 | */ |
1395 | #define AR5K_DIAG_SW_5210 0x8068 /* Register Address [5210] */ | 1395 | #define AR5K_DIAG_SW_5210 0x8068 /* Register Address [5210] */ |
1396 | #define AR5K_DIAG_SW_5211 0x8048 /* Register Address [5211+] */ | 1396 | #define AR5K_DIAG_SW_5211 0x8048 /* Register Address [5211+] */ |
1397 | #define AR5K_DIAG_SW (ah->ah_version == AR5K_AR5210 ? \ | 1397 | #define AR5K_DIAG_SW (ah->ah_version == AR5K_AR5210 ? \ |
1398 | AR5K_DIAG_SW_5210 : AR5K_DIAG_SW_5211) | 1398 | AR5K_DIAG_SW_5210 : AR5K_DIAG_SW_5211) |
1399 | #define AR5K_DIAG_SW_DIS_WEP_ACK 0x00000001 /* Disable ACKs if WEP key is invalid */ | 1399 | #define AR5K_DIAG_SW_DIS_WEP_ACK 0x00000001 /* Disable ACKs if WEP key is invalid */ |
1400 | #define AR5K_DIAG_SW_DIS_ACK 0x00000002 /* Disable ACKs */ | 1400 | #define AR5K_DIAG_SW_DIS_ACK 0x00000002 /* Disable ACKs */ |
1401 | #define AR5K_DIAG_SW_DIS_CTS 0x00000004 /* Disable CTSs */ | 1401 | #define AR5K_DIAG_SW_DIS_CTS 0x00000004 /* Disable CTSs */ |
1402 | #define AR5K_DIAG_SW_DIS_ENC 0x00000008 /* Disable encryption */ | 1402 | #define AR5K_DIAG_SW_DIS_ENC 0x00000008 /* Disable encryption */ |
1403 | #define AR5K_DIAG_SW_DIS_DEC 0x00000010 /* Disable decryption */ | 1403 | #define AR5K_DIAG_SW_DIS_DEC 0x00000010 /* Disable decryption */ |
1404 | #define AR5K_DIAG_SW_DIS_TX 0x00000020 /* Disable transmit [5210] */ | 1404 | #define AR5K_DIAG_SW_DIS_TX 0x00000020 /* Disable transmit [5210] */ |
1405 | #define AR5K_DIAG_SW_DIS_RX_5210 0x00000040 /* Disable recieve */ | 1405 | #define AR5K_DIAG_SW_DIS_RX_5210 0x00000040 /* Disable recieve */ |
1406 | #define AR5K_DIAG_SW_DIS_RX_5211 0x00000020 | 1406 | #define AR5K_DIAG_SW_DIS_RX_5211 0x00000020 |
1407 | #define AR5K_DIAG_SW_DIS_RX (ah->ah_version == AR5K_AR5210 ? \ | 1407 | #define AR5K_DIAG_SW_DIS_RX (ah->ah_version == AR5K_AR5210 ? \ |
1408 | AR5K_DIAG_SW_DIS_RX_5210 : AR5K_DIAG_SW_DIS_RX_5211) | 1408 | AR5K_DIAG_SW_DIS_RX_5210 : AR5K_DIAG_SW_DIS_RX_5211) |
1409 | #define AR5K_DIAG_SW_LOOP_BACK_5210 0x00000080 /* Loopback (i guess it goes with DIS_TX) [5210] */ | 1409 | #define AR5K_DIAG_SW_LOOP_BACK_5210 0x00000080 /* Loopback (i guess it goes with DIS_TX) [5210] */ |
1410 | #define AR5K_DIAG_SW_LOOP_BACK_5211 0x00000040 | 1410 | #define AR5K_DIAG_SW_LOOP_BACK_5211 0x00000040 |
1411 | #define AR5K_DIAG_SW_LOOP_BACK (ah->ah_version == AR5K_AR5210 ? \ | 1411 | #define AR5K_DIAG_SW_LOOP_BACK (ah->ah_version == AR5K_AR5210 ? \ |
1412 | AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211) | 1412 | AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211) |
1413 | #define AR5K_DIAG_SW_CORR_FCS_5210 0x00000100 /* Corrupted FCS */ | 1413 | #define AR5K_DIAG_SW_CORR_FCS_5210 0x00000100 /* Corrupted FCS */ |
1414 | #define AR5K_DIAG_SW_CORR_FCS_5211 0x00000080 | 1414 | #define AR5K_DIAG_SW_CORR_FCS_5211 0x00000080 |
1415 | #define AR5K_DIAG_SW_CORR_FCS (ah->ah_version == AR5K_AR5210 ? \ | 1415 | #define AR5K_DIAG_SW_CORR_FCS (ah->ah_version == AR5K_AR5210 ? \ |
1416 | AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211) | 1416 | AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211) |
1417 | #define AR5K_DIAG_SW_CHAN_INFO_5210 0x00000200 /* Dump channel info */ | 1417 | #define AR5K_DIAG_SW_CHAN_INFO_5210 0x00000200 /* Dump channel info */ |
1418 | #define AR5K_DIAG_SW_CHAN_INFO_5211 0x00000100 | 1418 | #define AR5K_DIAG_SW_CHAN_INFO_5211 0x00000100 |
1419 | #define AR5K_DIAG_SW_CHAN_INFO (ah->ah_version == AR5K_AR5210 ? \ | 1419 | #define AR5K_DIAG_SW_CHAN_INFO (ah->ah_version == AR5K_AR5210 ? \ |
1420 | AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211) | 1420 | AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211) |
1421 | #define AR5K_DIAG_SW_EN_SCRAM_SEED_5210 0x00000400 /* Enable fixed scrambler seed */ | 1421 | #define AR5K_DIAG_SW_EN_SCRAM_SEED_5210 0x00000400 /* Enable fixed scrambler seed */ |
1422 | #define AR5K_DIAG_SW_EN_SCRAM_SEED_5211 0x00000200 | 1422 | #define AR5K_DIAG_SW_EN_SCRAM_SEED_5211 0x00000200 |
1423 | #define AR5K_DIAG_SW_EN_SCRAM_SEED (ah->ah_version == AR5K_AR5210 ? \ | 1423 | #define AR5K_DIAG_SW_EN_SCRAM_SEED (ah->ah_version == AR5K_AR5210 ? \ |
1424 | AR5K_DIAG_SW_EN_SCRAM_SEED_5210 : AR5K_DIAG_SW_EN_SCRAM_SEED_5211) | 1424 | AR5K_DIAG_SW_EN_SCRAM_SEED_5210 : AR5K_DIAG_SW_EN_SCRAM_SEED_5211) |
1425 | #define AR5K_DIAG_SW_ECO_ENABLE 0x00000400 /* [5211+] */ | 1425 | #define AR5K_DIAG_SW_ECO_ENABLE 0x00000400 /* [5211+] */ |
1426 | #define AR5K_DIAG_SW_SCVRAM_SEED 0x0003f800 /* [5210] */ | 1426 | #define AR5K_DIAG_SW_SCVRAM_SEED 0x0003f800 /* [5210] */ |
1427 | #define AR5K_DIAG_SW_SCRAM_SEED_M 0x0001fc00 /* Scrambler seed mask */ | 1427 | #define AR5K_DIAG_SW_SCRAM_SEED_M 0x0001fc00 /* Scrambler seed mask */ |
1428 | #define AR5K_DIAG_SW_SCRAM_SEED_S 10 | 1428 | #define AR5K_DIAG_SW_SCRAM_SEED_S 10 |
1429 | #define AR5K_DIAG_SW_DIS_SEQ_INC 0x00040000 /* Disable seqnum increment (?)[5210] */ | 1429 | #define AR5K_DIAG_SW_DIS_SEQ_INC 0x00040000 /* Disable seqnum increment (?)[5210] */ |
1430 | #define AR5K_DIAG_SW_FRAME_NV0_5210 0x00080000 | 1430 | #define AR5K_DIAG_SW_FRAME_NV0_5210 0x00080000 |
1431 | #define AR5K_DIAG_SW_FRAME_NV0_5211 0x00020000 /* Accept frames of non-zero protocol number */ | 1431 | #define AR5K_DIAG_SW_FRAME_NV0_5211 0x00020000 /* Accept frames of non-zero protocol number */ |
1432 | #define AR5K_DIAG_SW_FRAME_NV0 (ah->ah_version == AR5K_AR5210 ? \ | 1432 | #define AR5K_DIAG_SW_FRAME_NV0 (ah->ah_version == AR5K_AR5210 ? \ |
1433 | AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211) | 1433 | AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211) |
1434 | #define AR5K_DIAG_SW_OBSPT_M 0x000c0000 /* Observation point select (?) */ | 1434 | #define AR5K_DIAG_SW_OBSPT_M 0x000c0000 /* Observation point select (?) */ |
1435 | #define AR5K_DIAG_SW_OBSPT_S 18 | 1435 | #define AR5K_DIAG_SW_OBSPT_S 18 |
1436 | #define AR5K_DIAG_SW_RX_CLEAR_HIGH 0x0010000 /* Force RX Clear high */ | 1436 | #define AR5K_DIAG_SW_RX_CLEAR_HIGH 0x0010000 /* Force RX Clear high */ |
1437 | #define AR5K_DIAG_SW_IGNORE_CARR_SENSE 0x0020000 /* Ignore virtual carrier sense */ | 1437 | #define AR5K_DIAG_SW_IGNORE_CARR_SENSE 0x0020000 /* Ignore virtual carrier sense */ |
1438 | #define AR5K_DIAG_SW_CHANEL_IDLE_HIGH 0x0040000 /* Force channel idle high */ | 1438 | #define AR5K_DIAG_SW_CHANEL_IDLE_HIGH 0x0040000 /* Force channel idle high */ |
1439 | #define AR5K_DIAG_SW_PHEAR_ME 0x0080000 /* ??? */ | 1439 | #define AR5K_DIAG_SW_PHEAR_ME 0x0080000 /* ??? */ |
1440 | 1440 | ||
1441 | /* | 1441 | /* |
1442 | * TSF (clock) register (lower 32 bits) | 1442 | * TSF (clock) register (lower 32 bits) |
1443 | */ | 1443 | */ |
1444 | #define AR5K_TSF_L32_5210 0x806c | 1444 | #define AR5K_TSF_L32_5210 0x806c |
1445 | #define AR5K_TSF_L32_5211 0x804c | 1445 | #define AR5K_TSF_L32_5211 0x804c |
1446 | #define AR5K_TSF_L32 (ah->ah_version == AR5K_AR5210 ? \ | 1446 | #define AR5K_TSF_L32 (ah->ah_version == AR5K_AR5210 ? \ |
1447 | AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211) | 1447 | AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211) |
1448 | 1448 | ||
1449 | /* | 1449 | /* |
1450 | * TSF (clock) register (higher 32 bits) | 1450 | * TSF (clock) register (higher 32 bits) |
1451 | */ | 1451 | */ |
1452 | #define AR5K_TSF_U32_5210 0x8070 | 1452 | #define AR5K_TSF_U32_5210 0x8070 |
1453 | #define AR5K_TSF_U32_5211 0x8050 | 1453 | #define AR5K_TSF_U32_5211 0x8050 |
1454 | #define AR5K_TSF_U32 (ah->ah_version == AR5K_AR5210 ? \ | 1454 | #define AR5K_TSF_U32 (ah->ah_version == AR5K_AR5210 ? \ |
1455 | AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211) | 1455 | AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211) |
1456 | 1456 | ||
1457 | /* | 1457 | /* |
1458 | * Last beacon timestamp register (Read Only) | 1458 | * Last beacon timestamp register (Read Only) |
1459 | */ | 1459 | */ |
1460 | #define AR5K_LAST_TSTP 0x8080 | 1460 | #define AR5K_LAST_TSTP 0x8080 |
1461 | 1461 | ||
1462 | /* | 1462 | /* |
1463 | * ADDAC test register [5211+] | 1463 | * ADDAC test register [5211+] |
1464 | */ | 1464 | */ |
1465 | #define AR5K_ADDAC_TEST 0x8054 /* Register Address */ | 1465 | #define AR5K_ADDAC_TEST 0x8054 /* Register Address */ |
1466 | #define AR5K_ADDAC_TEST_TXCONT 0x00000001 /* Test continuous tx */ | 1466 | #define AR5K_ADDAC_TEST_TXCONT 0x00000001 /* Test continuous tx */ |
1467 | #define AR5K_ADDAC_TEST_TST_MODE 0x00000002 /* Test mode */ | 1467 | #define AR5K_ADDAC_TEST_TST_MODE 0x00000002 /* Test mode */ |
1468 | #define AR5K_ADDAC_TEST_LOOP_EN 0x00000004 /* Enable loop */ | 1468 | #define AR5K_ADDAC_TEST_LOOP_EN 0x00000004 /* Enable loop */ |
1469 | #define AR5K_ADDAC_TEST_LOOP_LEN 0x00000008 /* Loop length (field) */ | 1469 | #define AR5K_ADDAC_TEST_LOOP_LEN 0x00000008 /* Loop length (field) */ |
1470 | #define AR5K_ADDAC_TEST_USE_U8 0x00004000 /* Use upper 8 bits */ | 1470 | #define AR5K_ADDAC_TEST_USE_U8 0x00004000 /* Use upper 8 bits */ |
1471 | #define AR5K_ADDAC_TEST_MSB 0x00008000 /* State of MSB */ | 1471 | #define AR5K_ADDAC_TEST_MSB 0x00008000 /* State of MSB */ |
1472 | #define AR5K_ADDAC_TEST_TRIG_SEL 0x00010000 /* Trigger select */ | 1472 | #define AR5K_ADDAC_TEST_TRIG_SEL 0x00010000 /* Trigger select */ |
1473 | #define AR5K_ADDAC_TEST_TRIG_PTY 0x00020000 /* Trigger polarity */ | 1473 | #define AR5K_ADDAC_TEST_TRIG_PTY 0x00020000 /* Trigger polarity */ |
1474 | #define AR5K_ADDAC_TEST_RXCONT 0x00040000 /* Continuous capture */ | 1474 | #define AR5K_ADDAC_TEST_RXCONT 0x00040000 /* Continuous capture */ |
1475 | #define AR5K_ADDAC_TEST_CAPTURE 0x00080000 /* Begin capture */ | 1475 | #define AR5K_ADDAC_TEST_CAPTURE 0x00080000 /* Begin capture */ |
1476 | #define AR5K_ADDAC_TEST_TST_ARM 0x00100000 /* ARM rx buffer for capture */ | 1476 | #define AR5K_ADDAC_TEST_TST_ARM 0x00100000 /* ARM rx buffer for capture */ |
1477 | 1477 | ||
1478 | /* | 1478 | /* |
1479 | * Default antenna register [5211+] | 1479 | * Default antenna register [5211+] |
1480 | */ | 1480 | */ |
1481 | #define AR5K_DEFAULT_ANTENNA 0x8058 | 1481 | #define AR5K_DEFAULT_ANTENNA 0x8058 |
1482 | 1482 | ||
1483 | /* | 1483 | /* |
1484 | * Frame control QoS mask register (?) [5211+] | 1484 | * Frame control QoS mask register (?) [5211+] |
1485 | * (FC_QOS_MASK) | 1485 | * (FC_QOS_MASK) |
1486 | */ | 1486 | */ |
1487 | #define AR5K_FRAME_CTL_QOSM 0x805c | 1487 | #define AR5K_FRAME_CTL_QOSM 0x805c |
1488 | 1488 | ||
1489 | /* | 1489 | /* |
1490 | * Seq mask register (?) [5211+] | 1490 | * Seq mask register (?) [5211+] |
1491 | */ | 1491 | */ |
1492 | #define AR5K_SEQ_MASK 0x8060 | 1492 | #define AR5K_SEQ_MASK 0x8060 |
1493 | 1493 | ||
1494 | /* | 1494 | /* |
1495 | * Retry count register [5210] | 1495 | * Retry count register [5210] |
1496 | */ | 1496 | */ |
1497 | #define AR5K_RETRY_CNT 0x8084 /* Register Address [5210] */ | 1497 | #define AR5K_RETRY_CNT 0x8084 /* Register Address [5210] */ |
1498 | #define AR5K_RETRY_CNT_SSH 0x0000003f /* Station short retry count (?) */ | 1498 | #define AR5K_RETRY_CNT_SSH 0x0000003f /* Station short retry count (?) */ |
1499 | #define AR5K_RETRY_CNT_SLG 0x00000fc0 /* Station long retry count (?) */ | 1499 | #define AR5K_RETRY_CNT_SLG 0x00000fc0 /* Station long retry count (?) */ |
1500 | 1500 | ||
1501 | /* | 1501 | /* |
1502 | * Back-off status register [5210] | 1502 | * Back-off status register [5210] |
1503 | */ | 1503 | */ |
1504 | #define AR5K_BACKOFF 0x8088 /* Register Address [5210] */ | 1504 | #define AR5K_BACKOFF 0x8088 /* Register Address [5210] */ |
1505 | #define AR5K_BACKOFF_CW 0x000003ff /* Backoff Contention Window (?) */ | 1505 | #define AR5K_BACKOFF_CW 0x000003ff /* Backoff Contention Window (?) */ |
1506 | #define AR5K_BACKOFF_CNT 0x03ff0000 /* Backoff count (?) */ | 1506 | #define AR5K_BACKOFF_CNT 0x03ff0000 /* Backoff count (?) */ |
1507 | 1507 | ||
1508 | 1508 | ||
1509 | 1509 | ||
1510 | /* | 1510 | /* |
1511 | * NAV register (current) | 1511 | * NAV register (current) |
1512 | */ | 1512 | */ |
1513 | #define AR5K_NAV_5210 0x808c | 1513 | #define AR5K_NAV_5210 0x808c |
1514 | #define AR5K_NAV_5211 0x8084 | 1514 | #define AR5K_NAV_5211 0x8084 |
1515 | #define AR5K_NAV (ah->ah_version == AR5K_AR5210 ? \ | 1515 | #define AR5K_NAV (ah->ah_version == AR5K_AR5210 ? \ |
1516 | AR5K_NAV_5210 : AR5K_NAV_5211) | 1516 | AR5K_NAV_5210 : AR5K_NAV_5211) |
1517 | 1517 | ||
1518 | /* | 1518 | /* |
1519 | * RTS success register | 1519 | * RTS success register |
1520 | */ | 1520 | */ |
1521 | #define AR5K_RTS_OK_5210 0x8090 | 1521 | #define AR5K_RTS_OK_5210 0x8090 |
1522 | #define AR5K_RTS_OK_5211 0x8088 | 1522 | #define AR5K_RTS_OK_5211 0x8088 |
1523 | #define AR5K_RTS_OK (ah->ah_version == AR5K_AR5210 ? \ | 1523 | #define AR5K_RTS_OK (ah->ah_version == AR5K_AR5210 ? \ |
1524 | AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211) | 1524 | AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211) |
1525 | 1525 | ||
1526 | /* | 1526 | /* |
1527 | * RTS failure register | 1527 | * RTS failure register |
1528 | */ | 1528 | */ |
1529 | #define AR5K_RTS_FAIL_5210 0x8094 | 1529 | #define AR5K_RTS_FAIL_5210 0x8094 |
1530 | #define AR5K_RTS_FAIL_5211 0x808c | 1530 | #define AR5K_RTS_FAIL_5211 0x808c |
1531 | #define AR5K_RTS_FAIL (ah->ah_version == AR5K_AR5210 ? \ | 1531 | #define AR5K_RTS_FAIL (ah->ah_version == AR5K_AR5210 ? \ |
1532 | AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211) | 1532 | AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211) |
1533 | 1533 | ||
1534 | /* | 1534 | /* |
1535 | * ACK failure register | 1535 | * ACK failure register |
1536 | */ | 1536 | */ |
1537 | #define AR5K_ACK_FAIL_5210 0x8098 | 1537 | #define AR5K_ACK_FAIL_5210 0x8098 |
1538 | #define AR5K_ACK_FAIL_5211 0x8090 | 1538 | #define AR5K_ACK_FAIL_5211 0x8090 |
1539 | #define AR5K_ACK_FAIL (ah->ah_version == AR5K_AR5210 ? \ | 1539 | #define AR5K_ACK_FAIL (ah->ah_version == AR5K_AR5210 ? \ |
1540 | AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211) | 1540 | AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211) |
1541 | 1541 | ||
1542 | /* | 1542 | /* |
1543 | * FCS failure register | 1543 | * FCS failure register |
1544 | */ | 1544 | */ |
1545 | #define AR5K_FCS_FAIL_5210 0x809c | 1545 | #define AR5K_FCS_FAIL_5210 0x809c |
1546 | #define AR5K_FCS_FAIL_5211 0x8094 | 1546 | #define AR5K_FCS_FAIL_5211 0x8094 |
1547 | #define AR5K_FCS_FAIL (ah->ah_version == AR5K_AR5210 ? \ | 1547 | #define AR5K_FCS_FAIL (ah->ah_version == AR5K_AR5210 ? \ |
1548 | AR5K_FCS_FAIL_5210 : AR5K_FCS_FAIL_5211) | 1548 | AR5K_FCS_FAIL_5210 : AR5K_FCS_FAIL_5211) |
1549 | 1549 | ||
1550 | /* | 1550 | /* |
1551 | * Beacon count register | 1551 | * Beacon count register |
1552 | */ | 1552 | */ |
1553 | #define AR5K_BEACON_CNT_5210 0x80a0 | 1553 | #define AR5K_BEACON_CNT_5210 0x80a0 |
1554 | #define AR5K_BEACON_CNT_5211 0x8098 | 1554 | #define AR5K_BEACON_CNT_5211 0x8098 |
1555 | #define AR5K_BEACON_CNT (ah->ah_version == AR5K_AR5210 ? \ | 1555 | #define AR5K_BEACON_CNT (ah->ah_version == AR5K_AR5210 ? \ |
1556 | AR5K_BEACON_CNT_5210 : AR5K_BEACON_CNT_5211) | 1556 | AR5K_BEACON_CNT_5210 : AR5K_BEACON_CNT_5211) |
1557 | 1557 | ||
1558 | 1558 | ||
1559 | /*===5212 Specific PCU registers===*/ | 1559 | /*===5212 Specific PCU registers===*/ |
1560 | 1560 | ||
1561 | /* | 1561 | /* |
1562 | * Transmit power control register | 1562 | * Transmit power control register |
1563 | */ | 1563 | */ |
1564 | #define AR5K_TPC 0x80e8 | 1564 | #define AR5K_TPC 0x80e8 |
1565 | #define AR5K_TPC_ACK 0x0000003f /* ack frames */ | 1565 | #define AR5K_TPC_ACK 0x0000003f /* ack frames */ |
1566 | #define AR5K_TPC_ACK_S 0 | 1566 | #define AR5K_TPC_ACK_S 0 |
1567 | #define AR5K_TPC_CTS 0x00003f00 /* cts frames */ | 1567 | #define AR5K_TPC_CTS 0x00003f00 /* cts frames */ |
1568 | #define AR5K_TPC_CTS_S 8 | 1568 | #define AR5K_TPC_CTS_S 8 |
1569 | #define AR5K_TPC_CHIRP 0x003f0000 /* chirp frames */ | 1569 | #define AR5K_TPC_CHIRP 0x003f0000 /* chirp frames */ |
1570 | #define AR5K_TPC_CHIRP_S 16 | 1570 | #define AR5K_TPC_CHIRP_S 16 |
1571 | #define AR5K_TPC_DOPPLER 0x0f000000 /* doppler chirp span */ | 1571 | #define AR5K_TPC_DOPPLER 0x0f000000 /* doppler chirp span */ |
1572 | #define AR5K_TPC_DOPPLER_S 24 | 1572 | #define AR5K_TPC_DOPPLER_S 24 |
1573 | 1573 | ||
1574 | /* | 1574 | /* |
1575 | * XR (eXtended Range) mode register | 1575 | * XR (eXtended Range) mode register |
1576 | */ | 1576 | */ |
1577 | #define AR5K_XRMODE 0x80c0 /* Register Address */ | 1577 | #define AR5K_XRMODE 0x80c0 /* Register Address */ |
1578 | #define AR5K_XRMODE_POLL_TYPE_M 0x0000003f /* Mask for Poll type (?) */ | 1578 | #define AR5K_XRMODE_POLL_TYPE_M 0x0000003f /* Mask for Poll type (?) */ |
1579 | #define AR5K_XRMODE_POLL_TYPE_S 0 | 1579 | #define AR5K_XRMODE_POLL_TYPE_S 0 |
1580 | #define AR5K_XRMODE_POLL_SUBTYPE_M 0x0000003c /* Mask for Poll subtype (?) */ | 1580 | #define AR5K_XRMODE_POLL_SUBTYPE_M 0x0000003c /* Mask for Poll subtype (?) */ |
1581 | #define AR5K_XRMODE_POLL_SUBTYPE_S 2 | 1581 | #define AR5K_XRMODE_POLL_SUBTYPE_S 2 |
1582 | #define AR5K_XRMODE_POLL_WAIT_ALL 0x00000080 /* Wait for poll */ | 1582 | #define AR5K_XRMODE_POLL_WAIT_ALL 0x00000080 /* Wait for poll */ |
1583 | #define AR5K_XRMODE_SIFS_DELAY 0x000fff00 /* Mask for SIFS delay */ | 1583 | #define AR5K_XRMODE_SIFS_DELAY 0x000fff00 /* Mask for SIFS delay */ |
1584 | #define AR5K_XRMODE_FRAME_HOLD_M 0xfff00000 /* Mask for frame hold (?) */ | 1584 | #define AR5K_XRMODE_FRAME_HOLD_M 0xfff00000 /* Mask for frame hold (?) */ |
1585 | #define AR5K_XRMODE_FRAME_HOLD_S 20 | 1585 | #define AR5K_XRMODE_FRAME_HOLD_S 20 |
1586 | 1586 | ||
1587 | /* | 1587 | /* |
1588 | * XR delay register | 1588 | * XR delay register |
1589 | */ | 1589 | */ |
1590 | #define AR5K_XRDELAY 0x80c4 /* Register Address */ | 1590 | #define AR5K_XRDELAY 0x80c4 /* Register Address */ |
1591 | #define AR5K_XRDELAY_SLOT_DELAY_M 0x0000ffff /* Mask for slot delay */ | 1591 | #define AR5K_XRDELAY_SLOT_DELAY_M 0x0000ffff /* Mask for slot delay */ |
1592 | #define AR5K_XRDELAY_SLOT_DELAY_S 0 | 1592 | #define AR5K_XRDELAY_SLOT_DELAY_S 0 |
1593 | #define AR5K_XRDELAY_CHIRP_DELAY_M 0xffff0000 /* Mask for CHIRP data delay */ | 1593 | #define AR5K_XRDELAY_CHIRP_DELAY_M 0xffff0000 /* Mask for CHIRP data delay */ |
1594 | #define AR5K_XRDELAY_CHIRP_DELAY_S 16 | 1594 | #define AR5K_XRDELAY_CHIRP_DELAY_S 16 |
1595 | 1595 | ||
1596 | /* | 1596 | /* |
1597 | * XR timeout register | 1597 | * XR timeout register |
1598 | */ | 1598 | */ |
1599 | #define AR5K_XRTIMEOUT 0x80c8 /* Register Address */ | 1599 | #define AR5K_XRTIMEOUT 0x80c8 /* Register Address */ |
1600 | #define AR5K_XRTIMEOUT_CHIRP_M 0x0000ffff /* Mask for CHIRP timeout */ | 1600 | #define AR5K_XRTIMEOUT_CHIRP_M 0x0000ffff /* Mask for CHIRP timeout */ |
1601 | #define AR5K_XRTIMEOUT_CHIRP_S 0 | 1601 | #define AR5K_XRTIMEOUT_CHIRP_S 0 |
1602 | #define AR5K_XRTIMEOUT_POLL_M 0xffff0000 /* Mask for Poll timeout */ | 1602 | #define AR5K_XRTIMEOUT_POLL_M 0xffff0000 /* Mask for Poll timeout */ |
1603 | #define AR5K_XRTIMEOUT_POLL_S 16 | 1603 | #define AR5K_XRTIMEOUT_POLL_S 16 |
1604 | 1604 | ||
1605 | /* | 1605 | /* |
1606 | * XR chirp register | 1606 | * XR chirp register |
1607 | */ | 1607 | */ |
1608 | #define AR5K_XRCHIRP 0x80cc /* Register Address */ | 1608 | #define AR5K_XRCHIRP 0x80cc /* Register Address */ |
1609 | #define AR5K_XRCHIRP_SEND 0x00000001 /* Send CHIRP */ | 1609 | #define AR5K_XRCHIRP_SEND 0x00000001 /* Send CHIRP */ |
1610 | #define AR5K_XRCHIRP_GAP 0xffff0000 /* Mask for CHIRP gap (?) */ | 1610 | #define AR5K_XRCHIRP_GAP 0xffff0000 /* Mask for CHIRP gap (?) */ |
1611 | 1611 | ||
1612 | /* | 1612 | /* |
1613 | * XR stomp register | 1613 | * XR stomp register |
1614 | */ | 1614 | */ |
1615 | #define AR5K_XRSTOMP 0x80d0 /* Register Address */ | 1615 | #define AR5K_XRSTOMP 0x80d0 /* Register Address */ |
1616 | #define AR5K_XRSTOMP_TX 0x00000001 /* Stomp Tx (?) */ | 1616 | #define AR5K_XRSTOMP_TX 0x00000001 /* Stomp Tx (?) */ |
1617 | #define AR5K_XRSTOMP_RX 0x00000002 /* Stomp Rx (?) */ | 1617 | #define AR5K_XRSTOMP_RX 0x00000002 /* Stomp Rx (?) */ |
1618 | #define AR5K_XRSTOMP_TX_RSSI 0x00000004 /* Stomp Tx RSSI (?) */ | 1618 | #define AR5K_XRSTOMP_TX_RSSI 0x00000004 /* Stomp Tx RSSI (?) */ |
1619 | #define AR5K_XRSTOMP_TX_BSSID 0x00000008 /* Stomp Tx BSSID (?) */ | 1619 | #define AR5K_XRSTOMP_TX_BSSID 0x00000008 /* Stomp Tx BSSID (?) */ |
1620 | #define AR5K_XRSTOMP_DATA 0x00000010 /* Stomp data (?)*/ | 1620 | #define AR5K_XRSTOMP_DATA 0x00000010 /* Stomp data (?)*/ |
1621 | #define AR5K_XRSTOMP_RSSI_THRES 0x0000ff00 /* Mask for XR RSSI threshold */ | 1621 | #define AR5K_XRSTOMP_RSSI_THRES 0x0000ff00 /* Mask for XR RSSI threshold */ |
1622 | 1622 | ||
1623 | /* | 1623 | /* |
1624 | * First enhanced sleep register | 1624 | * First enhanced sleep register |
1625 | */ | 1625 | */ |
1626 | #define AR5K_SLEEP0 0x80d4 /* Register Address */ | 1626 | #define AR5K_SLEEP0 0x80d4 /* Register Address */ |
1627 | #define AR5K_SLEEP0_NEXT_DTIM 0x0007ffff /* Mask for next DTIM (?) */ | 1627 | #define AR5K_SLEEP0_NEXT_DTIM 0x0007ffff /* Mask for next DTIM (?) */ |
1628 | #define AR5K_SLEEP0_NEXT_DTIM_S 0 | 1628 | #define AR5K_SLEEP0_NEXT_DTIM_S 0 |
1629 | #define AR5K_SLEEP0_ASSUME_DTIM 0x00080000 /* Assume DTIM */ | 1629 | #define AR5K_SLEEP0_ASSUME_DTIM 0x00080000 /* Assume DTIM */ |
1630 | #define AR5K_SLEEP0_ENH_SLEEP_EN 0x00100000 /* Enable enchanced sleep control */ | 1630 | #define AR5K_SLEEP0_ENH_SLEEP_EN 0x00100000 /* Enable enchanced sleep control */ |
1631 | #define AR5K_SLEEP0_CABTO 0xff000000 /* Mask for CAB Time Out */ | 1631 | #define AR5K_SLEEP0_CABTO 0xff000000 /* Mask for CAB Time Out */ |
1632 | #define AR5K_SLEEP0_CABTO_S 24 | 1632 | #define AR5K_SLEEP0_CABTO_S 24 |
1633 | 1633 | ||
1634 | /* | 1634 | /* |
1635 | * Second enhanced sleep register | 1635 | * Second enhanced sleep register |
1636 | */ | 1636 | */ |
1637 | #define AR5K_SLEEP1 0x80d8 /* Register Address */ | 1637 | #define AR5K_SLEEP1 0x80d8 /* Register Address */ |
1638 | #define AR5K_SLEEP1_NEXT_TIM 0x0007ffff /* Mask for next TIM (?) */ | 1638 | #define AR5K_SLEEP1_NEXT_TIM 0x0007ffff /* Mask for next TIM (?) */ |
1639 | #define AR5K_SLEEP1_NEXT_TIM_S 0 | 1639 | #define AR5K_SLEEP1_NEXT_TIM_S 0 |
1640 | #define AR5K_SLEEP1_BEACON_TO 0xff000000 /* Mask for Beacon Time Out */ | 1640 | #define AR5K_SLEEP1_BEACON_TO 0xff000000 /* Mask for Beacon Time Out */ |
1641 | #define AR5K_SLEEP1_BEACON_TO_S 24 | 1641 | #define AR5K_SLEEP1_BEACON_TO_S 24 |
1642 | 1642 | ||
1643 | /* | 1643 | /* |
1644 | * Third enhanced sleep register | 1644 | * Third enhanced sleep register |
1645 | */ | 1645 | */ |
1646 | #define AR5K_SLEEP2 0x80dc /* Register Address */ | 1646 | #define AR5K_SLEEP2 0x80dc /* Register Address */ |
1647 | #define AR5K_SLEEP2_TIM_PER 0x0000ffff /* Mask for TIM period (?) */ | 1647 | #define AR5K_SLEEP2_TIM_PER 0x0000ffff /* Mask for TIM period (?) */ |
1648 | #define AR5K_SLEEP2_TIM_PER_S 0 | 1648 | #define AR5K_SLEEP2_TIM_PER_S 0 |
1649 | #define AR5K_SLEEP2_DTIM_PER 0xffff0000 /* Mask for DTIM period (?) */ | 1649 | #define AR5K_SLEEP2_DTIM_PER 0xffff0000 /* Mask for DTIM period (?) */ |
1650 | #define AR5K_SLEEP2_DTIM_PER_S 16 | 1650 | #define AR5K_SLEEP2_DTIM_PER_S 16 |
1651 | 1651 | ||
1652 | /* | 1652 | /* |
1653 | * BSSID mask registers | 1653 | * BSSID mask registers |
1654 | */ | 1654 | */ |
1655 | #define AR5K_BSS_IDM0 0x80e0 /* Upper bits */ | 1655 | #define AR5K_BSS_IDM0 0x80e0 /* Upper bits */ |
1656 | #define AR5K_BSS_IDM1 0x80e4 /* Lower bits */ | 1656 | #define AR5K_BSS_IDM1 0x80e4 /* Lower bits */ |
1657 | 1657 | ||
1658 | /* | 1658 | /* |
1659 | * TX power control (TPC) register | 1659 | * TX power control (TPC) register |
1660 | * | 1660 | * |
1661 | * XXX: PCDAC steps (0.5dbm) or DBM ? | 1661 | * XXX: PCDAC steps (0.5dbm) or DBM ? |
1662 | * | 1662 | * |
1663 | */ | 1663 | */ |
1664 | #define AR5K_TXPC 0x80e8 /* Register Address */ | 1664 | #define AR5K_TXPC 0x80e8 /* Register Address */ |
1665 | #define AR5K_TXPC_ACK_M 0x0000003f /* ACK tx power */ | 1665 | #define AR5K_TXPC_ACK_M 0x0000003f /* ACK tx power */ |
1666 | #define AR5K_TXPC_ACK_S 0 | 1666 | #define AR5K_TXPC_ACK_S 0 |
1667 | #define AR5K_TXPC_CTS_M 0x00003f00 /* CTS tx power */ | 1667 | #define AR5K_TXPC_CTS_M 0x00003f00 /* CTS tx power */ |
1668 | #define AR5K_TXPC_CTS_S 8 | 1668 | #define AR5K_TXPC_CTS_S 8 |
1669 | #define AR5K_TXPC_CHIRP_M 0x003f0000 /* CHIRP tx power */ | 1669 | #define AR5K_TXPC_CHIRP_M 0x003f0000 /* CHIRP tx power */ |
1670 | #define AR5K_TXPC_CHIRP_S 16 | 1670 | #define AR5K_TXPC_CHIRP_S 16 |
1671 | #define AR5K_TXPC_DOPPLER 0x0f000000 /* Doppler chirp span (?) */ | 1671 | #define AR5K_TXPC_DOPPLER 0x0f000000 /* Doppler chirp span (?) */ |
1672 | #define AR5K_TXPC_DOPPLER_S 24 | 1672 | #define AR5K_TXPC_DOPPLER_S 24 |
1673 | 1673 | ||
1674 | /* | 1674 | /* |
1675 | * Profile count registers | 1675 | * Profile count registers |
1676 | */ | 1676 | */ |
1677 | #define AR5K_PROFCNT_TX 0x80ec /* Tx count */ | 1677 | #define AR5K_PROFCNT_TX 0x80ec /* Tx count */ |
1678 | #define AR5K_PROFCNT_RX 0x80f0 /* Rx count */ | 1678 | #define AR5K_PROFCNT_RX 0x80f0 /* Rx count */ |
1679 | #define AR5K_PROFCNT_RXCLR 0x80f4 /* Clear Rx count */ | 1679 | #define AR5K_PROFCNT_RXCLR 0x80f4 /* Clear Rx count */ |
1680 | #define AR5K_PROFCNT_CYCLE 0x80f8 /* Cycle count (?) */ | 1680 | #define AR5K_PROFCNT_CYCLE 0x80f8 /* Cycle count (?) */ |
1681 | 1681 | ||
1682 | /* | 1682 | /* |
1683 | * Quiet period control registers | 1683 | * Quiet period control registers |
1684 | */ | 1684 | */ |
1685 | #define AR5K_QUIET_CTL1 0x80fc /* Register Address */ | 1685 | #define AR5K_QUIET_CTL1 0x80fc /* Register Address */ |
1686 | #define AR5K_QUIET_CTL1_NEXT_QT_TSF 0x0000ffff /* Next quiet period TSF (TU) */ | 1686 | #define AR5K_QUIET_CTL1_NEXT_QT_TSF 0x0000ffff /* Next quiet period TSF (TU) */ |
1687 | #define AR5K_QUIET_CTL1_NEXT_QT_TSF_S 0 | 1687 | #define AR5K_QUIET_CTL1_NEXT_QT_TSF_S 0 |
1688 | #define AR5K_QUIET_CTL1_QT_EN 0x00010000 /* Enable quiet period */ | 1688 | #define AR5K_QUIET_CTL1_QT_EN 0x00010000 /* Enable quiet period */ |
1689 | #define AR5K_QUIET_CTL1_ACK_CTS_EN 0x00020000 /* Send ACK/CTS during quiet period */ | 1689 | #define AR5K_QUIET_CTL1_ACK_CTS_EN 0x00020000 /* Send ACK/CTS during quiet period */ |
1690 | 1690 | ||
1691 | #define AR5K_QUIET_CTL2 0x8100 /* Register Address */ | 1691 | #define AR5K_QUIET_CTL2 0x8100 /* Register Address */ |
1692 | #define AR5K_QUIET_CTL2_QT_PER 0x0000ffff /* Mask for quiet period periodicity */ | 1692 | #define AR5K_QUIET_CTL2_QT_PER 0x0000ffff /* Mask for quiet period periodicity */ |
1693 | #define AR5K_QUIET_CTL2_QT_PER_S 0 | 1693 | #define AR5K_QUIET_CTL2_QT_PER_S 0 |
1694 | #define AR5K_QUIET_CTL2_QT_DUR 0xffff0000 /* Mask for quiet period duration */ | 1694 | #define AR5K_QUIET_CTL2_QT_DUR 0xffff0000 /* Mask for quiet period duration */ |
1695 | #define AR5K_QUIET_CTL2_QT_DUR_S 16 | 1695 | #define AR5K_QUIET_CTL2_QT_DUR_S 16 |
1696 | 1696 | ||
1697 | /* | 1697 | /* |
1698 | * TSF parameter register | 1698 | * TSF parameter register |
1699 | */ | 1699 | */ |
1700 | #define AR5K_TSF_PARM 0x8104 /* Register Address */ | 1700 | #define AR5K_TSF_PARM 0x8104 /* Register Address */ |
1701 | #define AR5K_TSF_PARM_INC 0x000000ff /* Mask for TSF increment */ | 1701 | #define AR5K_TSF_PARM_INC 0x000000ff /* Mask for TSF increment */ |
1702 | #define AR5K_TSF_PARM_INC_S 0 | 1702 | #define AR5K_TSF_PARM_INC_S 0 |
1703 | 1703 | ||
1704 | /* | 1704 | /* |
1705 | * QoS NOACK policy | 1705 | * QoS NOACK policy |
1706 | */ | 1706 | */ |
1707 | #define AR5K_QOS_NOACK 0x8108 /* Register Address */ | 1707 | #define AR5K_QOS_NOACK 0x8108 /* Register Address */ |
1708 | #define AR5K_QOS_NOACK_2BIT_VALUES 0x0000000f /* ??? */ | 1708 | #define AR5K_QOS_NOACK_2BIT_VALUES 0x0000000f /* ??? */ |
1709 | #define AR5K_QOS_NOACK_2BIT_VALUES_S 0 | 1709 | #define AR5K_QOS_NOACK_2BIT_VALUES_S 0 |
1710 | #define AR5K_QOS_NOACK_BIT_OFFSET 0x00000070 /* ??? */ | 1710 | #define AR5K_QOS_NOACK_BIT_OFFSET 0x00000070 /* ??? */ |
1711 | #define AR5K_QOS_NOACK_BIT_OFFSET_S 4 | 1711 | #define AR5K_QOS_NOACK_BIT_OFFSET_S 4 |
1712 | #define AR5K_QOS_NOACK_BYTE_OFFSET 0x00000180 /* ??? */ | 1712 | #define AR5K_QOS_NOACK_BYTE_OFFSET 0x00000180 /* ??? */ |
1713 | #define AR5K_QOS_NOACK_BYTE_OFFSET_S 7 | 1713 | #define AR5K_QOS_NOACK_BYTE_OFFSET_S 7 |
1714 | 1714 | ||
1715 | /* | 1715 | /* |
1716 | * PHY error filter register | 1716 | * PHY error filter register |
1717 | */ | 1717 | */ |
1718 | #define AR5K_PHY_ERR_FIL 0x810c | 1718 | #define AR5K_PHY_ERR_FIL 0x810c |
1719 | #define AR5K_PHY_ERR_FIL_RADAR 0x00000020 /* Radar signal */ | 1719 | #define AR5K_PHY_ERR_FIL_RADAR 0x00000020 /* Radar signal */ |
1720 | #define AR5K_PHY_ERR_FIL_OFDM 0x00020000 /* OFDM false detect (ANI) */ | 1720 | #define AR5K_PHY_ERR_FIL_OFDM 0x00020000 /* OFDM false detect (ANI) */ |
1721 | #define AR5K_PHY_ERR_FIL_CCK 0x02000000 /* CCK false detect (ANI) */ | 1721 | #define AR5K_PHY_ERR_FIL_CCK 0x02000000 /* CCK false detect (ANI) */ |
1722 | 1722 | ||
1723 | /* | 1723 | /* |
1724 | * XR latency register | 1724 | * XR latency register |
1725 | */ | 1725 | */ |
1726 | #define AR5K_XRLAT_TX 0x8110 | 1726 | #define AR5K_XRLAT_TX 0x8110 |
1727 | 1727 | ||
1728 | /* | 1728 | /* |
1729 | * ACK SIFS register | 1729 | * ACK SIFS register |
1730 | */ | 1730 | */ |
1731 | #define AR5K_ACKSIFS 0x8114 /* Register Address */ | 1731 | #define AR5K_ACKSIFS 0x8114 /* Register Address */ |
1732 | #define AR5K_ACKSIFS_INC 0x00000000 /* ACK SIFS Increment (field) */ | 1732 | #define AR5K_ACKSIFS_INC 0x00000000 /* ACK SIFS Increment (field) */ |
1733 | 1733 | ||
1734 | /* | 1734 | /* |
1735 | * MIC QoS control register (?) | 1735 | * MIC QoS control register (?) |
1736 | */ | 1736 | */ |
1737 | #define AR5K_MIC_QOS_CTL 0x8118 /* Register Address */ | 1737 | #define AR5K_MIC_QOS_CTL 0x8118 /* Register Address */ |
1738 | #define AR5K_MIC_QOS_CTL_OFF(_n) (1 << (_n * 2)) | 1738 | #define AR5K_MIC_QOS_CTL_OFF(_n) (1 << (_n * 2)) |
1739 | #define AR5K_MIC_QOS_CTL_MQ_EN 0x00010000 /* Enable MIC QoS */ | 1739 | #define AR5K_MIC_QOS_CTL_MQ_EN 0x00010000 /* Enable MIC QoS */ |
1740 | 1740 | ||
1741 | /* | 1741 | /* |
1742 | * MIC QoS select register (?) | 1742 | * MIC QoS select register (?) |
1743 | */ | 1743 | */ |
1744 | #define AR5K_MIC_QOS_SEL 0x811c | 1744 | #define AR5K_MIC_QOS_SEL 0x811c |
1745 | #define AR5K_MIC_QOS_SEL_OFF(_n) (1 << (_n * 4)) | 1745 | #define AR5K_MIC_QOS_SEL_OFF(_n) (1 << (_n * 4)) |
1746 | 1746 | ||
1747 | /* | 1747 | /* |
1748 | * Misc mode control register (?) | 1748 | * Misc mode control register (?) |
1749 | */ | 1749 | */ |
1750 | #define AR5K_MISC_MODE 0x8120 /* Register Address */ | 1750 | #define AR5K_MISC_MODE 0x8120 /* Register Address */ |
1751 | #define AR5K_MISC_MODE_FBSSID_MATCH 0x00000001 /* Force BSSID match */ | 1751 | #define AR5K_MISC_MODE_FBSSID_MATCH 0x00000001 /* Force BSSID match */ |
1752 | #define AR5K_MISC_MODE_ACKSIFS_MEM 0x00000002 /* ACK SIFS memory (?) */ | 1752 | #define AR5K_MISC_MODE_ACKSIFS_MEM 0x00000002 /* ACK SIFS memory (?) */ |
1753 | #define AR5K_MISC_MODE_COMBINED_MIC 0x00000004 /* use rx/tx MIC key */ | 1753 | #define AR5K_MISC_MODE_COMBINED_MIC 0x00000004 /* use rx/tx MIC key */ |
1754 | /* more bits */ | 1754 | /* more bits */ |
1755 | 1755 | ||
1756 | /* | 1756 | /* |
1757 | * OFDM Filter counter | 1757 | * OFDM Filter counter |
1758 | */ | 1758 | */ |
1759 | #define AR5K_OFDM_FIL_CNT 0x8124 | 1759 | #define AR5K_OFDM_FIL_CNT 0x8124 |
1760 | 1760 | ||
1761 | /* | 1761 | /* |
1762 | * CCK Filter counter | 1762 | * CCK Filter counter |
1763 | */ | 1763 | */ |
1764 | #define AR5K_CCK_FIL_CNT 0x8128 | 1764 | #define AR5K_CCK_FIL_CNT 0x8128 |
1765 | 1765 | ||
1766 | /* | 1766 | /* |
1767 | * PHY Error Counters (?) | 1767 | * PHY Error Counters (?) |
1768 | */ | 1768 | */ |
1769 | #define AR5K_PHYERR_CNT1 0x812c | 1769 | #define AR5K_PHYERR_CNT1 0x812c |
1770 | #define AR5K_PHYERR_CNT1_MASK 0x8130 | 1770 | #define AR5K_PHYERR_CNT1_MASK 0x8130 |
1771 | 1771 | ||
1772 | #define AR5K_PHYERR_CNT2 0x8134 | 1772 | #define AR5K_PHYERR_CNT2 0x8134 |
1773 | #define AR5K_PHYERR_CNT2_MASK 0x8138 | 1773 | #define AR5K_PHYERR_CNT2_MASK 0x8138 |
1774 | 1774 | ||
1775 | /* | 1775 | /* |
1776 | * TSF Threshold register (?) | 1776 | * TSF Threshold register (?) |
1777 | */ | 1777 | */ |
1778 | #define AR5K_TSF_THRES 0x813c | 1778 | #define AR5K_TSF_THRES 0x813c |
1779 | 1779 | ||
1780 | /* | 1780 | /* |
1781 | * TODO: Wake On Wireless registers | 1781 | * TODO: Wake On Wireless registers |
1782 | * Range: 0x8147 - 0x818c | 1782 | * Range: 0x8147 - 0x818c |
1783 | */ | 1783 | */ |
1784 | 1784 | ||
1785 | /* | 1785 | /* |
1786 | * Rate -> ACK SIFS mapping table (32 entries) | 1786 | * Rate -> ACK SIFS mapping table (32 entries) |
1787 | */ | 1787 | */ |
1788 | #define AR5K_RATE_ACKSIFS_BASE 0x8680 /* Register Address */ | 1788 | #define AR5K_RATE_ACKSIFS_BASE 0x8680 /* Register Address */ |
1789 | #define AR5K_RATE_ACKSIFS(_n) (AR5K_RATE_ACKSIFS_BSE + ((_n) << 2)) | 1789 | #define AR5K_RATE_ACKSIFS(_n) (AR5K_RATE_ACKSIFS_BSE + ((_n) << 2)) |
1790 | #define AR5K_RATE_ACKSIFS_NORMAL 0x00000001 /* Normal SIFS (field) */ | 1790 | #define AR5K_RATE_ACKSIFS_NORMAL 0x00000001 /* Normal SIFS (field) */ |
1791 | #define AR5K_RATE_ACKSIFS_TURBO 0x00000400 /* Turbo SIFS (field) */ | 1791 | #define AR5K_RATE_ACKSIFS_TURBO 0x00000400 /* Turbo SIFS (field) */ |
1792 | 1792 | ||
1793 | /* | 1793 | /* |
1794 | * Rate -> duration mapping table (32 entries) | 1794 | * Rate -> duration mapping table (32 entries) |
1795 | */ | 1795 | */ |
1796 | #define AR5K_RATE_DUR_BASE 0x8700 | 1796 | #define AR5K_RATE_DUR_BASE 0x8700 |
1797 | #define AR5K_RATE_DUR(_n) (AR5K_RATE_DUR_BASE + ((_n) << 2)) | 1797 | #define AR5K_RATE_DUR(_n) (AR5K_RATE_DUR_BASE + ((_n) << 2)) |
1798 | 1798 | ||
1799 | /* | 1799 | /* |
1800 | * Rate -> db mapping table | 1800 | * Rate -> db mapping table |
1801 | * (8 entries, each one has 4 8bit fields) | 1801 | * (8 entries, each one has 4 8bit fields) |
1802 | */ | 1802 | */ |
1803 | #define AR5K_RATE2DB_BASE 0x87c0 | 1803 | #define AR5K_RATE2DB_BASE 0x87c0 |
1804 | #define AR5K_RATE2DB(_n) (AR5K_RATE2DB_BASE + ((_n) << 2)) | 1804 | #define AR5K_RATE2DB(_n) (AR5K_RATE2DB_BASE + ((_n) << 2)) |
1805 | 1805 | ||
1806 | /* | 1806 | /* |
1807 | * db -> Rate mapping table | 1807 | * db -> Rate mapping table |
1808 | * (8 entries, each one has 4 8bit fields) | 1808 | * (8 entries, each one has 4 8bit fields) |
1809 | */ | 1809 | */ |
1810 | #define AR5K_DB2RATE_BASE 0x87e0 | 1810 | #define AR5K_DB2RATE_BASE 0x87e0 |
1811 | #define AR5K_DB2RATE(_n) (AR5K_DB2RATE_BASE + ((_n) << 2)) | 1811 | #define AR5K_DB2RATE(_n) (AR5K_DB2RATE_BASE + ((_n) << 2)) |
1812 | 1812 | ||
1813 | /*===5212 end===*/ | 1813 | /*===5212 end===*/ |
1814 | 1814 | ||
1815 | /* | 1815 | /* |
1816 | * Key table (WEP) register | 1816 | * Key table (WEP) register |
1817 | */ | 1817 | */ |
1818 | #define AR5K_KEYTABLE_0_5210 0x9000 | 1818 | #define AR5K_KEYTABLE_0_5210 0x9000 |
1819 | #define AR5K_KEYTABLE_0_5211 0x8800 | 1819 | #define AR5K_KEYTABLE_0_5211 0x8800 |
1820 | #define AR5K_KEYTABLE_5210(_n) (AR5K_KEYTABLE_0_5210 + ((_n) << 5)) | 1820 | #define AR5K_KEYTABLE_5210(_n) (AR5K_KEYTABLE_0_5210 + ((_n) << 5)) |
1821 | #define AR5K_KEYTABLE_5211(_n) (AR5K_KEYTABLE_0_5211 + ((_n) << 5)) | 1821 | #define AR5K_KEYTABLE_5211(_n) (AR5K_KEYTABLE_0_5211 + ((_n) << 5)) |
1822 | #define AR5K_KEYTABLE(_n) (ah->ah_version == AR5K_AR5210 ? \ | 1822 | #define AR5K_KEYTABLE(_n) (ah->ah_version == AR5K_AR5210 ? \ |
1823 | AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n)) | 1823 | AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n)) |
1824 | #define AR5K_KEYTABLE_OFF(_n, x) (AR5K_KEYTABLE(_n) + (x << 2)) | 1824 | #define AR5K_KEYTABLE_OFF(_n, x) (AR5K_KEYTABLE(_n) + (x << 2)) |
1825 | #define AR5K_KEYTABLE_TYPE(_n) AR5K_KEYTABLE_OFF(_n, 5) | 1825 | #define AR5K_KEYTABLE_TYPE(_n) AR5K_KEYTABLE_OFF(_n, 5) |
1826 | #define AR5K_KEYTABLE_TYPE_40 0x00000000 | 1826 | #define AR5K_KEYTABLE_TYPE_40 0x00000000 |
1827 | #define AR5K_KEYTABLE_TYPE_104 0x00000001 | 1827 | #define AR5K_KEYTABLE_TYPE_104 0x00000001 |
1828 | #define AR5K_KEYTABLE_TYPE_128 0x00000003 | 1828 | #define AR5K_KEYTABLE_TYPE_128 0x00000003 |
1829 | #define AR5K_KEYTABLE_TYPE_TKIP 0x00000004 /* [5212+] */ | 1829 | #define AR5K_KEYTABLE_TYPE_TKIP 0x00000004 /* [5212+] */ |
1830 | #define AR5K_KEYTABLE_TYPE_AES 0x00000005 /* [5211+] */ | 1830 | #define AR5K_KEYTABLE_TYPE_AES 0x00000005 /* [5211+] */ |
1831 | #define AR5K_KEYTABLE_TYPE_CCM 0x00000006 /* [5212+] */ | 1831 | #define AR5K_KEYTABLE_TYPE_CCM 0x00000006 /* [5212+] */ |
1832 | #define AR5K_KEYTABLE_TYPE_NULL 0x00000007 /* [5211+] */ | 1832 | #define AR5K_KEYTABLE_TYPE_NULL 0x00000007 /* [5211+] */ |
1833 | #define AR5K_KEYTABLE_ANTENNA 0x00000008 /* [5212+] */ | 1833 | #define AR5K_KEYTABLE_ANTENNA 0x00000008 /* [5212+] */ |
1834 | #define AR5K_KEYTABLE_MAC0(_n) AR5K_KEYTABLE_OFF(_n, 6) | 1834 | #define AR5K_KEYTABLE_MAC0(_n) AR5K_KEYTABLE_OFF(_n, 6) |
1835 | #define AR5K_KEYTABLE_MAC1(_n) AR5K_KEYTABLE_OFF(_n, 7) | 1835 | #define AR5K_KEYTABLE_MAC1(_n) AR5K_KEYTABLE_OFF(_n, 7) |
1836 | #define AR5K_KEYTABLE_VALID 0x00008000 | 1836 | #define AR5K_KEYTABLE_VALID 0x00008000 |
1837 | 1837 | ||
1838 | /* If key type is TKIP and MIC is enabled | 1838 | /* If key type is TKIP and MIC is enabled |
1839 | * MIC key goes in offset entry + 64 */ | 1839 | * MIC key goes in offset entry + 64 */ |
1840 | #define AR5K_KEYTABLE_MIC_OFFSET 64 | 1840 | #define AR5K_KEYTABLE_MIC_OFFSET 64 |
1841 | 1841 | ||
1842 | /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit | 1842 | /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit |
1843 | * WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit | 1843 | * WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit |
1844 | * WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit | 1844 | * WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit |
1845 | * | 1845 | * |
1846 | * Some vendors have introduced bigger WEP keys to address | 1846 | * Some vendors have introduced bigger WEP keys to address |
1847 | * security vulnerabilities in WEP. This includes: | 1847 | * security vulnerabilities in WEP. This includes: |
1848 | * | 1848 | * |
1849 | * WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit | 1849 | * WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit |
1850 | * | 1850 | * |
1851 | * We can expand this if we find ar5k Atheros cards with a larger | 1851 | * We can expand this if we find ar5k Atheros cards with a larger |
1852 | * key table size. | 1852 | * key table size. |
1853 | */ | 1853 | */ |
1854 | #define AR5K_KEYTABLE_SIZE_5210 64 | 1854 | #define AR5K_KEYTABLE_SIZE_5210 64 |
1855 | #define AR5K_KEYTABLE_SIZE_5211 128 | 1855 | #define AR5K_KEYTABLE_SIZE_5211 128 |
1856 | #define AR5K_KEYTABLE_SIZE (ah->ah_version == AR5K_AR5210 ? \ | 1856 | #define AR5K_KEYTABLE_SIZE (ah->ah_version == AR5K_AR5210 ? \ |
1857 | AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211) | 1857 | AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211) |
1858 | 1858 | ||
1859 | 1859 | ||
1860 | /*===PHY REGISTERS===*/ | 1860 | /*===PHY REGISTERS===*/ |
1861 | 1861 | ||
1862 | /* | 1862 | /* |
1863 | * PHY registers start | 1863 | * PHY registers start |
1864 | */ | 1864 | */ |
1865 | #define AR5K_PHY_BASE 0x9800 | 1865 | #define AR5K_PHY_BASE 0x9800 |
1866 | #define AR5K_PHY(_n) (AR5K_PHY_BASE + ((_n) << 2)) | 1866 | #define AR5K_PHY(_n) (AR5K_PHY_BASE + ((_n) << 2)) |
1867 | 1867 | ||
1868 | /* | 1868 | /* |
1869 | * TST_2 (Misc config parameters) | 1869 | * TST_2 (Misc config parameters) |
1870 | */ | 1870 | */ |
1871 | #define AR5K_PHY_TST2 0x9800 /* Register Address */ | 1871 | #define AR5K_PHY_TST2 0x9800 /* Register Address */ |
1872 | #define AR5K_PHY_TST2_TRIG_SEL 0x00000007 /* Trigger select (?)*/ | 1872 | #define AR5K_PHY_TST2_TRIG_SEL 0x00000007 /* Trigger select (?)*/ |
1873 | #define AR5K_PHY_TST2_TRIG 0x00000010 /* Trigger (?) */ | 1873 | #define AR5K_PHY_TST2_TRIG 0x00000010 /* Trigger (?) */ |
1874 | #define AR5K_PHY_TST2_CBUS_MODE 0x00000060 /* Cardbus mode (?) */ | 1874 | #define AR5K_PHY_TST2_CBUS_MODE 0x00000060 /* Cardbus mode (?) */ |
1875 | #define AR5K_PHY_TST2_CLK32 0x00000400 /* CLK_OUT is CLK32 (32Khz external) */ | 1875 | #define AR5K_PHY_TST2_CLK32 0x00000400 /* CLK_OUT is CLK32 (32Khz external) */ |
1876 | #define AR5K_PHY_TST2_CHANCOR_DUMP_EN 0x00000800 /* Enable Chancor dump (?) */ | 1876 | #define AR5K_PHY_TST2_CHANCOR_DUMP_EN 0x00000800 /* Enable Chancor dump (?) */ |
1877 | #define AR5K_PHY_TST2_EVEN_CHANCOR_DUMP 0x00001000 /* Even Chancor dump (?) */ | 1877 | #define AR5K_PHY_TST2_EVEN_CHANCOR_DUMP 0x00001000 /* Even Chancor dump (?) */ |
1878 | #define AR5K_PHY_TST2_RFSILENT_EN 0x00002000 /* Enable RFSILENT */ | 1878 | #define AR5K_PHY_TST2_RFSILENT_EN 0x00002000 /* Enable RFSILENT */ |
1879 | #define AR5K_PHY_TST2_ALT_RFDATA 0x00004000 /* Alternate RFDATA (5-2GHz switch ?) */ | 1879 | #define AR5K_PHY_TST2_ALT_RFDATA 0x00004000 /* Alternate RFDATA (5-2GHz switch ?) */ |
1880 | #define AR5K_PHY_TST2_MINI_OBS_EN 0x00008000 /* Enable mini OBS (?) */ | 1880 | #define AR5K_PHY_TST2_MINI_OBS_EN 0x00008000 /* Enable mini OBS (?) */ |
1881 | #define AR5K_PHY_TST2_RX2_IS_RX5_INV 0x00010000 /* 2GHz rx path is the 5GHz path inverted (?) */ | 1881 | #define AR5K_PHY_TST2_RX2_IS_RX5_INV 0x00010000 /* 2GHz rx path is the 5GHz path inverted (?) */ |
1882 | #define AR5K_PHY_TST2_SLOW_CLK160 0x00020000 /* Slow CLK160 (?) */ | 1882 | #define AR5K_PHY_TST2_SLOW_CLK160 0x00020000 /* Slow CLK160 (?) */ |
1883 | #define AR5K_PHY_TST2_AGC_OBS_SEL_3 0x00040000 /* AGC OBS Select 3 (?) */ | 1883 | #define AR5K_PHY_TST2_AGC_OBS_SEL_3 0x00040000 /* AGC OBS Select 3 (?) */ |
1884 | #define AR5K_PHY_TST2_BBB_OBS_SEL 0x00080000 /* BB OBS Select (field ?) */ | 1884 | #define AR5K_PHY_TST2_BBB_OBS_SEL 0x00080000 /* BB OBS Select (field ?) */ |
1885 | #define AR5K_PHY_TST2_ADC_OBS_SEL 0x00800000 /* ADC OBS Select (field ?) */ | 1885 | #define AR5K_PHY_TST2_ADC_OBS_SEL 0x00800000 /* ADC OBS Select (field ?) */ |
1886 | #define AR5K_PHY_TST2_RX_CLR_SEL 0x08000000 /* RX Clear Select (?) */ | 1886 | #define AR5K_PHY_TST2_RX_CLR_SEL 0x08000000 /* RX Clear Select (?) */ |
1887 | #define AR5K_PHY_TST2_FORCE_AGC_CLR 0x10000000 /* Force AGC clear (?) */ | 1887 | #define AR5K_PHY_TST2_FORCE_AGC_CLR 0x10000000 /* Force AGC clear (?) */ |
1888 | #define AR5K_PHY_SHIFT_2GHZ 0x00004007 /* Used to access 2GHz radios */ | 1888 | #define AR5K_PHY_SHIFT_2GHZ 0x00004007 /* Used to access 2GHz radios */ |
1889 | #define AR5K_PHY_SHIFT_5GHZ 0x00000007 /* Used to access 5GHz radios (default) */ | 1889 | #define AR5K_PHY_SHIFT_5GHZ 0x00000007 /* Used to access 5GHz radios (default) */ |
1890 | 1890 | ||
1891 | /* | 1891 | /* |
1892 | * PHY frame control register [5110] /turbo mode register [5111+] | 1892 | * PHY frame control register [5110] /turbo mode register [5111+] |
1893 | * | 1893 | * |
1894 | * There is another frame control register for [5111+] | 1894 | * There is another frame control register for [5111+] |
1895 | * at address 0x9944 (see below) but the 2 first flags | 1895 | * at address 0x9944 (see below) but the 2 first flags |
1896 | * are common here between 5110 frame control register | 1896 | * are common here between 5110 frame control register |
1897 | * and [5111+] turbo mode register, so this also works as | 1897 | * and [5111+] turbo mode register, so this also works as |
1898 | * a "turbo mode register" for 5110. We treat this one as | 1898 | * a "turbo mode register" for 5110. We treat this one as |
1899 | * a frame control register for 5110 below. | 1899 | * a frame control register for 5110 below. |
1900 | */ | 1900 | */ |
1901 | #define AR5K_PHY_TURBO 0x9804 /* Register Address */ | 1901 | #define AR5K_PHY_TURBO 0x9804 /* Register Address */ |
1902 | #define AR5K_PHY_TURBO_MODE 0x00000001 /* Enable turbo mode */ | 1902 | #define AR5K_PHY_TURBO_MODE 0x00000001 /* Enable turbo mode */ |
1903 | #define AR5K_PHY_TURBO_SHORT 0x00000002 /* Set short symbols to turbo mode */ | 1903 | #define AR5K_PHY_TURBO_SHORT 0x00000002 /* Set short symbols to turbo mode */ |
1904 | #define AR5K_PHY_TURBO_MIMO 0x00000004 /* Set turbo for mimo mimo */ | 1904 | #define AR5K_PHY_TURBO_MIMO 0x00000004 /* Set turbo for mimo mimo */ |
1905 | 1905 | ||
1906 | /* | 1906 | /* |
1907 | * PHY agility command register | 1907 | * PHY agility command register |
1908 | * (aka TST_1) | 1908 | * (aka TST_1) |
1909 | */ | 1909 | */ |
1910 | #define AR5K_PHY_AGC 0x9808 /* Register Address */ | 1910 | #define AR5K_PHY_AGC 0x9808 /* Register Address */ |
1911 | #define AR5K_PHY_TST1 0x9808 | 1911 | #define AR5K_PHY_TST1 0x9808 |
1912 | #define AR5K_PHY_AGC_DISABLE 0x08000000 /* Disable AGC to A2 (?)*/ | 1912 | #define AR5K_PHY_AGC_DISABLE 0x08000000 /* Disable AGC to A2 (?)*/ |
1913 | #define AR5K_PHY_TST1_TXHOLD 0x00003800 /* Set tx hold (?) */ | 1913 | #define AR5K_PHY_TST1_TXHOLD 0x00003800 /* Set tx hold (?) */ |
1914 | #define AR5K_PHY_TST1_TXSRC_SRC 0x00000002 /* Used with bit 7 (?) */ | 1914 | #define AR5K_PHY_TST1_TXSRC_SRC 0x00000002 /* Used with bit 7 (?) */ |
1915 | #define AR5K_PHY_TST1_TXSRC_SRC_S 1 | 1915 | #define AR5K_PHY_TST1_TXSRC_SRC_S 1 |
1916 | #define AR5K_PHY_TST1_TXSRC_ALT 0x00000080 /* Set input to tsdac (?) */ | 1916 | #define AR5K_PHY_TST1_TXSRC_ALT 0x00000080 /* Set input to tsdac (?) */ |
1917 | #define AR5K_PHY_TST1_TXSRC_ALT_S 7 | 1917 | #define AR5K_PHY_TST1_TXSRC_ALT_S 7 |
1918 | 1918 | ||
1919 | 1919 | ||
1920 | /* | 1920 | /* |
1921 | * PHY timing register 3 [5112+] | 1921 | * PHY timing register 3 [5112+] |
1922 | */ | 1922 | */ |
1923 | #define AR5K_PHY_TIMING_3 0x9814 | 1923 | #define AR5K_PHY_TIMING_3 0x9814 |
1924 | #define AR5K_PHY_TIMING_3_DSC_MAN 0xfffe0000 | 1924 | #define AR5K_PHY_TIMING_3_DSC_MAN 0xfffe0000 |
1925 | #define AR5K_PHY_TIMING_3_DSC_MAN_S 17 | 1925 | #define AR5K_PHY_TIMING_3_DSC_MAN_S 17 |
1926 | #define AR5K_PHY_TIMING_3_DSC_EXP 0x0001e000 | 1926 | #define AR5K_PHY_TIMING_3_DSC_EXP 0x0001e000 |
1927 | #define AR5K_PHY_TIMING_3_DSC_EXP_S 13 | 1927 | #define AR5K_PHY_TIMING_3_DSC_EXP_S 13 |
1928 | 1928 | ||
1929 | /* | 1929 | /* |
1930 | * PHY chip revision register | 1930 | * PHY chip revision register |
1931 | */ | 1931 | */ |
1932 | #define AR5K_PHY_CHIP_ID 0x9818 | 1932 | #define AR5K_PHY_CHIP_ID 0x9818 |
1933 | 1933 | ||
1934 | /* | 1934 | /* |
1935 | * PHY activation register | 1935 | * PHY activation register |
1936 | */ | 1936 | */ |
1937 | #define AR5K_PHY_ACT 0x981c /* Register Address */ | 1937 | #define AR5K_PHY_ACT 0x981c /* Register Address */ |
1938 | #define AR5K_PHY_ACT_ENABLE 0x00000001 /* Activate PHY */ | 1938 | #define AR5K_PHY_ACT_ENABLE 0x00000001 /* Activate PHY */ |
1939 | #define AR5K_PHY_ACT_DISABLE 0x00000002 /* Deactivate PHY */ | 1939 | #define AR5K_PHY_ACT_DISABLE 0x00000002 /* Deactivate PHY */ |
1940 | 1940 | ||
1941 | /* | 1941 | /* |
1942 | * PHY RF control registers | 1942 | * PHY RF control registers |
1943 | */ | 1943 | */ |
1944 | #define AR5K_PHY_RF_CTL2 0x9824 /* Register Address */ | 1944 | #define AR5K_PHY_RF_CTL2 0x9824 /* Register Address */ |
1945 | #define AR5K_PHY_RF_CTL2_TXF2TXD_START 0x0000000f /* TX frame to TX data start */ | 1945 | #define AR5K_PHY_RF_CTL2_TXF2TXD_START 0x0000000f /* TX frame to TX data start */ |
1946 | #define AR5K_PHY_RF_CTL2_TXF2TXD_START_S 0 | 1946 | #define AR5K_PHY_RF_CTL2_TXF2TXD_START_S 0 |
1947 | 1947 | ||
1948 | #define AR5K_PHY_RF_CTL3 0x9828 /* Register Address */ | 1948 | #define AR5K_PHY_RF_CTL3 0x9828 /* Register Address */ |
1949 | #define AR5K_PHY_RF_CTL3_TXE2XLNA_ON 0x0000ff00 /* TX end to XLNA on */ | 1949 | #define AR5K_PHY_RF_CTL3_TXE2XLNA_ON 0x0000ff00 /* TX end to XLNA on */ |
1950 | #define AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S 8 | 1950 | #define AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S 8 |
1951 | 1951 | ||
1952 | #define AR5K_PHY_ADC_CTL 0x982c | 1952 | #define AR5K_PHY_ADC_CTL 0x982c |
1953 | #define AR5K_PHY_ADC_CTL_INBUFGAIN_OFF 0x00000003 | 1953 | #define AR5K_PHY_ADC_CTL_INBUFGAIN_OFF 0x00000003 |
1954 | #define AR5K_PHY_ADC_CTL_INBUFGAIN_OFF_S 0 | 1954 | #define AR5K_PHY_ADC_CTL_INBUFGAIN_OFF_S 0 |
1955 | #define AR5K_PHY_ADC_CTL_PWD_DAC_OFF 0x00002000 | 1955 | #define AR5K_PHY_ADC_CTL_PWD_DAC_OFF 0x00002000 |
1956 | #define AR5K_PHY_ADC_CTL_PWD_BAND_GAP_OFF 0x00004000 | 1956 | #define AR5K_PHY_ADC_CTL_PWD_BAND_GAP_OFF 0x00004000 |
1957 | #define AR5K_PHY_ADC_CTL_PWD_ADC_OFF 0x00008000 | 1957 | #define AR5K_PHY_ADC_CTL_PWD_ADC_OFF 0x00008000 |
1958 | #define AR5K_PHY_ADC_CTL_INBUFGAIN_ON 0x00030000 | 1958 | #define AR5K_PHY_ADC_CTL_INBUFGAIN_ON 0x00030000 |
1959 | #define AR5K_PHY_ADC_CTL_INBUFGAIN_ON_S 16 | 1959 | #define AR5K_PHY_ADC_CTL_INBUFGAIN_ON_S 16 |
1960 | 1960 | ||
1961 | #define AR5K_PHY_RF_CTL4 0x9834 /* Register Address */ | 1961 | #define AR5K_PHY_RF_CTL4 0x9834 /* Register Address */ |
1962 | #define AR5K_PHY_RF_CTL4_TXF2XPA_A_ON 0x00000001 /* TX frame to XPA A on (field) */ | 1962 | #define AR5K_PHY_RF_CTL4_TXF2XPA_A_ON 0x00000001 /* TX frame to XPA A on (field) */ |
1963 | #define AR5K_PHY_RF_CTL4_TXF2XPA_B_ON 0x00000100 /* TX frame to XPA B on (field) */ | 1963 | #define AR5K_PHY_RF_CTL4_TXF2XPA_B_ON 0x00000100 /* TX frame to XPA B on (field) */ |
1964 | #define AR5K_PHY_RF_CTL4_TXE2XPA_A_OFF 0x00010000 /* TX end to XPA A off (field) */ | 1964 | #define AR5K_PHY_RF_CTL4_TXE2XPA_A_OFF 0x00010000 /* TX end to XPA A off (field) */ |
1965 | #define AR5K_PHY_RF_CTL4_TXE2XPA_B_OFF 0x01000000 /* TX end to XPA B off (field) */ | 1965 | #define AR5K_PHY_RF_CTL4_TXE2XPA_B_OFF 0x01000000 /* TX end to XPA B off (field) */ |
1966 | 1966 | ||
1967 | /* | 1967 | /* |
1968 | * Pre-Amplifier control register | 1968 | * Pre-Amplifier control register |
1969 | * (XPA -> external pre-amplifier) | 1969 | * (XPA -> external pre-amplifier) |
1970 | */ | 1970 | */ |
1971 | #define AR5K_PHY_PA_CTL 0x9838 /* Register Address */ | 1971 | #define AR5K_PHY_PA_CTL 0x9838 /* Register Address */ |
1972 | #define AR5K_PHY_PA_CTL_XPA_A_HI 0x00000001 /* XPA A high (?) */ | 1972 | #define AR5K_PHY_PA_CTL_XPA_A_HI 0x00000001 /* XPA A high (?) */ |
1973 | #define AR5K_PHY_PA_CTL_XPA_B_HI 0x00000002 /* XPA B high (?) */ | 1973 | #define AR5K_PHY_PA_CTL_XPA_B_HI 0x00000002 /* XPA B high (?) */ |
1974 | #define AR5K_PHY_PA_CTL_XPA_A_EN 0x00000004 /* Enable XPA A */ | 1974 | #define AR5K_PHY_PA_CTL_XPA_A_EN 0x00000004 /* Enable XPA A */ |
1975 | #define AR5K_PHY_PA_CTL_XPA_B_EN 0x00000008 /* Enable XPA B */ | 1975 | #define AR5K_PHY_PA_CTL_XPA_B_EN 0x00000008 /* Enable XPA B */ |
1976 | 1976 | ||
1977 | /* | 1977 | /* |
1978 | * PHY settling register | 1978 | * PHY settling register |
1979 | */ | 1979 | */ |
1980 | #define AR5K_PHY_SETTLING 0x9844 /* Register Address */ | 1980 | #define AR5K_PHY_SETTLING 0x9844 /* Register Address */ |
1981 | #define AR5K_PHY_SETTLING_AGC 0x0000007f /* AGC settling time */ | 1981 | #define AR5K_PHY_SETTLING_AGC 0x0000007f /* AGC settling time */ |
1982 | #define AR5K_PHY_SETTLING_AGC_S 0 | 1982 | #define AR5K_PHY_SETTLING_AGC_S 0 |
1983 | #define AR5K_PHY_SETTLING_SWITCH 0x00003f80 /* Switch settlig time */ | 1983 | #define AR5K_PHY_SETTLING_SWITCH 0x00003f80 /* Switch settlig time */ |
1984 | #define AR5K_PHY_SETTLING_SWITCH_S 7 | 1984 | #define AR5K_PHY_SETTLING_SWITCH_S 7 |
1985 | 1985 | ||
1986 | /* | 1986 | /* |
1987 | * PHY Gain registers | 1987 | * PHY Gain registers |
1988 | */ | 1988 | */ |
1989 | #define AR5K_PHY_GAIN 0x9848 /* Register Address */ | 1989 | #define AR5K_PHY_GAIN 0x9848 /* Register Address */ |
1990 | #define AR5K_PHY_GAIN_TXRX_ATTEN 0x0003f000 /* TX-RX Attenuation */ | 1990 | #define AR5K_PHY_GAIN_TXRX_ATTEN 0x0003f000 /* TX-RX Attenuation */ |
1991 | #define AR5K_PHY_GAIN_TXRX_ATTEN_S 12 | 1991 | #define AR5K_PHY_GAIN_TXRX_ATTEN_S 12 |
1992 | #define AR5K_PHY_GAIN_TXRX_RF_MAX 0x007c0000 | 1992 | #define AR5K_PHY_GAIN_TXRX_RF_MAX 0x007c0000 |
1993 | #define AR5K_PHY_GAIN_TXRX_RF_MAX_S 18 | 1993 | #define AR5K_PHY_GAIN_TXRX_RF_MAX_S 18 |
1994 | 1994 | ||
1995 | #define AR5K_PHY_GAIN_OFFSET 0x984c /* Register Address */ | 1995 | #define AR5K_PHY_GAIN_OFFSET 0x984c /* Register Address */ |
1996 | #define AR5K_PHY_GAIN_OFFSET_RXTX_FLAG 0x00020000 /* RX-TX flag (?) */ | 1996 | #define AR5K_PHY_GAIN_OFFSET_RXTX_FLAG 0x00020000 /* RX-TX flag (?) */ |
1997 | 1997 | ||
1998 | /* | 1998 | /* |
1999 | * Desired ADC/PGA size register | 1999 | * Desired ADC/PGA size register |
2000 | * (for more infos read ANI patent) | 2000 | * (for more infos read ANI patent) |
2001 | */ | 2001 | */ |
2002 | #define AR5K_PHY_DESIRED_SIZE 0x9850 /* Register Address */ | 2002 | #define AR5K_PHY_DESIRED_SIZE 0x9850 /* Register Address */ |
2003 | #define AR5K_PHY_DESIRED_SIZE_ADC 0x000000ff /* ADC desired size */ | 2003 | #define AR5K_PHY_DESIRED_SIZE_ADC 0x000000ff /* ADC desired size */ |
2004 | #define AR5K_PHY_DESIRED_SIZE_ADC_S 0 | 2004 | #define AR5K_PHY_DESIRED_SIZE_ADC_S 0 |
2005 | #define AR5K_PHY_DESIRED_SIZE_PGA 0x0000ff00 /* PGA desired size */ | 2005 | #define AR5K_PHY_DESIRED_SIZE_PGA 0x0000ff00 /* PGA desired size */ |
2006 | #define AR5K_PHY_DESIRED_SIZE_PGA_S 8 | 2006 | #define AR5K_PHY_DESIRED_SIZE_PGA_S 8 |
2007 | #define AR5K_PHY_DESIRED_SIZE_TOT 0x0ff00000 /* Total desired size */ | 2007 | #define AR5K_PHY_DESIRED_SIZE_TOT 0x0ff00000 /* Total desired size */ |
2008 | #define AR5K_PHY_DESIRED_SIZE_TOT_S 20 | 2008 | #define AR5K_PHY_DESIRED_SIZE_TOT_S 20 |
2009 | 2009 | ||
2010 | /* | 2010 | /* |
2011 | * PHY signal register | 2011 | * PHY signal register |
2012 | * (for more infos read ANI patent) | 2012 | * (for more infos read ANI patent) |
2013 | */ | 2013 | */ |
2014 | #define AR5K_PHY_SIG 0x9858 /* Register Address */ | 2014 | #define AR5K_PHY_SIG 0x9858 /* Register Address */ |
2015 | #define AR5K_PHY_SIG_FIRSTEP 0x0003f000 /* FIRSTEP */ | 2015 | #define AR5K_PHY_SIG_FIRSTEP 0x0003f000 /* FIRSTEP */ |
2016 | #define AR5K_PHY_SIG_FIRSTEP_S 12 | 2016 | #define AR5K_PHY_SIG_FIRSTEP_S 12 |
2017 | #define AR5K_PHY_SIG_FIRPWR 0x03fc0000 /* FIPWR */ | 2017 | #define AR5K_PHY_SIG_FIRPWR 0x03fc0000 /* FIPWR */ |
2018 | #define AR5K_PHY_SIG_FIRPWR_S 18 | 2018 | #define AR5K_PHY_SIG_FIRPWR_S 18 |
2019 | 2019 | ||
2020 | /* | 2020 | /* |
2021 | * PHY coarse agility control register | 2021 | * PHY coarse agility control register |
2022 | * (for more infos read ANI patent) | 2022 | * (for more infos read ANI patent) |
2023 | */ | 2023 | */ |
2024 | #define AR5K_PHY_AGCCOARSE 0x985c /* Register Address */ | 2024 | #define AR5K_PHY_AGCCOARSE 0x985c /* Register Address */ |
2025 | #define AR5K_PHY_AGCCOARSE_LO 0x00007f80 /* AGC Coarse low */ | 2025 | #define AR5K_PHY_AGCCOARSE_LO 0x00007f80 /* AGC Coarse low */ |
2026 | #define AR5K_PHY_AGCCOARSE_LO_S 7 | 2026 | #define AR5K_PHY_AGCCOARSE_LO_S 7 |
2027 | #define AR5K_PHY_AGCCOARSE_HI 0x003f8000 /* AGC Coarse high */ | 2027 | #define AR5K_PHY_AGCCOARSE_HI 0x003f8000 /* AGC Coarse high */ |
2028 | #define AR5K_PHY_AGCCOARSE_HI_S 15 | 2028 | #define AR5K_PHY_AGCCOARSE_HI_S 15 |
2029 | 2029 | ||
2030 | /* | 2030 | /* |
2031 | * PHY agility control register | 2031 | * PHY agility control register |
2032 | */ | 2032 | */ |
2033 | #define AR5K_PHY_AGCCTL 0x9860 /* Register address */ | 2033 | #define AR5K_PHY_AGCCTL 0x9860 /* Register address */ |
2034 | #define AR5K_PHY_AGCCTL_CAL 0x00000001 /* Enable PHY calibration */ | 2034 | #define AR5K_PHY_AGCCTL_CAL 0x00000001 /* Enable PHY calibration */ |
2035 | #define AR5K_PHY_AGCCTL_NF 0x00000002 /* Enable Noise Floor calibration */ | 2035 | #define AR5K_PHY_AGCCTL_NF 0x00000002 /* Enable Noise Floor calibration */ |
2036 | #define AR5K_PHY_AGCCTL_OFDM_DIV_DIS 0x00000008 /* Disable antenna diversity on OFDM modes */ | 2036 | #define AR5K_PHY_AGCCTL_OFDM_DIV_DIS 0x00000008 /* Disable antenna diversity on OFDM modes */ |
2037 | #define AR5K_PHY_AGCCTL_NF_EN 0x00008000 /* Enable nf calibration to happen (?) */ | 2037 | #define AR5K_PHY_AGCCTL_NF_EN 0x00008000 /* Enable nf calibration to happen (?) */ |
2038 | #define AR5K_PHY_AGCTL_FLTR_CAL 0x00010000 /* Allow filter calibration (?) */ | 2038 | #define AR5K_PHY_AGCTL_FLTR_CAL 0x00010000 /* Allow filter calibration (?) */ |
2039 | #define AR5K_PHY_AGCCTL_NF_NOUPDATE 0x00020000 /* Don't update nf automaticaly */ | 2039 | #define AR5K_PHY_AGCCTL_NF_NOUPDATE 0x00020000 /* Don't update nf automaticaly */ |
2040 | 2040 | ||
2041 | /* | 2041 | /* |
2042 | * PHY noise floor status register | 2042 | * PHY noise floor status register |
2043 | */ | 2043 | */ |
2044 | #define AR5K_PHY_NF 0x9864 /* Register address */ | 2044 | #define AR5K_PHY_NF 0x9864 /* Register address */ |
2045 | #define AR5K_PHY_NF_M 0x000001ff /* Noise floor mask */ | 2045 | #define AR5K_PHY_NF_M 0x000001ff /* Noise floor mask */ |
2046 | #define AR5K_PHY_NF_ACTIVE 0x00000100 /* Noise floor calibration still active */ | 2046 | #define AR5K_PHY_NF_ACTIVE 0x00000100 /* Noise floor calibration still active */ |
2047 | #define AR5K_PHY_NF_RVAL(_n) (((_n) >> 19) & AR5K_PHY_NF_M) | 2047 | #define AR5K_PHY_NF_RVAL(_n) (((_n) >> 19) & AR5K_PHY_NF_M) |
2048 | #define AR5K_PHY_NF_AVAL(_n) (-((_n) ^ AR5K_PHY_NF_M) + 1) | 2048 | #define AR5K_PHY_NF_AVAL(_n) (-((_n) ^ AR5K_PHY_NF_M) + 1) |
2049 | #define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9)) | 2049 | #define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9)) |
2050 | #define AR5K_PHY_NF_THRESH62 0x0007f000 /* Thresh62 -check ANI patent- (field) */ | 2050 | #define AR5K_PHY_NF_THRESH62 0x0007f000 /* Thresh62 -check ANI patent- (field) */ |
2051 | #define AR5K_PHY_NF_THRESH62_S 12 | 2051 | #define AR5K_PHY_NF_THRESH62_S 12 |
2052 | #define AR5K_PHY_NF_MINCCA_PWR 0x0ff80000 /* ??? */ | 2052 | #define AR5K_PHY_NF_MINCCA_PWR 0x0ff80000 /* ??? */ |
2053 | #define AR5K_PHY_NF_MINCCA_PWR_S 19 | 2053 | #define AR5K_PHY_NF_MINCCA_PWR_S 19 |
2054 | 2054 | ||
2055 | /* | 2055 | /* |
2056 | * PHY ADC saturation register [5110] | 2056 | * PHY ADC saturation register [5110] |
2057 | */ | 2057 | */ |
2058 | #define AR5K_PHY_ADCSAT 0x9868 | 2058 | #define AR5K_PHY_ADCSAT 0x9868 |
2059 | #define AR5K_PHY_ADCSAT_ICNT 0x0001f800 | 2059 | #define AR5K_PHY_ADCSAT_ICNT 0x0001f800 |
2060 | #define AR5K_PHY_ADCSAT_ICNT_S 11 | 2060 | #define AR5K_PHY_ADCSAT_ICNT_S 11 |
2061 | #define AR5K_PHY_ADCSAT_THR 0x000007e0 | 2061 | #define AR5K_PHY_ADCSAT_THR 0x000007e0 |
2062 | #define AR5K_PHY_ADCSAT_THR_S 5 | 2062 | #define AR5K_PHY_ADCSAT_THR_S 5 |
2063 | 2063 | ||
2064 | /* | 2064 | /* |
2065 | * PHY Weak ofdm signal detection threshold registers (ANI) [5212+] | 2065 | * PHY Weak ofdm signal detection threshold registers (ANI) [5212+] |
2066 | */ | 2066 | */ |
2067 | 2067 | ||
2068 | /* High thresholds */ | 2068 | /* High thresholds */ |
2069 | #define AR5K_PHY_WEAK_OFDM_HIGH_THR 0x9868 | 2069 | #define AR5K_PHY_WEAK_OFDM_HIGH_THR 0x9868 |
2070 | #define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT 0x0000001f | 2070 | #define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT 0x0000001f |
2071 | #define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT_S 0 | 2071 | #define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT_S 0 |
2072 | #define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1 0x00fe0000 | 2072 | #define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1 0x00fe0000 |
2073 | #define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1_S 17 | 2073 | #define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1_S 17 |
2074 | #define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2 0x7f000000 | 2074 | #define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2 0x7f000000 |
2075 | #define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_S 24 | 2075 | #define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_S 24 |
2076 | 2076 | ||
2077 | /* Low thresholds */ | 2077 | /* Low thresholds */ |
2078 | #define AR5K_PHY_WEAK_OFDM_LOW_THR 0x986c | 2078 | #define AR5K_PHY_WEAK_OFDM_LOW_THR 0x986c |
2079 | #define AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN 0x00000001 | 2079 | #define AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN 0x00000001 |
2080 | #define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT 0x00003f00 | 2080 | #define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT 0x00003f00 |
2081 | #define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT_S 8 | 2081 | #define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT_S 8 |
2082 | #define AR5K_PHY_WEAK_OFDM_LOW_THR_M1 0x001fc000 | 2082 | #define AR5K_PHY_WEAK_OFDM_LOW_THR_M1 0x001fc000 |
2083 | #define AR5K_PHY_WEAK_OFDM_LOW_THR_M1_S 14 | 2083 | #define AR5K_PHY_WEAK_OFDM_LOW_THR_M1_S 14 |
2084 | #define AR5K_PHY_WEAK_OFDM_LOW_THR_M2 0x0fe00000 | 2084 | #define AR5K_PHY_WEAK_OFDM_LOW_THR_M2 0x0fe00000 |
2085 | #define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_S 21 | 2085 | #define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_S 21 |
2086 | 2086 | ||
2087 | 2087 | ||
2088 | /* | 2088 | /* |
2089 | * PHY sleep registers [5112+] | 2089 | * PHY sleep registers [5112+] |
2090 | */ | 2090 | */ |
2091 | #define AR5K_PHY_SCR 0x9870 | 2091 | #define AR5K_PHY_SCR 0x9870 |
2092 | 2092 | ||
2093 | #define AR5K_PHY_SLMT 0x9874 | 2093 | #define AR5K_PHY_SLMT 0x9874 |
2094 | #define AR5K_PHY_SLMT_32MHZ 0x0000007f | 2094 | #define AR5K_PHY_SLMT_32MHZ 0x0000007f |
2095 | 2095 | ||
2096 | #define AR5K_PHY_SCAL 0x9878 | 2096 | #define AR5K_PHY_SCAL 0x9878 |
2097 | #define AR5K_PHY_SCAL_32MHZ 0x0000000e | 2097 | #define AR5K_PHY_SCAL_32MHZ 0x0000000e |
2098 | #define AR5K_PHY_SCAL_32MHZ_2417 0x0000000a | 2098 | #define AR5K_PHY_SCAL_32MHZ_2417 0x0000000a |
2099 | #define AR5K_PHY_SCAL_32MHZ_HB63 0x00000032 | 2099 | #define AR5K_PHY_SCAL_32MHZ_HB63 0x00000032 |
2100 | 2100 | ||
2101 | /* | 2101 | /* |
2102 | * PHY PLL (Phase Locked Loop) control register | 2102 | * PHY PLL (Phase Locked Loop) control register |
2103 | */ | 2103 | */ |
2104 | #define AR5K_PHY_PLL 0x987c | 2104 | #define AR5K_PHY_PLL 0x987c |
2105 | #define AR5K_PHY_PLL_20MHZ 0x00000013 /* For half rate (?) */ | 2105 | #define AR5K_PHY_PLL_20MHZ 0x00000013 /* For half rate (?) */ |
2106 | /* 40MHz -> 5GHz band */ | 2106 | /* 40MHz -> 5GHz band */ |
2107 | #define AR5K_PHY_PLL_40MHZ_5211 0x00000018 | 2107 | #define AR5K_PHY_PLL_40MHZ_5211 0x00000018 |
2108 | #define AR5K_PHY_PLL_40MHZ_5212 0x000000aa | 2108 | #define AR5K_PHY_PLL_40MHZ_5212 0x000000aa |
2109 | #define AR5K_PHY_PLL_40MHZ_5413 0x00000004 | 2109 | #define AR5K_PHY_PLL_40MHZ_5413 0x00000004 |
2110 | #define AR5K_PHY_PLL_40MHZ (ah->ah_version == AR5K_AR5211 ? \ | 2110 | #define AR5K_PHY_PLL_40MHZ (ah->ah_version == AR5K_AR5211 ? \ |
2111 | AR5K_PHY_PLL_40MHZ_5211 : AR5K_PHY_PLL_40MHZ_5212) | 2111 | AR5K_PHY_PLL_40MHZ_5211 : AR5K_PHY_PLL_40MHZ_5212) |
2112 | /* 44MHz -> 2.4GHz band */ | 2112 | /* 44MHz -> 2.4GHz band */ |
2113 | #define AR5K_PHY_PLL_44MHZ_5211 0x00000019 | 2113 | #define AR5K_PHY_PLL_44MHZ_5211 0x00000019 |
2114 | #define AR5K_PHY_PLL_44MHZ_5212 0x000000ab | 2114 | #define AR5K_PHY_PLL_44MHZ_5212 0x000000ab |
2115 | #define AR5K_PHY_PLL_44MHZ (ah->ah_version == AR5K_AR5211 ? \ | 2115 | #define AR5K_PHY_PLL_44MHZ (ah->ah_version == AR5K_AR5211 ? \ |
2116 | AR5K_PHY_PLL_44MHZ_5211 : AR5K_PHY_PLL_44MHZ_5212) | 2116 | AR5K_PHY_PLL_44MHZ_5211 : AR5K_PHY_PLL_44MHZ_5212) |
2117 | 2117 | ||
2118 | #define AR5K_PHY_PLL_RF5111 0x00000000 | 2118 | #define AR5K_PHY_PLL_RF5111 0x00000000 |
2119 | #define AR5K_PHY_PLL_RF5112 0x00000040 | 2119 | #define AR5K_PHY_PLL_RF5112 0x00000040 |
2120 | #define AR5K_PHY_PLL_HALF_RATE 0x00000100 | 2120 | #define AR5K_PHY_PLL_HALF_RATE 0x00000100 |
2121 | #define AR5K_PHY_PLL_QUARTER_RATE 0x00000200 | 2121 | #define AR5K_PHY_PLL_QUARTER_RATE 0x00000200 |
2122 | 2122 | ||
2123 | /* | 2123 | /* |
2124 | * RF Buffer register | 2124 | * RF Buffer register |
2125 | * | 2125 | * |
2126 | * It's obvious from the code that 0x989c is the buffer register but | 2126 | * It's obvious from the code that 0x989c is the buffer register but |
2127 | * for the other special registers that we write to after sending each | 2127 | * for the other special registers that we write to after sending each |
2128 | * packet, i have no idea. So i'll name them BUFFER_CONTROL_X registers | 2128 | * packet, i have no idea. So i'll name them BUFFER_CONTROL_X registers |
2129 | * for now. It's interesting that they are also used for some other operations. | 2129 | * for now. It's interesting that they are also used for some other operations. |
2130 | */ | 2130 | */ |
2131 | 2131 | ||
2132 | #define AR5K_RF_BUFFER 0x989c | 2132 | #define AR5K_RF_BUFFER 0x989c |
2133 | #define AR5K_RF_BUFFER_CONTROL_0 0x98c0 /* Channel on 5110 */ | 2133 | #define AR5K_RF_BUFFER_CONTROL_0 0x98c0 /* Channel on 5110 */ |
2134 | #define AR5K_RF_BUFFER_CONTROL_1 0x98c4 /* Bank 7 on 5112 */ | 2134 | #define AR5K_RF_BUFFER_CONTROL_1 0x98c4 /* Bank 7 on 5112 */ |
2135 | #define AR5K_RF_BUFFER_CONTROL_2 0x98cc /* Bank 7 on 5111 */ | 2135 | #define AR5K_RF_BUFFER_CONTROL_2 0x98cc /* Bank 7 on 5111 */ |
2136 | 2136 | ||
2137 | #define AR5K_RF_BUFFER_CONTROL_3 0x98d0 /* Bank 2 on 5112 */ | 2137 | #define AR5K_RF_BUFFER_CONTROL_3 0x98d0 /* Bank 2 on 5112 */ |
2138 | /* Channel set on 5111 */ | 2138 | /* Channel set on 5111 */ |
2139 | /* Used to read radio revision*/ | 2139 | /* Used to read radio revision*/ |
2140 | 2140 | ||
2141 | #define AR5K_RF_BUFFER_CONTROL_4 0x98d4 /* RF Stage register on 5110 */ | 2141 | #define AR5K_RF_BUFFER_CONTROL_4 0x98d4 /* RF Stage register on 5110 */ |
2142 | /* Bank 0,1,2,6 on 5111 */ | 2142 | /* Bank 0,1,2,6 on 5111 */ |
2143 | /* Bank 1 on 5112 */ | 2143 | /* Bank 1 on 5112 */ |
2144 | /* Used during activation on 5111 */ | 2144 | /* Used during activation on 5111 */ |
2145 | 2145 | ||
2146 | #define AR5K_RF_BUFFER_CONTROL_5 0x98d8 /* Bank 3 on 5111 */ | 2146 | #define AR5K_RF_BUFFER_CONTROL_5 0x98d8 /* Bank 3 on 5111 */ |
2147 | /* Used during activation on 5111 */ | 2147 | /* Used during activation on 5111 */ |
2148 | /* Channel on 5112 */ | 2148 | /* Channel on 5112 */ |
2149 | /* Bank 6 on 5112 */ | 2149 | /* Bank 6 on 5112 */ |
2150 | 2150 | ||
2151 | #define AR5K_RF_BUFFER_CONTROL_6 0x98dc /* Bank 3 on 5112 */ | 2151 | #define AR5K_RF_BUFFER_CONTROL_6 0x98dc /* Bank 3 on 5112 */ |
2152 | 2152 | ||
2153 | /* | 2153 | /* |
2154 | * PHY RF stage register [5210] | 2154 | * PHY RF stage register [5210] |
2155 | */ | 2155 | */ |
2156 | #define AR5K_PHY_RFSTG 0x98d4 | 2156 | #define AR5K_PHY_RFSTG 0x98d4 |
2157 | #define AR5K_PHY_RFSTG_DISABLE 0x00000021 | 2157 | #define AR5K_PHY_RFSTG_DISABLE 0x00000021 |
2158 | 2158 | ||
2159 | /* | 2159 | /* |
2160 | * BIN masks (?) | 2160 | * BIN masks (?) |
2161 | */ | 2161 | */ |
2162 | #define AR5K_PHY_BIN_MASK_1 0x9900 | 2162 | #define AR5K_PHY_BIN_MASK_1 0x9900 |
2163 | #define AR5K_PHY_BIN_MASK_2 0x9904 | 2163 | #define AR5K_PHY_BIN_MASK_2 0x9904 |
2164 | #define AR5K_PHY_BIN_MASK_3 0x9908 | 2164 | #define AR5K_PHY_BIN_MASK_3 0x9908 |
2165 | 2165 | ||
2166 | #define AR5K_PHY_BIN_MASK_CTL 0x990c | 2166 | #define AR5K_PHY_BIN_MASK_CTL 0x990c |
2167 | #define AR5K_PHY_BIN_MASK_CTL_MASK_4 0x00003fff | 2167 | #define AR5K_PHY_BIN_MASK_CTL_MASK_4 0x00003fff |
2168 | #define AR5K_PHY_BIN_MASK_CTL_MASK_4_S 0 | 2168 | #define AR5K_PHY_BIN_MASK_CTL_MASK_4_S 0 |
2169 | #define AR5K_PHY_BIN_MASK_CTL_RATE 0xff000000 | 2169 | #define AR5K_PHY_BIN_MASK_CTL_RATE 0xff000000 |
2170 | #define AR5K_PHY_BIN_MASK_CTL_RATE_S 24 | 2170 | #define AR5K_PHY_BIN_MASK_CTL_RATE_S 24 |
2171 | 2171 | ||
2172 | /* | 2172 | /* |
2173 | * PHY Antenna control register | 2173 | * PHY Antenna control register |
2174 | */ | 2174 | */ |
2175 | #define AR5K_PHY_ANT_CTL 0x9910 /* Register Address */ | 2175 | #define AR5K_PHY_ANT_CTL 0x9910 /* Register Address */ |
2176 | #define AR5K_PHY_ANT_CTL_TXRX_EN 0x00000001 /* Enable TX/RX (?) */ | 2176 | #define AR5K_PHY_ANT_CTL_TXRX_EN 0x00000001 /* Enable TX/RX (?) */ |
2177 | #define AR5K_PHY_ANT_CTL_SECTORED_ANT 0x00000004 /* Sectored Antenna */ | 2177 | #define AR5K_PHY_ANT_CTL_SECTORED_ANT 0x00000004 /* Sectored Antenna */ |
2178 | #define AR5K_PHY_ANT_CTL_HITUNE5 0x00000008 /* Hitune5 (?) */ | 2178 | #define AR5K_PHY_ANT_CTL_HITUNE5 0x00000008 /* Hitune5 (?) */ |
2179 | #define AR5K_PHY_ANT_CTL_SWTABLE_IDLE 0x000003f0 /* Switch table idle (?) */ | 2179 | #define AR5K_PHY_ANT_CTL_SWTABLE_IDLE 0x000003f0 /* Switch table idle (?) */ |
2180 | #define AR5K_PHY_ANT_CTL_SWTABLE_IDLE_S 4 | 2180 | #define AR5K_PHY_ANT_CTL_SWTABLE_IDLE_S 4 |
2181 | 2181 | ||
2182 | /* | 2182 | /* |
2183 | * PHY receiver delay register [5111+] | 2183 | * PHY receiver delay register [5111+] |
2184 | */ | 2184 | */ |
2185 | #define AR5K_PHY_RX_DELAY 0x9914 /* Register Address */ | 2185 | #define AR5K_PHY_RX_DELAY 0x9914 /* Register Address */ |
2186 | #define AR5K_PHY_RX_DELAY_M 0x00003fff /* Mask for RX activate to receive delay (/100ns) */ | 2186 | #define AR5K_PHY_RX_DELAY_M 0x00003fff /* Mask for RX activate to receive delay (/100ns) */ |
2187 | 2187 | ||
2188 | /* | 2188 | /* |
2189 | * PHY max rx length register (?) [5111] | 2189 | * PHY max rx length register (?) [5111] |
2190 | */ | 2190 | */ |
2191 | #define AR5K_PHY_MAX_RX_LEN 0x991c | 2191 | #define AR5K_PHY_MAX_RX_LEN 0x991c |
2192 | 2192 | ||
2193 | /* | 2193 | /* |
2194 | * PHY timing register 4 | 2194 | * PHY timing register 4 |
2195 | * I(nphase)/Q(adrature) calibration register [5111+] | 2195 | * I(nphase)/Q(adrature) calibration register [5111+] |
2196 | */ | 2196 | */ |
2197 | #define AR5K_PHY_IQ 0x9920 /* Register Address */ | 2197 | #define AR5K_PHY_IQ 0x9920 /* Register Address */ |
2198 | #define AR5K_PHY_IQ_CORR_Q_Q_COFF 0x0000001f /* Mask for q correction info */ | 2198 | #define AR5K_PHY_IQ_CORR_Q_Q_COFF 0x0000001f /* Mask for q correction info */ |
2199 | #define AR5K_PHY_IQ_CORR_Q_I_COFF 0x000007e0 /* Mask for i correction info */ | 2199 | #define AR5K_PHY_IQ_CORR_Q_I_COFF 0x000007e0 /* Mask for i correction info */ |
2200 | #define AR5K_PHY_IQ_CORR_Q_I_COFF_S 5 | 2200 | #define AR5K_PHY_IQ_CORR_Q_I_COFF_S 5 |
2201 | #define AR5K_PHY_IQ_CORR_ENABLE 0x00000800 /* Enable i/q correction */ | 2201 | #define AR5K_PHY_IQ_CORR_ENABLE 0x00000800 /* Enable i/q correction */ |
2202 | #define AR5K_PHY_IQ_CAL_NUM_LOG_MAX 0x0000f000 /* Mask for max number of samples in log scale */ | 2202 | #define AR5K_PHY_IQ_CAL_NUM_LOG_MAX 0x0000f000 /* Mask for max number of samples in log scale */ |
2203 | #define AR5K_PHY_IQ_CAL_NUM_LOG_MAX_S 12 | 2203 | #define AR5K_PHY_IQ_CAL_NUM_LOG_MAX_S 12 |
2204 | #define AR5K_PHY_IQ_RUN 0x00010000 /* Run i/q calibration */ | 2204 | #define AR5K_PHY_IQ_RUN 0x00010000 /* Run i/q calibration */ |
2205 | #define AR5K_PHY_IQ_USE_PT_DF 0x00020000 /* Use pilot track df (?) */ | 2205 | #define AR5K_PHY_IQ_USE_PT_DF 0x00020000 /* Use pilot track df (?) */ |
2206 | #define AR5K_PHY_IQ_EARLY_TRIG_THR 0x00200000 /* Early trigger threshold (?) (field) */ | 2206 | #define AR5K_PHY_IQ_EARLY_TRIG_THR 0x00200000 /* Early trigger threshold (?) (field) */ |
2207 | #define AR5K_PHY_IQ_PILOT_MASK_EN 0x10000000 /* Enable pilot mask (?) */ | 2207 | #define AR5K_PHY_IQ_PILOT_MASK_EN 0x10000000 /* Enable pilot mask (?) */ |
2208 | #define AR5K_PHY_IQ_CHAN_MASK_EN 0x20000000 /* Enable channel mask (?) */ | 2208 | #define AR5K_PHY_IQ_CHAN_MASK_EN 0x20000000 /* Enable channel mask (?) */ |
2209 | #define AR5K_PHY_IQ_SPUR_FILT_EN 0x40000000 /* Enable spur filter */ | 2209 | #define AR5K_PHY_IQ_SPUR_FILT_EN 0x40000000 /* Enable spur filter */ |
2210 | #define AR5K_PHY_IQ_SPUR_RSSI_EN 0x80000000 /* Enable spur rssi */ | 2210 | #define AR5K_PHY_IQ_SPUR_RSSI_EN 0x80000000 /* Enable spur rssi */ |
2211 | 2211 | ||
2212 | /* | 2212 | /* |
2213 | * PHY timing register 5 | 2213 | * PHY timing register 5 |
2214 | * OFDM Self-correlator Cyclic RSSI threshold params | 2214 | * OFDM Self-correlator Cyclic RSSI threshold params |
2215 | * (Check out bb_cycpwr_thr1 on ANI patent) | 2215 | * (Check out bb_cycpwr_thr1 on ANI patent) |
2216 | */ | 2216 | */ |
2217 | #define AR5K_PHY_OFDM_SELFCORR 0x9924 /* Register Address */ | 2217 | #define AR5K_PHY_OFDM_SELFCORR 0x9924 /* Register Address */ |
2218 | #define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_EN 0x00000001 /* Enable cyclic RSSI thr 1 */ | 2218 | #define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_EN 0x00000001 /* Enable cyclic RSSI thr 1 */ |
2219 | #define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1 0x000000fe /* Mask for Cyclic RSSI threshold 1 */ | 2219 | #define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1 0x000000fe /* Mask for Cyclic RSSI threshold 1 */ |
2220 | #define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_S 1 | 2220 | #define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_S 1 |
2221 | #define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR3 0x00000100 /* Cyclic RSSI threshold 3 (field) (?) */ | 2221 | #define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR3 0x00000100 /* Cyclic RSSI threshold 3 (field) (?) */ |
2222 | #define AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR_EN 0x00008000 /* Enable 1A RSSI threshold (?) */ | 2222 | #define AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR_EN 0x00008000 /* Enable 1A RSSI threshold (?) */ |
2223 | #define AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR 0x00010000 /* 1A RSSI threshold (field) (?) */ | 2223 | #define AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR 0x00010000 /* 1A RSSI threshold (field) (?) */ |
2224 | #define AR5K_PHY_OFDM_SELFCORR_LSCTHR_HIRSSI 0x00800000 /* Long sc threshold hi rssi (?) */ | 2224 | #define AR5K_PHY_OFDM_SELFCORR_LSCTHR_HIRSSI 0x00800000 /* Long sc threshold hi rssi (?) */ |
2225 | 2225 | ||
2226 | /* | 2226 | /* |
2227 | * PHY-only warm reset register | 2227 | * PHY-only warm reset register |
2228 | */ | 2228 | */ |
2229 | #define AR5K_PHY_WARM_RESET 0x9928 | 2229 | #define AR5K_PHY_WARM_RESET 0x9928 |
2230 | 2230 | ||
2231 | /* | 2231 | /* |
2232 | * PHY-only control register | 2232 | * PHY-only control register |
2233 | */ | 2233 | */ |
2234 | #define AR5K_PHY_CTL 0x992c /* Register Address */ | 2234 | #define AR5K_PHY_CTL 0x992c /* Register Address */ |
2235 | #define AR5K_PHY_CTL_RX_DRAIN_RATE 0x00000001 /* RX drain rate (?) */ | 2235 | #define AR5K_PHY_CTL_RX_DRAIN_RATE 0x00000001 /* RX drain rate (?) */ |
2236 | #define AR5K_PHY_CTL_LATE_TX_SIG_SYM 0x00000002 /* Late tx signal symbol (?) */ | 2236 | #define AR5K_PHY_CTL_LATE_TX_SIG_SYM 0x00000002 /* Late tx signal symbol (?) */ |
2237 | #define AR5K_PHY_CTL_GEN_SCRAMBLER 0x00000004 /* Generate scrambler */ | 2237 | #define AR5K_PHY_CTL_GEN_SCRAMBLER 0x00000004 /* Generate scrambler */ |
2238 | #define AR5K_PHY_CTL_TX_ANT_SEL 0x00000008 /* TX antenna select */ | 2238 | #define AR5K_PHY_CTL_TX_ANT_SEL 0x00000008 /* TX antenna select */ |
2239 | #define AR5K_PHY_CTL_TX_ANT_STATIC 0x00000010 /* Static TX antenna */ | 2239 | #define AR5K_PHY_CTL_TX_ANT_STATIC 0x00000010 /* Static TX antenna */ |
2240 | #define AR5K_PHY_CTL_RX_ANT_SEL 0x00000020 /* RX antenna select */ | 2240 | #define AR5K_PHY_CTL_RX_ANT_SEL 0x00000020 /* RX antenna select */ |
2241 | #define AR5K_PHY_CTL_RX_ANT_STATIC 0x00000040 /* Static RX antenna */ | 2241 | #define AR5K_PHY_CTL_RX_ANT_STATIC 0x00000040 /* Static RX antenna */ |
2242 | #define AR5K_PHY_CTL_LOW_FREQ_SLE_EN 0x00000080 /* Enable low freq sleep */ | 2242 | #define AR5K_PHY_CTL_LOW_FREQ_SLE_EN 0x00000080 /* Enable low freq sleep */ |
2243 | 2243 | ||
2244 | /* | 2244 | /* |
2245 | * PHY PAPD probe register [5111+] | 2245 | * PHY PAPD probe register [5111+] |
2246 | */ | 2246 | */ |
2247 | #define AR5K_PHY_PAPD_PROBE 0x9930 | 2247 | #define AR5K_PHY_PAPD_PROBE 0x9930 |
2248 | #define AR5K_PHY_PAPD_PROBE_SH_HI_PAR 0x00000001 | 2248 | #define AR5K_PHY_PAPD_PROBE_SH_HI_PAR 0x00000001 |
2249 | #define AR5K_PHY_PAPD_PROBE_PCDAC_BIAS 0x00000002 | 2249 | #define AR5K_PHY_PAPD_PROBE_PCDAC_BIAS 0x00000002 |
2250 | #define AR5K_PHY_PAPD_PROBE_COMP_GAIN 0x00000040 | 2250 | #define AR5K_PHY_PAPD_PROBE_COMP_GAIN 0x00000040 |
2251 | #define AR5K_PHY_PAPD_PROBE_TXPOWER 0x00007e00 | 2251 | #define AR5K_PHY_PAPD_PROBE_TXPOWER 0x00007e00 |
2252 | #define AR5K_PHY_PAPD_PROBE_TXPOWER_S 9 | 2252 | #define AR5K_PHY_PAPD_PROBE_TXPOWER_S 9 |
2253 | #define AR5K_PHY_PAPD_PROBE_TX_NEXT 0x00008000 | 2253 | #define AR5K_PHY_PAPD_PROBE_TX_NEXT 0x00008000 |
2254 | #define AR5K_PHY_PAPD_PROBE_PREDIST_EN 0x00010000 | 2254 | #define AR5K_PHY_PAPD_PROBE_PREDIST_EN 0x00010000 |
2255 | #define AR5K_PHY_PAPD_PROBE_TYPE 0x01800000 /* [5112+] */ | 2255 | #define AR5K_PHY_PAPD_PROBE_TYPE 0x01800000 /* [5112+] */ |
2256 | #define AR5K_PHY_PAPD_PROBE_TYPE_S 23 | 2256 | #define AR5K_PHY_PAPD_PROBE_TYPE_S 23 |
2257 | #define AR5K_PHY_PAPD_PROBE_TYPE_OFDM 0 | 2257 | #define AR5K_PHY_PAPD_PROBE_TYPE_OFDM 0 |
2258 | #define AR5K_PHY_PAPD_PROBE_TYPE_XR 1 | 2258 | #define AR5K_PHY_PAPD_PROBE_TYPE_XR 1 |
2259 | #define AR5K_PHY_PAPD_PROBE_TYPE_CCK 2 | 2259 | #define AR5K_PHY_PAPD_PROBE_TYPE_CCK 2 |
2260 | #define AR5K_PHY_PAPD_PROBE_GAINF 0xfe000000 | 2260 | #define AR5K_PHY_PAPD_PROBE_GAINF 0xfe000000 |
2261 | #define AR5K_PHY_PAPD_PROBE_GAINF_S 25 | 2261 | #define AR5K_PHY_PAPD_PROBE_GAINF_S 25 |
2262 | #define AR5K_PHY_PAPD_PROBE_INI_5111 0x00004883 /* [5212+] */ | 2262 | #define AR5K_PHY_PAPD_PROBE_INI_5111 0x00004883 /* [5212+] */ |
2263 | #define AR5K_PHY_PAPD_PROBE_INI_5112 0x00004882 /* [5212+] */ | 2263 | #define AR5K_PHY_PAPD_PROBE_INI_5112 0x00004882 /* [5212+] */ |
2264 | 2264 | ||
2265 | /* | 2265 | /* |
2266 | * PHY TX rate power registers [5112+] | 2266 | * PHY TX rate power registers [5112+] |
2267 | */ | 2267 | */ |
2268 | #define AR5K_PHY_TXPOWER_RATE1 0x9934 | 2268 | #define AR5K_PHY_TXPOWER_RATE1 0x9934 |
2269 | #define AR5K_PHY_TXPOWER_RATE2 0x9938 | 2269 | #define AR5K_PHY_TXPOWER_RATE2 0x9938 |
2270 | #define AR5K_PHY_TXPOWER_RATE_MAX 0x993c | 2270 | #define AR5K_PHY_TXPOWER_RATE_MAX 0x993c |
2271 | #define AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE 0x00000040 | 2271 | #define AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE 0x00000040 |
2272 | #define AR5K_PHY_TXPOWER_RATE3 0xa234 | 2272 | #define AR5K_PHY_TXPOWER_RATE3 0xa234 |
2273 | #define AR5K_PHY_TXPOWER_RATE4 0xa238 | 2273 | #define AR5K_PHY_TXPOWER_RATE4 0xa238 |
2274 | 2274 | ||
2275 | /* | 2275 | /* |
2276 | * PHY frame control register [5111+] | 2276 | * PHY frame control register [5111+] |
2277 | */ | 2277 | */ |
2278 | #define AR5K_PHY_FRAME_CTL_5210 0x9804 | 2278 | #define AR5K_PHY_FRAME_CTL_5210 0x9804 |
2279 | #define AR5K_PHY_FRAME_CTL_5211 0x9944 | 2279 | #define AR5K_PHY_FRAME_CTL_5211 0x9944 |
2280 | #define AR5K_PHY_FRAME_CTL (ah->ah_version == AR5K_AR5210 ? \ | 2280 | #define AR5K_PHY_FRAME_CTL (ah->ah_version == AR5K_AR5210 ? \ |
2281 | AR5K_PHY_FRAME_CTL_5210 : AR5K_PHY_FRAME_CTL_5211) | 2281 | AR5K_PHY_FRAME_CTL_5210 : AR5K_PHY_FRAME_CTL_5211) |
2282 | /*---[5111+]---*/ | 2282 | /*---[5111+]---*/ |
2283 | #define AR5K_PHY_FRAME_CTL_TX_CLIP 0x00000038 /* Mask for tx clip (?) */ | 2283 | #define AR5K_PHY_FRAME_CTL_TX_CLIP 0x00000038 /* Mask for tx clip (?) */ |
2284 | #define AR5K_PHY_FRAME_CTL_TX_CLIP_S 3 | 2284 | #define AR5K_PHY_FRAME_CTL_TX_CLIP_S 3 |
2285 | #define AR5K_PHY_FRAME_CTL_PREP_CHINFO 0x00010000 /* Prepend chan info */ | 2285 | #define AR5K_PHY_FRAME_CTL_PREP_CHINFO 0x00010000 /* Prepend chan info */ |
2286 | #define AR5K_PHY_FRAME_CTL_EMU 0x80000000 | 2286 | #define AR5K_PHY_FRAME_CTL_EMU 0x80000000 |
2287 | #define AR5K_PHY_FRAME_CTL_EMU_S 31 | 2287 | #define AR5K_PHY_FRAME_CTL_EMU_S 31 |
2288 | /*---[5110/5111]---*/ | 2288 | /*---[5110/5111]---*/ |
2289 | #define AR5K_PHY_FRAME_CTL_TIMING_ERR 0x01000000 /* PHY timing error */ | 2289 | #define AR5K_PHY_FRAME_CTL_TIMING_ERR 0x01000000 /* PHY timing error */ |
2290 | #define AR5K_PHY_FRAME_CTL_PARITY_ERR 0x02000000 /* Parity error */ | 2290 | #define AR5K_PHY_FRAME_CTL_PARITY_ERR 0x02000000 /* Parity error */ |
2291 | #define AR5K_PHY_FRAME_CTL_ILLRATE_ERR 0x04000000 /* Illegal rate */ | 2291 | #define AR5K_PHY_FRAME_CTL_ILLRATE_ERR 0x04000000 /* Illegal rate */ |
2292 | #define AR5K_PHY_FRAME_CTL_ILLLEN_ERR 0x08000000 /* Illegal length */ | 2292 | #define AR5K_PHY_FRAME_CTL_ILLLEN_ERR 0x08000000 /* Illegal length */ |
2293 | #define AR5K_PHY_FRAME_CTL_SERVICE_ERR 0x20000000 | 2293 | #define AR5K_PHY_FRAME_CTL_SERVICE_ERR 0x20000000 |
2294 | #define AR5K_PHY_FRAME_CTL_TXURN_ERR 0x40000000 /* TX underrun */ | 2294 | #define AR5K_PHY_FRAME_CTL_TXURN_ERR 0x40000000 /* TX underrun */ |
2295 | #define AR5K_PHY_FRAME_CTL_INI AR5K_PHY_FRAME_CTL_SERVICE_ERR | \ | 2295 | #define AR5K_PHY_FRAME_CTL_INI AR5K_PHY_FRAME_CTL_SERVICE_ERR | \ |
2296 | AR5K_PHY_FRAME_CTL_TXURN_ERR | \ | 2296 | AR5K_PHY_FRAME_CTL_TXURN_ERR | \ |
2297 | AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \ | 2297 | AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \ |
2298 | AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \ | 2298 | AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \ |
2299 | AR5K_PHY_FRAME_CTL_PARITY_ERR | \ | 2299 | AR5K_PHY_FRAME_CTL_PARITY_ERR | \ |
2300 | AR5K_PHY_FRAME_CTL_TIMING_ERR | 2300 | AR5K_PHY_FRAME_CTL_TIMING_ERR |
2301 | 2301 | ||
2302 | /* | 2302 | /* |
2303 | * PHY Tx Power adjustment register [5212A+] | 2303 | * PHY Tx Power adjustment register [5212A+] |
2304 | */ | 2304 | */ |
2305 | #define AR5K_PHY_TX_PWR_ADJ 0x994c | 2305 | #define AR5K_PHY_TX_PWR_ADJ 0x994c |
2306 | #define AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA 0x00000fc0 | 2306 | #define AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA 0x00000fc0 |
2307 | #define AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA_S 6 | 2307 | #define AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA_S 6 |
2308 | #define AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX 0x00fc0000 | 2308 | #define AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX 0x00fc0000 |
2309 | #define AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX_S 18 | 2309 | #define AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX_S 18 |
2310 | 2310 | ||
2311 | /* | 2311 | /* |
2312 | * PHY radar detection register [5111+] | 2312 | * PHY radar detection register [5111+] |
2313 | */ | 2313 | */ |
2314 | #define AR5K_PHY_RADAR 0x9954 | 2314 | #define AR5K_PHY_RADAR 0x9954 |
2315 | #define AR5K_PHY_RADAR_ENABLE 0x00000001 | 2315 | #define AR5K_PHY_RADAR_ENABLE 0x00000001 |
2316 | #define AR5K_PHY_RADAR_DISABLE 0x00000000 | 2316 | #define AR5K_PHY_RADAR_DISABLE 0x00000000 |
2317 | #define AR5K_PHY_RADAR_INBANDTHR 0x0000003e /* Inband threshold | 2317 | #define AR5K_PHY_RADAR_INBANDTHR 0x0000003e /* Inband threshold |
2318 | 5-bits, units unknown {0..31} | 2318 | 5-bits, units unknown {0..31} |
2319 | (? MHz ?) */ | 2319 | (? MHz ?) */ |
2320 | #define AR5K_PHY_RADAR_INBANDTHR_S 1 | 2320 | #define AR5K_PHY_RADAR_INBANDTHR_S 1 |
2321 | 2321 | ||
2322 | #define AR5K_PHY_RADAR_PRSSI_THR 0x00000fc0 /* Pulse RSSI/SNR threshold | 2322 | #define AR5K_PHY_RADAR_PRSSI_THR 0x00000fc0 /* Pulse RSSI/SNR threshold |
2323 | 6-bits, dBm range {0..63} | 2323 | 6-bits, dBm range {0..63} |
2324 | in dBm units. */ | 2324 | in dBm units. */ |
2325 | #define AR5K_PHY_RADAR_PRSSI_THR_S 6 | 2325 | #define AR5K_PHY_RADAR_PRSSI_THR_S 6 |
2326 | 2326 | ||
2327 | #define AR5K_PHY_RADAR_PHEIGHT_THR 0x0003f000 /* Pulse height threshold | 2327 | #define AR5K_PHY_RADAR_PHEIGHT_THR 0x0003f000 /* Pulse height threshold |
2328 | 6-bits, dBm range {0..63} | 2328 | 6-bits, dBm range {0..63} |
2329 | in dBm units. */ | 2329 | in dBm units. */ |
2330 | #define AR5K_PHY_RADAR_PHEIGHT_THR_S 12 | 2330 | #define AR5K_PHY_RADAR_PHEIGHT_THR_S 12 |
2331 | 2331 | ||
2332 | #define AR5K_PHY_RADAR_RSSI_THR 0x00fc0000 /* Radar RSSI/SNR threshold. | 2332 | #define AR5K_PHY_RADAR_RSSI_THR 0x00fc0000 /* Radar RSSI/SNR threshold. |
2333 | 6-bits, dBm range {0..63} | 2333 | 6-bits, dBm range {0..63} |
2334 | in dBm units. */ | 2334 | in dBm units. */ |
2335 | #define AR5K_PHY_RADAR_RSSI_THR_S 18 | 2335 | #define AR5K_PHY_RADAR_RSSI_THR_S 18 |
2336 | 2336 | ||
2337 | #define AR5K_PHY_RADAR_FIRPWR_THR 0x7f000000 /* Finite Impulse Response | 2337 | #define AR5K_PHY_RADAR_FIRPWR_THR 0x7f000000 /* Finite Impulse Response |
2338 | filter power out threshold. | 2338 | filter power out threshold. |
2339 | 7-bits, standard power range | 2339 | 7-bits, standard power range |
2340 | {0..127} in 1/2 dBm units. */ | 2340 | {0..127} in 1/2 dBm units. */ |
2341 | #define AR5K_PHY_RADAR_FIRPWR_THRS 24 | 2341 | #define AR5K_PHY_RADAR_FIRPWR_THRS 24 |
2342 | 2342 | ||
2343 | /* | 2343 | /* |
2344 | * PHY antenna switch table registers | 2344 | * PHY antenna switch table registers |
2345 | */ | 2345 | */ |
2346 | #define AR5K_PHY_ANT_SWITCH_TABLE_0 0x9960 | 2346 | #define AR5K_PHY_ANT_SWITCH_TABLE_0 0x9960 |
2347 | #define AR5K_PHY_ANT_SWITCH_TABLE_1 0x9964 | 2347 | #define AR5K_PHY_ANT_SWITCH_TABLE_1 0x9964 |
2348 | 2348 | ||
2349 | /* | 2349 | /* |
2350 | * PHY Noise floor threshold | 2350 | * PHY Noise floor threshold |
2351 | */ | 2351 | */ |
2352 | #define AR5K_PHY_NFTHRES 0x9968 | 2352 | #define AR5K_PHY_NFTHRES 0x9968 |
2353 | 2353 | ||
2354 | /* | 2354 | /* |
2355 | * Sigma Delta register (?) [5213] | 2355 | * Sigma Delta register (?) [5213] |
2356 | */ | 2356 | */ |
2357 | #define AR5K_PHY_SIGMA_DELTA 0x996C | 2357 | #define AR5K_PHY_SIGMA_DELTA 0x996C |
2358 | #define AR5K_PHY_SIGMA_DELTA_ADC_SEL 0x00000003 | 2358 | #define AR5K_PHY_SIGMA_DELTA_ADC_SEL 0x00000003 |
2359 | #define AR5K_PHY_SIGMA_DELTA_ADC_SEL_S 0 | 2359 | #define AR5K_PHY_SIGMA_DELTA_ADC_SEL_S 0 |
2360 | #define AR5K_PHY_SIGMA_DELTA_FILT2 0x000000f8 | 2360 | #define AR5K_PHY_SIGMA_DELTA_FILT2 0x000000f8 |
2361 | #define AR5K_PHY_SIGMA_DELTA_FILT2_S 3 | 2361 | #define AR5K_PHY_SIGMA_DELTA_FILT2_S 3 |
2362 | #define AR5K_PHY_SIGMA_DELTA_FILT1 0x00001f00 | 2362 | #define AR5K_PHY_SIGMA_DELTA_FILT1 0x00001f00 |
2363 | #define AR5K_PHY_SIGMA_DELTA_FILT1_S 8 | 2363 | #define AR5K_PHY_SIGMA_DELTA_FILT1_S 8 |
2364 | #define AR5K_PHY_SIGMA_DELTA_ADC_CLIP 0x01ffe000 | 2364 | #define AR5K_PHY_SIGMA_DELTA_ADC_CLIP 0x01ffe000 |
2365 | #define AR5K_PHY_SIGMA_DELTA_ADC_CLIP_S 13 | 2365 | #define AR5K_PHY_SIGMA_DELTA_ADC_CLIP_S 13 |
2366 | 2366 | ||
2367 | /* | 2367 | /* |
2368 | * RF restart register [5112+] (?) | 2368 | * RF restart register [5112+] (?) |
2369 | */ | 2369 | */ |
2370 | #define AR5K_PHY_RESTART 0x9970 /* restart */ | 2370 | #define AR5K_PHY_RESTART 0x9970 /* restart */ |
2371 | #define AR5K_PHY_RESTART_DIV_GC 0x001c0000 /* Fast diversity gc_limit (?) */ | 2371 | #define AR5K_PHY_RESTART_DIV_GC 0x001c0000 /* Fast diversity gc_limit (?) */ |
2372 | #define AR5K_PHY_RESTART_DIV_GC_S 18 | 2372 | #define AR5K_PHY_RESTART_DIV_GC_S 18 |
2373 | 2373 | ||
2374 | /* | 2374 | /* |
2375 | * RF Bus access request register (for synth-oly channel switching) | 2375 | * RF Bus access request register (for synth-oly channel switching) |
2376 | */ | 2376 | */ |
2377 | #define AR5K_PHY_RFBUS_REQ 0x997C | 2377 | #define AR5K_PHY_RFBUS_REQ 0x997C |
2378 | #define AR5K_PHY_RFBUS_REQ_REQUEST 0x00000001 | 2378 | #define AR5K_PHY_RFBUS_REQ_REQUEST 0x00000001 |
2379 | 2379 | ||
2380 | /* | 2380 | /* |
2381 | * Spur mitigation masks (?) | 2381 | * Spur mitigation masks (?) |
2382 | */ | 2382 | */ |
2383 | #define AR5K_PHY_TIMING_7 0x9980 | 2383 | #define AR5K_PHY_TIMING_7 0x9980 |
2384 | #define AR5K_PHY_TIMING_8 0x9984 | 2384 | #define AR5K_PHY_TIMING_8 0x9984 |
2385 | #define AR5K_PHY_TIMING_8_PILOT_MASK_2 0x000fffff | 2385 | #define AR5K_PHY_TIMING_8_PILOT_MASK_2 0x000fffff |
2386 | #define AR5K_PHY_TIMING_8_PILOT_MASK_2_S 0 | 2386 | #define AR5K_PHY_TIMING_8_PILOT_MASK_2_S 0 |
2387 | 2387 | ||
2388 | #define AR5K_PHY_BIN_MASK2_1 0x9988 | 2388 | #define AR5K_PHY_BIN_MASK2_1 0x9988 |
2389 | #define AR5K_PHY_BIN_MASK2_2 0x998c | 2389 | #define AR5K_PHY_BIN_MASK2_2 0x998c |
2390 | #define AR5K_PHY_BIN_MASK2_3 0x9990 | 2390 | #define AR5K_PHY_BIN_MASK2_3 0x9990 |
2391 | 2391 | ||
2392 | #define AR5K_PHY_BIN_MASK2_4 0x9994 | 2392 | #define AR5K_PHY_BIN_MASK2_4 0x9994 |
2393 | #define AR5K_PHY_BIN_MASK2_4_MASK_4 0x00003fff | 2393 | #define AR5K_PHY_BIN_MASK2_4_MASK_4 0x00003fff |
2394 | #define AR5K_PHY_BIN_MASK2_4_MASK_4_S 0 | 2394 | #define AR5K_PHY_BIN_MASK2_4_MASK_4_S 0 |
2395 | 2395 | ||
2396 | #define AR5K_PHY_TIMING_9 0x9998 | 2396 | #define AR5K_PHY_TIMING_9 0x9998 |
2397 | #define AR5K_PHY_TIMING_10 0x999c | 2397 | #define AR5K_PHY_TIMING_10 0x999c |
2398 | #define AR5K_PHY_TIMING_10_PILOT_MASK_2 0x000fffff | 2398 | #define AR5K_PHY_TIMING_10_PILOT_MASK_2 0x000fffff |
2399 | #define AR5K_PHY_TIMING_10_PILOT_MASK_2_S 0 | 2399 | #define AR5K_PHY_TIMING_10_PILOT_MASK_2_S 0 |
2400 | 2400 | ||
2401 | /* | 2401 | /* |
2402 | * Spur mitigation control | 2402 | * Spur mitigation control |
2403 | */ | 2403 | */ |
2404 | #define AR5K_PHY_TIMING_11 0x99a0 /* Register address */ | 2404 | #define AR5K_PHY_TIMING_11 0x99a0 /* Register address */ |
2405 | #define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE 0x000fffff /* Spur delta phase */ | 2405 | #define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE 0x000fffff /* Spur delta phase */ |
2406 | #define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE_S 0 | 2406 | #define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE_S 0 |
2407 | #define AR5K_PHY_TIMING_11_SPUR_FREQ_SD 0x3ff00000 /* Freq sigma delta */ | 2407 | #define AR5K_PHY_TIMING_11_SPUR_FREQ_SD 0x3ff00000 /* Freq sigma delta */ |
2408 | #define AR5K_PHY_TIMING_11_SPUR_FREQ_SD_S 20 | 2408 | #define AR5K_PHY_TIMING_11_SPUR_FREQ_SD_S 20 |
2409 | #define AR5K_PHY_TIMING_11_USE_SPUR_IN_AGC 0x40000000 /* Spur filter in AGC detector */ | 2409 | #define AR5K_PHY_TIMING_11_USE_SPUR_IN_AGC 0x40000000 /* Spur filter in AGC detector */ |
2410 | #define AR5K_PHY_TIMING_11_USE_SPUR_IN_SELFCOR 0x80000000 /* Spur filter in OFDM self correlator */ | 2410 | #define AR5K_PHY_TIMING_11_USE_SPUR_IN_SELFCOR 0x80000000 /* Spur filter in OFDM self correlator */ |
2411 | 2411 | ||
2412 | /* | 2412 | /* |
2413 | * Gain tables | 2413 | * Gain tables |
2414 | */ | 2414 | */ |
2415 | #define AR5K_BB_GAIN_BASE 0x9b00 /* BaseBand Amplifier Gain table base address */ | 2415 | #define AR5K_BB_GAIN_BASE 0x9b00 /* BaseBand Amplifier Gain table base address */ |
2416 | #define AR5K_BB_GAIN(_n) (AR5K_BB_GAIN_BASE + ((_n) << 2)) | 2416 | #define AR5K_BB_GAIN(_n) (AR5K_BB_GAIN_BASE + ((_n) << 2)) |
2417 | #define AR5K_RF_GAIN_BASE 0x9a00 /* RF Amplrifier Gain table base address */ | 2417 | #define AR5K_RF_GAIN_BASE 0x9a00 /* RF Amplrifier Gain table base address */ |
2418 | #define AR5K_RF_GAIN(_n) (AR5K_RF_GAIN_BASE + ((_n) << 2)) | 2418 | #define AR5K_RF_GAIN(_n) (AR5K_RF_GAIN_BASE + ((_n) << 2)) |
2419 | 2419 | ||
2420 | /* | 2420 | /* |
2421 | * PHY timing IQ calibration result register [5111+] | 2421 | * PHY timing IQ calibration result register [5111+] |
2422 | */ | 2422 | */ |
2423 | #define AR5K_PHY_IQRES_CAL_PWR_I 0x9c10 /* I (Inphase) power value */ | 2423 | #define AR5K_PHY_IQRES_CAL_PWR_I 0x9c10 /* I (Inphase) power value */ |
2424 | #define AR5K_PHY_IQRES_CAL_PWR_Q 0x9c14 /* Q (Quadrature) power value */ | 2424 | #define AR5K_PHY_IQRES_CAL_PWR_Q 0x9c14 /* Q (Quadrature) power value */ |
2425 | #define AR5K_PHY_IQRES_CAL_CORR 0x9c18 /* I/Q Correlation */ | 2425 | #define AR5K_PHY_IQRES_CAL_CORR 0x9c18 /* I/Q Correlation */ |
2426 | 2426 | ||
2427 | /* | 2427 | /* |
2428 | * PHY current RSSI register [5111+] | 2428 | * PHY current RSSI register [5111+] |
2429 | */ | 2429 | */ |
2430 | #define AR5K_PHY_CURRENT_RSSI 0x9c1c | 2430 | #define AR5K_PHY_CURRENT_RSSI 0x9c1c |
2431 | 2431 | ||
2432 | /* | 2432 | /* |
2433 | * PHY RF Bus grant register | 2433 | * PHY RF Bus grant register |
2434 | */ | 2434 | */ |
2435 | #define AR5K_PHY_RFBUS_GRANT 0x9c20 | 2435 | #define AR5K_PHY_RFBUS_GRANT 0x9c20 |
2436 | #define AR5K_PHY_RFBUS_GRANT_OK 0x00000001 | 2436 | #define AR5K_PHY_RFBUS_GRANT_OK 0x00000001 |
2437 | 2437 | ||
2438 | /* | 2438 | /* |
2439 | * PHY ADC test register | 2439 | * PHY ADC test register |
2440 | */ | 2440 | */ |
2441 | #define AR5K_PHY_ADC_TEST 0x9c24 | 2441 | #define AR5K_PHY_ADC_TEST 0x9c24 |
2442 | #define AR5K_PHY_ADC_TEST_I 0x00000001 | 2442 | #define AR5K_PHY_ADC_TEST_I 0x00000001 |
2443 | #define AR5K_PHY_ADC_TEST_Q 0x00000200 | 2443 | #define AR5K_PHY_ADC_TEST_Q 0x00000200 |
2444 | 2444 | ||
2445 | /* | 2445 | /* |
2446 | * PHY DAC test register | 2446 | * PHY DAC test register |
2447 | */ | 2447 | */ |
2448 | #define AR5K_PHY_DAC_TEST 0x9c28 | 2448 | #define AR5K_PHY_DAC_TEST 0x9c28 |
2449 | #define AR5K_PHY_DAC_TEST_I 0x00000001 | 2449 | #define AR5K_PHY_DAC_TEST_I 0x00000001 |
2450 | #define AR5K_PHY_DAC_TEST_Q 0x00000200 | 2450 | #define AR5K_PHY_DAC_TEST_Q 0x00000200 |
2451 | 2451 | ||
2452 | /* | 2452 | /* |
2453 | * PHY PTAT register (?) | 2453 | * PHY PTAT register (?) |
2454 | */ | 2454 | */ |
2455 | #define AR5K_PHY_PTAT 0x9c2c | 2455 | #define AR5K_PHY_PTAT 0x9c2c |
2456 | 2456 | ||
2457 | /* | 2457 | /* |
2458 | * PHY Illegal TX rate register [5112+] | 2458 | * PHY Illegal TX rate register [5112+] |
2459 | */ | 2459 | */ |
2460 | #define AR5K_PHY_BAD_TX_RATE 0x9c30 | 2460 | #define AR5K_PHY_BAD_TX_RATE 0x9c30 |
2461 | 2461 | ||
2462 | /* | 2462 | /* |
2463 | * PHY SPUR Power register [5112+] | 2463 | * PHY SPUR Power register [5112+] |
2464 | */ | 2464 | */ |
2465 | #define AR5K_PHY_SPUR_PWR 0x9c34 /* Register Address */ | 2465 | #define AR5K_PHY_SPUR_PWR 0x9c34 /* Register Address */ |
2466 | #define AR5K_PHY_SPUR_PWR_I 0x00000001 /* SPUR Power estimate for I (field) */ | 2466 | #define AR5K_PHY_SPUR_PWR_I 0x00000001 /* SPUR Power estimate for I (field) */ |
2467 | #define AR5K_PHY_SPUR_PWR_Q 0x00000100 /* SPUR Power estimate for Q (field) */ | 2467 | #define AR5K_PHY_SPUR_PWR_Q 0x00000100 /* SPUR Power estimate for Q (field) */ |
2468 | #define AR5K_PHY_SPUR_PWR_FILT 0x00010000 /* Power with SPUR removed (field) */ | 2468 | #define AR5K_PHY_SPUR_PWR_FILT 0x00010000 /* Power with SPUR removed (field) */ |
2469 | 2469 | ||
2470 | /* | 2470 | /* |
2471 | * PHY Channel status register [5112+] (?) | 2471 | * PHY Channel status register [5112+] (?) |
2472 | */ | 2472 | */ |
2473 | #define AR5K_PHY_CHAN_STATUS 0x9c38 | 2473 | #define AR5K_PHY_CHAN_STATUS 0x9c38 |
2474 | #define AR5K_PHY_CHAN_STATUS_BT_ACT 0x00000001 | 2474 | #define AR5K_PHY_CHAN_STATUS_BT_ACT 0x00000001 |
2475 | #define AR5K_PHY_CHAN_STATUS_RX_CLR_RAW 0x00000002 | 2475 | #define AR5K_PHY_CHAN_STATUS_RX_CLR_RAW 0x00000002 |
2476 | #define AR5K_PHY_CHAN_STATUS_RX_CLR_MAC 0x00000004 | 2476 | #define AR5K_PHY_CHAN_STATUS_RX_CLR_MAC 0x00000004 |
2477 | #define AR5K_PHY_CHAN_STATUS_RX_CLR_PAP 0x00000008 | 2477 | #define AR5K_PHY_CHAN_STATUS_RX_CLR_PAP 0x00000008 |
2478 | 2478 | ||
2479 | /* | 2479 | /* |
2480 | * Heavy clip enable register | 2480 | * Heavy clip enable register |
2481 | */ | 2481 | */ |
2482 | #define AR5K_PHY_HEAVY_CLIP_ENABLE 0x99e0 | 2482 | #define AR5K_PHY_HEAVY_CLIP_ENABLE 0x99e0 |
2483 | 2483 | ||
2484 | /* | 2484 | /* |
2485 | * PHY clock sleep registers [5112+] | 2485 | * PHY clock sleep registers [5112+] |
2486 | */ | 2486 | */ |
2487 | #define AR5K_PHY_SCLOCK 0x99f0 | 2487 | #define AR5K_PHY_SCLOCK 0x99f0 |
2488 | #define AR5K_PHY_SCLOCK_32MHZ 0x0000000c | 2488 | #define AR5K_PHY_SCLOCK_32MHZ 0x0000000c |
2489 | #define AR5K_PHY_SDELAY 0x99f4 | 2489 | #define AR5K_PHY_SDELAY 0x99f4 |
2490 | #define AR5K_PHY_SDELAY_32MHZ 0x000000ff | 2490 | #define AR5K_PHY_SDELAY_32MHZ 0x000000ff |
2491 | #define AR5K_PHY_SPENDING 0x99f8 | 2491 | #define AR5K_PHY_SPENDING 0x99f8 |
2492 | 2492 | ||
2493 | 2493 | ||
2494 | /* | 2494 | /* |
2495 | * PHY PAPD I (power?) table (?) | 2495 | * PHY PAPD I (power?) table (?) |
2496 | * (92! entries) | 2496 | * (92! entries) |
2497 | */ | 2497 | */ |
2498 | #define AR5K_PHY_PAPD_I_BASE 0xa000 | 2498 | #define AR5K_PHY_PAPD_I_BASE 0xa000 |
2499 | #define AR5K_PHY_PAPD_I(_n) (AR5K_PHY_PAPD_I_BASE + ((_n) << 2)) | 2499 | #define AR5K_PHY_PAPD_I(_n) (AR5K_PHY_PAPD_I_BASE + ((_n) << 2)) |
2500 | 2500 | ||
2501 | /* | 2501 | /* |
2502 | * PHY PCDAC TX power table | 2502 | * PHY PCDAC TX power table |
2503 | */ | 2503 | */ |
2504 | #define AR5K_PHY_PCDAC_TXPOWER_BASE 0xa180 | 2504 | #define AR5K_PHY_PCDAC_TXPOWER_BASE 0xa180 |
2505 | #define AR5K_PHY_PCDAC_TXPOWER(_n) (AR5K_PHY_PCDAC_TXPOWER_BASE + ((_n) << 2)) | 2505 | #define AR5K_PHY_PCDAC_TXPOWER(_n) (AR5K_PHY_PCDAC_TXPOWER_BASE + ((_n) << 2)) |
2506 | 2506 | ||
2507 | /* | 2507 | /* |
2508 | * PHY mode register [5111+] | 2508 | * PHY mode register [5111+] |
2509 | */ | 2509 | */ |
2510 | #define AR5K_PHY_MODE 0x0a200 /* Register Address */ | 2510 | #define AR5K_PHY_MODE 0x0a200 /* Register Address */ |
2511 | #define AR5K_PHY_MODE_MOD 0x00000001 /* PHY Modulation bit */ | 2511 | #define AR5K_PHY_MODE_MOD 0x00000001 /* PHY Modulation bit */ |
2512 | #define AR5K_PHY_MODE_MOD_OFDM 0 | 2512 | #define AR5K_PHY_MODE_MOD_OFDM 0 |
2513 | #define AR5K_PHY_MODE_MOD_CCK 1 | 2513 | #define AR5K_PHY_MODE_MOD_CCK 1 |
2514 | #define AR5K_PHY_MODE_FREQ 0x00000002 /* Freq mode bit */ | 2514 | #define AR5K_PHY_MODE_FREQ 0x00000002 /* Freq mode bit */ |
2515 | #define AR5K_PHY_MODE_FREQ_5GHZ 0 | 2515 | #define AR5K_PHY_MODE_FREQ_5GHZ 0 |
2516 | #define AR5K_PHY_MODE_FREQ_2GHZ 2 | 2516 | #define AR5K_PHY_MODE_FREQ_2GHZ 2 |
2517 | #define AR5K_PHY_MODE_MOD_DYN 0x00000004 /* Enable Dynamic OFDM/CCK mode [5112+] */ | 2517 | #define AR5K_PHY_MODE_MOD_DYN 0x00000004 /* Enable Dynamic OFDM/CCK mode [5112+] */ |
2518 | #define AR5K_PHY_MODE_RAD 0x00000008 /* [5212+] */ | 2518 | #define AR5K_PHY_MODE_RAD 0x00000008 /* [5212+] */ |
2519 | #define AR5K_PHY_MODE_RAD_RF5111 0 | 2519 | #define AR5K_PHY_MODE_RAD_RF5111 0 |
2520 | #define AR5K_PHY_MODE_RAD_RF5112 8 | 2520 | #define AR5K_PHY_MODE_RAD_RF5112 8 |
2521 | #define AR5K_PHY_MODE_XR 0x00000010 /* Enable XR mode [5112+] */ | 2521 | #define AR5K_PHY_MODE_XR 0x00000010 /* Enable XR mode [5112+] */ |
2522 | #define AR5K_PHY_MODE_HALF_RATE 0x00000020 /* Enable Half rate (test) */ | 2522 | #define AR5K_PHY_MODE_HALF_RATE 0x00000020 /* Enable Half rate (test) */ |
2523 | #define AR5K_PHY_MODE_QUARTER_RATE 0x00000040 /* Enable Quarter rat (test) */ | 2523 | #define AR5K_PHY_MODE_QUARTER_RATE 0x00000040 /* Enable Quarter rat (test) */ |
2524 | 2524 | ||
2525 | /* | 2525 | /* |
2526 | * PHY CCK transmit control register [5111+ (?)] | 2526 | * PHY CCK transmit control register [5111+ (?)] |
2527 | */ | 2527 | */ |
2528 | #define AR5K_PHY_CCKTXCTL 0xa204 | 2528 | #define AR5K_PHY_CCKTXCTL 0xa204 |
2529 | #define AR5K_PHY_CCKTXCTL_WORLD 0x00000000 | 2529 | #define AR5K_PHY_CCKTXCTL_WORLD 0x00000000 |
2530 | #define AR5K_PHY_CCKTXCTL_JAPAN 0x00000010 | 2530 | #define AR5K_PHY_CCKTXCTL_JAPAN 0x00000010 |
2531 | #define AR5K_PHY_CCKTXCTL_SCRAMBLER_DIS 0x00000001 | 2531 | #define AR5K_PHY_CCKTXCTL_SCRAMBLER_DIS 0x00000001 |
2532 | #define AR5K_PHY_CCKTXCTK_DAC_SCALE 0x00000004 | 2532 | #define AR5K_PHY_CCKTXCTK_DAC_SCALE 0x00000004 |
2533 | 2533 | ||
2534 | /* | 2534 | /* |
2535 | * PHY CCK Cross-correlator Barker RSSI threshold register [5212+] | 2535 | * PHY CCK Cross-correlator Barker RSSI threshold register [5212+] |
2536 | */ | 2536 | */ |
2537 | #define AR5K_PHY_CCK_CROSSCORR 0xa208 | 2537 | #define AR5K_PHY_CCK_CROSSCORR 0xa208 |
2538 | #define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR 0x0000003f | 2538 | #define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR 0x0000003f |
2539 | #define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR_S 0 | 2539 | #define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR_S 0 |
2540 | 2540 | ||
2541 | /* Same address is used for antenna diversity activation */ | 2541 | /* Same address is used for antenna diversity activation */ |
2542 | #define AR5K_PHY_FAST_ANT_DIV 0xa208 | 2542 | #define AR5K_PHY_FAST_ANT_DIV 0xa208 |
2543 | #define AR5K_PHY_FAST_ANT_DIV_EN 0x00002000 | 2543 | #define AR5K_PHY_FAST_ANT_DIV_EN 0x00002000 |
2544 | 2544 | ||
2545 | /* | 2545 | /* |
2546 | * PHY 2GHz gain register [5111+] | 2546 | * PHY 2GHz gain register [5111+] |
2547 | */ | 2547 | */ |
2548 | #define AR5K_PHY_GAIN_2GHZ 0xa20c | 2548 | #define AR5K_PHY_GAIN_2GHZ 0xa20c |
2549 | #define AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX 0x00fc0000 | 2549 | #define AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX 0x00fc0000 |
2550 | #define AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX_S 18 | 2550 | #define AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX_S 18 |
2551 | #define AR5K_PHY_GAIN_2GHZ_INI_5111 0x6480416c | 2551 | #define AR5K_PHY_GAIN_2GHZ_INI_5111 0x6480416c |
2552 | 2552 | ||
2553 | #define AR5K_PHY_CCK_RX_CTL_4 0xa21c | 2553 | #define AR5K_PHY_CCK_RX_CTL_4 0xa21c |
2554 | #define AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT 0x01f80000 | 2554 | #define AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT 0x01f80000 |
2555 | #define AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT_S 19 | 2555 | #define AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT_S 19 |
2556 | 2556 | ||
2557 | #define AR5K_PHY_DAG_CCK_CTL 0xa228 | 2557 | #define AR5K_PHY_DAG_CCK_CTL 0xa228 |
2558 | #define AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR 0x00000200 | 2558 | #define AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR 0x00000200 |
2559 | #define AR5K_PHY_DAG_CCK_CTL_RSSI_THR 0x0001fc00 | 2559 | #define AR5K_PHY_DAG_CCK_CTL_RSSI_THR 0x0001fc00 |
2560 | #define AR5K_PHY_DAG_CCK_CTL_RSSI_THR_S 10 | 2560 | #define AR5K_PHY_DAG_CCK_CTL_RSSI_THR_S 10 |
2561 | 2561 | ||
2562 | #define AR5K_PHY_FAST_ADC 0xa24c | 2562 | #define AR5K_PHY_FAST_ADC 0xa24c |
2563 | 2563 | ||
2564 | #define AR5K_PHY_BLUETOOTH 0xa254 | 2564 | #define AR5K_PHY_BLUETOOTH 0xa254 |
2565 | 2565 | ||
2566 | /* | 2566 | /* |
2567 | * Transmit Power Control register | 2567 | * Transmit Power Control register |
2568 | * [2413+] | 2568 | * [2413+] |
2569 | */ | 2569 | */ |
2570 | #define AR5K_PHY_TPC_RG1 0xa258 | 2570 | #define AR5K_PHY_TPC_RG1 0xa258 |
2571 | #define AR5K_PHY_TPC_RG1_NUM_PD_GAIN 0x0000c000 | 2571 | #define AR5K_PHY_TPC_RG1_NUM_PD_GAIN 0x0000c000 |
2572 | #define AR5K_PHY_TPC_RG1_NUM_PD_GAIN_S 14 | 2572 | #define AR5K_PHY_TPC_RG1_NUM_PD_GAIN_S 14 |
2573 | #define AR5K_PHY_TPC_RG1_PDGAIN_1 0x00030000 | 2573 | #define AR5K_PHY_TPC_RG1_PDGAIN_1 0x00030000 |
2574 | #define AR5K_PHY_TPC_RG1_PDGAIN_1_S 16 | 2574 | #define AR5K_PHY_TPC_RG1_PDGAIN_1_S 16 |
2575 | #define AR5K_PHY_TPC_RG1_PDGAIN_2 0x000c0000 | 2575 | #define AR5K_PHY_TPC_RG1_PDGAIN_2 0x000c0000 |
2576 | #define AR5K_PHY_TPC_RG1_PDGAIN_2_S 18 | 2576 | #define AR5K_PHY_TPC_RG1_PDGAIN_2_S 18 |
2577 | #define AR5K_PHY_TPC_RG1_PDGAIN_3 0x00300000 | 2577 | #define AR5K_PHY_TPC_RG1_PDGAIN_3 0x00300000 |
2578 | #define AR5K_PHY_TPC_RG1_PDGAIN_3_S 20 | 2578 | #define AR5K_PHY_TPC_RG1_PDGAIN_3_S 20 |
2579 | 2579 | ||
2580 | #define AR5K_PHY_TPC_RG5 0xa26C | 2580 | #define AR5K_PHY_TPC_RG5 0xa26C |
2581 | #define AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP 0x0000000F | 2581 | #define AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP 0x0000000F |
2582 | #define AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP_S 0 | 2582 | #define AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP_S 0 |
2583 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1 0x000003F0 | 2583 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1 0x000003F0 |
2584 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1_S 4 | 2584 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1_S 4 |
2585 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2 0x0000FC00 | 2585 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2 0x0000FC00 |
2586 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2_S 10 | 2586 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2_S 10 |
2587 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3 0x003F0000 | 2587 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3 0x003F0000 |
2588 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3_S 16 | 2588 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3_S 16 |
2589 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4 0x0FC00000 | 2589 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4 0x0FC00000 |
2590 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4_S 22 | 2590 | #define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4_S 22 |
2591 | 2591 | ||
2592 | /* | 2592 | /* |
2593 | * PHY PDADC Tx power table | 2593 | * PHY PDADC Tx power table |
2594 | */ | 2594 | */ |
2595 | #define AR5K_PHY_PDADC_TXPOWER_BASE 0xa280 | 2595 | #define AR5K_PHY_PDADC_TXPOWER_BASE 0xa280 |
2596 | #define AR5K_PHY_PDADC_TXPOWER(_n) (AR5K_PHY_PDADC_TXPOWER_BASE + ((_n) << 2)) | 2596 | #define AR5K_PHY_PDADC_TXPOWER(_n) (AR5K_PHY_PDADC_TXPOWER_BASE + ((_n) << 2)) |
2597 | 2597 |
drivers/net/wireless/atmel.c
1 | /*** -*- linux-c -*- ********************************************************** | 1 | /*** -*- linux-c -*- ********************************************************** |
2 | 2 | ||
3 | Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. | 3 | Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. |
4 | 4 | ||
5 | Copyright 2000-2001 ATMEL Corporation. | 5 | Copyright 2000-2001 ATMEL Corporation. |
6 | Copyright 2003-2004 Simon Kelley. | 6 | Copyright 2003-2004 Simon Kelley. |
7 | 7 | ||
8 | This code was developed from version 2.1.1 of the Atmel drivers, | 8 | This code was developed from version 2.1.1 of the Atmel drivers, |
9 | released by Atmel corp. under the GPL in December 2002. It also | 9 | released by Atmel corp. under the GPL in December 2002. It also |
10 | includes code from the Linux aironet drivers (C) Benjamin Reed, | 10 | includes code from the Linux aironet drivers (C) Benjamin Reed, |
11 | and the Linux PCMCIA package, (C) David Hinds and the Linux wireless | 11 | and the Linux PCMCIA package, (C) David Hinds and the Linux wireless |
12 | extensions, (C) Jean Tourrilhes. | 12 | extensions, (C) Jean Tourrilhes. |
13 | 13 | ||
14 | The firmware module for reading the MAC address of the card comes from | 14 | The firmware module for reading the MAC address of the card comes from |
15 | net.russotto.AtmelMACFW, written by Matthew T. Russotto and copyright | 15 | net.russotto.AtmelMACFW, written by Matthew T. Russotto and copyright |
16 | by him. net.russotto.AtmelMACFW is used under the GPL license version 2. | 16 | by him. net.russotto.AtmelMACFW is used under the GPL license version 2. |
17 | This file contains the module in binary form and, under the terms | 17 | This file contains the module in binary form and, under the terms |
18 | of the GPL, in source form. The source is located at the end of the file. | 18 | of the GPL, in source form. The source is located at the end of the file. |
19 | 19 | ||
20 | This program is free software; you can redistribute it and/or modify | 20 | This program is free software; you can redistribute it and/or modify |
21 | it under the terms of the GNU General Public License as published by | 21 | it under the terms of the GNU General Public License as published by |
22 | the Free Software Foundation; either version 2 of the License, or | 22 | the Free Software Foundation; either version 2 of the License, or |
23 | (at your option) any later version. | 23 | (at your option) any later version. |
24 | 24 | ||
25 | This software is distributed in the hope that it will be useful, | 25 | This software is distributed in the hope that it will be useful, |
26 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 26 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
27 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 27 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
28 | GNU General Public License for more details. | 28 | GNU General Public License for more details. |
29 | 29 | ||
30 | You should have received a copy of the GNU General Public License | 30 | You should have received a copy of the GNU General Public License |
31 | along with Atmel wireless lan drivers; if not, write to the Free Software | 31 | along with Atmel wireless lan drivers; if not, write to the Free Software |
32 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 32 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
33 | 33 | ||
34 | For all queries about this code, please contact the current author, | 34 | For all queries about this code, please contact the current author, |
35 | Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation. | 35 | Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation. |
36 | 36 | ||
37 | Credit is due to HP UK and Cambridge Online Systems Ltd for supplying | 37 | Credit is due to HP UK and Cambridge Online Systems Ltd for supplying |
38 | hardware used during development of this driver. | 38 | hardware used during development of this driver. |
39 | 39 | ||
40 | ******************************************************************************/ | 40 | ******************************************************************************/ |
41 | 41 | ||
42 | #include <linux/init.h> | 42 | #include <linux/init.h> |
43 | 43 | ||
44 | #include <linux/kernel.h> | 44 | #include <linux/kernel.h> |
45 | #include <linux/ptrace.h> | 45 | #include <linux/ptrace.h> |
46 | #include <linux/slab.h> | 46 | #include <linux/slab.h> |
47 | #include <linux/string.h> | 47 | #include <linux/string.h> |
48 | #include <linux/ctype.h> | 48 | #include <linux/ctype.h> |
49 | #include <linux/timer.h> | 49 | #include <linux/timer.h> |
50 | #include <asm/byteorder.h> | 50 | #include <asm/byteorder.h> |
51 | #include <asm/io.h> | 51 | #include <asm/io.h> |
52 | #include <asm/system.h> | 52 | #include <asm/system.h> |
53 | #include <asm/uaccess.h> | 53 | #include <asm/uaccess.h> |
54 | #include <linux/module.h> | 54 | #include <linux/module.h> |
55 | #include <linux/netdevice.h> | 55 | #include <linux/netdevice.h> |
56 | #include <linux/etherdevice.h> | 56 | #include <linux/etherdevice.h> |
57 | #include <linux/skbuff.h> | 57 | #include <linux/skbuff.h> |
58 | #include <linux/if_arp.h> | 58 | #include <linux/if_arp.h> |
59 | #include <linux/ioport.h> | 59 | #include <linux/ioport.h> |
60 | #include <linux/fcntl.h> | 60 | #include <linux/fcntl.h> |
61 | #include <linux/delay.h> | 61 | #include <linux/delay.h> |
62 | #include <linux/wireless.h> | 62 | #include <linux/wireless.h> |
63 | #include <net/iw_handler.h> | 63 | #include <net/iw_handler.h> |
64 | #include <linux/crc32.h> | 64 | #include <linux/crc32.h> |
65 | #include <linux/proc_fs.h> | 65 | #include <linux/proc_fs.h> |
66 | #include <linux/device.h> | 66 | #include <linux/device.h> |
67 | #include <linux/moduleparam.h> | 67 | #include <linux/moduleparam.h> |
68 | #include <linux/firmware.h> | 68 | #include <linux/firmware.h> |
69 | #include <linux/jiffies.h> | 69 | #include <linux/jiffies.h> |
70 | #include <linux/ieee80211.h> | 70 | #include <linux/ieee80211.h> |
71 | #include "atmel.h" | 71 | #include "atmel.h" |
72 | 72 | ||
73 | #define DRIVER_MAJOR 0 | 73 | #define DRIVER_MAJOR 0 |
74 | #define DRIVER_MINOR 98 | 74 | #define DRIVER_MINOR 98 |
75 | 75 | ||
76 | MODULE_AUTHOR("Simon Kelley"); | 76 | MODULE_AUTHOR("Simon Kelley"); |
77 | MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); | 77 | MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); |
78 | MODULE_LICENSE("GPL"); | 78 | MODULE_LICENSE("GPL"); |
79 | MODULE_SUPPORTED_DEVICE("Atmel at76c50x wireless cards"); | 79 | MODULE_SUPPORTED_DEVICE("Atmel at76c50x wireless cards"); |
80 | 80 | ||
81 | /* The name of the firmware file to be loaded | 81 | /* The name of the firmware file to be loaded |
82 | over-rides any automatic selection */ | 82 | over-rides any automatic selection */ |
83 | static char *firmware = NULL; | 83 | static char *firmware = NULL; |
84 | module_param(firmware, charp, 0); | 84 | module_param(firmware, charp, 0); |
85 | 85 | ||
86 | /* table of firmware file names */ | 86 | /* table of firmware file names */ |
87 | static struct { | 87 | static struct { |
88 | AtmelFWType fw_type; | 88 | AtmelFWType fw_type; |
89 | const char *fw_file; | 89 | const char *fw_file; |
90 | const char *fw_file_ext; | 90 | const char *fw_file_ext; |
91 | } fw_table[] = { | 91 | } fw_table[] = { |
92 | { ATMEL_FW_TYPE_502, "atmel_at76c502", "bin" }, | 92 | { ATMEL_FW_TYPE_502, "atmel_at76c502", "bin" }, |
93 | { ATMEL_FW_TYPE_502D, "atmel_at76c502d", "bin" }, | 93 | { ATMEL_FW_TYPE_502D, "atmel_at76c502d", "bin" }, |
94 | { ATMEL_FW_TYPE_502E, "atmel_at76c502e", "bin" }, | 94 | { ATMEL_FW_TYPE_502E, "atmel_at76c502e", "bin" }, |
95 | { ATMEL_FW_TYPE_502_3COM, "atmel_at76c502_3com", "bin" }, | 95 | { ATMEL_FW_TYPE_502_3COM, "atmel_at76c502_3com", "bin" }, |
96 | { ATMEL_FW_TYPE_504, "atmel_at76c504", "bin" }, | 96 | { ATMEL_FW_TYPE_504, "atmel_at76c504", "bin" }, |
97 | { ATMEL_FW_TYPE_504_2958, "atmel_at76c504_2958", "bin" }, | 97 | { ATMEL_FW_TYPE_504_2958, "atmel_at76c504_2958", "bin" }, |
98 | { ATMEL_FW_TYPE_504A_2958, "atmel_at76c504a_2958", "bin" }, | 98 | { ATMEL_FW_TYPE_504A_2958, "atmel_at76c504a_2958", "bin" }, |
99 | { ATMEL_FW_TYPE_506, "atmel_at76c506", "bin" }, | 99 | { ATMEL_FW_TYPE_506, "atmel_at76c506", "bin" }, |
100 | { ATMEL_FW_TYPE_NONE, NULL, NULL } | 100 | { ATMEL_FW_TYPE_NONE, NULL, NULL } |
101 | }; | 101 | }; |
102 | 102 | ||
103 | #define MAX_SSID_LENGTH 32 | 103 | #define MAX_SSID_LENGTH 32 |
104 | #define MGMT_JIFFIES (256 * HZ / 100) | 104 | #define MGMT_JIFFIES (256 * HZ / 100) |
105 | 105 | ||
106 | #define MAX_BSS_ENTRIES 64 | 106 | #define MAX_BSS_ENTRIES 64 |
107 | 107 | ||
108 | /* registers */ | 108 | /* registers */ |
109 | #define GCR 0x00 /* (SIR0) General Configuration Register */ | 109 | #define GCR 0x00 /* (SIR0) General Configuration Register */ |
110 | #define BSR 0x02 /* (SIR1) Bank Switching Select Register */ | 110 | #define BSR 0x02 /* (SIR1) Bank Switching Select Register */ |
111 | #define AR 0x04 | 111 | #define AR 0x04 |
112 | #define DR 0x08 | 112 | #define DR 0x08 |
113 | #define MR1 0x12 /* Mirror Register 1 */ | 113 | #define MR1 0x12 /* Mirror Register 1 */ |
114 | #define MR2 0x14 /* Mirror Register 2 */ | 114 | #define MR2 0x14 /* Mirror Register 2 */ |
115 | #define MR3 0x16 /* Mirror Register 3 */ | 115 | #define MR3 0x16 /* Mirror Register 3 */ |
116 | #define MR4 0x18 /* Mirror Register 4 */ | 116 | #define MR4 0x18 /* Mirror Register 4 */ |
117 | 117 | ||
118 | #define GPR1 0x0c | 118 | #define GPR1 0x0c |
119 | #define GPR2 0x0e | 119 | #define GPR2 0x0e |
120 | #define GPR3 0x10 | 120 | #define GPR3 0x10 |
121 | /* | 121 | /* |
122 | * Constants for the GCR register. | 122 | * Constants for the GCR register. |
123 | */ | 123 | */ |
124 | #define GCR_REMAP 0x0400 /* Remap internal SRAM to 0 */ | 124 | #define GCR_REMAP 0x0400 /* Remap internal SRAM to 0 */ |
125 | #define GCR_SWRES 0x0080 /* BIU reset (ARM and PAI are NOT reset) */ | 125 | #define GCR_SWRES 0x0080 /* BIU reset (ARM and PAI are NOT reset) */ |
126 | #define GCR_CORES 0x0060 /* Core Reset (ARM and PAI are reset) */ | 126 | #define GCR_CORES 0x0060 /* Core Reset (ARM and PAI are reset) */ |
127 | #define GCR_ENINT 0x0002 /* Enable Interrupts */ | 127 | #define GCR_ENINT 0x0002 /* Enable Interrupts */ |
128 | #define GCR_ACKINT 0x0008 /* Acknowledge Interrupts */ | 128 | #define GCR_ACKINT 0x0008 /* Acknowledge Interrupts */ |
129 | 129 | ||
130 | #define BSS_SRAM 0x0200 /* AMBA module selection --> SRAM */ | 130 | #define BSS_SRAM 0x0200 /* AMBA module selection --> SRAM */ |
131 | #define BSS_IRAM 0x0100 /* AMBA module selection --> IRAM */ | 131 | #define BSS_IRAM 0x0100 /* AMBA module selection --> IRAM */ |
132 | /* | 132 | /* |
133 | *Constants for the MR registers. | 133 | *Constants for the MR registers. |
134 | */ | 134 | */ |
135 | #define MAC_INIT_COMPLETE 0x0001 /* MAC init has been completed */ | 135 | #define MAC_INIT_COMPLETE 0x0001 /* MAC init has been completed */ |
136 | #define MAC_BOOT_COMPLETE 0x0010 /* MAC boot has been completed */ | 136 | #define MAC_BOOT_COMPLETE 0x0010 /* MAC boot has been completed */ |
137 | #define MAC_INIT_OK 0x0002 /* MAC boot has been completed */ | 137 | #define MAC_INIT_OK 0x0002 /* MAC boot has been completed */ |
138 | 138 | ||
139 | #define MIB_MAX_DATA_BYTES 212 | 139 | #define MIB_MAX_DATA_BYTES 212 |
140 | #define MIB_HEADER_SIZE 4 /* first four fields */ | 140 | #define MIB_HEADER_SIZE 4 /* first four fields */ |
141 | 141 | ||
142 | struct get_set_mib { | 142 | struct get_set_mib { |
143 | u8 type; | 143 | u8 type; |
144 | u8 size; | 144 | u8 size; |
145 | u8 index; | 145 | u8 index; |
146 | u8 reserved; | 146 | u8 reserved; |
147 | u8 data[MIB_MAX_DATA_BYTES]; | 147 | u8 data[MIB_MAX_DATA_BYTES]; |
148 | }; | 148 | }; |
149 | 149 | ||
150 | struct rx_desc { | 150 | struct rx_desc { |
151 | u32 Next; | 151 | u32 Next; |
152 | u16 MsduPos; | 152 | u16 MsduPos; |
153 | u16 MsduSize; | 153 | u16 MsduSize; |
154 | 154 | ||
155 | u8 State; | 155 | u8 State; |
156 | u8 Status; | 156 | u8 Status; |
157 | u8 Rate; | 157 | u8 Rate; |
158 | u8 Rssi; | 158 | u8 Rssi; |
159 | u8 LinkQuality; | 159 | u8 LinkQuality; |
160 | u8 PreambleType; | 160 | u8 PreambleType; |
161 | u16 Duration; | 161 | u16 Duration; |
162 | u32 RxTime; | 162 | u32 RxTime; |
163 | }; | 163 | }; |
164 | 164 | ||
165 | #define RX_DESC_FLAG_VALID 0x80 | 165 | #define RX_DESC_FLAG_VALID 0x80 |
166 | #define RX_DESC_FLAG_CONSUMED 0x40 | 166 | #define RX_DESC_FLAG_CONSUMED 0x40 |
167 | #define RX_DESC_FLAG_IDLE 0x00 | 167 | #define RX_DESC_FLAG_IDLE 0x00 |
168 | 168 | ||
169 | #define RX_STATUS_SUCCESS 0x00 | 169 | #define RX_STATUS_SUCCESS 0x00 |
170 | 170 | ||
171 | #define RX_DESC_MSDU_POS_OFFSET 4 | 171 | #define RX_DESC_MSDU_POS_OFFSET 4 |
172 | #define RX_DESC_MSDU_SIZE_OFFSET 6 | 172 | #define RX_DESC_MSDU_SIZE_OFFSET 6 |
173 | #define RX_DESC_FLAGS_OFFSET 8 | 173 | #define RX_DESC_FLAGS_OFFSET 8 |
174 | #define RX_DESC_STATUS_OFFSET 9 | 174 | #define RX_DESC_STATUS_OFFSET 9 |
175 | #define RX_DESC_RSSI_OFFSET 11 | 175 | #define RX_DESC_RSSI_OFFSET 11 |
176 | #define RX_DESC_LINK_QUALITY_OFFSET 12 | 176 | #define RX_DESC_LINK_QUALITY_OFFSET 12 |
177 | #define RX_DESC_PREAMBLE_TYPE_OFFSET 13 | 177 | #define RX_DESC_PREAMBLE_TYPE_OFFSET 13 |
178 | #define RX_DESC_DURATION_OFFSET 14 | 178 | #define RX_DESC_DURATION_OFFSET 14 |
179 | #define RX_DESC_RX_TIME_OFFSET 16 | 179 | #define RX_DESC_RX_TIME_OFFSET 16 |
180 | 180 | ||
181 | struct tx_desc { | 181 | struct tx_desc { |
182 | u32 NextDescriptor; | 182 | u32 NextDescriptor; |
183 | u16 TxStartOfFrame; | 183 | u16 TxStartOfFrame; |
184 | u16 TxLength; | 184 | u16 TxLength; |
185 | 185 | ||
186 | u8 TxState; | 186 | u8 TxState; |
187 | u8 TxStatus; | 187 | u8 TxStatus; |
188 | u8 RetryCount; | 188 | u8 RetryCount; |
189 | 189 | ||
190 | u8 TxRate; | 190 | u8 TxRate; |
191 | 191 | ||
192 | u8 KeyIndex; | 192 | u8 KeyIndex; |
193 | u8 ChiperType; | 193 | u8 ChiperType; |
194 | u8 ChipreLength; | 194 | u8 ChipreLength; |
195 | u8 Reserved1; | 195 | u8 Reserved1; |
196 | 196 | ||
197 | u8 Reserved; | 197 | u8 Reserved; |
198 | u8 PacketType; | 198 | u8 PacketType; |
199 | u16 HostTxLength; | 199 | u16 HostTxLength; |
200 | }; | 200 | }; |
201 | 201 | ||
202 | #define TX_DESC_NEXT_OFFSET 0 | 202 | #define TX_DESC_NEXT_OFFSET 0 |
203 | #define TX_DESC_POS_OFFSET 4 | 203 | #define TX_DESC_POS_OFFSET 4 |
204 | #define TX_DESC_SIZE_OFFSET 6 | 204 | #define TX_DESC_SIZE_OFFSET 6 |
205 | #define TX_DESC_FLAGS_OFFSET 8 | 205 | #define TX_DESC_FLAGS_OFFSET 8 |
206 | #define TX_DESC_STATUS_OFFSET 9 | 206 | #define TX_DESC_STATUS_OFFSET 9 |
207 | #define TX_DESC_RETRY_OFFSET 10 | 207 | #define TX_DESC_RETRY_OFFSET 10 |
208 | #define TX_DESC_RATE_OFFSET 11 | 208 | #define TX_DESC_RATE_OFFSET 11 |
209 | #define TX_DESC_KEY_INDEX_OFFSET 12 | 209 | #define TX_DESC_KEY_INDEX_OFFSET 12 |
210 | #define TX_DESC_CIPHER_TYPE_OFFSET 13 | 210 | #define TX_DESC_CIPHER_TYPE_OFFSET 13 |
211 | #define TX_DESC_CIPHER_LENGTH_OFFSET 14 | 211 | #define TX_DESC_CIPHER_LENGTH_OFFSET 14 |
212 | #define TX_DESC_PACKET_TYPE_OFFSET 17 | 212 | #define TX_DESC_PACKET_TYPE_OFFSET 17 |
213 | #define TX_DESC_HOST_LENGTH_OFFSET 18 | 213 | #define TX_DESC_HOST_LENGTH_OFFSET 18 |
214 | 214 | ||
215 | /* | 215 | /* |
216 | * Host-MAC interface | 216 | * Host-MAC interface |
217 | */ | 217 | */ |
218 | 218 | ||
219 | #define TX_STATUS_SUCCESS 0x00 | 219 | #define TX_STATUS_SUCCESS 0x00 |
220 | 220 | ||
221 | #define TX_FIRM_OWN 0x80 | 221 | #define TX_FIRM_OWN 0x80 |
222 | #define TX_DONE 0x40 | 222 | #define TX_DONE 0x40 |
223 | 223 | ||
224 | #define TX_ERROR 0x01 | 224 | #define TX_ERROR 0x01 |
225 | 225 | ||
226 | #define TX_PACKET_TYPE_DATA 0x01 | 226 | #define TX_PACKET_TYPE_DATA 0x01 |
227 | #define TX_PACKET_TYPE_MGMT 0x02 | 227 | #define TX_PACKET_TYPE_MGMT 0x02 |
228 | 228 | ||
229 | #define ISR_EMPTY 0x00 /* no bits set in ISR */ | 229 | #define ISR_EMPTY 0x00 /* no bits set in ISR */ |
230 | #define ISR_TxCOMPLETE 0x01 /* packet transmitted */ | 230 | #define ISR_TxCOMPLETE 0x01 /* packet transmitted */ |
231 | #define ISR_RxCOMPLETE 0x02 /* packet received */ | 231 | #define ISR_RxCOMPLETE 0x02 /* packet received */ |
232 | #define ISR_RxFRAMELOST 0x04 /* Rx Frame lost */ | 232 | #define ISR_RxFRAMELOST 0x04 /* Rx Frame lost */ |
233 | #define ISR_FATAL_ERROR 0x08 /* Fatal error */ | 233 | #define ISR_FATAL_ERROR 0x08 /* Fatal error */ |
234 | #define ISR_COMMAND_COMPLETE 0x10 /* command completed */ | 234 | #define ISR_COMMAND_COMPLETE 0x10 /* command completed */ |
235 | #define ISR_OUT_OF_RANGE 0x20 /* command completed */ | 235 | #define ISR_OUT_OF_RANGE 0x20 /* command completed */ |
236 | #define ISR_IBSS_MERGE 0x40 /* (4.1.2.30): IBSS merge */ | 236 | #define ISR_IBSS_MERGE 0x40 /* (4.1.2.30): IBSS merge */ |
237 | #define ISR_GENERIC_IRQ 0x80 | 237 | #define ISR_GENERIC_IRQ 0x80 |
238 | 238 | ||
239 | #define Local_Mib_Type 0x01 | 239 | #define Local_Mib_Type 0x01 |
240 | #define Mac_Address_Mib_Type 0x02 | 240 | #define Mac_Address_Mib_Type 0x02 |
241 | #define Mac_Mib_Type 0x03 | 241 | #define Mac_Mib_Type 0x03 |
242 | #define Statistics_Mib_Type 0x04 | 242 | #define Statistics_Mib_Type 0x04 |
243 | #define Mac_Mgmt_Mib_Type 0x05 | 243 | #define Mac_Mgmt_Mib_Type 0x05 |
244 | #define Mac_Wep_Mib_Type 0x06 | 244 | #define Mac_Wep_Mib_Type 0x06 |
245 | #define Phy_Mib_Type 0x07 | 245 | #define Phy_Mib_Type 0x07 |
246 | #define Multi_Domain_MIB 0x08 | 246 | #define Multi_Domain_MIB 0x08 |
247 | 247 | ||
248 | #define MAC_MGMT_MIB_CUR_BSSID_POS 14 | 248 | #define MAC_MGMT_MIB_CUR_BSSID_POS 14 |
249 | #define MAC_MIB_FRAG_THRESHOLD_POS 8 | 249 | #define MAC_MIB_FRAG_THRESHOLD_POS 8 |
250 | #define MAC_MIB_RTS_THRESHOLD_POS 10 | 250 | #define MAC_MIB_RTS_THRESHOLD_POS 10 |
251 | #define MAC_MIB_SHORT_RETRY_POS 16 | 251 | #define MAC_MIB_SHORT_RETRY_POS 16 |
252 | #define MAC_MIB_LONG_RETRY_POS 17 | 252 | #define MAC_MIB_LONG_RETRY_POS 17 |
253 | #define MAC_MIB_SHORT_RETRY_LIMIT_POS 16 | 253 | #define MAC_MIB_SHORT_RETRY_LIMIT_POS 16 |
254 | #define MAC_MGMT_MIB_BEACON_PER_POS 0 | 254 | #define MAC_MGMT_MIB_BEACON_PER_POS 0 |
255 | #define MAC_MGMT_MIB_STATION_ID_POS 6 | 255 | #define MAC_MGMT_MIB_STATION_ID_POS 6 |
256 | #define MAC_MGMT_MIB_CUR_PRIVACY_POS 11 | 256 | #define MAC_MGMT_MIB_CUR_PRIVACY_POS 11 |
257 | #define MAC_MGMT_MIB_CUR_BSSID_POS 14 | 257 | #define MAC_MGMT_MIB_CUR_BSSID_POS 14 |
258 | #define MAC_MGMT_MIB_PS_MODE_POS 53 | 258 | #define MAC_MGMT_MIB_PS_MODE_POS 53 |
259 | #define MAC_MGMT_MIB_LISTEN_INTERVAL_POS 54 | 259 | #define MAC_MGMT_MIB_LISTEN_INTERVAL_POS 54 |
260 | #define MAC_MGMT_MIB_MULTI_DOMAIN_IMPLEMENTED 56 | 260 | #define MAC_MGMT_MIB_MULTI_DOMAIN_IMPLEMENTED 56 |
261 | #define MAC_MGMT_MIB_MULTI_DOMAIN_ENABLED 57 | 261 | #define MAC_MGMT_MIB_MULTI_DOMAIN_ENABLED 57 |
262 | #define PHY_MIB_CHANNEL_POS 14 | 262 | #define PHY_MIB_CHANNEL_POS 14 |
263 | #define PHY_MIB_RATE_SET_POS 20 | 263 | #define PHY_MIB_RATE_SET_POS 20 |
264 | #define PHY_MIB_REG_DOMAIN_POS 26 | 264 | #define PHY_MIB_REG_DOMAIN_POS 26 |
265 | #define LOCAL_MIB_AUTO_TX_RATE_POS 3 | 265 | #define LOCAL_MIB_AUTO_TX_RATE_POS 3 |
266 | #define LOCAL_MIB_SSID_SIZE 5 | 266 | #define LOCAL_MIB_SSID_SIZE 5 |
267 | #define LOCAL_MIB_TX_PROMISCUOUS_POS 6 | 267 | #define LOCAL_MIB_TX_PROMISCUOUS_POS 6 |
268 | #define LOCAL_MIB_TX_MGMT_RATE_POS 7 | 268 | #define LOCAL_MIB_TX_MGMT_RATE_POS 7 |
269 | #define LOCAL_MIB_TX_CONTROL_RATE_POS 8 | 269 | #define LOCAL_MIB_TX_CONTROL_RATE_POS 8 |
270 | #define LOCAL_MIB_PREAMBLE_TYPE 9 | 270 | #define LOCAL_MIB_PREAMBLE_TYPE 9 |
271 | #define MAC_ADDR_MIB_MAC_ADDR_POS 0 | 271 | #define MAC_ADDR_MIB_MAC_ADDR_POS 0 |
272 | 272 | ||
273 | #define CMD_Set_MIB_Vars 0x01 | 273 | #define CMD_Set_MIB_Vars 0x01 |
274 | #define CMD_Get_MIB_Vars 0x02 | 274 | #define CMD_Get_MIB_Vars 0x02 |
275 | #define CMD_Scan 0x03 | 275 | #define CMD_Scan 0x03 |
276 | #define CMD_Join 0x04 | 276 | #define CMD_Join 0x04 |
277 | #define CMD_Start 0x05 | 277 | #define CMD_Start 0x05 |
278 | #define CMD_EnableRadio 0x06 | 278 | #define CMD_EnableRadio 0x06 |
279 | #define CMD_DisableRadio 0x07 | 279 | #define CMD_DisableRadio 0x07 |
280 | #define CMD_SiteSurvey 0x0B | 280 | #define CMD_SiteSurvey 0x0B |
281 | 281 | ||
282 | #define CMD_STATUS_IDLE 0x00 | 282 | #define CMD_STATUS_IDLE 0x00 |
283 | #define CMD_STATUS_COMPLETE 0x01 | 283 | #define CMD_STATUS_COMPLETE 0x01 |
284 | #define CMD_STATUS_UNKNOWN 0x02 | 284 | #define CMD_STATUS_UNKNOWN 0x02 |
285 | #define CMD_STATUS_INVALID_PARAMETER 0x03 | 285 | #define CMD_STATUS_INVALID_PARAMETER 0x03 |
286 | #define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04 | 286 | #define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04 |
287 | #define CMD_STATUS_TIME_OUT 0x07 | 287 | #define CMD_STATUS_TIME_OUT 0x07 |
288 | #define CMD_STATUS_IN_PROGRESS 0x08 | 288 | #define CMD_STATUS_IN_PROGRESS 0x08 |
289 | #define CMD_STATUS_REJECTED_RADIO_OFF 0x09 | 289 | #define CMD_STATUS_REJECTED_RADIO_OFF 0x09 |
290 | #define CMD_STATUS_HOST_ERROR 0xFF | 290 | #define CMD_STATUS_HOST_ERROR 0xFF |
291 | #define CMD_STATUS_BUSY 0xFE | 291 | #define CMD_STATUS_BUSY 0xFE |
292 | 292 | ||
293 | #define CMD_BLOCK_COMMAND_OFFSET 0 | 293 | #define CMD_BLOCK_COMMAND_OFFSET 0 |
294 | #define CMD_BLOCK_STATUS_OFFSET 1 | 294 | #define CMD_BLOCK_STATUS_OFFSET 1 |
295 | #define CMD_BLOCK_PARAMETERS_OFFSET 4 | 295 | #define CMD_BLOCK_PARAMETERS_OFFSET 4 |
296 | 296 | ||
297 | #define SCAN_OPTIONS_SITE_SURVEY 0x80 | 297 | #define SCAN_OPTIONS_SITE_SURVEY 0x80 |
298 | 298 | ||
299 | #define MGMT_FRAME_BODY_OFFSET 24 | 299 | #define MGMT_FRAME_BODY_OFFSET 24 |
300 | #define MAX_AUTHENTICATION_RETRIES 3 | 300 | #define MAX_AUTHENTICATION_RETRIES 3 |
301 | #define MAX_ASSOCIATION_RETRIES 3 | 301 | #define MAX_ASSOCIATION_RETRIES 3 |
302 | 302 | ||
303 | #define AUTHENTICATION_RESPONSE_TIME_OUT 1000 | 303 | #define AUTHENTICATION_RESPONSE_TIME_OUT 1000 |
304 | 304 | ||
305 | #define MAX_WIRELESS_BODY 2316 /* mtu is 2312, CRC is 4 */ | 305 | #define MAX_WIRELESS_BODY 2316 /* mtu is 2312, CRC is 4 */ |
306 | #define LOOP_RETRY_LIMIT 500000 | 306 | #define LOOP_RETRY_LIMIT 500000 |
307 | 307 | ||
308 | #define ACTIVE_MODE 1 | 308 | #define ACTIVE_MODE 1 |
309 | #define PS_MODE 2 | 309 | #define PS_MODE 2 |
310 | 310 | ||
311 | #define MAX_ENCRYPTION_KEYS 4 | 311 | #define MAX_ENCRYPTION_KEYS 4 |
312 | #define MAX_ENCRYPTION_KEY_SIZE 40 | 312 | #define MAX_ENCRYPTION_KEY_SIZE 40 |
313 | 313 | ||
314 | /* | 314 | /* |
315 | * 802.11 related definitions | 315 | * 802.11 related definitions |
316 | */ | 316 | */ |
317 | 317 | ||
318 | /* | 318 | /* |
319 | * Regulatory Domains | 319 | * Regulatory Domains |
320 | */ | 320 | */ |
321 | 321 | ||
322 | #define REG_DOMAIN_FCC 0x10 /* Channels 1-11 USA */ | 322 | #define REG_DOMAIN_FCC 0x10 /* Channels 1-11 USA */ |
323 | #define REG_DOMAIN_DOC 0x20 /* Channel 1-11 Canada */ | 323 | #define REG_DOMAIN_DOC 0x20 /* Channel 1-11 Canada */ |
324 | #define REG_DOMAIN_ETSI 0x30 /* Channel 1-13 Europe (ex Spain/France) */ | 324 | #define REG_DOMAIN_ETSI 0x30 /* Channel 1-13 Europe (ex Spain/France) */ |
325 | #define REG_DOMAIN_SPAIN 0x31 /* Channel 10-11 Spain */ | 325 | #define REG_DOMAIN_SPAIN 0x31 /* Channel 10-11 Spain */ |
326 | #define REG_DOMAIN_FRANCE 0x32 /* Channel 10-13 France */ | 326 | #define REG_DOMAIN_FRANCE 0x32 /* Channel 10-13 France */ |
327 | #define REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */ | 327 | #define REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */ |
328 | #define REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan(MKK1) */ | 328 | #define REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan(MKK1) */ |
329 | #define REG_DOMAIN_ISRAEL 0x50 /* Channel 3-9 ISRAEL */ | 329 | #define REG_DOMAIN_ISRAEL 0x50 /* Channel 3-9 ISRAEL */ |
330 | 330 | ||
331 | #define BSS_TYPE_AD_HOC 1 | 331 | #define BSS_TYPE_AD_HOC 1 |
332 | #define BSS_TYPE_INFRASTRUCTURE 2 | 332 | #define BSS_TYPE_INFRASTRUCTURE 2 |
333 | 333 | ||
334 | #define SCAN_TYPE_ACTIVE 0 | 334 | #define SCAN_TYPE_ACTIVE 0 |
335 | #define SCAN_TYPE_PASSIVE 1 | 335 | #define SCAN_TYPE_PASSIVE 1 |
336 | 336 | ||
337 | #define LONG_PREAMBLE 0 | 337 | #define LONG_PREAMBLE 0 |
338 | #define SHORT_PREAMBLE 1 | 338 | #define SHORT_PREAMBLE 1 |
339 | #define AUTO_PREAMBLE 2 | 339 | #define AUTO_PREAMBLE 2 |
340 | 340 | ||
341 | #define DATA_FRAME_WS_HEADER_SIZE 30 | 341 | #define DATA_FRAME_WS_HEADER_SIZE 30 |
342 | 342 | ||
343 | /* promiscuous mode control */ | 343 | /* promiscuous mode control */ |
344 | #define PROM_MODE_OFF 0x0 | 344 | #define PROM_MODE_OFF 0x0 |
345 | #define PROM_MODE_UNKNOWN 0x1 | 345 | #define PROM_MODE_UNKNOWN 0x1 |
346 | #define PROM_MODE_CRC_FAILED 0x2 | 346 | #define PROM_MODE_CRC_FAILED 0x2 |
347 | #define PROM_MODE_DUPLICATED 0x4 | 347 | #define PROM_MODE_DUPLICATED 0x4 |
348 | #define PROM_MODE_MGMT 0x8 | 348 | #define PROM_MODE_MGMT 0x8 |
349 | #define PROM_MODE_CTRL 0x10 | 349 | #define PROM_MODE_CTRL 0x10 |
350 | #define PROM_MODE_BAD_PROTOCOL 0x20 | 350 | #define PROM_MODE_BAD_PROTOCOL 0x20 |
351 | 351 | ||
352 | #define IFACE_INT_STATUS_OFFSET 0 | 352 | #define IFACE_INT_STATUS_OFFSET 0 |
353 | #define IFACE_INT_MASK_OFFSET 1 | 353 | #define IFACE_INT_MASK_OFFSET 1 |
354 | #define IFACE_LOCKOUT_HOST_OFFSET 2 | 354 | #define IFACE_LOCKOUT_HOST_OFFSET 2 |
355 | #define IFACE_LOCKOUT_MAC_OFFSET 3 | 355 | #define IFACE_LOCKOUT_MAC_OFFSET 3 |
356 | #define IFACE_FUNC_CTRL_OFFSET 28 | 356 | #define IFACE_FUNC_CTRL_OFFSET 28 |
357 | #define IFACE_MAC_STAT_OFFSET 30 | 357 | #define IFACE_MAC_STAT_OFFSET 30 |
358 | #define IFACE_GENERIC_INT_TYPE_OFFSET 32 | 358 | #define IFACE_GENERIC_INT_TYPE_OFFSET 32 |
359 | 359 | ||
360 | #define CIPHER_SUITE_NONE 0 | 360 | #define CIPHER_SUITE_NONE 0 |
361 | #define CIPHER_SUITE_WEP_64 1 | 361 | #define CIPHER_SUITE_WEP_64 1 |
362 | #define CIPHER_SUITE_TKIP 2 | 362 | #define CIPHER_SUITE_TKIP 2 |
363 | #define CIPHER_SUITE_AES 3 | 363 | #define CIPHER_SUITE_AES 3 |
364 | #define CIPHER_SUITE_CCX 4 | 364 | #define CIPHER_SUITE_CCX 4 |
365 | #define CIPHER_SUITE_WEP_128 5 | 365 | #define CIPHER_SUITE_WEP_128 5 |
366 | 366 | ||
367 | /* | 367 | /* |
368 | * IFACE MACROS & definitions | 368 | * IFACE MACROS & definitions |
369 | */ | 369 | */ |
370 | 370 | ||
371 | /* | 371 | /* |
372 | * FuncCtrl field: | 372 | * FuncCtrl field: |
373 | */ | 373 | */ |
374 | #define FUNC_CTRL_TxENABLE 0x10 | 374 | #define FUNC_CTRL_TxENABLE 0x10 |
375 | #define FUNC_CTRL_RxENABLE 0x20 | 375 | #define FUNC_CTRL_RxENABLE 0x20 |
376 | #define FUNC_CTRL_INIT_COMPLETE 0x01 | 376 | #define FUNC_CTRL_INIT_COMPLETE 0x01 |
377 | 377 | ||
378 | /* A stub firmware image which reads the MAC address from NVRAM on the card. | 378 | /* A stub firmware image which reads the MAC address from NVRAM on the card. |
379 | For copyright information and source see the end of this file. */ | 379 | For copyright information and source see the end of this file. */ |
380 | static u8 mac_reader[] = { | 380 | static u8 mac_reader[] = { |
381 | 0x06, 0x00, 0x00, 0xea, 0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea, | 381 | 0x06, 0x00, 0x00, 0xea, 0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea, |
382 | 0x01, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, | 382 | 0x01, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, |
383 | 0xd3, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x0e, 0x04, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, | 383 | 0xd3, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x0e, 0x04, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, |
384 | 0x81, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x81, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x1c, 0x10, 0x90, 0xe5, | 384 | 0x81, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x81, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x1c, 0x10, 0x90, 0xe5, |
385 | 0x10, 0x10, 0xc1, 0xe3, 0x1c, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x08, 0x10, 0x80, 0xe5, | 385 | 0x10, 0x10, 0xc1, 0xe3, 0x1c, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x08, 0x10, 0x80, 0xe5, |
386 | 0x02, 0x03, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0xb0, 0x10, 0xc0, 0xe1, 0xb4, 0x10, 0xc0, 0xe1, | 386 | 0x02, 0x03, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0xb0, 0x10, 0xc0, 0xe1, 0xb4, 0x10, 0xc0, 0xe1, |
387 | 0xb8, 0x10, 0xc0, 0xe1, 0xbc, 0x10, 0xc0, 0xe1, 0x56, 0xdc, 0xa0, 0xe3, 0x21, 0x00, 0x00, 0xeb, | 387 | 0xb8, 0x10, 0xc0, 0xe1, 0xbc, 0x10, 0xc0, 0xe1, 0x56, 0xdc, 0xa0, 0xe3, 0x21, 0x00, 0x00, 0xeb, |
388 | 0x0a, 0x00, 0xa0, 0xe3, 0x1a, 0x00, 0x00, 0xeb, 0x10, 0x00, 0x00, 0xeb, 0x07, 0x00, 0x00, 0xeb, | 388 | 0x0a, 0x00, 0xa0, 0xe3, 0x1a, 0x00, 0x00, 0xeb, 0x10, 0x00, 0x00, 0xeb, 0x07, 0x00, 0x00, 0xeb, |
389 | 0x02, 0x03, 0xa0, 0xe3, 0x02, 0x14, 0xa0, 0xe3, 0xb4, 0x10, 0xc0, 0xe1, 0x4c, 0x10, 0x9f, 0xe5, | 389 | 0x02, 0x03, 0xa0, 0xe3, 0x02, 0x14, 0xa0, 0xe3, 0xb4, 0x10, 0xc0, 0xe1, 0x4c, 0x10, 0x9f, 0xe5, |
390 | 0xbc, 0x10, 0xc0, 0xe1, 0x10, 0x10, 0xa0, 0xe3, 0xb8, 0x10, 0xc0, 0xe1, 0xfe, 0xff, 0xff, 0xea, | 390 | 0xbc, 0x10, 0xc0, 0xe1, 0x10, 0x10, 0xa0, 0xe3, 0xb8, 0x10, 0xc0, 0xe1, 0xfe, 0xff, 0xff, 0xea, |
391 | 0x00, 0x40, 0x2d, 0xe9, 0x00, 0x20, 0xa0, 0xe3, 0x02, 0x3c, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, | 391 | 0x00, 0x40, 0x2d, 0xe9, 0x00, 0x20, 0xa0, 0xe3, 0x02, 0x3c, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, |
392 | 0x28, 0x00, 0x9f, 0xe5, 0x37, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, | 392 | 0x28, 0x00, 0x9f, 0xe5, 0x37, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, |
393 | 0x00, 0x40, 0x2d, 0xe9, 0x12, 0x2e, 0xa0, 0xe3, 0x06, 0x30, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, | 393 | 0x00, 0x40, 0x2d, 0xe9, 0x12, 0x2e, 0xa0, 0xe3, 0x06, 0x30, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, |
394 | 0x02, 0x04, 0xa0, 0xe3, 0x2f, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, | 394 | 0x02, 0x04, 0xa0, 0xe3, 0x2f, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, |
395 | 0x00, 0x02, 0x00, 0x02, 0x80, 0x01, 0x90, 0xe0, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe2, | 395 | 0x00, 0x02, 0x00, 0x02, 0x80, 0x01, 0x90, 0xe0, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe2, |
396 | 0xfc, 0xff, 0xff, 0xea, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0x10, 0xa0, 0xe3, 0xf3, 0x06, 0xa0, 0xe3, | 396 | 0xfc, 0xff, 0xff, 0xea, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0x10, 0xa0, 0xe3, 0xf3, 0x06, 0xa0, 0xe3, |
397 | 0x00, 0x10, 0x80, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3, | 397 | 0x00, 0x10, 0x80, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3, |
398 | 0x04, 0x10, 0x80, 0xe5, 0x00, 0x10, 0x80, 0xe5, 0x0e, 0x34, 0xa0, 0xe3, 0x1c, 0x10, 0x93, 0xe5, | 398 | 0x04, 0x10, 0x80, 0xe5, 0x00, 0x10, 0x80, 0xe5, 0x0e, 0x34, 0xa0, 0xe3, 0x1c, 0x10, 0x93, 0xe5, |
399 | 0x02, 0x1a, 0x81, 0xe3, 0x1c, 0x10, 0x83, 0xe5, 0x58, 0x11, 0x9f, 0xe5, 0x30, 0x10, 0x80, 0xe5, | 399 | 0x02, 0x1a, 0x81, 0xe3, 0x1c, 0x10, 0x83, 0xe5, 0x58, 0x11, 0x9f, 0xe5, 0x30, 0x10, 0x80, 0xe5, |
400 | 0x54, 0x11, 0x9f, 0xe5, 0x34, 0x10, 0x80, 0xe5, 0x38, 0x10, 0x80, 0xe5, 0x3c, 0x10, 0x80, 0xe5, | 400 | 0x54, 0x11, 0x9f, 0xe5, 0x34, 0x10, 0x80, 0xe5, 0x38, 0x10, 0x80, 0xe5, 0x3c, 0x10, 0x80, 0xe5, |
401 | 0x10, 0x10, 0x90, 0xe5, 0x08, 0x00, 0x90, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xf3, 0x16, 0xa0, 0xe3, | 401 | 0x10, 0x10, 0x90, 0xe5, 0x08, 0x00, 0x90, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xf3, 0x16, 0xa0, 0xe3, |
402 | 0x08, 0x00, 0x91, 0xe5, 0x05, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5, 0x10, 0x00, 0x91, 0xe5, | 402 | 0x08, 0x00, 0x91, 0xe5, 0x05, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5, 0x10, 0x00, 0x91, 0xe5, |
403 | 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0xff, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5, | 403 | 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0xff, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5, |
404 | 0x10, 0x00, 0x91, 0xe5, 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5, | 404 | 0x10, 0x00, 0x91, 0xe5, 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5, |
405 | 0x10, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5, | 405 | 0x10, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5, |
406 | 0xff, 0x00, 0x00, 0xe2, 0x1e, 0xff, 0x2f, 0xe1, 0x30, 0x40, 0x2d, 0xe9, 0x00, 0x50, 0xa0, 0xe1, | 406 | 0xff, 0x00, 0x00, 0xe2, 0x1e, 0xff, 0x2f, 0xe1, 0x30, 0x40, 0x2d, 0xe9, 0x00, 0x50, 0xa0, 0xe1, |
407 | 0x03, 0x40, 0xa0, 0xe1, 0xa2, 0x02, 0xa0, 0xe1, 0x08, 0x00, 0x00, 0xe2, 0x03, 0x00, 0x80, 0xe2, | 407 | 0x03, 0x40, 0xa0, 0xe1, 0xa2, 0x02, 0xa0, 0xe1, 0x08, 0x00, 0x00, 0xe2, 0x03, 0x00, 0x80, 0xe2, |
408 | 0xd8, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0xc1, 0xe5, 0x01, 0x20, 0xc1, 0xe5, 0xe2, 0xff, 0xff, 0xeb, | 408 | 0xd8, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0xc1, 0xe5, 0x01, 0x20, 0xc1, 0xe5, 0xe2, 0xff, 0xff, 0xeb, |
409 | 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x1a, 0x14, 0x00, 0xa0, 0xe3, 0xc4, 0xff, 0xff, 0xeb, | 409 | 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x1a, 0x14, 0x00, 0xa0, 0xe3, 0xc4, 0xff, 0xff, 0xeb, |
410 | 0x04, 0x20, 0xa0, 0xe1, 0x05, 0x10, 0xa0, 0xe1, 0x02, 0x00, 0xa0, 0xe3, 0x01, 0x00, 0x00, 0xeb, | 410 | 0x04, 0x20, 0xa0, 0xe1, 0x05, 0x10, 0xa0, 0xe1, 0x02, 0x00, 0xa0, 0xe3, 0x01, 0x00, 0x00, 0xeb, |
411 | 0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x70, 0x40, 0x2d, 0xe9, 0xf3, 0x46, 0xa0, 0xe3, | 411 | 0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x70, 0x40, 0x2d, 0xe9, 0xf3, 0x46, 0xa0, 0xe3, |
412 | 0x00, 0x30, 0xa0, 0xe3, 0x00, 0x00, 0x50, 0xe3, 0x08, 0x00, 0x00, 0x9a, 0x8c, 0x50, 0x9f, 0xe5, | 412 | 0x00, 0x30, 0xa0, 0xe3, 0x00, 0x00, 0x50, 0xe3, 0x08, 0x00, 0x00, 0x9a, 0x8c, 0x50, 0x9f, 0xe5, |
413 | 0x03, 0x60, 0xd5, 0xe7, 0x0c, 0x60, 0x84, 0xe5, 0x10, 0x60, 0x94, 0xe5, 0x02, 0x00, 0x16, 0xe3, | 413 | 0x03, 0x60, 0xd5, 0xe7, 0x0c, 0x60, 0x84, 0xe5, 0x10, 0x60, 0x94, 0xe5, 0x02, 0x00, 0x16, 0xe3, |
414 | 0xfc, 0xff, 0xff, 0x0a, 0x01, 0x30, 0x83, 0xe2, 0x00, 0x00, 0x53, 0xe1, 0xf7, 0xff, 0xff, 0x3a, | 414 | 0xfc, 0xff, 0xff, 0x0a, 0x01, 0x30, 0x83, 0xe2, 0x00, 0x00, 0x53, 0xe1, 0xf7, 0xff, 0xff, 0x3a, |
415 | 0xff, 0x30, 0xa0, 0xe3, 0x0c, 0x30, 0x84, 0xe5, 0x08, 0x00, 0x94, 0xe5, 0x10, 0x00, 0x94, 0xe5, | 415 | 0xff, 0x30, 0xa0, 0xe3, 0x0c, 0x30, 0x84, 0xe5, 0x08, 0x00, 0x94, 0xe5, 0x10, 0x00, 0x94, 0xe5, |
416 | 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x94, 0xe5, 0x00, 0x00, 0xa0, 0xe3, | 416 | 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x94, 0xe5, 0x00, 0x00, 0xa0, 0xe3, |
417 | 0x00, 0x00, 0x52, 0xe3, 0x0b, 0x00, 0x00, 0x9a, 0x10, 0x50, 0x94, 0xe5, 0x02, 0x00, 0x15, 0xe3, | 417 | 0x00, 0x00, 0x52, 0xe3, 0x0b, 0x00, 0x00, 0x9a, 0x10, 0x50, 0x94, 0xe5, 0x02, 0x00, 0x15, 0xe3, |
418 | 0xfc, 0xff, 0xff, 0x0a, 0x0c, 0x30, 0x84, 0xe5, 0x10, 0x50, 0x94, 0xe5, 0x01, 0x00, 0x15, 0xe3, | 418 | 0xfc, 0xff, 0xff, 0x0a, 0x0c, 0x30, 0x84, 0xe5, 0x10, 0x50, 0x94, 0xe5, 0x01, 0x00, 0x15, 0xe3, |
419 | 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x50, 0x94, 0xe5, 0x01, 0x50, 0xc1, 0xe4, 0x01, 0x00, 0x80, 0xe2, | 419 | 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x50, 0x94, 0xe5, 0x01, 0x50, 0xc1, 0xe4, 0x01, 0x00, 0x80, 0xe2, |
420 | 0x02, 0x00, 0x50, 0xe1, 0xf3, 0xff, 0xff, 0x3a, 0xc8, 0x00, 0xa0, 0xe3, 0x98, 0xff, 0xff, 0xeb, | 420 | 0x02, 0x00, 0x50, 0xe1, 0xf3, 0xff, 0xff, 0x3a, 0xc8, 0x00, 0xa0, 0xe3, 0x98, 0xff, 0xff, 0xeb, |
421 | 0x70, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x0c, 0x00, 0x02, 0x01, 0x02, 0x00, 0x02, | 421 | 0x70, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x0c, 0x00, 0x02, 0x01, 0x02, 0x00, 0x02, |
422 | 0x00, 0x01, 0x00, 0x02 | 422 | 0x00, 0x01, 0x00, 0x02 |
423 | }; | 423 | }; |
424 | 424 | ||
425 | struct atmel_private { | 425 | struct atmel_private { |
426 | void *card; /* Bus dependent stucture varies for PCcard */ | 426 | void *card; /* Bus dependent stucture varies for PCcard */ |
427 | int (*present_callback)(void *); /* And callback which uses it */ | 427 | int (*present_callback)(void *); /* And callback which uses it */ |
428 | char firmware_id[32]; | 428 | char firmware_id[32]; |
429 | AtmelFWType firmware_type; | 429 | AtmelFWType firmware_type; |
430 | u8 *firmware; | 430 | u8 *firmware; |
431 | int firmware_length; | 431 | int firmware_length; |
432 | struct timer_list management_timer; | 432 | struct timer_list management_timer; |
433 | struct net_device *dev; | 433 | struct net_device *dev; |
434 | struct device *sys_dev; | 434 | struct device *sys_dev; |
435 | struct iw_statistics wstats; | 435 | struct iw_statistics wstats; |
436 | spinlock_t irqlock, timerlock; /* spinlocks */ | 436 | spinlock_t irqlock, timerlock; /* spinlocks */ |
437 | enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type; | 437 | enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type; |
438 | enum { | 438 | enum { |
439 | CARD_TYPE_PARALLEL_FLASH, | 439 | CARD_TYPE_PARALLEL_FLASH, |
440 | CARD_TYPE_SPI_FLASH, | 440 | CARD_TYPE_SPI_FLASH, |
441 | CARD_TYPE_EEPROM | 441 | CARD_TYPE_EEPROM |
442 | } card_type; | 442 | } card_type; |
443 | int do_rx_crc; /* If we need to CRC incoming packets */ | 443 | int do_rx_crc; /* If we need to CRC incoming packets */ |
444 | int probe_crc; /* set if we don't yet know */ | 444 | int probe_crc; /* set if we don't yet know */ |
445 | int crc_ok_cnt, crc_ko_cnt; /* counters for probing */ | 445 | int crc_ok_cnt, crc_ko_cnt; /* counters for probing */ |
446 | u16 rx_desc_head; | 446 | u16 rx_desc_head; |
447 | u16 tx_desc_free, tx_desc_head, tx_desc_tail, tx_desc_previous; | 447 | u16 tx_desc_free, tx_desc_head, tx_desc_tail, tx_desc_previous; |
448 | u16 tx_free_mem, tx_buff_head, tx_buff_tail; | 448 | u16 tx_free_mem, tx_buff_head, tx_buff_tail; |
449 | 449 | ||
450 | u16 frag_seq, frag_len, frag_no; | 450 | u16 frag_seq, frag_len, frag_no; |
451 | u8 frag_source[6]; | 451 | u8 frag_source[6]; |
452 | 452 | ||
453 | u8 wep_is_on, default_key, exclude_unencrypted, encryption_level; | 453 | u8 wep_is_on, default_key, exclude_unencrypted, encryption_level; |
454 | u8 group_cipher_suite, pairwise_cipher_suite; | 454 | u8 group_cipher_suite, pairwise_cipher_suite; |
455 | u8 wep_keys[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE]; | 455 | u8 wep_keys[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE]; |
456 | int wep_key_len[MAX_ENCRYPTION_KEYS]; | 456 | int wep_key_len[MAX_ENCRYPTION_KEYS]; |
457 | int use_wpa, radio_on_broken; /* firmware dependent stuff. */ | 457 | int use_wpa, radio_on_broken; /* firmware dependent stuff. */ |
458 | 458 | ||
459 | u16 host_info_base; | 459 | u16 host_info_base; |
460 | struct host_info_struct { | 460 | struct host_info_struct { |
461 | /* NB this is matched to the hardware, don't change. */ | 461 | /* NB this is matched to the hardware, don't change. */ |
462 | u8 volatile int_status; | 462 | u8 volatile int_status; |
463 | u8 volatile int_mask; | 463 | u8 volatile int_mask; |
464 | u8 volatile lockout_host; | 464 | u8 volatile lockout_host; |
465 | u8 volatile lockout_mac; | 465 | u8 volatile lockout_mac; |
466 | 466 | ||
467 | u16 tx_buff_pos; | 467 | u16 tx_buff_pos; |
468 | u16 tx_buff_size; | 468 | u16 tx_buff_size; |
469 | u16 tx_desc_pos; | 469 | u16 tx_desc_pos; |
470 | u16 tx_desc_count; | 470 | u16 tx_desc_count; |
471 | 471 | ||
472 | u16 rx_buff_pos; | 472 | u16 rx_buff_pos; |
473 | u16 rx_buff_size; | 473 | u16 rx_buff_size; |
474 | u16 rx_desc_pos; | 474 | u16 rx_desc_pos; |
475 | u16 rx_desc_count; | 475 | u16 rx_desc_count; |
476 | 476 | ||
477 | u16 build_version; | 477 | u16 build_version; |
478 | u16 command_pos; | 478 | u16 command_pos; |
479 | 479 | ||
480 | u16 major_version; | 480 | u16 major_version; |
481 | u16 minor_version; | 481 | u16 minor_version; |
482 | 482 | ||
483 | u16 func_ctrl; | 483 | u16 func_ctrl; |
484 | u16 mac_status; | 484 | u16 mac_status; |
485 | u16 generic_IRQ_type; | 485 | u16 generic_IRQ_type; |
486 | u8 reserved[2]; | 486 | u8 reserved[2]; |
487 | } host_info; | 487 | } host_info; |
488 | 488 | ||
489 | enum { | 489 | enum { |
490 | STATION_STATE_SCANNING, | 490 | STATION_STATE_SCANNING, |
491 | STATION_STATE_JOINNING, | 491 | STATION_STATE_JOINNING, |
492 | STATION_STATE_AUTHENTICATING, | 492 | STATION_STATE_AUTHENTICATING, |
493 | STATION_STATE_ASSOCIATING, | 493 | STATION_STATE_ASSOCIATING, |
494 | STATION_STATE_READY, | 494 | STATION_STATE_READY, |
495 | STATION_STATE_REASSOCIATING, | 495 | STATION_STATE_REASSOCIATING, |
496 | STATION_STATE_DOWN, | 496 | STATION_STATE_DOWN, |
497 | STATION_STATE_MGMT_ERROR | 497 | STATION_STATE_MGMT_ERROR |
498 | } station_state; | 498 | } station_state; |
499 | 499 | ||
500 | int operating_mode, power_mode; | 500 | int operating_mode, power_mode; |
501 | time_t last_qual; | 501 | time_t last_qual; |
502 | int beacons_this_sec; | 502 | int beacons_this_sec; |
503 | int channel; | 503 | int channel; |
504 | int reg_domain, config_reg_domain; | 504 | int reg_domain, config_reg_domain; |
505 | int tx_rate; | 505 | int tx_rate; |
506 | int auto_tx_rate; | 506 | int auto_tx_rate; |
507 | int rts_threshold; | 507 | int rts_threshold; |
508 | int frag_threshold; | 508 | int frag_threshold; |
509 | int long_retry, short_retry; | 509 | int long_retry, short_retry; |
510 | int preamble; | 510 | int preamble; |
511 | int default_beacon_period, beacon_period, listen_interval; | 511 | int default_beacon_period, beacon_period, listen_interval; |
512 | int CurrentAuthentTransactionSeqNum, ExpectedAuthentTransactionSeqNum; | 512 | int CurrentAuthentTransactionSeqNum, ExpectedAuthentTransactionSeqNum; |
513 | int AuthenticationRequestRetryCnt, AssociationRequestRetryCnt, ReAssociationRequestRetryCnt; | 513 | int AuthenticationRequestRetryCnt, AssociationRequestRetryCnt, ReAssociationRequestRetryCnt; |
514 | enum { | 514 | enum { |
515 | SITE_SURVEY_IDLE, | 515 | SITE_SURVEY_IDLE, |
516 | SITE_SURVEY_IN_PROGRESS, | 516 | SITE_SURVEY_IN_PROGRESS, |
517 | SITE_SURVEY_COMPLETED | 517 | SITE_SURVEY_COMPLETED |
518 | } site_survey_state; | 518 | } site_survey_state; |
519 | unsigned long last_survey; | 519 | unsigned long last_survey; |
520 | 520 | ||
521 | int station_was_associated, station_is_associated; | 521 | int station_was_associated, station_is_associated; |
522 | int fast_scan; | 522 | int fast_scan; |
523 | 523 | ||
524 | struct bss_info { | 524 | struct bss_info { |
525 | int channel; | 525 | int channel; |
526 | int SSIDsize; | 526 | int SSIDsize; |
527 | int RSSI; | 527 | int RSSI; |
528 | int UsingWEP; | 528 | int UsingWEP; |
529 | int preamble; | 529 | int preamble; |
530 | int beacon_period; | 530 | int beacon_period; |
531 | int BSStype; | 531 | int BSStype; |
532 | u8 BSSID[6]; | 532 | u8 BSSID[6]; |
533 | u8 SSID[MAX_SSID_LENGTH]; | 533 | u8 SSID[MAX_SSID_LENGTH]; |
534 | } BSSinfo[MAX_BSS_ENTRIES]; | 534 | } BSSinfo[MAX_BSS_ENTRIES]; |
535 | int BSS_list_entries, current_BSS; | 535 | int BSS_list_entries, current_BSS; |
536 | int connect_to_any_BSS; | 536 | int connect_to_any_BSS; |
537 | int SSID_size, new_SSID_size; | 537 | int SSID_size, new_SSID_size; |
538 | u8 CurrentBSSID[6], BSSID[6]; | 538 | u8 CurrentBSSID[6], BSSID[6]; |
539 | u8 SSID[MAX_SSID_LENGTH], new_SSID[MAX_SSID_LENGTH]; | 539 | u8 SSID[MAX_SSID_LENGTH], new_SSID[MAX_SSID_LENGTH]; |
540 | u64 last_beacon_timestamp; | 540 | u64 last_beacon_timestamp; |
541 | u8 rx_buf[MAX_WIRELESS_BODY]; | 541 | u8 rx_buf[MAX_WIRELESS_BODY]; |
542 | }; | 542 | }; |
543 | 543 | ||
544 | static u8 atmel_basic_rates[4] = {0x82, 0x84, 0x0b, 0x16}; | 544 | static u8 atmel_basic_rates[4] = {0x82, 0x84, 0x0b, 0x16}; |
545 | 545 | ||
546 | static const struct { | 546 | static const struct { |
547 | int reg_domain; | 547 | int reg_domain; |
548 | int min, max; | 548 | int min, max; |
549 | char *name; | 549 | char *name; |
550 | } channel_table[] = { { REG_DOMAIN_FCC, 1, 11, "USA" }, | 550 | } channel_table[] = { { REG_DOMAIN_FCC, 1, 11, "USA" }, |
551 | { REG_DOMAIN_DOC, 1, 11, "Canada" }, | 551 | { REG_DOMAIN_DOC, 1, 11, "Canada" }, |
552 | { REG_DOMAIN_ETSI, 1, 13, "Europe" }, | 552 | { REG_DOMAIN_ETSI, 1, 13, "Europe" }, |
553 | { REG_DOMAIN_SPAIN, 10, 11, "Spain" }, | 553 | { REG_DOMAIN_SPAIN, 10, 11, "Spain" }, |
554 | { REG_DOMAIN_FRANCE, 10, 13, "France" }, | 554 | { REG_DOMAIN_FRANCE, 10, 13, "France" }, |
555 | { REG_DOMAIN_MKK, 14, 14, "MKK" }, | 555 | { REG_DOMAIN_MKK, 14, 14, "MKK" }, |
556 | { REG_DOMAIN_MKK1, 1, 14, "MKK1" }, | 556 | { REG_DOMAIN_MKK1, 1, 14, "MKK1" }, |
557 | { REG_DOMAIN_ISRAEL, 3, 9, "Israel"} }; | 557 | { REG_DOMAIN_ISRAEL, 3, 9, "Israel"} }; |
558 | 558 | ||
559 | static void build_wpa_mib(struct atmel_private *priv); | 559 | static void build_wpa_mib(struct atmel_private *priv); |
560 | static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | 560 | static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); |
561 | static void atmel_copy_to_card(struct net_device *dev, u16 dest, | 561 | static void atmel_copy_to_card(struct net_device *dev, u16 dest, |
562 | const unsigned char *src, u16 len); | 562 | const unsigned char *src, u16 len); |
563 | static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, | 563 | static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, |
564 | u16 src, u16 len); | 564 | u16 src, u16 len); |
565 | static void atmel_set_gcr(struct net_device *dev, u16 mask); | 565 | static void atmel_set_gcr(struct net_device *dev, u16 mask); |
566 | static void atmel_clear_gcr(struct net_device *dev, u16 mask); | 566 | static void atmel_clear_gcr(struct net_device *dev, u16 mask); |
567 | static int atmel_lock_mac(struct atmel_private *priv); | 567 | static int atmel_lock_mac(struct atmel_private *priv); |
568 | static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); | 568 | static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); |
569 | static void atmel_command_irq(struct atmel_private *priv); | 569 | static void atmel_command_irq(struct atmel_private *priv); |
570 | static int atmel_validate_channel(struct atmel_private *priv, int channel); | 570 | static int atmel_validate_channel(struct atmel_private *priv, int channel); |
571 | static void atmel_management_frame(struct atmel_private *priv, | 571 | static void atmel_management_frame(struct atmel_private *priv, |
572 | struct ieee80211_hdr *header, | 572 | struct ieee80211_hdr *header, |
573 | u16 frame_len, u8 rssi); | 573 | u16 frame_len, u8 rssi); |
574 | static void atmel_management_timer(u_long a); | 574 | static void atmel_management_timer(u_long a); |
575 | static void atmel_send_command(struct atmel_private *priv, int command, | 575 | static void atmel_send_command(struct atmel_private *priv, int command, |
576 | void *cmd, int cmd_size); | 576 | void *cmd, int cmd_size); |
577 | static int atmel_send_command_wait(struct atmel_private *priv, int command, | 577 | static int atmel_send_command_wait(struct atmel_private *priv, int command, |
578 | void *cmd, int cmd_size); | 578 | void *cmd, int cmd_size); |
579 | static void atmel_transmit_management_frame(struct atmel_private *priv, | 579 | static void atmel_transmit_management_frame(struct atmel_private *priv, |
580 | struct ieee80211_hdr *header, | 580 | struct ieee80211_hdr *header, |
581 | u8 *body, int body_len); | 581 | u8 *body, int body_len); |
582 | 582 | ||
583 | static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); | 583 | static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); |
584 | static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, | 584 | static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, |
585 | u8 data); | 585 | u8 data); |
586 | static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, | 586 | static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, |
587 | u16 data); | 587 | u16 data); |
588 | static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, | 588 | static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, |
589 | u8 *data, int data_len); | 589 | u8 *data, int data_len); |
590 | static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, | 590 | static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, |
591 | u8 *data, int data_len); | 591 | u8 *data, int data_len); |
592 | static void atmel_scan(struct atmel_private *priv, int specific_ssid); | 592 | static void atmel_scan(struct atmel_private *priv, int specific_ssid); |
593 | static void atmel_join_bss(struct atmel_private *priv, int bss_index); | 593 | static void atmel_join_bss(struct atmel_private *priv, int bss_index); |
594 | static void atmel_smooth_qual(struct atmel_private *priv); | 594 | static void atmel_smooth_qual(struct atmel_private *priv); |
595 | static void atmel_writeAR(struct net_device *dev, u16 data); | 595 | static void atmel_writeAR(struct net_device *dev, u16 data); |
596 | static int probe_atmel_card(struct net_device *dev); | 596 | static int probe_atmel_card(struct net_device *dev); |
597 | static int reset_atmel_card(struct net_device *dev); | 597 | static int reset_atmel_card(struct net_device *dev); |
598 | static void atmel_enter_state(struct atmel_private *priv, int new_state); | 598 | static void atmel_enter_state(struct atmel_private *priv, int new_state); |
599 | int atmel_open (struct net_device *dev); | 599 | int atmel_open (struct net_device *dev); |
600 | 600 | ||
601 | static inline u16 atmel_hi(struct atmel_private *priv, u16 offset) | 601 | static inline u16 atmel_hi(struct atmel_private *priv, u16 offset) |
602 | { | 602 | { |
603 | return priv->host_info_base + offset; | 603 | return priv->host_info_base + offset; |
604 | } | 604 | } |
605 | 605 | ||
606 | static inline u16 atmel_co(struct atmel_private *priv, u16 offset) | 606 | static inline u16 atmel_co(struct atmel_private *priv, u16 offset) |
607 | { | 607 | { |
608 | return priv->host_info.command_pos + offset; | 608 | return priv->host_info.command_pos + offset; |
609 | } | 609 | } |
610 | 610 | ||
611 | static inline u16 atmel_rx(struct atmel_private *priv, u16 offset, u16 desc) | 611 | static inline u16 atmel_rx(struct atmel_private *priv, u16 offset, u16 desc) |
612 | { | 612 | { |
613 | return priv->host_info.rx_desc_pos + (sizeof(struct rx_desc) * desc) + offset; | 613 | return priv->host_info.rx_desc_pos + (sizeof(struct rx_desc) * desc) + offset; |
614 | } | 614 | } |
615 | 615 | ||
616 | static inline u16 atmel_tx(struct atmel_private *priv, u16 offset, u16 desc) | 616 | static inline u16 atmel_tx(struct atmel_private *priv, u16 offset, u16 desc) |
617 | { | 617 | { |
618 | return priv->host_info.tx_desc_pos + (sizeof(struct tx_desc) * desc) + offset; | 618 | return priv->host_info.tx_desc_pos + (sizeof(struct tx_desc) * desc) + offset; |
619 | } | 619 | } |
620 | 620 | ||
621 | static inline u8 atmel_read8(struct net_device *dev, u16 offset) | 621 | static inline u8 atmel_read8(struct net_device *dev, u16 offset) |
622 | { | 622 | { |
623 | return inb(dev->base_addr + offset); | 623 | return inb(dev->base_addr + offset); |
624 | } | 624 | } |
625 | 625 | ||
626 | static inline void atmel_write8(struct net_device *dev, u16 offset, u8 data) | 626 | static inline void atmel_write8(struct net_device *dev, u16 offset, u8 data) |
627 | { | 627 | { |
628 | outb(data, dev->base_addr + offset); | 628 | outb(data, dev->base_addr + offset); |
629 | } | 629 | } |
630 | 630 | ||
631 | static inline u16 atmel_read16(struct net_device *dev, u16 offset) | 631 | static inline u16 atmel_read16(struct net_device *dev, u16 offset) |
632 | { | 632 | { |
633 | return inw(dev->base_addr + offset); | 633 | return inw(dev->base_addr + offset); |
634 | } | 634 | } |
635 | 635 | ||
636 | static inline void atmel_write16(struct net_device *dev, u16 offset, u16 data) | 636 | static inline void atmel_write16(struct net_device *dev, u16 offset, u16 data) |
637 | { | 637 | { |
638 | outw(data, dev->base_addr + offset); | 638 | outw(data, dev->base_addr + offset); |
639 | } | 639 | } |
640 | 640 | ||
641 | static inline u8 atmel_rmem8(struct atmel_private *priv, u16 pos) | 641 | static inline u8 atmel_rmem8(struct atmel_private *priv, u16 pos) |
642 | { | 642 | { |
643 | atmel_writeAR(priv->dev, pos); | 643 | atmel_writeAR(priv->dev, pos); |
644 | return atmel_read8(priv->dev, DR); | 644 | return atmel_read8(priv->dev, DR); |
645 | } | 645 | } |
646 | 646 | ||
647 | static inline void atmel_wmem8(struct atmel_private *priv, u16 pos, u16 data) | 647 | static inline void atmel_wmem8(struct atmel_private *priv, u16 pos, u16 data) |
648 | { | 648 | { |
649 | atmel_writeAR(priv->dev, pos); | 649 | atmel_writeAR(priv->dev, pos); |
650 | atmel_write8(priv->dev, DR, data); | 650 | atmel_write8(priv->dev, DR, data); |
651 | } | 651 | } |
652 | 652 | ||
653 | static inline u16 atmel_rmem16(struct atmel_private *priv, u16 pos) | 653 | static inline u16 atmel_rmem16(struct atmel_private *priv, u16 pos) |
654 | { | 654 | { |
655 | atmel_writeAR(priv->dev, pos); | 655 | atmel_writeAR(priv->dev, pos); |
656 | return atmel_read16(priv->dev, DR); | 656 | return atmel_read16(priv->dev, DR); |
657 | } | 657 | } |
658 | 658 | ||
659 | static inline void atmel_wmem16(struct atmel_private *priv, u16 pos, u16 data) | 659 | static inline void atmel_wmem16(struct atmel_private *priv, u16 pos, u16 data) |
660 | { | 660 | { |
661 | atmel_writeAR(priv->dev, pos); | 661 | atmel_writeAR(priv->dev, pos); |
662 | atmel_write16(priv->dev, DR, data); | 662 | atmel_write16(priv->dev, DR, data); |
663 | } | 663 | } |
664 | 664 | ||
665 | static const struct iw_handler_def atmel_handler_def; | 665 | static const struct iw_handler_def atmel_handler_def; |
666 | 666 | ||
667 | static void tx_done_irq(struct atmel_private *priv) | 667 | static void tx_done_irq(struct atmel_private *priv) |
668 | { | 668 | { |
669 | int i; | 669 | int i; |
670 | 670 | ||
671 | for (i = 0; | 671 | for (i = 0; |
672 | atmel_rmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head)) == TX_DONE && | 672 | atmel_rmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head)) == TX_DONE && |
673 | i < priv->host_info.tx_desc_count; | 673 | i < priv->host_info.tx_desc_count; |
674 | i++) { | 674 | i++) { |
675 | u8 status = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_STATUS_OFFSET, priv->tx_desc_head)); | 675 | u8 status = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_STATUS_OFFSET, priv->tx_desc_head)); |
676 | u16 msdu_size = atmel_rmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_head)); | 676 | u16 msdu_size = atmel_rmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_head)); |
677 | u8 type = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_head)); | 677 | u8 type = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_head)); |
678 | 678 | ||
679 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head), 0); | 679 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head), 0); |
680 | 680 | ||
681 | priv->tx_free_mem += msdu_size; | 681 | priv->tx_free_mem += msdu_size; |
682 | priv->tx_desc_free++; | 682 | priv->tx_desc_free++; |
683 | 683 | ||
684 | if (priv->tx_buff_head + msdu_size > (priv->host_info.tx_buff_pos + priv->host_info.tx_buff_size)) | 684 | if (priv->tx_buff_head + msdu_size > (priv->host_info.tx_buff_pos + priv->host_info.tx_buff_size)) |
685 | priv->tx_buff_head = 0; | 685 | priv->tx_buff_head = 0; |
686 | else | 686 | else |
687 | priv->tx_buff_head += msdu_size; | 687 | priv->tx_buff_head += msdu_size; |
688 | 688 | ||
689 | if (priv->tx_desc_head < (priv->host_info.tx_desc_count - 1)) | 689 | if (priv->tx_desc_head < (priv->host_info.tx_desc_count - 1)) |
690 | priv->tx_desc_head++ ; | 690 | priv->tx_desc_head++ ; |
691 | else | 691 | else |
692 | priv->tx_desc_head = 0; | 692 | priv->tx_desc_head = 0; |
693 | 693 | ||
694 | if (type == TX_PACKET_TYPE_DATA) { | 694 | if (type == TX_PACKET_TYPE_DATA) { |
695 | if (status == TX_STATUS_SUCCESS) | 695 | if (status == TX_STATUS_SUCCESS) |
696 | priv->dev->stats.tx_packets++; | 696 | priv->dev->stats.tx_packets++; |
697 | else | 697 | else |
698 | priv->dev->stats.tx_errors++; | 698 | priv->dev->stats.tx_errors++; |
699 | netif_wake_queue(priv->dev); | 699 | netif_wake_queue(priv->dev); |
700 | } | 700 | } |
701 | } | 701 | } |
702 | } | 702 | } |
703 | 703 | ||
704 | static u16 find_tx_buff(struct atmel_private *priv, u16 len) | 704 | static u16 find_tx_buff(struct atmel_private *priv, u16 len) |
705 | { | 705 | { |
706 | u16 bottom_free = priv->host_info.tx_buff_size - priv->tx_buff_tail; | 706 | u16 bottom_free = priv->host_info.tx_buff_size - priv->tx_buff_tail; |
707 | 707 | ||
708 | if (priv->tx_desc_free == 3 || priv->tx_free_mem < len) | 708 | if (priv->tx_desc_free == 3 || priv->tx_free_mem < len) |
709 | return 0; | 709 | return 0; |
710 | 710 | ||
711 | if (bottom_free >= len) | 711 | if (bottom_free >= len) |
712 | return priv->host_info.tx_buff_pos + priv->tx_buff_tail; | 712 | return priv->host_info.tx_buff_pos + priv->tx_buff_tail; |
713 | 713 | ||
714 | if (priv->tx_free_mem - bottom_free >= len) { | 714 | if (priv->tx_free_mem - bottom_free >= len) { |
715 | priv->tx_buff_tail = 0; | 715 | priv->tx_buff_tail = 0; |
716 | return priv->host_info.tx_buff_pos; | 716 | return priv->host_info.tx_buff_pos; |
717 | } | 717 | } |
718 | 718 | ||
719 | return 0; | 719 | return 0; |
720 | } | 720 | } |
721 | 721 | ||
722 | static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, | 722 | static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, |
723 | u16 len, u16 buff, u8 type) | 723 | u16 len, u16 buff, u8 type) |
724 | { | 724 | { |
725 | atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, priv->tx_desc_tail), buff); | 725 | atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, priv->tx_desc_tail), buff); |
726 | atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_tail), len); | 726 | atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_tail), len); |
727 | if (!priv->use_wpa) | 727 | if (!priv->use_wpa) |
728 | atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len); | 728 | atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len); |
729 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_tail), type); | 729 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_tail), type); |
730 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RATE_OFFSET, priv->tx_desc_tail), priv->tx_rate); | 730 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RATE_OFFSET, priv->tx_desc_tail), priv->tx_rate); |
731 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RETRY_OFFSET, priv->tx_desc_tail), 0); | 731 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RETRY_OFFSET, priv->tx_desc_tail), 0); |
732 | if (priv->use_wpa) { | 732 | if (priv->use_wpa) { |
733 | int cipher_type, cipher_length; | 733 | int cipher_type, cipher_length; |
734 | if (is_bcast) { | 734 | if (is_bcast) { |
735 | cipher_type = priv->group_cipher_suite; | 735 | cipher_type = priv->group_cipher_suite; |
736 | if (cipher_type == CIPHER_SUITE_WEP_64 || | 736 | if (cipher_type == CIPHER_SUITE_WEP_64 || |
737 | cipher_type == CIPHER_SUITE_WEP_128) | 737 | cipher_type == CIPHER_SUITE_WEP_128) |
738 | cipher_length = 8; | 738 | cipher_length = 8; |
739 | else if (cipher_type == CIPHER_SUITE_TKIP) | 739 | else if (cipher_type == CIPHER_SUITE_TKIP) |
740 | cipher_length = 12; | 740 | cipher_length = 12; |
741 | else if (priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_64 || | 741 | else if (priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_64 || |
742 | priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_128) { | 742 | priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_128) { |
743 | cipher_type = priv->pairwise_cipher_suite; | 743 | cipher_type = priv->pairwise_cipher_suite; |
744 | cipher_length = 8; | 744 | cipher_length = 8; |
745 | } else { | 745 | } else { |
746 | cipher_type = CIPHER_SUITE_NONE; | 746 | cipher_type = CIPHER_SUITE_NONE; |
747 | cipher_length = 0; | 747 | cipher_length = 0; |
748 | } | 748 | } |
749 | } else { | 749 | } else { |
750 | cipher_type = priv->pairwise_cipher_suite; | 750 | cipher_type = priv->pairwise_cipher_suite; |
751 | if (cipher_type == CIPHER_SUITE_WEP_64 || | 751 | if (cipher_type == CIPHER_SUITE_WEP_64 || |
752 | cipher_type == CIPHER_SUITE_WEP_128) | 752 | cipher_type == CIPHER_SUITE_WEP_128) |
753 | cipher_length = 8; | 753 | cipher_length = 8; |
754 | else if (cipher_type == CIPHER_SUITE_TKIP) | 754 | else if (cipher_type == CIPHER_SUITE_TKIP) |
755 | cipher_length = 12; | 755 | cipher_length = 12; |
756 | else if (priv->group_cipher_suite == CIPHER_SUITE_WEP_64 || | 756 | else if (priv->group_cipher_suite == CIPHER_SUITE_WEP_64 || |
757 | priv->group_cipher_suite == CIPHER_SUITE_WEP_128) { | 757 | priv->group_cipher_suite == CIPHER_SUITE_WEP_128) { |
758 | cipher_type = priv->group_cipher_suite; | 758 | cipher_type = priv->group_cipher_suite; |
759 | cipher_length = 8; | 759 | cipher_length = 8; |
760 | } else { | 760 | } else { |
761 | cipher_type = CIPHER_SUITE_NONE; | 761 | cipher_type = CIPHER_SUITE_NONE; |
762 | cipher_length = 0; | 762 | cipher_length = 0; |
763 | } | 763 | } |
764 | } | 764 | } |
765 | 765 | ||
766 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_TYPE_OFFSET, priv->tx_desc_tail), | 766 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_TYPE_OFFSET, priv->tx_desc_tail), |
767 | cipher_type); | 767 | cipher_type); |
768 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_LENGTH_OFFSET, priv->tx_desc_tail), | 768 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_LENGTH_OFFSET, priv->tx_desc_tail), |
769 | cipher_length); | 769 | cipher_length); |
770 | } | 770 | } |
771 | atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_tail), 0x80000000L); | 771 | atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_tail), 0x80000000L); |
772 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_tail), TX_FIRM_OWN); | 772 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_tail), TX_FIRM_OWN); |
773 | if (priv->tx_desc_previous != priv->tx_desc_tail) | 773 | if (priv->tx_desc_previous != priv->tx_desc_tail) |
774 | atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_previous), 0); | 774 | atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_previous), 0); |
775 | priv->tx_desc_previous = priv->tx_desc_tail; | 775 | priv->tx_desc_previous = priv->tx_desc_tail; |
776 | if (priv->tx_desc_tail < (priv->host_info.tx_desc_count - 1)) | 776 | if (priv->tx_desc_tail < (priv->host_info.tx_desc_count - 1)) |
777 | priv->tx_desc_tail++; | 777 | priv->tx_desc_tail++; |
778 | else | 778 | else |
779 | priv->tx_desc_tail = 0; | 779 | priv->tx_desc_tail = 0; |
780 | priv->tx_desc_free--; | 780 | priv->tx_desc_free--; |
781 | priv->tx_free_mem -= len; | 781 | priv->tx_free_mem -= len; |
782 | } | 782 | } |
783 | 783 | ||
784 | static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) | 784 | static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) |
785 | { | 785 | { |
786 | static const u8 SNAP_RFC1024[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | 786 | static const u8 SNAP_RFC1024[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; |
787 | struct atmel_private *priv = netdev_priv(dev); | 787 | struct atmel_private *priv = netdev_priv(dev); |
788 | struct ieee80211_hdr header; | 788 | struct ieee80211_hdr header; |
789 | unsigned long flags; | 789 | unsigned long flags; |
790 | u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; | 790 | u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; |
791 | 791 | ||
792 | if (priv->card && priv->present_callback && | 792 | if (priv->card && priv->present_callback && |
793 | !(*priv->present_callback)(priv->card)) { | 793 | !(*priv->present_callback)(priv->card)) { |
794 | dev->stats.tx_errors++; | 794 | dev->stats.tx_errors++; |
795 | dev_kfree_skb(skb); | 795 | dev_kfree_skb(skb); |
796 | return NETDEV_TX_OK; | 796 | return NETDEV_TX_OK; |
797 | } | 797 | } |
798 | 798 | ||
799 | if (priv->station_state != STATION_STATE_READY) { | 799 | if (priv->station_state != STATION_STATE_READY) { |
800 | dev->stats.tx_errors++; | 800 | dev->stats.tx_errors++; |
801 | dev_kfree_skb(skb); | 801 | dev_kfree_skb(skb); |
802 | return NETDEV_TX_OK; | 802 | return NETDEV_TX_OK; |
803 | } | 803 | } |
804 | 804 | ||
805 | /* first ensure the timer func cannot run */ | 805 | /* first ensure the timer func cannot run */ |
806 | spin_lock_bh(&priv->timerlock); | 806 | spin_lock_bh(&priv->timerlock); |
807 | /* then stop the hardware ISR */ | 807 | /* then stop the hardware ISR */ |
808 | spin_lock_irqsave(&priv->irqlock, flags); | 808 | spin_lock_irqsave(&priv->irqlock, flags); |
809 | /* nb doing the above in the opposite order will deadlock */ | 809 | /* nb doing the above in the opposite order will deadlock */ |
810 | 810 | ||
811 | /* The Wireless Header is 30 bytes. In the Ethernet packet we "cut" the | 811 | /* The Wireless Header is 30 bytes. In the Ethernet packet we "cut" the |
812 | 12 first bytes (containing DA/SA) and put them in the appropriate | 812 | 12 first bytes (containing DA/SA) and put them in the appropriate |
813 | fields of the Wireless Header. Thus the packet length is then the | 813 | fields of the Wireless Header. Thus the packet length is then the |
814 | initial + 18 (+30-12) */ | 814 | initial + 18 (+30-12) */ |
815 | 815 | ||
816 | if (!(buff = find_tx_buff(priv, len + 18))) { | 816 | if (!(buff = find_tx_buff(priv, len + 18))) { |
817 | dev->stats.tx_dropped++; | 817 | dev->stats.tx_dropped++; |
818 | spin_unlock_irqrestore(&priv->irqlock, flags); | 818 | spin_unlock_irqrestore(&priv->irqlock, flags); |
819 | spin_unlock_bh(&priv->timerlock); | 819 | spin_unlock_bh(&priv->timerlock); |
820 | netif_stop_queue(dev); | 820 | netif_stop_queue(dev); |
821 | return NETDEV_TX_BUSY; | 821 | return NETDEV_TX_BUSY; |
822 | } | 822 | } |
823 | 823 | ||
824 | frame_ctl = IEEE80211_FTYPE_DATA; | 824 | frame_ctl = IEEE80211_FTYPE_DATA; |
825 | header.duration_id = 0; | 825 | header.duration_id = 0; |
826 | header.seq_ctrl = 0; | 826 | header.seq_ctrl = 0; |
827 | if (priv->wep_is_on) | 827 | if (priv->wep_is_on) |
828 | frame_ctl |= IEEE80211_FCTL_PROTECTED; | 828 | frame_ctl |= IEEE80211_FCTL_PROTECTED; |
829 | if (priv->operating_mode == IW_MODE_ADHOC) { | 829 | if (priv->operating_mode == IW_MODE_ADHOC) { |
830 | skb_copy_from_linear_data(skb, &header.addr1, 6); | 830 | skb_copy_from_linear_data(skb, &header.addr1, 6); |
831 | memcpy(&header.addr2, dev->dev_addr, 6); | 831 | memcpy(&header.addr2, dev->dev_addr, 6); |
832 | memcpy(&header.addr3, priv->BSSID, 6); | 832 | memcpy(&header.addr3, priv->BSSID, 6); |
833 | } else { | 833 | } else { |
834 | frame_ctl |= IEEE80211_FCTL_TODS; | 834 | frame_ctl |= IEEE80211_FCTL_TODS; |
835 | memcpy(&header.addr1, priv->CurrentBSSID, 6); | 835 | memcpy(&header.addr1, priv->CurrentBSSID, 6); |
836 | memcpy(&header.addr2, dev->dev_addr, 6); | 836 | memcpy(&header.addr2, dev->dev_addr, 6); |
837 | skb_copy_from_linear_data(skb, &header.addr3, 6); | 837 | skb_copy_from_linear_data(skb, &header.addr3, 6); |
838 | } | 838 | } |
839 | 839 | ||
840 | if (priv->use_wpa) | 840 | if (priv->use_wpa) |
841 | memcpy(&header.addr4, SNAP_RFC1024, 6); | 841 | memcpy(&header.addr4, SNAP_RFC1024, 6); |
842 | 842 | ||
843 | header.frame_control = cpu_to_le16(frame_ctl); | 843 | header.frame_control = cpu_to_le16(frame_ctl); |
844 | /* Copy the wireless header into the card */ | 844 | /* Copy the wireless header into the card */ |
845 | atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE); | 845 | atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE); |
846 | /* Copy the packet sans its 802.3 header addresses which have been replaced */ | 846 | /* Copy the packet sans its 802.3 header addresses which have been replaced */ |
847 | atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12); | 847 | atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12); |
848 | priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE; | 848 | priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE; |
849 | 849 | ||
850 | /* low bit of first byte of destination tells us if broadcast */ | 850 | /* low bit of first byte of destination tells us if broadcast */ |
851 | tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA); | 851 | tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA); |
852 | dev->trans_start = jiffies; | 852 | dev->trans_start = jiffies; |
853 | dev->stats.tx_bytes += len; | 853 | dev->stats.tx_bytes += len; |
854 | 854 | ||
855 | spin_unlock_irqrestore(&priv->irqlock, flags); | 855 | spin_unlock_irqrestore(&priv->irqlock, flags); |
856 | spin_unlock_bh(&priv->timerlock); | 856 | spin_unlock_bh(&priv->timerlock); |
857 | dev_kfree_skb(skb); | 857 | dev_kfree_skb(skb); |
858 | 858 | ||
859 | return NETDEV_TX_OK; | 859 | return NETDEV_TX_OK; |
860 | } | 860 | } |
861 | 861 | ||
862 | static void atmel_transmit_management_frame(struct atmel_private *priv, | 862 | static void atmel_transmit_management_frame(struct atmel_private *priv, |
863 | struct ieee80211_hdr *header, | 863 | struct ieee80211_hdr *header, |
864 | u8 *body, int body_len) | 864 | u8 *body, int body_len) |
865 | { | 865 | { |
866 | u16 buff; | 866 | u16 buff; |
867 | int len = MGMT_FRAME_BODY_OFFSET + body_len; | 867 | int len = MGMT_FRAME_BODY_OFFSET + body_len; |
868 | 868 | ||
869 | if (!(buff = find_tx_buff(priv, len))) | 869 | if (!(buff = find_tx_buff(priv, len))) |
870 | return; | 870 | return; |
871 | 871 | ||
872 | atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET); | 872 | atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET); |
873 | atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len); | 873 | atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len); |
874 | priv->tx_buff_tail += len; | 874 | priv->tx_buff_tail += len; |
875 | tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT); | 875 | tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT); |
876 | } | 876 | } |
877 | 877 | ||
878 | static void fast_rx_path(struct atmel_private *priv, | 878 | static void fast_rx_path(struct atmel_private *priv, |
879 | struct ieee80211_hdr *header, | 879 | struct ieee80211_hdr *header, |
880 | u16 msdu_size, u16 rx_packet_loc, u32 crc) | 880 | u16 msdu_size, u16 rx_packet_loc, u32 crc) |
881 | { | 881 | { |
882 | /* fast path: unfragmented packet copy directly into skbuf */ | 882 | /* fast path: unfragmented packet copy directly into skbuf */ |
883 | u8 mac4[6]; | 883 | u8 mac4[6]; |
884 | struct sk_buff *skb; | 884 | struct sk_buff *skb; |
885 | unsigned char *skbp; | 885 | unsigned char *skbp; |
886 | 886 | ||
887 | /* get the final, mac 4 header field, this tells us encapsulation */ | 887 | /* get the final, mac 4 header field, this tells us encapsulation */ |
888 | atmel_copy_to_host(priv->dev, mac4, rx_packet_loc + 24, 6); | 888 | atmel_copy_to_host(priv->dev, mac4, rx_packet_loc + 24, 6); |
889 | msdu_size -= 6; | 889 | msdu_size -= 6; |
890 | 890 | ||
891 | if (priv->do_rx_crc) { | 891 | if (priv->do_rx_crc) { |
892 | crc = crc32_le(crc, mac4, 6); | 892 | crc = crc32_le(crc, mac4, 6); |
893 | msdu_size -= 4; | 893 | msdu_size -= 4; |
894 | } | 894 | } |
895 | 895 | ||
896 | if (!(skb = dev_alloc_skb(msdu_size + 14))) { | 896 | if (!(skb = dev_alloc_skb(msdu_size + 14))) { |
897 | priv->dev->stats.rx_dropped++; | 897 | priv->dev->stats.rx_dropped++; |
898 | return; | 898 | return; |
899 | } | 899 | } |
900 | 900 | ||
901 | skb_reserve(skb, 2); | 901 | skb_reserve(skb, 2); |
902 | skbp = skb_put(skb, msdu_size + 12); | 902 | skbp = skb_put(skb, msdu_size + 12); |
903 | atmel_copy_to_host(priv->dev, skbp + 12, rx_packet_loc + 30, msdu_size); | 903 | atmel_copy_to_host(priv->dev, skbp + 12, rx_packet_loc + 30, msdu_size); |
904 | 904 | ||
905 | if (priv->do_rx_crc) { | 905 | if (priv->do_rx_crc) { |
906 | u32 netcrc; | 906 | u32 netcrc; |
907 | crc = crc32_le(crc, skbp + 12, msdu_size); | 907 | crc = crc32_le(crc, skbp + 12, msdu_size); |
908 | atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4); | 908 | atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4); |
909 | if ((crc ^ 0xffffffff) != netcrc) { | 909 | if ((crc ^ 0xffffffff) != netcrc) { |
910 | priv->dev->stats.rx_crc_errors++; | 910 | priv->dev->stats.rx_crc_errors++; |
911 | dev_kfree_skb(skb); | 911 | dev_kfree_skb(skb); |
912 | return; | 912 | return; |
913 | } | 913 | } |
914 | } | 914 | } |
915 | 915 | ||
916 | memcpy(skbp, header->addr1, 6); /* destination address */ | 916 | memcpy(skbp, header->addr1, 6); /* destination address */ |
917 | if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) | 917 | if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) |
918 | memcpy(&skbp[6], header->addr3, 6); | 918 | memcpy(&skbp[6], header->addr3, 6); |
919 | else | 919 | else |
920 | memcpy(&skbp[6], header->addr2, 6); /* source address */ | 920 | memcpy(&skbp[6], header->addr2, 6); /* source address */ |
921 | 921 | ||
922 | skb->protocol = eth_type_trans(skb, priv->dev); | 922 | skb->protocol = eth_type_trans(skb, priv->dev); |
923 | skb->ip_summed = CHECKSUM_NONE; | 923 | skb->ip_summed = CHECKSUM_NONE; |
924 | netif_rx(skb); | 924 | netif_rx(skb); |
925 | priv->dev->stats.rx_bytes += 12 + msdu_size; | 925 | priv->dev->stats.rx_bytes += 12 + msdu_size; |
926 | priv->dev->stats.rx_packets++; | 926 | priv->dev->stats.rx_packets++; |
927 | } | 927 | } |
928 | 928 | ||
929 | /* Test to see if the packet in card memory at packet_loc has a valid CRC | 929 | /* Test to see if the packet in card memory at packet_loc has a valid CRC |
930 | It doesn't matter that this is slow: it is only used to proble the first few | 930 | It doesn't matter that this is slow: it is only used to proble the first few |
931 | packets. */ | 931 | packets. */ |
932 | static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) | 932 | static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) |
933 | { | 933 | { |
934 | int i = msdu_size - 4; | 934 | int i = msdu_size - 4; |
935 | u32 netcrc, crc = 0xffffffff; | 935 | u32 netcrc, crc = 0xffffffff; |
936 | 936 | ||
937 | if (msdu_size < 4) | 937 | if (msdu_size < 4) |
938 | return 0; | 938 | return 0; |
939 | 939 | ||
940 | atmel_copy_to_host(priv->dev, (void *)&netcrc, packet_loc + i, 4); | 940 | atmel_copy_to_host(priv->dev, (void *)&netcrc, packet_loc + i, 4); |
941 | 941 | ||
942 | atmel_writeAR(priv->dev, packet_loc); | 942 | atmel_writeAR(priv->dev, packet_loc); |
943 | while (i--) { | 943 | while (i--) { |
944 | u8 octet = atmel_read8(priv->dev, DR); | 944 | u8 octet = atmel_read8(priv->dev, DR); |
945 | crc = crc32_le(crc, &octet, 1); | 945 | crc = crc32_le(crc, &octet, 1); |
946 | } | 946 | } |
947 | 947 | ||
948 | return (crc ^ 0xffffffff) == netcrc; | 948 | return (crc ^ 0xffffffff) == netcrc; |
949 | } | 949 | } |
950 | 950 | ||
951 | static void frag_rx_path(struct atmel_private *priv, | 951 | static void frag_rx_path(struct atmel_private *priv, |
952 | struct ieee80211_hdr *header, | 952 | struct ieee80211_hdr *header, |
953 | u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, | 953 | u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, |
954 | u8 frag_no, int more_frags) | 954 | u8 frag_no, int more_frags) |
955 | { | 955 | { |
956 | u8 mac4[6]; | 956 | u8 mac4[6]; |
957 | u8 source[6]; | 957 | u8 source[6]; |
958 | struct sk_buff *skb; | 958 | struct sk_buff *skb; |
959 | 959 | ||
960 | if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) | 960 | if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) |
961 | memcpy(source, header->addr3, 6); | 961 | memcpy(source, header->addr3, 6); |
962 | else | 962 | else |
963 | memcpy(source, header->addr2, 6); | 963 | memcpy(source, header->addr2, 6); |
964 | 964 | ||
965 | rx_packet_loc += 24; /* skip header */ | 965 | rx_packet_loc += 24; /* skip header */ |
966 | 966 | ||
967 | if (priv->do_rx_crc) | 967 | if (priv->do_rx_crc) |
968 | msdu_size -= 4; | 968 | msdu_size -= 4; |
969 | 969 | ||
970 | if (frag_no == 0) { /* first fragment */ | 970 | if (frag_no == 0) { /* first fragment */ |
971 | atmel_copy_to_host(priv->dev, mac4, rx_packet_loc, 6); | 971 | atmel_copy_to_host(priv->dev, mac4, rx_packet_loc, 6); |
972 | msdu_size -= 6; | 972 | msdu_size -= 6; |
973 | rx_packet_loc += 6; | 973 | rx_packet_loc += 6; |
974 | 974 | ||
975 | if (priv->do_rx_crc) | 975 | if (priv->do_rx_crc) |
976 | crc = crc32_le(crc, mac4, 6); | 976 | crc = crc32_le(crc, mac4, 6); |
977 | 977 | ||
978 | priv->frag_seq = seq_no; | 978 | priv->frag_seq = seq_no; |
979 | priv->frag_no = 1; | 979 | priv->frag_no = 1; |
980 | priv->frag_len = msdu_size; | 980 | priv->frag_len = msdu_size; |
981 | memcpy(priv->frag_source, source, 6); | 981 | memcpy(priv->frag_source, source, 6); |
982 | memcpy(&priv->rx_buf[6], source, 6); | 982 | memcpy(&priv->rx_buf[6], source, 6); |
983 | memcpy(priv->rx_buf, header->addr1, 6); | 983 | memcpy(priv->rx_buf, header->addr1, 6); |
984 | 984 | ||
985 | atmel_copy_to_host(priv->dev, &priv->rx_buf[12], rx_packet_loc, msdu_size); | 985 | atmel_copy_to_host(priv->dev, &priv->rx_buf[12], rx_packet_loc, msdu_size); |
986 | 986 | ||
987 | if (priv->do_rx_crc) { | 987 | if (priv->do_rx_crc) { |
988 | u32 netcrc; | 988 | u32 netcrc; |
989 | crc = crc32_le(crc, &priv->rx_buf[12], msdu_size); | 989 | crc = crc32_le(crc, &priv->rx_buf[12], msdu_size); |
990 | atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); | 990 | atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); |
991 | if ((crc ^ 0xffffffff) != netcrc) { | 991 | if ((crc ^ 0xffffffff) != netcrc) { |
992 | priv->dev->stats.rx_crc_errors++; | 992 | priv->dev->stats.rx_crc_errors++; |
993 | memset(priv->frag_source, 0xff, 6); | 993 | memset(priv->frag_source, 0xff, 6); |
994 | } | 994 | } |
995 | } | 995 | } |
996 | 996 | ||
997 | } else if (priv->frag_no == frag_no && | 997 | } else if (priv->frag_no == frag_no && |
998 | priv->frag_seq == seq_no && | 998 | priv->frag_seq == seq_no && |
999 | memcmp(priv->frag_source, source, 6) == 0) { | 999 | memcmp(priv->frag_source, source, 6) == 0) { |
1000 | 1000 | ||
1001 | atmel_copy_to_host(priv->dev, &priv->rx_buf[12 + priv->frag_len], | 1001 | atmel_copy_to_host(priv->dev, &priv->rx_buf[12 + priv->frag_len], |
1002 | rx_packet_loc, msdu_size); | 1002 | rx_packet_loc, msdu_size); |
1003 | if (priv->do_rx_crc) { | 1003 | if (priv->do_rx_crc) { |
1004 | u32 netcrc; | 1004 | u32 netcrc; |
1005 | crc = crc32_le(crc, | 1005 | crc = crc32_le(crc, |
1006 | &priv->rx_buf[12 + priv->frag_len], | 1006 | &priv->rx_buf[12 + priv->frag_len], |
1007 | msdu_size); | 1007 | msdu_size); |
1008 | atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); | 1008 | atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); |
1009 | if ((crc ^ 0xffffffff) != netcrc) { | 1009 | if ((crc ^ 0xffffffff) != netcrc) { |
1010 | priv->dev->stats.rx_crc_errors++; | 1010 | priv->dev->stats.rx_crc_errors++; |
1011 | memset(priv->frag_source, 0xff, 6); | 1011 | memset(priv->frag_source, 0xff, 6); |
1012 | more_frags = 1; /* don't send broken assembly */ | 1012 | more_frags = 1; /* don't send broken assembly */ |
1013 | } | 1013 | } |
1014 | } | 1014 | } |
1015 | 1015 | ||
1016 | priv->frag_len += msdu_size; | 1016 | priv->frag_len += msdu_size; |
1017 | priv->frag_no++; | 1017 | priv->frag_no++; |
1018 | 1018 | ||
1019 | if (!more_frags) { /* last one */ | 1019 | if (!more_frags) { /* last one */ |
1020 | memset(priv->frag_source, 0xff, 6); | 1020 | memset(priv->frag_source, 0xff, 6); |
1021 | if (!(skb = dev_alloc_skb(priv->frag_len + 14))) { | 1021 | if (!(skb = dev_alloc_skb(priv->frag_len + 14))) { |
1022 | priv->dev->stats.rx_dropped++; | 1022 | priv->dev->stats.rx_dropped++; |
1023 | } else { | 1023 | } else { |
1024 | skb_reserve(skb, 2); | 1024 | skb_reserve(skb, 2); |
1025 | memcpy(skb_put(skb, priv->frag_len + 12), | 1025 | memcpy(skb_put(skb, priv->frag_len + 12), |
1026 | priv->rx_buf, | 1026 | priv->rx_buf, |
1027 | priv->frag_len + 12); | 1027 | priv->frag_len + 12); |
1028 | skb->protocol = eth_type_trans(skb, priv->dev); | 1028 | skb->protocol = eth_type_trans(skb, priv->dev); |
1029 | skb->ip_summed = CHECKSUM_NONE; | 1029 | skb->ip_summed = CHECKSUM_NONE; |
1030 | netif_rx(skb); | 1030 | netif_rx(skb); |
1031 | priv->dev->stats.rx_bytes += priv->frag_len + 12; | 1031 | priv->dev->stats.rx_bytes += priv->frag_len + 12; |
1032 | priv->dev->stats.rx_packets++; | 1032 | priv->dev->stats.rx_packets++; |
1033 | } | 1033 | } |
1034 | } | 1034 | } |
1035 | } else | 1035 | } else |
1036 | priv->wstats.discard.fragment++; | 1036 | priv->wstats.discard.fragment++; |
1037 | } | 1037 | } |
1038 | 1038 | ||
1039 | static void rx_done_irq(struct atmel_private *priv) | 1039 | static void rx_done_irq(struct atmel_private *priv) |
1040 | { | 1040 | { |
1041 | int i; | 1041 | int i; |
1042 | struct ieee80211_hdr header; | 1042 | struct ieee80211_hdr header; |
1043 | 1043 | ||
1044 | for (i = 0; | 1044 | for (i = 0; |
1045 | atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && | 1045 | atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && |
1046 | i < priv->host_info.rx_desc_count; | 1046 | i < priv->host_info.rx_desc_count; |
1047 | i++) { | 1047 | i++) { |
1048 | 1048 | ||
1049 | u16 msdu_size, rx_packet_loc, frame_ctl, seq_control; | 1049 | u16 msdu_size, rx_packet_loc, frame_ctl, seq_control; |
1050 | u8 status = atmel_rmem8(priv, atmel_rx(priv, RX_DESC_STATUS_OFFSET, priv->rx_desc_head)); | 1050 | u8 status = atmel_rmem8(priv, atmel_rx(priv, RX_DESC_STATUS_OFFSET, priv->rx_desc_head)); |
1051 | u32 crc = 0xffffffff; | 1051 | u32 crc = 0xffffffff; |
1052 | 1052 | ||
1053 | if (status != RX_STATUS_SUCCESS) { | 1053 | if (status != RX_STATUS_SUCCESS) { |
1054 | if (status == 0xc1) /* determined by experiment */ | 1054 | if (status == 0xc1) /* determined by experiment */ |
1055 | priv->wstats.discard.nwid++; | 1055 | priv->wstats.discard.nwid++; |
1056 | else | 1056 | else |
1057 | priv->dev->stats.rx_errors++; | 1057 | priv->dev->stats.rx_errors++; |
1058 | goto next; | 1058 | goto next; |
1059 | } | 1059 | } |
1060 | 1060 | ||
1061 | msdu_size = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_SIZE_OFFSET, priv->rx_desc_head)); | 1061 | msdu_size = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_SIZE_OFFSET, priv->rx_desc_head)); |
1062 | rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head)); | 1062 | rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head)); |
1063 | 1063 | ||
1064 | if (msdu_size < 30) { | 1064 | if (msdu_size < 30) { |
1065 | priv->dev->stats.rx_errors++; | 1065 | priv->dev->stats.rx_errors++; |
1066 | goto next; | 1066 | goto next; |
1067 | } | 1067 | } |
1068 | 1068 | ||
1069 | /* Get header as far as end of seq_ctrl */ | 1069 | /* Get header as far as end of seq_ctrl */ |
1070 | atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24); | 1070 | atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24); |
1071 | frame_ctl = le16_to_cpu(header.frame_control); | 1071 | frame_ctl = le16_to_cpu(header.frame_control); |
1072 | seq_control = le16_to_cpu(header.seq_ctrl); | 1072 | seq_control = le16_to_cpu(header.seq_ctrl); |
1073 | 1073 | ||
1074 | /* probe for CRC use here if needed once five packets have | 1074 | /* probe for CRC use here if needed once five packets have |
1075 | arrived with the same crc status, we assume we know what's | 1075 | arrived with the same crc status, we assume we know what's |
1076 | happening and stop probing */ | 1076 | happening and stop probing */ |
1077 | if (priv->probe_crc) { | 1077 | if (priv->probe_crc) { |
1078 | if (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED)) { | 1078 | if (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED)) { |
1079 | priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size); | 1079 | priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size); |
1080 | } else { | 1080 | } else { |
1081 | priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24); | 1081 | priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24); |
1082 | } | 1082 | } |
1083 | if (priv->do_rx_crc) { | 1083 | if (priv->do_rx_crc) { |
1084 | if (priv->crc_ok_cnt++ > 5) | 1084 | if (priv->crc_ok_cnt++ > 5) |
1085 | priv->probe_crc = 0; | 1085 | priv->probe_crc = 0; |
1086 | } else { | 1086 | } else { |
1087 | if (priv->crc_ko_cnt++ > 5) | 1087 | if (priv->crc_ko_cnt++ > 5) |
1088 | priv->probe_crc = 0; | 1088 | priv->probe_crc = 0; |
1089 | } | 1089 | } |
1090 | } | 1090 | } |
1091 | 1091 | ||
1092 | /* don't CRC header when WEP in use */ | 1092 | /* don't CRC header when WEP in use */ |
1093 | if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED))) { | 1093 | if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED))) { |
1094 | crc = crc32_le(0xffffffff, (unsigned char *)&header, 24); | 1094 | crc = crc32_le(0xffffffff, (unsigned char *)&header, 24); |
1095 | } | 1095 | } |
1096 | msdu_size -= 24; /* header */ | 1096 | msdu_size -= 24; /* header */ |
1097 | 1097 | ||
1098 | if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { | 1098 | if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { |
1099 | int more_fragments = frame_ctl & IEEE80211_FCTL_MOREFRAGS; | 1099 | int more_fragments = frame_ctl & IEEE80211_FCTL_MOREFRAGS; |
1100 | u8 packet_fragment_no = seq_control & IEEE80211_SCTL_FRAG; | 1100 | u8 packet_fragment_no = seq_control & IEEE80211_SCTL_FRAG; |
1101 | u16 packet_sequence_no = (seq_control & IEEE80211_SCTL_SEQ) >> 4; | 1101 | u16 packet_sequence_no = (seq_control & IEEE80211_SCTL_SEQ) >> 4; |
1102 | 1102 | ||
1103 | if (!more_fragments && packet_fragment_no == 0) { | 1103 | if (!more_fragments && packet_fragment_no == 0) { |
1104 | fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc); | 1104 | fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc); |
1105 | } else { | 1105 | } else { |
1106 | frag_rx_path(priv, &header, msdu_size, rx_packet_loc, crc, | 1106 | frag_rx_path(priv, &header, msdu_size, rx_packet_loc, crc, |
1107 | packet_sequence_no, packet_fragment_no, more_fragments); | 1107 | packet_sequence_no, packet_fragment_no, more_fragments); |
1108 | } | 1108 | } |
1109 | } | 1109 | } |
1110 | 1110 | ||
1111 | if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { | 1111 | if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { |
1112 | /* copy rest of packet into buffer */ | 1112 | /* copy rest of packet into buffer */ |
1113 | atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size); | 1113 | atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size); |
1114 | 1114 | ||
1115 | /* we use the same buffer for frag reassembly and control packets */ | 1115 | /* we use the same buffer for frag reassembly and control packets */ |
1116 | memset(priv->frag_source, 0xff, 6); | 1116 | memset(priv->frag_source, 0xff, 6); |
1117 | 1117 | ||
1118 | if (priv->do_rx_crc) { | 1118 | if (priv->do_rx_crc) { |
1119 | /* last 4 octets is crc */ | 1119 | /* last 4 octets is crc */ |
1120 | msdu_size -= 4; | 1120 | msdu_size -= 4; |
1121 | crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size); | 1121 | crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size); |
1122 | if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) { | 1122 | if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) { |
1123 | priv->dev->stats.rx_crc_errors++; | 1123 | priv->dev->stats.rx_crc_errors++; |
1124 | goto next; | 1124 | goto next; |
1125 | } | 1125 | } |
1126 | } | 1126 | } |
1127 | 1127 | ||
1128 | atmel_management_frame(priv, &header, msdu_size, | 1128 | atmel_management_frame(priv, &header, msdu_size, |
1129 | atmel_rmem8(priv, atmel_rx(priv, RX_DESC_RSSI_OFFSET, priv->rx_desc_head))); | 1129 | atmel_rmem8(priv, atmel_rx(priv, RX_DESC_RSSI_OFFSET, priv->rx_desc_head))); |
1130 | } | 1130 | } |
1131 | 1131 | ||
1132 | next: | 1132 | next: |
1133 | /* release descriptor */ | 1133 | /* release descriptor */ |
1134 | atmel_wmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head), RX_DESC_FLAG_CONSUMED); | 1134 | atmel_wmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head), RX_DESC_FLAG_CONSUMED); |
1135 | 1135 | ||
1136 | if (priv->rx_desc_head < (priv->host_info.rx_desc_count - 1)) | 1136 | if (priv->rx_desc_head < (priv->host_info.rx_desc_count - 1)) |
1137 | priv->rx_desc_head++; | 1137 | priv->rx_desc_head++; |
1138 | else | 1138 | else |
1139 | priv->rx_desc_head = 0; | 1139 | priv->rx_desc_head = 0; |
1140 | } | 1140 | } |
1141 | } | 1141 | } |
1142 | 1142 | ||
1143 | static irqreturn_t service_interrupt(int irq, void *dev_id) | 1143 | static irqreturn_t service_interrupt(int irq, void *dev_id) |
1144 | { | 1144 | { |
1145 | struct net_device *dev = (struct net_device *) dev_id; | 1145 | struct net_device *dev = (struct net_device *) dev_id; |
1146 | struct atmel_private *priv = netdev_priv(dev); | 1146 | struct atmel_private *priv = netdev_priv(dev); |
1147 | u8 isr; | 1147 | u8 isr; |
1148 | int i = -1; | 1148 | int i = -1; |
1149 | static u8 irq_order[] = { | 1149 | static u8 irq_order[] = { |
1150 | ISR_OUT_OF_RANGE, | 1150 | ISR_OUT_OF_RANGE, |
1151 | ISR_RxCOMPLETE, | 1151 | ISR_RxCOMPLETE, |
1152 | ISR_TxCOMPLETE, | 1152 | ISR_TxCOMPLETE, |
1153 | ISR_RxFRAMELOST, | 1153 | ISR_RxFRAMELOST, |
1154 | ISR_FATAL_ERROR, | 1154 | ISR_FATAL_ERROR, |
1155 | ISR_COMMAND_COMPLETE, | 1155 | ISR_COMMAND_COMPLETE, |
1156 | ISR_IBSS_MERGE, | 1156 | ISR_IBSS_MERGE, |
1157 | ISR_GENERIC_IRQ | 1157 | ISR_GENERIC_IRQ |
1158 | }; | 1158 | }; |
1159 | 1159 | ||
1160 | if (priv->card && priv->present_callback && | 1160 | if (priv->card && priv->present_callback && |
1161 | !(*priv->present_callback)(priv->card)) | 1161 | !(*priv->present_callback)(priv->card)) |
1162 | return IRQ_HANDLED; | 1162 | return IRQ_HANDLED; |
1163 | 1163 | ||
1164 | /* In this state upper-level code assumes it can mess with | 1164 | /* In this state upper-level code assumes it can mess with |
1165 | the card unhampered by interrupts which may change register state. | 1165 | the card unhampered by interrupts which may change register state. |
1166 | Note that even though the card shouldn't generate interrupts | 1166 | Note that even though the card shouldn't generate interrupts |
1167 | the inturrupt line may be shared. This allows card setup | 1167 | the inturrupt line may be shared. This allows card setup |
1168 | to go on without disabling interrupts for a long time. */ | 1168 | to go on without disabling interrupts for a long time. */ |
1169 | if (priv->station_state == STATION_STATE_DOWN) | 1169 | if (priv->station_state == STATION_STATE_DOWN) |
1170 | return IRQ_NONE; | 1170 | return IRQ_NONE; |
1171 | 1171 | ||
1172 | atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ | 1172 | atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ |
1173 | 1173 | ||
1174 | while (1) { | 1174 | while (1) { |
1175 | if (!atmel_lock_mac(priv)) { | 1175 | if (!atmel_lock_mac(priv)) { |
1176 | /* failed to contact card */ | 1176 | /* failed to contact card */ |
1177 | printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); | 1177 | printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); |
1178 | return IRQ_HANDLED; | 1178 | return IRQ_HANDLED; |
1179 | } | 1179 | } |
1180 | 1180 | ||
1181 | isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); | 1181 | isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); |
1182 | atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); | 1182 | atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); |
1183 | 1183 | ||
1184 | if (!isr) { | 1184 | if (!isr) { |
1185 | atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ | 1185 | atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ |
1186 | return i == -1 ? IRQ_NONE : IRQ_HANDLED; | 1186 | return i == -1 ? IRQ_NONE : IRQ_HANDLED; |
1187 | } | 1187 | } |
1188 | 1188 | ||
1189 | atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */ | 1189 | atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */ |
1190 | 1190 | ||
1191 | for (i = 0; i < ARRAY_SIZE(irq_order); i++) | 1191 | for (i = 0; i < ARRAY_SIZE(irq_order); i++) |
1192 | if (isr & irq_order[i]) | 1192 | if (isr & irq_order[i]) |
1193 | break; | 1193 | break; |
1194 | 1194 | ||
1195 | if (!atmel_lock_mac(priv)) { | 1195 | if (!atmel_lock_mac(priv)) { |
1196 | /* failed to contact card */ | 1196 | /* failed to contact card */ |
1197 | printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); | 1197 | printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); |
1198 | return IRQ_HANDLED; | 1198 | return IRQ_HANDLED; |
1199 | } | 1199 | } |
1200 | 1200 | ||
1201 | isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); | 1201 | isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); |
1202 | isr ^= irq_order[i]; | 1202 | isr ^= irq_order[i]; |
1203 | atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr); | 1203 | atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr); |
1204 | atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); | 1204 | atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); |
1205 | 1205 | ||
1206 | switch (irq_order[i]) { | 1206 | switch (irq_order[i]) { |
1207 | 1207 | ||
1208 | case ISR_OUT_OF_RANGE: | 1208 | case ISR_OUT_OF_RANGE: |
1209 | if (priv->operating_mode == IW_MODE_INFRA && | 1209 | if (priv->operating_mode == IW_MODE_INFRA && |
1210 | priv->station_state == STATION_STATE_READY) { | 1210 | priv->station_state == STATION_STATE_READY) { |
1211 | priv->station_is_associated = 0; | 1211 | priv->station_is_associated = 0; |
1212 | atmel_scan(priv, 1); | 1212 | atmel_scan(priv, 1); |
1213 | } | 1213 | } |
1214 | break; | 1214 | break; |
1215 | 1215 | ||
1216 | case ISR_RxFRAMELOST: | 1216 | case ISR_RxFRAMELOST: |
1217 | priv->wstats.discard.misc++; | 1217 | priv->wstats.discard.misc++; |
1218 | /* fall through */ | 1218 | /* fall through */ |
1219 | case ISR_RxCOMPLETE: | 1219 | case ISR_RxCOMPLETE: |
1220 | rx_done_irq(priv); | 1220 | rx_done_irq(priv); |
1221 | break; | 1221 | break; |
1222 | 1222 | ||
1223 | case ISR_TxCOMPLETE: | 1223 | case ISR_TxCOMPLETE: |
1224 | tx_done_irq(priv); | 1224 | tx_done_irq(priv); |
1225 | break; | 1225 | break; |
1226 | 1226 | ||
1227 | case ISR_FATAL_ERROR: | 1227 | case ISR_FATAL_ERROR: |
1228 | printk(KERN_ALERT "%s: *** FATAL error interrupt ***\n", dev->name); | 1228 | printk(KERN_ALERT "%s: *** FATAL error interrupt ***\n", dev->name); |
1229 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | 1229 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); |
1230 | break; | 1230 | break; |
1231 | 1231 | ||
1232 | case ISR_COMMAND_COMPLETE: | 1232 | case ISR_COMMAND_COMPLETE: |
1233 | atmel_command_irq(priv); | 1233 | atmel_command_irq(priv); |
1234 | break; | 1234 | break; |
1235 | 1235 | ||
1236 | case ISR_IBSS_MERGE: | 1236 | case ISR_IBSS_MERGE: |
1237 | atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, | 1237 | atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, |
1238 | priv->CurrentBSSID, 6); | 1238 | priv->CurrentBSSID, 6); |
1239 | /* The WPA stuff cares about the current AP address */ | 1239 | /* The WPA stuff cares about the current AP address */ |
1240 | if (priv->use_wpa) | 1240 | if (priv->use_wpa) |
1241 | build_wpa_mib(priv); | 1241 | build_wpa_mib(priv); |
1242 | break; | 1242 | break; |
1243 | case ISR_GENERIC_IRQ: | 1243 | case ISR_GENERIC_IRQ: |
1244 | printk(KERN_INFO "%s: Generic_irq received.\n", dev->name); | 1244 | printk(KERN_INFO "%s: Generic_irq received.\n", dev->name); |
1245 | break; | 1245 | break; |
1246 | } | 1246 | } |
1247 | } | 1247 | } |
1248 | } | 1248 | } |
1249 | 1249 | ||
1250 | static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev) | 1250 | static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev) |
1251 | { | 1251 | { |
1252 | struct atmel_private *priv = netdev_priv(dev); | 1252 | struct atmel_private *priv = netdev_priv(dev); |
1253 | 1253 | ||
1254 | /* update the link quality here in case we are seeing no beacons | 1254 | /* update the link quality here in case we are seeing no beacons |
1255 | at all to drive the process */ | 1255 | at all to drive the process */ |
1256 | atmel_smooth_qual(priv); | 1256 | atmel_smooth_qual(priv); |
1257 | 1257 | ||
1258 | priv->wstats.status = priv->station_state; | 1258 | priv->wstats.status = priv->station_state; |
1259 | 1259 | ||
1260 | if (priv->operating_mode == IW_MODE_INFRA) { | 1260 | if (priv->operating_mode == IW_MODE_INFRA) { |
1261 | if (priv->station_state != STATION_STATE_READY) { | 1261 | if (priv->station_state != STATION_STATE_READY) { |
1262 | priv->wstats.qual.qual = 0; | 1262 | priv->wstats.qual.qual = 0; |
1263 | priv->wstats.qual.level = 0; | 1263 | priv->wstats.qual.level = 0; |
1264 | priv->wstats.qual.updated = (IW_QUAL_QUAL_INVALID | 1264 | priv->wstats.qual.updated = (IW_QUAL_QUAL_INVALID |
1265 | | IW_QUAL_LEVEL_INVALID); | 1265 | | IW_QUAL_LEVEL_INVALID); |
1266 | } | 1266 | } |
1267 | priv->wstats.qual.noise = 0; | 1267 | priv->wstats.qual.noise = 0; |
1268 | priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID; | 1268 | priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID; |
1269 | } else { | 1269 | } else { |
1270 | /* Quality levels cannot be determined in ad-hoc mode, | 1270 | /* Quality levels cannot be determined in ad-hoc mode, |
1271 | because we can 'hear' more that one remote station. */ | 1271 | because we can 'hear' more that one remote station. */ |
1272 | priv->wstats.qual.qual = 0; | 1272 | priv->wstats.qual.qual = 0; |
1273 | priv->wstats.qual.level = 0; | 1273 | priv->wstats.qual.level = 0; |
1274 | priv->wstats.qual.noise = 0; | 1274 | priv->wstats.qual.noise = 0; |
1275 | priv->wstats.qual.updated = IW_QUAL_QUAL_INVALID | 1275 | priv->wstats.qual.updated = IW_QUAL_QUAL_INVALID |
1276 | | IW_QUAL_LEVEL_INVALID | 1276 | | IW_QUAL_LEVEL_INVALID |
1277 | | IW_QUAL_NOISE_INVALID; | 1277 | | IW_QUAL_NOISE_INVALID; |
1278 | priv->wstats.miss.beacon = 0; | 1278 | priv->wstats.miss.beacon = 0; |
1279 | } | 1279 | } |
1280 | 1280 | ||
1281 | return &priv->wstats; | 1281 | return &priv->wstats; |
1282 | } | 1282 | } |
1283 | 1283 | ||
1284 | static int atmel_change_mtu(struct net_device *dev, int new_mtu) | 1284 | static int atmel_change_mtu(struct net_device *dev, int new_mtu) |
1285 | { | 1285 | { |
1286 | if ((new_mtu < 68) || (new_mtu > 2312)) | 1286 | if ((new_mtu < 68) || (new_mtu > 2312)) |
1287 | return -EINVAL; | 1287 | return -EINVAL; |
1288 | dev->mtu = new_mtu; | 1288 | dev->mtu = new_mtu; |
1289 | return 0; | 1289 | return 0; |
1290 | } | 1290 | } |
1291 | 1291 | ||
1292 | static int atmel_set_mac_address(struct net_device *dev, void *p) | 1292 | static int atmel_set_mac_address(struct net_device *dev, void *p) |
1293 | { | 1293 | { |
1294 | struct sockaddr *addr = p; | 1294 | struct sockaddr *addr = p; |
1295 | 1295 | ||
1296 | memcpy (dev->dev_addr, addr->sa_data, dev->addr_len); | 1296 | memcpy (dev->dev_addr, addr->sa_data, dev->addr_len); |
1297 | return atmel_open(dev); | 1297 | return atmel_open(dev); |
1298 | } | 1298 | } |
1299 | 1299 | ||
1300 | EXPORT_SYMBOL(atmel_open); | 1300 | EXPORT_SYMBOL(atmel_open); |
1301 | 1301 | ||
1302 | int atmel_open(struct net_device *dev) | 1302 | int atmel_open(struct net_device *dev) |
1303 | { | 1303 | { |
1304 | struct atmel_private *priv = netdev_priv(dev); | 1304 | struct atmel_private *priv = netdev_priv(dev); |
1305 | int i, channel, err; | 1305 | int i, channel, err; |
1306 | 1306 | ||
1307 | /* any scheduled timer is no longer needed and might screw things up.. */ | 1307 | /* any scheduled timer is no longer needed and might screw things up.. */ |
1308 | del_timer_sync(&priv->management_timer); | 1308 | del_timer_sync(&priv->management_timer); |
1309 | 1309 | ||
1310 | /* Interrupts will not touch the card once in this state... */ | 1310 | /* Interrupts will not touch the card once in this state... */ |
1311 | priv->station_state = STATION_STATE_DOWN; | 1311 | priv->station_state = STATION_STATE_DOWN; |
1312 | 1312 | ||
1313 | if (priv->new_SSID_size) { | 1313 | if (priv->new_SSID_size) { |
1314 | memcpy(priv->SSID, priv->new_SSID, priv->new_SSID_size); | 1314 | memcpy(priv->SSID, priv->new_SSID, priv->new_SSID_size); |
1315 | priv->SSID_size = priv->new_SSID_size; | 1315 | priv->SSID_size = priv->new_SSID_size; |
1316 | priv->new_SSID_size = 0; | 1316 | priv->new_SSID_size = 0; |
1317 | } | 1317 | } |
1318 | priv->BSS_list_entries = 0; | 1318 | priv->BSS_list_entries = 0; |
1319 | 1319 | ||
1320 | priv->AuthenticationRequestRetryCnt = 0; | 1320 | priv->AuthenticationRequestRetryCnt = 0; |
1321 | priv->AssociationRequestRetryCnt = 0; | 1321 | priv->AssociationRequestRetryCnt = 0; |
1322 | priv->ReAssociationRequestRetryCnt = 0; | 1322 | priv->ReAssociationRequestRetryCnt = 0; |
1323 | priv->CurrentAuthentTransactionSeqNum = 0x0001; | 1323 | priv->CurrentAuthentTransactionSeqNum = 0x0001; |
1324 | priv->ExpectedAuthentTransactionSeqNum = 0x0002; | 1324 | priv->ExpectedAuthentTransactionSeqNum = 0x0002; |
1325 | 1325 | ||
1326 | priv->site_survey_state = SITE_SURVEY_IDLE; | 1326 | priv->site_survey_state = SITE_SURVEY_IDLE; |
1327 | priv->station_is_associated = 0; | 1327 | priv->station_is_associated = 0; |
1328 | 1328 | ||
1329 | err = reset_atmel_card(dev); | 1329 | err = reset_atmel_card(dev); |
1330 | if (err) | 1330 | if (err) |
1331 | return err; | 1331 | return err; |
1332 | 1332 | ||
1333 | if (priv->config_reg_domain) { | 1333 | if (priv->config_reg_domain) { |
1334 | priv->reg_domain = priv->config_reg_domain; | 1334 | priv->reg_domain = priv->config_reg_domain; |
1335 | atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS, priv->reg_domain); | 1335 | atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS, priv->reg_domain); |
1336 | } else { | 1336 | } else { |
1337 | priv->reg_domain = atmel_get_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS); | 1337 | priv->reg_domain = atmel_get_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS); |
1338 | for (i = 0; i < ARRAY_SIZE(channel_table); i++) | 1338 | for (i = 0; i < ARRAY_SIZE(channel_table); i++) |
1339 | if (priv->reg_domain == channel_table[i].reg_domain) | 1339 | if (priv->reg_domain == channel_table[i].reg_domain) |
1340 | break; | 1340 | break; |
1341 | if (i == ARRAY_SIZE(channel_table)) { | 1341 | if (i == ARRAY_SIZE(channel_table)) { |
1342 | priv->reg_domain = REG_DOMAIN_MKK1; | 1342 | priv->reg_domain = REG_DOMAIN_MKK1; |
1343 | printk(KERN_ALERT "%s: failed to get regulatory domain: assuming MKK1.\n", dev->name); | 1343 | printk(KERN_ALERT "%s: failed to get regulatory domain: assuming MKK1.\n", dev->name); |
1344 | } | 1344 | } |
1345 | } | 1345 | } |
1346 | 1346 | ||
1347 | if ((channel = atmel_validate_channel(priv, priv->channel))) | 1347 | if ((channel = atmel_validate_channel(priv, priv->channel))) |
1348 | priv->channel = channel; | 1348 | priv->channel = channel; |
1349 | 1349 | ||
1350 | /* this moves station_state on.... */ | 1350 | /* this moves station_state on.... */ |
1351 | atmel_scan(priv, 1); | 1351 | atmel_scan(priv, 1); |
1352 | 1352 | ||
1353 | atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */ | 1353 | atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */ |
1354 | return 0; | 1354 | return 0; |
1355 | } | 1355 | } |
1356 | 1356 | ||
1357 | static int atmel_close(struct net_device *dev) | 1357 | static int atmel_close(struct net_device *dev) |
1358 | { | 1358 | { |
1359 | struct atmel_private *priv = netdev_priv(dev); | 1359 | struct atmel_private *priv = netdev_priv(dev); |
1360 | 1360 | ||
1361 | /* Send event to userspace that we are disassociating */ | 1361 | /* Send event to userspace that we are disassociating */ |
1362 | if (priv->station_state == STATION_STATE_READY) { | 1362 | if (priv->station_state == STATION_STATE_READY) { |
1363 | union iwreq_data wrqu; | 1363 | union iwreq_data wrqu; |
1364 | 1364 | ||
1365 | wrqu.data.length = 0; | 1365 | wrqu.data.length = 0; |
1366 | wrqu.data.flags = 0; | 1366 | wrqu.data.flags = 0; |
1367 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 1367 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
1368 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | 1368 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); |
1369 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | 1369 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); |
1370 | } | 1370 | } |
1371 | 1371 | ||
1372 | atmel_enter_state(priv, STATION_STATE_DOWN); | 1372 | atmel_enter_state(priv, STATION_STATE_DOWN); |
1373 | 1373 | ||
1374 | if (priv->bus_type == BUS_TYPE_PCCARD) | 1374 | if (priv->bus_type == BUS_TYPE_PCCARD) |
1375 | atmel_write16(dev, GCR, 0x0060); | 1375 | atmel_write16(dev, GCR, 0x0060); |
1376 | atmel_write16(dev, GCR, 0x0040); | 1376 | atmel_write16(dev, GCR, 0x0040); |
1377 | return 0; | 1377 | return 0; |
1378 | } | 1378 | } |
1379 | 1379 | ||
1380 | static int atmel_validate_channel(struct atmel_private *priv, int channel) | 1380 | static int atmel_validate_channel(struct atmel_private *priv, int channel) |
1381 | { | 1381 | { |
1382 | /* check that channel is OK, if so return zero, | 1382 | /* check that channel is OK, if so return zero, |
1383 | else return suitable default channel */ | 1383 | else return suitable default channel */ |
1384 | int i; | 1384 | int i; |
1385 | 1385 | ||
1386 | for (i = 0; i < ARRAY_SIZE(channel_table); i++) | 1386 | for (i = 0; i < ARRAY_SIZE(channel_table); i++) |
1387 | if (priv->reg_domain == channel_table[i].reg_domain) { | 1387 | if (priv->reg_domain == channel_table[i].reg_domain) { |
1388 | if (channel >= channel_table[i].min && | 1388 | if (channel >= channel_table[i].min && |
1389 | channel <= channel_table[i].max) | 1389 | channel <= channel_table[i].max) |
1390 | return 0; | 1390 | return 0; |
1391 | else | 1391 | else |
1392 | return channel_table[i].min; | 1392 | return channel_table[i].min; |
1393 | } | 1393 | } |
1394 | return 0; | 1394 | return 0; |
1395 | } | 1395 | } |
1396 | 1396 | ||
1397 | static int atmel_proc_output (char *buf, struct atmel_private *priv) | 1397 | static int atmel_proc_output (char *buf, struct atmel_private *priv) |
1398 | { | 1398 | { |
1399 | int i; | 1399 | int i; |
1400 | char *p = buf; | 1400 | char *p = buf; |
1401 | char *s, *r, *c; | 1401 | char *s, *r, *c; |
1402 | 1402 | ||
1403 | p += sprintf(p, "Driver version:\t\t%d.%d\n", | 1403 | p += sprintf(p, "Driver version:\t\t%d.%d\n", |
1404 | DRIVER_MAJOR, DRIVER_MINOR); | 1404 | DRIVER_MAJOR, DRIVER_MINOR); |
1405 | 1405 | ||
1406 | if (priv->station_state != STATION_STATE_DOWN) { | 1406 | if (priv->station_state != STATION_STATE_DOWN) { |
1407 | p += sprintf(p, "Firmware version:\t%d.%d build %d\n" | 1407 | p += sprintf(p, "Firmware version:\t%d.%d build %d\n" |
1408 | "Firmware location:\t", | 1408 | "Firmware location:\t", |
1409 | priv->host_info.major_version, | 1409 | priv->host_info.major_version, |
1410 | priv->host_info.minor_version, | 1410 | priv->host_info.minor_version, |
1411 | priv->host_info.build_version); | 1411 | priv->host_info.build_version); |
1412 | 1412 | ||
1413 | if (priv->card_type != CARD_TYPE_EEPROM) | 1413 | if (priv->card_type != CARD_TYPE_EEPROM) |
1414 | p += sprintf(p, "on card\n"); | 1414 | p += sprintf(p, "on card\n"); |
1415 | else if (priv->firmware) | 1415 | else if (priv->firmware) |
1416 | p += sprintf(p, "%s loaded by host\n", | 1416 | p += sprintf(p, "%s loaded by host\n", |
1417 | priv->firmware_id); | 1417 | priv->firmware_id); |
1418 | else | 1418 | else |
1419 | p += sprintf(p, "%s loaded by hotplug\n", | 1419 | p += sprintf(p, "%s loaded by hotplug\n", |
1420 | priv->firmware_id); | 1420 | priv->firmware_id); |
1421 | 1421 | ||
1422 | switch (priv->card_type) { | 1422 | switch (priv->card_type) { |
1423 | case CARD_TYPE_PARALLEL_FLASH: | 1423 | case CARD_TYPE_PARALLEL_FLASH: |
1424 | c = "Parallel flash"; | 1424 | c = "Parallel flash"; |
1425 | break; | 1425 | break; |
1426 | case CARD_TYPE_SPI_FLASH: | 1426 | case CARD_TYPE_SPI_FLASH: |
1427 | c = "SPI flash\n"; | 1427 | c = "SPI flash\n"; |
1428 | break; | 1428 | break; |
1429 | case CARD_TYPE_EEPROM: | 1429 | case CARD_TYPE_EEPROM: |
1430 | c = "EEPROM"; | 1430 | c = "EEPROM"; |
1431 | break; | 1431 | break; |
1432 | default: | 1432 | default: |
1433 | c = "<unknown>"; | 1433 | c = "<unknown>"; |
1434 | } | 1434 | } |
1435 | 1435 | ||
1436 | r = "<unknown>"; | 1436 | r = "<unknown>"; |
1437 | for (i = 0; i < ARRAY_SIZE(channel_table); i++) | 1437 | for (i = 0; i < ARRAY_SIZE(channel_table); i++) |
1438 | if (priv->reg_domain == channel_table[i].reg_domain) | 1438 | if (priv->reg_domain == channel_table[i].reg_domain) |
1439 | r = channel_table[i].name; | 1439 | r = channel_table[i].name; |
1440 | 1440 | ||
1441 | p += sprintf(p, "MAC memory type:\t%s\n", c); | 1441 | p += sprintf(p, "MAC memory type:\t%s\n", c); |
1442 | p += sprintf(p, "Regulatory domain:\t%s\n", r); | 1442 | p += sprintf(p, "Regulatory domain:\t%s\n", r); |
1443 | p += sprintf(p, "Host CRC checking:\t%s\n", | 1443 | p += sprintf(p, "Host CRC checking:\t%s\n", |
1444 | priv->do_rx_crc ? "On" : "Off"); | 1444 | priv->do_rx_crc ? "On" : "Off"); |
1445 | p += sprintf(p, "WPA-capable firmware:\t%s\n", | 1445 | p += sprintf(p, "WPA-capable firmware:\t%s\n", |
1446 | priv->use_wpa ? "Yes" : "No"); | 1446 | priv->use_wpa ? "Yes" : "No"); |
1447 | } | 1447 | } |
1448 | 1448 | ||
1449 | switch (priv->station_state) { | 1449 | switch (priv->station_state) { |
1450 | case STATION_STATE_SCANNING: | 1450 | case STATION_STATE_SCANNING: |
1451 | s = "Scanning"; | 1451 | s = "Scanning"; |
1452 | break; | 1452 | break; |
1453 | case STATION_STATE_JOINNING: | 1453 | case STATION_STATE_JOINNING: |
1454 | s = "Joining"; | 1454 | s = "Joining"; |
1455 | break; | 1455 | break; |
1456 | case STATION_STATE_AUTHENTICATING: | 1456 | case STATION_STATE_AUTHENTICATING: |
1457 | s = "Authenticating"; | 1457 | s = "Authenticating"; |
1458 | break; | 1458 | break; |
1459 | case STATION_STATE_ASSOCIATING: | 1459 | case STATION_STATE_ASSOCIATING: |
1460 | s = "Associating"; | 1460 | s = "Associating"; |
1461 | break; | 1461 | break; |
1462 | case STATION_STATE_READY: | 1462 | case STATION_STATE_READY: |
1463 | s = "Ready"; | 1463 | s = "Ready"; |
1464 | break; | 1464 | break; |
1465 | case STATION_STATE_REASSOCIATING: | 1465 | case STATION_STATE_REASSOCIATING: |
1466 | s = "Reassociating"; | 1466 | s = "Reassociating"; |
1467 | break; | 1467 | break; |
1468 | case STATION_STATE_MGMT_ERROR: | 1468 | case STATION_STATE_MGMT_ERROR: |
1469 | s = "Management error"; | 1469 | s = "Management error"; |
1470 | break; | 1470 | break; |
1471 | case STATION_STATE_DOWN: | 1471 | case STATION_STATE_DOWN: |
1472 | s = "Down"; | 1472 | s = "Down"; |
1473 | break; | 1473 | break; |
1474 | default: | 1474 | default: |
1475 | s = "<unknown>"; | 1475 | s = "<unknown>"; |
1476 | } | 1476 | } |
1477 | 1477 | ||
1478 | p += sprintf(p, "Current state:\t\t%s\n", s); | 1478 | p += sprintf(p, "Current state:\t\t%s\n", s); |
1479 | return p - buf; | 1479 | return p - buf; |
1480 | } | 1480 | } |
1481 | 1481 | ||
1482 | static int atmel_read_proc(char *page, char **start, off_t off, | 1482 | static int atmel_read_proc(char *page, char **start, off_t off, |
1483 | int count, int *eof, void *data) | 1483 | int count, int *eof, void *data) |
1484 | { | 1484 | { |
1485 | struct atmel_private *priv = data; | 1485 | struct atmel_private *priv = data; |
1486 | int len = atmel_proc_output (page, priv); | 1486 | int len = atmel_proc_output (page, priv); |
1487 | if (len <= off+count) | 1487 | if (len <= off+count) |
1488 | *eof = 1; | 1488 | *eof = 1; |
1489 | *start = page + off; | 1489 | *start = page + off; |
1490 | len -= off; | 1490 | len -= off; |
1491 | if (len > count) | 1491 | if (len > count) |
1492 | len = count; | 1492 | len = count; |
1493 | if (len < 0) | 1493 | if (len < 0) |
1494 | len = 0; | 1494 | len = 0; |
1495 | return len; | 1495 | return len; |
1496 | } | 1496 | } |
1497 | 1497 | ||
1498 | static const struct net_device_ops atmel_netdev_ops = { | 1498 | static const struct net_device_ops atmel_netdev_ops = { |
1499 | .ndo_open = atmel_open, | 1499 | .ndo_open = atmel_open, |
1500 | .ndo_stop = atmel_close, | 1500 | .ndo_stop = atmel_close, |
1501 | .ndo_change_mtu = atmel_change_mtu, | 1501 | .ndo_change_mtu = atmel_change_mtu, |
1502 | .ndo_set_mac_address = atmel_set_mac_address, | 1502 | .ndo_set_mac_address = atmel_set_mac_address, |
1503 | .ndo_start_xmit = start_tx, | 1503 | .ndo_start_xmit = start_tx, |
1504 | .ndo_do_ioctl = atmel_ioctl, | 1504 | .ndo_do_ioctl = atmel_ioctl, |
1505 | .ndo_validate_addr = eth_validate_addr, | 1505 | .ndo_validate_addr = eth_validate_addr, |
1506 | }; | 1506 | }; |
1507 | 1507 | ||
1508 | struct net_device *init_atmel_card(unsigned short irq, unsigned long port, | 1508 | struct net_device *init_atmel_card(unsigned short irq, unsigned long port, |
1509 | const AtmelFWType fw_type, | 1509 | const AtmelFWType fw_type, |
1510 | struct device *sys_dev, | 1510 | struct device *sys_dev, |
1511 | int (*card_present)(void *), void *card) | 1511 | int (*card_present)(void *), void *card) |
1512 | { | 1512 | { |
1513 | struct proc_dir_entry *ent; | 1513 | struct proc_dir_entry *ent; |
1514 | struct net_device *dev; | 1514 | struct net_device *dev; |
1515 | struct atmel_private *priv; | 1515 | struct atmel_private *priv; |
1516 | int rc; | 1516 | int rc; |
1517 | 1517 | ||
1518 | /* Create the network device object. */ | 1518 | /* Create the network device object. */ |
1519 | dev = alloc_etherdev(sizeof(*priv)); | 1519 | dev = alloc_etherdev(sizeof(*priv)); |
1520 | if (!dev) { | 1520 | if (!dev) { |
1521 | printk(KERN_ERR "atmel: Couldn't alloc_etherdev\n"); | 1521 | printk(KERN_ERR "atmel: Couldn't alloc_etherdev\n"); |
1522 | return NULL; | 1522 | return NULL; |
1523 | } | 1523 | } |
1524 | if (dev_alloc_name(dev, dev->name) < 0) { | 1524 | if (dev_alloc_name(dev, dev->name) < 0) { |
1525 | printk(KERN_ERR "atmel: Couldn't get name!\n"); | 1525 | printk(KERN_ERR "atmel: Couldn't get name!\n"); |
1526 | goto err_out_free; | 1526 | goto err_out_free; |
1527 | } | 1527 | } |
1528 | 1528 | ||
1529 | priv = netdev_priv(dev); | 1529 | priv = netdev_priv(dev); |
1530 | priv->dev = dev; | 1530 | priv->dev = dev; |
1531 | priv->sys_dev = sys_dev; | 1531 | priv->sys_dev = sys_dev; |
1532 | priv->present_callback = card_present; | 1532 | priv->present_callback = card_present; |
1533 | priv->card = card; | 1533 | priv->card = card; |
1534 | priv->firmware = NULL; | 1534 | priv->firmware = NULL; |
1535 | priv->firmware_id[0] = '\0'; | 1535 | priv->firmware_id[0] = '\0'; |
1536 | priv->firmware_type = fw_type; | 1536 | priv->firmware_type = fw_type; |
1537 | if (firmware) /* module parameter */ | 1537 | if (firmware) /* module parameter */ |
1538 | strcpy(priv->firmware_id, firmware); | 1538 | strcpy(priv->firmware_id, firmware); |
1539 | priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI; | 1539 | priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI; |
1540 | priv->station_state = STATION_STATE_DOWN; | 1540 | priv->station_state = STATION_STATE_DOWN; |
1541 | priv->do_rx_crc = 0; | 1541 | priv->do_rx_crc = 0; |
1542 | /* For PCMCIA cards, some chips need CRC, some don't | 1542 | /* For PCMCIA cards, some chips need CRC, some don't |
1543 | so we have to probe. */ | 1543 | so we have to probe. */ |
1544 | if (priv->bus_type == BUS_TYPE_PCCARD) { | 1544 | if (priv->bus_type == BUS_TYPE_PCCARD) { |
1545 | priv->probe_crc = 1; | 1545 | priv->probe_crc = 1; |
1546 | priv->crc_ok_cnt = priv->crc_ko_cnt = 0; | 1546 | priv->crc_ok_cnt = priv->crc_ko_cnt = 0; |
1547 | } else | 1547 | } else |
1548 | priv->probe_crc = 0; | 1548 | priv->probe_crc = 0; |
1549 | priv->last_qual = jiffies; | 1549 | priv->last_qual = jiffies; |
1550 | priv->last_beacon_timestamp = 0; | 1550 | priv->last_beacon_timestamp = 0; |
1551 | memset(priv->frag_source, 0xff, sizeof(priv->frag_source)); | 1551 | memset(priv->frag_source, 0xff, sizeof(priv->frag_source)); |
1552 | memset(priv->BSSID, 0, 6); | 1552 | memset(priv->BSSID, 0, 6); |
1553 | priv->CurrentBSSID[0] = 0xFF; /* Initialize to something invalid.... */ | 1553 | priv->CurrentBSSID[0] = 0xFF; /* Initialize to something invalid.... */ |
1554 | priv->station_was_associated = 0; | 1554 | priv->station_was_associated = 0; |
1555 | 1555 | ||
1556 | priv->last_survey = jiffies; | 1556 | priv->last_survey = jiffies; |
1557 | priv->preamble = LONG_PREAMBLE; | 1557 | priv->preamble = LONG_PREAMBLE; |
1558 | priv->operating_mode = IW_MODE_INFRA; | 1558 | priv->operating_mode = IW_MODE_INFRA; |
1559 | priv->connect_to_any_BSS = 0; | 1559 | priv->connect_to_any_BSS = 0; |
1560 | priv->config_reg_domain = 0; | 1560 | priv->config_reg_domain = 0; |
1561 | priv->reg_domain = 0; | 1561 | priv->reg_domain = 0; |
1562 | priv->tx_rate = 3; | 1562 | priv->tx_rate = 3; |
1563 | priv->auto_tx_rate = 1; | 1563 | priv->auto_tx_rate = 1; |
1564 | priv->channel = 4; | 1564 | priv->channel = 4; |
1565 | priv->power_mode = 0; | 1565 | priv->power_mode = 0; |
1566 | priv->SSID[0] = '\0'; | 1566 | priv->SSID[0] = '\0'; |
1567 | priv->SSID_size = 0; | 1567 | priv->SSID_size = 0; |
1568 | priv->new_SSID_size = 0; | 1568 | priv->new_SSID_size = 0; |
1569 | priv->frag_threshold = 2346; | 1569 | priv->frag_threshold = 2346; |
1570 | priv->rts_threshold = 2347; | 1570 | priv->rts_threshold = 2347; |
1571 | priv->short_retry = 7; | 1571 | priv->short_retry = 7; |
1572 | priv->long_retry = 4; | 1572 | priv->long_retry = 4; |
1573 | 1573 | ||
1574 | priv->wep_is_on = 0; | 1574 | priv->wep_is_on = 0; |
1575 | priv->default_key = 0; | 1575 | priv->default_key = 0; |
1576 | priv->encryption_level = 0; | 1576 | priv->encryption_level = 0; |
1577 | priv->exclude_unencrypted = 0; | 1577 | priv->exclude_unencrypted = 0; |
1578 | priv->group_cipher_suite = priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; | 1578 | priv->group_cipher_suite = priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; |
1579 | priv->use_wpa = 0; | 1579 | priv->use_wpa = 0; |
1580 | memset(priv->wep_keys, 0, sizeof(priv->wep_keys)); | 1580 | memset(priv->wep_keys, 0, sizeof(priv->wep_keys)); |
1581 | memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len)); | 1581 | memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len)); |
1582 | 1582 | ||
1583 | priv->default_beacon_period = priv->beacon_period = 100; | 1583 | priv->default_beacon_period = priv->beacon_period = 100; |
1584 | priv->listen_interval = 1; | 1584 | priv->listen_interval = 1; |
1585 | 1585 | ||
1586 | init_timer(&priv->management_timer); | 1586 | init_timer(&priv->management_timer); |
1587 | spin_lock_init(&priv->irqlock); | 1587 | spin_lock_init(&priv->irqlock); |
1588 | spin_lock_init(&priv->timerlock); | 1588 | spin_lock_init(&priv->timerlock); |
1589 | priv->management_timer.function = atmel_management_timer; | 1589 | priv->management_timer.function = atmel_management_timer; |
1590 | priv->management_timer.data = (unsigned long) dev; | 1590 | priv->management_timer.data = (unsigned long) dev; |
1591 | 1591 | ||
1592 | dev->netdev_ops = &atmel_netdev_ops; | 1592 | dev->netdev_ops = &atmel_netdev_ops; |
1593 | dev->wireless_handlers = &atmel_handler_def; | 1593 | dev->wireless_handlers = &atmel_handler_def; |
1594 | dev->irq = irq; | 1594 | dev->irq = irq; |
1595 | dev->base_addr = port; | 1595 | dev->base_addr = port; |
1596 | 1596 | ||
1597 | SET_NETDEV_DEV(dev, sys_dev); | 1597 | SET_NETDEV_DEV(dev, sys_dev); |
1598 | 1598 | ||
1599 | if ((rc = request_irq(dev->irq, service_interrupt, IRQF_SHARED, dev->name, dev))) { | 1599 | if ((rc = request_irq(dev->irq, service_interrupt, IRQF_SHARED, dev->name, dev))) { |
1600 | printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc); | 1600 | printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc); |
1601 | goto err_out_free; | 1601 | goto err_out_free; |
1602 | } | 1602 | } |
1603 | 1603 | ||
1604 | if (!request_region(dev->base_addr, 32, | 1604 | if (!request_region(dev->base_addr, 32, |
1605 | priv->bus_type == BUS_TYPE_PCCARD ? "atmel_cs" : "atmel_pci")) { | 1605 | priv->bus_type == BUS_TYPE_PCCARD ? "atmel_cs" : "atmel_pci")) { |
1606 | goto err_out_irq; | 1606 | goto err_out_irq; |
1607 | } | 1607 | } |
1608 | 1608 | ||
1609 | if (register_netdev(dev)) | 1609 | if (register_netdev(dev)) |
1610 | goto err_out_res; | 1610 | goto err_out_res; |
1611 | 1611 | ||
1612 | if (!probe_atmel_card(dev)) { | 1612 | if (!probe_atmel_card(dev)) { |
1613 | unregister_netdev(dev); | 1613 | unregister_netdev(dev); |
1614 | goto err_out_res; | 1614 | goto err_out_res; |
1615 | } | 1615 | } |
1616 | 1616 | ||
1617 | netif_carrier_off(dev); | 1617 | netif_carrier_off(dev); |
1618 | 1618 | ||
1619 | ent = create_proc_read_entry ("driver/atmel", 0, NULL, atmel_read_proc, priv); | 1619 | ent = create_proc_read_entry ("driver/atmel", 0, NULL, atmel_read_proc, priv); |
1620 | if (!ent) | 1620 | if (!ent) |
1621 | printk(KERN_WARNING "atmel: unable to create /proc entry.\n"); | 1621 | printk(KERN_WARNING "atmel: unable to create /proc entry.\n"); |
1622 | 1622 | ||
1623 | printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n", | 1623 | printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n", |
1624 | dev->name, DRIVER_MAJOR, DRIVER_MINOR, dev->dev_addr); | 1624 | dev->name, DRIVER_MAJOR, DRIVER_MINOR, dev->dev_addr); |
1625 | 1625 | ||
1626 | return dev; | 1626 | return dev; |
1627 | 1627 | ||
1628 | err_out_res: | 1628 | err_out_res: |
1629 | release_region(dev->base_addr, 32); | 1629 | release_region(dev->base_addr, 32); |
1630 | err_out_irq: | 1630 | err_out_irq: |
1631 | free_irq(dev->irq, dev); | 1631 | free_irq(dev->irq, dev); |
1632 | err_out_free: | 1632 | err_out_free: |
1633 | free_netdev(dev); | 1633 | free_netdev(dev); |
1634 | return NULL; | 1634 | return NULL; |
1635 | } | 1635 | } |
1636 | 1636 | ||
1637 | EXPORT_SYMBOL(init_atmel_card); | 1637 | EXPORT_SYMBOL(init_atmel_card); |
1638 | 1638 | ||
1639 | void stop_atmel_card(struct net_device *dev) | 1639 | void stop_atmel_card(struct net_device *dev) |
1640 | { | 1640 | { |
1641 | struct atmel_private *priv = netdev_priv(dev); | 1641 | struct atmel_private *priv = netdev_priv(dev); |
1642 | 1642 | ||
1643 | /* put a brick on it... */ | 1643 | /* put a brick on it... */ |
1644 | if (priv->bus_type == BUS_TYPE_PCCARD) | 1644 | if (priv->bus_type == BUS_TYPE_PCCARD) |
1645 | atmel_write16(dev, GCR, 0x0060); | 1645 | atmel_write16(dev, GCR, 0x0060); |
1646 | atmel_write16(dev, GCR, 0x0040); | 1646 | atmel_write16(dev, GCR, 0x0040); |
1647 | 1647 | ||
1648 | del_timer_sync(&priv->management_timer); | 1648 | del_timer_sync(&priv->management_timer); |
1649 | unregister_netdev(dev); | 1649 | unregister_netdev(dev); |
1650 | remove_proc_entry("driver/atmel", NULL); | 1650 | remove_proc_entry("driver/atmel", NULL); |
1651 | free_irq(dev->irq, dev); | 1651 | free_irq(dev->irq, dev); |
1652 | kfree(priv->firmware); | 1652 | kfree(priv->firmware); |
1653 | release_region(dev->base_addr, 32); | 1653 | release_region(dev->base_addr, 32); |
1654 | free_netdev(dev); | 1654 | free_netdev(dev); |
1655 | } | 1655 | } |
1656 | 1656 | ||
1657 | EXPORT_SYMBOL(stop_atmel_card); | 1657 | EXPORT_SYMBOL(stop_atmel_card); |
1658 | 1658 | ||
1659 | static int atmel_set_essid(struct net_device *dev, | 1659 | static int atmel_set_essid(struct net_device *dev, |
1660 | struct iw_request_info *info, | 1660 | struct iw_request_info *info, |
1661 | struct iw_point *dwrq, | 1661 | struct iw_point *dwrq, |
1662 | char *extra) | 1662 | char *extra) |
1663 | { | 1663 | { |
1664 | struct atmel_private *priv = netdev_priv(dev); | 1664 | struct atmel_private *priv = netdev_priv(dev); |
1665 | 1665 | ||
1666 | /* Check if we asked for `any' */ | 1666 | /* Check if we asked for `any' */ |
1667 | if (dwrq->flags == 0) { | 1667 | if (dwrq->flags == 0) { |
1668 | priv->connect_to_any_BSS = 1; | 1668 | priv->connect_to_any_BSS = 1; |
1669 | } else { | 1669 | } else { |
1670 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | 1670 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; |
1671 | 1671 | ||
1672 | priv->connect_to_any_BSS = 0; | 1672 | priv->connect_to_any_BSS = 0; |
1673 | 1673 | ||
1674 | /* Check the size of the string */ | 1674 | /* Check the size of the string */ |
1675 | if (dwrq->length > MAX_SSID_LENGTH) | 1675 | if (dwrq->length > MAX_SSID_LENGTH) |
1676 | return -E2BIG; | 1676 | return -E2BIG; |
1677 | if (index != 0) | 1677 | if (index != 0) |
1678 | return -EINVAL; | 1678 | return -EINVAL; |
1679 | 1679 | ||
1680 | memcpy(priv->new_SSID, extra, dwrq->length); | 1680 | memcpy(priv->new_SSID, extra, dwrq->length); |
1681 | priv->new_SSID_size = dwrq->length; | 1681 | priv->new_SSID_size = dwrq->length; |
1682 | } | 1682 | } |
1683 | 1683 | ||
1684 | return -EINPROGRESS; | 1684 | return -EINPROGRESS; |
1685 | } | 1685 | } |
1686 | 1686 | ||
1687 | static int atmel_get_essid(struct net_device *dev, | 1687 | static int atmel_get_essid(struct net_device *dev, |
1688 | struct iw_request_info *info, | 1688 | struct iw_request_info *info, |
1689 | struct iw_point *dwrq, | 1689 | struct iw_point *dwrq, |
1690 | char *extra) | 1690 | char *extra) |
1691 | { | 1691 | { |
1692 | struct atmel_private *priv = netdev_priv(dev); | 1692 | struct atmel_private *priv = netdev_priv(dev); |
1693 | 1693 | ||
1694 | /* Get the current SSID */ | 1694 | /* Get the current SSID */ |
1695 | if (priv->new_SSID_size != 0) { | 1695 | if (priv->new_SSID_size != 0) { |
1696 | memcpy(extra, priv->new_SSID, priv->new_SSID_size); | 1696 | memcpy(extra, priv->new_SSID, priv->new_SSID_size); |
1697 | dwrq->length = priv->new_SSID_size; | 1697 | dwrq->length = priv->new_SSID_size; |
1698 | } else { | 1698 | } else { |
1699 | memcpy(extra, priv->SSID, priv->SSID_size); | 1699 | memcpy(extra, priv->SSID, priv->SSID_size); |
1700 | dwrq->length = priv->SSID_size; | 1700 | dwrq->length = priv->SSID_size; |
1701 | } | 1701 | } |
1702 | 1702 | ||
1703 | dwrq->flags = !priv->connect_to_any_BSS; /* active */ | 1703 | dwrq->flags = !priv->connect_to_any_BSS; /* active */ |
1704 | 1704 | ||
1705 | return 0; | 1705 | return 0; |
1706 | } | 1706 | } |
1707 | 1707 | ||
1708 | static int atmel_get_wap(struct net_device *dev, | 1708 | static int atmel_get_wap(struct net_device *dev, |
1709 | struct iw_request_info *info, | 1709 | struct iw_request_info *info, |
1710 | struct sockaddr *awrq, | 1710 | struct sockaddr *awrq, |
1711 | char *extra) | 1711 | char *extra) |
1712 | { | 1712 | { |
1713 | struct atmel_private *priv = netdev_priv(dev); | 1713 | struct atmel_private *priv = netdev_priv(dev); |
1714 | memcpy(awrq->sa_data, priv->CurrentBSSID, 6); | 1714 | memcpy(awrq->sa_data, priv->CurrentBSSID, 6); |
1715 | awrq->sa_family = ARPHRD_ETHER; | 1715 | awrq->sa_family = ARPHRD_ETHER; |
1716 | 1716 | ||
1717 | return 0; | 1717 | return 0; |
1718 | } | 1718 | } |
1719 | 1719 | ||
1720 | static int atmel_set_encode(struct net_device *dev, | 1720 | static int atmel_set_encode(struct net_device *dev, |
1721 | struct iw_request_info *info, | 1721 | struct iw_request_info *info, |
1722 | struct iw_point *dwrq, | 1722 | struct iw_point *dwrq, |
1723 | char *extra) | 1723 | char *extra) |
1724 | { | 1724 | { |
1725 | struct atmel_private *priv = netdev_priv(dev); | 1725 | struct atmel_private *priv = netdev_priv(dev); |
1726 | 1726 | ||
1727 | /* Basic checking: do we have a key to set ? | 1727 | /* Basic checking: do we have a key to set ? |
1728 | * Note : with the new API, it's impossible to get a NULL pointer. | 1728 | * Note : with the new API, it's impossible to get a NULL pointer. |
1729 | * Therefore, we need to check a key size == 0 instead. | 1729 | * Therefore, we need to check a key size == 0 instead. |
1730 | * New version of iwconfig properly set the IW_ENCODE_NOKEY flag | 1730 | * New version of iwconfig properly set the IW_ENCODE_NOKEY flag |
1731 | * when no key is present (only change flags), but older versions | 1731 | * when no key is present (only change flags), but older versions |
1732 | * don't do it. - Jean II */ | 1732 | * don't do it. - Jean II */ |
1733 | if (dwrq->length > 0) { | 1733 | if (dwrq->length > 0) { |
1734 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | 1734 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; |
1735 | int current_index = priv->default_key; | 1735 | int current_index = priv->default_key; |
1736 | /* Check the size of the key */ | 1736 | /* Check the size of the key */ |
1737 | if (dwrq->length > 13) { | 1737 | if (dwrq->length > 13) { |
1738 | return -EINVAL; | 1738 | return -EINVAL; |
1739 | } | 1739 | } |
1740 | /* Check the index (none -> use current) */ | 1740 | /* Check the index (none -> use current) */ |
1741 | if (index < 0 || index >= 4) | 1741 | if (index < 0 || index >= 4) |
1742 | index = current_index; | 1742 | index = current_index; |
1743 | else | 1743 | else |
1744 | priv->default_key = index; | 1744 | priv->default_key = index; |
1745 | /* Set the length */ | 1745 | /* Set the length */ |
1746 | if (dwrq->length > 5) | 1746 | if (dwrq->length > 5) |
1747 | priv->wep_key_len[index] = 13; | 1747 | priv->wep_key_len[index] = 13; |
1748 | else | 1748 | else |
1749 | if (dwrq->length > 0) | 1749 | if (dwrq->length > 0) |
1750 | priv->wep_key_len[index] = 5; | 1750 | priv->wep_key_len[index] = 5; |
1751 | else | 1751 | else |
1752 | /* Disable the key */ | 1752 | /* Disable the key */ |
1753 | priv->wep_key_len[index] = 0; | 1753 | priv->wep_key_len[index] = 0; |
1754 | /* Check if the key is not marked as invalid */ | 1754 | /* Check if the key is not marked as invalid */ |
1755 | if (!(dwrq->flags & IW_ENCODE_NOKEY)) { | 1755 | if (!(dwrq->flags & IW_ENCODE_NOKEY)) { |
1756 | /* Cleanup */ | 1756 | /* Cleanup */ |
1757 | memset(priv->wep_keys[index], 0, 13); | 1757 | memset(priv->wep_keys[index], 0, 13); |
1758 | /* Copy the key in the driver */ | 1758 | /* Copy the key in the driver */ |
1759 | memcpy(priv->wep_keys[index], extra, dwrq->length); | 1759 | memcpy(priv->wep_keys[index], extra, dwrq->length); |
1760 | } | 1760 | } |
1761 | /* WE specify that if a valid key is set, encryption | 1761 | /* WE specify that if a valid key is set, encryption |
1762 | * should be enabled (user may turn it off later) | 1762 | * should be enabled (user may turn it off later) |
1763 | * This is also how "iwconfig ethX key on" works */ | 1763 | * This is also how "iwconfig ethX key on" works */ |
1764 | if (index == current_index && | 1764 | if (index == current_index && |
1765 | priv->wep_key_len[index] > 0) { | 1765 | priv->wep_key_len[index] > 0) { |
1766 | priv->wep_is_on = 1; | 1766 | priv->wep_is_on = 1; |
1767 | priv->exclude_unencrypted = 1; | 1767 | priv->exclude_unencrypted = 1; |
1768 | if (priv->wep_key_len[index] > 5) { | 1768 | if (priv->wep_key_len[index] > 5) { |
1769 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; | 1769 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; |
1770 | priv->encryption_level = 2; | 1770 | priv->encryption_level = 2; |
1771 | } else { | 1771 | } else { |
1772 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; | 1772 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; |
1773 | priv->encryption_level = 1; | 1773 | priv->encryption_level = 1; |
1774 | } | 1774 | } |
1775 | } | 1775 | } |
1776 | } else { | 1776 | } else { |
1777 | /* Do we want to just set the transmit key index ? */ | 1777 | /* Do we want to just set the transmit key index ? */ |
1778 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | 1778 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; |
1779 | if (index >= 0 && index < 4) { | 1779 | if (index >= 0 && index < 4) { |
1780 | priv->default_key = index; | 1780 | priv->default_key = index; |
1781 | } else | 1781 | } else |
1782 | /* Don't complain if only change the mode */ | 1782 | /* Don't complain if only change the mode */ |
1783 | if (!(dwrq->flags & IW_ENCODE_MODE)) | 1783 | if (!(dwrq->flags & IW_ENCODE_MODE)) |
1784 | return -EINVAL; | 1784 | return -EINVAL; |
1785 | } | 1785 | } |
1786 | /* Read the flags */ | 1786 | /* Read the flags */ |
1787 | if (dwrq->flags & IW_ENCODE_DISABLED) { | 1787 | if (dwrq->flags & IW_ENCODE_DISABLED) { |
1788 | priv->wep_is_on = 0; | 1788 | priv->wep_is_on = 0; |
1789 | priv->encryption_level = 0; | 1789 | priv->encryption_level = 0; |
1790 | priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; | 1790 | priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; |
1791 | } else { | 1791 | } else { |
1792 | priv->wep_is_on = 1; | 1792 | priv->wep_is_on = 1; |
1793 | if (priv->wep_key_len[priv->default_key] > 5) { | 1793 | if (priv->wep_key_len[priv->default_key] > 5) { |
1794 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; | 1794 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; |
1795 | priv->encryption_level = 2; | 1795 | priv->encryption_level = 2; |
1796 | } else { | 1796 | } else { |
1797 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; | 1797 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; |
1798 | priv->encryption_level = 1; | 1798 | priv->encryption_level = 1; |
1799 | } | 1799 | } |
1800 | } | 1800 | } |
1801 | if (dwrq->flags & IW_ENCODE_RESTRICTED) | 1801 | if (dwrq->flags & IW_ENCODE_RESTRICTED) |
1802 | priv->exclude_unencrypted = 1; | 1802 | priv->exclude_unencrypted = 1; |
1803 | if (dwrq->flags & IW_ENCODE_OPEN) | 1803 | if (dwrq->flags & IW_ENCODE_OPEN) |
1804 | priv->exclude_unencrypted = 0; | 1804 | priv->exclude_unencrypted = 0; |
1805 | 1805 | ||
1806 | return -EINPROGRESS; /* Call commit handler */ | 1806 | return -EINPROGRESS; /* Call commit handler */ |
1807 | } | 1807 | } |
1808 | 1808 | ||
1809 | static int atmel_get_encode(struct net_device *dev, | 1809 | static int atmel_get_encode(struct net_device *dev, |
1810 | struct iw_request_info *info, | 1810 | struct iw_request_info *info, |
1811 | struct iw_point *dwrq, | 1811 | struct iw_point *dwrq, |
1812 | char *extra) | 1812 | char *extra) |
1813 | { | 1813 | { |
1814 | struct atmel_private *priv = netdev_priv(dev); | 1814 | struct atmel_private *priv = netdev_priv(dev); |
1815 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | 1815 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; |
1816 | 1816 | ||
1817 | if (!priv->wep_is_on) | 1817 | if (!priv->wep_is_on) |
1818 | dwrq->flags = IW_ENCODE_DISABLED; | 1818 | dwrq->flags = IW_ENCODE_DISABLED; |
1819 | else { | 1819 | else { |
1820 | if (priv->exclude_unencrypted) | 1820 | if (priv->exclude_unencrypted) |
1821 | dwrq->flags = IW_ENCODE_RESTRICTED; | 1821 | dwrq->flags = IW_ENCODE_RESTRICTED; |
1822 | else | 1822 | else |
1823 | dwrq->flags = IW_ENCODE_OPEN; | 1823 | dwrq->flags = IW_ENCODE_OPEN; |
1824 | } | 1824 | } |
1825 | /* Which key do we want ? -1 -> tx index */ | 1825 | /* Which key do we want ? -1 -> tx index */ |
1826 | if (index < 0 || index >= 4) | 1826 | if (index < 0 || index >= 4) |
1827 | index = priv->default_key; | 1827 | index = priv->default_key; |
1828 | dwrq->flags |= index + 1; | 1828 | dwrq->flags |= index + 1; |
1829 | /* Copy the key to the user buffer */ | 1829 | /* Copy the key to the user buffer */ |
1830 | dwrq->length = priv->wep_key_len[index]; | 1830 | dwrq->length = priv->wep_key_len[index]; |
1831 | if (dwrq->length > 16) { | 1831 | if (dwrq->length > 16) { |
1832 | dwrq->length = 0; | 1832 | dwrq->length = 0; |
1833 | } else { | 1833 | } else { |
1834 | memset(extra, 0, 16); | 1834 | memset(extra, 0, 16); |
1835 | memcpy(extra, priv->wep_keys[index], dwrq->length); | 1835 | memcpy(extra, priv->wep_keys[index], dwrq->length); |
1836 | } | 1836 | } |
1837 | 1837 | ||
1838 | return 0; | 1838 | return 0; |
1839 | } | 1839 | } |
1840 | 1840 | ||
1841 | static int atmel_set_encodeext(struct net_device *dev, | 1841 | static int atmel_set_encodeext(struct net_device *dev, |
1842 | struct iw_request_info *info, | 1842 | struct iw_request_info *info, |
1843 | union iwreq_data *wrqu, | 1843 | union iwreq_data *wrqu, |
1844 | char *extra) | 1844 | char *extra) |
1845 | { | 1845 | { |
1846 | struct atmel_private *priv = netdev_priv(dev); | 1846 | struct atmel_private *priv = netdev_priv(dev); |
1847 | struct iw_point *encoding = &wrqu->encoding; | 1847 | struct iw_point *encoding = &wrqu->encoding; |
1848 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | 1848 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; |
1849 | int idx, key_len, alg = ext->alg, set_key = 1; | 1849 | int idx, key_len, alg = ext->alg, set_key = 1; |
1850 | 1850 | ||
1851 | /* Determine and validate the key index */ | 1851 | /* Determine and validate the key index */ |
1852 | idx = encoding->flags & IW_ENCODE_INDEX; | 1852 | idx = encoding->flags & IW_ENCODE_INDEX; |
1853 | if (idx) { | 1853 | if (idx) { |
1854 | if (idx < 1 || idx > 4) | 1854 | if (idx < 1 || idx > 4) |
1855 | return -EINVAL; | 1855 | return -EINVAL; |
1856 | idx--; | 1856 | idx--; |
1857 | } else | 1857 | } else |
1858 | idx = priv->default_key; | 1858 | idx = priv->default_key; |
1859 | 1859 | ||
1860 | if (encoding->flags & IW_ENCODE_DISABLED) | 1860 | if (encoding->flags & IW_ENCODE_DISABLED) |
1861 | alg = IW_ENCODE_ALG_NONE; | 1861 | alg = IW_ENCODE_ALG_NONE; |
1862 | 1862 | ||
1863 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { | 1863 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { |
1864 | priv->default_key = idx; | 1864 | priv->default_key = idx; |
1865 | set_key = ext->key_len > 0 ? 1 : 0; | 1865 | set_key = ext->key_len > 0 ? 1 : 0; |
1866 | } | 1866 | } |
1867 | 1867 | ||
1868 | if (set_key) { | 1868 | if (set_key) { |
1869 | /* Set the requested key first */ | 1869 | /* Set the requested key first */ |
1870 | switch (alg) { | 1870 | switch (alg) { |
1871 | case IW_ENCODE_ALG_NONE: | 1871 | case IW_ENCODE_ALG_NONE: |
1872 | priv->wep_is_on = 0; | 1872 | priv->wep_is_on = 0; |
1873 | priv->encryption_level = 0; | 1873 | priv->encryption_level = 0; |
1874 | priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; | 1874 | priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; |
1875 | break; | 1875 | break; |
1876 | case IW_ENCODE_ALG_WEP: | 1876 | case IW_ENCODE_ALG_WEP: |
1877 | if (ext->key_len > 5) { | 1877 | if (ext->key_len > 5) { |
1878 | priv->wep_key_len[idx] = 13; | 1878 | priv->wep_key_len[idx] = 13; |
1879 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; | 1879 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; |
1880 | priv->encryption_level = 2; | 1880 | priv->encryption_level = 2; |
1881 | } else if (ext->key_len > 0) { | 1881 | } else if (ext->key_len > 0) { |
1882 | priv->wep_key_len[idx] = 5; | 1882 | priv->wep_key_len[idx] = 5; |
1883 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; | 1883 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; |
1884 | priv->encryption_level = 1; | 1884 | priv->encryption_level = 1; |
1885 | } else { | 1885 | } else { |
1886 | return -EINVAL; | 1886 | return -EINVAL; |
1887 | } | 1887 | } |
1888 | priv->wep_is_on = 1; | 1888 | priv->wep_is_on = 1; |
1889 | memset(priv->wep_keys[idx], 0, 13); | 1889 | memset(priv->wep_keys[idx], 0, 13); |
1890 | key_len = min ((int)ext->key_len, priv->wep_key_len[idx]); | 1890 | key_len = min ((int)ext->key_len, priv->wep_key_len[idx]); |
1891 | memcpy(priv->wep_keys[idx], ext->key, key_len); | 1891 | memcpy(priv->wep_keys[idx], ext->key, key_len); |
1892 | break; | 1892 | break; |
1893 | default: | 1893 | default: |
1894 | return -EINVAL; | 1894 | return -EINVAL; |
1895 | } | 1895 | } |
1896 | } | 1896 | } |
1897 | 1897 | ||
1898 | return -EINPROGRESS; | 1898 | return -EINPROGRESS; |
1899 | } | 1899 | } |
1900 | 1900 | ||
1901 | static int atmel_get_encodeext(struct net_device *dev, | 1901 | static int atmel_get_encodeext(struct net_device *dev, |
1902 | struct iw_request_info *info, | 1902 | struct iw_request_info *info, |
1903 | union iwreq_data *wrqu, | 1903 | union iwreq_data *wrqu, |
1904 | char *extra) | 1904 | char *extra) |
1905 | { | 1905 | { |
1906 | struct atmel_private *priv = netdev_priv(dev); | 1906 | struct atmel_private *priv = netdev_priv(dev); |
1907 | struct iw_point *encoding = &wrqu->encoding; | 1907 | struct iw_point *encoding = &wrqu->encoding; |
1908 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | 1908 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; |
1909 | int idx, max_key_len; | 1909 | int idx, max_key_len; |
1910 | 1910 | ||
1911 | max_key_len = encoding->length - sizeof(*ext); | 1911 | max_key_len = encoding->length - sizeof(*ext); |
1912 | if (max_key_len < 0) | 1912 | if (max_key_len < 0) |
1913 | return -EINVAL; | 1913 | return -EINVAL; |
1914 | 1914 | ||
1915 | idx = encoding->flags & IW_ENCODE_INDEX; | 1915 | idx = encoding->flags & IW_ENCODE_INDEX; |
1916 | if (idx) { | 1916 | if (idx) { |
1917 | if (idx < 1 || idx > 4) | 1917 | if (idx < 1 || idx > 4) |
1918 | return -EINVAL; | 1918 | return -EINVAL; |
1919 | idx--; | 1919 | idx--; |
1920 | } else | 1920 | } else |
1921 | idx = priv->default_key; | 1921 | idx = priv->default_key; |
1922 | 1922 | ||
1923 | encoding->flags = idx + 1; | 1923 | encoding->flags = idx + 1; |
1924 | memset(ext, 0, sizeof(*ext)); | 1924 | memset(ext, 0, sizeof(*ext)); |
1925 | 1925 | ||
1926 | if (!priv->wep_is_on) { | 1926 | if (!priv->wep_is_on) { |
1927 | ext->alg = IW_ENCODE_ALG_NONE; | 1927 | ext->alg = IW_ENCODE_ALG_NONE; |
1928 | ext->key_len = 0; | 1928 | ext->key_len = 0; |
1929 | encoding->flags |= IW_ENCODE_DISABLED; | 1929 | encoding->flags |= IW_ENCODE_DISABLED; |
1930 | } else { | 1930 | } else { |
1931 | if (priv->encryption_level > 0) | 1931 | if (priv->encryption_level > 0) |
1932 | ext->alg = IW_ENCODE_ALG_WEP; | 1932 | ext->alg = IW_ENCODE_ALG_WEP; |
1933 | else | 1933 | else |
1934 | return -EINVAL; | 1934 | return -EINVAL; |
1935 | 1935 | ||
1936 | ext->key_len = priv->wep_key_len[idx]; | 1936 | ext->key_len = priv->wep_key_len[idx]; |
1937 | memcpy(ext->key, priv->wep_keys[idx], ext->key_len); | 1937 | memcpy(ext->key, priv->wep_keys[idx], ext->key_len); |
1938 | encoding->flags |= IW_ENCODE_ENABLED; | 1938 | encoding->flags |= IW_ENCODE_ENABLED; |
1939 | } | 1939 | } |
1940 | 1940 | ||
1941 | return 0; | 1941 | return 0; |
1942 | } | 1942 | } |
1943 | 1943 | ||
1944 | static int atmel_set_auth(struct net_device *dev, | 1944 | static int atmel_set_auth(struct net_device *dev, |
1945 | struct iw_request_info *info, | 1945 | struct iw_request_info *info, |
1946 | union iwreq_data *wrqu, char *extra) | 1946 | union iwreq_data *wrqu, char *extra) |
1947 | { | 1947 | { |
1948 | struct atmel_private *priv = netdev_priv(dev); | 1948 | struct atmel_private *priv = netdev_priv(dev); |
1949 | struct iw_param *param = &wrqu->param; | 1949 | struct iw_param *param = &wrqu->param; |
1950 | 1950 | ||
1951 | switch (param->flags & IW_AUTH_INDEX) { | 1951 | switch (param->flags & IW_AUTH_INDEX) { |
1952 | case IW_AUTH_WPA_VERSION: | 1952 | case IW_AUTH_WPA_VERSION: |
1953 | case IW_AUTH_CIPHER_PAIRWISE: | 1953 | case IW_AUTH_CIPHER_PAIRWISE: |
1954 | case IW_AUTH_CIPHER_GROUP: | 1954 | case IW_AUTH_CIPHER_GROUP: |
1955 | case IW_AUTH_KEY_MGMT: | 1955 | case IW_AUTH_KEY_MGMT: |
1956 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | 1956 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: |
1957 | case IW_AUTH_PRIVACY_INVOKED: | 1957 | case IW_AUTH_PRIVACY_INVOKED: |
1958 | /* | 1958 | /* |
1959 | * atmel does not use these parameters | 1959 | * atmel does not use these parameters |
1960 | */ | 1960 | */ |
1961 | break; | 1961 | break; |
1962 | 1962 | ||
1963 | case IW_AUTH_DROP_UNENCRYPTED: | 1963 | case IW_AUTH_DROP_UNENCRYPTED: |
1964 | priv->exclude_unencrypted = param->value ? 1 : 0; | 1964 | priv->exclude_unencrypted = param->value ? 1 : 0; |
1965 | break; | 1965 | break; |
1966 | 1966 | ||
1967 | case IW_AUTH_80211_AUTH_ALG: { | 1967 | case IW_AUTH_80211_AUTH_ALG: { |
1968 | if (param->value & IW_AUTH_ALG_SHARED_KEY) { | 1968 | if (param->value & IW_AUTH_ALG_SHARED_KEY) { |
1969 | priv->exclude_unencrypted = 1; | 1969 | priv->exclude_unencrypted = 1; |
1970 | } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { | 1970 | } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { |
1971 | priv->exclude_unencrypted = 0; | 1971 | priv->exclude_unencrypted = 0; |
1972 | } else | 1972 | } else |
1973 | return -EINVAL; | 1973 | return -EINVAL; |
1974 | break; | 1974 | break; |
1975 | } | 1975 | } |
1976 | 1976 | ||
1977 | case IW_AUTH_WPA_ENABLED: | 1977 | case IW_AUTH_WPA_ENABLED: |
1978 | /* Silently accept disable of WPA */ | 1978 | /* Silently accept disable of WPA */ |
1979 | if (param->value > 0) | 1979 | if (param->value > 0) |
1980 | return -EOPNOTSUPP; | 1980 | return -EOPNOTSUPP; |
1981 | break; | 1981 | break; |
1982 | 1982 | ||
1983 | default: | 1983 | default: |
1984 | return -EOPNOTSUPP; | 1984 | return -EOPNOTSUPP; |
1985 | } | 1985 | } |
1986 | return -EINPROGRESS; | 1986 | return -EINPROGRESS; |
1987 | } | 1987 | } |
1988 | 1988 | ||
1989 | static int atmel_get_auth(struct net_device *dev, | 1989 | static int atmel_get_auth(struct net_device *dev, |
1990 | struct iw_request_info *info, | 1990 | struct iw_request_info *info, |
1991 | union iwreq_data *wrqu, char *extra) | 1991 | union iwreq_data *wrqu, char *extra) |
1992 | { | 1992 | { |
1993 | struct atmel_private *priv = netdev_priv(dev); | 1993 | struct atmel_private *priv = netdev_priv(dev); |
1994 | struct iw_param *param = &wrqu->param; | 1994 | struct iw_param *param = &wrqu->param; |
1995 | 1995 | ||
1996 | switch (param->flags & IW_AUTH_INDEX) { | 1996 | switch (param->flags & IW_AUTH_INDEX) { |
1997 | case IW_AUTH_DROP_UNENCRYPTED: | 1997 | case IW_AUTH_DROP_UNENCRYPTED: |
1998 | param->value = priv->exclude_unencrypted; | 1998 | param->value = priv->exclude_unencrypted; |
1999 | break; | 1999 | break; |
2000 | 2000 | ||
2001 | case IW_AUTH_80211_AUTH_ALG: | 2001 | case IW_AUTH_80211_AUTH_ALG: |
2002 | if (priv->exclude_unencrypted == 1) | 2002 | if (priv->exclude_unencrypted == 1) |
2003 | param->value = IW_AUTH_ALG_SHARED_KEY; | 2003 | param->value = IW_AUTH_ALG_SHARED_KEY; |
2004 | else | 2004 | else |
2005 | param->value = IW_AUTH_ALG_OPEN_SYSTEM; | 2005 | param->value = IW_AUTH_ALG_OPEN_SYSTEM; |
2006 | break; | 2006 | break; |
2007 | 2007 | ||
2008 | case IW_AUTH_WPA_ENABLED: | 2008 | case IW_AUTH_WPA_ENABLED: |
2009 | param->value = 0; | 2009 | param->value = 0; |
2010 | break; | 2010 | break; |
2011 | 2011 | ||
2012 | default: | 2012 | default: |
2013 | return -EOPNOTSUPP; | 2013 | return -EOPNOTSUPP; |
2014 | } | 2014 | } |
2015 | return 0; | 2015 | return 0; |
2016 | } | 2016 | } |
2017 | 2017 | ||
2018 | 2018 | ||
2019 | static int atmel_get_name(struct net_device *dev, | 2019 | static int atmel_get_name(struct net_device *dev, |
2020 | struct iw_request_info *info, | 2020 | struct iw_request_info *info, |
2021 | char *cwrq, | 2021 | char *cwrq, |
2022 | char *extra) | 2022 | char *extra) |
2023 | { | 2023 | { |
2024 | strcpy(cwrq, "IEEE 802.11-DS"); | 2024 | strcpy(cwrq, "IEEE 802.11-DS"); |
2025 | return 0; | 2025 | return 0; |
2026 | } | 2026 | } |
2027 | 2027 | ||
2028 | static int atmel_set_rate(struct net_device *dev, | 2028 | static int atmel_set_rate(struct net_device *dev, |
2029 | struct iw_request_info *info, | 2029 | struct iw_request_info *info, |
2030 | struct iw_param *vwrq, | 2030 | struct iw_param *vwrq, |
2031 | char *extra) | 2031 | char *extra) |
2032 | { | 2032 | { |
2033 | struct atmel_private *priv = netdev_priv(dev); | 2033 | struct atmel_private *priv = netdev_priv(dev); |
2034 | 2034 | ||
2035 | if (vwrq->fixed == 0) { | 2035 | if (vwrq->fixed == 0) { |
2036 | priv->tx_rate = 3; | 2036 | priv->tx_rate = 3; |
2037 | priv->auto_tx_rate = 1; | 2037 | priv->auto_tx_rate = 1; |
2038 | } else { | 2038 | } else { |
2039 | priv->auto_tx_rate = 0; | 2039 | priv->auto_tx_rate = 0; |
2040 | 2040 | ||
2041 | /* Which type of value ? */ | 2041 | /* Which type of value ? */ |
2042 | if ((vwrq->value < 4) && (vwrq->value >= 0)) { | 2042 | if ((vwrq->value < 4) && (vwrq->value >= 0)) { |
2043 | /* Setting by rate index */ | 2043 | /* Setting by rate index */ |
2044 | priv->tx_rate = vwrq->value; | 2044 | priv->tx_rate = vwrq->value; |
2045 | } else { | 2045 | } else { |
2046 | /* Setting by frequency value */ | 2046 | /* Setting by frequency value */ |
2047 | switch (vwrq->value) { | 2047 | switch (vwrq->value) { |
2048 | case 1000000: | 2048 | case 1000000: |
2049 | priv->tx_rate = 0; | 2049 | priv->tx_rate = 0; |
2050 | break; | 2050 | break; |
2051 | case 2000000: | 2051 | case 2000000: |
2052 | priv->tx_rate = 1; | 2052 | priv->tx_rate = 1; |
2053 | break; | 2053 | break; |
2054 | case 5500000: | 2054 | case 5500000: |
2055 | priv->tx_rate = 2; | 2055 | priv->tx_rate = 2; |
2056 | break; | 2056 | break; |
2057 | case 11000000: | 2057 | case 11000000: |
2058 | priv->tx_rate = 3; | 2058 | priv->tx_rate = 3; |
2059 | break; | 2059 | break; |
2060 | default: | 2060 | default: |
2061 | return -EINVAL; | 2061 | return -EINVAL; |
2062 | } | 2062 | } |
2063 | } | 2063 | } |
2064 | } | 2064 | } |
2065 | 2065 | ||
2066 | return -EINPROGRESS; | 2066 | return -EINPROGRESS; |
2067 | } | 2067 | } |
2068 | 2068 | ||
2069 | static int atmel_set_mode(struct net_device *dev, | 2069 | static int atmel_set_mode(struct net_device *dev, |
2070 | struct iw_request_info *info, | 2070 | struct iw_request_info *info, |
2071 | __u32 *uwrq, | 2071 | __u32 *uwrq, |
2072 | char *extra) | 2072 | char *extra) |
2073 | { | 2073 | { |
2074 | struct atmel_private *priv = netdev_priv(dev); | 2074 | struct atmel_private *priv = netdev_priv(dev); |
2075 | 2075 | ||
2076 | if (*uwrq != IW_MODE_ADHOC && *uwrq != IW_MODE_INFRA) | 2076 | if (*uwrq != IW_MODE_ADHOC && *uwrq != IW_MODE_INFRA) |
2077 | return -EINVAL; | 2077 | return -EINVAL; |
2078 | 2078 | ||
2079 | priv->operating_mode = *uwrq; | 2079 | priv->operating_mode = *uwrq; |
2080 | return -EINPROGRESS; | 2080 | return -EINPROGRESS; |
2081 | } | 2081 | } |
2082 | 2082 | ||
2083 | static int atmel_get_mode(struct net_device *dev, | 2083 | static int atmel_get_mode(struct net_device *dev, |
2084 | struct iw_request_info *info, | 2084 | struct iw_request_info *info, |
2085 | __u32 *uwrq, | 2085 | __u32 *uwrq, |
2086 | char *extra) | 2086 | char *extra) |
2087 | { | 2087 | { |
2088 | struct atmel_private *priv = netdev_priv(dev); | 2088 | struct atmel_private *priv = netdev_priv(dev); |
2089 | 2089 | ||
2090 | *uwrq = priv->operating_mode; | 2090 | *uwrq = priv->operating_mode; |
2091 | return 0; | 2091 | return 0; |
2092 | } | 2092 | } |
2093 | 2093 | ||
2094 | static int atmel_get_rate(struct net_device *dev, | 2094 | static int atmel_get_rate(struct net_device *dev, |
2095 | struct iw_request_info *info, | 2095 | struct iw_request_info *info, |
2096 | struct iw_param *vwrq, | 2096 | struct iw_param *vwrq, |
2097 | char *extra) | 2097 | char *extra) |
2098 | { | 2098 | { |
2099 | struct atmel_private *priv = netdev_priv(dev); | 2099 | struct atmel_private *priv = netdev_priv(dev); |
2100 | 2100 | ||
2101 | if (priv->auto_tx_rate) { | 2101 | if (priv->auto_tx_rate) { |
2102 | vwrq->fixed = 0; | 2102 | vwrq->fixed = 0; |
2103 | vwrq->value = 11000000; | 2103 | vwrq->value = 11000000; |
2104 | } else { | 2104 | } else { |
2105 | vwrq->fixed = 1; | 2105 | vwrq->fixed = 1; |
2106 | switch (priv->tx_rate) { | 2106 | switch (priv->tx_rate) { |
2107 | case 0: | 2107 | case 0: |
2108 | vwrq->value = 1000000; | 2108 | vwrq->value = 1000000; |
2109 | break; | 2109 | break; |
2110 | case 1: | 2110 | case 1: |
2111 | vwrq->value = 2000000; | 2111 | vwrq->value = 2000000; |
2112 | break; | 2112 | break; |
2113 | case 2: | 2113 | case 2: |
2114 | vwrq->value = 5500000; | 2114 | vwrq->value = 5500000; |
2115 | break; | 2115 | break; |
2116 | case 3: | 2116 | case 3: |
2117 | vwrq->value = 11000000; | 2117 | vwrq->value = 11000000; |
2118 | break; | 2118 | break; |
2119 | } | 2119 | } |
2120 | } | 2120 | } |
2121 | return 0; | 2121 | return 0; |
2122 | } | 2122 | } |
2123 | 2123 | ||
2124 | static int atmel_set_power(struct net_device *dev, | 2124 | static int atmel_set_power(struct net_device *dev, |
2125 | struct iw_request_info *info, | 2125 | struct iw_request_info *info, |
2126 | struct iw_param *vwrq, | 2126 | struct iw_param *vwrq, |
2127 | char *extra) | 2127 | char *extra) |
2128 | { | 2128 | { |
2129 | struct atmel_private *priv = netdev_priv(dev); | 2129 | struct atmel_private *priv = netdev_priv(dev); |
2130 | priv->power_mode = vwrq->disabled ? 0 : 1; | 2130 | priv->power_mode = vwrq->disabled ? 0 : 1; |
2131 | return -EINPROGRESS; | 2131 | return -EINPROGRESS; |
2132 | } | 2132 | } |
2133 | 2133 | ||
2134 | static int atmel_get_power(struct net_device *dev, | 2134 | static int atmel_get_power(struct net_device *dev, |
2135 | struct iw_request_info *info, | 2135 | struct iw_request_info *info, |
2136 | struct iw_param *vwrq, | 2136 | struct iw_param *vwrq, |
2137 | char *extra) | 2137 | char *extra) |
2138 | { | 2138 | { |
2139 | struct atmel_private *priv = netdev_priv(dev); | 2139 | struct atmel_private *priv = netdev_priv(dev); |
2140 | vwrq->disabled = priv->power_mode ? 0 : 1; | 2140 | vwrq->disabled = priv->power_mode ? 0 : 1; |
2141 | vwrq->flags = IW_POWER_ON; | 2141 | vwrq->flags = IW_POWER_ON; |
2142 | return 0; | 2142 | return 0; |
2143 | } | 2143 | } |
2144 | 2144 | ||
2145 | static int atmel_set_retry(struct net_device *dev, | 2145 | static int atmel_set_retry(struct net_device *dev, |
2146 | struct iw_request_info *info, | 2146 | struct iw_request_info *info, |
2147 | struct iw_param *vwrq, | 2147 | struct iw_param *vwrq, |
2148 | char *extra) | 2148 | char *extra) |
2149 | { | 2149 | { |
2150 | struct atmel_private *priv = netdev_priv(dev); | 2150 | struct atmel_private *priv = netdev_priv(dev); |
2151 | 2151 | ||
2152 | if (!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) { | 2152 | if (!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) { |
2153 | if (vwrq->flags & IW_RETRY_LONG) | 2153 | if (vwrq->flags & IW_RETRY_LONG) |
2154 | priv->long_retry = vwrq->value; | 2154 | priv->long_retry = vwrq->value; |
2155 | else if (vwrq->flags & IW_RETRY_SHORT) | 2155 | else if (vwrq->flags & IW_RETRY_SHORT) |
2156 | priv->short_retry = vwrq->value; | 2156 | priv->short_retry = vwrq->value; |
2157 | else { | 2157 | else { |
2158 | /* No modifier : set both */ | 2158 | /* No modifier : set both */ |
2159 | priv->long_retry = vwrq->value; | 2159 | priv->long_retry = vwrq->value; |
2160 | priv->short_retry = vwrq->value; | 2160 | priv->short_retry = vwrq->value; |
2161 | } | 2161 | } |
2162 | return -EINPROGRESS; | 2162 | return -EINPROGRESS; |
2163 | } | 2163 | } |
2164 | 2164 | ||
2165 | return -EINVAL; | 2165 | return -EINVAL; |
2166 | } | 2166 | } |
2167 | 2167 | ||
2168 | static int atmel_get_retry(struct net_device *dev, | 2168 | static int atmel_get_retry(struct net_device *dev, |
2169 | struct iw_request_info *info, | 2169 | struct iw_request_info *info, |
2170 | struct iw_param *vwrq, | 2170 | struct iw_param *vwrq, |
2171 | char *extra) | 2171 | char *extra) |
2172 | { | 2172 | { |
2173 | struct atmel_private *priv = netdev_priv(dev); | 2173 | struct atmel_private *priv = netdev_priv(dev); |
2174 | 2174 | ||
2175 | vwrq->disabled = 0; /* Can't be disabled */ | 2175 | vwrq->disabled = 0; /* Can't be disabled */ |
2176 | 2176 | ||
2177 | /* Note : by default, display the short retry number */ | 2177 | /* Note : by default, display the short retry number */ |
2178 | if (vwrq->flags & IW_RETRY_LONG) { | 2178 | if (vwrq->flags & IW_RETRY_LONG) { |
2179 | vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; | 2179 | vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; |
2180 | vwrq->value = priv->long_retry; | 2180 | vwrq->value = priv->long_retry; |
2181 | } else { | 2181 | } else { |
2182 | vwrq->flags = IW_RETRY_LIMIT; | 2182 | vwrq->flags = IW_RETRY_LIMIT; |
2183 | vwrq->value = priv->short_retry; | 2183 | vwrq->value = priv->short_retry; |
2184 | if (priv->long_retry != priv->short_retry) | 2184 | if (priv->long_retry != priv->short_retry) |
2185 | vwrq->flags |= IW_RETRY_SHORT; | 2185 | vwrq->flags |= IW_RETRY_SHORT; |
2186 | } | 2186 | } |
2187 | 2187 | ||
2188 | return 0; | 2188 | return 0; |
2189 | } | 2189 | } |
2190 | 2190 | ||
2191 | static int atmel_set_rts(struct net_device *dev, | 2191 | static int atmel_set_rts(struct net_device *dev, |
2192 | struct iw_request_info *info, | 2192 | struct iw_request_info *info, |
2193 | struct iw_param *vwrq, | 2193 | struct iw_param *vwrq, |
2194 | char *extra) | 2194 | char *extra) |
2195 | { | 2195 | { |
2196 | struct atmel_private *priv = netdev_priv(dev); | 2196 | struct atmel_private *priv = netdev_priv(dev); |
2197 | int rthr = vwrq->value; | 2197 | int rthr = vwrq->value; |
2198 | 2198 | ||
2199 | if (vwrq->disabled) | 2199 | if (vwrq->disabled) |
2200 | rthr = 2347; | 2200 | rthr = 2347; |
2201 | if ((rthr < 0) || (rthr > 2347)) { | 2201 | if ((rthr < 0) || (rthr > 2347)) { |
2202 | return -EINVAL; | 2202 | return -EINVAL; |
2203 | } | 2203 | } |
2204 | priv->rts_threshold = rthr; | 2204 | priv->rts_threshold = rthr; |
2205 | 2205 | ||
2206 | return -EINPROGRESS; /* Call commit handler */ | 2206 | return -EINPROGRESS; /* Call commit handler */ |
2207 | } | 2207 | } |
2208 | 2208 | ||
2209 | static int atmel_get_rts(struct net_device *dev, | 2209 | static int atmel_get_rts(struct net_device *dev, |
2210 | struct iw_request_info *info, | 2210 | struct iw_request_info *info, |
2211 | struct iw_param *vwrq, | 2211 | struct iw_param *vwrq, |
2212 | char *extra) | 2212 | char *extra) |
2213 | { | 2213 | { |
2214 | struct atmel_private *priv = netdev_priv(dev); | 2214 | struct atmel_private *priv = netdev_priv(dev); |
2215 | 2215 | ||
2216 | vwrq->value = priv->rts_threshold; | 2216 | vwrq->value = priv->rts_threshold; |
2217 | vwrq->disabled = (vwrq->value >= 2347); | 2217 | vwrq->disabled = (vwrq->value >= 2347); |
2218 | vwrq->fixed = 1; | 2218 | vwrq->fixed = 1; |
2219 | 2219 | ||
2220 | return 0; | 2220 | return 0; |
2221 | } | 2221 | } |
2222 | 2222 | ||
2223 | static int atmel_set_frag(struct net_device *dev, | 2223 | static int atmel_set_frag(struct net_device *dev, |
2224 | struct iw_request_info *info, | 2224 | struct iw_request_info *info, |
2225 | struct iw_param *vwrq, | 2225 | struct iw_param *vwrq, |
2226 | char *extra) | 2226 | char *extra) |
2227 | { | 2227 | { |
2228 | struct atmel_private *priv = netdev_priv(dev); | 2228 | struct atmel_private *priv = netdev_priv(dev); |
2229 | int fthr = vwrq->value; | 2229 | int fthr = vwrq->value; |
2230 | 2230 | ||
2231 | if (vwrq->disabled) | 2231 | if (vwrq->disabled) |
2232 | fthr = 2346; | 2232 | fthr = 2346; |
2233 | if ((fthr < 256) || (fthr > 2346)) { | 2233 | if ((fthr < 256) || (fthr > 2346)) { |
2234 | return -EINVAL; | 2234 | return -EINVAL; |
2235 | } | 2235 | } |
2236 | fthr &= ~0x1; /* Get an even value - is it really needed ??? */ | 2236 | fthr &= ~0x1; /* Get an even value - is it really needed ??? */ |
2237 | priv->frag_threshold = fthr; | 2237 | priv->frag_threshold = fthr; |
2238 | 2238 | ||
2239 | return -EINPROGRESS; /* Call commit handler */ | 2239 | return -EINPROGRESS; /* Call commit handler */ |
2240 | } | 2240 | } |
2241 | 2241 | ||
2242 | static int atmel_get_frag(struct net_device *dev, | 2242 | static int atmel_get_frag(struct net_device *dev, |
2243 | struct iw_request_info *info, | 2243 | struct iw_request_info *info, |
2244 | struct iw_param *vwrq, | 2244 | struct iw_param *vwrq, |
2245 | char *extra) | 2245 | char *extra) |
2246 | { | 2246 | { |
2247 | struct atmel_private *priv = netdev_priv(dev); | 2247 | struct atmel_private *priv = netdev_priv(dev); |
2248 | 2248 | ||
2249 | vwrq->value = priv->frag_threshold; | 2249 | vwrq->value = priv->frag_threshold; |
2250 | vwrq->disabled = (vwrq->value >= 2346); | 2250 | vwrq->disabled = (vwrq->value >= 2346); |
2251 | vwrq->fixed = 1; | 2251 | vwrq->fixed = 1; |
2252 | 2252 | ||
2253 | return 0; | 2253 | return 0; |
2254 | } | 2254 | } |
2255 | 2255 | ||
2256 | static int atmel_set_freq(struct net_device *dev, | 2256 | static int atmel_set_freq(struct net_device *dev, |
2257 | struct iw_request_info *info, | 2257 | struct iw_request_info *info, |
2258 | struct iw_freq *fwrq, | 2258 | struct iw_freq *fwrq, |
2259 | char *extra) | 2259 | char *extra) |
2260 | { | 2260 | { |
2261 | struct atmel_private *priv = netdev_priv(dev); | 2261 | struct atmel_private *priv = netdev_priv(dev); |
2262 | int rc = -EINPROGRESS; /* Call commit handler */ | 2262 | int rc = -EINPROGRESS; /* Call commit handler */ |
2263 | 2263 | ||
2264 | /* If setting by frequency, convert to a channel */ | 2264 | /* If setting by frequency, convert to a channel */ |
2265 | if (fwrq->e == 1) { | 2265 | if (fwrq->e == 1) { |
2266 | int f = fwrq->m / 100000; | 2266 | int f = fwrq->m / 100000; |
2267 | 2267 | ||
2268 | /* Hack to fall through... */ | 2268 | /* Hack to fall through... */ |
2269 | fwrq->e = 0; | 2269 | fwrq->e = 0; |
2270 | fwrq->m = ieee80211_freq_to_dsss_chan(f); | 2270 | fwrq->m = ieee80211_freq_to_dsss_chan(f); |
2271 | } | 2271 | } |
2272 | /* Setting by channel number */ | 2272 | /* Setting by channel number */ |
2273 | if ((fwrq->m > 1000) || (fwrq->e > 0)) | 2273 | if ((fwrq->m > 1000) || (fwrq->e > 0)) |
2274 | rc = -EOPNOTSUPP; | 2274 | rc = -EOPNOTSUPP; |
2275 | else { | 2275 | else { |
2276 | int channel = fwrq->m; | 2276 | int channel = fwrq->m; |
2277 | if (atmel_validate_channel(priv, channel) == 0) { | 2277 | if (atmel_validate_channel(priv, channel) == 0) { |
2278 | priv->channel = channel; | 2278 | priv->channel = channel; |
2279 | } else { | 2279 | } else { |
2280 | rc = -EINVAL; | 2280 | rc = -EINVAL; |
2281 | } | 2281 | } |
2282 | } | 2282 | } |
2283 | return rc; | 2283 | return rc; |
2284 | } | 2284 | } |
2285 | 2285 | ||
2286 | static int atmel_get_freq(struct net_device *dev, | 2286 | static int atmel_get_freq(struct net_device *dev, |
2287 | struct iw_request_info *info, | 2287 | struct iw_request_info *info, |
2288 | struct iw_freq *fwrq, | 2288 | struct iw_freq *fwrq, |
2289 | char *extra) | 2289 | char *extra) |
2290 | { | 2290 | { |
2291 | struct atmel_private *priv = netdev_priv(dev); | 2291 | struct atmel_private *priv = netdev_priv(dev); |
2292 | 2292 | ||
2293 | fwrq->m = priv->channel; | 2293 | fwrq->m = priv->channel; |
2294 | fwrq->e = 0; | 2294 | fwrq->e = 0; |
2295 | return 0; | 2295 | return 0; |
2296 | } | 2296 | } |
2297 | 2297 | ||
2298 | static int atmel_set_scan(struct net_device *dev, | 2298 | static int atmel_set_scan(struct net_device *dev, |
2299 | struct iw_request_info *info, | 2299 | struct iw_request_info *info, |
2300 | struct iw_point *dwrq, | 2300 | struct iw_point *dwrq, |
2301 | char *extra) | 2301 | char *extra) |
2302 | { | 2302 | { |
2303 | struct atmel_private *priv = netdev_priv(dev); | 2303 | struct atmel_private *priv = netdev_priv(dev); |
2304 | unsigned long flags; | 2304 | unsigned long flags; |
2305 | 2305 | ||
2306 | /* Note : you may have realised that, as this is a SET operation, | 2306 | /* Note : you may have realised that, as this is a SET operation, |
2307 | * this is privileged and therefore a normal user can't | 2307 | * this is privileged and therefore a normal user can't |
2308 | * perform scanning. | 2308 | * perform scanning. |
2309 | * This is not an error, while the device perform scanning, | 2309 | * This is not an error, while the device perform scanning, |
2310 | * traffic doesn't flow, so it's a perfect DoS... | 2310 | * traffic doesn't flow, so it's a perfect DoS... |
2311 | * Jean II */ | 2311 | * Jean II */ |
2312 | 2312 | ||
2313 | if (priv->station_state == STATION_STATE_DOWN) | 2313 | if (priv->station_state == STATION_STATE_DOWN) |
2314 | return -EAGAIN; | 2314 | return -EAGAIN; |
2315 | 2315 | ||
2316 | /* Timeout old surveys. */ | 2316 | /* Timeout old surveys. */ |
2317 | if (time_after(jiffies, priv->last_survey + 20 * HZ)) | 2317 | if (time_after(jiffies, priv->last_survey + 20 * HZ)) |
2318 | priv->site_survey_state = SITE_SURVEY_IDLE; | 2318 | priv->site_survey_state = SITE_SURVEY_IDLE; |
2319 | priv->last_survey = jiffies; | 2319 | priv->last_survey = jiffies; |
2320 | 2320 | ||
2321 | /* Initiate a scan command */ | 2321 | /* Initiate a scan command */ |
2322 | if (priv->site_survey_state == SITE_SURVEY_IN_PROGRESS) | 2322 | if (priv->site_survey_state == SITE_SURVEY_IN_PROGRESS) |
2323 | return -EBUSY; | 2323 | return -EBUSY; |
2324 | 2324 | ||
2325 | del_timer_sync(&priv->management_timer); | 2325 | del_timer_sync(&priv->management_timer); |
2326 | spin_lock_irqsave(&priv->irqlock, flags); | 2326 | spin_lock_irqsave(&priv->irqlock, flags); |
2327 | 2327 | ||
2328 | priv->site_survey_state = SITE_SURVEY_IN_PROGRESS; | 2328 | priv->site_survey_state = SITE_SURVEY_IN_PROGRESS; |
2329 | priv->fast_scan = 0; | 2329 | priv->fast_scan = 0; |
2330 | atmel_scan(priv, 0); | 2330 | atmel_scan(priv, 0); |
2331 | spin_unlock_irqrestore(&priv->irqlock, flags); | 2331 | spin_unlock_irqrestore(&priv->irqlock, flags); |
2332 | 2332 | ||
2333 | return 0; | 2333 | return 0; |
2334 | } | 2334 | } |
2335 | 2335 | ||
2336 | static int atmel_get_scan(struct net_device *dev, | 2336 | static int atmel_get_scan(struct net_device *dev, |
2337 | struct iw_request_info *info, | 2337 | struct iw_request_info *info, |
2338 | struct iw_point *dwrq, | 2338 | struct iw_point *dwrq, |
2339 | char *extra) | 2339 | char *extra) |
2340 | { | 2340 | { |
2341 | struct atmel_private *priv = netdev_priv(dev); | 2341 | struct atmel_private *priv = netdev_priv(dev); |
2342 | int i; | 2342 | int i; |
2343 | char *current_ev = extra; | 2343 | char *current_ev = extra; |
2344 | struct iw_event iwe; | 2344 | struct iw_event iwe; |
2345 | 2345 | ||
2346 | if (priv->site_survey_state != SITE_SURVEY_COMPLETED) | 2346 | if (priv->site_survey_state != SITE_SURVEY_COMPLETED) |
2347 | return -EAGAIN; | 2347 | return -EAGAIN; |
2348 | 2348 | ||
2349 | for (i = 0; i < priv->BSS_list_entries; i++) { | 2349 | for (i = 0; i < priv->BSS_list_entries; i++) { |
2350 | iwe.cmd = SIOCGIWAP; | 2350 | iwe.cmd = SIOCGIWAP; |
2351 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | 2351 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; |
2352 | memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, 6); | 2352 | memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, 6); |
2353 | current_ev = iwe_stream_add_event(info, current_ev, | 2353 | current_ev = iwe_stream_add_event(info, current_ev, |
2354 | extra + IW_SCAN_MAX_DATA, | 2354 | extra + IW_SCAN_MAX_DATA, |
2355 | &iwe, IW_EV_ADDR_LEN); | 2355 | &iwe, IW_EV_ADDR_LEN); |
2356 | 2356 | ||
2357 | iwe.u.data.length = priv->BSSinfo[i].SSIDsize; | 2357 | iwe.u.data.length = priv->BSSinfo[i].SSIDsize; |
2358 | if (iwe.u.data.length > 32) | 2358 | if (iwe.u.data.length > 32) |
2359 | iwe.u.data.length = 32; | 2359 | iwe.u.data.length = 32; |
2360 | iwe.cmd = SIOCGIWESSID; | 2360 | iwe.cmd = SIOCGIWESSID; |
2361 | iwe.u.data.flags = 1; | 2361 | iwe.u.data.flags = 1; |
2362 | current_ev = iwe_stream_add_point(info, current_ev, | 2362 | current_ev = iwe_stream_add_point(info, current_ev, |
2363 | extra + IW_SCAN_MAX_DATA, | 2363 | extra + IW_SCAN_MAX_DATA, |
2364 | &iwe, priv->BSSinfo[i].SSID); | 2364 | &iwe, priv->BSSinfo[i].SSID); |
2365 | 2365 | ||
2366 | iwe.cmd = SIOCGIWMODE; | 2366 | iwe.cmd = SIOCGIWMODE; |
2367 | iwe.u.mode = priv->BSSinfo[i].BSStype; | 2367 | iwe.u.mode = priv->BSSinfo[i].BSStype; |
2368 | current_ev = iwe_stream_add_event(info, current_ev, | 2368 | current_ev = iwe_stream_add_event(info, current_ev, |
2369 | extra + IW_SCAN_MAX_DATA, | 2369 | extra + IW_SCAN_MAX_DATA, |
2370 | &iwe, IW_EV_UINT_LEN); | 2370 | &iwe, IW_EV_UINT_LEN); |
2371 | 2371 | ||
2372 | iwe.cmd = SIOCGIWFREQ; | 2372 | iwe.cmd = SIOCGIWFREQ; |
2373 | iwe.u.freq.m = priv->BSSinfo[i].channel; | 2373 | iwe.u.freq.m = priv->BSSinfo[i].channel; |
2374 | iwe.u.freq.e = 0; | 2374 | iwe.u.freq.e = 0; |
2375 | current_ev = iwe_stream_add_event(info, current_ev, | 2375 | current_ev = iwe_stream_add_event(info, current_ev, |
2376 | extra + IW_SCAN_MAX_DATA, | 2376 | extra + IW_SCAN_MAX_DATA, |
2377 | &iwe, IW_EV_FREQ_LEN); | 2377 | &iwe, IW_EV_FREQ_LEN); |
2378 | 2378 | ||
2379 | /* Add quality statistics */ | 2379 | /* Add quality statistics */ |
2380 | iwe.cmd = IWEVQUAL; | 2380 | iwe.cmd = IWEVQUAL; |
2381 | iwe.u.qual.level = priv->BSSinfo[i].RSSI; | 2381 | iwe.u.qual.level = priv->BSSinfo[i].RSSI; |
2382 | iwe.u.qual.qual = iwe.u.qual.level; | 2382 | iwe.u.qual.qual = iwe.u.qual.level; |
2383 | /* iwe.u.qual.noise = SOMETHING */ | 2383 | /* iwe.u.qual.noise = SOMETHING */ |
2384 | current_ev = iwe_stream_add_event(info, current_ev, | 2384 | current_ev = iwe_stream_add_event(info, current_ev, |
2385 | extra + IW_SCAN_MAX_DATA, | 2385 | extra + IW_SCAN_MAX_DATA, |
2386 | &iwe, IW_EV_QUAL_LEN); | 2386 | &iwe, IW_EV_QUAL_LEN); |
2387 | 2387 | ||
2388 | 2388 | ||
2389 | iwe.cmd = SIOCGIWENCODE; | 2389 | iwe.cmd = SIOCGIWENCODE; |
2390 | if (priv->BSSinfo[i].UsingWEP) | 2390 | if (priv->BSSinfo[i].UsingWEP) |
2391 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | 2391 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; |
2392 | else | 2392 | else |
2393 | iwe.u.data.flags = IW_ENCODE_DISABLED; | 2393 | iwe.u.data.flags = IW_ENCODE_DISABLED; |
2394 | iwe.u.data.length = 0; | 2394 | iwe.u.data.length = 0; |
2395 | current_ev = iwe_stream_add_point(info, current_ev, | 2395 | current_ev = iwe_stream_add_point(info, current_ev, |
2396 | extra + IW_SCAN_MAX_DATA, | 2396 | extra + IW_SCAN_MAX_DATA, |
2397 | &iwe, NULL); | 2397 | &iwe, NULL); |
2398 | } | 2398 | } |
2399 | 2399 | ||
2400 | /* Length of data */ | 2400 | /* Length of data */ |
2401 | dwrq->length = (current_ev - extra); | 2401 | dwrq->length = (current_ev - extra); |
2402 | dwrq->flags = 0; | 2402 | dwrq->flags = 0; |
2403 | 2403 | ||
2404 | return 0; | 2404 | return 0; |
2405 | } | 2405 | } |
2406 | 2406 | ||
2407 | static int atmel_get_range(struct net_device *dev, | 2407 | static int atmel_get_range(struct net_device *dev, |
2408 | struct iw_request_info *info, | 2408 | struct iw_request_info *info, |
2409 | struct iw_point *dwrq, | 2409 | struct iw_point *dwrq, |
2410 | char *extra) | 2410 | char *extra) |
2411 | { | 2411 | { |
2412 | struct atmel_private *priv = netdev_priv(dev); | 2412 | struct atmel_private *priv = netdev_priv(dev); |
2413 | struct iw_range *range = (struct iw_range *) extra; | 2413 | struct iw_range *range = (struct iw_range *) extra; |
2414 | int k, i, j; | 2414 | int k, i, j; |
2415 | 2415 | ||
2416 | dwrq->length = sizeof(struct iw_range); | 2416 | dwrq->length = sizeof(struct iw_range); |
2417 | memset(range, 0, sizeof(struct iw_range)); | 2417 | memset(range, 0, sizeof(struct iw_range)); |
2418 | range->min_nwid = 0x0000; | 2418 | range->min_nwid = 0x0000; |
2419 | range->max_nwid = 0x0000; | 2419 | range->max_nwid = 0x0000; |
2420 | range->num_channels = 0; | 2420 | range->num_channels = 0; |
2421 | for (j = 0; j < ARRAY_SIZE(channel_table); j++) | 2421 | for (j = 0; j < ARRAY_SIZE(channel_table); j++) |
2422 | if (priv->reg_domain == channel_table[j].reg_domain) { | 2422 | if (priv->reg_domain == channel_table[j].reg_domain) { |
2423 | range->num_channels = channel_table[j].max - channel_table[j].min + 1; | 2423 | range->num_channels = channel_table[j].max - channel_table[j].min + 1; |
2424 | break; | 2424 | break; |
2425 | } | 2425 | } |
2426 | if (range->num_channels != 0) { | 2426 | if (range->num_channels != 0) { |
2427 | for (k = 0, i = channel_table[j].min; i <= channel_table[j].max; i++) { | 2427 | for (k = 0, i = channel_table[j].min; i <= channel_table[j].max; i++) { |
2428 | range->freq[k].i = i; /* List index */ | 2428 | range->freq[k].i = i; /* List index */ |
2429 | 2429 | ||
2430 | /* Values in MHz -> * 10^5 * 10 */ | 2430 | /* Values in MHz -> * 10^5 * 10 */ |
2431 | range->freq[k].m = (ieee80211_dsss_chan_to_freq(i) * | 2431 | range->freq[k].m = (ieee80211_dsss_chan_to_freq(i) * |
2432 | 100000); | 2432 | 100000); |
2433 | range->freq[k++].e = 1; | 2433 | range->freq[k++].e = 1; |
2434 | } | 2434 | } |
2435 | range->num_frequency = k; | 2435 | range->num_frequency = k; |
2436 | } | 2436 | } |
2437 | 2437 | ||
2438 | range->max_qual.qual = 100; | 2438 | range->max_qual.qual = 100; |
2439 | range->max_qual.level = 100; | 2439 | range->max_qual.level = 100; |
2440 | range->max_qual.noise = 0; | 2440 | range->max_qual.noise = 0; |
2441 | range->max_qual.updated = IW_QUAL_NOISE_INVALID; | 2441 | range->max_qual.updated = IW_QUAL_NOISE_INVALID; |
2442 | 2442 | ||
2443 | range->avg_qual.qual = 50; | 2443 | range->avg_qual.qual = 50; |
2444 | range->avg_qual.level = 50; | 2444 | range->avg_qual.level = 50; |
2445 | range->avg_qual.noise = 0; | 2445 | range->avg_qual.noise = 0; |
2446 | range->avg_qual.updated = IW_QUAL_NOISE_INVALID; | 2446 | range->avg_qual.updated = IW_QUAL_NOISE_INVALID; |
2447 | 2447 | ||
2448 | range->sensitivity = 0; | 2448 | range->sensitivity = 0; |
2449 | 2449 | ||
2450 | range->bitrate[0] = 1000000; | 2450 | range->bitrate[0] = 1000000; |
2451 | range->bitrate[1] = 2000000; | 2451 | range->bitrate[1] = 2000000; |
2452 | range->bitrate[2] = 5500000; | 2452 | range->bitrate[2] = 5500000; |
2453 | range->bitrate[3] = 11000000; | 2453 | range->bitrate[3] = 11000000; |
2454 | range->num_bitrates = 4; | 2454 | range->num_bitrates = 4; |
2455 | 2455 | ||
2456 | range->min_rts = 0; | 2456 | range->min_rts = 0; |
2457 | range->max_rts = 2347; | 2457 | range->max_rts = 2347; |
2458 | range->min_frag = 256; | 2458 | range->min_frag = 256; |
2459 | range->max_frag = 2346; | 2459 | range->max_frag = 2346; |
2460 | 2460 | ||
2461 | range->encoding_size[0] = 5; | 2461 | range->encoding_size[0] = 5; |
2462 | range->encoding_size[1] = 13; | 2462 | range->encoding_size[1] = 13; |
2463 | range->num_encoding_sizes = 2; | 2463 | range->num_encoding_sizes = 2; |
2464 | range->max_encoding_tokens = 4; | 2464 | range->max_encoding_tokens = 4; |
2465 | 2465 | ||
2466 | range->pmp_flags = IW_POWER_ON; | 2466 | range->pmp_flags = IW_POWER_ON; |
2467 | range->pmt_flags = IW_POWER_ON; | 2467 | range->pmt_flags = IW_POWER_ON; |
2468 | range->pm_capa = 0; | 2468 | range->pm_capa = 0; |
2469 | 2469 | ||
2470 | range->we_version_source = WIRELESS_EXT; | 2470 | range->we_version_source = WIRELESS_EXT; |
2471 | range->we_version_compiled = WIRELESS_EXT; | 2471 | range->we_version_compiled = WIRELESS_EXT; |
2472 | range->retry_capa = IW_RETRY_LIMIT ; | 2472 | range->retry_capa = IW_RETRY_LIMIT ; |
2473 | range->retry_flags = IW_RETRY_LIMIT; | 2473 | range->retry_flags = IW_RETRY_LIMIT; |
2474 | range->r_time_flags = 0; | 2474 | range->r_time_flags = 0; |
2475 | range->min_retry = 1; | 2475 | range->min_retry = 1; |
2476 | range->max_retry = 65535; | 2476 | range->max_retry = 65535; |
2477 | 2477 | ||
2478 | return 0; | 2478 | return 0; |
2479 | } | 2479 | } |
2480 | 2480 | ||
2481 | static int atmel_set_wap(struct net_device *dev, | 2481 | static int atmel_set_wap(struct net_device *dev, |
2482 | struct iw_request_info *info, | 2482 | struct iw_request_info *info, |
2483 | struct sockaddr *awrq, | 2483 | struct sockaddr *awrq, |
2484 | char *extra) | 2484 | char *extra) |
2485 | { | 2485 | { |
2486 | struct atmel_private *priv = netdev_priv(dev); | 2486 | struct atmel_private *priv = netdev_priv(dev); |
2487 | int i; | 2487 | int i; |
2488 | static const u8 any[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | 2488 | static const u8 any[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
2489 | static const u8 off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | 2489 | static const u8 off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
2490 | unsigned long flags; | 2490 | unsigned long flags; |
2491 | 2491 | ||
2492 | if (awrq->sa_family != ARPHRD_ETHER) | 2492 | if (awrq->sa_family != ARPHRD_ETHER) |
2493 | return -EINVAL; | 2493 | return -EINVAL; |
2494 | 2494 | ||
2495 | if (!memcmp(any, awrq->sa_data, 6) || | 2495 | if (!memcmp(any, awrq->sa_data, 6) || |
2496 | !memcmp(off, awrq->sa_data, 6)) { | 2496 | !memcmp(off, awrq->sa_data, 6)) { |
2497 | del_timer_sync(&priv->management_timer); | 2497 | del_timer_sync(&priv->management_timer); |
2498 | spin_lock_irqsave(&priv->irqlock, flags); | 2498 | spin_lock_irqsave(&priv->irqlock, flags); |
2499 | atmel_scan(priv, 1); | 2499 | atmel_scan(priv, 1); |
2500 | spin_unlock_irqrestore(&priv->irqlock, flags); | 2500 | spin_unlock_irqrestore(&priv->irqlock, flags); |
2501 | return 0; | 2501 | return 0; |
2502 | } | 2502 | } |
2503 | 2503 | ||
2504 | for (i = 0; i < priv->BSS_list_entries; i++) { | 2504 | for (i = 0; i < priv->BSS_list_entries; i++) { |
2505 | if (memcmp(priv->BSSinfo[i].BSSID, awrq->sa_data, 6) == 0) { | 2505 | if (memcmp(priv->BSSinfo[i].BSSID, awrq->sa_data, 6) == 0) { |
2506 | if (!priv->wep_is_on && priv->BSSinfo[i].UsingWEP) { | 2506 | if (!priv->wep_is_on && priv->BSSinfo[i].UsingWEP) { |
2507 | return -EINVAL; | 2507 | return -EINVAL; |
2508 | } else if (priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) { | 2508 | } else if (priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) { |
2509 | return -EINVAL; | 2509 | return -EINVAL; |
2510 | } else { | 2510 | } else { |
2511 | del_timer_sync(&priv->management_timer); | 2511 | del_timer_sync(&priv->management_timer); |
2512 | spin_lock_irqsave(&priv->irqlock, flags); | 2512 | spin_lock_irqsave(&priv->irqlock, flags); |
2513 | atmel_join_bss(priv, i); | 2513 | atmel_join_bss(priv, i); |
2514 | spin_unlock_irqrestore(&priv->irqlock, flags); | 2514 | spin_unlock_irqrestore(&priv->irqlock, flags); |
2515 | return 0; | 2515 | return 0; |
2516 | } | 2516 | } |
2517 | } | 2517 | } |
2518 | } | 2518 | } |
2519 | 2519 | ||
2520 | return -EINVAL; | 2520 | return -EINVAL; |
2521 | } | 2521 | } |
2522 | 2522 | ||
2523 | static int atmel_config_commit(struct net_device *dev, | 2523 | static int atmel_config_commit(struct net_device *dev, |
2524 | struct iw_request_info *info, /* NULL */ | 2524 | struct iw_request_info *info, /* NULL */ |
2525 | void *zwrq, /* NULL */ | 2525 | void *zwrq, /* NULL */ |
2526 | char *extra) /* NULL */ | 2526 | char *extra) /* NULL */ |
2527 | { | 2527 | { |
2528 | return atmel_open(dev); | 2528 | return atmel_open(dev); |
2529 | } | 2529 | } |
2530 | 2530 | ||
2531 | static const iw_handler atmel_handler[] = | 2531 | static const iw_handler atmel_handler[] = |
2532 | { | 2532 | { |
2533 | (iw_handler) atmel_config_commit, /* SIOCSIWCOMMIT */ | 2533 | (iw_handler) atmel_config_commit, /* SIOCSIWCOMMIT */ |
2534 | (iw_handler) atmel_get_name, /* SIOCGIWNAME */ | 2534 | (iw_handler) atmel_get_name, /* SIOCGIWNAME */ |
2535 | (iw_handler) NULL, /* SIOCSIWNWID */ | 2535 | (iw_handler) NULL, /* SIOCSIWNWID */ |
2536 | (iw_handler) NULL, /* SIOCGIWNWID */ | 2536 | (iw_handler) NULL, /* SIOCGIWNWID */ |
2537 | (iw_handler) atmel_set_freq, /* SIOCSIWFREQ */ | 2537 | (iw_handler) atmel_set_freq, /* SIOCSIWFREQ */ |
2538 | (iw_handler) atmel_get_freq, /* SIOCGIWFREQ */ | 2538 | (iw_handler) atmel_get_freq, /* SIOCGIWFREQ */ |
2539 | (iw_handler) atmel_set_mode, /* SIOCSIWMODE */ | 2539 | (iw_handler) atmel_set_mode, /* SIOCSIWMODE */ |
2540 | (iw_handler) atmel_get_mode, /* SIOCGIWMODE */ | 2540 | (iw_handler) atmel_get_mode, /* SIOCGIWMODE */ |
2541 | (iw_handler) NULL, /* SIOCSIWSENS */ | 2541 | (iw_handler) NULL, /* SIOCSIWSENS */ |
2542 | (iw_handler) NULL, /* SIOCGIWSENS */ | 2542 | (iw_handler) NULL, /* SIOCGIWSENS */ |
2543 | (iw_handler) NULL, /* SIOCSIWRANGE */ | 2543 | (iw_handler) NULL, /* SIOCSIWRANGE */ |
2544 | (iw_handler) atmel_get_range, /* SIOCGIWRANGE */ | 2544 | (iw_handler) atmel_get_range, /* SIOCGIWRANGE */ |
2545 | (iw_handler) NULL, /* SIOCSIWPRIV */ | 2545 | (iw_handler) NULL, /* SIOCSIWPRIV */ |
2546 | (iw_handler) NULL, /* SIOCGIWPRIV */ | 2546 | (iw_handler) NULL, /* SIOCGIWPRIV */ |
2547 | (iw_handler) NULL, /* SIOCSIWSTATS */ | 2547 | (iw_handler) NULL, /* SIOCSIWSTATS */ |
2548 | (iw_handler) NULL, /* SIOCGIWSTATS */ | 2548 | (iw_handler) NULL, /* SIOCGIWSTATS */ |
2549 | (iw_handler) NULL, /* SIOCSIWSPY */ | 2549 | (iw_handler) NULL, /* SIOCSIWSPY */ |
2550 | (iw_handler) NULL, /* SIOCGIWSPY */ | 2550 | (iw_handler) NULL, /* SIOCGIWSPY */ |
2551 | (iw_handler) NULL, /* -- hole -- */ | 2551 | (iw_handler) NULL, /* -- hole -- */ |
2552 | (iw_handler) NULL, /* -- hole -- */ | 2552 | (iw_handler) NULL, /* -- hole -- */ |
2553 | (iw_handler) atmel_set_wap, /* SIOCSIWAP */ | 2553 | (iw_handler) atmel_set_wap, /* SIOCSIWAP */ |
2554 | (iw_handler) atmel_get_wap, /* SIOCGIWAP */ | 2554 | (iw_handler) atmel_get_wap, /* SIOCGIWAP */ |
2555 | (iw_handler) NULL, /* -- hole -- */ | 2555 | (iw_handler) NULL, /* -- hole -- */ |
2556 | (iw_handler) NULL, /* SIOCGIWAPLIST */ | 2556 | (iw_handler) NULL, /* SIOCGIWAPLIST */ |
2557 | (iw_handler) atmel_set_scan, /* SIOCSIWSCAN */ | 2557 | (iw_handler) atmel_set_scan, /* SIOCSIWSCAN */ |
2558 | (iw_handler) atmel_get_scan, /* SIOCGIWSCAN */ | 2558 | (iw_handler) atmel_get_scan, /* SIOCGIWSCAN */ |
2559 | (iw_handler) atmel_set_essid, /* SIOCSIWESSID */ | 2559 | (iw_handler) atmel_set_essid, /* SIOCSIWESSID */ |
2560 | (iw_handler) atmel_get_essid, /* SIOCGIWESSID */ | 2560 | (iw_handler) atmel_get_essid, /* SIOCGIWESSID */ |
2561 | (iw_handler) NULL, /* SIOCSIWNICKN */ | 2561 | (iw_handler) NULL, /* SIOCSIWNICKN */ |
2562 | (iw_handler) NULL, /* SIOCGIWNICKN */ | 2562 | (iw_handler) NULL, /* SIOCGIWNICKN */ |
2563 | (iw_handler) NULL, /* -- hole -- */ | 2563 | (iw_handler) NULL, /* -- hole -- */ |
2564 | (iw_handler) NULL, /* -- hole -- */ | 2564 | (iw_handler) NULL, /* -- hole -- */ |
2565 | (iw_handler) atmel_set_rate, /* SIOCSIWRATE */ | 2565 | (iw_handler) atmel_set_rate, /* SIOCSIWRATE */ |
2566 | (iw_handler) atmel_get_rate, /* SIOCGIWRATE */ | 2566 | (iw_handler) atmel_get_rate, /* SIOCGIWRATE */ |
2567 | (iw_handler) atmel_set_rts, /* SIOCSIWRTS */ | 2567 | (iw_handler) atmel_set_rts, /* SIOCSIWRTS */ |
2568 | (iw_handler) atmel_get_rts, /* SIOCGIWRTS */ | 2568 | (iw_handler) atmel_get_rts, /* SIOCGIWRTS */ |
2569 | (iw_handler) atmel_set_frag, /* SIOCSIWFRAG */ | 2569 | (iw_handler) atmel_set_frag, /* SIOCSIWFRAG */ |
2570 | (iw_handler) atmel_get_frag, /* SIOCGIWFRAG */ | 2570 | (iw_handler) atmel_get_frag, /* SIOCGIWFRAG */ |
2571 | (iw_handler) NULL, /* SIOCSIWTXPOW */ | 2571 | (iw_handler) NULL, /* SIOCSIWTXPOW */ |
2572 | (iw_handler) NULL, /* SIOCGIWTXPOW */ | 2572 | (iw_handler) NULL, /* SIOCGIWTXPOW */ |
2573 | (iw_handler) atmel_set_retry, /* SIOCSIWRETRY */ | 2573 | (iw_handler) atmel_set_retry, /* SIOCSIWRETRY */ |
2574 | (iw_handler) atmel_get_retry, /* SIOCGIWRETRY */ | 2574 | (iw_handler) atmel_get_retry, /* SIOCGIWRETRY */ |
2575 | (iw_handler) atmel_set_encode, /* SIOCSIWENCODE */ | 2575 | (iw_handler) atmel_set_encode, /* SIOCSIWENCODE */ |
2576 | (iw_handler) atmel_get_encode, /* SIOCGIWENCODE */ | 2576 | (iw_handler) atmel_get_encode, /* SIOCGIWENCODE */ |
2577 | (iw_handler) atmel_set_power, /* SIOCSIWPOWER */ | 2577 | (iw_handler) atmel_set_power, /* SIOCSIWPOWER */ |
2578 | (iw_handler) atmel_get_power, /* SIOCGIWPOWER */ | 2578 | (iw_handler) atmel_get_power, /* SIOCGIWPOWER */ |
2579 | (iw_handler) NULL, /* -- hole -- */ | 2579 | (iw_handler) NULL, /* -- hole -- */ |
2580 | (iw_handler) NULL, /* -- hole -- */ | 2580 | (iw_handler) NULL, /* -- hole -- */ |
2581 | (iw_handler) NULL, /* SIOCSIWGENIE */ | 2581 | (iw_handler) NULL, /* SIOCSIWGENIE */ |
2582 | (iw_handler) NULL, /* SIOCGIWGENIE */ | 2582 | (iw_handler) NULL, /* SIOCGIWGENIE */ |
2583 | (iw_handler) atmel_set_auth, /* SIOCSIWAUTH */ | 2583 | (iw_handler) atmel_set_auth, /* SIOCSIWAUTH */ |
2584 | (iw_handler) atmel_get_auth, /* SIOCGIWAUTH */ | 2584 | (iw_handler) atmel_get_auth, /* SIOCGIWAUTH */ |
2585 | (iw_handler) atmel_set_encodeext, /* SIOCSIWENCODEEXT */ | 2585 | (iw_handler) atmel_set_encodeext, /* SIOCSIWENCODEEXT */ |
2586 | (iw_handler) atmel_get_encodeext, /* SIOCGIWENCODEEXT */ | 2586 | (iw_handler) atmel_get_encodeext, /* SIOCGIWENCODEEXT */ |
2587 | (iw_handler) NULL, /* SIOCSIWPMKSA */ | 2587 | (iw_handler) NULL, /* SIOCSIWPMKSA */ |
2588 | }; | 2588 | }; |
2589 | 2589 | ||
2590 | static const iw_handler atmel_private_handler[] = | 2590 | static const iw_handler atmel_private_handler[] = |
2591 | { | 2591 | { |
2592 | NULL, /* SIOCIWFIRSTPRIV */ | 2592 | NULL, /* SIOCIWFIRSTPRIV */ |
2593 | }; | 2593 | }; |
2594 | 2594 | ||
2595 | typedef struct atmel_priv_ioctl { | 2595 | typedef struct atmel_priv_ioctl { |
2596 | char id[32]; | 2596 | char id[32]; |
2597 | unsigned char __user *data; | 2597 | unsigned char __user *data; |
2598 | unsigned short len; | 2598 | unsigned short len; |
2599 | } atmel_priv_ioctl; | 2599 | } atmel_priv_ioctl; |
2600 | 2600 | ||
2601 | #define ATMELFWL SIOCIWFIRSTPRIV | 2601 | #define ATMELFWL SIOCIWFIRSTPRIV |
2602 | #define ATMELIDIFC ATMELFWL + 1 | 2602 | #define ATMELIDIFC ATMELFWL + 1 |
2603 | #define ATMELRD ATMELFWL + 2 | 2603 | #define ATMELRD ATMELFWL + 2 |
2604 | #define ATMELMAGIC 0x51807 | 2604 | #define ATMELMAGIC 0x51807 |
2605 | #define REGDOMAINSZ 20 | 2605 | #define REGDOMAINSZ 20 |
2606 | 2606 | ||
2607 | static const struct iw_priv_args atmel_private_args[] = { | 2607 | static const struct iw_priv_args atmel_private_args[] = { |
2608 | { | 2608 | { |
2609 | .cmd = ATMELFWL, | 2609 | .cmd = ATMELFWL, |
2610 | .set_args = IW_PRIV_TYPE_BYTE | 2610 | .set_args = IW_PRIV_TYPE_BYTE |
2611 | | IW_PRIV_SIZE_FIXED | 2611 | | IW_PRIV_SIZE_FIXED |
2612 | | sizeof (atmel_priv_ioctl), | 2612 | | sizeof (atmel_priv_ioctl), |
2613 | .get_args = IW_PRIV_TYPE_NONE, | 2613 | .get_args = IW_PRIV_TYPE_NONE, |
2614 | .name = "atmelfwl" | 2614 | .name = "atmelfwl" |
2615 | }, { | 2615 | }, { |
2616 | .cmd = ATMELIDIFC, | 2616 | .cmd = ATMELIDIFC, |
2617 | .set_args = IW_PRIV_TYPE_NONE, | 2617 | .set_args = IW_PRIV_TYPE_NONE, |
2618 | .get_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | 2618 | .get_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, |
2619 | .name = "atmelidifc" | 2619 | .name = "atmelidifc" |
2620 | }, { | 2620 | }, { |
2621 | .cmd = ATMELRD, | 2621 | .cmd = ATMELRD, |
2622 | .set_args = IW_PRIV_TYPE_CHAR | REGDOMAINSZ, | 2622 | .set_args = IW_PRIV_TYPE_CHAR | REGDOMAINSZ, |
2623 | .get_args = IW_PRIV_TYPE_NONE, | 2623 | .get_args = IW_PRIV_TYPE_NONE, |
2624 | .name = "regdomain" | 2624 | .name = "regdomain" |
2625 | }, | 2625 | }, |
2626 | }; | 2626 | }; |
2627 | 2627 | ||
2628 | static const struct iw_handler_def atmel_handler_def = { | 2628 | static const struct iw_handler_def atmel_handler_def = { |
2629 | .num_standard = ARRAY_SIZE(atmel_handler), | 2629 | .num_standard = ARRAY_SIZE(atmel_handler), |
2630 | .num_private = ARRAY_SIZE(atmel_private_handler), | 2630 | .num_private = ARRAY_SIZE(atmel_private_handler), |
2631 | .num_private_args = ARRAY_SIZE(atmel_private_args), | 2631 | .num_private_args = ARRAY_SIZE(atmel_private_args), |
2632 | .standard = (iw_handler *) atmel_handler, | 2632 | .standard = (iw_handler *) atmel_handler, |
2633 | .private = (iw_handler *) atmel_private_handler, | 2633 | .private = (iw_handler *) atmel_private_handler, |
2634 | .private_args = (struct iw_priv_args *) atmel_private_args, | 2634 | .private_args = (struct iw_priv_args *) atmel_private_args, |
2635 | .get_wireless_stats = atmel_get_wireless_stats | 2635 | .get_wireless_stats = atmel_get_wireless_stats |
2636 | }; | 2636 | }; |
2637 | 2637 | ||
2638 | static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | 2638 | static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
2639 | { | 2639 | { |
2640 | int i, rc = 0; | 2640 | int i, rc = 0; |
2641 | struct atmel_private *priv = netdev_priv(dev); | 2641 | struct atmel_private *priv = netdev_priv(dev); |
2642 | atmel_priv_ioctl com; | 2642 | atmel_priv_ioctl com; |
2643 | struct iwreq *wrq = (struct iwreq *) rq; | 2643 | struct iwreq *wrq = (struct iwreq *) rq; |
2644 | unsigned char *new_firmware; | 2644 | unsigned char *new_firmware; |
2645 | char domain[REGDOMAINSZ + 1]; | 2645 | char domain[REGDOMAINSZ + 1]; |
2646 | 2646 | ||
2647 | switch (cmd) { | 2647 | switch (cmd) { |
2648 | case ATMELIDIFC: | 2648 | case ATMELIDIFC: |
2649 | wrq->u.param.value = ATMELMAGIC; | 2649 | wrq->u.param.value = ATMELMAGIC; |
2650 | break; | 2650 | break; |
2651 | 2651 | ||
2652 | case ATMELFWL: | 2652 | case ATMELFWL: |
2653 | if (copy_from_user(&com, rq->ifr_data, sizeof(com))) { | 2653 | if (copy_from_user(&com, rq->ifr_data, sizeof(com))) { |
2654 | rc = -EFAULT; | 2654 | rc = -EFAULT; |
2655 | break; | 2655 | break; |
2656 | } | 2656 | } |
2657 | 2657 | ||
2658 | if (!capable(CAP_NET_ADMIN)) { | 2658 | if (!capable(CAP_NET_ADMIN)) { |
2659 | rc = -EPERM; | 2659 | rc = -EPERM; |
2660 | break; | 2660 | break; |
2661 | } | 2661 | } |
2662 | 2662 | ||
2663 | if (!(new_firmware = kmalloc(com.len, GFP_KERNEL))) { | 2663 | if (!(new_firmware = kmalloc(com.len, GFP_KERNEL))) { |
2664 | rc = -ENOMEM; | 2664 | rc = -ENOMEM; |
2665 | break; | 2665 | break; |
2666 | } | 2666 | } |
2667 | 2667 | ||
2668 | if (copy_from_user(new_firmware, com.data, com.len)) { | 2668 | if (copy_from_user(new_firmware, com.data, com.len)) { |
2669 | kfree(new_firmware); | 2669 | kfree(new_firmware); |
2670 | rc = -EFAULT; | 2670 | rc = -EFAULT; |
2671 | break; | 2671 | break; |
2672 | } | 2672 | } |
2673 | 2673 | ||
2674 | kfree(priv->firmware); | 2674 | kfree(priv->firmware); |
2675 | 2675 | ||
2676 | priv->firmware = new_firmware; | 2676 | priv->firmware = new_firmware; |
2677 | priv->firmware_length = com.len; | 2677 | priv->firmware_length = com.len; |
2678 | strncpy(priv->firmware_id, com.id, 31); | 2678 | strncpy(priv->firmware_id, com.id, 31); |
2679 | priv->firmware_id[31] = '\0'; | 2679 | priv->firmware_id[31] = '\0'; |
2680 | break; | 2680 | break; |
2681 | 2681 | ||
2682 | case ATMELRD: | 2682 | case ATMELRD: |
2683 | if (copy_from_user(domain, rq->ifr_data, REGDOMAINSZ)) { | 2683 | if (copy_from_user(domain, rq->ifr_data, REGDOMAINSZ)) { |
2684 | rc = -EFAULT; | 2684 | rc = -EFAULT; |
2685 | break; | 2685 | break; |
2686 | } | 2686 | } |
2687 | 2687 | ||
2688 | if (!capable(CAP_NET_ADMIN)) { | 2688 | if (!capable(CAP_NET_ADMIN)) { |
2689 | rc = -EPERM; | 2689 | rc = -EPERM; |
2690 | break; | 2690 | break; |
2691 | } | 2691 | } |
2692 | 2692 | ||
2693 | domain[REGDOMAINSZ] = 0; | 2693 | domain[REGDOMAINSZ] = 0; |
2694 | rc = -EINVAL; | 2694 | rc = -EINVAL; |
2695 | for (i = 0; i < ARRAY_SIZE(channel_table); i++) { | 2695 | for (i = 0; i < ARRAY_SIZE(channel_table); i++) { |
2696 | /* strcasecmp doesn't exist in the library */ | 2696 | /* strcasecmp doesn't exist in the library */ |
2697 | char *a = channel_table[i].name; | 2697 | char *a = channel_table[i].name; |
2698 | char *b = domain; | 2698 | char *b = domain; |
2699 | while (*a) { | 2699 | while (*a) { |
2700 | char c1 = *a++; | 2700 | char c1 = *a++; |
2701 | char c2 = *b++; | 2701 | char c2 = *b++; |
2702 | if (tolower(c1) != tolower(c2)) | 2702 | if (tolower(c1) != tolower(c2)) |
2703 | break; | 2703 | break; |
2704 | } | 2704 | } |
2705 | if (!*a && !*b) { | 2705 | if (!*a && !*b) { |
2706 | priv->config_reg_domain = channel_table[i].reg_domain; | 2706 | priv->config_reg_domain = channel_table[i].reg_domain; |
2707 | rc = 0; | 2707 | rc = 0; |
2708 | } | 2708 | } |
2709 | } | 2709 | } |
2710 | 2710 | ||
2711 | if (rc == 0 && priv->station_state != STATION_STATE_DOWN) | 2711 | if (rc == 0 && priv->station_state != STATION_STATE_DOWN) |
2712 | rc = atmel_open(dev); | 2712 | rc = atmel_open(dev); |
2713 | break; | 2713 | break; |
2714 | 2714 | ||
2715 | default: | 2715 | default: |
2716 | rc = -EOPNOTSUPP; | 2716 | rc = -EOPNOTSUPP; |
2717 | } | 2717 | } |
2718 | 2718 | ||
2719 | return rc; | 2719 | return rc; |
2720 | } | 2720 | } |
2721 | 2721 | ||
2722 | struct auth_body { | 2722 | struct auth_body { |
2723 | __le16 alg; | 2723 | __le16 alg; |
2724 | __le16 trans_seq; | 2724 | __le16 trans_seq; |
2725 | __le16 status; | 2725 | __le16 status; |
2726 | u8 el_id; | 2726 | u8 el_id; |
2727 | u8 chall_text_len; | 2727 | u8 chall_text_len; |
2728 | u8 chall_text[253]; | 2728 | u8 chall_text[253]; |
2729 | }; | 2729 | }; |
2730 | 2730 | ||
2731 | static void atmel_enter_state(struct atmel_private *priv, int new_state) | 2731 | static void atmel_enter_state(struct atmel_private *priv, int new_state) |
2732 | { | 2732 | { |
2733 | int old_state = priv->station_state; | 2733 | int old_state = priv->station_state; |
2734 | 2734 | ||
2735 | if (new_state == old_state) | 2735 | if (new_state == old_state) |
2736 | return; | 2736 | return; |
2737 | 2737 | ||
2738 | priv->station_state = new_state; | 2738 | priv->station_state = new_state; |
2739 | 2739 | ||
2740 | if (new_state == STATION_STATE_READY) { | 2740 | if (new_state == STATION_STATE_READY) { |
2741 | netif_start_queue(priv->dev); | 2741 | netif_start_queue(priv->dev); |
2742 | netif_carrier_on(priv->dev); | 2742 | netif_carrier_on(priv->dev); |
2743 | } | 2743 | } |
2744 | 2744 | ||
2745 | if (old_state == STATION_STATE_READY) { | 2745 | if (old_state == STATION_STATE_READY) { |
2746 | netif_carrier_off(priv->dev); | 2746 | netif_carrier_off(priv->dev); |
2747 | if (netif_running(priv->dev)) | 2747 | if (netif_running(priv->dev)) |
2748 | netif_stop_queue(priv->dev); | 2748 | netif_stop_queue(priv->dev); |
2749 | priv->last_beacon_timestamp = 0; | 2749 | priv->last_beacon_timestamp = 0; |
2750 | } | 2750 | } |
2751 | } | 2751 | } |
2752 | 2752 | ||
2753 | static void atmel_scan(struct atmel_private *priv, int specific_ssid) | 2753 | static void atmel_scan(struct atmel_private *priv, int specific_ssid) |
2754 | { | 2754 | { |
2755 | struct { | 2755 | struct { |
2756 | u8 BSSID[6]; | 2756 | u8 BSSID[6]; |
2757 | u8 SSID[MAX_SSID_LENGTH]; | 2757 | u8 SSID[MAX_SSID_LENGTH]; |
2758 | u8 scan_type; | 2758 | u8 scan_type; |
2759 | u8 channel; | 2759 | u8 channel; |
2760 | __le16 BSS_type; | 2760 | __le16 BSS_type; |
2761 | __le16 min_channel_time; | 2761 | __le16 min_channel_time; |
2762 | __le16 max_channel_time; | 2762 | __le16 max_channel_time; |
2763 | u8 options; | 2763 | u8 options; |
2764 | u8 SSID_size; | 2764 | u8 SSID_size; |
2765 | } cmd; | 2765 | } cmd; |
2766 | 2766 | ||
2767 | memset(cmd.BSSID, 0xff, 6); | 2767 | memset(cmd.BSSID, 0xff, 6); |
2768 | 2768 | ||
2769 | if (priv->fast_scan) { | 2769 | if (priv->fast_scan) { |
2770 | cmd.SSID_size = priv->SSID_size; | 2770 | cmd.SSID_size = priv->SSID_size; |
2771 | memcpy(cmd.SSID, priv->SSID, priv->SSID_size); | 2771 | memcpy(cmd.SSID, priv->SSID, priv->SSID_size); |
2772 | cmd.min_channel_time = cpu_to_le16(10); | 2772 | cmd.min_channel_time = cpu_to_le16(10); |
2773 | cmd.max_channel_time = cpu_to_le16(50); | 2773 | cmd.max_channel_time = cpu_to_le16(50); |
2774 | } else { | 2774 | } else { |
2775 | priv->BSS_list_entries = 0; | 2775 | priv->BSS_list_entries = 0; |
2776 | cmd.SSID_size = 0; | 2776 | cmd.SSID_size = 0; |
2777 | cmd.min_channel_time = cpu_to_le16(10); | 2777 | cmd.min_channel_time = cpu_to_le16(10); |
2778 | cmd.max_channel_time = cpu_to_le16(120); | 2778 | cmd.max_channel_time = cpu_to_le16(120); |
2779 | } | 2779 | } |
2780 | 2780 | ||
2781 | cmd.options = 0; | 2781 | cmd.options = 0; |
2782 | 2782 | ||
2783 | if (!specific_ssid) | 2783 | if (!specific_ssid) |
2784 | cmd.options |= SCAN_OPTIONS_SITE_SURVEY; | 2784 | cmd.options |= SCAN_OPTIONS_SITE_SURVEY; |
2785 | 2785 | ||
2786 | cmd.channel = (priv->channel & 0x7f); | 2786 | cmd.channel = (priv->channel & 0x7f); |
2787 | cmd.scan_type = SCAN_TYPE_ACTIVE; | 2787 | cmd.scan_type = SCAN_TYPE_ACTIVE; |
2788 | cmd.BSS_type = cpu_to_le16(priv->operating_mode == IW_MODE_ADHOC ? | 2788 | cmd.BSS_type = cpu_to_le16(priv->operating_mode == IW_MODE_ADHOC ? |
2789 | BSS_TYPE_AD_HOC : BSS_TYPE_INFRASTRUCTURE); | 2789 | BSS_TYPE_AD_HOC : BSS_TYPE_INFRASTRUCTURE); |
2790 | 2790 | ||
2791 | atmel_send_command(priv, CMD_Scan, &cmd, sizeof(cmd)); | 2791 | atmel_send_command(priv, CMD_Scan, &cmd, sizeof(cmd)); |
2792 | 2792 | ||
2793 | /* This must come after all hardware access to avoid being messed up | 2793 | /* This must come after all hardware access to avoid being messed up |
2794 | by stuff happening in interrupt context after we leave STATE_DOWN */ | 2794 | by stuff happening in interrupt context after we leave STATE_DOWN */ |
2795 | atmel_enter_state(priv, STATION_STATE_SCANNING); | 2795 | atmel_enter_state(priv, STATION_STATE_SCANNING); |
2796 | } | 2796 | } |
2797 | 2797 | ||
2798 | static void join(struct atmel_private *priv, int type) | 2798 | static void join(struct atmel_private *priv, int type) |
2799 | { | 2799 | { |
2800 | struct { | 2800 | struct { |
2801 | u8 BSSID[6]; | 2801 | u8 BSSID[6]; |
2802 | u8 SSID[MAX_SSID_LENGTH]; | 2802 | u8 SSID[MAX_SSID_LENGTH]; |
2803 | u8 BSS_type; /* this is a short in a scan command - weird */ | 2803 | u8 BSS_type; /* this is a short in a scan command - weird */ |
2804 | u8 channel; | 2804 | u8 channel; |
2805 | __le16 timeout; | 2805 | __le16 timeout; |
2806 | u8 SSID_size; | 2806 | u8 SSID_size; |
2807 | u8 reserved; | 2807 | u8 reserved; |
2808 | } cmd; | 2808 | } cmd; |
2809 | 2809 | ||
2810 | cmd.SSID_size = priv->SSID_size; | 2810 | cmd.SSID_size = priv->SSID_size; |
2811 | memcpy(cmd.SSID, priv->SSID, priv->SSID_size); | 2811 | memcpy(cmd.SSID, priv->SSID, priv->SSID_size); |
2812 | memcpy(cmd.BSSID, priv->CurrentBSSID, 6); | 2812 | memcpy(cmd.BSSID, priv->CurrentBSSID, 6); |
2813 | cmd.channel = (priv->channel & 0x7f); | 2813 | cmd.channel = (priv->channel & 0x7f); |
2814 | cmd.BSS_type = type; | 2814 | cmd.BSS_type = type; |
2815 | cmd.timeout = cpu_to_le16(2000); | 2815 | cmd.timeout = cpu_to_le16(2000); |
2816 | 2816 | ||
2817 | atmel_send_command(priv, CMD_Join, &cmd, sizeof(cmd)); | 2817 | atmel_send_command(priv, CMD_Join, &cmd, sizeof(cmd)); |
2818 | } | 2818 | } |
2819 | 2819 | ||
2820 | static void start(struct atmel_private *priv, int type) | 2820 | static void start(struct atmel_private *priv, int type) |
2821 | { | 2821 | { |
2822 | struct { | 2822 | struct { |
2823 | u8 BSSID[6]; | 2823 | u8 BSSID[6]; |
2824 | u8 SSID[MAX_SSID_LENGTH]; | 2824 | u8 SSID[MAX_SSID_LENGTH]; |
2825 | u8 BSS_type; | 2825 | u8 BSS_type; |
2826 | u8 channel; | 2826 | u8 channel; |
2827 | u8 SSID_size; | 2827 | u8 SSID_size; |
2828 | u8 reserved[3]; | 2828 | u8 reserved[3]; |
2829 | } cmd; | 2829 | } cmd; |
2830 | 2830 | ||
2831 | cmd.SSID_size = priv->SSID_size; | 2831 | cmd.SSID_size = priv->SSID_size; |
2832 | memcpy(cmd.SSID, priv->SSID, priv->SSID_size); | 2832 | memcpy(cmd.SSID, priv->SSID, priv->SSID_size); |
2833 | memcpy(cmd.BSSID, priv->BSSID, 6); | 2833 | memcpy(cmd.BSSID, priv->BSSID, 6); |
2834 | cmd.BSS_type = type; | 2834 | cmd.BSS_type = type; |
2835 | cmd.channel = (priv->channel & 0x7f); | 2835 | cmd.channel = (priv->channel & 0x7f); |
2836 | 2836 | ||
2837 | atmel_send_command(priv, CMD_Start, &cmd, sizeof(cmd)); | 2837 | atmel_send_command(priv, CMD_Start, &cmd, sizeof(cmd)); |
2838 | } | 2838 | } |
2839 | 2839 | ||
2840 | static void handle_beacon_probe(struct atmel_private *priv, u16 capability, | 2840 | static void handle_beacon_probe(struct atmel_private *priv, u16 capability, |
2841 | u8 channel) | 2841 | u8 channel) |
2842 | { | 2842 | { |
2843 | int rejoin = 0; | 2843 | int rejoin = 0; |
2844 | int new = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? | 2844 | int new = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? |
2845 | SHORT_PREAMBLE : LONG_PREAMBLE; | 2845 | SHORT_PREAMBLE : LONG_PREAMBLE; |
2846 | 2846 | ||
2847 | if (priv->preamble != new) { | 2847 | if (priv->preamble != new) { |
2848 | priv->preamble = new; | 2848 | priv->preamble = new; |
2849 | rejoin = 1; | 2849 | rejoin = 1; |
2850 | atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, new); | 2850 | atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, new); |
2851 | } | 2851 | } |
2852 | 2852 | ||
2853 | if (priv->channel != channel) { | 2853 | if (priv->channel != channel) { |
2854 | priv->channel = channel; | 2854 | priv->channel = channel; |
2855 | rejoin = 1; | 2855 | rejoin = 1; |
2856 | atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_CHANNEL_POS, channel); | 2856 | atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_CHANNEL_POS, channel); |
2857 | } | 2857 | } |
2858 | 2858 | ||
2859 | if (rejoin) { | 2859 | if (rejoin) { |
2860 | priv->station_is_associated = 0; | 2860 | priv->station_is_associated = 0; |
2861 | atmel_enter_state(priv, STATION_STATE_JOINNING); | 2861 | atmel_enter_state(priv, STATION_STATE_JOINNING); |
2862 | 2862 | ||
2863 | if (priv->operating_mode == IW_MODE_INFRA) | 2863 | if (priv->operating_mode == IW_MODE_INFRA) |
2864 | join(priv, BSS_TYPE_INFRASTRUCTURE); | 2864 | join(priv, BSS_TYPE_INFRASTRUCTURE); |
2865 | else | 2865 | else |
2866 | join(priv, BSS_TYPE_AD_HOC); | 2866 | join(priv, BSS_TYPE_AD_HOC); |
2867 | } | 2867 | } |
2868 | } | 2868 | } |
2869 | 2869 | ||
2870 | static void send_authentication_request(struct atmel_private *priv, u16 system, | 2870 | static void send_authentication_request(struct atmel_private *priv, u16 system, |
2871 | u8 *challenge, int challenge_len) | 2871 | u8 *challenge, int challenge_len) |
2872 | { | 2872 | { |
2873 | struct ieee80211_hdr header; | 2873 | struct ieee80211_hdr header; |
2874 | struct auth_body auth; | 2874 | struct auth_body auth; |
2875 | 2875 | ||
2876 | header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); | 2876 | header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); |
2877 | header.duration_id = cpu_to_le16(0x8000); | 2877 | header.duration_id = cpu_to_le16(0x8000); |
2878 | header.seq_ctrl = 0; | 2878 | header.seq_ctrl = 0; |
2879 | memcpy(header.addr1, priv->CurrentBSSID, 6); | 2879 | memcpy(header.addr1, priv->CurrentBSSID, 6); |
2880 | memcpy(header.addr2, priv->dev->dev_addr, 6); | 2880 | memcpy(header.addr2, priv->dev->dev_addr, 6); |
2881 | memcpy(header.addr3, priv->CurrentBSSID, 6); | 2881 | memcpy(header.addr3, priv->CurrentBSSID, 6); |
2882 | 2882 | ||
2883 | if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1) | 2883 | if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1) |
2884 | /* no WEP for authentication frames with TrSeqNo 1 */ | 2884 | /* no WEP for authentication frames with TrSeqNo 1 */ |
2885 | header.frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | 2885 | header.frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
2886 | 2886 | ||
2887 | auth.alg = cpu_to_le16(system); | 2887 | auth.alg = cpu_to_le16(system); |
2888 | 2888 | ||
2889 | auth.status = 0; | 2889 | auth.status = 0; |
2890 | auth.trans_seq = cpu_to_le16(priv->CurrentAuthentTransactionSeqNum); | 2890 | auth.trans_seq = cpu_to_le16(priv->CurrentAuthentTransactionSeqNum); |
2891 | priv->ExpectedAuthentTransactionSeqNum = priv->CurrentAuthentTransactionSeqNum+1; | 2891 | priv->ExpectedAuthentTransactionSeqNum = priv->CurrentAuthentTransactionSeqNum+1; |
2892 | priv->CurrentAuthentTransactionSeqNum += 2; | 2892 | priv->CurrentAuthentTransactionSeqNum += 2; |
2893 | 2893 | ||
2894 | if (challenge_len != 0) { | 2894 | if (challenge_len != 0) { |
2895 | auth.el_id = 16; /* challenge_text */ | 2895 | auth.el_id = 16; /* challenge_text */ |
2896 | auth.chall_text_len = challenge_len; | 2896 | auth.chall_text_len = challenge_len; |
2897 | memcpy(auth.chall_text, challenge, challenge_len); | 2897 | memcpy(auth.chall_text, challenge, challenge_len); |
2898 | atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 8 + challenge_len); | 2898 | atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 8 + challenge_len); |
2899 | } else { | 2899 | } else { |
2900 | atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 6); | 2900 | atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 6); |
2901 | } | 2901 | } |
2902 | } | 2902 | } |
2903 | 2903 | ||
2904 | static void send_association_request(struct atmel_private *priv, int is_reassoc) | 2904 | static void send_association_request(struct atmel_private *priv, int is_reassoc) |
2905 | { | 2905 | { |
2906 | u8 *ssid_el_p; | 2906 | u8 *ssid_el_p; |
2907 | int bodysize; | 2907 | int bodysize; |
2908 | struct ieee80211_hdr header; | 2908 | struct ieee80211_hdr header; |
2909 | struct ass_req_format { | 2909 | struct ass_req_format { |
2910 | __le16 capability; | 2910 | __le16 capability; |
2911 | __le16 listen_interval; | 2911 | __le16 listen_interval; |
2912 | u8 ap[6]; /* nothing after here directly accessible */ | 2912 | u8 ap[6]; /* nothing after here directly accessible */ |
2913 | u8 ssid_el_id; | 2913 | u8 ssid_el_id; |
2914 | u8 ssid_len; | 2914 | u8 ssid_len; |
2915 | u8 ssid[MAX_SSID_LENGTH]; | 2915 | u8 ssid[MAX_SSID_LENGTH]; |
2916 | u8 sup_rates_el_id; | 2916 | u8 sup_rates_el_id; |
2917 | u8 sup_rates_len; | 2917 | u8 sup_rates_len; |
2918 | u8 rates[4]; | 2918 | u8 rates[4]; |
2919 | } body; | 2919 | } body; |
2920 | 2920 | ||
2921 | header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 2921 | header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
2922 | (is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ)); | 2922 | (is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ)); |
2923 | header.duration_id = cpu_to_le16(0x8000); | 2923 | header.duration_id = cpu_to_le16(0x8000); |
2924 | header.seq_ctrl = 0; | 2924 | header.seq_ctrl = 0; |
2925 | 2925 | ||
2926 | memcpy(header.addr1, priv->CurrentBSSID, 6); | 2926 | memcpy(header.addr1, priv->CurrentBSSID, 6); |
2927 | memcpy(header.addr2, priv->dev->dev_addr, 6); | 2927 | memcpy(header.addr2, priv->dev->dev_addr, 6); |
2928 | memcpy(header.addr3, priv->CurrentBSSID, 6); | 2928 | memcpy(header.addr3, priv->CurrentBSSID, 6); |
2929 | 2929 | ||
2930 | body.capability = cpu_to_le16(WLAN_CAPABILITY_ESS); | 2930 | body.capability = cpu_to_le16(WLAN_CAPABILITY_ESS); |
2931 | if (priv->wep_is_on) | 2931 | if (priv->wep_is_on) |
2932 | body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); | 2932 | body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); |
2933 | if (priv->preamble == SHORT_PREAMBLE) | 2933 | if (priv->preamble == SHORT_PREAMBLE) |
2934 | body.capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); | 2934 | body.capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); |
2935 | 2935 | ||
2936 | body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period); | 2936 | body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period); |
2937 | 2937 | ||
2938 | /* current AP address - only in reassoc frame */ | 2938 | /* current AP address - only in reassoc frame */ |
2939 | if (is_reassoc) { | 2939 | if (is_reassoc) { |
2940 | memcpy(body.ap, priv->CurrentBSSID, 6); | 2940 | memcpy(body.ap, priv->CurrentBSSID, 6); |
2941 | ssid_el_p = (u8 *)&body.ssid_el_id; | 2941 | ssid_el_p = (u8 *)&body.ssid_el_id; |
2942 | bodysize = 18 + priv->SSID_size; | 2942 | bodysize = 18 + priv->SSID_size; |
2943 | } else { | 2943 | } else { |
2944 | ssid_el_p = (u8 *)&body.ap[0]; | 2944 | ssid_el_p = (u8 *)&body.ap[0]; |
2945 | bodysize = 12 + priv->SSID_size; | 2945 | bodysize = 12 + priv->SSID_size; |
2946 | } | 2946 | } |
2947 | 2947 | ||
2948 | ssid_el_p[0] = WLAN_EID_SSID; | 2948 | ssid_el_p[0] = WLAN_EID_SSID; |
2949 | ssid_el_p[1] = priv->SSID_size; | 2949 | ssid_el_p[1] = priv->SSID_size; |
2950 | memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size); | 2950 | memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size); |
2951 | ssid_el_p[2 + priv->SSID_size] = WLAN_EID_SUPP_RATES; | 2951 | ssid_el_p[2 + priv->SSID_size] = WLAN_EID_SUPP_RATES; |
2952 | ssid_el_p[3 + priv->SSID_size] = 4; /* len of suported rates */ | 2952 | ssid_el_p[3 + priv->SSID_size] = 4; /* len of suported rates */ |
2953 | memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4); | 2953 | memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4); |
2954 | 2954 | ||
2955 | atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize); | 2955 | atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize); |
2956 | } | 2956 | } |
2957 | 2957 | ||
2958 | static int is_frame_from_current_bss(struct atmel_private *priv, | 2958 | static int is_frame_from_current_bss(struct atmel_private *priv, |
2959 | struct ieee80211_hdr *header) | 2959 | struct ieee80211_hdr *header) |
2960 | { | 2960 | { |
2961 | if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) | 2961 | if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) |
2962 | return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; | 2962 | return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; |
2963 | else | 2963 | else |
2964 | return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0; | 2964 | return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0; |
2965 | } | 2965 | } |
2966 | 2966 | ||
2967 | static int retrieve_bss(struct atmel_private *priv) | 2967 | static int retrieve_bss(struct atmel_private *priv) |
2968 | { | 2968 | { |
2969 | int i; | 2969 | int i; |
2970 | int max_rssi = -128; | 2970 | int max_rssi = -128; |
2971 | int max_index = -1; | 2971 | int max_index = -1; |
2972 | 2972 | ||
2973 | if (priv->BSS_list_entries == 0) | 2973 | if (priv->BSS_list_entries == 0) |
2974 | return -1; | 2974 | return -1; |
2975 | 2975 | ||
2976 | if (priv->connect_to_any_BSS) { | 2976 | if (priv->connect_to_any_BSS) { |
2977 | /* Select a BSS with the max-RSSI but of the same type and of | 2977 | /* Select a BSS with the max-RSSI but of the same type and of |
2978 | the same WEP mode and that it is not marked as 'bad' (i.e. | 2978 | the same WEP mode and that it is not marked as 'bad' (i.e. |
2979 | we had previously failed to connect to this BSS with the | 2979 | we had previously failed to connect to this BSS with the |
2980 | settings that we currently use) */ | 2980 | settings that we currently use) */ |
2981 | priv->current_BSS = 0; | 2981 | priv->current_BSS = 0; |
2982 | for (i = 0; i < priv->BSS_list_entries; i++) { | 2982 | for (i = 0; i < priv->BSS_list_entries; i++) { |
2983 | if (priv->operating_mode == priv->BSSinfo[i].BSStype && | 2983 | if (priv->operating_mode == priv->BSSinfo[i].BSStype && |
2984 | ((!priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) || | 2984 | ((!priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) || |
2985 | (priv->wep_is_on && priv->BSSinfo[i].UsingWEP)) && | 2985 | (priv->wep_is_on && priv->BSSinfo[i].UsingWEP)) && |
2986 | !(priv->BSSinfo[i].channel & 0x80)) { | 2986 | !(priv->BSSinfo[i].channel & 0x80)) { |
2987 | max_rssi = priv->BSSinfo[i].RSSI; | 2987 | max_rssi = priv->BSSinfo[i].RSSI; |
2988 | priv->current_BSS = max_index = i; | 2988 | priv->current_BSS = max_index = i; |
2989 | } | 2989 | } |
2990 | } | 2990 | } |
2991 | return max_index; | 2991 | return max_index; |
2992 | } | 2992 | } |
2993 | 2993 | ||
2994 | for (i = 0; i < priv->BSS_list_entries; i++) { | 2994 | for (i = 0; i < priv->BSS_list_entries; i++) { |
2995 | if (priv->SSID_size == priv->BSSinfo[i].SSIDsize && | 2995 | if (priv->SSID_size == priv->BSSinfo[i].SSIDsize && |
2996 | memcmp(priv->SSID, priv->BSSinfo[i].SSID, priv->SSID_size) == 0 && | 2996 | memcmp(priv->SSID, priv->BSSinfo[i].SSID, priv->SSID_size) == 0 && |
2997 | priv->operating_mode == priv->BSSinfo[i].BSStype && | 2997 | priv->operating_mode == priv->BSSinfo[i].BSStype && |
2998 | atmel_validate_channel(priv, priv->BSSinfo[i].channel) == 0) { | 2998 | atmel_validate_channel(priv, priv->BSSinfo[i].channel) == 0) { |
2999 | if (priv->BSSinfo[i].RSSI >= max_rssi) { | 2999 | if (priv->BSSinfo[i].RSSI >= max_rssi) { |
3000 | max_rssi = priv->BSSinfo[i].RSSI; | 3000 | max_rssi = priv->BSSinfo[i].RSSI; |
3001 | max_index = i; | 3001 | max_index = i; |
3002 | } | 3002 | } |
3003 | } | 3003 | } |
3004 | } | 3004 | } |
3005 | return max_index; | 3005 | return max_index; |
3006 | } | 3006 | } |
3007 | 3007 | ||
3008 | static void store_bss_info(struct atmel_private *priv, | 3008 | static void store_bss_info(struct atmel_private *priv, |
3009 | struct ieee80211_hdr *header, u16 capability, | 3009 | struct ieee80211_hdr *header, u16 capability, |
3010 | u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len, | 3010 | u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len, |
3011 | u8 *ssid, int is_beacon) | 3011 | u8 *ssid, int is_beacon) |
3012 | { | 3012 | { |
3013 | u8 *bss = capability & WLAN_CAPABILITY_ESS ? header->addr2 : header->addr3; | 3013 | u8 *bss = capability & WLAN_CAPABILITY_ESS ? header->addr2 : header->addr3; |
3014 | int i, index; | 3014 | int i, index; |
3015 | 3015 | ||
3016 | for (index = -1, i = 0; i < priv->BSS_list_entries; i++) | 3016 | for (index = -1, i = 0; i < priv->BSS_list_entries; i++) |
3017 | if (memcmp(bss, priv->BSSinfo[i].BSSID, 6) == 0) | 3017 | if (memcmp(bss, priv->BSSinfo[i].BSSID, 6) == 0) |
3018 | index = i; | 3018 | index = i; |
3019 | 3019 | ||
3020 | /* If we process a probe and an entry from this BSS exists | 3020 | /* If we process a probe and an entry from this BSS exists |
3021 | we will update the BSS entry with the info from this BSS. | 3021 | we will update the BSS entry with the info from this BSS. |
3022 | If we process a beacon we will only update RSSI */ | 3022 | If we process a beacon we will only update RSSI */ |
3023 | 3023 | ||
3024 | if (index == -1) { | 3024 | if (index == -1) { |
3025 | if (priv->BSS_list_entries == MAX_BSS_ENTRIES) | 3025 | if (priv->BSS_list_entries == MAX_BSS_ENTRIES) |
3026 | return; | 3026 | return; |
3027 | index = priv->BSS_list_entries++; | 3027 | index = priv->BSS_list_entries++; |
3028 | memcpy(priv->BSSinfo[index].BSSID, bss, 6); | 3028 | memcpy(priv->BSSinfo[index].BSSID, bss, 6); |
3029 | priv->BSSinfo[index].RSSI = rssi; | 3029 | priv->BSSinfo[index].RSSI = rssi; |
3030 | } else { | 3030 | } else { |
3031 | if (rssi > priv->BSSinfo[index].RSSI) | 3031 | if (rssi > priv->BSSinfo[index].RSSI) |
3032 | priv->BSSinfo[index].RSSI = rssi; | 3032 | priv->BSSinfo[index].RSSI = rssi; |
3033 | if (is_beacon) | 3033 | if (is_beacon) |
3034 | return; | 3034 | return; |
3035 | } | 3035 | } |
3036 | 3036 | ||
3037 | priv->BSSinfo[index].channel = channel; | 3037 | priv->BSSinfo[index].channel = channel; |
3038 | priv->BSSinfo[index].beacon_period = beacon_period; | 3038 | priv->BSSinfo[index].beacon_period = beacon_period; |
3039 | priv->BSSinfo[index].UsingWEP = capability & WLAN_CAPABILITY_PRIVACY; | 3039 | priv->BSSinfo[index].UsingWEP = capability & WLAN_CAPABILITY_PRIVACY; |
3040 | memcpy(priv->BSSinfo[index].SSID, ssid, ssid_len); | 3040 | memcpy(priv->BSSinfo[index].SSID, ssid, ssid_len); |
3041 | priv->BSSinfo[index].SSIDsize = ssid_len; | 3041 | priv->BSSinfo[index].SSIDsize = ssid_len; |
3042 | 3042 | ||
3043 | if (capability & WLAN_CAPABILITY_IBSS) | 3043 | if (capability & WLAN_CAPABILITY_IBSS) |
3044 | priv->BSSinfo[index].BSStype = IW_MODE_ADHOC; | 3044 | priv->BSSinfo[index].BSStype = IW_MODE_ADHOC; |
3045 | else if (capability & WLAN_CAPABILITY_ESS) | 3045 | else if (capability & WLAN_CAPABILITY_ESS) |
3046 | priv->BSSinfo[index].BSStype = IW_MODE_INFRA; | 3046 | priv->BSSinfo[index].BSStype = IW_MODE_INFRA; |
3047 | 3047 | ||
3048 | priv->BSSinfo[index].preamble = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? | 3048 | priv->BSSinfo[index].preamble = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? |
3049 | SHORT_PREAMBLE : LONG_PREAMBLE; | 3049 | SHORT_PREAMBLE : LONG_PREAMBLE; |
3050 | } | 3050 | } |
3051 | 3051 | ||
3052 | static void authenticate(struct atmel_private *priv, u16 frame_len) | 3052 | static void authenticate(struct atmel_private *priv, u16 frame_len) |
3053 | { | 3053 | { |
3054 | struct auth_body *auth = (struct auth_body *)priv->rx_buf; | 3054 | struct auth_body *auth = (struct auth_body *)priv->rx_buf; |
3055 | u16 status = le16_to_cpu(auth->status); | 3055 | u16 status = le16_to_cpu(auth->status); |
3056 | u16 trans_seq_no = le16_to_cpu(auth->trans_seq); | 3056 | u16 trans_seq_no = le16_to_cpu(auth->trans_seq); |
3057 | u16 system = le16_to_cpu(auth->alg); | 3057 | u16 system = le16_to_cpu(auth->alg); |
3058 | 3058 | ||
3059 | if (status == WLAN_STATUS_SUCCESS && !priv->wep_is_on) { | 3059 | if (status == WLAN_STATUS_SUCCESS && !priv->wep_is_on) { |
3060 | /* no WEP */ | 3060 | /* no WEP */ |
3061 | if (priv->station_was_associated) { | 3061 | if (priv->station_was_associated) { |
3062 | atmel_enter_state(priv, STATION_STATE_REASSOCIATING); | 3062 | atmel_enter_state(priv, STATION_STATE_REASSOCIATING); |
3063 | send_association_request(priv, 1); | 3063 | send_association_request(priv, 1); |
3064 | return; | 3064 | return; |
3065 | } else { | 3065 | } else { |
3066 | atmel_enter_state(priv, STATION_STATE_ASSOCIATING); | 3066 | atmel_enter_state(priv, STATION_STATE_ASSOCIATING); |
3067 | send_association_request(priv, 0); | 3067 | send_association_request(priv, 0); |
3068 | return; | 3068 | return; |
3069 | } | 3069 | } |
3070 | } | 3070 | } |
3071 | 3071 | ||
3072 | if (status == WLAN_STATUS_SUCCESS && priv->wep_is_on) { | 3072 | if (status == WLAN_STATUS_SUCCESS && priv->wep_is_on) { |
3073 | int should_associate = 0; | 3073 | int should_associate = 0; |
3074 | /* WEP */ | 3074 | /* WEP */ |
3075 | if (trans_seq_no != priv->ExpectedAuthentTransactionSeqNum) | 3075 | if (trans_seq_no != priv->ExpectedAuthentTransactionSeqNum) |
3076 | return; | 3076 | return; |
3077 | 3077 | ||
3078 | if (system == WLAN_AUTH_OPEN) { | 3078 | if (system == WLAN_AUTH_OPEN) { |
3079 | if (trans_seq_no == 0x0002) { | 3079 | if (trans_seq_no == 0x0002) { |
3080 | should_associate = 1; | 3080 | should_associate = 1; |
3081 | } | 3081 | } |
3082 | } else if (system == WLAN_AUTH_SHARED_KEY) { | 3082 | } else if (system == WLAN_AUTH_SHARED_KEY) { |
3083 | if (trans_seq_no == 0x0002 && | 3083 | if (trans_seq_no == 0x0002 && |
3084 | auth->el_id == WLAN_EID_CHALLENGE) { | 3084 | auth->el_id == WLAN_EID_CHALLENGE) { |
3085 | send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len); | 3085 | send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len); |
3086 | return; | 3086 | return; |
3087 | } else if (trans_seq_no == 0x0004) { | 3087 | } else if (trans_seq_no == 0x0004) { |
3088 | should_associate = 1; | 3088 | should_associate = 1; |
3089 | } | 3089 | } |
3090 | } | 3090 | } |
3091 | 3091 | ||
3092 | if (should_associate) { | 3092 | if (should_associate) { |
3093 | if (priv->station_was_associated) { | 3093 | if (priv->station_was_associated) { |
3094 | atmel_enter_state(priv, STATION_STATE_REASSOCIATING); | 3094 | atmel_enter_state(priv, STATION_STATE_REASSOCIATING); |
3095 | send_association_request(priv, 1); | 3095 | send_association_request(priv, 1); |
3096 | return; | 3096 | return; |
3097 | } else { | 3097 | } else { |
3098 | atmel_enter_state(priv, STATION_STATE_ASSOCIATING); | 3098 | atmel_enter_state(priv, STATION_STATE_ASSOCIATING); |
3099 | send_association_request(priv, 0); | 3099 | send_association_request(priv, 0); |
3100 | return; | 3100 | return; |
3101 | } | 3101 | } |
3102 | } | 3102 | } |
3103 | } | 3103 | } |
3104 | 3104 | ||
3105 | if (status == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { | 3105 | if (status == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { |
3106 | /* Flip back and forth between WEP auth modes until the max | 3106 | /* Flip back and forth between WEP auth modes until the max |
3107 | * authentication tries has been exceeded. | 3107 | * authentication tries has been exceeded. |
3108 | */ | 3108 | */ |
3109 | if (system == WLAN_AUTH_OPEN) { | 3109 | if (system == WLAN_AUTH_OPEN) { |
3110 | priv->CurrentAuthentTransactionSeqNum = 0x001; | 3110 | priv->CurrentAuthentTransactionSeqNum = 0x001; |
3111 | priv->exclude_unencrypted = 1; | 3111 | priv->exclude_unencrypted = 1; |
3112 | send_authentication_request(priv, WLAN_AUTH_SHARED_KEY, NULL, 0); | 3112 | send_authentication_request(priv, WLAN_AUTH_SHARED_KEY, NULL, 0); |
3113 | return; | 3113 | return; |
3114 | } else if (system == WLAN_AUTH_SHARED_KEY | 3114 | } else if (system == WLAN_AUTH_SHARED_KEY |
3115 | && priv->wep_is_on) { | 3115 | && priv->wep_is_on) { |
3116 | priv->CurrentAuthentTransactionSeqNum = 0x001; | 3116 | priv->CurrentAuthentTransactionSeqNum = 0x001; |
3117 | priv->exclude_unencrypted = 0; | 3117 | priv->exclude_unencrypted = 0; |
3118 | send_authentication_request(priv, WLAN_AUTH_OPEN, NULL, 0); | 3118 | send_authentication_request(priv, WLAN_AUTH_OPEN, NULL, 0); |
3119 | return; | 3119 | return; |
3120 | } else if (priv->connect_to_any_BSS) { | 3120 | } else if (priv->connect_to_any_BSS) { |
3121 | int bss_index; | 3121 | int bss_index; |
3122 | 3122 | ||
3123 | priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; | 3123 | priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; |
3124 | 3124 | ||
3125 | if ((bss_index = retrieve_bss(priv)) != -1) { | 3125 | if ((bss_index = retrieve_bss(priv)) != -1) { |
3126 | atmel_join_bss(priv, bss_index); | 3126 | atmel_join_bss(priv, bss_index); |
3127 | return; | 3127 | return; |
3128 | } | 3128 | } |
3129 | } | 3129 | } |
3130 | } | 3130 | } |
3131 | 3131 | ||
3132 | priv->AuthenticationRequestRetryCnt = 0; | 3132 | priv->AuthenticationRequestRetryCnt = 0; |
3133 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | 3133 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); |
3134 | priv->station_is_associated = 0; | 3134 | priv->station_is_associated = 0; |
3135 | } | 3135 | } |
3136 | 3136 | ||
3137 | static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) | 3137 | static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) |
3138 | { | 3138 | { |
3139 | struct ass_resp_format { | 3139 | struct ass_resp_format { |
3140 | __le16 capability; | 3140 | __le16 capability; |
3141 | __le16 status; | 3141 | __le16 status; |
3142 | __le16 ass_id; | 3142 | __le16 ass_id; |
3143 | u8 el_id; | 3143 | u8 el_id; |
3144 | u8 length; | 3144 | u8 length; |
3145 | u8 rates[4]; | 3145 | u8 rates[4]; |
3146 | } *ass_resp = (struct ass_resp_format *)priv->rx_buf; | 3146 | } *ass_resp = (struct ass_resp_format *)priv->rx_buf; |
3147 | 3147 | ||
3148 | u16 status = le16_to_cpu(ass_resp->status); | 3148 | u16 status = le16_to_cpu(ass_resp->status); |
3149 | u16 ass_id = le16_to_cpu(ass_resp->ass_id); | 3149 | u16 ass_id = le16_to_cpu(ass_resp->ass_id); |
3150 | u16 rates_len = ass_resp->length > 4 ? 4 : ass_resp->length; | 3150 | u16 rates_len = ass_resp->length > 4 ? 4 : ass_resp->length; |
3151 | 3151 | ||
3152 | union iwreq_data wrqu; | 3152 | union iwreq_data wrqu; |
3153 | 3153 | ||
3154 | if (frame_len < 8 + rates_len) | 3154 | if (frame_len < 8 + rates_len) |
3155 | return; | 3155 | return; |
3156 | 3156 | ||
3157 | if (status == WLAN_STATUS_SUCCESS) { | 3157 | if (status == WLAN_STATUS_SUCCESS) { |
3158 | if (subtype == IEEE80211_STYPE_ASSOC_RESP) | 3158 | if (subtype == IEEE80211_STYPE_ASSOC_RESP) |
3159 | priv->AssociationRequestRetryCnt = 0; | 3159 | priv->AssociationRequestRetryCnt = 0; |
3160 | else | 3160 | else |
3161 | priv->ReAssociationRequestRetryCnt = 0; | 3161 | priv->ReAssociationRequestRetryCnt = 0; |
3162 | 3162 | ||
3163 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, | 3163 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, |
3164 | MAC_MGMT_MIB_STATION_ID_POS, ass_id & 0x3fff); | 3164 | MAC_MGMT_MIB_STATION_ID_POS, ass_id & 0x3fff); |
3165 | atmel_set_mib(priv, Phy_Mib_Type, | 3165 | atmel_set_mib(priv, Phy_Mib_Type, |
3166 | PHY_MIB_RATE_SET_POS, ass_resp->rates, rates_len); | 3166 | PHY_MIB_RATE_SET_POS, ass_resp->rates, rates_len); |
3167 | if (priv->power_mode == 0) { | 3167 | if (priv->power_mode == 0) { |
3168 | priv->listen_interval = 1; | 3168 | priv->listen_interval = 1; |
3169 | atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, | 3169 | atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, |
3170 | MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); | 3170 | MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); |
3171 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, | 3171 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, |
3172 | MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); | 3172 | MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); |
3173 | } else { | 3173 | } else { |
3174 | priv->listen_interval = 2; | 3174 | priv->listen_interval = 2; |
3175 | atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, | 3175 | atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, |
3176 | MAC_MGMT_MIB_PS_MODE_POS, PS_MODE); | 3176 | MAC_MGMT_MIB_PS_MODE_POS, PS_MODE); |
3177 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, | 3177 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, |
3178 | MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 2); | 3178 | MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 2); |
3179 | } | 3179 | } |
3180 | 3180 | ||
3181 | priv->station_is_associated = 1; | 3181 | priv->station_is_associated = 1; |
3182 | priv->station_was_associated = 1; | 3182 | priv->station_was_associated = 1; |
3183 | atmel_enter_state(priv, STATION_STATE_READY); | 3183 | atmel_enter_state(priv, STATION_STATE_READY); |
3184 | 3184 | ||
3185 | /* Send association event to userspace */ | 3185 | /* Send association event to userspace */ |
3186 | wrqu.data.length = 0; | 3186 | wrqu.data.length = 0; |
3187 | wrqu.data.flags = 0; | 3187 | wrqu.data.flags = 0; |
3188 | memcpy(wrqu.ap_addr.sa_data, priv->CurrentBSSID, ETH_ALEN); | 3188 | memcpy(wrqu.ap_addr.sa_data, priv->CurrentBSSID, ETH_ALEN); |
3189 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 3189 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
3190 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | 3190 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); |
3191 | 3191 | ||
3192 | return; | 3192 | return; |
3193 | } | 3193 | } |
3194 | 3194 | ||
3195 | if (subtype == IEEE80211_STYPE_ASSOC_RESP && | 3195 | if (subtype == IEEE80211_STYPE_ASSOC_RESP && |
3196 | status != WLAN_STATUS_ASSOC_DENIED_RATES && | 3196 | status != WLAN_STATUS_ASSOC_DENIED_RATES && |
3197 | status != WLAN_STATUS_CAPS_UNSUPPORTED && | 3197 | status != WLAN_STATUS_CAPS_UNSUPPORTED && |
3198 | priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { | 3198 | priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { |
3199 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | 3199 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); |
3200 | priv->AssociationRequestRetryCnt++; | 3200 | priv->AssociationRequestRetryCnt++; |
3201 | send_association_request(priv, 0); | 3201 | send_association_request(priv, 0); |
3202 | return; | 3202 | return; |
3203 | } | 3203 | } |
3204 | 3204 | ||
3205 | if (subtype == IEEE80211_STYPE_REASSOC_RESP && | 3205 | if (subtype == IEEE80211_STYPE_REASSOC_RESP && |
3206 | status != WLAN_STATUS_ASSOC_DENIED_RATES && | 3206 | status != WLAN_STATUS_ASSOC_DENIED_RATES && |
3207 | status != WLAN_STATUS_CAPS_UNSUPPORTED && | 3207 | status != WLAN_STATUS_CAPS_UNSUPPORTED && |
3208 | priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { | 3208 | priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { |
3209 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | 3209 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); |
3210 | priv->ReAssociationRequestRetryCnt++; | 3210 | priv->ReAssociationRequestRetryCnt++; |
3211 | send_association_request(priv, 1); | 3211 | send_association_request(priv, 1); |
3212 | return; | 3212 | return; |
3213 | } | 3213 | } |
3214 | 3214 | ||
3215 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | 3215 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); |
3216 | priv->station_is_associated = 0; | 3216 | priv->station_is_associated = 0; |
3217 | 3217 | ||
3218 | if (priv->connect_to_any_BSS) { | 3218 | if (priv->connect_to_any_BSS) { |
3219 | int bss_index; | 3219 | int bss_index; |
3220 | priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; | 3220 | priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; |
3221 | 3221 | ||
3222 | if ((bss_index = retrieve_bss(priv)) != -1) | 3222 | if ((bss_index = retrieve_bss(priv)) != -1) |
3223 | atmel_join_bss(priv, bss_index); | 3223 | atmel_join_bss(priv, bss_index); |
3224 | } | 3224 | } |
3225 | } | 3225 | } |
3226 | 3226 | ||
3227 | static void atmel_join_bss(struct atmel_private *priv, int bss_index) | 3227 | static void atmel_join_bss(struct atmel_private *priv, int bss_index) |
3228 | { | 3228 | { |
3229 | struct bss_info *bss = &priv->BSSinfo[bss_index]; | 3229 | struct bss_info *bss = &priv->BSSinfo[bss_index]; |
3230 | 3230 | ||
3231 | memcpy(priv->CurrentBSSID, bss->BSSID, 6); | 3231 | memcpy(priv->CurrentBSSID, bss->BSSID, 6); |
3232 | memcpy(priv->SSID, bss->SSID, priv->SSID_size = bss->SSIDsize); | 3232 | memcpy(priv->SSID, bss->SSID, priv->SSID_size = bss->SSIDsize); |
3233 | 3233 | ||
3234 | /* The WPA stuff cares about the current AP address */ | 3234 | /* The WPA stuff cares about the current AP address */ |
3235 | if (priv->use_wpa) | 3235 | if (priv->use_wpa) |
3236 | build_wpa_mib(priv); | 3236 | build_wpa_mib(priv); |
3237 | 3237 | ||
3238 | /* When switching to AdHoc turn OFF Power Save if needed */ | 3238 | /* When switching to AdHoc turn OFF Power Save if needed */ |
3239 | 3239 | ||
3240 | if (bss->BSStype == IW_MODE_ADHOC && | 3240 | if (bss->BSStype == IW_MODE_ADHOC && |
3241 | priv->operating_mode != IW_MODE_ADHOC && | 3241 | priv->operating_mode != IW_MODE_ADHOC && |
3242 | priv->power_mode) { | 3242 | priv->power_mode) { |
3243 | priv->power_mode = 0; | 3243 | priv->power_mode = 0; |
3244 | priv->listen_interval = 1; | 3244 | priv->listen_interval = 1; |
3245 | atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, | 3245 | atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, |
3246 | MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); | 3246 | MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); |
3247 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, | 3247 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, |
3248 | MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); | 3248 | MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); |
3249 | } | 3249 | } |
3250 | 3250 | ||
3251 | priv->operating_mode = bss->BSStype; | 3251 | priv->operating_mode = bss->BSStype; |
3252 | priv->channel = bss->channel & 0x7f; | 3252 | priv->channel = bss->channel & 0x7f; |
3253 | priv->beacon_period = bss->beacon_period; | 3253 | priv->beacon_period = bss->beacon_period; |
3254 | 3254 | ||
3255 | if (priv->preamble != bss->preamble) { | 3255 | if (priv->preamble != bss->preamble) { |
3256 | priv->preamble = bss->preamble; | 3256 | priv->preamble = bss->preamble; |
3257 | atmel_set_mib8(priv, Local_Mib_Type, | 3257 | atmel_set_mib8(priv, Local_Mib_Type, |
3258 | LOCAL_MIB_PREAMBLE_TYPE, bss->preamble); | 3258 | LOCAL_MIB_PREAMBLE_TYPE, bss->preamble); |
3259 | } | 3259 | } |
3260 | 3260 | ||
3261 | if (!priv->wep_is_on && bss->UsingWEP) { | 3261 | if (!priv->wep_is_on && bss->UsingWEP) { |
3262 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | 3262 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); |
3263 | priv->station_is_associated = 0; | 3263 | priv->station_is_associated = 0; |
3264 | return; | 3264 | return; |
3265 | } | 3265 | } |
3266 | 3266 | ||
3267 | if (priv->wep_is_on && !bss->UsingWEP) { | 3267 | if (priv->wep_is_on && !bss->UsingWEP) { |
3268 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | 3268 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); |
3269 | priv->station_is_associated = 0; | 3269 | priv->station_is_associated = 0; |
3270 | return; | 3270 | return; |
3271 | } | 3271 | } |
3272 | 3272 | ||
3273 | atmel_enter_state(priv, STATION_STATE_JOINNING); | 3273 | atmel_enter_state(priv, STATION_STATE_JOINNING); |
3274 | 3274 | ||
3275 | if (priv->operating_mode == IW_MODE_INFRA) | 3275 | if (priv->operating_mode == IW_MODE_INFRA) |
3276 | join(priv, BSS_TYPE_INFRASTRUCTURE); | 3276 | join(priv, BSS_TYPE_INFRASTRUCTURE); |
3277 | else | 3277 | else |
3278 | join(priv, BSS_TYPE_AD_HOC); | 3278 | join(priv, BSS_TYPE_AD_HOC); |
3279 | } | 3279 | } |
3280 | 3280 | ||
3281 | static void restart_search(struct atmel_private *priv) | 3281 | static void restart_search(struct atmel_private *priv) |
3282 | { | 3282 | { |
3283 | int bss_index; | 3283 | int bss_index; |
3284 | 3284 | ||
3285 | if (!priv->connect_to_any_BSS) { | 3285 | if (!priv->connect_to_any_BSS) { |
3286 | atmel_scan(priv, 1); | 3286 | atmel_scan(priv, 1); |
3287 | } else { | 3287 | } else { |
3288 | priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; | 3288 | priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; |
3289 | 3289 | ||
3290 | if ((bss_index = retrieve_bss(priv)) != -1) | 3290 | if ((bss_index = retrieve_bss(priv)) != -1) |
3291 | atmel_join_bss(priv, bss_index); | 3291 | atmel_join_bss(priv, bss_index); |
3292 | else | 3292 | else |
3293 | atmel_scan(priv, 0); | 3293 | atmel_scan(priv, 0); |
3294 | } | 3294 | } |
3295 | } | 3295 | } |
3296 | 3296 | ||
3297 | static void smooth_rssi(struct atmel_private *priv, u8 rssi) | 3297 | static void smooth_rssi(struct atmel_private *priv, u8 rssi) |
3298 | { | 3298 | { |
3299 | u8 old = priv->wstats.qual.level; | 3299 | u8 old = priv->wstats.qual.level; |
3300 | u8 max_rssi = 42; /* 502-rmfd-revd max by experiment, default for now */ | 3300 | u8 max_rssi = 42; /* 502-rmfd-revd max by experiment, default for now */ |
3301 | 3301 | ||
3302 | switch (priv->firmware_type) { | 3302 | switch (priv->firmware_type) { |
3303 | case ATMEL_FW_TYPE_502E: | 3303 | case ATMEL_FW_TYPE_502E: |
3304 | max_rssi = 63; /* 502-rmfd-reve max by experiment */ | 3304 | max_rssi = 63; /* 502-rmfd-reve max by experiment */ |
3305 | break; | 3305 | break; |
3306 | default: | 3306 | default: |
3307 | break; | 3307 | break; |
3308 | } | 3308 | } |
3309 | 3309 | ||
3310 | rssi = rssi * 100 / max_rssi; | 3310 | rssi = rssi * 100 / max_rssi; |
3311 | if ((rssi + old) % 2) | 3311 | if ((rssi + old) % 2) |
3312 | priv->wstats.qual.level = (rssi + old) / 2 + 1; | 3312 | priv->wstats.qual.level = (rssi + old) / 2 + 1; |
3313 | else | 3313 | else |
3314 | priv->wstats.qual.level = (rssi + old) / 2; | 3314 | priv->wstats.qual.level = (rssi + old) / 2; |
3315 | priv->wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; | 3315 | priv->wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; |
3316 | priv->wstats.qual.updated &= ~IW_QUAL_LEVEL_INVALID; | 3316 | priv->wstats.qual.updated &= ~IW_QUAL_LEVEL_INVALID; |
3317 | } | 3317 | } |
3318 | 3318 | ||
3319 | static void atmel_smooth_qual(struct atmel_private *priv) | 3319 | static void atmel_smooth_qual(struct atmel_private *priv) |
3320 | { | 3320 | { |
3321 | unsigned long time_diff = (jiffies - priv->last_qual) / HZ; | 3321 | unsigned long time_diff = (jiffies - priv->last_qual) / HZ; |
3322 | while (time_diff--) { | 3322 | while (time_diff--) { |
3323 | priv->last_qual += HZ; | 3323 | priv->last_qual += HZ; |
3324 | priv->wstats.qual.qual = priv->wstats.qual.qual / 2; | 3324 | priv->wstats.qual.qual = priv->wstats.qual.qual / 2; |
3325 | priv->wstats.qual.qual += | 3325 | priv->wstats.qual.qual += |
3326 | priv->beacons_this_sec * priv->beacon_period * (priv->wstats.qual.level + 100) / 4000; | 3326 | priv->beacons_this_sec * priv->beacon_period * (priv->wstats.qual.level + 100) / 4000; |
3327 | priv->beacons_this_sec = 0; | 3327 | priv->beacons_this_sec = 0; |
3328 | } | 3328 | } |
3329 | priv->wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; | 3329 | priv->wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; |
3330 | priv->wstats.qual.updated &= ~IW_QUAL_QUAL_INVALID; | 3330 | priv->wstats.qual.updated &= ~IW_QUAL_QUAL_INVALID; |
3331 | } | 3331 | } |
3332 | 3332 | ||
3333 | /* deals with incoming managment frames. */ | 3333 | /* deals with incoming management frames. */ |
3334 | static void atmel_management_frame(struct atmel_private *priv, | 3334 | static void atmel_management_frame(struct atmel_private *priv, |
3335 | struct ieee80211_hdr *header, | 3335 | struct ieee80211_hdr *header, |
3336 | u16 frame_len, u8 rssi) | 3336 | u16 frame_len, u8 rssi) |
3337 | { | 3337 | { |
3338 | u16 subtype; | 3338 | u16 subtype; |
3339 | 3339 | ||
3340 | subtype = le16_to_cpu(header->frame_control) & IEEE80211_FCTL_STYPE; | 3340 | subtype = le16_to_cpu(header->frame_control) & IEEE80211_FCTL_STYPE; |
3341 | switch (subtype) { | 3341 | switch (subtype) { |
3342 | case IEEE80211_STYPE_BEACON: | 3342 | case IEEE80211_STYPE_BEACON: |
3343 | case IEEE80211_STYPE_PROBE_RESP: | 3343 | case IEEE80211_STYPE_PROBE_RESP: |
3344 | 3344 | ||
3345 | /* beacon frame has multiple variable-length fields - | 3345 | /* beacon frame has multiple variable-length fields - |
3346 | never let an engineer loose with a data structure design. */ | 3346 | never let an engineer loose with a data structure design. */ |
3347 | { | 3347 | { |
3348 | struct beacon_format { | 3348 | struct beacon_format { |
3349 | __le64 timestamp; | 3349 | __le64 timestamp; |
3350 | __le16 interval; | 3350 | __le16 interval; |
3351 | __le16 capability; | 3351 | __le16 capability; |
3352 | u8 ssid_el_id; | 3352 | u8 ssid_el_id; |
3353 | u8 ssid_length; | 3353 | u8 ssid_length; |
3354 | /* ssid here */ | 3354 | /* ssid here */ |
3355 | u8 rates_el_id; | 3355 | u8 rates_el_id; |
3356 | u8 rates_length; | 3356 | u8 rates_length; |
3357 | /* rates here */ | 3357 | /* rates here */ |
3358 | u8 ds_el_id; | 3358 | u8 ds_el_id; |
3359 | u8 ds_length; | 3359 | u8 ds_length; |
3360 | /* ds here */ | 3360 | /* ds here */ |
3361 | } *beacon = (struct beacon_format *)priv->rx_buf; | 3361 | } *beacon = (struct beacon_format *)priv->rx_buf; |
3362 | 3362 | ||
3363 | u8 channel, rates_length, ssid_length; | 3363 | u8 channel, rates_length, ssid_length; |
3364 | u64 timestamp = le64_to_cpu(beacon->timestamp); | 3364 | u64 timestamp = le64_to_cpu(beacon->timestamp); |
3365 | u16 beacon_interval = le16_to_cpu(beacon->interval); | 3365 | u16 beacon_interval = le16_to_cpu(beacon->interval); |
3366 | u16 capability = le16_to_cpu(beacon->capability); | 3366 | u16 capability = le16_to_cpu(beacon->capability); |
3367 | u8 *beaconp = priv->rx_buf; | 3367 | u8 *beaconp = priv->rx_buf; |
3368 | ssid_length = beacon->ssid_length; | 3368 | ssid_length = beacon->ssid_length; |
3369 | /* this blows chunks. */ | 3369 | /* this blows chunks. */ |
3370 | if (frame_len < 14 || frame_len < ssid_length + 15) | 3370 | if (frame_len < 14 || frame_len < ssid_length + 15) |
3371 | return; | 3371 | return; |
3372 | rates_length = beaconp[beacon->ssid_length + 15]; | 3372 | rates_length = beaconp[beacon->ssid_length + 15]; |
3373 | if (frame_len < ssid_length + rates_length + 18) | 3373 | if (frame_len < ssid_length + rates_length + 18) |
3374 | return; | 3374 | return; |
3375 | if (ssid_length > MAX_SSID_LENGTH) | 3375 | if (ssid_length > MAX_SSID_LENGTH) |
3376 | return; | 3376 | return; |
3377 | channel = beaconp[ssid_length + rates_length + 18]; | 3377 | channel = beaconp[ssid_length + rates_length + 18]; |
3378 | 3378 | ||
3379 | if (priv->station_state == STATION_STATE_READY) { | 3379 | if (priv->station_state == STATION_STATE_READY) { |
3380 | smooth_rssi(priv, rssi); | 3380 | smooth_rssi(priv, rssi); |
3381 | if (is_frame_from_current_bss(priv, header)) { | 3381 | if (is_frame_from_current_bss(priv, header)) { |
3382 | priv->beacons_this_sec++; | 3382 | priv->beacons_this_sec++; |
3383 | atmel_smooth_qual(priv); | 3383 | atmel_smooth_qual(priv); |
3384 | if (priv->last_beacon_timestamp) { | 3384 | if (priv->last_beacon_timestamp) { |
3385 | /* Note truncate this to 32 bits - kernel can't divide a long long */ | 3385 | /* Note truncate this to 32 bits - kernel can't divide a long long */ |
3386 | u32 beacon_delay = timestamp - priv->last_beacon_timestamp; | 3386 | u32 beacon_delay = timestamp - priv->last_beacon_timestamp; |
3387 | int beacons = beacon_delay / (beacon_interval * 1000); | 3387 | int beacons = beacon_delay / (beacon_interval * 1000); |
3388 | if (beacons > 1) | 3388 | if (beacons > 1) |
3389 | priv->wstats.miss.beacon += beacons - 1; | 3389 | priv->wstats.miss.beacon += beacons - 1; |
3390 | } | 3390 | } |
3391 | priv->last_beacon_timestamp = timestamp; | 3391 | priv->last_beacon_timestamp = timestamp; |
3392 | handle_beacon_probe(priv, capability, channel); | 3392 | handle_beacon_probe(priv, capability, channel); |
3393 | } | 3393 | } |
3394 | } | 3394 | } |
3395 | 3395 | ||
3396 | if (priv->station_state == STATION_STATE_SCANNING) | 3396 | if (priv->station_state == STATION_STATE_SCANNING) |
3397 | store_bss_info(priv, header, capability, | 3397 | store_bss_info(priv, header, capability, |
3398 | beacon_interval, channel, rssi, | 3398 | beacon_interval, channel, rssi, |
3399 | ssid_length, | 3399 | ssid_length, |
3400 | &beacon->rates_el_id, | 3400 | &beacon->rates_el_id, |
3401 | subtype == IEEE80211_STYPE_BEACON); | 3401 | subtype == IEEE80211_STYPE_BEACON); |
3402 | } | 3402 | } |
3403 | break; | 3403 | break; |
3404 | 3404 | ||
3405 | case IEEE80211_STYPE_AUTH: | 3405 | case IEEE80211_STYPE_AUTH: |
3406 | 3406 | ||
3407 | if (priv->station_state == STATION_STATE_AUTHENTICATING) | 3407 | if (priv->station_state == STATION_STATE_AUTHENTICATING) |
3408 | authenticate(priv, frame_len); | 3408 | authenticate(priv, frame_len); |
3409 | 3409 | ||
3410 | break; | 3410 | break; |
3411 | 3411 | ||
3412 | case IEEE80211_STYPE_ASSOC_RESP: | 3412 | case IEEE80211_STYPE_ASSOC_RESP: |
3413 | case IEEE80211_STYPE_REASSOC_RESP: | 3413 | case IEEE80211_STYPE_REASSOC_RESP: |
3414 | 3414 | ||
3415 | if (priv->station_state == STATION_STATE_ASSOCIATING || | 3415 | if (priv->station_state == STATION_STATE_ASSOCIATING || |
3416 | priv->station_state == STATION_STATE_REASSOCIATING) | 3416 | priv->station_state == STATION_STATE_REASSOCIATING) |
3417 | associate(priv, frame_len, subtype); | 3417 | associate(priv, frame_len, subtype); |
3418 | 3418 | ||
3419 | break; | 3419 | break; |
3420 | 3420 | ||
3421 | case IEEE80211_STYPE_DISASSOC: | 3421 | case IEEE80211_STYPE_DISASSOC: |
3422 | if (priv->station_is_associated && | 3422 | if (priv->station_is_associated && |
3423 | priv->operating_mode == IW_MODE_INFRA && | 3423 | priv->operating_mode == IW_MODE_INFRA && |
3424 | is_frame_from_current_bss(priv, header)) { | 3424 | is_frame_from_current_bss(priv, header)) { |
3425 | priv->station_was_associated = 0; | 3425 | priv->station_was_associated = 0; |
3426 | priv->station_is_associated = 0; | 3426 | priv->station_is_associated = 0; |
3427 | 3427 | ||
3428 | atmel_enter_state(priv, STATION_STATE_JOINNING); | 3428 | atmel_enter_state(priv, STATION_STATE_JOINNING); |
3429 | join(priv, BSS_TYPE_INFRASTRUCTURE); | 3429 | join(priv, BSS_TYPE_INFRASTRUCTURE); |
3430 | } | 3430 | } |
3431 | 3431 | ||
3432 | break; | 3432 | break; |
3433 | 3433 | ||
3434 | case IEEE80211_STYPE_DEAUTH: | 3434 | case IEEE80211_STYPE_DEAUTH: |
3435 | if (priv->operating_mode == IW_MODE_INFRA && | 3435 | if (priv->operating_mode == IW_MODE_INFRA && |
3436 | is_frame_from_current_bss(priv, header)) { | 3436 | is_frame_from_current_bss(priv, header)) { |
3437 | priv->station_was_associated = 0; | 3437 | priv->station_was_associated = 0; |
3438 | 3438 | ||
3439 | atmel_enter_state(priv, STATION_STATE_JOINNING); | 3439 | atmel_enter_state(priv, STATION_STATE_JOINNING); |
3440 | join(priv, BSS_TYPE_INFRASTRUCTURE); | 3440 | join(priv, BSS_TYPE_INFRASTRUCTURE); |
3441 | } | 3441 | } |
3442 | 3442 | ||
3443 | break; | 3443 | break; |
3444 | } | 3444 | } |
3445 | } | 3445 | } |
3446 | 3446 | ||
3447 | /* run when timer expires */ | 3447 | /* run when timer expires */ |
3448 | static void atmel_management_timer(u_long a) | 3448 | static void atmel_management_timer(u_long a) |
3449 | { | 3449 | { |
3450 | struct net_device *dev = (struct net_device *) a; | 3450 | struct net_device *dev = (struct net_device *) a; |
3451 | struct atmel_private *priv = netdev_priv(dev); | 3451 | struct atmel_private *priv = netdev_priv(dev); |
3452 | unsigned long flags; | 3452 | unsigned long flags; |
3453 | 3453 | ||
3454 | /* Check if the card has been yanked. */ | 3454 | /* Check if the card has been yanked. */ |
3455 | if (priv->card && priv->present_callback && | 3455 | if (priv->card && priv->present_callback && |
3456 | !(*priv->present_callback)(priv->card)) | 3456 | !(*priv->present_callback)(priv->card)) |
3457 | return; | 3457 | return; |
3458 | 3458 | ||
3459 | spin_lock_irqsave(&priv->irqlock, flags); | 3459 | spin_lock_irqsave(&priv->irqlock, flags); |
3460 | 3460 | ||
3461 | switch (priv->station_state) { | 3461 | switch (priv->station_state) { |
3462 | 3462 | ||
3463 | case STATION_STATE_AUTHENTICATING: | 3463 | case STATION_STATE_AUTHENTICATING: |
3464 | if (priv->AuthenticationRequestRetryCnt >= MAX_AUTHENTICATION_RETRIES) { | 3464 | if (priv->AuthenticationRequestRetryCnt >= MAX_AUTHENTICATION_RETRIES) { |
3465 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | 3465 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); |
3466 | priv->station_is_associated = 0; | 3466 | priv->station_is_associated = 0; |
3467 | priv->AuthenticationRequestRetryCnt = 0; | 3467 | priv->AuthenticationRequestRetryCnt = 0; |
3468 | restart_search(priv); | 3468 | restart_search(priv); |
3469 | } else { | 3469 | } else { |
3470 | int auth = WLAN_AUTH_OPEN; | 3470 | int auth = WLAN_AUTH_OPEN; |
3471 | priv->AuthenticationRequestRetryCnt++; | 3471 | priv->AuthenticationRequestRetryCnt++; |
3472 | priv->CurrentAuthentTransactionSeqNum = 0x0001; | 3472 | priv->CurrentAuthentTransactionSeqNum = 0x0001; |
3473 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | 3473 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); |
3474 | if (priv->wep_is_on && priv->exclude_unencrypted) | 3474 | if (priv->wep_is_on && priv->exclude_unencrypted) |
3475 | auth = WLAN_AUTH_SHARED_KEY; | 3475 | auth = WLAN_AUTH_SHARED_KEY; |
3476 | send_authentication_request(priv, auth, NULL, 0); | 3476 | send_authentication_request(priv, auth, NULL, 0); |
3477 | } | 3477 | } |
3478 | break; | 3478 | break; |
3479 | 3479 | ||
3480 | case STATION_STATE_ASSOCIATING: | 3480 | case STATION_STATE_ASSOCIATING: |
3481 | if (priv->AssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { | 3481 | if (priv->AssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { |
3482 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | 3482 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); |
3483 | priv->station_is_associated = 0; | 3483 | priv->station_is_associated = 0; |
3484 | priv->AssociationRequestRetryCnt = 0; | 3484 | priv->AssociationRequestRetryCnt = 0; |
3485 | restart_search(priv); | 3485 | restart_search(priv); |
3486 | } else { | 3486 | } else { |
3487 | priv->AssociationRequestRetryCnt++; | 3487 | priv->AssociationRequestRetryCnt++; |
3488 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | 3488 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); |
3489 | send_association_request(priv, 0); | 3489 | send_association_request(priv, 0); |
3490 | } | 3490 | } |
3491 | break; | 3491 | break; |
3492 | 3492 | ||
3493 | case STATION_STATE_REASSOCIATING: | 3493 | case STATION_STATE_REASSOCIATING: |
3494 | if (priv->ReAssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { | 3494 | if (priv->ReAssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { |
3495 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | 3495 | atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); |
3496 | priv->station_is_associated = 0; | 3496 | priv->station_is_associated = 0; |
3497 | priv->ReAssociationRequestRetryCnt = 0; | 3497 | priv->ReAssociationRequestRetryCnt = 0; |
3498 | restart_search(priv); | 3498 | restart_search(priv); |
3499 | } else { | 3499 | } else { |
3500 | priv->ReAssociationRequestRetryCnt++; | 3500 | priv->ReAssociationRequestRetryCnt++; |
3501 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | 3501 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); |
3502 | send_association_request(priv, 1); | 3502 | send_association_request(priv, 1); |
3503 | } | 3503 | } |
3504 | break; | 3504 | break; |
3505 | 3505 | ||
3506 | default: | 3506 | default: |
3507 | break; | 3507 | break; |
3508 | } | 3508 | } |
3509 | 3509 | ||
3510 | spin_unlock_irqrestore(&priv->irqlock, flags); | 3510 | spin_unlock_irqrestore(&priv->irqlock, flags); |
3511 | } | 3511 | } |
3512 | 3512 | ||
3513 | static void atmel_command_irq(struct atmel_private *priv) | 3513 | static void atmel_command_irq(struct atmel_private *priv) |
3514 | { | 3514 | { |
3515 | u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); | 3515 | u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); |
3516 | u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET)); | 3516 | u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET)); |
3517 | int fast_scan; | 3517 | int fast_scan; |
3518 | union iwreq_data wrqu; | 3518 | union iwreq_data wrqu; |
3519 | 3519 | ||
3520 | if (status == CMD_STATUS_IDLE || | 3520 | if (status == CMD_STATUS_IDLE || |
3521 | status == CMD_STATUS_IN_PROGRESS) | 3521 | status == CMD_STATUS_IN_PROGRESS) |
3522 | return; | 3522 | return; |
3523 | 3523 | ||
3524 | switch (command) { | 3524 | switch (command) { |
3525 | case CMD_Start: | 3525 | case CMD_Start: |
3526 | if (status == CMD_STATUS_COMPLETE) { | 3526 | if (status == CMD_STATUS_COMPLETE) { |
3527 | priv->station_was_associated = priv->station_is_associated; | 3527 | priv->station_was_associated = priv->station_is_associated; |
3528 | atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, | 3528 | atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, |
3529 | (u8 *)priv->CurrentBSSID, 6); | 3529 | (u8 *)priv->CurrentBSSID, 6); |
3530 | atmel_enter_state(priv, STATION_STATE_READY); | 3530 | atmel_enter_state(priv, STATION_STATE_READY); |
3531 | } | 3531 | } |
3532 | break; | 3532 | break; |
3533 | 3533 | ||
3534 | case CMD_Scan: | 3534 | case CMD_Scan: |
3535 | fast_scan = priv->fast_scan; | 3535 | fast_scan = priv->fast_scan; |
3536 | priv->fast_scan = 0; | 3536 | priv->fast_scan = 0; |
3537 | 3537 | ||
3538 | if (status != CMD_STATUS_COMPLETE) { | 3538 | if (status != CMD_STATUS_COMPLETE) { |
3539 | atmel_scan(priv, 1); | 3539 | atmel_scan(priv, 1); |
3540 | } else { | 3540 | } else { |
3541 | int bss_index = retrieve_bss(priv); | 3541 | int bss_index = retrieve_bss(priv); |
3542 | int notify_scan_complete = 1; | 3542 | int notify_scan_complete = 1; |
3543 | if (bss_index != -1) { | 3543 | if (bss_index != -1) { |
3544 | atmel_join_bss(priv, bss_index); | 3544 | atmel_join_bss(priv, bss_index); |
3545 | } else if (priv->operating_mode == IW_MODE_ADHOC && | 3545 | } else if (priv->operating_mode == IW_MODE_ADHOC && |
3546 | priv->SSID_size != 0) { | 3546 | priv->SSID_size != 0) { |
3547 | start(priv, BSS_TYPE_AD_HOC); | 3547 | start(priv, BSS_TYPE_AD_HOC); |
3548 | } else { | 3548 | } else { |
3549 | priv->fast_scan = !fast_scan; | 3549 | priv->fast_scan = !fast_scan; |
3550 | atmel_scan(priv, 1); | 3550 | atmel_scan(priv, 1); |
3551 | notify_scan_complete = 0; | 3551 | notify_scan_complete = 0; |
3552 | } | 3552 | } |
3553 | priv->site_survey_state = SITE_SURVEY_COMPLETED; | 3553 | priv->site_survey_state = SITE_SURVEY_COMPLETED; |
3554 | if (notify_scan_complete) { | 3554 | if (notify_scan_complete) { |
3555 | wrqu.data.length = 0; | 3555 | wrqu.data.length = 0; |
3556 | wrqu.data.flags = 0; | 3556 | wrqu.data.flags = 0; |
3557 | wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); | 3557 | wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); |
3558 | } | 3558 | } |
3559 | } | 3559 | } |
3560 | break; | 3560 | break; |
3561 | 3561 | ||
3562 | case CMD_SiteSurvey: | 3562 | case CMD_SiteSurvey: |
3563 | priv->fast_scan = 0; | 3563 | priv->fast_scan = 0; |
3564 | 3564 | ||
3565 | if (status != CMD_STATUS_COMPLETE) | 3565 | if (status != CMD_STATUS_COMPLETE) |
3566 | return; | 3566 | return; |
3567 | 3567 | ||
3568 | priv->site_survey_state = SITE_SURVEY_COMPLETED; | 3568 | priv->site_survey_state = SITE_SURVEY_COMPLETED; |
3569 | if (priv->station_is_associated) { | 3569 | if (priv->station_is_associated) { |
3570 | atmel_enter_state(priv, STATION_STATE_READY); | 3570 | atmel_enter_state(priv, STATION_STATE_READY); |
3571 | wrqu.data.length = 0; | 3571 | wrqu.data.length = 0; |
3572 | wrqu.data.flags = 0; | 3572 | wrqu.data.flags = 0; |
3573 | wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); | 3573 | wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); |
3574 | } else { | 3574 | } else { |
3575 | atmel_scan(priv, 1); | 3575 | atmel_scan(priv, 1); |
3576 | } | 3576 | } |
3577 | break; | 3577 | break; |
3578 | 3578 | ||
3579 | case CMD_Join: | 3579 | case CMD_Join: |
3580 | if (status == CMD_STATUS_COMPLETE) { | 3580 | if (status == CMD_STATUS_COMPLETE) { |
3581 | if (priv->operating_mode == IW_MODE_ADHOC) { | 3581 | if (priv->operating_mode == IW_MODE_ADHOC) { |
3582 | priv->station_was_associated = priv->station_is_associated; | 3582 | priv->station_was_associated = priv->station_is_associated; |
3583 | atmel_enter_state(priv, STATION_STATE_READY); | 3583 | atmel_enter_state(priv, STATION_STATE_READY); |
3584 | } else { | 3584 | } else { |
3585 | int auth = WLAN_AUTH_OPEN; | 3585 | int auth = WLAN_AUTH_OPEN; |
3586 | priv->AuthenticationRequestRetryCnt = 0; | 3586 | priv->AuthenticationRequestRetryCnt = 0; |
3587 | atmel_enter_state(priv, STATION_STATE_AUTHENTICATING); | 3587 | atmel_enter_state(priv, STATION_STATE_AUTHENTICATING); |
3588 | 3588 | ||
3589 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | 3589 | mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); |
3590 | priv->CurrentAuthentTransactionSeqNum = 0x0001; | 3590 | priv->CurrentAuthentTransactionSeqNum = 0x0001; |
3591 | if (priv->wep_is_on && priv->exclude_unencrypted) | 3591 | if (priv->wep_is_on && priv->exclude_unencrypted) |
3592 | auth = WLAN_AUTH_SHARED_KEY; | 3592 | auth = WLAN_AUTH_SHARED_KEY; |
3593 | send_authentication_request(priv, auth, NULL, 0); | 3593 | send_authentication_request(priv, auth, NULL, 0); |
3594 | } | 3594 | } |
3595 | return; | 3595 | return; |
3596 | } | 3596 | } |
3597 | 3597 | ||
3598 | atmel_scan(priv, 1); | 3598 | atmel_scan(priv, 1); |
3599 | } | 3599 | } |
3600 | } | 3600 | } |
3601 | 3601 | ||
3602 | static int atmel_wakeup_firmware(struct atmel_private *priv) | 3602 | static int atmel_wakeup_firmware(struct atmel_private *priv) |
3603 | { | 3603 | { |
3604 | struct host_info_struct *iface = &priv->host_info; | 3604 | struct host_info_struct *iface = &priv->host_info; |
3605 | u16 mr1, mr3; | 3605 | u16 mr1, mr3; |
3606 | int i; | 3606 | int i; |
3607 | 3607 | ||
3608 | if (priv->card_type == CARD_TYPE_SPI_FLASH) | 3608 | if (priv->card_type == CARD_TYPE_SPI_FLASH) |
3609 | atmel_set_gcr(priv->dev, GCR_REMAP); | 3609 | atmel_set_gcr(priv->dev, GCR_REMAP); |
3610 | 3610 | ||
3611 | /* wake up on-board processor */ | 3611 | /* wake up on-board processor */ |
3612 | atmel_clear_gcr(priv->dev, 0x0040); | 3612 | atmel_clear_gcr(priv->dev, 0x0040); |
3613 | atmel_write16(priv->dev, BSR, BSS_SRAM); | 3613 | atmel_write16(priv->dev, BSR, BSS_SRAM); |
3614 | 3614 | ||
3615 | if (priv->card_type == CARD_TYPE_SPI_FLASH) | 3615 | if (priv->card_type == CARD_TYPE_SPI_FLASH) |
3616 | mdelay(100); | 3616 | mdelay(100); |
3617 | 3617 | ||
3618 | /* and wait for it */ | 3618 | /* and wait for it */ |
3619 | for (i = LOOP_RETRY_LIMIT; i; i--) { | 3619 | for (i = LOOP_RETRY_LIMIT; i; i--) { |
3620 | mr1 = atmel_read16(priv->dev, MR1); | 3620 | mr1 = atmel_read16(priv->dev, MR1); |
3621 | mr3 = atmel_read16(priv->dev, MR3); | 3621 | mr3 = atmel_read16(priv->dev, MR3); |
3622 | 3622 | ||
3623 | if (mr3 & MAC_BOOT_COMPLETE) | 3623 | if (mr3 & MAC_BOOT_COMPLETE) |
3624 | break; | 3624 | break; |
3625 | if (mr1 & MAC_BOOT_COMPLETE && | 3625 | if (mr1 & MAC_BOOT_COMPLETE && |
3626 | priv->bus_type == BUS_TYPE_PCCARD) | 3626 | priv->bus_type == BUS_TYPE_PCCARD) |
3627 | break; | 3627 | break; |
3628 | } | 3628 | } |
3629 | 3629 | ||
3630 | if (i == 0) { | 3630 | if (i == 0) { |
3631 | printk(KERN_ALERT "%s: MAC failed to boot.\n", priv->dev->name); | 3631 | printk(KERN_ALERT "%s: MAC failed to boot.\n", priv->dev->name); |
3632 | return -EIO; | 3632 | return -EIO; |
3633 | } | 3633 | } |
3634 | 3634 | ||
3635 | if ((priv->host_info_base = atmel_read16(priv->dev, MR2)) == 0xffff) { | 3635 | if ((priv->host_info_base = atmel_read16(priv->dev, MR2)) == 0xffff) { |
3636 | printk(KERN_ALERT "%s: card missing.\n", priv->dev->name); | 3636 | printk(KERN_ALERT "%s: card missing.\n", priv->dev->name); |
3637 | return -ENODEV; | 3637 | return -ENODEV; |
3638 | } | 3638 | } |
3639 | 3639 | ||
3640 | /* now check for completion of MAC initialization through | 3640 | /* now check for completion of MAC initialization through |
3641 | the FunCtrl field of the IFACE, poll MR1 to detect completion of | 3641 | the FunCtrl field of the IFACE, poll MR1 to detect completion of |
3642 | MAC initialization, check completion status, set interrupt mask, | 3642 | MAC initialization, check completion status, set interrupt mask, |
3643 | enables interrupts and calls Tx and Rx initialization functions */ | 3643 | enables interrupts and calls Tx and Rx initialization functions */ |
3644 | 3644 | ||
3645 | atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), FUNC_CTRL_INIT_COMPLETE); | 3645 | atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), FUNC_CTRL_INIT_COMPLETE); |
3646 | 3646 | ||
3647 | for (i = LOOP_RETRY_LIMIT; i; i--) { | 3647 | for (i = LOOP_RETRY_LIMIT; i; i--) { |
3648 | mr1 = atmel_read16(priv->dev, MR1); | 3648 | mr1 = atmel_read16(priv->dev, MR1); |
3649 | mr3 = atmel_read16(priv->dev, MR3); | 3649 | mr3 = atmel_read16(priv->dev, MR3); |
3650 | 3650 | ||
3651 | if (mr3 & MAC_INIT_COMPLETE) | 3651 | if (mr3 & MAC_INIT_COMPLETE) |
3652 | break; | 3652 | break; |
3653 | if (mr1 & MAC_INIT_COMPLETE && | 3653 | if (mr1 & MAC_INIT_COMPLETE && |
3654 | priv->bus_type == BUS_TYPE_PCCARD) | 3654 | priv->bus_type == BUS_TYPE_PCCARD) |
3655 | break; | 3655 | break; |
3656 | } | 3656 | } |
3657 | 3657 | ||
3658 | if (i == 0) { | 3658 | if (i == 0) { |
3659 | printk(KERN_ALERT "%s: MAC failed to initialise.\n", | 3659 | printk(KERN_ALERT "%s: MAC failed to initialise.\n", |
3660 | priv->dev->name); | 3660 | priv->dev->name); |
3661 | return -EIO; | 3661 | return -EIO; |
3662 | } | 3662 | } |
3663 | 3663 | ||
3664 | /* Check for MAC_INIT_OK only on the register that the MAC_INIT_OK was set */ | 3664 | /* Check for MAC_INIT_OK only on the register that the MAC_INIT_OK was set */ |
3665 | if ((mr3 & MAC_INIT_COMPLETE) && | 3665 | if ((mr3 & MAC_INIT_COMPLETE) && |
3666 | !(atmel_read16(priv->dev, MR3) & MAC_INIT_OK)) { | 3666 | !(atmel_read16(priv->dev, MR3) & MAC_INIT_OK)) { |
3667 | printk(KERN_ALERT "%s: MAC failed MR3 self-test.\n", priv->dev->name); | 3667 | printk(KERN_ALERT "%s: MAC failed MR3 self-test.\n", priv->dev->name); |
3668 | return -EIO; | 3668 | return -EIO; |
3669 | } | 3669 | } |
3670 | if ((mr1 & MAC_INIT_COMPLETE) && | 3670 | if ((mr1 & MAC_INIT_COMPLETE) && |
3671 | !(atmel_read16(priv->dev, MR1) & MAC_INIT_OK)) { | 3671 | !(atmel_read16(priv->dev, MR1) & MAC_INIT_OK)) { |
3672 | printk(KERN_ALERT "%s: MAC failed MR1 self-test.\n", priv->dev->name); | 3672 | printk(KERN_ALERT "%s: MAC failed MR1 self-test.\n", priv->dev->name); |
3673 | return -EIO; | 3673 | return -EIO; |
3674 | } | 3674 | } |
3675 | 3675 | ||
3676 | atmel_copy_to_host(priv->dev, (unsigned char *)iface, | 3676 | atmel_copy_to_host(priv->dev, (unsigned char *)iface, |
3677 | priv->host_info_base, sizeof(*iface)); | 3677 | priv->host_info_base, sizeof(*iface)); |
3678 | 3678 | ||
3679 | iface->tx_buff_pos = le16_to_cpu(iface->tx_buff_pos); | 3679 | iface->tx_buff_pos = le16_to_cpu(iface->tx_buff_pos); |
3680 | iface->tx_buff_size = le16_to_cpu(iface->tx_buff_size); | 3680 | iface->tx_buff_size = le16_to_cpu(iface->tx_buff_size); |
3681 | iface->tx_desc_pos = le16_to_cpu(iface->tx_desc_pos); | 3681 | iface->tx_desc_pos = le16_to_cpu(iface->tx_desc_pos); |
3682 | iface->tx_desc_count = le16_to_cpu(iface->tx_desc_count); | 3682 | iface->tx_desc_count = le16_to_cpu(iface->tx_desc_count); |
3683 | iface->rx_buff_pos = le16_to_cpu(iface->rx_buff_pos); | 3683 | iface->rx_buff_pos = le16_to_cpu(iface->rx_buff_pos); |
3684 | iface->rx_buff_size = le16_to_cpu(iface->rx_buff_size); | 3684 | iface->rx_buff_size = le16_to_cpu(iface->rx_buff_size); |
3685 | iface->rx_desc_pos = le16_to_cpu(iface->rx_desc_pos); | 3685 | iface->rx_desc_pos = le16_to_cpu(iface->rx_desc_pos); |
3686 | iface->rx_desc_count = le16_to_cpu(iface->rx_desc_count); | 3686 | iface->rx_desc_count = le16_to_cpu(iface->rx_desc_count); |
3687 | iface->build_version = le16_to_cpu(iface->build_version); | 3687 | iface->build_version = le16_to_cpu(iface->build_version); |
3688 | iface->command_pos = le16_to_cpu(iface->command_pos); | 3688 | iface->command_pos = le16_to_cpu(iface->command_pos); |
3689 | iface->major_version = le16_to_cpu(iface->major_version); | 3689 | iface->major_version = le16_to_cpu(iface->major_version); |
3690 | iface->minor_version = le16_to_cpu(iface->minor_version); | 3690 | iface->minor_version = le16_to_cpu(iface->minor_version); |
3691 | iface->func_ctrl = le16_to_cpu(iface->func_ctrl); | 3691 | iface->func_ctrl = le16_to_cpu(iface->func_ctrl); |
3692 | iface->mac_status = le16_to_cpu(iface->mac_status); | 3692 | iface->mac_status = le16_to_cpu(iface->mac_status); |
3693 | 3693 | ||
3694 | return 0; | 3694 | return 0; |
3695 | } | 3695 | } |
3696 | 3696 | ||
3697 | /* determine type of memory and MAC address */ | 3697 | /* determine type of memory and MAC address */ |
3698 | static int probe_atmel_card(struct net_device *dev) | 3698 | static int probe_atmel_card(struct net_device *dev) |
3699 | { | 3699 | { |
3700 | int rc = 0; | 3700 | int rc = 0; |
3701 | struct atmel_private *priv = netdev_priv(dev); | 3701 | struct atmel_private *priv = netdev_priv(dev); |
3702 | 3702 | ||
3703 | /* reset pccard */ | 3703 | /* reset pccard */ |
3704 | if (priv->bus_type == BUS_TYPE_PCCARD) | 3704 | if (priv->bus_type == BUS_TYPE_PCCARD) |
3705 | atmel_write16(dev, GCR, 0x0060); | 3705 | atmel_write16(dev, GCR, 0x0060); |
3706 | 3706 | ||
3707 | atmel_write16(dev, GCR, 0x0040); | 3707 | atmel_write16(dev, GCR, 0x0040); |
3708 | mdelay(500); | 3708 | mdelay(500); |
3709 | 3709 | ||
3710 | if (atmel_read16(dev, MR2) == 0) { | 3710 | if (atmel_read16(dev, MR2) == 0) { |
3711 | /* No stored firmware so load a small stub which just | 3711 | /* No stored firmware so load a small stub which just |
3712 | tells us the MAC address */ | 3712 | tells us the MAC address */ |
3713 | int i; | 3713 | int i; |
3714 | priv->card_type = CARD_TYPE_EEPROM; | 3714 | priv->card_type = CARD_TYPE_EEPROM; |
3715 | atmel_write16(dev, BSR, BSS_IRAM); | 3715 | atmel_write16(dev, BSR, BSS_IRAM); |
3716 | atmel_copy_to_card(dev, 0, mac_reader, sizeof(mac_reader)); | 3716 | atmel_copy_to_card(dev, 0, mac_reader, sizeof(mac_reader)); |
3717 | atmel_set_gcr(dev, GCR_REMAP); | 3717 | atmel_set_gcr(dev, GCR_REMAP); |
3718 | atmel_clear_gcr(priv->dev, 0x0040); | 3718 | atmel_clear_gcr(priv->dev, 0x0040); |
3719 | atmel_write16(dev, BSR, BSS_SRAM); | 3719 | atmel_write16(dev, BSR, BSS_SRAM); |
3720 | for (i = LOOP_RETRY_LIMIT; i; i--) | 3720 | for (i = LOOP_RETRY_LIMIT; i; i--) |
3721 | if (atmel_read16(dev, MR3) & MAC_BOOT_COMPLETE) | 3721 | if (atmel_read16(dev, MR3) & MAC_BOOT_COMPLETE) |
3722 | break; | 3722 | break; |
3723 | if (i == 0) { | 3723 | if (i == 0) { |
3724 | printk(KERN_ALERT "%s: MAC failed to boot MAC address reader.\n", dev->name); | 3724 | printk(KERN_ALERT "%s: MAC failed to boot MAC address reader.\n", dev->name); |
3725 | } else { | 3725 | } else { |
3726 | atmel_copy_to_host(dev, dev->dev_addr, atmel_read16(dev, MR2), 6); | 3726 | atmel_copy_to_host(dev, dev->dev_addr, atmel_read16(dev, MR2), 6); |
3727 | /* got address, now squash it again until the network | 3727 | /* got address, now squash it again until the network |
3728 | interface is opened */ | 3728 | interface is opened */ |
3729 | if (priv->bus_type == BUS_TYPE_PCCARD) | 3729 | if (priv->bus_type == BUS_TYPE_PCCARD) |
3730 | atmel_write16(dev, GCR, 0x0060); | 3730 | atmel_write16(dev, GCR, 0x0060); |
3731 | atmel_write16(dev, GCR, 0x0040); | 3731 | atmel_write16(dev, GCR, 0x0040); |
3732 | rc = 1; | 3732 | rc = 1; |
3733 | } | 3733 | } |
3734 | } else if (atmel_read16(dev, MR4) == 0) { | 3734 | } else if (atmel_read16(dev, MR4) == 0) { |
3735 | /* Mac address easy in this case. */ | 3735 | /* Mac address easy in this case. */ |
3736 | priv->card_type = CARD_TYPE_PARALLEL_FLASH; | 3736 | priv->card_type = CARD_TYPE_PARALLEL_FLASH; |
3737 | atmel_write16(dev, BSR, 1); | 3737 | atmel_write16(dev, BSR, 1); |
3738 | atmel_copy_to_host(dev, dev->dev_addr, 0xc000, 6); | 3738 | atmel_copy_to_host(dev, dev->dev_addr, 0xc000, 6); |
3739 | atmel_write16(dev, BSR, 0x200); | 3739 | atmel_write16(dev, BSR, 0x200); |
3740 | rc = 1; | 3740 | rc = 1; |
3741 | } else { | 3741 | } else { |
3742 | /* Standard firmware in flash, boot it up and ask | 3742 | /* Standard firmware in flash, boot it up and ask |
3743 | for the Mac Address */ | 3743 | for the Mac Address */ |
3744 | priv->card_type = CARD_TYPE_SPI_FLASH; | 3744 | priv->card_type = CARD_TYPE_SPI_FLASH; |
3745 | if (atmel_wakeup_firmware(priv) == 0) { | 3745 | if (atmel_wakeup_firmware(priv) == 0) { |
3746 | atmel_get_mib(priv, Mac_Address_Mib_Type, 0, dev->dev_addr, 6); | 3746 | atmel_get_mib(priv, Mac_Address_Mib_Type, 0, dev->dev_addr, 6); |
3747 | 3747 | ||
3748 | /* got address, now squash it again until the network | 3748 | /* got address, now squash it again until the network |
3749 | interface is opened */ | 3749 | interface is opened */ |
3750 | if (priv->bus_type == BUS_TYPE_PCCARD) | 3750 | if (priv->bus_type == BUS_TYPE_PCCARD) |
3751 | atmel_write16(dev, GCR, 0x0060); | 3751 | atmel_write16(dev, GCR, 0x0060); |
3752 | atmel_write16(dev, GCR, 0x0040); | 3752 | atmel_write16(dev, GCR, 0x0040); |
3753 | rc = 1; | 3753 | rc = 1; |
3754 | } | 3754 | } |
3755 | } | 3755 | } |
3756 | 3756 | ||
3757 | if (rc) { | 3757 | if (rc) { |
3758 | if (dev->dev_addr[0] == 0xFF) { | 3758 | if (dev->dev_addr[0] == 0xFF) { |
3759 | u8 default_mac[] = {0x00, 0x04, 0x25, 0x00, 0x00, 0x00}; | 3759 | u8 default_mac[] = {0x00, 0x04, 0x25, 0x00, 0x00, 0x00}; |
3760 | printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name); | 3760 | printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name); |
3761 | memcpy(dev->dev_addr, default_mac, 6); | 3761 | memcpy(dev->dev_addr, default_mac, 6); |
3762 | } | 3762 | } |
3763 | } | 3763 | } |
3764 | 3764 | ||
3765 | return rc; | 3765 | return rc; |
3766 | } | 3766 | } |
3767 | 3767 | ||
3768 | /* Move the encyption information on the MIB structure. | 3768 | /* Move the encyption information on the MIB structure. |
3769 | This routine is for the pre-WPA firmware: later firmware has | 3769 | This routine is for the pre-WPA firmware: later firmware has |
3770 | a different format MIB and a different routine. */ | 3770 | a different format MIB and a different routine. */ |
3771 | static void build_wep_mib(struct atmel_private *priv) | 3771 | static void build_wep_mib(struct atmel_private *priv) |
3772 | { | 3772 | { |
3773 | struct { /* NB this is matched to the hardware, don't change. */ | 3773 | struct { /* NB this is matched to the hardware, don't change. */ |
3774 | u8 wep_is_on; | 3774 | u8 wep_is_on; |
3775 | u8 default_key; /* 0..3 */ | 3775 | u8 default_key; /* 0..3 */ |
3776 | u8 reserved; | 3776 | u8 reserved; |
3777 | u8 exclude_unencrypted; | 3777 | u8 exclude_unencrypted; |
3778 | 3778 | ||
3779 | u32 WEPICV_error_count; | 3779 | u32 WEPICV_error_count; |
3780 | u32 WEP_excluded_count; | 3780 | u32 WEP_excluded_count; |
3781 | 3781 | ||
3782 | u8 wep_keys[MAX_ENCRYPTION_KEYS][13]; | 3782 | u8 wep_keys[MAX_ENCRYPTION_KEYS][13]; |
3783 | u8 encryption_level; /* 0, 1, 2 */ | 3783 | u8 encryption_level; /* 0, 1, 2 */ |
3784 | u8 reserved2[3]; | 3784 | u8 reserved2[3]; |
3785 | } mib; | 3785 | } mib; |
3786 | int i; | 3786 | int i; |
3787 | 3787 | ||
3788 | mib.wep_is_on = priv->wep_is_on; | 3788 | mib.wep_is_on = priv->wep_is_on; |
3789 | if (priv->wep_is_on) { | 3789 | if (priv->wep_is_on) { |
3790 | if (priv->wep_key_len[priv->default_key] > 5) | 3790 | if (priv->wep_key_len[priv->default_key] > 5) |
3791 | mib.encryption_level = 2; | 3791 | mib.encryption_level = 2; |
3792 | else | 3792 | else |
3793 | mib.encryption_level = 1; | 3793 | mib.encryption_level = 1; |
3794 | } else { | 3794 | } else { |
3795 | mib.encryption_level = 0; | 3795 | mib.encryption_level = 0; |
3796 | } | 3796 | } |
3797 | 3797 | ||
3798 | mib.default_key = priv->default_key; | 3798 | mib.default_key = priv->default_key; |
3799 | mib.exclude_unencrypted = priv->exclude_unencrypted; | 3799 | mib.exclude_unencrypted = priv->exclude_unencrypted; |
3800 | 3800 | ||
3801 | for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) | 3801 | for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) |
3802 | memcpy(mib.wep_keys[i], priv->wep_keys[i], 13); | 3802 | memcpy(mib.wep_keys[i], priv->wep_keys[i], 13); |
3803 | 3803 | ||
3804 | atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib)); | 3804 | atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib)); |
3805 | } | 3805 | } |
3806 | 3806 | ||
3807 | static void build_wpa_mib(struct atmel_private *priv) | 3807 | static void build_wpa_mib(struct atmel_private *priv) |
3808 | { | 3808 | { |
3809 | /* This is for the later (WPA enabled) firmware. */ | 3809 | /* This is for the later (WPA enabled) firmware. */ |
3810 | 3810 | ||
3811 | struct { /* NB this is matched to the hardware, don't change. */ | 3811 | struct { /* NB this is matched to the hardware, don't change. */ |
3812 | u8 cipher_default_key_value[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE]; | 3812 | u8 cipher_default_key_value[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE]; |
3813 | u8 receiver_address[6]; | 3813 | u8 receiver_address[6]; |
3814 | u8 wep_is_on; | 3814 | u8 wep_is_on; |
3815 | u8 default_key; /* 0..3 */ | 3815 | u8 default_key; /* 0..3 */ |
3816 | u8 group_key; | 3816 | u8 group_key; |
3817 | u8 exclude_unencrypted; | 3817 | u8 exclude_unencrypted; |
3818 | u8 encryption_type; | 3818 | u8 encryption_type; |
3819 | u8 reserved; | 3819 | u8 reserved; |
3820 | 3820 | ||
3821 | u32 WEPICV_error_count; | 3821 | u32 WEPICV_error_count; |
3822 | u32 WEP_excluded_count; | 3822 | u32 WEP_excluded_count; |
3823 | 3823 | ||
3824 | u8 key_RSC[4][8]; | 3824 | u8 key_RSC[4][8]; |
3825 | } mib; | 3825 | } mib; |
3826 | 3826 | ||
3827 | int i; | 3827 | int i; |
3828 | 3828 | ||
3829 | mib.wep_is_on = priv->wep_is_on; | 3829 | mib.wep_is_on = priv->wep_is_on; |
3830 | mib.exclude_unencrypted = priv->exclude_unencrypted; | 3830 | mib.exclude_unencrypted = priv->exclude_unencrypted; |
3831 | memcpy(mib.receiver_address, priv->CurrentBSSID, 6); | 3831 | memcpy(mib.receiver_address, priv->CurrentBSSID, 6); |
3832 | 3832 | ||
3833 | /* zero all the keys before adding in valid ones. */ | 3833 | /* zero all the keys before adding in valid ones. */ |
3834 | memset(mib.cipher_default_key_value, 0, sizeof(mib.cipher_default_key_value)); | 3834 | memset(mib.cipher_default_key_value, 0, sizeof(mib.cipher_default_key_value)); |
3835 | 3835 | ||
3836 | if (priv->wep_is_on) { | 3836 | if (priv->wep_is_on) { |
3837 | /* There's a comment in the Atmel code to the effect that this | 3837 | /* There's a comment in the Atmel code to the effect that this |
3838 | is only valid when still using WEP, it may need to be set to | 3838 | is only valid when still using WEP, it may need to be set to |
3839 | something to use WPA */ | 3839 | something to use WPA */ |
3840 | memset(mib.key_RSC, 0, sizeof(mib.key_RSC)); | 3840 | memset(mib.key_RSC, 0, sizeof(mib.key_RSC)); |
3841 | 3841 | ||
3842 | mib.default_key = mib.group_key = 255; | 3842 | mib.default_key = mib.group_key = 255; |
3843 | for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) { | 3843 | for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) { |
3844 | if (priv->wep_key_len[i] > 0) { | 3844 | if (priv->wep_key_len[i] > 0) { |
3845 | memcpy(mib.cipher_default_key_value[i], priv->wep_keys[i], MAX_ENCRYPTION_KEY_SIZE); | 3845 | memcpy(mib.cipher_default_key_value[i], priv->wep_keys[i], MAX_ENCRYPTION_KEY_SIZE); |
3846 | if (i == priv->default_key) { | 3846 | if (i == priv->default_key) { |
3847 | mib.default_key = i; | 3847 | mib.default_key = i; |
3848 | mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 7; | 3848 | mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 7; |
3849 | mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->pairwise_cipher_suite; | 3849 | mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->pairwise_cipher_suite; |
3850 | } else { | 3850 | } else { |
3851 | mib.group_key = i; | 3851 | mib.group_key = i; |
3852 | priv->group_cipher_suite = priv->pairwise_cipher_suite; | 3852 | priv->group_cipher_suite = priv->pairwise_cipher_suite; |
3853 | mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 1; | 3853 | mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 1; |
3854 | mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->group_cipher_suite; | 3854 | mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->group_cipher_suite; |
3855 | } | 3855 | } |
3856 | } | 3856 | } |
3857 | } | 3857 | } |
3858 | if (mib.default_key == 255) | 3858 | if (mib.default_key == 255) |
3859 | mib.default_key = mib.group_key != 255 ? mib.group_key : 0; | 3859 | mib.default_key = mib.group_key != 255 ? mib.group_key : 0; |
3860 | if (mib.group_key == 255) | 3860 | if (mib.group_key == 255) |
3861 | mib.group_key = mib.default_key; | 3861 | mib.group_key = mib.default_key; |
3862 | 3862 | ||
3863 | } | 3863 | } |
3864 | 3864 | ||
3865 | atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib)); | 3865 | atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib)); |
3866 | } | 3866 | } |
3867 | 3867 | ||
3868 | static int reset_atmel_card(struct net_device *dev) | 3868 | static int reset_atmel_card(struct net_device *dev) |
3869 | { | 3869 | { |
3870 | /* do everything necessary to wake up the hardware, including | 3870 | /* do everything necessary to wake up the hardware, including |
3871 | waiting for the lightning strike and throwing the knife switch.... | 3871 | waiting for the lightning strike and throwing the knife switch.... |
3872 | 3872 | ||
3873 | set all the Mib values which matter in the card to match | 3873 | set all the Mib values which matter in the card to match |
3874 | their settings in the atmel_private structure. Some of these | 3874 | their settings in the atmel_private structure. Some of these |
3875 | can be altered on the fly, but many (WEP, infrastucture or ad-hoc) | 3875 | can be altered on the fly, but many (WEP, infrastucture or ad-hoc) |
3876 | can only be changed by tearing down the world and coming back through | 3876 | can only be changed by tearing down the world and coming back through |
3877 | here. | 3877 | here. |
3878 | 3878 | ||
3879 | This routine is also responsible for initialising some | 3879 | This routine is also responsible for initialising some |
3880 | hardware-specific fields in the atmel_private structure, | 3880 | hardware-specific fields in the atmel_private structure, |
3881 | including a copy of the firmware's hostinfo stucture | 3881 | including a copy of the firmware's hostinfo stucture |
3882 | which is the route into the rest of the firmware datastructures. */ | 3882 | which is the route into the rest of the firmware datastructures. */ |
3883 | 3883 | ||
3884 | struct atmel_private *priv = netdev_priv(dev); | 3884 | struct atmel_private *priv = netdev_priv(dev); |
3885 | u8 configuration; | 3885 | u8 configuration; |
3886 | int old_state = priv->station_state; | 3886 | int old_state = priv->station_state; |
3887 | int err = 0; | 3887 | int err = 0; |
3888 | 3888 | ||
3889 | /* data to add to the firmware names, in priority order | 3889 | /* data to add to the firmware names, in priority order |
3890 | this implemenents firmware versioning */ | 3890 | this implemenents firmware versioning */ |
3891 | 3891 | ||
3892 | static char *firmware_modifier[] = { | 3892 | static char *firmware_modifier[] = { |
3893 | "-wpa", | 3893 | "-wpa", |
3894 | "", | 3894 | "", |
3895 | NULL | 3895 | NULL |
3896 | }; | 3896 | }; |
3897 | 3897 | ||
3898 | /* reset pccard */ | 3898 | /* reset pccard */ |
3899 | if (priv->bus_type == BUS_TYPE_PCCARD) | 3899 | if (priv->bus_type == BUS_TYPE_PCCARD) |
3900 | atmel_write16(priv->dev, GCR, 0x0060); | 3900 | atmel_write16(priv->dev, GCR, 0x0060); |
3901 | 3901 | ||
3902 | /* stop card , disable interrupts */ | 3902 | /* stop card , disable interrupts */ |
3903 | atmel_write16(priv->dev, GCR, 0x0040); | 3903 | atmel_write16(priv->dev, GCR, 0x0040); |
3904 | 3904 | ||
3905 | if (priv->card_type == CARD_TYPE_EEPROM) { | 3905 | if (priv->card_type == CARD_TYPE_EEPROM) { |
3906 | /* copy in firmware if needed */ | 3906 | /* copy in firmware if needed */ |
3907 | const struct firmware *fw_entry = NULL; | 3907 | const struct firmware *fw_entry = NULL; |
3908 | const unsigned char *fw; | 3908 | const unsigned char *fw; |
3909 | int len = priv->firmware_length; | 3909 | int len = priv->firmware_length; |
3910 | if (!(fw = priv->firmware)) { | 3910 | if (!(fw = priv->firmware)) { |
3911 | if (priv->firmware_type == ATMEL_FW_TYPE_NONE) { | 3911 | if (priv->firmware_type == ATMEL_FW_TYPE_NONE) { |
3912 | if (strlen(priv->firmware_id) == 0) { | 3912 | if (strlen(priv->firmware_id) == 0) { |
3913 | printk(KERN_INFO | 3913 | printk(KERN_INFO |
3914 | "%s: card type is unknown: assuming at76c502 firmware is OK.\n", | 3914 | "%s: card type is unknown: assuming at76c502 firmware is OK.\n", |
3915 | dev->name); | 3915 | dev->name); |
3916 | printk(KERN_INFO | 3916 | printk(KERN_INFO |
3917 | "%s: if not, use the firmware= module parameter.\n", | 3917 | "%s: if not, use the firmware= module parameter.\n", |
3918 | dev->name); | 3918 | dev->name); |
3919 | strcpy(priv->firmware_id, "atmel_at76c502.bin"); | 3919 | strcpy(priv->firmware_id, "atmel_at76c502.bin"); |
3920 | } | 3920 | } |
3921 | err = request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev); | 3921 | err = request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev); |
3922 | if (err != 0) { | 3922 | if (err != 0) { |
3923 | printk(KERN_ALERT | 3923 | printk(KERN_ALERT |
3924 | "%s: firmware %s is missing, cannot continue.\n", | 3924 | "%s: firmware %s is missing, cannot continue.\n", |
3925 | dev->name, priv->firmware_id); | 3925 | dev->name, priv->firmware_id); |
3926 | return err; | 3926 | return err; |
3927 | } | 3927 | } |
3928 | } else { | 3928 | } else { |
3929 | int fw_index = 0; | 3929 | int fw_index = 0; |
3930 | int success = 0; | 3930 | int success = 0; |
3931 | 3931 | ||
3932 | /* get firmware filename entry based on firmware type ID */ | 3932 | /* get firmware filename entry based on firmware type ID */ |
3933 | while (fw_table[fw_index].fw_type != priv->firmware_type | 3933 | while (fw_table[fw_index].fw_type != priv->firmware_type |
3934 | && fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) | 3934 | && fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) |
3935 | fw_index++; | 3935 | fw_index++; |
3936 | 3936 | ||
3937 | /* construct the actual firmware file name */ | 3937 | /* construct the actual firmware file name */ |
3938 | if (fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) { | 3938 | if (fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) { |
3939 | int i; | 3939 | int i; |
3940 | for (i = 0; firmware_modifier[i]; i++) { | 3940 | for (i = 0; firmware_modifier[i]; i++) { |
3941 | snprintf(priv->firmware_id, 32, "%s%s.%s", fw_table[fw_index].fw_file, | 3941 | snprintf(priv->firmware_id, 32, "%s%s.%s", fw_table[fw_index].fw_file, |
3942 | firmware_modifier[i], fw_table[fw_index].fw_file_ext); | 3942 | firmware_modifier[i], fw_table[fw_index].fw_file_ext); |
3943 | priv->firmware_id[31] = '\0'; | 3943 | priv->firmware_id[31] = '\0'; |
3944 | if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) == 0) { | 3944 | if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) == 0) { |
3945 | success = 1; | 3945 | success = 1; |
3946 | break; | 3946 | break; |
3947 | } | 3947 | } |
3948 | } | 3948 | } |
3949 | } | 3949 | } |
3950 | if (!success) { | 3950 | if (!success) { |
3951 | printk(KERN_ALERT | 3951 | printk(KERN_ALERT |
3952 | "%s: firmware %s is missing, cannot start.\n", | 3952 | "%s: firmware %s is missing, cannot start.\n", |
3953 | dev->name, priv->firmware_id); | 3953 | dev->name, priv->firmware_id); |
3954 | priv->firmware_id[0] = '\0'; | 3954 | priv->firmware_id[0] = '\0'; |
3955 | return -ENOENT; | 3955 | return -ENOENT; |
3956 | } | 3956 | } |
3957 | } | 3957 | } |
3958 | 3958 | ||
3959 | fw = fw_entry->data; | 3959 | fw = fw_entry->data; |
3960 | len = fw_entry->size; | 3960 | len = fw_entry->size; |
3961 | } | 3961 | } |
3962 | 3962 | ||
3963 | if (len <= 0x6000) { | 3963 | if (len <= 0x6000) { |
3964 | atmel_write16(priv->dev, BSR, BSS_IRAM); | 3964 | atmel_write16(priv->dev, BSR, BSS_IRAM); |
3965 | atmel_copy_to_card(priv->dev, 0, fw, len); | 3965 | atmel_copy_to_card(priv->dev, 0, fw, len); |
3966 | atmel_set_gcr(priv->dev, GCR_REMAP); | 3966 | atmel_set_gcr(priv->dev, GCR_REMAP); |
3967 | } else { | 3967 | } else { |
3968 | /* Remap */ | 3968 | /* Remap */ |
3969 | atmel_set_gcr(priv->dev, GCR_REMAP); | 3969 | atmel_set_gcr(priv->dev, GCR_REMAP); |
3970 | atmel_write16(priv->dev, BSR, BSS_IRAM); | 3970 | atmel_write16(priv->dev, BSR, BSS_IRAM); |
3971 | atmel_copy_to_card(priv->dev, 0, fw, 0x6000); | 3971 | atmel_copy_to_card(priv->dev, 0, fw, 0x6000); |
3972 | atmel_write16(priv->dev, BSR, 0x2ff); | 3972 | atmel_write16(priv->dev, BSR, 0x2ff); |
3973 | atmel_copy_to_card(priv->dev, 0x8000, &fw[0x6000], len - 0x6000); | 3973 | atmel_copy_to_card(priv->dev, 0x8000, &fw[0x6000], len - 0x6000); |
3974 | } | 3974 | } |
3975 | 3975 | ||
3976 | if (fw_entry) | 3976 | if (fw_entry) |
3977 | release_firmware(fw_entry); | 3977 | release_firmware(fw_entry); |
3978 | } | 3978 | } |
3979 | 3979 | ||
3980 | err = atmel_wakeup_firmware(priv); | 3980 | err = atmel_wakeup_firmware(priv); |
3981 | if (err != 0) | 3981 | if (err != 0) |
3982 | return err; | 3982 | return err; |
3983 | 3983 | ||
3984 | /* Check the version and set the correct flag for wpa stuff, | 3984 | /* Check the version and set the correct flag for wpa stuff, |
3985 | old and new firmware is incompatible. | 3985 | old and new firmware is incompatible. |
3986 | The pre-wpa 3com firmware reports major version 5, | 3986 | The pre-wpa 3com firmware reports major version 5, |
3987 | the wpa 3com firmware is major version 4 and doesn't need | 3987 | the wpa 3com firmware is major version 4 and doesn't need |
3988 | the 3com broken-ness filter. */ | 3988 | the 3com broken-ness filter. */ |
3989 | priv->use_wpa = (priv->host_info.major_version == 4); | 3989 | priv->use_wpa = (priv->host_info.major_version == 4); |
3990 | priv->radio_on_broken = (priv->host_info.major_version == 5); | 3990 | priv->radio_on_broken = (priv->host_info.major_version == 5); |
3991 | 3991 | ||
3992 | /* unmask all irq sources */ | 3992 | /* unmask all irq sources */ |
3993 | atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_MASK_OFFSET), 0xff); | 3993 | atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_MASK_OFFSET), 0xff); |
3994 | 3994 | ||
3995 | /* int Tx system and enable Tx */ | 3995 | /* int Tx system and enable Tx */ |
3996 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, 0), 0); | 3996 | atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, 0), 0); |
3997 | atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, 0), 0x80000000L); | 3997 | atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, 0), 0x80000000L); |
3998 | atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, 0), 0); | 3998 | atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, 0), 0); |
3999 | atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, 0), 0); | 3999 | atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, 0), 0); |
4000 | 4000 | ||
4001 | priv->tx_desc_free = priv->host_info.tx_desc_count; | 4001 | priv->tx_desc_free = priv->host_info.tx_desc_count; |
4002 | priv->tx_desc_head = 0; | 4002 | priv->tx_desc_head = 0; |
4003 | priv->tx_desc_tail = 0; | 4003 | priv->tx_desc_tail = 0; |
4004 | priv->tx_desc_previous = 0; | 4004 | priv->tx_desc_previous = 0; |
4005 | priv->tx_free_mem = priv->host_info.tx_buff_size; | 4005 | priv->tx_free_mem = priv->host_info.tx_buff_size; |
4006 | priv->tx_buff_head = 0; | 4006 | priv->tx_buff_head = 0; |
4007 | priv->tx_buff_tail = 0; | 4007 | priv->tx_buff_tail = 0; |
4008 | 4008 | ||
4009 | configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); | 4009 | configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); |
4010 | atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), | 4010 | atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), |
4011 | configuration | FUNC_CTRL_TxENABLE); | 4011 | configuration | FUNC_CTRL_TxENABLE); |
4012 | 4012 | ||
4013 | /* init Rx system and enable */ | 4013 | /* init Rx system and enable */ |
4014 | priv->rx_desc_head = 0; | 4014 | priv->rx_desc_head = 0; |
4015 | 4015 | ||
4016 | configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); | 4016 | configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); |
4017 | atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), | 4017 | atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), |
4018 | configuration | FUNC_CTRL_RxENABLE); | 4018 | configuration | FUNC_CTRL_RxENABLE); |
4019 | 4019 | ||
4020 | if (!priv->radio_on_broken) { | 4020 | if (!priv->radio_on_broken) { |
4021 | if (atmel_send_command_wait(priv, CMD_EnableRadio, NULL, 0) == | 4021 | if (atmel_send_command_wait(priv, CMD_EnableRadio, NULL, 0) == |
4022 | CMD_STATUS_REJECTED_RADIO_OFF) { | 4022 | CMD_STATUS_REJECTED_RADIO_OFF) { |
4023 | printk(KERN_INFO "%s: cannot turn the radio on.\n", | 4023 | printk(KERN_INFO "%s: cannot turn the radio on.\n", |
4024 | dev->name); | 4024 | dev->name); |
4025 | return -EIO; | 4025 | return -EIO; |
4026 | } | 4026 | } |
4027 | } | 4027 | } |
4028 | 4028 | ||
4029 | /* set up enough MIB values to run. */ | 4029 | /* set up enough MIB values to run. */ |
4030 | atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_AUTO_TX_RATE_POS, priv->auto_tx_rate); | 4030 | atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_AUTO_TX_RATE_POS, priv->auto_tx_rate); |
4031 | atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_TX_PROMISCUOUS_POS, PROM_MODE_OFF); | 4031 | atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_TX_PROMISCUOUS_POS, PROM_MODE_OFF); |
4032 | atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_RTS_THRESHOLD_POS, priv->rts_threshold); | 4032 | atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_RTS_THRESHOLD_POS, priv->rts_threshold); |
4033 | atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_FRAG_THRESHOLD_POS, priv->frag_threshold); | 4033 | atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_FRAG_THRESHOLD_POS, priv->frag_threshold); |
4034 | atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_SHORT_RETRY_POS, priv->short_retry); | 4034 | atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_SHORT_RETRY_POS, priv->short_retry); |
4035 | atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_LONG_RETRY_POS, priv->long_retry); | 4035 | atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_LONG_RETRY_POS, priv->long_retry); |
4036 | atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, priv->preamble); | 4036 | atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, priv->preamble); |
4037 | atmel_set_mib(priv, Mac_Address_Mib_Type, MAC_ADDR_MIB_MAC_ADDR_POS, | 4037 | atmel_set_mib(priv, Mac_Address_Mib_Type, MAC_ADDR_MIB_MAC_ADDR_POS, |
4038 | priv->dev->dev_addr, 6); | 4038 | priv->dev->dev_addr, 6); |
4039 | atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); | 4039 | atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); |
4040 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); | 4040 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); |
4041 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_BEACON_PER_POS, priv->default_beacon_period); | 4041 | atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_BEACON_PER_POS, priv->default_beacon_period); |
4042 | atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, atmel_basic_rates, 4); | 4042 | atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, atmel_basic_rates, 4); |
4043 | atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep_is_on); | 4043 | atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep_is_on); |
4044 | if (priv->use_wpa) | 4044 | if (priv->use_wpa) |
4045 | build_wpa_mib(priv); | 4045 | build_wpa_mib(priv); |
4046 | else | 4046 | else |
4047 | build_wep_mib(priv); | 4047 | build_wep_mib(priv); |
4048 | 4048 | ||
4049 | if (old_state == STATION_STATE_READY) { | 4049 | if (old_state == STATION_STATE_READY) { |
4050 | union iwreq_data wrqu; | 4050 | union iwreq_data wrqu; |
4051 | 4051 | ||
4052 | wrqu.data.length = 0; | 4052 | wrqu.data.length = 0; |
4053 | wrqu.data.flags = 0; | 4053 | wrqu.data.flags = 0; |
4054 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 4054 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
4055 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | 4055 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); |
4056 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | 4056 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); |
4057 | } | 4057 | } |
4058 | 4058 | ||
4059 | return 0; | 4059 | return 0; |
4060 | } | 4060 | } |
4061 | 4061 | ||
4062 | static void atmel_send_command(struct atmel_private *priv, int command, | 4062 | static void atmel_send_command(struct atmel_private *priv, int command, |
4063 | void *cmd, int cmd_size) | 4063 | void *cmd, int cmd_size) |
4064 | { | 4064 | { |
4065 | if (cmd) | 4065 | if (cmd) |
4066 | atmel_copy_to_card(priv->dev, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET), | 4066 | atmel_copy_to_card(priv->dev, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET), |
4067 | cmd, cmd_size); | 4067 | cmd, cmd_size); |
4068 | 4068 | ||
4069 | atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET), command); | 4069 | atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET), command); |
4070 | atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET), 0); | 4070 | atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET), 0); |
4071 | } | 4071 | } |
4072 | 4072 | ||
4073 | static int atmel_send_command_wait(struct atmel_private *priv, int command, | 4073 | static int atmel_send_command_wait(struct atmel_private *priv, int command, |
4074 | void *cmd, int cmd_size) | 4074 | void *cmd, int cmd_size) |
4075 | { | 4075 | { |
4076 | int i, status; | 4076 | int i, status; |
4077 | 4077 | ||
4078 | atmel_send_command(priv, command, cmd, cmd_size); | 4078 | atmel_send_command(priv, command, cmd, cmd_size); |
4079 | 4079 | ||
4080 | for (i = 5000; i; i--) { | 4080 | for (i = 5000; i; i--) { |
4081 | status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); | 4081 | status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); |
4082 | if (status != CMD_STATUS_IDLE && | 4082 | if (status != CMD_STATUS_IDLE && |
4083 | status != CMD_STATUS_IN_PROGRESS) | 4083 | status != CMD_STATUS_IN_PROGRESS) |
4084 | break; | 4084 | break; |
4085 | udelay(20); | 4085 | udelay(20); |
4086 | } | 4086 | } |
4087 | 4087 | ||
4088 | if (i == 0) { | 4088 | if (i == 0) { |
4089 | printk(KERN_ALERT "%s: failed to contact MAC.\n", priv->dev->name); | 4089 | printk(KERN_ALERT "%s: failed to contact MAC.\n", priv->dev->name); |
4090 | status = CMD_STATUS_HOST_ERROR; | 4090 | status = CMD_STATUS_HOST_ERROR; |
4091 | } else { | 4091 | } else { |
4092 | if (command != CMD_EnableRadio) | 4092 | if (command != CMD_EnableRadio) |
4093 | status = CMD_STATUS_COMPLETE; | 4093 | status = CMD_STATUS_COMPLETE; |
4094 | } | 4094 | } |
4095 | 4095 | ||
4096 | return status; | 4096 | return status; |
4097 | } | 4097 | } |
4098 | 4098 | ||
4099 | static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index) | 4099 | static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index) |
4100 | { | 4100 | { |
4101 | struct get_set_mib m; | 4101 | struct get_set_mib m; |
4102 | m.type = type; | 4102 | m.type = type; |
4103 | m.size = 1; | 4103 | m.size = 1; |
4104 | m.index = index; | 4104 | m.index = index; |
4105 | 4105 | ||
4106 | atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + 1); | 4106 | atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + 1); |
4107 | return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE)); | 4107 | return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE)); |
4108 | } | 4108 | } |
4109 | 4109 | ||
4110 | static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data) | 4110 | static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data) |
4111 | { | 4111 | { |
4112 | struct get_set_mib m; | 4112 | struct get_set_mib m; |
4113 | m.type = type; | 4113 | m.type = type; |
4114 | m.size = 1; | 4114 | m.size = 1; |
4115 | m.index = index; | 4115 | m.index = index; |
4116 | m.data[0] = data; | 4116 | m.data[0] = data; |
4117 | 4117 | ||
4118 | atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 1); | 4118 | atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 1); |
4119 | } | 4119 | } |
4120 | 4120 | ||
4121 | static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, | 4121 | static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, |
4122 | u16 data) | 4122 | u16 data) |
4123 | { | 4123 | { |
4124 | struct get_set_mib m; | 4124 | struct get_set_mib m; |
4125 | m.type = type; | 4125 | m.type = type; |
4126 | m.size = 2; | 4126 | m.size = 2; |
4127 | m.index = index; | 4127 | m.index = index; |
4128 | m.data[0] = data; | 4128 | m.data[0] = data; |
4129 | m.data[1] = data >> 8; | 4129 | m.data[1] = data >> 8; |
4130 | 4130 | ||
4131 | atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 2); | 4131 | atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 2); |
4132 | } | 4132 | } |
4133 | 4133 | ||
4134 | static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, | 4134 | static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, |
4135 | u8 *data, int data_len) | 4135 | u8 *data, int data_len) |
4136 | { | 4136 | { |
4137 | struct get_set_mib m; | 4137 | struct get_set_mib m; |
4138 | m.type = type; | 4138 | m.type = type; |
4139 | m.size = data_len; | 4139 | m.size = data_len; |
4140 | m.index = index; | 4140 | m.index = index; |
4141 | 4141 | ||
4142 | if (data_len > MIB_MAX_DATA_BYTES) | 4142 | if (data_len > MIB_MAX_DATA_BYTES) |
4143 | printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name); | 4143 | printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name); |
4144 | 4144 | ||
4145 | memcpy(m.data, data, data_len); | 4145 | memcpy(m.data, data, data_len); |
4146 | atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + data_len); | 4146 | atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + data_len); |
4147 | } | 4147 | } |
4148 | 4148 | ||
4149 | static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, | 4149 | static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, |
4150 | u8 *data, int data_len) | 4150 | u8 *data, int data_len) |
4151 | { | 4151 | { |
4152 | struct get_set_mib m; | 4152 | struct get_set_mib m; |
4153 | m.type = type; | 4153 | m.type = type; |
4154 | m.size = data_len; | 4154 | m.size = data_len; |
4155 | m.index = index; | 4155 | m.index = index; |
4156 | 4156 | ||
4157 | if (data_len > MIB_MAX_DATA_BYTES) | 4157 | if (data_len > MIB_MAX_DATA_BYTES) |
4158 | printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name); | 4158 | printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name); |
4159 | 4159 | ||
4160 | atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + data_len); | 4160 | atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + data_len); |
4161 | atmel_copy_to_host(priv->dev, data, | 4161 | atmel_copy_to_host(priv->dev, data, |
4162 | atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE), data_len); | 4162 | atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE), data_len); |
4163 | } | 4163 | } |
4164 | 4164 | ||
4165 | static void atmel_writeAR(struct net_device *dev, u16 data) | 4165 | static void atmel_writeAR(struct net_device *dev, u16 data) |
4166 | { | 4166 | { |
4167 | int i; | 4167 | int i; |
4168 | outw(data, dev->base_addr + AR); | 4168 | outw(data, dev->base_addr + AR); |
4169 | /* Address register appears to need some convincing..... */ | 4169 | /* Address register appears to need some convincing..... */ |
4170 | for (i = 0; data != inw(dev->base_addr + AR) && i < 10; i++) | 4170 | for (i = 0; data != inw(dev->base_addr + AR) && i < 10; i++) |
4171 | outw(data, dev->base_addr + AR); | 4171 | outw(data, dev->base_addr + AR); |
4172 | } | 4172 | } |
4173 | 4173 | ||
4174 | static void atmel_copy_to_card(struct net_device *dev, u16 dest, | 4174 | static void atmel_copy_to_card(struct net_device *dev, u16 dest, |
4175 | const unsigned char *src, u16 len) | 4175 | const unsigned char *src, u16 len) |
4176 | { | 4176 | { |
4177 | int i; | 4177 | int i; |
4178 | atmel_writeAR(dev, dest); | 4178 | atmel_writeAR(dev, dest); |
4179 | if (dest % 2) { | 4179 | if (dest % 2) { |
4180 | atmel_write8(dev, DR, *src); | 4180 | atmel_write8(dev, DR, *src); |
4181 | src++; len--; | 4181 | src++; len--; |
4182 | } | 4182 | } |
4183 | for (i = len; i > 1 ; i -= 2) { | 4183 | for (i = len; i > 1 ; i -= 2) { |
4184 | u8 lb = *src++; | 4184 | u8 lb = *src++; |
4185 | u8 hb = *src++; | 4185 | u8 hb = *src++; |
4186 | atmel_write16(dev, DR, lb | (hb << 8)); | 4186 | atmel_write16(dev, DR, lb | (hb << 8)); |
4187 | } | 4187 | } |
4188 | if (i) | 4188 | if (i) |
4189 | atmel_write8(dev, DR, *src); | 4189 | atmel_write8(dev, DR, *src); |
4190 | } | 4190 | } |
4191 | 4191 | ||
4192 | static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, | 4192 | static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, |
4193 | u16 src, u16 len) | 4193 | u16 src, u16 len) |
4194 | { | 4194 | { |
4195 | int i; | 4195 | int i; |
4196 | atmel_writeAR(dev, src); | 4196 | atmel_writeAR(dev, src); |
4197 | if (src % 2) { | 4197 | if (src % 2) { |
4198 | *dest = atmel_read8(dev, DR); | 4198 | *dest = atmel_read8(dev, DR); |
4199 | dest++; len--; | 4199 | dest++; len--; |
4200 | } | 4200 | } |
4201 | for (i = len; i > 1 ; i -= 2) { | 4201 | for (i = len; i > 1 ; i -= 2) { |
4202 | u16 hw = atmel_read16(dev, DR); | 4202 | u16 hw = atmel_read16(dev, DR); |
4203 | *dest++ = hw; | 4203 | *dest++ = hw; |
4204 | *dest++ = hw >> 8; | 4204 | *dest++ = hw >> 8; |
4205 | } | 4205 | } |
4206 | if (i) | 4206 | if (i) |
4207 | *dest = atmel_read8(dev, DR); | 4207 | *dest = atmel_read8(dev, DR); |
4208 | } | 4208 | } |
4209 | 4209 | ||
4210 | static void atmel_set_gcr(struct net_device *dev, u16 mask) | 4210 | static void atmel_set_gcr(struct net_device *dev, u16 mask) |
4211 | { | 4211 | { |
4212 | outw(inw(dev->base_addr + GCR) | mask, dev->base_addr + GCR); | 4212 | outw(inw(dev->base_addr + GCR) | mask, dev->base_addr + GCR); |
4213 | } | 4213 | } |
4214 | 4214 | ||
4215 | static void atmel_clear_gcr(struct net_device *dev, u16 mask) | 4215 | static void atmel_clear_gcr(struct net_device *dev, u16 mask) |
4216 | { | 4216 | { |
4217 | outw(inw(dev->base_addr + GCR) & ~mask, dev->base_addr + GCR); | 4217 | outw(inw(dev->base_addr + GCR) & ~mask, dev->base_addr + GCR); |
4218 | } | 4218 | } |
4219 | 4219 | ||
4220 | static int atmel_lock_mac(struct atmel_private *priv) | 4220 | static int atmel_lock_mac(struct atmel_private *priv) |
4221 | { | 4221 | { |
4222 | int i, j = 20; | 4222 | int i, j = 20; |
4223 | retry: | 4223 | retry: |
4224 | for (i = 5000; i; i--) { | 4224 | for (i = 5000; i; i--) { |
4225 | if (!atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) | 4225 | if (!atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) |
4226 | break; | 4226 | break; |
4227 | udelay(20); | 4227 | udelay(20); |
4228 | } | 4228 | } |
4229 | 4229 | ||
4230 | if (!i) | 4230 | if (!i) |
4231 | return 0; /* timed out */ | 4231 | return 0; /* timed out */ |
4232 | 4232 | ||
4233 | atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 1); | 4233 | atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 1); |
4234 | if (atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) { | 4234 | if (atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) { |
4235 | atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); | 4235 | atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); |
4236 | if (!j--) | 4236 | if (!j--) |
4237 | return 0; /* timed out */ | 4237 | return 0; /* timed out */ |
4238 | goto retry; | 4238 | goto retry; |
4239 | } | 4239 | } |
4240 | 4240 | ||
4241 | return 1; | 4241 | return 1; |
4242 | } | 4242 | } |
4243 | 4243 | ||
4244 | static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data) | 4244 | static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data) |
4245 | { | 4245 | { |
4246 | atmel_writeAR(priv->dev, pos); | 4246 | atmel_writeAR(priv->dev, pos); |
4247 | atmel_write16(priv->dev, DR, data); /* card is little-endian */ | 4247 | atmel_write16(priv->dev, DR, data); /* card is little-endian */ |
4248 | atmel_write16(priv->dev, DR, data >> 16); | 4248 | atmel_write16(priv->dev, DR, data >> 16); |
4249 | } | 4249 | } |
4250 | 4250 | ||
4251 | /***************************************************************************/ | 4251 | /***************************************************************************/ |
4252 | /* There follows the source form of the MAC address reading firmware */ | 4252 | /* There follows the source form of the MAC address reading firmware */ |
4253 | /***************************************************************************/ | 4253 | /***************************************************************************/ |
4254 | #if 0 | 4254 | #if 0 |
4255 | 4255 | ||
4256 | /* Copyright 2003 Matthew T. Russotto */ | 4256 | /* Copyright 2003 Matthew T. Russotto */ |
4257 | /* But derived from the Atmel 76C502 firmware written by Atmel and */ | 4257 | /* But derived from the Atmel 76C502 firmware written by Atmel and */ |
4258 | /* included in "atmel wireless lan drivers" package */ | 4258 | /* included in "atmel wireless lan drivers" package */ |
4259 | /** | 4259 | /** |
4260 | This file is part of net.russotto.AtmelMACFW, hereto referred to | 4260 | This file is part of net.russotto.AtmelMACFW, hereto referred to |
4261 | as AtmelMACFW | 4261 | as AtmelMACFW |
4262 | 4262 | ||
4263 | AtmelMACFW is free software; you can redistribute it and/or modify | 4263 | AtmelMACFW is free software; you can redistribute it and/or modify |
4264 | it under the terms of the GNU General Public License version 2 | 4264 | it under the terms of the GNU General Public License version 2 |
4265 | as published by the Free Software Foundation. | 4265 | as published by the Free Software Foundation. |
4266 | 4266 | ||
4267 | AtmelMACFW is distributed in the hope that it will be useful, | 4267 | AtmelMACFW is distributed in the hope that it will be useful, |
4268 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 4268 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
4269 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 4269 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4270 | GNU General Public License for more details. | 4270 | GNU General Public License for more details. |
4271 | 4271 | ||
4272 | You should have received a copy of the GNU General Public License | 4272 | You should have received a copy of the GNU General Public License |
4273 | along with AtmelMACFW; if not, write to the Free Software | 4273 | along with AtmelMACFW; if not, write to the Free Software |
4274 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 4274 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
4275 | 4275 | ||
4276 | ****************************************************************************/ | 4276 | ****************************************************************************/ |
4277 | /* This firmware should work on the 76C502 RFMD, RFMD_D, and RFMD_E */ | 4277 | /* This firmware should work on the 76C502 RFMD, RFMD_D, and RFMD_E */ |
4278 | /* It will probably work on the 76C504 and 76C502 RFMD_3COM */ | 4278 | /* It will probably work on the 76C504 and 76C502 RFMD_3COM */ |
4279 | /* It only works on SPI EEPROM versions of the card. */ | 4279 | /* It only works on SPI EEPROM versions of the card. */ |
4280 | 4280 | ||
4281 | /* This firmware initializes the SPI controller and clock, reads the MAC */ | 4281 | /* This firmware initializes the SPI controller and clock, reads the MAC */ |
4282 | /* address from the EEPROM into SRAM, and puts the SRAM offset of the MAC */ | 4282 | /* address from the EEPROM into SRAM, and puts the SRAM offset of the MAC */ |
4283 | /* address in MR2, and sets MR3 to 0x10 to indicate it is done */ | 4283 | /* address in MR2, and sets MR3 to 0x10 to indicate it is done */ |
4284 | /* It also puts a complete copy of the EEPROM in SRAM with the offset in */ | 4284 | /* It also puts a complete copy of the EEPROM in SRAM with the offset in */ |
4285 | /* MR4, for investigational purposes (maybe we can determine chip type */ | 4285 | /* MR4, for investigational purposes (maybe we can determine chip type */ |
4286 | /* from that?) */ | 4286 | /* from that?) */ |
4287 | 4287 | ||
4288 | .org 0 | 4288 | .org 0 |
4289 | .set MRBASE, 0x8000000 | 4289 | .set MRBASE, 0x8000000 |
4290 | .set CPSR_INITIAL, 0xD3 /* IRQ/FIQ disabled, ARM mode, Supervisor state */ | 4290 | .set CPSR_INITIAL, 0xD3 /* IRQ/FIQ disabled, ARM mode, Supervisor state */ |
4291 | .set CPSR_USER, 0xD1 /* IRQ/FIQ disabled, ARM mode, USER state */ | 4291 | .set CPSR_USER, 0xD1 /* IRQ/FIQ disabled, ARM mode, USER state */ |
4292 | .set SRAM_BASE, 0x02000000 | 4292 | .set SRAM_BASE, 0x02000000 |
4293 | .set SP_BASE, 0x0F300000 | 4293 | .set SP_BASE, 0x0F300000 |
4294 | .set UNK_BASE, 0x0F000000 /* Some internal device, but which one? */ | 4294 | .set UNK_BASE, 0x0F000000 /* Some internal device, but which one? */ |
4295 | .set SPI_CGEN_BASE, 0x0E000000 /* Some internal device, but which one? */ | 4295 | .set SPI_CGEN_BASE, 0x0E000000 /* Some internal device, but which one? */ |
4296 | .set UNK3_BASE, 0x02014000 /* Some internal device, but which one? */ | 4296 | .set UNK3_BASE, 0x02014000 /* Some internal device, but which one? */ |
4297 | .set STACK_BASE, 0x5600 | 4297 | .set STACK_BASE, 0x5600 |
4298 | .set SP_SR, 0x10 | 4298 | .set SP_SR, 0x10 |
4299 | .set SP_TDRE, 2 /* status register bit -- TDR empty */ | 4299 | .set SP_TDRE, 2 /* status register bit -- TDR empty */ |
4300 | .set SP_RDRF, 1 /* status register bit -- RDR full */ | 4300 | .set SP_RDRF, 1 /* status register bit -- RDR full */ |
4301 | .set SP_SWRST, 0x80 | 4301 | .set SP_SWRST, 0x80 |
4302 | .set SP_SPIEN, 0x1 | 4302 | .set SP_SPIEN, 0x1 |
4303 | .set SP_CR, 0 /* control register */ | 4303 | .set SP_CR, 0 /* control register */ |
4304 | .set SP_MR, 4 /* mode register */ | 4304 | .set SP_MR, 4 /* mode register */ |
4305 | .set SP_RDR, 0x08 /* Read Data Register */ | 4305 | .set SP_RDR, 0x08 /* Read Data Register */ |
4306 | .set SP_TDR, 0x0C /* Transmit Data Register */ | 4306 | .set SP_TDR, 0x0C /* Transmit Data Register */ |
4307 | .set SP_CSR0, 0x30 /* chip select registers */ | 4307 | .set SP_CSR0, 0x30 /* chip select registers */ |
4308 | .set SP_CSR1, 0x34 | 4308 | .set SP_CSR1, 0x34 |
4309 | .set SP_CSR2, 0x38 | 4309 | .set SP_CSR2, 0x38 |
4310 | .set SP_CSR3, 0x3C | 4310 | .set SP_CSR3, 0x3C |
4311 | .set NVRAM_CMD_RDSR, 5 /* read status register */ | 4311 | .set NVRAM_CMD_RDSR, 5 /* read status register */ |
4312 | .set NVRAM_CMD_READ, 3 /* read data */ | 4312 | .set NVRAM_CMD_READ, 3 /* read data */ |
4313 | .set NVRAM_SR_RDY, 1 /* RDY bit. This bit is inverted */ | 4313 | .set NVRAM_SR_RDY, 1 /* RDY bit. This bit is inverted */ |
4314 | .set SPI_8CLOCKS, 0xFF /* Writing this to the TDR doesn't do anything to the | 4314 | .set SPI_8CLOCKS, 0xFF /* Writing this to the TDR doesn't do anything to the |
4315 | serial output, since SO is normally high. But it | 4315 | serial output, since SO is normally high. But it |
4316 | does cause 8 clock cycles and thus 8 bits to be | 4316 | does cause 8 clock cycles and thus 8 bits to be |
4317 | clocked in to the chip. See Atmel's SPI | 4317 | clocked in to the chip. See Atmel's SPI |
4318 | controller (e.g. AT91M55800) timing and 4K | 4318 | controller (e.g. AT91M55800) timing and 4K |
4319 | SPI EEPROM manuals */ | 4319 | SPI EEPROM manuals */ |
4320 | 4320 | ||
4321 | .set NVRAM_SCRATCH, 0x02000100 /* arbitrary area for scratchpad memory */ | 4321 | .set NVRAM_SCRATCH, 0x02000100 /* arbitrary area for scratchpad memory */ |
4322 | .set NVRAM_IMAGE, 0x02000200 | 4322 | .set NVRAM_IMAGE, 0x02000200 |
4323 | .set NVRAM_LENGTH, 0x0200 | 4323 | .set NVRAM_LENGTH, 0x0200 |
4324 | .set MAC_ADDRESS_MIB, SRAM_BASE | 4324 | .set MAC_ADDRESS_MIB, SRAM_BASE |
4325 | .set MAC_ADDRESS_LENGTH, 6 | 4325 | .set MAC_ADDRESS_LENGTH, 6 |
4326 | .set MAC_BOOT_FLAG, 0x10 | 4326 | .set MAC_BOOT_FLAG, 0x10 |
4327 | .set MR1, 0 | 4327 | .set MR1, 0 |
4328 | .set MR2, 4 | 4328 | .set MR2, 4 |
4329 | .set MR3, 8 | 4329 | .set MR3, 8 |
4330 | .set MR4, 0xC | 4330 | .set MR4, 0xC |
4331 | RESET_VECTOR: | 4331 | RESET_VECTOR: |
4332 | b RESET_HANDLER | 4332 | b RESET_HANDLER |
4333 | UNDEF_VECTOR: | 4333 | UNDEF_VECTOR: |
4334 | b HALT1 | 4334 | b HALT1 |
4335 | SWI_VECTOR: | 4335 | SWI_VECTOR: |
4336 | b HALT1 | 4336 | b HALT1 |
4337 | IABORT_VECTOR: | 4337 | IABORT_VECTOR: |
4338 | b HALT1 | 4338 | b HALT1 |
4339 | DABORT_VECTOR: | 4339 | DABORT_VECTOR: |
4340 | RESERVED_VECTOR: | 4340 | RESERVED_VECTOR: |
4341 | b HALT1 | 4341 | b HALT1 |
4342 | IRQ_VECTOR: | 4342 | IRQ_VECTOR: |
4343 | b HALT1 | 4343 | b HALT1 |
4344 | FIQ_VECTOR: | 4344 | FIQ_VECTOR: |
4345 | b HALT1 | 4345 | b HALT1 |
4346 | HALT1: b HALT1 | 4346 | HALT1: b HALT1 |
4347 | RESET_HANDLER: | 4347 | RESET_HANDLER: |
4348 | mov r0, #CPSR_INITIAL | 4348 | mov r0, #CPSR_INITIAL |
4349 | msr CPSR_c, r0 /* This is probably unnecessary */ | 4349 | msr CPSR_c, r0 /* This is probably unnecessary */ |
4350 | 4350 | ||
4351 | /* I'm guessing this is initializing clock generator electronics for SPI */ | 4351 | /* I'm guessing this is initializing clock generator electronics for SPI */ |
4352 | ldr r0, =SPI_CGEN_BASE | 4352 | ldr r0, =SPI_CGEN_BASE |
4353 | mov r1, #0 | 4353 | mov r1, #0 |
4354 | mov r1, r1, lsl #3 | 4354 | mov r1, r1, lsl #3 |
4355 | orr r1, r1, #0 | 4355 | orr r1, r1, #0 |
4356 | str r1, [r0] | 4356 | str r1, [r0] |
4357 | ldr r1, [r0, #28] | 4357 | ldr r1, [r0, #28] |
4358 | bic r1, r1, #16 | 4358 | bic r1, r1, #16 |
4359 | str r1, [r0, #28] | 4359 | str r1, [r0, #28] |
4360 | mov r1, #1 | 4360 | mov r1, #1 |
4361 | str r1, [r0, #8] | 4361 | str r1, [r0, #8] |
4362 | 4362 | ||
4363 | ldr r0, =MRBASE | 4363 | ldr r0, =MRBASE |
4364 | mov r1, #0 | 4364 | mov r1, #0 |
4365 | strh r1, [r0, #MR1] | 4365 | strh r1, [r0, #MR1] |
4366 | strh r1, [r0, #MR2] | 4366 | strh r1, [r0, #MR2] |
4367 | strh r1, [r0, #MR3] | 4367 | strh r1, [r0, #MR3] |
4368 | strh r1, [r0, #MR4] | 4368 | strh r1, [r0, #MR4] |
4369 | 4369 | ||
4370 | mov sp, #STACK_BASE | 4370 | mov sp, #STACK_BASE |
4371 | bl SP_INIT | 4371 | bl SP_INIT |
4372 | mov r0, #10 | 4372 | mov r0, #10 |
4373 | bl DELAY9 | 4373 | bl DELAY9 |
4374 | bl GET_MAC_ADDR | 4374 | bl GET_MAC_ADDR |
4375 | bl GET_WHOLE_NVRAM | 4375 | bl GET_WHOLE_NVRAM |
4376 | ldr r0, =MRBASE | 4376 | ldr r0, =MRBASE |
4377 | ldr r1, =MAC_ADDRESS_MIB | 4377 | ldr r1, =MAC_ADDRESS_MIB |
4378 | strh r1, [r0, #MR2] | 4378 | strh r1, [r0, #MR2] |
4379 | ldr r1, =NVRAM_IMAGE | 4379 | ldr r1, =NVRAM_IMAGE |
4380 | strh r1, [r0, #MR4] | 4380 | strh r1, [r0, #MR4] |
4381 | mov r1, #MAC_BOOT_FLAG | 4381 | mov r1, #MAC_BOOT_FLAG |
4382 | strh r1, [r0, #MR3] | 4382 | strh r1, [r0, #MR3] |
4383 | HALT2: b HALT2 | 4383 | HALT2: b HALT2 |
4384 | .func Get_Whole_NVRAM, GET_WHOLE_NVRAM | 4384 | .func Get_Whole_NVRAM, GET_WHOLE_NVRAM |
4385 | GET_WHOLE_NVRAM: | 4385 | GET_WHOLE_NVRAM: |
4386 | stmdb sp!, {lr} | 4386 | stmdb sp!, {lr} |
4387 | mov r2, #0 /* 0th bytes of NVRAM */ | 4387 | mov r2, #0 /* 0th bytes of NVRAM */ |
4388 | mov r3, #NVRAM_LENGTH | 4388 | mov r3, #NVRAM_LENGTH |
4389 | mov r1, #0 /* not used in routine */ | 4389 | mov r1, #0 /* not used in routine */ |
4390 | ldr r0, =NVRAM_IMAGE | 4390 | ldr r0, =NVRAM_IMAGE |
4391 | bl NVRAM_XFER | 4391 | bl NVRAM_XFER |
4392 | ldmia sp!, {lr} | 4392 | ldmia sp!, {lr} |
4393 | bx lr | 4393 | bx lr |
4394 | .endfunc | 4394 | .endfunc |
4395 | 4395 | ||
4396 | .func Get_MAC_Addr, GET_MAC_ADDR | 4396 | .func Get_MAC_Addr, GET_MAC_ADDR |
4397 | GET_MAC_ADDR: | 4397 | GET_MAC_ADDR: |
4398 | stmdb sp!, {lr} | 4398 | stmdb sp!, {lr} |
4399 | mov r2, #0x120 /* address of MAC Address within NVRAM */ | 4399 | mov r2, #0x120 /* address of MAC Address within NVRAM */ |
4400 | mov r3, #MAC_ADDRESS_LENGTH | 4400 | mov r3, #MAC_ADDRESS_LENGTH |
4401 | mov r1, #0 /* not used in routine */ | 4401 | mov r1, #0 /* not used in routine */ |
4402 | ldr r0, =MAC_ADDRESS_MIB | 4402 | ldr r0, =MAC_ADDRESS_MIB |
4403 | bl NVRAM_XFER | 4403 | bl NVRAM_XFER |
4404 | ldmia sp!, {lr} | 4404 | ldmia sp!, {lr} |
4405 | bx lr | 4405 | bx lr |
4406 | .endfunc | 4406 | .endfunc |
4407 | .ltorg | 4407 | .ltorg |
4408 | .func Delay9, DELAY9 | 4408 | .func Delay9, DELAY9 |
4409 | DELAY9: | 4409 | DELAY9: |
4410 | adds r0, r0, r0, LSL #3 /* r0 = r0 * 9 */ | 4410 | adds r0, r0, r0, LSL #3 /* r0 = r0 * 9 */ |
4411 | DELAYLOOP: | 4411 | DELAYLOOP: |
4412 | beq DELAY9_done | 4412 | beq DELAY9_done |
4413 | subs r0, r0, #1 | 4413 | subs r0, r0, #1 |
4414 | b DELAYLOOP | 4414 | b DELAYLOOP |
4415 | DELAY9_done: | 4415 | DELAY9_done: |
4416 | bx lr | 4416 | bx lr |
4417 | .endfunc | 4417 | .endfunc |
4418 | 4418 | ||
4419 | .func SP_Init, SP_INIT | 4419 | .func SP_Init, SP_INIT |
4420 | SP_INIT: | 4420 | SP_INIT: |
4421 | mov r1, #SP_SWRST | 4421 | mov r1, #SP_SWRST |
4422 | ldr r0, =SP_BASE | 4422 | ldr r0, =SP_BASE |
4423 | str r1, [r0, #SP_CR] /* reset the SPI */ | 4423 | str r1, [r0, #SP_CR] /* reset the SPI */ |
4424 | mov r1, #0 | 4424 | mov r1, #0 |
4425 | str r1, [r0, #SP_CR] /* release SPI from reset state */ | 4425 | str r1, [r0, #SP_CR] /* release SPI from reset state */ |
4426 | mov r1, #SP_SPIEN | 4426 | mov r1, #SP_SPIEN |
4427 | str r1, [r0, #SP_MR] /* set the SPI to MASTER mode*/ | 4427 | str r1, [r0, #SP_MR] /* set the SPI to MASTER mode*/ |
4428 | str r1, [r0, #SP_CR] /* enable the SPI */ | 4428 | str r1, [r0, #SP_CR] /* enable the SPI */ |
4429 | 4429 | ||
4430 | /* My guess would be this turns on the SPI clock */ | 4430 | /* My guess would be this turns on the SPI clock */ |
4431 | ldr r3, =SPI_CGEN_BASE | 4431 | ldr r3, =SPI_CGEN_BASE |
4432 | ldr r1, [r3, #28] | 4432 | ldr r1, [r3, #28] |
4433 | orr r1, r1, #0x2000 | 4433 | orr r1, r1, #0x2000 |
4434 | str r1, [r3, #28] | 4434 | str r1, [r3, #28] |
4435 | 4435 | ||
4436 | ldr r1, =0x2000c01 | 4436 | ldr r1, =0x2000c01 |
4437 | str r1, [r0, #SP_CSR0] | 4437 | str r1, [r0, #SP_CSR0] |
4438 | ldr r1, =0x2000201 | 4438 | ldr r1, =0x2000201 |
4439 | str r1, [r0, #SP_CSR1] | 4439 | str r1, [r0, #SP_CSR1] |
4440 | str r1, [r0, #SP_CSR2] | 4440 | str r1, [r0, #SP_CSR2] |
4441 | str r1, [r0, #SP_CSR3] | 4441 | str r1, [r0, #SP_CSR3] |
4442 | ldr r1, [r0, #SP_SR] | 4442 | ldr r1, [r0, #SP_SR] |
4443 | ldr r0, [r0, #SP_RDR] | 4443 | ldr r0, [r0, #SP_RDR] |
4444 | bx lr | 4444 | bx lr |
4445 | .endfunc | 4445 | .endfunc |
4446 | .func NVRAM_Init, NVRAM_INIT | 4446 | .func NVRAM_Init, NVRAM_INIT |
4447 | NVRAM_INIT: | 4447 | NVRAM_INIT: |
4448 | ldr r1, =SP_BASE | 4448 | ldr r1, =SP_BASE |
4449 | ldr r0, [r1, #SP_RDR] | 4449 | ldr r0, [r1, #SP_RDR] |
4450 | mov r0, #NVRAM_CMD_RDSR | 4450 | mov r0, #NVRAM_CMD_RDSR |
4451 | str r0, [r1, #SP_TDR] | 4451 | str r0, [r1, #SP_TDR] |
4452 | SP_loop1: | 4452 | SP_loop1: |
4453 | ldr r0, [r1, #SP_SR] | 4453 | ldr r0, [r1, #SP_SR] |
4454 | tst r0, #SP_TDRE | 4454 | tst r0, #SP_TDRE |
4455 | beq SP_loop1 | 4455 | beq SP_loop1 |
4456 | 4456 | ||
4457 | mov r0, #SPI_8CLOCKS | 4457 | mov r0, #SPI_8CLOCKS |
4458 | str r0, [r1, #SP_TDR] | 4458 | str r0, [r1, #SP_TDR] |
4459 | SP_loop2: | 4459 | SP_loop2: |
4460 | ldr r0, [r1, #SP_SR] | 4460 | ldr r0, [r1, #SP_SR] |
4461 | tst r0, #SP_TDRE | 4461 | tst r0, #SP_TDRE |
4462 | beq SP_loop2 | 4462 | beq SP_loop2 |
4463 | 4463 | ||
4464 | ldr r0, [r1, #SP_RDR] | 4464 | ldr r0, [r1, #SP_RDR] |
4465 | SP_loop3: | 4465 | SP_loop3: |
4466 | ldr r0, [r1, #SP_SR] | 4466 | ldr r0, [r1, #SP_SR] |
4467 | tst r0, #SP_RDRF | 4467 | tst r0, #SP_RDRF |
4468 | beq SP_loop3 | 4468 | beq SP_loop3 |
4469 | 4469 | ||
4470 | ldr r0, [r1, #SP_RDR] | 4470 | ldr r0, [r1, #SP_RDR] |
4471 | and r0, r0, #255 | 4471 | and r0, r0, #255 |
4472 | bx lr | 4472 | bx lr |
4473 | .endfunc | 4473 | .endfunc |
4474 | 4474 | ||
4475 | .func NVRAM_Xfer, NVRAM_XFER | 4475 | .func NVRAM_Xfer, NVRAM_XFER |
4476 | /* r0 = dest address */ | 4476 | /* r0 = dest address */ |
4477 | /* r1 = not used */ | 4477 | /* r1 = not used */ |
4478 | /* r2 = src address within NVRAM */ | 4478 | /* r2 = src address within NVRAM */ |
4479 | /* r3 = length */ | 4479 | /* r3 = length */ |
4480 | NVRAM_XFER: | 4480 | NVRAM_XFER: |
4481 | stmdb sp!, {r4, r5, lr} | 4481 | stmdb sp!, {r4, r5, lr} |
4482 | mov r5, r0 /* save r0 (dest address) */ | 4482 | mov r5, r0 /* save r0 (dest address) */ |
4483 | mov r4, r3 /* save r3 (length) */ | 4483 | mov r4, r3 /* save r3 (length) */ |
4484 | mov r0, r2, LSR #5 /* SPI memories put A8 in the command field */ | 4484 | mov r0, r2, LSR #5 /* SPI memories put A8 in the command field */ |
4485 | and r0, r0, #8 | 4485 | and r0, r0, #8 |
4486 | add r0, r0, #NVRAM_CMD_READ | 4486 | add r0, r0, #NVRAM_CMD_READ |
4487 | ldr r1, =NVRAM_SCRATCH | 4487 | ldr r1, =NVRAM_SCRATCH |
4488 | strb r0, [r1, #0] /* save command in NVRAM_SCRATCH[0] */ | 4488 | strb r0, [r1, #0] /* save command in NVRAM_SCRATCH[0] */ |
4489 | strb r2, [r1, #1] /* save low byte of source address in NVRAM_SCRATCH[1] */ | 4489 | strb r2, [r1, #1] /* save low byte of source address in NVRAM_SCRATCH[1] */ |
4490 | _local1: | 4490 | _local1: |
4491 | bl NVRAM_INIT | 4491 | bl NVRAM_INIT |
4492 | tst r0, #NVRAM_SR_RDY | 4492 | tst r0, #NVRAM_SR_RDY |
4493 | bne _local1 | 4493 | bne _local1 |
4494 | mov r0, #20 | 4494 | mov r0, #20 |
4495 | bl DELAY9 | 4495 | bl DELAY9 |
4496 | mov r2, r4 /* length */ | 4496 | mov r2, r4 /* length */ |
4497 | mov r1, r5 /* dest address */ | 4497 | mov r1, r5 /* dest address */ |
4498 | mov r0, #2 /* bytes to transfer in command */ | 4498 | mov r0, #2 /* bytes to transfer in command */ |
4499 | bl NVRAM_XFER2 | 4499 | bl NVRAM_XFER2 |
4500 | ldmia sp!, {r4, r5, lr} | 4500 | ldmia sp!, {r4, r5, lr} |
4501 | bx lr | 4501 | bx lr |
4502 | .endfunc | 4502 | .endfunc |
4503 | 4503 | ||
4504 | .func NVRAM_Xfer2, NVRAM_XFER2 | 4504 | .func NVRAM_Xfer2, NVRAM_XFER2 |
4505 | NVRAM_XFER2: | 4505 | NVRAM_XFER2: |
4506 | stmdb sp!, {r4, r5, r6, lr} | 4506 | stmdb sp!, {r4, r5, r6, lr} |
4507 | ldr r4, =SP_BASE | 4507 | ldr r4, =SP_BASE |
4508 | mov r3, #0 | 4508 | mov r3, #0 |
4509 | cmp r0, #0 | 4509 | cmp r0, #0 |
4510 | bls _local2 | 4510 | bls _local2 |
4511 | ldr r5, =NVRAM_SCRATCH | 4511 | ldr r5, =NVRAM_SCRATCH |
4512 | _local4: | 4512 | _local4: |
4513 | ldrb r6, [r5, r3] | 4513 | ldrb r6, [r5, r3] |
4514 | str r6, [r4, #SP_TDR] | 4514 | str r6, [r4, #SP_TDR] |
4515 | _local3: | 4515 | _local3: |
4516 | ldr r6, [r4, #SP_SR] | 4516 | ldr r6, [r4, #SP_SR] |
4517 | tst r6, #SP_TDRE | 4517 | tst r6, #SP_TDRE |
4518 | beq _local3 | 4518 | beq _local3 |
4519 | add r3, r3, #1 | 4519 | add r3, r3, #1 |
4520 | cmp r3, r0 /* r0 is # of bytes to send out (command+addr) */ | 4520 | cmp r3, r0 /* r0 is # of bytes to send out (command+addr) */ |
4521 | blo _local4 | 4521 | blo _local4 |
4522 | _local2: | 4522 | _local2: |
4523 | mov r3, #SPI_8CLOCKS | 4523 | mov r3, #SPI_8CLOCKS |
4524 | str r3, [r4, #SP_TDR] | 4524 | str r3, [r4, #SP_TDR] |
4525 | ldr r0, [r4, #SP_RDR] | 4525 | ldr r0, [r4, #SP_RDR] |
4526 | _local5: | 4526 | _local5: |
4527 | ldr r0, [r4, #SP_SR] | 4527 | ldr r0, [r4, #SP_SR] |
4528 | tst r0, #SP_RDRF | 4528 | tst r0, #SP_RDRF |
4529 | beq _local5 | 4529 | beq _local5 |
4530 | ldr r0, [r4, #SP_RDR] /* what's this byte? It's the byte read while writing the TDR -- nonsense, because the NVRAM doesn't read and write at the same time */ | 4530 | ldr r0, [r4, #SP_RDR] /* what's this byte? It's the byte read while writing the TDR -- nonsense, because the NVRAM doesn't read and write at the same time */ |
4531 | mov r0, #0 | 4531 | mov r0, #0 |
4532 | cmp r2, #0 /* r2 is # of bytes to copy in */ | 4532 | cmp r2, #0 /* r2 is # of bytes to copy in */ |
4533 | bls _local6 | 4533 | bls _local6 |
4534 | _local7: | 4534 | _local7: |
4535 | ldr r5, [r4, #SP_SR] | 4535 | ldr r5, [r4, #SP_SR] |
4536 | tst r5, #SP_TDRE | 4536 | tst r5, #SP_TDRE |
4537 | beq _local7 | 4537 | beq _local7 |
4538 | str r3, [r4, #SP_TDR] /* r3 has SPI_8CLOCKS */ | 4538 | str r3, [r4, #SP_TDR] /* r3 has SPI_8CLOCKS */ |
4539 | _local8: | 4539 | _local8: |
4540 | ldr r5, [r4, #SP_SR] | 4540 | ldr r5, [r4, #SP_SR] |
4541 | tst r5, #SP_RDRF | 4541 | tst r5, #SP_RDRF |
4542 | beq _local8 | 4542 | beq _local8 |
4543 | ldr r5, [r4, #SP_RDR] /* but didn't we read this byte above? */ | 4543 | ldr r5, [r4, #SP_RDR] /* but didn't we read this byte above? */ |
4544 | strb r5, [r1], #1 /* postindexed */ | 4544 | strb r5, [r1], #1 /* postindexed */ |
4545 | add r0, r0, #1 | 4545 | add r0, r0, #1 |
4546 | cmp r0, r2 | 4546 | cmp r0, r2 |
4547 | blo _local7 /* since we don't send another address, the NVRAM must be capable of sequential reads */ | 4547 | blo _local7 /* since we don't send another address, the NVRAM must be capable of sequential reads */ |
4548 | _local6: | 4548 | _local6: |
4549 | mov r0, #200 | 4549 | mov r0, #200 |
4550 | bl DELAY9 | 4550 | bl DELAY9 |
4551 | ldmia sp!, {r4, r5, r6, lr} | 4551 | ldmia sp!, {r4, r5, r6, lr} |
4552 | bx lr | 4552 | bx lr |
4553 | #endif | 4553 | #endif |
4554 | 4554 |
drivers/usb/host/xhci.h
1 | /* | 1 | /* |
2 | * xHCI host controller driver | 2 | * xHCI host controller driver |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Intel Corp. | 4 | * Copyright (C) 2008 Intel Corp. |
5 | * | 5 | * |
6 | * Author: Sarah Sharp | 6 | * Author: Sarah Sharp |
7 | * Some code borrowed from the Linux EHCI driver. | 7 | * Some code borrowed from the Linux EHCI driver. |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, but | 13 | * This program is distributed in the hope that it will be useful, but |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | 15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
16 | * for more details. | 16 | * for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to the Free Software Foundation, | 19 | * along with this program; if not, write to the Free Software Foundation, |
20 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 20 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #ifndef __LINUX_XHCI_HCD_H | 23 | #ifndef __LINUX_XHCI_HCD_H |
24 | #define __LINUX_XHCI_HCD_H | 24 | #define __LINUX_XHCI_HCD_H |
25 | 25 | ||
26 | #include <linux/usb.h> | 26 | #include <linux/usb.h> |
27 | #include <linux/timer.h> | 27 | #include <linux/timer.h> |
28 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
29 | 29 | ||
30 | #include "../core/hcd.h" | 30 | #include "../core/hcd.h" |
31 | /* Code sharing between pci-quirks and xhci hcd */ | 31 | /* Code sharing between pci-quirks and xhci hcd */ |
32 | #include "xhci-ext-caps.h" | 32 | #include "xhci-ext-caps.h" |
33 | 33 | ||
34 | /* xHCI PCI Configuration Registers */ | 34 | /* xHCI PCI Configuration Registers */ |
35 | #define XHCI_SBRN_OFFSET (0x60) | 35 | #define XHCI_SBRN_OFFSET (0x60) |
36 | 36 | ||
37 | /* Max number of USB devices for any host controller - limit in section 6.1 */ | 37 | /* Max number of USB devices for any host controller - limit in section 6.1 */ |
38 | #define MAX_HC_SLOTS 256 | 38 | #define MAX_HC_SLOTS 256 |
39 | /* Section 5.3.3 - MaxPorts */ | 39 | /* Section 5.3.3 - MaxPorts */ |
40 | #define MAX_HC_PORTS 127 | 40 | #define MAX_HC_PORTS 127 |
41 | 41 | ||
42 | /* | 42 | /* |
43 | * xHCI register interface. | 43 | * xHCI register interface. |
44 | * This corresponds to the eXtensible Host Controller Interface (xHCI) | 44 | * This corresponds to the eXtensible Host Controller Interface (xHCI) |
45 | * Revision 0.95 specification | 45 | * Revision 0.95 specification |
46 | */ | 46 | */ |
47 | 47 | ||
48 | /** | 48 | /** |
49 | * struct xhci_cap_regs - xHCI Host Controller Capability Registers. | 49 | * struct xhci_cap_regs - xHCI Host Controller Capability Registers. |
50 | * @hc_capbase: length of the capabilities register and HC version number | 50 | * @hc_capbase: length of the capabilities register and HC version number |
51 | * @hcs_params1: HCSPARAMS1 - Structural Parameters 1 | 51 | * @hcs_params1: HCSPARAMS1 - Structural Parameters 1 |
52 | * @hcs_params2: HCSPARAMS2 - Structural Parameters 2 | 52 | * @hcs_params2: HCSPARAMS2 - Structural Parameters 2 |
53 | * @hcs_params3: HCSPARAMS3 - Structural Parameters 3 | 53 | * @hcs_params3: HCSPARAMS3 - Structural Parameters 3 |
54 | * @hcc_params: HCCPARAMS - Capability Parameters | 54 | * @hcc_params: HCCPARAMS - Capability Parameters |
55 | * @db_off: DBOFF - Doorbell array offset | 55 | * @db_off: DBOFF - Doorbell array offset |
56 | * @run_regs_off: RTSOFF - Runtime register space offset | 56 | * @run_regs_off: RTSOFF - Runtime register space offset |
57 | */ | 57 | */ |
58 | struct xhci_cap_regs { | 58 | struct xhci_cap_regs { |
59 | u32 hc_capbase; | 59 | u32 hc_capbase; |
60 | u32 hcs_params1; | 60 | u32 hcs_params1; |
61 | u32 hcs_params2; | 61 | u32 hcs_params2; |
62 | u32 hcs_params3; | 62 | u32 hcs_params3; |
63 | u32 hcc_params; | 63 | u32 hcc_params; |
64 | u32 db_off; | 64 | u32 db_off; |
65 | u32 run_regs_off; | 65 | u32 run_regs_off; |
66 | /* Reserved up to (CAPLENGTH - 0x1C) */ | 66 | /* Reserved up to (CAPLENGTH - 0x1C) */ |
67 | }; | 67 | }; |
68 | 68 | ||
69 | /* hc_capbase bitmasks */ | 69 | /* hc_capbase bitmasks */ |
70 | /* bits 7:0 - how long is the Capabilities register */ | 70 | /* bits 7:0 - how long is the Capabilities register */ |
71 | #define HC_LENGTH(p) XHCI_HC_LENGTH(p) | 71 | #define HC_LENGTH(p) XHCI_HC_LENGTH(p) |
72 | /* bits 31:16 */ | 72 | /* bits 31:16 */ |
73 | #define HC_VERSION(p) (((p) >> 16) & 0xffff) | 73 | #define HC_VERSION(p) (((p) >> 16) & 0xffff) |
74 | 74 | ||
75 | /* HCSPARAMS1 - hcs_params1 - bitmasks */ | 75 | /* HCSPARAMS1 - hcs_params1 - bitmasks */ |
76 | /* bits 0:7, Max Device Slots */ | 76 | /* bits 0:7, Max Device Slots */ |
77 | #define HCS_MAX_SLOTS(p) (((p) >> 0) & 0xff) | 77 | #define HCS_MAX_SLOTS(p) (((p) >> 0) & 0xff) |
78 | #define HCS_SLOTS_MASK 0xff | 78 | #define HCS_SLOTS_MASK 0xff |
79 | /* bits 8:18, Max Interrupters */ | 79 | /* bits 8:18, Max Interrupters */ |
80 | #define HCS_MAX_INTRS(p) (((p) >> 8) & 0x7ff) | 80 | #define HCS_MAX_INTRS(p) (((p) >> 8) & 0x7ff) |
81 | /* bits 24:31, Max Ports - max value is 0x7F = 127 ports */ | 81 | /* bits 24:31, Max Ports - max value is 0x7F = 127 ports */ |
82 | #define HCS_MAX_PORTS(p) (((p) >> 24) & 0x7f) | 82 | #define HCS_MAX_PORTS(p) (((p) >> 24) & 0x7f) |
83 | 83 | ||
84 | /* HCSPARAMS2 - hcs_params2 - bitmasks */ | 84 | /* HCSPARAMS2 - hcs_params2 - bitmasks */ |
85 | /* bits 0:3, frames or uframes that SW needs to queue transactions | 85 | /* bits 0:3, frames or uframes that SW needs to queue transactions |
86 | * ahead of the HW to meet periodic deadlines */ | 86 | * ahead of the HW to meet periodic deadlines */ |
87 | #define HCS_IST(p) (((p) >> 0) & 0xf) | 87 | #define HCS_IST(p) (((p) >> 0) & 0xf) |
88 | /* bits 4:7, max number of Event Ring segments */ | 88 | /* bits 4:7, max number of Event Ring segments */ |
89 | #define HCS_ERST_MAX(p) (((p) >> 4) & 0xf) | 89 | #define HCS_ERST_MAX(p) (((p) >> 4) & 0xf) |
90 | /* bit 26 Scratchpad restore - for save/restore HW state - not used yet */ | 90 | /* bit 26 Scratchpad restore - for save/restore HW state - not used yet */ |
91 | /* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */ | 91 | /* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */ |
92 | #define HCS_MAX_SCRATCHPAD(p) (((p) >> 27) & 0x1f) | 92 | #define HCS_MAX_SCRATCHPAD(p) (((p) >> 27) & 0x1f) |
93 | 93 | ||
94 | /* HCSPARAMS3 - hcs_params3 - bitmasks */ | 94 | /* HCSPARAMS3 - hcs_params3 - bitmasks */ |
95 | /* bits 0:7, Max U1 to U0 latency for the roothub ports */ | 95 | /* bits 0:7, Max U1 to U0 latency for the roothub ports */ |
96 | #define HCS_U1_LATENCY(p) (((p) >> 0) & 0xff) | 96 | #define HCS_U1_LATENCY(p) (((p) >> 0) & 0xff) |
97 | /* bits 16:31, Max U2 to U0 latency for the roothub ports */ | 97 | /* bits 16:31, Max U2 to U0 latency for the roothub ports */ |
98 | #define HCS_U2_LATENCY(p) (((p) >> 16) & 0xffff) | 98 | #define HCS_U2_LATENCY(p) (((p) >> 16) & 0xffff) |
99 | 99 | ||
100 | /* HCCPARAMS - hcc_params - bitmasks */ | 100 | /* HCCPARAMS - hcc_params - bitmasks */ |
101 | /* true: HC can use 64-bit address pointers */ | 101 | /* true: HC can use 64-bit address pointers */ |
102 | #define HCC_64BIT_ADDR(p) ((p) & (1 << 0)) | 102 | #define HCC_64BIT_ADDR(p) ((p) & (1 << 0)) |
103 | /* true: HC can do bandwidth negotiation */ | 103 | /* true: HC can do bandwidth negotiation */ |
104 | #define HCC_BANDWIDTH_NEG(p) ((p) & (1 << 1)) | 104 | #define HCC_BANDWIDTH_NEG(p) ((p) & (1 << 1)) |
105 | /* true: HC uses 64-byte Device Context structures | 105 | /* true: HC uses 64-byte Device Context structures |
106 | * FIXME 64-byte context structures aren't supported yet. | 106 | * FIXME 64-byte context structures aren't supported yet. |
107 | */ | 107 | */ |
108 | #define HCC_64BYTE_CONTEXT(p) ((p) & (1 << 2)) | 108 | #define HCC_64BYTE_CONTEXT(p) ((p) & (1 << 2)) |
109 | /* true: HC has port power switches */ | 109 | /* true: HC has port power switches */ |
110 | #define HCC_PPC(p) ((p) & (1 << 3)) | 110 | #define HCC_PPC(p) ((p) & (1 << 3)) |
111 | /* true: HC has port indicators */ | 111 | /* true: HC has port indicators */ |
112 | #define HCS_INDICATOR(p) ((p) & (1 << 4)) | 112 | #define HCS_INDICATOR(p) ((p) & (1 << 4)) |
113 | /* true: HC has Light HC Reset Capability */ | 113 | /* true: HC has Light HC Reset Capability */ |
114 | #define HCC_LIGHT_RESET(p) ((p) & (1 << 5)) | 114 | #define HCC_LIGHT_RESET(p) ((p) & (1 << 5)) |
115 | /* true: HC supports latency tolerance messaging */ | 115 | /* true: HC supports latency tolerance messaging */ |
116 | #define HCC_LTC(p) ((p) & (1 << 6)) | 116 | #define HCC_LTC(p) ((p) & (1 << 6)) |
117 | /* true: no secondary Stream ID Support */ | 117 | /* true: no secondary Stream ID Support */ |
118 | #define HCC_NSS(p) ((p) & (1 << 7)) | 118 | #define HCC_NSS(p) ((p) & (1 << 7)) |
119 | /* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */ | 119 | /* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */ |
120 | #define HCC_MAX_PSA (1 << ((((p) >> 12) & 0xf) + 1)) | 120 | #define HCC_MAX_PSA (1 << ((((p) >> 12) & 0xf) + 1)) |
121 | /* Extended Capabilities pointer from PCI base - section 5.3.6 */ | 121 | /* Extended Capabilities pointer from PCI base - section 5.3.6 */ |
122 | #define HCC_EXT_CAPS(p) XHCI_HCC_EXT_CAPS(p) | 122 | #define HCC_EXT_CAPS(p) XHCI_HCC_EXT_CAPS(p) |
123 | 123 | ||
124 | /* db_off bitmask - bits 0:1 reserved */ | 124 | /* db_off bitmask - bits 0:1 reserved */ |
125 | #define DBOFF_MASK (~0x3) | 125 | #define DBOFF_MASK (~0x3) |
126 | 126 | ||
127 | /* run_regs_off bitmask - bits 0:4 reserved */ | 127 | /* run_regs_off bitmask - bits 0:4 reserved */ |
128 | #define RTSOFF_MASK (~0x1f) | 128 | #define RTSOFF_MASK (~0x1f) |
129 | 129 | ||
130 | 130 | ||
131 | /* Number of registers per port */ | 131 | /* Number of registers per port */ |
132 | #define NUM_PORT_REGS 4 | 132 | #define NUM_PORT_REGS 4 |
133 | 133 | ||
134 | /** | 134 | /** |
135 | * struct xhci_op_regs - xHCI Host Controller Operational Registers. | 135 | * struct xhci_op_regs - xHCI Host Controller Operational Registers. |
136 | * @command: USBCMD - xHC command register | 136 | * @command: USBCMD - xHC command register |
137 | * @status: USBSTS - xHC status register | 137 | * @status: USBSTS - xHC status register |
138 | * @page_size: This indicates the page size that the host controller | 138 | * @page_size: This indicates the page size that the host controller |
139 | * supports. If bit n is set, the HC supports a page size | 139 | * supports. If bit n is set, the HC supports a page size |
140 | * of 2^(n+12), up to a 128MB page size. | 140 | * of 2^(n+12), up to a 128MB page size. |
141 | * 4K is the minimum page size. | 141 | * 4K is the minimum page size. |
142 | * @cmd_ring: CRP - 64-bit Command Ring Pointer | 142 | * @cmd_ring: CRP - 64-bit Command Ring Pointer |
143 | * @dcbaa_ptr: DCBAAP - 64-bit Device Context Base Address Array Pointer | 143 | * @dcbaa_ptr: DCBAAP - 64-bit Device Context Base Address Array Pointer |
144 | * @config_reg: CONFIG - Configure Register | 144 | * @config_reg: CONFIG - Configure Register |
145 | * @port_status_base: PORTSCn - base address for Port Status and Control | 145 | * @port_status_base: PORTSCn - base address for Port Status and Control |
146 | * Each port has a Port Status and Control register, | 146 | * Each port has a Port Status and Control register, |
147 | * followed by a Port Power Management Status and Control | 147 | * followed by a Port Power Management Status and Control |
148 | * register, a Port Link Info register, and a reserved | 148 | * register, a Port Link Info register, and a reserved |
149 | * register. | 149 | * register. |
150 | * @port_power_base: PORTPMSCn - base address for | 150 | * @port_power_base: PORTPMSCn - base address for |
151 | * Port Power Management Status and Control | 151 | * Port Power Management Status and Control |
152 | * @port_link_base: PORTLIn - base address for Port Link Info (current | 152 | * @port_link_base: PORTLIn - base address for Port Link Info (current |
153 | * Link PM state and control) for USB 2.1 and USB 3.0 | 153 | * Link PM state and control) for USB 2.1 and USB 3.0 |
154 | * devices. | 154 | * devices. |
155 | */ | 155 | */ |
156 | struct xhci_op_regs { | 156 | struct xhci_op_regs { |
157 | u32 command; | 157 | u32 command; |
158 | u32 status; | 158 | u32 status; |
159 | u32 page_size; | 159 | u32 page_size; |
160 | u32 reserved1; | 160 | u32 reserved1; |
161 | u32 reserved2; | 161 | u32 reserved2; |
162 | u32 dev_notification; | 162 | u32 dev_notification; |
163 | u64 cmd_ring; | 163 | u64 cmd_ring; |
164 | /* rsvd: offset 0x20-2F */ | 164 | /* rsvd: offset 0x20-2F */ |
165 | u32 reserved3[4]; | 165 | u32 reserved3[4]; |
166 | u64 dcbaa_ptr; | 166 | u64 dcbaa_ptr; |
167 | u32 config_reg; | 167 | u32 config_reg; |
168 | /* rsvd: offset 0x3C-3FF */ | 168 | /* rsvd: offset 0x3C-3FF */ |
169 | u32 reserved4[241]; | 169 | u32 reserved4[241]; |
170 | /* port 1 registers, which serve as a base address for other ports */ | 170 | /* port 1 registers, which serve as a base address for other ports */ |
171 | u32 port_status_base; | 171 | u32 port_status_base; |
172 | u32 port_power_base; | 172 | u32 port_power_base; |
173 | u32 port_link_base; | 173 | u32 port_link_base; |
174 | u32 reserved5; | 174 | u32 reserved5; |
175 | /* registers for ports 2-255 */ | 175 | /* registers for ports 2-255 */ |
176 | u32 reserved6[NUM_PORT_REGS*254]; | 176 | u32 reserved6[NUM_PORT_REGS*254]; |
177 | }; | 177 | }; |
178 | 178 | ||
179 | /* USBCMD - USB command - command bitmasks */ | 179 | /* USBCMD - USB command - command bitmasks */ |
180 | /* start/stop HC execution - do not write unless HC is halted*/ | 180 | /* start/stop HC execution - do not write unless HC is halted*/ |
181 | #define CMD_RUN XHCI_CMD_RUN | 181 | #define CMD_RUN XHCI_CMD_RUN |
182 | /* Reset HC - resets internal HC state machine and all registers (except | 182 | /* Reset HC - resets internal HC state machine and all registers (except |
183 | * PCI config regs). HC does NOT drive a USB reset on the downstream ports. | 183 | * PCI config regs). HC does NOT drive a USB reset on the downstream ports. |
184 | * The xHCI driver must reinitialize the xHC after setting this bit. | 184 | * The xHCI driver must reinitialize the xHC after setting this bit. |
185 | */ | 185 | */ |
186 | #define CMD_RESET (1 << 1) | 186 | #define CMD_RESET (1 << 1) |
187 | /* Event Interrupt Enable - a '1' allows interrupts from the host controller */ | 187 | /* Event Interrupt Enable - a '1' allows interrupts from the host controller */ |
188 | #define CMD_EIE XHCI_CMD_EIE | 188 | #define CMD_EIE XHCI_CMD_EIE |
189 | /* Host System Error Interrupt Enable - get out-of-band signal for HC errors */ | 189 | /* Host System Error Interrupt Enable - get out-of-band signal for HC errors */ |
190 | #define CMD_HSEIE XHCI_CMD_HSEIE | 190 | #define CMD_HSEIE XHCI_CMD_HSEIE |
191 | /* bits 4:6 are reserved (and should be preserved on writes). */ | 191 | /* bits 4:6 are reserved (and should be preserved on writes). */ |
192 | /* light reset (port status stays unchanged) - reset completed when this is 0 */ | 192 | /* light reset (port status stays unchanged) - reset completed when this is 0 */ |
193 | #define CMD_LRESET (1 << 7) | 193 | #define CMD_LRESET (1 << 7) |
194 | /* FIXME: ignoring host controller save/restore state for now. */ | 194 | /* FIXME: ignoring host controller save/restore state for now. */ |
195 | #define CMD_CSS (1 << 8) | 195 | #define CMD_CSS (1 << 8) |
196 | #define CMD_CRS (1 << 9) | 196 | #define CMD_CRS (1 << 9) |
197 | /* Enable Wrap Event - '1' means xHC generates an event when MFINDEX wraps. */ | 197 | /* Enable Wrap Event - '1' means xHC generates an event when MFINDEX wraps. */ |
198 | #define CMD_EWE XHCI_CMD_EWE | 198 | #define CMD_EWE XHCI_CMD_EWE |
199 | /* MFINDEX power management - '1' means xHC can stop MFINDEX counter if all root | 199 | /* MFINDEX power management - '1' means xHC can stop MFINDEX counter if all root |
200 | * hubs are in U3 (selective suspend), disconnect, disabled, or powered-off. | 200 | * hubs are in U3 (selective suspend), disconnect, disabled, or powered-off. |
201 | * '0' means the xHC can power it off if all ports are in the disconnect, | 201 | * '0' means the xHC can power it off if all ports are in the disconnect, |
202 | * disabled, or powered-off state. | 202 | * disabled, or powered-off state. |
203 | */ | 203 | */ |
204 | #define CMD_PM_INDEX (1 << 11) | 204 | #define CMD_PM_INDEX (1 << 11) |
205 | /* bits 12:31 are reserved (and should be preserved on writes). */ | 205 | /* bits 12:31 are reserved (and should be preserved on writes). */ |
206 | 206 | ||
207 | /* USBSTS - USB status - status bitmasks */ | 207 | /* USBSTS - USB status - status bitmasks */ |
208 | /* HC not running - set to 1 when run/stop bit is cleared. */ | 208 | /* HC not running - set to 1 when run/stop bit is cleared. */ |
209 | #define STS_HALT XHCI_STS_HALT | 209 | #define STS_HALT XHCI_STS_HALT |
210 | /* serious error, e.g. PCI parity error. The HC will clear the run/stop bit. */ | 210 | /* serious error, e.g. PCI parity error. The HC will clear the run/stop bit. */ |
211 | #define STS_FATAL (1 << 2) | 211 | #define STS_FATAL (1 << 2) |
212 | /* event interrupt - clear this prior to clearing any IP flags in IR set*/ | 212 | /* event interrupt - clear this prior to clearing any IP flags in IR set*/ |
213 | #define STS_EINT (1 << 3) | 213 | #define STS_EINT (1 << 3) |
214 | /* port change detect */ | 214 | /* port change detect */ |
215 | #define STS_PORT (1 << 4) | 215 | #define STS_PORT (1 << 4) |
216 | /* bits 5:7 reserved and zeroed */ | 216 | /* bits 5:7 reserved and zeroed */ |
217 | /* save state status - '1' means xHC is saving state */ | 217 | /* save state status - '1' means xHC is saving state */ |
218 | #define STS_SAVE (1 << 8) | 218 | #define STS_SAVE (1 << 8) |
219 | /* restore state status - '1' means xHC is restoring state */ | 219 | /* restore state status - '1' means xHC is restoring state */ |
220 | #define STS_RESTORE (1 << 9) | 220 | #define STS_RESTORE (1 << 9) |
221 | /* true: save or restore error */ | 221 | /* true: save or restore error */ |
222 | #define STS_SRE (1 << 10) | 222 | #define STS_SRE (1 << 10) |
223 | /* true: Controller Not Ready to accept doorbell or op reg writes after reset */ | 223 | /* true: Controller Not Ready to accept doorbell or op reg writes after reset */ |
224 | #define STS_CNR XHCI_STS_CNR | 224 | #define STS_CNR XHCI_STS_CNR |
225 | /* true: internal Host Controller Error - SW needs to reset and reinitialize */ | 225 | /* true: internal Host Controller Error - SW needs to reset and reinitialize */ |
226 | #define STS_HCE (1 << 12) | 226 | #define STS_HCE (1 << 12) |
227 | /* bits 13:31 reserved and should be preserved */ | 227 | /* bits 13:31 reserved and should be preserved */ |
228 | 228 | ||
229 | /* | 229 | /* |
230 | * DNCTRL - Device Notification Control Register - dev_notification bitmasks | 230 | * DNCTRL - Device Notification Control Register - dev_notification bitmasks |
231 | * Generate a device notification event when the HC sees a transaction with a | 231 | * Generate a device notification event when the HC sees a transaction with a |
232 | * notification type that matches a bit set in this bit field. | 232 | * notification type that matches a bit set in this bit field. |
233 | */ | 233 | */ |
234 | #define DEV_NOTE_MASK (0xffff) | 234 | #define DEV_NOTE_MASK (0xffff) |
235 | #define ENABLE_DEV_NOTE(x) (1 << x) | 235 | #define ENABLE_DEV_NOTE(x) (1 << x) |
236 | /* Most of the device notification types should only be used for debug. | 236 | /* Most of the device notification types should only be used for debug. |
237 | * SW does need to pay attention to function wake notifications. | 237 | * SW does need to pay attention to function wake notifications. |
238 | */ | 238 | */ |
239 | #define DEV_NOTE_FWAKE ENABLE_DEV_NOTE(1) | 239 | #define DEV_NOTE_FWAKE ENABLE_DEV_NOTE(1) |
240 | 240 | ||
241 | /* CRCR - Command Ring Control Register - cmd_ring bitmasks */ | 241 | /* CRCR - Command Ring Control Register - cmd_ring bitmasks */ |
242 | /* bit 0 is the command ring cycle state */ | 242 | /* bit 0 is the command ring cycle state */ |
243 | /* stop ring operation after completion of the currently executing command */ | 243 | /* stop ring operation after completion of the currently executing command */ |
244 | #define CMD_RING_PAUSE (1 << 1) | 244 | #define CMD_RING_PAUSE (1 << 1) |
245 | /* stop ring immediately - abort the currently executing command */ | 245 | /* stop ring immediately - abort the currently executing command */ |
246 | #define CMD_RING_ABORT (1 << 2) | 246 | #define CMD_RING_ABORT (1 << 2) |
247 | /* true: command ring is running */ | 247 | /* true: command ring is running */ |
248 | #define CMD_RING_RUNNING (1 << 3) | 248 | #define CMD_RING_RUNNING (1 << 3) |
249 | /* bits 4:5 reserved and should be preserved */ | 249 | /* bits 4:5 reserved and should be preserved */ |
250 | /* Command Ring pointer - bit mask for the lower 32 bits. */ | 250 | /* Command Ring pointer - bit mask for the lower 32 bits. */ |
251 | #define CMD_RING_RSVD_BITS (0x3f) | 251 | #define CMD_RING_RSVD_BITS (0x3f) |
252 | 252 | ||
253 | /* CONFIG - Configure Register - config_reg bitmasks */ | 253 | /* CONFIG - Configure Register - config_reg bitmasks */ |
254 | /* bits 0:7 - maximum number of device slots enabled (NumSlotsEn) */ | 254 | /* bits 0:7 - maximum number of device slots enabled (NumSlotsEn) */ |
255 | #define MAX_DEVS(p) ((p) & 0xff) | 255 | #define MAX_DEVS(p) ((p) & 0xff) |
256 | /* bits 8:31 - reserved and should be preserved */ | 256 | /* bits 8:31 - reserved and should be preserved */ |
257 | 257 | ||
258 | /* PORTSC - Port Status and Control Register - port_status_base bitmasks */ | 258 | /* PORTSC - Port Status and Control Register - port_status_base bitmasks */ |
259 | /* true: device connected */ | 259 | /* true: device connected */ |
260 | #define PORT_CONNECT (1 << 0) | 260 | #define PORT_CONNECT (1 << 0) |
261 | /* true: port enabled */ | 261 | /* true: port enabled */ |
262 | #define PORT_PE (1 << 1) | 262 | #define PORT_PE (1 << 1) |
263 | /* bit 2 reserved and zeroed */ | 263 | /* bit 2 reserved and zeroed */ |
264 | /* true: port has an over-current condition */ | 264 | /* true: port has an over-current condition */ |
265 | #define PORT_OC (1 << 3) | 265 | #define PORT_OC (1 << 3) |
266 | /* true: port reset signaling asserted */ | 266 | /* true: port reset signaling asserted */ |
267 | #define PORT_RESET (1 << 4) | 267 | #define PORT_RESET (1 << 4) |
268 | /* Port Link State - bits 5:8 | 268 | /* Port Link State - bits 5:8 |
269 | * A read gives the current link PM state of the port, | 269 | * A read gives the current link PM state of the port, |
270 | * a write with Link State Write Strobe set sets the link state. | 270 | * a write with Link State Write Strobe set sets the link state. |
271 | */ | 271 | */ |
272 | /* true: port has power (see HCC_PPC) */ | 272 | /* true: port has power (see HCC_PPC) */ |
273 | #define PORT_POWER (1 << 9) | 273 | #define PORT_POWER (1 << 9) |
274 | /* bits 10:13 indicate device speed: | 274 | /* bits 10:13 indicate device speed: |
275 | * 0 - undefined speed - port hasn't be initialized by a reset yet | 275 | * 0 - undefined speed - port hasn't be initialized by a reset yet |
276 | * 1 - full speed | 276 | * 1 - full speed |
277 | * 2 - low speed | 277 | * 2 - low speed |
278 | * 3 - high speed | 278 | * 3 - high speed |
279 | * 4 - super speed | 279 | * 4 - super speed |
280 | * 5-15 reserved | 280 | * 5-15 reserved |
281 | */ | 281 | */ |
282 | #define DEV_SPEED_MASK (0xf << 10) | 282 | #define DEV_SPEED_MASK (0xf << 10) |
283 | #define XDEV_FS (0x1 << 10) | 283 | #define XDEV_FS (0x1 << 10) |
284 | #define XDEV_LS (0x2 << 10) | 284 | #define XDEV_LS (0x2 << 10) |
285 | #define XDEV_HS (0x3 << 10) | 285 | #define XDEV_HS (0x3 << 10) |
286 | #define XDEV_SS (0x4 << 10) | 286 | #define XDEV_SS (0x4 << 10) |
287 | #define DEV_UNDEFSPEED(p) (((p) & DEV_SPEED_MASK) == (0x0<<10)) | 287 | #define DEV_UNDEFSPEED(p) (((p) & DEV_SPEED_MASK) == (0x0<<10)) |
288 | #define DEV_FULLSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_FS) | 288 | #define DEV_FULLSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_FS) |
289 | #define DEV_LOWSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_LS) | 289 | #define DEV_LOWSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_LS) |
290 | #define DEV_HIGHSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_HS) | 290 | #define DEV_HIGHSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_HS) |
291 | #define DEV_SUPERSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_SS) | 291 | #define DEV_SUPERSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_SS) |
292 | /* Bits 20:23 in the Slot Context are the speed for the device */ | 292 | /* Bits 20:23 in the Slot Context are the speed for the device */ |
293 | #define SLOT_SPEED_FS (XDEV_FS << 10) | 293 | #define SLOT_SPEED_FS (XDEV_FS << 10) |
294 | #define SLOT_SPEED_LS (XDEV_LS << 10) | 294 | #define SLOT_SPEED_LS (XDEV_LS << 10) |
295 | #define SLOT_SPEED_HS (XDEV_HS << 10) | 295 | #define SLOT_SPEED_HS (XDEV_HS << 10) |
296 | #define SLOT_SPEED_SS (XDEV_SS << 10) | 296 | #define SLOT_SPEED_SS (XDEV_SS << 10) |
297 | /* Port Indicator Control */ | 297 | /* Port Indicator Control */ |
298 | #define PORT_LED_OFF (0 << 14) | 298 | #define PORT_LED_OFF (0 << 14) |
299 | #define PORT_LED_AMBER (1 << 14) | 299 | #define PORT_LED_AMBER (1 << 14) |
300 | #define PORT_LED_GREEN (2 << 14) | 300 | #define PORT_LED_GREEN (2 << 14) |
301 | #define PORT_LED_MASK (3 << 14) | 301 | #define PORT_LED_MASK (3 << 14) |
302 | /* Port Link State Write Strobe - set this when changing link state */ | 302 | /* Port Link State Write Strobe - set this when changing link state */ |
303 | #define PORT_LINK_STROBE (1 << 16) | 303 | #define PORT_LINK_STROBE (1 << 16) |
304 | /* true: connect status change */ | 304 | /* true: connect status change */ |
305 | #define PORT_CSC (1 << 17) | 305 | #define PORT_CSC (1 << 17) |
306 | /* true: port enable change */ | 306 | /* true: port enable change */ |
307 | #define PORT_PEC (1 << 18) | 307 | #define PORT_PEC (1 << 18) |
308 | /* true: warm reset for a USB 3.0 device is done. A "hot" reset puts the port | 308 | /* true: warm reset for a USB 3.0 device is done. A "hot" reset puts the port |
309 | * into an enabled state, and the device into the default state. A "warm" reset | 309 | * into an enabled state, and the device into the default state. A "warm" reset |
310 | * also resets the link, forcing the device through the link training sequence. | 310 | * also resets the link, forcing the device through the link training sequence. |
311 | * SW can also look at the Port Reset register to see when warm reset is done. | 311 | * SW can also look at the Port Reset register to see when warm reset is done. |
312 | */ | 312 | */ |
313 | #define PORT_WRC (1 << 19) | 313 | #define PORT_WRC (1 << 19) |
314 | /* true: over-current change */ | 314 | /* true: over-current change */ |
315 | #define PORT_OCC (1 << 20) | 315 | #define PORT_OCC (1 << 20) |
316 | /* true: reset change - 1 to 0 transition of PORT_RESET */ | 316 | /* true: reset change - 1 to 0 transition of PORT_RESET */ |
317 | #define PORT_RC (1 << 21) | 317 | #define PORT_RC (1 << 21) |
318 | /* port link status change - set on some port link state transitions: | 318 | /* port link status change - set on some port link state transitions: |
319 | * Transition Reason | 319 | * Transition Reason |
320 | * ------------------------------------------------------------------------------ | 320 | * ------------------------------------------------------------------------------ |
321 | * - U3 to Resume Wakeup signaling from a device | 321 | * - U3 to Resume Wakeup signaling from a device |
322 | * - Resume to Recovery to U0 USB 3.0 device resume | 322 | * - Resume to Recovery to U0 USB 3.0 device resume |
323 | * - Resume to U0 USB 2.0 device resume | 323 | * - Resume to U0 USB 2.0 device resume |
324 | * - U3 to Recovery to U0 Software resume of USB 3.0 device complete | 324 | * - U3 to Recovery to U0 Software resume of USB 3.0 device complete |
325 | * - U3 to U0 Software resume of USB 2.0 device complete | 325 | * - U3 to U0 Software resume of USB 2.0 device complete |
326 | * - U2 to U0 L1 resume of USB 2.1 device complete | 326 | * - U2 to U0 L1 resume of USB 2.1 device complete |
327 | * - U0 to U0 (???) L1 entry rejection by USB 2.1 device | 327 | * - U0 to U0 (???) L1 entry rejection by USB 2.1 device |
328 | * - U0 to disabled L1 entry error with USB 2.1 device | 328 | * - U0 to disabled L1 entry error with USB 2.1 device |
329 | * - Any state to inactive Error on USB 3.0 port | 329 | * - Any state to inactive Error on USB 3.0 port |
330 | */ | 330 | */ |
331 | #define PORT_PLC (1 << 22) | 331 | #define PORT_PLC (1 << 22) |
332 | /* port configure error change - port failed to configure its link partner */ | 332 | /* port configure error change - port failed to configure its link partner */ |
333 | #define PORT_CEC (1 << 23) | 333 | #define PORT_CEC (1 << 23) |
334 | /* bit 24 reserved */ | 334 | /* bit 24 reserved */ |
335 | /* wake on connect (enable) */ | 335 | /* wake on connect (enable) */ |
336 | #define PORT_WKCONN_E (1 << 25) | 336 | #define PORT_WKCONN_E (1 << 25) |
337 | /* wake on disconnect (enable) */ | 337 | /* wake on disconnect (enable) */ |
338 | #define PORT_WKDISC_E (1 << 26) | 338 | #define PORT_WKDISC_E (1 << 26) |
339 | /* wake on over-current (enable) */ | 339 | /* wake on over-current (enable) */ |
340 | #define PORT_WKOC_E (1 << 27) | 340 | #define PORT_WKOC_E (1 << 27) |
341 | /* bits 28:29 reserved */ | 341 | /* bits 28:29 reserved */ |
342 | /* true: device is removable - for USB 3.0 roothub emulation */ | 342 | /* true: device is removable - for USB 3.0 roothub emulation */ |
343 | #define PORT_DEV_REMOVE (1 << 30) | 343 | #define PORT_DEV_REMOVE (1 << 30) |
344 | /* Initiate a warm port reset - complete when PORT_WRC is '1' */ | 344 | /* Initiate a warm port reset - complete when PORT_WRC is '1' */ |
345 | #define PORT_WR (1 << 31) | 345 | #define PORT_WR (1 << 31) |
346 | 346 | ||
347 | /* Port Power Management Status and Control - port_power_base bitmasks */ | 347 | /* Port Power Management Status and Control - port_power_base bitmasks */ |
348 | /* Inactivity timer value for transitions into U1, in microseconds. | 348 | /* Inactivity timer value for transitions into U1, in microseconds. |
349 | * Timeout can be up to 127us. 0xFF means an infinite timeout. | 349 | * Timeout can be up to 127us. 0xFF means an infinite timeout. |
350 | */ | 350 | */ |
351 | #define PORT_U1_TIMEOUT(p) ((p) & 0xff) | 351 | #define PORT_U1_TIMEOUT(p) ((p) & 0xff) |
352 | /* Inactivity timer value for transitions into U2 */ | 352 | /* Inactivity timer value for transitions into U2 */ |
353 | #define PORT_U2_TIMEOUT(p) (((p) & 0xff) << 8) | 353 | #define PORT_U2_TIMEOUT(p) (((p) & 0xff) << 8) |
354 | /* Bits 24:31 for port testing */ | 354 | /* Bits 24:31 for port testing */ |
355 | 355 | ||
356 | 356 | ||
357 | /** | 357 | /** |
358 | * struct xhci_intr_reg - Interrupt Register Set | 358 | * struct xhci_intr_reg - Interrupt Register Set |
359 | * @irq_pending: IMAN - Interrupt Management Register. Used to enable | 359 | * @irq_pending: IMAN - Interrupt Management Register. Used to enable |
360 | * interrupts and check for pending interrupts. | 360 | * interrupts and check for pending interrupts. |
361 | * @irq_control: IMOD - Interrupt Moderation Register. | 361 | * @irq_control: IMOD - Interrupt Moderation Register. |
362 | * Used to throttle interrupts. | 362 | * Used to throttle interrupts. |
363 | * @erst_size: Number of segments in the Event Ring Segment Table (ERST). | 363 | * @erst_size: Number of segments in the Event Ring Segment Table (ERST). |
364 | * @erst_base: ERST base address. | 364 | * @erst_base: ERST base address. |
365 | * @erst_dequeue: Event ring dequeue pointer. | 365 | * @erst_dequeue: Event ring dequeue pointer. |
366 | * | 366 | * |
367 | * Each interrupter (defined by a MSI-X vector) has an event ring and an Event | 367 | * Each interrupter (defined by a MSI-X vector) has an event ring and an Event |
368 | * Ring Segment Table (ERST) associated with it. The event ring is comprised of | 368 | * Ring Segment Table (ERST) associated with it. The event ring is comprised of |
369 | * multiple segments of the same size. The HC places events on the ring and | 369 | * multiple segments of the same size. The HC places events on the ring and |
370 | * "updates the Cycle bit in the TRBs to indicate to software the current | 370 | * "updates the Cycle bit in the TRBs to indicate to software the current |
371 | * position of the Enqueue Pointer." The HCD (Linux) processes those events and | 371 | * position of the Enqueue Pointer." The HCD (Linux) processes those events and |
372 | * updates the dequeue pointer. | 372 | * updates the dequeue pointer. |
373 | */ | 373 | */ |
374 | struct xhci_intr_reg { | 374 | struct xhci_intr_reg { |
375 | u32 irq_pending; | 375 | u32 irq_pending; |
376 | u32 irq_control; | 376 | u32 irq_control; |
377 | u32 erst_size; | 377 | u32 erst_size; |
378 | u32 rsvd; | 378 | u32 rsvd; |
379 | u64 erst_base; | 379 | u64 erst_base; |
380 | u64 erst_dequeue; | 380 | u64 erst_dequeue; |
381 | }; | 381 | }; |
382 | 382 | ||
383 | /* irq_pending bitmasks */ | 383 | /* irq_pending bitmasks */ |
384 | #define ER_IRQ_PENDING(p) ((p) & 0x1) | 384 | #define ER_IRQ_PENDING(p) ((p) & 0x1) |
385 | /* bits 2:31 need to be preserved */ | 385 | /* bits 2:31 need to be preserved */ |
386 | /* THIS IS BUGGY - FIXME - IP IS WRITE 1 TO CLEAR */ | 386 | /* THIS IS BUGGY - FIXME - IP IS WRITE 1 TO CLEAR */ |
387 | #define ER_IRQ_CLEAR(p) ((p) & 0xfffffffe) | 387 | #define ER_IRQ_CLEAR(p) ((p) & 0xfffffffe) |
388 | #define ER_IRQ_ENABLE(p) ((ER_IRQ_CLEAR(p)) | 0x2) | 388 | #define ER_IRQ_ENABLE(p) ((ER_IRQ_CLEAR(p)) | 0x2) |
389 | #define ER_IRQ_DISABLE(p) ((ER_IRQ_CLEAR(p)) & ~(0x2)) | 389 | #define ER_IRQ_DISABLE(p) ((ER_IRQ_CLEAR(p)) & ~(0x2)) |
390 | 390 | ||
391 | /* irq_control bitmasks */ | 391 | /* irq_control bitmasks */ |
392 | /* Minimum interval between interrupts (in 250ns intervals). The interval | 392 | /* Minimum interval between interrupts (in 250ns intervals). The interval |
393 | * between interrupts will be longer if there are no events on the event ring. | 393 | * between interrupts will be longer if there are no events on the event ring. |
394 | * Default is 4000 (1 ms). | 394 | * Default is 4000 (1 ms). |
395 | */ | 395 | */ |
396 | #define ER_IRQ_INTERVAL_MASK (0xffff) | 396 | #define ER_IRQ_INTERVAL_MASK (0xffff) |
397 | /* Counter used to count down the time to the next interrupt - HW use only */ | 397 | /* Counter used to count down the time to the next interrupt - HW use only */ |
398 | #define ER_IRQ_COUNTER_MASK (0xffff << 16) | 398 | #define ER_IRQ_COUNTER_MASK (0xffff << 16) |
399 | 399 | ||
400 | /* erst_size bitmasks */ | 400 | /* erst_size bitmasks */ |
401 | /* Preserve bits 16:31 of erst_size */ | 401 | /* Preserve bits 16:31 of erst_size */ |
402 | #define ERST_SIZE_MASK (0xffff << 16) | 402 | #define ERST_SIZE_MASK (0xffff << 16) |
403 | 403 | ||
404 | /* erst_dequeue bitmasks */ | 404 | /* erst_dequeue bitmasks */ |
405 | /* Dequeue ERST Segment Index (DESI) - Segment number (or alias) | 405 | /* Dequeue ERST Segment Index (DESI) - Segment number (or alias) |
406 | * where the current dequeue pointer lies. This is an optional HW hint. | 406 | * where the current dequeue pointer lies. This is an optional HW hint. |
407 | */ | 407 | */ |
408 | #define ERST_DESI_MASK (0x7) | 408 | #define ERST_DESI_MASK (0x7) |
409 | /* Event Handler Busy (EHB) - is the event ring scheduled to be serviced by | 409 | /* Event Handler Busy (EHB) - is the event ring scheduled to be serviced by |
410 | * a work queue (or delayed service routine)? | 410 | * a work queue (or delayed service routine)? |
411 | */ | 411 | */ |
412 | #define ERST_EHB (1 << 3) | 412 | #define ERST_EHB (1 << 3) |
413 | #define ERST_PTR_MASK (0xf) | 413 | #define ERST_PTR_MASK (0xf) |
414 | 414 | ||
415 | /** | 415 | /** |
416 | * struct xhci_run_regs | 416 | * struct xhci_run_regs |
417 | * @microframe_index: | 417 | * @microframe_index: |
418 | * MFINDEX - current microframe number | 418 | * MFINDEX - current microframe number |
419 | * | 419 | * |
420 | * Section 5.5 Host Controller Runtime Registers: | 420 | * Section 5.5 Host Controller Runtime Registers: |
421 | * "Software should read and write these registers using only Dword (32 bit) | 421 | * "Software should read and write these registers using only Dword (32 bit) |
422 | * or larger accesses" | 422 | * or larger accesses" |
423 | */ | 423 | */ |
424 | struct xhci_run_regs { | 424 | struct xhci_run_regs { |
425 | u32 microframe_index; | 425 | u32 microframe_index; |
426 | u32 rsvd[7]; | 426 | u32 rsvd[7]; |
427 | struct xhci_intr_reg ir_set[128]; | 427 | struct xhci_intr_reg ir_set[128]; |
428 | }; | 428 | }; |
429 | 429 | ||
430 | /** | 430 | /** |
431 | * struct doorbell_array | 431 | * struct doorbell_array |
432 | * | 432 | * |
433 | * Section 5.6 | 433 | * Section 5.6 |
434 | */ | 434 | */ |
435 | struct xhci_doorbell_array { | 435 | struct xhci_doorbell_array { |
436 | u32 doorbell[256]; | 436 | u32 doorbell[256]; |
437 | }; | 437 | }; |
438 | 438 | ||
439 | #define DB_TARGET_MASK 0xFFFFFF00 | 439 | #define DB_TARGET_MASK 0xFFFFFF00 |
440 | #define DB_STREAM_ID_MASK 0x0000FFFF | 440 | #define DB_STREAM_ID_MASK 0x0000FFFF |
441 | #define DB_TARGET_HOST 0x0 | 441 | #define DB_TARGET_HOST 0x0 |
442 | #define DB_STREAM_ID_HOST 0x0 | 442 | #define DB_STREAM_ID_HOST 0x0 |
443 | #define DB_MASK (0xff << 8) | 443 | #define DB_MASK (0xff << 8) |
444 | 444 | ||
445 | /* Endpoint Target - bits 0:7 */ | 445 | /* Endpoint Target - bits 0:7 */ |
446 | #define EPI_TO_DB(p) (((p) + 1) & 0xff) | 446 | #define EPI_TO_DB(p) (((p) + 1) & 0xff) |
447 | 447 | ||
448 | 448 | ||
449 | /** | 449 | /** |
450 | * struct xhci_container_ctx | 450 | * struct xhci_container_ctx |
451 | * @type: Type of context. Used to calculated offsets to contained contexts. | 451 | * @type: Type of context. Used to calculated offsets to contained contexts. |
452 | * @size: Size of the context data | 452 | * @size: Size of the context data |
453 | * @bytes: The raw context data given to HW | 453 | * @bytes: The raw context data given to HW |
454 | * @dma: dma address of the bytes | 454 | * @dma: dma address of the bytes |
455 | * | 455 | * |
456 | * Represents either a Device or Input context. Holds a pointer to the raw | 456 | * Represents either a Device or Input context. Holds a pointer to the raw |
457 | * memory used for the context (bytes) and dma address of it (dma). | 457 | * memory used for the context (bytes) and dma address of it (dma). |
458 | */ | 458 | */ |
459 | struct xhci_container_ctx { | 459 | struct xhci_container_ctx { |
460 | unsigned type; | 460 | unsigned type; |
461 | #define XHCI_CTX_TYPE_DEVICE 0x1 | 461 | #define XHCI_CTX_TYPE_DEVICE 0x1 |
462 | #define XHCI_CTX_TYPE_INPUT 0x2 | 462 | #define XHCI_CTX_TYPE_INPUT 0x2 |
463 | 463 | ||
464 | int size; | 464 | int size; |
465 | 465 | ||
466 | u8 *bytes; | 466 | u8 *bytes; |
467 | dma_addr_t dma; | 467 | dma_addr_t dma; |
468 | }; | 468 | }; |
469 | 469 | ||
470 | /** | 470 | /** |
471 | * struct xhci_slot_ctx | 471 | * struct xhci_slot_ctx |
472 | * @dev_info: Route string, device speed, hub info, and last valid endpoint | 472 | * @dev_info: Route string, device speed, hub info, and last valid endpoint |
473 | * @dev_info2: Max exit latency for device number, root hub port number | 473 | * @dev_info2: Max exit latency for device number, root hub port number |
474 | * @tt_info: tt_info is used to construct split transaction tokens | 474 | * @tt_info: tt_info is used to construct split transaction tokens |
475 | * @dev_state: slot state and device address | 475 | * @dev_state: slot state and device address |
476 | * | 476 | * |
477 | * Slot Context - section 6.2.1.1. This assumes the HC uses 32-byte context | 477 | * Slot Context - section 6.2.1.1. This assumes the HC uses 32-byte context |
478 | * structures. If the HC uses 64-byte contexts, there is an additional 32 bytes | 478 | * structures. If the HC uses 64-byte contexts, there is an additional 32 bytes |
479 | * reserved at the end of the slot context for HC internal use. | 479 | * reserved at the end of the slot context for HC internal use. |
480 | */ | 480 | */ |
481 | struct xhci_slot_ctx { | 481 | struct xhci_slot_ctx { |
482 | u32 dev_info; | 482 | u32 dev_info; |
483 | u32 dev_info2; | 483 | u32 dev_info2; |
484 | u32 tt_info; | 484 | u32 tt_info; |
485 | u32 dev_state; | 485 | u32 dev_state; |
486 | /* offset 0x10 to 0x1f reserved for HC internal use */ | 486 | /* offset 0x10 to 0x1f reserved for HC internal use */ |
487 | u32 reserved[4]; | 487 | u32 reserved[4]; |
488 | }; | 488 | }; |
489 | 489 | ||
490 | /* dev_info bitmasks */ | 490 | /* dev_info bitmasks */ |
491 | /* Route String - 0:19 */ | 491 | /* Route String - 0:19 */ |
492 | #define ROUTE_STRING_MASK (0xfffff) | 492 | #define ROUTE_STRING_MASK (0xfffff) |
493 | /* Device speed - values defined by PORTSC Device Speed field - 20:23 */ | 493 | /* Device speed - values defined by PORTSC Device Speed field - 20:23 */ |
494 | #define DEV_SPEED (0xf << 20) | 494 | #define DEV_SPEED (0xf << 20) |
495 | /* bit 24 reserved */ | 495 | /* bit 24 reserved */ |
496 | /* Is this LS/FS device connected through a HS hub? - bit 25 */ | 496 | /* Is this LS/FS device connected through a HS hub? - bit 25 */ |
497 | #define DEV_MTT (0x1 << 25) | 497 | #define DEV_MTT (0x1 << 25) |
498 | /* Set if the device is a hub - bit 26 */ | 498 | /* Set if the device is a hub - bit 26 */ |
499 | #define DEV_HUB (0x1 << 26) | 499 | #define DEV_HUB (0x1 << 26) |
500 | /* Index of the last valid endpoint context in this device context - 27:31 */ | 500 | /* Index of the last valid endpoint context in this device context - 27:31 */ |
501 | #define LAST_CTX_MASK (0x1f << 27) | 501 | #define LAST_CTX_MASK (0x1f << 27) |
502 | #define LAST_CTX(p) ((p) << 27) | 502 | #define LAST_CTX(p) ((p) << 27) |
503 | #define LAST_CTX_TO_EP_NUM(p) (((p) >> 27) - 1) | 503 | #define LAST_CTX_TO_EP_NUM(p) (((p) >> 27) - 1) |
504 | #define SLOT_FLAG (1 << 0) | 504 | #define SLOT_FLAG (1 << 0) |
505 | #define EP0_FLAG (1 << 1) | 505 | #define EP0_FLAG (1 << 1) |
506 | 506 | ||
507 | /* dev_info2 bitmasks */ | 507 | /* dev_info2 bitmasks */ |
508 | /* Max Exit Latency (ms) - worst case time to wake up all links in dev path */ | 508 | /* Max Exit Latency (ms) - worst case time to wake up all links in dev path */ |
509 | #define MAX_EXIT (0xffff) | 509 | #define MAX_EXIT (0xffff) |
510 | /* Root hub port number that is needed to access the USB device */ | 510 | /* Root hub port number that is needed to access the USB device */ |
511 | #define ROOT_HUB_PORT(p) (((p) & 0xff) << 16) | 511 | #define ROOT_HUB_PORT(p) (((p) & 0xff) << 16) |
512 | 512 | ||
513 | /* tt_info bitmasks */ | 513 | /* tt_info bitmasks */ |
514 | /* | 514 | /* |
515 | * TT Hub Slot ID - for low or full speed devices attached to a high-speed hub | 515 | * TT Hub Slot ID - for low or full speed devices attached to a high-speed hub |
516 | * The Slot ID of the hub that isolates the high speed signaling from | 516 | * The Slot ID of the hub that isolates the high speed signaling from |
517 | * this low or full-speed device. '0' if attached to root hub port. | 517 | * this low or full-speed device. '0' if attached to root hub port. |
518 | */ | 518 | */ |
519 | #define TT_SLOT (0xff) | 519 | #define TT_SLOT (0xff) |
520 | /* | 520 | /* |
521 | * The number of the downstream facing port of the high-speed hub | 521 | * The number of the downstream facing port of the high-speed hub |
522 | * '0' if the device is not low or full speed. | 522 | * '0' if the device is not low or full speed. |
523 | */ | 523 | */ |
524 | #define TT_PORT (0xff << 8) | 524 | #define TT_PORT (0xff << 8) |
525 | 525 | ||
526 | /* dev_state bitmasks */ | 526 | /* dev_state bitmasks */ |
527 | /* USB device address - assigned by the HC */ | 527 | /* USB device address - assigned by the HC */ |
528 | #define DEV_ADDR_MASK (0xff) | 528 | #define DEV_ADDR_MASK (0xff) |
529 | /* bits 8:26 reserved */ | 529 | /* bits 8:26 reserved */ |
530 | /* Slot state */ | 530 | /* Slot state */ |
531 | #define SLOT_STATE (0x1f << 27) | 531 | #define SLOT_STATE (0x1f << 27) |
532 | #define GET_SLOT_STATE(p) (((p) & (0x1f << 27)) >> 27) | 532 | #define GET_SLOT_STATE(p) (((p) & (0x1f << 27)) >> 27) |
533 | 533 | ||
534 | 534 | ||
535 | /** | 535 | /** |
536 | * struct xhci_ep_ctx | 536 | * struct xhci_ep_ctx |
537 | * @ep_info: endpoint state, streams, mult, and interval information. | 537 | * @ep_info: endpoint state, streams, mult, and interval information. |
538 | * @ep_info2: information on endpoint type, max packet size, max burst size, | 538 | * @ep_info2: information on endpoint type, max packet size, max burst size, |
539 | * error count, and whether the HC will force an event for all | 539 | * error count, and whether the HC will force an event for all |
540 | * transactions. | 540 | * transactions. |
541 | * @deq: 64-bit ring dequeue pointer address. If the endpoint only | 541 | * @deq: 64-bit ring dequeue pointer address. If the endpoint only |
542 | * defines one stream, this points to the endpoint transfer ring. | 542 | * defines one stream, this points to the endpoint transfer ring. |
543 | * Otherwise, it points to a stream context array, which has a | 543 | * Otherwise, it points to a stream context array, which has a |
544 | * ring pointer for each flow. | 544 | * ring pointer for each flow. |
545 | * @tx_info: | 545 | * @tx_info: |
546 | * Average TRB lengths for the endpoint ring and | 546 | * Average TRB lengths for the endpoint ring and |
547 | * max payload within an Endpoint Service Interval Time (ESIT). | 547 | * max payload within an Endpoint Service Interval Time (ESIT). |
548 | * | 548 | * |
549 | * Endpoint Context - section 6.2.1.2. This assumes the HC uses 32-byte context | 549 | * Endpoint Context - section 6.2.1.2. This assumes the HC uses 32-byte context |
550 | * structures. If the HC uses 64-byte contexts, there is an additional 32 bytes | 550 | * structures. If the HC uses 64-byte contexts, there is an additional 32 bytes |
551 | * reserved at the end of the endpoint context for HC internal use. | 551 | * reserved at the end of the endpoint context for HC internal use. |
552 | */ | 552 | */ |
553 | struct xhci_ep_ctx { | 553 | struct xhci_ep_ctx { |
554 | u32 ep_info; | 554 | u32 ep_info; |
555 | u32 ep_info2; | 555 | u32 ep_info2; |
556 | u64 deq; | 556 | u64 deq; |
557 | u32 tx_info; | 557 | u32 tx_info; |
558 | /* offset 0x14 - 0x1f reserved for HC internal use */ | 558 | /* offset 0x14 - 0x1f reserved for HC internal use */ |
559 | u32 reserved[3]; | 559 | u32 reserved[3]; |
560 | }; | 560 | }; |
561 | 561 | ||
562 | /* ep_info bitmasks */ | 562 | /* ep_info bitmasks */ |
563 | /* | 563 | /* |
564 | * Endpoint State - bits 0:2 | 564 | * Endpoint State - bits 0:2 |
565 | * 0 - disabled | 565 | * 0 - disabled |
566 | * 1 - running | 566 | * 1 - running |
567 | * 2 - halted due to halt condition - ok to manipulate endpoint ring | 567 | * 2 - halted due to halt condition - ok to manipulate endpoint ring |
568 | * 3 - stopped | 568 | * 3 - stopped |
569 | * 4 - TRB error | 569 | * 4 - TRB error |
570 | * 5-7 - reserved | 570 | * 5-7 - reserved |
571 | */ | 571 | */ |
572 | #define EP_STATE_MASK (0xf) | 572 | #define EP_STATE_MASK (0xf) |
573 | #define EP_STATE_DISABLED 0 | 573 | #define EP_STATE_DISABLED 0 |
574 | #define EP_STATE_RUNNING 1 | 574 | #define EP_STATE_RUNNING 1 |
575 | #define EP_STATE_HALTED 2 | 575 | #define EP_STATE_HALTED 2 |
576 | #define EP_STATE_STOPPED 3 | 576 | #define EP_STATE_STOPPED 3 |
577 | #define EP_STATE_ERROR 4 | 577 | #define EP_STATE_ERROR 4 |
578 | /* Mult - Max number of burtst within an interval, in EP companion desc. */ | 578 | /* Mult - Max number of burtst within an interval, in EP companion desc. */ |
579 | #define EP_MULT(p) ((p & 0x3) << 8) | 579 | #define EP_MULT(p) ((p & 0x3) << 8) |
580 | /* bits 10:14 are Max Primary Streams */ | 580 | /* bits 10:14 are Max Primary Streams */ |
581 | /* bit 15 is Linear Stream Array */ | 581 | /* bit 15 is Linear Stream Array */ |
582 | /* Interval - period between requests to an endpoint - 125u increments. */ | 582 | /* Interval - period between requests to an endpoint - 125u increments. */ |
583 | #define EP_INTERVAL(p) ((p & 0xff) << 16) | 583 | #define EP_INTERVAL(p) ((p & 0xff) << 16) |
584 | 584 | ||
585 | /* ep_info2 bitmasks */ | 585 | /* ep_info2 bitmasks */ |
586 | /* | 586 | /* |
587 | * Force Event - generate transfer events for all TRBs for this endpoint | 587 | * Force Event - generate transfer events for all TRBs for this endpoint |
588 | * This will tell the HC to ignore the IOC and ISP flags (for debugging only). | 588 | * This will tell the HC to ignore the IOC and ISP flags (for debugging only). |
589 | */ | 589 | */ |
590 | #define FORCE_EVENT (0x1) | 590 | #define FORCE_EVENT (0x1) |
591 | #define ERROR_COUNT(p) (((p) & 0x3) << 1) | 591 | #define ERROR_COUNT(p) (((p) & 0x3) << 1) |
592 | #define EP_TYPE(p) ((p) << 3) | 592 | #define EP_TYPE(p) ((p) << 3) |
593 | #define ISOC_OUT_EP 1 | 593 | #define ISOC_OUT_EP 1 |
594 | #define BULK_OUT_EP 2 | 594 | #define BULK_OUT_EP 2 |
595 | #define INT_OUT_EP 3 | 595 | #define INT_OUT_EP 3 |
596 | #define CTRL_EP 4 | 596 | #define CTRL_EP 4 |
597 | #define ISOC_IN_EP 5 | 597 | #define ISOC_IN_EP 5 |
598 | #define BULK_IN_EP 6 | 598 | #define BULK_IN_EP 6 |
599 | #define INT_IN_EP 7 | 599 | #define INT_IN_EP 7 |
600 | /* bit 6 reserved */ | 600 | /* bit 6 reserved */ |
601 | /* bit 7 is Host Initiate Disable - for disabling stream selection */ | 601 | /* bit 7 is Host Initiate Disable - for disabling stream selection */ |
602 | #define MAX_BURST(p) (((p)&0xff) << 8) | 602 | #define MAX_BURST(p) (((p)&0xff) << 8) |
603 | #define MAX_PACKET(p) (((p)&0xffff) << 16) | 603 | #define MAX_PACKET(p) (((p)&0xffff) << 16) |
604 | 604 | ||
605 | 605 | ||
606 | /** | 606 | /** |
607 | * struct xhci_input_control_context | 607 | * struct xhci_input_control_context |
608 | * Input control context; see section 6.2.5. | 608 | * Input control context; see section 6.2.5. |
609 | * | 609 | * |
610 | * @drop_context: set the bit of the endpoint context you want to disable | 610 | * @drop_context: set the bit of the endpoint context you want to disable |
611 | * @add_context: set the bit of the endpoint context you want to enable | 611 | * @add_context: set the bit of the endpoint context you want to enable |
612 | */ | 612 | */ |
613 | struct xhci_input_control_ctx { | 613 | struct xhci_input_control_ctx { |
614 | u32 drop_flags; | 614 | u32 drop_flags; |
615 | u32 add_flags; | 615 | u32 add_flags; |
616 | u32 rsvd2[6]; | 616 | u32 rsvd2[6]; |
617 | }; | 617 | }; |
618 | 618 | ||
619 | /* drop context bitmasks */ | 619 | /* drop context bitmasks */ |
620 | #define DROP_EP(x) (0x1 << x) | 620 | #define DROP_EP(x) (0x1 << x) |
621 | /* add context bitmasks */ | 621 | /* add context bitmasks */ |
622 | #define ADD_EP(x) (0x1 << x) | 622 | #define ADD_EP(x) (0x1 << x) |
623 | 623 | ||
624 | struct xhci_virt_device { | 624 | struct xhci_virt_device { |
625 | /* | 625 | /* |
626 | * Commands to the hardware are passed an "input context" that | 626 | * Commands to the hardware are passed an "input context" that |
627 | * tells the hardware what to change in its data structures. | 627 | * tells the hardware what to change in its data structures. |
628 | * The hardware will return changes in an "output context" that | 628 | * The hardware will return changes in an "output context" that |
629 | * software must allocate for the hardware. We need to keep | 629 | * software must allocate for the hardware. We need to keep |
630 | * track of input and output contexts separately because | 630 | * track of input and output contexts separately because |
631 | * these commands might fail and we don't trust the hardware. | 631 | * these commands might fail and we don't trust the hardware. |
632 | */ | 632 | */ |
633 | struct xhci_container_ctx *out_ctx; | 633 | struct xhci_container_ctx *out_ctx; |
634 | /* Used for addressing devices and configuration changes */ | 634 | /* Used for addressing devices and configuration changes */ |
635 | struct xhci_container_ctx *in_ctx; | 635 | struct xhci_container_ctx *in_ctx; |
636 | 636 | ||
637 | /* FIXME when stream support is added */ | 637 | /* FIXME when stream support is added */ |
638 | struct xhci_ring *ep_rings[31]; | 638 | struct xhci_ring *ep_rings[31]; |
639 | /* Temporary storage in case the configure endpoint command fails and we | 639 | /* Temporary storage in case the configure endpoint command fails and we |
640 | * have to restore the device state to the previous state | 640 | * have to restore the device state to the previous state |
641 | */ | 641 | */ |
642 | struct xhci_ring *new_ep_rings[31]; | 642 | struct xhci_ring *new_ep_rings[31]; |
643 | struct completion cmd_completion; | 643 | struct completion cmd_completion; |
644 | /* Status of the last command issued for this device */ | 644 | /* Status of the last command issued for this device */ |
645 | u32 cmd_status; | 645 | u32 cmd_status; |
646 | }; | 646 | }; |
647 | 647 | ||
648 | 648 | ||
649 | /** | 649 | /** |
650 | * struct xhci_device_context_array | 650 | * struct xhci_device_context_array |
651 | * @dev_context_ptr array of 64-bit DMA addresses for device contexts | 651 | * @dev_context_ptr array of 64-bit DMA addresses for device contexts |
652 | */ | 652 | */ |
653 | struct xhci_device_context_array { | 653 | struct xhci_device_context_array { |
654 | /* 64-bit device addresses; we only write 32-bit addresses */ | 654 | /* 64-bit device addresses; we only write 32-bit addresses */ |
655 | u64 dev_context_ptrs[MAX_HC_SLOTS]; | 655 | u64 dev_context_ptrs[MAX_HC_SLOTS]; |
656 | /* private xHCD pointers */ | 656 | /* private xHCD pointers */ |
657 | dma_addr_t dma; | 657 | dma_addr_t dma; |
658 | }; | 658 | }; |
659 | /* TODO: write function to set the 64-bit device DMA address */ | 659 | /* TODO: write function to set the 64-bit device DMA address */ |
660 | /* | 660 | /* |
661 | * TODO: change this to be dynamically sized at HC mem init time since the HC | 661 | * TODO: change this to be dynamically sized at HC mem init time since the HC |
662 | * might not be able to handle the maximum number of devices possible. | 662 | * might not be able to handle the maximum number of devices possible. |
663 | */ | 663 | */ |
664 | 664 | ||
665 | 665 | ||
666 | struct xhci_stream_ctx { | 666 | struct xhci_stream_ctx { |
667 | /* 64-bit stream ring address, cycle state, and stream type */ | 667 | /* 64-bit stream ring address, cycle state, and stream type */ |
668 | u64 stream_ring; | 668 | u64 stream_ring; |
669 | /* offset 0x14 - 0x1f reserved for HC internal use */ | 669 | /* offset 0x14 - 0x1f reserved for HC internal use */ |
670 | u32 reserved[2]; | 670 | u32 reserved[2]; |
671 | }; | 671 | }; |
672 | 672 | ||
673 | 673 | ||
674 | struct xhci_transfer_event { | 674 | struct xhci_transfer_event { |
675 | /* 64-bit buffer address, or immediate data */ | 675 | /* 64-bit buffer address, or immediate data */ |
676 | u64 buffer; | 676 | u64 buffer; |
677 | u32 transfer_len; | 677 | u32 transfer_len; |
678 | /* This field is interpreted differently based on the type of TRB */ | 678 | /* This field is interpreted differently based on the type of TRB */ |
679 | u32 flags; | 679 | u32 flags; |
680 | }; | 680 | }; |
681 | 681 | ||
682 | /** Transfer Event bit fields **/ | 682 | /** Transfer Event bit fields **/ |
683 | #define TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f) | 683 | #define TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f) |
684 | 684 | ||
685 | /* Completion Code - only applicable for some types of TRBs */ | 685 | /* Completion Code - only applicable for some types of TRBs */ |
686 | #define COMP_CODE_MASK (0xff << 24) | 686 | #define COMP_CODE_MASK (0xff << 24) |
687 | #define GET_COMP_CODE(p) (((p) & COMP_CODE_MASK) >> 24) | 687 | #define GET_COMP_CODE(p) (((p) & COMP_CODE_MASK) >> 24) |
688 | #define COMP_SUCCESS 1 | 688 | #define COMP_SUCCESS 1 |
689 | /* Data Buffer Error */ | 689 | /* Data Buffer Error */ |
690 | #define COMP_DB_ERR 2 | 690 | #define COMP_DB_ERR 2 |
691 | /* Babble Detected Error */ | 691 | /* Babble Detected Error */ |
692 | #define COMP_BABBLE 3 | 692 | #define COMP_BABBLE 3 |
693 | /* USB Transaction Error */ | 693 | /* USB Transaction Error */ |
694 | #define COMP_TX_ERR 4 | 694 | #define COMP_TX_ERR 4 |
695 | /* TRB Error - some TRB field is invalid */ | 695 | /* TRB Error - some TRB field is invalid */ |
696 | #define COMP_TRB_ERR 5 | 696 | #define COMP_TRB_ERR 5 |
697 | /* Stall Error - USB device is stalled */ | 697 | /* Stall Error - USB device is stalled */ |
698 | #define COMP_STALL 6 | 698 | #define COMP_STALL 6 |
699 | /* Resource Error - HC doesn't have memory for that device configuration */ | 699 | /* Resource Error - HC doesn't have memory for that device configuration */ |
700 | #define COMP_ENOMEM 7 | 700 | #define COMP_ENOMEM 7 |
701 | /* Bandwidth Error - not enough room in schedule for this dev config */ | 701 | /* Bandwidth Error - not enough room in schedule for this dev config */ |
702 | #define COMP_BW_ERR 8 | 702 | #define COMP_BW_ERR 8 |
703 | /* No Slots Available Error - HC ran out of device slots */ | 703 | /* No Slots Available Error - HC ran out of device slots */ |
704 | #define COMP_ENOSLOTS 9 | 704 | #define COMP_ENOSLOTS 9 |
705 | /* Invalid Stream Type Error */ | 705 | /* Invalid Stream Type Error */ |
706 | #define COMP_STREAM_ERR 10 | 706 | #define COMP_STREAM_ERR 10 |
707 | /* Slot Not Enabled Error - doorbell rung for disabled device slot */ | 707 | /* Slot Not Enabled Error - doorbell rung for disabled device slot */ |
708 | #define COMP_EBADSLT 11 | 708 | #define COMP_EBADSLT 11 |
709 | /* Endpoint Not Enabled Error */ | 709 | /* Endpoint Not Enabled Error */ |
710 | #define COMP_EBADEP 12 | 710 | #define COMP_EBADEP 12 |
711 | /* Short Packet */ | 711 | /* Short Packet */ |
712 | #define COMP_SHORT_TX 13 | 712 | #define COMP_SHORT_TX 13 |
713 | /* Ring Underrun - doorbell rung for an empty isoc OUT ep ring */ | 713 | /* Ring Underrun - doorbell rung for an empty isoc OUT ep ring */ |
714 | #define COMP_UNDERRUN 14 | 714 | #define COMP_UNDERRUN 14 |
715 | /* Ring Overrun - isoc IN ep ring is empty when ep is scheduled to RX */ | 715 | /* Ring Overrun - isoc IN ep ring is empty when ep is scheduled to RX */ |
716 | #define COMP_OVERRUN 15 | 716 | #define COMP_OVERRUN 15 |
717 | /* Virtual Function Event Ring Full Error */ | 717 | /* Virtual Function Event Ring Full Error */ |
718 | #define COMP_VF_FULL 16 | 718 | #define COMP_VF_FULL 16 |
719 | /* Parameter Error - Context parameter is invalid */ | 719 | /* Parameter Error - Context parameter is invalid */ |
720 | #define COMP_EINVAL 17 | 720 | #define COMP_EINVAL 17 |
721 | /* Bandwidth Overrun Error - isoc ep exceeded its allocated bandwidth */ | 721 | /* Bandwidth Overrun Error - isoc ep exceeded its allocated bandwidth */ |
722 | #define COMP_BW_OVER 18 | 722 | #define COMP_BW_OVER 18 |
723 | /* Context State Error - illegal context state transition requested */ | 723 | /* Context State Error - illegal context state transition requested */ |
724 | #define COMP_CTX_STATE 19 | 724 | #define COMP_CTX_STATE 19 |
725 | /* No Ping Response Error - HC didn't get PING_RESPONSE in time to TX */ | 725 | /* No Ping Response Error - HC didn't get PING_RESPONSE in time to TX */ |
726 | #define COMP_PING_ERR 20 | 726 | #define COMP_PING_ERR 20 |
727 | /* Event Ring is full */ | 727 | /* Event Ring is full */ |
728 | #define COMP_ER_FULL 21 | 728 | #define COMP_ER_FULL 21 |
729 | /* Missed Service Error - HC couldn't service an isoc ep within interval */ | 729 | /* Missed Service Error - HC couldn't service an isoc ep within interval */ |
730 | #define COMP_MISSED_INT 23 | 730 | #define COMP_MISSED_INT 23 |
731 | /* Successfully stopped command ring */ | 731 | /* Successfully stopped command ring */ |
732 | #define COMP_CMD_STOP 24 | 732 | #define COMP_CMD_STOP 24 |
733 | /* Successfully aborted current command and stopped command ring */ | 733 | /* Successfully aborted current command and stopped command ring */ |
734 | #define COMP_CMD_ABORT 25 | 734 | #define COMP_CMD_ABORT 25 |
735 | /* Stopped - transfer was terminated by a stop endpoint command */ | 735 | /* Stopped - transfer was terminated by a stop endpoint command */ |
736 | #define COMP_STOP 26 | 736 | #define COMP_STOP 26 |
737 | /* Same as COMP_EP_STOPPED, but the transfered length in the event is invalid */ | 737 | /* Same as COMP_EP_STOPPED, but the transfered length in the event is invalid */ |
738 | #define COMP_STOP_INVAL 27 | 738 | #define COMP_STOP_INVAL 27 |
739 | /* Control Abort Error - Debug Capability - control pipe aborted */ | 739 | /* Control Abort Error - Debug Capability - control pipe aborted */ |
740 | #define COMP_DBG_ABORT 28 | 740 | #define COMP_DBG_ABORT 28 |
741 | /* TRB type 29 and 30 reserved */ | 741 | /* TRB type 29 and 30 reserved */ |
742 | /* Isoc Buffer Overrun - an isoc IN ep sent more data than could fit in TD */ | 742 | /* Isoc Buffer Overrun - an isoc IN ep sent more data than could fit in TD */ |
743 | #define COMP_BUFF_OVER 31 | 743 | #define COMP_BUFF_OVER 31 |
744 | /* Event Lost Error - xHC has an "internal event overrun condition" */ | 744 | /* Event Lost Error - xHC has an "internal event overrun condition" */ |
745 | #define COMP_ISSUES 32 | 745 | #define COMP_ISSUES 32 |
746 | /* Undefined Error - reported when other error codes don't apply */ | 746 | /* Undefined Error - reported when other error codes don't apply */ |
747 | #define COMP_UNKNOWN 33 | 747 | #define COMP_UNKNOWN 33 |
748 | /* Invalid Stream ID Error */ | 748 | /* Invalid Stream ID Error */ |
749 | #define COMP_STRID_ERR 34 | 749 | #define COMP_STRID_ERR 34 |
750 | /* Secondary Bandwidth Error - may be returned by a Configure Endpoint cmd */ | 750 | /* Secondary Bandwidth Error - may be returned by a Configure Endpoint cmd */ |
751 | /* FIXME - check for this */ | 751 | /* FIXME - check for this */ |
752 | #define COMP_2ND_BW_ERR 35 | 752 | #define COMP_2ND_BW_ERR 35 |
753 | /* Split Transaction Error */ | 753 | /* Split Transaction Error */ |
754 | #define COMP_SPLIT_ERR 36 | 754 | #define COMP_SPLIT_ERR 36 |
755 | 755 | ||
756 | struct xhci_link_trb { | 756 | struct xhci_link_trb { |
757 | /* 64-bit segment pointer*/ | 757 | /* 64-bit segment pointer*/ |
758 | u64 segment_ptr; | 758 | u64 segment_ptr; |
759 | u32 intr_target; | 759 | u32 intr_target; |
760 | u32 control; | 760 | u32 control; |
761 | }; | 761 | }; |
762 | 762 | ||
763 | /* control bitfields */ | 763 | /* control bitfields */ |
764 | #define LINK_TOGGLE (0x1<<1) | 764 | #define LINK_TOGGLE (0x1<<1) |
765 | 765 | ||
766 | /* Command completion event TRB */ | 766 | /* Command completion event TRB */ |
767 | struct xhci_event_cmd { | 767 | struct xhci_event_cmd { |
768 | /* Pointer to command TRB, or the value passed by the event data trb */ | 768 | /* Pointer to command TRB, or the value passed by the event data trb */ |
769 | u64 cmd_trb; | 769 | u64 cmd_trb; |
770 | u32 status; | 770 | u32 status; |
771 | u32 flags; | 771 | u32 flags; |
772 | }; | 772 | }; |
773 | 773 | ||
774 | /* flags bitmasks */ | 774 | /* flags bitmasks */ |
775 | /* bits 16:23 are the virtual function ID */ | 775 | /* bits 16:23 are the virtual function ID */ |
776 | /* bits 24:31 are the slot ID */ | 776 | /* bits 24:31 are the slot ID */ |
777 | #define TRB_TO_SLOT_ID(p) (((p) & (0xff<<24)) >> 24) | 777 | #define TRB_TO_SLOT_ID(p) (((p) & (0xff<<24)) >> 24) |
778 | #define SLOT_ID_FOR_TRB(p) (((p) & 0xff) << 24) | 778 | #define SLOT_ID_FOR_TRB(p) (((p) & 0xff) << 24) |
779 | 779 | ||
780 | /* Stop Endpoint TRB - ep_index to endpoint ID for this TRB */ | 780 | /* Stop Endpoint TRB - ep_index to endpoint ID for this TRB */ |
781 | #define TRB_TO_EP_INDEX(p) ((((p) & (0x1f << 16)) >> 16) - 1) | 781 | #define TRB_TO_EP_INDEX(p) ((((p) & (0x1f << 16)) >> 16) - 1) |
782 | #define EP_ID_FOR_TRB(p) ((((p) + 1) & 0x1f) << 16) | 782 | #define EP_ID_FOR_TRB(p) ((((p) + 1) & 0x1f) << 16) |
783 | 783 | ||
784 | 784 | ||
785 | /* Port Status Change Event TRB fields */ | 785 | /* Port Status Change Event TRB fields */ |
786 | /* Port ID - bits 31:24 */ | 786 | /* Port ID - bits 31:24 */ |
787 | #define GET_PORT_ID(p) (((p) & (0xff << 24)) >> 24) | 787 | #define GET_PORT_ID(p) (((p) & (0xff << 24)) >> 24) |
788 | 788 | ||
789 | /* Normal TRB fields */ | 789 | /* Normal TRB fields */ |
790 | /* transfer_len bitmasks - bits 0:16 */ | 790 | /* transfer_len bitmasks - bits 0:16 */ |
791 | #define TRB_LEN(p) ((p) & 0x1ffff) | 791 | #define TRB_LEN(p) ((p) & 0x1ffff) |
792 | /* TD size - number of bytes remaining in the TD (including this TRB): | 792 | /* TD size - number of bytes remaining in the TD (including this TRB): |
793 | * bits 17 - 21. Shift the number of bytes by 10. */ | 793 | * bits 17 - 21. Shift the number of bytes by 10. */ |
794 | #define TD_REMAINDER(p) ((((p) >> 10) & 0x1f) << 17) | 794 | #define TD_REMAINDER(p) ((((p) >> 10) & 0x1f) << 17) |
795 | /* Interrupter Target - which MSI-X vector to target the completion event at */ | 795 | /* Interrupter Target - which MSI-X vector to target the completion event at */ |
796 | #define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22) | 796 | #define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22) |
797 | #define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff) | 797 | #define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff) |
798 | 798 | ||
799 | /* Cycle bit - indicates TRB ownership by HC or HCD */ | 799 | /* Cycle bit - indicates TRB ownership by HC or HCD */ |
800 | #define TRB_CYCLE (1<<0) | 800 | #define TRB_CYCLE (1<<0) |
801 | /* | 801 | /* |
802 | * Force next event data TRB to be evaluated before task switch. | 802 | * Force next event data TRB to be evaluated before task switch. |
803 | * Used to pass OS data back after a TD completes. | 803 | * Used to pass OS data back after a TD completes. |
804 | */ | 804 | */ |
805 | #define TRB_ENT (1<<1) | 805 | #define TRB_ENT (1<<1) |
806 | /* Interrupt on short packet */ | 806 | /* Interrupt on short packet */ |
807 | #define TRB_ISP (1<<2) | 807 | #define TRB_ISP (1<<2) |
808 | /* Set PCIe no snoop attribute */ | 808 | /* Set PCIe no snoop attribute */ |
809 | #define TRB_NO_SNOOP (1<<3) | 809 | #define TRB_NO_SNOOP (1<<3) |
810 | /* Chain multiple TRBs into a TD */ | 810 | /* Chain multiple TRBs into a TD */ |
811 | #define TRB_CHAIN (1<<4) | 811 | #define TRB_CHAIN (1<<4) |
812 | /* Interrupt on completion */ | 812 | /* Interrupt on completion */ |
813 | #define TRB_IOC (1<<5) | 813 | #define TRB_IOC (1<<5) |
814 | /* The buffer pointer contains immediate data */ | 814 | /* The buffer pointer contains immediate data */ |
815 | #define TRB_IDT (1<<6) | 815 | #define TRB_IDT (1<<6) |
816 | 816 | ||
817 | 817 | ||
818 | /* Control transfer TRB specific fields */ | 818 | /* Control transfer TRB specific fields */ |
819 | #define TRB_DIR_IN (1<<16) | 819 | #define TRB_DIR_IN (1<<16) |
820 | 820 | ||
821 | struct xhci_generic_trb { | 821 | struct xhci_generic_trb { |
822 | u32 field[4]; | 822 | u32 field[4]; |
823 | }; | 823 | }; |
824 | 824 | ||
825 | union xhci_trb { | 825 | union xhci_trb { |
826 | struct xhci_link_trb link; | 826 | struct xhci_link_trb link; |
827 | struct xhci_transfer_event trans_event; | 827 | struct xhci_transfer_event trans_event; |
828 | struct xhci_event_cmd event_cmd; | 828 | struct xhci_event_cmd event_cmd; |
829 | struct xhci_generic_trb generic; | 829 | struct xhci_generic_trb generic; |
830 | }; | 830 | }; |
831 | 831 | ||
832 | /* TRB bit mask */ | 832 | /* TRB bit mask */ |
833 | #define TRB_TYPE_BITMASK (0xfc00) | 833 | #define TRB_TYPE_BITMASK (0xfc00) |
834 | #define TRB_TYPE(p) ((p) << 10) | 834 | #define TRB_TYPE(p) ((p) << 10) |
835 | /* TRB type IDs */ | 835 | /* TRB type IDs */ |
836 | /* bulk, interrupt, isoc scatter/gather, and control data stage */ | 836 | /* bulk, interrupt, isoc scatter/gather, and control data stage */ |
837 | #define TRB_NORMAL 1 | 837 | #define TRB_NORMAL 1 |
838 | /* setup stage for control transfers */ | 838 | /* setup stage for control transfers */ |
839 | #define TRB_SETUP 2 | 839 | #define TRB_SETUP 2 |
840 | /* data stage for control transfers */ | 840 | /* data stage for control transfers */ |
841 | #define TRB_DATA 3 | 841 | #define TRB_DATA 3 |
842 | /* status stage for control transfers */ | 842 | /* status stage for control transfers */ |
843 | #define TRB_STATUS 4 | 843 | #define TRB_STATUS 4 |
844 | /* isoc transfers */ | 844 | /* isoc transfers */ |
845 | #define TRB_ISOC 5 | 845 | #define TRB_ISOC 5 |
846 | /* TRB for linking ring segments */ | 846 | /* TRB for linking ring segments */ |
847 | #define TRB_LINK 6 | 847 | #define TRB_LINK 6 |
848 | #define TRB_EVENT_DATA 7 | 848 | #define TRB_EVENT_DATA 7 |
849 | /* Transfer Ring No-op (not for the command ring) */ | 849 | /* Transfer Ring No-op (not for the command ring) */ |
850 | #define TRB_TR_NOOP 8 | 850 | #define TRB_TR_NOOP 8 |
851 | /* Command TRBs */ | 851 | /* Command TRBs */ |
852 | /* Enable Slot Command */ | 852 | /* Enable Slot Command */ |
853 | #define TRB_ENABLE_SLOT 9 | 853 | #define TRB_ENABLE_SLOT 9 |
854 | /* Disable Slot Command */ | 854 | /* Disable Slot Command */ |
855 | #define TRB_DISABLE_SLOT 10 | 855 | #define TRB_DISABLE_SLOT 10 |
856 | /* Address Device Command */ | 856 | /* Address Device Command */ |
857 | #define TRB_ADDR_DEV 11 | 857 | #define TRB_ADDR_DEV 11 |
858 | /* Configure Endpoint Command */ | 858 | /* Configure Endpoint Command */ |
859 | #define TRB_CONFIG_EP 12 | 859 | #define TRB_CONFIG_EP 12 |
860 | /* Evaluate Context Command */ | 860 | /* Evaluate Context Command */ |
861 | #define TRB_EVAL_CONTEXT 13 | 861 | #define TRB_EVAL_CONTEXT 13 |
862 | /* Reset Endpoint Command */ | 862 | /* Reset Endpoint Command */ |
863 | #define TRB_RESET_EP 14 | 863 | #define TRB_RESET_EP 14 |
864 | /* Stop Transfer Ring Command */ | 864 | /* Stop Transfer Ring Command */ |
865 | #define TRB_STOP_RING 15 | 865 | #define TRB_STOP_RING 15 |
866 | /* Set Transfer Ring Dequeue Pointer Command */ | 866 | /* Set Transfer Ring Dequeue Pointer Command */ |
867 | #define TRB_SET_DEQ 16 | 867 | #define TRB_SET_DEQ 16 |
868 | /* Reset Device Command */ | 868 | /* Reset Device Command */ |
869 | #define TRB_RESET_DEV 17 | 869 | #define TRB_RESET_DEV 17 |
870 | /* Force Event Command (opt) */ | 870 | /* Force Event Command (opt) */ |
871 | #define TRB_FORCE_EVENT 18 | 871 | #define TRB_FORCE_EVENT 18 |
872 | /* Negotiate Bandwidth Command (opt) */ | 872 | /* Negotiate Bandwidth Command (opt) */ |
873 | #define TRB_NEG_BANDWIDTH 19 | 873 | #define TRB_NEG_BANDWIDTH 19 |
874 | /* Set Latency Tolerance Value Command (opt) */ | 874 | /* Set Latency Tolerance Value Command (opt) */ |
875 | #define TRB_SET_LT 20 | 875 | #define TRB_SET_LT 20 |
876 | /* Get port bandwidth Command */ | 876 | /* Get port bandwidth Command */ |
877 | #define TRB_GET_BW 21 | 877 | #define TRB_GET_BW 21 |
878 | /* Force Header Command - generate a transaction or link management packet */ | 878 | /* Force Header Command - generate a transaction or link management packet */ |
879 | #define TRB_FORCE_HEADER 22 | 879 | #define TRB_FORCE_HEADER 22 |
880 | /* No-op Command - not for transfer rings */ | 880 | /* No-op Command - not for transfer rings */ |
881 | #define TRB_CMD_NOOP 23 | 881 | #define TRB_CMD_NOOP 23 |
882 | /* TRB IDs 24-31 reserved */ | 882 | /* TRB IDs 24-31 reserved */ |
883 | /* Event TRBS */ | 883 | /* Event TRBS */ |
884 | /* Transfer Event */ | 884 | /* Transfer Event */ |
885 | #define TRB_TRANSFER 32 | 885 | #define TRB_TRANSFER 32 |
886 | /* Command Completion Event */ | 886 | /* Command Completion Event */ |
887 | #define TRB_COMPLETION 33 | 887 | #define TRB_COMPLETION 33 |
888 | /* Port Status Change Event */ | 888 | /* Port Status Change Event */ |
889 | #define TRB_PORT_STATUS 34 | 889 | #define TRB_PORT_STATUS 34 |
890 | /* Bandwidth Request Event (opt) */ | 890 | /* Bandwidth Request Event (opt) */ |
891 | #define TRB_BANDWIDTH_EVENT 35 | 891 | #define TRB_BANDWIDTH_EVENT 35 |
892 | /* Doorbell Event (opt) */ | 892 | /* Doorbell Event (opt) */ |
893 | #define TRB_DOORBELL 36 | 893 | #define TRB_DOORBELL 36 |
894 | /* Host Controller Event */ | 894 | /* Host Controller Event */ |
895 | #define TRB_HC_EVENT 37 | 895 | #define TRB_HC_EVENT 37 |
896 | /* Device Notification Event - device sent function wake notification */ | 896 | /* Device Notification Event - device sent function wake notification */ |
897 | #define TRB_DEV_NOTE 38 | 897 | #define TRB_DEV_NOTE 38 |
898 | /* MFINDEX Wrap Event - microframe counter wrapped */ | 898 | /* MFINDEX Wrap Event - microframe counter wrapped */ |
899 | #define TRB_MFINDEX_WRAP 39 | 899 | #define TRB_MFINDEX_WRAP 39 |
900 | /* TRB IDs 40-47 reserved, 48-63 is vendor-defined */ | 900 | /* TRB IDs 40-47 reserved, 48-63 is vendor-defined */ |
901 | 901 | ||
902 | /* | 902 | /* |
903 | * TRBS_PER_SEGMENT must be a multiple of 4, | 903 | * TRBS_PER_SEGMENT must be a multiple of 4, |
904 | * since the command ring is 64-byte aligned. | 904 | * since the command ring is 64-byte aligned. |
905 | * It must also be greater than 16. | 905 | * It must also be greater than 16. |
906 | */ | 906 | */ |
907 | #define TRBS_PER_SEGMENT 64 | 907 | #define TRBS_PER_SEGMENT 64 |
908 | #define SEGMENT_SIZE (TRBS_PER_SEGMENT*16) | 908 | #define SEGMENT_SIZE (TRBS_PER_SEGMENT*16) |
909 | /* TRB buffer pointers can't cross 64KB boundaries */ | 909 | /* TRB buffer pointers can't cross 64KB boundaries */ |
910 | #define TRB_MAX_BUFF_SHIFT 16 | 910 | #define TRB_MAX_BUFF_SHIFT 16 |
911 | #define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT) | 911 | #define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT) |
912 | 912 | ||
913 | struct xhci_segment { | 913 | struct xhci_segment { |
914 | union xhci_trb *trbs; | 914 | union xhci_trb *trbs; |
915 | /* private to HCD */ | 915 | /* private to HCD */ |
916 | struct xhci_segment *next; | 916 | struct xhci_segment *next; |
917 | dma_addr_t dma; | 917 | dma_addr_t dma; |
918 | }; | 918 | }; |
919 | 919 | ||
920 | struct xhci_td { | 920 | struct xhci_td { |
921 | struct list_head td_list; | 921 | struct list_head td_list; |
922 | struct list_head cancelled_td_list; | 922 | struct list_head cancelled_td_list; |
923 | struct urb *urb; | 923 | struct urb *urb; |
924 | struct xhci_segment *start_seg; | 924 | struct xhci_segment *start_seg; |
925 | union xhci_trb *first_trb; | 925 | union xhci_trb *first_trb; |
926 | union xhci_trb *last_trb; | 926 | union xhci_trb *last_trb; |
927 | }; | 927 | }; |
928 | 928 | ||
929 | struct xhci_ring { | 929 | struct xhci_ring { |
930 | struct xhci_segment *first_seg; | 930 | struct xhci_segment *first_seg; |
931 | union xhci_trb *enqueue; | 931 | union xhci_trb *enqueue; |
932 | struct xhci_segment *enq_seg; | 932 | struct xhci_segment *enq_seg; |
933 | unsigned int enq_updates; | 933 | unsigned int enq_updates; |
934 | union xhci_trb *dequeue; | 934 | union xhci_trb *dequeue; |
935 | struct xhci_segment *deq_seg; | 935 | struct xhci_segment *deq_seg; |
936 | unsigned int deq_updates; | 936 | unsigned int deq_updates; |
937 | struct list_head td_list; | 937 | struct list_head td_list; |
938 | /* ---- Related to URB cancellation ---- */ | 938 | /* ---- Related to URB cancellation ---- */ |
939 | struct list_head cancelled_td_list; | 939 | struct list_head cancelled_td_list; |
940 | unsigned int cancels_pending; | 940 | unsigned int cancels_pending; |
941 | unsigned int state; | 941 | unsigned int state; |
942 | #define SET_DEQ_PENDING (1 << 0) | 942 | #define SET_DEQ_PENDING (1 << 0) |
943 | #define EP_HALTED (1 << 1) | 943 | #define EP_HALTED (1 << 1) |
944 | /* The TRB that was last reported in a stopped endpoint ring */ | 944 | /* The TRB that was last reported in a stopped endpoint ring */ |
945 | union xhci_trb *stopped_trb; | 945 | union xhci_trb *stopped_trb; |
946 | struct xhci_td *stopped_td; | 946 | struct xhci_td *stopped_td; |
947 | /* | 947 | /* |
948 | * Write the cycle state into the TRB cycle field to give ownership of | 948 | * Write the cycle state into the TRB cycle field to give ownership of |
949 | * the TRB to the host controller (if we are the producer), or to check | 949 | * the TRB to the host controller (if we are the producer), or to check |
950 | * if we own the TRB (if we are the consumer). See section 4.9.1. | 950 | * if we own the TRB (if we are the consumer). See section 4.9.1. |
951 | */ | 951 | */ |
952 | u32 cycle_state; | 952 | u32 cycle_state; |
953 | }; | 953 | }; |
954 | 954 | ||
955 | struct xhci_dequeue_state { | 955 | struct xhci_dequeue_state { |
956 | struct xhci_segment *new_deq_seg; | 956 | struct xhci_segment *new_deq_seg; |
957 | union xhci_trb *new_deq_ptr; | 957 | union xhci_trb *new_deq_ptr; |
958 | int new_cycle_state; | 958 | int new_cycle_state; |
959 | }; | 959 | }; |
960 | 960 | ||
961 | struct xhci_erst_entry { | 961 | struct xhci_erst_entry { |
962 | /* 64-bit event ring segment address */ | 962 | /* 64-bit event ring segment address */ |
963 | u64 seg_addr; | 963 | u64 seg_addr; |
964 | u32 seg_size; | 964 | u32 seg_size; |
965 | /* Set to zero */ | 965 | /* Set to zero */ |
966 | u32 rsvd; | 966 | u32 rsvd; |
967 | }; | 967 | }; |
968 | 968 | ||
969 | struct xhci_erst { | 969 | struct xhci_erst { |
970 | struct xhci_erst_entry *entries; | 970 | struct xhci_erst_entry *entries; |
971 | unsigned int num_entries; | 971 | unsigned int num_entries; |
972 | /* xhci->event_ring keeps track of segment dma addresses */ | 972 | /* xhci->event_ring keeps track of segment dma addresses */ |
973 | dma_addr_t erst_dma_addr; | 973 | dma_addr_t erst_dma_addr; |
974 | /* Num entries the ERST can contain */ | 974 | /* Num entries the ERST can contain */ |
975 | unsigned int erst_size; | 975 | unsigned int erst_size; |
976 | }; | 976 | }; |
977 | 977 | ||
978 | struct xhci_scratchpad { | 978 | struct xhci_scratchpad { |
979 | u64 *sp_array; | 979 | u64 *sp_array; |
980 | dma_addr_t sp_dma; | 980 | dma_addr_t sp_dma; |
981 | void **sp_buffers; | 981 | void **sp_buffers; |
982 | dma_addr_t *sp_dma_buffers; | 982 | dma_addr_t *sp_dma_buffers; |
983 | }; | 983 | }; |
984 | 984 | ||
985 | /* | 985 | /* |
986 | * Each segment table entry is 4*32bits long. 1K seems like an ok size: | 986 | * Each segment table entry is 4*32bits long. 1K seems like an ok size: |
987 | * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, | 987 | * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, |
988 | * meaning 64 ring segments. | 988 | * meaning 64 ring segments. |
989 | * Initial allocated size of the ERST, in number of entries */ | 989 | * Initial allocated size of the ERST, in number of entries */ |
990 | #define ERST_NUM_SEGS 1 | 990 | #define ERST_NUM_SEGS 1 |
991 | /* Initial allocated size of the ERST, in number of entries */ | 991 | /* Initial allocated size of the ERST, in number of entries */ |
992 | #define ERST_SIZE 64 | 992 | #define ERST_SIZE 64 |
993 | /* Initial number of event segment rings allocated */ | 993 | /* Initial number of event segment rings allocated */ |
994 | #define ERST_ENTRIES 1 | 994 | #define ERST_ENTRIES 1 |
995 | /* Poll every 60 seconds */ | 995 | /* Poll every 60 seconds */ |
996 | #define POLL_TIMEOUT 60 | 996 | #define POLL_TIMEOUT 60 |
997 | /* XXX: Make these module parameters */ | 997 | /* XXX: Make these module parameters */ |
998 | 998 | ||
999 | 999 | ||
1000 | /* There is one ehci_hci structure per controller */ | 1000 | /* There is one ehci_hci structure per controller */ |
1001 | struct xhci_hcd { | 1001 | struct xhci_hcd { |
1002 | /* glue to PCI and HCD framework */ | 1002 | /* glue to PCI and HCD framework */ |
1003 | struct xhci_cap_regs __iomem *cap_regs; | 1003 | struct xhci_cap_regs __iomem *cap_regs; |
1004 | struct xhci_op_regs __iomem *op_regs; | 1004 | struct xhci_op_regs __iomem *op_regs; |
1005 | struct xhci_run_regs __iomem *run_regs; | 1005 | struct xhci_run_regs __iomem *run_regs; |
1006 | struct xhci_doorbell_array __iomem *dba; | 1006 | struct xhci_doorbell_array __iomem *dba; |
1007 | /* Our HCD's current interrupter register set */ | 1007 | /* Our HCD's current interrupter register set */ |
1008 | struct xhci_intr_reg __iomem *ir_set; | 1008 | struct xhci_intr_reg __iomem *ir_set; |
1009 | 1009 | ||
1010 | /* Cached register copies of read-only HC data */ | 1010 | /* Cached register copies of read-only HC data */ |
1011 | __u32 hcs_params1; | 1011 | __u32 hcs_params1; |
1012 | __u32 hcs_params2; | 1012 | __u32 hcs_params2; |
1013 | __u32 hcs_params3; | 1013 | __u32 hcs_params3; |
1014 | __u32 hcc_params; | 1014 | __u32 hcc_params; |
1015 | 1015 | ||
1016 | spinlock_t lock; | 1016 | spinlock_t lock; |
1017 | 1017 | ||
1018 | /* packed release number */ | 1018 | /* packed release number */ |
1019 | u8 sbrn; | 1019 | u8 sbrn; |
1020 | u16 hci_version; | 1020 | u16 hci_version; |
1021 | u8 max_slots; | 1021 | u8 max_slots; |
1022 | u8 max_interrupters; | 1022 | u8 max_interrupters; |
1023 | u8 max_ports; | 1023 | u8 max_ports; |
1024 | u8 isoc_threshold; | 1024 | u8 isoc_threshold; |
1025 | int event_ring_max; | 1025 | int event_ring_max; |
1026 | int addr_64; | 1026 | int addr_64; |
1027 | /* 4KB min, 128MB max */ | 1027 | /* 4KB min, 128MB max */ |
1028 | int page_size; | 1028 | int page_size; |
1029 | /* Valid values are 12 to 20, inclusive */ | 1029 | /* Valid values are 12 to 20, inclusive */ |
1030 | int page_shift; | 1030 | int page_shift; |
1031 | /* only one MSI vector for now, but might need more later */ | 1031 | /* only one MSI vector for now, but might need more later */ |
1032 | int msix_count; | 1032 | int msix_count; |
1033 | struct msix_entry *msix_entries; | 1033 | struct msix_entry *msix_entries; |
1034 | /* data structures */ | 1034 | /* data structures */ |
1035 | struct xhci_device_context_array *dcbaa; | 1035 | struct xhci_device_context_array *dcbaa; |
1036 | struct xhci_ring *cmd_ring; | 1036 | struct xhci_ring *cmd_ring; |
1037 | struct xhci_ring *event_ring; | 1037 | struct xhci_ring *event_ring; |
1038 | struct xhci_erst erst; | 1038 | struct xhci_erst erst; |
1039 | /* Scratchpad */ | 1039 | /* Scratchpad */ |
1040 | struct xhci_scratchpad *scratchpad; | 1040 | struct xhci_scratchpad *scratchpad; |
1041 | 1041 | ||
1042 | /* slot enabling and address device helpers */ | 1042 | /* slot enabling and address device helpers */ |
1043 | struct completion addr_dev; | 1043 | struct completion addr_dev; |
1044 | int slot_id; | 1044 | int slot_id; |
1045 | /* Internal mirror of the HW's dcbaa */ | 1045 | /* Internal mirror of the HW's dcbaa */ |
1046 | struct xhci_virt_device *devs[MAX_HC_SLOTS]; | 1046 | struct xhci_virt_device *devs[MAX_HC_SLOTS]; |
1047 | 1047 | ||
1048 | /* DMA pools */ | 1048 | /* DMA pools */ |
1049 | struct dma_pool *device_pool; | 1049 | struct dma_pool *device_pool; |
1050 | struct dma_pool *segment_pool; | 1050 | struct dma_pool *segment_pool; |
1051 | 1051 | ||
1052 | #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING | 1052 | #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING |
1053 | /* Poll the rings - for debugging */ | 1053 | /* Poll the rings - for debugging */ |
1054 | struct timer_list event_ring_timer; | 1054 | struct timer_list event_ring_timer; |
1055 | int zombie; | 1055 | int zombie; |
1056 | #endif | 1056 | #endif |
1057 | /* Statistics */ | 1057 | /* Statistics */ |
1058 | int noops_submitted; | 1058 | int noops_submitted; |
1059 | int noops_handled; | 1059 | int noops_handled; |
1060 | int error_bitmask; | 1060 | int error_bitmask; |
1061 | }; | 1061 | }; |
1062 | 1062 | ||
1063 | /* For testing purposes */ | 1063 | /* For testing purposes */ |
1064 | #define NUM_TEST_NOOPS 0 | 1064 | #define NUM_TEST_NOOPS 0 |
1065 | 1065 | ||
1066 | /* convert between an HCD pointer and the corresponding EHCI_HCD */ | 1066 | /* convert between an HCD pointer and the corresponding EHCI_HCD */ |
1067 | static inline struct xhci_hcd *hcd_to_xhci(struct usb_hcd *hcd) | 1067 | static inline struct xhci_hcd *hcd_to_xhci(struct usb_hcd *hcd) |
1068 | { | 1068 | { |
1069 | return (struct xhci_hcd *) (hcd->hcd_priv); | 1069 | return (struct xhci_hcd *) (hcd->hcd_priv); |
1070 | } | 1070 | } |
1071 | 1071 | ||
1072 | static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci) | 1072 | static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci) |
1073 | { | 1073 | { |
1074 | return container_of((void *) xhci, struct usb_hcd, hcd_priv); | 1074 | return container_of((void *) xhci, struct usb_hcd, hcd_priv); |
1075 | } | 1075 | } |
1076 | 1076 | ||
1077 | #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING | 1077 | #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING |
1078 | #define XHCI_DEBUG 1 | 1078 | #define XHCI_DEBUG 1 |
1079 | #else | 1079 | #else |
1080 | #define XHCI_DEBUG 0 | 1080 | #define XHCI_DEBUG 0 |
1081 | #endif | 1081 | #endif |
1082 | 1082 | ||
1083 | #define xhci_dbg(xhci, fmt, args...) \ | 1083 | #define xhci_dbg(xhci, fmt, args...) \ |
1084 | do { if (XHCI_DEBUG) dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0) | 1084 | do { if (XHCI_DEBUG) dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0) |
1085 | #define xhci_info(xhci, fmt, args...) \ | 1085 | #define xhci_info(xhci, fmt, args...) \ |
1086 | do { if (XHCI_DEBUG) dev_info(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0) | 1086 | do { if (XHCI_DEBUG) dev_info(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0) |
1087 | #define xhci_err(xhci, fmt, args...) \ | 1087 | #define xhci_err(xhci, fmt, args...) \ |
1088 | dev_err(xhci_to_hcd(xhci)->self.controller , fmt , ## args) | 1088 | dev_err(xhci_to_hcd(xhci)->self.controller , fmt , ## args) |
1089 | #define xhci_warn(xhci, fmt, args...) \ | 1089 | #define xhci_warn(xhci, fmt, args...) \ |
1090 | dev_warn(xhci_to_hcd(xhci)->self.controller , fmt , ## args) | 1090 | dev_warn(xhci_to_hcd(xhci)->self.controller , fmt , ## args) |
1091 | 1091 | ||
1092 | /* TODO: copied from ehci.h - can be refactored? */ | 1092 | /* TODO: copied from ehci.h - can be refactored? */ |
1093 | /* xHCI spec says all registers are little endian */ | 1093 | /* xHCI spec says all registers are little endian */ |
1094 | static inline unsigned int xhci_readl(const struct xhci_hcd *xhci, | 1094 | static inline unsigned int xhci_readl(const struct xhci_hcd *xhci, |
1095 | __u32 __iomem *regs) | 1095 | __u32 __iomem *regs) |
1096 | { | 1096 | { |
1097 | return readl(regs); | 1097 | return readl(regs); |
1098 | } | 1098 | } |
1099 | static inline void xhci_writel(struct xhci_hcd *xhci, | 1099 | static inline void xhci_writel(struct xhci_hcd *xhci, |
1100 | const unsigned int val, __u32 __iomem *regs) | 1100 | const unsigned int val, __u32 __iomem *regs) |
1101 | { | 1101 | { |
1102 | xhci_dbg(xhci, | 1102 | xhci_dbg(xhci, |
1103 | "`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n", | 1103 | "`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n", |
1104 | regs, val); | 1104 | regs, val); |
1105 | writel(val, regs); | 1105 | writel(val, regs); |
1106 | } | 1106 | } |
1107 | 1107 | ||
1108 | /* | 1108 | /* |
1109 | * Registers should always be accessed with double word or quad word accesses. | 1109 | * Registers should always be accessed with double word or quad word accesses. |
1110 | * | 1110 | * |
1111 | * Some xHCI implementations may support 64-bit address pointers. Registers | 1111 | * Some xHCI implementations may support 64-bit address pointers. Registers |
1112 | * with 64-bit address pointers should be written to with dword accesses by | 1112 | * with 64-bit address pointers should be written to with dword accesses by |
1113 | * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second. | 1113 | * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second. |
1114 | * xHCI implementations that do not support 64-bit address pointers will ignore | 1114 | * xHCI implementations that do not support 64-bit address pointers will ignore |
1115 | * the high dword, and write order is irrelevant. | 1115 | * the high dword, and write order is irrelevant. |
1116 | */ | 1116 | */ |
1117 | static inline u64 xhci_read_64(const struct xhci_hcd *xhci, | 1117 | static inline u64 xhci_read_64(const struct xhci_hcd *xhci, |
1118 | __u64 __iomem *regs) | 1118 | __u64 __iomem *regs) |
1119 | { | 1119 | { |
1120 | __u32 __iomem *ptr = (__u32 __iomem *) regs; | 1120 | __u32 __iomem *ptr = (__u32 __iomem *) regs; |
1121 | u64 val_lo = readl(ptr); | 1121 | u64 val_lo = readl(ptr); |
1122 | u64 val_hi = readl(ptr + 1); | 1122 | u64 val_hi = readl(ptr + 1); |
1123 | return val_lo + (val_hi << 32); | 1123 | return val_lo + (val_hi << 32); |
1124 | } | 1124 | } |
1125 | static inline void xhci_write_64(struct xhci_hcd *xhci, | 1125 | static inline void xhci_write_64(struct xhci_hcd *xhci, |
1126 | const u64 val, __u64 __iomem *regs) | 1126 | const u64 val, __u64 __iomem *regs) |
1127 | { | 1127 | { |
1128 | __u32 __iomem *ptr = (__u32 __iomem *) regs; | 1128 | __u32 __iomem *ptr = (__u32 __iomem *) regs; |
1129 | u32 val_lo = lower_32_bits(val); | 1129 | u32 val_lo = lower_32_bits(val); |
1130 | u32 val_hi = upper_32_bits(val); | 1130 | u32 val_hi = upper_32_bits(val); |
1131 | 1131 | ||
1132 | xhci_dbg(xhci, | 1132 | xhci_dbg(xhci, |
1133 | "`MEM_WRITE_DWORD(3'b000, 64'h%p, 64'h%0lx, 4'hf);\n", | 1133 | "`MEM_WRITE_DWORD(3'b000, 64'h%p, 64'h%0lx, 4'hf);\n", |
1134 | regs, (long unsigned int) val); | 1134 | regs, (long unsigned int) val); |
1135 | writel(val_lo, ptr); | 1135 | writel(val_lo, ptr); |
1136 | writel(val_hi, ptr + 1); | 1136 | writel(val_hi, ptr + 1); |
1137 | } | 1137 | } |
1138 | 1138 | ||
1139 | /* xHCI debugging */ | 1139 | /* xHCI debugging */ |
1140 | void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num); | 1140 | void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num); |
1141 | void xhci_print_registers(struct xhci_hcd *xhci); | 1141 | void xhci_print_registers(struct xhci_hcd *xhci); |
1142 | void xhci_dbg_regs(struct xhci_hcd *xhci); | 1142 | void xhci_dbg_regs(struct xhci_hcd *xhci); |
1143 | void xhci_print_run_regs(struct xhci_hcd *xhci); | 1143 | void xhci_print_run_regs(struct xhci_hcd *xhci); |
1144 | void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb); | 1144 | void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb); |
1145 | void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb); | 1145 | void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb); |
1146 | void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg); | 1146 | void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg); |
1147 | void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring); | 1147 | void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring); |
1148 | void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst); | 1148 | void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst); |
1149 | void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci); | 1149 | void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci); |
1150 | void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring); | 1150 | void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring); |
1151 | void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int last_ep); | 1151 | void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int last_ep); |
1152 | 1152 | ||
1153 | /* xHCI memory managment */ | 1153 | /* xHCI memory management */ |
1154 | void xhci_mem_cleanup(struct xhci_hcd *xhci); | 1154 | void xhci_mem_cleanup(struct xhci_hcd *xhci); |
1155 | int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags); | 1155 | int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags); |
1156 | void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id); | 1156 | void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id); |
1157 | int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags); | 1157 | int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags); |
1158 | int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev); | 1158 | int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev); |
1159 | unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc); | 1159 | unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc); |
1160 | unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc); | 1160 | unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc); |
1161 | void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep); | 1161 | void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep); |
1162 | int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, | 1162 | int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, |
1163 | struct usb_device *udev, struct usb_host_endpoint *ep, | 1163 | struct usb_device *udev, struct usb_host_endpoint *ep, |
1164 | gfp_t mem_flags); | 1164 | gfp_t mem_flags); |
1165 | void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring); | 1165 | void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring); |
1166 | 1166 | ||
1167 | #ifdef CONFIG_PCI | 1167 | #ifdef CONFIG_PCI |
1168 | /* xHCI PCI glue */ | 1168 | /* xHCI PCI glue */ |
1169 | int xhci_register_pci(void); | 1169 | int xhci_register_pci(void); |
1170 | void xhci_unregister_pci(void); | 1170 | void xhci_unregister_pci(void); |
1171 | #endif | 1171 | #endif |
1172 | 1172 | ||
1173 | /* xHCI host controller glue */ | 1173 | /* xHCI host controller glue */ |
1174 | int xhci_halt(struct xhci_hcd *xhci); | 1174 | int xhci_halt(struct xhci_hcd *xhci); |
1175 | int xhci_reset(struct xhci_hcd *xhci); | 1175 | int xhci_reset(struct xhci_hcd *xhci); |
1176 | int xhci_init(struct usb_hcd *hcd); | 1176 | int xhci_init(struct usb_hcd *hcd); |
1177 | int xhci_run(struct usb_hcd *hcd); | 1177 | int xhci_run(struct usb_hcd *hcd); |
1178 | void xhci_stop(struct usb_hcd *hcd); | 1178 | void xhci_stop(struct usb_hcd *hcd); |
1179 | void xhci_shutdown(struct usb_hcd *hcd); | 1179 | void xhci_shutdown(struct usb_hcd *hcd); |
1180 | int xhci_get_frame(struct usb_hcd *hcd); | 1180 | int xhci_get_frame(struct usb_hcd *hcd); |
1181 | irqreturn_t xhci_irq(struct usb_hcd *hcd); | 1181 | irqreturn_t xhci_irq(struct usb_hcd *hcd); |
1182 | int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev); | 1182 | int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev); |
1183 | void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev); | 1183 | void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev); |
1184 | int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev); | 1184 | int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev); |
1185 | int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags); | 1185 | int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags); |
1186 | int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status); | 1186 | int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status); |
1187 | int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); | 1187 | int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); |
1188 | int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); | 1188 | int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); |
1189 | void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep); | 1189 | void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep); |
1190 | int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); | 1190 | int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); |
1191 | void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); | 1191 | void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); |
1192 | 1192 | ||
1193 | /* xHCI ring, segment, TRB, and TD functions */ | 1193 | /* xHCI ring, segment, TRB, and TD functions */ |
1194 | dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); | 1194 | dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); |
1195 | void xhci_ring_cmd_db(struct xhci_hcd *xhci); | 1195 | void xhci_ring_cmd_db(struct xhci_hcd *xhci); |
1196 | void *xhci_setup_one_noop(struct xhci_hcd *xhci); | 1196 | void *xhci_setup_one_noop(struct xhci_hcd *xhci); |
1197 | void xhci_handle_event(struct xhci_hcd *xhci); | 1197 | void xhci_handle_event(struct xhci_hcd *xhci); |
1198 | void xhci_set_hc_event_deq(struct xhci_hcd *xhci); | 1198 | void xhci_set_hc_event_deq(struct xhci_hcd *xhci); |
1199 | int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id); | 1199 | int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id); |
1200 | int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, | 1200 | int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, |
1201 | u32 slot_id); | 1201 | u32 slot_id); |
1202 | int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, | 1202 | int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, |
1203 | unsigned int ep_index); | 1203 | unsigned int ep_index); |
1204 | int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, | 1204 | int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, |
1205 | int slot_id, unsigned int ep_index); | 1205 | int slot_id, unsigned int ep_index); |
1206 | int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, | 1206 | int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, |
1207 | int slot_id, unsigned int ep_index); | 1207 | int slot_id, unsigned int ep_index); |
1208 | int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, | 1208 | int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, |
1209 | u32 slot_id); | 1209 | u32 slot_id); |
1210 | int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, | 1210 | int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, |
1211 | unsigned int ep_index); | 1211 | unsigned int ep_index); |
1212 | void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, | 1212 | void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, |
1213 | unsigned int slot_id, unsigned int ep_index, | 1213 | unsigned int slot_id, unsigned int ep_index, |
1214 | struct xhci_td *cur_td, struct xhci_dequeue_state *state); | 1214 | struct xhci_td *cur_td, struct xhci_dequeue_state *state); |
1215 | void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, | 1215 | void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, |
1216 | struct xhci_ring *ep_ring, unsigned int slot_id, | 1216 | struct xhci_ring *ep_ring, unsigned int slot_id, |
1217 | unsigned int ep_index, struct xhci_dequeue_state *deq_state); | 1217 | unsigned int ep_index, struct xhci_dequeue_state *deq_state); |
1218 | 1218 | ||
1219 | /* xHCI roothub code */ | 1219 | /* xHCI roothub code */ |
1220 | int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, | 1220 | int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, |
1221 | char *buf, u16 wLength); | 1221 | char *buf, u16 wLength); |
1222 | int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); | 1222 | int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); |
1223 | 1223 | ||
1224 | /* xHCI contexts */ | 1224 | /* xHCI contexts */ |
1225 | struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); | 1225 | struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); |
1226 | struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); | 1226 | struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); |
1227 | struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index); | 1227 | struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index); |
1228 | 1228 | ||
1229 | #endif /* __LINUX_XHCI_HCD_H */ | 1229 | #endif /* __LINUX_XHCI_HCD_H */ |
1230 | 1230 |
drivers/usb/wusbcore/wa-hc.h
1 | /* | 1 | /* |
2 | * HWA Host Controller Driver | 2 | * HWA Host Controller Driver |
3 | * Wire Adapter Control/Data Streaming Iface (WUSB1.0[8]) | 3 | * Wire Adapter Control/Data Streaming Iface (WUSB1.0[8]) |
4 | * | 4 | * |
5 | * Copyright (C) 2005-2006 Intel Corporation | 5 | * Copyright (C) 2005-2006 Intel Corporation |
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | 6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU General Public License version | 9 | * modify it under the terms of the GNU General Public License version |
10 | * 2 as published by the Free Software Foundation. | 10 | * 2 as published by the Free Software Foundation. |
11 | * | 11 | * |
12 | * This program is distributed in the hope that it will be useful, | 12 | * This program is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
16 | * | 16 | * |
17 | * You should have received a copy of the GNU General Public License | 17 | * You should have received a copy of the GNU General Public License |
18 | * along with this program; if not, write to the Free Software | 18 | * along with this program; if not, write to the Free Software |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
20 | * 02110-1301, USA. | 20 | * 02110-1301, USA. |
21 | * | 21 | * |
22 | * | 22 | * |
23 | * This driver implements a USB Host Controller (struct usb_hcd) for a | 23 | * This driver implements a USB Host Controller (struct usb_hcd) for a |
24 | * Wireless USB Host Controller based on the Wireless USB 1.0 | 24 | * Wireless USB Host Controller based on the Wireless USB 1.0 |
25 | * Host-Wire-Adapter specification (in layman terms, a USB-dongle that | 25 | * Host-Wire-Adapter specification (in layman terms, a USB-dongle that |
26 | * implements a Wireless USB host). | 26 | * implements a Wireless USB host). |
27 | * | 27 | * |
28 | * Check out the Design-overview.txt file in the source documentation | 28 | * Check out the Design-overview.txt file in the source documentation |
29 | * for other details on the implementation. | 29 | * for other details on the implementation. |
30 | * | 30 | * |
31 | * Main blocks: | 31 | * Main blocks: |
32 | * | 32 | * |
33 | * driver glue with the driver API, workqueue daemon | 33 | * driver glue with the driver API, workqueue daemon |
34 | * | 34 | * |
35 | * lc RC instance life cycle management (create, destroy...) | 35 | * lc RC instance life cycle management (create, destroy...) |
36 | * | 36 | * |
37 | * hcd glue with the USB API Host Controller Interface API. | 37 | * hcd glue with the USB API Host Controller Interface API. |
38 | * | 38 | * |
39 | * nep Notification EndPoint managent: collect notifications | 39 | * nep Notification EndPoint managent: collect notifications |
40 | * and queue them with the workqueue daemon. | 40 | * and queue them with the workqueue daemon. |
41 | * | 41 | * |
42 | * Handle notifications as coming from the NEP. Sends them | 42 | * Handle notifications as coming from the NEP. Sends them |
43 | * off others to their respective modules (eg: connect, | 43 | * off others to their respective modules (eg: connect, |
44 | * disconnect and reset go to devconnect). | 44 | * disconnect and reset go to devconnect). |
45 | * | 45 | * |
46 | * rpipe Remote Pipe management; rpipe is what we use to write | 46 | * rpipe Remote Pipe management; rpipe is what we use to write |
47 | * to an endpoint on a WUSB device that is connected to a | 47 | * to an endpoint on a WUSB device that is connected to a |
48 | * HWA RC. | 48 | * HWA RC. |
49 | * | 49 | * |
50 | * xfer Transfer managment -- this is all the code that gets a | 50 | * xfer Transfer management -- this is all the code that gets a |
51 | * buffer and pushes it to a device (or viceversa). * | 51 | * buffer and pushes it to a device (or viceversa). * |
52 | * | 52 | * |
53 | * Some day a lot of this code will be shared between this driver and | 53 | * Some day a lot of this code will be shared between this driver and |
54 | * the drivers for DWA (xfer, rpipe). | 54 | * the drivers for DWA (xfer, rpipe). |
55 | * | 55 | * |
56 | * All starts at driver.c:hwahc_probe(), when one of this guys is | 56 | * All starts at driver.c:hwahc_probe(), when one of this guys is |
57 | * connected. hwahc_disconnect() stops it. | 57 | * connected. hwahc_disconnect() stops it. |
58 | * | 58 | * |
59 | * During operation, the main driver is devices connecting or | 59 | * During operation, the main driver is devices connecting or |
60 | * disconnecting. They cause the HWA RC to send notifications into | 60 | * disconnecting. They cause the HWA RC to send notifications into |
61 | * nep.c:hwahc_nep_cb() that will dispatch them to | 61 | * nep.c:hwahc_nep_cb() that will dispatch them to |
62 | * notif.c:wa_notif_dispatch(). From there they will fan to cause | 62 | * notif.c:wa_notif_dispatch(). From there they will fan to cause |
63 | * device connects, disconnects, etc. | 63 | * device connects, disconnects, etc. |
64 | * | 64 | * |
65 | * Note much of the activity is difficult to follow. For example a | 65 | * Note much of the activity is difficult to follow. For example a |
66 | * device connect goes to devconnect, which will cause the "fake" root | 66 | * device connect goes to devconnect, which will cause the "fake" root |
67 | * hub port to show a connect and stop there. Then khubd will notice | 67 | * hub port to show a connect and stop there. Then khubd will notice |
68 | * and call into the rh.c:hwahc_rc_port_reset() code to authenticate | 68 | * and call into the rh.c:hwahc_rc_port_reset() code to authenticate |
69 | * the device (and this might require user intervention) and enable | 69 | * the device (and this might require user intervention) and enable |
70 | * the port. | 70 | * the port. |
71 | * | 71 | * |
72 | * We also have a timer workqueue going from devconnect.c that | 72 | * We also have a timer workqueue going from devconnect.c that |
73 | * schedules in hwahc_devconnect_create(). | 73 | * schedules in hwahc_devconnect_create(). |
74 | * | 74 | * |
75 | * The rest of the traffic is in the usual entry points of a USB HCD, | 75 | * The rest of the traffic is in the usual entry points of a USB HCD, |
76 | * which are hooked up in driver.c:hwahc_rc_driver, and defined in | 76 | * which are hooked up in driver.c:hwahc_rc_driver, and defined in |
77 | * hcd.c. | 77 | * hcd.c. |
78 | */ | 78 | */ |
79 | 79 | ||
80 | #ifndef __HWAHC_INTERNAL_H__ | 80 | #ifndef __HWAHC_INTERNAL_H__ |
81 | #define __HWAHC_INTERNAL_H__ | 81 | #define __HWAHC_INTERNAL_H__ |
82 | 82 | ||
83 | #include <linux/completion.h> | 83 | #include <linux/completion.h> |
84 | #include <linux/usb.h> | 84 | #include <linux/usb.h> |
85 | #include <linux/mutex.h> | 85 | #include <linux/mutex.h> |
86 | #include <linux/spinlock.h> | 86 | #include <linux/spinlock.h> |
87 | #include <linux/uwb.h> | 87 | #include <linux/uwb.h> |
88 | #include <linux/usb/wusb.h> | 88 | #include <linux/usb/wusb.h> |
89 | #include <linux/usb/wusb-wa.h> | 89 | #include <linux/usb/wusb-wa.h> |
90 | 90 | ||
91 | struct wusbhc; | 91 | struct wusbhc; |
92 | struct wahc; | 92 | struct wahc; |
93 | extern void wa_urb_enqueue_run(struct work_struct *ws); | 93 | extern void wa_urb_enqueue_run(struct work_struct *ws); |
94 | 94 | ||
95 | /** | 95 | /** |
96 | * RPipe instance | 96 | * RPipe instance |
97 | * | 97 | * |
98 | * @descr's fields are kept in LE, as we need to send it back and | 98 | * @descr's fields are kept in LE, as we need to send it back and |
99 | * forth. | 99 | * forth. |
100 | * | 100 | * |
101 | * @wa is referenced when set | 101 | * @wa is referenced when set |
102 | * | 102 | * |
103 | * @segs_available is the number of requests segments that still can | 103 | * @segs_available is the number of requests segments that still can |
104 | * be submitted to the controller without overloading | 104 | * be submitted to the controller without overloading |
105 | * it. It is initialized to descr->wRequests when | 105 | * it. It is initialized to descr->wRequests when |
106 | * aiming. | 106 | * aiming. |
107 | * | 107 | * |
108 | * A rpipe supports a max of descr->wRequests at the same time; before | 108 | * A rpipe supports a max of descr->wRequests at the same time; before |
109 | * submitting seg_lock has to be taken. If segs_avail > 0, then we can | 109 | * submitting seg_lock has to be taken. If segs_avail > 0, then we can |
110 | * submit; if not, we have to queue them. | 110 | * submit; if not, we have to queue them. |
111 | */ | 111 | */ |
112 | struct wa_rpipe { | 112 | struct wa_rpipe { |
113 | struct kref refcnt; | 113 | struct kref refcnt; |
114 | struct usb_rpipe_descriptor descr; | 114 | struct usb_rpipe_descriptor descr; |
115 | struct usb_host_endpoint *ep; | 115 | struct usb_host_endpoint *ep; |
116 | struct wahc *wa; | 116 | struct wahc *wa; |
117 | spinlock_t seg_lock; | 117 | spinlock_t seg_lock; |
118 | struct list_head seg_list; | 118 | struct list_head seg_list; |
119 | atomic_t segs_available; | 119 | atomic_t segs_available; |
120 | u8 buffer[1]; /* For reads/writes on USB */ | 120 | u8 buffer[1]; /* For reads/writes on USB */ |
121 | }; | 121 | }; |
122 | 122 | ||
123 | 123 | ||
124 | /** | 124 | /** |
125 | * Instance of a HWA Host Controller | 125 | * Instance of a HWA Host Controller |
126 | * | 126 | * |
127 | * Except where a more specific lock/mutex applies or atomic, all | 127 | * Except where a more specific lock/mutex applies or atomic, all |
128 | * fields protected by @mutex. | 128 | * fields protected by @mutex. |
129 | * | 129 | * |
130 | * @wa_descr Can be accessed without locking because it is in | 130 | * @wa_descr Can be accessed without locking because it is in |
131 | * the same area where the device descriptors were | 131 | * the same area where the device descriptors were |
132 | * read, so it is guaranteed to exist umodified while | 132 | * read, so it is guaranteed to exist umodified while |
133 | * the device exists. | 133 | * the device exists. |
134 | * | 134 | * |
135 | * Endianess has been converted to CPU's. | 135 | * Endianess has been converted to CPU's. |
136 | * | 136 | * |
137 | * @nep_* can be accessed without locking as its processing is | 137 | * @nep_* can be accessed without locking as its processing is |
138 | * serialized; we submit a NEP URB and it comes to | 138 | * serialized; we submit a NEP URB and it comes to |
139 | * hwahc_nep_cb(), which won't issue another URB until it is | 139 | * hwahc_nep_cb(), which won't issue another URB until it is |
140 | * done processing it. | 140 | * done processing it. |
141 | * | 141 | * |
142 | * @xfer_list: | 142 | * @xfer_list: |
143 | * | 143 | * |
144 | * List of active transfers to verify existence from a xfer id | 144 | * List of active transfers to verify existence from a xfer id |
145 | * gotten from the xfer result message. Can't use urb->list because | 145 | * gotten from the xfer result message. Can't use urb->list because |
146 | * it goes by endpoint, and we don't know the endpoint at the time | 146 | * it goes by endpoint, and we don't know the endpoint at the time |
147 | * when we get the xfer result message. We can't really rely on the | 147 | * when we get the xfer result message. We can't really rely on the |
148 | * pointer (will have to change for 64 bits) as the xfer id is 32 bits. | 148 | * pointer (will have to change for 64 bits) as the xfer id is 32 bits. |
149 | * | 149 | * |
150 | * @xfer_delayed_list: List of transfers that need to be started | 150 | * @xfer_delayed_list: List of transfers that need to be started |
151 | * (with a workqueue, because they were | 151 | * (with a workqueue, because they were |
152 | * submitted from an atomic context). | 152 | * submitted from an atomic context). |
153 | * | 153 | * |
154 | * FIXME: this needs to be layered up: a wusbhc layer (for sharing | 154 | * FIXME: this needs to be layered up: a wusbhc layer (for sharing |
155 | * comonalities with WHCI), a wa layer (for sharing | 155 | * comonalities with WHCI), a wa layer (for sharing |
156 | * comonalities with DWA-RC). | 156 | * comonalities with DWA-RC). |
157 | */ | 157 | */ |
158 | struct wahc { | 158 | struct wahc { |
159 | struct usb_device *usb_dev; | 159 | struct usb_device *usb_dev; |
160 | struct usb_interface *usb_iface; | 160 | struct usb_interface *usb_iface; |
161 | 161 | ||
162 | /* HC to deliver notifications */ | 162 | /* HC to deliver notifications */ |
163 | union { | 163 | union { |
164 | struct wusbhc *wusb; | 164 | struct wusbhc *wusb; |
165 | struct dwahc *dwa; | 165 | struct dwahc *dwa; |
166 | }; | 166 | }; |
167 | 167 | ||
168 | const struct usb_endpoint_descriptor *dto_epd, *dti_epd; | 168 | const struct usb_endpoint_descriptor *dto_epd, *dti_epd; |
169 | const struct usb_wa_descriptor *wa_descr; | 169 | const struct usb_wa_descriptor *wa_descr; |
170 | 170 | ||
171 | struct urb *nep_urb; /* Notification EndPoint [lockless] */ | 171 | struct urb *nep_urb; /* Notification EndPoint [lockless] */ |
172 | struct edc nep_edc; | 172 | struct edc nep_edc; |
173 | void *nep_buffer; | 173 | void *nep_buffer; |
174 | size_t nep_buffer_size; | 174 | size_t nep_buffer_size; |
175 | 175 | ||
176 | atomic_t notifs_queued; | 176 | atomic_t notifs_queued; |
177 | 177 | ||
178 | u16 rpipes; | 178 | u16 rpipes; |
179 | unsigned long *rpipe_bm; /* rpipe usage bitmap */ | 179 | unsigned long *rpipe_bm; /* rpipe usage bitmap */ |
180 | spinlock_t rpipe_bm_lock; /* protect rpipe_bm */ | 180 | spinlock_t rpipe_bm_lock; /* protect rpipe_bm */ |
181 | struct mutex rpipe_mutex; /* assigning resources to endpoints */ | 181 | struct mutex rpipe_mutex; /* assigning resources to endpoints */ |
182 | 182 | ||
183 | struct urb *dti_urb; /* URB for reading xfer results */ | 183 | struct urb *dti_urb; /* URB for reading xfer results */ |
184 | struct urb *buf_in_urb; /* URB for reading data in */ | 184 | struct urb *buf_in_urb; /* URB for reading data in */ |
185 | struct edc dti_edc; /* DTI error density counter */ | 185 | struct edc dti_edc; /* DTI error density counter */ |
186 | struct wa_xfer_result *xfer_result; /* real size = dti_ep maxpktsize */ | 186 | struct wa_xfer_result *xfer_result; /* real size = dti_ep maxpktsize */ |
187 | size_t xfer_result_size; | 187 | size_t xfer_result_size; |
188 | 188 | ||
189 | s32 status; /* For reading status */ | 189 | s32 status; /* For reading status */ |
190 | 190 | ||
191 | struct list_head xfer_list; | 191 | struct list_head xfer_list; |
192 | struct list_head xfer_delayed_list; | 192 | struct list_head xfer_delayed_list; |
193 | spinlock_t xfer_list_lock; | 193 | spinlock_t xfer_list_lock; |
194 | struct work_struct xfer_work; | 194 | struct work_struct xfer_work; |
195 | atomic_t xfer_id_count; | 195 | atomic_t xfer_id_count; |
196 | }; | 196 | }; |
197 | 197 | ||
198 | 198 | ||
199 | extern int wa_create(struct wahc *wa, struct usb_interface *iface); | 199 | extern int wa_create(struct wahc *wa, struct usb_interface *iface); |
200 | extern void __wa_destroy(struct wahc *wa); | 200 | extern void __wa_destroy(struct wahc *wa); |
201 | void wa_reset_all(struct wahc *wa); | 201 | void wa_reset_all(struct wahc *wa); |
202 | 202 | ||
203 | 203 | ||
204 | /* Miscellaneous constants */ | 204 | /* Miscellaneous constants */ |
205 | enum { | 205 | enum { |
206 | /** Max number of EPROTO errors we tolerate on the NEP in a | 206 | /** Max number of EPROTO errors we tolerate on the NEP in a |
207 | * period of time */ | 207 | * period of time */ |
208 | HWAHC_EPROTO_MAX = 16, | 208 | HWAHC_EPROTO_MAX = 16, |
209 | /** Period of time for EPROTO errors (in jiffies) */ | 209 | /** Period of time for EPROTO errors (in jiffies) */ |
210 | HWAHC_EPROTO_PERIOD = 4 * HZ, | 210 | HWAHC_EPROTO_PERIOD = 4 * HZ, |
211 | }; | 211 | }; |
212 | 212 | ||
213 | 213 | ||
214 | /* Notification endpoint handling */ | 214 | /* Notification endpoint handling */ |
215 | extern int wa_nep_create(struct wahc *, struct usb_interface *); | 215 | extern int wa_nep_create(struct wahc *, struct usb_interface *); |
216 | extern void wa_nep_destroy(struct wahc *); | 216 | extern void wa_nep_destroy(struct wahc *); |
217 | 217 | ||
218 | static inline int wa_nep_arm(struct wahc *wa, gfp_t gfp_mask) | 218 | static inline int wa_nep_arm(struct wahc *wa, gfp_t gfp_mask) |
219 | { | 219 | { |
220 | struct urb *urb = wa->nep_urb; | 220 | struct urb *urb = wa->nep_urb; |
221 | urb->transfer_buffer = wa->nep_buffer; | 221 | urb->transfer_buffer = wa->nep_buffer; |
222 | urb->transfer_buffer_length = wa->nep_buffer_size; | 222 | urb->transfer_buffer_length = wa->nep_buffer_size; |
223 | return usb_submit_urb(urb, gfp_mask); | 223 | return usb_submit_urb(urb, gfp_mask); |
224 | } | 224 | } |
225 | 225 | ||
226 | static inline void wa_nep_disarm(struct wahc *wa) | 226 | static inline void wa_nep_disarm(struct wahc *wa) |
227 | { | 227 | { |
228 | usb_kill_urb(wa->nep_urb); | 228 | usb_kill_urb(wa->nep_urb); |
229 | } | 229 | } |
230 | 230 | ||
231 | 231 | ||
232 | /* RPipes */ | 232 | /* RPipes */ |
233 | static inline void wa_rpipe_init(struct wahc *wa) | 233 | static inline void wa_rpipe_init(struct wahc *wa) |
234 | { | 234 | { |
235 | spin_lock_init(&wa->rpipe_bm_lock); | 235 | spin_lock_init(&wa->rpipe_bm_lock); |
236 | mutex_init(&wa->rpipe_mutex); | 236 | mutex_init(&wa->rpipe_mutex); |
237 | } | 237 | } |
238 | 238 | ||
239 | static inline void wa_init(struct wahc *wa) | 239 | static inline void wa_init(struct wahc *wa) |
240 | { | 240 | { |
241 | edc_init(&wa->nep_edc); | 241 | edc_init(&wa->nep_edc); |
242 | atomic_set(&wa->notifs_queued, 0); | 242 | atomic_set(&wa->notifs_queued, 0); |
243 | wa_rpipe_init(wa); | 243 | wa_rpipe_init(wa); |
244 | edc_init(&wa->dti_edc); | 244 | edc_init(&wa->dti_edc); |
245 | INIT_LIST_HEAD(&wa->xfer_list); | 245 | INIT_LIST_HEAD(&wa->xfer_list); |
246 | INIT_LIST_HEAD(&wa->xfer_delayed_list); | 246 | INIT_LIST_HEAD(&wa->xfer_delayed_list); |
247 | spin_lock_init(&wa->xfer_list_lock); | 247 | spin_lock_init(&wa->xfer_list_lock); |
248 | INIT_WORK(&wa->xfer_work, wa_urb_enqueue_run); | 248 | INIT_WORK(&wa->xfer_work, wa_urb_enqueue_run); |
249 | atomic_set(&wa->xfer_id_count, 1); | 249 | atomic_set(&wa->xfer_id_count, 1); |
250 | } | 250 | } |
251 | 251 | ||
252 | /** | 252 | /** |
253 | * Destroy a pipe (when refcount drops to zero) | 253 | * Destroy a pipe (when refcount drops to zero) |
254 | * | 254 | * |
255 | * Assumes it has been moved to the "QUIESCING" state. | 255 | * Assumes it has been moved to the "QUIESCING" state. |
256 | */ | 256 | */ |
257 | struct wa_xfer; | 257 | struct wa_xfer; |
258 | extern void rpipe_destroy(struct kref *_rpipe); | 258 | extern void rpipe_destroy(struct kref *_rpipe); |
259 | static inline | 259 | static inline |
260 | void __rpipe_get(struct wa_rpipe *rpipe) | 260 | void __rpipe_get(struct wa_rpipe *rpipe) |
261 | { | 261 | { |
262 | kref_get(&rpipe->refcnt); | 262 | kref_get(&rpipe->refcnt); |
263 | } | 263 | } |
264 | extern int rpipe_get_by_ep(struct wahc *, struct usb_host_endpoint *, | 264 | extern int rpipe_get_by_ep(struct wahc *, struct usb_host_endpoint *, |
265 | struct urb *, gfp_t); | 265 | struct urb *, gfp_t); |
266 | static inline void rpipe_put(struct wa_rpipe *rpipe) | 266 | static inline void rpipe_put(struct wa_rpipe *rpipe) |
267 | { | 267 | { |
268 | kref_put(&rpipe->refcnt, rpipe_destroy); | 268 | kref_put(&rpipe->refcnt, rpipe_destroy); |
269 | 269 | ||
270 | } | 270 | } |
271 | extern void rpipe_ep_disable(struct wahc *, struct usb_host_endpoint *); | 271 | extern void rpipe_ep_disable(struct wahc *, struct usb_host_endpoint *); |
272 | extern int wa_rpipes_create(struct wahc *); | 272 | extern int wa_rpipes_create(struct wahc *); |
273 | extern void wa_rpipes_destroy(struct wahc *); | 273 | extern void wa_rpipes_destroy(struct wahc *); |
274 | static inline void rpipe_avail_dec(struct wa_rpipe *rpipe) | 274 | static inline void rpipe_avail_dec(struct wa_rpipe *rpipe) |
275 | { | 275 | { |
276 | atomic_dec(&rpipe->segs_available); | 276 | atomic_dec(&rpipe->segs_available); |
277 | } | 277 | } |
278 | 278 | ||
279 | /** | 279 | /** |
280 | * Returns true if the rpipe is ready to submit more segments. | 280 | * Returns true if the rpipe is ready to submit more segments. |
281 | */ | 281 | */ |
282 | static inline int rpipe_avail_inc(struct wa_rpipe *rpipe) | 282 | static inline int rpipe_avail_inc(struct wa_rpipe *rpipe) |
283 | { | 283 | { |
284 | return atomic_inc_return(&rpipe->segs_available) > 0 | 284 | return atomic_inc_return(&rpipe->segs_available) > 0 |
285 | && !list_empty(&rpipe->seg_list); | 285 | && !list_empty(&rpipe->seg_list); |
286 | } | 286 | } |
287 | 287 | ||
288 | 288 | ||
289 | /* Transferring data */ | 289 | /* Transferring data */ |
290 | extern int wa_urb_enqueue(struct wahc *, struct usb_host_endpoint *, | 290 | extern int wa_urb_enqueue(struct wahc *, struct usb_host_endpoint *, |
291 | struct urb *, gfp_t); | 291 | struct urb *, gfp_t); |
292 | extern int wa_urb_dequeue(struct wahc *, struct urb *); | 292 | extern int wa_urb_dequeue(struct wahc *, struct urb *); |
293 | extern void wa_handle_notif_xfer(struct wahc *, struct wa_notif_hdr *); | 293 | extern void wa_handle_notif_xfer(struct wahc *, struct wa_notif_hdr *); |
294 | 294 | ||
295 | 295 | ||
296 | /* Misc | 296 | /* Misc |
297 | * | 297 | * |
298 | * FIXME: Refcounting for the actual @hwahc object is not correct; I | 298 | * FIXME: Refcounting for the actual @hwahc object is not correct; I |
299 | * mean, this should be refcounting on the HCD underneath, but | 299 | * mean, this should be refcounting on the HCD underneath, but |
300 | * it is not. In any case, the semantics for HCD refcounting | 300 | * it is not. In any case, the semantics for HCD refcounting |
301 | * are *weird*...on refcount reaching zero it just frees | 301 | * are *weird*...on refcount reaching zero it just frees |
302 | * it...no RC specific function is called...unless I miss | 302 | * it...no RC specific function is called...unless I miss |
303 | * something. | 303 | * something. |
304 | * | 304 | * |
305 | * FIXME: has to go away in favour of an 'struct' hcd based sollution | 305 | * FIXME: has to go away in favour of an 'struct' hcd based sollution |
306 | */ | 306 | */ |
307 | static inline struct wahc *wa_get(struct wahc *wa) | 307 | static inline struct wahc *wa_get(struct wahc *wa) |
308 | { | 308 | { |
309 | usb_get_intf(wa->usb_iface); | 309 | usb_get_intf(wa->usb_iface); |
310 | return wa; | 310 | return wa; |
311 | } | 311 | } |
312 | 312 | ||
313 | static inline void wa_put(struct wahc *wa) | 313 | static inline void wa_put(struct wahc *wa) |
314 | { | 314 | { |
315 | usb_put_intf(wa->usb_iface); | 315 | usb_put_intf(wa->usb_iface); |
316 | } | 316 | } |
317 | 317 | ||
318 | 318 | ||
319 | static inline int __wa_feature(struct wahc *wa, unsigned op, u16 feature) | 319 | static inline int __wa_feature(struct wahc *wa, unsigned op, u16 feature) |
320 | { | 320 | { |
321 | return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | 321 | return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), |
322 | op ? USB_REQ_SET_FEATURE : USB_REQ_CLEAR_FEATURE, | 322 | op ? USB_REQ_SET_FEATURE : USB_REQ_CLEAR_FEATURE, |
323 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 323 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, |
324 | feature, | 324 | feature, |
325 | wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, | 325 | wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, |
326 | NULL, 0, 1000 /* FIXME: arbitrary */); | 326 | NULL, 0, 1000 /* FIXME: arbitrary */); |
327 | } | 327 | } |
328 | 328 | ||
329 | 329 | ||
330 | static inline int __wa_set_feature(struct wahc *wa, u16 feature) | 330 | static inline int __wa_set_feature(struct wahc *wa, u16 feature) |
331 | { | 331 | { |
332 | return __wa_feature(wa, 1, feature); | 332 | return __wa_feature(wa, 1, feature); |
333 | } | 333 | } |
334 | 334 | ||
335 | 335 | ||
336 | static inline int __wa_clear_feature(struct wahc *wa, u16 feature) | 336 | static inline int __wa_clear_feature(struct wahc *wa, u16 feature) |
337 | { | 337 | { |
338 | return __wa_feature(wa, 0, feature); | 338 | return __wa_feature(wa, 0, feature); |
339 | } | 339 | } |
340 | 340 | ||
341 | 341 | ||
342 | /** | 342 | /** |
343 | * Return the status of a Wire Adapter | 343 | * Return the status of a Wire Adapter |
344 | * | 344 | * |
345 | * @wa: Wire Adapter instance | 345 | * @wa: Wire Adapter instance |
346 | * @returns < 0 errno code on error, or status bitmap as described | 346 | * @returns < 0 errno code on error, or status bitmap as described |
347 | * in WUSB1.0[8.3.1.6]. | 347 | * in WUSB1.0[8.3.1.6]. |
348 | * | 348 | * |
349 | * NOTE: need malloc, some arches don't take USB from the stack | 349 | * NOTE: need malloc, some arches don't take USB from the stack |
350 | */ | 350 | */ |
351 | static inline | 351 | static inline |
352 | s32 __wa_get_status(struct wahc *wa) | 352 | s32 __wa_get_status(struct wahc *wa) |
353 | { | 353 | { |
354 | s32 result; | 354 | s32 result; |
355 | result = usb_control_msg( | 355 | result = usb_control_msg( |
356 | wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), | 356 | wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), |
357 | USB_REQ_GET_STATUS, | 357 | USB_REQ_GET_STATUS, |
358 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 358 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, |
359 | 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, | 359 | 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, |
360 | &wa->status, sizeof(wa->status), | 360 | &wa->status, sizeof(wa->status), |
361 | 1000 /* FIXME: arbitrary */); | 361 | 1000 /* FIXME: arbitrary */); |
362 | if (result >= 0) | 362 | if (result >= 0) |
363 | result = wa->status; | 363 | result = wa->status; |
364 | return result; | 364 | return result; |
365 | } | 365 | } |
366 | 366 | ||
367 | 367 | ||
368 | /** | 368 | /** |
369 | * Waits until the Wire Adapter's status matches @mask/@value | 369 | * Waits until the Wire Adapter's status matches @mask/@value |
370 | * | 370 | * |
371 | * @wa: Wire Adapter instance. | 371 | * @wa: Wire Adapter instance. |
372 | * @returns < 0 errno code on error, otherwise status. | 372 | * @returns < 0 errno code on error, otherwise status. |
373 | * | 373 | * |
374 | * Loop until the WAs status matches the mask and value (status & mask | 374 | * Loop until the WAs status matches the mask and value (status & mask |
375 | * == value). Timeout if it doesn't happen. | 375 | * == value). Timeout if it doesn't happen. |
376 | * | 376 | * |
377 | * FIXME: is there an official specification on how long status | 377 | * FIXME: is there an official specification on how long status |
378 | * changes can take? | 378 | * changes can take? |
379 | */ | 379 | */ |
380 | static inline s32 __wa_wait_status(struct wahc *wa, u32 mask, u32 value) | 380 | static inline s32 __wa_wait_status(struct wahc *wa, u32 mask, u32 value) |
381 | { | 381 | { |
382 | s32 result; | 382 | s32 result; |
383 | unsigned loops = 10; | 383 | unsigned loops = 10; |
384 | do { | 384 | do { |
385 | msleep(50); | 385 | msleep(50); |
386 | result = __wa_get_status(wa); | 386 | result = __wa_get_status(wa); |
387 | if ((result & mask) == value) | 387 | if ((result & mask) == value) |
388 | break; | 388 | break; |
389 | if (loops-- == 0) { | 389 | if (loops-- == 0) { |
390 | result = -ETIMEDOUT; | 390 | result = -ETIMEDOUT; |
391 | break; | 391 | break; |
392 | } | 392 | } |
393 | } while (result >= 0); | 393 | } while (result >= 0); |
394 | return result; | 394 | return result; |
395 | } | 395 | } |
396 | 396 | ||
397 | 397 | ||
398 | /** Command @hwahc to stop, @returns 0 if ok, < 0 errno code on error */ | 398 | /** Command @hwahc to stop, @returns 0 if ok, < 0 errno code on error */ |
399 | static inline int __wa_stop(struct wahc *wa) | 399 | static inline int __wa_stop(struct wahc *wa) |
400 | { | 400 | { |
401 | int result; | 401 | int result; |
402 | struct device *dev = &wa->usb_iface->dev; | 402 | struct device *dev = &wa->usb_iface->dev; |
403 | 403 | ||
404 | result = __wa_clear_feature(wa, WA_ENABLE); | 404 | result = __wa_clear_feature(wa, WA_ENABLE); |
405 | if (result < 0 && result != -ENODEV) { | 405 | if (result < 0 && result != -ENODEV) { |
406 | dev_err(dev, "error commanding HC to stop: %d\n", result); | 406 | dev_err(dev, "error commanding HC to stop: %d\n", result); |
407 | goto out; | 407 | goto out; |
408 | } | 408 | } |
409 | result = __wa_wait_status(wa, WA_ENABLE, 0); | 409 | result = __wa_wait_status(wa, WA_ENABLE, 0); |
410 | if (result < 0 && result != -ENODEV) | 410 | if (result < 0 && result != -ENODEV) |
411 | dev_err(dev, "error waiting for HC to stop: %d\n", result); | 411 | dev_err(dev, "error waiting for HC to stop: %d\n", result); |
412 | out: | 412 | out: |
413 | return 0; | 413 | return 0; |
414 | } | 414 | } |
415 | 415 | ||
416 | 416 | ||
417 | #endif /* #ifndef __HWAHC_INTERNAL_H__ */ | 417 | #endif /* #ifndef __HWAHC_INTERNAL_H__ */ |
418 | 418 |
include/linux/mISDNif.h
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * Author Karsten Keil <kkeil@novell.com> | 3 | * Author Karsten Keil <kkeil@novell.com> |
4 | * | 4 | * |
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | 5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> |
6 | * | 6 | * |
7 | * This code is free software; you can redistribute it and/or modify | 7 | * This code is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE | 8 | * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE |
9 | * version 2.1 as published by the Free Software Foundation. | 9 | * version 2.1 as published by the Free Software Foundation. |
10 | * | 10 | * |
11 | * This code is distributed in the hope that it will be useful, | 11 | * This code is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU LESSER GENERAL PUBLIC LICENSE for more details. | 14 | * GNU LESSER GENERAL PUBLIC LICENSE for more details. |
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #ifndef mISDNIF_H | 18 | #ifndef mISDNIF_H |
19 | #define mISDNIF_H | 19 | #define mISDNIF_H |
20 | 20 | ||
21 | #include <stdarg.h> | 21 | #include <stdarg.h> |
22 | #include <linux/types.h> | 22 | #include <linux/types.h> |
23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
24 | #include <linux/socket.h> | 24 | #include <linux/socket.h> |
25 | 25 | ||
26 | /* | 26 | /* |
27 | * ABI Version 32 bit | 27 | * ABI Version 32 bit |
28 | * | 28 | * |
29 | * <8 bit> Major version | 29 | * <8 bit> Major version |
30 | * - changed if any interface become backwards incompatible | 30 | * - changed if any interface become backwards incompatible |
31 | * | 31 | * |
32 | * <8 bit> Minor version | 32 | * <8 bit> Minor version |
33 | * - changed if any interface is extended but backwards compatible | 33 | * - changed if any interface is extended but backwards compatible |
34 | * | 34 | * |
35 | * <16 bit> Release number | 35 | * <16 bit> Release number |
36 | * - should be incremented on every checkin | 36 | * - should be incremented on every checkin |
37 | */ | 37 | */ |
38 | #define MISDN_MAJOR_VERSION 1 | 38 | #define MISDN_MAJOR_VERSION 1 |
39 | #define MISDN_MINOR_VERSION 1 | 39 | #define MISDN_MINOR_VERSION 1 |
40 | #define MISDN_RELEASE 21 | 40 | #define MISDN_RELEASE 21 |
41 | 41 | ||
42 | /* primitives for information exchange | 42 | /* primitives for information exchange |
43 | * generell format | 43 | * generell format |
44 | * <16 bit 0 > | 44 | * <16 bit 0 > |
45 | * <8 bit command> | 45 | * <8 bit command> |
46 | * BIT 8 = 1 LAYER private | 46 | * BIT 8 = 1 LAYER private |
47 | * BIT 7 = 1 answer | 47 | * BIT 7 = 1 answer |
48 | * BIT 6 = 1 DATA | 48 | * BIT 6 = 1 DATA |
49 | * <8 bit target layer mask> | 49 | * <8 bit target layer mask> |
50 | * | 50 | * |
51 | * Layer = 00 is reserved for general commands | 51 | * Layer = 00 is reserved for general commands |
52 | Layer = 01 L2 -> HW | 52 | Layer = 01 L2 -> HW |
53 | Layer = 02 HW -> L2 | 53 | Layer = 02 HW -> L2 |
54 | Layer = 04 L3 -> L2 | 54 | Layer = 04 L3 -> L2 |
55 | Layer = 08 L2 -> L3 | 55 | Layer = 08 L2 -> L3 |
56 | * Layer = FF is reserved for broadcast commands | 56 | * Layer = FF is reserved for broadcast commands |
57 | */ | 57 | */ |
58 | 58 | ||
59 | #define MISDN_CMDMASK 0xff00 | 59 | #define MISDN_CMDMASK 0xff00 |
60 | #define MISDN_LAYERMASK 0x00ff | 60 | #define MISDN_LAYERMASK 0x00ff |
61 | 61 | ||
62 | /* generell commands */ | 62 | /* generell commands */ |
63 | #define OPEN_CHANNEL 0x0100 | 63 | #define OPEN_CHANNEL 0x0100 |
64 | #define CLOSE_CHANNEL 0x0200 | 64 | #define CLOSE_CHANNEL 0x0200 |
65 | #define CONTROL_CHANNEL 0x0300 | 65 | #define CONTROL_CHANNEL 0x0300 |
66 | #define CHECK_DATA 0x0400 | 66 | #define CHECK_DATA 0x0400 |
67 | 67 | ||
68 | /* layer 2 -> layer 1 */ | 68 | /* layer 2 -> layer 1 */ |
69 | #define PH_ACTIVATE_REQ 0x0101 | 69 | #define PH_ACTIVATE_REQ 0x0101 |
70 | #define PH_DEACTIVATE_REQ 0x0201 | 70 | #define PH_DEACTIVATE_REQ 0x0201 |
71 | #define PH_DATA_REQ 0x2001 | 71 | #define PH_DATA_REQ 0x2001 |
72 | #define MPH_ACTIVATE_REQ 0x0501 | 72 | #define MPH_ACTIVATE_REQ 0x0501 |
73 | #define MPH_DEACTIVATE_REQ 0x0601 | 73 | #define MPH_DEACTIVATE_REQ 0x0601 |
74 | #define MPH_INFORMATION_REQ 0x0701 | 74 | #define MPH_INFORMATION_REQ 0x0701 |
75 | #define PH_CONTROL_REQ 0x0801 | 75 | #define PH_CONTROL_REQ 0x0801 |
76 | 76 | ||
77 | /* layer 1 -> layer 2 */ | 77 | /* layer 1 -> layer 2 */ |
78 | #define PH_ACTIVATE_IND 0x0102 | 78 | #define PH_ACTIVATE_IND 0x0102 |
79 | #define PH_ACTIVATE_CNF 0x4102 | 79 | #define PH_ACTIVATE_CNF 0x4102 |
80 | #define PH_DEACTIVATE_IND 0x0202 | 80 | #define PH_DEACTIVATE_IND 0x0202 |
81 | #define PH_DEACTIVATE_CNF 0x4202 | 81 | #define PH_DEACTIVATE_CNF 0x4202 |
82 | #define PH_DATA_IND 0x2002 | 82 | #define PH_DATA_IND 0x2002 |
83 | #define PH_DATA_E_IND 0x3002 | 83 | #define PH_DATA_E_IND 0x3002 |
84 | #define MPH_ACTIVATE_IND 0x0502 | 84 | #define MPH_ACTIVATE_IND 0x0502 |
85 | #define MPH_DEACTIVATE_IND 0x0602 | 85 | #define MPH_DEACTIVATE_IND 0x0602 |
86 | #define MPH_INFORMATION_IND 0x0702 | 86 | #define MPH_INFORMATION_IND 0x0702 |
87 | #define PH_DATA_CNF 0x6002 | 87 | #define PH_DATA_CNF 0x6002 |
88 | #define PH_CONTROL_IND 0x0802 | 88 | #define PH_CONTROL_IND 0x0802 |
89 | #define PH_CONTROL_CNF 0x4802 | 89 | #define PH_CONTROL_CNF 0x4802 |
90 | 90 | ||
91 | /* layer 3 -> layer 2 */ | 91 | /* layer 3 -> layer 2 */ |
92 | #define DL_ESTABLISH_REQ 0x1004 | 92 | #define DL_ESTABLISH_REQ 0x1004 |
93 | #define DL_RELEASE_REQ 0x1104 | 93 | #define DL_RELEASE_REQ 0x1104 |
94 | #define DL_DATA_REQ 0x3004 | 94 | #define DL_DATA_REQ 0x3004 |
95 | #define DL_UNITDATA_REQ 0x3104 | 95 | #define DL_UNITDATA_REQ 0x3104 |
96 | #define DL_INFORMATION_REQ 0x0004 | 96 | #define DL_INFORMATION_REQ 0x0004 |
97 | 97 | ||
98 | /* layer 2 -> layer 3 */ | 98 | /* layer 2 -> layer 3 */ |
99 | #define DL_ESTABLISH_IND 0x1008 | 99 | #define DL_ESTABLISH_IND 0x1008 |
100 | #define DL_ESTABLISH_CNF 0x5008 | 100 | #define DL_ESTABLISH_CNF 0x5008 |
101 | #define DL_RELEASE_IND 0x1108 | 101 | #define DL_RELEASE_IND 0x1108 |
102 | #define DL_RELEASE_CNF 0x5108 | 102 | #define DL_RELEASE_CNF 0x5108 |
103 | #define DL_DATA_IND 0x3008 | 103 | #define DL_DATA_IND 0x3008 |
104 | #define DL_UNITDATA_IND 0x3108 | 104 | #define DL_UNITDATA_IND 0x3108 |
105 | #define DL_INFORMATION_IND 0x0008 | 105 | #define DL_INFORMATION_IND 0x0008 |
106 | 106 | ||
107 | /* intern layer 2 managment */ | 107 | /* intern layer 2 management */ |
108 | #define MDL_ASSIGN_REQ 0x1804 | 108 | #define MDL_ASSIGN_REQ 0x1804 |
109 | #define MDL_ASSIGN_IND 0x1904 | 109 | #define MDL_ASSIGN_IND 0x1904 |
110 | #define MDL_REMOVE_REQ 0x1A04 | 110 | #define MDL_REMOVE_REQ 0x1A04 |
111 | #define MDL_REMOVE_IND 0x1B04 | 111 | #define MDL_REMOVE_IND 0x1B04 |
112 | #define MDL_STATUS_UP_IND 0x1C04 | 112 | #define MDL_STATUS_UP_IND 0x1C04 |
113 | #define MDL_STATUS_DOWN_IND 0x1D04 | 113 | #define MDL_STATUS_DOWN_IND 0x1D04 |
114 | #define MDL_STATUS_UI_IND 0x1E04 | 114 | #define MDL_STATUS_UI_IND 0x1E04 |
115 | #define MDL_ERROR_IND 0x1F04 | 115 | #define MDL_ERROR_IND 0x1F04 |
116 | #define MDL_ERROR_RSP 0x5F04 | 116 | #define MDL_ERROR_RSP 0x5F04 |
117 | 117 | ||
118 | /* DL_INFORMATION_IND types */ | 118 | /* DL_INFORMATION_IND types */ |
119 | #define DL_INFO_L2_CONNECT 0x0001 | 119 | #define DL_INFO_L2_CONNECT 0x0001 |
120 | #define DL_INFO_L2_REMOVED 0x0002 | 120 | #define DL_INFO_L2_REMOVED 0x0002 |
121 | 121 | ||
122 | /* PH_CONTROL types */ | 122 | /* PH_CONTROL types */ |
123 | /* TOUCH TONE IS 0x20XX XX "0"..."9", "A","B","C","D","*","#" */ | 123 | /* TOUCH TONE IS 0x20XX XX "0"..."9", "A","B","C","D","*","#" */ |
124 | #define DTMF_TONE_VAL 0x2000 | 124 | #define DTMF_TONE_VAL 0x2000 |
125 | #define DTMF_TONE_MASK 0x007F | 125 | #define DTMF_TONE_MASK 0x007F |
126 | #define DTMF_TONE_START 0x2100 | 126 | #define DTMF_TONE_START 0x2100 |
127 | #define DTMF_TONE_STOP 0x2200 | 127 | #define DTMF_TONE_STOP 0x2200 |
128 | #define DTMF_HFC_COEF 0x4000 | 128 | #define DTMF_HFC_COEF 0x4000 |
129 | #define DSP_CONF_JOIN 0x2403 | 129 | #define DSP_CONF_JOIN 0x2403 |
130 | #define DSP_CONF_SPLIT 0x2404 | 130 | #define DSP_CONF_SPLIT 0x2404 |
131 | #define DSP_RECEIVE_OFF 0x2405 | 131 | #define DSP_RECEIVE_OFF 0x2405 |
132 | #define DSP_RECEIVE_ON 0x2406 | 132 | #define DSP_RECEIVE_ON 0x2406 |
133 | #define DSP_ECHO_ON 0x2407 | 133 | #define DSP_ECHO_ON 0x2407 |
134 | #define DSP_ECHO_OFF 0x2408 | 134 | #define DSP_ECHO_OFF 0x2408 |
135 | #define DSP_MIX_ON 0x2409 | 135 | #define DSP_MIX_ON 0x2409 |
136 | #define DSP_MIX_OFF 0x240a | 136 | #define DSP_MIX_OFF 0x240a |
137 | #define DSP_DELAY 0x240b | 137 | #define DSP_DELAY 0x240b |
138 | #define DSP_JITTER 0x240c | 138 | #define DSP_JITTER 0x240c |
139 | #define DSP_TXDATA_ON 0x240d | 139 | #define DSP_TXDATA_ON 0x240d |
140 | #define DSP_TXDATA_OFF 0x240e | 140 | #define DSP_TXDATA_OFF 0x240e |
141 | #define DSP_TX_DEJITTER 0x240f | 141 | #define DSP_TX_DEJITTER 0x240f |
142 | #define DSP_TX_DEJ_OFF 0x2410 | 142 | #define DSP_TX_DEJ_OFF 0x2410 |
143 | #define DSP_TONE_PATT_ON 0x2411 | 143 | #define DSP_TONE_PATT_ON 0x2411 |
144 | #define DSP_TONE_PATT_OFF 0x2412 | 144 | #define DSP_TONE_PATT_OFF 0x2412 |
145 | #define DSP_VOL_CHANGE_TX 0x2413 | 145 | #define DSP_VOL_CHANGE_TX 0x2413 |
146 | #define DSP_VOL_CHANGE_RX 0x2414 | 146 | #define DSP_VOL_CHANGE_RX 0x2414 |
147 | #define DSP_BF_ENABLE_KEY 0x2415 | 147 | #define DSP_BF_ENABLE_KEY 0x2415 |
148 | #define DSP_BF_DISABLE 0x2416 | 148 | #define DSP_BF_DISABLE 0x2416 |
149 | #define DSP_BF_ACCEPT 0x2416 | 149 | #define DSP_BF_ACCEPT 0x2416 |
150 | #define DSP_BF_REJECT 0x2417 | 150 | #define DSP_BF_REJECT 0x2417 |
151 | #define DSP_PIPELINE_CFG 0x2418 | 151 | #define DSP_PIPELINE_CFG 0x2418 |
152 | #define HFC_VOL_CHANGE_TX 0x2601 | 152 | #define HFC_VOL_CHANGE_TX 0x2601 |
153 | #define HFC_VOL_CHANGE_RX 0x2602 | 153 | #define HFC_VOL_CHANGE_RX 0x2602 |
154 | #define HFC_SPL_LOOP_ON 0x2603 | 154 | #define HFC_SPL_LOOP_ON 0x2603 |
155 | #define HFC_SPL_LOOP_OFF 0x2604 | 155 | #define HFC_SPL_LOOP_OFF 0x2604 |
156 | /* for T30 FAX and analog modem */ | 156 | /* for T30 FAX and analog modem */ |
157 | #define HW_MOD_FRM 0x4000 | 157 | #define HW_MOD_FRM 0x4000 |
158 | #define HW_MOD_FRH 0x4001 | 158 | #define HW_MOD_FRH 0x4001 |
159 | #define HW_MOD_FTM 0x4002 | 159 | #define HW_MOD_FTM 0x4002 |
160 | #define HW_MOD_FTH 0x4003 | 160 | #define HW_MOD_FTH 0x4003 |
161 | #define HW_MOD_FTS 0x4004 | 161 | #define HW_MOD_FTS 0x4004 |
162 | #define HW_MOD_CONNECT 0x4010 | 162 | #define HW_MOD_CONNECT 0x4010 |
163 | #define HW_MOD_OK 0x4011 | 163 | #define HW_MOD_OK 0x4011 |
164 | #define HW_MOD_NOCARR 0x4012 | 164 | #define HW_MOD_NOCARR 0x4012 |
165 | #define HW_MOD_FCERROR 0x4013 | 165 | #define HW_MOD_FCERROR 0x4013 |
166 | #define HW_MOD_READY 0x4014 | 166 | #define HW_MOD_READY 0x4014 |
167 | #define HW_MOD_LASTDATA 0x4015 | 167 | #define HW_MOD_LASTDATA 0x4015 |
168 | 168 | ||
169 | /* DSP_TONE_PATT_ON parameter */ | 169 | /* DSP_TONE_PATT_ON parameter */ |
170 | #define TONE_OFF 0x0000 | 170 | #define TONE_OFF 0x0000 |
171 | #define TONE_GERMAN_DIALTONE 0x0001 | 171 | #define TONE_GERMAN_DIALTONE 0x0001 |
172 | #define TONE_GERMAN_OLDDIALTONE 0x0002 | 172 | #define TONE_GERMAN_OLDDIALTONE 0x0002 |
173 | #define TONE_AMERICAN_DIALTONE 0x0003 | 173 | #define TONE_AMERICAN_DIALTONE 0x0003 |
174 | #define TONE_GERMAN_DIALPBX 0x0004 | 174 | #define TONE_GERMAN_DIALPBX 0x0004 |
175 | #define TONE_GERMAN_OLDDIALPBX 0x0005 | 175 | #define TONE_GERMAN_OLDDIALPBX 0x0005 |
176 | #define TONE_AMERICAN_DIALPBX 0x0006 | 176 | #define TONE_AMERICAN_DIALPBX 0x0006 |
177 | #define TONE_GERMAN_RINGING 0x0007 | 177 | #define TONE_GERMAN_RINGING 0x0007 |
178 | #define TONE_GERMAN_OLDRINGING 0x0008 | 178 | #define TONE_GERMAN_OLDRINGING 0x0008 |
179 | #define TONE_AMERICAN_RINGPBX 0x000b | 179 | #define TONE_AMERICAN_RINGPBX 0x000b |
180 | #define TONE_GERMAN_RINGPBX 0x000c | 180 | #define TONE_GERMAN_RINGPBX 0x000c |
181 | #define TONE_GERMAN_OLDRINGPBX 0x000d | 181 | #define TONE_GERMAN_OLDRINGPBX 0x000d |
182 | #define TONE_AMERICAN_RINGING 0x000e | 182 | #define TONE_AMERICAN_RINGING 0x000e |
183 | #define TONE_GERMAN_BUSY 0x000f | 183 | #define TONE_GERMAN_BUSY 0x000f |
184 | #define TONE_GERMAN_OLDBUSY 0x0010 | 184 | #define TONE_GERMAN_OLDBUSY 0x0010 |
185 | #define TONE_AMERICAN_BUSY 0x0011 | 185 | #define TONE_AMERICAN_BUSY 0x0011 |
186 | #define TONE_GERMAN_HANGUP 0x0012 | 186 | #define TONE_GERMAN_HANGUP 0x0012 |
187 | #define TONE_GERMAN_OLDHANGUP 0x0013 | 187 | #define TONE_GERMAN_OLDHANGUP 0x0013 |
188 | #define TONE_AMERICAN_HANGUP 0x0014 | 188 | #define TONE_AMERICAN_HANGUP 0x0014 |
189 | #define TONE_SPECIAL_INFO 0x0015 | 189 | #define TONE_SPECIAL_INFO 0x0015 |
190 | #define TONE_GERMAN_GASSENBESETZT 0x0016 | 190 | #define TONE_GERMAN_GASSENBESETZT 0x0016 |
191 | #define TONE_GERMAN_AUFSCHALTTON 0x0016 | 191 | #define TONE_GERMAN_AUFSCHALTTON 0x0016 |
192 | 192 | ||
193 | /* MPH_INFORMATION_IND */ | 193 | /* MPH_INFORMATION_IND */ |
194 | #define L1_SIGNAL_LOS_OFF 0x0010 | 194 | #define L1_SIGNAL_LOS_OFF 0x0010 |
195 | #define L1_SIGNAL_LOS_ON 0x0011 | 195 | #define L1_SIGNAL_LOS_ON 0x0011 |
196 | #define L1_SIGNAL_AIS_OFF 0x0012 | 196 | #define L1_SIGNAL_AIS_OFF 0x0012 |
197 | #define L1_SIGNAL_AIS_ON 0x0013 | 197 | #define L1_SIGNAL_AIS_ON 0x0013 |
198 | #define L1_SIGNAL_RDI_OFF 0x0014 | 198 | #define L1_SIGNAL_RDI_OFF 0x0014 |
199 | #define L1_SIGNAL_RDI_ON 0x0015 | 199 | #define L1_SIGNAL_RDI_ON 0x0015 |
200 | #define L1_SIGNAL_SLIP_RX 0x0020 | 200 | #define L1_SIGNAL_SLIP_RX 0x0020 |
201 | #define L1_SIGNAL_SLIP_TX 0x0021 | 201 | #define L1_SIGNAL_SLIP_TX 0x0021 |
202 | 202 | ||
203 | /* | 203 | /* |
204 | * protocol ids | 204 | * protocol ids |
205 | * D channel 1-31 | 205 | * D channel 1-31 |
206 | * B channel 33 - 63 | 206 | * B channel 33 - 63 |
207 | */ | 207 | */ |
208 | 208 | ||
209 | #define ISDN_P_NONE 0 | 209 | #define ISDN_P_NONE 0 |
210 | #define ISDN_P_BASE 0 | 210 | #define ISDN_P_BASE 0 |
211 | #define ISDN_P_TE_S0 0x01 | 211 | #define ISDN_P_TE_S0 0x01 |
212 | #define ISDN_P_NT_S0 0x02 | 212 | #define ISDN_P_NT_S0 0x02 |
213 | #define ISDN_P_TE_E1 0x03 | 213 | #define ISDN_P_TE_E1 0x03 |
214 | #define ISDN_P_NT_E1 0x04 | 214 | #define ISDN_P_NT_E1 0x04 |
215 | #define ISDN_P_TE_UP0 0x05 | 215 | #define ISDN_P_TE_UP0 0x05 |
216 | #define ISDN_P_NT_UP0 0x06 | 216 | #define ISDN_P_NT_UP0 0x06 |
217 | 217 | ||
218 | #define IS_ISDN_P_TE(p) ((p == ISDN_P_TE_S0) || (p == ISDN_P_TE_E1) || \ | 218 | #define IS_ISDN_P_TE(p) ((p == ISDN_P_TE_S0) || (p == ISDN_P_TE_E1) || \ |
219 | (p == ISDN_P_TE_UP0) || (p == ISDN_P_LAPD_TE)) | 219 | (p == ISDN_P_TE_UP0) || (p == ISDN_P_LAPD_TE)) |
220 | #define IS_ISDN_P_NT(p) ((p == ISDN_P_NT_S0) || (p == ISDN_P_NT_E1) || \ | 220 | #define IS_ISDN_P_NT(p) ((p == ISDN_P_NT_S0) || (p == ISDN_P_NT_E1) || \ |
221 | (p == ISDN_P_NT_UP0) || (p == ISDN_P_LAPD_NT)) | 221 | (p == ISDN_P_NT_UP0) || (p == ISDN_P_LAPD_NT)) |
222 | #define IS_ISDN_P_S0(p) ((p == ISDN_P_TE_S0) || (p == ISDN_P_NT_S0)) | 222 | #define IS_ISDN_P_S0(p) ((p == ISDN_P_TE_S0) || (p == ISDN_P_NT_S0)) |
223 | #define IS_ISDN_P_E1(p) ((p == ISDN_P_TE_E1) || (p == ISDN_P_NT_E1)) | 223 | #define IS_ISDN_P_E1(p) ((p == ISDN_P_TE_E1) || (p == ISDN_P_NT_E1)) |
224 | #define IS_ISDN_P_UP0(p) ((p == ISDN_P_TE_UP0) || (p == ISDN_P_NT_UP0)) | 224 | #define IS_ISDN_P_UP0(p) ((p == ISDN_P_TE_UP0) || (p == ISDN_P_NT_UP0)) |
225 | 225 | ||
226 | 226 | ||
227 | #define ISDN_P_LAPD_TE 0x10 | 227 | #define ISDN_P_LAPD_TE 0x10 |
228 | #define ISDN_P_LAPD_NT 0x11 | 228 | #define ISDN_P_LAPD_NT 0x11 |
229 | 229 | ||
230 | #define ISDN_P_B_MASK 0x1f | 230 | #define ISDN_P_B_MASK 0x1f |
231 | #define ISDN_P_B_START 0x20 | 231 | #define ISDN_P_B_START 0x20 |
232 | 232 | ||
233 | #define ISDN_P_B_RAW 0x21 | 233 | #define ISDN_P_B_RAW 0x21 |
234 | #define ISDN_P_B_HDLC 0x22 | 234 | #define ISDN_P_B_HDLC 0x22 |
235 | #define ISDN_P_B_X75SLP 0x23 | 235 | #define ISDN_P_B_X75SLP 0x23 |
236 | #define ISDN_P_B_L2DTMF 0x24 | 236 | #define ISDN_P_B_L2DTMF 0x24 |
237 | #define ISDN_P_B_L2DSP 0x25 | 237 | #define ISDN_P_B_L2DSP 0x25 |
238 | #define ISDN_P_B_L2DSPHDLC 0x26 | 238 | #define ISDN_P_B_L2DSPHDLC 0x26 |
239 | #define ISDN_P_B_T30_FAX 0x27 | 239 | #define ISDN_P_B_T30_FAX 0x27 |
240 | #define ISDN_P_B_MODEM_ASYNC 0x28 | 240 | #define ISDN_P_B_MODEM_ASYNC 0x28 |
241 | 241 | ||
242 | #define OPTION_L2_PMX 1 | 242 | #define OPTION_L2_PMX 1 |
243 | #define OPTION_L2_PTP 2 | 243 | #define OPTION_L2_PTP 2 |
244 | #define OPTION_L2_FIXEDTEI 3 | 244 | #define OPTION_L2_FIXEDTEI 3 |
245 | #define OPTION_L2_CLEANUP 4 | 245 | #define OPTION_L2_CLEANUP 4 |
246 | #define OPTION_L1_HOLD 5 | 246 | #define OPTION_L1_HOLD 5 |
247 | 247 | ||
248 | /* should be in sync with linux/kobject.h:KOBJ_NAME_LEN */ | 248 | /* should be in sync with linux/kobject.h:KOBJ_NAME_LEN */ |
249 | #define MISDN_MAX_IDLEN 20 | 249 | #define MISDN_MAX_IDLEN 20 |
250 | 250 | ||
251 | struct mISDNhead { | 251 | struct mISDNhead { |
252 | unsigned int prim; | 252 | unsigned int prim; |
253 | unsigned int id; | 253 | unsigned int id; |
254 | } __attribute__((packed)); | 254 | } __attribute__((packed)); |
255 | 255 | ||
256 | #define MISDN_HEADER_LEN sizeof(struct mISDNhead) | 256 | #define MISDN_HEADER_LEN sizeof(struct mISDNhead) |
257 | #define MAX_DATA_SIZE 2048 | 257 | #define MAX_DATA_SIZE 2048 |
258 | #define MAX_DATA_MEM (MAX_DATA_SIZE + MISDN_HEADER_LEN) | 258 | #define MAX_DATA_MEM (MAX_DATA_SIZE + MISDN_HEADER_LEN) |
259 | #define MAX_DFRAME_LEN 260 | 259 | #define MAX_DFRAME_LEN 260 |
260 | 260 | ||
261 | #define MISDN_ID_ADDR_MASK 0xFFFF | 261 | #define MISDN_ID_ADDR_MASK 0xFFFF |
262 | #define MISDN_ID_TEI_MASK 0xFF00 | 262 | #define MISDN_ID_TEI_MASK 0xFF00 |
263 | #define MISDN_ID_SAPI_MASK 0x00FF | 263 | #define MISDN_ID_SAPI_MASK 0x00FF |
264 | #define MISDN_ID_TEI_ANY 0x7F00 | 264 | #define MISDN_ID_TEI_ANY 0x7F00 |
265 | 265 | ||
266 | #define MISDN_ID_ANY 0xFFFF | 266 | #define MISDN_ID_ANY 0xFFFF |
267 | #define MISDN_ID_NONE 0xFFFE | 267 | #define MISDN_ID_NONE 0xFFFE |
268 | 268 | ||
269 | #define GROUP_TEI 127 | 269 | #define GROUP_TEI 127 |
270 | #define TEI_SAPI 63 | 270 | #define TEI_SAPI 63 |
271 | #define CTRL_SAPI 0 | 271 | #define CTRL_SAPI 0 |
272 | 272 | ||
273 | #define MISDN_MAX_CHANNEL 127 | 273 | #define MISDN_MAX_CHANNEL 127 |
274 | #define MISDN_CHMAP_SIZE ((MISDN_MAX_CHANNEL + 1) >> 3) | 274 | #define MISDN_CHMAP_SIZE ((MISDN_MAX_CHANNEL + 1) >> 3) |
275 | 275 | ||
276 | #define SOL_MISDN 0 | 276 | #define SOL_MISDN 0 |
277 | 277 | ||
278 | struct sockaddr_mISDN { | 278 | struct sockaddr_mISDN { |
279 | sa_family_t family; | 279 | sa_family_t family; |
280 | unsigned char dev; | 280 | unsigned char dev; |
281 | unsigned char channel; | 281 | unsigned char channel; |
282 | unsigned char sapi; | 282 | unsigned char sapi; |
283 | unsigned char tei; | 283 | unsigned char tei; |
284 | }; | 284 | }; |
285 | 285 | ||
286 | struct mISDNversion { | 286 | struct mISDNversion { |
287 | unsigned char major; | 287 | unsigned char major; |
288 | unsigned char minor; | 288 | unsigned char minor; |
289 | unsigned short release; | 289 | unsigned short release; |
290 | }; | 290 | }; |
291 | 291 | ||
292 | struct mISDN_devinfo { | 292 | struct mISDN_devinfo { |
293 | u_int id; | 293 | u_int id; |
294 | u_int Dprotocols; | 294 | u_int Dprotocols; |
295 | u_int Bprotocols; | 295 | u_int Bprotocols; |
296 | u_int protocol; | 296 | u_int protocol; |
297 | u_char channelmap[MISDN_CHMAP_SIZE]; | 297 | u_char channelmap[MISDN_CHMAP_SIZE]; |
298 | u_int nrbchan; | 298 | u_int nrbchan; |
299 | char name[MISDN_MAX_IDLEN]; | 299 | char name[MISDN_MAX_IDLEN]; |
300 | }; | 300 | }; |
301 | 301 | ||
302 | struct mISDN_devrename { | 302 | struct mISDN_devrename { |
303 | u_int id; | 303 | u_int id; |
304 | char name[MISDN_MAX_IDLEN]; /* new name */ | 304 | char name[MISDN_MAX_IDLEN]; /* new name */ |
305 | }; | 305 | }; |
306 | 306 | ||
307 | /* MPH_INFORMATION_REQ payload */ | 307 | /* MPH_INFORMATION_REQ payload */ |
308 | struct ph_info_ch { | 308 | struct ph_info_ch { |
309 | __u32 protocol; | 309 | __u32 protocol; |
310 | __u64 Flags; | 310 | __u64 Flags; |
311 | }; | 311 | }; |
312 | 312 | ||
313 | struct ph_info_dch { | 313 | struct ph_info_dch { |
314 | struct ph_info_ch ch; | 314 | struct ph_info_ch ch; |
315 | __u16 state; | 315 | __u16 state; |
316 | __u16 num_bch; | 316 | __u16 num_bch; |
317 | }; | 317 | }; |
318 | 318 | ||
319 | struct ph_info { | 319 | struct ph_info { |
320 | struct ph_info_dch dch; | 320 | struct ph_info_dch dch; |
321 | struct ph_info_ch bch[]; | 321 | struct ph_info_ch bch[]; |
322 | }; | 322 | }; |
323 | 323 | ||
324 | /* timer device ioctl */ | 324 | /* timer device ioctl */ |
325 | #define IMADDTIMER _IOR('I', 64, int) | 325 | #define IMADDTIMER _IOR('I', 64, int) |
326 | #define IMDELTIMER _IOR('I', 65, int) | 326 | #define IMDELTIMER _IOR('I', 65, int) |
327 | 327 | ||
328 | /* socket ioctls */ | 328 | /* socket ioctls */ |
329 | #define IMGETVERSION _IOR('I', 66, int) | 329 | #define IMGETVERSION _IOR('I', 66, int) |
330 | #define IMGETCOUNT _IOR('I', 67, int) | 330 | #define IMGETCOUNT _IOR('I', 67, int) |
331 | #define IMGETDEVINFO _IOR('I', 68, int) | 331 | #define IMGETDEVINFO _IOR('I', 68, int) |
332 | #define IMCTRLREQ _IOR('I', 69, int) | 332 | #define IMCTRLREQ _IOR('I', 69, int) |
333 | #define IMCLEAR_L2 _IOR('I', 70, int) | 333 | #define IMCLEAR_L2 _IOR('I', 70, int) |
334 | #define IMSETDEVNAME _IOR('I', 71, struct mISDN_devrename) | 334 | #define IMSETDEVNAME _IOR('I', 71, struct mISDN_devrename) |
335 | #define IMHOLD_L1 _IOR('I', 72, int) | 335 | #define IMHOLD_L1 _IOR('I', 72, int) |
336 | 336 | ||
337 | static inline int | 337 | static inline int |
338 | test_channelmap(u_int nr, u_char *map) | 338 | test_channelmap(u_int nr, u_char *map) |
339 | { | 339 | { |
340 | if (nr <= MISDN_MAX_CHANNEL) | 340 | if (nr <= MISDN_MAX_CHANNEL) |
341 | return map[nr >> 3] & (1 << (nr & 7)); | 341 | return map[nr >> 3] & (1 << (nr & 7)); |
342 | else | 342 | else |
343 | return 0; | 343 | return 0; |
344 | } | 344 | } |
345 | 345 | ||
346 | static inline void | 346 | static inline void |
347 | set_channelmap(u_int nr, u_char *map) | 347 | set_channelmap(u_int nr, u_char *map) |
348 | { | 348 | { |
349 | map[nr >> 3] |= (1 << (nr & 7)); | 349 | map[nr >> 3] |= (1 << (nr & 7)); |
350 | } | 350 | } |
351 | 351 | ||
352 | static inline void | 352 | static inline void |
353 | clear_channelmap(u_int nr, u_char *map) | 353 | clear_channelmap(u_int nr, u_char *map) |
354 | { | 354 | { |
355 | map[nr >> 3] &= ~(1 << (nr & 7)); | 355 | map[nr >> 3] &= ~(1 << (nr & 7)); |
356 | } | 356 | } |
357 | 357 | ||
358 | /* CONTROL_CHANNEL parameters */ | 358 | /* CONTROL_CHANNEL parameters */ |
359 | #define MISDN_CTRL_GETOP 0x0000 | 359 | #define MISDN_CTRL_GETOP 0x0000 |
360 | #define MISDN_CTRL_LOOP 0x0001 | 360 | #define MISDN_CTRL_LOOP 0x0001 |
361 | #define MISDN_CTRL_CONNECT 0x0002 | 361 | #define MISDN_CTRL_CONNECT 0x0002 |
362 | #define MISDN_CTRL_DISCONNECT 0x0004 | 362 | #define MISDN_CTRL_DISCONNECT 0x0004 |
363 | #define MISDN_CTRL_PCMCONNECT 0x0010 | 363 | #define MISDN_CTRL_PCMCONNECT 0x0010 |
364 | #define MISDN_CTRL_PCMDISCONNECT 0x0020 | 364 | #define MISDN_CTRL_PCMDISCONNECT 0x0020 |
365 | #define MISDN_CTRL_SETPEER 0x0040 | 365 | #define MISDN_CTRL_SETPEER 0x0040 |
366 | #define MISDN_CTRL_UNSETPEER 0x0080 | 366 | #define MISDN_CTRL_UNSETPEER 0x0080 |
367 | #define MISDN_CTRL_RX_OFF 0x0100 | 367 | #define MISDN_CTRL_RX_OFF 0x0100 |
368 | #define MISDN_CTRL_FILL_EMPTY 0x0200 | 368 | #define MISDN_CTRL_FILL_EMPTY 0x0200 |
369 | #define MISDN_CTRL_GETPEER 0x0400 | 369 | #define MISDN_CTRL_GETPEER 0x0400 |
370 | #define MISDN_CTRL_HW_FEATURES_OP 0x2000 | 370 | #define MISDN_CTRL_HW_FEATURES_OP 0x2000 |
371 | #define MISDN_CTRL_HW_FEATURES 0x2001 | 371 | #define MISDN_CTRL_HW_FEATURES 0x2001 |
372 | #define MISDN_CTRL_HFC_OP 0x4000 | 372 | #define MISDN_CTRL_HFC_OP 0x4000 |
373 | #define MISDN_CTRL_HFC_PCM_CONN 0x4001 | 373 | #define MISDN_CTRL_HFC_PCM_CONN 0x4001 |
374 | #define MISDN_CTRL_HFC_PCM_DISC 0x4002 | 374 | #define MISDN_CTRL_HFC_PCM_DISC 0x4002 |
375 | #define MISDN_CTRL_HFC_CONF_JOIN 0x4003 | 375 | #define MISDN_CTRL_HFC_CONF_JOIN 0x4003 |
376 | #define MISDN_CTRL_HFC_CONF_SPLIT 0x4004 | 376 | #define MISDN_CTRL_HFC_CONF_SPLIT 0x4004 |
377 | #define MISDN_CTRL_HFC_RECEIVE_OFF 0x4005 | 377 | #define MISDN_CTRL_HFC_RECEIVE_OFF 0x4005 |
378 | #define MISDN_CTRL_HFC_RECEIVE_ON 0x4006 | 378 | #define MISDN_CTRL_HFC_RECEIVE_ON 0x4006 |
379 | #define MISDN_CTRL_HFC_ECHOCAN_ON 0x4007 | 379 | #define MISDN_CTRL_HFC_ECHOCAN_ON 0x4007 |
380 | #define MISDN_CTRL_HFC_ECHOCAN_OFF 0x4008 | 380 | #define MISDN_CTRL_HFC_ECHOCAN_OFF 0x4008 |
381 | #define MISDN_CTRL_HFC_WD_INIT 0x4009 | 381 | #define MISDN_CTRL_HFC_WD_INIT 0x4009 |
382 | #define MISDN_CTRL_HFC_WD_RESET 0x400A | 382 | #define MISDN_CTRL_HFC_WD_RESET 0x400A |
383 | 383 | ||
384 | /* socket options */ | 384 | /* socket options */ |
385 | #define MISDN_TIME_STAMP 0x0001 | 385 | #define MISDN_TIME_STAMP 0x0001 |
386 | 386 | ||
387 | struct mISDN_ctrl_req { | 387 | struct mISDN_ctrl_req { |
388 | int op; | 388 | int op; |
389 | int channel; | 389 | int channel; |
390 | int p1; | 390 | int p1; |
391 | int p2; | 391 | int p2; |
392 | }; | 392 | }; |
393 | 393 | ||
394 | /* muxer options */ | 394 | /* muxer options */ |
395 | #define MISDN_OPT_ALL 1 | 395 | #define MISDN_OPT_ALL 1 |
396 | #define MISDN_OPT_TEIMGR 2 | 396 | #define MISDN_OPT_TEIMGR 2 |
397 | 397 | ||
398 | #ifdef __KERNEL__ | 398 | #ifdef __KERNEL__ |
399 | #include <linux/list.h> | 399 | #include <linux/list.h> |
400 | #include <linux/skbuff.h> | 400 | #include <linux/skbuff.h> |
401 | #include <linux/net.h> | 401 | #include <linux/net.h> |
402 | #include <net/sock.h> | 402 | #include <net/sock.h> |
403 | #include <linux/completion.h> | 403 | #include <linux/completion.h> |
404 | 404 | ||
405 | #define DEBUG_CORE 0x000000ff | 405 | #define DEBUG_CORE 0x000000ff |
406 | #define DEBUG_CORE_FUNC 0x00000002 | 406 | #define DEBUG_CORE_FUNC 0x00000002 |
407 | #define DEBUG_SOCKET 0x00000004 | 407 | #define DEBUG_SOCKET 0x00000004 |
408 | #define DEBUG_MANAGER 0x00000008 | 408 | #define DEBUG_MANAGER 0x00000008 |
409 | #define DEBUG_SEND_ERR 0x00000010 | 409 | #define DEBUG_SEND_ERR 0x00000010 |
410 | #define DEBUG_MSG_THREAD 0x00000020 | 410 | #define DEBUG_MSG_THREAD 0x00000020 |
411 | #define DEBUG_QUEUE_FUNC 0x00000040 | 411 | #define DEBUG_QUEUE_FUNC 0x00000040 |
412 | #define DEBUG_L1 0x0000ff00 | 412 | #define DEBUG_L1 0x0000ff00 |
413 | #define DEBUG_L1_FSM 0x00000200 | 413 | #define DEBUG_L1_FSM 0x00000200 |
414 | #define DEBUG_L2 0x00ff0000 | 414 | #define DEBUG_L2 0x00ff0000 |
415 | #define DEBUG_L2_FSM 0x00020000 | 415 | #define DEBUG_L2_FSM 0x00020000 |
416 | #define DEBUG_L2_CTRL 0x00040000 | 416 | #define DEBUG_L2_CTRL 0x00040000 |
417 | #define DEBUG_L2_RECV 0x00080000 | 417 | #define DEBUG_L2_RECV 0x00080000 |
418 | #define DEBUG_L2_TEI 0x00100000 | 418 | #define DEBUG_L2_TEI 0x00100000 |
419 | #define DEBUG_L2_TEIFSM 0x00200000 | 419 | #define DEBUG_L2_TEIFSM 0x00200000 |
420 | #define DEBUG_TIMER 0x01000000 | 420 | #define DEBUG_TIMER 0x01000000 |
421 | #define DEBUG_CLOCK 0x02000000 | 421 | #define DEBUG_CLOCK 0x02000000 |
422 | 422 | ||
423 | #define mISDN_HEAD_P(s) ((struct mISDNhead *)&s->cb[0]) | 423 | #define mISDN_HEAD_P(s) ((struct mISDNhead *)&s->cb[0]) |
424 | #define mISDN_HEAD_PRIM(s) (((struct mISDNhead *)&s->cb[0])->prim) | 424 | #define mISDN_HEAD_PRIM(s) (((struct mISDNhead *)&s->cb[0])->prim) |
425 | #define mISDN_HEAD_ID(s) (((struct mISDNhead *)&s->cb[0])->id) | 425 | #define mISDN_HEAD_ID(s) (((struct mISDNhead *)&s->cb[0])->id) |
426 | 426 | ||
427 | /* socket states */ | 427 | /* socket states */ |
428 | #define MISDN_OPEN 1 | 428 | #define MISDN_OPEN 1 |
429 | #define MISDN_BOUND 2 | 429 | #define MISDN_BOUND 2 |
430 | #define MISDN_CLOSED 3 | 430 | #define MISDN_CLOSED 3 |
431 | 431 | ||
432 | struct mISDNchannel; | 432 | struct mISDNchannel; |
433 | struct mISDNdevice; | 433 | struct mISDNdevice; |
434 | struct mISDNstack; | 434 | struct mISDNstack; |
435 | struct mISDNclock; | 435 | struct mISDNclock; |
436 | 436 | ||
437 | struct channel_req { | 437 | struct channel_req { |
438 | u_int protocol; | 438 | u_int protocol; |
439 | struct sockaddr_mISDN adr; | 439 | struct sockaddr_mISDN adr; |
440 | struct mISDNchannel *ch; | 440 | struct mISDNchannel *ch; |
441 | }; | 441 | }; |
442 | 442 | ||
443 | typedef int (ctrl_func_t)(struct mISDNchannel *, u_int, void *); | 443 | typedef int (ctrl_func_t)(struct mISDNchannel *, u_int, void *); |
444 | typedef int (send_func_t)(struct mISDNchannel *, struct sk_buff *); | 444 | typedef int (send_func_t)(struct mISDNchannel *, struct sk_buff *); |
445 | typedef int (create_func_t)(struct channel_req *); | 445 | typedef int (create_func_t)(struct channel_req *); |
446 | 446 | ||
447 | struct Bprotocol { | 447 | struct Bprotocol { |
448 | struct list_head list; | 448 | struct list_head list; |
449 | char *name; | 449 | char *name; |
450 | u_int Bprotocols; | 450 | u_int Bprotocols; |
451 | create_func_t *create; | 451 | create_func_t *create; |
452 | }; | 452 | }; |
453 | 453 | ||
454 | struct mISDNchannel { | 454 | struct mISDNchannel { |
455 | struct list_head list; | 455 | struct list_head list; |
456 | u_int protocol; | 456 | u_int protocol; |
457 | u_int nr; | 457 | u_int nr; |
458 | u_long opt; | 458 | u_long opt; |
459 | u_int addr; | 459 | u_int addr; |
460 | struct mISDNstack *st; | 460 | struct mISDNstack *st; |
461 | struct mISDNchannel *peer; | 461 | struct mISDNchannel *peer; |
462 | send_func_t *send; | 462 | send_func_t *send; |
463 | send_func_t *recv; | 463 | send_func_t *recv; |
464 | ctrl_func_t *ctrl; | 464 | ctrl_func_t *ctrl; |
465 | }; | 465 | }; |
466 | 466 | ||
467 | struct mISDN_sock_list { | 467 | struct mISDN_sock_list { |
468 | struct hlist_head head; | 468 | struct hlist_head head; |
469 | rwlock_t lock; | 469 | rwlock_t lock; |
470 | }; | 470 | }; |
471 | 471 | ||
472 | struct mISDN_sock { | 472 | struct mISDN_sock { |
473 | struct sock sk; | 473 | struct sock sk; |
474 | struct mISDNchannel ch; | 474 | struct mISDNchannel ch; |
475 | u_int cmask; | 475 | u_int cmask; |
476 | struct mISDNdevice *dev; | 476 | struct mISDNdevice *dev; |
477 | }; | 477 | }; |
478 | 478 | ||
479 | 479 | ||
480 | 480 | ||
481 | struct mISDNdevice { | 481 | struct mISDNdevice { |
482 | struct mISDNchannel D; | 482 | struct mISDNchannel D; |
483 | u_int id; | 483 | u_int id; |
484 | u_int Dprotocols; | 484 | u_int Dprotocols; |
485 | u_int Bprotocols; | 485 | u_int Bprotocols; |
486 | u_int nrbchan; | 486 | u_int nrbchan; |
487 | u_char channelmap[MISDN_CHMAP_SIZE]; | 487 | u_char channelmap[MISDN_CHMAP_SIZE]; |
488 | struct list_head bchannels; | 488 | struct list_head bchannels; |
489 | struct mISDNchannel *teimgr; | 489 | struct mISDNchannel *teimgr; |
490 | struct device dev; | 490 | struct device dev; |
491 | }; | 491 | }; |
492 | 492 | ||
493 | struct mISDNstack { | 493 | struct mISDNstack { |
494 | u_long status; | 494 | u_long status; |
495 | struct mISDNdevice *dev; | 495 | struct mISDNdevice *dev; |
496 | struct task_struct *thread; | 496 | struct task_struct *thread; |
497 | struct completion *notify; | 497 | struct completion *notify; |
498 | wait_queue_head_t workq; | 498 | wait_queue_head_t workq; |
499 | struct sk_buff_head msgq; | 499 | struct sk_buff_head msgq; |
500 | struct list_head layer2; | 500 | struct list_head layer2; |
501 | struct mISDNchannel *layer1; | 501 | struct mISDNchannel *layer1; |
502 | struct mISDNchannel own; | 502 | struct mISDNchannel own; |
503 | struct mutex lmutex; /* protect lists */ | 503 | struct mutex lmutex; /* protect lists */ |
504 | struct mISDN_sock_list l1sock; | 504 | struct mISDN_sock_list l1sock; |
505 | #ifdef MISDN_MSG_STATS | 505 | #ifdef MISDN_MSG_STATS |
506 | u_int msg_cnt; | 506 | u_int msg_cnt; |
507 | u_int sleep_cnt; | 507 | u_int sleep_cnt; |
508 | u_int stopped_cnt; | 508 | u_int stopped_cnt; |
509 | #endif | 509 | #endif |
510 | }; | 510 | }; |
511 | 511 | ||
512 | typedef int (clockctl_func_t)(void *, int); | 512 | typedef int (clockctl_func_t)(void *, int); |
513 | 513 | ||
514 | struct mISDNclock { | 514 | struct mISDNclock { |
515 | struct list_head list; | 515 | struct list_head list; |
516 | char name[64]; | 516 | char name[64]; |
517 | int pri; | 517 | int pri; |
518 | clockctl_func_t *ctl; | 518 | clockctl_func_t *ctl; |
519 | void *priv; | 519 | void *priv; |
520 | }; | 520 | }; |
521 | 521 | ||
522 | /* global alloc/queue functions */ | 522 | /* global alloc/queue functions */ |
523 | 523 | ||
524 | static inline struct sk_buff * | 524 | static inline struct sk_buff * |
525 | mI_alloc_skb(unsigned int len, gfp_t gfp_mask) | 525 | mI_alloc_skb(unsigned int len, gfp_t gfp_mask) |
526 | { | 526 | { |
527 | struct sk_buff *skb; | 527 | struct sk_buff *skb; |
528 | 528 | ||
529 | skb = alloc_skb(len + MISDN_HEADER_LEN, gfp_mask); | 529 | skb = alloc_skb(len + MISDN_HEADER_LEN, gfp_mask); |
530 | if (likely(skb)) | 530 | if (likely(skb)) |
531 | skb_reserve(skb, MISDN_HEADER_LEN); | 531 | skb_reserve(skb, MISDN_HEADER_LEN); |
532 | return skb; | 532 | return skb; |
533 | } | 533 | } |
534 | 534 | ||
535 | static inline struct sk_buff * | 535 | static inline struct sk_buff * |
536 | _alloc_mISDN_skb(u_int prim, u_int id, u_int len, void *dp, gfp_t gfp_mask) | 536 | _alloc_mISDN_skb(u_int prim, u_int id, u_int len, void *dp, gfp_t gfp_mask) |
537 | { | 537 | { |
538 | struct sk_buff *skb = mI_alloc_skb(len, gfp_mask); | 538 | struct sk_buff *skb = mI_alloc_skb(len, gfp_mask); |
539 | struct mISDNhead *hh; | 539 | struct mISDNhead *hh; |
540 | 540 | ||
541 | if (!skb) | 541 | if (!skb) |
542 | return NULL; | 542 | return NULL; |
543 | if (len) | 543 | if (len) |
544 | memcpy(skb_put(skb, len), dp, len); | 544 | memcpy(skb_put(skb, len), dp, len); |
545 | hh = mISDN_HEAD_P(skb); | 545 | hh = mISDN_HEAD_P(skb); |
546 | hh->prim = prim; | 546 | hh->prim = prim; |
547 | hh->id = id; | 547 | hh->id = id; |
548 | return skb; | 548 | return skb; |
549 | } | 549 | } |
550 | 550 | ||
551 | static inline void | 551 | static inline void |
552 | _queue_data(struct mISDNchannel *ch, u_int prim, | 552 | _queue_data(struct mISDNchannel *ch, u_int prim, |
553 | u_int id, u_int len, void *dp, gfp_t gfp_mask) | 553 | u_int id, u_int len, void *dp, gfp_t gfp_mask) |
554 | { | 554 | { |
555 | struct sk_buff *skb; | 555 | struct sk_buff *skb; |
556 | 556 | ||
557 | if (!ch->peer) | 557 | if (!ch->peer) |
558 | return; | 558 | return; |
559 | skb = _alloc_mISDN_skb(prim, id, len, dp, gfp_mask); | 559 | skb = _alloc_mISDN_skb(prim, id, len, dp, gfp_mask); |
560 | if (!skb) | 560 | if (!skb) |
561 | return; | 561 | return; |
562 | if (ch->recv(ch->peer, skb)) | 562 | if (ch->recv(ch->peer, skb)) |
563 | dev_kfree_skb(skb); | 563 | dev_kfree_skb(skb); |
564 | } | 564 | } |
565 | 565 | ||
566 | /* global register/unregister functions */ | 566 | /* global register/unregister functions */ |
567 | 567 | ||
568 | extern int mISDN_register_device(struct mISDNdevice *, | 568 | extern int mISDN_register_device(struct mISDNdevice *, |
569 | struct device *parent, char *name); | 569 | struct device *parent, char *name); |
570 | extern void mISDN_unregister_device(struct mISDNdevice *); | 570 | extern void mISDN_unregister_device(struct mISDNdevice *); |
571 | extern int mISDN_register_Bprotocol(struct Bprotocol *); | 571 | extern int mISDN_register_Bprotocol(struct Bprotocol *); |
572 | extern void mISDN_unregister_Bprotocol(struct Bprotocol *); | 572 | extern void mISDN_unregister_Bprotocol(struct Bprotocol *); |
573 | extern struct mISDNclock *mISDN_register_clock(char *, int, clockctl_func_t *, | 573 | extern struct mISDNclock *mISDN_register_clock(char *, int, clockctl_func_t *, |
574 | void *); | 574 | void *); |
575 | extern void mISDN_unregister_clock(struct mISDNclock *); | 575 | extern void mISDN_unregister_clock(struct mISDNclock *); |
576 | 576 | ||
577 | static inline struct mISDNdevice *dev_to_mISDN(struct device *dev) | 577 | static inline struct mISDNdevice *dev_to_mISDN(struct device *dev) |
578 | { | 578 | { |
579 | if (dev) | 579 | if (dev) |
580 | return dev_get_drvdata(dev); | 580 | return dev_get_drvdata(dev); |
581 | else | 581 | else |
582 | return NULL; | 582 | return NULL; |
583 | } | 583 | } |
584 | 584 | ||
585 | extern void set_channel_address(struct mISDNchannel *, u_int, u_int); | 585 | extern void set_channel_address(struct mISDNchannel *, u_int, u_int); |
586 | extern void mISDN_clock_update(struct mISDNclock *, int, struct timeval *); | 586 | extern void mISDN_clock_update(struct mISDNclock *, int, struct timeval *); |
587 | extern unsigned short mISDN_clock_get(void); | 587 | extern unsigned short mISDN_clock_get(void); |
588 | 588 | ||
589 | #endif /* __KERNEL__ */ | 589 | #endif /* __KERNEL__ */ |
590 | #endif /* mISDNIF_H */ | 590 | #endif /* mISDNIF_H */ |
591 | 591 |