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