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