diff options
author | Jan Beulich <JBeulich@suse.com> | 2016-06-24 05:13:34 -0400 |
---|---|---|
committer | David Vrabel <david.vrabel@citrix.com> | 2016-06-24 05:53:03 -0400 |
commit | d2bd05d88d245c13b64c3bf9c8927a1c56453d8c (patch) | |
tree | 49b0a103f90f6d553a7bc69d5177f0784bda68e2 | |
parent | d6b186c1e2d852a92c43f090d0d8fad4704d51ef (diff) |
xen-pciback: return proper values during BAR sizing
Reads following writes with all address bits set to 1 should return all
changeable address bits as one, not the BAR size (nor, as was the case
for the upper half of 64-bit BARs, the high half of the region's end
address). Presumably this didn't cause any problems so far because
consumers use the value to calculate the size (usually via val & -val),
and do nothing else with it.
But also consider the exception here: Unimplemented BARs should always
return all zeroes.
And finally, the check for whether to return the sizing address on read
for the ROM BAR should ignore all non-address bits, not just the ROM
Enable one.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
-rw-r--r-- | drivers/xen/xen-pciback/conf_space_header.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/drivers/xen/xen-pciback/conf_space_header.c b/drivers/xen/xen-pciback/conf_space_header.c index ad3d17d29c81..9ead1c2ff1dd 100644 --- a/drivers/xen/xen-pciback/conf_space_header.c +++ b/drivers/xen/xen-pciback/conf_space_header.c | |||
@@ -145,7 +145,7 @@ static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data) | |||
145 | /* A write to obtain the length must happen as a 32-bit write. | 145 | /* A write to obtain the length must happen as a 32-bit write. |
146 | * This does not (yet) support writing individual bytes | 146 | * This does not (yet) support writing individual bytes |
147 | */ | 147 | */ |
148 | if (value == ~PCI_ROM_ADDRESS_ENABLE) | 148 | if ((value | ~PCI_ROM_ADDRESS_MASK) == ~0U) |
149 | bar->which = 1; | 149 | bar->which = 1; |
150 | else { | 150 | else { |
151 | u32 tmpval; | 151 | u32 tmpval; |
@@ -225,38 +225,42 @@ static inline void read_dev_bar(struct pci_dev *dev, | |||
225 | (PCI_BASE_ADDRESS_SPACE_MEMORY | | 225 | (PCI_BASE_ADDRESS_SPACE_MEMORY | |
226 | PCI_BASE_ADDRESS_MEM_TYPE_64))) { | 226 | PCI_BASE_ADDRESS_MEM_TYPE_64))) { |
227 | bar_info->val = res[pos - 1].start >> 32; | 227 | bar_info->val = res[pos - 1].start >> 32; |
228 | bar_info->len_val = res[pos - 1].end >> 32; | 228 | bar_info->len_val = -resource_size(&res[pos - 1]) >> 32; |
229 | return; | 229 | return; |
230 | } | 230 | } |
231 | } | 231 | } |
232 | 232 | ||
233 | if (!res[pos].flags || | ||
234 | (res[pos].flags & (IORESOURCE_DISABLED | IORESOURCE_UNSET | | ||
235 | IORESOURCE_BUSY))) | ||
236 | return; | ||
237 | |||
233 | bar_info->val = res[pos].start | | 238 | bar_info->val = res[pos].start | |
234 | (res[pos].flags & PCI_REGION_FLAG_MASK); | 239 | (res[pos].flags & PCI_REGION_FLAG_MASK); |
235 | bar_info->len_val = resource_size(&res[pos]); | 240 | bar_info->len_val = -resource_size(&res[pos]) | |
241 | (res[pos].flags & PCI_REGION_FLAG_MASK); | ||
236 | } | 242 | } |
237 | 243 | ||
238 | static void *bar_init(struct pci_dev *dev, int offset) | 244 | static void *bar_init(struct pci_dev *dev, int offset) |
239 | { | 245 | { |
240 | struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL); | 246 | struct pci_bar_info *bar = kzalloc(sizeof(*bar), GFP_KERNEL); |
241 | 247 | ||
242 | if (!bar) | 248 | if (!bar) |
243 | return ERR_PTR(-ENOMEM); | 249 | return ERR_PTR(-ENOMEM); |
244 | 250 | ||
245 | read_dev_bar(dev, bar, offset, ~0); | 251 | read_dev_bar(dev, bar, offset, ~0); |
246 | bar->which = 0; | ||
247 | 252 | ||
248 | return bar; | 253 | return bar; |
249 | } | 254 | } |
250 | 255 | ||
251 | static void *rom_init(struct pci_dev *dev, int offset) | 256 | static void *rom_init(struct pci_dev *dev, int offset) |
252 | { | 257 | { |
253 | struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL); | 258 | struct pci_bar_info *bar = kzalloc(sizeof(*bar), GFP_KERNEL); |
254 | 259 | ||
255 | if (!bar) | 260 | if (!bar) |
256 | return ERR_PTR(-ENOMEM); | 261 | return ERR_PTR(-ENOMEM); |
257 | 262 | ||
258 | read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE); | 263 | read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE); |
259 | bar->which = 0; | ||
260 | 264 | ||
261 | return bar; | 265 | return bar; |
262 | } | 266 | } |