I have a requirement to transmit data and receive data at the same time. The received data is not done during the read(). It is performed during the write().
the user calls the ioctl first specifying a buffer for the receive buffer. Then the write() is performed as follows: getpid of the write task. getpriority() of write task, stsetprio() of the interrupt thread ID to (stgetprio() <<1)+1.
setup output dma using the following steps: mem_lock() /*locks users' output buffer using write task id*/ caculate number of DMA pages required for operation. mmchain() to retrieve physical address of output DMA pages.
setup receive dma using the following steps: mem_lock() /*locks users' output buffer using write task id*/ caculate number of DMA pages required for operation. mmchain() to retrieve physical address of received buffer DMA pages.
Setup hardware for output and input DMA. Enable the hardward for DMA operation.
when interrupt occurs, mem_unlock() both output and input buffers.
The above operation works find the first time. However, if I try it again, the system either crashes(most of the time) or hangs up.
If I do strictly write() operations, it works find...no crashes.
It looks like the receive buffer is causing a problem but I haven't been able to figure it out. It has been 3 days, and I need to solve this problem.
I noticed that I'm using the write task ID to lock the memory for receive buffer although the buffer was give to the driver during an ioctl call. Is this correct? Could this be causing my problem? should I be locking the received buffer during the ioctl call?
My experience with LynxOS is limitted. I'm a Windows Device Driver guy.
John wrote: > On Thu, 10 Jul 2008 14:50:00 -0700, Cyril Novikov > <cnovi...@mail.remove.this.ru> wrote:
>> John wrote:
>>> If I do strictly write() operations, it works find...no crashes. >> "Works fine" meaning it doesn't crash or doesn't crash AND the written data is >> correct (as in matches what was expected to be written)?
> Correct. The write() completes and the data is received correctly. > However, if I try to receive anything, the system crashes.
That means virtual to bus address conversion is done properly... Hard to say what's wrong with the read, then. Can you quote your code that converts virtual addresses to bus addresses?
>>>> If I do strictly write() operations, it works find...no crashes. >>> "Works fine" meaning it doesn't crash or doesn't crash AND the written data is >>> correct (as in matches what was expected to be written)?
>> Correct. The write() completes and the data is received correctly. >> However, if I try to receive anything, the system crashes.
>That means virtual to bus address conversion is done properly... Hard to say >what's wrong with the read, then. Can you quote your code that converts virtual >addresses to bus addresses?
Here's the code, common to both the write buffer and receive buffer. The taskId are the same for the write and the receive.
The DmaArray is saved in the driver's data structure. One for write and one for received.
If I do the write without the receive, everthing works ok. If I do a read(). That works ok. The problem shows up when I try the write() with a receive at the same time (no read()). The first time it appears to work find. But when I try to do any I/O read() or write(), the system crashes or hangs-up.
John wrote: > On Mon, 14 Jul 2008 16:55:21 -0700, Cyril Novikov > <cnovi...@mail.remove.this.ru> wrote:
>> John wrote: >>> On Thu, 10 Jul 2008 14:50:00 -0700, Cyril Novikov >>> <cnovi...@mail.remove.this.ru> wrote:
>>>> John wrote:
>>>>> If I do strictly write() operations, it works find...no crashes. >>>> "Works fine" meaning it doesn't crash or doesn't crash AND the written data is >>>> correct (as in matches what was expected to be written)? >>> Correct. The write() completes and the data is received correctly. >>> However, if I try to receive anything, the system crashes. >> That means virtual to bus address conversion is done properly... Hard to say >> what's wrong with the read, then. Can you quote your code that converts virtual >> addresses to bus addresses? > Here's the code, common to both the write buffer and receive buffer. > The taskId are the same for the write and the receive.
> /* Lock memory */
[skipped]
I do not see any problems in the code.
I have the following notes:
> when interrupt occurs, mem_unlock() both output and input buffers.
Hopefully, you don't call mem_unlock() from the interrupt handler. Make sure you don't make any calls that are not explicitly allowed from interrupt handlers.
> I noticed that I'm using the write task ID to lock the memory for > receive buffer although the buffer was give to the driver during an > ioctl call. Is this correct? Could this be causing my problem? should > I be locking the received buffer during the ioctl call?
Where does the buffer memory come from? If from the userland, you should lock it during ioctl(). Hopefully, the process that allocated the buffer is still alive when you do DMA. If the buffer is allocated with sysbrk(), you don't need to lock it at all, kernel memory is not swappable. In fact, something may break if you attempt to lock it (though I am not familiar with that LynxOS version code that well).
>>> John wrote: >>>> On Thu, 10 Jul 2008 14:50:00 -0700, Cyril Novikov >>>> <cnovi...@mail.remove.this.ru> wrote:
>>>>> John wrote:
>>>>>> If I do strictly write() operations, it works find...no crashes. >>>>> "Works fine" meaning it doesn't crash or doesn't crash AND the written data is >>>>> correct (as in matches what was expected to be written)? >>>> Correct. The write() completes and the data is received correctly. >>>> However, if I try to receive anything, the system crashes. >>> That means virtual to bus address conversion is done properly... Hard to say >>> what's wrong with the read, then. Can you quote your code that converts virtual >>> addresses to bus addresses? >> Here's the code, common to both the write buffer and receive buffer. >> The taskId are the same for the write and the receive.
>> /* Lock memory */ >[skipped]
>I do not see any problems in the code.
>I have the following notes:
> > when interrupt occurs, mem_unlock() both output and input buffers.
>Hopefully, you don't call mem_unlock() from the interrupt handler. Make sure you >don't make any calls that are not explicitly allowed from interrupt handlers.
>> I noticed that I'm using the write task ID to lock the memory for >> receive buffer although the buffer was give to the driver during an >> ioctl call. Is this correct? Could this be causing my problem? should >> I be locking the received buffer during the ioctl call?
>Where does the buffer memory come from? If from the userland, you should lock it >during ioctl(). Hopefully, the process that allocated the buffer is still alive >when you do DMA. If the buffer is allocated with sysbrk(), you don't need to >lock it at all, kernel memory is not swappable. In fact, something may break if >you attempt to lock it (though I am not familiar with that LynxOS version code >that well).
The buffer does come from the user during ioctl() but I don't lock it down until the write(). The process is still active. the application calls the ioctl() to set the receive buffer and other stuff and then calls the write() to kick thing off.
the wierd part is that everything looks ok from the print statements and bus analyzer. The driver gets back to the user and then the system crashes. It does sound like a pointer problem but I just don't see it. the code is common to other drivers on other systems and they work just find.
John wrote: >>> when interrupt occurs, mem_unlock() both output and input buffers. >> Hopefully, you don't call mem_unlock() from the interrupt handler. Make sure you >> don't make any calls that are not explicitly allowed from interrupt handlers.
>>> I noticed that I'm using the write task ID to lock the memory for >>> receive buffer although the buffer was give to the driver during an >>> ioctl call. Is this correct? Could this be causing my problem? should >>> I be locking the received buffer during the ioctl call? >> Where does the buffer memory come from? If from the userland, you should lock it >> during ioctl(). Hopefully, the process that allocated the buffer is still alive >> when you do DMA. If the buffer is allocated with sysbrk(), you don't need to >> lock it at all, kernel memory is not swappable. In fact, something may break if >> you attempt to lock it (though I am not familiar with that LynxOS version code >> that well).
> The buffer does come from the user during ioctl() but I don't lock it > down until the write(). The process is still active. the application > calls the ioctl() to set the receive buffer and other stuff and then > calls the write() to kick thing off.
So, are ioctl() and write() called by the same process or not? I'm confused by another post where you said:
"I noticed that I'm using the write task ID to lock the memory for receive buffer although the buffer was give to the driver during an ioctl call. Is this correct?"
Are you asking whether a "task ID" (I assume you talk about the process ID here) is the same during a process' lifetime? Yes, the process ID is constant.
>>>> when interrupt occurs, mem_unlock() both output and input buffers. >>> Hopefully, you don't call mem_unlock() from the interrupt handler. Make sure you >>> don't make any calls that are not explicitly allowed from interrupt handlers.
>>>> I noticed that I'm using the write task ID to lock the memory for >>>> receive buffer although the buffer was give to the driver during an >>>> ioctl call. Is this correct? Could this be causing my problem? should >>>> I be locking the received buffer during the ioctl call? >>> Where does the buffer memory come from? If from the userland, you should lock it >>> during ioctl(). Hopefully, the process that allocated the buffer is still alive >>> when you do DMA. If the buffer is allocated with sysbrk(), you don't need to >>> lock it at all, kernel memory is not swappable. In fact, something may break if >>> you attempt to lock it (though I am not familiar with that LynxOS version code >>> that well).
>> The buffer does come from the user during ioctl() but I don't lock it >> down until the write(). The process is still active. the application >> calls the ioctl() to set the receive buffer and other stuff and then >> calls the write() to kick thing off.
>So, are ioctl() and write() called by the same process or not? I'm confused by >another post where you said:
>"I noticed that I'm using the write task ID to lock the memory for >receive buffer although the buffer was give to the driver during an >ioctl call. Is this correct?"
>Are you asking whether a "task ID" (I assume you talk about the process ID here) >is the same during a process' lifetime? Yes, the process ID is constant.
Yes, it is called by the same process. The process first calls the ioctl() to setup the receive buffer and then calls the write() to kick-off the write/read opeartion.
The read is independent of the write operation. The read acts like an echo. for every word transmitted, the same word is received. I only get 1 interrupt, on the completion of the output. I'm going to try to put a delay on the write completion to ensure the read buffer has not been unlocked and paged out. I don't think it is. The bus analyzer shows that interrupt thread is waking up to process the interrupt in approx. 100 ms, which is more that enough time for the last word to be received into memory before the memory is unlock and maybe paged out.
My next step is to use kernel memory, receive the data, and then copy the data back to the user.
If this works, I might have to do that way although I personally don't like it. time is running out.