Re: rtwn(4) extension rtl8188ee receiving constantly interrupts

2017-12-28 Thread Farhan Khan
Hi Andriy,

I attempted to re-write all bits back, but the result is the same. Strange.

Perhaps the initialization code is wrong somewhere? I will give it another
review.

--
Farhan Khan
PGP Fingerprint: B28D 2726 E2BC A97E 3854 5ABE 9A9F 00BC D525 16EE

On Thu, Dec 28, 2017 at 4:28 AM, Andriy Voskoboinyk 
wrote:

> Hi,
>
> there are some issues that may cause wrong interrupt handling:
>
> 1) IMR register bits - they were taken from 92c
> (and they are not compatible - for example, RXFOVW seems to be moved
> to the ext register)
>
> 2) Try to ACK (write back) all bits,
> not masked ones (like it is done for 92c)
>
>
>
> 2017-12-22 0:43 GMT+02:00, Farhan Khan :
>
>> Hi,
>>>
>>> As I wrote a few weeks back, I am working on the extension to rtwn(4) to
>>> add
>>> RTL8188EE support. At the moment, I am working on the Rx code, which
>>> handles
>>> interrupts. After the interrupt is triggered, the code goes into the Rx
>>> routine
>>> and delivers "junk data" in a continuous loop. It seems that the
>>> interrupt
>>> code
>>> is **constantly** called - enough that the load average is frequently
>>> above
>>> 1.0.
>>>
>>> I suspect the issue is giving the WiFi driver an acknowledgement of some
>>> sort,
>>> but I am not certain. I attempted to copy Linux's interrupt code as best
>>> as
>>> possible, but cannot determine if the error is within my code.
>>>
>>> Here is a verbose explanation of what I believe Linux is doing and what I
>>> am
>>> doing on FreeBSD.
>>>
>>> -Linux code works as follows-
>>>
>>> 1. The IRQ trigger calls the function _rtl_pci_interrupt
>>>(drivers/net/wireless/realtek/rtlwifi/pci.c)
>>> 2. This calls disable_interrupt, which for rtl8188ee is
>>>rtl88ee_disable_interrupt. This function writes IMR_DISABLED (0x0) to
>>>REG_HIMR (0xb0) and REG_HIMRE (0xb8).
>>> 3. Next _rtl_pci_interrupt calls interrupt_recognized(), a function
>>> pointer
>>> to
>>>rtl88ee_interrupt_recognized(), which:
>>>* Reads from REG_HISR (0xb4), stores the value in 'inta', ANDs that
>>> value
>>> by
>>>  0x200084ff, then writes that value back to the same register.
>>>* Reads from REG_HISRE (0xbc), stores the value in 'intb', ANDs that
>>> value by
>>>  0x100, then writes that value back to the same register.
>>>Then the function returns returns.
>>>
>>> 4. Back in _rtl_pci_interrupt if 'inta' is 0 and 'intb' is 0x, the
>>> code
>>> will
>>>skip step 5, goto to "done" and execute enable_interrupt code
>>>(rtl88ee_enable_interrupt)
>>>
>>> 5. If bit(0) is set to 1, this is an Rx interrupt and will run
>>>_rtl_pci_rx_interrupt(). From my review of the code, from here the
>>> Linux
>>>driver will read from the DMA memory and send the frame to the
>>> ieee80211
>>>layer. I only found 1 additional read instruction related to the power
>>> value,
>>>but nothing else is changed.
>>>
>>> 6. Here is the "done" portion, that happens no matter what, but is jumped
>>> to
>>>immediately as referenced above. It will call enable_interrupt(), a
>>> function
>>>pointer to rtl88ee_enable_Interrupt(), which will:
>>>a. Write 0x200084ff to REG_HIMR (0xb0)
>>>b. Write 0x100 to REG_HIMRE (0xb8)
>>>c. Write 0 to to REG_C2HEVT_CLEAR (0x01AF, A register having to do
>>> with
>>> C2H
>>>   firmware)
>>>d. Write 0xc0 to REG_HSIMR (0x58 , I know this value from printf'ing
>>> it)
>>>
>>> This is what I identified from reviewing from the Linux code.
>>>
>>> -My FreeBSD Code-
>>>
>>> My code is located here:
>>> https://github.com/khanzf/freebsd/tree/rx_not_working/sys/dev/rtwn/.
>>>
>>> 1. The IRQ trigger calls the function rtwn_pci_intr()
>>>(sys/dev/rtwn/pci/rtwn_pci_rx.c)
>>> 2. The equivalent of Linux's line 2 and 3 is in rtwn_classify_intr,
>>> which is
>>> a
>>>pointer to r88ee_enable_intr located in
>>> sys/dev/rtwn/rtl8188e/pci/r88ee_rx.
>>>This write's 0x0 to REG_HIMR (0xb0) and REG_HIMRE (0xb8)
>>> 3. Continuing, the same function:
>>>* Reads from ISR_MINE (same as REG_HISR, 0xb4), ANDs the value by
>>> 0x200084ff,
>>>  store it in 'status'. Then I write the value back to the same
>>> register.
>>>* Read from REG_HISRE (0xbc), AND the value by 0x100, store it in
>>> 'statusb'.
>>>  Write this value back to the same register.
>>>* Since this is an Rx register, the 'ret' value is AND'd by
>>> RTWN_PCI_INTR_RX.
>>>
>>> 4. In the Linux code, if 'status' is 0x0 and 'statusb' is 0x, it will
>>> goto
>>>to "done". On FreeBSD, it simply does not set any bits on the 'ret'
>>> value
>>> and
>>>the function returns 0, going back to rtwn_pci_intr.
>>>
>>> 5. Returning to rtwn_pci_intr(), if the 'ret' (now 'status') has
>>>RTWN_PCI_INTR_RX flag on, it executes rtwn_pci_tx_done(), which will
>>> read
>>> the
>>>DMA memory and send the frame to the ieee80211 layer. The execution
>>> will
>>> skip
>>>step 5 if 'ret' was 0 (the RTWN_PCI_INTR_RX flag was 

Re: rtwn(4) extension rtl8188ee receiving constantly interrupts

2017-12-28 Thread Andriy Voskoboinyk

Hi,

there are some issues that may cause wrong interrupt handling:

1) IMR register bits - they were taken from 92c
(and they are not compatible - for example, RXFOVW seems to be moved
to the ext register)

