Contributors: 13
Author Tokens Token Proportion Commits Commit Proportion
Ilpo Järvinen 1113 86.75% 8 27.59%
Atsushi Nemoto 63 4.91% 1 3.45%
Linus Torvalds (pre-git) 48 3.74% 8 27.59%
Ivan Kokshaysky 13 1.01% 2 6.90%
Russell King 11 0.86% 2 6.90%
Yinghai Lu 10 0.78% 1 3.45%
Christian König 8 0.62% 1 3.45%
Michał Winiarski 4 0.31% 1 3.45%
Wei Huang 4 0.31% 1 3.45%
Mika Westerberg 3 0.23% 1 3.45%
Amey Narkhede 3 0.23% 1 3.45%
Sam Ravnborg 2 0.16% 1 3.45%
Björn Helgaas 1 0.08% 1 3.45%
Total 1283 29


// SPDX-License-Identifier: GPL-2.0
/*
 * Cardbus bridge setup routines.
 */

#include <linux/bitfield.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/sizes.h>
#include <linux/sprintf.h>
#include <linux/types.h>

#include "pci.h"

#define CARDBUS_LATENCY_TIMER		176	/* secondary latency timer */
#define CARDBUS_RESERVE_BUSNR		3

#define DEFAULT_CARDBUS_IO_SIZE		SZ_256
#define DEFAULT_CARDBUS_MEM_SIZE	SZ_64M
/* pci=cbmemsize=nnM,cbiosize=nn can override this */
static unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE;
static unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;

unsigned long pci_cardbus_resource_alignment(struct resource *res)
{
	if (res->flags & IORESOURCE_IO)
		return pci_cardbus_io_size;
	if (res->flags & IORESOURCE_MEM)
		return pci_cardbus_mem_size;
	return 0;
}

int pci_bus_size_cardbus_bridge(struct pci_bus *bus,
				struct list_head *realloc_head)
{
	struct pci_dev *bridge = bus->self;
	struct resource *b_res;
	resource_size_t b_res_3_size = pci_cardbus_mem_size * 2;
	u16 ctrl;

	b_res = &bridge->resource[PCI_CB_BRIDGE_IO_0_WINDOW];
	if (resource_assigned(b_res))
		goto handle_b_res_1;
	/*
	 * Reserve some resources for CardBus.  We reserve a fixed amount
	 * of bus space for CardBus bridges.
	 */
	resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size);
	b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
	if (realloc_head) {
		b_res->end -= pci_cardbus_io_size;
		pci_dev_res_add_to_list(realloc_head, bridge, b_res,
					pci_cardbus_io_size,
					pci_cardbus_io_size);
	}

handle_b_res_1:
	b_res = &bridge->resource[PCI_CB_BRIDGE_IO_1_WINDOW];
	if (resource_assigned(b_res))
		goto handle_b_res_2;
	resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size);
	b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
	if (realloc_head) {
		b_res->end -= pci_cardbus_io_size;
		pci_dev_res_add_to_list(realloc_head, bridge, b_res,
					pci_cardbus_io_size,
					pci_cardbus_io_size);
	}

handle_b_res_2:
	/* MEM1 must not be pref MMIO */
	pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
	if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM1) {
		ctrl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1;
		pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
		pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
	}

	/* Check whether prefetchable memory is supported by this bridge. */
	pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
	if (!(ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0)) {
		ctrl |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0;
		pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
		pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
	}

	b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_0_WINDOW];
	if (resource_assigned(b_res))
		goto handle_b_res_3;
	/*
	 * If we have prefetchable memory support, allocate two regions.
	 * Otherwise, allocate one region of twice the size.
	 */
	if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
		resource_set_range(b_res, pci_cardbus_mem_size,
				   pci_cardbus_mem_size);
		b_res->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH |
				    IORESOURCE_STARTALIGN;
		if (realloc_head) {
			b_res->end -= pci_cardbus_mem_size;
			pci_dev_res_add_to_list(realloc_head, bridge, b_res,
						pci_cardbus_mem_size,
						pci_cardbus_mem_size);
		}

		/* Reduce that to half */
		b_res_3_size = pci_cardbus_mem_size;
	}

handle_b_res_3:
	b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_1_WINDOW];
	if (resource_assigned(b_res))
		goto handle_done;
	resource_set_range(b_res, pci_cardbus_mem_size, b_res_3_size);
	b_res->flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN;
	if (realloc_head) {
		b_res->end -= b_res_3_size;
		pci_dev_res_add_to_list(realloc_head, bridge, b_res,
					b_res_3_size, pci_cardbus_mem_size);
	}

handle_done:
	return 0;
}

