Add support for dual emac mode.

In dual emac mode, the CPSW subsystem provides two independent ethernets.

This is implemented (as recommended by TI's TRM) with a mixture of switch
settings (vlans) and specific features of CPSW subsystem.

The driver was splitted to accommodate the shared parts (RX and TX rings
for example) while it still provides two independent ethernets.

Each of the ethernet ports driver has it's own set of MDIO registers among
the other private settings.

Previously this driver always operate in promisc mode, now the Switch ALE
(address table entry) is properly initialized and enabled.

The driver is also tested (and known to work) with both ports operating in
single port mode (active_slave 0 or 1).

Tested on uBMC (dual emac mode, both ports in single mode, giga and fast
ethernet) and BBB (single port, fast ethernet).

Sponsored by:	Rubicon Communications (Netgate)
This commit is contained in:
Luiz Otavio O Souza 2016-03-17 19:35:08 +00:00
parent ff63037da1
commit 23cd11b603
3 changed files with 1125 additions and 743 deletions

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,7 @@
#define CPSW_PORT_OFFSET 0x0100
#define CPSW_PORT_P_MAX_BLKS(p) (CPSW_PORT_OFFSET + 0x08 + ((p) * 0x100))
#define CPSW_PORT_P_BLK_CNT(p) (CPSW_PORT_OFFSET + 0x0C + ((p) * 0x100))
#define CPSW_PORT_P_VLAN(p) (CPSW_PORT_OFFSET + 0x14 + ((p) * 0x100))
#define CPSW_PORT_P_TX_PRI_MAP(p) (CPSW_PORT_OFFSET + 0x118 + ((p-1) * 0x100))
#define CPSW_PORT_P0_CPDMA_TX_PRI_MAP (CPSW_PORT_OFFSET + 0x01C)
#define CPSW_PORT_P0_CPDMA_RX_CH_MAP (CPSW_PORT_OFFSET + 0x020)
@ -81,15 +82,36 @@
#define CPSW_ALE_OFFSET 0x0D00
#define CPSW_ALE_CONTROL (CPSW_ALE_OFFSET + 0x08)
#define CPSW_ALE_CTL_ENABLE (1U << 31)
#define CPSW_ALE_CTL_CLEAR_TBL (1 << 30)
#define CPSW_ALE_CTL_BYPASS (1 << 4)
#define CPSW_ALE_CTL_VLAN_AWARE (1 << 2)
#define CPSW_ALE_TBLCTL (CPSW_ALE_OFFSET + 0x20)
#define CPSW_ALE_TBLW2 (CPSW_ALE_OFFSET + 0x34)
#define CPSW_ALE_TBLW1 (CPSW_ALE_OFFSET + 0x38)
#define CPSW_ALE_TBLW0 (CPSW_ALE_OFFSET + 0x3C)
#define ALE_MCAST(_a) ((_a[1] >> 8) & 1)
#define ALE_MCAST_FWD (3 << 30)
#define ALE_PORTS(_a) ((_a[2] >> 2) & 7)
#define ALE_TYPE(_a) ((_a[1] >> 28) & 3)
#define ALE_TYPE_ADDR 1
#define ALE_TYPE_VLAN 2
#define ALE_TYPE_VLAN_ADDR 3
#define ALE_VLAN(_a) ((_a[1] >> 16) & 0xfff)
#define ALE_VLAN_REGFLOOD(_a) ((_a[0] >> 8) & 7)
#define ALE_VLAN_UNREGFLOOD(_a) ((_a[0] >> 16) & 7)
#define ALE_VLAN_UNTAG(_a) ((_a[0] >> 24) & 7)
#define ALE_VLAN_MEMBERS(_a) (_a[0] & 7)
#define CPSW_ALE_PORTCTL(p) (CPSW_ALE_OFFSET + 0x40 + ((p) * 0x04))
/* SL1 is at 0x0D80, SL2 is at 0x0DC0 */
#define CPSW_SL_OFFSET 0x0D80
#define CPSW_SL_MACCONTROL(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x04)
#define CPSW_SL_MACTL_IFCTL_B (1 << 16)
#define CPSW_SL_MACTL_IFCTL_A (1 << 15)
#define CPSW_SL_MACTL_GIG (1 << 7)
#define CPSW_SL_MACTL_GMII_ENABLE (1 << 5)
#define CPSW_SL_MACTL_FULLDUPLEX (1 << 0)
#define CPSW_SL_MACSTATUS(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x08)
#define CPSW_SL_SOFT_RESET(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x0C)
#define CPSW_SL_RX_MAXLEN(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x10)
@ -99,8 +121,18 @@
#define MDIO_OFFSET 0x1000
#define MDIOCONTROL (MDIO_OFFSET + 0x04)
#define MDIOCTL_ENABLE (1 << 30)
#define MDIOCTL_FAULTENB (1 << 18)
#define MDIOLINKINTRAW (MDIO_OFFSET + 0x10)
#define MDIOLINKINTMASKED (MDIO_OFFSET + 0x14)
#define MDIOUSERACCESS0 (MDIO_OFFSET + 0x80)
#define MDIOUSERPHYSEL0 (MDIO_OFFSET + 0x84)
#define MDIOUSERACCESS1 (MDIO_OFFSET + 0x88)
#define MDIOUSERPHYSEL1 (MDIO_OFFSET + 0x8C)
#define MDIO_PHYSEL_LINKINTENB (1 << 6)
#define MDIO_PHYACCESS_GO (1U << 31)
#define MDIO_PHYACCESS_WRITE (1 << 30)
#define MDIO_PHYACCESS_ACK (1 << 29)
#define CPSW_WR_OFFSET 0x1200
#define CPSW_WR_SOFT_RESET (CPSW_WR_OFFSET + 0x04)
@ -114,18 +146,25 @@
#define CPSW_WR_C_RX_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x44)
#define CPSW_WR_C_TX_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x48)
#define CPSW_WR_C_MISC_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x4C)
#define CPSW_WR_C_MISC_EVNT_PEND (1 << 4)
#define CPSW_WR_C_MISC_STAT_PEND (1 << 3)
#define CPSW_WR_C_MISC_HOST_PEND (1 << 2)
#define CPSW_WR_C_MISC_MDIOLINK (1 << 1)
#define CPSW_WR_C_MISC_MDIOUSER (1 << 0)
#define CPSW_CPPI_RAM_OFFSET 0x2000
#define CPSW_CPPI_RAM_SIZE 0x2000
#define CPSW_MEMWINDOW_SIZE 0x4000
#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)
#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)
#define CPDMA_BD_TO_PORT (1 << 4)
#define CPDMA_BD_PORT_MASK 3
struct cpsw_cpdma_bd {
volatile uint32_t next;

View File

@ -29,6 +29,7 @@
#ifndef _IF_CPSWVAR_H
#define _IF_CPSWVAR_H
#define CPSW_PORTS 2
#define CPSW_INTR_COUNT 4
/* MII BUS */
@ -64,51 +65,42 @@ struct cpsw_queue {
int hdp_offset;
};
struct cpsw_softc {
struct ifnet *ifp;
phandle_t node;
struct cpsw_port {
device_t dev;
int phy;
int vlan;
};
struct cpsw_softc {
device_t dev;
int active_slave;
int debug;
int dualemac;
phandle_t node;
struct bintime attach_uptime; /* system uptime when attach happened. */
struct bintime init_uptime; /* system uptime when init happened. */
struct cpsw_port port[2];
/* TODO: We should set up a child structure for each port;
store mac, phy information, etc, in that structure. */
uint8_t mac_addr[ETHER_ADDR_LEN];
/* RX and TX buffer tracking */
struct cpsw_queue rx, tx;
device_t miibus;
struct mii_data *mii;
/* We expect 1 memory resource and 4 interrupts from the device tree. */
struct resource *mem_res;
int mem_rid;
struct resource *mem_res;
struct resource *irq_res[CPSW_INTR_COUNT];
/* Interrupts get recorded here as we initialize them. */
/* Interrupt teardown just walks this list. */
struct {
struct resource *res;
void *ih_cookie;
const char *description;
} interrupts[CPSW_INTR_COUNT];
int interrupt_count;
uint32_t cpsw_if_flags;
int cpsw_media_status;
struct {
int resets;
int timer;
struct callout callout;
} watchdog;
bus_dma_tag_t mbuf_dtag;
void *ih_cookie[CPSW_INTR_COUNT];
/* An mbuf full of nulls for TX padding. */
bus_dmamap_t null_mbuf_dmamap;
struct mbuf *null_mbuf;
bus_addr_t null_mbuf_paddr;
/* RX and TX buffer tracking */
struct cpsw_queue rx, tx;
bus_dma_tag_t mbuf_dtag;
struct {
int resets;
int timer;
struct callout callout;
} watchdog;
/* 64-bit versions of 32-bit hardware statistics counters */
uint64_t shadow_stats[CPSW_SYSCTL_COUNT];
@ -123,4 +115,23 @@ struct cpsw_softc {
struct cpsw_slots avail;
};
struct cpswp_softc {
device_t dev;
device_t miibus;
device_t pdev;
int media_status;
int unit;
int vlan;
struct bintime init_uptime; /* system uptime when init happened. */
struct callout mii_callout;
struct cpsw_softc *swsc;
struct ifnet *ifp;
struct mii_data *mii;
struct mtx lock;
uint32_t if_flags;
uint32_t phy;
uint32_t phyaccess;
uint32_t physel;
};
#endif /*_IF_CPSWVAR_H */