1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3* Filename: config.c 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 11#include <linux/types.h> 12#include <linux/crc32.h> 13#include <linux/swab.h> 14 15#include "rsxx_priv.h" 16#include "rsxx_cfg.h" 17 18static void initialize_config(struct rsxx_card_cfg *cfg) 19{ 20 cfg->hdr.version = RSXX_CFG_VERSION; 21 22 cfg->data.block_size = RSXX_HW_BLK_SIZE; 23 cfg->data.stripe_size = RSXX_HW_BLK_SIZE; 24 cfg->data.vendor_id = RSXX_VENDOR_ID_IBM; 25 cfg->data.cache_order = (-1); 26 cfg->data.intr_coal.mode = RSXX_INTR_COAL_DISABLED; 27 cfg->data.intr_coal.count = 0; 28 cfg->data.intr_coal.latency = 0; 29} 30 31static u32 config_data_crc32(struct rsxx_card_cfg *cfg) 32{ 33 /* 34 * Return the compliment of the CRC to ensure compatibility 35 * (i.e. this is how early rsxx drivers did it.) 36 */ 37 38 return ~crc32(~0, &cfg->data, sizeof(cfg->data)); 39} 40 41 42/*----------------- Config Byte Swap Functions -------------------*/ 43static void config_hdr_be_to_cpu(struct card_cfg_hdr *hdr) 44{ 45 hdr->version = be32_to_cpu((__force __be32) hdr->version); 46 hdr->crc = be32_to_cpu((__force __be32) hdr->crc); 47} 48 49static void config_hdr_cpu_to_be(struct card_cfg_hdr *hdr) 50{ 51 hdr->version = (__force u32) cpu_to_be32(hdr->version); 52 hdr->crc = (__force u32) cpu_to_be32(hdr->crc); 53} 54 55static void config_data_swab(struct rsxx_card_cfg *cfg) 56{ 57 u32 *data = (u32 *) &cfg->data; 58 int i; 59 60 for (i = 0; i < (sizeof(cfg->data) / 4); i++) 61 data[i] = swab32(data[i]); 62} 63 64static void config_data_le_to_cpu(struct rsxx_card_cfg *cfg) 65{ 66 u32 *data = (u32 *) &cfg->data; 67 int i; 68 69 for (i = 0; i < (sizeof(cfg->data) / 4); i++) 70 data[i] = le32_to_cpu((__force __le32) data[i]); 71} 72 73static void config_data_cpu_to_le(struct rsxx_card_cfg *cfg) 74{ 75 u32 *data = (u32 *) &cfg->data; 76 int i; 77 78 for (i = 0; i < (sizeof(cfg->data) / 4); i++) 79 data[i] = (__force u32) cpu_to_le32(data[i]); 80} 81 82 83/*----------------- Config Operations ------------------*/ 84static int rsxx_save_config(struct rsxx_cardinfo *card) 85{ 86 struct rsxx_card_cfg cfg; 87 int st; 88 89 memcpy(&cfg, &card->config, sizeof(cfg)); 90 91 if (unlikely(cfg.hdr.version != RSXX_CFG_VERSION)) { 92 dev_err(CARD_TO_DEV(card), 93 "Cannot save config with invalid version %d\n", 94 cfg.hdr.version); 95 return -EINVAL; 96 } 97 98 /* Convert data to little endian for the CRC calculation. */ 99 config_data_cpu_to_le(&cfg); 100 101 cfg.hdr.crc = config_data_crc32(&cfg); 102 103 /* 104 * Swap the data from little endian to big endian so it can be 105 * stored. 106 */ 107 config_data_swab(&cfg); 108 config_hdr_cpu_to_be(&cfg.hdr); 109 110 st = rsxx_creg_write(card, CREG_ADD_CONFIG, sizeof(cfg), &cfg, 1); 111 if (st) 112 return st; 113 114 return 0; 115} 116 117int rsxx_load_config(struct rsxx_cardinfo *card) 118{ 119 int st; 120 u32 crc; 121 122 st = rsxx_creg_read(card, CREG_ADD_CONFIG, sizeof(card->config), 123 &card->config, 1); 124 if (st) { 125 dev_err(CARD_TO_DEV(card), 126 "Failed reading card config.\n"); 127 return st; 128 } 129 130 config_hdr_be_to_cpu(&card->config.hdr); 131 132 if (card->config.hdr.version == RSXX_CFG_VERSION) { 133 /* 134 * We calculate the CRC with the data in little endian, because 135 * early drivers did not take big endian CPUs into account. 136 * The data is always stored in big endian, so we need to byte 137 * swap it before calculating the CRC. 138 */ 139 140 config_data_swab(&card->config); 141 142 /* Check the CRC */ 143 crc = config_data_crc32(&card->config); 144 if (crc != card->config.hdr.crc) { 145 dev_err(CARD_TO_DEV(card), 146 "Config corruption detected!\n"); 147 dev_info(CARD_TO_DEV(card), 148 "CRC (sb x%08x is x%08x)\n", 149 card->config.hdr.crc, crc); 150 return -EIO; 151 } 152 153 /* Convert the data to CPU byteorder */ 154 config_data_le_to_cpu(&card->config); 155 156 } else if (card->config.hdr.version != 0) { 157 dev_err(CARD_TO_DEV(card), 158 "Invalid config version %d.\n", 159 card->config.hdr.version); 160 /* 161 * Config version changes require special handling from the 162 * user 163 */ 164 return -EINVAL; 165 } else { 166 dev_info(CARD_TO_DEV(card), 167 "Initializing card configuration.\n"); 168 initialize_config(&card->config); 169 st = rsxx_save_config(card); 170 if (st) 171 return st; 172 } 173 174 card->config_valid = 1; 175 176 dev_dbg(CARD_TO_DEV(card), "version: x%08x\n", 177 card->config.hdr.version); 178 dev_dbg(CARD_TO_DEV(card), "crc: x%08x\n", 179 card->config.hdr.crc); 180 dev_dbg(CARD_TO_DEV(card), "block_size: x%08x\n", 181 card->config.data.block_size); 182 dev_dbg(CARD_TO_DEV(card), "stripe_size: x%08x\n", 183 card->config.data.stripe_size); 184 dev_dbg(CARD_TO_DEV(card), "vendor_id: x%08x\n", 185 card->config.data.vendor_id); 186 dev_dbg(CARD_TO_DEV(card), "cache_order: x%08x\n", 187 card->config.data.cache_order); 188 dev_dbg(CARD_TO_DEV(card), "mode: x%08x\n", 189 card->config.data.intr_coal.mode); 190 dev_dbg(CARD_TO_DEV(card), "count: x%08x\n", 191 card->config.data.intr_coal.count); 192 dev_dbg(CARD_TO_DEV(card), "latency: x%08x\n", 193 card->config.data.intr_coal.latency); 194 195 return 0; 196} 197 198