| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * This file is subject to the terms and conditions of the GNU General Public | 
|  | 3 | * License.  See the file "COPYING" in the main directory of this archive | 
|  | 4 | * for more details. | 
|  | 5 | * | 
|  | 6 | * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> | 
|  | 7 | */ | 
|  | 8 |  | 
|  | 9 | #include <linux/types.h> | 
|  | 10 | #include <linux/pci.h> | 
|  | 11 | #include <linux/kernel.h> | 
|  | 12 | #include <linux/delay.h> | 
|  | 13 | #include <linux/io.h> | 
|  | 14 |  | 
|  | 15 | #include "pci-bcm63xx.h" | 
|  | 16 |  | 
|  | 17 | /* | 
|  | 18 | * swizzle 32bits data to return only the needed part | 
|  | 19 | */ | 
|  | 20 | static int postprocess_read(u32 data, int where, unsigned int size) | 
|  | 21 | { | 
|  | 22 | u32 ret; | 
|  | 23 |  | 
|  | 24 | ret = 0; | 
|  | 25 | switch (size) { | 
|  | 26 | case 1: | 
|  | 27 | ret = (data >> ((where & 3) << 3)) & 0xff; | 
|  | 28 | break; | 
|  | 29 | case 2: | 
|  | 30 | ret = (data >> ((where & 3) << 3)) & 0xffff; | 
|  | 31 | break; | 
|  | 32 | case 4: | 
|  | 33 | ret = data; | 
|  | 34 | break; | 
|  | 35 | } | 
|  | 36 | return ret; | 
|  | 37 | } | 
|  | 38 |  | 
|  | 39 | static int preprocess_write(u32 orig_data, u32 val, int where, | 
|  | 40 | unsigned int size) | 
|  | 41 | { | 
|  | 42 | u32 ret; | 
|  | 43 |  | 
|  | 44 | ret = 0; | 
|  | 45 | switch (size) { | 
|  | 46 | case 1: | 
|  | 47 | ret = (orig_data & ~(0xff << ((where & 3) << 3))) | | 
|  | 48 | (val << ((where & 3) << 3)); | 
|  | 49 | break; | 
|  | 50 | case 2: | 
|  | 51 | ret = (orig_data & ~(0xffff << ((where & 3) << 3))) | | 
|  | 52 | (val << ((where & 3) << 3)); | 
|  | 53 | break; | 
|  | 54 | case 4: | 
|  | 55 | ret = val; | 
|  | 56 | break; | 
|  | 57 | } | 
|  | 58 | return ret; | 
|  | 59 | } | 
|  | 60 |  | 
|  | 61 | /* | 
|  | 62 | * setup hardware for a configuration cycle with given parameters | 
|  | 63 | */ | 
|  | 64 | static int bcm63xx_setup_cfg_access(int type, unsigned int busn, | 
|  | 65 | unsigned int devfn, int where) | 
|  | 66 | { | 
|  | 67 | unsigned int slot, func, reg; | 
|  | 68 | u32 val; | 
|  | 69 |  | 
|  | 70 | slot = PCI_SLOT(devfn); | 
|  | 71 | func = PCI_FUNC(devfn); | 
|  | 72 | reg = where >> 2; | 
|  | 73 |  | 
|  | 74 | /* sanity check */ | 
|  | 75 | if (slot > (MPI_L2PCFG_DEVNUM_MASK >> MPI_L2PCFG_DEVNUM_SHIFT)) | 
|  | 76 | return 1; | 
|  | 77 |  | 
|  | 78 | if (func > (MPI_L2PCFG_FUNC_MASK >> MPI_L2PCFG_FUNC_SHIFT)) | 
|  | 79 | return 1; | 
|  | 80 |  | 
|  | 81 | if (reg > (MPI_L2PCFG_REG_MASK >> MPI_L2PCFG_REG_SHIFT)) | 
|  | 82 | return 1; | 
|  | 83 |  | 
|  | 84 | /* ok, setup config access */ | 
|  | 85 | val = (reg << MPI_L2PCFG_REG_SHIFT); | 
|  | 86 | val |= (func << MPI_L2PCFG_FUNC_SHIFT); | 
|  | 87 | val |= (slot << MPI_L2PCFG_DEVNUM_SHIFT); | 
|  | 88 | val |= MPI_L2PCFG_CFG_USEREG_MASK; | 
|  | 89 | val |= MPI_L2PCFG_CFG_SEL_MASK; | 
|  | 90 | /* type 0 cycle for local bus, type 1 cycle for anything else */ | 
|  | 91 | if (type != 0) { | 
|  | 92 | /* FIXME: how to specify bus ??? */ | 
|  | 93 | val |= (1 << MPI_L2PCFG_CFG_TYPE_SHIFT); | 
|  | 94 | } | 
|  | 95 | bcm_mpi_writel(val, MPI_L2PCFG_REG); | 
|  | 96 |  | 
|  | 97 | return 0; | 
|  | 98 | } | 
|  | 99 |  | 
|  | 100 | static int bcm63xx_do_cfg_read(int type, unsigned int busn, | 
|  | 101 | unsigned int devfn, int where, int size, | 
|  | 102 | u32 *val) | 
|  | 103 | { | 
|  | 104 | u32 data; | 
|  | 105 |  | 
|  | 106 | /* two phase cycle, first we write address, then read data at | 
|  | 107 | * another location, caller already has a spinlock so no need | 
|  | 108 | * to add one here  */ | 
|  | 109 | if (bcm63xx_setup_cfg_access(type, busn, devfn, where)) | 
|  | 110 | return PCIBIOS_DEVICE_NOT_FOUND; | 
|  | 111 | iob(); | 
|  | 112 | data = le32_to_cpu(__raw_readl(pci_iospace_start)); | 
|  | 113 | /* restore IO space normal behaviour */ | 
|  | 114 | bcm_mpi_writel(0, MPI_L2PCFG_REG); | 
|  | 115 |  | 
|  | 116 | *val = postprocess_read(data, where, size); | 
|  | 117 |  | 
|  | 118 | return PCIBIOS_SUCCESSFUL; | 
|  | 119 | } | 
|  | 120 |  | 
|  | 121 | static int bcm63xx_do_cfg_write(int type, unsigned int busn, | 
|  | 122 | unsigned int devfn, int where, int size, | 
|  | 123 | u32 val) | 
|  | 124 | { | 
|  | 125 | u32 data; | 
|  | 126 |  | 
|  | 127 | /* two phase cycle, first we write address, then write data to | 
|  | 128 | * another location, caller already has a spinlock so no need | 
|  | 129 | * to add one here  */ | 
|  | 130 | if (bcm63xx_setup_cfg_access(type, busn, devfn, where)) | 
|  | 131 | return PCIBIOS_DEVICE_NOT_FOUND; | 
|  | 132 | iob(); | 
|  | 133 |  | 
|  | 134 | data = le32_to_cpu(__raw_readl(pci_iospace_start)); | 
|  | 135 | data = preprocess_write(data, val, where, size); | 
|  | 136 |  | 
|  | 137 | __raw_writel(cpu_to_le32(data), pci_iospace_start); | 
|  | 138 | wmb(); | 
|  | 139 | /* no way to know the access is done, we have to wait */ | 
|  | 140 | udelay(500); | 
|  | 141 | /* restore IO space normal behaviour */ | 
|  | 142 | bcm_mpi_writel(0, MPI_L2PCFG_REG); | 
|  | 143 |  | 
|  | 144 | return PCIBIOS_SUCCESSFUL; | 
|  | 145 | } | 
|  | 146 |  | 
|  | 147 | static int bcm63xx_pci_read(struct pci_bus *bus, unsigned int devfn, | 
|  | 148 | int where, int size, u32 *val) | 
|  | 149 | { | 
|  | 150 | int type; | 
|  | 151 |  | 
|  | 152 | type = bus->parent ? 1 : 0; | 
|  | 153 |  | 
|  | 154 | if (type == 0 && PCI_SLOT(devfn) == CARDBUS_PCI_IDSEL) | 
|  | 155 | return PCIBIOS_DEVICE_NOT_FOUND; | 
|  | 156 |  | 
|  | 157 | return bcm63xx_do_cfg_read(type, bus->number, devfn, | 
|  | 158 | where, size, val); | 
|  | 159 | } | 
|  | 160 |  | 
|  | 161 | static int bcm63xx_pci_write(struct pci_bus *bus, unsigned int devfn, | 
|  | 162 | int where, int size, u32 val) | 
|  | 163 | { | 
|  | 164 | int type; | 
|  | 165 |  | 
|  | 166 | type = bus->parent ? 1 : 0; | 
|  | 167 |  | 
|  | 168 | if (type == 0 && PCI_SLOT(devfn) == CARDBUS_PCI_IDSEL) | 
|  | 169 | return PCIBIOS_DEVICE_NOT_FOUND; | 
|  | 170 |  | 
|  | 171 | return bcm63xx_do_cfg_write(type, bus->number, devfn, | 
|  | 172 | where, size, val); | 
|  | 173 | } | 
|  | 174 |  | 
|  | 175 | struct pci_ops bcm63xx_pci_ops = { | 
|  | 176 | .read	= bcm63xx_pci_read, | 
|  | 177 | .write	= bcm63xx_pci_write | 
|  | 178 | }; | 
|  | 179 |  | 
|  | 180 | #ifdef CONFIG_CARDBUS | 
|  | 181 | /* | 
|  | 182 | * emulate configuration read access on a cardbus bridge | 
|  | 183 | */ | 
|  | 184 | #define FAKE_CB_BRIDGE_SLOT	0x1e | 
|  | 185 |  | 
|  | 186 | static int fake_cb_bridge_bus_number = -1; | 
|  | 187 |  | 
|  | 188 | static struct { | 
|  | 189 | u16 pci_command; | 
|  | 190 | u8 cb_latency; | 
|  | 191 | u8 subordinate_busn; | 
|  | 192 | u8 cardbus_busn; | 
|  | 193 | u8 pci_busn; | 
|  | 194 | int bus_assigned; | 
|  | 195 | u16 bridge_control; | 
|  | 196 |  | 
|  | 197 | u32 mem_base0; | 
|  | 198 | u32 mem_limit0; | 
|  | 199 | u32 mem_base1; | 
|  | 200 | u32 mem_limit1; | 
|  | 201 |  | 
|  | 202 | u32 io_base0; | 
|  | 203 | u32 io_limit0; | 
|  | 204 | u32 io_base1; | 
|  | 205 | u32 io_limit1; | 
|  | 206 | } fake_cb_bridge_regs; | 
|  | 207 |  | 
|  | 208 | static int fake_cb_bridge_read(int where, int size, u32 *val) | 
|  | 209 | { | 
|  | 210 | unsigned int reg; | 
|  | 211 | u32 data; | 
|  | 212 |  | 
|  | 213 | data = 0; | 
|  | 214 | reg = where >> 2; | 
|  | 215 | switch (reg) { | 
|  | 216 | case (PCI_VENDOR_ID >> 2): | 
|  | 217 | case (PCI_CB_SUBSYSTEM_VENDOR_ID >> 2): | 
|  | 218 | /* create dummy vendor/device id from our cpu id */ | 
|  | 219 | data = (bcm63xx_get_cpu_id() << 16) | PCI_VENDOR_ID_BROADCOM; | 
|  | 220 | break; | 
|  | 221 |  | 
|  | 222 | case (PCI_COMMAND >> 2): | 
|  | 223 | data = (PCI_STATUS_DEVSEL_SLOW << 16); | 
|  | 224 | data |= fake_cb_bridge_regs.pci_command; | 
|  | 225 | break; | 
|  | 226 |  | 
|  | 227 | case (PCI_CLASS_REVISION >> 2): | 
|  | 228 | data = (PCI_CLASS_BRIDGE_CARDBUS << 16); | 
|  | 229 | break; | 
|  | 230 |  | 
|  | 231 | case (PCI_CACHE_LINE_SIZE >> 2): | 
|  | 232 | data = (PCI_HEADER_TYPE_CARDBUS << 16); | 
|  | 233 | break; | 
|  | 234 |  | 
|  | 235 | case (PCI_INTERRUPT_LINE >> 2): | 
|  | 236 | /* bridge control */ | 
|  | 237 | data = (fake_cb_bridge_regs.bridge_control << 16); | 
|  | 238 | /* pin:intA line:0xff */ | 
|  | 239 | data |= (0x1 << 8) | 0xff; | 
|  | 240 | break; | 
|  | 241 |  | 
|  | 242 | case (PCI_CB_PRIMARY_BUS >> 2): | 
|  | 243 | data = (fake_cb_bridge_regs.cb_latency << 24); | 
|  | 244 | data |= (fake_cb_bridge_regs.subordinate_busn << 16); | 
|  | 245 | data |= (fake_cb_bridge_regs.cardbus_busn << 8); | 
|  | 246 | data |= fake_cb_bridge_regs.pci_busn; | 
|  | 247 | break; | 
|  | 248 |  | 
|  | 249 | case (PCI_CB_MEMORY_BASE_0 >> 2): | 
|  | 250 | data = fake_cb_bridge_regs.mem_base0; | 
|  | 251 | break; | 
|  | 252 |  | 
|  | 253 | case (PCI_CB_MEMORY_LIMIT_0 >> 2): | 
|  | 254 | data = fake_cb_bridge_regs.mem_limit0; | 
|  | 255 | break; | 
|  | 256 |  | 
|  | 257 | case (PCI_CB_MEMORY_BASE_1 >> 2): | 
|  | 258 | data = fake_cb_bridge_regs.mem_base1; | 
|  | 259 | break; | 
|  | 260 |  | 
|  | 261 | case (PCI_CB_MEMORY_LIMIT_1 >> 2): | 
|  | 262 | data = fake_cb_bridge_regs.mem_limit1; | 
|  | 263 | break; | 
|  | 264 |  | 
|  | 265 | case (PCI_CB_IO_BASE_0 >> 2): | 
|  | 266 | /* | 1 for 32bits io support */ | 
|  | 267 | data = fake_cb_bridge_regs.io_base0 | 0x1; | 
|  | 268 | break; | 
|  | 269 |  | 
|  | 270 | case (PCI_CB_IO_LIMIT_0 >> 2): | 
|  | 271 | data = fake_cb_bridge_regs.io_limit0; | 
|  | 272 | break; | 
|  | 273 |  | 
|  | 274 | case (PCI_CB_IO_BASE_1 >> 2): | 
|  | 275 | /* | 1 for 32bits io support */ | 
|  | 276 | data = fake_cb_bridge_regs.io_base1 | 0x1; | 
|  | 277 | break; | 
|  | 278 |  | 
|  | 279 | case (PCI_CB_IO_LIMIT_1 >> 2): | 
|  | 280 | data = fake_cb_bridge_regs.io_limit1; | 
|  | 281 | break; | 
|  | 282 | } | 
|  | 283 |  | 
|  | 284 | *val = postprocess_read(data, where, size); | 
|  | 285 | return PCIBIOS_SUCCESSFUL; | 
|  | 286 | } | 
|  | 287 |  | 
|  | 288 | /* | 
|  | 289 | * emulate configuration write access on a cardbus bridge | 
|  | 290 | */ | 
|  | 291 | static int fake_cb_bridge_write(int where, int size, u32 val) | 
|  | 292 | { | 
|  | 293 | unsigned int reg; | 
|  | 294 | u32 data, tmp; | 
|  | 295 | int ret; | 
|  | 296 |  | 
|  | 297 | ret = fake_cb_bridge_read((where & ~0x3), 4, &data); | 
|  | 298 | if (ret != PCIBIOS_SUCCESSFUL) | 
|  | 299 | return ret; | 
|  | 300 |  | 
|  | 301 | data = preprocess_write(data, val, where, size); | 
|  | 302 |  | 
|  | 303 | reg = where >> 2; | 
|  | 304 | switch (reg) { | 
|  | 305 | case (PCI_COMMAND >> 2): | 
|  | 306 | fake_cb_bridge_regs.pci_command = (data & 0xffff); | 
|  | 307 | break; | 
|  | 308 |  | 
|  | 309 | case (PCI_CB_PRIMARY_BUS >> 2): | 
|  | 310 | fake_cb_bridge_regs.cb_latency = (data >> 24) & 0xff; | 
|  | 311 | fake_cb_bridge_regs.subordinate_busn = (data >> 16) & 0xff; | 
|  | 312 | fake_cb_bridge_regs.cardbus_busn = (data >> 8) & 0xff; | 
|  | 313 | fake_cb_bridge_regs.pci_busn = data & 0xff; | 
|  | 314 | if (fake_cb_bridge_regs.cardbus_busn) | 
|  | 315 | fake_cb_bridge_regs.bus_assigned = 1; | 
|  | 316 | break; | 
|  | 317 |  | 
|  | 318 | case (PCI_INTERRUPT_LINE >> 2): | 
|  | 319 | tmp = (data >> 16) & 0xffff; | 
|  | 320 | /* disable memory prefetch support */ | 
|  | 321 | tmp &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM0; | 
|  | 322 | tmp &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1; | 
|  | 323 | fake_cb_bridge_regs.bridge_control = tmp; | 
|  | 324 | break; | 
|  | 325 |  | 
|  | 326 | case (PCI_CB_MEMORY_BASE_0 >> 2): | 
|  | 327 | fake_cb_bridge_regs.mem_base0 = data; | 
|  | 328 | break; | 
|  | 329 |  | 
|  | 330 | case (PCI_CB_MEMORY_LIMIT_0 >> 2): | 
|  | 331 | fake_cb_bridge_regs.mem_limit0 = data; | 
|  | 332 | break; | 
|  | 333 |  | 
|  | 334 | case (PCI_CB_MEMORY_BASE_1 >> 2): | 
|  | 335 | fake_cb_bridge_regs.mem_base1 = data; | 
|  | 336 | break; | 
|  | 337 |  | 
|  | 338 | case (PCI_CB_MEMORY_LIMIT_1 >> 2): | 
|  | 339 | fake_cb_bridge_regs.mem_limit1 = data; | 
|  | 340 | break; | 
|  | 341 |  | 
|  | 342 | case (PCI_CB_IO_BASE_0 >> 2): | 
|  | 343 | fake_cb_bridge_regs.io_base0 = data; | 
|  | 344 | break; | 
|  | 345 |  | 
|  | 346 | case (PCI_CB_IO_LIMIT_0 >> 2): | 
|  | 347 | fake_cb_bridge_regs.io_limit0 = data; | 
|  | 348 | break; | 
|  | 349 |  | 
|  | 350 | case (PCI_CB_IO_BASE_1 >> 2): | 
|  | 351 | fake_cb_bridge_regs.io_base1 = data; | 
|  | 352 | break; | 
|  | 353 |  | 
|  | 354 | case (PCI_CB_IO_LIMIT_1 >> 2): | 
|  | 355 | fake_cb_bridge_regs.io_limit1 = data; | 
|  | 356 | break; | 
|  | 357 | } | 
|  | 358 |  | 
|  | 359 | return PCIBIOS_SUCCESSFUL; | 
|  | 360 | } | 
|  | 361 |  | 
|  | 362 | static int bcm63xx_cb_read(struct pci_bus *bus, unsigned int devfn, | 
|  | 363 | int where, int size, u32 *val) | 
|  | 364 | { | 
|  | 365 | /* snoop access to slot 0x1e on root bus, we fake a cardbus | 
|  | 366 | * bridge at this location */ | 
|  | 367 | if (!bus->parent && PCI_SLOT(devfn) == FAKE_CB_BRIDGE_SLOT) { | 
|  | 368 | fake_cb_bridge_bus_number = bus->number; | 
|  | 369 | return fake_cb_bridge_read(where, size, val); | 
|  | 370 | } | 
|  | 371 |  | 
|  | 372 | /* a  configuration  cycle for	the  device  behind the	 cardbus | 
|  | 373 | * bridge is  actually done as a  type 0 cycle	on the primary | 
|  | 374 | * bus. This means that only  one device can be on the cardbus | 
|  | 375 | * bus */ | 
|  | 376 | if (fake_cb_bridge_regs.bus_assigned && | 
|  | 377 | bus->number == fake_cb_bridge_regs.cardbus_busn && | 
|  | 378 | PCI_SLOT(devfn) == 0) | 
|  | 379 | return bcm63xx_do_cfg_read(0, 0, | 
|  | 380 | PCI_DEVFN(CARDBUS_PCI_IDSEL, 0), | 
|  | 381 | where, size, val); | 
|  | 382 |  | 
|  | 383 | return PCIBIOS_DEVICE_NOT_FOUND; | 
|  | 384 | } | 
|  | 385 |  | 
|  | 386 | static int bcm63xx_cb_write(struct pci_bus *bus, unsigned int devfn, | 
|  | 387 | int where, int size, u32 val) | 
|  | 388 | { | 
|  | 389 | if (!bus->parent && PCI_SLOT(devfn) == FAKE_CB_BRIDGE_SLOT) { | 
|  | 390 | fake_cb_bridge_bus_number = bus->number; | 
|  | 391 | return fake_cb_bridge_write(where, size, val); | 
|  | 392 | } | 
|  | 393 |  | 
|  | 394 | if (fake_cb_bridge_regs.bus_assigned && | 
|  | 395 | bus->number == fake_cb_bridge_regs.cardbus_busn && | 
|  | 396 | PCI_SLOT(devfn) == 0) | 
|  | 397 | return bcm63xx_do_cfg_write(0, 0, | 
|  | 398 | PCI_DEVFN(CARDBUS_PCI_IDSEL, 0), | 
|  | 399 | where, size, val); | 
|  | 400 |  | 
|  | 401 | return PCIBIOS_DEVICE_NOT_FOUND; | 
|  | 402 | } | 
|  | 403 |  | 
|  | 404 | struct pci_ops bcm63xx_cb_ops = { | 
|  | 405 | .read	= bcm63xx_cb_read, | 
|  | 406 | .write	 = bcm63xx_cb_write, | 
|  | 407 | }; | 
|  | 408 |  | 
|  | 409 | /* | 
|  | 410 | * only one IO window, so it  cannot be shared by PCI and cardbus, use | 
|  | 411 | * fixup to choose and detect unhandled configuration | 
|  | 412 | */ | 
|  | 413 | static void bcm63xx_fixup(struct pci_dev *dev) | 
|  | 414 | { | 
|  | 415 | static int io_window = -1; | 
|  | 416 | int i, found, new_io_window; | 
|  | 417 | u32 val; | 
|  | 418 |  | 
|  | 419 | /* look for any io resource */ | 
|  | 420 | found = 0; | 
|  | 421 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | 
|  | 422 | if (pci_resource_flags(dev, i) & IORESOURCE_IO) { | 
|  | 423 | found = 1; | 
|  | 424 | break; | 
|  | 425 | } | 
|  | 426 | } | 
|  | 427 |  | 
|  | 428 | if (!found) | 
|  | 429 | return; | 
|  | 430 |  | 
|  | 431 | /* skip our fake bus with only cardbus bridge on it */ | 
|  | 432 | if (dev->bus->number == fake_cb_bridge_bus_number) | 
|  | 433 | return; | 
|  | 434 |  | 
|  | 435 | /* find on which bus the device is */ | 
|  | 436 | if (fake_cb_bridge_regs.bus_assigned && | 
|  | 437 | dev->bus->number == fake_cb_bridge_regs.cardbus_busn && | 
|  | 438 | PCI_SLOT(dev->devfn) == 0) | 
|  | 439 | new_io_window = 1; | 
|  | 440 | else | 
|  | 441 | new_io_window = 0; | 
|  | 442 |  | 
|  | 443 | if (new_io_window == io_window) | 
|  | 444 | return; | 
|  | 445 |  | 
|  | 446 | if (io_window != -1) { | 
|  | 447 | printk(KERN_ERR "bcm63xx: both PCI and cardbus devices " | 
|  | 448 | "need IO, which hardware cannot do\n"); | 
|  | 449 | return; | 
|  | 450 | } | 
|  | 451 |  | 
|  | 452 | printk(KERN_INFO "bcm63xx: PCI IO window assigned to %s\n", | 
|  | 453 | (new_io_window == 0) ? "PCI" : "cardbus"); | 
|  | 454 |  | 
|  | 455 | val = bcm_mpi_readl(MPI_L2PIOREMAP_REG); | 
|  | 456 | if (io_window) | 
|  | 457 | val |= MPI_L2PREMAP_IS_CARDBUS_MASK; | 
|  | 458 | else | 
|  | 459 | val &= ~MPI_L2PREMAP_IS_CARDBUS_MASK; | 
|  | 460 | bcm_mpi_writel(val, MPI_L2PIOREMAP_REG); | 
|  | 461 |  | 
|  | 462 | io_window = new_io_window; | 
|  | 463 | } | 
|  | 464 |  | 
|  | 465 | DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, bcm63xx_fixup); | 
|  | 466 | #endif | 
|  | 467 |  | 
|  | 468 | static int bcm63xx_pcie_can_access(struct pci_bus *bus, int devfn) | 
|  | 469 | { | 
|  | 470 | switch (bus->number) { | 
|  | 471 | case PCIE_BUS_BRIDGE: | 
|  | 472 | return PCI_SLOT(devfn) == 0; | 
|  | 473 | case PCIE_BUS_DEVICE: | 
|  | 474 | if (PCI_SLOT(devfn) == 0) | 
|  | 475 | return bcm_pcie_readl(PCIE_DLSTATUS_REG) | 
|  | 476 | & DLSTATUS_PHYLINKUP; | 
|  | 477 | default: | 
|  | 478 | return false; | 
|  | 479 | } | 
|  | 480 | } | 
|  | 481 |  | 
|  | 482 | static int bcm63xx_pcie_read(struct pci_bus *bus, unsigned int devfn, | 
|  | 483 | int where, int size, u32 *val) | 
|  | 484 | { | 
|  | 485 | u32 data; | 
|  | 486 | u32 reg = where & ~3; | 
|  | 487 |  | 
|  | 488 | if (!bcm63xx_pcie_can_access(bus, devfn)) | 
|  | 489 | return PCIBIOS_DEVICE_NOT_FOUND; | 
|  | 490 |  | 
|  | 491 | if (bus->number == PCIE_BUS_DEVICE) | 
|  | 492 | reg += PCIE_DEVICE_OFFSET; | 
|  | 493 |  | 
|  | 494 | data = bcm_pcie_readl(reg); | 
|  | 495 |  | 
|  | 496 | *val = postprocess_read(data, where, size); | 
|  | 497 |  | 
|  | 498 | return PCIBIOS_SUCCESSFUL; | 
|  | 499 |  | 
|  | 500 | } | 
|  | 501 |  | 
|  | 502 | static int bcm63xx_pcie_write(struct pci_bus *bus, unsigned int devfn, | 
|  | 503 | int where, int size, u32 val) | 
|  | 504 | { | 
|  | 505 | u32 data; | 
|  | 506 | u32 reg = where & ~3; | 
|  | 507 |  | 
|  | 508 | if (!bcm63xx_pcie_can_access(bus, devfn)) | 
|  | 509 | return PCIBIOS_DEVICE_NOT_FOUND; | 
|  | 510 |  | 
|  | 511 | if (bus->number == PCIE_BUS_DEVICE) | 
|  | 512 | reg += PCIE_DEVICE_OFFSET; | 
|  | 513 |  | 
|  | 514 |  | 
|  | 515 | data = bcm_pcie_readl(reg); | 
|  | 516 |  | 
|  | 517 | data = preprocess_write(data, val, where, size); | 
|  | 518 | bcm_pcie_writel(data, reg); | 
|  | 519 |  | 
|  | 520 | return PCIBIOS_SUCCESSFUL; | 
|  | 521 | } | 
|  | 522 |  | 
|  | 523 |  | 
|  | 524 | struct pci_ops bcm63xx_pcie_ops = { | 
|  | 525 | .read	= bcm63xx_pcie_read, | 
|  | 526 | .write	= bcm63xx_pcie_write | 
|  | 527 | }; |