[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 1/6] PCI config space access overhaul
From: |
Alexander Graf |
Subject: |
Re: [Qemu-devel] [PATCH 1/6] PCI config space access overhaul |
Date: |
Tue, 12 Jan 2010 11:36:58 +0100 |
On 05.01.2010, at 13:46, Isaku Yamahata wrote:
> Basically it looks good.
> Some minor comments below.
>
> Although further clean up is possible,
> this is first small step.
>
> On Mon, Jan 04, 2010 at 08:32:50AM +0100, Alexander Graf wrote:
>> Different host buses may have different layouts for config space accessors.
>>
>> The Mac U3 for example uses the following define to access Type 0 (directly
>> attached) devices:
>>
>> #define MACRISC_CFA0(devfn, off) \
>> ((1 << (unsigned int)PCI_SLOT(dev_fn)) \
>> | (((unsigned int)PCI_FUNC(dev_fn)) << 8) \
>> | (((unsigned int)(off)) & 0xFCUL))
>>
>> Obviously, this is different from the encoding we interpret in qemu. In
>> order to let host controllers take some influence there, we can just
>> introduce a decoding function that takes whatever accessor we have and
>> decodes it into understandable fields.
>>
>> To not touch all different code paths in qemu, I added this on top of
>> the existing config_reg element. In the future, we should work on gradually
>> moving references to config_reg to config_reg_dec and then phase out
>> config_reg.
>>
>> This patch is the groundwork for Uninorth PCI config space fixes.
>>
>> Signed-off-by: Alexander Graf <address@hidden>
>> CC: Michael S. Tsirkin <address@hidden>
>> CC: Benjamin Herrenschmidt <address@hidden>
>>
>> ---
>>
>> v1 -> v2:
>>
>> - merge data access functions
>> - use decoding function for config space bits
>> - introduce encoding function for x86 style encodings
>>
>> ---
>> hw/apb_pci.c | 1 +
>> hw/grackle_pci.c | 1 +
>> hw/gt64xxx.c | 1 +
>> hw/pci.h | 13 ++++++
>> hw/pci_host.c | 48 ++++++++++++++++++-----
>> hw/pci_host.h | 16 ++++++++
>> hw/pci_host_template.h | 90
>> +++++++++++++-------------------------------
>> hw/pci_host_template_all.h | 23 +++++++++++
>> hw/piix_pci.c | 1 +
>> hw/ppc4xx_pci.c | 1 +
>> hw/ppce500_pci.c | 1 +
>> hw/unin_pci.c | 1 +
>> 12 files changed, 123 insertions(+), 74 deletions(-)
>> create mode 100644 hw/pci_host_template_all.h
>>
>> diff --git a/hw/apb_pci.c b/hw/apb_pci.c
>> index f05308b..fedb84c 100644
>> --- a/hw/apb_pci.c
>> +++ b/hw/apb_pci.c
>> @@ -222,6 +222,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
>> /* mem_data */
>> sysbus_mmio_map(s, 3, mem_base);
>> d = FROM_SYSBUS(APBState, s);
>> + pci_host_init(&d->host_state);
>> d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
>> pci_apb_set_irq, pci_pbm_map_irq,
>> pic,
>> 0, 32);
>> diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
>> index ee4fed5..7feba63 100644
>> --- a/hw/grackle_pci.c
>> +++ b/hw/grackle_pci.c
>> @@ -88,6 +88,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
>> qdev_init_nofail(dev);
>> s = sysbus_from_qdev(dev);
>> d = FROM_SYSBUS(GrackleState, s);
>> + pci_host_init(&d->host_state);
>> d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
>> pci_grackle_set_irq,
>> pci_grackle_map_irq,
>> diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
>> index fb7f5bd..8cf93ca 100644
>> --- a/hw/gt64xxx.c
>> +++ b/hw/gt64xxx.c
>> @@ -1120,6 +1120,7 @@ PCIBus *pci_gt64120_init(qemu_irq *pic)
>> s = qemu_mallocz(sizeof(GT64120State));
>> s->pci = qemu_mallocz(sizeof(GT64120PCIState));
>>
>> + pci_host_init(s->pci);
>> s->pci->bus = pci_register_bus(NULL, "pci",
>> pci_gt64120_set_irq, pci_gt64120_map_irq,
>> pic, 144, 4);
>> diff --git a/hw/pci.h b/hw/pci.h
>> index fd16460..cfaa0a9 100644
>> --- a/hw/pci.h
>> +++ b/hw/pci.h
>> @@ -10,10 +10,23 @@
>>
>> /* PCI bus */
>>
>> +typedef struct PCIAddress {
>> + PCIBus *domain;
>> + uint8_t bus;
>> + uint8_t slot;
>> + uint8_t fn;
>> +} PCIAddress;
>> +
>> #define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
>> #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
>> #define PCI_FUNC(devfn) ((devfn) & 0x07)
>>
>> +static inline uint32_t pci_addr_to_devfn(PCIAddress *addr, uint32_t offset)
>> +{
>> + return ((addr->bus & 0xff) << 16) | (PCI_DEVFN(addr->slot, addr->fn) <<
>> 8) |
>> + offset;
>> +}
>> +
>
> Hmm, this name doesn't seem good.
> devfn sounds something like encoded (slot, fn) pair (to me),
> but the function returns something else.
I'm open for naming suggestions.
>
> This function is used for pci_data_{read, write}()
> which again decodes bus, slot, fn.
> So shouldn't they be changed to accept PCIAddress itself?
>
>
>> /* Class, Vendor and Device IDs from Linux's pci_ids.h */
>> #include "pci_ids.h"
>>
>> diff --git a/hw/pci_host.c b/hw/pci_host.c
>> index eeb8dee..746ffc2 100644
>> --- a/hw/pci_host.c
>> +++ b/hw/pci_host.c
>> @@ -32,13 +32,6 @@ do { printf("pci_host_data: " fmt , ## __VA_ARGS__); }
>> while (0)
>> #define PCI_DPRINTF(fmt, ...)
>> #endif
>>
>> -/*
>> - * PCI address
>> - * bit 16 - 24: bus number
>> - * bit 8 - 15: devfun number
>> - * bit 0 - 7: offset in configuration space of a given pci device
>> - */
>> -
>> /* the helper functio to get a PCIDeice* for a given pci address */
>> static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr)
>> {
>> @@ -56,7 +49,7 @@ void pci_data_write(PCIBus *s, uint32_t addr, uint32_t
>> val, int len)
>> if (!pci_dev)
>> return;
>>
>> - PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRI32x" len=%d\n",
>> + PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n",
>
> Good catch. This part should be split into another patch.
Right :).
>
>> __func__, pci_dev->name, config_addr, val, len);
>> pci_dev->config_write(pci_dev, config_addr, val, len);
>> }
>> @@ -89,7 +82,9 @@ static void pci_host_config_writel(void *opaque,
>> target_phys_addr_t addr,
>> #endif
>> PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n",
>> __func__, addr, val);
>> +
>> s->config_reg = val;
>> + s->decode_config_reg(s, val, &s->config_reg_dec);
>> }
>>
>> static uint32_t pci_host_config_readl(void *opaque, target_phys_addr_t addr)
>> @@ -131,7 +126,9 @@ static void pci_host_config_writel_noswap(void *opaque,
>>
>> PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n",
>> __func__, addr, val);
>> +
>> s->config_reg = val;
>> + s->decode_config_reg(s, val, &s->config_reg_dec);
>> }
>>
>> static uint32_t pci_host_config_readl_noswap(void *opaque,
>> @@ -169,7 +166,9 @@ static void pci_host_config_writel_ioport(void *opaque,
>> PCIHostState *s = opaque;
>>
>> PCI_DPRINTF("%s addr %"PRIx32 " val %"PRIx32"\n", __func__, addr, val);
>> +
>> s->config_reg = val;
>> + s->decode_config_reg(s, val, &s->config_reg_dec);
>> }
>>
>> static uint32_t pci_host_config_readl_ioport(void *opaque, uint32_t addr)
>> @@ -190,7 +189,7 @@ void pci_host_conf_register_ioport(pio_addr_t ioport,
>> PCIHostState *s)
>> #define PCI_ADDR_T target_phys_addr_t
>> #define PCI_HOST_SUFFIX _mmio
>>
>> -#include "pci_host_template.h"
>> +#include "pci_host_template_all.h"
>>
>> static CPUWriteMemoryFunc * const pci_host_data_write_mmio[] = {
>> pci_host_data_writeb_mmio,
>> @@ -217,7 +216,7 @@ int pci_host_data_register_mmio(PCIHostState *s)
>> #define PCI_ADDR_T uint32_t
>> #define PCI_HOST_SUFFIX _ioport
>>
>> -#include "pci_host_template.h"
>> +#include "pci_host_template_all.h"
>>
>> void pci_host_data_register_ioport(pio_addr_t ioport, PCIHostState *s)
>> {
>> @@ -228,3 +227,32 @@ void pci_host_data_register_ioport(pio_addr_t ioport,
>> PCIHostState *s)
>> register_ioport_read(ioport, 4, 2, pci_host_data_readw_ioport, s);
>> register_ioport_read(ioport, 4, 4, pci_host_data_readl_ioport, s);
>> }
>> +
>> +/* This implements the default x86 way of interpreting a PCI address
>> + *
>> + * PCI address
>> + * bit 16 - 24: bus number
>> + * bit 11 - 15: slot number
>> + * bit 8 - 10: function number
>> + * bit 0 - 7: offset in configuration space of a given pci device
>> + */
>> +
>> +void pci_host_decode_config_reg(PCIHostState *s, uint32_t config_reg,
>> + PCIConfigAddress *decoded)
>> +{
>> + uint32_t devfn;
>> +
>> + decoded->addr.domain = s->bus;
>> + decoded->addr.bus = (config_reg >> 16) & 0xff;
>> + devfn = config_reg >> 8;
>> + decoded->addr.slot = (config_reg >> 11) & 0x1f;
>> + decoded->addr.fn = (config_reg >> 8) & 0x7;
>> + decoded->offset = config_reg & 0xff;
>> + decoded->addr_mask = 3;
>> + decoded->valid = (config_reg & (1u << 31)) ? true : false;
>> +}
>> +
>> +void pci_host_init(PCIHostState *s)
>> +{
>> + s->decode_config_reg = pci_host_decode_config_reg;
>> +}
>> diff --git a/hw/pci_host.h b/hw/pci_host.h
>> index a006687..0fcdf64 100644
>> --- a/hw/pci_host.h
>> +++ b/hw/pci_host.h
>> @@ -30,14 +30,30 @@
>>
>> #include "sysbus.h"
>>
>> +/* for config space access */
>> +typedef struct PCIConfigAddress {
>> + PCIAddress addr;
>> + uint32_t addr_mask;
>> + uint16_t offset;
>> + bool valid;
>> +} PCIConfigAddress;
>> +
>> +typedef void (*pci_config_reg_fn)(PCIHostState *s, uint32_t config_reg,
>> + PCIConfigAddress *conf);
>> +
>> struct PCIHostState {
>> SysBusDevice busdev;
>> + pci_config_reg_fn decode_config_reg;
>> + PCIConfigAddress config_reg_dec;
>> uint32_t config_reg;
>> PCIBus *bus;
>> };
>>
>> void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len);
>> uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len);
>> +void pci_host_init(PCIHostState *s);
>> +void pci_host_decode_config_reg(PCIHostState *s, uint32_t config_reg,
>> + PCIConfigAddress *decoded);
>>
>> /* for mmio */
>> int pci_host_conf_register_mmio(PCIHostState *s);
>> diff --git a/hw/pci_host_template.h b/hw/pci_host_template.h
>> index 11e6c88..d989c25 100644
>> --- a/hw/pci_host_template.h
>> +++ b/hw/pci_host_template.h
>> @@ -25,85 +25,47 @@
>> /* Worker routines for a PCI host controller that uses an {address,data}
>> register pair to access PCI configuration space. */
>>
>> -static void glue(pci_host_data_writeb, PCI_HOST_SUFFIX)(
>> +static void glue(glue(pci_host_data_write, PCI_HOST_BWL), PCI_HOST_SUFFIX)(
>> void* opaque, PCI_ADDR_T addr, uint32_t val)
>> {
>> PCIHostState *s = opaque;
>> + PCIConfigAddress *config_reg = &s->config_reg_dec;
>> + int offset = config_reg->offset;
>>
>> - PCI_DPRINTF("writeb addr " TARGET_FMT_plx " val %x\n",
>> - (target_phys_addr_t)addr, val);
>> - if (s->config_reg & (1u << 31))
>> - pci_data_write(s->bus, s->config_reg | (addr & 3), val, 1);
>> -}
>> -
>> -static void glue(pci_host_data_writew, PCI_HOST_SUFFIX)(
>> - void* opaque, PCI_ADDR_T addr, uint32_t val)
>> -{
>> - PCIHostState *s = opaque;
>> -#ifdef TARGET_WORDS_BIGENDIAN
>> - val = bswap16(val);
>> +#if defined(TARGET_WORDS_BIGENDIAN) && (PCI_HOST_BITS > 8)
>> + val = glue(bswap, PCI_HOST_BITS)(val);
>> #endif
>> - PCI_DPRINTF("writew addr " TARGET_FMT_plx " val %x\n",
>> - (target_phys_addr_t)addr, val);
>> - if (s->config_reg & (1u << 31))
>> - pci_data_write(s->bus, s->config_reg | (addr & 3), val, 2);
>> -}
>>
>> -static void glue(pci_host_data_writel, PCI_HOST_SUFFIX)(
>> - void* opaque, PCI_ADDR_T addr, uint32_t val)
>> -{
>> - PCIHostState *s = opaque;
>> -#ifdef TARGET_WORDS_BIGENDIAN
>> - val = bswap32(val);
>> -#endif
>> - PCI_DPRINTF("writel addr " TARGET_FMT_plx " val %x\n",
>> - (target_phys_addr_t)addr, val);
>> - if (s->config_reg & (1u << 31))
>> - pci_data_write(s->bus, s->config_reg, val, 4);
>> + offset |= (addr & config_reg->addr_mask);
>> + PCI_DPRINTF("%s: addr " TARGET_FMT_plx " val %x\n",
>> + __func__, (target_phys_addr_t)addr, val);
>> + if (config_reg->valid) {
>> + pci_data_write(s->bus, pci_addr_to_devfn(&config_reg->addr,
>> offset), val,
>> + sizeof(glue(glue(uint, PCI_HOST_BITS), _t)));
>> + }
>> }
>>
>> -static uint32_t glue(pci_host_data_readb, PCI_HOST_SUFFIX)(
>> +static uint32_t glue(glue(pci_host_data_read, PCI_HOST_BWL),
>> PCI_HOST_SUFFIX)(
>> void* opaque, PCI_ADDR_T addr)
>> {
>> PCIHostState *s = opaque;
>> + PCIConfigAddress *config_reg = &s->config_reg_dec;
>> + int offset = config_reg->offset;
>> uint32_t val;
>>
>> - if (!(s->config_reg & (1 << 31)))
>> - return 0xff;
>> - val = pci_data_read(s->bus, s->config_reg | (addr & 3), 1);
>> - PCI_DPRINTF("readb addr " TARGET_FMT_plx " val %x\n",
>> - (target_phys_addr_t)addr, val);
>> - return val;
>> -}
>> + if (!config_reg->valid) {
>> + return ( 1ULL << PCI_HOST_BITS ) - 1;
>
> Are you using intentionally 1ULL (64bit) not to overflow it?
We are overflowing it for a short amount of time.
1 << PCI_HOST_BITS = 0x100000000
0x100000000 - 1 = 0xffffffff
That's why we need the ULL.
>
>
>> + }
>>
>> -static uint32_t glue(pci_host_data_readw, PCI_HOST_SUFFIX)(
>> - void* opaque, PCI_ADDR_T addr)
>> -{
>> - PCIHostState *s = opaque;
>> - uint32_t val;
>> - if (!(s->config_reg & (1 << 31)))
>> - return 0xffff;
>> - val = pci_data_read(s->bus, s->config_reg | (addr & 3), 2);
>> - PCI_DPRINTF("readw addr " TARGET_FMT_plx " val %x\n",
>> - (target_phys_addr_t)addr, val);
>> -#ifdef TARGET_WORDS_BIGENDIAN
>> - val = bswap16(val);
>> -#endif
>> - return val;
>> -}
>> + offset |= (addr & config_reg->addr_mask);
>> + val = pci_data_read(s->bus, pci_addr_to_devfn(&config_reg->addr,
>> offset),
>> + sizeof(glue(glue(uint, PCI_HOST_BITS), _t)));
>> + PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %x\n",
>> + __func__, (target_phys_addr_t)addr, val);
>>
>> -static uint32_t glue(pci_host_data_readl, PCI_HOST_SUFFIX)(
>> - void* opaque, PCI_ADDR_T addr)
>> -{
>> - PCIHostState *s = opaque;
>> - uint32_t val;
>> - if (!(s->config_reg & (1 << 31)))
>> - return 0xffffffff;
>> - val = pci_data_read(s->bus, s->config_reg | (addr & 3), 4);
>> - PCI_DPRINTF("readl addr " TARGET_FMT_plx " val %x\n",
>> - (target_phys_addr_t)addr, val);
>> -#ifdef TARGET_WORDS_BIGENDIAN
>> - val = bswap32(val);
>> +#if defined(TARGET_WORDS_BIGENDIAN) && (PCI_HOST_BITS > 8)
>> + val = glue(bswap, PCI_HOST_BITS)(val);
>> #endif
>> +
>> return val;
>> }
>> diff --git a/hw/pci_host_template_all.h b/hw/pci_host_template_all.h
>> new file mode 100644
>> index 0000000..74b3e84
>> --- /dev/null
>> +++ b/hw/pci_host_template_all.h
>> @@ -0,0 +1,23 @@
>> +#define PCI_HOST_BWL b
>> +#define PCI_HOST_BITS 8
>> +
>> +#include "pci_host_template.h"
>> +
>> +#undef PCI_HOST_BWL
>> +#undef PCI_HOST_BITS
>> +
>> +#define PCI_HOST_BWL w
>> +#define PCI_HOST_BITS 16
>> +
>> +#include "pci_host_template.h"
>> +
>> +#undef PCI_HOST_BWL
>> +#undef PCI_HOST_BITS
>> +
>> +#define PCI_HOST_BWL l
>> +#define PCI_HOST_BITS 32
>> +
>> +#include "pci_host_template.h"
>> +
>> +#undef PCI_HOST_BWL
>> +#undef PCI_HOST_BITS
>
> Oh, another new cpp tricks.
> I'm ok with this trick. However Michael may have his own idea.
> This trick would be split out into independent patch.
Well I got fed up with having to change 10 lines of code that all look the same
;-).
Alex
- [Qemu-devel] [PATCH 0/6] PPC NewWorld fixery v2, Alexander Graf, 2010/01/04
- [Qemu-devel] [PATCH 4/6] Include dump of lspci -nn on real G5, Alexander Graf, 2010/01/04
- [Qemu-devel] [PATCH 6/6] Enable secondary cmd64x, Alexander Graf, 2010/01/04
- [Qemu-devel] [PATCH 3/6] Use Mac99_U3 type on ppc64, Alexander Graf, 2010/01/04
- [Qemu-devel] [PATCH 2/6] Add config space conversion function for uni_north, Alexander Graf, 2010/01/04
- [Qemu-devel] [PATCH 5/6] Make interrupts work, Alexander Graf, 2010/01/04
- [Qemu-devel] [PATCH 1/6] PCI config space access overhaul, Alexander Graf, 2010/01/04
- [Qemu-devel] Re: [PATCH 1/6] PCI config space access overhaul, Michael S. Tsirkin, 2010/01/05