mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
When a bridge window contains big and small resource(s), the small resource(s) may not amount to the half of the size of the big resource which would allow calculate_head_align() to shrink the head alignment. This results in always placing the small resource(s) after the big resource. In general, it would be good to be able to place the small resource(s) before the big resource to achieve better utilization of the address space. In the cases where the large resource can only fit at the end of the window, it is even required. However, carrying the information over from pbus_size_mem() and calculate_head_align() to __pci_assign_resource() and pcibios_align_resource() is not easy with the current data structures. A somewhat hacky way to move the non-aligning tail part to the head is possible within pcibios_align_resource(). The free space between the start of the free space span and the aligned start address can be compared with the non-aligning remainder of the size. If the free space is larger than the remainder, placing the remainder before the start address is possible. This relocation should generally work, because PCI resources consist only power-of-2 atoms. Various arch requirements may still need to override the relocation, so the relocation is only applied selectively in such cases. Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221205 Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Tested-by: Xifer <xiferdev@gmail.com> Link: https://patch.msgid.link/20260324165633.4583-10-ilpo.jarvinen@linux.intel.com
82 lines
2.1 KiB
C
82 lines
2.1 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* pci.c -- basic PCI support code
|
|
*
|
|
* (C) Copyright 2011, Greg Ungerer <gerg@uclinux.org>
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/types.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/init.h>
|
|
#include <linux/pci.h>
|
|
|
|
/*
|
|
* From arch/i386/kernel/pci-i386.c:
|
|
*
|
|
* We need to avoid collisions with `mirrored' VGA ports
|
|
* and other strange ISA hardware, so we always want the
|
|
* addresses to be allocated in the 0x000-0x0ff region
|
|
* modulo 0x400.
|
|
*
|
|
* Why? Because some silly external IO cards only decode
|
|
* the low 10 bits of the IO address. The 0x00-0xff region
|
|
* is reserved for motherboard devices that decode all 16
|
|
* bits, so it's ok to allocate at, say, 0x2800-0x28ff,
|
|
* but we want to try to avoid allocating at 0x2900-0x2bff
|
|
* which might be mirrored at 0x0100-0x03ff..
|
|
*/
|
|
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
|
const struct resource *empty_res,
|
|
resource_size_t size,
|
|
resource_size_t align)
|
|
{
|
|
struct pci_dev *dev = data;
|
|
resource_size_t start = res->start;
|
|
|
|
if ((res->flags & IORESOURCE_IO) && (start & 0x300))
|
|
start = (start + 0x3ff) & ~0x3ff;
|
|
|
|
if (res->flags & IORESOURCE_MEM)
|
|
return pci_align_resource(dev, res, empty_res, size, align);
|
|
|
|
return start;
|
|
}
|
|
|
|
/*
|
|
* This is taken from the ARM code for this.
|
|
*/
|
|
int pcibios_enable_device(struct pci_dev *dev, int mask)
|
|
{
|
|
u16 cmd, newcmd;
|
|
int ret;
|
|
|
|
ret = pci_enable_resources(dev, mask);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
/*
|
|
* Bridges (eg, cardbus bridges) need to be fully enabled
|
|
*/
|
|
if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) {
|
|
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
|
newcmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
|
|
if (newcmd != cmd) {
|
|
pr_info("PCI: enabling bridge %s (0x%04x -> 0x%04x)\n",
|
|
pci_name(dev), cmd, newcmd);
|
|
pci_write_config_word(dev, PCI_COMMAND, newcmd);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void pcibios_fixup_bus(struct pci_bus *bus)
|
|
{
|
|
struct pci_dev *dev;
|
|
|
|
list_for_each_entry(dev, &bus->devices, bus_list) {
|
|
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8);
|
|
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32);
|
|
}
|
|
}
|