Overhauled CPSW driver for TI CPSW Ethernet module

(as used in AM335x SoC for BeagleBone).

Among other things:
 * Watchdog reset doesn't hang the driver.
 * Disconnecting cable doesn't hang the driver.
 * ifconfig up/down doesn't hang the driver
 * Out-of-memory no longer panics the driver.

Known issues:
 * Doesn't have good support for fragmented packets
   (calls m_defrag() on TX, assumes RX packets are never fragmented)
 * Promisc and allmulti still unimplimented
 * addmulti and delmulti still unimplemented
 * TX queue still stalls (but watchdog now consistently recovers in ~5s)
 * No sysctl monitoring
 * Only supports port0
 * No switch configuration support
 * Not tested on anything but BeagleBone

Committed from: BeagleBone
This commit is contained in:
Tim Kientzle 2013-01-01 18:55:04 +00:00
parent 620667435c
commit 5bf325556b
3 changed files with 623 additions and 374 deletions

File diff suppressed because it is too large Load Diff

View File

@ -44,7 +44,9 @@
#define CPSW_CPDMA_OFFSET 0x0800
#define CPSW_CPDMA_TX_CONTROL (CPSW_CPDMA_OFFSET + 0x04)
#define CPSW_CPDMA_TX_TEARDOWN (CPSW_CPDMA_OFFSET + 0x08)
#define CPSW_CPDMA_RX_CONTROL (CPSW_CPDMA_OFFSET + 0x14)
#define CPSW_CPDMA_RX_TEARDOWN (CPSW_CPDMA_OFFSET + 0x18)
#define CPSW_CPDMA_SOFT_RESET (CPSW_CPDMA_OFFSET + 0x1c)
#define CPSW_CPDMA_DMACONTROL (CPSW_CPDMA_OFFSET + 0x20)
#define CPSW_CPDMA_DMASTATUS (CPSW_CPDMA_OFFSET + 0x24)
@ -63,10 +65,14 @@
#define CPSW_CPDMA_DMA_INTMASK_SET (CPSW_CPDMA_OFFSET + 0xB8)
#define CPSW_CPDMA_DMA_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0xBC)
#define CPSW_CPDMA_RX_FREEBUFFER(p) (CPSW_CPDMA_OFFSET + 0x0e0 + ((p) * 0x04))
#define CPSW_CPDMA_TX_HDP(p) (CPSW_CPDMA_OFFSET + 0x200 + ((p) * 0x04))
#define CPSW_CPDMA_RX_HDP(p) (CPSW_CPDMA_OFFSET + 0x220 + ((p) * 0x04))
#define CPSW_CPDMA_TX_CP(p) (CPSW_CPDMA_OFFSET + 0x240 + ((p) * 0x04))
#define CPSW_CPDMA_RX_CP(p) (CPSW_CPDMA_OFFSET + 0x260 + ((p) * 0x04))
#define CPSW_STATS_OFFSET 0x0900
#define CPSW_STATERAM_OFFSET 0x0A00
#define CPSW_CPDMA_TX_HDP(p) (CPSW_STATERAM_OFFSET + 0x00 + ((p) * 0x04))
#define CPSW_CPDMA_RX_HDP(p) (CPSW_STATERAM_OFFSET + 0x20 + ((p) * 0x04))
#define CPSW_CPDMA_TX_CP(p) (CPSW_STATERAM_OFFSET + 0x40 + ((p) * 0x04))
#define CPSW_CPDMA_RX_CP(p) (CPSW_STATERAM_OFFSET + 0x60 + ((p) * 0x04))
#define CPSW_CPTS_OFFSET 0x0C00

View File

@ -39,6 +39,14 @@
#define CPSW_MAX_RX_BUFFERS 128
#define CPSW_MAX_ALE_ENTRIES 1024
struct cpsw_slot {
bus_dmamap_t dmamap;
struct mbuf *mbuf;
int index;
STAILQ_ENTRY(cpsw_slot) next;
};
STAILQ_HEAD(cpsw_queue, cpsw_slot);
struct cpsw_softc {
struct ifnet *ifp;
phandle_t node;
@ -57,29 +65,36 @@ struct cpsw_softc {
struct callout wd_callout;
int wd_timer;
/* buffers */
bus_dma_tag_t mbuf_dtag;
bus_dmamap_t tx_dmamap[CPSW_MAX_TX_BUFFERS];
bus_dmamap_t rx_dmamap[CPSW_MAX_RX_BUFFERS];
struct mbuf *tx_mbuf[CPSW_MAX_TX_BUFFERS];
struct mbuf *rx_mbuf[CPSW_MAX_RX_BUFFERS];
int txbd_head;
int txbd_queue_size;
int rxbd_head;
int rxbd_tail;
int tmp;
int eoq;
int tc[CPSW_MAX_TX_BUFFERS];
int tc_unload[CPSW_MAX_TX_BUFFERS];
struct cpsw_softc *phy_sc;
/* RX buffer tracking */
int rx_running;
struct cpsw_queue rx_active;
struct cpsw_queue rx_avail;
struct cpsw_slot _rx_slots[CPSW_MAX_RX_BUFFERS];
/* TX buffer tracking. */
int tx_running;
struct cpsw_queue tx_active;
struct cpsw_queue tx_avail;
struct cpsw_slot _tx_slots[CPSW_MAX_TX_BUFFERS];
/* Statistics */
uint32_t tx_enqueues; /* total TX bufs added to queue */
uint32_t tx_retires; /* total TX bufs removed from queue */
uint32_t tx_retires_at_wd_reset; /* used for watchdog */
/* Note: tx_queued != tx_enqueues - tx_retires
At driver reset, packets can be discarded
from TX queue without being retired. */
int tx_queued; /* Current bufs in TX queue */
int tx_max_queued;
};
#define CPDMA_BD_SOP (1<<15)
#define CPDMA_BD_EOP (1<<14)
#define CPDMA_BD_OWNER (1<<13)
#define CPDMA_BD_EOQ (1<<12)
#define CPDMA_BD_TDOWNCMPLT (1<<11)
#define CPDMA_BD_PKT_ERR_MASK (3<< 4)
struct cpsw_cpdma_bd {