Page 1 of 1

RTL 8139 only first transmit works...

Posted: Thu Aug 25, 2011 12:04 pm
by lama
Hello again :D
I have noticed that my transmit routine works only once. I pass the data that I want to send, set TSD and TSAD (i use only first descriptor) and then just clear the OWN bit, which will start the loading netcard's FIFO with data from TSAD. Then I just keep checking OWN bit until is set, which means that DMA transfer has been finished. Then I get interrupt (TOK), reset it and everything is fine.
But when I try to do it again, that OWN flag will never go high as well as the TOK interrupt is ofcouse always low. And above all, when I checked that TSD register, all bites are read zero.
There is the code that does transmit:

Code: Select all

sendp:     			; edi packet begins, esi packet ends
mov ds, dx
cmp dword [BASE], 0
jnz sendp_goon
pushad
push dx
mov eax, 0x29
mov ebx, 0x802910ec
int 0x80
pop dx
mov ax, dx
mov ds, ax
mov dword [BASE], ebx
popad
sendp_goon:
mov esi, ebx
mov edx, dword [BASE]
add dx, TSAD0
mov eax, edi
out dx, eax			; packet start 
sub esi, edi			; packet count
mov edx, dword [BASE]
add dx, TSD0
in eax, dx			; get TSD (transmit descriptor)
and eax, 0xffffc000		; clear lenght and own
add eax, esi			; adding len to TSD
out dx, eax
;mov ecx, 1000
checkownclear:			; means DMA operation finished 
in eax, dx
and eax, 0x2000
cmp eax, 0x2000
jne checkownclear
;loopnz checkownclear
ret
Thanks for any help.

Re: RTL 8139 only first transmit works...

Posted: Fri Aug 26, 2011 7:42 am
by thepowersgang
Your problem is that you're only using the first descriptor, the card cycles through the descriptors as it transmits. So the first packet is sent using TD0, then the next with TD1, and so on.

Just keep track of the current descriptor so you know which one the card will use next :)

Re: RTL 8139 only first transmit works...

Posted: Fri Aug 26, 2011 10:02 am
by lama
Well, actually i have tried cycling through all 4 descriptors, but it does not work, OWN bit is never set, as well as TOK interrupt never goes high (first call works ofcourse).
Oh, and PIC and NIC's irq is reseted properly after first interrrupt arrives.

Re: RTL 8139 only first transmit works...

Posted: Fri Aug 26, 2011 6:38 pm
by thepowersgang
Well, you do need to cycle through the descriptors, so implement that.

Are you feeding the card physical addresses? Apart from that, I can't see anything wrong (in terms of hardware access) with your code. It could do with some better commenting though. And note that "test eax, 0x2000; jz checkownclear" would be a better way of checking the OWN bit.

Re: RTL 8139 only first transmit works...

Posted: Sat Aug 27, 2011 6:20 am
by lama
Right, TEST is better :) I never did anything with MAC registers, I thought I don't need physical addresses to transmit.

Re: RTL 8139 only first transmit works...

Posted: Sat Aug 27, 2011 10:47 am
by thepowersgang
By that I meant physical memory addresses, but that shouldn't be the issue.

I will blow my own trumpet for a bit, and point you to my implementation for reference: https://github.com/thepowersgang/acess2 ... /rtl8139.c

Re: RTL 8139 only first transmit works...

Posted: Sat Aug 27, 2011 11:48 am
by lama
Oh, yes the given memory is physical, 1:1 paging.
Thanks a lot :)

Re: RTL 8139 only first transmit works...

Posted: Sat Aug 27, 2011 12:18 pm
by lama
So, I have read your code and I just don't know where can I possibly go wrong :(
The only big difference I noticed is the fact, that you have setup your TSAD 'only once' ; I mean like you have selected addresses that are to be written to TSAD only once, and the actual data, that you want to send, just copy to that fixed address.
I change TSAD on runtime; I have address with data on it, and that address I write to TSAD for each transmit.
Anyway, I implemented switching between all Tx descriptors, but still nothing.

Code: Select all

