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 
initialize_config(struct rsxx_card_cfg * cfg)18 static 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 
config_data_crc32(struct rsxx_card_cfg * cfg)31 static 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 -------------------*/
config_hdr_be_to_cpu(struct card_cfg_hdr * hdr)43 static 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 
config_hdr_cpu_to_be(struct card_cfg_hdr * hdr)49 static 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 
config_data_swab(struct rsxx_card_cfg * cfg)55 static 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 
config_data_le_to_cpu(struct rsxx_card_cfg * cfg)64 static 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 
config_data_cpu_to_le(struct rsxx_card_cfg * cfg)73 static 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 ------------------*/
rsxx_save_config(struct rsxx_cardinfo * card)84 static 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 
rsxx_load_config(struct rsxx_cardinfo * card)117 int 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