From: Alexander Graf <agraf@suse.de>
To: "Hervé Poussineau" <hpoussin@reactos.org>
Cc: "qemu-ppc@nongnu.org" <qemu-ppc@nongnu.org>,
"qemu-devel@nongnu.org" <qemu-devel@nongnu.org>,
"Andreas Färber" <afaerber@suse.de>
Subject: Re: [Qemu-devel] [Qemu-ppc] [PATCH 1/7] pci: add MPC105 PCI host bridge emulation
Date: Mon, 06 May 2013 17:01:30 +0200 [thread overview]
Message-ID: <5187C5CA.2060805@suse.de> (raw)
In-Reply-To: <518351BA.1060603@reactos.org>
On 05/03/2013 07:57 AM, Hervé Poussineau wrote:
> Alexander Graf a écrit :
>>
>> Am 02.05.2013 um 22:08 schrieb Hervé Poussineau <hpoussin@reactos.org>:
>>
>>> Non-contiguous I/O is not implemented.
>>>
>>> There is also somewhere a bug in the memory controller, which means
>>> that some real firmwares may not detect the correct amount of memory.
>>> This can be bypassed by adding '-m 1G' on the command line.
>>>
>>> Add x-auto-conf property, to automatically configure the memory
>>> controller at startup. This will be required by OpenBIOS, which
>>> doesn't know how to do it.
>>
>> Why not teach it? I'd prefer to see that logic in firmware.
>
> Me too, but I'm not confident enough in my capabilities to do it.
Huh? Why not? Most of the device initialization code in OpenBIOS happens
in C, so you don't even have to touch Forth code :).
> Autoconfiguration is only in one place of the code, so I think it can
> be removed easily once OpenBIOS has this logic.
I'd prefer if we could come up with a clean model from the start. It
really shouldn't be hard at all.
>
>>
>>> Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
>>> ---
>>> default-configs/ppc-softmmu.mak | 1 +
>>> hw/pci-host/Makefile.objs | 1 +
>>> hw/pci-host/mpc105.c | 488
>>> +++++++++++++++++++++++++++++++++++++++
>>> include/hw/pci/pci_ids.h | 1 +
>>> trace-events | 7 +
>>> 5 files changed, 498 insertions(+)
>>> create mode 100644 hw/pci-host/mpc105.c
>>>
>>> diff --git a/default-configs/ppc-softmmu.mak
>>> b/default-configs/ppc-softmmu.mak
>>> index cc3587f..f79b058 100644
>>> --- a/default-configs/ppc-softmmu.mak
>>> +++ b/default-configs/ppc-softmmu.mak
>>> @@ -28,6 +28,7 @@ CONFIG_MAC_NVRAM=y
>>> CONFIG_MAC_DBDMA=y
>>> CONFIG_HEATHROW_PIC=y
>>> CONFIG_GRACKLE_PCI=y
>>> +CONFIG_MPC105_PCI=y
>>> CONFIG_UNIN_PCI=y
>>> CONFIG_DEC_PCI=y
>>> CONFIG_PPCE500_PCI=y
>>> diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs
>>> index 909e702..ec4427b 100644
>>> --- a/hw/pci-host/Makefile.objs
>>> +++ b/hw/pci-host/Makefile.objs
>>> @@ -3,6 +3,7 @@ common-obj-y += pam.o
>>> # PPC devices
>>> common-obj-$(CONFIG_PREP_PCI) += prep.o
>>> common-obj-$(CONFIG_GRACKLE_PCI) += grackle.o
>>> +common-obj-$(CONFIG_MPC105_PCI) += mpc105.o
>>> # NewWorld PowerMac
>>> common-obj-$(CONFIG_UNIN_PCI) += uninorth.o
>>> common-obj-$(CONFIG_DEC_PCI) += dec.o
>>> diff --git a/hw/pci-host/mpc105.c b/hw/pci-host/mpc105.c
>>> new file mode 100644
>>> index 0000000..8e4cc95
>>> --- /dev/null
>>> +++ b/hw/pci-host/mpc105.c
>>> @@ -0,0 +1,488 @@
>>> +/*
>>> + * QEMU MPC-105 Eagle PCI host
>>> + *
>>> + * Copyright (c) 2013 Hervé Poussineau
>>> + *
>>> + * This program is free software: you can redistribute it and/or
>>> modify
>>> + * it under the terms of the GNU General Public License as
>>> published by
>>> + * the Free Software Foundation, either version 2 of the License, or
>>> + * (at your option) version 3 or any later version.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>>> + * GNU General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU General Public License
>>> + * along with this program. If not, see
>>> <http://www.gnu.org/licenses/>.
>>> + */
>>> +
>>> +#include "hw/pci/pci.h"
>>> +#include "hw/pci/pci_bus.h"
>>> +#include "hw/pci/pci_host.h"
>>> +#include "hw/i386/pc.h"
>>
>> That include sounds odd :).
>
> Sure, but you need to access pic_read_irq() :)
> hw/pci-host/prep.c also includes it.
Phew. Would be a good thing to pull out of there. But it's out of the
scope for this set.
>
>>
>>> +#include "hw/loader.h"
>>> +#include "exec/address-spaces.h"
>>> +#include "elf.h"
>>> +#include "trace.h"
>>> +
>>> +#define TYPE_MPC105_PCI_HOST_BRIDGE "mpc105-pcihost"
>>> +#define MPC105_PCI_HOST_BRIDGE(obj) \
>>> + OBJECT_CHECK(Mpc105HostState, (obj), TYPE_MPC105_PCI_HOST_BRIDGE)
>>> +
>>> +#define TYPE_MPC105 "mpc105"
>>> +#define MPC105(obj) \
>>> + OBJECT_CHECK(Mpc105State, (obj), TYPE_MPC105)
>>> +
>>> +#define MEM_STA_03 0x0080
>>> +#define MEM_STA_47 0x0084
>>> +#define EXT_MEM_STA_03 0x0088
>>> +#define EXT_MEM_STA_47 0x008c
>>> +#define MEM_END_03 0x0090
>>> +#define MEM_END_47 0x0094
>>> +#define EXT_MEM_END_03 0x0098
>>> +#define EXT_MEM_END_47 0x009c
>>> +#define MEM_BANK_EN 0x00a0
>>> +#define PROC_CFG_A8 0x00a8
>>> +#define PROC_CFG_AC 0x00ac
>>> +#define ALT_OSV_1 0x00ba
>>> +#define ERR_EN_REG1 0x00c0
>>> +#define ERR_DR1 0x00c1
>>> +#define ERR_EN_REG2 0x00c4
>>> +#define MEM_CFG_1 0x00f0
>>> +#define MEM_CFG_2 0x00f4
>>> +#define MEM_CFG_4 0x00fc
>>> +
>>> +#define MEM_CFG_1_MEMGO (1 << 19)
>>> +
>>> +#define BIOS_SIZE (1024 * 1024)
>>> +
>>> +typedef struct Mpc105State {
>>> + PCIDevice parent_obj;
>>> + uint32_t ram_size;
>>> + uint32_t elf_machine;
>>> + uint32_t x_auto_conf;
>>> + char *bios_name;
>>> + MemoryRegion bios;
>>> + MemoryRegion simm[8];
>>> + bool use_sizer[8];
>>> + /* use a sizer to allow access to only part of a simm */
>>> + MemoryRegion sizer[8];
>>> +} Mpc105State;
>>> +
>>> +static uint64_t mpc105_unassigned_read(void *opaque, hwaddr addr,
>>> + unsigned int size)
>>> +{
>>> + trace_mpc105_unassigned_mem_read(addr);
>>> + return 0;
>>> +}
>>> +
>>> +static void mpc105_unassigned_write(void *opaque, hwaddr addr,
>>> uint64_t data,
>>> + unsigned int size)
>>> +{
>>> + trace_mpc105_unassigned_mem_write(addr, data);
>>> +}
>>> +
>>> +static const MemoryRegionOps mpc105_unassigned_ops = {
>>> + .read = mpc105_unassigned_read,
>>> + .write = mpc105_unassigned_write,
>>> +};
>>> +
>>> +static void mpc105_update_memory_mappings(Mpc105State *s)
>>> +{
>>> + uint32_t start_address, end_address;
>>> + uint32_t start, ext_start, end, ext_end;
>>> + uint32_t cfg1;
>>> + uint64_t simm_size;
>>> + uint8_t *pci_conf;
>>> + uint8_t en;
>>> + bool enabled;
>>> + int i;
>>> +
>>> + pci_conf = PCI_DEVICE(s)->config;
>>> + cfg1 = pci_get_long(pci_conf + MEM_CFG_1);
>>> +
>>> + memory_region_transaction_begin();
>>> + if (cfg1 & MEM_CFG_1_MEMGO) {
>>> + en = pci_get_byte(pci_conf + MEM_BANK_EN);
>>> + } else {
>>> + en = 0;
>>> + }
>>> +
>>> + for (i = 0; i < 8; i++) {
>>> + enabled = (en & (1 << i));
>>> +
>>> + start = pci_get_byte(pci_conf + MEM_STA_03 + i);
>>> + ext_start = pci_get_byte(pci_conf + EXT_MEM_STA_03 + i) & 0x3;
>>> + end = pci_get_byte(pci_conf + MEM_END_03 + i);
>>> + ext_end = pci_get_byte(pci_conf + EXT_MEM_STA_03 + i) & 0x3;
>>> + start_address = (ext_start << 28) | (start << 20);
>>> + end_address = (ext_end << 28) | (end << 20) | 0xfffff;
>>> +
>>> + enabled &= start_address < end_address;
>>> +
>>> + if (enabled) {
>>> + trace_mpc105_simm_enable(i, start_address, end_address
>>> + 1);
>>> + } else {
>>> + trace_mpc105_simm_disable(i);
>>> + }
>>> +
>>> + simm_size = memory_region_size(&s->simm[i]);
>>> + if (simm_size == 0) {
>>> + continue;
>>> + }
>>> +
>>> + /* Clean links between system memory, sizer and simm */
>>> + if (s->use_sizer[i]) {
>>> + memory_region_del_subregion(get_system_memory(),
>>> &s->sizer[i]);
>>> + memory_region_del_subregion(&s->sizer[i], &s->simm[i]);
>>> + s->use_sizer[i] = false;
>>> + } else {
>>> + memory_region_del_subregion(get_system_memory(),
>>> &s->simm[i]);
>>> + }
>>> +
>>> + /* Recreate links compatible with new memory layout */
>>> + if (enabled && end_address - start_address + 1 < simm_size) {
>>> + memory_region_init_io(&s->sizer[i],
>>> &mpc105_unassigned_ops,
>>> + s, memory_region_name(&s->sizer[i]),
>>> + end_address - start_address + 1);
>>> + memory_region_add_subregion(&s->sizer[i], 0, &s->simm[i]);
>>> + memory_region_add_subregion(get_system_memory(),
>>> start_address,
>>> + &s->sizer[i]);
>>> + s->use_sizer[i] = true;
>>> + } else {
>>> + memory_region_add_subregion(get_system_memory(),
>>> start_address,
>>> + &s->simm[i]);
>>> + }
>>> + memory_region_set_enabled(&s->simm[i], enabled);
>>> + }
>>> + memory_region_transaction_commit();
>>> +}
>>> +
>>> +static void mpc105_write_config(PCIDevice *dev, uint32_t addr,
>>> uint32_t val,
>>> + int l)
>>> +{
>>> + Mpc105State *s = MPC105(dev);
>>> +
>>> + pci_default_write_config(dev, addr, val, l);
>>> + if ((addr >= MEM_STA_03 && addr <= MEM_BANK_EN) || addr ==
>>> MEM_CFG_1) {
>>> + mpc105_update_memory_mappings(s);
>>> + }
>>> +}
>>> +
>>> +static void mpc105_reset(Mpc105State *s)
>>> +{
>>> + PCIDevice *pci = PCI_DEVICE(s);
>>> + uint8_t *pci_conf;
>>> + int id;
>>> +
>>> + pci_conf = pci->config;
>>> +
>>> + memset(pci_conf + PCI_CONFIG_HEADER_SIZE, 0,
>>> + PCI_CONFIG_SPACE_SIZE - PCI_CONFIG_HEADER_SIZE);
>>> + pci_conf[PCI_COMMAND] = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
>>> + pci_conf[PCI_STATUS] = PCI_STATUS_FAST_BACK;
>>> + pci_set_long(pci_conf + PROC_CFG_A8, 0xff000010);
>>> + pci_set_long(pci_conf + PROC_CFG_AC, 0x000c060c);
>>> + pci_set_byte(pci_conf + ALT_OSV_1, 0x04);
>>> + pci_set_byte(pci_conf + ERR_EN_REG1, 0x01);
>>> + pci_set_long(pci_conf + MEM_CFG_1, 0xff020000);
>>> + pci_set_long(pci_conf + MEM_CFG_2, 0x00000003);
>>> + pci_set_long(pci_conf + MEM_CFG_4, 0x00100000);
>>> +
>>> + memset(pci->wmask + PCI_CONFIG_HEADER_SIZE, 0,
>>> + MEM_CFG_1 - PCI_CONFIG_HEADER_SIZE);
>>> + memset(pci->wmask + 0x70, 0xff, 2);
>>> + memset(pci->wmask + MEM_STA_03, 0xff, MEM_BANK_EN - MEM_STA_03
>>> + 1);
>>> + memset(pci->wmask + PROC_CFG_A8, 0xff, 8);
>>> + pci_set_word(pci->wmask + ALT_OSV_1, 0xffff);
>>> + pci_set_byte(pci->wmask + ERR_EN_REG1, 0xff);
>>> + pci_set_byte(pci->w1cmask + ERR_DR1, 0xff);
>>> + pci_set_byte(pci->w1cmask + 0xc3, 0xff);
>>> + pci_set_byte(pci->wmask + ERR_EN_REG2, 0xff);
>>> + pci_set_byte(pci->w1cmask + 0xc5, 0xff);
>>> + pci_set_byte(pci->w1cmask + 0xc7, 0xff);
>>> +
>>> + for (id = 0; id < 8; ++id) {
>>> + memory_region_set_enabled(&s->simm[id], false);
>>> + }
>>> +
>>> + if (s->x_auto_conf) {
>>> + /* enable all memory banks, starting from address 0 */
>>> + uint32_t start_address = 0, end_address = 0;
>>> + uint8_t ext_start, ext_end, enabled = 0;
>>> + int i;
>>> + for (i = 0; i < 8; i++) {
>>> + if (!memory_region_size(&s->simm[i])) {
>>> + continue;
>>> + }
>>> + end_address += memory_region_size(&s->simm[i]);
>>> + ext_start = pci_get_byte(pci_conf + EXT_MEM_STA_03 + i)
>>> & ~0x3;
>>> + ext_end = pci_get_byte(pci_conf + EXT_MEM_STA_03 + i) &
>>> ~0x3;
>>> + ext_start |= (start_address >> 28) & 0x3;
>>> + ext_end |= ((end_address - 1) >> 28) & 0x3;
>>> + pci_set_byte(pci_conf + MEM_STA_03 + i, start_address
>>> >> 20);
>>> + pci_set_byte(pci_conf + EXT_MEM_STA_03 + i, ext_start);
>>> + pci_set_byte(pci_conf + MEM_END_03 + i, (end_address -
>>> 1) >> 20);
>>> + pci_set_byte(pci_conf + EXT_MEM_END_03 + i, ext_end);
>>> + start_address = end_address;
>>> + enabled |= 1 << i;
>>> + }
>>> + pci_set_byte(pci_conf + MEM_BANK_EN, enabled);
>>> + pci_long_test_and_set_mask(pci_conf + MEM_CFG_1,
>>> MEM_CFG_1_MEMGO);
>>> + mpc105_update_memory_mappings(s);
>>> + }
>>> +}
>>> +
>>> +static void qdev_mpc105_reset(DeviceState *dev)
>>> +{
>>> + Mpc105State *s = MPC105(dev);
>>> + mpc105_reset(s);
>>> +}
>>> +
>>> +static int mpc105_post_load(void *opaque, int version_id)
>>> +{
>>> + Mpc105State *s = opaque;
>>> + mpc105_update_memory_mappings(s);
>>> + return 0;
>>> +}
>>> +
>>> +static const VMStateDescription vmstate_mpc105 = {
>>> + .name = "mpc105",
>>> + .version_id = 1,
>>> + .minimum_version_id = 0,
>>> + .minimum_version_id_old = 1,
>>> + .post_load = mpc105_post_load,
>>> + .fields = (VMStateField[]) {
>>> + VMSTATE_PCI_DEVICE(parent_obj, Mpc105State),
>>> + VMSTATE_END_OF_LIST()
>>> + }
>>> +};
>>> +
>>> +static uint64_t mpc105_intack_read(void *opaque, hwaddr addr,
>>> + unsigned int size)
>>> +{
>>> + return pic_read_irq(isa_pic);
>>> +}
>>> +
>>> +static const MemoryRegionOps mpc105_intack_ops = {
>>> + .read = mpc105_intack_read,
>>> + .valid = {
>>> + .max_access_size = 1,
>>> + },
>>> +};
>>> +
>>> +static int mpc105_initfn(PCIDevice *dev)
>>> +{
>>> + Mpc105State *s = MPC105(dev);
>>> + char *filename;
>>> + int bios_size = -1;
>>> + int i = 0;
>>> + uint32_t simm_size[8] = { 0 };
>>> +
>>> + unsigned int ram_size = s->ram_size / (1024 * 1024);
>>> + while (i < 8) {
>>> + int idx = qemu_fls(ram_size);
>>> + if (idx < 5) {
>>> + /* Need at least 16 Mb for a slot */
>>> + break;
>>> + } else if (idx >= 8) {
>>> + /* Limit to 128 Mb by slot (at max) */
>>> + idx = 8;
>>> + }
>>> + simm_size[i] = 1 << (idx - 1);
>>> + ram_size -= simm_size[i];
>>> + i++;
>>> + }
>>> +
>>> + for (i = 0; i < 8; i++) {
>>> + char name[] = "simm.?";
>>> + name[5] = i + '0';
>>> + if (simm_size[i]) {
>>> + trace_mpc105_simm_size(i, simm_size[i]);
>>> + memory_region_init_ram(&s->simm[i], name,
>>> + simm_size[i] * 1024 * 1024);
>>> + vmstate_register_ram_global(&s->simm[i]);
>>> + } else {
>>> + memory_region_init(&s->simm[i], name, 0);
>>> + }
>>> + memory_region_init(&s->sizer[i], "sizer", 0);
>>> + memory_region_add_subregion_overlap(get_system_memory(), 0,
>>> + &s->simm[i], i);
>>> + memory_region_set_enabled(&s->simm[i], false);
>>> + }
>>> +
>>> + memory_region_init_ram(&s->bios, "bios", BIOS_SIZE);
>>> + memory_region_set_readonly(&s->bios, true);
>>> + memory_region_add_subregion(get_system_memory(),
>>> (uint32_t)(-BIOS_SIZE),
>>> + &s->bios);
>>> + vmstate_register_ram_global(&s->bios);
>>> + if (s->bios_name) {
>>
>> Can't you just reuse the normal -bios logic?
>
> bios property is filled with -bios name in the machine init function.
> mpc105 datasheet explicity says where the bios/firmware i loaded, and
> I wanted to keep the machine init function as small as possible.
I see, you just pass it from the machine model to the device. That's fine.
>
>>
>>> + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, s->bios_name);
>>> + if (filename) {
>>> + if (s->elf_machine != EM_NONE) {
>>
>> Elf machine?
>
> Yes, like EM_PPC, required by function load_elf below.
to make the device target agnostic. Works for me :).
Alex
next prev parent reply other threads:[~2013-05-06 15:01 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-05-02 20:08 [Qemu-devel] [PATCH 0/7] ppc/prep: add IBM RS/6000 43p machine Hervé Poussineau
2013-05-02 20:08 ` [Qemu-devel] [PATCH 1/7] pci: add MPC105 PCI host bridge emulation Hervé Poussineau
2013-05-02 21:01 ` [Qemu-devel] [Qemu-ppc] " Alexander Graf
2013-05-03 5:57 ` Hervé Poussineau
2013-05-06 15:01 ` Alexander Graf [this message]
2013-05-06 20:57 ` Hervé Poussineau
2013-05-06 22:16 ` Alexander Graf
2013-05-06 22:41 ` Andreas Färber
2013-05-07 5:48 ` Hervé Poussineau
2013-05-09 17:47 ` Blue Swirl
2013-05-02 20:08 ` [Qemu-devel] [PATCH 2/7] qom: handle registration of new types when initializing the first ones Hervé Poussineau
2013-05-03 11:46 ` Andreas Färber
2013-05-05 8:38 ` Hervé Poussineau
2013-05-02 20:09 ` [Qemu-devel] [PATCH 3/7] m48t59: move ISA ports/memory regions registration to QOM constructor Hervé Poussineau
2013-05-02 20:09 ` [Qemu-devel] [PATCH 4/7] m48t59: register a QOM type for each nvram type we support Hervé Poussineau
2013-05-02 21:29 ` Artyom Tarasenko
2013-05-03 5:50 ` Hervé Poussineau
2013-05-03 23:16 ` Artyom Tarasenko
2013-05-04 5:24 ` Hervé Poussineau
2013-05-02 20:09 ` [Qemu-devel] [PATCH 5/7] m48t59: add a Nvram interface Hervé Poussineau
2013-05-02 20:09 ` [Qemu-devel] [PATCH 6/7] prep: add IBM RS/6000 7248 (43p) machine emulation Hervé Poussineau
2013-05-02 20:09 ` [Qemu-devel] [PATCH 7/7] prep: QOM'ify System I/O Hervé Poussineau
2013-05-03 11:36 ` Andreas Färber
2013-05-04 9:38 ` Hervé Poussineau
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5187C5CA.2060805@suse.de \
--to=agraf@suse.de \
--cc=afaerber@suse.de \
--cc=hpoussin@reactos.org \
--cc=qemu-devel@nongnu.org \
--cc=qemu-ppc@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.