You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
216 lines
5.8 KiB
216 lines
5.8 KiB
//! Intel 10Gb Network Adapter 82599 i.e. ixgbe network driver
|
|
//! Datasheet: https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82599-10-gbe-controller-datasheet.pdf
|
|
|
|
use alloc::string::String;
|
|
use alloc::sync::Arc;
|
|
use alloc::vec::Vec;
|
|
|
|
use alloc::collections::BTreeMap;
|
|
use isomorphic_drivers::net::ethernet::intel::ixgbe;
|
|
use log::*;
|
|
use rcore_memory::paging::PageTable;
|
|
use rcore_memory::PAGE_SIZE;
|
|
use smoltcp::iface::*;
|
|
use smoltcp::phy::{self, Checksum, DeviceCapabilities};
|
|
use smoltcp::time::Instant;
|
|
use smoltcp::wire::EthernetAddress;
|
|
use smoltcp::wire::*;
|
|
use smoltcp::Result;
|
|
|
|
use crate::memory::active_table;
|
|
use crate::net::SOCKETS;
|
|
use crate::sync::FlagsGuard;
|
|
use crate::sync::SpinNoIrqLock as Mutex;
|
|
|
|
use super::super::{provider::Provider, DeviceType, Driver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY};
|
|
|
|
#[derive(Clone)]
|
|
struct IXGBEDriver {
|
|
inner: ixgbe::IXGBEDriver,
|
|
header: usize,
|
|
size: usize,
|
|
mtu: usize,
|
|
}
|
|
|
|
pub struct IXGBEInterface {
|
|
iface: Mutex<EthernetInterface<'static, 'static, 'static, IXGBEDriver>>,
|
|
driver: IXGBEDriver,
|
|
ifname: String,
|
|
irq: Option<u32>,
|
|
id: String,
|
|
}
|
|
|
|
impl Driver for IXGBEInterface {
|
|
fn try_handle_interrupt(&self, irq: Option<u32>) -> bool {
|
|
if irq.is_some() && self.irq.is_some() && irq != self.irq {
|
|
// not ours, skip it
|
|
return false;
|
|
}
|
|
|
|
let handled = {
|
|
let _ = FlagsGuard::no_irq_region();
|
|
self.driver.inner.try_handle_interrupt()
|
|
};
|
|
|
|
if handled {
|
|
let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
|
|
let mut sockets = SOCKETS.lock();
|
|
match self.iface.lock().poll(&mut sockets, timestamp) {
|
|
Ok(_) => {
|
|
SOCKET_ACTIVITY.notify_all();
|
|
}
|
|
Err(err) => {
|
|
debug!("poll got err {}", err);
|
|
}
|
|
}
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
fn device_type(&self) -> DeviceType {
|
|
DeviceType::Net
|
|
}
|
|
|
|
fn get_id(&self) -> String {
|
|
self.ifname.clone()
|
|
}
|
|
|
|
fn get_mac(&self) -> EthernetAddress {
|
|
self.iface.lock().ethernet_addr()
|
|
}
|
|
|
|
fn get_ifname(&self) -> String {
|
|
self.ifname.clone()
|
|
}
|
|
|
|
fn ipv4_address(&self) -> Option<Ipv4Address> {
|
|
self.iface.lock().ipv4_address()
|
|
}
|
|
|
|
fn poll(&self) {
|
|
let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
|
|
let mut sockets = SOCKETS.lock();
|
|
match self.iface.lock().poll(&mut sockets, timestamp) {
|
|
Ok(_) => {
|
|
SOCKET_ACTIVITY.notify_all();
|
|
}
|
|
Err(err) => {
|
|
debug!("poll got err {}", err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pub struct IXGBERxToken(Vec<u8>);
|
|
pub struct IXGBETxToken(IXGBEDriver);
|
|
|
|
impl<'a> phy::Device<'a> for IXGBEDriver {
|
|
type RxToken = IXGBERxToken;
|
|
type TxToken = IXGBETxToken;
|
|
|
|
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
|
|
let _ = FlagsGuard::no_irq_region();
|
|
if self.inner.can_send() {
|
|
if let Some(data) = self.inner.recv() {
|
|
Some((IXGBERxToken(data), IXGBETxToken(self.clone())))
|
|
} else {
|
|
None
|
|
}
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
fn transmit(&'a mut self) -> Option<Self::TxToken> {
|
|
let _ = FlagsGuard::no_irq_region();
|
|
if self.inner.can_send() {
|
|
Some(IXGBETxToken(self.clone()))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
fn capabilities(&self) -> DeviceCapabilities {
|
|
let mut caps = DeviceCapabilities::default();
|
|
// do not use max MTU by default
|
|
//caps.max_transmission_unit = ixgbe::IXGBEDriver::get_mtu(); // max MTU
|
|
caps.max_transmission_unit = self.mtu;
|
|
caps.max_burst_size = Some(256);
|
|
// IP Rx checksum is offloaded with RXCSUM
|
|
caps.checksum.ipv4 = Checksum::Tx;
|
|
caps
|
|
}
|
|
}
|
|
|
|
impl phy::RxToken for IXGBERxToken {
|
|
fn consume<R, F>(self, _timestamp: Instant, f: F) -> Result<R>
|
|
where
|
|
F: FnOnce(&[u8]) -> Result<R>,
|
|
{
|
|
f(&self.0)
|
|
}
|
|
}
|
|
|
|
impl phy::TxToken for IXGBETxToken {
|
|
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
|
|
where
|
|
F: FnOnce(&mut [u8]) -> Result<R>,
|
|
{
|
|
let _ = FlagsGuard::no_irq_region();
|
|
let mut buffer = [0u8; ixgbe::IXGBEDriver::get_mtu()];
|
|
let result = f(&mut buffer[..len]);
|
|
if result.is_ok() {
|
|
(self.0).inner.send(&buffer[..len]);
|
|
}
|
|
result
|
|
}
|
|
}
|
|
|
|
pub fn ixgbe_init(
|
|
name: String,
|
|
irq: Option<u32>,
|
|
header: usize,
|
|
size: usize,
|
|
) -> Arc<IXGBEInterface> {
|
|
let _ = FlagsGuard::no_irq_region();
|
|
let ixgbe = ixgbe::IXGBEDriver::init(Provider::new(), header, size);
|
|
ixgbe.enable_irq();
|
|
|
|
let ethernet_addr = EthernetAddress::from_bytes(&ixgbe.get_mac().as_bytes());
|
|
|
|
let net_driver = IXGBEDriver {
|
|
inner: ixgbe,
|
|
header,
|
|
size,
|
|
mtu: 1500,
|
|
};
|
|
|
|
let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, 0, 2), 24)];
|
|
let neighbor_cache = NeighborCache::new(BTreeMap::new());
|
|
let mut routes = Routes::new(BTreeMap::new());
|
|
routes
|
|
.add_default_ipv4_route(Ipv4Address::new(10, 0, 0, 1))
|
|
.unwrap();
|
|
let mut iface = EthernetInterfaceBuilder::new(net_driver.clone())
|
|
.ethernet_addr(ethernet_addr)
|
|
.ip_addrs(ip_addrs)
|
|
.neighbor_cache(neighbor_cache)
|
|
.routes(routes)
|
|
.finalize();
|
|
|
|
info!("ixgbe: interface {} up", &name);
|
|
|
|
let ixgbe_iface = IXGBEInterface {
|
|
iface: Mutex::new(iface),
|
|
driver: net_driver.clone(),
|
|
ifname: name.clone(),
|
|
id: name,
|
|
irq,
|
|
};
|
|
|
|
let driver = Arc::new(ixgbe_iface);
|
|
DRIVERS.write().push(driver.clone());
|
|
NET_DRIVERS.write().push(driver.clone());
|
|
driver
|
|
}
|