curr_tsd db 0                           ; current descriptor
sendp:     			; edi packet begins, esi packet ends
mov ds, dx
cmp dword [BASE], 0
jnz sendp_goon
pushad
push dx
mov eax, 0x29
mov ebx, 0x802910ec
int 0x80
pop dx
mov ax, dx
mov ds, ax
mov dword [BASE], ebx
popad
sendp_goon:
mov esi, ebx
mov edx, dword [BASE]
add dx, TSAD0
movzx eax, byte [curr_tsd]
shl eax, 2			; each TSD is 4 bytes wide like this, TSD0 (10h-13h), TSD1 (14h-17h), TSD2 (18h-1bh), TSD3 (1ch-1fh)
add dx, ax			; same as TSAD0, TSAD1, TSAD2, TSAD3 
mov eax, edi
out dx, eax			; packet start 
sub esi, edi			; packet count
mov edx, dword [BASE]
add dx, TSD0
movzx eax, byte [curr_tsd]
shl eax, 2
add dx, ax
in eax, dx			; get TSD (transmit descriptor)
and eax, 0xffffc000		; clear lenght and own
add eax, esi			; adding len to TSD
out dx, eax
;mov ecx, 1000
checkownclear:			; means DMA operation finished
in eax, dx
and eax, 0x2000
cmp eax, 0x2000
jne checkownclear
;loopnz checkownclear
inc byte [curr_tsd]
and byte [curr_tsd], 3
ret

Re: RTL 8139 only first transmit works...

Posted: Sat Aug 27, 2011 6:16 pm
by thepowersgang
Try setting the early TX threshold (bits 16-21 of the TSD) to zero, your problem may be that the second packet is smaller? In fact, don't even bother reading the current TSD value, just set it all yourself.

Re: RTL 8139 only first transmit works...

Posted: Wed Aug 31, 2011 10:40 am
by lama
Hm, according to datasheet, the only bits that are writable are Early Tx Threshold, OWN and SIZE, everything else is cleared after SIZE is written.
So I decided to clear everything, and just add length. That works... at first attempt :D So same situation as before.
Oh, and yes - I'm sending one packet all over again, payload in it is stored as system variable, nothing changes accept the memory that is written to TSAD ofcourse (packet is again assembled, getting payload from that variable).
So data and length remains the same.

Re: RTL 8139 only first transmit works...

Posted: Wed Aug 31, 2011 1:05 pm
by lama
Well, if I stop checking for that OWN bit, then it goes like this :
Send first packed, received interrupt, everything OK.
Send second packet, nothing happened, no interrupt, OWN never gets high etc..
Send third packet, received interrupt, everything OK.
Send fourth packet, nothing happened, no interrupt, OWN never gets high etc..
And this pattern repeats all over again :D

Re: RTL 8139 only first transmit works...

Posted: Wed Aug 31, 2011 6:35 pm
by thepowersgang
Two things to check first.

1. Is this actually a RTL8139? The PCI ID you're using suggests that it's a RTL8029, which is a NE2000 compatible card (iirc).
2. Do you correctly ACK the TOK interrupt?

Re: RTL 8139 only first transmit works...

Posted: Thu Sep 01, 2011 2:40 am
by lama
I obtain data that are necessary for driver to work (IO base, IRQ) from the PCI. This is another driver that can register any device on PCI bus. Driver is assigned to device by comparing Vendor and Device ID, so it is 100% correct.
I just noticed that there is a bug in sendp routine - yes it is that part that verifies if BASE was successfully retrieved from device (registered by PCI driver), and if not, it will ask for it again. Yes, it is passing value of 0x802910ec which is identifier for Ne2000 netcard (0x8029, ofcourse 8139 is 0x8139).
That's because I was working on Ne2000 before are started to write RTL 8139, so I kinda mess this up :D
But in this case it does not matter, because this code is never executed - BASE is never zero, it was properly obtained during card power on.
This bug is fixed now.
And if I handle TOK correctly, well I do TOK INT reset by writing TOK to ISR, then send EOI to both master and slave PIC. In fact I do reset all INTs in ISR
(ax = 0xffff).
Currently I do this:
1) Read ISR and check for specific INT. As for now, only TOK and ROK are enabled in IMR.
2) If no INT bit is set high, I send EOI to both PIC channels and just ret.
3) I do whatever I want in my ISR handler.
4) Reset ISR by writing a corresponding bit (one, writing zero does nothing according to RTL spec) to it.
5) Send EOI to both PIC channels.
6) Goto 1