2020-01-18 09:38:21 +01:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* 1. Redistributions of source code must retain the above copyright notice , this
* list of conditions and the following disclaimer .
*
* 2. Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2019-04-02 19:54:38 +02:00
# include <Kernel/Net/E1000NetworkAdapter.h>
2019-12-14 10:47:17 +01:00
# include <Kernel/Thread.h>
2020-02-09 16:47:15 +02:00
# include <LibBareMetal/IO.h>
2019-03-10 15:25:33 +01:00
2020-01-09 23:34:26 +02:00
//#define E1000_DEBUG
2020-02-16 01:27:42 +01:00
namespace Kernel {
2019-06-07 11:43:58 +02:00
# define REG_CTRL 0x0000
# define REG_STATUS 0x0008
# define REG_EEPROM 0x0014
# define REG_CTRL_EXT 0x0018
2020-03-20 00:44:42 +02:00
# define REG_INTERRUPT_CAUSE_READ 0x00C0
# define REG_INTERRUPT_RATE 0x00C4
# define REG_INTERRUPT_MASK_SET 0x00D0
# define REG_INTERRUPT_MASK_CLEAR 0x00D8
2019-06-07 11:43:58 +02:00
# define REG_RCTRL 0x0100
# define REG_RXDESCLO 0x2800
# define REG_RXDESCHI 0x2804
# define REG_RXDESCLEN 0x2808
# define REG_RXDESCHEAD 0x2810
# define REG_RXDESCTAIL 0x2818
# define REG_TCTRL 0x0400
# define REG_TXDESCLO 0x3800
# define REG_TXDESCHI 0x3804
# define REG_TXDESCLEN 0x3808
# define REG_TXDESCHEAD 0x3810
# define REG_TXDESCTAIL 0x3818
# define REG_RDTR 0x2820 // RX Delay Timer Register
# define REG_RXDCTL 0x3828 // RX Descriptor Control
# define REG_RADV 0x282C // RX Int. Absolute Delay Timer
# define REG_RSRPD 0x2C00 // RX Small Packet Detect Interrupt
# define REG_TIPG 0x0410 // Transmit Inter Packet Gap
# define ECTRL_SLU 0x40 //set link up
# define RCTL_EN (1 << 1) // Receiver Enable
# define RCTL_SBP (1 << 2) // Store Bad Packets
# define RCTL_UPE (1 << 3) // Unicast Promiscuous Enabled
# define RCTL_MPE (1 << 4) // Multicast Promiscuous Enabled
# define RCTL_LPE (1 << 5) // Long Packet Reception Enable
# define RCTL_LBM_NONE (0 << 6) // No Loopback
# define RCTL_LBM_PHY (3 << 6) // PHY or external SerDesc loopback
# define RTCL_RDMTS_HALF (0 << 8) // Free Buffer Threshold is 1/2 of RDLEN
# define RTCL_RDMTS_QUARTER (1 << 8) // Free Buffer Threshold is 1/4 of RDLEN
# define RTCL_RDMTS_EIGHTH (2 << 8) // Free Buffer Threshold is 1/8 of RDLEN
# define RCTL_MO_36 (0 << 12) // Multicast Offset - bits 47:36
# define RCTL_MO_35 (1 << 12) // Multicast Offset - bits 46:35
# define RCTL_MO_34 (2 << 12) // Multicast Offset - bits 45:34
# define RCTL_MO_32 (3 << 12) // Multicast Offset - bits 43:32
# define RCTL_BAM (1 << 15) // Broadcast Accept Mode
# define RCTL_VFE (1 << 18) // VLAN Filter Enable
# define RCTL_CFIEN (1 << 19) // Canonical Form Indicator Enable
# define RCTL_CFI (1 << 20) // Canonical Form Indicator Bit Value
# define RCTL_DPF (1 << 22) // Discard Pause Frames
# define RCTL_PMCF (1 << 23) // Pass MAC Control Frames
# define RCTL_SECRC (1 << 26) // Strip Ethernet CRC
2019-03-10 20:59:23 +01:00
// Buffer Sizes
2019-06-07 11:43:58 +02:00
# define RCTL_BSIZE_256 (3 << 16)
# define RCTL_BSIZE_512 (2 << 16)
# define RCTL_BSIZE_1024 (1 << 16)
# define RCTL_BSIZE_2048 (0 << 16)
# define RCTL_BSIZE_4096 ((3 << 16) | (1 << 25))
# define RCTL_BSIZE_8192 ((2 << 16) | (1 << 25))
# define RCTL_BSIZE_16384 ((1 << 16) | (1 << 25))
2019-03-10 20:59:23 +01:00
// Transmit Command
2019-06-07 11:43:58 +02:00
# define CMD_EOP (1 << 0) // End of Packet
# define CMD_IFCS (1 << 1) // Insert FCS
# define CMD_IC (1 << 2) // Insert Checksum
# define CMD_RS (1 << 3) // Report Status
# define CMD_RPS (1 << 4) // Report Packet Sent
# define CMD_VLE (1 << 6) // VLAN Packet Enable
# define CMD_IDE (1 << 7) // Interrupt Delay Enable
2019-03-10 20:59:23 +01:00
// TCTL Register
2019-06-07 11:43:58 +02:00
# define TCTL_EN (1 << 1) // Transmit Enable
# define TCTL_PSP (1 << 3) // Pad Short Packets
# define TCTL_CT_SHIFT 4 // Collision Threshold
# define TCTL_COLD_SHIFT 12 // Collision Distance
# define TCTL_SWXOFF (1 << 22) // Software XOFF Transmission
# define TCTL_RTLC (1 << 24) // Re-transmit on Late Collision
2019-03-10 20:59:23 +01:00
2019-06-07 11:43:58 +02:00
# define TSTA_DD (1 << 0) // Descriptor Done
# define TSTA_EC (1 << 1) // Excess Collisions
# define TSTA_LC (1 << 2) // Late Collision
# define LSTA_TU (1 << 3) // Transmit Underrun
2019-03-10 15:25:33 +01:00
2019-08-22 00:52:50 +10:00
// STATUS Register
# define STATUS_FD 0x01
# define STATUS_LU 0x02
# define STATUS_TXOFF 0x08
# define STATUS_SPEED 0xC0
# define STATUS_SPEED_10MB 0x00
# define STATUS_SPEED_100MB 0x40
# define STATUS_SPEED_1000MB1 0x80
# define STATUS_SPEED_1000MB2 0xC0
2020-03-20 00:44:42 +02:00
// Interrupt Masks
# define INTERRUPT_TXDW (1 << 0)
# define INTERRUPT_TXQE (1 << 1)
# define INTERRUPT_LSC (1 << 2)
# define INTERRUPT_RXSEQ (1 << 3)
# define INTERRUPT_RXDMT0 (1 << 4)
# define INTERRUPT_RXO (1 << 6)
# define INTERRUPT_RXT0 (1 << 7)
# define INTERRUPT_MDAC (1 << 9)
# define INTERRUPT_RXCFG (1 << 10)
# define INTERRUPT_PHYINT (1 << 12)
# define INTERRUPT_TXD_LOW (1 << 15)
# define INTERRUPT_SRPD (1 << 16)
2020-02-02 01:52:51 +02:00
void E1000NetworkAdapter : : detect ( const PCI : : Address & address )
2019-03-10 15:25:33 +01:00
{
2020-02-02 01:52:51 +02:00
if ( address . is_null ( ) )
return ;
2019-03-10 15:25:33 +01:00
static const PCI : : ID qemu_bochs_vbox_id = { 0x8086 , 0x100e } ;
2020-02-02 01:52:51 +02:00
const PCI : : ID id = PCI : : get_id ( address ) ;
if ( id ! = qemu_bochs_vbox_id )
return ;
u8 irq = PCI : : get_interrupt_line ( address ) ;
2020-02-08 00:19:46 +01:00
( void ) adopt ( * new E1000NetworkAdapter ( address , irq ) ) . leak_ref ( ) ;
2019-03-10 15:25:33 +01:00
}
2020-02-22 23:56:00 +02:00
E1000NetworkAdapter : : E1000NetworkAdapter ( PCI : : Address address , u8 irq )
: PCI : : Device ( address , irq )
2020-03-01 16:16:26 +02:00
, m_io_base ( PCI : : get_BAR1 ( pci_address ( ) ) & ~ 1 )
2020-03-06 21:40:36 +02:00
, m_rx_descriptors_region ( MM . allocate_contiguous_kernel_region ( PAGE_ROUND_UP ( sizeof ( e1000_rx_desc ) * number_of_rx_descriptors + 16 ) , " E1000 RX " , Region : : Access : : Read | Region : : Access : : Write ) )
, m_tx_descriptors_region ( MM . allocate_contiguous_kernel_region ( PAGE_ROUND_UP ( sizeof ( e1000_tx_desc ) * number_of_tx_descriptors + 16 ) , " E1000 TX " , Region : : Access : : Read | Region : : Access : : Write ) )
2019-03-10 15:25:33 +01:00
{
2019-06-16 07:06:49 +02:00
set_interface_name ( " e1k " ) ;
2020-03-08 17:33:51 +02:00
klog ( ) < < " E1000: Found @ " < < pci_address ( ) ;
2019-03-11 11:11:29 +01:00
2020-02-22 23:56:00 +02:00
enable_bus_mastering ( pci_address ( ) ) ;
2019-03-11 11:11:29 +01:00
2020-04-08 16:56:36 +02:00
size_t mmio_base_size = PCI : : get_BAR_space_size ( pci_address ( ) , 0 ) ;
2020-02-22 23:56:00 +02:00
m_mmio_region = MM . allocate_kernel_region ( PhysicalAddress ( page_base_of ( PCI : : get_BAR0 ( pci_address ( ) ) ) ) , PAGE_ROUND_UP ( mmio_base_size ) , " E1000 MMIO " , Region : : Access : : Read | Region : : Access : : Write , false , false ) ;
2020-01-09 23:34:26 +02:00
m_mmio_base = m_mmio_region - > vaddr ( ) ;
2019-03-10 15:25:33 +01:00
m_use_mmio = true ;
2020-02-22 23:56:00 +02:00
m_interrupt_line = PCI : : get_interrupt_line ( pci_address ( ) ) ;
2020-03-01 16:16:26 +02:00
klog ( ) < < " E1000: port base: " < < m_io_base ;
klog ( ) < < " E1000: MMIO base: " < < PhysicalAddress ( PCI : : get_BAR0 ( pci_address ( ) ) & 0xfffffffc ) ;
klog ( ) < < " E1000: MMIO base size: " < < mmio_base_size < < " bytes " ;
klog ( ) < < " E1000: Interrupt line: " < < m_interrupt_line ;
2019-03-10 15:25:33 +01:00
detect_eeprom ( ) ;
2020-03-01 16:16:26 +02:00
klog ( ) < < " E1000: Has EEPROM? " < < m_has_eeprom ;
2019-03-10 15:25:33 +01:00
read_mac_address ( ) ;
2019-03-10 19:15:22 +01:00
const auto & mac = mac_address ( ) ;
2020-03-01 16:16:26 +02:00
klog ( ) < < " E1000: MAC address: " < < String : : format ( " %b " , mac [ 0 ] ) < < " : " < < String : : format ( " %b " , mac [ 1 ] ) < < " : " < < String : : format ( " %b " , mac [ 2 ] ) < < " : " < < String : : format ( " %b " , mac [ 3 ] ) < < " : " < < String : : format ( " %b " , mac [ 4 ] ) < < " : " < < String : : format ( " %b " , mac [ 5 ] ) ;
2019-03-10 20:59:23 +01:00
2019-07-03 21:17:35 +02:00
u32 flags = in32 ( REG_CTRL ) ;
2019-03-10 20:59:23 +01:00
out32 ( REG_CTRL , flags | ECTRL_SLU ) ;
2020-03-20 00:44:42 +02:00
out16 ( REG_INTERRUPT_RATE , 6000 ) ; // Interrupt rate of 1.536 milliseconds
2019-03-10 20:59:23 +01:00
initialize_rx_descriptors ( ) ;
initialize_tx_descriptors ( ) ;
2020-03-20 00:44:42 +02:00
out32 ( REG_INTERRUPT_MASK_SET , 0x1f6dc ) ;
out32 ( REG_INTERRUPT_MASK_SET , INTERRUPT_LSC | INTERRUPT_RXT0 ) ;
in32 ( REG_INTERRUPT_CAUSE_READ ) ;
2019-03-10 20:59:23 +01:00
2020-01-22 22:23:50 +01:00
enable_irq ( ) ;
2019-03-10 15:25:33 +01:00
}
E1000NetworkAdapter : : ~ E1000NetworkAdapter ( )
{
}
2020-03-09 16:24:29 +02:00
void E1000NetworkAdapter : : handle_irq ( const RegisterState & )
2019-03-10 15:25:33 +01:00
{
2020-03-20 00:44:42 +02:00
out32 ( REG_INTERRUPT_MASK_CLEAR , 0xffffffff ) ;
2019-03-10 20:59:23 +01:00
2020-03-20 00:44:42 +02:00
u32 status = in32 ( REG_INTERRUPT_CAUSE_READ ) ;
2019-03-10 20:59:23 +01:00
if ( status & 4 ) {
2019-07-03 21:17:35 +02:00
u32 flags = in32 ( REG_CTRL ) ;
2019-03-10 20:59:23 +01:00
out32 ( REG_CTRL , flags | ECTRL_SLU ) ;
}
if ( status & 0x80 ) {
2019-03-10 23:40:09 +01:00
receive ( ) ;
2019-03-10 20:59:23 +01:00
}
2020-03-20 00:44:42 +02:00
if ( status & 0x10 ) {
// Threshold OK?
}
2019-12-14 10:47:17 +01:00
m_wait_queue . wake_all ( ) ;
2020-03-20 00:44:42 +02:00
out32 ( REG_INTERRUPT_MASK_SET , INTERRUPT_LSC | INTERRUPT_RXT0 | INTERRUPT_RXO ) ;
2019-03-10 15:25:33 +01:00
}
void E1000NetworkAdapter : : detect_eeprom ( )
{
out32 ( REG_EEPROM , 0x1 ) ;
for ( volatile int i = 0 ; i < 999 ; + + i ) {
2019-07-03 21:17:35 +02:00
u32 data = in32 ( REG_EEPROM ) ;
2019-03-10 15:25:33 +01:00
if ( data & 0x10 ) {
m_has_eeprom = true ;
return ;
}
}
m_has_eeprom = false ;
}
2019-07-03 21:17:35 +02:00
u32 E1000NetworkAdapter : : read_eeprom ( u8 address )
2019-03-10 15:25:33 +01:00
{
2019-07-03 21:17:35 +02:00
u16 data = 0 ;
u32 tmp = 0 ;
2019-03-10 15:25:33 +01:00
if ( m_has_eeprom ) {
2019-07-03 21:17:35 +02:00
out32 ( REG_EEPROM , ( ( u32 ) address < < 8 ) | 1 ) ;
2019-03-10 15:25:33 +01:00
while ( ! ( ( tmp = in32 ( REG_EEPROM ) ) & ( 1 < < 4 ) ) )
;
} else {
2019-07-03 21:17:35 +02:00
out32 ( REG_EEPROM , ( ( u32 ) address < < 2 ) | 1 ) ;
2019-03-10 15:25:33 +01:00
while ( ! ( ( tmp = in32 ( REG_EEPROM ) ) & ( 1 < < 1 ) ) )
;
}
data = ( tmp > > 16 ) & 0xffff ;
return data ;
}
void E1000NetworkAdapter : : read_mac_address ( )
{
if ( m_has_eeprom ) {
2019-07-03 21:17:35 +02:00
u8 mac [ 6 ] ;
u32 tmp = read_eeprom ( 0 ) ;
2019-03-10 15:25:33 +01:00
mac [ 0 ] = tmp & 0xff ;
mac [ 1 ] = tmp > > 8 ;
tmp = read_eeprom ( 1 ) ;
mac [ 2 ] = tmp & 0xff ;
mac [ 3 ] = tmp > > 8 ;
tmp = read_eeprom ( 2 ) ;
mac [ 4 ] = tmp & 0xff ;
mac [ 5 ] = tmp > > 8 ;
set_mac_address ( mac ) ;
} else {
ASSERT_NOT_REACHED ( ) ;
}
}
2019-08-22 00:52:50 +10:00
bool E1000NetworkAdapter : : link_up ( )
{
return ( in32 ( REG_STATUS ) & STATUS_LU ) ;
}
2019-03-10 20:59:23 +01:00
void E1000NetworkAdapter : : initialize_rx_descriptors ( )
{
2020-03-06 21:40:36 +02:00
auto * rx_descriptors = ( e1000_tx_desc * ) m_rx_descriptors_region - > vaddr ( ) . as_ptr ( ) ;
2019-03-10 20:59:23 +01:00
for ( int i = 0 ; i < number_of_rx_descriptors ; + + i ) {
2020-03-06 21:40:36 +02:00
auto & descriptor = rx_descriptors [ i ] ;
m_rx_buffers_regions . append ( MM . allocate_contiguous_kernel_region ( PAGE_ROUND_UP ( 8192 ) , " E1000 RX buffer " , Region : : Access : : Read | Region : : Access : : Write ) ) ;
descriptor . addr = m_rx_buffers_regions [ i ] - > vmobject ( ) . physical_pages ( ) [ 0 ] - > paddr ( ) . get ( ) ;
2019-03-10 20:59:23 +01:00
descriptor . status = 0 ;
}
2020-03-06 21:40:36 +02:00
out32 ( REG_RXDESCLO , m_rx_descriptors_region - > vmobject ( ) . physical_pages ( ) [ 0 ] - > paddr ( ) . get ( ) ) ;
2019-03-10 20:59:23 +01:00
out32 ( REG_RXDESCHI , 0 ) ;
out32 ( REG_RXDESCLEN , number_of_rx_descriptors * sizeof ( e1000_rx_desc ) ) ;
out32 ( REG_RXDESCHEAD , 0 ) ;
out32 ( REG_RXDESCTAIL , number_of_rx_descriptors - 1 ) ;
2019-06-07 11:43:58 +02:00
out32 ( REG_RCTRL , RCTL_EN | RCTL_SBP | RCTL_UPE | RCTL_MPE | RCTL_LBM_NONE | RTCL_RDMTS_HALF | RCTL_BAM | RCTL_SECRC | RCTL_BSIZE_8192 ) ;
2019-03-10 20:59:23 +01:00
}
void E1000NetworkAdapter : : initialize_tx_descriptors ( )
{
2020-03-06 21:40:36 +02:00
auto * tx_descriptors = ( e1000_tx_desc * ) m_tx_descriptors_region - > vaddr ( ) . as_ptr ( ) ;
2019-03-10 20:59:23 +01:00
for ( int i = 0 ; i < number_of_tx_descriptors ; + + i ) {
2020-03-06 21:40:36 +02:00
auto & descriptor = tx_descriptors [ i ] ;
m_tx_buffers_regions . append ( MM . allocate_contiguous_kernel_region ( PAGE_ROUND_UP ( 8192 ) , " E1000 TX buffer " , Region : : Access : : Read | Region : : Access : : Write ) ) ;
descriptor . addr = m_tx_buffers_regions [ i ] - > vmobject ( ) . physical_pages ( ) [ 0 ] - > paddr ( ) . get ( ) ;
2019-03-10 20:59:23 +01:00
descriptor . cmd = 0 ;
}
2020-03-06 21:40:36 +02:00
out32 ( REG_TXDESCLO , m_tx_descriptors_region - > vmobject ( ) . physical_pages ( ) [ 0 ] - > paddr ( ) . get ( ) ) ;
2019-03-10 20:59:23 +01:00
out32 ( REG_TXDESCHI , 0 ) ;
out32 ( REG_TXDESCLEN , number_of_tx_descriptors * sizeof ( e1000_tx_desc ) ) ;
out32 ( REG_TXDESCHEAD , 0 ) ;
2019-03-11 23:21:38 +01:00
out32 ( REG_TXDESCTAIL , 0 ) ;
2019-03-10 20:59:23 +01:00
2019-03-11 23:21:38 +01:00
out32 ( REG_TCTRL , in32 ( REG_TCTRL ) | TCTL_EN | TCTL_PSP ) ;
2019-03-10 20:59:23 +01:00
out32 ( REG_TIPG , 0x0060200A ) ;
}
2019-07-03 21:17:35 +02:00
void E1000NetworkAdapter : : out8 ( u16 address , u8 data )
2019-03-10 15:25:33 +01:00
{
2020-01-09 23:34:26 +02:00
# ifdef E1000_DEBUG
2020-02-24 14:45:46 +02:00
dbg ( ) < < " E1000: OUT @ 0x " < < address ;
2020-01-09 23:34:26 +02:00
# endif
2019-03-10 15:25:33 +01:00
if ( m_use_mmio ) {
2019-07-03 21:17:35 +02:00
auto * ptr = ( volatile u8 * ) ( m_mmio_base . get ( ) + address ) ;
2019-03-10 15:25:33 +01:00
* ptr = data ;
return ;
}
2020-03-01 16:16:26 +02:00
m_io_base . offset ( address ) . out ( data ) ;
2019-03-10 15:25:33 +01:00
}
2019-07-03 21:17:35 +02:00
void E1000NetworkAdapter : : out16 ( u16 address , u16 data )
2019-03-10 15:25:33 +01:00
{
2020-01-09 23:34:26 +02:00
# ifdef E1000_DEBUG
2020-02-24 14:45:46 +02:00
dbg ( ) < < " E1000: OUT @ 0x " < < address ;
2020-01-09 23:34:26 +02:00
# endif
2019-03-10 15:25:33 +01:00
if ( m_use_mmio ) {
2019-07-03 21:17:35 +02:00
auto * ptr = ( volatile u16 * ) ( m_mmio_base . get ( ) + address ) ;
2019-03-10 15:25:33 +01:00
* ptr = data ;
return ;
}
2020-03-01 16:16:26 +02:00
m_io_base . offset ( address ) . out ( data ) ;
2019-03-10 15:25:33 +01:00
}
2019-07-03 21:17:35 +02:00
void E1000NetworkAdapter : : out32 ( u16 address , u32 data )
2019-03-10 15:25:33 +01:00
{
2020-01-09 23:34:26 +02:00
# ifdef E1000_DEBUG
2020-02-24 14:45:46 +02:00
dbg ( ) < < " E1000: OUT @ 0x " < < address ;
2020-01-09 23:34:26 +02:00
# endif
2019-03-10 15:25:33 +01:00
if ( m_use_mmio ) {
2019-07-03 21:17:35 +02:00
auto * ptr = ( volatile u32 * ) ( m_mmio_base . get ( ) + address ) ;
2019-03-10 15:25:33 +01:00
* ptr = data ;
return ;
}
2020-03-01 16:16:26 +02:00
m_io_base . offset ( address ) . out ( data ) ;
2019-03-10 15:25:33 +01:00
}
2019-07-03 21:17:35 +02:00
u8 E1000NetworkAdapter : : in8 ( u16 address )
2019-03-10 15:25:33 +01:00
{
2020-01-09 23:34:26 +02:00
# ifdef E1000_DEBUG
2020-02-24 14:45:46 +02:00
dbg ( ) < < " E1000: IN @ 0x " < < address ;
2020-01-09 23:34:26 +02:00
# endif
2019-03-10 15:25:33 +01:00
if ( m_use_mmio )
2019-07-03 21:17:35 +02:00
return * ( volatile u8 * ) ( m_mmio_base . get ( ) + address ) ;
2020-03-01 16:16:26 +02:00
return m_io_base . offset ( address ) . in < u8 > ( ) ;
2019-03-10 15:25:33 +01:00
}
2019-07-03 21:17:35 +02:00
u16 E1000NetworkAdapter : : in16 ( u16 address )
2019-03-10 15:25:33 +01:00
{
2020-01-09 23:34:26 +02:00
# ifdef E1000_DEBUG
2020-02-24 14:45:46 +02:00
dbg ( ) < < " E1000: IN @ 0x " < < address ;
2020-01-09 23:34:26 +02:00
# endif
2019-03-10 15:25:33 +01:00
if ( m_use_mmio )
2019-07-03 21:17:35 +02:00
return * ( volatile u16 * ) ( m_mmio_base . get ( ) + address ) ;
2020-03-01 16:16:26 +02:00
return m_io_base . offset ( address ) . in < u16 > ( ) ;
2019-03-10 15:25:33 +01:00
}
2019-07-03 21:17:35 +02:00
u32 E1000NetworkAdapter : : in32 ( u16 address )
2019-03-10 15:25:33 +01:00
{
2020-01-09 23:34:26 +02:00
# ifdef E1000_DEBUG
2020-02-24 14:45:46 +02:00
dbg ( ) < < " E1000: IN @ 0x " < < address ;
2020-01-09 23:34:26 +02:00
# endif
2019-03-10 15:25:33 +01:00
if ( m_use_mmio )
2019-07-03 21:17:35 +02:00
return * ( volatile u32 * ) ( m_mmio_base . get ( ) + address ) ;
2020-03-01 16:16:26 +02:00
return m_io_base . offset ( address ) . in < u32 > ( ) ;
2019-03-10 15:25:33 +01:00
}
2019-03-10 20:59:23 +01:00
2020-01-29 18:29:04 +01:00
void E1000NetworkAdapter : : send_raw ( const u8 * data , size_t length )
2019-03-10 20:59:23 +01:00
{
2020-01-22 22:23:50 +01:00
disable_irq ( ) ;
2019-07-03 21:17:35 +02:00
u32 tx_current = in32 ( REG_TXDESCTAIL ) ;
2019-03-11 23:21:38 +01:00
# ifdef E1000_DEBUG
2020-03-01 16:16:26 +02:00
klog ( ) < < " E1000: Sending packet ( " < < length < < " bytes) " ;
2019-03-11 23:21:38 +01:00
# endif
2020-03-06 21:40:36 +02:00
auto * tx_descriptors = ( e1000_tx_desc * ) m_tx_descriptors_region - > vaddr ( ) . as_ptr ( ) ;
auto & descriptor = tx_descriptors [ tx_current ] ;
2019-03-11 23:21:38 +01:00
ASSERT ( length < = 8192 ) ;
2020-03-06 21:40:36 +02:00
auto * vptr = ( void * ) m_tx_buffers_regions [ tx_current ] - > vaddr ( ) . as_ptr ( ) ;
2020-01-17 19:59:20 +01:00
memcpy ( vptr , data , length ) ;
2019-03-10 20:59:23 +01:00
descriptor . length = length ;
2019-03-11 23:21:38 +01:00
descriptor . status = 0 ;
2019-03-11 12:43:45 +01:00
descriptor . cmd = CMD_EOP | CMD_IFCS | CMD_RS ;
2019-03-11 23:21:38 +01:00
# ifdef E1000_DEBUG
2020-03-01 16:16:26 +02:00
klog ( ) < < " E1000: Using tx descriptor " < < tx_current < < " (head is at " < < in32 ( REG_TXDESCHEAD ) < < " ) " ;
2019-03-11 23:21:38 +01:00
# endif
tx_current = ( tx_current + 1 ) % number_of_tx_descriptors ;
2019-12-14 13:02:40 +01:00
cli ( ) ;
2020-01-22 22:23:50 +01:00
enable_irq ( ) ;
2020-03-06 15:52:44 +02:00
out32 ( REG_TXDESCTAIL , tx_current ) ;
2019-12-14 10:47:17 +01:00
for ( ; ; ) {
2019-12-14 13:02:40 +01:00
if ( descriptor . status ) {
sti ( ) ;
2019-12-14 10:47:17 +01:00
break ;
2019-12-14 13:02:40 +01:00
}
2020-02-17 15:04:27 +01:00
Thread : : current - > wait_on ( m_wait_queue ) ;
2019-12-14 10:47:17 +01:00
}
2019-03-11 23:21:38 +01:00
# ifdef E1000_DEBUG
2020-03-06 21:40:36 +02:00
klog ( ) < < " E1000: Sent packet, status is now " < < String : : format ( " %b " , descriptor . status ) < < " ! " ;
2019-03-11 23:21:38 +01:00
# endif
2019-03-10 20:59:23 +01:00
}
2019-03-10 23:40:09 +01:00
void E1000NetworkAdapter : : receive ( )
{
2020-03-06 21:40:36 +02:00
auto * rx_descriptors = ( e1000_tx_desc * ) m_rx_descriptors_region - > vaddr ( ) . as_ptr ( ) ;
2019-07-03 21:17:35 +02:00
u32 rx_current ;
2019-03-11 23:21:38 +01:00
for ( ; ; ) {
rx_current = in32 ( REG_RXDESCTAIL ) ;
if ( rx_current = = in32 ( REG_RXDESCHEAD ) )
return ;
rx_current = ( rx_current + 1 ) % number_of_rx_descriptors ;
2020-03-06 21:40:36 +02:00
if ( ! ( rx_descriptors [ rx_current ] . status & 1 ) )
2019-03-11 23:21:38 +01:00
break ;
2020-03-06 21:40:36 +02:00
auto * buffer = m_rx_buffers_regions [ rx_current ] - > vaddr ( ) . as_ptr ( ) ;
u16 length = rx_descriptors [ rx_current ] . length ;
2019-03-11 23:21:38 +01:00
# ifdef E1000_DEBUG
2020-03-01 16:16:26 +02:00
klog ( ) < < " E1000: Received 1 packet @ " < < buffer < < " ( " < < length < < " ) bytes! " ;
2019-03-11 23:21:38 +01:00
# endif
2019-03-11 12:43:45 +01:00
did_receive ( buffer , length ) ;
2020-03-06 21:40:36 +02:00
rx_descriptors [ rx_current ] . status = 0 ;
2019-03-11 23:21:38 +01:00
out32 ( REG_RXDESCTAIL , rx_current ) ;
2019-03-10 23:40:09 +01:00
}
}
2020-02-16 01:27:42 +01:00
}