Our ‘nic.c’ module We create a ‘character-mode’ device-driver for the 82573L NIC

advertisement
Our ‘nic.c’ module
We create a ‘character-mode’
device-driver for the 82573L NIC
to use in future experiments
No way to communicate
SOFTWARE
Linux operating system kernel
(no knowledge of the NIC)
These
components
lack a way
to interact
HARDWARE
Network interface controller
(no knowledge of the OS)
Role for a ‘device driver’
SOFTWARE
Linux operating system kernel
(no knowledge of the NIC)
device driver module
(knows about both the OS and the NIC)
HARDWARE
Network interface controller
(no knowledge of the OS)
Character devices
• The concept of a ‘character mode’ device is that
it provides a ‘stream’ of data bytes that an
application-programs can access by using
standard Linux system-calls:
–
–
–
–
–
‘open()’
‘write()’
‘read()’
‘close()’
Maybe other ‘methods’ (depending on the device)
Requirement
• The character-mode devices are known to
a Linux system by their ‘names’ and by an
associated pair of ID-numbers (major and
minor) normally set up by a ‘superuser’
root# mknod /dev/nic c 97 0
root# chmod a+rw /dev/nic
Driver module
nic.c
my_proc_rx()
this module’s
collection of
‘payload’
functions
my_proc_tx()
isr()
read()
write()
fops
required pair of
module
administration
functions
module_init
module_exit
character-mode
device-driver’s
required
‘file-operations’
data-structure
Overview
user space
standard
runtime
libraries
kernel space
Linux
operating system
Kernel
file subsystem
application
program
networking subsystem
char driver module
hardware
We bypass use
of the TCP/IP
protocol stack
for our demo
Transmit operation
user space
kernel space
Linux OS kernel
runtime library
write()
file subsystem
nic device-driver
my_write()
user data-buffer
copy_from_user()
packet buffer
DMA
application program
hardware
Receive operation
user space
kernel space
Linux OS kernel
runtime library
read()
file subsystem
nic device-driver
my_read()
user data-buffer
copy_to_user()
packet buffer
application program
DMA
hardware
We ‘tweak’ our packet-format
• Our ‘nictx.c’ and ‘nicrx.c’ modules elected
to use the Ethernet-header’s Type/Length
field for storing the number of data-bytes
• But this allows our driver to be misled by
packet’s which don’t follow that scheme
• So we added a ‘signature’ and relocated
our ‘count’ field to the ‘payload’ region
0
6
destination MAC-address
12
source MAC-address
actual bytes of user-data
Type/Len
14
count
Using ‘echo’ and ‘cat’
• Our device-driver module ‘nic.c’ is intended
to allow two programs that are running on a
pair of our classroom PCs to communicate
via their ‘secondary’ Ethernet interfaces
Transmitting…
$ echo Hello > /dev/nic
$_
Receiving…
$ cat /dev/nic
Hello
_
Exploring RX Descriptor FIFO
Timeout for an in-class demonstration
‘push’ versus ‘pull’
Host memory
transmit
packet
buffer
Ethernet controller
push
transmit-FIFO
to/from
LAN
receive
packet
buffer
pull
receive-FIFO
The ‘write()’ routine in our ‘nic.c’ driver can transfer some data anytime there
is at least one Tx-descriptor that is not “owned” by the network hardware, but
the ‘read()’ routine in our ‘nic.c’ driver will have to wait for some data to arrive.
So to avoid doing any wasteful busy-waiting, our ‘nic.c’ driver can utilize the
Linux kernel’s sleep/wakeup mechanism – if it enables the NIC’s interrupts!
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 ‘nic.c’ device-driver will have a few
additional code and data components that
were absent from our ‘nictx.c’ and ‘nicrx.c’
kernel-module demos
How NIC’s interrupts work
• There are four interrupt-related registers
which are essential for us to understand
0x00C0
ICR
Interrupt Cause Read
0x00C8
ICS
Interrupt Cause Set
0x00D0
IMS
Interrupt Mask Set/Read
0x00D8
IMC
Interrupt Mask Clear
Interrupt-event types
31
30
18 17 16 15 14
reserved
10
9
8
7
6
5
4
2
1
reserved
31: INT_ASSERTED (1=yes,0=no)
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)
82573L
0
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 Mask Clear
• Your driver can discover which interrupts
have been enabled by reading IMS – but
your driver cannot ‘disable’ any interrupts
by writing to that register
• Instead a specific interrupt can be disabled
by writing a ‘1’ to the corresponding bit in
the Interrupt Mask Clear register
• Writing ‘0’ to a register-bit has no effect on
the interrupt controller’s Interrupt Mask
Interrupt Cause Read
• When interrupts occur, your driver’s ‘interrupt
service routine’ (isr) discovers which specific
conditions triggered the interruption if it reads
the NIC’s 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)
Our interrupt-handling
• We decided to enable only a subset of the
possible interrupt causes (those related to
transmits, receives, and link-changes):
#define INTR_MASK
(1<<0)|(1<<1)|(1<<15)|(1<<2)|(1<<4)|(1<<6)|(1<<7)
transmit-related
receive-related
link-status changed
• The ones we take action on are TXDW,
RXT0, and RXDMT0
NIC “owns” some Rx-descriptors
RDBAH/RDBAL
RDLEN
=0x80
0
1
2
3
4
5
6
7
Our ‘static’ variables
rxhead
pickup
descriptor 0
descriptor 1
descriptor 2
descriptor 3
RDH
This register gets
initialized to 0, then
gets changed by the
controller as new
packets are received
descriptor 4
RDT
descriptor 5
This register gets
advanced by 4 when
the NIC’s supply of
descriptors drops
below a programmed
threshold
descriptor 6
descriptor 7
Keeps track of where packet-data resumes
In-class exercise
• Login to a pair of classroom machines
• Install our ‘nic.ko’ module on both hosts
• Try transferring a textfile from one of the
machines to the other, by using ‘cat’:
hrn23501$ cat textfile > /dev/nic
hrn23502$ cat /dev/nic > recv1000.out
• How large a textfile can you successfully
transfer using our Linux device-driver?
• Any problems encountered doing this?
Download