Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d044af17 authored by Dan Williams's avatar Dan Williams
Browse files

isci: Add support for probing OROM for OEM params



We need to scan the OROM for signature and grab the OEM parameters. We
also need to do the same for EFI. If all fails then we resort to user
binary blob, and if that fails then we go to the defaults.

Share the format with the create_fw utility so that all possible sources
of the parameters are in-sync.

Signed-off-by: default avatarDave Jiang <dave.jiang@intel.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 9affa289
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ EXTRA_CFLAGS += -Idrivers/scsi/isci/core/ -Idrivers/scsi/isci/
obj-$(CONFIG_SCSI_ISCI) += isci.o
isci-objs := init.o phy.o request.o sata.o \
	     remote_device.o port.o timers.o \
	     host.o task.o events.o \
	     host.o task.o events.o probe_roms.o \
	     core/scic_sds_controller.o  \
	     core/scic_sds_remote_device.o    \
	     core/scic_sds_request.o \
+2 −39
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@
#include "sci_status.h"
#include "intel_sas.h"
#include "sci_controller_constants.h"
#include "probe_roms.h"

struct scic_sds_controller;

@@ -223,44 +224,6 @@ union scic_user_parameters {
 */
#define SCIC_SDS_PARM_PHY_MASK_MAX 0xF

/**
 * struct scic_sds_oem_parameters - This structure delineates the various OEM
 *    parameters that must be set the core user.
 *
 *
 */
struct scic_sds_oem_parameters {
	struct {
		/**
		 * This field indicates whether Spread Spectrum Clocking (SSC)
		 * should be enabled or disabled.
		 */
		bool do_enable_ssc;

	} controller;

	struct {
		/**
		 * This field specifies the phys to be contained inside a port.
		 * The bit position in the mask specifies the index of the phy
		 * to be contained in the port.  Multiple bits (i.e. phys)
		 * can be contained in a single port.
		 */
		u8 phy_mask;

	} ports[SCI_MAX_PORTS];

	struct sci_phy_oem_params {
		/**
		 * This field specifies the SAS address to be transmitted on
		 * for this phy index.
		 */
		struct sci_sas_address sas_address;

	} phys[SCI_MAX_PHYS];

};

/**
 * This structure/union specifies the various different OEM parameter sets
 *    available.  Each type is specific to a hardware controller version.
@@ -273,7 +236,7 @@ union scic_oem_parameters {
	 * Storage Controller Unit (SCU) Driver Standard (SDS) version
	 * 1.
	 */
	struct scic_sds_oem_parameters sds1;
	struct scic_sds_oem_params sds1;

};

