GNU Linux-libre 5.10.215-gnu1
[releases.git] / drivers / block / rsxx / config.c
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
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
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 -------------------*/
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
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
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
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
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 ------------------*/
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
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