All of lore.kernel.org
 help / color / mirror / Atom feed
From: Anthony Liguori <anthony@codemonkey.ws>
To: Blue Swirl <blauwirbel@gmail.com>
Cc: qemu-devel <qemu-devel@nongnu.org>,
	"Michael S. Tsirkin" <mst@redhat.com>
Subject: Re: [Qemu-devel] [PATCH, RFC] pci: handle BAR mapping at pci level
Date: Wed, 07 Jul 2010 14:02:53 -0500	[thread overview]
Message-ID: <4C34CF5D.3070903@codemonkey.ws> (raw)
In-Reply-To: <AANLkTim5y9JcKEduGP4A5rtGDaGW1dCngczppNXvItQz@mail.gmail.com>

On 07/07/2010 12:53 PM, Blue Swirl wrote:
> Add I/O port registration functions which separate registration
> from the mapping stage.
>
> Move IOIO and MMIO BAR mapping to pci.c.
>
> TODO: fix dirty logging, coalesced MMIO and base address comparisons
> (eepro100 etc). Bridge filtering may be broken. Broke virtio-pci and MSIX.
>
> Signed-off-by: Blue Swirl<blauwirbel@gmail.com>
> ---
> i386 boots but resets. PPC and Sparc64 can't even start.
>
> Patch also available at
> git://repo.or.cz/qemu/blueswirl.git
>
> It may be worthwhile to break this into some kind of smaller steps.
>
>   hw/ac97.c         |   60 +++++++++++---------
>   hw/cirrus_vga.c   |   40 +++-----------
>   hw/e1000.c        |   37 +-----------
>   hw/eepro100.c     |   77 ++++++++++----------------
>   hw/es1370.c       |   32 +++++------
>   hw/ide/cmd646.c   |  149 +++++++++++++++++++++++++++++++-------------------
>   hw/ide/piix.c     |   74 ++++++++++++++++---------
>   hw/ide/via.c      |   67 ++++++++++++++--------
>   hw/isa.h          |    1 +
>   hw/isa_mmio.c     |   17 +++++-
>   hw/lsi53c895a.c   |   60 ++++++--------------
>   hw/macio.c        |  107 +++++++++++-------------------------
>   hw/ne2000.c       |   66 +++++++++++++++-------
>   hw/openpic.c      |   36 ++----------
>   hw/pci.c          |  158 ++++++++++++++++++++++++++++++++--------------------
>   hw/pci.h          |   18 +++++-
>   hw/pcnet.c        |   62 ++++++++++-----------
>   hw/ppc_mac.h      |    5 +-
>   hw/ppc_newworld.c |    2 +-
>   hw/ppc_oldworld.c |    4 +-
>   hw/rtl8139.c      |   42 +++++---------
>   hw/sun4u.c        |   29 +++------
>   hw/usb-ohci.c     |   10 +---
>   hw/usb-uhci.c     |   31 +++++-----
>   hw/vga-pci.c      |   22 +------
>   hw/virtio-pci.c   |   39 ++++++-------
>   hw/vmware_vga.c   |  107 ++++++++++++++++++------------------
>   hw/wdt_i6300esb.c |   38 +++++--------
>   ioport.c          |  119 ++++++++++++++++++++++++++++++++++++----
>   ioport.h          |    6 ++
>   30 files changed, 778 insertions(+), 737 deletions(-)
>
> diff --git a/hw/ac97.c b/hw/ac97.c
> index 4319bc8..28d0c19 100644
> --- a/hw/ac97.c
> +++ b/hw/ac97.c
> @@ -1234,31 +1234,29 @@ static const VMStateDescription vmstate_ac97 = {
>       }
>   };
>
> -static void ac97_map (PCIDevice *pci_dev, int region_num,
> -                      pcibus_t addr, pcibus_t size, int type)
> -{
> -    AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, pci_dev);
> -    PCIDevice *d =&s->dev;
> -
> -    if (!region_num) {
> -        s->base[0] = addr;
> -        register_ioport_read (addr, 256 * 1, 1, nam_readb, d);
> -        register_ioport_read (addr, 256 * 2, 2, nam_readw, d);
> -        register_ioport_read (addr, 256 * 4, 4, nam_readl, d);
> -        register_ioport_write (addr, 256 * 1, 1, nam_writeb, d);
> -        register_ioport_write (addr, 256 * 2, 2, nam_writew, d);
> -        register_ioport_write (addr, 256 * 4, 4, nam_writel, d);
> -    }
> -    else {
> -        s->base[1] = addr;
> -        register_ioport_read (addr, 64 * 1, 1, nabm_readb, d);
> -        register_ioport_read (addr, 64 * 2, 2, nabm_readw, d);
> -        register_ioport_read (addr, 64 * 4, 4, nabm_readl, d);
> -        register_ioport_write (addr, 64 * 1, 1, nabm_writeb, d);
> -        register_ioport_write (addr, 64 * 2, 2, nabm_writew, d);
> -        register_ioport_write (addr, 64 * 4, 4, nabm_writel, d);
> -    }
> -}
> +static IOPortWriteFunc * const nam_writes[] = {
> +    nam_writeb,
> +    nam_writew,
> +    nam_writel,
> +};
> +
> +static IOPortReadFunc * const nam_reads[] = {
> +    nam_readb,
> +    nam_readw,
> +    nam_readl,
> +};
> +
> +static IOPortWriteFunc * const nabm_writes[] = {
> +    nabm_writeb,
> +    nabm_writew,
> +    nabm_writel,
> +};
> +
> +static IOPortReadFunc * const nabm_reads[] = {
> +    nabm_readb,
> +    nabm_readw,
> +    nabm_readl,
> +};
>
>   static void ac97_on_reset (void *opaque)
>   {
> @@ -1280,6 +1278,7 @@ static int ac97_initfn (PCIDevice *dev)
>   {
>       AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
>       uint8_t *c = s->dev.config;
> +    int io_index;
>
>       pci_config_set_vendor_id (c, PCI_VENDOR_ID_INTEL); /* ro */
>       pci_config_set_device_id (c, PCI_DEVICE_ID_INTEL_82801AA_5); /* ro */
> @@ -1321,9 +1320,14 @@ static int ac97_initfn (PCIDevice *dev)
>       /* TODO: RST# value should be 0. */
>       c[PCI_INTERRUPT_PIN] = 0x01;      /* intr_pn interrupt pin ro */
>
> -    pci_register_bar (&s->dev, 0, 256 * 4, PCI_BASE_ADDRESS_SPACE_IO,
> -                      ac97_map);
> -    pci_register_bar (&s->dev, 1, 64 * 4, PCI_BASE_ADDRESS_SPACE_IO, ac97_map);
> +    pci_register_bar(&s->dev, 0, 256 * 4, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(nam_reads, nam_writes, 256 * 4, s);
> +    pci_bar_map(&s->dev, 0, 0, 0, 256 * 4, io_index);
> +
> +    pci_register_bar(&s->dev, 1, 64 * 4, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(nabm_reads, nabm_writes, 64 * 4, s);
> +    pci_bar_map(&s->dev, 1, 0, 0, 64 * 4, io_index);
>    

Any reason to keep this a three step process?  I see no reason not to 
unify the io and mem function pointers into a single type.  These 
callbacks should be working off of pci bus addresses and should not be 
tied directly to CPU memory/pio callbacks.

Regards,

Anthony Liguori

> +
>       qemu_register_reset (ac97_on_reset, s);
>       AUD_register_card ("ac97",&s->card);
>       ac97_on_reset (s);
> diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
> index bbd4b08..829d837 100644
> --- a/hw/cirrus_vga.c
> +++ b/hw/cirrus_vga.c
> @@ -3139,36 +3139,6 @@ void isa_cirrus_vga_init(void)
>    *
>    ***************************************/
>
> -static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
> -			       pcibus_t addr, pcibus_t size, int type)
> -{
> -    CirrusVGAState *s =&DO_UPCAST(PCICirrusVGAState, dev, d)->cirrus_vga;
> -
> -    /* XXX: add byte swapping apertures */
> -    cpu_register_physical_memory(addr, s->vga.vram_size,
> -				 s->cirrus_linear_io_addr);
> -    cpu_register_physical_memory(addr + 0x1000000, 0x400000,
> -				 s->cirrus_linear_bitblt_io_addr);
> -
> -    s->vga.map_addr = s->vga.map_end = 0;
> -    s->vga.lfb_addr = addr&  TARGET_PAGE_MASK;
> -    s->vga.lfb_end = ((addr + VGA_RAM_SIZE) + TARGET_PAGE_SIZE - 1)&
> TARGET_PAGE_MASK;
> -    /* account for overflow */
> -    if (s->vga.lfb_end<  addr + VGA_RAM_SIZE)
> -        s->vga.lfb_end = addr + VGA_RAM_SIZE;
> -
> -    vga_dirty_log_start(&s->vga);
> -}
> -
> -static void cirrus_pci_mmio_map(PCIDevice *d, int region_num,
> -				pcibus_t addr, pcibus_t size, int type)
> -{
> -    CirrusVGAState *s =&DO_UPCAST(PCICirrusVGAState, dev, d)->cirrus_vga;
> -
> -    cpu_register_physical_memory(addr, CIRRUS_PNPMMIO_SIZE,
> -				 s->cirrus_mmio_io_addr);
> -}
> -
>   static void pci_cirrus_write_config(PCIDevice *d,
>                                       uint32_t address, uint32_t val, int len)
>   {
> @@ -3205,10 +3175,16 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
>        /* memory #1 memory-mapped I/O */
>        /* XXX: s->vga.vram_size must be a power of two */
>        pci_register_bar((PCIDevice *)d, 0, 0x2000000,
> -                      PCI_BASE_ADDRESS_MEM_PREFETCH, cirrus_pci_lfb_map);
> +                      PCI_BASE_ADDRESS_MEM_PREFETCH);
> +     pci_bar_map((PCIDevice *)d, 0, 0, 0, s->vga.vram_size,
> +                 s->cirrus_linear_io_addr);
> +     pci_bar_map((PCIDevice *)d, 0, 1, 0x1000000, 0x400000,
> +                 s->cirrus_linear_bitblt_io_addr);
>        if (device_id == CIRRUS_ID_CLGD5446) {
>            pci_register_bar((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE,
> -                          PCI_BASE_ADDRESS_SPACE_MEMORY, cirrus_pci_mmio_map);
> +                          PCI_BASE_ADDRESS_SPACE_MEMORY);
> +         pci_bar_map((PCIDevice *)d, 1, 0, 0, CIRRUS_PNPMMIO_SIZE,
> +                     s->cirrus_mmio_io_addr);
>        }
>        return 0;
>   }
> diff --git a/hw/e1000.c b/hw/e1000.c
> index 0da65f9..b5e9143 100644
> --- a/hw/e1000.c
> +++ b/hw/e1000.c
> @@ -149,14 +149,6 @@ static const char phy_regcap[0x20] = {
>   };
>
>   static void
> -ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr,
> -           pcibus_t size, int type)
> -{
> -    DBGOUT(IO, "e1000_ioport_map addr=0x%04"FMT_PCIBUS
> -           " size=0x%08"FMT_PCIBUS"\n", addr, size);
> -}
> -
> -static void
>   set_interrupt_cause(E1000State *s, int index, uint32_t val)
>   {
>       if (val)
> @@ -1018,30 +1010,6 @@ static CPUReadMemoryFunc * const e1000_mmio_read[] = {
>   };
>
>   static void
> -e1000_mmio_map(PCIDevice *pci_dev, int region_num,
> -                pcibus_t addr, pcibus_t size, int type)
> -{
> -    E1000State *d = DO_UPCAST(E1000State, dev, pci_dev);
> -    int i;
> -    const uint32_t excluded_regs[] = {
> -        E1000_MDIC, E1000_ICR, E1000_ICS, E1000_IMS,
> -        E1000_IMC, E1000_TCTL, E1000_TDT, PNPMMIO_SIZE
> -    };
> -
> -
> -    DBGOUT(MMIO, "e1000_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
> -           addr, size);
> -
> -    cpu_register_physical_memory(addr, PNPMMIO_SIZE, d->mmio_index);
> -    qemu_register_coalesced_mmio(addr, excluded_regs[0]);
> -
> -    for (i = 0; excluded_regs[i] != PNPMMIO_SIZE; i++)
> -        qemu_register_coalesced_mmio(addr + excluded_regs[i] + 4,
> -                                     excluded_regs[i + 1] -
> -                                     excluded_regs[i] - 4);
> -}
> -
> -static void
>   e1000_cleanup(VLANClientState *nc)
>   {
>       E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
> @@ -1106,10 +1074,11 @@ static int pci_e1000_init(PCIDevice *pci_dev)
>               e1000_mmio_write, d);
>
>       pci_register_bar((PCIDevice *)d, 0, PNPMMIO_SIZE,
> -                           PCI_BASE_ADDRESS_SPACE_MEMORY, e1000_mmio_map);
> +                     PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    pci_bar_map((PCIDevice *)d, 0, 0, 0, PNPMMIO_SIZE, d->mmio_index);
>
>       pci_register_bar((PCIDevice *)d, 1, IOPORT_SIZE,
> -                           PCI_BASE_ADDRESS_SPACE_IO, ioport_map);
> +                     PCI_BASE_ADDRESS_SPACE_IO);
>
>       memmove(d->eeprom_data, e1000_eeprom_template,
>           sizeof e1000_eeprom_template);
> diff --git a/hw/eepro100.c b/hw/eepro100.c
> index 2b75c8f..da41476 100644
> --- a/hw/eepro100.c
> +++ b/hw/eepro100.c
> @@ -226,7 +226,7 @@ typedef struct {
>       uint8_t scb_stat;           /* SCB stat/ack byte */
>       uint8_t int_stat;           /* PCI interrupt status */
>       /* region must not be saved by nic_save. */
> -    uint32_t region[3];         /* PCI region addresses */
> +    uint32_t region;         /* PCI region addresses */
>       uint16_t mdimem[32];
>       eeprom_t *eeprom;
>       uint32_t device;            /* device variant */
> @@ -1479,19 +1479,19 @@ static uint32_t ioport_read1(void *opaque,
> uint32_t addr)
>   #if 0
>       logout("addr=%s\n", regname(addr));
>   #endif
> -    return eepro100_read1(s, addr - s->region[1]);
> +    return eepro100_read1(s, addr - s->region);
>   }
>
>   static uint32_t ioport_read2(void *opaque, uint32_t addr)
>   {
>       EEPRO100State *s = opaque;
> -    return eepro100_read2(s, addr - s->region[1]);
> +    return eepro100_read2(s, addr - s->region);
>   }
>
>   static uint32_t ioport_read4(void *opaque, uint32_t addr)
>   {
>       EEPRO100State *s = opaque;
> -    return eepro100_read4(s, addr - s->region[1]);
> +    return eepro100_read4(s, addr - s->region);
>   }
>
>   static void ioport_write1(void *opaque, uint32_t addr, uint32_t val)
> @@ -1500,43 +1500,35 @@ static void ioport_write1(void *opaque,
> uint32_t addr, uint32_t val)
>   #if 0
>       logout("addr=%s val=0x%02x\n", regname(addr), val);
>   #endif
> -    eepro100_write1(s, addr - s->region[1], val);
> +    eepro100_write1(s, addr - s->region, val);
>   }
>
>   static void ioport_write2(void *opaque, uint32_t addr, uint32_t val)
>   {
>       EEPRO100State *s = opaque;
> -    eepro100_write2(s, addr - s->region[1], val);
> +    eepro100_write2(s, addr - s->region, val);
>   }
>
>   static void ioport_write4(void *opaque, uint32_t addr, uint32_t val)
>   {
>       EEPRO100State *s = opaque;
> -    eepro100_write4(s, addr - s->region[1], val);
> +    eepro100_write4(s, addr - s->region, val);
>   }
>
>   /***********************************************************/
>   /* PCI EEPRO100 definitions */
>
> -static void pci_map(PCIDevice * pci_dev, int region_num,
> -                    pcibus_t addr, pcibus_t size, int type)
> -{
> -    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
> -
> -    TRACE(OTHER, logout("region %d, addr=0x%08"FMT_PCIBUS", "
> -          "size=0x%08"FMT_PCIBUS", type=%d\n",
> -          region_num, addr, size, type));
> -
> -    assert(region_num == 1);
> -    register_ioport_write(addr, size, 1, ioport_write1, s);
> -    register_ioport_read(addr, size, 1, ioport_read1, s);
> -    register_ioport_write(addr, size, 2, ioport_write2, s);
> -    register_ioport_read(addr, size, 2, ioport_read2, s);
> -    register_ioport_write(addr, size, 4, ioport_write4, s);
> -    register_ioport_read(addr, size, 4, ioport_read4, s);
> +static IOPortWriteFunc * const io_writes[] = {
> +    ioport_write1,
> +    ioport_write2,
> +    ioport_write4,
> +};
>
> -    s->region[region_num] = addr;
> -}
> +static IOPortReadFunc * const io_reads[] = {
> +    ioport_read1,
> +    ioport_read2,
> +    ioport_read4,
> +};
>
>   /*****************************************************************************
>    *
> @@ -1610,22 +1602,6 @@ static CPUReadMemoryFunc * const pci_mmio_read[] = {
>       pci_mmio_readl
>   };
>
> -static void pci_mmio_map(PCIDevice * pci_dev, int region_num,
> -                         pcibus_t addr, pcibus_t size, int type)
> -{
> -    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
> -
> -    TRACE(OTHER, logout("region %d, addr=0x%08"FMT_PCIBUS", "
> -          "size=0x%08"FMT_PCIBUS", type=%d\n",
> -          region_num, addr, size, type));
> -
> -    assert(region_num == 0 || region_num == 2);
> -
> -    /* Map control / status registers and flash. */
> -    cpu_register_physical_memory(addr, size, s->mmio_index);
> -    s->region[region_num] = addr;
> -}
> -
>   static int nic_can_receive(VLANClientState *nc)
>   {
>       EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque;
> @@ -1853,6 +1829,7 @@ static int e100_nic_init(PCIDevice *pci_dev)
>       EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
>       E100PCIDeviceInfo *e100_device = DO_UPCAST(E100PCIDeviceInfo, pci.qdev,
>                                                  pci_dev->qdev.info);
> +    int io_index;
>
>       TRACE(OTHER, logout("\n"));
>
> @@ -1868,17 +1845,23 @@ static int e100_nic_init(PCIDevice *pci_dev)
>       s->mmio_index =
>           cpu_register_io_memory(pci_mmio_read, pci_mmio_write, s);
>
> +    /* Map control / status registers. */
>       pci_register_bar(&s->dev, 0, PCI_MEM_SIZE,
>                              PCI_BASE_ADDRESS_SPACE_MEMORY |
> -                           PCI_BASE_ADDRESS_MEM_PREFETCH, pci_mmio_map);
> -    pci_register_bar(&s->dev, 1, PCI_IO_SIZE, PCI_BASE_ADDRESS_SPACE_IO,
> -                           pci_map);
> -    pci_register_bar(&s->dev, 2, PCI_FLASH_SIZE, PCI_BASE_ADDRESS_SPACE_MEMORY,
> -                           pci_mmio_map);
> +                           PCI_BASE_ADDRESS_MEM_PREFETCH);
> +    pci_bar_map(&s->dev, 0, 0, 0, PCI_IO_SIZE, s->mmio_index);
> +
> +    io_index = cpu_register_io(io_reads, io_writes, PCI_IO_SIZE, s);
> +    pci_register_bar(&s->dev, 1, PCI_IO_SIZE, PCI_BASE_ADDRESS_SPACE_IO);
> +    pci_bar_map(&s->dev, 1, 0, 0, PCI_IO_SIZE, io_index);
> +
> +    /* Map flash. */
> +    pci_register_bar(&s->dev, 2, PCI_FLASH_SIZE,
> +                     PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    pci_bar_map(&s->dev, 2, 0, 0, PCI_FLASH_SIZE, s->mmio_index);
>
>       qemu_macaddr_default_if_unset(&s->conf.macaddr);
>       logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6));
> -    assert(s->region[1] == 0);
>
>       nic_reset(s);
>
> diff --git a/hw/es1370.c b/hw/es1370.c
> index 40cb48c..652f0d4 100644
> --- a/hw/es1370.c
> +++ b/hw/es1370.c
> @@ -906,23 +906,17 @@ static void es1370_adc_callback (void *opaque, int avail)
>       es1370_run_channel (s, ADC_CHANNEL, avail);
>   }
>
> -static void es1370_map (PCIDevice *pci_dev, int region_num,
> -                        pcibus_t addr, pcibus_t size, int type)
> -{
> -    ES1370State *s = DO_UPCAST (ES1370State, dev, pci_dev);
> -
> -    (void) region_num;
> -    (void) size;
> -    (void) type;
> -
> -    register_ioport_write (addr, 0x40 * 4, 1, es1370_writeb, s);
> -    register_ioport_write (addr, 0x40 * 2, 2, es1370_writew, s);
> -    register_ioport_write (addr, 0x40, 4, es1370_writel, s);
> +static IOPortWriteFunc * const es1370_writes[] = {
> +    es1370_writeb,
> +    es1370_writew,
> +    es1370_writel,
> +};
>
> -    register_ioport_read (addr, 0x40 * 4, 1, es1370_readb, s);
> -    register_ioport_read (addr, 0x40 * 2, 2, es1370_readw, s);
> -    register_ioport_read (addr, 0x40, 4, es1370_readl, s);
> -}
> +static IOPortReadFunc * const es1370_reads[] = {
> +    es1370_readb,
> +    es1370_readw,
> +    es1370_readl,
> +};
>
>   static const VMStateDescription vmstate_es1370_channel = {
>       .name = "es1370_channel",
> @@ -997,6 +991,7 @@ static int es1370_initfn (PCIDevice *dev)
>   {
>       ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
>       uint8_t *c = s->dev.config;
> +    int io_index;
>
>       pci_config_set_vendor_id (c, PCI_VENDOR_ID_ENSONIQ);
>       pci_config_set_device_id (c, PCI_DEVICE_ID_ENSONIQ_ES1370);
> @@ -1023,7 +1018,10 @@ static int es1370_initfn (PCIDevice *dev)
>       c[PCI_MIN_GNT] = 0x0c;
>       c[PCI_MAX_LAT] = 0x80;
>
> -    pci_register_bar (&s->dev, 0, 256, PCI_BASE_ADDRESS_SPACE_IO, es1370_map);
> +    pci_register_bar (&s->dev, 0, 256, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(es1370_reads, es1370_writes, 256, s);
> +    pci_bar_map(&s->dev, 0, 0, 0, 256, io_index);
> +
>       qemu_register_reset (es1370_on_reset, s);
>
>       AUD_register_card ("es1370",&s->card);
> diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
> index 8b71a13..b30e279 100644
> --- a/hw/ide/cmd646.c
> +++ b/hw/ide/cmd646.c
> @@ -44,29 +44,29 @@
>
>   static void cmd646_update_irq(PCIIDEState *d);
>
> -static void ide_map(PCIDevice *pci_dev, int region_num,
> -                    pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
> -    IDEBus *bus;
> -
> -    if (region_num<= 3) {
> -        bus =&d->bus[(region_num>>  1)];
> -        if (region_num&  1) {
> -            register_ioport_read(addr + 2, 1, 1, ide_status_read, bus);
> -            register_ioport_write(addr + 2, 1, 1, ide_cmd_write, bus);
> -        } else {
> -            register_ioport_write(addr, 8, 1, ide_ioport_write, bus);
> -            register_ioport_read(addr, 8, 1, ide_ioport_read, bus);
> -
> -            /* data ports */
> -            register_ioport_write(addr, 2, 2, ide_data_writew, bus);
> -            register_ioport_read(addr, 2, 2, ide_data_readw, bus);
> -            register_ioport_write(addr, 4, 4, ide_data_writel, bus);
> -            register_ioport_read(addr, 4, 4, ide_data_readl, bus);
> -        }
> -    }
> -}
> +static IOPortWriteFunc * const ide_cmd_writes[] = {
> +    ide_cmd_write,
> +    NULL,
> +    NULL,
> +};
> +
> +static IOPortReadFunc * const ide_status_reads[] = {
> +    ide_status_read,
> +    NULL,
> +    NULL,
> +};
> +
> +static IOPortWriteFunc * const ide_ioport_writes[] = {
> +    ide_ioport_write,
> +    ide_data_writew,
> +    ide_data_writel,
> +};
> +
> +static IOPortReadFunc * const ide_ioport_reads[] = {
> +    ide_ioport_read,
> +    ide_data_readw,
> +    ide_data_readl,
> +};
>
>   static uint32_t bmdma_readb_common(PCIIDEState *pci_dev, BMDMAState *bm,
>                                      uint32_t addr)
> @@ -159,35 +159,41 @@ static void bmdma_writeb_1(void *opaque,
> uint32_t addr, uint32_t val)
>       bmdma_writeb_common(pci_dev, bm, addr, val);
>   }
>
> -static void bmdma_map(PCIDevice *pci_dev, int region_num,
> -                    pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
> -    int i;
> +static IOPortWriteFunc * const bmdma_io_writes_0[] = {
> +    bmdma_writeb_0,
> +    NULL,
> +    NULL,
> +};
>
> -    for(i = 0;i<  2; i++) {
> -        BMDMAState *bm =&d->bmdma[i];
> -        d->bus[i].bmdma = bm;
> -        bm->bus = d->bus+i;
> -        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
> +static IOPortReadFunc * const bmdma_io_reads_0[] = {
> +    bmdma_readb_0,
> +    NULL,
> +    NULL,
> +};
>
> -        if (i == 0) {
> -            register_ioport_write(addr, 4, 1, bmdma_writeb_0, d);
> -            register_ioport_read(addr, 4, 1, bmdma_readb_0, d);
> -        } else {
> -            register_ioport_write(addr, 4, 1, bmdma_writeb_1, d);
> -            register_ioport_read(addr, 4, 1, bmdma_readb_1, d);
> -        }
> +static IOPortWriteFunc * const bmdma_io_writes_1[] = {
> +    bmdma_writeb_1,
> +    NULL,
> +    NULL,
> +};
>
> -        register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
> -        register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
> -        register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
> -        register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
> -        register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
> -        register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
> -        addr += 8;
> -    }
> -}
> +static IOPortReadFunc * const bmdma_io_reads_1[] = {
> +    bmdma_readb_1,
> +    NULL,
> +    NULL,
> +};
> +
> +static IOPortWriteFunc * const bmdma_addr_writes[] = {
> +    bmdma_addr_writeb,
> +    bmdma_addr_writew,
> +    bmdma_addr_writel,
> +};
> +
> +static IOPortReadFunc * const bmdma_addr_reads[] = {
> +    bmdma_addr_readb,
> +    bmdma_addr_readw,
> +    bmdma_addr_readl,
> +};
>
>   /* XXX: call it also when the MRDMODE is changed from the PCI config
>      registers */
> @@ -232,6 +238,8 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
>       PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
>       uint8_t *pci_conf = d->dev.config;
>       qemu_irq *irq;
> +    unsigned int i;
> +    int io_index;
>
>       pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CMD);
>       pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_CMD_646);
> @@ -248,11 +256,38 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
>           pci_conf[0x51] |= 0x08; /* enable IDE1 */
>       }
>
> -    pci_register_bar(dev, 0, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
> -    pci_register_bar(dev, 1, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
> -    pci_register_bar(dev, 2, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
> -    pci_register_bar(dev, 3, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
> -    pci_register_bar(dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
> +    pci_register_bar(dev, 0, 0x8, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(ide_ioport_reads, ide_ioport_writes,
> 8,&d->bus[0]);
> +    pci_bar_map(&d->dev, 0, 0, 8, 8, io_index);
> +    pci_register_bar(dev, 1, 0x4, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(ide_status_reads, ide_cmd_writes, 1,
> &d->bus[0]);
> +    pci_bar_map(&d->dev, 1, 0, 1, 1, io_index);
> +    pci_register_bar(dev, 2, 0x8, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(ide_ioport_reads, ide_ioport_writes,
> 8,&d->bus[1]);
> +    pci_bar_map(&d->dev, 2, 0, 8, 8, io_index);
> +    pci_register_bar(dev, 3, 0x4, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(ide_status_reads, ide_cmd_writes, 1,
> &d->bus[1]);
> +    pci_bar_map(&d->dev, 3, 0, 1, 1, io_index);
> +    pci_register_bar(dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO);
> +    for (i = 0; i<  2; i++) {
> +        BMDMAState *bm =&d->bmdma[i];
> +
> +        d->bus[i].bmdma = bm;
> +        bm->bus = d->bus+i;
> +        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
> +
> +        if (i == 0) {
> +            io_index = cpu_register_io(bmdma_io_reads_0, bmdma_io_writes_0,
> +                                       1, d);
> +        } else {
> +            io_index = cpu_register_io(bmdma_io_reads_1, bmdma_io_writes_1,
> +                                       1, d);
> +        }
> +        pci_bar_map(&d->dev, 4, i * 4 + 0, 0, 1, io_index);
> +
> +        io_index = cpu_register_io(bmdma_addr_reads, bmdma_addr_writes, 4, bm);
> +        pci_bar_map(&d->dev, 4, i * 4 + 4, 4, 4, io_index);
> +    }
>
>       /* TODO: RST# value should be 0 */
>       pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
> diff --git a/hw/ide/piix.c b/hw/ide/piix.c
> index 9223834..0506990 100644
> --- a/hw/ide/piix.c
> +++ b/hw/ide/piix.c
> @@ -68,32 +68,35 @@ static void bmdma_writeb(void *opaque, uint32_t
> addr, uint32_t val)
>       }
>   }
>
> -static void bmdma_map(PCIDevice *pci_dev, int region_num,
> -                    pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
> -    int i;
> +static IOPortWriteFunc * const bmdma_cmd_io_writes[] = {
> +    bmdma_cmd_writeb,
> +    NULL,
> +    NULL,
> +};
>
> -    for(i = 0;i<  2; i++) {
> -        BMDMAState *bm =&d->bmdma[i];
> -        d->bus[i].bmdma = bm;
> -        bm->bus = d->bus+i;
> -        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
> +static IOPortWriteFunc * const bmdma_io_writes[] = {
> +    bmdma_writeb,
> +    NULL,
> +    NULL,
> +};
>
> -        register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
> +static IOPortReadFunc * const bmdma_io_reads[] = {
> +    bmdma_readb,
> +    NULL,
> +    NULL,
> +};
>
> -        register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
> -        register_ioport_read(addr, 4, 1, bmdma_readb, bm);
> +static IOPortWriteFunc * const bmdma_addr_writes[] = {
> +    bmdma_addr_writeb,
> +    bmdma_addr_writew,
> +    bmdma_addr_writel,
> +};
>
> -        register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
> -        register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
> -        register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
> -        register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
> -        register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
> -        register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
> -        addr += 8;
> -    }
> -}
> +static IOPortReadFunc * const bmdma_addr_reads[] = {
> +    bmdma_addr_readb,
> +    bmdma_addr_readw,
> +    bmdma_addr_readl,
> +};
>
>   static void piix3_reset(void *opaque)
>   {
> @@ -119,6 +122,8 @@ static void piix3_reset(void *opaque)
>   static int pci_piix_ide_initfn(PCIIDEState *d)
>   {
>       uint8_t *pci_conf = d->dev.config;
> +    unsigned int i;
> +    int io_index;
>
>       pci_conf[PCI_CLASS_PROG] = 0x80; // legacy ATA mode
>       pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
> @@ -126,7 +131,22 @@ static int pci_piix_ide_initfn(PCIIDEState *d)
>
>       qemu_register_reset(piix3_reset, d);
>
> -    pci_register_bar(&d->dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
> +    pci_register_bar(&d->dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO);
> +    for (i = 0; i<  2; i++) {
> +        BMDMAState *bm =&d->bmdma[i];
> +
> +        d->bus[i].bmdma = bm;
> +        bm->bus = d->bus + i;
> +        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
> +        io_index = cpu_register_io(NULL, bmdma_cmd_io_writes, 1, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 0, 0, 1, io_index);
> +        io_index = cpu_register_io(NULL, bmdma_io_writes, 3, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 1, 1, 3, io_index);
> +        io_index = cpu_register_io(bmdma_io_reads, NULL, 4, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 2, 0, 4, io_index);
> +        io_index = cpu_register_io(bmdma_addr_reads, bmdma_addr_writes, 4, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 3, 4, 4, io_index);
> +    }
>
>       vmstate_register(&d->dev.qdev, 0,&vmstate_ide_pci, d);
>
> diff --git a/hw/ide/via.c b/hw/ide/via.c
> index a403e8c..d2f5d00 100644
> --- a/hw/ide/via.c
> +++ b/hw/ide/via.c
> @@ -70,32 +70,35 @@ static void bmdma_writeb(void *opaque, uint32_t
> addr, uint32_t val)
>       }
>   }
>
> -static void bmdma_map(PCIDevice *pci_dev, int region_num,
> -                    pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
> -    int i;
> +static IOPortWriteFunc * const bmdma_cmd_io_writes[] = {
> +    bmdma_cmd_writeb,
> +    NULL,
> +    NULL,
> +};
>
> -    for(i = 0;i<  2; i++) {
> -        BMDMAState *bm =&d->bmdma[i];
> -        d->bus[i].bmdma = bm;
> -        bm->bus = d->bus+i;
> -        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
> +static IOPortWriteFunc * const bmdma_io_writes[] = {
> +    bmdma_writeb,
> +    NULL,
> +    NULL,
> +};
>
> -        register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
> +static IOPortReadFunc * const bmdma_io_reads[] = {
> +    bmdma_readb,
> +    NULL,
> +    NULL,
> +};
>
> -        register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
> -        register_ioport_read(addr, 4, 1, bmdma_readb, bm);
> +static IOPortWriteFunc * const bmdma_addr_writes[] = {
> +    bmdma_addr_writeb,
> +    bmdma_addr_writew,
> +    bmdma_addr_writel,
> +};
>
> -        register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
> -        register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
> -        register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
> -        register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
> -        register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
> -        register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
> -        addr += 8;
> -    }
> -}
> +static IOPortReadFunc * const bmdma_addr_reads[] = {
> +    bmdma_addr_readb,
> +    bmdma_addr_readw,
> +    bmdma_addr_readl,
> +};
>
>   static void via_reset(void *opaque)
>   {
> @@ -144,6 +147,8 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
>   {
>       PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);;
>       uint8_t *pci_conf = d->dev.config;
> +    unsigned int i;
> +    int io_index;
>
>       pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA);
>       pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_IDE);
> @@ -154,8 +159,22 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
>       pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
>
>       qemu_register_reset(via_reset, d);
> -    pci_register_bar((PCIDevice *)d, 4, 0x10,
> -                           PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
> +    pci_register_bar((PCIDevice *)d, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO);
> +    for (i = 0; i<  2; i++) {
> +        BMDMAState *bm =&d->bmdma[i];
> +
> +        d->bus[i].bmdma = bm;
> +        bm->bus = d->bus + i;
> +        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
> +        io_index = cpu_register_io(NULL, bmdma_cmd_io_writes, 1, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 0, 0, 1, io_index);
> +        io_index = cpu_register_io(NULL, bmdma_io_writes, 3, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 1, 1, 3, io_index);
> +        io_index = cpu_register_io(bmdma_io_reads, NULL, 4, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 2, 0, 4, io_index);
> +        io_index = cpu_register_io(bmdma_addr_reads, bmdma_addr_writes, 4, bm);
> +        pci_bar_map(&d->dev, 0, i * 4 + 3, 4, 4, io_index);
> +    }
>
>       vmstate_register(&dev->qdev, 0,&vmstate_ide_pci, d);
>
> diff --git a/hw/isa.h b/hw/isa.h
> index aaf0272..6fba4ac 100644
> --- a/hw/isa.h
> +++ b/hw/isa.h
> @@ -33,6 +33,7 @@ ISADevice *isa_create_simple(const char *name);
>   extern target_phys_addr_t isa_mem_base;
>
>   void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size, int be);
> +int pci_isa_mmio_init(int be);
>
>   /* dma.c */
>   int DMA_get_channel_mode (int nchan);
> diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c
> index 66bdd2c..3b2de4a 100644
> --- a/hw/isa_mmio.c
> +++ b/hw/isa_mmio.c
> @@ -125,7 +125,7 @@ static CPUReadMemoryFunc * const isa_mmio_read_le[] = {
>
>   static int isa_mmio_iomemtype = 0;
>
> -void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size, int be)
> +static int isa_mmio_memtype(int be)
>   {
>       if (!isa_mmio_iomemtype) {
>           if (be) {
> @@ -138,5 +138,18 @@ void isa_mmio_init(target_phys_addr_t base,
> target_phys_addr_t size, int be)
>                                                           NULL);
>           }
>       }
> -    cpu_register_physical_memory(base, size, isa_mmio_iomemtype);
> +    return isa_mmio_iomemtype;
> +}
> +
> +void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size, int be)
> +{
> +    int isa;
> +
> +    isa = isa_mmio_memtype(be);
> +    cpu_register_physical_memory(base, size, isa);
> +}
> +
> +int pci_isa_mmio_init(int be)
> +{
> +    return isa_mmio_memtype(be);
>   }
> diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
> index bd7b661..32de5d1 100644
> --- a/hw/lsi53c895a.c
> +++ b/hw/lsi53c895a.c
> @@ -186,7 +186,6 @@ typedef struct {
>       PCIDevice dev;
>       int mmio_io_addr;
>       int ram_io_addr;
> -    uint32_t script_ram_base;
>
>       int carry; /* ??? Should this be an a visible register somewhere?  */
>       int sense;
> @@ -390,10 +389,6 @@ static inline uint32_t read_dword(LSIState *s,
> uint32_t addr)
>   {
>       uint32_t buf;
>
> -    /* Optimize reading from SCRIPTS RAM.  */
> -    if ((addr&  0xffffe000) == s->script_ram_base) {
> -        return s->script_ram[(addr&  0x1fff)>>  2];
> -    }
>       cpu_physical_memory_read(addr, (uint8_t *)&buf, 4);
>       return cpu_to_le32(buf);
>   }
> @@ -2004,39 +1999,17 @@ static void lsi_io_writel(void *opaque,
> uint32_t addr, uint32_t val)
>       lsi_reg_writeb(s, addr + 3, (val>>  24)&  0xff);
>   }
>
> -static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num,
> -                           pcibus_t addr, pcibus_t size, int type)
> -{
> -    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
> -
> -    DPRINTF("Mapping IO at %08"FMT_PCIBUS"\n", addr);
> -
> -    register_ioport_write(addr, 256, 1, lsi_io_writeb, s);
> -    register_ioport_read(addr, 256, 1, lsi_io_readb, s);
> -    register_ioport_write(addr, 256, 2, lsi_io_writew, s);
> -    register_ioport_read(addr, 256, 2, lsi_io_readw, s);
> -    register_ioport_write(addr, 256, 4, lsi_io_writel, s);
> -    register_ioport_read(addr, 256, 4, lsi_io_readl, s);
> -}
> -
> -static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num,
> -                            pcibus_t addr, pcibus_t size, int type)
> -{
> -    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
> -
> -    DPRINTF("Mapping ram at %08"FMT_PCIBUS"\n", addr);
> -    s->script_ram_base = addr;
> -    cpu_register_physical_memory(addr + 0, 0x2000, s->ram_io_addr);
> -}
> -
> -static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
> -                             pcibus_t addr, pcibus_t size, int type)
> -{
> -    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
> +static IOPortWriteFunc * const lsi_io_writes[] = {
> +    lsi_io_writeb,
> +    lsi_io_writew,
> +    lsi_io_writel,
> +};
>
> -    DPRINTF("Mapping registers at %08"FMT_PCIBUS"\n", addr);
> -    cpu_register_physical_memory(addr + 0, 0x400, s->mmio_io_addr);
> -}
> +static IOPortReadFunc * const lsi_io_reads[] = {
> +    lsi_io_readb,
> +    lsi_io_readw,
> +    lsi_io_readl,
> +};
>
>   static void lsi_scsi_reset(DeviceState *dev)
>   {
> @@ -2153,6 +2126,7 @@ static int lsi_scsi_init(PCIDevice *dev)
>   {
>       LSIState *s = DO_UPCAST(LSIState, dev, dev);
>       uint8_t *pci_conf;
> +    int io_index;
>
>       pci_conf = s->dev.config;
>
> @@ -2177,12 +2151,16 @@ static int lsi_scsi_init(PCIDevice *dev)
>                                               lsi_ram_writefn, s);
>
>       /* TODO: use dev and get rid of cast below */
> -    pci_register_bar((struct PCIDevice *)s, 0, 256,
> -                           PCI_BASE_ADDRESS_SPACE_IO, lsi_io_mapfunc);
> +    pci_register_bar((struct PCIDevice *)s, 0, 256, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(lsi_io_reads, lsi_io_writes, 256, s);
> +    pci_bar_map((struct PCIDevice *)s, 0, 0, 0, 256, io_index);
> +
>       pci_register_bar((struct PCIDevice *)s, 1, 0x400,
> -                           PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_mmio_mapfunc);
> +                           PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    pci_bar_map((struct PCIDevice *)s, 1, 0, 0, 0x400, s->mmio_io_addr);
>       pci_register_bar((struct PCIDevice *)s, 2, 0x2000,
> -                           PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
> +                           PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    pci_bar_map((struct PCIDevice *)s, 2, 0, 0, 0x2000, s->ram_io_addr);
>       QTAILQ_INIT(&s->queue);
>
>       scsi_bus_new(&s->bus,&dev->qdev, 1, LSI_MAX_DEVS, lsi_command_complete);
> diff --git a/hw/macio.c b/hw/macio.c
> index e92e82a..653b4df 100644
> --- a/hw/macio.c
> +++ b/hw/macio.c
> @@ -27,83 +27,16 @@
>   #include "pci.h"
>   #include "escc.h"
>
> -typedef struct macio_state_t macio_state_t;
> -struct macio_state_t {
> -    int is_oldworld;
> -    int pic_mem_index;
> -    int dbdma_mem_index;
> -    int cuda_mem_index;
> -    int escc_mem_index;
> -    void *nvram;
> -    int nb_ide;
> -    int ide_mem_index[4];
> -};
> -
> -static void macio_map (PCIDevice *pci_dev, int region_num,
> -                       pcibus_t addr, pcibus_t size, int type)
> -{
> -    macio_state_t *macio_state;
> -    int i;
> -
> -    macio_state = (macio_state_t *)(pci_dev + 1);
> -    if (macio_state->pic_mem_index>= 0) {
> -        if (macio_state->is_oldworld) {
> -            /* Heathrow PIC */
> -            cpu_register_physical_memory(addr + 0x00000, 0x1000,
> -                                         macio_state->pic_mem_index);
> -        } else {
> -            /* OpenPIC */
> -            cpu_register_physical_memory(addr + 0x40000, 0x40000,
> -                                         macio_state->pic_mem_index);
> -        }
> -    }
> -    if (macio_state->dbdma_mem_index>= 0) {
> -        cpu_register_physical_memory(addr + 0x08000, 0x1000,
> -                                     macio_state->dbdma_mem_index);
> -    }
> -    if (macio_state->escc_mem_index>= 0) {
> -        cpu_register_physical_memory(addr + 0x13000, ESCC_SIZE<<  4,
> -                                     macio_state->escc_mem_index);
> -    }
> -    if (macio_state->cuda_mem_index>= 0) {
> -        cpu_register_physical_memory(addr + 0x16000, 0x2000,
> -                                     macio_state->cuda_mem_index);
> -    }
> -    for (i = 0; i<  macio_state->nb_ide; i++) {
> -        if (macio_state->ide_mem_index[i]>= 0) {
> -            cpu_register_physical_memory(addr + 0x1f000 + (i * 0x1000), 0x1000,
> -                                         macio_state->ide_mem_index[i]);
> -        }
> -    }
> -    if (macio_state->nvram != NULL)
> -        macio_nvram_map(macio_state->nvram, addr + 0x60000);
> -}
> -
>   void macio_init (PCIBus *bus, int device_id, int is_oldworld, int
> pic_mem_index,
> -                 int dbdma_mem_index, int cuda_mem_index, void *nvram,
> -                 int nb_ide, int *ide_mem_index, int escc_mem_index)
> +                 int dbdma_mem_index, int cuda_mem_index, int nvram_size,
> +                 int nvram_mem_index, int nb_ide, int *ide_mem_index,
> +                 int escc_mem_index)
>   {
>       PCIDevice *d;
> -    macio_state_t *macio_state;
>       int i;
>
> -    d = pci_register_device(bus, "macio",
> -                            sizeof(PCIDevice) + sizeof(macio_state_t),
> -                            -1, NULL, NULL);
> -    macio_state = (macio_state_t *)(d + 1);
> -    macio_state->is_oldworld = is_oldworld;
> -    macio_state->pic_mem_index = pic_mem_index;
> -    macio_state->dbdma_mem_index = dbdma_mem_index;
> -    macio_state->cuda_mem_index = cuda_mem_index;
> -    macio_state->escc_mem_index = escc_mem_index;
> -    macio_state->nvram = nvram;
> -    if (nb_ide>  4)
> -        nb_ide = 4;
> -    macio_state->nb_ide = nb_ide;
> -    for (i = 0; i<  nb_ide; i++)
> -        macio_state->ide_mem_index[i] = ide_mem_index[i];
> -    for (; i<  4; i++)
> -        macio_state->ide_mem_index[i] = -1;
> +    d = pci_register_device(bus, "macio", sizeof(PCIDevice), -1, NULL, NULL);
> +
>       /* Note: this code is strongly inspirated from the corresponding code
>          in PearPC */
>
> @@ -114,6 +47,32 @@ void macio_init (PCIBus *bus, int device_id, int
> is_oldworld, int pic_mem_index,
>
>       d->config[0x3d] = 0x01; // interrupt on pin 1
>
> -    pci_register_bar(d, 0, 0x80000,
> -                           PCI_BASE_ADDRESS_SPACE_MEMORY, macio_map);
> +    pci_register_bar(d, 0, 0x80000, PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    if (pic_mem_index>= 0) {
> +        if (is_oldworld) {
> +            /* Heathrow PIC */
> +            pci_bar_map(d, 0, 0, 0x1000, 0, pic_mem_index);
> +        } else {
> +            /* OpenPIC */
> +            pci_bar_map(d, 0, 0, 0x40000, 0x40000, pic_mem_index);
> +        }
> +    }
> +    if (dbdma_mem_index>= 0) {
> +        pci_bar_map(d, 0, 1, 0x8000, 0x1000, dbdma_mem_index);
> +    }
> +    if (escc_mem_index>= 0) {
> +        pci_bar_map(d, 0, 2, 0x13000, ESCC_SIZE<<  4, escc_mem_index);
> +    }
> +    if (cuda_mem_index>= 0) {
> +        pci_bar_map(d, 0, 3, 0x16000, 0x2000, cuda_mem_index);
> +    }
> +    for (i = 0; i<  nb_ide; i++) {
> +        if (ide_mem_index[i]>= 0) {
> +            pci_bar_map(d, 0, 4 + i, 0x1f000 + (i * 0x1000), 0x1000,
> +                        ide_mem_index[i]);
> +        }
> +    }
> +    if (nvram_mem_index>= 0) {
> +        pci_bar_map(d, 0, 4 + nb_ide, 0x60000, nvram_size, nvram_mem_index);
> +    }
>   }
> diff --git a/hw/ne2000.c b/hw/ne2000.c
> index 78fe14f..7598e76 100644
> --- a/hw/ne2000.c
> +++ b/hw/ne2000.c
> @@ -464,6 +464,18 @@ uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
>       return ret;
>   }
>
> +static IOPortWriteFunc * const ne2000_io_writes[] = {
> +    ne2000_ioport_write,
> +    NULL,
> +    NULL,
> +};
> +
> +static IOPortReadFunc * const ne2000_io_reads[] = {
> +    ne2000_ioport_read,
> +    NULL,
> +    NULL,
> +};
> +
>   static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr,
>                                        uint32_t val)
>   {
> @@ -611,6 +623,18 @@ static uint32_t ne2000_asic_ioport_readl(void
> *opaque, uint32_t addr)
>       return ret;
>   }
>
> +static IOPortWriteFunc * const ne2000_asic_io_writes[] = {
> +    ne2000_asic_ioport_write,
> +    ne2000_asic_ioport_write,
> +    ne2000_asic_ioport_writel,
> +};
> +
> +static IOPortReadFunc * const ne2000_asic_io_reads[] = {
> +    ne2000_asic_ioport_read,
> +    ne2000_asic_ioport_read,
> +    ne2000_asic_ioport_readl,
> +};
> +
>   void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val)
>   {
>       /* nothing to do (end of reset pulse) */
> @@ -623,6 +647,18 @@ uint32_t ne2000_reset_ioport_read(void *opaque,
> uint32_t addr)
>       return 0;
>   }
>
> +static IOPortWriteFunc * const ne2000_reset_io_writes[] = {
> +    ne2000_reset_ioport_write,
> +    NULL,
> +    NULL,
> +};
> +
> +static IOPortReadFunc * const ne2000_reset_io_reads[] = {
> +    ne2000_reset_ioport_read,
> +    NULL,
> +    NULL,
> +};
> +
>   static int ne2000_post_load(void* opaque, int version_id)
>   {
>       NE2000State* s = opaque;
> @@ -678,26 +714,6 @@ static const VMStateDescription vmstate_pci_ne2000 = {
>   /***********************************************************/
>   /* PCI NE2000 definitions */
>
> -static void ne2000_map(PCIDevice *pci_dev, int region_num,
> -                       pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
> -    NE2000State *s =&d->ne2000;
> -
> -    register_ioport_write(addr, 16, 1, ne2000_ioport_write, s);
> -    register_ioport_read(addr, 16, 1, ne2000_ioport_read, s);
> -
> -    register_ioport_write(addr + 0x10, 1, 1, ne2000_asic_ioport_write, s);
> -    register_ioport_read(addr + 0x10, 1, 1, ne2000_asic_ioport_read, s);
> -    register_ioport_write(addr + 0x10, 2, 2, ne2000_asic_ioport_write, s);
> -    register_ioport_read(addr + 0x10, 2, 2, ne2000_asic_ioport_read, s);
> -    register_ioport_write(addr + 0x10, 4, 4, ne2000_asic_ioport_writel, s);
> -    register_ioport_read(addr + 0x10, 4, 4, ne2000_asic_ioport_readl, s);
> -
> -    register_ioport_write(addr + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
> -    register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
> -}
> -
>   static void ne2000_cleanup(VLANClientState *nc)
>   {
>       NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
> @@ -718,6 +734,7 @@ static int pci_ne2000_init(PCIDevice *pci_dev)
>       PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
>       NE2000State *s;
>       uint8_t *pci_conf;
> +    int io_index;
>
>       pci_conf = d->dev.config;
>       pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK);
> @@ -727,9 +744,14 @@ static int pci_ne2000_init(PCIDevice *pci_dev)
>       /* TODO: RST# value should be 0. PCI spec 6.2.4 */
>       pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
>
> -    pci_register_bar(&d->dev, 0, 0x100,
> -                           PCI_BASE_ADDRESS_SPACE_IO, ne2000_map);
>       s =&d->ne2000;
> +    pci_register_bar(&d->dev, 0, 0x100, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(ne2000_io_reads, ne2000_io_writes, 16, s);
> +    pci_bar_map(&d->dev, 0, 0, 0, 16, io_index);
> +    io_index = cpu_register_io(ne2000_asic_io_reads,
> ne2000_asic_io_writes, 4, s);
> +    pci_bar_map(&d->dev, 0, 1, 0x10, 4, io_index);
> +    io_index = cpu_register_io(ne2000_reset_io_reads,
> ne2000_reset_io_writes, 1, s);
> +    pci_bar_map(&d->dev, 0, 2, 0x1f, 1, io_index);
>       s->irq = d->dev.irq[0];
>
>       qemu_macaddr_default_if_unset(&s->c.macaddr);
> diff --git a/hw/openpic.c b/hw/openpic.c
> index 2b4cb00..ed1903d 100644
> --- a/hw/openpic.c
> +++ b/hw/openpic.c
> @@ -1013,34 +1013,6 @@ static CPUReadMemoryFunc * const openpic_read[] = {
>       &openpic_readl,
>   };
>
> -static void openpic_map(PCIDevice *pci_dev, int region_num,
> -                        pcibus_t addr, pcibus_t size, int type)
> -{
> -    openpic_t *opp;
> -
> -    DPRINTF("Map OpenPIC\n");
> -    opp = (openpic_t *)pci_dev;
> -    /* Global registers */
> -    DPRINTF("Register OPENPIC gbl   %08x =>  %08x\n",
> -            addr + 0x1000, addr + 0x1000 + 0x100);
> -    /* Timer registers */
> -    DPRINTF("Register OPENPIC timer %08x =>  %08x\n",
> -            addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
> -    /* Interrupt source registers */
> -    DPRINTF("Register OPENPIC src   %08x =>  %08x\n",
> -            addr + 0x10000, addr + 0x10000 + 0x20 * (OPENPIC_EXT_IRQ + 2));
> -    /* Per CPU registers */
> -    DPRINTF("Register OPENPIC dst   %08x =>  %08x\n",
> -            addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
> -    cpu_register_physical_memory(addr, 0x40000, opp->mem_index);
> -#if 0 // Don't implement ISU for now
> -    opp_io_memory = cpu_register_io_memory(openpic_src_read,
> -                                           openpic_src_write);
> -    cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
> -                                 opp_io_memory);
> -#endif
> -}
> -
>   static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
>   {
>       unsigned int i;
> @@ -1199,12 +1171,14 @@ qemu_irq *openpic_init (PCIBus *bus, int
> *pmem_index, int nb_cpus,
>
>           /* Register I/O spaces */
>           pci_register_bar((PCIDevice *)opp, 0, 0x40000,
> -                               PCI_BASE_ADDRESS_SPACE_MEMORY,&openpic_map);
> +                               PCI_BASE_ADDRESS_SPACE_MEMORY);
>       } else {
>           opp = qemu_mallocz(sizeof(openpic_t));
>       }
> -    opp->mem_index = cpu_register_io_memory(openpic_read,
> -                                            openpic_write, opp);
> +    opp->mem_index = cpu_register_io_memory(openpic_read, openpic_write, opp);
> +    if (bus) {
> +        pci_bar_map((PCIDevice *)opp, 0, 0, 0x40000, 0, opp->mem_index);
> +    }
>
>       //    isu_base&= 0xFFFC0000;
>       opp->nb_cpus = nb_cpus;
> diff --git a/hw/pci.c b/hw/pci.c
> index a7ff566..fd4b1bb 100644
> --- a/hw/pci.c
> +++ b/hw/pci.c
> @@ -681,19 +681,28 @@ static target_phys_addr_t pci_to_cpu_addr(PCIBus *bus,
>   static void pci_unregister_io_regions(PCIDevice *pci_dev)
>   {
>       PCIIORegion *r;
> -    int i;
> +    PCIIOSubRegion *s;
> +    int i, j;
>
>       for(i = 0; i<  PCI_NUM_REGIONS; i++) {
>           r =&pci_dev->io_regions[i];
>           if (!r->size || r->addr == PCI_BAR_UNMAPPED)
>               continue;
> -        if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {
> -            isa_unassign_ioport(r->addr, r->filtered_size);
> -        } else {
> -            cpu_register_physical_memory(pci_to_cpu_addr(pci_dev->bus,
> -                                                         r->addr),
> -                                         r->filtered_size,
> -                                         IO_MEM_UNASSIGNED);
> +
> +        for (j = 0; j<  PCI_NUM_SUBREGIONS; j++) {
> +            s =&r->subregions[j];
> +
> +            if (!s->size) {
> +                continue;
> +            }
> +            if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {
> +                isa_unassign_ioport(r->addr + s->offset, s->filtered_size);
> +            } else {
> +                cpu_register_physical_memory(pci_to_cpu_addr(pci_dev->bus,
> +                                                         r->addr + s->offset),
> +                                             s->filtered_size,
> +                                             IO_MEM_UNASSIGNED);
> +            }
>           }
>       }
>   }
> @@ -716,8 +725,7 @@ static int pci_unregister_device(DeviceState *dev)
>   }
>
>   void pci_register_bar(PCIDevice *pci_dev, int region_num,
> -                            pcibus_t size, int type,
> -                            PCIMapIORegionFunc *map_func)
> +                      pcibus_t size, int type)
>   {
>       PCIIORegion *r;
>       uint32_t addr;
> @@ -735,9 +743,7 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
>       r =&pci_dev->io_regions[region_num];
>       r->addr = PCI_BAR_UNMAPPED;
>       r->size = size;
> -    r->filtered_size = size;
>       r->type = type;
> -    r->map_func = map_func;
>
>       wmask = ~(size - 1);
>       addr = pci_bar(pci_dev, region_num);
> @@ -756,6 +762,23 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
>       }
>   }
>
> +void pci_bar_map(PCIDevice *pci_dev, int region_num, int subregion_num,
> +                 pcibus_t offset, pcibus_t size, int ix)
> +{
> +    PCIIOSubRegion *s;
> +
> +    if ((unsigned int)region_num>= PCI_NUM_REGIONS ||
> +        (unsigned int)subregion_num>= PCI_NUM_SUBREGIONS) {
> +        return;
> +    }
> +
> +    s =&pci_dev->io_regions[region_num].subregions[subregion_num];
> +
> +    s->offset = offset;
> +    s->size = size;
> +    s->ix = ix;
> +}
> +
>   static uint32_t pci_config_get_io_base(PCIDevice *d,
>                                          uint32_t base, uint32_t base_upper16)
>   {
> @@ -928,8 +951,9 @@ static pcibus_t pci_bar_address(PCIDevice *d,
>   static void pci_update_mappings(PCIDevice *d)
>   {
>       PCIIORegion *r;
> -    int i;
> -    pcibus_t new_addr, filtered_size;
> +    PCIIOSubRegion *s;
> +    int i, j;
> +    pcibus_t bar_addr, new_addr, filtered_size;
>
>       for(i = 0; i<  PCI_NUM_REGIONS; i++) {
>           r =&d->io_regions[i];
> @@ -938,54 +962,71 @@ static void pci_update_mappings(PCIDevice *d)
>           if (!r->size)
>               continue;
>
> -        new_addr = pci_bar_address(d, i, r->type, r->size);
> +        bar_addr = pci_bar_address(d, i, r->type, r->size);
>
> -        /* bridge filtering */
> -        filtered_size = r->size;
> -        if (new_addr != PCI_BAR_UNMAPPED) {
> -            pci_bridge_filter(d,&new_addr,&filtered_size, r->type);
> -        }
> +        for (j = 0; j<  PCI_NUM_SUBREGIONS; j++) {
> +            s =&r->subregions[j];
>
> -        /* This bar isn't changed */
> -        if (new_addr == r->addr&&  filtered_size == r->filtered_size)
> -            continue;
> +            /* this region isn't registered */
> +            if (!s->size) {
> +                continue;
> +            }
>
> -        /* now do the real mapping */
> -        if (r->addr != PCI_BAR_UNMAPPED) {
> -            if (r->type&  PCI_BASE_ADDRESS_SPACE_IO) {
> -                int class;
> -                /* NOTE: specific hack for IDE in PC case:
> -                   only one byte must be mapped. */
> -                class = pci_get_word(d->config + PCI_CLASS_DEVICE);
> -                if (class == 0x0101&&  r->size == 4) {
> -                    isa_unassign_ioport(r->addr + 2, 1);
> +            new_addr = bar_addr + s->offset;
> +            /* bridge filtering */
> +            filtered_size = s->size;
> +            if (bar_addr != PCI_BAR_UNMAPPED) {
> +                pci_bridge_filter(d,&new_addr,&filtered_size, r->type);
> +            }
> +
> +            /* This bar isn't changed */
> +            if (new_addr == r->addr + s->offset&&
> +                filtered_size == s->filtered_size)
> +                continue;
> +
> +            /* now do the real mapping */
> +            if (r->addr != PCI_BAR_UNMAPPED) {
> +                if (r->type&  PCI_BASE_ADDRESS_SPACE_IO) {
> +                    int class;
> +                    /* NOTE: specific hack for IDE in PC case:
> +                       only one byte must be mapped. */
> +                    class = pci_get_word(d->config + PCI_CLASS_DEVICE);
> +                    if (class == 0x0101&&  r->size == 4) {
> +                        isa_unassign_ioport(r->addr + s->offset + 2, 1);
> +                    } else {
> +                        isa_unassign_ioport(r->addr + s->offset,
> +                                            s->filtered_size);
> +                    }
>                   } else {
> -                    isa_unassign_ioport(r->addr, r->filtered_size);
> +                    cpu_register_physical_memory(pci_to_cpu_addr(d->bus,
> +                                                                 r->addr +
> +                                                                 s->offset),
> +                                                 s->filtered_size,
> +                                                 IO_MEM_UNASSIGNED);
> +                    qemu_unregister_coalesced_mmio(r->addr + s->offset,
> +                                                   s->filtered_size);
>                   }
> -            } else {
> -                cpu_register_physical_memory(pci_to_cpu_addr(d->bus, r->addr),
> -                                             r->filtered_size,
> -                                             IO_MEM_UNASSIGNED);
> -                qemu_unregister_coalesced_mmio(r->addr, r->filtered_size);
>               }
> -        }
> -        r->addr = new_addr;
> -        r->filtered_size = filtered_size;
> -        if (r->addr != PCI_BAR_UNMAPPED) {
> -            /*
> -             * TODO: currently almost all the map funcions assumes
> -             * filtered_size == size and addr&  ~(size - 1) == addr.
> -             * However with bridge filtering, they aren't always true.
> -             * Teach them such cases, such that filtered_size<  size and
> -             * addr&  (size - 1) != 0.
> -             */
> -            if (r->type&  PCI_BASE_ADDRESS_SPACE_IO) {
> -                r->map_func(d, i, r->addr, r->filtered_size, r->type);
> -            } else {
> -                r->map_func(d, i, pci_to_cpu_addr(d->bus, r->addr),
> -                            r->filtered_size, r->type);
> +            s->filtered_size = filtered_size;
> +            if (new_addr != PCI_BAR_UNMAPPED) {
> +                /*
> +                 * TODO: currently almost all the map funcions assumes
> +                 * filtered_size == size and addr&  ~(size - 1) == addr.
> +                 * However with bridge filtering, they aren't always true.
> +                 * Teach them such cases, such that filtered_size<  size and
> +                 * addr&  (size - 1) != 0.
> +                 */
> +                if (r->type&  PCI_BASE_ADDRESS_SPACE_IO) {
> +                    cpu_map_io(new_addr, s->ix);
> +                } else {
> +                    cpu_register_physical_memory(pci_to_cpu_addr(d->bus,
> +                                                                 new_addr),
> +                                                 s->filtered_size,
> +                                                 s->ix);
> +                }
>               }
>           }
> +        r->addr = bar_addr;
>       }
>   }
>
> @@ -1704,11 +1745,6 @@ static uint8_t
> pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
>       return next;
>   }
>
> -static void pci_map_option_rom(PCIDevice *pdev, int region_num,
> pcibus_t addr, pcibus_t size, int type)
> -{
> -    cpu_register_physical_memory(addr, size, pdev->rom_offset);
> -}
> -
>   /* Add an option rom for the device */
>   static int pci_add_option_rom(PCIDevice *pdev)
>   {
> @@ -1761,8 +1797,8 @@ static int pci_add_option_rom(PCIDevice *pdev)
>       load_image(path, ptr);
>       qemu_free(path);
>
> -    pci_register_bar(pdev, PCI_ROM_SLOT, size,
> -                     0, pci_map_option_rom);
> +    pci_register_bar(pdev, PCI_ROM_SLOT, size, 0);
> +    pci_bar_map(pdev, PCI_ROM_SLOT, 0, 0, size, pdev->rom_offset);
>
>       return 0;
>   }
> diff --git a/hw/pci.h b/hw/pci.h
> index 3a15bd4..3648105 100644
> --- a/hw/pci.h
> +++ b/hw/pci.h
> @@ -80,13 +80,21 @@ typedef void PCIMapIORegionFunc(PCIDevice
> *pci_dev, int region_num,
>                                   pcibus_t addr, pcibus_t size, int type);
>   typedef int PCIUnregisterFunc(PCIDevice *pci_dev);
>
> +typedef struct PCIIOSubRegion {
> +    pcibus_t offset; /* offset to BAR start. -1 means not mapped */
> +    pcibus_t size;
> +    pcibus_t filtered_size;
> +    int ix;
> +} PCIIOSubRegion;
> +
> +#define PCI_NUM_SUBREGIONS 8
> +
>   typedef struct PCIIORegion {
>       pcibus_t addr; /* current PCI mapping address. -1 means not mapped */
>   #define PCI_BAR_UNMAPPED (~(pcibus_t)0)
>       pcibus_t size;
> -    pcibus_t filtered_size;
>       uint8_t type;
> -    PCIMapIORegionFunc *map_func;
> +    PCIIOSubRegion subregions[PCI_NUM_SUBREGIONS];
>   } PCIIORegion;
>
>   #define PCI_ROM_SLOT 6
> @@ -175,8 +183,10 @@ PCIDevice *pci_register_device(PCIBus *bus, const
> char *name,
>                                  PCIConfigWriteFunc *config_write);
>
>   void pci_register_bar(PCIDevice *pci_dev, int region_num,
> -                            pcibus_t size, int type,
> -                            PCIMapIORegionFunc *map_func);
> +                      pcibus_t size, int type);
> +
> +void pci_bar_map(PCIDevice *pci_dev, int region_num, int subregion_num,
> +                 pcibus_t offset, pcibus_t size, int ix);
>
>   int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
>   int pci_add_capability_at_offset(PCIDevice *pci_dev, uint8_t cap_id,
> diff --git a/hw/pcnet.c b/hw/pcnet.c
> index 5e63eb5..4782717 100644
> --- a/hw/pcnet.c
> +++ b/hw/pcnet.c
> @@ -1615,6 +1615,18 @@ static uint32_t pcnet_aprom_readb(void *opaque,
> uint32_t addr)
>       return val;
>   }
>
> +static IOPortWriteFunc * const pcnet_aprom_writes[] = {
> +    pcnet_aprom_writeb,
> +    NULL,
> +    NULL,
> +};
> +
> +static IOPortReadFunc * const pcnet_aprom_reads[] = {
> +    pcnet_aprom_readb,
> +    NULL,
> +    NULL,
> +};
> +
>   void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
>   {
>       PCNetState *s = opaque;
> @@ -1726,24 +1738,17 @@ static uint32_t pcnet_ioport_readl(void
> *opaque, uint32_t addr)
>       return val;
>   }
>
> -static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
> -                             pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCNetState *d =&DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state;
> -
> -#ifdef PCNET_DEBUG_IO
> -    printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n",
> -           addr, size);
> -#endif
> -
> -    register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
> -    register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
> +static IOPortWriteFunc * const pcnet_ioport_writes[] = {
> +    NULL,
> +    pcnet_ioport_writew,
> +    pcnet_ioport_writel,
> +};
>
> -    register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
> -    register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
> -    register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
> -    register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
> -}
> +static IOPortReadFunc * const pcnet_ioport_reads[] = {
> +    NULL,
> +    pcnet_ioport_readw,
> +    pcnet_ioport_readl,
> +};
>
>   static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr,
> uint32_t val)
>   {
> @@ -1915,19 +1920,6 @@ static CPUReadMemoryFunc * const pcnet_mmio_read[] = {
>       &pcnet_mmio_readl
>   };
>
> -static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
> -                            pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
> -
> -#ifdef PCNET_DEBUG_IO
> -    printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
> -           addr, size);
> -#endif
> -
> -    cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE,
> d->state.mmio_index);
> -}
> -
>   static void pci_physical_memory_write(void *dma_opaque,
> target_phys_addr_t addr,
>                                         uint8_t *buf, int len, int do_bswap)
>   {
> @@ -1971,6 +1963,7 @@ static int pci_pcnet_init(PCIDevice *pci_dev)
>       PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
>       PCNetState *s =&d->state;
>       uint8_t *pci_conf;
> +    int io_index;
>
>   #if 0
>       printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
> @@ -2011,10 +2004,15 @@ static int pci_pcnet_init(PCIDevice *pci_dev)
>
>       /* TODO: use pci_dev, avoid cast below. */
>       pci_register_bar((PCIDevice *)d, 0, PCNET_IOPORT_SIZE,
> -                           PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
> +                           PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(pcnet_aprom_reads, pcnet_aprom_writes, 16, s);
> +    pci_bar_map((PCIDevice *)d, 0, 0, 0, 16, io_index);
> +    io_index = cpu_register_io(pcnet_ioport_reads, pcnet_ioport_writes, 16, s);
> +    pci_bar_map((PCIDevice *)d, 0, 1, 0x10, 16, io_index);
>
>       pci_register_bar((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE,
> -                           PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map);
> +                           PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    pci_bar_map((PCIDevice *)d, 1, 0, 0, PCNET_PNPMMIO_SIZE, s->mmio_index);
>
>       s->irq = pci_dev->irq[0];
>       s->phys_mem_read = pci_physical_memory_read;
> diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
> index 89f96bb..6b3e27f 100644
> --- a/hw/ppc_mac.h
> +++ b/hw/ppc_mac.h
> @@ -46,8 +46,9 @@ void cuda_init (int *cuda_mem_index, qemu_irq irq);
>
>   /* MacIO */
>   void macio_init (PCIBus *bus, int device_id, int is_oldworld, int
> pic_mem_index,
> -                 int dbdma_mem_index, int cuda_mem_index, void *nvram,
> -                 int nb_ide, int *ide_mem_index, int escc_mem_index);
> +                 int dbdma_mem_index, int cuda_mem_index, int nvram_size,
> +                 int nvram_mem_index, int nb_ide, int *ide_mem_index,
> +                 int escc_mem_index);
>
>   /* Heathrow PIC */
>   qemu_irq *heathrow_pic_init(int *pmem_index,
> diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
> index fbba9b6..75fef3c 100644
> --- a/hw/ppc_newworld.c
> +++ b/hw/ppc_newworld.c
> @@ -383,7 +383,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
>       adb_mouse_init(&adb_bus);
>
>       macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem_index,
> -               dbdma_mem_index, cuda_mem_index, NULL, 3, ide_mem_index,
> +               dbdma_mem_index, cuda_mem_index, -1, 0, 3, ide_mem_index,
>                  escc_mem_index);
>
>       if (usb_enabled) {
> diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
> index 6b3ab89..220dca7 100644
> --- a/hw/ppc_oldworld.c
> +++ b/hw/ppc_oldworld.c
> @@ -366,8 +366,8 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
>       pmac_format_nvram_partition(nvr, 0x2000);
>
>       macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem_index,
> -               dbdma_mem_index, cuda_mem_index, nvr, 2, ide_mem_index,
> -               escc_mem_index);
> +               dbdma_mem_index, cuda_mem_index, nvram_mem_index, 0x2000,
> +               2, ide_mem_index, escc_mem_index);
>
>       if (usb_enabled) {
>           usb_ohci_init_pci(pci_bus, -1);
> diff --git a/hw/rtl8139.c b/hw/rtl8139.c
> index 72e2242..d87f3ae 100644
> --- a/hw/rtl8139.c
> +++ b/hw/rtl8139.c
> @@ -3269,28 +3269,17 @@ static const VMStateDescription vmstate_rtl8139 = {
>   /***********************************************************/
>   /* PCI RTL8139 definitions */
>
> -static void rtl8139_mmio_map(PCIDevice *pci_dev, int region_num,
> -                       pcibus_t addr, pcibus_t size, int type)
> -{
> -    RTL8139State *s = DO_UPCAST(RTL8139State, dev, pci_dev);
> -
> -    cpu_register_physical_memory(addr + 0, 0x100, s->rtl8139_mmio_io_addr);
> -}
> -
> -static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num,
> -                       pcibus_t addr, pcibus_t size, int type)
> -{
> -    RTL8139State *s = DO_UPCAST(RTL8139State, dev, pci_dev);
> -
> -    register_ioport_write(addr, 0x100, 1, rtl8139_ioport_writeb, s);
> -    register_ioport_read( addr, 0x100, 1, rtl8139_ioport_readb,  s);
> -
> -    register_ioport_write(addr, 0x100, 2, rtl8139_ioport_writew, s);
> -    register_ioport_read( addr, 0x100, 2, rtl8139_ioport_readw,  s);
> +static IOPortWriteFunc * const rtl8139_io_writes[] = {
> +    rtl8139_ioport_writeb,
> +    rtl8139_ioport_writew,
> +    rtl8139_ioport_writel,
> +};
>
> -    register_ioport_write(addr, 0x100, 4, rtl8139_ioport_writel, s);
> -    register_ioport_read( addr, 0x100, 4, rtl8139_ioport_readl,  s);
> -}
> +static IOPortReadFunc * const rtl8139_io_reads[] = {
> +    rtl8139_ioport_readb,
> +    rtl8139_ioport_readw,
> +    rtl8139_ioport_readl,
> +};
>
>   static CPUReadMemoryFunc * const rtl8139_mmio_read[3] = {
>       rtl8139_mmio_readb,
> @@ -3353,6 +3342,7 @@ static int pci_rtl8139_init(PCIDevice *dev)
>   {
>       RTL8139State * s = DO_UPCAST(RTL8139State, dev, dev);
>       uint8_t *pci_conf;
> +    int io_index;
>
>       pci_conf = s->dev.config;
>       pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK);
> @@ -3372,11 +3362,11 @@ static int pci_rtl8139_init(PCIDevice *dev)
>       s->rtl8139_mmio_io_addr =
>           cpu_register_io_memory(rtl8139_mmio_read, rtl8139_mmio_write, s);
>
> -    pci_register_bar(&s->dev, 0, 0x100,
> -                           PCI_BASE_ADDRESS_SPACE_IO,  rtl8139_ioport_map);
> -
> -    pci_register_bar(&s->dev, 1, 0x100,
> -                           PCI_BASE_ADDRESS_SPACE_MEMORY, rtl8139_mmio_map);
> +    pci_register_bar(&s->dev, 0, 0x100, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(rtl8139_io_reads, rtl8139_io_writes, 0x100, s);
> +    pci_bar_map(&s->dev, 0, 0, 0, 0x100, io_index);
> +    pci_register_bar(&s->dev, 1, 0x100, PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    pci_bar_map(&s->dev, 1, 0, 0, 0x100, s->rtl8139_mmio_io_addr);
>
>       qemu_macaddr_default_if_unset(&s->conf.macaddr);
>
> diff --git a/hw/sun4u.c b/hw/sun4u.c
> index 2234b4e..48d89d3 100644
> --- a/hw/sun4u.c
> +++ b/hw/sun4u.c
> @@ -517,21 +517,6 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
>       }
>   }
>
> -static void ebus_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
> -                              pcibus_t addr, pcibus_t size, int type)
> -{
> -    EBUS_DPRINTF("Mapping region %d registers at %" FMT_PCIBUS "\n",
> -                 region_num, addr);
> -    switch (region_num) {
> -    case 0:
> -        isa_mmio_init(addr, 0x1000000, 1);
> -        break;
> -    case 1:
> -        isa_mmio_init(addr, 0x800000, 1);
> -        break;
> -    }
> -}
> -
>   static void dummy_isa_irq_handler(void *opaque, int n, int level)
>   {
>   }
> @@ -550,6 +535,8 @@ pci_ebus_init(PCIBus *bus, int devfn)
>   static int
>   pci_ebus_init1(PCIDevice *s)
>   {
> +    int io_index;
> +
>       isa_bus_new(&s->qdev);
>
>       pci_config_set_vendor_id(s->config, PCI_VENDOR_ID_SUN);
> @@ -564,10 +551,14 @@ pci_ebus_init1(PCIDevice *s)
>       s->config[0x0D] = 0x0a; // latency_timer
>       s->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
>
> -    pci_register_bar(s, 0, 0x1000000, PCI_BASE_ADDRESS_SPACE_MEMORY,
> -                           ebus_mmio_mapfunc);
> -    pci_register_bar(s, 1, 0x800000,  PCI_BASE_ADDRESS_SPACE_MEMORY,
> -                           ebus_mmio_mapfunc);
> +    pci_register_bar(s, 0, 0x1000000, PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    io_index = pci_isa_mmio_init(1);
> +    pci_bar_map(s, 0, 0, 0, 0x1000000, io_index);
> +
> +    pci_register_bar(s, 1, 0x800000, PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    io_index = pci_isa_mmio_init(1);
> +    pci_bar_map(s, 1, 0, 0, 0x800000, io_index);
> +
>       return 0;
>   }
>
> diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
> index c60fd8d..343603f 100644
> --- a/hw/usb-ohci.c
> +++ b/hw/usb-ohci.c
> @@ -1717,13 +1717,6 @@ typedef struct {
>       OHCIState state;
>   } OHCIPCIState;
>
> -static void ohci_mapfunc(PCIDevice *pci_dev, int i,
> -            pcibus_t addr, pcibus_t size, int type)
> -{
> -    OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, pci_dev);
> -    cpu_register_physical_memory(addr, size, ohci->state.mem);
> -}
> -
>   static int usb_ohci_initfn_pci(struct PCIDevice *dev)
>   {
>       OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev);
> @@ -1742,7 +1735,8 @@ static int usb_ohci_initfn_pci(struct PCIDevice *dev)
>
>       /* TODO: avoid cast below by using dev */
>       pci_register_bar((struct PCIDevice *)ohci, 0, 256,
> -                           PCI_BASE_ADDRESS_SPACE_MEMORY, ohci_mapfunc);
> +                     PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    pci_bar_map((struct PCIDevice *)ohci, 0, 0, 256, 0, ohci->state.mem);
>       return 0;
>   }
>
> diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
> index 4cdb55e..b182eb5 100644
> --- a/hw/usb-uhci.c
> +++ b/hw/usb-uhci.c
> @@ -1088,23 +1088,22 @@ static void uhci_frame_timer(void *opaque)
>       qemu_mod_timer(s->frame_timer, s->expire_time);
>   }
>
> -static void uhci_map(PCIDevice *pci_dev, int region_num,
> -                    pcibus_t addr, pcibus_t size, int type)
> -{
> -    UHCIState *s = (UHCIState *)pci_dev;
> -
> -    register_ioport_write(addr, 32, 2, uhci_ioport_writew, s);
> -    register_ioport_read(addr, 32, 2, uhci_ioport_readw, s);
> -    register_ioport_write(addr, 32, 4, uhci_ioport_writel, s);
> -    register_ioport_read(addr, 32, 4, uhci_ioport_readl, s);
> -    register_ioport_write(addr, 32, 1, uhci_ioport_writeb, s);
> -    register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
> -}
> +static IOPortWriteFunc * const uhci_io_writes[] = {
> +    uhci_ioport_writeb,
> +    uhci_ioport_writew,
> +    uhci_ioport_writel,
> +};
> +
> +static IOPortReadFunc * const uhci_io_reads[] = {
> +    uhci_ioport_readb,
> +    uhci_ioport_readw,
> +    uhci_ioport_readl,
> +};
>
>   static int usb_uhci_common_initfn(UHCIState *s)
>   {
>       uint8_t *pci_conf = s->dev.config;
> -    int i;
> +    int i, io_index;
>
>       pci_conf[PCI_REVISION_ID] = 0x01; // revision number
>       pci_conf[PCI_CLASS_PROG] = 0x00;
> @@ -1127,9 +1126,9 @@ static int usb_uhci_common_initfn(UHCIState *s)
>
>       /* Use region 4 for consistency with real hardware.  BSD guests seem
>          to rely on this.  */
> -    pci_register_bar(&s->dev, 4, 0x20,
> -                           PCI_BASE_ADDRESS_SPACE_IO, uhci_map);
> -
> +    pci_register_bar(&s->dev, 4, 0x20, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(uhci_io_reads, uhci_io_writes, 32, s);
> +    pci_bar_map(&s->dev, 4, 0, 0, 0x20, io_index);
>       return 0;
>   }
>
> diff --git a/hw/vga-pci.c b/hw/vga-pci.c
> index eef78ed..818e77f 100644
> --- a/hw/vga-pci.c
> +++ b/hw/vga-pci.c
> @@ -47,21 +47,6 @@ static const VMStateDescription vmstate_vga_pci = {
>       }
>   };
>
> -static void vga_map(PCIDevice *pci_dev, int region_num,
> -                    pcibus_t addr, pcibus_t size, int type)
> -{
> -    PCIVGAState *d = (PCIVGAState *)pci_dev;
> -    VGACommonState *s =&d->vga;
> -    if (region_num == PCI_ROM_SLOT) {
> -        cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
> -    } else {
> -        cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
> -        s->map_addr = addr;
> -        s->map_end = addr + s->vram_size;
> -        vga_dirty_log_start(s);
> -    }
> -}
> -
>   static void pci_vga_write_config(PCIDevice *d,
>                                    uint32_t address, uint32_t val, int len)
>   {
> @@ -93,8 +78,8 @@ static int pci_vga_initfn(PCIDevice *dev)
>        pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
>
>        /* XXX: VGA_RAM_SIZE must be a power of two */
> -     pci_register_bar(&d->dev, 0, VGA_RAM_SIZE,
> -                      PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
> +     pci_register_bar(&d->dev, 0, VGA_RAM_SIZE, PCI_BASE_ADDRESS_MEM_PREFETCH);
> +     pci_bar_map(&d->dev, 0, 0, 0, s->vram_size, s->vram_offset);
>
>        if (s->bios_size) {
>           unsigned int bios_total_size;
> @@ -103,7 +88,8 @@ static int pci_vga_initfn(PCIDevice *dev)
>           while (bios_total_size<  s->bios_size)
>               bios_total_size<<= 1;
>           pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size,
> -                         PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
> +                         PCI_BASE_ADDRESS_MEM_PREFETCH);
> +        pci_bar_map(&d->dev, PCI_ROM_SLOT, 0, 0, s->bios_size, s->bios_offset);
>        }
>
>       vga_init_vbe(s);
> diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
> index c6ef825..415acfc 100644
> --- a/hw/virtio-pci.c
> +++ b/hw/virtio-pci.c
> @@ -374,25 +374,17 @@ static void virtio_pci_config_writel(void
> *opaque, uint32_t addr, uint32_t val)
>       virtio_config_writel(proxy->vdev, addr, val);
>   }
>
> -static void virtio_map(PCIDevice *pci_dev, int region_num,
> -                       pcibus_t addr, pcibus_t size, int type)
> -{
> -    VirtIOPCIProxy *proxy = container_of(pci_dev, VirtIOPCIProxy, pci_dev);
> -    VirtIODevice *vdev = proxy->vdev;
> -    unsigned config_len = VIRTIO_PCI_REGION_SIZE(pci_dev) + vdev->config_len;
> -
> -    proxy->addr = addr;
> -
> -    register_ioport_write(addr, config_len, 1,
> virtio_pci_config_writeb, proxy);
> -    register_ioport_write(addr, config_len, 2,
> virtio_pci_config_writew, proxy);
> -    register_ioport_write(addr, config_len, 4,
> virtio_pci_config_writel, proxy);
> -    register_ioport_read(addr, config_len, 1, virtio_pci_config_readb, proxy);
> -    register_ioport_read(addr, config_len, 2, virtio_pci_config_readw, proxy);
> -    register_ioport_read(addr, config_len, 4, virtio_pci_config_readl, proxy);
> +static IOPortWriteFunc * const virtio_pci_config_io_writes[] = {
> +    virtio_pci_config_writeb,
> +    virtio_pci_config_writew,
> +    virtio_pci_config_writel,
> +};
>
> -    if (vdev->config_len)
> -        vdev->get_config(vdev, vdev->config);
> -}
> +static IOPortReadFunc * const virtio_pci_config_io_reads[] = {
> +    virtio_pci_config_readb,
> +    virtio_pci_config_readw,
> +    virtio_pci_config_readl,
> +};
>
>   static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
>                                   uint32_t val, int len)
> @@ -495,6 +487,7 @@ static void virtio_init_pci(VirtIOPCIProxy *proxy,
> VirtIODevice *vdev,
>   {
>       uint8_t *config;
>       uint32_t size;
> +    int io_index;
>
>       proxy->vdev = vdev;
>
> @@ -518,8 +511,7 @@ static void virtio_init_pci(VirtIOPCIProxy *proxy,
> VirtIODevice *vdev,
>       if (vdev->nvectors&&  !msix_init(&proxy->pci_dev, vdev->nvectors, 1, 0)) {
>           pci_register_bar(&proxy->pci_dev, 1,
>                            msix_bar_size(&proxy->pci_dev),
> -                         PCI_BASE_ADDRESS_SPACE_MEMORY,
> -                         msix_mmio_map);
> +                         PCI_BASE_ADDRESS_SPACE_MEMORY);
>       } else
>           vdev->nvectors = 0;
>
> @@ -529,8 +521,11 @@ static void virtio_init_pci(VirtIOPCIProxy
> *proxy, VirtIODevice *vdev,
>       if (size&  (size-1))
>           size = 1<<  qemu_fls(size);
>
> -    pci_register_bar(&proxy->pci_dev, 0, size, PCI_BASE_ADDRESS_SPACE_IO,
> -                           virtio_map);
> +    pci_register_bar(&proxy->pci_dev, 0, size, PCI_BASE_ADDRESS_SPACE_IO);
> +    io_index = cpu_register_io(virtio_pci_config_io_reads,
> +                               virtio_pci_config_io_writes,
> +                               size,&proxy->pci_dev);
> +    pci_bar_map(&proxy->pci_dev, 0, 0, 0, size, io_index);
>
>       virtio_bind_device(vdev,&virtio_pci_bindings, proxy);
>       proxy->host_features |= 0x1<<  VIRTIO_F_NOTIFY_ON_EMPTY;
> diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
> index 9e72d2e..bf5f075 100644
> --- a/hw/vmware_vga.c
> +++ b/hw/vmware_vga.c
> @@ -1178,65 +1178,47 @@ static void vmsvga_init(struct vmsvga_state_s
> *s, int vga_ram_size)
>       vmsvga_reset(s);
>   }
>
> -static void pci_vmsvga_map_ioport(PCIDevice *pci_dev, int region_num,
> -                pcibus_t addr, pcibus_t size, int type)
> -{
> -    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
> -    struct vmsvga_state_s *s =&d->chip;
> -
> -    register_ioport_read(addr + SVGA_IO_MUL * SVGA_INDEX_PORT,
> -                    1, 4, vmsvga_index_read, s);
> -    register_ioport_write(addr + SVGA_IO_MUL * SVGA_INDEX_PORT,
> -                    1, 4, vmsvga_index_write, s);
> -    register_ioport_read(addr + SVGA_IO_MUL * SVGA_VALUE_PORT,
> -                    1, 4, vmsvga_value_read, s);
> -    register_ioport_write(addr + SVGA_IO_MUL * SVGA_VALUE_PORT,
> -                    1, 4, vmsvga_value_write, s);
> -    register_ioport_read(addr + SVGA_IO_MUL * SVGA_BIOS_PORT,
> -                    1, 4, vmsvga_bios_read, s);
> -    register_ioport_write(addr + SVGA_IO_MUL * SVGA_BIOS_PORT,
> -                    1, 4, vmsvga_bios_write, s);
> -}
> +static IOPortWriteFunc * const vmsvga_index_io_writes[] = {
> +    NULL,
> +    NULL,
> +    vmsvga_index_write,
> +};
>
> -static void pci_vmsvga_map_mem(PCIDevice *pci_dev, int region_num,
> -                pcibus_t addr, pcibus_t size, int type)
> -{
> -    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
> -    struct vmsvga_state_s *s =&d->chip;
> -    ram_addr_t iomemtype;
> +static IOPortReadFunc * const vmsvga_index_io_reads[] = {
> +    NULL,
> +    NULL,
> +    vmsvga_index_read,
> +};
>
> -    s->vram_base = addr;
> -#ifdef DIRECT_VRAM
> -    iomemtype = cpu_register_io_memory(vmsvga_vram_read,
> -                    vmsvga_vram_write, s);
> -#else
> -    iomemtype = s->vga.vram_offset | IO_MEM_RAM;
> -#endif
> -    cpu_register_physical_memory(s->vram_base, s->vga.vram_size,
> -                    iomemtype);
> +static IOPortWriteFunc * const vmsvga_value_io_writes[] = {
> +    NULL,
> +    NULL,
> +    vmsvga_value_write,
> +};
>
> -    s->vga.map_addr = addr;
> -    s->vga.map_end = addr + s->vga.vram_size;
> -    vga_dirty_log_restart(&s->vga);
> -}
> +static IOPortReadFunc * const vmsvga_value_io_reads[] = {
> +    NULL,
> +    NULL,
> +    vmsvga_value_read,
> +};
>
> -static void pci_vmsvga_map_fifo(PCIDevice *pci_dev, int region_num,
> -                pcibus_t addr, pcibus_t size, int type)
> -{
> -    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
> -    struct vmsvga_state_s *s =&d->chip;
> -    ram_addr_t iomemtype;
> +static IOPortWriteFunc * const vmsvga_bios_io_writes[] = {
> +    NULL,
> +    NULL,
> +    vmsvga_bios_write,
> +};
>
> -    s->fifo_base = addr;
> -    iomemtype = s->fifo_offset | IO_MEM_RAM;
> -    cpu_register_physical_memory(s->fifo_base, s->fifo_size,
> -                    iomemtype);
> -}
> +static IOPortReadFunc * const vmsvga_bios_io_reads[] = {
> +    NULL,
> +    NULL,
> +    vmsvga_bios_read,
> +};
>
>   static int pci_vmsvga_initfn(PCIDevice *dev)
>   {
>       struct pci_vmsvga_state_s *s =
>           DO_UPCAST(struct pci_vmsvga_state_s, card, dev);
> +    ram_addr_t iomemtype;
>
>       pci_config_set_vendor_id(s->card.config, PCI_VENDOR_ID_VMWARE);
>       pci_config_set_device_id(s->card.config, SVGA_PCI_DEVICE_ID);
> @@ -1253,16 +1235,33 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
>       s->card.config[PCI_SUBSYSTEM_ID + 1] = SVGA_PCI_DEVICE_ID>>  8;
>       s->card.config[PCI_INTERRUPT_LINE] = 0xff;		/* End */
>
> -    pci_register_bar(&s->card, 0, 0x10,
> -                    PCI_BASE_ADDRESS_SPACE_IO, pci_vmsvga_map_ioport);
> +    pci_register_bar(&s->card, 0, 0x10, PCI_BASE_ADDRESS_SPACE_IO);
> +    iomemtype = cpu_register_io(vmsvga_index_io_reads, vmsvga_index_io_writes,
> +                                4,&s->card);
> +    pci_bar_map(&s->card, 0, 0, SVGA_IO_MUL * SVGA_INDEX_PORT, 4, iomemtype);
> +    iomemtype = cpu_register_io(vmsvga_value_io_reads, vmsvga_value_io_writes,
> +                                4,&s->card);
> +    pci_bar_map(&s->card, 0, 0, SVGA_IO_MUL * SVGA_VALUE_PORT, 4, iomemtype);
> +    iomemtype = cpu_register_io(vmsvga_bios_io_reads, vmsvga_bios_io_writes,
> +                                4,&s->card);
> +    pci_bar_map(&s->card, 0, 0, SVGA_IO_MUL * SVGA_BIOS_PORT, 4, iomemtype);
>       pci_register_bar(&s->card, 1, VGA_RAM_SIZE,
> -                    PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_mem);
> -
> +                     PCI_BASE_ADDRESS_MEM_PREFETCH);
>       pci_register_bar(&s->card, 2, SVGA_FIFO_SIZE,
> -		     PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_fifo);
> +                     PCI_BASE_ADDRESS_MEM_PREFETCH);
>
>       vmsvga_init(&s->chip, VGA_RAM_SIZE);
>
> +#ifdef DIRECT_VRAM
> +    iomemtype = cpu_register_io_memory(vmsvga_vram_read,
> +                    vmsvga_vram_write, s);
> +#else
> +    iomemtype = s->chip.vga.vram_offset | IO_MEM_RAM;
> +#endif
> +    pci_bar_map(&s->card, 1, 0, 0, s->chip.vga.vram_size, iomemtype);
> +    iomemtype = s->chip.fifo_offset | IO_MEM_RAM;
> +    pci_bar_map(&s->card, 2, 0, 0, s->chip.fifo_size, iomemtype);
> +
>       return 0;
>   }
>
> diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
> index be0e89e..4c5bb32 100644
> --- a/hw/wdt_i6300esb.c
> +++ b/hw/wdt_i6300esb.c
> @@ -342,29 +342,17 @@ static void i6300esb_mem_writel(void *vp,
> target_phys_addr_t addr, uint32_t val)
>       }
>   }
>
> -static void i6300esb_map(PCIDevice *dev, int region_num,
> -                         pcibus_t addr, pcibus_t size, int type)
> -{
> -    static CPUReadMemoryFunc * const mem_read[3] = {
> -        i6300esb_mem_readb,
> -        i6300esb_mem_readw,
> -        i6300esb_mem_readl,
> -    };
> -    static CPUWriteMemoryFunc * const mem_write[3] = {
> -        i6300esb_mem_writeb,
> -        i6300esb_mem_writew,
> -        i6300esb_mem_writel,
> -    };
> -    I6300State *d = DO_UPCAST(I6300State, dev, dev);
> -    int io_mem;
> -
> -    i6300esb_debug("addr = %"FMT_PCIBUS", size = %"FMT_PCIBUS", type = %d\n",
> -                   addr, size, type);
> +static CPUReadMemoryFunc * const mem_read[3] = {
> +    i6300esb_mem_readb,
> +    i6300esb_mem_readw,
> +    i6300esb_mem_readl,
> +};
>
> -    io_mem = cpu_register_io_memory(mem_read, mem_write, d);
> -    cpu_register_physical_memory (addr, 0x10, io_mem);
> -    /* qemu_register_coalesced_mmio (addr, 0x10); ? */
> -}
> +static CPUWriteMemoryFunc * const mem_write[3] = {
> +    i6300esb_mem_writeb,
> +    i6300esb_mem_writew,
> +    i6300esb_mem_writel,
> +};
>
>   static const VMStateDescription vmstate_i6300esb = {
>       .name = "i6300esb_wdt",
> @@ -393,6 +381,7 @@ static int i6300esb_init(PCIDevice *dev)
>   {
>       I6300State *d = DO_UPCAST(I6300State, dev, dev);
>       uint8_t *pci_conf;
> +    int io_mem;
>
>       d->reboot_enabled = 1;
>       d->clock_scale = CLOCK_SCALE_1KHZ;
> @@ -413,8 +402,9 @@ static int i6300esb_init(PCIDevice *dev)
>       pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER);
>       pci_conf[PCI_HEADER_TYPE] = 0x00;
>
> -    pci_register_bar(&d->dev, 0, 0x10,
> -                            PCI_BASE_ADDRESS_SPACE_MEMORY, i6300esb_map);
> +    pci_register_bar(&d->dev, 0, 0x10, PCI_BASE_ADDRESS_SPACE_MEMORY);
> +    io_mem = cpu_register_io_memory(mem_read, mem_write, d);
> +    pci_bar_map(&d->dev, 0, 0, 0, 0x10, io_mem);
>
>       return 0;
>   }
> diff --git a/ioport.c b/ioport.c
> index 53dd87a..90fec90 100644
> --- a/ioport.c
> +++ b/ioport.c
> @@ -54,29 +54,39 @@ static IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
>   static IOPortReadFunc default_ioport_readb, default_ioport_readw,
> default_ioport_readl;
>   static IOPortWriteFunc default_ioport_writeb, default_ioport_writew,
> default_ioport_writel;
>
> +#define IO_NB_ENTRIES 256
> +
> +static IOPortWriteFunc *io_writes[IO_NB_ENTRIES][3];
> +static IOPortReadFunc *io_reads[IO_NB_ENTRIES][3];
> +static void *io_opaques[IO_NB_ENTRIES];
> +static int io_sizes[IO_NB_ENTRIES];
> +static char io_used[IO_NB_ENTRIES];
> +
> +static IOPortReadFunc * const default_read_func[3] = {
> +    default_ioport_readb,
> +    default_ioport_readw,
> +    default_ioport_readl
> +};
> +
>   static uint32_t ioport_read(int index, uint32_t address)
>   {
> -    static IOPortReadFunc * const default_func[3] = {
> -        default_ioport_readb,
> -        default_ioport_readw,
> -        default_ioport_readl
> -    };
>       IOPortReadFunc *func = ioport_read_table[index][address];
>       if (!func)
> -        func = default_func[index];
> +        func = default_read_func[index];
>       return func(ioport_opaque[address], address);
>   }
>
> +static IOPortWriteFunc * const default_write_func[3] = {
> +    default_ioport_writeb,
> +    default_ioport_writew,
> +    default_ioport_writel
> +};
> +
>   static void ioport_write(int index, uint32_t address, uint32_t data)
>   {
> -    static IOPortWriteFunc * const default_func[3] = {
> -        default_ioport_writeb,
> -        default_ioport_writew,
> -        default_ioport_writel
> -    };
>       IOPortWriteFunc *func = ioport_write_table[index][address];
>       if (!func)
> -        func = default_func[index];
> +        func = default_write_func[index];
>       func(ioport_opaque[address], address, data);
>   }
>
> @@ -173,6 +183,86 @@ int register_ioport_write(pio_addr_t start, int
> length, int size,
>       return 0;
>   }
>
> +static int get_free_io_mem_idx(void)
> +{
> +    int i;
> +
> +    for (i = 0; i<  IO_NB_ENTRIES; i++) {
> +        if (!io_used[i]) {
> +            io_used[i] = 1;
> +            return i;
> +        }
> +    }
> +    fprintf(stderr, "RAN out out io_mem_idx, max %d !\n", IO_NB_ENTRIES);
> +    return -1;
> +}
> +
> +/* io_read and io_write are arrays of functions containing the
> +   function to access byte (index 0), word (index 1) and dword (index
> +   2). Functions can be omitted with a NULL function pointer. (-1) is
> +   returned if error. */
> +int cpu_register_io(IOPortReadFunc * const *io_read,
> +                    IOPortWriteFunc * const *io_write,
> +                    int size, void *opaque)
> +{
> +    unsigned int i;
> +    int io_index;
> +
> +    io_index = get_free_io_mem_idx();
> +    if (io_index == -1) {
> +        return io_index;
> +    }
> +
> +    if (io_read) {
> +        for (i = 0; i<  3; ++i) {
> +            io_reads[io_index][i] = io_read[i];
> +        }
> +    }
> +    if (io_write) {
> +        for (i = 0; i<  3; ++i) {
> +            io_writes[io_index][i] = io_write[i];
> +        }
> +    }
> +    io_opaques[io_index] = opaque;
> +    io_sizes[io_index] = size;
> +
> +    return io_index;
> +}
> +
> +void cpu_unregister_io(int io_index)
> +{
> +    unsigned int i;
> +
> +    for (i = 0; i<  3; i++) {
> +        io_reads[io_index][i] = NULL;
> +        io_writes[io_index][i] = NULL;
> +    }
> +    io_opaques[io_index] = NULL;
> +    io_sizes[io_index] = 0;
> +    io_used[io_index] = 0;
> +}
> +
> +void cpu_map_io(pio_addr_t start, int io_index)
> +{
> +    unsigned int i, j;
> +
> +    assert(io_index>= 0);
> +    for (i = start; i<  start + io_sizes[io_index]; i++) {
> +        for (j = 0; j<  3; j++) {
> +            if (io_reads[io_index][j]) {
> +                register_ioport_read(i, io_sizes[io_index], 1<<  j,
> +                                     io_reads[io_index][j],
> +                                     io_opaques[io_index]);
> +            }
> +            if (io_writes[io_index][j]) {
> +                register_ioport_write(i, io_sizes[io_index], 1<<  j,
> +                                      io_writes[io_index][j],
> +                                      io_opaques[io_index]);
> +            }
> +        }
> +    }
> +}
> +
>   void isa_unassign_ioport(pio_addr_t start, int length)
>   {
>       int i;
> @@ -190,6 +280,11 @@ void isa_unassign_ioport(pio_addr_t start, int length)
>       }
>   }
>
> +void cpu_unmap_io(pio_addr_t start, int io_index)
> +{
> +    isa_unassign_ioport(start, io_sizes[io_index]);
> +}
> +
>   /***********************************************************/
>
>   void cpu_outb(pio_addr_t addr, uint8_t val)
> diff --git a/ioport.h b/ioport.h
> index 3d3c8a3..4ba78ed 100644
> --- a/ioport.h
> +++ b/ioport.h
> @@ -40,6 +40,12 @@ int register_ioport_read(pio_addr_t start, int
> length, int size,
>                            IOPortReadFunc *func, void *opaque);
>   int register_ioport_write(pio_addr_t start, int length, int size,
>                             IOPortWriteFunc *func, void *opaque);
> +int cpu_register_io(IOPortReadFunc * const *io_read,
> +                    IOPortWriteFunc * const *io_write,
> +                    int size, void *opaque);
> +void cpu_unregister_io(int io_index);
> +void cpu_map_io(pio_addr_t start, int io_index);
> +void cpu_unmap_io(pio_addr_t start, int io_index);
>   void isa_unassign_ioport(pio_addr_t start, int length);
>
>
>    

  parent reply	other threads:[~2010-07-07 19:03 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-07-07 17:53 [Qemu-devel] [PATCH, RFC] pci: handle BAR mapping at pci level Blue Swirl
2010-07-07 17:55 ` [Qemu-devel] " Michael S. Tsirkin
2010-07-07 18:12   ` Blue Swirl
2010-07-07 18:15 ` [Qemu-devel] " malc
2010-07-07 19:29   ` Blue Swirl
2010-07-07 19:02 ` Anthony Liguori [this message]
2010-07-07 19:36   ` Blue Swirl

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=4C34CF5D.3070903@codemonkey.ws \
    --to=anthony@codemonkey.ws \
    --cc=blauwirbel@gmail.com \
    --cc=mst@redhat.com \
    --cc=qemu-devel@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.