From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:54519) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UZMv2-0008T8-Ke for qemu-devel@nongnu.org; Mon, 06 May 2013 11:01:42 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UZMv0-0000cl-CX for qemu-devel@nongnu.org; Mon, 06 May 2013 11:01:36 -0400 Message-ID: <5187C5CA.2060805@suse.de> Date: Mon, 06 May 2013 17:01:30 +0200 From: Alexander Graf MIME-Version: 1.0 References: <1367525344-7755-1-git-send-email-hpoussin@reactos.org> <1367525344-7755-2-git-send-email-hpoussin@reactos.org> <30C12B1E-5007-4B74-9A14-8F21C2D1F369@suse.de> <518351BA.1060603@reactos.org> In-Reply-To: <518351BA.1060603@reactos.org> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [Qemu-ppc] [PATCH 1/7] pci: add MPC105 PCI host bridge emulation List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: =?UTF-8?B?SGVydsOpIFBvdXNzaW5lYXU=?= Cc: "qemu-ppc@nongnu.org" , "qemu-devel@nongnu.org" , =?UTF-8?B?QW5kcmVhcyBGw6RyYmVy?= On 05/03/2013 07:57 AM, Herv=C3=A9 Poussineau wrote: > Alexander Graf a =C3=A9crit : >> >> Am 02.05.2013 um 22:08 schrieb Herv=C3=A9 Poussineau : >> >>> 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=20 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=20 > be removed easily once OpenBIOS has this logic. I'd prefer if we could come up with a clean model from the start. It=20 really shouldn't be hard at all. > >> >>> Signed-off-by: Herv=C3=A9 Poussineau >>> --- >>> default-configs/ppc-softmmu.mak | 1 + >>> hw/pci-host/Makefile.objs | 1 + >>> hw/pci-host/mpc105.c | 488=20 >>> +++++++++++++++++++++++++++++++++++++++ >>> 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=20 >>> 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=3Dy >>> CONFIG_MAC_DBDMA=3Dy >>> CONFIG_HEATHROW_PIC=3Dy >>> CONFIG_GRACKLE_PCI=3Dy >>> +CONFIG_MPC105_PCI=3Dy >>> CONFIG_UNIN_PCI=3Dy >>> CONFIG_DEC_PCI=3Dy >>> CONFIG_PPCE500_PCI=3Dy >>> 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 +=3D pam.o >>> # PPC devices >>> common-obj-$(CONFIG_PREP_PCI) +=3D prep.o >>> common-obj-$(CONFIG_GRACKLE_PCI) +=3D grackle.o >>> +common-obj-$(CONFIG_MPC105_PCI) +=3D mpc105.o >>> # NewWorld PowerMac >>> common-obj-$(CONFIG_UNIN_PCI) +=3D uninorth.o >>> common-obj-$(CONFIG_DEC_PCI) +=3D 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=C3=A9 Poussineau >>> + * >>> + * This program is free software: you can redistribute it and/or=20 >>> modify >>> + * it under the terms of the GNU General Public License as=20 >>> 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=20 >>> . >>> + */ >>> + >>> +#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=20 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,=20 >>> uint64_t data, >>> + unsigned int size) >>> +{ >>> + trace_mpc105_unassigned_mem_write(addr, data); >>> +} >>> + >>> +static const MemoryRegionOps mpc105_unassigned_ops =3D { >>> + .read =3D mpc105_unassigned_read, >>> + .write =3D 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 =3D PCI_DEVICE(s)->config; >>> + cfg1 =3D pci_get_long(pci_conf + MEM_CFG_1); >>> + >>> + memory_region_transaction_begin(); >>> + if (cfg1 & MEM_CFG_1_MEMGO) { >>> + en =3D pci_get_byte(pci_conf + MEM_BANK_EN); >>> + } else { >>> + en =3D 0; >>> + } >>> + >>> + for (i =3D 0; i < 8; i++) { >>> + enabled =3D (en & (1 << i)); >>> + >>> + start =3D pci_get_byte(pci_conf + MEM_STA_03 + i); >>> + ext_start =3D pci_get_byte(pci_conf + EXT_MEM_STA_03 + i) & = 0x3; >>> + end =3D pci_get_byte(pci_conf + MEM_END_03 + i); >>> + ext_end =3D pci_get_byte(pci_conf + EXT_MEM_STA_03 + i) & 0x= 3; >>> + start_address =3D (ext_start << 28) | (start << 20); >>> + end_address =3D (ext_end << 28) | (end << 20) | 0xfffff; >>> + >>> + enabled &=3D start_address < end_address; >>> + >>> + if (enabled) { >>> + trace_mpc105_simm_enable(i, start_address, end_address=20 >>> + 1); >>> + } else { >>> + trace_mpc105_simm_disable(i); >>> + } >>> + >>> + simm_size =3D memory_region_size(&s->simm[i]); >>> + if (simm_size =3D=3D 0) { >>> + continue; >>> + } >>> + >>> + /* Clean links between system memory, sizer and simm */ >>> + if (s->use_sizer[i]) { >>> + memory_region_del_subregion(get_system_memory(),=20 >>> &s->sizer[i]); >>> + memory_region_del_subregion(&s->sizer[i], &s->simm[i]); >>> + s->use_sizer[i] =3D false; >>> + } else { >>> + memory_region_del_subregion(get_system_memory(),=20 >>> &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],=20 >>> &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(),=20 >>> start_address, >>> + &s->sizer[i]); >>> + s->use_sizer[i] =3D true; >>> + } else { >>> + memory_region_add_subregion(get_system_memory(),=20 >>> 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,=20 >>> uint32_t val, >>> + int l) >>> +{ >>> + Mpc105State *s =3D MPC105(dev); >>> + >>> + pci_default_write_config(dev, addr, val, l); >>> + if ((addr >=3D MEM_STA_03 && addr <=3D MEM_BANK_EN) || addr =3D=3D= =20 >>> MEM_CFG_1) { >>> + mpc105_update_memory_mappings(s); >>> + } >>> +} >>> + >>> +static void mpc105_reset(Mpc105State *s) >>> +{ >>> + PCIDevice *pci =3D PCI_DEVICE(s); >>> + uint8_t *pci_conf; >>> + int id; >>> + >>> + pci_conf =3D pci->config; >>> + >>> + memset(pci_conf + PCI_CONFIG_HEADER_SIZE, 0, >>> + PCI_CONFIG_SPACE_SIZE - PCI_CONFIG_HEADER_SIZE); >>> + pci_conf[PCI_COMMAND] =3D PCI_COMMAND_MASTER | PCI_COMMAND_MEMOR= Y; >>> + pci_conf[PCI_STATUS] =3D 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=20 >>> + 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 =3D 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 =3D 0, end_address =3D 0; >>> + uint8_t ext_start, ext_end, enabled =3D 0; >>> + int i; >>> + for (i =3D 0; i < 8; i++) { >>> + if (!memory_region_size(&s->simm[i])) { >>> + continue; >>> + } >>> + end_address +=3D memory_region_size(&s->simm[i]); >>> + ext_start =3D pci_get_byte(pci_conf + EXT_MEM_STA_03 + i= )=20 >>> & ~0x3; >>> + ext_end =3D pci_get_byte(pci_conf + EXT_MEM_STA_03 + i) = &=20 >>> ~0x3; >>> + ext_start |=3D (start_address >> 28) & 0x3; >>> + ext_end |=3D ((end_address - 1) >> 28) & 0x3; >>> + pci_set_byte(pci_conf + MEM_STA_03 + i, start_address=20 >>> >> 20); >>> + pci_set_byte(pci_conf + EXT_MEM_STA_03 + i, ext_start); >>> + pci_set_byte(pci_conf + MEM_END_03 + i, (end_address -=20 >>> 1) >> 20); >>> + pci_set_byte(pci_conf + EXT_MEM_END_03 + i, ext_end); >>> + start_address =3D end_address; >>> + enabled |=3D 1 << i; >>> + } >>> + pci_set_byte(pci_conf + MEM_BANK_EN, enabled); >>> + pci_long_test_and_set_mask(pci_conf + MEM_CFG_1,=20 >>> MEM_CFG_1_MEMGO); >>> + mpc105_update_memory_mappings(s); >>> + } >>> +} >>> + >>> +static void qdev_mpc105_reset(DeviceState *dev) >>> +{ >>> + Mpc105State *s =3D MPC105(dev); >>> + mpc105_reset(s); >>> +} >>> + >>> +static int mpc105_post_load(void *opaque, int version_id) >>> +{ >>> + Mpc105State *s =3D opaque; >>> + mpc105_update_memory_mappings(s); >>> + return 0; >>> +} >>> + >>> +static const VMStateDescription vmstate_mpc105 =3D { >>> + .name =3D "mpc105", >>> + .version_id =3D 1, >>> + .minimum_version_id =3D 0, >>> + .minimum_version_id_old =3D 1, >>> + .post_load =3D mpc105_post_load, >>> + .fields =3D (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 =3D { >>> + .read =3D mpc105_intack_read, >>> + .valid =3D { >>> + .max_access_size =3D 1, >>> + }, >>> +}; >>> + >>> +static int mpc105_initfn(PCIDevice *dev) >>> +{ >>> + Mpc105State *s =3D MPC105(dev); >>> + char *filename; >>> + int bios_size =3D -1; >>> + int i =3D 0; >>> + uint32_t simm_size[8] =3D { 0 }; >>> + >>> + unsigned int ram_size =3D s->ram_size / (1024 * 1024); >>> + while (i < 8) { >>> + int idx =3D qemu_fls(ram_size); >>> + if (idx < 5) { >>> + /* Need at least 16 Mb for a slot */ >>> + break; >>> + } else if (idx >=3D 8) { >>> + /* Limit to 128 Mb by slot (at max) */ >>> + idx =3D 8; >>> + } >>> + simm_size[i] =3D 1 << (idx - 1); >>> + ram_size -=3D simm_size[i]; >>> + i++; >>> + } >>> + >>> + for (i =3D 0; i < 8; i++) { >>> + char name[] =3D "simm.?"; >>> + name[5] =3D 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(),=20 >>> (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=20 > 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 =3D qemu_find_file(QEMU_FILE_TYPE_BIOS, s->bios_nam= e); >>> + if (filename) { >>> + if (s->elf_machine !=3D EM_NONE) { >> >> Elf machine? > > Yes, like EM_PPC, required by function load_elf below. to make the device target agnostic. Works for me :). Alex