linux/drivers/block/rsxx/config.c
<<
>>
Prefs
   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
  18static 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
  31static 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 -------------------*/
  43static 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
  49static 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
  55static 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
  64static 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
  73static 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 ------------------*/
  84static 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
 117int 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