mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-04 11:56:50 +07:00
Merge branch 'pci/gavin-window-alignment' into next
* pci/gavin-window-alignment: powerpc/powernv: I/O and memory alignment for P2P bridges powerpc/PCI: Override pcibios_window_alignment() PCI: Refactor pbus_size_mem() PCI: Align P2P windows using pcibios_window_alignment() PCI: Add weak pcibios_window_alignment() interface
This commit is contained in:
commit
a63ab613ff
@ -214,6 +214,9 @@ struct machdep_calls {
|
|||||||
/* Called after scan and before resource survey */
|
/* Called after scan and before resource survey */
|
||||||
void (*pcibios_fixup_phb)(struct pci_controller *hose);
|
void (*pcibios_fixup_phb)(struct pci_controller *hose);
|
||||||
|
|
||||||
|
/* Called during PCI resource reassignment */
|
||||||
|
resource_size_t (*pcibios_window_alignment)(struct pci_bus *, unsigned long type);
|
||||||
|
|
||||||
/* Called to shutdown machine specific hardware not already controlled
|
/* Called to shutdown machine specific hardware not already controlled
|
||||||
* by other drivers.
|
* by other drivers.
|
||||||
*/
|
*/
|
||||||
|
@ -99,6 +99,26 @@ void pcibios_free_controller(struct pci_controller *phb)
|
|||||||
kfree(phb);
|
kfree(phb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The function is used to return the minimal alignment
|
||||||
|
* for memory or I/O windows of the associated P2P bridge.
|
||||||
|
* By default, 4KiB alignment for I/O windows and 1MiB for
|
||||||
|
* memory windows.
|
||||||
|
*/
|
||||||
|
resource_size_t pcibios_window_alignment(struct pci_bus *bus,
|
||||||
|
unsigned long type)
|
||||||
|
{
|
||||||
|
if (ppc_md.pcibios_window_alignment)
|
||||||
|
return ppc_md.pcibios_window_alignment(bus, type);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PCI core will figure out the default
|
||||||
|
* alignment: 4KiB for I/O and 1MiB for
|
||||||
|
* memory window.
|
||||||
|
*/
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static resource_size_t pcibios_io_size(const struct pci_controller *hose)
|
static resource_size_t pcibios_io_size(const struct pci_controller *hose)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
|
@ -1139,6 +1139,44 @@ static void __devinit pnv_pci_ioda_fixup_phb(struct pci_controller *hose)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the alignment for I/O or memory windows for P2P
|
||||||
|
* bridges. That actually depends on how PEs are segmented.
|
||||||
|
* For now, we return I/O or M32 segment size for PE sensitive
|
||||||
|
* P2P bridges. Otherwise, the default values (4KiB for I/O,
|
||||||
|
* 1MiB for memory) will be returned.
|
||||||
|
*
|
||||||
|
* The current PCI bus might be put into one PE, which was
|
||||||
|
* create against the parent PCI bridge. For that case, we
|
||||||
|
* needn't enlarge the alignment so that we can save some
|
||||||
|
* resources.
|
||||||
|
*/
|
||||||
|
static resource_size_t pnv_pci_window_alignment(struct pci_bus *bus,
|
||||||
|
unsigned long type)
|
||||||
|
{
|
||||||
|
struct pci_dev *bridge;
|
||||||
|
struct pci_controller *hose = pci_bus_to_host(bus);
|
||||||
|
struct pnv_phb *phb = hose->private_data;
|
||||||
|
int num_pci_bridges = 0;
|
||||||
|
|
||||||
|
bridge = bus->self;
|
||||||
|
while (bridge) {
|
||||||
|
if (pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE) {
|
||||||
|
num_pci_bridges++;
|
||||||
|
if (num_pci_bridges >= 2)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bridge = bridge->bus->self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need support prefetchable memory window later */
|
||||||
|
if (type & IORESOURCE_MEM)
|
||||||
|
return phb->ioda.m32_segsize;
|
||||||
|
|
||||||
|
return phb->ioda.io_segsize;
|
||||||
|
}
|
||||||
|
|
||||||
/* Prevent enabling devices for which we couldn't properly
|
/* Prevent enabling devices for which we couldn't properly
|
||||||
* assign a PE
|
* assign a PE
|
||||||
*/
|
*/
|
||||||
@ -1306,6 +1344,7 @@ void __init pnv_pci_init_ioda1_phb(struct device_node *np)
|
|||||||
*/
|
*/
|
||||||
ppc_md.pcibios_fixup_phb = pnv_pci_ioda_fixup_phb;
|
ppc_md.pcibios_fixup_phb = pnv_pci_ioda_fixup_phb;
|
||||||
ppc_md.pcibios_enable_device_hook = pnv_pci_enable_device_hook;
|
ppc_md.pcibios_enable_device_hook = pnv_pci_enable_device_hook;
|
||||||
|
ppc_md.pcibios_window_alignment = pnv_pci_window_alignment;
|
||||||
pci_add_flags(PCI_PROBE_ONLY | PCI_REASSIGN_ALL_RSRC);
|
pci_add_flags(PCI_PROBE_ONLY | PCI_REASSIGN_ALL_RSRC);
|
||||||
|
|
||||||
/* Reset IODA tables to a clean state */
|
/* Reset IODA tables to a clean state */
|
||||||
|
@ -697,6 +697,38 @@ static resource_size_t calculate_memsize(resource_size_t size,
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus,
|
||||||
|
unsigned long type)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PCI_P2P_DEFAULT_MEM_ALIGN 0x100000 /* 1MiB */
|
||||||
|
#define PCI_P2P_DEFAULT_IO_ALIGN 0x1000 /* 4KiB */
|
||||||
|
#define PCI_P2P_DEFAULT_IO_ALIGN_1K 0x400 /* 1KiB */
|
||||||
|
|
||||||
|
static resource_size_t window_alignment(struct pci_bus *bus,
|
||||||
|
unsigned long type)
|
||||||
|
{
|
||||||
|
resource_size_t align = 1, arch_align;
|
||||||
|
|
||||||
|
if (type & IORESOURCE_MEM)
|
||||||
|
align = PCI_P2P_DEFAULT_MEM_ALIGN;
|
||||||
|
else if (type & IORESOURCE_IO) {
|
||||||
|
/*
|
||||||
|
* Per spec, I/O windows are 4K-aligned, but some
|
||||||
|
* bridges have an extension to support 1K alignment.
|
||||||
|
*/
|
||||||
|
if (bus->self->io_window_1k)
|
||||||
|
align = PCI_P2P_DEFAULT_IO_ALIGN_1K;
|
||||||
|
else
|
||||||
|
align = PCI_P2P_DEFAULT_IO_ALIGN;
|
||||||
|
}
|
||||||
|
|
||||||
|
arch_align = pcibios_window_alignment(bus, type);
|
||||||
|
return max(align, arch_align);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pbus_size_io() - size the io window of a given bus
|
* pbus_size_io() - size the io window of a given bus
|
||||||
*
|
*
|
||||||
@ -717,17 +749,12 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
|
|||||||
struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
|
struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
|
||||||
unsigned long size = 0, size0 = 0, size1 = 0;
|
unsigned long size = 0, size0 = 0, size1 = 0;
|
||||||
resource_size_t children_add_size = 0;
|
resource_size_t children_add_size = 0;
|
||||||
resource_size_t min_align = 4096, align;
|
resource_size_t min_align, io_align, align;
|
||||||
|
|
||||||
if (!b_res)
|
if (!b_res)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
io_align = min_align = window_alignment(bus, IORESOURCE_IO);
|
||||||
* Per spec, I/O windows are 4K-aligned, but some bridges have an
|
|
||||||
* extension to support 1K alignment.
|
|
||||||
*/
|
|
||||||
if (bus->self->io_window_1k)
|
|
||||||
min_align = 1024;
|
|
||||||
list_for_each_entry(dev, &bus->devices, bus_list) {
|
list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -754,8 +781,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (min_align > 4096)
|
if (min_align > io_align)
|
||||||
min_align = 4096;
|
min_align = io_align;
|
||||||
|
|
||||||
size0 = calculate_iosize(size, min_size, size1,
|
size0 = calculate_iosize(size, min_size, size1,
|
||||||
resource_size(b_res), min_align);
|
resource_size(b_res), min_align);
|
||||||
@ -785,6 +812,28 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline resource_size_t calculate_mem_align(resource_size_t *aligns,
|
||||||
|
int max_order)
|
||||||
|
{
|
||||||
|
resource_size_t align = 0;
|
||||||
|
resource_size_t min_align = 0;
|
||||||
|
int order;
|
||||||
|
|
||||||
|
for (order = 0; order <= max_order; order++) {
|
||||||
|
resource_size_t align1 = 1;
|
||||||
|
|
||||||
|
align1 <<= (order + 20);
|
||||||
|
|
||||||
|
if (!align)
|
||||||
|
min_align = align1;
|
||||||
|
else if (ALIGN(align + min_align, min_align) < align1)
|
||||||
|
min_align = align1 >> 1;
|
||||||
|
align += aligns[order];
|
||||||
|
}
|
||||||
|
|
||||||
|
return min_align;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pbus_size_mem() - size the memory window of a given bus
|
* pbus_size_mem() - size the memory window of a given bus
|
||||||
*
|
*
|
||||||
@ -864,19 +913,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
|
|||||||
children_add_size += get_res_add_size(realloc_head, r);
|
children_add_size += get_res_add_size(realloc_head, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
align = 0;
|
|
||||||
min_align = 0;
|
|
||||||
for (order = 0; order <= max_order; order++) {
|
|
||||||
resource_size_t align1 = 1;
|
|
||||||
|
|
||||||
align1 <<= (order + 20);
|
min_align = calculate_mem_align(aligns, max_order);
|
||||||
|
min_align = max(min_align, window_alignment(bus, b_res->flags & mask));
|
||||||
if (!align)
|
|
||||||
min_align = align1;
|
|
||||||
else if (ALIGN(align + min_align, min_align) < align1)
|
|
||||||
min_align = align1 >> 1;
|
|
||||||
align += aligns[order];
|
|
||||||
}
|
|
||||||
size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align);
|
size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align);
|
||||||
if (children_add_size > add_size)
|
if (children_add_size > add_size)
|
||||||
add_size = children_add_size;
|
add_size = children_add_size;
|
||||||
|
@ -1061,6 +1061,8 @@ int pci_cfg_space_size_ext(struct pci_dev *dev);
|
|||||||
int pci_cfg_space_size(struct pci_dev *dev);
|
int pci_cfg_space_size(struct pci_dev *dev);
|
||||||
unsigned char pci_bus_max_busnr(struct pci_bus *bus);
|
unsigned char pci_bus_max_busnr(struct pci_bus *bus);
|
||||||
void pci_setup_bridge(struct pci_bus *bus);
|
void pci_setup_bridge(struct pci_bus *bus);
|
||||||
|
resource_size_t pcibios_window_alignment(struct pci_bus *bus,
|
||||||
|
unsigned long type);
|
||||||
|
|
||||||
#define PCI_VGA_STATE_CHANGE_BRIDGE (1 << 0)
|
#define PCI_VGA_STATE_CHANGE_BRIDGE (1 << 0)
|
||||||
#define PCI_VGA_STATE_CHANGE_DECODES (1 << 1)
|
#define PCI_VGA_STATE_CHANGE_DECODES (1 << 1)
|
||||||
|
Loading…
Reference in New Issue
Block a user