2) Try to ACK (write back) all bits,
not masked ones (like it is done for 92c)


2017-12-22 0:43 GMT+02:00, Farhan Khan :

Hi,

As I wrote a few weeks back, I am working on the extension to rtwn(4) to
add
RTL8188EE support. At the moment, I am working on the Rx code, which
handles
interrupts. After the interrupt is triggered, the code goes into the Rx
routine
and delivers "junk data" in a continuous loop. It seems that the  
interrupt

code
is **constantly** called - enough that the load average is frequently  
above

1.0.

I suspect the issue is giving the WiFi driver an acknowledgement of some
sort,
but I am not certain. I attempted to copy Linux's interrupt code as  
best as

possible, but cannot determine if the error is within my code.

Here is a verbose explanation of what I believe Linux is doing and what  
I

am
doing on FreeBSD.

-Linux code works as follows-

1. The IRQ trigger calls the function _rtl_pci_interrupt
   (drivers/net/wireless/realtek/rtlwifi/pci.c)
2. This calls disable_interrupt, which for rtl8188ee is
   rtl88ee_disable_interrupt. This function writes IMR_DISABLED (0x0) to
   REG_HIMR (0xb0) and REG_HIMRE (0xb8).
3. Next _rtl_pci_interrupt calls interrupt_recognized(), a function  
pointer

to
   rtl88ee_interrupt_recognized(), which:
   * Reads from REG_HISR (0xb4), stores the value in 'inta', ANDs that  
value

by
 0x200084ff, then writes that value back to the same register.
   * Reads from REG_HISRE (0xbc), stores the value in 'intb', ANDs that
value by
 0x100, then writes that value back to the same register.
   Then the function returns returns.

4. Back in _rtl_pci_interrupt if 'inta' is 0 and 'intb' is 0x, the  
code

will
   skip step 5, goto to "done" and execute enable_interrupt code
   (rtl88ee_enable_interrupt)

5. If bit(0) is set to 1, this is an Rx interrupt and will run
   _rtl_pci_rx_interrupt(). From my review of the code, from here the  
Linux
   driver will read from the DMA memory and send the frame to the  
ieee80211
   layer. I only found 1 additional read instruction related to the  
power

value,
   but nothing else is changed.

6. Here is the "done" portion, that happens no matter what, but is  
jumped

to
   immediately as referenced above. It will call enable_interrupt(), a
function
   pointer to rtl88ee_enable_Interrupt(), which will:
   a. Write 0x200084ff to REG_HIMR (0xb0)
   b. Write 0x100 to REG_HIMRE (0xb8)
   c. Write 0 to to REG_C2HEVT_CLEAR (0x01AF, A register having to do  
with

C2H
  firmware)
   d. Write 0xc0 to REG_HSIMR (0x58 , I know this value from printf'ing  
it)


