OSDev.org

The Place to Start for Operating System Developers
It is currently Tue Apr 23, 2024 12:34 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 8 posts ] 
Author Message
 Post subject: XHCI
PostPosted: Sat Dec 07, 2019 7:06 am 
Offline
Member
Member

Joined: Tue Aug 30, 2016 1:31 pm
Posts: 69
Hello everyone,

Im making a XHCI driver.
This is the code I made:
https://github.com/AdeRegt/SanderOSUSB/ ... dev/xhci.c

Somehow the event ring is not working. what am I doing wrong?

XHCI on Bochs is saying the command doorbell is rang and successfull.
00126191490d[XHCI ] Command Doorbell Rang
00126191490d[XHCI ] Dump command trb: 9(dec) (0x0000000000000000 0x00000000 0x00002400) (0)
00126191490d[XHCI ] 0x0000000000054000: Command Ring: Found Enable Slot TRB (slot = 1) (returning 1)

The event ring only returns 0


Top
 Profile  
 
 Post subject: Re: XHCI
PostPosted: Sat Dec 07, 2019 2:55 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
I am afraid we are going to need a little more details. What is not working? What results are you getting? Please give more detail and an example of what is actually not working.

Did you run the code with the XHCI in debug mode? i.e.: Have Bochs print all of the BX_DEBUG() items to your log file. This will show a bit more detail of what is actually happening.

Ben
- http://www.fysnet.net/the_universal_serial_bus.htm


Top
 Profile  
 
 Post subject: Re: XHCI
PostPosted: Sat Dec 07, 2019 3:51 pm 
Offline
Member
Member

