ARM技术论坛
直播中

申根换

7年用户 1594经验值
私信 关注
[经验]

GIC ITS的ITS tables和Command Queue访问简析

GICv3的ITS将Message Based Interrupt (MSI)转换为一个发送给GIC Redistributor的LPI中断。这个过程需要使用GIC ITS Device Table,Interrupt Translation Tables和Collection Table.

1.jpg

而这些Device Table,Interrupt Translation Tables和Collection Table是放在外部内存中的,它们占用的内存由系统软件分配(通常是GIC driver),软件通过将这些table的base address写入GICITS_BASER[n]寄存器告诉ITS hardware。为了加速GIC ITS对这些tables的访问,GIC hardware可以对这些table项进行缓存(cache)。

未命名绘图-第 2 页.jpg

CPU软件如GIC driver一般只在分配这些table时,直接写0到它们进行初始化。这些table对这些table项的配置是由软件发送command到ITS command queue来间接实现的,ITS command queue也是放在外部内存中的,它占用的内存也是由软件分配。

软件通过将command queue的base address写入GICITS_CBASER寄存器告诉ITS hardware.为了加速GICITS对这些tables的访问,GIC hardware可以对这些command queue进行缓存(cache)。

在GICITS_BASER[n]和GICITS_CBASER寄存器中,除了上面所说的cacheability属性之外,还可以设置shareability属性。

通过将ITS对这些table和command queue的访问设置为Shareable, Cacheable, 可能可以实现GIC ITS和CPU对它们访问的一致性,避免额外的cache maintenance操作,但这取决于hardware层面上是否可以实现这个一致性。

对于GIC-500, 因为它ITS访问tables和command queue的接口是AXI4 master interface. 因此硬件上不支持与CPU的coherency,它的GICITS_BASER[n]和GICITS_CBASER寄存器中的shareability属性是不可写的。

但其cacheability还是可以programmable的。在GIC-500的TRM中提到,

The GIC-500 does not support shareability, but does have programmable cacheability settings. However, as the GIC-500 is unable to snoop caches, ARM recommends that cacheability fields in registers such as GICR_PENDBASER are always programmed to 0b001 (Normal, Non-cacheable).

对于GIC-600/GIC-700, GIC ITS访问tables和command queue的接口是ACE-lite master interface, 通过coherent interconnect, 硬件上可以实现与CPU的一致性。

因而它的GICITS_BASER[n]和GICITS_CBASER寄存器中的shareability和cacheability属性都是programmable的。

Linux kernel的处理方式

Linux kernel的GICv3 driver是在一般的Normal Cacheable, Shareable的内存中分配ITS tables和command queue的内存的。因而CPU软件对它的访问属性是Normal Cacheable, Shareable的。

Linux kernel的GICv3 driver通过检测GICITS_BASER[n]和GICITS_CBASER寄存器中的shareability是否可写(方式是:先在寄存器中写为shareable,在读回这个值,看看是否写成功)来判断硬件设计上GIC ITS和CPU是否可以实现一致性。

1. 如果shareability可以成功设置为shareable,那么在GICITS_BASER[n]和GICITS_CBASER寄存器中设置GIC ITS对ITS tables/command queue访问属性为Normal Cacheable, Shareable。

GIC-600/700的GICITS_BASER[n]和GICITS_CBASER寄存器中的shareability是可写的。

2. 如果shareability不能成功设置为shareable,那么在GICITS_BASER[n]和GICITS_CBASER寄存器中设置GIC ITS对ITS tables/command queue访问属性为Normal non-Cacheable, non-Shareable.同时设置一个软件flag, ITS_FLAGS_CMDQ_NEEDS_FLUSHING, 在GIC driver将ITS命令写入command queue后额外加上gic_flush_dcache_to_poc,进行cache clean到PoC(到外部内存)。

GIC-500的GICITS_BASER[n]和GICITS_CBASER寄存器中的shareability是不可写的。