This is what I identified from reviewing from the Linux code.

-My FreeBSD Code-

My code is located here:
https://github.com/khanzf/freebsd/tree/rx_not_working/sys/dev/rtwn/.

1. The IRQ trigger calls the function rtwn_pci_intr()
   (sys/dev/rtwn/pci/rtwn_pci_rx.c)
2. The equivalent of Linux's line 2 and 3 is in rtwn_classify_intr,  
which is

a
   pointer to r88ee_enable_intr located in
sys/dev/rtwn/rtl8188e/pci/r88ee_rx.
   This write's 0x0 to REG_HIMR (0xb0) and REG_HIMRE (0xb8)
3. Continuing, the same function:
   * Reads from ISR_MINE (same as REG_HISR, 0xb4), ANDs the value by
0x200084ff,
 store it in 'status'. Then I write the value back to the same
register.
   * Read from REG_HISRE (0xbc), AND the value by 0x100, store it in
'statusb'.
 Write this value back to the same register.
   * Since this is an Rx register, the 'ret' value is AND'd by
RTWN_PCI_INTR_RX.

4. In the Linux code, if 'status' is 0x0 and 'statusb' is 0x, it  
will

goto
   to "done". On FreeBSD, it simply does not set any bits on the 'ret'  
value

and
   the function returns 0, going back to rtwn_pci_intr.

5. Returning to rtwn_pci_intr(), if the 'ret' (now 'status') has
   RTWN_PCI_INTR_RX flag on, it executes rtwn_pci_tx_done(), which will  
read

the
   DMA memory and send the frame to the ieee80211 layer. The execution  
will

skip
   step 5 if 'ret' was 0 (the RTWN_PCI_INTR_RX flag was never set). This
returns
   execution back to rtwn_pci_intr().

6. rtwn_pci_intr() concludes by running rtwn_pci_enable_intr(). This is
similar
   to Linux's enable_interrupt(), it does the following:
   a. Write 0x200084f to R88EE_HIMR (0xb0)
   b. Write 0x100 to R88EE_HIMRE (0xb8)
   c. Write 0x0 to REG_C2HEVT_CLEAR (0x01AF)
   d. Write 0xc0 to REG_HSIMR

-

To me, it appears that I did a complete 1-to-1 copy of the Linux code.
However,
in my case the driver is receiving constant interrupts without  
stopping. I

am
not certain what I am missing or what is different. Could it be that
something
outside of this particular code path was not properly set. If so, what
might
that be?

Please advise.
Thank you,

--
Farhan Khan
PGP 

Re: rtwn(4) extension rtl8188ee receiving constantly interrupts

2017-12-26 Thread Farhan Khan
Hi Adrian,

> So, what do the bits in R88EE_HIMR mean? What about HIRME? Let's
> figure out which it is.

Unfortunately, I do not know what these values are regarding. My
speculation is that R88EE_HIMR and HIMRE are how you notify the device to
clear the interrupt. On the Linux source, they are both in a function
called rtl88ee_disable_interrupt. The Linux documentation puts them in a
struct called rtl_var_map and labels this section as"reg map". It is not
clear to me what that means.

It could be the C2H, but I commented out the FW loading code entirely, but
this issue remains. I am going to re-review the initialization code.
Perhaps the issue lays there. Its a challenge, because the Linux and
FreeBSD structure of the code is not 1-to-1.



--
Farhan Khan
PGP Fingerprint: B28D 2726 E2BC A97E 3854 5ABE 9A9F 00BC D525 16EE

On Sun, Dec 24, 2017 at 9:55 PM, Adrian Chadd  wrote:

