/****************************************************************************** * * ae531x_MACAddressSet - Set the ethernet address * * Sets the ethernet address from the given address field * * RETURNS: void */ static void ae531x_MACAddressSet(ae531x_MAC_t *MACInfo) { unsigned int data; UINT8 *macAddr; ARRIVE(); macAddr = macAddrGet(MACInfo); /* set our MAC address */ data = (macAddr[5]<<8) | macAddr[4]; ae531x_WriteMacReg(MACInfo, MacAddrHigh, data ); data = (macAddr[3]<<24) | (macAddr[2]<<16) | (macAddr[1]<<8) | macAddr[0]; ae531x_WriteMacReg(MACInfo, MacAddrLow, data ); AE531X_PRINT(AE531X_DEBUG_RESET, ("eth%d Verify MAC address %8.8X %8.8X \n", MACInfo->unit, ae531x_ReadMacReg(MACInfo, MacAddrLow), ae531x_ReadMacReg(MACInfo, MacAddrHigh))); AE531X_PRINT(AE531X_DEBUG_RESET, (" sb = %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", 0xff&macAddr[0], 0xff&macAddr[1], 0xff&macAddr[2], 0xff&macAddr[3], 0xff&macAddr[4], 0xff&macAddr[5])); LEAVE(); }
/****************************************************************************** * ae531x_RxQueueCreate - create a circular queue of Rx descriptors */ int ae531x_RxQueueCreate(ae531x_MAC_t *MACInfo, AE531X_QUEUE *q, char *pMem, int count) { int i; VIRT_ADDR descAddr; ARRIVE(); ae531x_QueueInit(q, pMem, count); q->reapDescAddr = NULL; /* Initialize Rx buffer descriptors */ for (i=0, descAddr=q->firstDescAddr; i<count; i++, descAddr=(VIRT_ADDR)((UINT32)descAddr + AE531X_QUEUE_ELE_SIZE)) { void *swptr; char *rxBuffer; int rxBufferSize; swptr = ae531x_rxbuf_alloc(MACInfo, &rxBuffer, &rxBufferSize); if (swptr == NULL) { AE531X_PRINT(AE531X_DEBUG_RESET, ("eth%d RX queue: ae531x_rxbuf_alloc failed\n", MACInfo->unit)); ae531x_QueueDestroy(q); return -1; } AE531X_DESC_SWPTR_SET(descAddr, swptr); AE531X_DESC_STATUS_SET(descAddr, DescOwnByDma); AE531X_DESC_CTRLEN_SET(descAddr, rxBufferSize); AE531X_DESC_BUFPTR_SET(descAddr, virt_to_bus(rxBuffer)); AE531X_DESC_LNKBUF_SET(descAddr, (UINT32)0); } /* for each desc */ /* Make the queue circular */ AE531X_DESC_CTRLEN_SET(q->lastDescAddr, DescEndOfRing|AE531X_DESC_CTRLEN_GET(q->lastDescAddr)); AE531X_PRINT(AE531X_DEBUG_RESET, ("eth%d Rxbuf begin = %x, end = %x\n", MACInfo->unit, (UINT32)q->firstDescAddr, (UINT32)q->lastDescAddr)); LEAVE(); return 0; }
static void ae531x_TxReap(ae531x_MAC_t *MACInfo) { AE531X_QUEUE *txq; VIRT_ADDR txDesc; UINT32 cmdsts; int reaped; ae531xTxBuf_t *TxBuf; unsigned long key; txq = &MACInfo->txQueue; reaped = 0; // XXXTODO: bug - won't be able to reap once run out of descriptors while (1) { txDesc = AE531X_QUEUE_ELE_NEXT_GET(txq, txq->reapDescAddr); if (txDesc == txq->curDescAddr) { break; } cmdsts = AE531X_DESC_STATUS_GET(KSEG1ADDR(txDesc)); if (cmdsts & DescOwnByDma) { break; } TxBuf = (ae531xTxBuf_t *)AE531X_DESC_SWPTR_GET(txDesc); AE531X_PRINT(AE531X_DEBUG_TX_REAP, ("TXREAP: cur=%p reap=%p txDesc=%p TxBuf=%p\n", txq->curDescAddr, txq->reapDescAddr, txDesc, TxBuf)); key = TxBuf->key; /* Release transmit buffer associated with completed transmit */ ae531x_txbuf_free(TxBuf); AE531X_DESC_SWPTR_SET(txDesc, (void *)0x1bad0dad); ae531xTxAvail++; txq->reapDescAddr = txDesc; reaped++; } if (reaped > 0) { AE531X_PRINT(AE531X_DEBUG_TX_REAP, ("reaped=%d TxAvail=%d\n", reaped, ae531xTxAvail)); } else { aeUselessReap++; } }
/****************************************************************************** * ae531x_TxQueueCreate - create a circular queue of descriptors for Transmit */ static int ae531x_TxQueueCreate(ae531x_MAC_t *MACInfo, AE531X_QUEUE *q, char *pMem, int count) { int i; VIRT_ADDR descAddr; ARRIVE(); ae531x_QueueInit(q, pMem, count); q->reapDescAddr = q->lastDescAddr; /* Initialize Tx buffer descriptors. */ for (i=0, descAddr=q->firstDescAddr; i<count; i++, descAddr=(VIRT_ADDR)((UINT32)descAddr + AE531X_QUEUE_ELE_SIZE)) { /* Update the size, BUFPTR, and SWPTR fields */ AE531X_DESC_STATUS_SET(descAddr, 0); AE531X_DESC_CTRLEN_SET(descAddr, 0); AE531X_DESC_BUFPTR_SET(descAddr, (UINT32)0); AE531X_DESC_LNKBUF_SET(descAddr, (UINT32)0); AE531X_DESC_SWPTR_SET(descAddr, (void *)0); } /* for each desc */ /* Make the queue circular */ AE531X_DESC_CTRLEN_SET(q->lastDescAddr, DescEndOfRing|AE531X_DESC_CTRLEN_GET(q->lastDescAddr)); AE531X_PRINT(AE531X_DEBUG_RESET, ("eth%d Txbuf begin = %x, end = %x\n", MACInfo->unit, (UINT32)q->firstDescAddr, (UINT32)q->lastDescAddr)); LEAVE(); return 0; }
/****************************************************************************** * ae531x_unitLinkGained -- Called from PHY layer to notify the MAC layer * that there are 1 or more live links associated with a MAC. */ void ae531x_unitLinkGained(int ethUnit) { AE531X_PRINT(AE531X_DEBUG_LINK_CHANGE, ("enet%d link up\n", ethUnit)); }
/****************************************************************************** * ae531x_unitLinkLost -- Called from PHY layer to notify the MAC layer * that there are no longer any live links associated with a MAC. */ void ae531x_unitLinkLost(int ethUnit) { AE531X_PRINT(AE531X_DEBUG_LINK_CHANGE, ("enet%d link down\n", ethUnit)); }
/****************************************************************************** * * ae531x_DmaReset - Reset DMA and TLI controllers * * RETURNS: N/A */ void ae531x_DmaReset(ae531x_MAC_t *MACInfo) { int i; UINT32 descAddr; unsigned long oldIntrState; ARRIVE(); /* Disable device interrupts prior to any errors during stop */ intDisable(oldIntrState); /* Disable MAC rx and tx */ ae531x_ClearMacReg(MACInfo, MacControl, (MacRxEnable | MacTxEnable)); /* Reset dma controller */ ae531x_WriteDmaReg(MACInfo, DmaBusMode, DmaResetOn); /* Delay 2 usec */ sysUDelay(2); /* Flush the rx queue */ descAddr = (UINT32)MACInfo->rxQueue.firstDescAddr; MACInfo->rxQueue.curDescAddr = MACInfo->rxQueue.firstDescAddr; for (i=0; i<(MACInfo->rxDescCount); i++, descAddr += AE531X_QUEUE_ELE_SIZE) { AE531X_DESC_STATUS_SET(descAddr, DescOwnByDma); } /* Flush the tx queue */ descAddr = (UINT32)MACInfo->txQueue.firstDescAddr; MACInfo->txQueue.curDescAddr = MACInfo->txQueue.firstDescAddr; MACInfo->txQueue.reapDescAddr = MACInfo->txQueue.lastDescAddr; for (i=0; i<(MACInfo->txDescCount); i++, descAddr += AE531X_QUEUE_ELE_SIZE) { AE531X_DESC_STATUS_SET (descAddr, 0); } /* Set init register values */ ae531x_WriteDmaReg(MACInfo, DmaBusMode, DmaBusModeInit); /* Install the first Tx and Rx queues on the device */ ae531x_WriteDmaReg(MACInfo, DmaRxBaseAddr, (UINT32)MACInfo->rxQueue.firstDescAddr); ae531x_WriteDmaReg(MACInfo, DmaTxBaseAddr, (UINT32)MACInfo->txQueue.firstDescAddr); ae531x_WriteDmaReg(MACInfo, DmaControl, DmaStoreAndForward); ae531x_WriteDmaReg(MACInfo, DmaIntrEnb, DmaIntDisable); AE531X_PRINT(AE531X_DEBUG_RESET, ("eth%d: DMA RESET!\n", MACInfo->unit)); /* Turn on device interrupts -- enable most errors */ ae531x_DmaIntClear(MACInfo); /* clear interrupt requests */ ae531x_DmaIntEnable(MACInfo); /* enable interrupts */ ae531x_EndResetMode(MACInfo); intEnable(oldIntrState); LEAVE(); }
/****************************************************************************** * ae531x_AllocateQueues - Allocate receive and transmit queues */ int ae531x_AllocateQueues(ae531x_MAC_t *MACInfo) { size_t QMemSize; char *pTxBuf = NULL; char *pRxBuf = NULL; ARRIVE(); QMemSize = AE531X_QUEUE_ELE_SIZE * MACInfo->txDescCount; pTxBuf = MACInfo->pTxDescs; if (pTxBuf == NULL) { AE531X_PRINT(AE531X_DEBUG_RESET, ("eth%d Failed to allocate TX queue\n", MACInfo->unit)); goto AllocQFail; } if (ae531x_TxQueueCreate(MACInfo, &MACInfo->txQueue, pTxBuf, MACInfo->txDescCount) < 0) { AE531X_PRINT(AE531X_DEBUG_RESET, ("eth%d Failed to create TX queue\n", MACInfo->unit)); goto AllocQFail; } QMemSize = AE531X_QUEUE_ELE_SIZE * MACInfo->rxDescCount; pRxBuf = MACInfo->pRxDescs; if (pRxBuf == NULL) { AE531X_PRINT(AE531X_DEBUG_RESET, ("eth%d Failed to allocate RX queue\n", MACInfo->unit)); goto AllocQFail; } if (ae531x_RxQueueCreate(MACInfo, &MACInfo->rxQueue, pRxBuf, MACInfo->rxDescCount) < 0) { AE531X_PRINT(AE531X_DEBUG_RESET, ("eth%d Failed to create RX queue\n", MACInfo->unit)); goto AllocQFail; } AE531X_PRINT(AE531X_DEBUG_RESET, ("eth%d Memory setup complete.\n", MACInfo->unit)); LEAVE(); return 0; AllocQFail: MACInfo->txDescCount = 0; /* sanity */ MACInfo->rxDescCount = 0; /* sanity */ if (pTxBuf) { FREE(pTxBuf); } if (pRxBuf) { FREE(pRxBuf); } LEAVE(); return -1; }
static int ae531x_poll(struct eth_device *dev) { ae531xRxBuf_t *rxBuf, *newRxBuf; char *rxBufData; int unused_length; VIRT_ADDR rxDesc; int length; ae531x_MAC_t *MACInfo; unsigned int cmdsts; ae531x_priv_data_t *ae531x_priv; ae531x_priv = (ae531x_priv_data_t *)dev->priv; MACInfo = (ae531x_MAC_t *)&ae531x_priv->MACInfo; do { for(;;) { rxDesc = MACInfo->rxQueue.curDescAddr; cmdsts = AE531X_DESC_STATUS_GET(KSEG1ADDR(rxDesc)); if (cmdsts & DescOwnByDma) { /* There's nothing left to process in the RX ring */ goto rx_all_done; } AE531X_PRINT(AE531X_DEBUG_RX, ("consume rxDesc %p with cmdsts=0x%x\n", (void *)rxDesc, cmdsts)); AE531X_CONSUME_DESC((&MACInfo->rxQueue)); A_DATA_CACHE_INVAL(rxDesc, AE531X_DESC_SIZE); /* Process a packet */ length = AE531X_DESC_STATUS_RX_SIZE(cmdsts) - ETH_CRC_LEN; if ( (cmdsts & (DescRxFirst |DescRxLast | DescRxErrors)) == (DescRxFirst | DescRxLast) ) { /* Descriptor status indicates "NO errors" */ rxBuf = AE531X_DESC_SWPTR_GET(rxDesc); /* * Allocate a replacement buffer * We want to get another buffer ready for Rx ASAP. */ newRxBuf = ae531x_rxbuf_alloc(MACInfo, &rxBufData, &unused_length); if(newRxBuf == NULL ) { /* * Give this descriptor back to the DMA engine, * and drop the received packet. */ AE531X_PRINT(AE531X_DEBUG_ERROR, ("Can't allocate new rx buf\n")); } else { //diag_printf("rxBufData=%p\n",rxBufData); AE531X_DESC_BUFPTR_SET(rxDesc, virt_to_bus(rxBufData)); AE531X_DESC_SWPTR_SET(rxDesc, newRxBuf); } AE531X_DESC_STATUS_SET(rxDesc, DescOwnByDma); rxDesc = NULL; /* sanity -- cannot use rxDesc now */ sysWbFlush(); if (newRxBuf == NULL) { goto no_rx_bufs; } else { /* Sync data cache w.r.t. DMA */ A_DATA_CACHE_INVAL(rxBuf->data, length); /* Send the data up the stack */ AE531X_PRINT(AE531X_DEBUG_RX, ("Send data up stack: rxBuf=%p data=%p length=%d\n", (void *)rxBuf, (void *)rxBuf->data, length)); { unsigned long oldIntrState; rxBuf->next = NULL; intDisable(oldIntrState); if (ae531xRxRecvdListHead) { ae531xRxRecvdListTail->next = rxBuf; ae531xRxRecvdListTail = rxBuf; } else { ae531xRxRecvdListHead = rxBuf; ae531xRxRecvdListTail = rxBuf; } intEnable(oldIntrState); } NetReceive(rxBuf->data, length); /* Free driver Rx buffer */ ae531x_rxbuf_free(rxBuf); } } else { AE531X_PRINT(AE531X_DEBUG_ERROR, ("Bad receive. rxDesc=%p cmdsts=0x%8.8x\n", (void *)rxDesc, cmdsts)); } } } while (ae531x_ReadDmaReg(MACInfo, DmaStatus) & DmaIntRxCompleted); rx_all_done: ae531x_SetDmaReg(MACInfo, DmaIntrEnb, DmaIeRxCompleted | DmaIeRxNoBuffer); ae531x_WriteDmaReg(MACInfo, DmaRxPollDemand, 0); no_rx_bufs: return; }
static int ae531x_start(struct eth_device *dev, bd_t *bis) { ae531x_priv_data_t *ae531x_priv; ae531x_MAC_t *MACInfo; unsigned char enet_addr[ETHER_ADDR_LEN]; int i; ae531x_priv = (ae531x_priv_data_t *)dev->priv; MACInfo = (ae531x_MAC_t *)&ae531x_priv->MACInfo; memcpy(ae531x_priv->enet_addr, bis->bi_enetaddr, ETHER_ADDR_LEN); /* Attach interrupt handler */ /* TBDXXX */ /* Bring MAC and PHY out of reset */ // ae531x_reset(MACInfo); /* Initialize PHY */ // phySetup(MACInfo->unit, MACInfo->phyBase); /* Start thread to poll for phy link status changes */ /* TBDXXX -- do in ae531x_poll? */ /* Setup Transmit Descriptors */ MACInfo->txDescCount = AE531X_TX_DESC_COUNT_DEFAULT; MACInfo->pTxDescs = ae531xTxDescs; /* Setup Transmit buffer free list */ for (i=0; i<AE531X_TX_DESC_COUNT_DEFAULT; i++) { ae531xTxDataBuf[i].next = ae531xTxFreeList; ae531xTxFreeList = &ae531xTxDataBuf[i]; } ae531xTxAvail = AE531X_TX_DESC_COUNT_DEFAULT; /* Setup Receive Descriptors */ MACInfo->rxDescCount = AE531X_RX_DESC_COUNT_DEFAULT; MACInfo->pRxDescs = ae531xRxDescs; /* Setup Receive buffer free list */ for (i=0; i<AE531X_RX_DATA_BUF_COUNT; i++) { ae531xRxDataBuf[i].next = ae531xRxFreeList; ae531xRxFreeList = &ae531xRxDataBuf[i]; } /* Allocate RX/TX Queues */ if (ae531x_AllocateQueues(MACInfo) < 0) { AE531X_PRINT(AE531X_DEBUG_RESET, ("Queue allocation failed")); goto skip_start; } /* Initialize MAC */ ae531x_MACReset(MACInfo); /* Initialize DMA and descriptors */ ae531x_DmaReset(MACInfo); /* Enable Receive/Transmit */ ae531x_EnableComm(MACInfo); MACInfo->port_is_up = TRUE; skip_start: return 0; }