diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/scsi/sym53c8xx_2/sym_fw.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/scsi/sym53c8xx_2/sym_fw.c')
-rw-r--r-- | drivers/scsi/sym53c8xx_2/sym_fw.c | 568 |
1 files changed, 568 insertions, 0 deletions
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw.c b/drivers/scsi/sym53c8xx_2/sym_fw.c new file mode 100644 index 000000000000..fd36cf9858cb --- /dev/null +++ b/drivers/scsi/sym53c8xx_2/sym_fw.c | |||
@@ -0,0 +1,568 @@ | |||
1 | /* | ||
2 | * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family | ||
3 | * of PCI-SCSI IO processors. | ||
4 | * | ||
5 | * Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr> | ||
6 | * | ||
7 | * This driver is derived from the Linux sym53c8xx driver. | ||
8 | * Copyright (C) 1998-2000 Gerard Roudier | ||
9 | * | ||
10 | * The sym53c8xx driver is derived from the ncr53c8xx driver that had been | ||
11 | * a port of the FreeBSD ncr driver to Linux-1.2.13. | ||
12 | * | ||
13 | * The original ncr driver has been written for 386bsd and FreeBSD by | ||
14 | * Wolfgang Stanglmeier <wolf@cologne.de> | ||
15 | * Stefan Esser <se@mi.Uni-Koeln.de> | ||
16 | * Copyright (C) 1994 Wolfgang Stanglmeier | ||
17 | * | ||
18 | * Other major contributions: | ||
19 | * | ||
20 | * NVRAM detection and reading. | ||
21 | * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk> | ||
22 | * | ||
23 | *----------------------------------------------------------------------------- | ||
24 | * | ||
25 | * This program is free software; you can redistribute it and/or modify | ||
26 | * it under the terms of the GNU General Public License as published by | ||
27 | * the Free Software Foundation; either version 2 of the License, or | ||
28 | * (at your option) any later version. | ||
29 | * | ||
30 | * This program is distributed in the hope that it will be useful, | ||
31 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
32 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
33 | * GNU General Public License for more details. | ||
34 | * | ||
35 | * You should have received a copy of the GNU General Public License | ||
36 | * along with this program; if not, write to the Free Software | ||
37 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
38 | */ | ||
39 | |||
40 | #ifdef __FreeBSD__ | ||
41 | #include <dev/sym/sym_glue.h> | ||
42 | #else | ||
43 | #include "sym_glue.h" | ||
44 | #endif | ||
45 | |||
46 | /* | ||
47 | * Macros used for all firmwares. | ||
48 | */ | ||
49 | #define SYM_GEN_A(s, label) ((short) offsetof(s, label)), | ||
50 | #define SYM_GEN_B(s, label) ((short) offsetof(s, label)), | ||
51 | #define SYM_GEN_Z(s, label) ((short) offsetof(s, label)), | ||
52 | #define PADDR_A(label) SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label) | ||
53 | #define PADDR_B(label) SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label) | ||
54 | |||
55 | |||
56 | #if SYM_CONF_GENERIC_SUPPORT | ||
57 | /* | ||
58 | * Allocate firmware #1 script area. | ||
59 | */ | ||
60 | #define SYM_FWA_SCR sym_fw1a_scr | ||
61 | #define SYM_FWB_SCR sym_fw1b_scr | ||
62 | #define SYM_FWZ_SCR sym_fw1z_scr | ||
63 | #ifdef __FreeBSD__ | ||
64 | #include <dev/sym/sym_fw1.h> | ||
65 | #else | ||
66 | #include "sym_fw1.h" | ||
67 | #endif | ||
68 | static struct sym_fwa_ofs sym_fw1a_ofs = { | ||
69 | SYM_GEN_FW_A(struct SYM_FWA_SCR) | ||
70 | }; | ||
71 | static struct sym_fwb_ofs sym_fw1b_ofs = { | ||
72 | SYM_GEN_FW_B(struct SYM_FWB_SCR) | ||
73 | #ifdef SYM_OPT_HANDLE_DIR_UNKNOWN | ||
74 | SYM_GEN_B(struct SYM_FWB_SCR, data_io) | ||
75 | #endif | ||
76 | }; | ||
77 | static struct sym_fwz_ofs sym_fw1z_ofs = { | ||
78 | SYM_GEN_FW_Z(struct SYM_FWZ_SCR) | ||
79 | }; | ||
80 | #undef SYM_FWA_SCR | ||
81 | #undef SYM_FWB_SCR | ||
82 | #undef SYM_FWZ_SCR | ||
83 | #endif /* SYM_CONF_GENERIC_SUPPORT */ | ||
84 | |||
85 | /* | ||
86 | * Allocate firmware #2 script area. | ||
87 | */ | ||
88 | #define SYM_FWA_SCR sym_fw2a_scr | ||
89 | #define SYM_FWB_SCR sym_fw2b_scr | ||
90 | #define SYM_FWZ_SCR sym_fw2z_scr | ||
91 | #ifdef __FreeBSD__ | ||
92 | #include <dev/sym/sym_fw2.h> | ||
93 | #else | ||
94 | #include "sym_fw2.h" | ||
95 | #endif | ||
96 | static struct sym_fwa_ofs sym_fw2a_ofs = { | ||
97 | SYM_GEN_FW_A(struct SYM_FWA_SCR) | ||
98 | }; | ||
99 | static struct sym_fwb_ofs sym_fw2b_ofs = { | ||
100 | SYM_GEN_FW_B(struct SYM_FWB_SCR) | ||
101 | #ifdef SYM_OPT_HANDLE_DIR_UNKNOWN | ||
102 | SYM_GEN_B(struct SYM_FWB_SCR, data_io) | ||
103 | #endif | ||
104 | SYM_GEN_B(struct SYM_FWB_SCR, start64) | ||
105 | SYM_GEN_B(struct SYM_FWB_SCR, pm_handle) | ||
106 | }; | ||
107 | static struct sym_fwz_ofs sym_fw2z_ofs = { | ||
108 | SYM_GEN_FW_Z(struct SYM_FWZ_SCR) | ||
109 | }; | ||
110 | #undef SYM_FWA_SCR | ||
111 | #undef SYM_FWB_SCR | ||
112 | #undef SYM_FWZ_SCR | ||
113 | |||
114 | #undef SYM_GEN_A | ||
115 | #undef SYM_GEN_B | ||
116 | #undef SYM_GEN_Z | ||
117 | #undef PADDR_A | ||
118 | #undef PADDR_B | ||
119 | |||
120 | #if SYM_CONF_GENERIC_SUPPORT | ||
121 | /* | ||
122 | * Patch routine for firmware #1. | ||
123 | */ | ||
124 | static void | ||
125 | sym_fw1_patch(struct sym_hcb *np) | ||
126 | { | ||
127 | struct sym_fw1a_scr *scripta0; | ||
128 | struct sym_fw1b_scr *scriptb0; | ||
129 | |||
130 | scripta0 = (struct sym_fw1a_scr *) np->scripta0; | ||
131 | scriptb0 = (struct sym_fw1b_scr *) np->scriptb0; | ||
132 | |||
133 | /* | ||
134 | * Remove LED support if not needed. | ||
135 | */ | ||
136 | if (!(np->features & FE_LED0)) { | ||
137 | scripta0->idle[0] = cpu_to_scr(SCR_NO_OP); | ||
138 | scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP); | ||
139 | scripta0->start[0] = cpu_to_scr(SCR_NO_OP); | ||
140 | } | ||
141 | |||
142 | #ifdef SYM_CONF_IARB_SUPPORT | ||
143 | /* | ||
144 | * If user does not want to use IMMEDIATE ARBITRATION | ||
145 | * when we are reselected while attempting to arbitrate, | ||
146 | * patch the SCRIPTS accordingly with a SCRIPT NO_OP. | ||
147 | */ | ||
148 | if (!SYM_CONF_SET_IARB_ON_ARB_LOST) | ||
149 | scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP); | ||
150 | #endif | ||
151 | /* | ||
152 | * Patch some data in SCRIPTS. | ||
153 | * - start and done queue initial bus address. | ||
154 | * - target bus address table bus address. | ||
155 | */ | ||
156 | scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba); | ||
157 | scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba); | ||
158 | scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba); | ||
159 | } | ||
160 | #endif /* SYM_CONF_GENERIC_SUPPORT */ | ||
161 | |||
162 | /* | ||
163 | * Patch routine for firmware #2. | ||
164 | */ | ||
165 | static void | ||
166 | sym_fw2_patch(struct sym_hcb *np) | ||
167 | { | ||
168 | struct sym_fw2a_scr *scripta0; | ||
169 | struct sym_fw2b_scr *scriptb0; | ||
170 | |||
171 | scripta0 = (struct sym_fw2a_scr *) np->scripta0; | ||
172 | scriptb0 = (struct sym_fw2b_scr *) np->scriptb0; | ||
173 | |||
174 | /* | ||
175 | * Remove LED support if not needed. | ||
176 | */ | ||
177 | if (!(np->features & FE_LED0)) { | ||
178 | scripta0->idle[0] = cpu_to_scr(SCR_NO_OP); | ||
179 | scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP); | ||
180 | scripta0->start[0] = cpu_to_scr(SCR_NO_OP); | ||
181 | } | ||
182 | |||
183 | #if SYM_CONF_DMA_ADDRESSING_MODE == 2 | ||
184 | /* | ||
185 | * Remove useless 64 bit DMA specific SCRIPTS, | ||
186 | * when this feature is not available. | ||
187 | */ | ||
188 | if (!np->use_dac) { | ||
189 | scripta0->is_dmap_dirty[0] = cpu_to_scr(SCR_NO_OP); | ||
190 | scripta0->is_dmap_dirty[1] = 0; | ||
191 | scripta0->is_dmap_dirty[2] = cpu_to_scr(SCR_NO_OP); | ||
192 | scripta0->is_dmap_dirty[3] = 0; | ||
193 | } | ||
194 | #endif | ||
195 | |||
196 | #ifdef SYM_CONF_IARB_SUPPORT | ||
197 | /* | ||
198 | * If user does not want to use IMMEDIATE ARBITRATION | ||
199 | * when we are reselected while attempting to arbitrate, | ||
200 | * patch the SCRIPTS accordingly with a SCRIPT NO_OP. | ||
201 | */ | ||
202 | if (!SYM_CONF_SET_IARB_ON_ARB_LOST) | ||
203 | scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP); | ||
204 | #endif | ||
205 | /* | ||
206 | * Patch some variable in SCRIPTS. | ||
207 | * - start and done queue initial bus address. | ||
208 | * - target bus address table bus address. | ||
209 | */ | ||
210 | scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba); | ||
211 | scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba); | ||
212 | scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba); | ||
213 | |||
214 | /* | ||
215 | * Remove the load of SCNTL4 on reselection if not a C10. | ||
216 | */ | ||
217 | if (!(np->features & FE_C10)) { | ||
218 | scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP); | ||
219 | scripta0->resel_scntl4[1] = cpu_to_scr(0); | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * Remove a couple of work-arounds specific to C1010 if | ||
224 | * they are not desirable. See `sym_fw2.h' for more details. | ||
225 | */ | ||
226 | if (!(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 && | ||
227 | np->revision_id < 0x1 && | ||
228 | np->pciclk_khz < 60000)) { | ||
229 | scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP); | ||
230 | scripta0->datao_phase[1] = cpu_to_scr(0); | ||
231 | } | ||
232 | if (!(np->device_id == PCI_DEVICE_ID_LSI_53C1010_33 && | ||
233 | /* np->revision_id < 0xff */ 1)) { | ||
234 | scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP); | ||
235 | scripta0->sel_done[1] = cpu_to_scr(0); | ||
236 | } | ||
237 | |||
238 | /* | ||
239 | * Patch some other variables in SCRIPTS. | ||
240 | * These ones are loaded by the SCRIPTS processor. | ||
241 | */ | ||
242 | scriptb0->pm0_data_addr[0] = | ||
243 | cpu_to_scr(np->scripta_ba + | ||
244 | offsetof(struct sym_fw2a_scr, pm0_data)); | ||
245 | scriptb0->pm1_data_addr[0] = | ||
246 | cpu_to_scr(np->scripta_ba + | ||
247 | offsetof(struct sym_fw2a_scr, pm1_data)); | ||
248 | } | ||
249 | |||
250 | /* | ||
251 | * Fill the data area in scripts. | ||
252 | * To be done for all firmwares. | ||
253 | */ | ||
254 | static void | ||
255 | sym_fw_fill_data (u32 *in, u32 *out) | ||
256 | { | ||
257 | int i; | ||
258 | |||
259 | for (i = 0; i < SYM_CONF_MAX_SG; i++) { | ||
260 | *in++ = SCR_CHMOV_TBL ^ SCR_DATA_IN; | ||
261 | *in++ = offsetof (struct sym_dsb, data[i]); | ||
262 | *out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT; | ||
263 | *out++ = offsetof (struct sym_dsb, data[i]); | ||
264 | } | ||
265 | } | ||
266 | |||
267 | /* | ||
268 | * Setup useful script bus addresses. | ||
269 | * To be done for all firmwares. | ||
270 | */ | ||
271 | static void | ||
272 | sym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw) | ||
273 | { | ||
274 | u32 *pa; | ||
275 | u_short *po; | ||
276 | int i; | ||
277 | |||
278 | /* | ||
279 | * Build the bus address table for script A | ||
280 | * from the script A offset table. | ||
281 | */ | ||
282 | po = (u_short *) fw->a_ofs; | ||
283 | pa = (u32 *) &np->fwa_bas; | ||
284 | for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++) | ||
285 | pa[i] = np->scripta_ba + po[i]; | ||
286 | |||
287 | /* | ||
288 | * Same for script B. | ||
289 | */ | ||
290 | po = (u_short *) fw->b_ofs; | ||
291 | pa = (u32 *) &np->fwb_bas; | ||
292 | for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++) | ||
293 | pa[i] = np->scriptb_ba + po[i]; | ||
294 | |||
295 | /* | ||
296 | * Same for script Z. | ||
297 | */ | ||
298 | po = (u_short *) fw->z_ofs; | ||
299 | pa = (u32 *) &np->fwz_bas; | ||
300 | for (i = 0 ; i < sizeof(np->fwz_bas)/sizeof(u32) ; i++) | ||
301 | pa[i] = np->scriptz_ba + po[i]; | ||
302 | } | ||
303 | |||
304 | #if SYM_CONF_GENERIC_SUPPORT | ||
305 | /* | ||
306 | * Setup routine for firmware #1. | ||
307 | */ | ||
308 | static void | ||
309 | sym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw) | ||
310 | { | ||
311 | struct sym_fw1a_scr *scripta0; | ||
312 | struct sym_fw1b_scr *scriptb0; | ||
313 | |||
314 | scripta0 = (struct sym_fw1a_scr *) np->scripta0; | ||
315 | scriptb0 = (struct sym_fw1b_scr *) np->scriptb0; | ||
316 | |||
317 | /* | ||
318 | * Fill variable parts in scripts. | ||
319 | */ | ||
320 | sym_fw_fill_data(scripta0->data_in, scripta0->data_out); | ||
321 | |||
322 | /* | ||
323 | * Setup bus addresses used from the C code.. | ||
324 | */ | ||
325 | sym_fw_setup_bus_addresses(np, fw); | ||
326 | } | ||
327 | #endif /* SYM_CONF_GENERIC_SUPPORT */ | ||
328 | |||
329 | /* | ||
330 | * Setup routine for firmware #2. | ||
331 | */ | ||
332 | static void | ||
333 | sym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw) | ||
334 | { | ||
335 | struct sym_fw2a_scr *scripta0; | ||
336 | struct sym_fw2b_scr *scriptb0; | ||
337 | |||
338 | scripta0 = (struct sym_fw2a_scr *) np->scripta0; | ||
339 | scriptb0 = (struct sym_fw2b_scr *) np->scriptb0; | ||
340 | |||
341 | /* | ||
342 | * Fill variable parts in scripts. | ||
343 | */ | ||
344 | sym_fw_fill_data(scripta0->data_in, scripta0->data_out); | ||
345 | |||
346 | /* | ||
347 | * Setup bus addresses used from the C code.. | ||
348 | */ | ||
349 | sym_fw_setup_bus_addresses(np, fw); | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * Allocate firmware descriptors. | ||
354 | */ | ||
355 | #if SYM_CONF_GENERIC_SUPPORT | ||
356 | static struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic"); | ||
357 | #endif /* SYM_CONF_GENERIC_SUPPORT */ | ||
358 | static struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based"); | ||
359 | |||
360 | /* | ||
361 | * Find the most appropriate firmware for a chip. | ||
362 | */ | ||
363 | struct sym_fw * | ||
364 | sym_find_firmware(struct sym_chip *chip) | ||
365 | { | ||
366 | if (chip->features & FE_LDSTR) | ||
367 | return &sym_fw2; | ||
368 | #if SYM_CONF_GENERIC_SUPPORT | ||
369 | else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC))) | ||
370 | return &sym_fw1; | ||
371 | #endif | ||
372 | else | ||
373 | return NULL; | ||
374 | } | ||
375 | |||
376 | /* | ||
377 | * Bind a script to physical addresses. | ||
378 | */ | ||
379 | void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len) | ||
380 | { | ||
381 | u32 opcode, new, old, tmp1, tmp2; | ||
382 | u32 *end, *cur; | ||
383 | int relocs; | ||
384 | |||
385 | cur = start; | ||
386 | end = start + len/4; | ||
387 | |||
388 | while (cur < end) { | ||
389 | |||
390 | opcode = *cur; | ||
391 | |||
392 | /* | ||
393 | * If we forget to change the length | ||
394 | * in scripts, a field will be | ||
395 | * padded with 0. This is an illegal | ||
396 | * command. | ||
397 | */ | ||
398 | if (opcode == 0) { | ||
399 | printf ("%s: ERROR0 IN SCRIPT at %d.\n", | ||
400 | sym_name(np), (int) (cur-start)); | ||
401 | ++cur; | ||
402 | continue; | ||
403 | }; | ||
404 | |||
405 | /* | ||
406 | * We use the bogus value 0xf00ff00f ;-) | ||
407 | * to reserve data area in SCRIPTS. | ||
408 | */ | ||
409 | if (opcode == SCR_DATA_ZERO) { | ||
410 | *cur++ = 0; | ||
411 | continue; | ||
412 | } | ||
413 | |||
414 | if (DEBUG_FLAGS & DEBUG_SCRIPT) | ||
415 | printf ("%d: <%x>\n", (int) (cur-start), | ||
416 | (unsigned)opcode); | ||
417 | |||
418 | /* | ||
419 | * We don't have to decode ALL commands | ||
420 | */ | ||
421 | switch (opcode >> 28) { | ||
422 | case 0xf: | ||
423 | /* | ||
424 | * LOAD / STORE DSA relative, don't relocate. | ||
425 | */ | ||
426 | relocs = 0; | ||
427 | break; | ||
428 | case 0xe: | ||
429 | /* | ||
430 | * LOAD / STORE absolute. | ||
431 | */ | ||
432 | relocs = 1; | ||
433 | break; | ||
434 | case 0xc: | ||
435 | /* | ||
436 | * COPY has TWO arguments. | ||
437 | */ | ||
438 | relocs = 2; | ||
439 | tmp1 = cur[1]; | ||
440 | tmp2 = cur[2]; | ||
441 | if ((tmp1 ^ tmp2) & 3) { | ||
442 | printf ("%s: ERROR1 IN SCRIPT at %d.\n", | ||
443 | sym_name(np), (int) (cur-start)); | ||
444 | } | ||
445 | /* | ||
446 | * If PREFETCH feature not enabled, remove | ||
447 | * the NO FLUSH bit if present. | ||
448 | */ | ||
449 | if ((opcode & SCR_NO_FLUSH) && | ||
450 | !(np->features & FE_PFEN)) { | ||
451 | opcode = (opcode & ~SCR_NO_FLUSH); | ||
452 | } | ||
453 | break; | ||
454 | case 0x0: | ||
455 | /* | ||
456 | * MOVE/CHMOV (absolute address) | ||
457 | */ | ||
458 | if (!(np->features & FE_WIDE)) | ||
459 | opcode = (opcode | OPC_MOVE); | ||
460 | relocs = 1; | ||
461 | break; | ||
462 | case 0x1: | ||
463 | /* | ||
464 | * MOVE/CHMOV (table indirect) | ||
465 | */ | ||
466 | if (!(np->features & FE_WIDE)) | ||
467 | opcode = (opcode | OPC_MOVE); | ||
468 | relocs = 0; | ||
469 | break; | ||
470 | #ifdef SYM_CONF_TARGET_ROLE_SUPPORT | ||
471 | case 0x2: | ||
472 | /* | ||
473 | * MOVE/CHMOV in target role (absolute address) | ||
474 | */ | ||
475 | opcode &= ~0x20000000; | ||
476 | if (!(np->features & FE_WIDE)) | ||
477 | opcode = (opcode & ~OPC_TCHMOVE); | ||
478 | relocs = 1; | ||
479 | break; | ||
480 | case 0x3: | ||
481 | /* | ||
482 | * MOVE/CHMOV in target role (table indirect) | ||
483 | */ | ||
484 | opcode &= ~0x20000000; | ||
485 | if (!(np->features & FE_WIDE)) | ||
486 | opcode = (opcode & ~OPC_TCHMOVE); | ||
487 | relocs = 0; | ||
488 | break; | ||
489 | #endif | ||
490 | case 0x8: | ||
491 | /* | ||
492 | * JUMP / CALL | ||
493 | * don't relocate if relative :-) | ||
494 | */ | ||
495 | if (opcode & 0x00800000) | ||
496 | relocs = 0; | ||
497 | else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/ | ||
498 | relocs = 2; | ||
499 | else | ||
500 | relocs = 1; | ||
501 | break; | ||
502 | case 0x4: | ||
503 | case 0x5: | ||
504 | case 0x6: | ||
505 | case 0x7: | ||
506 | relocs = 1; | ||
507 | break; | ||
508 | default: | ||
509 | relocs = 0; | ||
510 | break; | ||
511 | }; | ||
512 | |||
513 | /* | ||
514 | * Scriptify:) the opcode. | ||
515 | */ | ||
516 | *cur++ = cpu_to_scr(opcode); | ||
517 | |||
518 | /* | ||
519 | * If no relocation, assume 1 argument | ||
520 | * and just scriptize:) it. | ||
521 | */ | ||
522 | if (!relocs) { | ||
523 | *cur = cpu_to_scr(*cur); | ||
524 | ++cur; | ||
525 | continue; | ||
526 | } | ||
527 | |||
528 | /* | ||
529 | * Otherwise performs all needed relocations. | ||
530 | */ | ||
531 | while (relocs--) { | ||
532 | old = *cur; | ||
533 | |||
534 | switch (old & RELOC_MASK) { | ||
535 | case RELOC_REGISTER: | ||
536 | new = (old & ~RELOC_MASK) + np->mmio_ba; | ||
537 | break; | ||
538 | case RELOC_LABEL_A: | ||
539 | new = (old & ~RELOC_MASK) + np->scripta_ba; | ||
540 | break; | ||
541 | case RELOC_LABEL_B: | ||
542 | new = (old & ~RELOC_MASK) + np->scriptb_ba; | ||
543 | break; | ||
544 | case RELOC_SOFTC: | ||
545 | new = (old & ~RELOC_MASK) + np->hcb_ba; | ||
546 | break; | ||
547 | case 0: | ||
548 | /* | ||
549 | * Don't relocate a 0 address. | ||
550 | * They are mostly used for patched or | ||
551 | * script self-modified areas. | ||
552 | */ | ||
553 | if (old == 0) { | ||
554 | new = old; | ||
555 | break; | ||
556 | } | ||
557 | /* fall through */ | ||
558 | default: | ||
559 | new = 0; | ||
560 | panic("sym_fw_bind_script: " | ||
561 | "weird relocation %x\n", old); | ||
562 | break; | ||
563 | } | ||
564 | |||
565 | *cur++ = cpu_to_scr(new); | ||
566 | } | ||
567 | }; | ||
568 | } | ||