> Hi,
>
> So it looks like the thing that's generating the interrupt isn't being
> cleared.
>
> So, what do the bits in R88EE_HIMR mean? What about HIRME? Let's
> figure out which it is.
>
> Also, is it something in C2H (the target to host event channel) that's
> not being handled?
>
>
>
> -adrian
>
>
>
> On 21 December 2017 at 14:43, Farhan Khan  wrote:
> > Hi,
> >
> > As I wrote a few weeks back, I am working on the extension to rtwn(4) to
> add
> > RTL8188EE support. At the moment, I am working on the Rx code, which
> handles
> > interrupts. After the interrupt is triggered, the code goes into the Rx
> routine
> > and delivers "junk data" in a continuous loop. It seems that the
> interrupt code
> > is **constantly** called - enough that the load average is frequently
> above 1.0.
> >
> > I suspect the issue is giving the WiFi driver an acknowledgement of some
> sort,
> > but I am not certain. I attempted to copy Linux's interrupt code as best
> as
> > possible, but cannot determine if the error is within my code.
> >
> > Here is a verbose explanation of what I believe Linux is doing and what
> I am
> > doing on FreeBSD.
> >
> > -Linux code works as follows-
> >
> > 1. The IRQ trigger calls the function _rtl_pci_interrupt
> >(drivers/net/wireless/realtek/rtlwifi/pci.c)
> > 2. This calls disable_interrupt, which for rtl8188ee is
> >rtl88ee_disable_interrupt. This function writes IMR_DISABLED (0x0) to
> >REG_HIMR (0xb0) and REG_HIMRE (0xb8).
> > 3. Next _rtl_pci_interrupt calls interrupt_recognized(), a function
> pointer to
> >rtl88ee_interrupt_recognized(), which:
> >* Reads from REG_HISR (0xb4), stores the value in 'inta', ANDs that
> value by
> >  0x200084ff, then writes that value back to the same register.
> >* Reads from REG_HISRE (0xbc), stores the value in 'intb', ANDs that
> value by
> >  0x100, then writes that value back to the same register.
> >Then the function returns returns.
> >
> > 4. Back in _rtl_pci_interrupt if 'inta' is 0 and 'intb' is 0x, the
> code will
> >skip step 5, goto to "done" and execute enable_interrupt code
> >(rtl88ee_enable_interrupt)
> >
> > 5. If bit(0) is set to 1, this is an Rx interrupt and will run
> >_rtl_pci_rx_interrupt(). From my review of the code, from here the
> Linux
> >driver will read from the DMA memory and send the frame to the
> ieee80211
> >layer. I only found 1 additional read instruction related to the
> power value,
> >but nothing else is changed.
> >
> > 6. Here is the "done" portion, that happens no matter what, but is
> jumped to
> >immediately as referenced above. It will call enable_interrupt(), a
> function
> >pointer to rtl88ee_enable_Interrupt(), which will:
> >a. Write 0x200084ff to REG_HIMR (0xb0)
> >b. Write 0x100 to REG_HIMRE (0xb8)
> >c. Write 0 to to REG_C2HEVT_CLEAR (0x01AF, A register having to do
> with C2H
> >   firmware)
> >d. Write 0xc0 to REG_HSIMR (0x58 , I know this value from printf'ing
> it)
> >
> > This is what I identified from reviewing from the Linux code.
> >
> > -My FreeBSD Code-
> >
> > My code is located here:
> > https://github.com/khanzf/freebsd/tree/rx_not_working/sys/dev/rtwn/.
> >
> > 1. The IRQ trigger calls the function rtwn_pci_intr()
> >(sys/dev/rtwn/pci/rtwn_pci_rx.c)
> > 2. The equivalent of Linux's line 2 and 3 is in rtwn_classify_intr,
> which is a
> >pointer to r88ee_enable_intr located in sys/dev/rtwn/rtl8188e/pci/r88e
> e_rx.
> >This write's 0x0 to REG_HIMR (0xb0) and REG_HIMRE (0xb8)
> > 3. Continuing, the same function:
> >* Reads from ISR_MINE (same as REG_HISR, 0xb4), ANDs the value by
> 0x200084ff,
> >  store it in 'status'. Then I write the value back to the same
> register.
> >* Read from REG_HISRE (0xbc), AND the value by 0x100, store it in
> 'statusb'.
> >  Write this value back to the same register.
> >* Since this is an Rx register, the 'ret' value is AND'd by
> RTWN_PCI_INTR_RX.
> >
> > 4. In the Linux code, if 'status' is 0x0 and 'statusb' 

Re: rtwn(4) extension rtl8188ee receiving constantly interrupts

2017-12-24 Thread Adrian Chadd
Hi,

So it looks like the thing that's generating the interrupt isn't being cleared.

So, what do the bits in R88EE_HIMR mean? What about HIRME? Let's
figure out which it is.

Also, is it something in C2H (the target to host event channel) that's
not being handled?



-adrian



