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_ENABLE)
 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 inline void read_dev_bar(struct pci_dev *dev,
 213                                struct pci_bar_info *bar_info, int offset,
 214                                u32 len_mask)
 215{
 216        int     pos;
 217        struct resource *res = dev->resource;
 218
 219        if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1)
 220                pos = PCI_ROM_RESOURCE;
 221        else {
 222                pos = (offset - PCI_BASE_ADDRESS_0) / 4;
 223                if (pos && ((res[pos - 1].flags & (PCI_BASE_ADDRESS_SPACE |
 224                                PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
 225                           (PCI_BASE_ADDRESS_SPACE_MEMORY |
 226                                PCI_BASE_ADDRESS_MEM_TYPE_64))) {
 227                        bar_info->val = res[pos - 1].start >> 32;
 228                        bar_info->len_val = res[pos - 1].end >> 32;
 229                        return;
 230                }
 231        }
 232
 233        bar_info->val = res[pos].start |
 234                        (res[pos].flags & PCI_REGION_FLAG_MASK);
 235        bar_info->len_val = resource_size(&res[pos]);
 236}
 237
 238static void *bar_init(struct pci_dev *dev, int offset)
 239{
 240        struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
 241
 242        if (!bar)
 243                return ERR_PTR(-ENOMEM);
 244
 245        read_dev_bar(dev, bar, offset, ~0);
 246        bar->which = 0;
 247
 248        return bar;
 249}
 250
 251static void *rom_init(struct pci_dev *dev, int offset)
 252{
 253        struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
 254
 255        if (!bar)
 256                return ERR_PTR(-ENOMEM);
 257
 258        read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
 259        bar->which = 0;
 260
 261        return bar;
 262}
 263
 264static void bar_reset(struct pci_dev *dev, int offset, void *data)
 265{
 266        struct pci_bar_info *bar = data;
 267
 268        bar->which = 0;
 269}
 270
 271static void bar_release(struct pci_dev *dev, int offset, void *data)
 272{
 273        kfree(data);
 274}
 275
 276static int xen_pcibk_read_vendor(struct pci_dev *dev, int offset,
 277                               u16 *value, void *data)
 278{
 279        *value = dev->vendor;
 280
 281        return 0;
 282}
 283
 284static int xen_pcibk_read_device(struct pci_dev *dev, int offset,
 285                               u16 *value, void *data)
 286{
 287        *value = dev->device;
 288
 289        return 0;
 290}
 291
 292static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
 293                          void *data)
 294{
 295        *value = (u8) dev->irq;
 296
 297        return 0;
 298}
 299
 300static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
 301{
 302        u8 cur_value;
 303        int err;
 304
 305        err = pci_read_config_byte(dev, offset, &cur_value);
 306        if (err)
 307                goto out;
 308
 309        if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
 310            || value == PCI_BIST_START)
 311                err = pci_write_config_byte(dev, offset, value);
 312
 313out:
 314        return err;
 315}
 316
 317static const struct config_field header_common[] = {
 318        {
 319         .offset    = PCI_VENDOR_ID,
 320         .size      = 2,
 321         .u.w.read  = xen_pcibk_read_vendor,
 322        },
 323        {
 324         .offset    = PCI_DEVICE_ID,
 325         .size      = 2,
 326         .u.w.read  = xen_pcibk_read_device,
 327        },
 328        {
 329         .offset    = PCI_COMMAND,
 330         .size      = 2,
 331         .init      = command_init,
 332         .release   = bar_release,
 333         .u.w.read  = command_read,
 334         .u.w.write = command_write,
 335        },
 336        {
 337         .offset    = PCI_INTERRUPT_LINE,
 338         .size      = 1,
 339         .u.b.read  = interrupt_read,
 340        },
 341        {
 342         .offset    = PCI_INTERRUPT_PIN,
 343         .size      = 1,
 344         .u.b.read  = xen_pcibk_read_config_byte,
 345        },
 346        {
 347         /* Any side effects of letting driver domain control cache line? */
 348         .offset    = PCI_CACHE_LINE_SIZE,
 349         .size      = 1,
 350         .u.b.read  = xen_pcibk_read_config_byte,
 351         .u.b.write = xen_pcibk_write_config_byte,
 352        },
 353        {
 354         .offset    = PCI_LATENCY_TIMER,
 355         .size      = 1,
 356         .u.b.read  = xen_pcibk_read_config_byte,
 357        },
 358        {
 359         .offset    = PCI_BIST,
 360         .size      = 1,
 361         .u.b.read  = xen_pcibk_read_config_byte,
 362         .u.b.write = bist_write,
 363        },
 364        {}
 365};
 366
 367#define CFG_FIELD_BAR(reg_offset)                       \
 368        {                                               \
 369        .offset     = reg_offset,                       \
 370        .size       = 4,                                \
 371        .init       = bar_init,                         \
 372        .reset      = bar_reset,                        \
 373        .release    = bar_release,                      \
 374        .u.dw.read  = bar_read,                         \
 375        .u.dw.write = bar_write,                        \
 376        }
 377
 378#define CFG_FIELD_ROM(reg_offset)                       \
 379        {                                               \
 380        .offset     = reg_offset,                       \
 381        .size       = 4,                                \
 382        .init       = rom_init,                         \
 383        .reset      = bar_reset,                        \
 384        .release    = bar_release,                      \
 385        .u.dw.read  = bar_read,                         \
 386        .u.dw.write = rom_write,                        \
 387        }
 388
 389static const struct config_field header_0[] = {
 390        CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
 391        CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
 392        CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
 393        CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
 394        CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
 395        CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
 396        CFG_FIELD_ROM(PCI_ROM_ADDRESS),
 397        {}
 398};
 399
 400static const struct config_field header_1[] = {
 401        CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
 402        CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
 403        CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
 404        {}
 405};
 406
 407int xen_pcibk_config_header_add_fields(struct pci_dev *dev)
 408{
 409        int err;
 410
 411        err = xen_pcibk_config_add_fields(dev, header_common);
 412        if (err)
 413                goto out;
 414
 415        switch (dev->hdr_type) {
 416        case PCI_HEADER_TYPE_NORMAL:
 417                err = xen_pcibk_config_add_fields(dev, header_0);
 418                break;
 419
 420        case PCI_HEADER_TYPE_BRIDGE:
 421                err = xen_pcibk_config_add_fields(dev, header_1);
 422                break;
 423
 424        default:
 425                err = -EINVAL;
 426                pr_err("%s: Unsupported header type %d!\n",
 427                       pci_name(dev), dev->hdr_type);
 428                break;
 429        }
 430
 431out:
 432        return err;
 433}
 434