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