refactor ethmac

This commit is contained in:
Sebastien Bourdeauducq 2017-08-06 02:18:33 +08:00
parent e8d6d84ac5
commit 8247c8f5a5
2 changed files with 243 additions and 246 deletions

View File

@ -3,6 +3,7 @@ use tm4c129x;
use core::slice;
use smoltcp::Error;
use smoltcp::wire::EthernetAddress;
use smoltcp::phy::{DeviceLimits, Device};
const EPHY_BMCR: u8 = 0x00; // Ethernet PHY Basic Mode Control
@ -38,28 +39,6 @@ const ETH_TX_BUFFER_SIZE: usize = 1536;
const ETH_RX_BUFFER_COUNT: usize = 3;
const ETH_RX_BUFFER_SIZE: usize = 1536;
pub struct EmacData {
pub tx_desc_buf: [u32; ETH_TX_BUFFER_COUNT * ETH_DESC_U32_SIZE],
pub rx_desc_buf: [u32; ETH_RX_BUFFER_COUNT * ETH_DESC_U32_SIZE],
pub tx_cur_desc: usize,
pub rx_cur_desc: usize,
pub tx_counter: u32,
pub rx_counter: u32,
pub tx_pkt_buf: [u8; ETH_TX_BUFFER_COUNT * ETH_TX_BUFFER_SIZE],
pub rx_pkt_buf: [u8; ETH_RX_BUFFER_COUNT * ETH_RX_BUFFER_SIZE],
}
static mut EMAC_DATA: EmacData = EmacData {
tx_desc_buf: [0; ETH_TX_BUFFER_COUNT * ETH_DESC_U32_SIZE],
rx_desc_buf: [0; ETH_RX_BUFFER_COUNT * ETH_DESC_U32_SIZE],
tx_cur_desc: 0,
rx_cur_desc: 0,
tx_counter: 0,
rx_counter: 0,
tx_pkt_buf: [0; ETH_TX_BUFFER_COUNT * ETH_TX_BUFFER_SIZE],
rx_pkt_buf: [0; ETH_RX_BUFFER_COUNT * ETH_RX_BUFFER_SIZE],
};
fn delay(d: u32) {
for _ in 0..d {
unsafe {
@ -127,7 +106,81 @@ fn phy_write_ext(reg_addr: u8, reg_data: u16) {
phy_write(EPHY_ADDAR, reg_data);
}
pub fn init(mac_addr: [u8; 6]) {
pub struct EthernetDevice {
tx_desc_buf: [u32; ETH_TX_BUFFER_COUNT * ETH_DESC_U32_SIZE],
rx_desc_buf: [u32; ETH_RX_BUFFER_COUNT * ETH_DESC_U32_SIZE],
tx_cur_desc: usize,
rx_cur_desc: usize,
tx_counter: u32,
rx_counter: u32,
tx_pkt_buf: [u8; ETH_TX_BUFFER_COUNT * ETH_TX_BUFFER_SIZE],
rx_pkt_buf: [u8; ETH_RX_BUFFER_COUNT * ETH_RX_BUFFER_SIZE],
}
impl EthernetDevice {
pub fn new(mac_addr: EthernetAddress) -> EthernetDevice {
let mut device = EthernetDevice {
tx_desc_buf: [0; ETH_TX_BUFFER_COUNT * ETH_DESC_U32_SIZE],
rx_desc_buf: [0; ETH_RX_BUFFER_COUNT * ETH_DESC_U32_SIZE],
tx_cur_desc: 0,
rx_cur_desc: 0,
tx_counter: 0,
rx_counter: 0,
tx_pkt_buf: [0; ETH_TX_BUFFER_COUNT * ETH_TX_BUFFER_SIZE],
rx_pkt_buf: [0; ETH_RX_BUFFER_COUNT * ETH_RX_BUFFER_SIZE],
};
// Initialize TX DMA descriptors
for x in 0..ETH_TX_BUFFER_COUNT {
let p = x * ETH_DESC_U32_SIZE;
let r = x * ETH_TX_BUFFER_SIZE;
// Initialize transmit flags
device.tx_desc_buf[p + 0] = 0;
// Initialize transmit buffer size
device.tx_desc_buf[p + 1] = 0;
// Transmit buffer address
device.tx_desc_buf[p + 2] = (&device.tx_pkt_buf[r] as *const u8) as u32;
// Next descriptor address
if x != ETH_TX_BUFFER_COUNT - 1 {
device.tx_desc_buf[p + 3] = (&device.tx_desc_buf[p + ETH_DESC_U32_SIZE] as *const u32) as u32;
} else {
device.tx_desc_buf[p + 3] = (&device.tx_desc_buf[0] as *const u32) as u32;
}
// Reserved fields
device.tx_desc_buf[p + 4] = 0;
device.tx_desc_buf[p + 5] = 0;
// Transmit frame time stamp
device.tx_desc_buf[p + 6] = 0;
device.tx_desc_buf[p + 7] = 0;
}
// Initialize RX DMA descriptors
for x in 0..ETH_RX_BUFFER_COUNT {
let p = x * ETH_DESC_U32_SIZE;
let r = x * ETH_RX_BUFFER_SIZE;
// The descriptor is initially owned by the DMA
device.rx_desc_buf[p + 0] = EMAC_RDES0_OWN;
// Use chain structure rather than ring structure
device.rx_desc_buf[p + 1] = EMAC_RDES1_RCH | ((ETH_RX_BUFFER_SIZE as u32) & EMAC_RDES1_RBS1);
// Receive buffer address
device.rx_desc_buf[p + 2] = (&device.rx_pkt_buf[r] as *const u8) as u32;
// Next descriptor address
if x != ETH_RX_BUFFER_COUNT - 1 {
device.rx_desc_buf[p + 3] = (&device.rx_desc_buf[p + ETH_DESC_U32_SIZE] as *const u32) as u32;
} else {
device.rx_desc_buf[p + 3] = (&device.rx_desc_buf[0] as *const u32) as u32;
}
// Extended status
device.rx_desc_buf[p + 4] = 0;
// Reserved field
device.rx_desc_buf[p + 5] = 0;
// Transmit frame time stamp
device.rx_desc_buf[p + 6] = 0;
device.rx_desc_buf[p + 7] = 0;
}
cortex_m::interrupt::free(|cs| {
let sysctl = tm4c129x::SYSCTL.borrow(cs);
let emac0 = tm4c129x::EMAC0.borrow(cs);
@ -159,7 +212,7 @@ pub fn init(mac_addr: [u8; 6]) {
// Reset PHY transceiver
phy_write(EPHY_BMCR, 1); // Initiate MII reset
while 1 == (phy_read(EPHY_BMCR) & 1) {}; // Wait for the reset to be completed
while (phy_read(EPHY_BMCR) & 1) == 1 {}; // Wait for the reset to be completed
// Configure PHY LEDs
phy_write_ext(EPHY_LEDCFG, 0x0008); // LED0 Link OK/Blink on TX/RX Activity
@ -204,10 +257,9 @@ pub fn init(mac_addr: [u8; 6]) {
w.bits(0) // ??? no use watchdog
});
// Set the high 2 bytes of the MAC address
// Set the MAC address
let mac_addr = mac_addr.0;
emac0.addr0h.write(|w| unsafe { w.addrhi().bits(mac_addr[4] as u16 | ((mac_addr[5] as u16) << 8)) });
// Set the low 4 bytes of the MAC address
emac0.addr0l.write(|w| unsafe {
w.addrlo().bits(mac_addr[0] as u32 | ((mac_addr[1] as u32) << 8) | ((mac_addr[2] as u32) << 16) | ((mac_addr[3] as u32) << 24))
});
@ -225,66 +277,8 @@ pub fn init(mac_addr: [u8; 6]) {
emac0.flowctl.write(|w| unsafe { w.bits(0)}); // Disable flow control ???
// Initialize TX DMA descriptors
for x in 0..ETH_TX_BUFFER_COUNT {
let p = x * ETH_DESC_U32_SIZE;
let r = x * ETH_TX_BUFFER_SIZE;
unsafe {
// Initialize transmit flags
EMAC_DATA.tx_desc_buf[p + 0] = 0;
// Initialize transmit buffer size
EMAC_DATA.tx_desc_buf[p + 1] = 0;
// Transmit buffer address
EMAC_DATA.tx_desc_buf[p + 2] = (&EMAC_DATA.tx_pkt_buf[r] as *const u8) as u32;
// Next descriptor address
if x != ETH_TX_BUFFER_COUNT - 1 {
EMAC_DATA.tx_desc_buf[p + 3] = (&EMAC_DATA.tx_desc_buf[p + ETH_DESC_U32_SIZE] as *const u32) as u32;
} else {
EMAC_DATA.tx_desc_buf[p + 3] = (&EMAC_DATA.tx_desc_buf[0] as *const u32) as u32;
}
// Reserved fields
EMAC_DATA.tx_desc_buf[p + 4] = 0;
EMAC_DATA.tx_desc_buf[p + 5] = 0;
// Transmit frame time stamp
EMAC_DATA.tx_desc_buf[p + 6] = 0;
EMAC_DATA.tx_desc_buf[p + 7] = 0;
}
}
// Initialize RX DMA descriptors
for x in 0..ETH_RX_BUFFER_COUNT {
let p = x * ETH_DESC_U32_SIZE;
let r = x * ETH_RX_BUFFER_SIZE;
unsafe {
// The descriptor is initially owned by the DMA
EMAC_DATA.rx_desc_buf[p + 0] = EMAC_RDES0_OWN;
// Use chain structure rather than ring structure
EMAC_DATA.rx_desc_buf[p + 1] = EMAC_RDES1_RCH | ((ETH_RX_BUFFER_SIZE as u32) & EMAC_RDES1_RBS1);
// Receive buffer address
EMAC_DATA.rx_desc_buf[p + 2] = (&EMAC_DATA.rx_pkt_buf[r] as *const u8) as u32;
// Next descriptor address
if x != ETH_RX_BUFFER_COUNT - 1 {
EMAC_DATA.rx_desc_buf[p + 3] = (&EMAC_DATA.rx_desc_buf[p + ETH_DESC_U32_SIZE] as *const u32) as u32;
} else {
EMAC_DATA.rx_desc_buf[p + 3] = (&EMAC_DATA.rx_desc_buf[0] as *const u32) as u32;
}
// Extended status
EMAC_DATA.rx_desc_buf[p + 4] = 0;
// Reserved field
EMAC_DATA.rx_desc_buf[p + 5] = 0;
// Transmit frame time stamp
EMAC_DATA.rx_desc_buf[p + 6] = 0;
EMAC_DATA.rx_desc_buf[p + 7] = 0;
}
}
unsafe {
EMAC_DATA.tx_cur_desc = 0;
EMAC_DATA.rx_cur_desc = 0;
}
emac0.txdladdr.write(|w| unsafe { w.bits((&EMAC_DATA.tx_desc_buf[0] as *const u32) as u32)});
emac0.rxdladdr.write(|w| unsafe { w.bits((&EMAC_DATA.rx_desc_buf[0] as *const u32) as u32)});
emac0.txdladdr.write(|w| unsafe { w.bits((&device.tx_desc_buf[0] as *const u32) as u32)});
emac0.rxdladdr.write(|w| unsafe { w.bits((&device.rx_desc_buf[0] as *const u32) as u32)});
// Manage MAC transmission and reception
emac0.cfg.modify(|_, w|
@ -297,23 +291,19 @@ pub fn init(mac_addr: [u8; 6]) {
w.sr().bit(true) // Start Receive
.st().bit(true) // Start Transmit
);
println!("EMAC init done");
});
device
}
fn release_rx_buf() {
unsafe {
EMAC_DATA.rx_cur_desc += ETH_DESC_U32_SIZE;
if EMAC_DATA.rx_cur_desc >= (ETH_RX_BUFFER_COUNT * ETH_DESC_U32_SIZE) {
EMAC_DATA.rx_cur_desc = 0;
fn release_rx_buf(&mut self) {
self.rx_cur_desc += ETH_DESC_U32_SIZE;
if self.rx_cur_desc >= (ETH_RX_BUFFER_COUNT * ETH_DESC_U32_SIZE) {
self.rx_cur_desc = 0;
}
EMAC_DATA.rx_desc_buf[EMAC_DATA.rx_cur_desc + 0] = EMAC_RDES0_OWN; // release descriptor
self.rx_desc_buf[self.rx_cur_desc + 0] = EMAC_RDES0_OWN; // release descriptor
}
}
pub struct EthernetDevice;
impl Device for EthernetDevice {
type RxBuffer = RxBuffer;
type TxBuffer = TxBuffer;
@ -326,92 +316,100 @@ impl Device for EthernetDevice {
}
fn receive(&mut self, _timestamp: u64) -> Result<Self::RxBuffer, Error> {
unsafe {
if (EMAC_DATA.rx_desc_buf[EMAC_DATA.rx_cur_desc + 0] & EMAC_RDES0_OWN) == 0 {
if (self.rx_desc_buf[self.rx_cur_desc + 0] & EMAC_RDES0_OWN) == 0 {
// check for the whole packet in the buffer and no any error
if (EMAC_RDES0_FS | EMAC_RDES0_LS) == EMAC_DATA.rx_desc_buf[EMAC_DATA.rx_cur_desc + 0] & (EMAC_RDES0_FS | EMAC_RDES0_LS | EMAC_RDES0_ES) {
if (EMAC_RDES0_FS | EMAC_RDES0_LS) == self.rx_desc_buf[self.rx_cur_desc + 0] & (EMAC_RDES0_FS | EMAC_RDES0_LS | EMAC_RDES0_ES) {
// Retrieve the length of the frame
let mut n = (EMAC_DATA.rx_desc_buf[EMAC_DATA.rx_cur_desc + 0] & EMAC_RDES0_FL) >> 16;
let mut n = (self.rx_desc_buf[self.rx_cur_desc + 0] & EMAC_RDES0_FL) >> 16;
// Limit the number of data to read
if n > ETH_RX_BUFFER_SIZE as u32 { n = ETH_RX_BUFFER_SIZE as u32; }
Ok(RxBuffer(slice::from_raw_parts(EMAC_DATA.rx_desc_buf[EMAC_DATA.rx_cur_desc + 2] as * mut u8,
n as usize)))
let sl = unsafe {
slice::from_raw_parts(self.rx_desc_buf[self.rx_cur_desc + 2] as * mut u8,
n as usize)
};
Ok(RxBuffer(sl, self))
} else {
// Ignore invalid frame
release_rx_buf();
self.release_rx_buf();
Err(Error::Exhausted)
}
} else {
Err(Error::Exhausted) // currently no buffers to process
}
}
}
fn transmit(&mut self, _timestamp: u64, length: usize) -> Result<Self::TxBuffer, Error> {
unsafe {
// Check if the TX DMA buffer released
if (EMAC_DATA.tx_desc_buf[EMAC_DATA.tx_cur_desc + 0] & EMAC_TDES0_OWN) == 0 {
if (self.tx_desc_buf[self.tx_cur_desc + 0] & EMAC_TDES0_OWN) == 0 {
// Write the number of bytes to send
EMAC_DATA.tx_desc_buf[EMAC_DATA.tx_cur_desc + 1] = length as u32 & EMAC_TDES1_TBS1;
self.tx_desc_buf[self.tx_cur_desc + 1] = length as u32 & EMAC_TDES1_TBS1;
Ok(TxBuffer(slice::from_raw_parts_mut(EMAC_DATA.tx_desc_buf[EMAC_DATA.tx_cur_desc + 2] as * mut u8,
ETH_TX_BUFFER_SIZE)))
let sl = unsafe {
slice::from_raw_parts_mut(self.tx_desc_buf[self.tx_cur_desc + 2] as * mut u8,
ETH_TX_BUFFER_SIZE)
};
Ok(TxBuffer(sl, self))
} else {
// to do if need: Instruct the DMA to poll the receive descriptor list
Err(Error::Exhausted)
}
}
}
}
pub struct RxBuffer(&'static [u8]);
pub struct RxBuffer(*const [u8], *mut EthernetDevice);
impl AsRef<[u8]> for RxBuffer {
fn as_ref(&self) -> &[u8] { self.0 }
fn as_ref(&self) -> &[u8] {
unsafe { &*self.0 }
}
}
impl Drop for RxBuffer {
fn drop(&mut self) {
release_rx_buf();
unsafe { EMAC_DATA.rx_counter += 1 }; // Increment RX statistics
let mut device = unsafe { &mut *self.1 };
device.release_rx_buf();
device.rx_counter += 1;
}
}
pub struct TxBuffer(&'static mut [u8]);
pub struct TxBuffer(*mut [u8], *mut EthernetDevice);
impl AsRef<[u8]> for TxBuffer {
fn as_ref(&self) -> &[u8] { self.0 }
fn as_ref(&self) -> &[u8] {
unsafe { &*self.0 }
}
}
impl AsMut<[u8]> for TxBuffer {
fn as_mut(&mut self) -> &mut [u8] { self.0 }
fn as_mut(&mut self) -> &mut [u8] {
unsafe { &mut *self.0 }
}
}
impl Drop for TxBuffer {
fn drop(&mut self) {
unsafe {
let mut device = unsafe { &mut *self.1 };
// Use chain structure rather than ring structure
// Set LS and FS flags as the data fits in a single buffer and give the ownership of the descriptor to the DMA
EMAC_DATA.tx_desc_buf[EMAC_DATA.tx_cur_desc + 0] = EMAC_TDES0_LS | EMAC_TDES0_FS | EMAC_TDES0_TCH;
EMAC_DATA.tx_desc_buf[EMAC_DATA.tx_cur_desc + 0] |= EMAC_TDES0_OWN; // Set ownersip for DMA here
device.tx_desc_buf[device.tx_cur_desc + 0] = EMAC_TDES0_LS | EMAC_TDES0_FS | EMAC_TDES0_TCH;
device.tx_desc_buf[device.tx_cur_desc + 0] |= EMAC_TDES0_OWN; // Set ownership for DMA here
cortex_m::interrupt::free(|cs| {
let emac0 = tm4c129x::EMAC0.borrow(cs);
// Clear TU flag to resume processing
emac0.dmaris.write(|w| w.tu().bit(true));
// Instruct the DMA to poll the transmit descriptor list
emac0.txpolld.write(|w| w.tpd().bits(0));
unsafe { emac0.txpolld.write(|w| w.tpd().bits(0)); }
});
// Calculate next DMA descriptor offset
let mut tx_next_desc = EMAC_DATA.tx_cur_desc + ETH_DESC_U32_SIZE;
let mut tx_next_desc = device.tx_cur_desc + ETH_DESC_U32_SIZE;
if tx_next_desc >= (ETH_TX_BUFFER_COUNT * ETH_DESC_U32_SIZE) {
tx_next_desc = 0;
}
EMAC_DATA.tx_cur_desc = tx_next_desc;
device.tx_cur_desc = tx_next_desc;
EMAC_DATA.tx_counter += 1;
}
device.tx_counter += 1;
}
}

View File

@ -166,8 +166,7 @@ fn main_with_fpu() {
println!("MAC {} IP {}", hardware_addr, protocol_addrs[0]);
let mut arp_cache_entries: [_; 8] = Default::default();
let mut arp_cache = SliceArpCache::new(&mut arp_cache_entries[..]);
ethmac::init(hardware_addr.0);
let mut device = ethmac::EthernetDevice;
let mut device = ethmac::EthernetDevice::new(hardware_addr);
let mut iface = EthernetInterface::new(
&mut device, &mut arp_cache as &mut ArpCache,
hardware_addr, &mut protocol_addrs[..]);