Joined: Tue Aug 30, 2016 1:31 pm
Posts: 69
Yes, Bochs is in XHCI debug mode.
I am actually debuggin me code using the sourcecode of bochs and I expect this message to popup:
Interrupter 0: Event Ring Table has 1 entries:
(see http://bochs.sourceforge.net/cgi-bin/lx ... i.cc#L2177 )

Also I expect, after the debugmessage that the queue-item is executed, that there would be an event TRB on the event ring.
I test this by reading the bytes at 0x41400 (this address I specified at the Event Ring Segment Table)


Top
 Profile  
 
 Post subject: Re: XHCI
PostPosted: Sat Dec 07, 2019 7:26 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
So you are trying to enable the slot:
Quote:
XHCI on Bochs is saying the command doorbell is rang and successfull.
00126191490d[XHCI ] Command Doorbell Rang
00126191490d[XHCI ] Dump command trb: 9(dec) (0x0000000000000000 0x00000000 0x00002400) (0)
00126191490d[XHCI ] 0x0000000000054000: Command Ring: Found Enable Slot TRB (slot = 1) (returning 1)
The command is returning a value of 1, which is expected. A completion code of 1.

This means that your command ring is most likely correct. However, since you are not receiving an event ring entry, you need to look at your event ring code and setup.

Your event ring register should point to a Segment Table, which in turn will point to one or more Ring Segments. These Segment Rings must be 64-byte aligned, must not be more than 64k in size, and must not cross a 64k boundary.

Does your Event Ring Base Address Register point to a Segment Table?
Code:
   // setting up "Event Ring Segment Table"
   unsigned long rsb1 = 0x1000;
   unsigned long rsb2 = 0x1008;
   ((unsigned long*)rsb1)[0] |= 0x41400;    // pointer to event ring queue
   ((unsigned long*)rsb2)[0] |= 16;   // size of ring segment (minimal length)
   // setting up "Event Ring Segment Table Base Address Register (ERSTBA)"
   unsigned long erstba_addr = rtsoff + 0x030;
   ((unsigned long*)erstba_addr)[0] |= 0x1000; // table at 0x1000 for now
Looks like it does. However, is your Segment Table actually at physical address 0x00001000? This seems a bit odd, but okay.

You should be writing the Dequeue Pointer Register with bit 3 set, clearing the bit. This should be done to clear the Busy bit. If the bit happens to be set (remembering that it is Write Clear), the Interrupter won't write an event.

Also, you should write the Interrupter Address register last, after all the other writes. The specification states that it must be written to last (of all the other Interrupter registers). This way when the hardware recognizes this write, it may read all the other registers and initialize its internal interrupter state. If you haven't written the other registers yet, this may cause some problems.

Make a few changes to your code so that you write the Interrupter Address register last, clear bit 3 of the Dequeue pointer register, and see what happens.

Ben
- http://www.fysnet.net/the_universal_serial_bus.htm


Top
 Profile  
 
 Post subject: Re: XHCI
PostPosted: Sun Dec 08, 2019 7:53 am 
Offline
Member
Member

Joined: Tue Aug 30, 2016 1:31 pm
Posts: 69
Thank you for the comment.
I uploaded the changed code.
I reordered the moments when the registers are written.
Now I have the following order:
Setup event ring segment table
setting up "Event Ring Segment Table Size Register (ERSTSZ)" to 1
setting up "Event Ring Dequeue Pointer Register (ERDP)" to 0x41400 and forced clear bit 3
setting up "Event Ring Segment Table Base Address Register (ERSTBA)" to 0x1000
I disabled interrupts , if I enabled it, it keeps interrupting forever and not continue code execution.
At least I tell xhci to enable interrupts.

This are BOCHS logs:
00101731586d[XHCI ] register read from offset 0x0007: 0x0000000000000000 (len=1)
00101731586d[XHCI ] register read from offset 0x0018: 0x0000000000000600 (len=4)
00101803864d[XHCI ] register read from offset 0x0014: 0x0000000000000800 (len=4)
00101876867d[XHCI ] register read from offset 0x0000: 0x0000000000000020 (len=1)
00101876867d[XHCI ] register read from offset 0x0058: 0x0000000000000000 (len=4)
00101913232d[XHCI ] register read from offset 0x0050: 0x0000000000000000 (len=4)
00101949584d[XHCI ] register read from offset 0x0038: 0x0000000000000000 (len=4)
00101985936d[XHCI ] register read from offset 0x0020: 0x0000000000000000 (len=4)
00102021878d[XHCI ] register read from offset 0x0020: 0x0000000000000000 (len=4)
00102021878d[XHCI ] register write to offset 0x0020: 0x0000000000000002 (len=4)
00104921765d[XHCI ] register read from offset 0x0024: 0x0000000000000001 (len=4)
00104921765d[XHCI ] register read from offset 0x0020: 0x0000000000000000 (len=4)
00104959256d[XHCI ] register read from offset 0x0628: 0x0000000000000000 (len=4)
00104959256d[XHCI ] register write to offset 0x0628: 0x0000000000000001 (len=4)
00104959256d[XHCI ] register write to offset 0x0638: 0x0000000000041400 (len=4)
00104959256d[XHCI ] register read from offset 0x0630: 0x0000000000000000 (len=4)
00104959256d[XHCI ] register write to offset 0x0630: 0x0000000000001000 (len=4)
00104959256d[XHCI ] register read from offset 0x0038: 0x0000000000000000 (len=4)
00104959256d[XHCI ] register write to offset 0x0038: 0x0000000000054000 (len=4)
00104959256d[XHCI ] register read from offset 0x0050: 0x0000000000000000 (len=4)
00104959256d[XHCI ] register write to offset 0x0050: 0x0000000000002000 (len=4)
00104959256d[XHCI ] register read from offset 0x0020: 0x0000000000000000 (len=4)
00104959256d[XHCI ] register write to offset 0x0020: 0x0000000000000004 (len=4)
00108521817d[XHCI ] register read from offset 0x0020: 0x0000000000000004 (len=4)
00108521817d[XHCI ] register write to offset 0x0020: 0x0000000000000005 (len=4)
00112121879d[XHCI ] register read from offset 0x0024: 0x0000000000000000 (len=4)
00112121879d[XHCI ] register read from offset 0x0020: 0x0000000000000005 (len=4)
00112195499d[XHCI ] register read from offset 0x0420: 0x0000000000000000 (len=4)
00112195509d[XHCI ] register write to offset 0x0420: 0x0000000000000210 (len=4)
00112195509i[XHCI ] Reset port #1, type=0
00115721931d[XHCI ] register read from offset 0x0420: 0x0000000000201203 (len=4)
00115795571d[XHCI ] register write to offset 0x0800: 0x0000000000000000 (len=4)
00115795571d[XHCI ] Command Doorbell Rang
00115795571d[XHCI ] Dump command trb: 9(dec) (0x0000000000000000 0x00000000 0x00002400) (0)
00115795571d[XHCI ] 0x0000000000054000: Command Ring: Found Enable Slot TRB (slot = 1) (returning 1)
00115795571d[XHCI ] register read from offset 0x0620: 0x0000000000000001 (len=1)
00115795585d[XHCI ] register write to offset 0x0620: 0x0000000000000002 (len=4)
00115938538d[XHCI ] register read from offset 0x0430: 0x0000000000000000 (len=4)
00115938538d[XHCI ] register write to offset 0x0430: 0x0000000000000210 (len=4)
00115938538i[XHCI ] Reset port #2, type=0
00119321994d[XHCI ] register read from offset 0x0430: 0x00000000000002A0 (len=4)
00119322002d[XHCI ] register read from offset 0x0440: 0x0000000000000000 (len=4)
00119322002d[XHCI ] register write to offset 0x0440: 0x0000000000000210 (len=4)
00119322002i[XHCI ] Reset port #3, type=0
00122922053d[XHCI ] register read from offset 0x0440: 0x00000000000002A0 (len=4)
00122922053d[XHCI ] register read from offset 0x0450: 0x0000000000000000 (len=4)
00122922053d[XHCI ] register write to offset 0x0450: 0x0000000000000210 (len=4)
00122922053i[XHCI ] Reset port #4, type=0
00126522112d[XHCI ] register read from offset 0x0450: 0x00000000000002A0 (len=4)
00126522112e[XHCI ] register read from unknown offset 0x00000460: 0x0000000000000000 (len=4)
00126522112d[XHCI ] register read from offset 0x0460: 0x0000000000000000 (len=4)
00126522112d[XHCI ] register write to offset 0x0460: 0x0000000000000210 (len=4)
00126522112e[XHCI ] register write to unknown offset 0x00000460: 0x0000000000000210 (len=4)
00130122160e[XHCI ] register read from unknown offset 0x00000460: 0x0000000000000000 (len=4)
00130122160d[XHCI ] register read from offset 0x0460: 0x0000000000000000 (len=4)
00130122160d[XHCI ] register read from offset 0x0038: 0x0000000000000008 (len=4)


Top
 Profile  
 
 Post subject: Re: XHCI
PostPosted: Sun Dec 08, 2019 6:49 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
I think I see your problem. Bochs emulates two xHCI sockets, requiring four register sets.

Remembering that each USB 3.0 socket requires two register sets if it supports both USB 3.0 *and* USB 2.0 devices. Therefore, the register sets are as follows:

Reg Set 0: USB 3.0 for socket 0
Reg Set 1: USB 3.0 for socket 1
Reg Set 2: USB 2.0 for socket 0
Reg Set 3: USB 2.0 for socket 1

The xHCI can support a 2.0 socket, or a 3.0 socket, or both. A register set will only support one or the other. If the socket supports both 3.0 *and* 2.0, there must be two register sets just for this socket. You have to get the address of each set before you can know which register set goes with which socket and which are companion register sets. This is called "the protocol of each port" and is described in the specification or the end of Chapter 9 of my book.

Ben
- http://www.fysnet.net/the_universal_serial_bus.htm


Last edited by BenLunt on Mon Dec 06, 2021 8:28 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: XHCI
PostPosted: Mon Dec 09, 2019 1:45 pm 
Offline
Member
Member

Joined: Tue Aug 30, 2016 1:31 pm
Posts: 69
So if I understand it all well, I should not reset other ports while I'm still needing something from me USB-port.
So, I tried the following: I am entering an endless loop, and wait until such an event arrives. (0x41400 5 bytes would contain something different as 0)
After 10 seconds there is still no change.

I decided to re-read the manual and thought that it would be a good idea to try to see what happened if I write a 0 to the other 32bits of the 64 registers for the table. and this works! Thank you very much.


Top
 Profile  
 
 Post subject: Re: XHCI
PostPosted: Mon Dec 09, 2019 6:11 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
SanderR wrote:
So if I understand it all well, I should not reset other ports while I'm still needing something from me USB-port.
It is okay to reset the other ports. Please note that since there are four port register sets, this doesn't mean that there are four ports. You *must* pair up the register sets. By stating the sentence I have quoted here, this tells me you don't understand that there might be two register sets for every physical port (called a socket).

SanderR wrote:
I decided to re-read the manual and thought that it would be a good idea to try to see what happened if I write a 0 to the other 32bits of the 64 registers for the table. and this works! Thank you very much.
Yes, you must check the Controller's configuration registers and see if it is a 64-bit capable controller. If the controller is 64-bit capable, you must write the addresses as 64-bit addresses, even if you are on a 32-bit machine.

Glad you got it working. Please read the manual on the part about pairing up register sets.

Ben
- http://www.fysnet.net/the_universal_serial_bus.htm


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot], SemrushBot [Bot] and 125 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group