PowerPC 4xx device emulation improvements
PATCH 1/1 PowerPC 4xx device emulation improvements
These patches improve the device emulation for PowerPC 4xx SoCs. They were tested with KVM on 440, rather than with qemu's instruction emulation (qemu doesn't emulate 440, and the 405 emulation doesn't work).
I'd especially appreciate some review of the PCI controller emulation, in particular bamboo_pci_map_irq() and bamboo_pci_set_irq().
-Hollis
PATCH 1/1 Order IRQ bit numbers as described in the UIC documentation
This is especially useful when debugging the UIC emulation.
qemu/hw/ppc405_uc.c +23 -22
@@ -2587,13 +2587,13 @@ppc405_dma_init (env, dma_irqs);/* Serial ports */ if (serial_hds[0 ] !=NULL ) { -ppc405_serial_init (env, mmio,0x300 , pic[31 ], serial_hds[0 ]); +ppc405_serial_init (env, mmio,0x300 , pic[0 ], serial_hds[0 ]); }if (serial_hds[1 ] !=NULL ) { -ppc405_serial_init (env, mmio,0x400 , pic[30 ], serial_hds[1 ]); +ppc405_serial_init (env, mmio,0x400 , pic[1 ], serial_hds[1 ]); }/* IIC controller */ -ppc405_i2c_init (env, mmio,0x500 , pic[29 ]); +ppc405_i2c_init (env, mmio,0x500 , pic[2 ]);/* GPIO */ ppc405_gpio_init (env, mmio,0x700 );/* CPU control */
@@ -2930,49 +2930,50 @@ pic =ppcuic_init (env, irqs,0x0C0 ,0 ,1 ); *picp = pic;/* SDRAM controller */ -ppc405_sdram_init (env, pic[14 ],2 , ram_bases, ram_sizes, do_init); +/* XXX 405EP has no ECC interrupt */ +ppc405_sdram_init (env, pic[17 ],2 , ram_bases, ram_sizes, do_init); offset =0 ;for (i =0 ; i <2 ; i++) offset += ram_sizes[i];/* External bus controller */ ppc405_ebc_init (env);/* DMA controller */ - dma_irqs[0 ] = pic[26 ]; - dma_irqs[1 ] = pic[25 ]; - dma_irqs[2 ] = pic[24 ]; - dma_irqs[3 ] = pic[23 ]; + dma_irqs[0 ] = pic[5 ]; + dma_irqs[1 ] = pic[6 ]; + dma_irqs[2 ] = pic[7 ]; + dma_irqs[3 ] = pic[8 ];ppc405_dma_init (env, dma_irqs);/* IIC controller */ -ppc405_i2c_init (env, mmio,0x500 , pic[29 ]); +ppc405_i2c_init (env, mmio,0x500 , pic[2 ]);/* GPIO */ ppc405_gpio_init (env, mmio,0x700 );/* Serial ports */ if (serial_hds[0 ] !=NULL ) { -ppc405_serial_init (env, mmio,0x300 , pic[31 ], serial_hds[0 ]); +ppc405_serial_init (env, mmio,0x300 , pic[0 ], serial_hds[0 ]); }if (serial_hds[1 ] !=NULL ) { -ppc405_serial_init (env, mmio,0x400 , pic[30 ], serial_hds[1 ]); +ppc405_serial_init (env, mmio,0x400 , pic[1 ], serial_hds[1 ]); }/* OCM */ ppc405_ocm_init (env, ram_sizes[0 ] + ram_sizes[1 ]); offset +=4096 ;/* GPT */ - gpt_irqs[0 ] = pic[12 ]; - gpt_irqs[1 ] = pic[11 ]; - gpt_irqs[2 ] = pic[10 ]; - gpt_irqs[3 ] = pic[9 ]; - gpt_irqs[4 ] = pic[8 ]; + gpt_irqs[0 ] = pic[19 ]; + gpt_irqs[1 ] = pic[20 ]; + gpt_irqs[2 ] = pic[21 ]; + gpt_irqs[3 ] = pic[22 ]; + gpt_irqs[4 ] = pic[23 ];ppc4xx_gpt_init (env, mmio,0x000 , gpt_irqs);/* PCI */ -/* Uses pic[28], pic[15], pic[13] */ +/* Uses pic[3], pic[16], pic[18] */ /* MAL */ - mal_irqs[0 ] = pic[20 ]; - mal_irqs[1 ] = pic[19 ]; - mal_irqs[2 ] = pic[18 ]; - mal_irqs[3 ] = pic[17 ]; + mal_irqs[0 ] = pic[11 ]; + mal_irqs[1 ] = pic[12 ]; + mal_irqs[2 ] = pic[13 ]; + mal_irqs[3 ] = pic[14 ];ppc405_mal_init (env, mal_irqs);/* Ethernet */ -/* Uses pic[22], pic[16], pic[14] */ +/* Uses pic[9], pic[15], pic[17] */ /* CPU control */ ppc405ep_cpc_init (env, clk_setup, sysclk); *offsetp = offset;
qemu/hw/ppc4xx_devs.c +1 -1
@@ -365,7 +365,7 @@uint32_t mask, sr; uic = opaque; - mask =1 << irq_num; + mask =1 << (31 -irq_num);#ifdef DEBUG_UIC if (loglevel &CPU_LOG_INT ) { fprintf(logfile, "%s: irq %d level %d uicsr %08" PRIx32
PATCH 1/1 Remember the state of level-triggered interrupts
In reply to Hollis BlanchardThis fixes the following race condition:
1. target handles an interrupt and begins to EOI
2. device raises an interrupt, setting UIC SR
3. target finishes EOI by clearing SR bit
On hardware, a device with a level-triggered interrupt would instantly re-assert SR after step 3, so we need to do the same.
qemu/hw/ppc4xx_devs.c +7 -2
@@ -278,6 +278,7 @@struct ppcuic_t {uint32_t dcr_base;int use_vectors; +uint32_t level;/* Remembers the state of level-triggered interrupts. */ uint32_t uicsr;/* Status register */ uint32_t uicer;/* Enable register */ uint32_t uiccr;/* Critical register */
@@ -385,10 +386,13 @@ uic->uicsr |= mask; }else {/* Level sensitive interrupt */ -if (level ==1 ) +if (level ==1 ) { uic->uicsr |= mask; -else + uic->level |= mask; + }else { uic->uicsr &= ~mask; + uic->level &= ~mask; + } }#ifdef DEBUG_UIC if (loglevel &CPU_LOG_INT ) {
@@ -460,6 +464,7 @@switch (dcrn) {case DCR_UICSR : uic->uicsr &= ~val; + uic->uicsr |= uic->level;ppcuic_trigger_irq (uic);break ;case DCR_UICSRS :
PATCH 1/1 Remove interrupt polarity code
In reply to Hollis BlanchardInterrupt polarity should have no functional effect, since qemu tracks logical IRQ state, not the electrical state of physical lines.
qemu/hw/ppc4xx_devs.c +1 -5
@@ -377,10 +377,7 @@if (irq_num <0 || irq_num >31 )return ; sr = uic->uicsr; -if (!(uic->uicpr & mask)) { -/* Negatively asserted IRQ */ - level = level ==0 ?1 :0 ; - } +/* Update status register */ if (uic->uictr & mask) {/* Edge sensitive interrupt */
@@ -479,7 +476,6 @@break ;case DCR_UICPR : uic->uicpr = val; -ppcuic_trigger_irq (uic);break ;case DCR_UICTR : uic->uictr = val;
PATCH 1/1 Emulate the PCI(-legacy) controller found on some 440 SoCs
In reply to Hollis Blanchardqemu/hw/ppc4xx.h +40 -0
@@ -2,6 +2,9 @@* QEMU PowerPC 4xx emulation shared definitions * * Copyright (c) 2007 Jocelyn Mayer +* +* Copyright 2008 IBM Corp. +* Authors: Hollis Blanchard <[email protected]> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal
@@ -46,4 +49,41 @@qemu_irq *ppcuic_init (CPUState *env,qemu_irq *irqs,uint32_t dcr_base,int has_ssr,int has_vr); + +struct pci_master_map { +uint32_t la; +uint32_t ma; +uint32_t pcila; +uint32_t pciha; +}; + +struct pci_target_map { +uint32_t ms; +uint32_t la; +uint32_t bar; +}; + +#define PPC44x_PCI_NR_PMMS 3 +#define PPC44x_PCI_NR_PTMS 2 + +struct ppc4xx_pci_t { +target_phys_addr_t config_space; +target_phys_addr_t registers; +struct pci_master_map pmm[PPC44x_PCI_NR_PMMS]; +struct pci_target_map ptm[PPC44x_PCI_NR_PTMS]; + +unsigned int pmm_offset_flags; +qemu_irq *pic; + +uint32_t pcic0_cfgaddr; +PCIBus *bus; +}; +typedef struct ppc4xx_pci_t ppc4xx_pci_t ; + +ppc4xx_pci_t *ppc4xx_pci_init (CPUState *env,qemu_irq *pic, +target_phys_addr_t config_space, +target_phys_addr_t int_ack, +target_phys_addr_t special_cycle, +target_phys_addr_t registers); +#endif /* !defined(PPC_4XX_H) */
qemu/hw/ppc4xx_devs.c +371 -0
386 lines not on this page · raw message
Re: [Qemu-devel] [PATCH 4 of 4] [qemu ppc pci] Emulate the PCI(-legacy) controller found on some 440 SoCs
Please find my comments inline.
Quoted 39 lines · Hollis Blanchard
Signed-off-by Hollis Blanchard <[email protected]>qemu/hw/ppc4xx.h +23
-0@@ -2,6 +2,9 @@* QEMU PowerPC 4xx emulation shared definitions * * Copyright (c) 2007 Jocelyn Mayer +* +* Copyright 2008 IBM Corp. +* Authors: Hollis Blanchard <[email protected]> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -46,4 +49,41 @@qemu_irq *ppcuic_init (CPUState *env,qemu_irq *irqs,uint32_t dcr_base,int has_ssr,int has_vr); + +struct pci_master_map { +uint32_t la; +uint32_t ma; +uint32_t pcila; +uint32_t pciha; +}; + +struct pci_target_map { +uint32_t ms; +uint32_t la; +uint32_t bar; +}; + +#define PPC44x_PCI_NR_PMMS 3 +#define PPC44x_PCI_NR_PTMS 2 + +struct ppc4xx_pci_t { +target_phys_addr_t config_space; +target_phys_addr_t registers;
qemu/hw/ppc4xx.h line 81
Quoted 10 lines
qemu/hw/ppc4xx.h +10
-0+struct pci_master_map pmm[PPC44x_PCI_NR_PMMS]; +struct pci_target_map ptm[PPC44x_PCI_NR_PTMS]; + +unsigned int pmm_offset_flags; +qemu_irq *pic; + +uint32_t pcic0_cfgaddr; +PCIBus *bus; +}; +typedef struct ppc4xx_pci_t ppc4xx_pci_t ;
Looking at the other PCI controller implementation, that could probably be PPC4xxState instead of ppc4xx_pci_t. But that's a detail.
Quoted 31 lines
qemu/hw/ppc4xx.h +7
-0+ +ppc4xx_pci_t *ppc4xx_pci_init (CPUState *env,qemu_irq *pic, +target_phys_addr_t config_space, +target_phys_addr_t int_ack, +target_phys_addr_t special_cycle, +target_phys_addr_t registers); +#endif /* !defined(PPC_4XX_H) */ qemu/hw/ppc4xx_devs.c +5
-0@@ -2,6 +2,9 @@* QEMU PowerPC 4xx embedded processors shared devices emulation * * Copyright (c) 2007 Jocelyn Mayer +* +* Copyright 2008 IBM Corp. +* Authors: Hollis Blanchard <[email protected]> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,6 +28,8 @@#include "ppc.h" #include "ppc4xx.h" #include "sysemu.h" +#include "pci.h" +#include "bswap.h" extern int loglevel;extern FILE *logfile;
qemu/hw/ppc4xx_devs.c line 548
Quoted 9 lines
qemu/hw/ppc4xx_devs.c +6
-0@@ -535,3 +540,369 @@return qemu_allocate_irqs (&ppcuic_set_irq, uic,UIC_MAX_IRQ ); } + + + + +#define PCIC0_CFGADDR 0x0 +#define PCIC0_CFGDATA 0x4
Those values are never used.
Quoted 17 lines
qemu/hw/ppc4xx_devs.c +17
-0+ +#define PCIL0_PMM0LA 0x0 +#define PCIL0_PMM0MA 0x4 +#define PCIL0_PMM0PCILA 0x8 +#define PCIL0_PMM0PCIHA 0xc +#define PCIL0_PMM1LA 0x10 +#define PCIL0_PMM1MA 0x14 +#define PCIL0_PMM1PCILA 0x18 +#define PCIL0_PMM1PCIHA 0x1c +#define PCIL0_PMM2LA 0x20 +#define PCIL0_PMM2MA 0x24 +#define PCIL0_PMM2PCILA 0x28 +#define PCIL0_PMM2PCIHA 0x2c +#define PCIL0_PTM1MS 0x30 +#define PCIL0_PTM1LA 0x34 +#define PCIL0_PTM2MS 0x38 +#define PCIL0_PTM2LA 0x3c
qemu/hw/ppc4xx_devs.c line 575
Quoted 10 lines
qemu/hw/ppc4xx_devs.c +10
-0+#define PCI_REG_SIZE 0x40 + +#define PPC44x_PCI_MA_MASK 0xfffff000 +#define PPC44x_PCI_MA_ENABLE 0x1 + + +static uint32_t pci4xx_cfgaddr_read4 (void *opaque,target_phys_addr_t addr) +{ +ppc4xx_pci_t *ppc4xx_pci = opaque; +return cpu_to_le32 (ppc4xx_pci->pcic0_cfgaddr);
This is wrong. QEMU works by passing values on the bus, and thus does not need to byteswap depending and the *host*.
If you need swap here, it's probably because the PCI controller is connected backward or does byteswapping. So you probably either want an unconditional call to bswap32() instead, or depending on TARGET_WORDS_BIGENDIAN if it is depending on the guest endianness.
qemu/hw/ppc4xx_devs.c line 582
Quoted 7 lines
qemu/hw/ppc4xx_devs.c +7
-0+} + +static CPUReadMemoryFunc *pci4xx_cfgaddr_read[] = { + &pci4xx_cfgaddr_read4, + &pci4xx_cfgaddr_read4, + &pci4xx_cfgaddr_read4, +};
It's seem usual to call use 'l', 'w', 'b' instead of '4', '2', '1'. Not really important though.
qemu/hw/ppc4xx_devs.c line 589
Quoted 6 lines
qemu/hw/ppc4xx_devs.c +6
-0+static void pci4xx_cfgaddr_write4 (void *opaque,target_phys_addr_t addr, +uint32_t value) +{ +ppc4xx_pci_t *ppc4xx_pci = opaque; + + value =le32_to_cpu (value);
endianness problem, as explained above
Quoted 28 lines
qemu/hw/ppc4xx_devs.c +28
-0+ + ppc4xx_pci->pcic0_cfgaddr = value & ~0x3 ; +} + +static CPUWriteMemoryFunc *pci4xx_cfgaddr_write[] = { + &pci4xx_cfgaddr_write4, + &pci4xx_cfgaddr_write4, + &pci4xx_cfgaddr_write4, +}; + +static uint32_t pci4xx_cfgdata_read1 (void *opaque,target_phys_addr_t addr) +{ +ppc4xx_pci_t *ppc4xx_pci = opaque; +int offset = addr &0x3 ; +uint32_t cfgaddr = ppc4xx_pci->pcic0_cfgaddr; +uint32_t value; + +if (!(cfgaddr & (1 <<31 ))) +return 0xffffffff ; + + value =pci_data_read (ppc4xx_pci->bus, cfgaddr | offset,1 ); + +return value; +} + +static uint32_t pci4xx_cfgdata_read2 (void *opaque,target_phys_addr_t addr) +{ +ppc4xx_pci_t *ppc4xx_pci = opaque;
qemu/hw/ppc4xx_devs.c line 627
Quoted 10 lines
qemu/hw/ppc4xx_devs.c +10
-0+int offset = addr &0x3 ; +uint32_t cfgaddr = ppc4xx_pci->pcic0_cfgaddr; +uint32_t value; + +if (!(cfgaddr & (1 <<31 ))) +return 0xffffffff ; + + value =pci_data_read (ppc4xx_pci->bus, cfgaddr | offset,2 ); + +return cpu_to_le16 (value);
endianness problem, as explained above. Note that you can use functions from pci_host.h which basically do the same, but correctly handle endianness.
Quoted 5 lines
qemu/hw/ppc4xx_devs.c +5
-0+} + +static uint32_t pci4xx_cfgdata_read4 (void *opaque,target_phys_addr_t addr) +{ +ppc4xx_pci_t *ppc4xx_pci = opaque;
qemu/hw/ppc4xx_devs.c line 642
Quoted 10 lines
qemu/hw/ppc4xx_devs.c +10
-0+int offset = addr &0x3 ; +uint32_t cfgaddr = ppc4xx_pci->pcic0_cfgaddr; +uint32_t value; + +if (!(cfgaddr & (1 <<31 ))) +return 0xffffffff ; + + value =pci_data_read (ppc4xx_pci->bus, cfgaddr | offset,4 ); + +return cpu_to_le32 (value);
endianness problem, as explained above
Quoted 15 lines
qemu/hw/ppc4xx_devs.c +15
-0+} + +static CPUReadMemoryFunc *pci4xx_cfgdata_read[] = { + &pci4xx_cfgdata_read1, + &pci4xx_cfgdata_read2, + &pci4xx_cfgdata_read4, +}; + +static void pci4xx_cfgdata_write1 (void *opaque,target_phys_addr_t addr, +uint32_t value) +{ +ppc4xx_pci_t *ppc4xx_pci = opaque; +int offset = addr &0x3 ; + + pci_data_write(ppc4xx_pci->bus, ppc4xx_pci->pcic0_cfgaddr | offset,
qemu/hw/ppc4xx_devs.c line 667
Quoted 10 lines
qemu/hw/ppc4xx_devs.c +10
-0+ value, 1); +} + +static void pci4xx_cfgdata_write2 (void *opaque,target_phys_addr_t addr, +uint32_t value) +{ +ppc4xx_pci_t *ppc4xx_pci = opaque; +int offset = addr &0x3 ; + + value =le16_to_cpu (value);
endianness problem, as explained above
qemu/hw/ppc4xx_devs.c line 679
Quoted 12 lines
qemu/hw/ppc4xx_devs.c +12
-0+ +pci_data_write (ppc4xx_pci->bus, ppc4xx_pci->pcic0_cfgaddr | offset, + value,2 ); +} + +static void pci4xx_cfgdata_write4 (void *opaque,target_phys_addr_t addr, +uint32_t value) +{ +ppc4xx_pci_t *ppc4xx_pci = opaque; +int offset = addr &0x3 ; + + value =le32_to_cpu (value);
endianness problem, as explained above
Quoted 8 lines
qemu/hw/ppc4xx_devs.c +8
-0+ +pci_data_write (ppc4xx_pci->bus, ppc4xx_pci->pcic0_cfgaddr | offset, + value,4 ); +} + +static CPUWriteMemoryFunc *pci4xx_cfgdata_write[] = { + &pci4xx_cfgdata_write1, + &pci4xx_cfgdata_write2,
qemu/hw/ppc4xx_devs.c line 697
Quoted 10 lines
qemu/hw/ppc4xx_devs.c +10
-0+ &pci4xx_cfgdata_write4, +}; + +static void pci_reg_write4 (void *opaque,target_phys_addr_t addr, +uint32_t value) +{ +struct ppc4xx_pci_t *pci = opaque; +unsigned long offset = addr - pci->registers; + + value =le32_to_cpu (value);
endianness problem, as explained above
Quoted 72 lines
qemu/hw/ppc4xx_devs.c +72
-0+ +switch (offset) { +case PCIL0_PMM0LA : + pci->pmm[0 ].la = value; +break ; +case PCIL0_PMM1LA : + pci->pmm[0 ].la = value; +break ; +case PCIL0_PMM2LA : + pci->pmm[0 ].la = value; +break ; +default : +//printf(" unhandled PCI internal register 0x%lx\n", offset); +break ; + } +} + +static uint32_t pci_reg_read4 (void *opaque,target_phys_addr_t addr) +{ +struct ppc4xx_pci_t *pci = opaque; +unsigned long offset = addr - pci->registers; +uint32_t value; + +switch (offset) { +case PCIL0_PMM0LA : + value = pci->pmm[0 ].la; +break ; +case PCIL0_PMM0MA : + value = pci->pmm[0 ].ma; +break ; +case PCIL0_PMM0PCIHA : + value = pci->pmm[0 ].pciha; +break ; +case PCIL0_PMM0PCILA : + value = pci->pmm[0 ].pcila; +break ; + +case PCIL0_PMM1LA : + value = pci->pmm[1 ].la; +break ; +case PCIL0_PMM1MA : + value = pci->pmm[1 ].ma; +break ; +case PCIL0_PMM1PCIHA : + value = pci->pmm[1 ].pciha; +break ; +case PCIL0_PMM1PCILA : + value = pci->pmm[1 ].pcila; +break ; + +case PCIL0_PMM2LA : + value = pci->pmm[2 ].la; +break ; +case PCIL0_PMM2MA : + value = pci->pmm[2 ].ma; +break ; +case PCIL0_PMM2PCIHA : + value = pci->pmm[2 ].pciha; +break ; +case PCIL0_PMM2PCILA : + value = pci->pmm[2 ].pcila; +break ; + +case PCIL0_PTM1MS : + value = pci->ptm[0 ].ms; +break ; +case PCIL0_PTM1LA : + value = pci->ptm[0 ].la; +break ; +case PCIL0_PTM2MS : + value = pci->ptm[1 ].ms; +break ;
qemu/hw/ppc4xx_devs.c line 779
Quoted 10 lines
qemu/hw/ppc4xx_devs.c +10
-0+case PCIL0_PTM2LA : + value = pci->ptm[1 ].la; +break ; + +default : +//printf(" read from invalid PCI internal register 0x%lx\n", offset); + value =0 ; + } + + value =cpu_to_le32 (value);
endianness problem, as explained above
Quoted 9 lines
qemu/hw/ppc4xx_devs.c +9
-0+ +return value; +} + +static CPUReadMemoryFunc *pci_reg_read[] = { + &pci_reg_read4, + &pci_reg_read4, + &pci_reg_read4, +};
qemu/hw/ppc4xx_devs.c line 798
Quoted 10 lines
qemu/hw/ppc4xx_devs.c +10
-0+ +static CPUWriteMemoryFunc *pci_reg_write[] = { + &pci_reg_write4, + &pci_reg_write4, + &pci_reg_write4, +}; + +static uint32_t pci_int_ack_read4 (void *opaque,target_phys_addr_t addr) +{ +printf ("%s\n" , __func__);
This should probably be inside a #ifdef #endif block. Also is it normal that this function does nothing? Given its name, I guess it is supposed to read the PIC controller to acknowledge an interrupt.
qemu/hw/ppc4xx_devs.c line 811
Quoted 13 lines
qemu/hw/ppc4xx_devs.c +13
-0+return 0 ; +} + +static CPUReadMemoryFunc *pci_int_ack_read[] = { + &pci_int_ack_read4, + &pci_int_ack_read4, + &pci_int_ack_read4, +}; + +static void pci_special_write4 (void *opaque,target_phys_addr_t addr, +uint32_t value) +{ +printf ("%s\n" , __func__);
Same here
Quoted 98 lines
qemu/hw/ppc4xx_devs.c +97
-0+} + +static CPUWriteMemoryFunc *pci_special_write[] = { + &pci_special_write4, + &pci_special_write4, + &pci_special_write4, +}; + +static int bamboo_pci_map_irq (PCIDevice *pci_dev,int irq_num) +{ +int slot = pci_dev->devfn >>3 ; + +#if 0 +printf ("### %s: devfn %x irq %d -> %d\n" , __func__, + pci_dev->devfn, irq_num, slot+1 ); +#endif + +/* All pins from each slot are tied to a single board IRQ (2-5) */ +return slot +1 ; +} + +static void bamboo_pci_set_irq (qemu_irq *pic,int irq_num,int level) +{ +#if 0 +printf ("### %s: PCI irq %d, UIC irq %d\n" , __func__, irq_num,30 - irq_num); +#endif + +/* Board IRQs 2-5 are connected to UIC IRQs 28-25 */ +qemu_set_irq (pic[30 -irq_num], level); +} + +/* XXX Needs some abstracting for boards other than Bamboo. */ +ppc4xx_pci_t *ppc4xx_pci_init (CPUState *env,qemu_irq *pic, +target_phys_addr_t config_space, +target_phys_addr_t int_ack, +target_phys_addr_t special_cycle, +target_phys_addr_t registers) +{ +ppc4xx_pci_t *pci; +PCIDevice *d; +int index; + + pci =qemu_mallocz (sizeof (ppc4xx_pci_t)); +if (!pci) +return NULL ; + + pci->config_space = config_space; + pci->registers = registers; + pci->pic = pic; + + pci->bus =pci_register_bus (bamboo_pci_set_irq, bamboo_pci_map_irq, + pic,0 ,4 ); + d =pci_register_device (pci->bus,"host bridge" ,sizeof (PCIDevice), +0 ,NULL ,NULL ); + d->config[0x00 ] =0x14 ;// vendor_id + d->config[0x01 ] =0x10 ; + d->config[0x02 ] =0x7f ;// device_id + d->config[0x03 ] =0x02 ; + d->config[0x0a ] =0x80 ;// class_sub = other bridge type + d->config[0x0b ] =0x06 ;// class_base = PCI_bridge + +/* CFGADDR */ + index =cpu_register_io_memory (0 , pci4xx_cfgaddr_read, + pci4xx_cfgaddr_write, pci); +if (index <0 ) + goto free; +cpu_register_physical_memory (config_space,4 , index); + +/* CFGDATA */ + index =cpu_register_io_memory (0 , pci4xx_cfgdata_read, + pci4xx_cfgdata_write, pci); +if (index <0 ) + goto free; +cpu_register_physical_memory (config_space +4 ,4 , index); + +/* "Special cycle" and interrupt acknowledge */ + index =cpu_register_io_memory (0 , pci_int_ack_read, + pci_special_write, pci); +if (index <0 ) + goto free; +cpu_register_physical_memory (int_ack,4 , index); + +/* Internal registers */ + index =cpu_register_io_memory (0 , pci_reg_read, pci_reg_write, pci); +if (index <0 ) + goto free; +cpu_register_physical_memory (registers,PCI_REG_SIZE , index); + +/* XXX register_savevm() */ + +return pci; + +free: +printf ("%s error\n" , __func__); +qemu_free (pci); +return NULL ; +}
Signature · 4 lines
.''`. Aurelien Jarno | GPG: 1024D/F1BCDB73 : :' : Debian developer | Electrical Engineer `. `' [email protected] | [email protected] `- people.debian.org/~aurel32 | www.aurel32.net