From 906b28a9acbc46452027a76b24ca8a00ca70ef64 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 26 Jan 2006 15:21:31 +0000 Subject: [PATCH] Added some PPC support to the PCI bus manager. We scan the Open Firmware device tree for PCI controllers and make them known to the bus manager, if we know how to talk with them. ATM we support only the UniNorth chip, which can be found in G4 Macs (code ported from FreeBSD). As far as I can judge it, all attached devices are identified correctly on all three host bridges of my Mac mini. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16102 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/platform/openfirmware/pci.h | 112 +++++++ .../kernel/bus_managers/pci/arch/ppc/Jamfile | 8 +- .../ppc/openfirmware/pci_openfirmware.cpp | 106 +++++++ .../arch/ppc/openfirmware/pci_openfirmware.h | 13 + .../ppc/openfirmware/pci_openfirmware_priv.h | 50 +++ .../pci/arch/ppc/openfirmware/uninorth.cpp | 284 ++++++++++++++++++ .../pci/arch/ppc/pci_controller.cpp | 10 + .../kernel/bus_managers/pci/arch/ppc/pci_io.c | 10 +- .../kernel/bus_managers/pci/arch/ppc/pci_io.h | 97 ++++++ 9 files changed, 686 insertions(+), 4 deletions(-) create mode 100644 headers/private/kernel/platform/openfirmware/pci.h create mode 100644 src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/pci_openfirmware.cpp create mode 100644 src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/pci_openfirmware.h create mode 100644 src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/pci_openfirmware_priv.h create mode 100644 src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/uninorth.cpp create mode 100644 src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_io.h 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