Blame view

arch/x86/pci/mmconfig_64.c 2.83 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
15a58ed12   Alexey Starikovskiy   ACPICA: Remove du...
3
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
   * This is an 64bit optimized version that always keeps the full mmconfig
   * space mapped. This allows lockless config space operation.
   */
  
  #include <linux/pci.h>
  #include <linux/init.h>
545493917   Greg Kroah-Hartman   [PATCH] PCI: add ...
10
  #include <linux/acpi.h>
d6ece5491   Andi Kleen   [PATCH] i386/x86-...
11
  #include <linux/bitmap.h>
946f2ee5c   Arjan van de Ven   [PATCH] i386/x86-...
12
  #include <asm/e820.h>
824877111   Jaswinder Singh Rajput   x86, pci: move ar...
13
  #include <asm/pci_x86.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14

8c57786ad   Bjorn Helgaas   x86/PCI: MMCONFIG...
15
  #define PREFIX "PCI: "
8b8a4e33e   Al Viro   [PATCH] i386,amd6...
16
  static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
1cde8a168   Greg Kroah-Hartman   [PATCH] PCI: use ...
17
  {
f6e1d8cc3   Bjorn Helgaas   x86/PCI: MMCONFIG...
18
  	struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
a0ca99096   Ivan Kokshaysky   PCI x86: always u...
19

f6e1d8cc3   Bjorn Helgaas   x86/PCI: MMCONFIG...
20
21
22
  	if (cfg && cfg->virt)
  		return cfg->virt + (PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12));
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
  }
  
  static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
  			  unsigned int devfn, int reg, int len, u32 *value)
  {
8b8a4e33e   Al Viro   [PATCH] i386,amd6...
28
  	char __iomem *addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29

928cf8c62   Andi Kleen   [PATCH] i386/x86-...
30
  	/* Why do we have this when nobody checks it. How about a BUG()!? -AK */
ecc16ba96   Andi Kleen   [PATCH] i386/x86-...
31
  	if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
a0ca99096   Ivan Kokshaysky   PCI x86: always u...
32
  err:		*value = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  		return -EINVAL;
49c93e84d   Andi Kleen   [PATCH] i386/x86-...
34
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35

928cf8c62   Andi Kleen   [PATCH] i386/x86-...
36
37
  	addr = pci_dev_base(seg, bus, devfn);
  	if (!addr)
a0ca99096   Ivan Kokshaysky   PCI x86: always u...
38
  		goto err;
928cf8c62   Andi Kleen   [PATCH] i386/x86-...
39

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
  	switch (len) {
  	case 1:
3320ad994   dean gaudet   x86: Work around ...
42
  		*value = mmio_config_readb(addr + reg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
  		break;
  	case 2:
3320ad994   dean gaudet   x86: Work around ...
45
  		*value = mmio_config_readw(addr + reg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
  		break;
  	case 4:
3320ad994   dean gaudet   x86: Work around ...
48
  		*value = mmio_config_readl(addr + reg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
53
54
55
56
57
  		break;
  	}
  
  	return 0;
  }
  
  static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
  			   unsigned int devfn, int reg, int len, u32 value)
  {
8b8a4e33e   Al Viro   [PATCH] i386,amd6...
58
  	char __iomem *addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59

928cf8c62   Andi Kleen   [PATCH] i386/x86-...
60
  	/* Why do we have this when nobody checks it. How about a BUG()!? -AK */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
  	if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
  		return -EINVAL;
928cf8c62   Andi Kleen   [PATCH] i386/x86-...
63
64
  	addr = pci_dev_base(seg, bus, devfn);
  	if (!addr)
a0ca99096   Ivan Kokshaysky   PCI x86: always u...
65
  		return -EINVAL;
928cf8c62   Andi Kleen   [PATCH] i386/x86-...
66

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
  	switch (len) {
  	case 1:
3320ad994   dean gaudet   x86: Work around ...
69
  		mmio_config_writeb(addr + reg, value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
  		break;
  	case 2:
3320ad994   dean gaudet   x86: Work around ...
72
  		mmio_config_writew(addr + reg, value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
  		break;
  	case 4:
3320ad994   dean gaudet   x86: Work around ...
75
  		mmio_config_writel(addr + reg, value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
  		break;
  	}
  
  	return 0;
  }
72da0b07b   Jan Beulich   x86: constify PCI...
81
  static const struct pci_raw_ops pci_mmcfg = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
84
  	.read =		pci_mmcfg_read,
  	.write =	pci_mmcfg_write,
  };
d215a9c8b   Bjorn Helgaas   x86/PCI: MMCONFIG...
85
  static void __iomem * __init mcfg_ioremap(struct pci_mmcfg_region *cfg)
44de0203f   OGAWA Hirofumi   [PATCH] mmconfig:...
86
87
  {
  	void __iomem *addr;
068258bc1   Yinghai Lu   x86/PCI: host mmc...
88
  	u64 start, size;
df5eb1d67   Bjorn Helgaas   x86/PCI: MMCONFIG...
89
  	int num_buses;
068258bc1   Yinghai Lu   x86/PCI: host mmc...
90

d7e6b66fe   Bjorn Helgaas   x86/PCI: MMCONFIG...
91
92
  	start = cfg->address + PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
  	num_buses = cfg->end_bus - cfg->start_bus + 1;
df5eb1d67   Bjorn Helgaas   x86/PCI: MMCONFIG...
93
  	size = PCI_MMCFG_BUS_OFFSET(num_buses);
068258bc1   Yinghai Lu   x86/PCI: host mmc...
94
  	addr = ioremap_nocache(start, size);
8c57786ad   Bjorn Helgaas   x86/PCI: MMCONFIG...
95
  	if (addr)
d7e6b66fe   Bjorn Helgaas   x86/PCI: MMCONFIG...
96
  		addr -= PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
44de0203f   OGAWA Hirofumi   [PATCH] mmconfig:...
97
98
  	return addr;
  }
b78673944   Olivier Galibert   [PATCH] mmconfig:...
99
  int __init pci_mmcfg_arch_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
  {
3f0f55039   Bjorn Helgaas   x86/PCI: MMCONFIG...
101
  	struct pci_mmcfg_region *cfg;
b78673944   Olivier Galibert   [PATCH] mmconfig:...
102

ff097ddd4   Bjorn Helgaas   x86/PCI: MMCONFIG...
103
  	list_for_each_entry(cfg, &pci_mmcfg_list, list) {
3f0f55039   Bjorn Helgaas   x86/PCI: MMCONFIG...
104
105
  		cfg->virt = mcfg_ioremap(cfg);
  		if (!cfg->virt) {
8c57786ad   Bjorn Helgaas   x86/PCI: MMCONFIG...
106
107
108
  			printk(KERN_ERR PREFIX "can't map MMCONFIG at %pR
  ",
  			       &cfg->res);
0b64ad712   Yinghai Lu   x86: clear pci_mm...
109
  			pci_mmcfg_arch_free();
b78673944   Olivier Galibert   [PATCH] mmconfig:...
110
  			return 0;
1cde8a168   Greg Kroah-Hartman   [PATCH] PCI: use ...
111
  		}
1cde8a168   Greg Kroah-Hartman   [PATCH] PCI: use ...
112
  	}
b6ce068a1   Matthew Wilcox   Change pci_raw_op...
113
  	raw_pci_ext_ops = &pci_mmcfg;
b78673944   Olivier Galibert   [PATCH] mmconfig:...
114
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
  }
0b64ad712   Yinghai Lu   x86: clear pci_mm...
116
117
118
  
  void __init pci_mmcfg_arch_free(void)
  {
3f0f55039   Bjorn Helgaas   x86/PCI: MMCONFIG...
119
  	struct pci_mmcfg_region *cfg;
0b64ad712   Yinghai Lu   x86: clear pci_mm...
120

ff097ddd4   Bjorn Helgaas   x86/PCI: MMCONFIG...
121
  	list_for_each_entry(cfg, &pci_mmcfg_list, list) {
3f0f55039   Bjorn Helgaas   x86/PCI: MMCONFIG...
122
123
124
  		if (cfg->virt) {
  			iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
  			cfg->virt = NULL;
0b64ad712   Yinghai Lu   x86: clear pci_mm...
125
126
  		}
  	}
0b64ad712   Yinghai Lu   x86: clear pci_mm...
127
  }