AnsweredAssumed Answered

P1013 eTSEC data not DMA'ing

Question asked by Steven Snyder on May 13, 2016
Latest reply on May 16, 2016 by Bill Paul

I am attempting to use eTSEC1 as a network device but see no evidence that the packet is being DMA'd from the TX ring buffer.  A scope on the transmit line between the P1013 and my PHY ( a TI DP83848) does not see TX asserted, and enabling loopback in MACCFG1 does not result in my packet appearing in a RX buffer.


The above is icing on the cake.  The real indication of nothing happening is that the TX Ready bit in the TX data buffer descriptor is never cleared.  There is no indication of error in IEVENT, or in TSTAT.  It seems like the P1013 isn't snooping my memory accesses, although I have both RX and TX snooping enabled.


I an not using interrupts, just relying on the status bits in the eTSEC-related registers to determine state.


I don't know if this is relevant, but I am attempting to do RMII transfers.  My PHY is configured (via MDIO) for Auto-Neg, supporting 10BASE-T and 100BASE-T, in both full- and half-duplex.  I've tried both full- and half-duplex in MACCFG2 without success.


TX & RX descriptors and buffers are 16-byte-aligned in memory (shown in regs below), but even if they weren't wouldn't there be some indication of error?


The code below is the simplest test case I can come up with, and below that are the register values after the failure to transmit my packet.


Any thoughts as to why I seem unable to transmit from eTSEC1?




#define DMACTRL_TDSEN   0x01000080
#define DMACTRL_TBDSEN  0x02000040
#define DMACTRL_GRS     0x00000010
#define DMACTRL_GTS     0x00000008
#define DMACTRL_TOD     0x00000004
#define DMACTRL_WOP     0x00000001

#define TXBD_READY      0x8000
#define TXBD_LAST       0x0800

#define INIT_PHYRMII ( (1 << 5) | (1 << 0) )