On 21 December 2017 at 14:43, Farhan Khan  wrote:
> Hi,
>
> As I wrote a few weeks back, I am working on the extension to rtwn(4) to add
> RTL8188EE support. At the moment, I am working on the Rx code, which handles
> interrupts. After the interrupt is triggered, the code goes into the Rx 
> routine
> and delivers "junk data" in a continuous loop. It seems that the interrupt 
> code
> is **constantly** called - enough that the load average is frequently above 
> 1.0.
>
> I suspect the issue is giving the WiFi driver an acknowledgement of some sort,
> but I am not certain. I attempted to copy Linux's interrupt code as best as
> possible, but cannot determine if the error is within my code.
>
> Here is a verbose explanation of what I believe Linux is doing and what I am
> doing on FreeBSD.
>
> -Linux code works as follows-
>
> 1. The IRQ trigger calls the function _rtl_pci_interrupt
>(drivers/net/wireless/realtek/rtlwifi/pci.c)
> 2. This calls disable_interrupt, which for rtl8188ee is
>rtl88ee_disable_interrupt. This function writes IMR_DISABLED (0x0) to
>REG_HIMR (0xb0) and REG_HIMRE (0xb8).
> 3. Next _rtl_pci_interrupt calls interrupt_recognized(), a function pointer to
>rtl88ee_interrupt_recognized(), which:
>* Reads from REG_HISR (0xb4), stores the value in 'inta', ANDs that value 
> by
>  0x200084ff, then writes that value back to the same register.
>* Reads from REG_HISRE (0xbc), stores the value in 'intb', ANDs that value 
> by
>  0x100, then writes that value back to the same register.
>Then the function returns returns.
>
> 4. Back in _rtl_pci_interrupt if 'inta' is 0 and 'intb' is 0x, the code 
> will
>skip step 5, goto to "done" and execute enable_interrupt code
>(rtl88ee_enable_interrupt)
>
> 5. If bit(0) is set to 1, this is an Rx interrupt and will run
>_rtl_pci_rx_interrupt(). From my review of the code, from here the Linux
>driver will read from the DMA memory and send the frame to the ieee80211
>layer. I only found 1 additional read instruction related to the power 
> value,
>but nothing else is changed.
>
> 6. Here is the "done" portion, that happens no matter what, but is jumped to
>immediately as referenced above. It will call enable_interrupt(), a 
> function
>pointer to rtl88ee_enable_Interrupt(), which will:
>a. Write 0x200084ff to REG_HIMR (0xb0)
>b. Write 0x100 to REG_HIMRE (0xb8)
>c. Write 0 to to REG_C2HEVT_CLEAR (0x01AF, A register having to do with C2H
>   firmware)
>d. Write 0xc0 to REG_HSIMR (0x58 , I know this value from printf'ing it)
>
> This is what I identified from reviewing from the Linux code.
>
> -My FreeBSD Code-
>
> My code is located here:
> https://github.com/khanzf/freebsd/tree/rx_not_working/sys/dev/rtwn/.
>
> 1. The IRQ trigger calls the function rtwn_pci_intr()
>(sys/dev/rtwn/pci/rtwn_pci_rx.c)
> 2. The equivalent of Linux's line 2 and 3 is in rtwn_classify_intr, which is a
>pointer to r88ee_enable_intr located in sys/dev/rtwn/rtl8188e/pci/r88ee_rx.
>This write's 0x0 to REG_HIMR (0xb0) and REG_HIMRE (0xb8)
> 3. Continuing, the same function:
>* Reads from ISR_MINE (same as REG_HISR, 0xb4), ANDs the value by 
> 0x200084ff,
>  store it in 'status'. Then I write the value back to the same register.
>* Read from REG_HISRE (0xbc), AND the value by 0x100, store it in 
> 'statusb'.
>  Write this value back to the same register.
>* Since this is an Rx register, the 'ret' value is AND'd by 
> RTWN_PCI_INTR_RX.
>
> 4. In the Linux code, if 'status' is 0x0 and 'statusb' is 0x, it will goto
>to "done". On FreeBSD, it simply does not set any bits on the 'ret' value 
> and
>the function returns 0, going back to rtwn_pci_intr.
>
> 5. Returning to rtwn_pci_intr(), if the 'ret' (now 'status') has
>RTWN_PCI_INTR_RX flag on, it executes rtwn_pci_tx_done(), which will read 
> the
>DMA memory and send the frame to the ieee80211 layer. The execution will 
> skip
>step 5 if 'ret' was 0 (the RTWN_PCI_INTR_RX flag was never set). This 
> returns
>execution back to rtwn_pci_intr().
>
> 6. rtwn_pci_intr() concludes by running rtwn_pci_enable_intr(). This is 
> similar
>to Linux's enable_interrupt(), it does the following:
>a. Write 0x200084f to R88EE_HIMR (0xb0)
>b. Write 0x100 to R88EE_HIMRE (0xb8)
>c. Write 0x0 to REG_C2HEVT_CLEAR (0x01AF)
>d. Write 0xc0 to REG_HSIMR
>
> -
>
> To me, it appears that I did a complete 1-to-1 copy of the Linux code. 
> However,
> in my case the driver is receiving constant interrupts without stopping. I am
> not certain what I am missing or what is different. Could it