162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *	Low-Level PCI Access for i386 machines.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *	(c) 1999 Martin Mares <mj@ucw.cz>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/errno.h>
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/ioport.h>
1162306a36Sopenharmony_ci#include <linux/spinlock.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#undef DEBUG
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#ifdef DEBUG
1662306a36Sopenharmony_ci#define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
1762306a36Sopenharmony_ci#else
1862306a36Sopenharmony_ci#define DBG(fmt, ...)				\
1962306a36Sopenharmony_cido {						\
2062306a36Sopenharmony_ci	if (0)					\
2162306a36Sopenharmony_ci		printk(fmt, ##__VA_ARGS__);	\
2262306a36Sopenharmony_ci} while (0)
2362306a36Sopenharmony_ci#endif
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define PCI_PROBE_BIOS		0x0001
2662306a36Sopenharmony_ci#define PCI_PROBE_CONF1		0x0002
2762306a36Sopenharmony_ci#define PCI_PROBE_CONF2		0x0004
2862306a36Sopenharmony_ci#define PCI_PROBE_MMCONF	0x0008
2962306a36Sopenharmony_ci#define PCI_PROBE_MASK		0x000f
3062306a36Sopenharmony_ci#define PCI_PROBE_NOEARLY	0x0010
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define PCI_NO_CHECKS		0x0400
3362306a36Sopenharmony_ci#define PCI_USE_PIRQ_MASK	0x0800
3462306a36Sopenharmony_ci#define PCI_ASSIGN_ROMS		0x1000
3562306a36Sopenharmony_ci#define PCI_BIOS_IRQ_SCAN	0x2000
3662306a36Sopenharmony_ci#define PCI_ASSIGN_ALL_BUSSES	0x4000
3762306a36Sopenharmony_ci#define PCI_CAN_SKIP_ISA_ALIGN	0x8000
3862306a36Sopenharmony_ci#define PCI_USE__CRS		0x10000
3962306a36Sopenharmony_ci#define PCI_CHECK_ENABLE_AMD_MMCONF	0x20000
4062306a36Sopenharmony_ci#define PCI_HAS_IO_ECS		0x40000
4162306a36Sopenharmony_ci#define PCI_NOASSIGN_ROMS	0x80000
4262306a36Sopenharmony_ci#define PCI_ROOT_NO_CRS		0x100000
4362306a36Sopenharmony_ci#define PCI_NOASSIGN_BARS	0x200000
4462306a36Sopenharmony_ci#define PCI_BIG_ROOT_WINDOW	0x400000
4562306a36Sopenharmony_ci#define PCI_USE_E820		0x800000
4662306a36Sopenharmony_ci#define PCI_NO_E820		0x1000000
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ciextern unsigned int pci_probe;
4962306a36Sopenharmony_ciextern unsigned long pirq_table_addr;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cienum pci_bf_sort_state {
5262306a36Sopenharmony_ci	pci_bf_sort_default,
5362306a36Sopenharmony_ci	pci_force_nobf,
5462306a36Sopenharmony_ci	pci_force_bf,
5562306a36Sopenharmony_ci	pci_dmi_bf,
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/* pci-i386.c */
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_civoid pcibios_resource_survey(void);
6162306a36Sopenharmony_civoid pcibios_set_cache_line_size(void);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/* pci-pc.c */
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ciextern int pcibios_last_bus;
6662306a36Sopenharmony_ciextern struct pci_ops pci_root_ops;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_civoid pcibios_scan_specific_bus(int busn);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* pci-irq.c */
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistruct pci_dev;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistruct irq_info {
7562306a36Sopenharmony_ci	u8 bus, devfn;			/* Bus, device and function */
7662306a36Sopenharmony_ci	struct {
7762306a36Sopenharmony_ci		u8 link;		/* IRQ line ID, chipset dependent,
7862306a36Sopenharmony_ci					   0 = not routed */
7962306a36Sopenharmony_ci		u16 bitmap;		/* Available IRQs */
8062306a36Sopenharmony_ci	} __attribute__((packed)) irq[4];
8162306a36Sopenharmony_ci	u8 slot;			/* Slot number, 0=onboard */
8262306a36Sopenharmony_ci	u8 rfu;
8362306a36Sopenharmony_ci} __attribute__((packed));
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistruct irq_routing_table {
8662306a36Sopenharmony_ci	u32 signature;			/* PIRQ_SIGNATURE should be here */
8762306a36Sopenharmony_ci	u16 version;			/* PIRQ_VERSION */
8862306a36Sopenharmony_ci	u16 size;			/* Table size in bytes */
8962306a36Sopenharmony_ci	u8 rtr_bus, rtr_devfn;		/* Where the interrupt router lies */
9062306a36Sopenharmony_ci	u16 exclusive_irqs;		/* IRQs devoted exclusively to
9162306a36Sopenharmony_ci					   PCI usage */
9262306a36Sopenharmony_ci	u16 rtr_vendor, rtr_device;	/* Vendor and device ID of
9362306a36Sopenharmony_ci					   interrupt router */
9462306a36Sopenharmony_ci	u32 miniport_data;		/* Crap */
9562306a36Sopenharmony_ci	u8 rfu[11];
9662306a36Sopenharmony_ci	u8 checksum;			/* Modulo 256 checksum must give 0 */
9762306a36Sopenharmony_ci	struct irq_info slots[];
9862306a36Sopenharmony_ci} __attribute__((packed));
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistruct irt_routing_table {
10162306a36Sopenharmony_ci	u32 signature;			/* IRT_SIGNATURE should be here */
10262306a36Sopenharmony_ci	u8 size;			/* Number of entries provided */
10362306a36Sopenharmony_ci	u8 used;			/* Number of entries actually used */
10462306a36Sopenharmony_ci	u16 exclusive_irqs;		/* IRQs devoted exclusively to
10562306a36Sopenharmony_ci					   PCI usage */
10662306a36Sopenharmony_ci	struct irq_info slots[];
10762306a36Sopenharmony_ci} __attribute__((packed));
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ciextern unsigned int pcibios_irq_mask;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ciextern raw_spinlock_t pci_config_lock;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ciextern int (*pcibios_enable_irq)(struct pci_dev *dev);
11462306a36Sopenharmony_ciextern void (*pcibios_disable_irq)(struct pci_dev *dev);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ciextern bool mp_should_keep_irq(struct device *dev);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistruct pci_raw_ops {
11962306a36Sopenharmony_ci	int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn,
12062306a36Sopenharmony_ci						int reg, int len, u32 *val);
12162306a36Sopenharmony_ci	int (*write)(unsigned int domain, unsigned int bus, unsigned int devfn,
12262306a36Sopenharmony_ci						int reg, int len, u32 val);
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ciextern const struct pci_raw_ops *raw_pci_ops;
12662306a36Sopenharmony_ciextern const struct pci_raw_ops *raw_pci_ext_ops;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ciextern const struct pci_raw_ops pci_mmcfg;
12962306a36Sopenharmony_ciextern const struct pci_raw_ops pci_direct_conf1;
13062306a36Sopenharmony_ciextern bool port_cf9_safe;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/* arch_initcall level */
13362306a36Sopenharmony_ci#ifdef CONFIG_PCI_DIRECT
13462306a36Sopenharmony_ciextern int pci_direct_probe(void);
13562306a36Sopenharmony_ciextern void pci_direct_init(int type);
13662306a36Sopenharmony_ci#else
13762306a36Sopenharmony_cistatic inline int pci_direct_probe(void) { return -1; }
13862306a36Sopenharmony_cistatic inline  void pci_direct_init(int type) { }
13962306a36Sopenharmony_ci#endif
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci#ifdef CONFIG_PCI_BIOS
14262306a36Sopenharmony_ciextern void pci_pcbios_init(void);
14362306a36Sopenharmony_ci#else
14462306a36Sopenharmony_cistatic inline void pci_pcbios_init(void) { }
14562306a36Sopenharmony_ci#endif
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ciextern void __init dmi_check_pciprobe(void);
14862306a36Sopenharmony_ciextern void __init dmi_check_skip_isa_align(void);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/* some common used subsys_initcalls */
15162306a36Sopenharmony_ci#ifdef CONFIG_PCI
15262306a36Sopenharmony_ciextern int __init pci_acpi_init(void);
15362306a36Sopenharmony_ci#else
15462306a36Sopenharmony_cistatic inline int  __init pci_acpi_init(void)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	return -EINVAL;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci#endif
15962306a36Sopenharmony_ciextern void __init pcibios_irq_init(void);
16062306a36Sopenharmony_ciextern int __init pcibios_init(void);
16162306a36Sopenharmony_ciextern int pci_legacy_init(void);
16262306a36Sopenharmony_ciextern void pcibios_fixup_irqs(void);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci/* pci-mmconfig.c */
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/* "PCI MMCONFIG %04x [bus %02x-%02x]" */
16762306a36Sopenharmony_ci#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistruct pci_mmcfg_region {
17062306a36Sopenharmony_ci	struct list_head list;
17162306a36Sopenharmony_ci	struct resource res;
17262306a36Sopenharmony_ci	u64 address;
17362306a36Sopenharmony_ci	char __iomem *virt;
17462306a36Sopenharmony_ci	u16 segment;
17562306a36Sopenharmony_ci	u8 start_bus;
17662306a36Sopenharmony_ci	u8 end_bus;
17762306a36Sopenharmony_ci	char name[PCI_MMCFG_RESOURCE_NAME_LEN];
17862306a36Sopenharmony_ci};
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ciextern int __init pci_mmcfg_arch_init(void);
18162306a36Sopenharmony_ciextern void __init pci_mmcfg_arch_free(void);
18262306a36Sopenharmony_ciextern int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg);
18362306a36Sopenharmony_ciextern void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg);
18462306a36Sopenharmony_ciextern int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
18562306a36Sopenharmony_ci			       phys_addr_t addr);
18662306a36Sopenharmony_ciextern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
18762306a36Sopenharmony_ciextern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
18862306a36Sopenharmony_ciextern struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start,
18962306a36Sopenharmony_ci							int end, u64 addr);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ciextern struct list_head pci_mmcfg_list;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci#define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci/*
19662306a36Sopenharmony_ci * On AMD Fam10h CPUs, all PCI MMIO configuration space accesses must use
19762306a36Sopenharmony_ci * %eax.  No other source or target registers may be used.  The following
19862306a36Sopenharmony_ci * mmio_config_* accessors enforce this.  See "BIOS and Kernel Developer's
19962306a36Sopenharmony_ci * Guide (BKDG) For AMD Family 10h Processors", rev. 3.48, sec 2.11.1,
20062306a36Sopenharmony_ci * "MMIO Configuration Coding Requirements".
20162306a36Sopenharmony_ci */
20262306a36Sopenharmony_cistatic inline unsigned char mmio_config_readb(void __iomem *pos)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	u8 val;
20562306a36Sopenharmony_ci	asm volatile("movb (%1),%%al" : "=a" (val) : "r" (pos));
20662306a36Sopenharmony_ci	return val;
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic inline unsigned short mmio_config_readw(void __iomem *pos)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	u16 val;
21262306a36Sopenharmony_ci	asm volatile("movw (%1),%%ax" : "=a" (val) : "r" (pos));
21362306a36Sopenharmony_ci	return val;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic inline unsigned int mmio_config_readl(void __iomem *pos)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	u32 val;
21962306a36Sopenharmony_ci	asm volatile("movl (%1),%%eax" : "=a" (val) : "r" (pos));
22062306a36Sopenharmony_ci	return val;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic inline void mmio_config_writeb(void __iomem *pos, u8 val)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	asm volatile("movb %%al,(%1)" : : "a" (val), "r" (pos) : "memory");
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic inline void mmio_config_writew(void __iomem *pos, u16 val)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	asm volatile("movw %%ax,(%1)" : : "a" (val), "r" (pos) : "memory");
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic inline void mmio_config_writel(void __iomem *pos, u32 val)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	asm volatile("movl %%eax,(%1)" : : "a" (val), "r" (pos) : "memory");
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci#ifdef CONFIG_PCI
23962306a36Sopenharmony_ci# ifdef CONFIG_ACPI
24062306a36Sopenharmony_ci#  define x86_default_pci_init		pci_acpi_init
24162306a36Sopenharmony_ci# else
24262306a36Sopenharmony_ci#  define x86_default_pci_init		pci_legacy_init
24362306a36Sopenharmony_ci# endif
24462306a36Sopenharmony_ci# define x86_default_pci_init_irq	pcibios_irq_init
24562306a36Sopenharmony_ci# define x86_default_pci_fixup_irqs	pcibios_fixup_irqs
24662306a36Sopenharmony_ci#else
24762306a36Sopenharmony_ci# define x86_default_pci_init		NULL
24862306a36Sopenharmony_ci# define x86_default_pci_init_irq	NULL
24962306a36Sopenharmony_ci# define x86_default_pci_fixup_irqs	NULL
25062306a36Sopenharmony_ci#endif
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci#if defined(CONFIG_PCI) && defined(CONFIG_ACPI)
25362306a36Sopenharmony_ciextern bool pci_use_e820;
25462306a36Sopenharmony_ci#else
25562306a36Sopenharmony_ci#define pci_use_e820 false
25662306a36Sopenharmony_ci#endif
257