1/* 2* Filename: config.c 3* 4* 5* Authors: Joshua Morris <josh.h.morris@us.ibm.com> 6* Philip Kelleher <pjk1939@linux.vnet.ibm.com> 7* 8* (C) Copyright 2013 IBM Corporation 9* 10* This program is free software; you can redistribute it and/or 11* modify it under the terms of the GNU General Public License as 12* published by the Free Software Foundation; either version 2 of the 13* License, or (at your option) any later version. 14* 15* This program is distributed in the hope that it will be useful, but 16* WITHOUT ANY WARRANTY; without even the implied warranty of 17* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18* General Public License for more details. 19* 20* You should have received a copy of the GNU General Public License 21* along with this program; if not, write to the Free Software Foundation, 22* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23*/ 24 25#include <linux/types.h> 26#include <linux/crc32.h> 27#include <linux/swab.h> 28 29#include "rsxx_priv.h" 30#include "rsxx_cfg.h" 31 32static void initialize_config(struct rsxx_card_cfg *cfg) 33{ 34 cfg->hdr.version = RSXX_CFG_VERSION; 35 36 cfg->data.block_size = RSXX_HW_BLK_SIZE; 37 cfg->data.stripe_size = RSXX_HW_BLK_SIZE; 38 cfg->data.vendor_id = RSXX_VENDOR_ID_IBM; 39 cfg->data.cache_order = (-1); 40 cfg->data.intr_coal.mode = RSXX_INTR_COAL_DISABLED; 41 cfg->data.intr_coal.count = 0; 42 cfg->data.intr_coal.latency = 0; 43} 44 45static u32 config_data_crc32(struct rsxx_card_cfg *cfg) 46{ 47 /* 48 * Return the compliment of the CRC to ensure compatibility 49 * (i.e. this is how early rsxx drivers did it.) 50 */ 51 52 return ~crc32(~0, &cfg->data, sizeof(cfg->data)); 53} 54 55 56/*----------------- Config Byte Swap Functions -------------------*/ 57static void config_hdr_be_to_cpu(struct card_cfg_hdr *hdr) 58{ 59 hdr->version = be32_to_cpu((__force __be32) hdr->version); 60 hdr->crc = be32_to_cpu((__force __be32) hdr->crc); 61} 62 63static void config_hdr_cpu_to_be(struct card_cfg_hdr *hdr) 64{ 65 hdr->version = (__force u32) cpu_to_be32(hdr->version); 66 hdr->crc = (__force u32) cpu_to_be32(hdr->crc); 67} 68 69static void config_data_swab(struct rsxx_card_cfg *cfg) 70{ 71 u32 *data = (u32 *) &cfg->data; 72 int i; 73 74 for (i = 0; i < (sizeof(cfg->data) / 4); i++) 75 data[i] = swab32(data[i]); 76} 77 78static void config_data_le_to_cpu(struct rsxx_card_cfg *cfg) 79{ 80 u32 *data = (u32 *) &cfg->data; 81 int i; 82 83 for (i = 0; i < (sizeof(cfg->data) / 4); i++) 84 data[i] = le32_to_cpu((__force __le32) data[i]); 85} 86 87static void config_data_cpu_to_le(struct rsxx_card_cfg *cfg) 88{ 89 u32 *data = (u32 *) &cfg->data; 90 int i; 91 92 for (i = 0; i < (sizeof(cfg->data) / 4); i++) 93 data[i] = (__force u32) cpu_to_le32(data[i]); 94} 95 96 97/*----------------- Config Operations ------------------*/ 98static int rsxx_save_config(struct rsxx_cardinfo *card) 99{ 100 struct rsxx_card_cfg cfg; 101 int st; 102 103 memcpy(&cfg, &card->config, sizeof(cfg)); 104 105 if (unlikely(cfg.hdr.version != RSXX_CFG_VERSION)) { 106 dev_err(CARD_TO_DEV(card), 107 "Cannot save config with invalid version %d\n", 108 cfg.hdr.version); 109 return -EINVAL; 110 } 111 112 /* Convert data to little endian for the CRC calculation. */ 113 config_data_cpu_to_le(&cfg); 114 115 cfg.hdr.crc = config_data_crc32(&cfg); 116 117 /* 118 * Swap the data from little endian to big endian so it can be 119 * stored. 120 */ 121 config_data_swab(&cfg); 122 config_hdr_cpu_to_be(&cfg.hdr); 123 124 st = rsxx_creg_write(card, CREG_ADD_CONFIG, sizeof(cfg), &cfg, 1); 125 if (st) 126 return st; 127 128 return 0; 129} 130 131int rsxx_load_config(struct rsxx_cardinfo *card) 132{ 133 int st; 134 u32 crc; 135 136 st = rsxx_creg_read(card, CREG_ADD_CONFIG, sizeof(card->config), 137 &card->config, 1); 138 if (st) { 139 dev_err(CARD_TO_DEV(card), 140 "Failed reading card config.\n"); 141 return st; 142 } 143 144 config_hdr_be_to_cpu(&card->config.hdr); 145 146 if (card->config.hdr.version == RSXX_CFG_VERSION) { 147 /* 148 * We calculate the CRC with the data in little endian, because 149 * early drivers did not take big endian CPUs into account. 150 * The data is always stored in big endian, so we need to byte 151 * swap it before calculating the CRC. 152 */ 153 154 config_data_swab(&card->config); 155 156 /* Check the CRC */ 157 crc = config_data_crc32(&card->config); 158 if (crc != card->config.hdr.crc) { 159 dev_err(CARD_TO_DEV(card), 160 "Config corruption detected!\n"); 161 dev_info(CARD_TO_DEV(card), 162 "CRC (sb x%08x is x%08x)\n", 163 card->config.hdr.crc, crc); 164 return -EIO; 165 } 166 167 /* Convert the data to CPU byteorder */ 168 config_data_le_to_cpu(&card->config); 169 170 } else if (card->config.hdr.version != 0) { 171 dev_err(CARD_TO_DEV(card), 172 "Invalid config version %d.\n", 173 card->config.hdr.version); 174 /* 175 * Config version changes require special handling from the 176 * user 177 */ 178 return -EINVAL; 179 } else { 180 dev_info(CARD_TO_DEV(card), 181 "Initializing card configuration.\n"); 182 initialize_config(&card->config); 183 st = rsxx_save_config(card); 184 if (st) 185 return st; 186 } 187 188 card->config_valid = 1; 189 190 dev_dbg(CARD_TO_DEV(card), "version: x%08x\n", 191 card->config.hdr.version); 192 dev_dbg(CARD_TO_DEV(card), "crc: x%08x\n", 193 card->config.hdr.crc); 194 dev_dbg(CARD_TO_DEV(card), "block_size: x%08x\n", 195 card->config.data.block_size); 196 dev_dbg(CARD_TO_DEV(card), "stripe_size: x%08x\n", 197 card->config.data.stripe_size); 198 dev_dbg(CARD_TO_DEV(card), "vendor_id: x%08x\n", 199 card->config.data.vendor_id); 200 dev_dbg(CARD_TO_DEV(card), "cache_order: x%08x\n", 201 card->config.data.cache_order); 202 dev_dbg(CARD_TO_DEV(card), "mode: x%08x\n", 203 card->config.data.intr_coal.mode); 204 dev_dbg(CARD_TO_DEV(card), "count: x%08x\n", 205 card->config.data.intr_coal.count); 206 dev_dbg(CARD_TO_DEV(card), "latency: x%08x\n", 207 card->config.data.intr_coal.latency); 208 209 return 0; 210} 211 212