11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
41da177e4SLinus Torvalds * of PCI-SCSI IO processors.
51da177e4SLinus Torvalds *
61da177e4SLinus Torvalds * Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * This driver is derived from the Linux sym53c8xx driver.
91da177e4SLinus Torvalds * Copyright (C) 1998-2000 Gerard Roudier
101da177e4SLinus Torvalds *
111da177e4SLinus Torvalds * The sym53c8xx driver is derived from the ncr53c8xx driver that had been
121da177e4SLinus Torvalds * a port of the FreeBSD ncr driver to Linux-1.2.13.
131da177e4SLinus Torvalds *
141da177e4SLinus Torvalds * The original ncr driver has been written for 386bsd and FreeBSD by
151da177e4SLinus Torvalds * Wolfgang Stanglmeier <wolf@cologne.de>
161da177e4SLinus Torvalds * Stefan Esser <se@mi.Uni-Koeln.de>
171da177e4SLinus Torvalds * Copyright (C) 1994 Wolfgang Stanglmeier
181da177e4SLinus Torvalds *
191da177e4SLinus Torvalds * Other major contributions:
201da177e4SLinus Torvalds *
211da177e4SLinus Torvalds * NVRAM detection and reading.
221da177e4SLinus Torvalds * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
231da177e4SLinus Torvalds *
241da177e4SLinus Torvalds *-----------------------------------------------------------------------------
251da177e4SLinus Torvalds */
261da177e4SLinus Torvalds
271da177e4SLinus Torvalds #include "sym_glue.h"
281da177e4SLinus Torvalds
291da177e4SLinus Torvalds /*
301da177e4SLinus Torvalds * Macros used for all firmwares.
311da177e4SLinus Torvalds */
321da177e4SLinus Torvalds #define SYM_GEN_A(s, label) ((short) offsetof(s, label)),
331da177e4SLinus Torvalds #define SYM_GEN_B(s, label) ((short) offsetof(s, label)),
341da177e4SLinus Torvalds #define SYM_GEN_Z(s, label) ((short) offsetof(s, label)),
351da177e4SLinus Torvalds #define PADDR_A(label) SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label)
361da177e4SLinus Torvalds #define PADDR_B(label) SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label)
371da177e4SLinus Torvalds
381da177e4SLinus Torvalds
391da177e4SLinus Torvalds #if SYM_CONF_GENERIC_SUPPORT
401da177e4SLinus Torvalds /*
411da177e4SLinus Torvalds * Allocate firmware #1 script area.
421da177e4SLinus Torvalds */
431da177e4SLinus Torvalds #define SYM_FWA_SCR sym_fw1a_scr
441da177e4SLinus Torvalds #define SYM_FWB_SCR sym_fw1b_scr
451da177e4SLinus Torvalds #define SYM_FWZ_SCR sym_fw1z_scr
461da177e4SLinus Torvalds #include "sym_fw1.h"
471da177e4SLinus Torvalds static struct sym_fwa_ofs sym_fw1a_ofs = {
481da177e4SLinus Torvalds SYM_GEN_FW_A(struct SYM_FWA_SCR)
491da177e4SLinus Torvalds };
501da177e4SLinus Torvalds static struct sym_fwb_ofs sym_fw1b_ofs = {
511da177e4SLinus Torvalds SYM_GEN_FW_B(struct SYM_FWB_SCR)
521da177e4SLinus Torvalds };
531da177e4SLinus Torvalds static struct sym_fwz_ofs sym_fw1z_ofs = {
541da177e4SLinus Torvalds SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
551da177e4SLinus Torvalds };
561da177e4SLinus Torvalds #undef SYM_FWA_SCR
571da177e4SLinus Torvalds #undef SYM_FWB_SCR
581da177e4SLinus Torvalds #undef SYM_FWZ_SCR
591da177e4SLinus Torvalds #endif /* SYM_CONF_GENERIC_SUPPORT */
601da177e4SLinus Torvalds
611da177e4SLinus Torvalds /*
621da177e4SLinus Torvalds * Allocate firmware #2 script area.
631da177e4SLinus Torvalds */
641da177e4SLinus Torvalds #define SYM_FWA_SCR sym_fw2a_scr
651da177e4SLinus Torvalds #define SYM_FWB_SCR sym_fw2b_scr
661da177e4SLinus Torvalds #define SYM_FWZ_SCR sym_fw2z_scr
671da177e4SLinus Torvalds #include "sym_fw2.h"
681da177e4SLinus Torvalds static struct sym_fwa_ofs sym_fw2a_ofs = {
691da177e4SLinus Torvalds SYM_GEN_FW_A(struct SYM_FWA_SCR)
701da177e4SLinus Torvalds };
711da177e4SLinus Torvalds static struct sym_fwb_ofs sym_fw2b_ofs = {
721da177e4SLinus Torvalds SYM_GEN_FW_B(struct SYM_FWB_SCR)
731da177e4SLinus Torvalds SYM_GEN_B(struct SYM_FWB_SCR, start64)
741da177e4SLinus Torvalds SYM_GEN_B(struct SYM_FWB_SCR, pm_handle)
751da177e4SLinus Torvalds };
761da177e4SLinus Torvalds static struct sym_fwz_ofs sym_fw2z_ofs = {
771da177e4SLinus Torvalds SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
781da177e4SLinus Torvalds };
791da177e4SLinus Torvalds #undef SYM_FWA_SCR
801da177e4SLinus Torvalds #undef SYM_FWB_SCR
811da177e4SLinus Torvalds #undef SYM_FWZ_SCR
821da177e4SLinus Torvalds
831da177e4SLinus Torvalds #undef SYM_GEN_A
841da177e4SLinus Torvalds #undef SYM_GEN_B
851da177e4SLinus Torvalds #undef SYM_GEN_Z
861da177e4SLinus Torvalds #undef PADDR_A
871da177e4SLinus Torvalds #undef PADDR_B
881da177e4SLinus Torvalds
891da177e4SLinus Torvalds #if SYM_CONF_GENERIC_SUPPORT
901da177e4SLinus Torvalds /*
911da177e4SLinus Torvalds * Patch routine for firmware #1.
921da177e4SLinus Torvalds */
931da177e4SLinus Torvalds static void
sym_fw1_patch(struct Scsi_Host * shost)945111eefaSMatthew Wilcox sym_fw1_patch(struct Scsi_Host *shost)
951da177e4SLinus Torvalds {
965111eefaSMatthew Wilcox struct sym_hcb *np = sym_get_hcb(shost);
971da177e4SLinus Torvalds struct sym_fw1a_scr *scripta0;
981da177e4SLinus Torvalds struct sym_fw1b_scr *scriptb0;
991da177e4SLinus Torvalds
1001da177e4SLinus Torvalds scripta0 = (struct sym_fw1a_scr *) np->scripta0;
1011da177e4SLinus Torvalds scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;
1021da177e4SLinus Torvalds
1031da177e4SLinus Torvalds /*
1041da177e4SLinus Torvalds * Remove LED support if not needed.
1051da177e4SLinus Torvalds */
1061da177e4SLinus Torvalds if (!(np->features & FE_LED0)) {
1071da177e4SLinus Torvalds scripta0->idle[0] = cpu_to_scr(SCR_NO_OP);
1081da177e4SLinus Torvalds scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP);
1091da177e4SLinus Torvalds scripta0->start[0] = cpu_to_scr(SCR_NO_OP);
1101da177e4SLinus Torvalds }
1111da177e4SLinus Torvalds
1121da177e4SLinus Torvalds #ifdef SYM_CONF_IARB_SUPPORT
1131da177e4SLinus Torvalds /*
1141da177e4SLinus Torvalds * If user does not want to use IMMEDIATE ARBITRATION
1151da177e4SLinus Torvalds * when we are reselected while attempting to arbitrate,
1161da177e4SLinus Torvalds * patch the SCRIPTS accordingly with a SCRIPT NO_OP.
1171da177e4SLinus Torvalds */
1181da177e4SLinus Torvalds if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
1191da177e4SLinus Torvalds scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
1201da177e4SLinus Torvalds #endif
1211da177e4SLinus Torvalds /*
1221da177e4SLinus Torvalds * Patch some data in SCRIPTS.
1231da177e4SLinus Torvalds * - start and done queue initial bus address.
1241da177e4SLinus Torvalds * - target bus address table bus address.
1251da177e4SLinus Torvalds */
1261da177e4SLinus Torvalds scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba);
1271da177e4SLinus Torvalds scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba);
1281da177e4SLinus Torvalds scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba);
1291da177e4SLinus Torvalds }
1301da177e4SLinus Torvalds #endif /* SYM_CONF_GENERIC_SUPPORT */
1311da177e4SLinus Torvalds
1321da177e4SLinus Torvalds /*
1331da177e4SLinus Torvalds * Patch routine for firmware #2.
1341da177e4SLinus Torvalds */
1351da177e4SLinus Torvalds static void
sym_fw2_patch(struct Scsi_Host * shost)1365111eefaSMatthew Wilcox sym_fw2_patch(struct Scsi_Host *shost)
1371da177e4SLinus Torvalds {
1385111eefaSMatthew Wilcox struct sym_data *sym_data = shost_priv(shost);
1395111eefaSMatthew Wilcox struct pci_dev *pdev = sym_data->pdev;
1405111eefaSMatthew Wilcox struct sym_hcb *np = sym_data->ncb;
1411da177e4SLinus Torvalds struct sym_fw2a_scr *scripta0;
1421da177e4SLinus Torvalds struct sym_fw2b_scr *scriptb0;
1431da177e4SLinus Torvalds
1441da177e4SLinus Torvalds scripta0 = (struct sym_fw2a_scr *) np->scripta0;
1451da177e4SLinus Torvalds scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;
1461da177e4SLinus Torvalds
1471da177e4SLinus Torvalds /*
1481da177e4SLinus Torvalds * Remove LED support if not needed.
1491da177e4SLinus Torvalds */
1501da177e4SLinus Torvalds if (!(np->features & FE_LED0)) {
1511da177e4SLinus Torvalds scripta0->idle[0] = cpu_to_scr(SCR_NO_OP);
1521da177e4SLinus Torvalds scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP);
1531da177e4SLinus Torvalds scripta0->start[0] = cpu_to_scr(SCR_NO_OP);
1541da177e4SLinus Torvalds }
1551da177e4SLinus Torvalds
1561da177e4SLinus Torvalds #if SYM_CONF_DMA_ADDRESSING_MODE == 2
1571da177e4SLinus Torvalds /*
1581da177e4SLinus Torvalds * Remove useless 64 bit DMA specific SCRIPTS,
1591da177e4SLinus Torvalds * when this feature is not available.
1601da177e4SLinus Torvalds */
1614d85b471SMatthew Wilcox if (!use_dac(np)) {
1621da177e4SLinus Torvalds scripta0->is_dmap_dirty[0] = cpu_to_scr(SCR_NO_OP);
1631da177e4SLinus Torvalds scripta0->is_dmap_dirty[1] = 0;
1641da177e4SLinus Torvalds scripta0->is_dmap_dirty[2] = cpu_to_scr(SCR_NO_OP);
1651da177e4SLinus Torvalds scripta0->is_dmap_dirty[3] = 0;
1661da177e4SLinus Torvalds }
1671da177e4SLinus Torvalds #endif
1681da177e4SLinus Torvalds
1691da177e4SLinus Torvalds #ifdef SYM_CONF_IARB_SUPPORT
1701da177e4SLinus Torvalds /*
1711da177e4SLinus Torvalds * If user does not want to use IMMEDIATE ARBITRATION
1721da177e4SLinus Torvalds * when we are reselected while attempting to arbitrate,
1731da177e4SLinus Torvalds * patch the SCRIPTS accordingly with a SCRIPT NO_OP.
1741da177e4SLinus Torvalds */
1751da177e4SLinus Torvalds if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
1761da177e4SLinus Torvalds scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
1771da177e4SLinus Torvalds #endif
1781da177e4SLinus Torvalds /*
1791da177e4SLinus Torvalds * Patch some variable in SCRIPTS.
1801da177e4SLinus Torvalds * - start and done queue initial bus address.
1811da177e4SLinus Torvalds * - target bus address table bus address.
1821da177e4SLinus Torvalds */
1831da177e4SLinus Torvalds scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba);
1841da177e4SLinus Torvalds scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba);
1851da177e4SLinus Torvalds scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba);
1861da177e4SLinus Torvalds
1871da177e4SLinus Torvalds /*
1881da177e4SLinus Torvalds * Remove the load of SCNTL4 on reselection if not a C10.
1891da177e4SLinus Torvalds */
1901da177e4SLinus Torvalds if (!(np->features & FE_C10)) {
1911da177e4SLinus Torvalds scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP);
1921da177e4SLinus Torvalds scripta0->resel_scntl4[1] = cpu_to_scr(0);
1931da177e4SLinus Torvalds }
1941da177e4SLinus Torvalds
1951da177e4SLinus Torvalds /*
1961da177e4SLinus Torvalds * Remove a couple of work-arounds specific to C1010 if
1971da177e4SLinus Torvalds * they are not desirable. See `sym_fw2.h' for more details.
1981da177e4SLinus Torvalds */
1995111eefaSMatthew Wilcox if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_66 &&
2005111eefaSMatthew Wilcox pdev->revision < 0x1 &&
2011da177e4SLinus Torvalds np->pciclk_khz < 60000)) {
2021da177e4SLinus Torvalds scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP);
2031da177e4SLinus Torvalds scripta0->datao_phase[1] = cpu_to_scr(0);
2041da177e4SLinus Torvalds }
2055111eefaSMatthew Wilcox if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 /* &&
2065111eefaSMatthew Wilcox pdev->revision < 0xff */)) {
2071da177e4SLinus Torvalds scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP);
2081da177e4SLinus Torvalds scripta0->sel_done[1] = cpu_to_scr(0);
2091da177e4SLinus Torvalds }
2101da177e4SLinus Torvalds
2111da177e4SLinus Torvalds /*
2121da177e4SLinus Torvalds * Patch some other variables in SCRIPTS.
2131da177e4SLinus Torvalds * These ones are loaded by the SCRIPTS processor.
2141da177e4SLinus Torvalds */
2151da177e4SLinus Torvalds scriptb0->pm0_data_addr[0] =
2161da177e4SLinus Torvalds cpu_to_scr(np->scripta_ba +
2171da177e4SLinus Torvalds offsetof(struct sym_fw2a_scr, pm0_data));
2181da177e4SLinus Torvalds scriptb0->pm1_data_addr[0] =
2191da177e4SLinus Torvalds cpu_to_scr(np->scripta_ba +
2201da177e4SLinus Torvalds offsetof(struct sym_fw2a_scr, pm1_data));
2211da177e4SLinus Torvalds }
2221da177e4SLinus Torvalds
2231da177e4SLinus Torvalds /*
2241da177e4SLinus Torvalds * Fill the data area in scripts.
2251da177e4SLinus Torvalds * To be done for all firmwares.
2261da177e4SLinus Torvalds */
2271da177e4SLinus Torvalds static void
sym_fw_fill_data(u32 * in,u32 * out)2281da177e4SLinus Torvalds sym_fw_fill_data (u32 *in, u32 *out)
2291da177e4SLinus Torvalds {
2301da177e4SLinus Torvalds int i;
2311da177e4SLinus Torvalds
2321da177e4SLinus Torvalds for (i = 0; i < SYM_CONF_MAX_SG; i++) {
2331da177e4SLinus Torvalds *in++ = SCR_CHMOV_TBL ^ SCR_DATA_IN;
2341da177e4SLinus Torvalds *in++ = offsetof (struct sym_dsb, data[i]);
2351da177e4SLinus Torvalds *out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT;
2361da177e4SLinus Torvalds *out++ = offsetof (struct sym_dsb, data[i]);
2371da177e4SLinus Torvalds }
2381da177e4SLinus Torvalds }
2391da177e4SLinus Torvalds
2401da177e4SLinus Torvalds /*
2411da177e4SLinus Torvalds * Setup useful script bus addresses.
2421da177e4SLinus Torvalds * To be done for all firmwares.
2431da177e4SLinus Torvalds */
2441da177e4SLinus Torvalds static void
sym_fw_setup_bus_addresses(struct sym_hcb * np,struct sym_fw * fw)2451da177e4SLinus Torvalds sym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw)
2461da177e4SLinus Torvalds {
2471da177e4SLinus Torvalds u32 *pa;
2481da177e4SLinus Torvalds u_short *po;
2491da177e4SLinus Torvalds int i;
2501da177e4SLinus Torvalds
2511da177e4SLinus Torvalds /*
2521da177e4SLinus Torvalds * Build the bus address table for script A
2531da177e4SLinus Torvalds * from the script A offset table.
2541da177e4SLinus Torvalds */
2551da177e4SLinus Torvalds po = (u_short *) fw->a_ofs;
2561da177e4SLinus Torvalds pa = (u32 *) &np->fwa_bas;
2571da177e4SLinus Torvalds for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++)
2581da177e4SLinus Torvalds pa[i] = np->scripta_ba + po[i];
2591da177e4SLinus Torvalds
2601da177e4SLinus Torvalds /*
2611da177e4SLinus Torvalds * Same for script B.
2621da177e4SLinus Torvalds */
2631da177e4SLinus Torvalds po = (u_short *) fw->b_ofs;
2641da177e4SLinus Torvalds pa = (u32 *) &np->fwb_bas;
2651da177e4SLinus Torvalds for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++)
2661da177e4SLinus Torvalds pa[i] = np->scriptb_ba + po[i];
2671da177e4SLinus Torvalds
2681da177e4SLinus Torvalds /*
2691da177e4SLinus Torvalds * Same for script Z.
2701da177e4SLinus Torvalds */
2711da177e4SLinus Torvalds po = (u_short *) fw->z_ofs;
2721da177e4SLinus Torvalds pa = (u32 *) &np->fwz_bas;
2731da177e4SLinus Torvalds for (i = 0 ; i < sizeof(np->fwz_bas)/sizeof(u32) ; i++)
2741da177e4SLinus Torvalds pa[i] = np->scriptz_ba + po[i];
2751da177e4SLinus Torvalds }
2761da177e4SLinus Torvalds
2771da177e4SLinus Torvalds #if SYM_CONF_GENERIC_SUPPORT
2781da177e4SLinus Torvalds /*
2791da177e4SLinus Torvalds * Setup routine for firmware #1.
2801da177e4SLinus Torvalds */
2811da177e4SLinus Torvalds static void
sym_fw1_setup(struct sym_hcb * np,struct sym_fw * fw)2821da177e4SLinus Torvalds sym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw)
2831da177e4SLinus Torvalds {
2841da177e4SLinus Torvalds struct sym_fw1a_scr *scripta0;
2851da177e4SLinus Torvalds
2861da177e4SLinus Torvalds scripta0 = (struct sym_fw1a_scr *) np->scripta0;
2871da177e4SLinus Torvalds
2881da177e4SLinus Torvalds /*
2891da177e4SLinus Torvalds * Fill variable parts in scripts.
2901da177e4SLinus Torvalds */
2911da177e4SLinus Torvalds sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
2921da177e4SLinus Torvalds
2931da177e4SLinus Torvalds /*
2941da177e4SLinus Torvalds * Setup bus addresses used from the C code..
2951da177e4SLinus Torvalds */
2961da177e4SLinus Torvalds sym_fw_setup_bus_addresses(np, fw);
2971da177e4SLinus Torvalds }
2981da177e4SLinus Torvalds #endif /* SYM_CONF_GENERIC_SUPPORT */
2991da177e4SLinus Torvalds
3001da177e4SLinus Torvalds /*
3011da177e4SLinus Torvalds * Setup routine for firmware #2.
3021da177e4SLinus Torvalds */
3031da177e4SLinus Torvalds static void
sym_fw2_setup(struct sym_hcb * np,struct sym_fw * fw)3041da177e4SLinus Torvalds sym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw)
3051da177e4SLinus Torvalds {
3061da177e4SLinus Torvalds struct sym_fw2a_scr *scripta0;
3071da177e4SLinus Torvalds
3081da177e4SLinus Torvalds scripta0 = (struct sym_fw2a_scr *) np->scripta0;
3091da177e4SLinus Torvalds
3101da177e4SLinus Torvalds /*
3111da177e4SLinus Torvalds * Fill variable parts in scripts.
3121da177e4SLinus Torvalds */
3131da177e4SLinus Torvalds sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
3141da177e4SLinus Torvalds
3151da177e4SLinus Torvalds /*
3161da177e4SLinus Torvalds * Setup bus addresses used from the C code..
3171da177e4SLinus Torvalds */
3181da177e4SLinus Torvalds sym_fw_setup_bus_addresses(np, fw);
3191da177e4SLinus Torvalds }
3201da177e4SLinus Torvalds
3211da177e4SLinus Torvalds /*
3221da177e4SLinus Torvalds * Allocate firmware descriptors.
3231da177e4SLinus Torvalds */
3241da177e4SLinus Torvalds #if SYM_CONF_GENERIC_SUPPORT
3251da177e4SLinus Torvalds static struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic");
3261da177e4SLinus Torvalds #endif /* SYM_CONF_GENERIC_SUPPORT */
3271da177e4SLinus Torvalds static struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based");
3281da177e4SLinus Torvalds
3291da177e4SLinus Torvalds /*
3301da177e4SLinus Torvalds * Find the most appropriate firmware for a chip.
3311da177e4SLinus Torvalds */
3321da177e4SLinus Torvalds struct sym_fw *
sym_find_firmware(struct sym_chip * chip)3331da177e4SLinus Torvalds sym_find_firmware(struct sym_chip *chip)
3341da177e4SLinus Torvalds {
3351da177e4SLinus Torvalds if (chip->features & FE_LDSTR)
3361da177e4SLinus Torvalds return &sym_fw2;
3371da177e4SLinus Torvalds #if SYM_CONF_GENERIC_SUPPORT
3381da177e4SLinus Torvalds else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC)))
3391da177e4SLinus Torvalds return &sym_fw1;
3401da177e4SLinus Torvalds #endif
3411da177e4SLinus Torvalds else
3421da177e4SLinus Torvalds return NULL;
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds
3451da177e4SLinus Torvalds /*
3461da177e4SLinus Torvalds * Bind a script to physical addresses.
3471da177e4SLinus Torvalds */
sym_fw_bind_script(struct sym_hcb * np,u32 * start,int len)3481da177e4SLinus Torvalds void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len)
3491da177e4SLinus Torvalds {
3501da177e4SLinus Torvalds u32 opcode, new, old, tmp1, tmp2;
3511da177e4SLinus Torvalds u32 *end, *cur;
3521da177e4SLinus Torvalds int relocs;
3531da177e4SLinus Torvalds
3541da177e4SLinus Torvalds cur = start;
3551da177e4SLinus Torvalds end = start + len/4;
3561da177e4SLinus Torvalds
3571da177e4SLinus Torvalds while (cur < end) {
3581da177e4SLinus Torvalds
3591da177e4SLinus Torvalds opcode = *cur;
3601da177e4SLinus Torvalds
3611da177e4SLinus Torvalds /*
3621da177e4SLinus Torvalds * If we forget to change the length
3631da177e4SLinus Torvalds * in scripts, a field will be
3641da177e4SLinus Torvalds * padded with 0. This is an illegal
3651da177e4SLinus Torvalds * command.
3661da177e4SLinus Torvalds */
3671da177e4SLinus Torvalds if (opcode == 0) {
3681da177e4SLinus Torvalds printf ("%s: ERROR0 IN SCRIPT at %d.\n",
3691da177e4SLinus Torvalds sym_name(np), (int) (cur-start));
3701da177e4SLinus Torvalds ++cur;
3711da177e4SLinus Torvalds continue;
3728d4089cdSJason Yan }
3731da177e4SLinus Torvalds
3741da177e4SLinus Torvalds /*
3751da177e4SLinus Torvalds * We use the bogus value 0xf00ff00f ;-)
3761da177e4SLinus Torvalds * to reserve data area in SCRIPTS.
3771da177e4SLinus Torvalds */
3781da177e4SLinus Torvalds if (opcode == SCR_DATA_ZERO) {
3791da177e4SLinus Torvalds *cur++ = 0;
3801da177e4SLinus Torvalds continue;
3811da177e4SLinus Torvalds }
3821da177e4SLinus Torvalds
3831da177e4SLinus Torvalds if (DEBUG_FLAGS & DEBUG_SCRIPT)
3841da177e4SLinus Torvalds printf ("%d: <%x>\n", (int) (cur-start),
3851da177e4SLinus Torvalds (unsigned)opcode);
3861da177e4SLinus Torvalds
3871da177e4SLinus Torvalds /*
3881da177e4SLinus Torvalds * We don't have to decode ALL commands
3891da177e4SLinus Torvalds */
3901da177e4SLinus Torvalds switch (opcode >> 28) {
3911da177e4SLinus Torvalds case 0xf:
3921da177e4SLinus Torvalds /*
3931da177e4SLinus Torvalds * LOAD / STORE DSA relative, don't relocate.
3941da177e4SLinus Torvalds */
3951da177e4SLinus Torvalds relocs = 0;
3961da177e4SLinus Torvalds break;
3971da177e4SLinus Torvalds case 0xe:
3981da177e4SLinus Torvalds /*
3991da177e4SLinus Torvalds * LOAD / STORE absolute.
4001da177e4SLinus Torvalds */
4011da177e4SLinus Torvalds relocs = 1;
4021da177e4SLinus Torvalds break;
4031da177e4SLinus Torvalds case 0xc:
4041da177e4SLinus Torvalds /*
4051da177e4SLinus Torvalds * COPY has TWO arguments.
4061da177e4SLinus Torvalds */
4071da177e4SLinus Torvalds relocs = 2;
4081da177e4SLinus Torvalds tmp1 = cur[1];
4091da177e4SLinus Torvalds tmp2 = cur[2];
4101da177e4SLinus Torvalds if ((tmp1 ^ tmp2) & 3) {
4111da177e4SLinus Torvalds printf ("%s: ERROR1 IN SCRIPT at %d.\n",
4121da177e4SLinus Torvalds sym_name(np), (int) (cur-start));
4131da177e4SLinus Torvalds }
4141da177e4SLinus Torvalds /*
4151da177e4SLinus Torvalds * If PREFETCH feature not enabled, remove
4161da177e4SLinus Torvalds * the NO FLUSH bit if present.
4171da177e4SLinus Torvalds */
4181da177e4SLinus Torvalds if ((opcode & SCR_NO_FLUSH) &&
4191da177e4SLinus Torvalds !(np->features & FE_PFEN)) {
4201da177e4SLinus Torvalds opcode = (opcode & ~SCR_NO_FLUSH);
4211da177e4SLinus Torvalds }
4221da177e4SLinus Torvalds break;
4231da177e4SLinus Torvalds case 0x0:
4241da177e4SLinus Torvalds /*
4251da177e4SLinus Torvalds * MOVE/CHMOV (absolute address)
4261da177e4SLinus Torvalds */
4271da177e4SLinus Torvalds if (!(np->features & FE_WIDE))
4281da177e4SLinus Torvalds opcode = (opcode | OPC_MOVE);
4291da177e4SLinus Torvalds relocs = 1;
4301da177e4SLinus Torvalds break;
4311da177e4SLinus Torvalds case 0x1:
4321da177e4SLinus Torvalds /*
4331da177e4SLinus Torvalds * MOVE/CHMOV (table indirect)
4341da177e4SLinus Torvalds */
4351da177e4SLinus Torvalds if (!(np->features & FE_WIDE))
4361da177e4SLinus Torvalds opcode = (opcode | OPC_MOVE);
4371da177e4SLinus Torvalds relocs = 0;
4381da177e4SLinus Torvalds break;
4391da177e4SLinus Torvalds #ifdef SYM_CONF_TARGET_ROLE_SUPPORT
4401da177e4SLinus Torvalds case 0x2:
4411da177e4SLinus Torvalds /*
4421da177e4SLinus Torvalds * MOVE/CHMOV in target role (absolute address)
4431da177e4SLinus Torvalds */
4441da177e4SLinus Torvalds opcode &= ~0x20000000;
4451da177e4SLinus Torvalds if (!(np->features & FE_WIDE))
4461da177e4SLinus Torvalds opcode = (opcode & ~OPC_TCHMOVE);
4471da177e4SLinus Torvalds relocs = 1;
4481da177e4SLinus Torvalds break;
4491da177e4SLinus Torvalds case 0x3:
4501da177e4SLinus Torvalds /*
4511da177e4SLinus Torvalds * MOVE/CHMOV in target role (table indirect)
4521da177e4SLinus Torvalds */
4531da177e4SLinus Torvalds opcode &= ~0x20000000;
4541da177e4SLinus Torvalds if (!(np->features & FE_WIDE))
4551da177e4SLinus Torvalds opcode = (opcode & ~OPC_TCHMOVE);
4561da177e4SLinus Torvalds relocs = 0;
4571da177e4SLinus Torvalds break;
4581da177e4SLinus Torvalds #endif
4591da177e4SLinus Torvalds case 0x8:
4601da177e4SLinus Torvalds /*
4611da177e4SLinus Torvalds * JUMP / CALL
4621da177e4SLinus Torvalds * don't relocate if relative :-)
4631da177e4SLinus Torvalds */
4641da177e4SLinus Torvalds if (opcode & 0x00800000)
4651da177e4SLinus Torvalds relocs = 0;
4661da177e4SLinus Torvalds else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/
4671da177e4SLinus Torvalds relocs = 2;
4681da177e4SLinus Torvalds else
4691da177e4SLinus Torvalds relocs = 1;
4701da177e4SLinus Torvalds break;
4711da177e4SLinus Torvalds case 0x4:
4721da177e4SLinus Torvalds case 0x5:
4731da177e4SLinus Torvalds case 0x6:
4741da177e4SLinus Torvalds case 0x7:
4751da177e4SLinus Torvalds relocs = 1;
4761da177e4SLinus Torvalds break;
4771da177e4SLinus Torvalds default:
4781da177e4SLinus Torvalds relocs = 0;
4791da177e4SLinus Torvalds break;
4808d4089cdSJason Yan }
4811da177e4SLinus Torvalds
4821da177e4SLinus Torvalds /*
4831da177e4SLinus Torvalds * Scriptify:) the opcode.
4841da177e4SLinus Torvalds */
4851da177e4SLinus Torvalds *cur++ = cpu_to_scr(opcode);
4861da177e4SLinus Torvalds
4871da177e4SLinus Torvalds /*
4881da177e4SLinus Torvalds * If no relocation, assume 1 argument
4891da177e4SLinus Torvalds * and just scriptize:) it.
4901da177e4SLinus Torvalds */
4911da177e4SLinus Torvalds if (!relocs) {
4921da177e4SLinus Torvalds *cur = cpu_to_scr(*cur);
4931da177e4SLinus Torvalds ++cur;
4941da177e4SLinus Torvalds continue;
4951da177e4SLinus Torvalds }
4961da177e4SLinus Torvalds
4971da177e4SLinus Torvalds /*
4981da177e4SLinus Torvalds * Otherwise performs all needed relocations.
4991da177e4SLinus Torvalds */
5001da177e4SLinus Torvalds while (relocs--) {
5011da177e4SLinus Torvalds old = *cur;
5021da177e4SLinus Torvalds
5031da177e4SLinus Torvalds switch (old & RELOC_MASK) {
5041da177e4SLinus Torvalds case RELOC_REGISTER:
5051da177e4SLinus Torvalds new = (old & ~RELOC_MASK) + np->mmio_ba;
5061da177e4SLinus Torvalds break;
5071da177e4SLinus Torvalds case RELOC_LABEL_A:
5081da177e4SLinus Torvalds new = (old & ~RELOC_MASK) + np->scripta_ba;
5091da177e4SLinus Torvalds break;
5101da177e4SLinus Torvalds case RELOC_LABEL_B:
5111da177e4SLinus Torvalds new = (old & ~RELOC_MASK) + np->scriptb_ba;
5121da177e4SLinus Torvalds break;
5131da177e4SLinus Torvalds case RELOC_SOFTC:
5141da177e4SLinus Torvalds new = (old & ~RELOC_MASK) + np->hcb_ba;
5151da177e4SLinus Torvalds break;
5161da177e4SLinus Torvalds case 0:
5171da177e4SLinus Torvalds /*
5181da177e4SLinus Torvalds * Don't relocate a 0 address.
5191da177e4SLinus Torvalds * They are mostly used for patched or
5201da177e4SLinus Torvalds * script self-modified areas.
5211da177e4SLinus Torvalds */
5221da177e4SLinus Torvalds if (old == 0) {
5231da177e4SLinus Torvalds new = old;
5241da177e4SLinus Torvalds break;
5251da177e4SLinus Torvalds }
5261da177e4SLinus Torvalds fallthrough;
5271da177e4SLinus Torvalds default:
5281da177e4SLinus Torvalds new = 0;
5291da177e4SLinus Torvalds panic("sym_fw_bind_script: "
5301da177e4SLinus Torvalds "weird relocation %x\n", old);
5311da177e4SLinus Torvalds break;
5321da177e4SLinus Torvalds }
5331da177e4SLinus Torvalds
5341da177e4SLinus Torvalds *cur++ = cpu_to_scr(new);
5351da177e4SLinus Torvalds }
5368d4089cdSJason Yan }
5371da177e4SLinus Torvalds }
538