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"