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