// SPDX-License-Identifier: GPL-2.0 /* * Cardbus bridge setup routines. */ #include #include #include #include #include #include #include #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, ®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. */ 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; }