linux/drivers/xen/xen-pciback/conf_space_header.c
<<
>>
Prefs
   1/*
   2 * PCI Backend - Handles the virtual fields in the configuration space headers.
   3 *
   4 * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
   5 */
   6
   7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   8
   9#include <linux/kernel.h>
  10#include <linux/pci.h>
  11#include "pciback.h"
  12#include "conf_space.h"
  13
  14struct pci_cmd_info {
  15        u16 val;
  16};
  17
  18struct pci_bar_info {
  19        u32 val;
  20        u32 len_val;
  21        int which;
  22};
  23
  24#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
  25#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
  26
  27/* Bits guests are allowed to control in permissive mode. */
  28#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \
  29                           PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \
  30                           PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK)
  31
  32static void *command_init(struct pci_dev *dev, int offset)
  33{
  34        struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
  35        int err;
  36
  37        if (!cmd)
  38                return ERR_PTR(-ENOMEM);
  39
  40        err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val);
  41        if (err) {
  42                kfree(cmd);
  43                return ERR_PTR(err);
  44        }
  45
  46        return cmd;
  47}
  48
  49static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
  50{
  51        int ret = pci_read_config_word(dev, offset, value);
  52        const struct pci_cmd_info *cmd = data;
  53
  54        *value &= PCI_COMMAND_GUEST;
  55        *value |= cmd->val & ~PCI_COMMAND_GUEST;
  56
  57        return ret;
  58}
  59
  60static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
  61{
  62        struct xen_pcibk_dev_data *dev_data;
  63        int err;
  64        u16 val;
  65        struct pci_cmd_info *cmd = data;
  66
  67        dev_data = pci_get_drvdata(dev);
  68        if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
  69                if (unlikely(verbose_request))
  70                        printk(KERN_DEBUG DRV_NAME ": %s: enable\n",
  71                               pci_name(dev));
  72                err = pci_enable_device(dev);
  73                if (err)
  74                        return err;
  75                if (dev_data)
  76                        dev_data->enable_intx = 1;
  77        } else if (pci_is_enabled(dev) && !is_enable_cmd(value)) {
  78                if (unlikely(verbose_request))
  79                        printk(KERN_DEBUG DRV_NAME ": %s: disable\n",
  80                               pci_name(dev));
  81                pci_disable_device(dev);
  82                if (dev_data)
  83                        dev_data->enable_intx = 0;
  84        }
  85
  86        if (!dev->is_busmaster && is_master_cmd(value)) {
  87                if (unlikely(verbose_request))
  88                        printk(KERN_DEBUG DRV_NAME ": %s: set bus master\n",
  89                               pci_name(dev));
  90                pci_set_master(dev);
  91        } else if (dev->is_busmaster && !is_master_cmd(value)) {
  92                if (unlikely(verbose_request))
  93                        printk(KERN_DEBUG DRV_NAME ": %s: clear bus master\n",
  94                               pci_name(dev));
  95                pci_clear_master(dev);
  96        }
  97
  98        if (!(cmd->val & PCI_COMMAND_INVALIDATE) &&
  99            (value & PCI_COMMAND_INVALIDATE)) {
 100                if (unlikely(verbose_request))
 101                        printk(KERN_DEBUG
 102                               DRV_NAME ": %s: enable memory-write-invalidate\n",
 103                               pci_name(dev));
 104                err = pci_set_mwi(dev);
 105                if (err) {
 106                        pr_warn("%s: cannot enable memory-write-invalidate (%d)\n",
 107                                pci_name(dev), err);
 108                        value &= ~PCI_COMMAND_INVALIDATE;
 109                }
 110        } else if ((cmd->val & PCI_COMMAND_INVALIDATE) &&
 111                   !(value & PCI_COMMAND_INVALIDATE)) {
 112                if (unlikely(verbose_request))
 113                        printk(KERN_DEBUG
 114                               DRV_NAME ": %s: disable memory-write-invalidate\n",
 115                               pci_name(dev));
 116                pci_clear_mwi(dev);
 117        }
 118
 119        cmd->val = value;
 120
 121        if (!xen_pcibk_permissive && (!dev_data || !dev_data->permissive))
 122                return 0;
 123
 124        /* Only allow the guest to control certain bits. */
 125        err = pci_read_config_word(dev, offset, &val);
 126        if (err || val == value)
 127                return err;
 128
 129        value &= PCI_COMMAND_GUEST;
 130        value |= val & ~PCI_COMMAND_GUEST;
 131
 132        return pci_write_config_word(dev, offset, value);
 133}
 134
 135static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
 136{
 137        struct pci_bar_info *bar = data;
 138
 139        if (unlikely(!bar)) {
 140                pr_warn(DRV_NAME ": driver data not found for %s\n",
 141                       pci_name(dev));
 142                return XEN_PCI_ERR_op_failed;
 143        }
 144
 145        /* A write to obtain the length must happen as a 32-bit write.
 146         * This does not (yet) support writing individual bytes
 147         */
 148        if ((value | ~PCI_ROM_ADDRESS_MASK) == ~0U)
 149                bar->which = 1;
 150        else {
 151                u32 tmpval;
 152                pci_read_config_dword(dev, offset, &tmpval);
 153                if (tmpval != bar->val && value == bar->val) {
 154                        /* Allow restoration of bar value. */
 155                        pci_write_config_dword(dev, offset, bar->val);
 156                }
 157                bar->which = 0;
 158        }
 159
 160        /* Do we need to support enabling/disabling the rom address here? */
 161
 162        return 0;
 163}
 164
 165/* For the BARs, only allow writes which write ~0 or
 166 * the correct resource information
 167 * (Needed for when the driver probes the resource usage)
 168 */
 169static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
 170{
 171        struct pci_bar_info *bar = data;
 172
 173        if (unlikely(!bar)) {
 174                pr_warn(DRV_NAME ": driver data not found for %s\n",
 175                       pci_name(dev));
 176                return XEN_PCI_ERR_op_failed;
 177        }
 178
 179        /* A write to obtain the length must happen as a 32-bit write.
 180         * This does not (yet) support writing individual bytes
 181         */
 182        if (value == ~0)
 183                bar->which = 1;
 184        else {
 185                u32 tmpval;
 186                pci_read_config_dword(dev, offset, &tmpval);
 187                if (tmpval != bar->val && value == bar->val) {
 188                        /* Allow restoration of bar value. */
 189                        pci_write_config_dword(dev, offset, bar->val);
 190                }
 191                bar->which = 0;
 192        }
 193
 194        return 0;
 195}
 196
 197static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
 198{
 199        struct pci_bar_info *bar = data;
 200
 201        if (unlikely(!bar)) {
 202                pr_warn(DRV_NAME ": driver data not found for %s\n",
 203                       pci_name(dev));
 204                return XEN_PCI_ERR_op_failed;
 205        }
 206
 207        *value = bar->which ? bar->len_val : bar->val;
 208
 209        return 0;
 210}
 211
 212static void *bar_init(struct pci_dev *dev, int offset)
 213{
 214        unsigned int pos;
 215        const struct resource *res = dev->resource;
 216        struct pci_bar_info *bar = kzalloc(sizeof(*bar), GFP_KERNEL);
 217
 218        if (!bar)
 219                return ERR_PTR(-ENOMEM);
 220
 221        if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1)
 222                pos = PCI_ROM_RESOURCE;
 223        else {
 224                pos = (offset - PCI_BASE_ADDRESS_0) / 4;
 225                if (pos && (res[pos - 1].flags & IORESOURCE_MEM_64)) {
 226                        bar->val = res[pos - 1].start >> 32;
 227                        bar->len_val = -resource_size(&res[pos - 1]) >> 32;
 228                        return bar;
 229                }
 230        }
 231
 232        if (!res[pos].flags ||
 233            (res[pos].flags & (IORESOURCE_DISABLED | IORESOURCE_UNSET |
 234                               IORESOURCE_BUSY)))
 235                return bar;
 236
 237        bar->val = res[pos].start |
 238                   (res[pos].flags & PCI_REGION_FLAG_MASK);
 239        bar->len_val = -resource_size(&res[pos]) |
 240                       (res[pos].flags & PCI_REGION_FLAG_MASK);
 241
 242        return bar;
 243}
 244
 245static void bar_reset(struct pci_dev *dev, int offset, void *data)
 246{
 247        struct pci_bar_info *bar = data;
 248
 249        bar->which = 0;
 250}
 251
 252static void bar_release(struct pci_dev *dev, int offset, void *data)
 253{
 254        kfree(data);
 255}
 256
 257static int xen_pcibk_read_vendor(struct pci_dev *dev, int offset,
 258                               u16 *value, void *data)
 259{
 260        *value = dev->vendor;
 261
 262        return 0;
 263}
 264
 265static int xen_pcibk_read_device(struct pci_dev *dev, int offset,
 266                               u16 *value, void *data)
 267{
 268        *value = dev->device;
 269
 270        return 0;
 271}
 272
 273static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
 274                          void *data)
 275{
 276        *value = (u8) dev->irq;
 277
 278        return 0;
 279}
 280
 281static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
 282{
 283        u8 cur_value;
 284        int err;
 285
 286        err = pci_read_config_byte(dev, offset, &cur_value);
 287        if (err)
 288                goto out;
 289
 290        if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
 291            || value == PCI_BIST_START)
 292                err = pci_write_config_byte(dev, offset, value);
 293
 294out:
 295        return err;
 296}
 297
 298static const struct config_field header_common[] = {
 299        {
 300         .offset    = PCI_VENDOR_ID,
 301         .size      = 2,
 302         .u.w.read  = xen_pcibk_read_vendor,
 303        },
 304        {
 305         .offset    = PCI_DEVICE_ID,
 306         .size      = 2,
 307         .u.w.read  = xen_pcibk_read_device,
 308        },
 309        {
 310         .offset    = PCI_COMMAND,
 311         .size      = 2,
 312         .init      = command_init,
 313         .release   = bar_release,
 314         .u.w.read  = command_read,
 315         .u.w.write = command_write,
 316        },
 317        {
 318         .offset    = PCI_INTERRUPT_LINE,
 319         .size      = 1,
 320         .u.b.read  = interrupt_read,
 321        },
 322        {
 323         .offset    = PCI_INTERRUPT_PIN,
 324         .size      = 1,
 325         .u.b.read  = xen_pcibk_read_config_byte,
 326        },
 327        {
 328         /* Any side effects of letting driver domain control cache line? */
 329         .offset    = PCI_CACHE_LINE_SIZE,
 330         .size      = 1,
 331         .u.b.read  = xen_pcibk_read_config_byte,
 332         .u.b.write = xen_pcibk_write_config_byte,
 333        },
 334        {
 335         .offset    = PCI_LATENCY_TIMER,
 336         .size      = 1,
 337         .u.b.read  = xen_pcibk_read_config_byte,
 338        },
 339        {
 340         .offset    = PCI_BIST,
 341         .size      = 1,
 342         .u.b.read  = xen_pcibk_read_config_byte,
 343         .u.b.write = bist_write,
 344        },
 345        {}
 346};
 347
 348#define CFG_FIELD_BAR(reg_offset)                       \
 349        {                                               \
 350        .offset     = reg_offset,                       \
 351        .size       = 4,                                \
 352        .init       = bar_init,                         \
 353        .reset      = bar_reset,                        \
 354        .release    = bar_release,                      \
 355        .u.dw.read  = bar_read,                         \
 356        .u.dw.write = bar_write,                        \
 357        }
 358
 359#define CFG_FIELD_ROM(reg_offset)                       \
 360        {                                               \
 361        .offset     = reg_offset,                       \
 362        .size       = 4,                                \
 363        .init       = bar_init,                         \
 364        .reset      = bar_reset,                        \
 365        .release    = bar_release,                      \
 366        .u.dw.read  = bar_read,                         \
 367        .u.dw.write = rom_write,                        \
 368        }
 369
 370static const struct config_field header_0[] = {
 371        CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
 372        CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
 373        CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
 374        CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
 375        CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
 376        CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
 377        CFG_FIELD_ROM(PCI_ROM_ADDRESS),
 378        {}
 379};
 380
 381static const struct config_field header_1[] = {
 382        CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
 383        CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
 384        CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
 385        {}
 386};
 387
 388int xen_pcibk_config_header_add_fields(struct pci_dev *dev)
 389{
 390        int err;
 391
 392        err = xen_pcibk_config_add_fields(dev, header_common);
 393        if (err)
 394                goto out;
 395
 396        switch (dev->hdr_type) {
 397        case PCI_HEADER_TYPE_NORMAL:
 398                err = xen_pcibk_config_add_fields(dev, header_0);
 399                break;
 400
 401        case PCI_HEADER_TYPE_BRIDGE:
 402                err = xen_pcibk_config_add_fields(dev, header_1);
 403                break;
 404
 405        default:
 406                err = -EINVAL;
 407                pr_err("%s: Unsupported header type %d!\n",
 408                       pci_name(dev), dev->hdr_type);
 409                break;
 410        }
 411
 412out:
 413        return err;
 414}
 415