• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
initialize_config(struct rsxx_card_cfg * cfg)32 static 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 
config_data_crc32(struct rsxx_card_cfg * cfg)45 static 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 -------------------*/
config_hdr_be_to_cpu(struct card_cfg_hdr * hdr)57 static 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 
config_hdr_cpu_to_be(struct card_cfg_hdr * hdr)63 static 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 
config_data_swab(struct rsxx_card_cfg * cfg)69 static 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 
config_data_le_to_cpu(struct rsxx_card_cfg * cfg)78 static 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 
config_data_cpu_to_le(struct rsxx_card_cfg * cfg)87 static 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 ------------------*/
rsxx_save_config(struct rsxx_cardinfo * card)98 static 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 
rsxx_load_config(struct rsxx_cardinfo * card)131 int 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