M7350/kernel/Documentation/networking/qfec.txt

310 lines
9.8 KiB
Plaintext
Raw Normal View History

2024-09-09 08:52:07 +00:00
Driver name: Qualcomm FSM9xxx Ethernet Driver
Supported hardware: FSM9xxx Ethernet Controller
Maintainer(s):
Author(s):
Introduction:
=============
The FSM9xxx Ethernet controller is register based with separate TX and RX DMA
engines supporting scatter/gather and support 1EEE-1588 timestamping.
MII, RevMII and RgMII interfaces are support. RgMII support 1G.
The driver supports gather but not scatter, uses the controller DMA engines,
and timestamping.
Hardware description:
=====================
The Ethernet Controller is a memory mapped register device with two
internal DMA engines for TX and RX path processing using separate
buffer-descriptors (BD) allocated from non-cached main memory for the TX
and RX paths. These BDs support scatter-gather but are only used to
transfer single max sized Ethernet frames. The BDs are sequentially
accessed as a ring, with an end-of-ring bit set in the last BD. Ownership
bits control access by hardware and software to individual BDs.
An additional 4 words of space can be configured and is allocated between
each BD to store additional information about the sk_buff associated with it.
The driver software uses 2 ring structures and local functions to manage
them to keep in sync with the hardware the BDs . The number of BDs is
determined from the space allocated for them (PAGE_SIZE). The ratio of RX
to TX BD is set by a #define.
Interrupts are used to service and replenish pre-allocated sk_buff for each
RX BD. TX frames are allocated to a TX BD and transmitted frames are
freed within the xmit() invoked to send the frame. No TX interrupts are
processed since sk_buffs are freed in the xmit().
Three PHY interfaces are supported: MII, RevMII and RgMII. The selected
interface is determined from the resource structure (to be completed) and
programmed into a register prior to resetting the Ethernet controller.
Separate PLLs are managed to provide MAC/PHY clocks in RevMii and RgMii
modes, and a 25mHz clock timestamping.
Software description
====================
Structures
struct qfec_buf_desc {
uint32_t status;
uint32_t ctl;
void *p_buf;
void *next;
};
struct buf_desc {
struct qfec_buf_desc desc; /* must be first */
struct sk_buff *skb;
void *buf_virt_addr;
void *buf_phys_addr;
uint32_t last_bd_flag;
};
struct ring {
int head;
int tail;
int n_free;
int len;
};
struct qfec_priv {
struct net_device *net_dev;
struct net_device_stats stats; /* req statistics */
struct device dev;
spinlock_t hw_lock;
unsigned int state; /* driver state */
void *bd_base; /* addr buf-desc */
dma_addr_t tbd_dma; /* dma/phy-addr buf-desc */
dma_addr_t rbd_dma; /* dma/phy-addr buf-desc */
struct resource *mac_res;
void *mac_base; /* mac (virt) base address */
struct resource *clk_res;
void *clk_base; /* clk (virt) base address */
unsigned int n_tbd; /* # of TX buf-desc */
struct ring ring_tbd; /* TX ring */
struct buf_desc *p_tbd; /* # TX buf-desc */
unsigned int n_rbd; /* # of RX buf-desc */
struct ring ring_rbd; /* RX ring */
struct buf_desc *p_rbd; /* # RX buf-desc */
unsigned long cntr[cntr_last]; /* activity counters */
struct mii_if_info mii;
int mdio_clk; /* phy mdio clock rate */
int phy_id; /* default PHY addr (0) */
struct timer_list phy_tmr; /* monitor PHY state */
};
Initialization is divided between probe() and open() such that the
net_device is allocated, the address space is mapped for register access,
and procfs files created in probe(). BD memory is allocated and
initialized along with interrupts and timers in open(). BD is not
de-allocated in close() allowing it to be debugged after the interface is
ifconfig down'd. This approach is intended to aid with debugging by
allowing configuring the interface down and up may clear some early usage
problems
Phy link state changes are monitored using a timer using some existing
functions from the mii library, but also with local functions intended to
support RGMII in the future.
A variety of information is accessible through procFs. Counters are used
to track various driver events, these include abnormal and error
interrupts. Hardware counters of various frame statistics (e.g. types and
sizes of TX and RX frames) are available. Hardware registers and up to the
50 TX and RX BDs can be can be displayed. A table of procfs filenames and
functions are used to create and delete the procfs entries as needed.
Probe()
Allocate and initialize the net_device structure with resource information
specifying the Ethernet controller, clock control and MAC address memory
regions. Set netdev_ops to a statically defined sub-structure supporting
the device.
Open()
Use qfec_mem_alloc() to allocate space for the buffer-descriptors (BD).
TX BDs are initialized by clearing the ownership bit of each. Each RX BD
is initialized using qfec_rbd_init(). Qfec_rbd_init() pre-allocates an
sk_buff, saving the addresses of both the sk_buff and its data buffer in the
additional BD space, setting the BD buf pointer to the physical address of
the sk_buff data, and finally setting the ownership bit.
Once the BDs are initialized, interface selected register is set to the
appropriate PHY interface configuration, and the Ethernet controller is
reset and its registers initialized, including the starting addresses of
the TX and RX BDs.
The PHY monitor state is initialized and the timer initialized and started.
Finally, the interrupt for the Ethernet controller is initialized.
Note - Interrupts from both from the external PHY and internal RevMii
PHY, are available, but neither is used in preference to the
timer.
Interrupt Processing
Besides recognizing abnormal error interrupts, RX, TX and GMAC interrupts
are recognized, although TX and GMAC interrupts are ignored but cleared and
counted. (The gmac interrupt can be ignored but must be disabled).
RX interrupts invoke a handler to process the received frame, send it
to the stack and re-allocate a replacement sk_bufff for the buffer-
descriptor.
Receive Processing
The RX buffer descriptors are initialized by _open() using qfec_rbd_init()
which pre-allocated an sk_buff, saving its address and the physical address
of its data in the additional BD space, as well as writing the physical
address to the BD pbuf entry read by HW. The size of the buffer and
other control information are written to the BD, as well as setting the
ownership bit.
A received frame generates an interrupt invoking qfec_rx_int(). It
repeatedly checks the ownership the next available BD, and passing the
sk_buff containing the received frame to the stack via netif_rx().
Once all received frames are processed, it repeatedly calls qfec_rbd_init()
to allocate a new sk_buff with each available BD.
Transmit Processing
Frames are transmitted through the start_xmit callback function.
qfec_tx_replenish() is immediately called to free sk_buffs from BD
that have been transmitted, before checking is a BD is available.
The sk_buff address is stored in the additional BD space and the
physical address of its data is store in the pbuf BD entry used
by the HW. The TX poll-demand register is accessed, causing the
HW to recheck the current BD and process it.
While the TX interrupt could be processed to free sk_buffs as BD
are processed, they are ignored since the sk_buffs will be freed
with each call to _xmit().
procfs
debug files are available to display the controller registers,
frame counters from the controller, driver activity counters, and
the first 50 entries of the RX and TX buffer descriptors.
Callbacks
In addition to the functions described above, the following functions
are used to support their correspondingly named device operations:
qfec_stop
qfec_do_ioctl
qfec_tx_timeout
qfec_set_mac_address
qfec_get_stats
qfec_set_config
eth_change_mtu
eth_validate_addr
Power Management
================
None
Interface:
==========
- Module-init/exit
- standard network interface functions
Module parameters:
==================
static struct resource qfec_resources [] = {
[0] = {
.start = QFEC_MAC_BASE,
.end = QFEC_MAC_BASE + QFEC_MAC_SIZE,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = QFEC_MAC_IRQ,
.end = QFEC_MAC_IRQ,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = QFEC_CLK_BASE,
.end = QFEC_CLK_BASE + QFEC_CLK_SIZE,
.flags = IORESOURCE_IO,
},
[3] = {
.start = QFEC_MAC_FUSE_BASE,
.end = QFEC_MAC_FUSE_BASE + QFEC_MAC_FUSE_SIZE,
.flags = IORESOURCE_DMA,
},
};
static struct platform_device qfec_device = {
.name = "qfec",
.id = 0,
.num_resources = ARRAY_SIZE(qfec_resources),
.resource = qfec_resources,
};
Resource entries exist for three address regions and one interrupt. The
interrupt is identified as IORESOURCE_IRQ, the controller registers as
OPRESOURCE_MEM, the clock control registers as IORESOURCE_IO, and the
MAC address fuses as IORESOURCE_DMA.
Dependencies:
=============
None
User space utilities:
=====================
See procfs descriptions
Known issues:
=============
- replace procfs w/ debugfs
To do:
======
- specify interface (MII/RevMII/RgMii) in resource structure
- RevMii support untested
- RgMii (10/100/1000)
- generic timestamp support