host/remote-lib/octeon-remote-pci.c阅读

1. 总体pcie操作集, 提供上层使用的回调

int octeon_remote_pci(octeon_remote_funcs_t *remote_funcs)
{
    remote_funcs->open = pci_open;
    remote_funcs->close = pci_close;
    remote_funcs->read_csr = pci_read_csr;
    remote_funcs->write_csr = pci_write_csr;
    remote_funcs->read_csr32 = pci_read_csr32;
    remote_funcs->write_csr32 = pci_write_csr32;
    remote_funcs->read_mem = pci_read_mem;
    remote_funcs->write_mem = pci_write_mem;
    remote_funcs->get_model = pci_get_model;
    remote_funcs->start_cores = pci_start_cores;
    remote_funcs->stop_cores = pci_stop_cores;
    remote_funcs->get_running_cores = pci_get_running_cores;
    remote_funcs->get_num_cores = pci_get_num_cores;
    remote_funcs->get_core_state = pci_get_core_state;
    remote_funcs->set_core_state = pci_set_core_state;
    remote_funcs->reset = pci_reset;
    remote_funcs->get_sample = pci_get_sample;

    if (getenv("OCTEON_PCI_DEBUG"))
        remote_funcs->debug++;

    return 0;
}

1.1. pci_open

int pci_open(const char *remote_spec)
  pci_get_device(int device)
    in = fopen("/proc/bus/pci/devices", "r");
    //这个文件里面每行都是个pcie设备
    while (!feof(in))
      //用fscanf读出相关信息
      fscanf(in, "%2x%2x %8x %x %Lx %Lx %Lx %Lx %Lx %Lx %Lx %Lx %Lx %Lx",省略)
      //找到对应的id, 得到br0和br1的地址和大小(物理地址)
      octeon_pci_bar0_address octeon_pci_bar1_address octeon_pci_bar0_size octeon_pci_bar1_size
      //检查是否打开了配置空间的master位, 注意写/proc/bus/pci/devices这个文件可以直接修改配置空间
  //使用/dev/mem来mmap64得到虚拟地址
  octeon_pci_bar0_ptr = octeon_remote_map(octeon_pci_bar0_address, octeon_pci_bar0_size, &bar0_cookie);
    mmap64(NULL, alength, PROT_READ|PROT_WRITE, MAP_SHARED, file_handle, physical_address & (int64_t)pagemask);
  //同样的, 获得bar1虚拟地址
  //这里是一些有关pcie变量的初始化?
  setup_globals()

1.2. pci_read_csr

uint64_t pci_read_csr(uint64_t physical_address)
  octeon2
    OCTEON_SLI_ADDR直接访问
    其他通过窗口寄存器(octeon_pci_bar0_win_rd_addr)转
  octeon3
    都通过octeon_pci_bar0_win_rd_addr转

1.3. pci_write_mem

void pci_write_mem(uint64_t physical_address, const void *buffer_ptr, int length)
    //原则上按照4M一块来写(还记得吗, bar1是16*4M的访问模式)
    //但这里有个问题, 就是physical_address应该是个任意地址, 而且length也应该是任意的
    //所以是这样访问, 把physical_address...length分成三大部分
    //不到4M的头+n*4M中间的+不到4M的尾
    char *buffer = (char*)buffer_ptr;
    uint32_t block_mask = (1<<22) - 1;
    uint64_t end_address = physical_address + length;


    /* We need to do writes in 4MB aligned chunks. This way we only need to
        mess with one BAR1 index register */
    do
    {
        void *ptr = octeon_pci_bar1_ptr + (physical_address & block_mask);
        if (end_address > (physical_address & ~(uint64_t)block_mask) + block_mask + 1)
            length = block_mask + 1 - (physical_address & block_mask);
        else
            length = end_address - physical_address;
        //只用到16个窗口的index0, 修改其基址
        pci_bar1_setup(physical_address);
        //根据地址对齐方式来拷贝
        fast_memcpy(ptr, buffer, length);
        buffer += length;
        physical_address += length;
    } while (physical_address < end_address);

results matching ""

    No results matching ""