cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sym_fw.c (12502B)


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