PCI: Clear all bridge res MEM_64 if host bridge has non mem64
PATCH 1/1 PCI: Clear all bridge res MEM_64 if host bridge has non mem64
So we could use bridge 64bit mem pref for children mem pref instead of forcing them into bridge mem.
Could help Marek's system as his system is using _CRS, and all mem res is under 4G.
--- drivers/pci/host-bridge.c | 7 +++++++ drivers/pci/pci.h | 1 + drivers/pci/probe.c | 9 +++++++++ drivers/pci/setup-bus.c | 3 +++ include/linux/pci.h | 1 + 5 files changed, 21 insertions(+)
drivers/pci/host-bridge.c +7 -0
@@ -31,6 +31,13 @@ void pci_set_host_bridge_release(struct bridge->release_data = release_data; } +bool pcibios_host_bridge_has_mem64_res (struct pci_bus *bus) +{ +struct pci_host_bridge *bridge =find_pci_host_bridge (bus); + +return bridge->has_mem64_res; +} +void pcibios_resource_to_bus (struct pci_bus *bus,struct pci_bus_region *region,struct resource *res) {
drivers/pci/pci.h +1 -0
@@ -196,6 +196,7 @@ enum pci_bar_type { pci_bar_mem64, /* A 64-bit memory BAR */ }; +bool pcibios_host_bridge_has_mem64_res (struct pci_bus *bus);bool pci_bus_read_dev_vendor_id (struct pci_bus *bus,int devfn,u32 *pl,int crs_timeout);int pci_setup_device (struct pci_dev *dev);
drivers/pci/probe.c +9 -0
@@ -1980,6 +1980,15 @@ struct pci_bus *pci_create_root_bus(strudev_info (&b->dev,"root bus resource %pR%s\n" , res, bus_addr); } +list_for_each_entry (window, &bridge->windows, list) { + res = window->res; +if (resource_type (res) ==IORESOURCE_MEM || + res->end >0xffffffff ) { + bridge->has_mem64_res = true; +break ; + } + } +down_write (&pci_bus_sem);list_add_tail (&b->node, &pci_root_buses);up_write (&pci_bus_sem);
include/linux/pci.h +1 -0
@@ -407,6 +407,7 @@ struct pci_host_bridge {struct list_head windows;/* pci_host_bridge_windows */ void (*release_fn)(struct pci_host_bridge *);void *release_data; +bool has_mem64_res; };#define to_pci_host_bridge (n) container_of(n, struct pci_host_bridge, dev)
drivers/pci/setup-bus.c +3 -0
@@ -693,6 +693,9 @@ static void pci_bridge_check_ranges(stru } } +if (!pcibios_host_bridge_has_mem64_res (bus)) + b_res[2 ].flags &= ~IORESOURCE_MEM_64 ; +/* double check if bridge does support 64 bit pref */ if (b_res[2 ].flags &IORESOURCE_MEM_64 ) {u32 mem_base_hi, tmp;
Bjorn Helgaas
maintainerQuoted 54 lines · Yinghai Lu
So we could use bridge 64bit mem pref for children mem pref instead of forcing them into bridge mem.
Could help Marek's system as his system is using
_CRS, and all mem res is under 4G.Reported-by Marek Kordik <[email protected]>Fixes 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources")Signed-off-by Yinghai Lu <[email protected]>--- drivers/pci/host-bridge.c | 7 +++++++ drivers/pci/pci.h | 1 + drivers/pci/probe.c | 9 +++++++++ drivers/pci/setup-bus.c | 3 +++ include/linux/pci.h | 1 + 5 files changed, 21 insertions(+)Index:
linux-2.6/drivers/pci/host-bridge.c
===================================================================drivers/pci/host-bridge.c +7
-0@@ -31,6 +31,13 @@ void pci_set_host_bridge_release(struct bridge->release_data = release_data; } +bool pcibios_host_bridge_has_mem64_res (struct pci_bus *bus) +{ +struct pci_host_bridge *bridge =find_pci_host_bridge (bus); + +return bridge->has_mem64_res; +} +void pcibios_resource_to_bus (struct pci_bus *bus,struct pci_bus_region *region,struct resource *res) {Index:
linux-2.6/drivers/pci/pci.h
===================================================================drivers/pci/pci.h +1
-0@@ -196,6 +196,7 @@ enum pci_bar_type { pci_bar_mem64, /* A 64-bit memory BAR */ }; +bool pcibios_host_bridge_has_mem64_res (struct pci_bus *bus);bool pci_bus_read_dev_vendor_id (struct pci_bus *bus,int devfn,u32 *pl,int crs_timeout);int pci_setup_device (struct pci_dev *dev);Index:
linux-2.6/drivers/pci/probe.c
===================================================================
drivers/pci/probe.c struct pci_bus *pci_create_root_bus(stru · line 1987
Quoted 8 lines
drivers/pci/probe.c +5
-0@@ -1980,6 +1980,15 @@ struct pci_bus *pci_create_root_bus(strudev_info (&b->dev,"root bus resource %pR%s\n" , res, bus_addr); } +list_for_each_entry (window, &bridge->windows, list) { + res = window->res; +if (resource_type (res) ==IORESOURCE_MEM || + res->end >0xffffffff ) { + bridge->has_mem64_res = true;
This is an interesting idea, but I think you're checking CPU addresses here, and you need to check PCI bus addresses.
Bjorn
Quoted 9 lines · Bjorn Helgaas
drivers/pci/probe.c struct pci_bus *pci_create_root_bus(stru · line 1987
Quoted 5 lines · Yinghai Lu
drivers/pci/probe.c +5
-0+list_for_each_entry (window, &bridge->windows, list) { + res = window->res; +if (resource_type (res) ==IORESOURCE_MEM || + res->end >0xffffffff ) { + bridge->has_mem64_res = true;This is an interesting idea, but I think you're checking CPU addresses here, and you need to check PCI bus addresses.
Looks like those IBM platforms have res > 4g, but pci bus address < 4g. If we check pci bus address, and then we would break those platforms.
Yinghai
A message that is not in the archive (sent off-list or not yet received): 20141210141537.GA9298@richard
My mutt hang, in case the mail isn't sent out, I resend it.
Quoted 9 lines · Wei Yang
Quoted 8 lines · Yinghai Lu
Quoted 7 lines · Bjorn Helgaas
Quoted 5 lines · Yinghai Lu
drivers/pci/probe.c +5
-0+list_for_each_entry (window, &bridge->windows, list) { + res = window->res; +if (resource_type (res) ==IORESOURCE_MEM || + res->end >0xffffffff ) { + bridge->has_mem64_res = true;
Quoted 6 lines
Quoted 6 lines
Quoted 2 lines
This is an interesting idea, but I think you're checking CPU addresses here, and you need to check PCI bus addresses.
Looks like those IBM platforms have res > 4g, but pci bus address < 4g. If we check pci bus address, and then we would break those platforms.
Hi, Yinghai
I did some test with patch on my machine. It looks good.
While as Bjorn mentioned, I think we could change it a little. The pci space on our machine is like this:
cpu address pci address
MEM 0x00003ff280000000..0x00003ff2fffeffff -> 0x00000000 8000 0000
MEM64 0x00003d5000000000..0x00003d5fffffffff -> 0x00003d50 0000 0000
Each root bridge has two MMIO window. From this output we could see the pci address for 64-bit window is above 4G.
I did a little change on your code, like this
list_for_each_entry(window, &bridge->windows, list) {
res = window->res;
if (resource_type(res) == IORESOURCE_MEM ||
- res->end > 0xffffffff) {
+ (res->end - window->offset) > 0xffffffff) {
bridge->has_mem64_res = true;
break;
}
}This also works on my machine.
One more question, with this patch, do we still need previous patch for Marek's problem?
Quoted 5 lines
Quoted 1 line
Yinghai
Signature · 2 lines
Richard Yang Help you, Help me
Signature · 2 lines
Richard Yang Help you, Help me
Quoted 41 lines · Wei Yang
My mutt hang, in case the mail isn't sent out, I resend it.
Quoted 9 lines · Wei Yang
Quoted 8 lines · Yinghai Lu
Quoted 7 lines · Bjorn Helgaas
Quoted 5 lines · Yinghai Lu
drivers/pci/probe.c +5
-0+list_for_each_entry (window, &bridge->windows, list) { + res = window->res; +if (resource_type (res) ==IORESOURCE_MEM || + res->end >0xffffffff ) { + bridge->has_mem64_res = true;Quoted 6 lines
Quoted 6 lines
Quoted 2 lines
This is an interesting idea, but I think you're checking CPU addresses here, and you need to check PCI bus addresses.
Looks like those IBM platforms have res > 4g, but pci bus address < 4g. If we check pci bus address, and then we would break those platforms.
Hi, Yinghai
I did some test with patch on my machine. It looks good.
While as Bjorn mentioned, I think we could change it a little. The pci space on our machine is like this:
cpu address pci address
MEM 0x00003ff280000000..0x00003ff2fffeffff ->0x000000008000 0000
MEM64 0x00003d5000000000..0x00003d5fffffffff ->0x00003d500000 0000Each root bridge has two MMIO window. From this output we could see the pci address for 64-bit window is above 4G.
I did a little change on your code, like this
list_for_each_entry(window, &bridge->windows, list) { res = window->res; if (resource_type(res) == IORESOURCE_MEM ||
Review
Quoted 6 lines
(quoted diff) +1
-1- res->end > 0xffffffff) { + (res->end - window->offset) > 0xffffffff) { bridge->has_mem64_res = true; break; } }
good, then we should change to compare region end.
Quoted 5 lines
This also works on my machine.
One more question, with this patch, do we still need previous patch for Marek's problem?
Only need this to make Marek's working.
but does not help on Zermond's
Thanks
Yinghai
Quoted 54 lines · Yinghai Lu
So we could use bridge 64bit mem pref for children mem pref instead of forcing them into bridge mem.
Could help Marek's system as his system is using
_CRS, and all mem res is under 4G.Reported-by Marek Kordik <[email protected]>Fixes 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources")Signed-off-by Yinghai Lu <[email protected]>---
drivers/pci/host-bridge.c | 7 +++++++ drivers/pci/pci.h | 1 + drivers/pci/probe.c | 9 +++++++++ drivers/pci/setup-bus.c | 3 +++ include/linux/pci.h | 1 + 5 files changed, 21 insertions(+)Index:
linux-2.6/drivers/pci/host-bridge.c
===================================================================drivers/pci/host-bridge.c +7
-0@@ -31,6 +31,13 @@ void pci_set_host_bridge_release(struct bridge->release_data = release_data; } +bool pcibios_host_bridge_has_mem64_res (struct pci_bus *bus) +{ +struct pci_host_bridge *bridge =find_pci_host_bridge (bus); + +return bridge->has_mem64_res; +} +void pcibios_resource_to_bus (struct pci_bus *bus,struct pci_bus_region *region,struct resource *res) {Index:
linux-2.6/drivers/pci/pci.h
===================================================================drivers/pci/pci.h +1
-0@@ -196,6 +196,7 @@ enum pci_bar_type { pci_bar_mem64, /* A 64-bit memory BAR */ }; +bool pcibios_host_bridge_has_mem64_res (struct pci_bus *bus);bool pci_bus_read_dev_vendor_id (struct pci_bus *bus,int devfn,u32 *pl,int crs_timeout);int pci_setup_device (struct pci_dev *dev);Index:
linux-2.6/drivers/pci/probe.c
===================================================================
drivers/pci/probe.c struct pci_bus *pci_create_root_bus(stru · line 1986
Quoted 7 lines
drivers/pci/probe.c +4
-0@@ -1980,6 +1980,15 @@ struct pci_bus *pci_create_root_bus(strudev_info (&b->dev,"root bus resource %pR%s\n" , res, bus_addr); } +list_for_each_entry (window, &bridge->windows, list) { + res = window->res; +if (resource_type (res) ==IORESOURCE_MEM || + res->end >0xffffffff ) {
Should we replace "||" with "&&" ?
Thanks,
Gavin
Quoted 35 lines
drivers/pci/probe.c +5
-0+ bridge->has_mem64_res = true; +break ; + } + } +down_write (&pci_bus_sem);list_add_tail (&b->node, &pci_root_buses);up_write (&pci_bus_sem);Index:
linux-2.6/include/linux/pci.h
===================================================================include/linux/pci.h +1
-0@@ -407,6 +407,7 @@ struct pci_host_bridge {struct list_head windows;/* pci_host_bridge_windows */ void (*release_fn)(struct pci_host_bridge *);void *release_data; +bool has_mem64_res; };#define to_pci_host_bridge (n) container_of(n, struct pci_host_bridge, dev)Index:
linux-2.6/drivers/pci/setup-bus.c
===================================================================drivers/pci/setup-bus.c +3
-0@@ -693,6 +693,9 @@ static void pci_bridge_check_ranges(stru } } +if (!pcibios_host_bridge_has_mem64_res (bus)) + b_res[2 ].flags &= ~IORESOURCE_MEM_64 ; +/* double check if bridge does support 64 bit pref */ if (b_res[2 ].flags &IORESOURCE_MEM_64 ) {u32 mem_base_hi, tmp;
Quoted 8 lines · Gavin Shan
drivers/pci/probe.c struct pci_bus *pci_create_root_bus(stru · line 1986
Quoted 5 lines · Yinghai Lu
drivers/pci/probe.c +4
-0+list_for_each_entry (window, &bridge->windows, list) { + res = window->res; +if (resource_type (res) ==IORESOURCE_MEM || + res->end >0xffffffff ) {Should we replace "||" with "&&" ?
oh, I missed that.
Will send updated version.
Thanks
Yinghai