Commit | Line | Data |
---|---|---|
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 | ||
12 | static 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) \ | |
25 | int 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) \ | |
40 | int 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 | ||
52 | PCI_OP_READ(byte, u8, 1) | |
53 | PCI_OP_READ(word, u16, 2) | |
54 | PCI_OP_READ(dword, u32, 4) | |
55 | PCI_OP_WRITE(byte, u8, 1) | |
56 | PCI_OP_WRITE(word, u16, 2) | |
57 | PCI_OP_WRITE(dword, u32, 4) | |
58 | ||
59 | EXPORT_SYMBOL(pci_bus_read_config_byte); | |
60 | EXPORT_SYMBOL(pci_bus_read_config_word); | |
61 | EXPORT_SYMBOL(pci_bus_read_config_dword); | |
62 | EXPORT_SYMBOL(pci_bus_write_config_byte); | |
63 | EXPORT_SYMBOL(pci_bus_write_config_word); | |
64 | EXPORT_SYMBOL(pci_bus_write_config_dword); | |
e04b0ea2 BK |
65 | |
66 | static 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) \ | |
76 | int 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) \ | |
95 | int 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 | ||
109 | PCI_USER_READ_CONFIG(byte, u8) | |
110 | PCI_USER_READ_CONFIG(word, u16) | |
111 | PCI_USER_READ_CONFIG(dword, u32) | |
112 | PCI_USER_WRITE_CONFIG(byte, u8) | |
113 | PCI_USER_WRITE_CONFIG(word, u16) | |
114 | PCI_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 | **/ | |
125 | void 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 | } | |
136 | EXPORT_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 | **/ | |
144 | void 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 | } | |
153 | EXPORT_SYMBOL_GPL(pci_unblock_user_cfg_access); |