]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/pci/access.c
pci: fix __pci_register_driver error handling
[mirror_ubuntu-artful-kernel.git] / drivers / pci / access.c
CommitLineData
1da177e4
LT
1#include <linux/pci.h>
2#include <linux/module.h>
3#include <linux/ioport.h>
4
48b19148
AB
5#include "pci.h"
6
1da177e4
LT
7/*
8 * This interrupt-safe spinlock protects all accesses to PCI
9 * configuration space.
10 */
11
12static DEFINE_SPINLOCK(pci_lock);
13
14/*
15 * Wrappers for all PCI configuration access functions. They just check
16 * alignment, do locking and call the low-level functions pointed to
17 * by pci_dev->ops.
18 */
19
20#define PCI_byte_BAD 0
21#define PCI_word_BAD (pos & 1)
22#define PCI_dword_BAD (pos & 3)
23
24#define PCI_OP_READ(size,type,len) \
25int pci_bus_read_config_##size \
26 (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \
27{ \
28 int res; \
29 unsigned long flags; \
30 u32 data = 0; \
31 if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
32 spin_lock_irqsave(&pci_lock, flags); \
33 res = bus->ops->read(bus, devfn, pos, len, &data); \
34 *value = (type)data; \
35 spin_unlock_irqrestore(&pci_lock, flags); \
36 return res; \
37}
38
39#define PCI_OP_WRITE(size,type,len) \
40int pci_bus_write_config_##size \
41 (struct pci_bus *bus, unsigned int devfn, int pos, type value) \
42{ \
43 int res; \
44 unsigned long flags; \
45 if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
46 spin_lock_irqsave(&pci_lock, flags); \
47 res = bus->ops->write(bus, devfn, pos, len, value); \
48 spin_unlock_irqrestore(&pci_lock, flags); \
49 return res; \
50}
51
52PCI_OP_READ(byte, u8, 1)
53PCI_OP_READ(word, u16, 2)
54PCI_OP_READ(dword, u32, 4)
55PCI_OP_WRITE(byte, u8, 1)
56PCI_OP_WRITE(word, u16, 2)
57PCI_OP_WRITE(dword, u32, 4)
58
59EXPORT_SYMBOL(pci_bus_read_config_byte);
60EXPORT_SYMBOL(pci_bus_read_config_word);
61EXPORT_SYMBOL(pci_bus_read_config_dword);
62EXPORT_SYMBOL(pci_bus_write_config_byte);
63EXPORT_SYMBOL(pci_bus_write_config_word);
64EXPORT_SYMBOL(pci_bus_write_config_dword);
e04b0ea2
BK
65
66static u32 pci_user_cached_config(struct pci_dev *dev, int pos)
67{
68 u32 data;
69
70 data = dev->saved_config_space[pos/sizeof(dev->saved_config_space[0])];
71 data >>= (pos % sizeof(dev->saved_config_space[0])) * 8;
72 return data;
73}
74
75#define PCI_USER_READ_CONFIG(size,type) \
76int pci_user_read_config_##size \
77 (struct pci_dev *dev, int pos, type *val) \
78{ \
79 unsigned long flags; \
80 int ret = 0; \
81 u32 data = -1; \
82 if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
83 spin_lock_irqsave(&pci_lock, flags); \
84 if (likely(!dev->block_ucfg_access)) \
85 ret = dev->bus->ops->read(dev->bus, dev->devfn, \
86 pos, sizeof(type), &data); \
87 else if (pos < sizeof(dev->saved_config_space)) \
88 data = pci_user_cached_config(dev, pos); \
89 spin_unlock_irqrestore(&pci_lock, flags); \
90 *val = (type)data; \
91 return ret; \
92}
93
94#define PCI_USER_WRITE_CONFIG(size,type) \
95int pci_user_write_config_##size \
96 (struct pci_dev *dev, int pos, type val) \
97{ \
98 unsigned long flags; \
99 int ret = -EIO; \
100 if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
101 spin_lock_irqsave(&pci_lock, flags); \
102 if (likely(!dev->block_ucfg_access)) \
103 ret = dev->bus->ops->write(dev->bus, dev->devfn, \
104 pos, sizeof(type), val); \
105 spin_unlock_irqrestore(&pci_lock, flags); \
106 return ret; \
107}
108
109PCI_USER_READ_CONFIG(byte, u8)
110PCI_USER_READ_CONFIG(word, u16)
111PCI_USER_READ_CONFIG(dword, u32)
112PCI_USER_WRITE_CONFIG(byte, u8)
113PCI_USER_WRITE_CONFIG(word, u16)
114PCI_USER_WRITE_CONFIG(dword, u32)
115
116/**
117 * pci_block_user_cfg_access - Block userspace PCI config reads/writes
118 * @dev: pci device struct
119 *
120 * This function blocks any userspace PCI config accesses from occurring.
121 * When blocked, any writes will be bit bucketed and reads will return the
122 * data saved using pci_save_state for the first 64 bytes of config
123 * space and return 0xff for all other config reads.
124 **/
125void pci_block_user_cfg_access(struct pci_dev *dev)
126{
127 unsigned long flags;
128
129 pci_save_state(dev);
130
131 /* spinlock to synchronize with anyone reading config space now */
132 spin_lock_irqsave(&pci_lock, flags);
133 dev->block_ucfg_access = 1;
134 spin_unlock_irqrestore(&pci_lock, flags);
135}
136EXPORT_SYMBOL_GPL(pci_block_user_cfg_access);
137
138/**
139 * pci_unblock_user_cfg_access - Unblock userspace PCI config reads/writes
140 * @dev: pci device struct
141 *
142 * This function allows userspace PCI config accesses to resume.
143 **/
144void pci_unblock_user_cfg_access(struct pci_dev *dev)
145{
146 unsigned long flags;
147
148 /* spinlock to synchronize with anyone reading saved config space */
149 spin_lock_irqsave(&pci_lock, flags);
150 dev->block_ucfg_access = 0;
151 spin_unlock_irqrestore(&pci_lock, flags);
152}
153EXPORT_SYMBOL_GPL(pci_unblock_user_cfg_access);