baser = (virt_to_phys(its->cmd_base)    |
         GITS_CBASER_RaWaWb        |
         GITS_CBASER_InnerShareable    |
         (ITS_CMD_QUEUE_SZ / SZ_4K - 1)    |
         GITS_CBASER_VALID);

    gits_write_cbaser(baser, its->base + GITS_CBASER);
    tmp = gits_read_cbaser(its->base + GITS_CBASER);

    if ((tmp ^ baser) & GITS_CBASER_SHAREABILITY_MASK) {
        if (!(tmp & GITS_CBASER_SHAREABILITY_MASK)) {
            /*
             * The HW reports non-shareable, we must
             * remove the cacheability attributes as
             * well.
             */
            baser &= ~(GITS_CBASER_SHAREABILITY_MASK |
                   GITS_CBASER_CACHEABILITY_MASK);
            baser |= GITS_CBASER_nC;
            gits_write_cbaser(baser, its->base + GITS_CBASER);
        }
        pr_info("ITS: using cache flushing for cmd queue\n");
        its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING;
    }

    gits_write_cwriter(0, its->base + GITS_CWRITER);

static void its_flush_cmd(struct its_node *its, struct its_cmd_block cmd)
{
/

  • Make sure the commands written to memory are observable by
  • the ITS.
    */
    if (its->flags & ITS_FLAGS_CMDQ_NEEDS_FLUSHING)
    gic_flush_dcache_to_poc(cmd, sizeof(*cmd));
    else
    dsb(ishst);
    }
#### 可能存在的问题

包含GIC-600/GIC-700的系统中,虽然ITS可以通过ACE-Lite支持IO coherency, 但有的系统可能会这样设计

![2.png](//file.elecfans.com/web2/M00/84/BF/poYBAGOhVuaAcsfaAACksMMBBDA326.jpg "2.png")

*注:GIC-600 ITS可以有单独的ACE-lite port,或是共用GIC
Distributor的ACE-Lite port
GIC-700 ITS共用GIC Distributor的ACE-Lite port*

GIC ITS/Distributor通过一个interconnect将ACE-Lite转换为了AXI interface,因而这个系统设计不能实现GIC ITS和CPU的硬件一致性。

在这样的系统上运行Linux GICv3 driver可能会出现一致性问题:

因为GIC-600/700的GICITS_BASER[n]和GICITS_CBASER寄存器中的shareability是可写的,在GICITS_BASER[n]和GICITS_CBASER寄存器中设置GIC ITS对ITS tables/command queue访问属性为Normal Cacheable, Shareable,并且GIC driver在发送ITS commandcommand queue后,不会附加CPU cache clean的操作。

但却无法实现硬件的一致性,因而可能出现GIC ITS无法看到还在CPU cache中的command#### 解决方式

对于这样的系统,可能需要hack一下GICv3 driver代码,将GICITS_BASER[n]和GICITS_CBASER寄存器中强行设置GIC ITS对ITS tables/command queue访问属性为Normal non-Cacheable, non-Shareable

baser = (virt_to_phys(its->cmd_base) |
GITS_CBASER_RaWaWb |
GITS_CBASER_InnerShareable |
(ITS_CMD_QUEUE_SZ / SZ_4K - 1) |
GITS_CBASER_VALID);

gits_write_cbaser(baser, its->base + GITS_CBASER);
tmp = gits_read_cbaser(its->base + GITS_CBASER);

        /*
         * The HW reports non-shareable, we must
         * remove the cacheability attributes as
         * well.
         */
        baser &= ~(GITS_CBASER_SHAREABILITY_MASK |
               GITS_CBASER_CACHEABILITY_MASK);
        baser |= GITS_CBASER_nC;
        gits_write_cbaser(baser, its->base + GITS_CBASER);
    
    pr_info("ITS: using cache flushing for cmd queue\n");
    its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING;

gits_write_cwriter(0, its->base + GITS_CWRITER);
更长远的方式是在Linux kernel 社区推出一个patch, 在device tree/ACPI的GIC ITS node中新加一个标识系统是否可以实现GIC ITS和CPU一致性的属性。而不是现在这样通过仅仅判断GIC IP本身是否支持一致性。

#### 扩展内容

GICv3 driver 对GIC Redistributor访问LPI tables (如LPI pending table,通过GIC Distributor的interface访问)有如上类似的处理,也可能有类似的一致性问题。




原作者:修志龙_ZenonXiu

更多回帖

发帖
×
20
完善资料,
赚取积分