Packet Receive Capability with Intel 82573L NIC: Similarities & Differences, Slides of Computer Applications

The similarities and differences between implementing the transmit-capability and receive-capability in a device-driver for intel's 82573l ethernet controller. It covers the 'push' versus 'pull' mechanism, the use of interrupts, and the handling of packet data. The document also includes information on the linux kernel's sleep/wakeup mechanism and the role of interrupt service routines.

Typology: Slides

2012/2013

Uploaded on 04/17/2013

pamelaaaa
pamelaaaa 🇮🇳

4.5

(12)

103 documents

1 / 25

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Our ‘recv1000.c’ driver
Implementing a ‘packet-receive’
capability with the Intel 82573L
network interface controller
Docsity.com
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19

Partial preview of the text

Download Packet Receive Capability with Intel 82573L NIC: Similarities & Differences and more Slides Computer Applications in PDF only on Docsity!

Our ‘recv1000.c’ driver

Implementing a ‘packet-receive’

capability with the Intel 82573L

network interface controller

Similarities

• There exist quite a few similarities between

implementing the ‘transmit-capability’ and the

‘receive-capability’ in a device-driver for Intel’s

82573L ethernet controller:

– Identical device-discovery and ioremap steps

– Same steps for ‘global reset’ of the hardware

– Comparable data-structure initializations

– Parallel setups for the TX and RX registers

• But there also are a few fundamental differences

(such as ‘active’ versus ‘passive’ roles for driver)

Sleep/wakeup

• We will need to employ a wait-queue, we

will need to enable device-interrupts, and

we will need to write and install the code

for an interrupt service routine (ISR)

• So our ‘recv1000.c’ driver will have a few

additional code and data components that

were absent in our ‘xmit1000.c’ driver

This function will program the actual data-transfer

Driver’s components

read

my_fops

my_read()

module_init() module_exit()

This function will allow us to inspect the receive-descriptors

This function will detect and configure

the hardware, define page-mappings,

allocate and initialize the descriptors,

install our ISR and enable interrupts,

start the ‘receive’ engine, create the

pseudo-file and register ‘my_fops’

This function will do needed ‘cleanup’

when it’s time to unload our driver –

turn off the ‘receive’ engine, disable

interrupts and remove our ISR, free

memory, delete page-table entries,

the pseudo-file, and the ‘my_fops’

‘struct’ holds one

function-pointer

my_get_info()

This function will awaken any sleeping reader-task

wait_queue_head my_isr()

Interrupt event-types

reserved reserved

82573L

31: INT_ASSERTED (1=yes,0=no)

31 30 18 17 16 15 14 10 9 8 7 6 5 4 2 1 0

17: ACK (Rx-ACK Frame detected)

16: SRPD (Small Rx-Packet detected)

15: TXD_LOW (Tx-Descr Low Thresh hit)

9: MDAC (MDI/O Access Completed) 7: RXT0 ( Receiver Timer expired) 6: RXO (Receiver Overrun) 4: RXDMT0 (Rx-Desc Min Thresh hit) 2: LSC (Link Status Change) 1: TXQE( Transmit Queue Empty) 0: TXDW (Transmit Descriptor Written Back)

Interrupt Mask Set/Read

• This register is used to enable a selection

of the device’s interrupts which the driver

will be prepared to recognize and handle

• A particular interrupt becomes ‘enabled’ if

software writes a ‘1’ to the corresponding

bit of this Interrupt Mask Set register

• Writing ‘0’ to any register-bit has no effect,

so interrupts can be enabled one-at-a-time

Interrupt Cause Read

• Whenever interrupts occur, your driver’s

interrupt service routine can discover the specific

conditions that triggered them if it reads the

Interrupt Cause Read register

• In this case your driver can clear any selection of

