]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/block/rsxx/config.c
tile: expect new initramfs name from hypervisor file system
[karo-tx-linux.git] / drivers / block / rsxx / config.c
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
32 static void initialize_config(void *config)
33 {
34         struct rsxx_card_cfg *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
47 static 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 -------------------*/
59 static 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
65 static 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
71 static 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
80 static 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
89 static 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 ------------------*/
100 static int 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
133 int 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