|
9 | 9 | #include <linux/of_pci.h> |
10 | 10 | #include <linux/pci.h> |
11 | 11 | #include <linux/pci_ids.h> |
| 12 | +#include <linux/pci-acpi.h> |
| 13 | +#include <linux/pci-ecam.h> |
12 | 14 |
|
13 | 15 | #include "../pci.h" |
14 | 16 |
|
@@ -97,55 +99,71 @@ static void loongson_mrrs_quirk(struct pci_dev *dev) |
97 | 99 | } |
98 | 100 | DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, loongson_mrrs_quirk); |
99 | 101 |
|
100 | | -static void __iomem *cfg1_map(struct loongson_pci *priv, int bus, |
101 | | - unsigned int devfn, int where) |
| 102 | +static struct loongson_pci *pci_bus_to_loongson_pci(struct pci_bus *bus) |
102 | 103 | { |
103 | | - unsigned long addroff = 0x0; |
| 104 | + struct pci_config_window *cfg; |
104 | 105 |
|
105 | | - if (bus != 0) |
106 | | - addroff |= BIT(28); /* Type 1 Access */ |
107 | | - addroff |= (where & 0xff) | ((where & 0xf00) << 16); |
108 | | - addroff |= (bus << 16) | (devfn << 8); |
109 | | - return priv->cfg1_base + addroff; |
| 106 | + if (acpi_disabled) |
| 107 | + return (struct loongson_pci *)(bus->sysdata); |
| 108 | + |
| 109 | + cfg = bus->sysdata; |
| 110 | + return (struct loongson_pci *)(cfg->priv); |
110 | 111 | } |
111 | 112 |
|
112 | | -static void __iomem *cfg0_map(struct loongson_pci *priv, int bus, |
113 | | - unsigned int devfn, int where) |
| 113 | +static void __iomem *cfg0_map(struct loongson_pci *priv, struct pci_bus *bus, |
| 114 | + unsigned int devfn, int where) |
114 | 115 | { |
115 | 116 | unsigned long addroff = 0x0; |
| 117 | + unsigned char busnum = bus->number; |
116 | 118 |
|
117 | | - if (bus != 0) |
| 119 | + if (!pci_is_root_bus(bus)) { |
118 | 120 | addroff |= BIT(24); /* Type 1 Access */ |
119 | | - addroff |= (bus << 16) | (devfn << 8) | where; |
| 121 | + addroff |= (busnum << 16); |
| 122 | + } |
| 123 | + addroff |= (devfn << 8) | where; |
120 | 124 | return priv->cfg0_base + addroff; |
121 | 125 | } |
122 | 126 |
|
123 | | -static void __iomem *pci_loongson_map_bus(struct pci_bus *bus, unsigned int devfn, |
124 | | - int where) |
| 127 | +static void __iomem *cfg1_map(struct loongson_pci *priv, struct pci_bus *bus, |
| 128 | + unsigned int devfn, int where) |
125 | 129 | { |
| 130 | + unsigned long addroff = 0x0; |
126 | 131 | unsigned char busnum = bus->number; |
127 | | - struct pci_host_bridge *bridge = pci_find_host_bridge(bus); |
128 | | - struct loongson_pci *priv = pci_host_bridge_priv(bridge); |
| 132 | + |
| 133 | + if (!pci_is_root_bus(bus)) { |
| 134 | + addroff |= BIT(28); /* Type 1 Access */ |
| 135 | + addroff |= (busnum << 16); |
| 136 | + } |
| 137 | + addroff |= (devfn << 8) | (where & 0xff) | ((where & 0xf00) << 16); |
| 138 | + return priv->cfg1_base + addroff; |
| 139 | +} |
| 140 | + |
| 141 | +static void __iomem *pci_loongson_map_bus(struct pci_bus *bus, |
| 142 | + unsigned int devfn, int where) |
| 143 | +{ |
| 144 | + struct loongson_pci *priv = pci_bus_to_loongson_pci(bus); |
129 | 145 |
|
130 | 146 | /* |
131 | 147 | * Do not read more than one device on the bus other than |
132 | | - * the host bus. For our hardware the root bus is always bus 0. |
| 148 | + * the host bus. |
133 | 149 | */ |
134 | 150 | if (priv->data->flags & FLAG_DEV_FIX && |
135 | 151 | !pci_is_root_bus(bus) && PCI_SLOT(devfn) > 0) |
136 | 152 | return NULL; |
137 | 153 |
|
138 | 154 | /* CFG0 can only access standard space */ |
139 | 155 | if (where < PCI_CFG_SPACE_SIZE && priv->cfg0_base) |
140 | | - return cfg0_map(priv, busnum, devfn, where); |
| 156 | + return cfg0_map(priv, bus, devfn, where); |
141 | 157 |
|
142 | 158 | /* CFG1 can access extended space */ |
143 | 159 | if (where < PCI_CFG_SPACE_EXP_SIZE && priv->cfg1_base) |
144 | | - return cfg1_map(priv, busnum, devfn, where); |
| 160 | + return cfg1_map(priv, bus, devfn, where); |
145 | 161 |
|
146 | 162 | return NULL; |
147 | 163 | } |
148 | 164 |
|
| 165 | +#ifdef CONFIG_OF |
| 166 | + |
149 | 167 | static int loongson_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) |
150 | 168 | { |
151 | 169 | int irq; |
@@ -259,3 +277,41 @@ static struct platform_driver loongson_pci_driver = { |
259 | 277 | .probe = loongson_pci_probe, |
260 | 278 | }; |
261 | 279 | builtin_platform_driver(loongson_pci_driver); |
| 280 | + |
| 281 | +#endif |
| 282 | + |
| 283 | +#ifdef CONFIG_ACPI |
| 284 | + |
| 285 | +static int loongson_pci_ecam_init(struct pci_config_window *cfg) |
| 286 | +{ |
| 287 | + struct device *dev = cfg->parent; |
| 288 | + struct loongson_pci *priv; |
| 289 | + struct loongson_pci_data *data; |
| 290 | + |
| 291 | + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
| 292 | + if (!priv) |
| 293 | + return -ENOMEM; |
| 294 | + |
| 295 | + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); |
| 296 | + if (!data) |
| 297 | + return -ENOMEM; |
| 298 | + |
| 299 | + cfg->priv = priv; |
| 300 | + data->flags = FLAG_CFG1; |
| 301 | + priv->data = data; |
| 302 | + priv->cfg1_base = cfg->win - (cfg->busr.start << 16); |
| 303 | + |
| 304 | + return 0; |
| 305 | +} |
| 306 | + |
| 307 | +const struct pci_ecam_ops loongson_pci_ecam_ops = { |
| 308 | + .bus_shift = 16, |
| 309 | + .init = loongson_pci_ecam_init, |
| 310 | + .pci_ops = { |
| 311 | + .map_bus = pci_loongson_map_bus, |
| 312 | + .read = pci_generic_config_read, |
| 313 | + .write = pci_generic_config_write, |
| 314 | + } |
| 315 | +}; |
| 316 | + |
| 317 | +#endif |
0 commit comments