these bits (except bit #31) by writing ‘1’s to them

(writing ‘0’s to this register will have no effect)

• If case no interrupt has occurred, reading this

register may have the side-effect of clearing it

Interrupt Cause Set

• For testing your driver’s interrupt-handler,

you can artificially trigger any particular

combination of interrupts by writing ‘1’s

into the corresponding register-bits of this

Interrupt Cause Set register (assuming

your combination of bits corresponds to

interrupts that are ‘enabled’ by ‘1’s being

present for them in the Interrupt Mask)

We ‘tweak’ our packet-format

• Our ‘xmit1000.c’ driver elected to have the

NIC append ‘padding’ to any short packets

• But this prevents a receiver from knowing

how many bytes represent actual data

• To solve this problem, we added our own

‘count’ field to each packet’s payload

actual bytes of user-data

destination MAC-address source MAC-address Type/Len^ count

Our ‘read()’ method

ssize_t my_read( struct file *file, char *buf, size_t len, loff_t *pos )

{

static int rxhead = 0; // to remember where we left off unsigned char *from = phys_to_virt( rxdesc[ rxhead ].base_addr ); unsigned int count;

// go to sleep if no new data-packets have been received yet if ( ioread32( io + E1000_RDH ) == rxhead ) if ( wait_event_interruptible( wq_rd, ioread32( io + E1000_RDH ) != rxhead ) ) return –EINTR;

// get the number of actual data-bytes in the new (possibly padded) data-packet count = (unsigned short)(from + 14); // data-count as stored by ‘xmit1000.c’ if ( count > len ) count = len; // can’t transfer more bytes than buffer can hold if ( copy_to_user( buf, from+16, count ) ) return –EFAULT;

// advance our static array-index variable to the next receive-descriptor rxhead = (1 + rxhead) % 8; // this index wraps-around after 8 descriptors return count; // tell kernel how many bytes were transferred

}

Receive Control (0x0100)

R

0 FLXBUF 0

SE

CRC

BSEX R

PMCF DPF R

CFI

CFI

EN

VFE BSIZE

B

A

M

R

=

MO DTYP RDMTS

I

L

O

S

S

L

U

LPE UPE 0 0 R

SBP E

N

LBM MPE

EN = Receive Enable DTYP = Descriptor Type DPF = Discard Pause Frames SBP = Store Bad Packets MO = Multicast Offset PMCF = Pass MAC Control Frames UPE = Unicast Promiscuous Enable BAM = Broadcast Accept Mode BSEX = Buffer Size Extension MPE = Multicast Promiscuous Enable BSIZE = Receive Buffer Size SECRC = Strip Ethernet CRC LPE = Long Packet reception Enable VFE = VLAN Filter Enable FLXBUF = Flexible Buffer size LBM = Loopback Mode CFIEN = Canonical Form Indicator Enable RDMTS = Rx-Descriptor Minimum Threshold Size CFI = Cannonical Form Indicator bit-value

82573L

Our driver initially will program this register with the value 0x0400801C. Then

later, when everything is ready, it will turn on bit #1 to ‘start the receive engine’

Packet-Split Rx Control (0x2170)

BSIZE

(in KB)

BSIZE

(in KB)

BSIZE

(in KB)

BSIZE

(in 1/8 KB)

31 30 29 24 23 22 21 16 15 14 13 8 7 6 0

If the controller is configured to use the packet-split feature (RCTL.DTYP=1),

then this register controls the sizes of the four receive-buffers, so there are

certain requirements that nonzero values appear in several of these fields.

But our ‘recv1000.c’ driver will use the ‘legacy’ receive-descriptor format

(i.e., RCRL.DTYP=0) and so this register will be disregarded by the NIC

and therefore we are allowed to program it with the value 0x00000000.

RX Checksum Control (0x5000)

reserved

packet

checksum

start

TCP/UDP Checksum Off-load enabled (1=yes, 0=no)

IP Checksum Off-load enabled (1=yes, 0=no)

This field controls the starting byte for the Packet Checksum calculation

Our driver programs this register with the value 0x00000000 (which disables

Checksum Off-loading for TCP/UDP packets (which we won’t be receiving)

and for IP packets (which likewise won’t be sent by our ‘xmit1000.c’ driver),

and all Packet-Checksums will be calculated starting from the very first byte

Rx-Descriptor Control (0x2828)

0 0 0 0 0 0 0

G

R

A

N

WTHRESH

(Writeback Threshold)

FRC

DPLX

FRC

SPD 0

HTHRESH

(Host Threshold)

I

L

O

S

A

S

D

E

L

R

S

T

PTHRESH

0 0 (Prefetch Threshold)

Recommended for 82573: 0x01010000 (GRAN=1, WTHRESH=1)

“This register controls the fetching and write back of receive descriptors. The three threshhold values are used to determine when descriptors are read from, and written to, host memory. Their values can be in units of cache lines or of descriptors (each descriptor is 16 bytes), based on the value of the GRAN bit (0=cache lines, 1=descriptors). When GRAN = 1, all descriptors are written back (even if not requested).” --Intel manual