I've heard nothing but positive feedback on this diff. It seems to
help fix sluggish ssh connections experienced while machines were
under high load. Looking for some folks to OK this. Thanks.

On Wed, Apr 16, 2014 at 2:35 PM, Benjamin Baier <program...@netzbasis.de> wrote:
> Compiles, boots and runs fine on my BBB.
> I have no problems with this patch but then i had no known problems before.
> - Ben
>
>
> On 04/12/14 17:00, Brandon Mercer wrote:
>>
>> This diff will properly initialize cpsw if uboot hasn't done so already.
>> It also adds support for 1000BaseT (RGMII) PHY found on some boards. Based
>> heavily on a netbsd diff. My BBB is out of comission so please test this and
>> provide feedback. Thanks.
>>
>>
>> diff -r 4d62a2f27093 -r 961793eb2b24 src/sys/arch/armv7/omap/if_cpsw.c
>> --- a/src/sys/arch/armv7/omap/if_cpsw.c Fri Apr 11 16:35:16 2014 -0400
>> +++ b/src/sys/arch/armv7/omap/if_cpsw.c Sat Apr 12 06:23:19 2014 -0400
>> @@ -127,7 +127,7 @@
>>         struct arpcom            sc_ac;
>>         struct mii_data          sc_mii;
>> -
>> +       bool sc_phy_has_1000t;
>>         struct cpsw_ring_data   *sc_rdp;
>>         volatile u_int           sc_txnext;
>>         volatile u_int           sc_txhead;
>> @@ -174,6 +174,10 @@
>>   int   cpsw_txintr(void *);
>>   int   cpsw_miscintr(void *);
>>   +#define      CPSW_MAX_ALE_ENTRIES    1024
>> +
>> +static int cpsw_ale_update_addresses(struct cpsw_softc *, int purge);
>> +
>>   void  cpsw_get_mac_addr(struct cpsw_softc *);
>>     struct cfattach cpsw_ca = {
>> @@ -298,6 +302,18 @@
>>         }
>>   }
>>   +static bool
>> +cpsw_phy_has_1000t(struct cpsw_softc * const sc)
>> +{
>> +       struct ifmedia_entry *ifm;
>> +
>> +       TAILQ_FOREACH(ifm, &sc->sc_mii.mii_media.ifm_list, ifm_list) {
>> +       if (IFM_SUBTYPE(ifm->ifm_media) == IFM_1000_T)
>> +               return true;
>> +       }
>> +       return false;
>> +}
>> +
>>   void
>>   cpsw_attach(struct device *parent, struct device *self, void *aux)
>>   {
>> @@ -405,14 +421,29 @@
>>         ifmedia_init(&sc->sc_mii.mii_media, 0, cpsw_mediachange,
>>             cpsw_mediastatus);
>> +
>> +       /* Initialize MDIO */
>> +       cpsw_write_4(sc, MDIOCONTROL, MDIOCTL_ENABLE | MDIOCTL_FAULTENB |
>> MDIOCTL_CLKDIV(0xff));
>> +       /* Clear ALE */
>> +       cpsw_write_4(sc, CPSW_ALE_CONTROL, ALECTL_CLEAR_TABLE);
>> +
>>         mii_attach(self, &sc->sc_mii, 0xffffffff,
>>             MII_PHY_ANY, MII_OFFSET_ANY, 0);
>>         if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
>>                 printf("no PHY found!\n");
>> +               sc->sc_phy_has_1000t = false;
>>                 ifmedia_add(&sc->sc_mii.mii_media,
>>                     IFM_ETHER|IFM_MANUAL, 0, NULL);
>>                 ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL);
>>         } else {
>> +               sc->sc_phy_has_1000t = cpsw_phy_has_1000t(sc);
>> +               if (sc->sc_phy_has_1000t) {
>> +                       printf("1000baseT PHY found. setting RGMII
>> Mode\n");
>> +                       /* Select the Interface RGMII Mode in the Control
>> Module */
>> +                       sitara_cm_reg_write_4(CPSW_GMII_SEL,
>> +                               GMIISEL_GMII2_SEL(RGMII_MODE) |
>> GMIISEL_GMII1_SEL(RGMII_MODE));
>> +               }
>> +
>>                 ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
>>         }
>>   @@ -781,6 +812,8 @@
>>         /* Reset and init Sliver port 1 and 2 */
>>         for (i = 0; i < 2; i++) {
>> +               uint32_t macctl;
>> +
>>                 /* Reset */
>>                 cpsw_write_4(sc, CPSW_SL_SOFT_RESET(i), 1);
>>                 while(cpsw_read_4(sc, CPSW_SL_SOFT_RESET(i)) & 1);
>> @@ -795,10 +828,12 @@
>>                 cpsw_write_4(sc, CPSW_PORT_P_SA_LO(i+1),
>>                     ac->ac_enaddr[4] | (ac->ac_enaddr[5] << 8));
>>   -             /* Set MACCONTROL for ports 0,1: FULLDUPLEX(1),
>> GMII_EN(5),
>> -                  IFCTL_A(15), IFCTL_B(16) FIXME */
>> -               cpsw_write_4(sc, CPSW_SL_MACCONTROL(i),
>> -                   1 | (1<<5) | (1<<15) | (1<<16));
>> +               /* Set MACCONTROL for ports 0,1 */
>> +               macctl = SLMACCTL_FULLDUPLEX | SLMACCTL_GMII_EN |
>> +                  SLMACCTL_IFCTL_A;
>> +               if (sc->sc_phy_has_1000t)
>> +                       macctl |= SLMACCTL_GIG;
>> +               cpsw_write_4(sc, CPSW_SL_MACCONTROL(i), macctl);
>>                 /* Set ALE port to forwarding(3) */
>>                 cpsw_write_4(sc, CPSW_ALE_PORTCTL(i+1), 3);
>> @@ -811,6 +846,9 @@
>>         /* Set ALE port to forwarding(3) */
>>         cpsw_write_4(sc, CPSW_ALE_PORTCTL(0), 3);
>>   +     /* Initialize addrs */
>> +       cpsw_ale_update_addresses(sc, 1);
>> +
>>         cpsw_write_4(sc, CPSW_SS_PTYPE, 0);
>>         cpsw_write_4(sc, CPSW_SS_STAT_PORT_EN, 7);
>>   @@ -1220,3 +1258,191 @@
>>         return 1;
>>   }
>> +/*
>> + * ALE support routines.
>> + */
>> +
>> +static void
>> +cpsw_ale_entry_init(uint32_t *ale_entry)
>> +{
>> +       ale_entry[0] = ale_entry[1] = ale_entry[2] = 0;
>> +}
>> +
>> +static void
>> +cpsw_ale_entry_set_mac(uint32_t *ale_entry, const uint8_t *mac)
>> +{
>> +       ale_entry[0] = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
>> +       ale_entry[1] = mac[0] << 8 | mac[1];
>> +}
>> +
>> +static void
>> +cpsw_ale_entry_set_bcast_mac(uint32_t *ale_entry)
>> +{
>> +       ale_entry[0] = 0xffffffff;
>> +       ale_entry[1] = 0x0000ffff;
>> +}
>> +
>> +static void
>> +cpsw_ale_entry_set(uint32_t *ale_entry, ale_entry_filed_t field, uint32_t
>> val)
>> +{
>> +       /* Entry type[61:60] is addr entry(1), Mcast fwd state[63:62] is
>> fw(3)*/
>> +       switch (field) {
>> +       case ALE_ENTRY_TYPE:
>> +               /* [61:60] */
>> +               ale_entry[1] |= (val & 0x3) << 28;
>> +               break;
>> +       case ALE_MCAST_FWD_STATE:
>> +               /* [63:62] */
>> +               ale_entry[1] |= (val & 0x3) << 30;
>> +               break;
>> +       case ALE_PORT_MASK:
>> +               /* [68:66] */
>> +               ale_entry[2] |= (val & 0x7) << 2;
>> +               break;
>> +       case ALE_PORT_NUMBER:
>> +               /* [67:66] */
>> +               ale_entry[2] |= (val & 0x3) << 2;
>> +               break;
>> +       default:
>> +               panic("Invalid ALE entry field: %d\n", field);
>> +       }
>> +
>> +       return;
>> +}
>> +
>> +static bool
>> +cpsw_ale_entry_mac_match(const uint32_t *ale_entry, const uint8_t *mac)
>> +{
>> +       return (((ale_entry[1] >> 8) & 0xff) == mac[0]) &&
>> +            (((ale_entry[1] >> 0) & 0xff) == mac[1]) &&
>> +            (((ale_entry[0] >>24) & 0xff) == mac[2]) &&
>> +            (((ale_entry[0] >>16) & 0xff) == mac[3]) &&
>> +            (((ale_entry[0] >> 8) & 0xff) == mac[4]) &&
>> +            (((ale_entry[0] >> 0) & 0xff) == mac[5]);
>> +}
>> +
>> +static void
>> +cpsw_ale_set_outgoing_mac(struct cpsw_softc *sc, int port, const uint8_t
>> *mac)
>> +{
>> +       cpsw_write_4(sc, CPSW_PORT_P_SA_HI(port),
>> +            mac[3] << 24 | mac[2] << 16 | mac[1] << 8 | mac[0]);
>> +       cpsw_write_4(sc, CPSW_PORT_P_SA_LO(port),
>> +            mac[5] << 8 | mac[4]);
>> +}
>> +
>> +static void
>> +cpsw_ale_read_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t
>> *ale_entry)
>> +{
>> +       cpsw_write_4(sc, CPSW_ALE_TBLCTL, idx & 1023);
>> +       ale_entry[0] = cpsw_read_4(sc, CPSW_ALE_TBLW0);
>> +       ale_entry[1] = cpsw_read_4(sc, CPSW_ALE_TBLW1);
>> +       ale_entry[2] = cpsw_read_4(sc, CPSW_ALE_TBLW2);
>> +}
>> +
>> +static void
>> +cpsw_ale_write_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t
>> *ale_entry)
>> +{
>> +       cpsw_write_4(sc, CPSW_ALE_TBLW0, ale_entry[0]);
>> +       cpsw_write_4(sc, CPSW_ALE_TBLW1, ale_entry[1]);
>> +       cpsw_write_4(sc, CPSW_ALE_TBLW2, ale_entry[2]);
>> +       cpsw_write_4(sc, CPSW_ALE_TBLCTL, 1 << 31 | (idx & 1023));
>> +}
>> +
>> +static int
>> +cpsw_ale_remove_all_mc_entries(struct cpsw_softc *sc)
>> +{
>> +       int i;
>> +       uint32_t ale_entry[3];
>> +
>> +       /* First two entries are link address and broadcast. */
>> +       for (i = 2; i < CPSW_MAX_ALE_ENTRIES; i++) {
>> +               cpsw_ale_read_entry(sc, i, ale_entry);
>> +               if (((ale_entry[1] >> 28) & 3) == 1 && /* Address entry */
>> +                    ((ale_entry[1] >> 8) & 1) == 1) { /* MCast link addr
>> */
>> +                       ale_entry[0] = ale_entry[1] = ale_entry[2] = 0;
>> +                       cpsw_ale_write_entry(sc, i, ale_entry);
>> +               }
>> +       }
>> +       return CPSW_MAX_ALE_ENTRIES;
>> +}
>> +
>> +static int
>> +cpsw_ale_mc_entry_set(struct cpsw_softc *sc, uint8_t portmask, uint8_t
>> *mac)
>> +{
>> +       int free_index = -1, matching_index = -1, i;
>> +       uint32_t ale_entry[3];
>> +
>> +       /* Find a matching entry or a free entry. */
>> +       for (i = 0; i < CPSW_MAX_ALE_ENTRIES; i++) {
>> +               cpsw_ale_read_entry(sc, i, ale_entry);
>> +
>> +               /* Entry Type[61:60] is 0 for free entry */
>> +               if (free_index < 0 && ((ale_entry[1] >> 28) & 3) == 0) {
>> +                       free_index = i;
>> +               }
>> +
>> +               if (cpsw_ale_entry_mac_match(ale_entry, mac)) {
>> +                       matching_index = i;
>> +                       break;
>> +               }
>> +       }
>> +
>> +       if (matching_index < 0) {
>> +               if (free_index < 0)
>> +                       return ENOMEM;
>> +               i = free_index;
>> +       }
>> +
>> +       cpsw_ale_entry_init(ale_entry);
>> +
>> +       cpsw_ale_entry_set_mac(ale_entry, mac);
>> +       cpsw_ale_entry_set(ale_entry, ALE_ENTRY_TYPE, ALE_TYPE_ADDRESS);
>> +       cpsw_ale_entry_set(ale_entry, ALE_MCAST_FWD_STATE,
>> ALE_FWSTATE_FWONLY);
>> +       cpsw_ale_entry_set(ale_entry, ALE_PORT_MASK, portmask);
>> +
>> +       cpsw_ale_write_entry(sc, i, ale_entry);
>> +
>> +       return 0;
>> +}
>> +
>> +static int
>> +cpsw_ale_update_addresses(struct cpsw_softc *sc, int purge)
>> +{
>> +       struct arpcom *ac = &sc->sc_ac;
>> +       uint8_t *mac = ac->ac_enaddr;
>> +       uint32_t ale_entry[3];
>> +       int i;
>> +       struct ether_multi *ifma;
>> +
>> +       cpsw_ale_entry_init(ale_entry);
>> +       /* Route incoming packets for our MAC address to Port 0 (host). */
>> +       /* For simplicity, keep this entry at table index 0 in the ALE. */
>> +       cpsw_ale_entry_set_mac(ale_entry, mac);
>> +       cpsw_ale_entry_set(ale_entry, ALE_ENTRY_TYPE, ALE_TYPE_ADDRESS);
>> +       cpsw_ale_entry_set(ale_entry, ALE_PORT_NUMBER, 0);
>> +       cpsw_ale_write_entry(sc, 0, ale_entry);
>> +
>> +       /* Set outgoing MAC Address for Ports 1 and 2. */
>> +       for (i = 1; i < 3; ++i)
>> +               cpsw_ale_set_outgoing_mac(sc, i, mac);
>> +
>> +       /* Keep the broadcast address at table entry 1. */
>> +       cpsw_ale_entry_init(ale_entry);
>> +       cpsw_ale_entry_set_bcast_mac(ale_entry);
>> +       cpsw_ale_entry_set(ale_entry, ALE_ENTRY_TYPE, ALE_TYPE_ADDRESS);
>> +       cpsw_ale_entry_set(ale_entry, ALE_MCAST_FWD_STATE,
>> ALE_FWSTATE_FWONLY);
>> +       cpsw_ale_entry_set(ale_entry, ALE_PORT_MASK, ALE_PORT_MASK_ALL);
>> +       cpsw_ale_write_entry(sc, 1, ale_entry);
>> +
>> +       /* SIOCDELMULTI doesn't specify the particular address
>> +*                  being removed, so we have to remove all and rebuild.
>> */
>> +       if (purge)
>> +               cpsw_ale_remove_all_mc_entries(sc);
>> +
>> +       /* Set other multicast addrs desired. */
>> +       LIST_FOREACH(ifma, &ac->ac_multiaddrs, enm_list) {
>> +               cpsw_ale_mc_entry_set(sc, ALE_PORT_MASK_ALL,
>> ifma->enm_addrlo);
>> +       }
>> +
>> +       return 0;
>> +}
>> diff -r 4d62a2f27093 -r 961793eb2b24 src/sys/arch/armv7/omap/if_cpswreg.h
>> --- a/src/sys/arch/armv7/omap/if_cpswreg.h      Fri Apr 11 16:35:16 2014
>> -0400
>> +++ b/src/sys/arch/armv7/omap/if_cpswreg.h      Sat Apr 12 06:23:19 2014
>> -0400
>> @@ -39,6 +39,7 @@
>>   #define CPSW_SS_SOFT_RESET            (CPSW_SS_OFFSET + 0x08)
>>   #define CPSW_SS_STAT_PORT_EN          (CPSW_SS_OFFSET + 0x0C)
>>   #define CPSW_SS_PTYPE                 (CPSW_SS_OFFSET + 0x10)
>> +#define CPSW_SS_RGMII_CTL              (CPSW_SS_OFFSET + 0x88)
>>     #define CPSW_PORT_OFFSET            0x0100
>>   #define CPSW_PORT_P_TX_PRI_MAP(p)     (CPSW_PORT_OFFSET + 0x118 + ((p-1)
>> * 0x100))
>> @@ -47,6 +48,8 @@
>>   #define CPSW_PORT_P_SA_LO(p)          (CPSW_PORT_OFFSET + 0x120 + ((p-1)
>> * 0x100))
>>   #define CPSW_PORT_P_SA_HI(p)          (CPSW_PORT_OFFSET + 0x124 + ((p-1)
>> * 0x100))
>>   +#define      CPSW_GMII_SEL                   0x0650
>> +
>>   #define CPSW_CPDMA_OFFSET             0x0800
>>   #define CPSW_CPDMA_TX_CONTROL         (CPSW_CPDMA_OFFSET + 0x04)
>>   #define CPSW_CPDMA_TX_TEARDOWN                (CPSW_CPDMA_OFFSET + 0x08)
>> @@ -112,7 +115,7 @@
>>   #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_MISC_HOST_PEND                   0x0004
>> +#define CPSW_MISC_HOST_PEND            0x0004
>>     #define CPSW_CPPI_RAM_OFFSET                0x2000
>>   @@ -139,4 +142,82 @@
>>   #define CPSW_INTROFF_TX               2
>>   #define CPSW_INTROFF_MISC     3
>>   + /* MDIOCONTROL Register Field */
>> +#define MDIOCTL_IDLE            (1<<31)
>> +#define MDIOCTL_ENABLE          (1<<30)
>> +#define MDIOCTL_HIGHEST_USER_CHANNEL(val)       ((0xf & (val)) << 24)
>> +#define MDIOCTL_PREAMBLE        (1<<20)
>> +#define MDIOCTL_FAULT           (1<<19)
>> +#define MDIOCTL_FAULTENB        (1<<18)
>> +#define MDIOCTL_INTTESTENB      (1<<17)
>> +#define MDIOCTL_CLKDIV(val)     (0xff & (val))
>> +
>> +/* ALE Control Register Field */
>> +#define ALECTL_ENABLE_ALE       (1<<31)
>> +#define ALECTL_CLEAR_TABLE      (1<<30)
>> +#define ALECTL_AGE_OUT_NOW      (1<<29)
>> +#define ALECTL_EN_P0_UNI_FLOOD  (1<<8)
>> +#define ALECTL_LEARN_NO_VID     (1<<7)
>> +#define ALECTL_EN_VID0_MODE     (1<<6)
>> +#define ALECTL_ENABLE_OUI_DENY  (1<<5)
>> +#define ALECTL_BYPASS           (1<<4)
>> +#define ALECTL_RATE_LIMIT_TX    (1<<3)
>> +#define ALECTL_VLAN_AWARE       (1<<2)
>> +#define ALECTL_ENABLE_AUTH_MODE (1<<1)
>> +#define ALECTL_ENABLE_RATE_LIMIT        (1<<0)
>> +
>> +/* GMII_SEL Register Field */
>> +#define GMIISEL_RMII2_IO_CLK_EN (1<<7)
>> +#define GMIISEL_RMII1_IO_CLK_EN (1<<6)
>> +#define GMIISEL_RGMII2_IDMODE   (1<<5)
>> +#define GMIISEL_RGMII1_IDMODE   (1<<4)
>> +#define GMIISEL_GMII2_SEL(val)  ((0x3 & (val)) << 2)
>> +#define GMIISEL_GMII1_SEL(val)  ((0x3 & (val)) << 0)
>> +#define GMII_MODE       0
>> +#define RMII_MODE       1
>> +#define RGMII_MODE      2
>> +
>> +/* Sliver MACCONTROL Register Field */
>> +#define SLMACCTL_RX_CMF_EN      (1<<24)
>> +#define SLMACCTL_RX_CSF_EN      (1<<23)
>> +#define SLMACCTL_RX_CEF_EN      (1<<22)
>> +#define SLMACCTL_TX_SHORT_GAP_LIM_EN    (1<<21)
>> +#define SLMACCTL_EXT_EN         (1<<18)
>> +#define SLMACCTL_GIG_FORCE      (1<<17)
>> +#define SLMACCTL_IFCTL_B        (1<<16)
>> +#define SLMACCTL_IFCTL_A        (1<<15)
>> +#define SLMACCTL_CMD_IDLE       (1<<11)
>> +#define SLMACCTL_TX_SHORT_GAP_EN        (1<<10)
>> +#define SLMACCTL_GIG            (1<<7)
>> +#define SLMACCTL_TX_PACE        (1<<6)
>> +#define SLMACCTL_GMII_EN        (1<<5)
>> +#define SLMACCTL_TX_FLOW_EN     (1<<4)
>> +#define SLMACCTL_RX_FLOW_EN     (1<<3)
>> +#define SLMACCTL_MTEST          (1<<2)
>> +#define SLMACCTL_LOOPBACK       (1<<1)
>> +#define SLMACCTL_FULLDUPLEX     (1<<0)
>> +
>> +/* ALE Address Table Entry Field */
>> +typedef enum {
>> +        ALE_ENTRY_TYPE,
>> +        ALE_MCAST_FWD_STATE,
>> +        ALE_PORT_MASK,
>> +        ALE_PORT_NUMBER,
>> +} ale_entry_filed_t;
>> +
>> +#define ALE_TYPE_FREE           0
>> +#define ALE_TYPE_ADDRESS        1
>> +#define ALE_TYPE_VLAN           2
>> +#define ALE_TYPE_VLAN_ADDRESS   3
>> +
>> +/*
>> + * The port state(s) required for the received port on a destination
>> address lookup
>> + * in order for the multicast packet to be forwarded to the transmit
>> port(s)
>> + */
>> +#define ALE_FWSTATE_ALL         1       /* Blocking/Forwarding/Learning
>> */
>> +#define ALE_FWSTATE_NOBLOCK     2       /* Forwarding/Learning */
>> +#define ALE_FWSTATE_FWONLY      3       /* Forwarding */
>> +
>> +#define ALE_PORT_MASK_ALL       7
>> +
>>   #endif /*_IF_CPSWREG_H */
>>
>

Reply via email to