| // 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(const 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, ®ion, 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, ®ion, 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, ®ion, 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, ®ion, 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. | |
| */ | |
| FIELD_MODIFY(PCI_SEC_LATENCY_TIMER_MASK, &buses, 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; | |
| } |