void pci_setup_cardbus_bridge(struct pci_bus *bus)
{
	struct pci_dev *bridge = bus->self;
	struct resource *res;
	struct pci_bus_region region;

	pci_info(bridge, "CardBus bridge to %pR\n",
		 &bus->busn_res);

	res = bus->resource[0];
	pcibios_resource_to_bus(bridge->bus, &region, res);
	if (resource_assigned(res) && res->flags & IORESOURCE_IO) {
		/*
		 * The IO resource is allocated a range twice as large as it
		 * would normally need.  This allows us to set both IO regs.
		 */
		pci_info(bridge, "  bridge window %pR\n", res);
		pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
					region.start);
		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
					region.end);
	}

	res = bus->resource[1];
	pcibios_resource_to_bus(bridge->bus, &region, res);
	if (resource_assigned(res) && res->flags & IORESOURCE_IO) {
		pci_info(bridge, "  bridge window %pR\n", res);
		pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
					region.start);
		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
					region.end);
	}

	res = bus->resource[2];
	pcibios_resource_to_bus(bridge->bus, &region, res);
	if (resource_assigned(res) && res->flags & IORESOURCE_MEM) {
		pci_info(bridge, "  bridge window %pR\n", res);
		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
					region.start);
		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
					region.end);
	}

	res = bus->resource[3];
	pcibios_resource_to_bus(bridge->bus, &region, res);
	if (resource_assigned(res) && res->flags & IORESOURCE_MEM) {
		pci_info(bridge, "  bridge window %pR\n", res);
		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
					region.start);
		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
					region.end);
	}
}
EXPORT_SYMBOL(pci_setup_cardbus_bridge);

int pci_setup_cardbus(char *str)
{
	if (!strncmp(str, "cbiosize=", 9)) {
		pci_cardbus_io_size = memparse(str + 9, &str);
		return 0;
	} else if (!strncmp(str, "cbmemsize=", 10)) {
		pci_cardbus_mem_size = memparse(str + 10, &str);
		return 0;
	}

	return -ENOENT;
}

int pci_cardbus_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
				   u32 buses, int max,
				   unsigned int available_buses, int pass)
{
	struct pci_bus *child;
	bool fixed_buses;
	u8 fixed_sec, fixed_sub;
	int next_busnr;
	u32 i, j = 0;

	/*
	 * We need to assign a number to this bus which we always do in the
	 * second pass.
	 */
	if (!pass) {
		/*
		 * Temporarily disable forwarding of the configuration
		 * cycles on all bridges in this bus segment to avoid
		 * possible conflicts in the second pass between two bridges
		 * programmed with overlapping bus ranges.
		 */
		pci_write_config_dword(dev, PCI_PRIMARY_BUS,
				       buses & PCI_SEC_LATENCY_TIMER_MASK);
		return max;
	}

	/* Clear errors */
	pci_write_config_word(dev, PCI_STATUS, 0xffff);

	/* Read bus numbers from EA Capability (if present) */
	fixed_buses = pci_ea_fixed_busnrs(dev, &fixed_sec, &fixed_sub);
	if (fixed_buses)
		next_busnr = fixed_sec;
	else
		next_busnr = max + 1;

	/*
	 * Prevent assigning a bus number that already exists. This can
	 * happen when a bridge is hot-plugged, so in this case we only
	 * re-scan this bus.
	 */
	child = pci_find_bus(pci_domain_nr(bus), next_busnr);
	if (!child) {
		child = pci_add_new_bus(bus, dev, next_busnr);
		if (!child)
			return max;
		pci_bus_insert_busn_res(child, next_busnr, bus->busn_res.end);
	}
	max++;
	if (available_buses)
		available_buses--;

	buses = (buses & PCI_SEC_LATENCY_TIMER_MASK) |
		FIELD_PREP(PCI_PRIMARY_BUS_MASK, child->primary) |
		FIELD_PREP(PCI_SECONDARY_BUS_MASK, child->busn_res.start) |
		FIELD_PREP(PCI_SUBORDINATE_BUS_MASK, child->busn_res.end);

	/*
	 * yenta.c forces a secondary latency timer of 176.
	 * Copy that behaviour here.
	 */
	buses &= ~PCI_SEC_LATENCY_TIMER_MASK;
	buses |= FIELD_PREP(PCI_SEC_LATENCY_TIMER_MASK, CARDBUS_LATENCY_TIMER);

	/* We need to blast all three values with a single write */
	pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);

	/*
	 * For CardBus bridges, we leave 4 bus numbers as cards with a
	 * PCI-to-PCI bridge can be inserted later.
	 */
	for (i = 0; i < CARDBUS_RESERVE_BUSNR; i++) {
		struct pci_bus *parent = bus;

		if (pci_find_bus(pci_domain_nr(bus), max + i + 1))
			break;

		while (parent->parent) {
			if (!pcibios_assign_all_busses() &&
			    (parent->busn_res.end > max) &&
			    (parent->busn_res.end <= max + i)) {
				j = 1;
			}
			parent = parent->parent;
		}
		if (j) {
			/*
			 * Often, there are two CardBus bridges -- try to
			 * leave one valid bus number for each one.
			 */
			i /= 2;
			break;
		}
	}
	max += i;

	/*
	 * Set subordinate bus number to its real value. If fixed
	 * subordinate bus number exists from EA capability then use it.
	 */
	if (fixed_buses)
		max = fixed_sub;
	pci_bus_update_busn_res_end(child, max);
	pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);

	scnprintf(child->name, sizeof(child->name), "PCI CardBus %04x:%02x",
		  pci_domain_nr(bus), child->number);

	pbus_validate_busn(child);

	return max;
}