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