Release 4.7 drivers/xen/xen-pciback/conf_space_header.c
/*
* PCI Backend - Handles the virtual fields in the configuration space headers.
*
* Author: Ryan Wilson <hap9@epoch.ncsc.mil>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/pci.h>
#include "pciback.h"
#include "conf_space.h"
struct pci_cmd_info {
u16 val;
};
struct pci_bar_info {
u32 val;
u32 len_val;
int which;
};
#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
/* Bits guests are allowed to control in permissive mode. */
#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \
PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \
PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK)
static void *command_init(struct pci_dev *dev, int offset)
{
struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
int err;
if (!cmd)
return ERR_PTR(-ENOMEM);
err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val);
if (err) {
kfree(cmd);
return ERR_PTR(err);
}
return cmd;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jan beulich | jan beulich | 80 | 100.00% | 1 | 100.00% |
| Total | 80 | 100.00% | 1 | 100.00% |
static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
{
int ret = pci_read_config_word(dev, offset, value);
const struct pci_cmd_info *cmd = data;
*value &= PCI_COMMAND_GUEST;
*value |= cmd->val & ~PCI_COMMAND_GUEST;
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
yu zhao | yu zhao | 41 | 68.33% | 1 | 50.00% |
jan beulich | jan beulich | 19 | 31.67% | 1 | 50.00% |
| Total | 60 | 100.00% | 2 | 100.00% |
static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
{
struct xen_pcibk_dev_data *dev_data;
int err;
u16 val;
struct pci_cmd_info *cmd = data;
dev_data = pci_get_drvdata(dev);
if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
if (unlikely(verbose_request))
printk(KERN_DEBUG DRV_NAME ": %s: enable\n",
pci_name(dev));
err = pci_enable_device(dev);
if (err)
return err;
if (dev_data)
dev_data->enable_intx = 1;
} else if (pci_is_enabled(dev) && !is_enable_cmd(value)) {
if (unlikely(verbose_request))
printk(KERN_DEBUG DRV_NAME ": %s: disable\n",
pci_name(dev));
pci_disable_device(dev);
if (dev_data)
dev_data->enable_intx = 0;
}
if (!dev->is_busmaster && is_master_cmd(value)) {
if (unlikely(verbose_request))
printk(KERN_DEBUG DRV_NAME ": %s: set bus master\n",
pci_name(dev));
pci_set_master(dev);
} else if (dev->is_busmaster && !is_master_cmd(value)) {
if (unlikely(verbose_request))
printk(KERN_DEBUG DRV_NAME ": %s: clear bus master\n",
pci_name(dev));
pci_clear_master(dev);
}
if (!(cmd->val & PCI_COMMAND_INVALIDATE) &&
(value & PCI_COMMAND_INVALIDATE)) {
if (unlikely(verbose_request))
printk(KERN_DEBUG
DRV_NAME ": %s: enable memory-write-invalidate\n",
pci_name(dev));
err = pci_set_mwi(dev);
if (err) {
pr_warn("%s: cannot enable memory-write-invalidate (%d)\n",
pci_name(dev), err);
value &= ~PCI_COMMAND_INVALIDATE;
}
} else if ((cmd->val & PCI_COMMAND_INVALIDATE) &&
!(value & PCI_COMMAND_INVALIDATE)) {
if (unlikely(verbose_request))
printk(KERN_DEBUG
DRV_NAME ": %s: disable memory-write-invalidate\n",
pci_name(dev));
pci_clear_mwi(dev);
}
cmd->val = value;
if (!xen_pcibk_permissive && (!dev_data || !dev_data->permissive))
return 0;
/* Only allow the guest to control certain bits. */
err = pci_read_config_word(dev, offset, &val);
if (err || val == value)
return err;
value &= PCI_COMMAND_GUEST;
value |= val & ~PCI_COMMAND_GUEST;
return pci_write_config_word(dev, offset, value);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
konrad rzeszutek wilk | konrad rzeszutek wilk | 225 | 57.99% | 3 | 42.86% |
jan beulich | jan beulich | 154 | 39.69% | 2 | 28.57% |
joe perches | joe perches | 8 | 2.06% | 1 | 14.29% |
ben hutchings | ben hutchings | 1 | 0.26% | 1 | 14.29% |
| Total | 388 | 100.00% | 7 | 100.00% |
static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
{
struct pci_bar_info *bar = data;
if (unlikely(!bar)) {
pr_warn(DRV_NAME ": driver data not found for %s\n",
pci_name(dev));
return XEN_PCI_ERR_op_failed;
}
/* A write to obtain the length must happen as a 32-bit write.
* This does not (yet) support writing individual bytes
*/
if ((value | ~PCI_ROM_ADDRESS_MASK) == ~0U)
bar->which = 1;
else {
u32 tmpval;
pci_read_config_dword(dev, offset, &tmpval);
if (tmpval != bar->val && value == bar->val) {
/* Allow restoration of bar value. */
pci_write_config_dword(dev, offset, bar->val);
}
bar->which = 0;
}
/* Do we need to support enabling/disabling the rom address here? */
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
konrad rzeszutek wilk | konrad rzeszutek wilk | 112 | 89.60% | 2 | 50.00% |
joe perches | joe perches | 7 | 5.60% | 1 | 25.00% |
jan beulich | jan beulich | 6 | 4.80% | 1 | 25.00% |
| Total | 125 | 100.00% | 4 | 100.00% |
/* For the BARs, only allow writes which write ~0 or
* the correct resource information
* (Needed for when the driver probes the resource usage)
*/
static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
{
struct pci_bar_info *bar = data;
if (unlikely(!bar)) {
pr_warn(DRV_NAME ": driver data not found for %s\n",
pci_name(dev));
return XEN_PCI_ERR_op_failed;
}
/* A write to obtain the length must happen as a 32-bit write.
* This does not (yet) support writing individual bytes
*/
if (value == ~0)
bar->which = 1;
else {
u32 tmpval;
pci_read_config_dword(dev, offset, &tmpval);
if (tmpval != bar->val && value == bar->val) {
/* Allow restoration of bar value. */
pci_write_config_dword(dev, offset, bar->val);
}
bar->which = 0;
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
konrad rzeszutek wilk | konrad rzeszutek wilk | 112 | 94.12% | 2 | 66.67% |
joe perches | joe perches | 7 | 5.88% | 1 | 33.33% |
| Total | 119 | 100.00% | 3 | 100.00% |
static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
{
struct pci_bar_info *bar = data;
if (unlikely(!bar)) {
pr_warn(DRV_NAME ": driver data not found for %s\n",
pci_name(dev));
return XEN_PCI_ERR_op_failed;
}
*value = bar->which ? bar->len_val : bar->val;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
konrad rzeszutek wilk | konrad rzeszutek wilk | 64 | 90.14% | 2 | 66.67% |
joe perches | joe perches | 7 | 9.86% | 1 | 33.33% |
| Total | 71 | 100.00% | 3 | 100.00% |
static inline void read_dev_bar(struct pci_dev *dev,
struct pci_bar_info *bar_info, int offset,
u32 len_mask)
{
int pos;
struct resource *res = dev->resource;
if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1)
pos = PCI_ROM_RESOURCE;
else {
pos = (offset - PCI_BASE_ADDRESS_0) / 4;
if (pos && ((res[pos - 1].flags & (PCI_BASE_ADDRESS_SPACE |
PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
(PCI_BASE_ADDRESS_SPACE_MEMORY |
PCI_BASE_ADDRESS_MEM_TYPE_64))) {
bar_info->val = res[pos - 1].start >> 32;
bar_info->len_val = -resource_size(&res[pos - 1]) >> 32;
return;
}
}
if (!res[pos].flags ||
(res[pos].flags & (IORESOURCE_DISABLED | IORESOURCE_UNSET |
IORESOURCE_BUSY)))
return;
bar_info->val = res[pos].start |
(res[pos].flags & PCI_REGION_FLAG_MASK);
bar_info->len_val = -resource_size(&res[pos]) |
(res[pos].flags & PCI_REGION_FLAG_MASK);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
yu zhao | yu zhao | 115 | 56.93% | 1 | 25.00% |
jan beulich | jan beulich | 45 | 22.28% | 1 | 25.00% |
konrad rzeszutek wilk | konrad rzeszutek wilk | 38 | 18.81% | 1 | 25.00% |
thomas meyer | thomas meyer | 4 | 1.98% | 1 | 25.00% |
| Total | 202 | 100.00% | 4 | 100.00% |
static void *bar_init(struct pci_dev *dev, int offset)
{
struct pci_bar_info *bar = kzalloc(sizeof(*bar), GFP_KERNEL);
if (!bar)
return ERR_PTR(-ENOMEM);
read_dev_bar(dev, bar, offset, ~0);
return bar;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
konrad rzeszutek wilk | konrad rzeszutek wilk | 57 | 98.28% | 1 | 50.00% |
jan beulich | jan beulich | 1 | 1.72% | 1 | 50.00% |
| Total | 58 | 100.00% | 2 | 100.00% |
static void *rom_init(struct pci_dev *dev, int offset)
{
struct pci_bar_info *bar = kzalloc(sizeof(*bar), GFP_KERNEL);
if (!bar)
return ERR_PTR(-ENOMEM);
read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
return bar;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
konrad rzeszutek wilk | konrad rzeszutek wilk | 57 | 98.28% | 1 | 50.00% |
jan beulich | jan beulich | 1 | 1.72% | 1 | 50.00% |
| Total | 58 | 100.00% | 2 | 100.00% |
static void bar_reset(struct pci_dev *dev, int offset, void *data)
{
struct pci_bar_info *bar = data;
bar->which = 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
konrad rzeszutek wilk | konrad rzeszutek wilk | 31 | 100.00% | 1 | 100.00% |
| Total | 31 | 100.00% | 1 | 100.00% |
static void bar_release(struct pci_dev *dev, int offset, void *data)
{
kfree(data);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
konrad rzeszutek wilk | konrad rzeszutek wilk | 23 | 100.00% | 1 | 100.00% |
| Total | 23 | 100.00% | 1 | 100.00% |
static int xen_pcibk_read_vendor(struct pci_dev *dev, int offset,
u16 *value, void *data)
{
*value = dev->vendor;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
yu zhao | yu zhao | 31 | 96.88% | 1 | 50.00% |
konrad rzeszutek wilk | konrad rzeszutek wilk | 1 | 3.12% | 1 | 50.00% |
| Total | 32 | 100.00% | 2 | 100.00% |
static int xen_pcibk_read_device(struct pci_dev *dev, int offset,
u16 *value, void *data)
{
*value = dev->device;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
yu zhao | yu zhao | 31 | 96.88% | 1 | 50.00% |
konrad rzeszutek wilk | konrad rzeszutek wilk | 1 | 3.12% | 1 | 50.00% |
| Total | 32 | 100.00% | 2 | 100.00% |
static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
void *data)
{
*value = (u8) dev->irq;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
konrad rzeszutek wilk | konrad rzeszutek wilk | 35 | 100.00% | 1 | 100.00% |
| Total | 35 | 100.00% | 1 | 100.00% |
static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
{
u8 cur_value;
int err;
err = pci_read_config_byte(dev, offset, &cur_value);
if (err)
goto out;
if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
|| value == PCI_BIST_START)
err = pci_write_config_byte(dev, offset, value);
out:
return err;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
konrad rzeszutek wilk | konrad rzeszutek wilk | 82 | 100.00% | 1 | 100.00% |
| Total | 82 | 100.00% | 1 | 100.00% |
static const struct config_field header_common[] = {
{
.offset = PCI_VENDOR_ID,
.size = 2,
.u.w.read = xen_pcibk_read_vendor,
},
{
.offset = PCI_DEVICE_ID,
.size = 2,
.u.w.read = xen_pcibk_read_device,
},
{
.offset = PCI_COMMAND,
.size = 2,
.init = command_init,
.release = bar_release,
.u.w.read = command_read,
.u.w.write = command_write,
},
{
.offset = PCI_INTERRUPT_LINE,
.size = 1,
.u.b.read = interrupt_read,
},
{
.offset = PCI_INTERRUPT_PIN,
.size = 1,
.u.b.read = xen_pcibk_read_config_byte,
},
{
/* Any side effects of letting driver domain control cache line? */
.offset = PCI_CACHE_LINE_SIZE,
.size = 1,
.u.b.read = xen_pcibk_read_config_byte,
.u.b.write = xen_pcibk_write_config_byte,
},
{
.offset = PCI_LATENCY_TIMER,
.size = 1,
.u.b.read = xen_pcibk_read_config_byte,
},
{
.offset = PCI_BIST,
.size = 1,
.u.b.read = xen_pcibk_read_config_byte,
.u.b.write = bist_write,
},
{}
};
#define CFG_FIELD_BAR(reg_offset) \
{ \
.offset = reg_offset, \
.size = 4, \
.init = bar_init, \
.reset = bar_reset, \
.release = bar_release, \
.u.dw.read = bar_read, \
.u.dw.write = bar_write, \
}
#define CFG_FIELD_ROM(reg_offset) \
{ \
.offset = reg_offset, \
.size = 4, \
.init = rom_init, \
.reset = bar_reset, \
.release = bar_release, \
.u.dw.read = bar_read, \
.u.dw.write = rom_write, \
}
static const struct config_field header_0[] = {
CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
CFG_FIELD_ROM(PCI_ROM_ADDRESS),
{}
};
static const struct config_field header_1[] = {
CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
{}
};
int xen_pcibk_config_header_add_fields(struct pci_dev *dev)
{
int err;
err = xen_pcibk_config_add_fields(dev, header_common);
if (err)
goto out;
switch (dev->hdr_type) {
case PCI_HEADER_TYPE_NORMAL:
err = xen_pcibk_config_add_fields(dev, header_0);
break;
case PCI_HEADER_TYPE_BRIDGE:
err = xen_pcibk_config_add_fields(dev, header_1);
break;
default:
err = -EINVAL;
pr_err("%s: Unsupported header type %d!\n",
pci_name(dev), dev->hdr_type);
break;
}
out:
return err;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
konrad rzeszutek wilk | konrad rzeszutek wilk | 79 | 88.76% | 2 | 66.67% |
joe perches | joe perches | 10 | 11.24% | 1 | 33.33% |
| Total | 89 | 100.00% | 3 | 100.00% |
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp |
konrad rzeszutek wilk | konrad rzeszutek wilk | 1213 | 65.50% | 4 | 36.36% |
jan beulich | jan beulich | 329 | 17.76% | 3 | 27.27% |
yu zhao | yu zhao | 259 | 13.98% | 1 | 9.09% |
joe perches | joe perches | 46 | 2.48% | 1 | 9.09% |
thomas meyer | thomas meyer | 4 | 0.22% | 1 | 9.09% |
ben hutchings | ben hutchings | 1 | 0.05% | 1 | 9.09% |
| Total | 1852 | 100.00% | 11 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.