mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-11-01 10:33:27 +00:00
310 lines
9.8 KiB
Text
310 lines
9.8 KiB
Text
|
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
|