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