diff options
author | ssant@in.ibm.com <ssant@in.ibm.com> | 2005-04-08 01:53:31 -0400 |
---|---|---|
committer | Greg KH <gregkh@suse.de> | 2005-05-04 02:45:15 -0400 |
commit | 4c0619add8c3a8b28e7fae8b15cc7b62de2f8148 (patch) | |
tree | 2e27d1c516480dd6f3686c05caac09b196475951 | |
parent | bc56b9e01190b9f1ad6b7c5c694b61bfe34c7aa5 (diff) |
[PATCH] PCI: fix up word-aligned 16-bit PCI config access through sysfs
This patch adds the possibility to do word-aligned 16-bit atomic PCI
configuration space accesses via the sysfs PCI interface. As a result, problems
with Emulex LFPC on IBM PowerPC64 are fixed.
Patch is present in SLES 9 SP1.
Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/pci/pci-sysfs.c | 82 |
1 files changed, 58 insertions, 24 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index d57ae71d32b1..8568b207f189 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -91,6 +91,7 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) | |||
91 | struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj)); | 91 | struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj)); |
92 | unsigned int size = 64; | 92 | unsigned int size = 64; |
93 | loff_t init_off = off; | 93 | loff_t init_off = off; |
94 | u8 *data = (u8*) buf; | ||
94 | 95 | ||
95 | /* Several chips lock up trying to read undefined config space */ | 96 | /* Several chips lock up trying to read undefined config space */ |
96 | if (capable(CAP_SYS_ADMIN)) { | 97 | if (capable(CAP_SYS_ADMIN)) { |
@@ -108,30 +109,47 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) | |||
108 | size = count; | 109 | size = count; |
109 | } | 110 | } |
110 | 111 | ||
111 | while (off & 3) { | 112 | if ((off & 1) && size) { |
112 | unsigned char val; | 113 | u8 val; |
113 | pci_read_config_byte(dev, off, &val); | 114 | pci_read_config_byte(dev, off, &val); |
114 | buf[off - init_off] = val; | 115 | data[off - init_off] = val; |
115 | off++; | 116 | off++; |
116 | if (--size == 0) | 117 | size--; |
117 | break; | 118 | } |
119 | |||
120 | if ((off & 3) && size > 2) { | ||
121 | u16 val; | ||
122 | pci_read_config_word(dev, off, &val); | ||
123 | data[off - init_off] = val & 0xff; | ||
124 | data[off - init_off + 1] = (val >> 8) & 0xff; | ||
125 | off += 2; | ||
126 | size -= 2; | ||
118 | } | 127 | } |
119 | 128 | ||
120 | while (size > 3) { | 129 | while (size > 3) { |
121 | unsigned int val; | 130 | u32 val; |
122 | pci_read_config_dword(dev, off, &val); | 131 | pci_read_config_dword(dev, off, &val); |
123 | buf[off - init_off] = val & 0xff; | 132 | data[off - init_off] = val & 0xff; |
124 | buf[off - init_off + 1] = (val >> 8) & 0xff; | 133 | data[off - init_off + 1] = (val >> 8) & 0xff; |
125 | buf[off - init_off + 2] = (val >> 16) & 0xff; | 134 | data[off - init_off + 2] = (val >> 16) & 0xff; |
126 | buf[off - init_off + 3] = (val >> 24) & 0xff; | 135 | data[off - init_off + 3] = (val >> 24) & 0xff; |
127 | off += 4; | 136 | off += 4; |
128 | size -= 4; | 137 | size -= 4; |
129 | } | 138 | } |
130 | 139 | ||
131 | while (size > 0) { | 140 | if (size >= 2) { |
132 | unsigned char val; | 141 | u16 val; |
142 | pci_read_config_word(dev, off, &val); | ||
143 | data[off - init_off] = val & 0xff; | ||
144 | data[off - init_off + 1] = (val >> 8) & 0xff; | ||
145 | off += 2; | ||
146 | size -= 2; | ||
147 | } | ||
148 | |||
149 | if (size > 0) { | ||
150 | u8 val; | ||
133 | pci_read_config_byte(dev, off, &val); | 151 | pci_read_config_byte(dev, off, &val); |
134 | buf[off - init_off] = val; | 152 | data[off - init_off] = val; |
135 | off++; | 153 | off++; |
136 | --size; | 154 | --size; |
137 | } | 155 | } |
@@ -145,6 +163,7 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count) | |||
145 | struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj)); | 163 | struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj)); |
146 | unsigned int size = count; | 164 | unsigned int size = count; |
147 | loff_t init_off = off; | 165 | loff_t init_off = off; |
166 | u8 *data = (u8*) buf; | ||
148 | 167 | ||
149 | if (off > dev->cfg_size) | 168 | if (off > dev->cfg_size) |
150 | return 0; | 169 | return 0; |
@@ -152,26 +171,41 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count) | |||
152 | size = dev->cfg_size - off; | 171 | size = dev->cfg_size - off; |
153 | count = size; | 172 | count = size; |
154 | } | 173 | } |
155 | 174 | ||
156 | while (off & 3) { | 175 | if ((off & 1) && size) { |
157 | pci_write_config_byte(dev, off, buf[off - init_off]); | 176 | pci_write_config_byte(dev, off, data[off - init_off]); |
158 | off++; | 177 | off++; |
159 | if (--size == 0) | 178 | size--; |
160 | break; | ||
161 | } | 179 | } |
180 | |||
181 | if ((off & 3) && size > 2) { | ||
182 | u16 val = data[off - init_off]; | ||
183 | val |= (u16) data[off - init_off + 1] << 8; | ||
184 | pci_write_config_word(dev, off, val); | ||
185 | off += 2; | ||
186 | size -= 2; | ||
187 | } | ||
162 | 188 | ||
163 | while (size > 3) { | 189 | while (size > 3) { |
164 | unsigned int val = buf[off - init_off]; | 190 | u32 val = data[off - init_off]; |
165 | val |= (unsigned int) buf[off - init_off + 1] << 8; | 191 | val |= (u32) data[off - init_off + 1] << 8; |
166 | val |= (unsigned int) buf[off - init_off + 2] << 16; | 192 | val |= (u32) data[off - init_off + 2] << 16; |
167 | val |= (unsigned int) buf[off - init_off + 3] << 24; | 193 | val |= (u32) data[off - init_off + 3] << 24; |
168 | pci_write_config_dword(dev, off, val); | 194 | pci_write_config_dword(dev, off, val); |
169 | off += 4; | 195 | off += 4; |
170 | size -= 4; | 196 | size -= 4; |
171 | } | 197 | } |
198 | |||
199 | if (size >= 2) { | ||
200 | u16 val = data[off - init_off]; | ||
201 | val |= (u16) data[off - init_off + 1] << 8; | ||
202 | pci_write_config_word(dev, off, val); | ||
203 | off += 2; | ||
204 | size -= 2; | ||
205 | } | ||
172 | 206 | ||
173 | while (size > 0) { | 207 | if (size) { |
174 | pci_write_config_byte(dev, off, buf[off - init_off]); | 208 | pci_write_config_byte(dev, off, data[off - init_off]); |
175 | off++; | 209 | off++; |
176 | --size; | 210 | --size; |
177 | } | 211 | } |