2011-12-02 11 views
6

Tôi có trình điều khiển yêu cầu độ trễ micro giây. Để tạo độ trễ này, trình điều khiển của tôi đang sử dụng chức năng udelay của hạt nhân. Cụ thể, có một cuộc gọi đến udelay (90):Nhân Linux: udelay() trả về quá sớm?

iowrite32(data, addr + DATA_OFFSET); 
iowrite32(trig, addr + CONTROL_OFFSET); 

udelay(30); 

trig |= 1; 
iowrite32(trig, addr + CONTROL_OFFSET); 

udelay(90); // This is the problematic call 

Chúng tôi đã gặp sự cố về độ tin cậy với thiết bị. Sau nhiều lần gỡ lỗi, chúng tôi đã tìm ra vấn đề với trình điều khiển tiếp tục trước khi 90us trôi qua. (Xem "bằng chứng" bên dưới.)

Tôi đang chạy phiên bản hạt nhân 2.6.38-11-chung SMP (Kubuntu 11.04, x86_64) trên Intel Pentium Dual Core (E5700).

Theo như tôi biết, tài liệu tuyên bố rằng udelay sẽ trì hoãn thực hiện cho ít nhất độ trễ được chỉ định và không thể ngắt. Có lỗi nào trong phiên bản này của hạt nhân không, hoặc tôi có hiểu lầm về việc sử dụng udelay không?


Để thuyết phục bản thân rằng vấn đề là do udelay trở về quá sớm, chúng tôi ăn một đồng hồ 100kHz với một trong các cổng vào/O và thực hiện chậm trễ của chúng ta như sau:

// Wait until n number of falling edges 
// are observed 
void clk100_delay(void *addr, u32 n) { 
    int i; 

    for (i = 0; i < n; i++) { 
     u32 prev_clk = ioread32(addr); 
     while (1) { 
      u32 clk = ioread32(addr); 
      if (prev_clk && !clk) { 
       break; 
      } else { 
       prev_clk = clk; 
      } 
     } 
    } 
} 

... và người lái xe bây giờ hoạt động hoàn hảo.


Là một lưu ý cuối cùng, tôi thấy a discussion chỉ ra rằng tần số rộng có thể gây ra cho gia đình * delay() chức năng để misbehave, nhưng đây là một danh sách gửi thư ARM - Tôi giả sử các vấn đề như vậy sẽ không tồn tại trên một máy tính dựa trên Linux x86.

Trả lời

2

E5700 có X86_FEATURE_CONSTANT_TSC nhưng không X86_FEATURE_NONSTOP_TSC. TSC là nguồn đồng hồ có khả năng cho số udelay. Trừ khi bị ràng buộc với một trong các lõi có mặt nạ ái lực, nhiệm vụ của bạn có thể đã được đặt trước và được lên lịch lại cho một CPU khác trong thời gian udelay. Hoặc TSC có thể không ổn định trong các chế độ CPU công suất thấp hơn.

Bạn có thể thử tắt các ngắt hoặc vô hiệu hóa việc sử dụng trong số udelay không? Ngoài ra, hãy thử đọc TSC trước và sau.

+0

Tôi sẽ dùng thử và liên hệ lại với bạn. Vì vậy, tôi hiểu bạn đúng, mỗi lõi có TSC riêng của nó, vì vậy nếu quá trình điều khiển của tôi là phục vụ đã được lên lịch lại cho CPU khác, TSC có thể không giống nhau? Ngoài ra, tôi có hiểu chính xác rằng X86_FEATURE_CONSTANT_TSC biểu thị rằng TSC của CPU ổn định không phụ thuộc vào việc tăng tần số và X86_FEATURE_NONSTOP_TSC có nghĩa là TSC sẽ không bao giờ ngừng đếm? Nếu vậy, khi nào một CPU sẽ ngăn chặn nó là TSC? –

+0

TSC có thể tạm dừng trong một số [C-States] (http://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface#Processor_states). –

+2

[Mã trễ [TSC-based]] (http://lxr.linux.no/#linux+v2.6.38/arch/x86/lib/delay.c#L51) các tài khoản được chuyển giữa các CPU trong thời gian trễ. TSC dừng lại trong thời gian trễ sẽ chỉ làm cho độ trễ * dài hơn *, không * ngắn hơn *, do đó không phải là vấn đề. – caf

3

Tôi không biết bất kỳ lỗi nào trong phiên bản hạt nhân đó (nhưng điều đó không có nghĩa là không có phiên bản nào).

udelay() không phải là "không gián đoạn" - nó không vô hiệu hóa việc sử dụng trước, do đó nhiệm vụ của bạn có thể được tác vụ RT thực hiện trước trong thời gian trễ. Tuy nhiên, điều tương tự cũng đúng với việc triển khai chậm trễ thay thế của bạn, do đó, điều đó có vẻ không phải là vấn đề.

Sự cố thực tế của bạn có phải là vấn đề liên quan đến bộ nhớ/mạch kết hợp DMA không? Việc triển khai chậm trễ thay thế của bạn truy cập vào bus, vì vậy điều này có thể che giấu vấn đề thực sự như là một tác dụng phụ.

+0

Xin lỗi, ý tôi là "uninterruptible" là cuộc gọi chỉ nên quay trở lại sau khi trì hoãn. Trong trình điều khiển này, tôi không sử dụng DMA. Đối với các vấn đề về kết nối bộ nhớ cache, thiết bị là một FPGA PCI-Express. Khi thăm dò thiết bị, tôi yêu cầu vùng I/O của nó và sử dụng ioremap_nocache() để lấy địa chỉ cơ sở được sử dụng trong tất cả các hàm I/O. Tôi nghĩ rằng bằng cách sử dụng ioremap_nocache() đảm bảo sự kết hợp bộ nhớ cache? –