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 <kha...@gmail.com> 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 0xffff, 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 0xFFFF, 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 Fingerprint: B28D 2726 E2BC A97E 3854 5ABE 9A9F 00BC D525 16EE
> _______________________________________________
> freebsd-wireless@freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/freebsd-wireless
> To unsubscribe, send any mail to "freebsd-wireless-unsubscr...@freebsd.org"
_______________________________________________
freebsd-wireless@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-wireless
To unsubscribe, send any mail to "freebsd-wireless-unsubscr...@freebsd.org"

Reply via email to