13

Linux 2.6.37 を実行する ARM デバイス用に開発しています。IO ピンをできるだけ速く切り替えようとしています。小さなカーネル モジュールとユーザー空間アプリケーションを作成しました。私は2つのことを試しました:

  1. を使用してカーネル空間から直接 GPIO 制御レジスタを操作しioremapます。
  2. mmap()GPIO 制御レジスタをキャッシュせずに、ユーザー空間から使用します。

どちらの方法も機能しますが、2 番目の方法は最初の方法よりも約 3 倍遅くなります (オシロスコープで観察)。すべてのキャッシュメカニズムを無効にしたと思います。

もちろん、カーネル空間の速度でユーザー空間からの柔軟性と開発の容易さという 2 つの世界を最大限に活用したいと考えています。

mmap()が よりも遅くなる理由を知っている人はいioremap()ますか?

これが私のコードです:

カーネル モジュール コード

static int ti81xx_usmap_mmap(struct file* pFile, struct vm_area_struct* pVma)
{
  pVma->vm_flags |= VM_RESERVED;
  pVma->vm_page_prot = pgprot_noncached(pVma->vm_page_prot);

  if (io_remap_pfn_range(pVma, pVma->vm_start, pVma->vm_pgoff,
                          pVma->vm_end - pVma->vm_start, pVma->vm_page_prot))
     return -EAGAIN;

  pVma->vm_ops = &ti81xx_usmap_vm_ops;
  return 0;
}

static void ti81xx_usmap_test_gpio(void)
{
  u32* pGpIoRegisters = ioremap_nocache(TI81XX_GPIO0_BASE, 0x400);
  const u32 pin = 1 << 24;
  int i;

  /* I should use IO read/write functions instead of pointer deferencing, 
   * but portability isn't the issue here */

  pGpIoRegisters[OMAP4_GPIO_OE >> 2] &= ~pin;    /* Set pin as output*/

  for (i = 0; i < 200000000; ++i)
  {
     pGpIoRegisters[OMAP4_GPIO_SETDATAOUT >> 2] = pin;
     pGpIoRegisters[OMAP4_GPIO_CLEARDATAOUT >> 2] = pin;
  }

  pGpIoRegisters[OMAP4_GPIO_OE >> 2] |= pin;    /* Set pin as input*/

  iounmap(pGpIoRegisters);
}

ユーザー空間のアプリケーション コード

int main(int argc, char** argv)
{
   int file, i;
   ulong* pGpIoRegisters = NULL;
   ulong pin = 1 << 24;

   file = open("/dev/ti81xx-usmap", O_RDWR | O_SYNC);

   if (file < 0)
   {
      printf("open failed (%d)\n", errno);
      return 1;
   }


   printf("Toggle from kernel space...");
   fflush(stdout);

   ioctl(file, TI81XX_USMAP_IOCTL_TEST_GPIO);

   printf(" done\n");    

   pGpIoRegisters = mmap(NULL, 0x400, PROT_READ | PROT_WRITE, MAP_SHARED, file, TI81XX_GPIO0_BASE);
   printf("Toggle from user space...");
   fflush(stdout);

   pGpIoRegisters[OMAP4_GPIO_OE >> 2] &= ~pin;

   for (i = 0; i < 30000000; ++i)
   {
      pGpIoRegisters[OMAP4_GPIO_SETDATAOUT >> 2] = pin;
      pGpIoRegisters[OMAP4_GPIO_CLEARDATAOUT >> 2] = pin;
   }

   pGpIoRegisters[OMAP4_GPIO_OE >> 2] |= pin;

   printf(" done\n");
   fflush(stdout);
   munmap(pGpIoRegisters, 0x400);    

   close(file);    
   return 0;
}
4

2 に答える 2

8

これは、ioremap_nocache() が VM マッピングで CPU 書き込みバッファーを引き続き有効にするのに対し、pgprot_noncached() はバッファー機能とキャッシュ機能の両方を無効にするためです。

リンゴとリンゴの比較は、代わりに ioremap_strongly_ordered() を使用することです。

于 2013-02-28T21:34:32.893 に答える
3

私の推測では、mmap書き込みが許可されているメモリに書き込んでいることを確認する必要があるため、カーネル バージョンよりも遅くなるでしょう (そのようなチェックは行わないと私は信じています/仮定します- -カーネルモジュールを使用して、物事を壊していないことを確信できるまでテストする責任があります)。

do_mmapカーネル空間から使用するために(私はそれだと思います)使用してみてmmap、それがどのように比較されるかを見てください。それが比較的速いなら、私は正しいです。そうでない場合は、別のものです。

于 2012-06-08T17:34:24.380 に答える