The original PCI config space accessor failed to issue master abort interrupt as necessary, it also didn't handle type 1 access and using south bridge concept which doesn't exist in Bonito.
Rework the whole mechanism accorading to the manual, also remove inaccurate comments. Signed-off-by: Jiaxun Yang <jiaxun.y...@flygoat.com> --- hw/pci-host/bonito.c | 202 ++++++++++++++++++----------------------------- hw/pci-host/trace-events | 3 - 2 files changed, 75 insertions(+), 130 deletions(-) diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 1c0d502a1e2dfa3c9803ca219cf505e08bf94a75..49b4be26393a08eda4f99c8e2ef8a0c455c57bc0 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -14,30 +14,6 @@ * fuloong 2e mini pc has a bonito north bridge. */ -/* - * what is the meaning of devfn in qemu and IDSEL in bonito northbridge? - * - * devfn pci_slot<<3 + funno - * one pci bus can have 32 devices and each device can have 8 functions. - * - * In bonito north bridge, pci slot = IDSEL bit - 12. - * For example, PCI_IDSEL_VIA686B = 17, - * pci slot = 17-12=5 - * - * so - * VT686B_FUN0's devfn = (5<<3)+0 - * VT686B_FUN1's devfn = (5<<3)+1 - * - * qemu also uses pci address for north bridge to access pci config register. - * bus_no [23:16] - * dev_no [15:11] - * fun_no [10:8] - * reg_no [7:2] - * - * so function bonito_sbridge_pciaddr for the translation from - * north bridge address to pci address. - */ - #include "qemu/osdep.h" #include "qemu/units.h" #include "qapi/error.h" @@ -106,11 +82,6 @@ #define BONITO_INTERNAL_REG_BASE (BONITO_REGBASE + BONITO_REG_BASE) #define BONITO_INTERNAL_REG_SIZE (0x70) -#define BONITO_SPCICONFIG_BASE (BONITO_PCICFG_BASE) -#define BONITO_SPCICONFIG_SIZE (BONITO_PCICFG_SIZE) - - - /* 1. Bonito h/w Configuration */ /* Power on register */ @@ -156,6 +127,9 @@ FIELD(PCIMEMBASECFG, IO1, 23, 1) #define BONITO_PCIMAP_CFG (0x18 >> 2) /* 0x118 */ +REG32(PCIMAP_CFG, 0x118) +FIELD(PCIMAP_CFG, AD16UP, 0, 16) +FIELD(PCIMAP_CFG, TYPE1, 16, 1) /* 5. ICU & GPIO regs */ /* GPIO Regs - r/w */ @@ -214,23 +188,14 @@ FIELD(PCIMEMBASECFG, IO1, 23, 1) #define BONITO_REGS (0x70 >> 2) -/* PCI config for south bridge. type 0 */ -#define BONITO_PCICONF_IDSEL_MASK 0xfffff800 /* [31:11] */ -#define BONITO_PCICONF_IDSEL_OFFSET 11 -#define BONITO_PCICONF_FUN_MASK 0x700 /* [10:8] */ -#define BONITO_PCICONF_FUN_OFFSET 8 -#define BONITO_PCICONF_REG_MASK_DS (~3) /* Per datasheet */ -#define BONITO_PCICONF_REG_MASK_HW 0xff /* As seen running PMON */ -#define BONITO_PCICONF_REG_OFFSET 0 - +/* PCI Access Cycle Fields */ +FIELD(TYPE0_CYCLE, FUNC, 8, 3) +FIELD(TYPE0_CYCLE, IDSEL, 11, 21) -/* idsel BIT = pci slot number +12 */ -#define PCI_SLOT_BASE 12 -#define PCI_IDSEL_VIA686B_BIT (17) -#define PCI_IDSEL_VIA686B (1 << PCI_IDSEL_VIA686B_BIT) - -#define PCI_ADDR(busno , devno , funno , regno) \ - ((PCI_BUILD_BDF(busno, PCI_DEVFN(devno , funno)) << 8) + (regno)) +FIELD(TYPE1_CYCLE, FUNC, 8, 3) +FIELD(TYPE1_CYCLE, DEV, 11, 5) +FIELD(TYPE1_CYCLE, BUS, 16, 8) +FIELD(TYPE1_CYCLE, IDSEL, 24, 8) typedef struct BonitoState BonitoState; @@ -580,108 +545,91 @@ static const MemoryRegionOps bonito_cop_ops = { }, }; -static uint32_t bonito_sbridge_pciaddr(void *opaque, hwaddr addr) +static PCIDevice *bonito_pcihost_cfg_decode(PCIBonitoState *s, hwaddr addr) { - PCIBonitoState *s = opaque; PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost); - uint32_t cfgaddr; - uint32_t idsel; - uint32_t devno; - uint32_t funno; - uint32_t regno; - uint32_t pciaddr; - - /* support type0 pci config */ - if ((s->regs[BONITO_PCIMAP_CFG] & 0x10000) != 0x0) { - return 0xffffffff; + uint32_t pcimap_cfg = s->regs[BONITO_PCIMAP_CFG]; + uint32_t cycle, dev, func, bus; + + cycle = addr | FIELD_EX32(pcimap_cfg, PCIMAP_CFG, AD16UP) << 16; + + if (FIELD_EX32(pcimap_cfg, PCIMAP_CFG, TYPE1)) { + dev = FIELD_EX32(cycle, TYPE1_CYCLE, DEV); + func = FIELD_EX32(cycle, TYPE1_CYCLE, FUNC); + bus = FIELD_EX32(cycle, TYPE1_CYCLE, BUS); + } else { + uint32_t idsel = FIELD_EX32(cycle, TYPE0_CYCLE, IDSEL); + if (idsel == 0) { + return NULL; + } + dev = ctz32(idsel); + func = FIELD_EX32(cycle, TYPE0_CYCLE, FUNC); + bus = 0; } - cfgaddr = addr & 0xffff; - cfgaddr |= (s->regs[BONITO_PCIMAP_CFG] & 0xffff) << 16; + return pci_find_device(phb->bus, bus, PCI_DEVFN(dev, func)); +} - idsel = (cfgaddr & BONITO_PCICONF_IDSEL_MASK) >> - BONITO_PCICONF_IDSEL_OFFSET; - devno = ctz32(idsel); - funno = (cfgaddr & BONITO_PCICONF_FUN_MASK) >> BONITO_PCICONF_FUN_OFFSET; - regno = (cfgaddr & BONITO_PCICONF_REG_MASK_HW) >> BONITO_PCICONF_REG_OFFSET; +static void bonito_pcihost_signal_mabort(PCIBonitoState *s) +{ + PCIDevice *d = &s->dev; + uint16_t status = pci_get_word(d->config + PCI_STATUS); - if (idsel == 0) { - error_report("error in bonito pci config address 0x" HWADDR_FMT_plx - ",pcimap_cfg=0x%x", addr, s->regs[BONITO_PCIMAP_CFG]); - exit(1); - } - pciaddr = PCI_ADDR(pci_bus_num(phb->bus), devno, funno, regno); - DPRINTF("cfgaddr %x pciaddr %x busno %x devno %d funno %d regno %d\n", - cfgaddr, pciaddr, pci_bus_num(phb->bus), devno, funno, regno); + status |= PCI_STATUS_REC_MASTER_ABORT; + pci_set_word(d->config + PCI_STATUS, status); - return pciaddr; + /* Generate a pulse, it's a edge triggered IRQ */ + bonito_set_irq(s->pcihost, ICU_PIN_MASTERERR, 1); + bonito_set_irq(s->pcihost, ICU_PIN_MASTERERR, 0); } -static void bonito_spciconf_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) +static MemTxResult bonito_pcihost_cfg_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned len, + MemTxAttrs attrs) { PCIBonitoState *s = opaque; - PCIDevice *d = PCI_DEVICE(s); - PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost); - uint32_t pciaddr; - uint16_t status; - - DPRINTF("bonito_spciconf_write "HWADDR_FMT_plx" size %d val %lx\n", - addr, size, val); - - pciaddr = bonito_sbridge_pciaddr(s, addr); - - if (pciaddr == 0xffffffff) { - return; - } - if (addr & ~BONITO_PCICONF_REG_MASK_DS) { - trace_bonito_spciconf_small_access(addr, size); + PCIDevice *dev; + + dev = bonito_pcihost_cfg_decode(s, addr); + if (!dev) { + bonito_pcihost_signal_mabort(s); + /* + * Vanilla bonito will actually triiger a bus error on master abort, + * Godson variant won't. We need to return all 1s. + */ + *data = UINT64_MAX; + return MEMTX_OK; } - /* set the pci address in s->config_reg */ - phb->config_reg = (pciaddr) | (1u << 31); - pci_data_write(phb->bus, phb->config_reg, val, size); + addr &= PCI_CONFIG_SPACE_SIZE - 1; + *data = pci_host_config_read_common(dev, addr, pci_config_size(dev), len); - /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */ - status = pci_get_word(d->config + PCI_STATUS); - status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT); - pci_set_word(d->config + PCI_STATUS, status); + return MEMTX_OK; } -static uint64_t bonito_spciconf_read(void *opaque, hwaddr addr, unsigned size) +static MemTxResult bonito_pcihost_cfg_write(void *opaque, hwaddr addr, + uint64_t data, unsigned len, + MemTxAttrs attrs) { PCIBonitoState *s = opaque; - PCIDevice *d = PCI_DEVICE(s); - PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost); - uint32_t pciaddr; - uint16_t status; - - DPRINTF("bonito_spciconf_read "HWADDR_FMT_plx" size %d\n", addr, size); + PCIDevice *dev; - pciaddr = bonito_sbridge_pciaddr(s, addr); - - if (pciaddr == 0xffffffff) { - return MAKE_64BIT_MASK(0, size * 8); - } - if (addr & ~BONITO_PCICONF_REG_MASK_DS) { - trace_bonito_spciconf_small_access(addr, size); + dev = bonito_pcihost_cfg_decode(s, addr); + if (!dev) { + bonito_pcihost_signal_mabort(s); + return MEMTX_OK; } - /* set the pci address in s->config_reg */ - phb->config_reg = (pciaddr) | (1u << 31); - - /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */ - status = pci_get_word(d->config + PCI_STATUS); - status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT); - pci_set_word(d->config + PCI_STATUS, status); + addr &= PCI_CONFIG_SPACE_SIZE - 1; + pci_host_config_write_common(dev, addr, pci_config_size(dev), data, len); - return pci_data_read(phb->bus, phb->config_reg, size); + return MEMTX_OK; } -/* south bridge PCI configure space. 0x1fe8 0000 - 0x1fef ffff */ -static const MemoryRegionOps bonito_spciconf_ops = { - .read = bonito_spciconf_read, - .write = bonito_spciconf_write, +/* PCI Configure Space access region. 0x1fe8 0000 - 0x1fef ffff */ +static const MemoryRegionOps bonito_pcihost_cfg_ops = { + .read_with_attrs = bonito_pcihost_cfg_read, + .write_with_attrs = bonito_pcihost_cfg_write, .valid.min_access_size = 1, .valid.max_access_size = 4, .impl.min_access_size = 1, @@ -812,10 +760,10 @@ static void bonito_pci_realize(PCIDevice *dev, Error **errp) memory_region_add_subregion(host_mem, BONITO_PCICONFIG_BASE, &phb->conf_mem); - /* set the south bridge pci configure mapping */ - memory_region_init_io(&phb->data_mem, OBJECT(s), &bonito_spciconf_ops, s, - "south-bridge-pci-config", BONITO_SPCICONFIG_SIZE); - memory_region_add_subregion(host_mem, BONITO_SPCICONFIG_BASE, + /* set the pci config space accessor mapping */ + memory_region_init_io(&phb->data_mem, OBJECT(s), &bonito_pcihost_cfg_ops, s, + "pci-host-config-access", BONITO_PCICFG_SIZE); + memory_region_add_subregion(host_mem, BONITO_PCICFG_BASE, &phb->data_mem); create_unimplemented_device("bonito", BONITO_REG_BASE, BONITO_REG_SIZE); diff --git a/hw/pci-host/trace-events b/hw/pci-host/trace-events index 0a816b9aa129bb0c37d207e2612e09ac4762d51a..bd9bdeadfd3678e303a412688d689cc01d06f709 100644 --- a/hw/pci-host/trace-events +++ b/hw/pci-host/trace-events @@ -1,8 +1,5 @@ # See docs/devel/tracing.rst for syntax documentation. -# bonito.c -bonito_spciconf_small_access(uint64_t addr, unsigned size) "PCI config address is smaller then 32-bit, addr: 0x%"PRIx64", size: %u" - # grackle.c grackle_set_irq(int irq_num, int level) "set_irq num %d level %d" -- Git-154)