18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * cardbus.c -- 16-bit PCMCIA core support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * The initial developer of the original code is David A. Hinds 68c2ecf20Sopenharmony_ci * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds 78c2ecf20Sopenharmony_ci * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * (C) 1999 David A. Hinds 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci/* 138c2ecf20Sopenharmony_ci * Cardbus handling has been re-written to be more of a PCI bridge thing, 148c2ecf20Sopenharmony_ci * and the PCI code basically does all the resource handling. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Linus, Jan 2000 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/pci.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <pcmcia/ss.h> 258c2ecf20Sopenharmony_ci#include <pcmcia/cistpl.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "cs_internal.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic void cardbus_config_irq_and_cls(struct pci_bus *bus, int irq) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci struct pci_dev *dev; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci list_for_each_entry(dev, &bus->devices, bus_list) { 348c2ecf20Sopenharmony_ci u8 irq_pin; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci /* 378c2ecf20Sopenharmony_ci * Since there is only one interrupt available to 388c2ecf20Sopenharmony_ci * CardBus devices, all devices downstream of this 398c2ecf20Sopenharmony_ci * device must be using this IRQ. 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin); 428c2ecf20Sopenharmony_ci if (irq_pin) { 438c2ecf20Sopenharmony_ci dev->irq = irq; 448c2ecf20Sopenharmony_ci pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci /* 488c2ecf20Sopenharmony_ci * Some controllers transfer very slowly with 0 CLS. 498c2ecf20Sopenharmony_ci * Configure it. This may fail as CLS configuration 508c2ecf20Sopenharmony_ci * is mandatory only for MWI. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci pci_set_cacheline_size(dev); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (dev->subordinate) 558c2ecf20Sopenharmony_ci cardbus_config_irq_and_cls(dev->subordinate, irq); 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/** 608c2ecf20Sopenharmony_ci * cb_alloc() - add CardBus device 618c2ecf20Sopenharmony_ci * @s: the pcmcia_socket where the CardBus device is located 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * cb_alloc() allocates the kernel data structures for a Cardbus device 648c2ecf20Sopenharmony_ci * and handles the lowest level PCI device setup issues. 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ciint __ref cb_alloc(struct pcmcia_socket *s) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct pci_bus *bus = s->cb_dev->subordinate; 698c2ecf20Sopenharmony_ci struct pci_dev *dev; 708c2ecf20Sopenharmony_ci unsigned int max, pass; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci pci_lock_rescan_remove(); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0)); 758c2ecf20Sopenharmony_ci pci_fixup_cardbus(bus); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci max = bus->busn_res.start; 788c2ecf20Sopenharmony_ci for (pass = 0; pass < 2; pass++) 798c2ecf20Sopenharmony_ci for_each_pci_bridge(dev, bus) 808c2ecf20Sopenharmony_ci max = pci_scan_bridge(bus, dev, max, pass); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* 838c2ecf20Sopenharmony_ci * Size all resources below the CardBus controller. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci pci_bus_size_bridges(bus); 868c2ecf20Sopenharmony_ci pci_bus_assign_resources(bus); 878c2ecf20Sopenharmony_ci cardbus_config_irq_and_cls(bus, s->pci_irq); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* socket specific tune function */ 908c2ecf20Sopenharmony_ci if (s->tune_bridge) 918c2ecf20Sopenharmony_ci s->tune_bridge(s, bus); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci pci_bus_add_devices(bus); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci pci_unlock_rescan_remove(); 968c2ecf20Sopenharmony_ci return 0; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/** 1008c2ecf20Sopenharmony_ci * cb_free() - remove CardBus device 1018c2ecf20Sopenharmony_ci * @s: the pcmcia_socket where the CardBus device was located 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * cb_free() handles the lowest level PCI device cleanup. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_civoid cb_free(struct pcmcia_socket *s) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct pci_dev *bridge, *dev, *tmp; 1088c2ecf20Sopenharmony_ci struct pci_bus *bus; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci bridge = s->cb_dev; 1118c2ecf20Sopenharmony_ci if (!bridge) 1128c2ecf20Sopenharmony_ci return; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci bus = bridge->subordinate; 1158c2ecf20Sopenharmony_ci if (!bus) 1168c2ecf20Sopenharmony_ci return; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci pci_lock_rescan_remove(); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) 1218c2ecf20Sopenharmony_ci pci_stop_and_remove_bus_device(dev); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci pci_unlock_rescan_remove(); 1248c2ecf20Sopenharmony_ci} 125