EHCI initialization issue to get control from legacy BIOS

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
iman
Member
Member
Posts: 84
Joined: Wed Feb 06, 2019 10:41 am
Libera.chat IRC: ImAn

EHCI initialization issue to get control from legacy BIOS

Post by iman »

Hi.
I am trying to initialize the EHCI controller after finding it on PCI.
The bus mastering bit is set, bar 0 had been obtained, memory mapped space (and not IO ports) is set, and extended capabilities value is getting as following:

Code: Select all

unsigned int eecp = (hccparams >> 8) & 0xFF; 
since the value of eecp in my OS is 0x68 (i.e. >= 0x40), it means the EHCI controller is under BIOS control and I need to get the control from BIOS and give it to the OS as following:

Code: Select all

 
    #define LEGSUP 0x00
    #define LEGSUP_HC_BIOS 0x00010000
    #define LEGSUP_HC_OS 0x01000000

    if (eecp >= 0x40) {
        // Disable BIOS legacy support
        unsigned int leg_sup = PCI_Read(id, eecp + LEGSUP);
        if (leg_sup & LEGSUP_HC_BIOS) {
            PCI_Write(id, eecp + LEGSUP, leg_sup | LEGSUP_HC_OS);
            while(1) {
                leg_sup = PCI_Read(id, eecp + LEGSUP);
                if (~leg_sup & LEGSUP_HC_BIOS && leg_sup & LEGSUP_HC_OS)
                    break;
            }
        }
    }
The problem is that the infinite loop never breaks, meaning that the leg_sup never changed after PCI_Write.
I also chcked leg_sup right after PCI_Write call and after every PCI_Read in the while loop, but it shows no change at all.

I am wondering what might be the source of the issue. Just to be clear, the both PCI_Read and PCI_Write calls, manipulates two 32 bits data and command ports
and the id value have been constructed based on the bus, slot, and function values after pci enumerations. Besides all these pci methods work flawlessly with other hardwares attached.

Thanks.
Iman Abdollahzadeh
Github
Codeberg
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: EHCI initialization issue to get control from legacy BIO

Post by SpyderTL »

Since I don't have the Order of Operations memorized, I would put in explicit parentheses and " != 0 " statements in that last if statement, just to make sure that your order of operations are correct.

EDIT: Also, that negate (~) looks wrong. I think that last line should just be:

Code: Select all

if ((leg_sup & LEGSUP_HC_BIOS) == 0)
                    break;
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
User avatar
zaval
Member
Member
Posts: 659
Joined: Fri Feb 17, 2017 4:01 pm
Location: Ukraine, Bachmut
Contact:

Re: EHCI initialization issue to get control from legacy BIO

Post by zaval »

Is it really meant to be that leg_sup should have set both LEGSUP_HC_BIOS and LEGSUP_HC_OS? Because your loop breaks only if that condition is true. ~ has priority over &. Also, you OR both flags when writing them into register. I can't say about EHCI, this is Ben Lunt, who can say for sure, but looks like you messed up the code hard. If you need to preserve the content of all other bits but LEGSUP_HC_BIOS and also set the LEGSUP_HC_OS bit, you need to do something like that:

Code: Select all

    if (eecp >= 0x40) {
        // Disable BIOS legacy support
        unsigned int leg_sup = PCI_Read(id, eecp + LEGSUP);
        if (leg_sup & LEGSUP_HC_BIOS) {
            leg_sup =  leg_sup ^ LEGSUP_HC_BIOS | LEGSUP_HC_OS;
            PCI_Write(id, eecp + LEGSUP, leg_sup);
            while(1) {
                leg_sup = PCI_Read(id, eecp + LEGSUP);
                if (~(leg_sup & LEGSUP_HC_BIOS) && leg_sup & LEGSUP_HC_OS)
                    break;
            }
        }
    }
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: EHCI initialization issue to get control from legacy BIO

Post by BenLunt »

Hi guys,

Sorry, I haven't had much time to "play" lately, darn it. However, I do watch for specific topics such as this.

As others have suggested, parentheses are suggested.

Also, if I remember correctly, and I would have to look over my notes to be sure, you don't need to preserve the other bits. Simply write a 1 to bit 24, then wait for it to be set *and* bit 16 to be clear. I strongly suggest a timeout test too. You don't want to be stuck there forever.

Two other quick points:

1) If you have an Intel ICH5 mobo (vendor:device 0x24DD8086), there is another Legacy register you have to use. I would have to look at my notes to describe how.

2) Some mobo/controllers must have all EHCI controllers switched from BIOS to OS *before* you read anything from any other EHCI controller. i.e.: If you switch the first EHCI controller from BIOS to OS and then start to initialize it while another EHCI is still in legacy mode (BIOS owned), that second ECHI controller will never come out of Legacy mode.

During your PCI enumeration and before you start your EHCI controller drivers, make sure all EHCI controllers are out of legacy mode first.

If you still can't get it to work, post here again and I will pull out my notes and look over your stuff.

Ben
- http://www.fysnet.net/the_universal_serial_bus.htm
User avatar
iman
Member
Member
Posts: 84
Joined: Wed Feb 06, 2019 10:41 am
Libera.chat IRC: ImAn

Re: EHCI initialization issue to get control from legacy BIO

Post by iman »

Dear SpyderTL, zaval, and Ben.

I looked more carefully into my code based on what you suggested.
Finally I figured out that the main issue came from my buggy PCI_Write method and I fixed it and it works now.

But I would like to reply to all your suggestions and what I found:
EDIT: Also, that negate (~) looks wrong. I think that last line should just be:

Code:

Code: Select all

if ((leg_sup & LEGSUP_HC_BIOS) == 0)
                    break;
It makes here more sense to me to have like what you proposed (cleaner and less ambiguous).
Is it really meant to be that leg_sup should have set both LEGSUP_HC_BIOS and LEGSUP_HC_OS?
I think not necessarily, but I was not careful before your mentioning. Now I fixed it. I had even a look at the Standalone EHCI usb debug driver in linux EHCI implementation https://github.com/torvalds/linux/blob/ ... hci-dbgp.c and I guess it is not needed to keep all the bits set.
If you have an Intel ICH5 mobo (vendor:device 0x24DD8086), there is another Legacy register you have to use
I checked my hardware and could not find it.
If you switch the first EHCI controller from BIOS to OS and then start to initialize it while another EHCI is still in legacy mode (BIOS owned), that second ECHI controller will never come out of Legacy mode
Indeed I have two EHCI controller on my PCI. In the beginning, after seeing your reply to my post and apart from caring about being mobo or not, I tried to get the BIOS control passed to the OS alternatively but both cases failed until I figured out my PCI_Write problem.

Thanks for all of your instructive comments.
Iman.
Iman Abdollahzadeh
Github
Codeberg
Post Reply