linux/drivers/xen/xen-pciback/conf_space.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * PCI Backend - Functions for creating a virtual configuration space for
   4 *               exported PCI Devices.
   5 *               It's dangerous to allow PCI Driver Domains to change their
   6 *               device's resources (memory, i/o ports, interrupts). We need to
   7 *               restrict changes to certain PCI Configuration registers:
   8 *               BARs, INTERRUPT_PIN, most registers in the header...
   9 *
  10 * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
  11 */
  12
  13#include <linux/kernel.h>
  14#include <linux/moduleparam.h>
  15#include <linux/pci.h>
  16#include "pciback.h"
  17#include "conf_space.h"
  18#include "conf_space_quirks.h"
  19
  20bool xen_pcibk_permissive;
  21module_param_named(permissive, xen_pcibk_permissive, bool, 0644);
  22
  23/* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word,
  24 * xen_pcibk_write_config_word, and xen_pcibk_write_config_byte are created. */
  25#define DEFINE_PCI_CONFIG(op, size, type)                       \
  26int xen_pcibk_##op##_config_##size                              \
  27(struct pci_dev *dev, int offset, type value, void *data)       \
  28{                                                               \
  29        return pci_##op##_config_##size(dev, offset, value);    \
  30}
  31
  32DEFINE_PCI_CONFIG(read, byte, u8 *)
  33DEFINE_PCI_CONFIG(read, word, u16 *)
  34DEFINE_PCI_CONFIG(read, dword, u32 *)
  35
  36DEFINE_PCI_CONFIG(write, byte, u8)
  37DEFINE_PCI_CONFIG(write, word, u16)
  38DEFINE_PCI_CONFIG(write, dword, u32)
  39
  40static int conf_space_read(struct pci_dev *dev,
  41                           const struct config_field_entry *entry,
  42                           int offset, u32 *value)
  43{
  44        int ret = 0;
  45        const struct config_field *field = entry->field;
  46
  47        *value = 0;
  48
  49        switch (field->size) {
  50        case 1:
  51                if (field->u.b.read)
  52                        ret = field->u.b.read(dev, offset, (u8 *) value,
  53                                              entry->data);
  54                break;
  55        case 2:
  56                if (field->u.w.read)
  57                        ret = field->u.w.read(dev, offset, (u16 *) value,
  58                                              entry->data);
  59                break;
  60        case 4:
  61                if (field->u.dw.read)
  62                        ret = field->u.dw.read(dev, offset, value, entry->data);
  63                break;
  64        }
  65        return ret;
  66}
  67
  68static int conf_space_write(struct pci_dev *dev,
  69                            const struct config_field_entry *entry,
  70                            int offset, u32 value)
  71{
  72        int ret = 0;
  73        const struct config_field *field = entry->field;
  74
  75        switch (field->size) {
  76        case 1:
  77                if (field->u.b.write)
  78                        ret = field->u.b.write(dev, offset, (u8) value,
  79                                               entry->data);
  80                break;
  81        case 2:
  82                if (field->u.w.write)
  83                        ret = field->u.w.write(dev, offset, (u16) value,
  84                                               entry->data);
  85                break;
  86        case 4:
  87                if (field->u.dw.write)
  88                        ret = field->u.dw.write(dev, offset, value,
  89                                                entry->data);
  90                break;
  91        }
  92        return ret;
  93}
  94
  95static inline u32 get_mask(int size)
  96{
  97        if (size == 1)
  98                return 0xff;
  99        else if (size == 2)
 100                return 0xffff;
 101        else
 102                return 0xffffffff;
 103}
 104
 105static inline int valid_request(int offset, int size)
 106{
 107        /* Validate request (no un-aligned requests) */
 108        if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0)
 109                return 1;
 110        return 0;
 111}
 112
 113static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
 114                              int offset)
 115{
 116        if (offset >= 0) {
 117                new_val_mask <<= (offset * 8);
 118                new_val <<= (offset * 8);
 119        } else {
 120                new_val_mask >>= (offset * -8);
 121                new_val >>= (offset * -8);
 122        }
 123        val = (val & ~new_val_mask) | (new_val & new_val_mask);
 124
 125        return val;
 126}
 127
 128static int xen_pcibios_err_to_errno(int err)
 129{
 130        switch (err) {
 131        case PCIBIOS_SUCCESSFUL:
 132                return XEN_PCI_ERR_success;
 133        case PCIBIOS_DEVICE_NOT_FOUND:
 134                return XEN_PCI_ERR_dev_not_found;
 135        case PCIBIOS_BAD_REGISTER_NUMBER:
 136                return XEN_PCI_ERR_invalid_offset;
 137        case PCIBIOS_FUNC_NOT_SUPPORTED:
 138                return XEN_PCI_ERR_not_implemented;
 139        case PCIBIOS_SET_FAILED:
 140                return XEN_PCI_ERR_access_denied;
 141        }
 142        return err;
 143}
 144
 145int xen_pcibk_config_read(struct pci_dev *dev, int offset, int size,
 146                          u32 *ret_val)
 147{
 148        int err = 0;
 149        struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
 150        const struct config_field_entry *cfg_entry;
 151        const struct config_field *field;
 152        int field_start, field_end;
 153        /* if read fails for any reason, return 0
 154         * (as if device didn't respond) */
 155        u32 value = 0, tmp_val;
 156
 157        if (unlikely(verbose_request))
 158                printk(KERN_DEBUG DRV_NAME ": %s: read %d bytes at 0x%x\n",
 159                       pci_name(dev), size, offset);
 160
 161        if (!valid_request(offset, size)) {
 162                err = XEN_PCI_ERR_invalid_offset;
 163                goto out;
 164        }
 165
 166        /* Get the real value first, then modify as appropriate */
 167        switch (size) {
 168        case 1:
 169                err = pci_read_config_byte(dev, offset, (u8 *) &value);
 170                break;
 171        case 2:
 172                err = pci_read_config_word(dev, offset, (u16 *) &value);
 173                break;
 174        case 4:
 175                err = pci_read_config_dword(dev, offset, &value);
 176                break;
 177        }
 178
 179        list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
 180                field = cfg_entry->field;
 181
 182                field_start = OFFSET(cfg_entry);
 183                field_end = OFFSET(cfg_entry) + field->size;
 184
 185                if (offset + size > field_start && field_end > offset) {
 186                        err = conf_space_read(dev, cfg_entry, field_start,
 187                                              &tmp_val);
 188                        if (err)
 189                                goto out;
 190
 191                        value = merge_value(value, tmp_val,
 192                                            get_mask(field->size),
 193                                            field_start - offset);
 194                }
 195        }
 196
 197out:
 198        if (unlikely(verbose_request))
 199                printk(KERN_DEBUG DRV_NAME ": %s: read %d bytes at 0x%x = %x\n",
 200                       pci_name(dev), size, offset, value);
 201
 202        *ret_val = value;
 203        return xen_pcibios_err_to_errno(err);
 204}
 205
 206int xen_pcibk_config_write(struct pci_dev *dev, int offset, int size, u32 value)
 207{
 208        int err = 0, handled = 0;
 209        struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
 210        const struct config_field_entry *cfg_entry;
 211        const struct config_field *field;
 212        u32 tmp_val;
 213        int field_start, field_end;
 214
 215        if (unlikely(verbose_request))
 216                printk(KERN_DEBUG
 217                       DRV_NAME ": %s: write request %d bytes at 0x%x = %x\n",
 218                       pci_name(dev), size, offset, value);
 219
 220        if (!valid_request(offset, size))
 221                return XEN_PCI_ERR_invalid_offset;
 222
 223        list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
 224                field = cfg_entry->field;
 225
 226                field_start = OFFSET(cfg_entry);
 227                field_end = OFFSET(cfg_entry) + field->size;
 228
 229                if (offset + size > field_start && field_end > offset) {
 230                        err = conf_space_read(dev, cfg_entry, field_start,
 231                                              &tmp_val);
 232                        if (err)
 233                                break;
 234
 235                        tmp_val = merge_value(tmp_val, value, get_mask(size),
 236                                              offset - field_start);
 237
 238                        err = conf_space_write(dev, cfg_entry, field_start,
 239                                               tmp_val);
 240
 241                        /* handled is set true here, but not every byte
 242                         * may have been written! Properly detecting if
 243                         * every byte is handled is unnecessary as the
 244                         * flag is used to detect devices that need
 245                         * special helpers to work correctly.
 246                         */
 247                        handled = 1;
 248                }
 249        }
 250
 251        if (!handled && !err) {
 252                /* By default, anything not specificially handled above is
 253                 * read-only. The permissive flag changes this behavior so
 254                 * that anything not specifically handled above is writable.
 255                 * This means that some fields may still be read-only because
 256                 * they have entries in the config_field list that intercept
 257                 * the write and do nothing. */
 258                if (dev_data->permissive || xen_pcibk_permissive) {
 259                        switch (size) {
 260                        case 1:
 261                                err = pci_write_config_byte(dev, offset,
 262                                                            (u8) value);
 263                                break;
 264                        case 2:
 265                                err = pci_write_config_word(dev, offset,
 266                                                            (u16) value);
 267                                break;
 268                        case 4:
 269                                err = pci_write_config_dword(dev, offset,
 270                                                             (u32) value);
 271                                break;
 272                        }
 273                } else if (!dev_data->warned_on_write) {
 274                        dev_data->warned_on_write = 1;
 275                        dev_warn(&dev->dev, "Driver tried to write to a "
 276                                 "read-only configuration space field at offset"
 277                                 " 0x%x, size %d. This may be harmless, but if "
 278                                 "you have problems with your device:\n"
 279                                 "1) see permissive attribute in sysfs\n"
 280                                 "2) report problems to the xen-devel "
 281                                 "mailing list along with details of your "
 282                                 "device obtained from lspci.\n", offset, size);
 283                }
 284        }
 285
 286        return xen_pcibios_err_to_errno(err);
 287}
 288
 289void xen_pcibk_config_free_dyn_fields(struct pci_dev *dev)
 290{
 291        struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
 292        struct config_field_entry *cfg_entry, *t;
 293        const struct config_field *field;
 294
 295        dev_dbg(&dev->dev, "free-ing dynamically allocated virtual "
 296                           "configuration space fields\n");
 297        if (!dev_data)
 298                return;
 299
 300        list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
 301                field = cfg_entry->field;
 302
 303                if (field->clean) {
 304                        field->clean((struct config_field *)field);
 305
 306                        kfree(cfg_entry->data);
 307
 308                        list_del(&cfg_entry->list);
 309                        kfree(cfg_entry);
 310                }
 311
 312        }
 313}
 314
 315void xen_pcibk_config_reset_dev(struct pci_dev *dev)
 316{
 317        struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
 318        const struct config_field_entry *cfg_entry;
 319        const struct config_field *field;
 320
 321        dev_dbg(&dev->dev, "resetting virtual configuration space\n");
 322        if (!dev_data)
 323                return;
 324
 325        list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
 326                field = cfg_entry->field;
 327
 328                if (field->reset)
 329                        field->reset(dev, OFFSET(cfg_entry), cfg_entry->data);
 330        }
 331}
 332
 333void xen_pcibk_config_free_dev(struct pci_dev *dev)
 334{
 335        struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
 336        struct config_field_entry *cfg_entry, *t;
 337        const struct config_field *field;
 338
 339        dev_dbg(&dev->dev, "free-ing virtual configuration space fields\n");
 340        if (!dev_data)
 341                return;
 342
 343        list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
 344                list_del(&cfg_entry->list);
 345
 346                field = cfg_entry->field;
 347
 348                if (field->release)
 349                        field->release(dev, OFFSET(cfg_entry), cfg_entry->data);
 350
 351                kfree(cfg_entry);
 352        }
 353}
 354
 355int xen_pcibk_config_add_field_offset(struct pci_dev *dev,
 356                                    const struct config_field *field,
 357                                    unsigned int base_offset)
 358{
 359        int err = 0;
 360        struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
 361        struct config_field_entry *cfg_entry;
 362        void *tmp;
 363
 364        cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
 365        if (!cfg_entry) {
 366                err = -ENOMEM;
 367                goto out;
 368        }
 369
 370        cfg_entry->data = NULL;
 371        cfg_entry->field = field;
 372        cfg_entry->base_offset = base_offset;
 373
 374        /* silently ignore duplicate fields */
 375        err = xen_pcibk_field_is_dup(dev, OFFSET(cfg_entry));
 376        if (err)
 377                goto out;
 378
 379        if (field->init) {
 380                tmp = field->init(dev, OFFSET(cfg_entry));
 381
 382                if (IS_ERR(tmp)) {
 383                        err = PTR_ERR(tmp);
 384                        goto out;
 385                }
 386
 387                cfg_entry->data = tmp;
 388        }
 389
 390        dev_dbg(&dev->dev, "added config field at offset 0x%02x\n",
 391                OFFSET(cfg_entry));
 392        list_add_tail(&cfg_entry->list, &dev_data->config_fields);
 393
 394out:
 395        if (err)
 396                kfree(cfg_entry);
 397
 398        return err;
 399}
 400
 401/* This sets up the device's virtual configuration space to keep track of
 402 * certain registers (like the base address registers (BARs) so that we can
 403 * keep the client from manipulating them directly.
 404 */
 405int xen_pcibk_config_init_dev(struct pci_dev *dev)
 406{
 407        int err = 0;
 408        struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
 409
 410        dev_dbg(&dev->dev, "initializing virtual configuration space\n");
 411
 412        INIT_LIST_HEAD(&dev_data->config_fields);
 413
 414        err = xen_pcibk_config_header_add_fields(dev);
 415        if (err)
 416                goto out;
 417
 418        err = xen_pcibk_config_capability_add_fields(dev);
 419        if (err)
 420                goto out;
 421
 422        err = xen_pcibk_config_quirks_init(dev);
 423
 424out:
 425        return err;
 426}
 427
 428int xen_pcibk_config_init(void)
 429{
 430        return xen_pcibk_config_capability_init();
 431}
 432