Home | History | Annotate | Download | only in fw_load_user
      1 /*
      2  * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
      3  *
      4  * This program is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU General Public License as
      6  * published by the Free Software Foundation; either version 2 of
      7  * the License, or (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it would be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  * GNU General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program; if not, write the Free Software Foundation,
     16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     17  *
     18  * Author:
     19  * Alexey Kodanev <alexey.kodanev (at) oracle.com>
     20  *
     21  * Test checks device firmware loading.
     22  */
     23 
     24 #define _GNU_SOURCE
     25 #include <sys/utsname.h>
     26 #include <stdio.h>
     27 #include <stdlib.h>
     28 #include <unistd.h>
     29 #include <string.h>
     30 
     31 #include "test.h"
     32 #include "safe_macros.h"
     33 #include "old_module.h"
     34 
     35 /* number of test firmware files */
     36 #define FW_FILES	5
     37 
     38 char *TCID = "fw_load";
     39 int TST_TOTAL = FW_FILES;
     40 
     41 static int fw_size = 0x1000;
     42 
     43 static const char fw_name[]	= "load_tst.fw";
     44 static const char module_name[]	= "ltp_fw_load.ko";
     45 
     46 /* paths to module's sysfs files */
     47 static const char dev_fwnum[]	= "/sys/devices/ltp_fw_load/fwnum";
     48 static const char dev_result[]	= "/sys/devices/ltp_fw_load/result";
     49 
     50 struct fw_file_info {
     51 	char *file;
     52 	char *dir;
     53 	int fake;
     54 	int remove_dir;
     55 	int remove_file;
     56 };
     57 
     58 static struct fw_file_info fw[FW_FILES];
     59 static int fw_num;
     60 
     61 /* test options */
     62 static char *narg;
     63 static int nflag;
     64 static int skip_cleanup;
     65 static int verbose;
     66 static const option_t options[] = {
     67 	{"n:", &nflag, &narg},
     68 	{"s", &skip_cleanup, NULL},
     69 	{"v", &verbose, NULL},
     70 	{NULL, NULL, NULL}
     71 };
     72 
     73 static void help(void);
     74 static void setup(int argc, char *argv[]);
     75 static void test_run(void);
     76 static void cleanup(void);
     77 
     78 /*
     79  * create firmware files in the fw_paths
     80  * @fw_paths: it must be termintated by a NULL pointer
     81  */
     82 static void create_firmware(char *const fw_paths[]);
     83 
     84 int main(int argc, char *argv[])
     85 {
     86 	setup(argc, argv);
     87 
     88 	test_run();
     89 
     90 	cleanup();
     91 
     92 	tst_exit();
     93 }
     94 
     95 static void help(void)
     96 {
     97 	printf("  -n x    Write x bytes to firmware file, default is %d\n",
     98 		fw_size);
     99 	printf("  -s      Skip cleanup\n");
    100 	printf("  -v      Verbose\n");
    101 }
    102 
    103 void setup(int argc, char *argv[])
    104 {
    105 
    106 	tst_parse_opts(argc, argv, options, help);
    107 
    108 	if (nflag) {
    109 		if (sscanf(narg, "%i", &fw_size) != 1)
    110 			tst_brkm(TBROK, NULL, "-n option arg is not a number");
    111 		if (fw_size < 0)
    112 			tst_brkm(TBROK, NULL, "-n option arg is less than 0");
    113 	}
    114 
    115 	tst_require_root();
    116 
    117 	if (tst_kvercmp(3, 7, 0) < 0) {
    118 		tst_brkm(TCONF, NULL,
    119 			"Test must be run with kernel 3.7 or newer");
    120 	}
    121 
    122 	char fw_size_param[19];
    123 	snprintf(fw_size_param, 19, "fw_size=%d", fw_size);
    124 	char *const mod_params[2] = { fw_size_param, NULL };
    125 	tst_module_load(NULL, module_name, mod_params);
    126 
    127 	tst_sig(FORK, DEF_HANDLER, cleanup);
    128 
    129 	/* get current Linux version and make firmware paths */
    130 	struct utsname uts_name;
    131 	uname(&uts_name);
    132 
    133 	/* 4 firmware paths + NULL */
    134 	char *fw_paths[5] = { "/lib/firmware", "/lib/firmware/updates" };
    135 	SAFE_ASPRINTF(cleanup, &fw_paths[2], "%s/%s", fw_paths[0], uts_name.release);
    136 	SAFE_ASPRINTF(cleanup, &fw_paths[3], "%s/%s", fw_paths[1], uts_name.release);
    137 
    138 	/* create firmware in the hard coded firmware search paths */
    139 	create_firmware(fw_paths);
    140 
    141 	free(fw_paths[2]);
    142 	free(fw_paths[3]);
    143 
    144 	/* make non-existent firmware file */
    145 	SAFE_ASPRINTF(cleanup, &fw[fw_num].file, "/n%d_%s", fw_num, fw_name);
    146 	fw[fw_num].fake = 1;
    147 	++fw_num;
    148 }
    149 
    150 static void test_run(void)
    151 {
    152 	/* initiate firmware requests */
    153 	SAFE_FILE_PRINTF(cleanup, dev_fwnum, "%d", fw_num);
    154 
    155 	/* get module results by reading result bit mask */
    156 	int result = 0;
    157 	SAFE_FILE_SCANF(cleanup, dev_result, "%d", &result);
    158 
    159 	int i, fail, offset;
    160 	for (i = 0; i < fw_num; ++i) {
    161 		fail = (result & (1 << i)) == 0 && !fw[i].fake;
    162 		offset = (fw[i].dir) ? strlen(fw[i].dir) : 0;
    163 		tst_resm((fail) ? TFAIL : TPASS,
    164 			"Expect: %s load firmware '...%s'",
    165 			(fw[i].fake) ? "can't" : "can",
    166 			fw[i].file + offset);
    167 	}
    168 }
    169 
    170 static void cleanup(void)
    171 {
    172 	if (skip_cleanup)
    173 		return;
    174 
    175 	int i;
    176 	/* remove subdirs first and then upper level dirs */
    177 	for (i = fw_num - 1; i >= 0; --i) {
    178 		if (fw[i].remove_file && remove(fw[i].file) == -1)
    179 			tst_resm(TWARN, "Can't remove: %s", fw[i].file);
    180 		free(fw[i].file);
    181 
    182 		if (fw[i].remove_dir && remove(fw[i].dir) == -1)
    183 			tst_resm(TWARN, "Can't remove %s", fw[i].dir);
    184 		free(fw[i].dir);
    185 	}
    186 
    187 	tst_module_unload(NULL, module_name);
    188 }
    189 
    190 static void create_firmware(char *const fw_paths[])
    191 {
    192 	int i = 0;
    193 	while (fw_paths[i] != NULL) {
    194 		struct fw_file_info *fi = &fw[fw_num];
    195 		fi->dir = strdup(fw_paths[i]);
    196 		if (access(fi->dir, X_OK) == -1) {
    197 			/* create dir */
    198 			SAFE_MKDIR(cleanup, fi->dir, 0755);
    199 			fi->remove_dir = 1;
    200 		}
    201 
    202 		/* create test firmware file */
    203 		SAFE_ASPRINTF(cleanup, &fi->file, "%s/n%d_%s", fi->dir, fw_num, fw_name);
    204 
    205 		FILE *f = SAFE_FOPEN(cleanup, fi->file, "w");
    206 		fi->remove_file = 1;
    207 		int k, byte = fw_num;
    208 		++fw_num;
    209 		for (k = 0; k < fw_size; ++k)
    210 			fputc(byte, f);
    211 		SAFE_FCLOSE(cleanup, f);
    212 		++i;
    213 	}
    214 }
    215