diff --git a/headers/private/kernel/platform/openfirmware/pci.h b/headers/private/kernel/platform/openfirmware/pci.h new file mode 100644 index 0000000000..8060d8d376 --- /dev/null +++ b/headers/private/kernel/platform/openfirmware/pci.h @@ -0,0 +1,112 @@ +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * from: NetBSD: ofw_pci.h,v 1.5 2003/10/22 09:04:39 mjl Exp + * + * $FreeBSD$ + */ + +#ifndef _KERNEL_OPEN_FIRMWARE_PCI_H +#define _KERNEL_OPEN_FIRMWARE_PCI_H + +#include + +/* + * PCI Bus Binding to: + * + * IEEE Std 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware + * + * Revision 2.1 + */ + +/* + * Section 2.2.1. Physical Address Formats + * + * A PCI physical address is represented by 3 address cells: + * + * phys.hi cell: npt000ss bbbbbbbb dddddfff rrrrrrrr + * phys.mid cell: hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh + * phys.lo cell: llllllll llllllll llllllll llllllll + * + * n nonrelocatable + * p prefetchable + * t aliased below 1MB (memory) or 64k (i/o) + * ss space code + * b bus number + * d device number + * f function number + * r register number + * h high 32-bits of PCI address + * l low 32-bits of PCI address + */ + +#define OFW_PCI_PHYS_HI_NONRELOCATABLE 0x80000000 +#define OFW_PCI_PHYS_HI_PREFETCHABLE 0x40000000 +#define OFW_PCI_PHYS_HI_ALIASED 0x20000000 +#define OFW_PCI_PHYS_HI_SPACEMASK 0x03000000 +#define OFW_PCI_PHYS_HI_BUSMASK 0x00ff0000 +#define OFW_PCI_PHYS_HI_BUSSHIFT 16 +#define OFW_PCI_PHYS_HI_DEVICEMASK 0x0000f800 +#define OFW_PCI_PHYS_HI_DEVICESHIFT 11 +#define OFW_PCI_PHYS_HI_FUNCTIONMASK 0x00000700 +#define OFW_PCI_PHYS_HI_FUNCTIONSHIFT 8 +#define OFW_PCI_PHYS_HI_REGISTERMASK 0x000000ff + +#define OFW_PCI_PHYS_HI_SPACE_CONFIG 0x00000000 +#define OFW_PCI_PHYS_HI_SPACE_IO 0x01000000 +#define OFW_PCI_PHYS_HI_SPACE_MEM32 0x02000000 +#define OFW_PCI_PHYS_HI_SPACE_MEM64 0x03000000 + +#define OFW_PCI_PHYS_HI_BUS(hi) \ + (((hi) & OFW_PCI_PHYS_HI_BUSMASK) >> OFW_PCI_PHYS_HI_BUSSHIFT) +#define OFW_PCI_PHYS_HI_DEVICE(hi) \ + (((hi) & OFW_PCI_PHYS_HI_DEVICEMASK) >> OFW_PCI_PHYS_HI_DEVICESHIFT) +#define OFW_PCI_PHYS_HI_FUNCTION(hi) \ + (((hi) & OFW_PCI_PHYS_HI_FUNCTIONMASK) >> OFW_PCI_PHYS_HI_FUNCTIONSHIFT) + +/* + * This has the 3 32bit cell values, plus 2 more to make up a 64-bit size. + */ +struct ofw_pci_register { + uint32 phys_hi; + uint32 phys_mid; + uint32 phys_lo; + uint32 size_hi; + uint32 size_lo; +}; + +#endif /* _KERNEL_OPEN_FIRMWARE_PCI_H */ diff --git a/src/add-ons/kernel/bus_managers/pci/arch/ppc/Jamfile b/src/add-ons/kernel/bus_managers/pci/arch/ppc/Jamfile index 6d0ec34ea5..f456b853ad 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/ppc/Jamfile +++ b/src/add-ons/kernel/bus_managers/pci/arch/ppc/Jamfile @@ -2,7 +2,13 @@ SubDir HAIKU_TOP src add-ons kernel bus_managers pci arch ppc ; SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) openfirmware ] ; + KernelStaticLibrary pci_arch_bus_manager : pci_controller.cpp pci_io.c - ; + + # openfirmware + pci_openfirmware.cpp + uninorth.cpp +; diff --git a/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/pci_openfirmware.cpp b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/pci_openfirmware.cpp new file mode 100644 index 0000000000..bacb3c9047 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/pci_openfirmware.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "pci_openfirmware.h" + +#include +#include + +#include + +#include +#include +#include + +#include "pci_openfirmware_priv.h" + + +typedef status_t (*probeFunction)(int, const StringArrayPropertyValue&); + +static const probeFunction sProbeFunctions[] = { + ppc_openfirmware_probe_uninorth, + NULL, +}; + + +status_t +ppc_openfirmware_pci_controller_init(void) +{ + char path[256]; + int cookie = 0; + while (of_get_next_device(&cookie, NULL, "pci", path, sizeof(path)) + == B_OK) { +dprintf("ppc_openfirmware_pci_controller_init(): pci device node: %s\n", path); + // get the device node and the "compatible" property + int deviceNode = of_finddevice(path); + StringArrayPropertyValue compatible; + status_t error = openfirmware_get_property(deviceNode, "compatible", + compatible); + if (error != B_OK) { + dprintf("ppc_openfirmware_pci_controller_init: Failed to get " + "\"compatible\" property for pci device: %s\n", path); + continue; + } + + // probe + for (int i = 0; sProbeFunctions[i]; i++) { + error = sProbeFunctions[i](deviceNode, compatible); + if (error == B_OK) + break; + } + } + + return B_OK; +} + + +// #pragma mark - support functions + + +char * +StringArrayPropertyValue::NextElement(int &cookie) const +{ + if (cookie >= length) + return NULL; + + char *result = value + cookie; + cookie += strnlen(result, length - cookie) + 1; + return result; +} + + +bool +StringArrayPropertyValue::ContainsElement(const char *value) const +{ + int cookie = 0; + while (char *checkValue = NextElement(cookie)) { + if (strcmp(checkValue, value) == 0) + return true; + } + + return false; +} + + +status_t +openfirmware_get_property(int package, const char *propertyName, + PropertyValue &value) +{ + value.length = of_getproplen(package, propertyName); + if (value.length < 0) + return B_ENTRY_NOT_FOUND; + + value.value = (char*)malloc(value.length); + if (!value.value) + return B_NO_MEMORY; + + if (of_getprop(package, propertyName, value.value, value.length) + == OF_FAILED) { + return B_ERROR; + } + + return B_OK; +} + diff --git a/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/pci_openfirmware.h b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/pci_openfirmware.h new file mode 100644 index 0000000000..4afbd58ec8 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/pci_openfirmware.h @@ -0,0 +1,13 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#ifndef PCI_BUS_MANAGER_PPC_OPEN_FIRMWARE_H +#define PCI_BUS_MANAGER_PPC_OPEN_FIRMWARE_H + +#include + +status_t ppc_openfirmware_pci_controller_init(void); + +#endif // PCI_BUS_MANAGER_PPC_OPEN_FIRMWARE_H diff --git a/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/pci_openfirmware_priv.h b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/pci_openfirmware_priv.h new file mode 100644 index 0000000000..bd57c6ac74 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/pci_openfirmware_priv.h @@ -0,0 +1,50 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#ifndef PCI_BUS_MANAGER_PPC_OPEN_FIRMWARE_PRIV_H +#define PCI_BUS_MANAGER_PPC_OPEN_FIRMWARE_PRIV_H + +#include +#include + +#include + + +struct StringArrayPropertyValue; + + +// implementations + +status_t ppc_openfirmware_probe_uninorth(int deviceNode, + const StringArrayPropertyValue &compatibleValue); + + +// property support + +struct PropertyValue { + PropertyValue() + : value(NULL) + { + } + + ~PropertyValue() + { + free(value); + } + + char *value; + int length; +}; + +struct StringArrayPropertyValue : PropertyValue { + + char *NextElement(int &cookie) const; + bool ContainsElement(const char *value) const; +}; + +status_t openfirmware_get_property(int package, const char *propertyName, + PropertyValue &value); + +#endif // PCI_BUS_MANAGER_PPC_OPEN_FIRMWARE_PRIV_H diff --git a/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/uninorth.cpp b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/uninorth.cpp new file mode 100644 index 0000000000..4f30406170 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/uninorth.cpp @@ -0,0 +1,284 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ +/*- + * Copyright (C) 2002 Benno Rice. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include + +#include + +#include +#include +#include + +#include "pci_controller.h" +#include "pci_io.h" +#include "pci_openfirmware_priv.h" + + +struct uninorth_range { + uint32 pci_hi; + uint32 pci_mid; + uint32 pci_lo; + uint32 host; + uint32 size_hi; + uint32 size_lo; +}; + +struct uninorth_host_bridge { + int device_node; + addr_t address_registers; + addr_t data_registers; + uint32 bus; + struct uninorth_range ranges[6]; + int range_count; +}; + + +#define out8rb(address, value) ppc_out8((vuint8*)(address), value) +#define out16rb(address, value) ppc_out16_reverse((vuint16*)(address), value) +#define out32rb(address, value) ppc_out32_reverse((vuint32*)(address), value) +#define in8rb(address) ppc_in8((const vuint8*)(address)) +#define in16rb(address) ppc_in16_reverse((const vuint16*)(address)) +#define in32rb(address) ppc_in32_reverse((const vuint32*)(address)) + + +static int uninorth_enable_config(struct uninorth_host_bridge *bridge, + uint8 bus, uint8 slot, uint8 function, uint8 offset); + +static status_t uninorth_read_pci_config(void *cookie, uint8 bus, uint8 device, + uint8 function, uint8 offset, uint8 size, uint32 *value); +static status_t uninorth_write_pci_config(void *cookie, uint8 bus, + uint8 device, uint8 function, uint8 offset, uint8 size, + uint32 value); +static status_t uninorth_get_max_bus_devices(void *cookie, int32 *count); +static status_t uninorth_read_pci_irq(void *cookie, uint8 bus, uint8 device, + uint8 function, uint8 pin, uint8 *irq); +static status_t uninorth_write_pci_irq(void *cookie, uint8 bus, uint8 device, + uint8 function, uint8 pin, uint8 irq); + +static pci_controller sUniNorthPCIController = { + uninorth_read_pci_config, + uninorth_write_pci_config, + uninorth_get_max_bus_devices, + uninorth_read_pci_irq, + uninorth_write_pci_irq, +}; + + +static status_t +uninorth_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function, + uint8 offset, uint8 size, uint32 *value) +{ + uninorth_host_bridge *bridge = (uninorth_host_bridge*)cookie; + + addr_t caoff = bridge->data_registers + (offset & 0x07); + + if (uninorth_enable_config(bridge, bus, device, function, offset) != 0) { + switch (size) { + case 1: + *value = in8rb(caoff); + break; + case 2: + *value = in16rb(caoff); + break; + case 4: + *value = in32rb(caoff); + break; + default: + *value = 0xffffffff; + break; + } + } else + *value = 0xffffffff; + + return B_OK; +} + + +static status_t uninorth_write_pci_config(void *cookie, uint8 bus, uint8 device, + uint8 function, uint8 offset, uint8 size, uint32 value) +{ + uninorth_host_bridge *bridge = (uninorth_host_bridge*)cookie; + + addr_t caoff = bridge->data_registers + (offset & 0x07); + + if (uninorth_enable_config(bridge, bus, device, function, offset)) { + switch (size) { + case 1: + out8rb(caoff, (uint8)value); + (void)in8rb(caoff); + break; + case 2: + out16rb(caoff, (uint16)value); + (void)in16rb(caoff); + break; + case 4: + out32rb(caoff, value); + (void)in32rb(caoff); + break; + } + } + + return B_OK; +} + + +static status_t uninorth_get_max_bus_devices(void *cookie, int32 *count) +{ + *count = 32; + return B_OK; +} + + +static status_t uninorth_read_pci_irq(void *cookie, uint8 bus, uint8 device, + uint8 function, uint8 pin, uint8 *irq) +{ + return B_ERROR; +} + + +static status_t uninorth_write_pci_irq(void *cookie, uint8 bus, uint8 device, + uint8 function, uint8 pin, uint8 irq) +{ + return B_ERROR; +} + + +// #pragma mark - + + +static int +uninorth_enable_config(struct uninorth_host_bridge *bridge, uint8 bus, + uint8 slot, uint8 function, uint8 offset) +{ +// uint32 pass; +// if (resource_int_value(device_get_name(sc->sc_dev), +// device_get_unit(sc->sc_dev), "skipslot", &pass) == 0) { +// if (pass == slot) +// return (0); +// } + + uint32 cfgval; + if (bridge->bus == bus) { + /* + * No slots less than 11 on the primary bus + */ + if (slot < 11) + return (0); + + cfgval = (1 << slot) | (function << 8) | (offset & 0xfc); + } else { + cfgval = (bus << 16) | (slot << 11) | (function << 8) | + (offset & 0xfc) | 1; + } + + do { + out32rb(bridge->address_registers, cfgval); + } while (in32rb(bridge->address_registers) != cfgval); + + return (1); +} + + +// #pragma mark - + +status_t +ppc_openfirmware_probe_uninorth(int deviceNode, + const StringArrayPropertyValue &compatibleValue) +{ + if (!compatibleValue.ContainsElement("uni-north")) + return B_ERROR; + + uint32 reg[2]; + if (of_getprop(deviceNode, "reg", reg, sizeof(reg)) < 8) + return B_ERROR; + + uint32 busrange[2]; + if (of_getprop(deviceNode, "bus-range", busrange, sizeof(busrange)) != 8) + return B_ERROR; + + uninorth_host_bridge *bridge + = (uninorth_host_bridge*)malloc(sizeof(uninorth_host_bridge)); + if (!bridge) + return B_NO_MEMORY; + + bridge->device_node = deviceNode; + bridge->address_registers = reg[0] + 0x800000; + bridge->data_registers = reg[0] + 0xc00000; + bridge->bus = busrange[0]; +// TODO: Check whether address and data registers have already been mapped by +// the Open Firmware. If not, map them ourselves. + + memset(bridge->ranges, 0, sizeof(bridge->ranges)); + int bytesRead = of_getprop(deviceNode, "ranges", bridge->ranges, + sizeof(bridge->ranges)); + + if (bytesRead < 0) { + dprintf("ppc_openfirmware_probe_uninorth: Could not get ranges.\n"); + return B_ERROR; + } + bridge->range_count = bytesRead / sizeof(uninorth_range); + + uninorth_range *ioRange = NULL; + uninorth_range *memoryRanges[2]; + int memoryRangeCount = 0; + + for (int i = 0; i < bridge->range_count; i++) { + uninorth_range *range = bridge->ranges + i; + switch (range->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) { + case OFW_PCI_PHYS_HI_SPACE_CONFIG: + break; + case OFW_PCI_PHYS_HI_SPACE_IO: + ioRange = range; + break; + case OFW_PCI_PHYS_HI_SPACE_MEM32: + memoryRanges[memoryRangeCount++] = range; + break; + case OFW_PCI_PHYS_HI_SPACE_MEM64: + break; + } + } + + if (ioRange == NULL) { + dprintf("ppc_openfirmware_probe_uninorth: Can't find io range.\n"); + return B_ERROR; + } + + if (memoryRangeCount == 0) { + dprintf("ppc_openfirmware_probe_uninorth: Can't find mem ranges.\n"); + return B_ERROR; + } + + status_t error = pci_controller_add(&sUniNorthPCIController, bridge); + if (error != B_OK) + free(bridge); + return error; +} diff --git a/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_controller.cpp b/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_controller.cpp index d306e9b994..67643c741a 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_controller.cpp +++ b/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_controller.cpp @@ -1,10 +1,20 @@ #include "pci_controller.h" + +#include + #include "pci_priv.h" +#include "openfirmware/pci_openfirmware.h" + status_t pci_controller_init(void) { + switch (PPCPlatform::Default()->PlatformType()) { + case PPC_PLATFORM_OPEN_FIRMWARE: + return ppc_openfirmware_pci_controller_init(); + break; + } return B_OK; } diff --git a/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_io.c b/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_io.c index 8e221029ea..4abb2fd8b3 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_io.c +++ b/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_io.c @@ -1,3 +1,4 @@ +#include "pci_io.h" #include "pci_priv.h" status_t @@ -10,37 +11,40 @@ pci_io_init() uint8 pci_read_io_8(int mapped_io_addr) { - return 0; + return ppc_in8((vuint8*)mapped_io_addr); } void pci_write_io_8(int mapped_io_addr, uint8 value) { + ppc_out8((vuint8*)mapped_io_addr, value); } uint16 pci_read_io_16(int mapped_io_addr) { - return 0; + return ppc_in16((vuint16*)mapped_io_addr); } void pci_write_io_16(int mapped_io_addr, uint16 value) { + ppc_out16((vuint16*)mapped_io_addr, value); } uint32 pci_read_io_32(int mapped_io_addr) { - return 0; + return ppc_in32((vuint32*)mapped_io_addr); } void pci_write_io_32(int mapped_io_addr, uint32 value) { + ppc_out32((vuint32*)mapped_io_addr, value); } diff --git a/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_io.h b/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_io.h new file mode 100644 index 0000000000..a0bf8e82de --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_io.h @@ -0,0 +1,97 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#ifndef PCI_BUS_MANAGER_PPC_IO_H +#define PCI_BUS_MANAGER_PPC_IO_H + +#include + +static inline void +ppc_out8(vuint8 *address, uint8 value) +{ + *address = value; + asm volatile("eieio; sync"); +} + + +static inline void +ppc_out16(vuint16 *address, uint16 value) +{ + *address = value; + asm volatile("eieio; sync"); +} + + +static inline void +ppc_out16_reverse(vuint16 *address, uint16 value) +{ + asm volatile("sthbrx %1, 0, %0" : : "r"(address), "r"(value)); + asm volatile("eieio; sync"); +} + + +static inline void +ppc_out32(vuint32 *address, uint32 value) +{ + *address = value; + asm volatile("eieio; sync"); +} + + +static inline void +ppc_out32_reverse(vuint32 *address, uint32 value) +{ + asm volatile("stwbrx %1, 0, %0" : : "r"(address), "r"(value)); + asm volatile("eieio; sync"); +} + + +static inline uint8 +ppc_in8(const vuint8 *address) +{ + uint8 value = *address; + asm volatile("eieio; sync"); + return value; +} + + +static inline uint16 +ppc_in16(const vuint16 *address) +{ + uint16 value = *address; + asm volatile("eieio; sync"); + return value; +} + + +static inline uint16 +ppc_in16_reverse(const vuint16 *address) +{ + uint16 value; + asm volatile("lhbrx %0, 0, %1" : "=r"(value) : "r"(address)); + asm volatile("eieio; sync"); + return value; +} + + +static inline uint32 +ppc_in32(const vuint32 *address) +{ + uint32 value = *address; + asm volatile("eieio; sync"); + return value; +} + + +static inline uint32 +ppc_in32_reverse(const vuint32 *address) +{ + uint32 value; + asm volatile("lwbrx %0, 0, %1" : "=r"(value) : "r"(address)); + asm volatile("eieio; sync"); + return value; +} + +#endif // PCI_BUS_MANAGER_PPC_IO_H