/* * PCI Backend - Handles the virtual fields found on the capability lists * in the configuration space. * * Author: Ryan Wilson */ #include #include #include "pciback.h" #include "conf_space.h" static LIST_HEAD(capabilities); struct xen_pcibk_config_capability { struct list_head cap_list; int capability; /* If the device has the capability found above, add these fields */ const struct config_field *fields; }; static const struct config_field caplist_header[] = { { .offset = PCI_CAP_LIST_ID, .size = 2, /* encompass PCI_CAP_LIST_ID & PCI_CAP_LIST_NEXT */ .u.w.read = xen_pcibk_read_config_word, .u.w.write = NULL, }, {} }; static inline void register_capability(struct xen_pcibk_config_capability *cap) { list_add_tail(&cap->cap_list, &capabilities); } int xen_pcibk_config_capability_add_fields(struct pci_dev *dev) { int err = 0; struct xen_pcibk_config_capability *cap; int cap_offset; list_for_each_entry(cap, &capabilities, cap_list) { cap_offset = pci_find_capability(dev, cap->capability); if (cap_offset) { dev_dbg(&dev->dev, "Found capability 0x%x at 0x%x\n", cap->capability, cap_offset); err = xen_pcibk_config_add_fields_offset(dev, caplist_header, cap_offset); if (err) goto out; err = xen_pcibk_config_add_fields_offset(dev, cap->fields, cap_offset); if (err) goto out; } } out: return err; } static int vpd_address_write(struct pci_dev *dev, int offset, u16 value, void *data) { /* Disallow writes to the vital product data */ if (value & PCI_VPD_ADDR_F) return PCIBIOS_SET_FAILED; else return pci_write_config_word(dev, offset, value); } static const struct config_field caplist_vpd[] = { { .offset = PCI_VPD_ADDR, .size = 2, .u.w.read = xen_pcibk_read_config_word, .u.w.write = vpd_address_write, }, { .offset = PCI_VPD_DATA, .size = 4, .u.dw.read = xen_pcibk_read_config_dword, .u.dw.write = NULL, }, {} }; static int pm_caps_read(struct pci_dev *dev, int offset, u16 *value, void *data) { int err; u16 real_value; err = pci_read_config_word(dev, offset, &real_value); if (err) goto out; *value = real_value & ~PCI_PM_CAP_PME_MASK; out: return err; } /* PM_OK_BITS specifies the bits that the driver domain is allowed to change. * Can't allow driver domain to enable PMEs - they're shared */ #define PM_OK_BITS (PCI_PM_CTRL_PME_STATUS|PCI_PM_CTRL_DATA_SEL_MASK) static int pm_ctrl_write(struct pci_dev *dev, int offset, u16 new_value, void *data) { int err; u16 old_value; pci_power_t new_state, old_state; err = pci_read_config_word(dev, offset, &old_value); if (err) goto out; old_state = (pci_power_t)(old_value & PCI_PM_CTRL_STATE_MASK); new_state = (pci_power_t)(new_value & PCI_PM_CTRL_STATE_MASK); new_value &= PM_OK_BITS; if ((old_value & PM_OK_BITS) != new_value) { new_value = (old_value & ~PM_OK_BITS) | new_value; err = pci_write_config_word(dev, offset, new_value); if (err) goto out; } /* Let pci core handle the power management change */ dev_dbg(&dev->dev, "set power state to %x\n", new_state); err = pci_set_power_state(dev, new_state); if (err) { err = PCIBIOS_SET_FAILED; goto out; } out: return err; } /* Ensure PMEs are disabled */ static void *pm_ctrl_init(struct pci_dev *dev, int offset) { int err; u16 value; err = pci_read_config_word(dev, offset, &value); if (err) goto out; if (value & PCI_PM_CTRL_PME_ENABLE) { value &= ~PCI_PM_CTRL_PME_ENABLE; err = pci_write_config_word(dev, offset, value); } out: return ERR_PTR(err); } static const struct config_field caplist_pm[] = { { .offset = PCI_PM_PMC, .size = 2, .u.w.read = pm_caps_read, }, { .offset = PCI_PM_CTRL, .size = 2, .init = pm_ctrl_init, .u.w.read = xen_pcibk_read_config_word, .u.w.write = pm_ctrl_write, }, { .offset = PCI_PM_PPB_EXTENSIONS, .size = 1, .u.b.read = xen_pcibk_read_config_byte, }, { .offset = PCI_PM_DATA_REGISTER, .size = 1, .u.b.read = xen_pcibk_read_config_byte, }, {} }; static struct xen_pcibk_config_capability xen_pcibk_config_capability_pm = { .capability = PCI_CAP_ID_PM, .fields = caplist_pm, }; static struct xen_pcibk_config_capability xen_pcibk_config_capability_vpd = { .capability = PCI_CAP_ID_VPD, .fields = caplist_vpd, }; int xen_pcibk_config_capability_init(void) { register_capability(&xen_pcibk_config_capability_vpd); register_capability(&xen_pcibk_config_capability_pm); return 0; } ss='right'>2016-12-25 14:30:04 -0800 committerLinus Torvalds <torvalds@linux-foundation.org>2016-12-25 14:30:04 -0800 commit3ddc76dfc786cc6f87852693227fb0b1f124f807 (patch) tree8192b4721e05cf6823087f9696db8c0c8f144b02 /net/bluetooth/hci_sysfs.c parentb272f732f888d4cf43c943a40c9aaa836f9b7431 (diff)parent1f3a8e49d8f28f498b8694464623ac20aebfe62a (diff)
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer type cleanups from Thomas Gleixner: "This series does a tree wide cleanup of types related to timers/timekeeping. - Get rid of cycles_t and use a plain u64. The type is not really helpful and caused more confusion than clarity - Get rid of the ktime union. The union has become useless as we use the scalar nanoseconds storage unconditionally now. The 32bit timespec alike storage got removed due to the Y2038 limitations some time ago. That leaves the odd union access around for no reason. Clean it up. Both changes have been done with coccinelle and a small amount of manual mopping up" * 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: ktime: Get rid of ktime_equal() ktime: Cleanup ktime_set() usage ktime: Get rid of the union clocksource: Use a plain u64 instead of cycle_t
Diffstat (limited to 'net/bluetooth/hci_sysfs.c')