void simple_gpp_xmit(void) {
   // Per doc: User initialization; page 976
   unsigned miistatus;
   int i, timeout=1000, txfailed=0;

   tsec_t         * const tregs = tsec_info[0].regs;
   tsec_mii_mng_t * const mregs = tsec_info[0].miiregs_sgmii;
   ccsr_gur_t     * const gregs = (unsigned int *)(CCSRBASE + 0xE0000);

   static const unsigned char packet[] = {
      0x00, 0x1e, 0x4f, 0x12, 0xcb, 0x2c, 0x00, 0x25,
      0x64, 0xbb, 0xd1, 0xab, 0x08, 0x00, 0x45, 0x00,
      0x00, 0x5c, 0xdd, 0x22, 0x00, 0x00, 0x80, 0x01,
      0x1f, 0x71, 0x0a, 0xc1, 0x14, 0x22, 0x0a, 0xc1,
      0x14, 0x6a, 0x08, 0x00, 0xef, 0x7e, 0x02, 0x00,
      0x94, 0x05, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
      0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
      0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
      0x77, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
      0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
      0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
      0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
      0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
      0x71, 0x72};

   // 0. disable active DMA (just in case)
   out_be32(&tregs->dmactrl, in_be32(&tregs->dmactrl) | (DMACTRL_GTS|DMACTRL_GRS));

   // 1. Set and clear MACCFG1 [Soft_Reset]
   out_be32(&tregs->maccfg1, MACCFG1_SOFT_RST);
   out_be32(&tregs->maccfg1, INIT_MACCFG1 | MACCFG1_LOOPBACK); 

   // 2. Initialize MACCFG2
   out_be32(&tregs->maccfg2, INIT_MACCFG2);  // RMII 10/100 full-duplex
   out_be32(&tregs->ecntrl,  INIT_ECNTRL);

   // 3. Initialize MAC station address
   out_be32((&tregs->macstnaddr2), 0x60020000);
   out_be32((&tregs->macstnaddr1), 0x4365878C);

   // 4. Set up the PHY using the MII management interface
   // 4a : phy: reset
   out_be32((&mregs->miimadd), PHY_PHYS_MASK | 0x00);
   out_be32((&mregs->miimcon), BMCR_RESET);
   while ( in_be32(&mregs->miimind) & MIIMIND_BUSY ) { udelay(1); }

   // 4b : phy: wait until reset completed
   do {
      out_be32((&mregs->miimcom), MIIMCOM_WRIT_CYCLE);
      out_be32((&mregs->miimcom), MIIMCOM_READ_CYCLE);
      while (in_be32(&mregs->miimind) & MIIMIND_BUSY) { udelay(1); }
      miistatus = in_be32(&mregs->miimstat);
   } while (miistatus & BMCR_RESET);

   // 4c : phy: set fixed 100Mbs full-duplex
   out_be32((&mregs->miimadd), PHY_PHYS_MASK | 0x00);
   out_be32((&mregs->miimcon), INIT_PHY100FD);
   while ( in_be32(&mregs->miimind) & MIIMIND_BUSY ) { udelay(1); }

   // 4d : phy: set RMII
   out_be32((&mregs->miimadd), PHY_PHYS_MASK | 0x17);
   out_be32((&mregs->miimcon), INIT_PHYRMII);
   while ( in_be32(&mregs->miimind) & MIIMIND_BUSY ) { udelay(1); }

   // 5. Clear IEVENTGg
   out_be32(&tregs->ievent, IEVENT_CLEAR_ALL); // all bits set

   // 6. Initialize IMASKGg
   out_be32(&tregs->imask, IMASK_MASK_ALL); // all bits cleared

   // 7. Initialize RCTRL
   out_be32(&tregs->rctrl, RCTRL_BC_MPROM);  // promiscuous mode

   // 8. Initialize DMACTRL
   // 8a : init aligned data dma descriptors
   for (i = 0; i < RXQUEUELEN; i++) {
      rtx.rxbd[i].status = 0x8000;
      rtx.rxbd[i].length = 0;
      rtx.rxbd[i].bufPtr = (uint)NetRxPackets[i];
   for (i = 0; i < TXQUEUELEN; i++) {
      rtx.txbd[i].status = 0;
      rtx.txbd[i].length = 0;
      rtx.txbd[i].bufPtr = 0;
   rtx.rxbd[RXQUEUELEN - 1].status |= 0x2000;
   rtx.txbd[TXQUEUELEN - 1].status |= 0x2000;

   // 8b : set pointers to TX/RX descriptors
   out_be32(&tregs->tbase, (unsigned int)(&rtx.txbd[0]));
   out_be32(&tregs->rbase, (unsigned int)(&rtx.rxbd[0]));

   // 8c : enable TX data/BD snooping, polled transmit
   out_be32(&tregs->dmactrl, in_be32(&tregs->dmactrl) | INIT_DMACTRL);

   // 8d : clear GTS/GRS
   out_be32(&tregs->dmactrl, in_be32(&tregs->dmactrl) & ~(DMACTRL_GTS|DMACTRL_GRS));

   // "transmit" a packet

   // populate TX descriptor
   rtx.txbd[0].bufPtr = (unsigned int)&packet[0];
   rtx.txbd[0].length = sizeof(packet);
   rtx.txbd[0].status = (TXBD_READY | TXBD_LAST);

   // tell the DMA to go
   out_be32(&tregs->tstat, TSTAT_CLEAR_THALT);

   // wait for buffer to be transmitted
   for (i = 0; (rtx.txbd[0].status & TXBD_READY) && !txfailed; i++) {
      if (timeout--)
         txfailed = 1;

   if (txfailed) {
      // Error-handling procedure; page 996
      unsigned short phyregs[0x20];
      printf("failed to xmit packet; TxBD[0] status: 0x%04x\n", rtx.txbd[0].status);

      // TSEC regs
      printf("maccfg1   == 0x%08x\n", in_be32(&tregs->maccfg1) );
      printf("maccfg2   == 0x%08x\n", in_be32(&tregs->maccfg2) );
      printf("ecntrl    == 0x%08x\n", in_be32(&tregs->ecntrl)  );
      printf("ievent    == 0x%08x\n", in_be32(&tregs->ievent)  );
      printf("imask     == 0x%08x\n", in_be32(&tregs->imask)   );
      printf("tctrl     == 0x%08x\n", in_be32(&tregs->tctrl)   );
      printf("rctrl     == 0x%08x\n", in_be32(&tregs->rctrl)   );
      printf("tbase     == 0x%08x\n", in_be32(&tregs->tbase)   );
      printf("rbase     == 0x%08x\n", in_be32(&tregs->rbase)   );
      printf("dmactrl   == 0x%08x\n", in_be32(&tregs->dmactrl) );
      printf("tstat     == 0x%08x\n", in_be32(&tregs->tstat)   );
      printf("rstat     == 0x%08x\n", in_be32(&tregs->rstat)   );

      // RMON regs
      printf("rmon tbyt == 0x%08x\n", in_be32(&tregs->rmon.tbyt)); 
      printf("rmon tpkt == 0x%08x\n", in_be32(&tregs->rmon.tpkt)); 
      printf("rmon tmca == 0x%08x\n", in_be32(&tregs->rmon.tmca)); 
      printf("rmon tbca == 0x%08x\n", in_be32(&tregs->rmon.tbca)); 
      printf("rmon txpf == 0x%08x\n", in_be32(&tregs->rmon.txpf)); 
      printf("rmon tdfr == 0x%08x\n", in_be32(&tregs->rmon.tdfr)); 
      printf("rmon tedf == 0x%08x\n", in_be32(&tregs->rmon.tedf)); 
      printf("rmon tscl == 0x%08x\n", in_be32(&tregs->rmon.tscl)); 
      printf("rmon tmcl == 0x%08x\n", in_be32(&tregs->rmon.tmcl)); 
      printf("rmon tlcl == 0x%08x\n", in_be32(&tregs->rmon.tlcl)); 
      printf("rmon txcl == 0x%08x\n", in_be32(&tregs->rmon.txcl)); 
      printf("rmon tncl == 0x%08x\n", in_be32(&tregs->rmon.tncl)); 
      printf("rmon res2 == 0x%08x\n", in_be32(&tregs->rmon.res2)); 
      printf("rmon tdrp == 0x%08x\n", in_be32(&tregs->rmon.tdrp)); 
      printf("rmon tjbr == 0x%08x\n", in_be32(&tregs->rmon.tjbr)); 
      printf("rmon tfcs == 0x%08x\n", in_be32(&tregs->rmon.tfcs)); 
      printf("rmon txcf == 0x%08x\n", in_be32(&tregs->rmon.txcf)); 
      printf("rmon tovr == 0x%08x\n", in_be32(&tregs->rmon.tovr)); 
      printf("rmon tund == 0x%08x\n", in_be32(&tregs->rmon.tund)); 
      printf("rmon tfrg == 0x%08x\n", in_be32(&tregs->rmon.tfrg)); 

      // misc P1013 regs
      printf("pordevsr  == 0x%08x\n", in_be32(&gregs->pordevsr)); 

      // PHY regs
      for (i=0; i<0x20; i++) {
         out_be32((&mregs->miimadd), PHY_PHYS_MASK | i);
         out_be32((&mregs->miimcom), MIIMCOM_WRIT_CYCLE);
         out_be32((&mregs->miimcom), MIIMCOM_READ_CYCLE);
         while (in_be32(&mregs->miimind) & MIIMIND_BUSY) { udelay(1); }
         phyregs[i] = in_be32(&mregs->miimstat);
      printf("PHY[0x00]: 0x%04x,0x%04x,0x%04x,0x%04x,0x%04x,0x%04x,0x%04x,0x%04x\n",
             phyregs[ 0],phyregs[ 1],phyregs[ 2],phyregs[ 3],phyregs[ 4],phyregs[ 5],phyregs[ 6],phyregs[ 7]);
      printf("PHY[0x08]: 0x%04x,0x%04x,0x%04x,0x%04x,0x%04x,0x%04x,0x%04x,0x%04x\n",
             phyregs[ 8],phyregs[ 9],phyregs[10],phyregs[11],phyregs[12],phyregs[13],phyregs[14],phyregs[15]);
      printf("PHY[0x10]: 0x%04x,0x%04x,0x%04x,0x%04x,0x%04x,0x%04x,0x%04x,0x%04x\n",
      printf("PHY[0x18]: 0x%04x,0x%04x,0x%04x,0x%04x,0x%04x,0x%04x,0x%04x,0x%04x\n",

failed to xmit packet; TxBD[0] status: 0x8800

maccfg1   == 0x00000105

maccfg2   == 0x00000101

ecntrl    == 0x0000100c

ievent    == 0x00000000

imask     == 0x00000000

tctrl     == 0x00000000

rctrl     == 0x00000008

tbase     == 0x00011800

rbase     == 0x00011810

dmactrl   == 0x000000c1

tstat     == 0x00000000

rstat     == 0x00000000

rmon tbyt == 0x00000000

rmon tpkt == 0x00000000

rmon tmca == 0x00000000

rmon tbca == 0x00000000

rmon txpf == 0x00000000

rmon tdfr == 0x00000000

rmon tedf == 0x00000000

rmon tscl == 0x00000000

rmon tmcl == 0x00000000

rmon tlcl == 0x00000000

rmon txcl == 0x00000000

rmon tncl == 0x00000000

rmon res2 == 0x00000000

rmon tdrp == 0x00000000

rmon tjbr == 0x00000000

rmon tfcs == 0x00000000

rmon txcf == 0x00000000

rmon tovr == 0x00000000

rmon tund == 0x00000000

rmon tfrg == 0x00000000

pordevsr  == 0x19000040

PHY[0x00]: 0x2100,0x7849,0x2000,0x5c90,0x0101,0x0000,0x0004,0x2001

PHY[0x08]: 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000

PHY[0x10]: 0x0005,0x0000,0x2000,0x0000,0x0000,0x0000,0x0100,0x0021

PHY[0x18]: 0x0000,0x8027,0x0904,0x0000,0x0000,0x6011,0x08be,0x0000