Author: mmel
Date: Sat Sep 19 11:27:16 2020
New Revision: 365900
URL: https://svnweb.freebsd.org/changeset/base/365900

Log:
  Implement workaround for broken access to configuration space.
  Due to a HW bug in the RockChip PCIe implementation, attempting to access
  a non-existent register in the configuration space will throw an exception.
  Use new bus functions bus_peek() and bus_poke() to overcomme this limitation.

Modified:
  head/sys/arm64/rockchip/rk_pcie.c

Modified: head/sys/arm64/rockchip/rk_pcie.c
==============================================================================
--- head/sys/arm64/rockchip/rk_pcie.c   Sat Sep 19 11:06:41 2020        
(r365899)
+++ head/sys/arm64/rockchip/rk_pcie.c   Sat Sep 19 11:27:16 2020        
(r365900)
@@ -310,7 +310,7 @@ rk_pcie_check_dev(struct rk_pcie_softc *sc, u_int bus,
        uint32_t val;
 
        if (bus < sc->bus_start || bus > sc->bus_end || slot > PCI_SLOTMAX ||
-           func > PCI_FUNCMAX || reg > PCI_REGMAX)
+           func > PCI_FUNCMAX || reg > PCIE_REGMAX)
                return (false);
 
        if (bus == sc->root_bus) {
@@ -325,8 +325,8 @@ rk_pcie_check_dev(struct rk_pcie_softc *sc, u_int bus,
        if (STATUS1_LINK_ST_GET(val) != STATUS1_LINK_ST_UP)
                return (false);
 
-       /* only one device is on first subordinate bus */
-       if (bus == sc->sub_bus  && slot)
+       /* only one device can be on first subordinate bus */
+       if (bus == sc->sub_bus  && slot != 0 )
                return (false);
        return (true);
 }
@@ -452,45 +452,41 @@ rk_pcie_read_config(device_t dev, u_int bus, u_int slo
     u_int func, u_int reg, int bytes)
 {
        struct rk_pcie_softc *sc;
-       uint32_t data;
+       uint32_t d32, data;
+       uint16_t d16;
+       uint8_t d8;
        uint64_t addr;
-       int type;
+       int type, ret;
 
        sc = device_get_softc(dev);
 
        if (!rk_pcie_check_dev(sc, bus, slot, func, reg))
                return (0xFFFFFFFFU);
-
        if (bus == sc->root_bus)
                return (rk_pcie_local_cfg_read(sc, false, reg, bytes));
 
        addr = ATU_CFG_BUS(bus) | ATU_CFG_SLOT(slot) | ATU_CFG_FUNC(func) |
            ATU_CFG_REG(reg);
-       if (bus == sc->sub_bus) {
-               type = ATU_TYPE_CFG0;
-       } else {
-               type = ATU_TYPE_CFG1;
-               /*
-               * XXX FIXME: any attempt to generate type1 configuration
-               * access causes external data abort
-               */
-               return (0xFFFFFFFFU);
-       }
+       type = bus == sc->sub_bus ? ATU_TYPE_CFG0: ATU_TYPE_CFG1;
        rk_pcie_map_cfg_atu(sc, 0, type);
 
+       ret = -1;
        switch (bytes) {
        case 1:
-               data = bus_read_1(sc->axi_mem_res, addr);
+               ret = bus_peek_1(sc->axi_mem_res, addr, &d8);
+               data = d8;
                break;
        case 2:
-               data = bus_read_2(sc->axi_mem_res, addr);
+               ret = bus_peek_2(sc->axi_mem_res, addr, &d16);
+               data = d16;
                break;
        case 4:
-               data = bus_read_4(sc->axi_mem_res, addr);
+               ret = bus_peek_4(sc->axi_mem_res, addr, &d32);
+               data = d32;
                break;
-       default:
-               data =  0xFFFFFFFFU;
        }
+       if (ret != 0)
+               data = 0xFFFFFFFF;
        return (data);
 }
 
@@ -512,27 +508,18 @@ rk_pcie_write_config(device_t dev, u_int bus, u_int sl
 
        addr = ATU_CFG_BUS(bus) | ATU_CFG_SLOT(slot) | ATU_CFG_FUNC(func) |
            ATU_CFG_REG(reg);
-       if (bus == sc->sub_bus){
-               type = ATU_TYPE_CFG0;
-       } else {
-               type = ATU_TYPE_CFG1;
-               /*
-               * XXX FIXME: any attempt to generate type1 configuration
-               * access causes external data abort
-               */
-               return;
-       }
+       type = bus == sc->sub_bus ? ATU_TYPE_CFG0: ATU_TYPE_CFG1;
        rk_pcie_map_cfg_atu(sc, 0, type);
 
        switch (bytes) {
        case 1:
-               bus_write_1(sc->axi_mem_res, addr, val);
+               bus_poke_1(sc->axi_mem_res, addr, (uint8_t)val);
                break;
        case 2:
-               bus_write_2(sc->axi_mem_res, addr, val);
+               bus_poke_2(sc->axi_mem_res, addr, (uint16_t)val);
                break;
        case 4:
-               bus_write_4(sc->axi_mem_res, addr, val);
+               bus_poke_4(sc->axi_mem_res, addr, val);
                break;
        default:
                break;
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to