Kernel: Ensure RTL8139NetworkAdapter uses virtual memory correctly

This commit is contained in:
Liav A 2020-03-06 22:52:50 +02:00 committed by Andreas Kling
parent 9dbc273675
commit 4479e874da
Notes: sideshowbarker 2024-07-19 08:49:49 +09:00
2 changed files with 18 additions and 19 deletions

View file

@ -140,7 +140,10 @@ void RTL8139NetworkAdapter::detect(const PCI::Address& address)
RTL8139NetworkAdapter::RTL8139NetworkAdapter(PCI::Address address, u8 irq)
: PCI::Device(address, irq)
, m_io_base(PCI::get_BAR0(pci_address()) & ~1)
, m_rx_buffer(MM.allocate_contiguous_kernel_region(PAGE_ROUND_UP(RX_BUFFER_SIZE + PACKET_SIZE_MAX), "RTL8139 RX", Region::Access::Read | Region::Access::Write))
, m_packet_buffer(MM.allocate_contiguous_kernel_region(PAGE_ROUND_UP(PACKET_SIZE_MAX), "RTL8139 Packet buffer", Region::Access::Read | Region::Access::Write))
{
m_tx_buffers.ensure_capacity(RTL8139_TX_BUFFER_COUNT);
set_interface_name("rtl8139");
klog() << "RTL8139: Found at PCI address " << String::format("%w", pci_address().seg()) << ":" << String::format("%b", pci_address().bus()) << ":" << String::format("%b", pci_address().slot()) << "." << String::format("%b", pci_address().function());
@ -154,17 +157,13 @@ RTL8139NetworkAdapter::RTL8139NetworkAdapter(PCI::Address address, u8 irq)
// we add space to account for overhang from the last packet - the rtl8139
// can optionally guarantee that packets will be contiguous by
// purposefully overrunning the rx buffer
m_rx_buffer_addr = (FlatPtr)virtual_to_low_physical(kmalloc_aligned(RX_BUFFER_SIZE + PACKET_SIZE_MAX, 16));
klog() << "RTL8139: RX buffer: " << PhysicalAddress(m_rx_buffer_addr);
klog() << "RTL8139: RX buffer: " << m_rx_buffer->vmobject().physical_pages()[0]->paddr();
auto tx_buffer_addr = (FlatPtr)virtual_to_low_physical(kmalloc_aligned(TX_BUFFER_SIZE * 4, 16));
for (int i = 0; i < RTL8139_TX_BUFFER_COUNT; i++) {
m_tx_buffer_addr[i] = tx_buffer_addr + TX_BUFFER_SIZE * i;
klog() << "RTL8139: TX buffer " << i << ": " << PhysicalAddress(m_tx_buffer_addr[i]);
m_tx_buffers.append(MM.allocate_contiguous_kernel_region(PAGE_ROUND_UP(TX_BUFFER_SIZE), "RTL8139 TX", Region::Access::Write | Region::Access::Read));
klog() << "RTL8139: TX buffer " << i << ": " << m_tx_buffers[i]->vmobject().physical_pages()[0]->paddr();
}
m_packet_buffer = (FlatPtr)kmalloc(PACKET_SIZE_MAX);
reset();
read_mac_address();
@ -250,7 +249,7 @@ void RTL8139NetworkAdapter::reset()
// device might be in sleep mode, this will take it out
out8(REG_CONFIG1, 0);
// set up rx buffer
out32(REG_RXBUF, m_rx_buffer_addr);
out32(REG_RXBUF, m_rx_buffer->vmobject().physical_pages()[0]->paddr().get());
// reset missed packet counter
out8(REG_MPC, 0);
// "basic mode control register" options - 100mbit, full duplex, auto
@ -268,7 +267,7 @@ void RTL8139NetworkAdapter::reset()
out32(REG_TXCFG, TXCFG_TXRR_ZERO | TXCFG_MAX_DMA_1K | TXCFG_IFG11);
// tell the chip where we want it to DMA from for outgoing packets.
for (int i = 0; i < 4; i++)
out32(REG_TXADDR0 + (i * 4), m_tx_buffer_addr[i]);
out32(REG_TXADDR0 + (i * 4), m_tx_buffers[i]->vmobject().physical_pages()[0]->paddr().get());
// re-lock config registers
out8(REG_CFG9346, CFG9346_NONE);
// enable rx/tx again in case they got turned off (apparently some cards
@ -320,8 +319,8 @@ void RTL8139NetworkAdapter::send_raw(const u8* data, size_t length)
m_tx_next_buffer = (hw_buffer + 1) % 4;
}
memcpy((void*)low_physical_to_virtual(m_tx_buffer_addr[hw_buffer]), data, length);
memset((void*)(low_physical_to_virtual(m_tx_buffer_addr[hw_buffer]) + length), 0, TX_BUFFER_SIZE - length);
memcpy(m_tx_buffers[hw_buffer]->vaddr().as_ptr(), data, length);
memset(m_tx_buffers[hw_buffer]->vaddr().as_ptr() + length, 0, TX_BUFFER_SIZE - length);
// the rtl8139 will not actually emit packets onto the network if they're
// smaller than 64 bytes. the rtl8139 adds a checksum to the end of each
@ -339,17 +338,17 @@ void RTL8139NetworkAdapter::send_raw(const u8* data, size_t length)
void RTL8139NetworkAdapter::receive()
{
auto* start_of_packet = (const u8*)(low_physical_to_virtual(m_rx_buffer_addr) + m_rx_buffer_offset);
auto* start_of_packet = m_rx_buffer->vaddr().as_ptr() + m_rx_buffer_offset;
u16 status = *(const u16*)(start_of_packet + 0);
u16 length = *(const u16*)(start_of_packet + 2);
#ifdef RTL8139_DEBUG
klog() << "RTL8139NetworkAdapter::receive status=0x" << String::format("%x",status) << " length=" << length << " offset=" << m_rx_buffer_offset;
klog() << "RTL8139NetworkAdapter::receive status=0x" << String::format("%x", status) << " length=" << length << " offset=" << m_rx_buffer_offset;
#endif
if (!(status & RX_OK) || (status & (RX_INVALID_SYMBOL_ERROR | RX_CRC_ERROR | RX_FRAME_ALIGNMENT_ERROR)) || (length >= PACKET_SIZE_MAX) || (length < PACKET_SIZE_MIN)) {
klog() << "RTL8139NetworkAdapter::receive got bad packet status=0x" << String::format("%x",status) << " length=" << length;
klog() << "RTL8139NetworkAdapter::receive got bad packet status=0x" << String::format("%x", status) << " length=" << length;
reset();
return;
}
@ -357,13 +356,13 @@ void RTL8139NetworkAdapter::receive()
// we never have to worry about the packet wrapping around the buffer,
// since we set RXCFG_WRAP_INHIBIT, which allows the rtl8139 to write data
// past the end of the alloted space.
memcpy((u8*)m_packet_buffer, (const u8*)(start_of_packet + 4), length - 4);
memcpy(m_packet_buffer->vaddr().as_ptr(), (const u8*)(start_of_packet + 4), length - 4);
// let the card know that we've read this data
m_rx_buffer_offset = ((m_rx_buffer_offset + length + 4 + 3) & ~3) % RX_BUFFER_SIZE;
out16(REG_CAPR, m_rx_buffer_offset - 0x10);
m_rx_buffer_offset %= RX_BUFFER_SIZE;
did_receive((const u8*)m_packet_buffer, length - 4);
did_receive(m_packet_buffer->vaddr().as_ptr(), length - 4);
}
void RTL8139NetworkAdapter::out8(u16 address, u8 data)

View file

@ -67,11 +67,11 @@ private:
IOAddress m_io_base;
u8 m_interrupt_line { 0 };
u32 m_rx_buffer_addr { 0 };
OwnPtr<Region> m_rx_buffer;
u16 m_rx_buffer_offset { 0 };
u32 m_tx_buffer_addr[RTL8139_TX_BUFFER_COUNT];
Vector<OwnPtr<Region>> m_tx_buffers;
u8 m_tx_next_buffer { 0 };
u32 m_packet_buffer { 0 };
OwnPtr<Region> m_packet_buffer;
bool m_link_up { false };
};
}