+2 −4
Original line number Diff line number Diff line
@@ -2039,10 +2039,8 @@ static void scic_sds_controller_set_default_config_parameters(struct scic_sds_co

	/* Initialize all of the phy parameter information. */
	for (index = 0; index < SCI_MAX_PHYS; index++) {
		/*
		 * Default to 3G (i.e. Gen 2) for now.  User can override if
		 * they choose. */
		scic->user_parameters.sds1.phys[index].max_speed_generation = 2;
		/* Default to 6G (i.e. Gen 3) for now. */
		scic->user_parameters.sds1.phys[index].max_speed_generation = 3;

		/* the frequencies cannot be 0 */
		scic->user_parameters.sds1.phys[index].align_insertion_frequency = 0x7f;
+55 −142
Original line number Diff line number Diff line
@@ -6,172 +6,85 @@
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <asm/types.h>
#include <strings.h>
#include <stdint.h>

char blob_name[] = "isci_firmware.bin";
char id[] = "#SCU MAGIC#";
unsigned char version = 1;
unsigned char sub_version = 0;


/*
 * For all defined arrays:
 * elements 0-3 are for SCU0, ports 0-3
 * elements 4-7 are for SCU1, ports 0-3
 *
 * valid configurations for one SCU are:
 *  P0  P1  P2  P3
 * ----------------
 * 0xF,0x0,0x0,0x0 # 1 x4 port
 * 0x3,0x0,0x4,0x8 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are each x1
 *                 # ports
 * 0x1,0x2,0xC,0x0 # Phys 0 and 1 are each x1 ports, phy 2 and phy 3 are a x2
 *                 # port
 * 0x3,0x0,0xC,0x0 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are a x2 port
 * 0x1,0x2,0x4,0x8 # Each phy is a x1 port (this is the default configuration)
 *
 * if there is a port/phy on which you do not wish to override the default
 * values, use the value assigned to UNINIT_PARAM (255).
 */
unsigned int phy_mask[] = { 1, 2, 4, 8, 1, 2, 4, 8 };


/* denotes SAS generation. i.e. 3: SAS Gen 3 6G */
unsigned int phy_gen[] = { 3, 3, 3, 3, 3, 3, 3, 3 };

/*
 * if there is a port/phy on which you do not wish to override the default
 * values, use the value "0000000000000000". SAS address of zero's is
 * considered invalid and will not be used.
 */
unsigned long long sas_addr[] = { 0x5FCFFFFFF0000000ULL,
				  0x5FCFFFFFF1000000ULL,
				  0x5FCFFFFFF2000000ULL,
				  0x5FCFFFFFF3000000ULL,
				  0x5FCFFFFFF4000000ULL,
				  0x5FCFFFFFF5000000ULL,
				  0x5FCFFFFFF6000000ULL,
				  0x5FCFFFFFF7000000ULL };

int write_blob(void)
#include "create_fw.h"
#include "../probe_roms.h"

int write_blob(struct isci_orom *isci_orom)
{
	FILE *fd;
	int err;
	size_t count;

	fd = fopen(blob_name, "w+");
	if (!fd) {
		perror("Open file for write failed");
		fclose(fd);
		return -EIO;
	}

	/* write id */
	err = fwrite((void *)id, sizeof(char), strlen(id)+1, fd);
	if (err == 0) {
		perror("write id failed");
		return err;
	}

	/* write version */
	err = fwrite((void *)&version, sizeof(version), 1, fd);
	if (err == 0) {
		perror("write version failed");
		return err;
	}

	/* write sub version */
	err = fwrite((void *)&sub_version, sizeof(sub_version), 1, fd);
	if (err == 0) {
		perror("write subversion failed");
		return err;
	}

	/* write phy mask header */
	err = fputc(0x1, fd);
	if (err == EOF) {
		perror("write phy mask header failed");
		return -EIO;
	}

	/* write size */
	err = fputc(8, fd);
	if (err == EOF) {
		perror("write phy mask size failed");
	count = fwrite(isci_orom, sizeof(struct isci_orom), 1, fd);
	if (count != 1) {
		perror("Write data failed");
		fclose(fd);
		return -EIO;
	}

	/* write phy masks */
	err = fwrite((void *)phy_mask, 1, sizeof(phy_mask), fd);
	if (err == 0) {
		perror("write phy_mask failed");
		return err;
	}
	fclose(fd);

	/* write phy gen header */
	err = fputc(0x2, fd);
	if (err == EOF) {
		perror("write phy gen header failed");
		return -EIO;
	return 0;
}

	/* write size */
	err = fputc(8, fd);
	if (err == EOF) {
		perror("write phy gen size failed");
		return -EIO;
	}
void set_binary_values(struct isci_orom *isci_orom)
{
	int ctrl_idx, phy_idx, port_idx;

	/* write phy_gen */
	err = fwrite((void *)phy_gen,
		     1,
		     sizeof(phy_gen),
		     fd);
	if (err == 0) {
		perror("write phy_gen failed");
		return err;
	}
	/* setting OROM signature */
	strncpy(isci_orom->hdr.signature, sig, strlen(sig));
	isci_orom->hdr.version = 0x10;
	isci_orom->hdr.total_block_length = sizeof(struct isci_orom);
	isci_orom->hdr.hdr_length = sizeof(struct sci_bios_oem_param_block_hdr);
	isci_orom->hdr.num_elements = num_elements;

	/* write phy gen header */
	err = fputc(0x3, fd);
	if (err == EOF) {
		perror("write sas addr header failed");
		return -EIO;
	}
	for (ctrl_idx = 0; ctrl_idx < 2; ctrl_idx++) {
		isci_orom->ctrl[ctrl_idx].controller.mode_type = mode_type;
		isci_orom->ctrl[ctrl_idx].controller.max_concurrent_dev_spin_up =
			max_num_concurrent_dev_spin_up;
		isci_orom->ctrl[ctrl_idx].controller.do_enable_ssc =
			enable_ssc;

	/* write size */
	err = fputc(8, fd);
	if (err == EOF) {
		perror("write sas addr size failed");
		return -EIO;
	}
		for (port_idx = 0; port_idx < 4; port_idx++)
			isci_orom->ctrl[ctrl_idx].ports[port_idx].phy_mask =
				phy_mask[ctrl_idx][port_idx];

	/* write sas_addr */
	err = fwrite((void *)sas_addr,
		     1,
		     sizeof(sas_addr),
		     fd);
	if (err == 0) {
		perror("write sas_addr failed");
		return err;
		for (phy_idx = 0; phy_idx < 4; phy_idx++) {
			isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.high =
				(__u32)(sas_addr[ctrl_idx][phy_idx] >> 32);
			isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.low =
				(__u32)(sas_addr[ctrl_idx][phy_idx]);
		}

	/* write end header */
	err = fputc(0xff, fd);
	if (err == EOF) {
		perror("write end header failed");
		return -EIO;
	}

	fclose(fd);

	return 0;
}

int main(void)
{
	int err;
	struct isci_orom *isci_orom;

	isci_orom = malloc(sizeof(struct isci_orom));
	memset(isci_orom, 0, sizeof(struct isci_orom));

	err = write_blob();
	if (err < 0)
	set_binary_values(isci_orom);

	err = write_blob(isci_orom);
	if (err < 0) {
		free(isci_orom);
		return err;
	}

	free(isci_orom);
	return 0;
}
+67 −0
Original line number Diff line number Diff line
#ifndef _CREATE_FW_H_
#define _CREATE_FW_H_


/* we are configuring for 2 SCUs */
static const int num_elements = 2;

/*
 * For all defined arrays:
 * elements 0-3 are for SCU0, ports 0-3
 * elements 4-7 are for SCU1, ports 0-3
 *
 * valid configurations for one SCU are:
 *  P0  P1  P2  P3
 * ----------------
 * 0xF,0x0,0x0,0x0 # 1 x4 port
 * 0x3,0x0,0x4,0x8 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are each x1
 *                 # ports
 * 0x1,0x2,0xC,0x0 # Phys 0 and 1 are each x1 ports, phy 2 and phy 3 are a x2
 *                 # port
 * 0x3,0x0,0xC,0x0 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are a x2 port
 * 0x1,0x2,0x4,0x8 # Each phy is a x1 port (this is the default configuration)
 *
 * if there is a port/phy on which you do not wish to override the default
 * values, use the value assigned to UNINIT_PARAM (255).
 */
#ifdef MPC
static const __u8 phy_mask[2][4] = { {1, 2, 4, 8},
				     {1, 2, 4, 8} };
#else	/* APC (default) */
static const __u8 phy_mask[2][4];
#endif

/* discovery mode type (port auto config mode by default ) */
static const int mode_type;

/* Maximum number of concurrent device spin up */
static const int max_num_concurrent_dev_spin_up = 1;

/* enable of ssc operation */
static const int enable_ssc;

/* AFE_TX_AMP_CONTROL */
static const unsigned int afe_tx_amp_control0 = 0x000e7c03;
static const unsigned int afe_tx_amp_control1 = 0x000e7c03;
static const unsigned int afe_tx_amp_control2 = 0x000e7c03;
static const unsigned int afe_tx_amp_control3 = 0x000e7c03;

/*
 * if there is a port/phy on which you do not wish to override the default
 * values, use the value "0000000000000000". SAS address of zero's is
 * considered invalid and will not be used.
 */
static const unsigned long long sas_addr[2][4] = { { 0x5FCFFFFFF0000000ULL,
						     0x5FCFFFFFF1000000ULL,
						     0x5FCFFFFFF2000000ULL,
						     0x5FCFFFFFF3000000ULL },
						   { 0x5FCFFFFFF4000000ULL,
						     0x5FCFFFFFF5000000ULL,
						     0x5FCFFFFFF6000000ULL,
						     0x5FCFFFFFF7000000ULL } };

static const char blob_name[] = "isci_firmware.bin";
static const char sig[] = "ISCUOEMB";
static const unsigned char version = 1;

#endif
Loading