net: axienet: Clean up DMA start/stop and error handling
Simplify the DMA error handling process, and remove some duplicated code between the DMA error handling and the stop function. Signed-off-by: Robert Hancock <robert.hancock@calian.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
17882fd425
commit
84b9ccc074
@ -226,6 +226,44 @@ static void axienet_dma_bd_release(struct net_device *ndev)
|
|||||||
lp->rx_bd_p);
|
lp->rx_bd_p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* axienet_dma_start - Set up DMA registers and start DMA operation
|
||||||
|
* @lp: Pointer to the axienet_local structure
|
||||||
|
*/
|
||||||
|
static void axienet_dma_start(struct axienet_local *lp)
|
||||||
|
{
|
||||||
|
u32 rx_cr, tx_cr;
|
||||||
|
|
||||||
|
/* Start updating the Rx channel control register */
|
||||||
|
rx_cr = (lp->coalesce_count_rx << XAXIDMA_COALESCE_SHIFT) |
|
||||||
|
(XAXIDMA_DFT_RX_WAITBOUND << XAXIDMA_DELAY_SHIFT) |
|
||||||
|
XAXIDMA_IRQ_ALL_MASK;
|
||||||
|
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, rx_cr);
|
||||||
|
|
||||||
|
/* Start updating the Tx channel control register */
|
||||||
|
tx_cr = (lp->coalesce_count_tx << XAXIDMA_COALESCE_SHIFT) |
|
||||||
|
(XAXIDMA_DFT_TX_WAITBOUND << XAXIDMA_DELAY_SHIFT) |
|
||||||
|
XAXIDMA_IRQ_ALL_MASK;
|
||||||
|
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, tx_cr);
|
||||||
|
|
||||||
|
/* Populate the tail pointer and bring the Rx Axi DMA engine out of
|
||||||
|
* halted state. This will make the Rx side ready for reception.
|
||||||
|
*/
|
||||||
|
axienet_dma_out_addr(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p);
|
||||||
|
rx_cr |= XAXIDMA_CR_RUNSTOP_MASK;
|
||||||
|
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, rx_cr);
|
||||||
|
axienet_dma_out_addr(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p +
|
||||||
|
(sizeof(*lp->rx_bd_v) * (lp->rx_bd_num - 1)));
|
||||||
|
|
||||||
|
/* Write to the RS (Run-stop) bit in the Tx channel control register.
|
||||||
|
* Tx channel is now ready to run. But only after we write to the
|
||||||
|
* tail pointer register that the Tx channel will start transmitting.
|
||||||
|
*/
|
||||||
|
axienet_dma_out_addr(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p);
|
||||||
|
tx_cr |= XAXIDMA_CR_RUNSTOP_MASK;
|
||||||
|
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, tx_cr);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* axienet_dma_bd_init - Setup buffer descriptor rings for Axi DMA
|
* axienet_dma_bd_init - Setup buffer descriptor rings for Axi DMA
|
||||||
* @ndev: Pointer to the net_device structure
|
* @ndev: Pointer to the net_device structure
|
||||||
@ -238,7 +276,6 @@ static void axienet_dma_bd_release(struct net_device *ndev)
|
|||||||
*/
|
*/
|
||||||
static int axienet_dma_bd_init(struct net_device *ndev)
|
static int axienet_dma_bd_init(struct net_device *ndev)
|
||||||
{
|
{
|
||||||
u32 cr;
|
|
||||||
int i;
|
int i;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct axienet_local *lp = netdev_priv(ndev);
|
struct axienet_local *lp = netdev_priv(ndev);
|
||||||
@ -296,50 +333,7 @@ static int axienet_dma_bd_init(struct net_device *ndev)
|
|||||||
lp->rx_bd_v[i].cntrl = lp->max_frm_size;
|
lp->rx_bd_v[i].cntrl = lp->max_frm_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start updating the Rx channel control register */
|
axienet_dma_start(lp);
|
||||||
cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
|
|
||||||
/* Update the interrupt coalesce count */
|
|
||||||
cr = ((cr & ~XAXIDMA_COALESCE_MASK) |
|
|
||||||
((lp->coalesce_count_rx) << XAXIDMA_COALESCE_SHIFT));
|
|
||||||
/* Update the delay timer count */
|
|
||||||
cr = ((cr & ~XAXIDMA_DELAY_MASK) |
|
|
||||||
(XAXIDMA_DFT_RX_WAITBOUND << XAXIDMA_DELAY_SHIFT));
|
|
||||||
/* Enable coalesce, delay timer and error interrupts */
|
|
||||||
cr |= XAXIDMA_IRQ_ALL_MASK;
|
|
||||||
/* Write to the Rx channel control register */
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr);
|
|
||||||
|
|
||||||
/* Start updating the Tx channel control register */
|
|
||||||
cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
|
|
||||||
/* Update the interrupt coalesce count */
|
|
||||||
cr = (((cr & ~XAXIDMA_COALESCE_MASK)) |
|
|
||||||
((lp->coalesce_count_tx) << XAXIDMA_COALESCE_SHIFT));
|
|
||||||
/* Update the delay timer count */
|
|
||||||
cr = (((cr & ~XAXIDMA_DELAY_MASK)) |
|
|
||||||
(XAXIDMA_DFT_TX_WAITBOUND << XAXIDMA_DELAY_SHIFT));
|
|
||||||
/* Enable coalesce, delay timer and error interrupts */
|
|
||||||
cr |= XAXIDMA_IRQ_ALL_MASK;
|
|
||||||
/* Write to the Tx channel control register */
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr);
|
|
||||||
|
|
||||||
/* Populate the tail pointer and bring the Rx Axi DMA engine out of
|
|
||||||
* halted state. This will make the Rx side ready for reception.
|
|
||||||
*/
|
|
||||||
axienet_dma_out_addr(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p);
|
|
||||||
cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET,
|
|
||||||
cr | XAXIDMA_CR_RUNSTOP_MASK);
|
|
||||||
axienet_dma_out_addr(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p +
|
|
||||||
(sizeof(*lp->rx_bd_v) * (lp->rx_bd_num - 1)));
|
|
||||||
|
|
||||||
/* Write to the RS (Run-stop) bit in the Tx channel control register.
|
|
||||||
* Tx channel is now ready to run. But only after we write to the
|
|
||||||
* tail pointer register that the Tx channel will start transmitting.
|
|
||||||
*/
|
|
||||||
axienet_dma_out_addr(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p);
|
|
||||||
cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET,
|
|
||||||
cr | XAXIDMA_CR_RUNSTOP_MASK);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
out:
|
out:
|
||||||
@ -530,6 +524,44 @@ static int __axienet_device_reset(struct axienet_local *lp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* axienet_dma_stop - Stop DMA operation
|
||||||
|
* @lp: Pointer to the axienet_local structure
|
||||||
|
*/
|
||||||
|
static void axienet_dma_stop(struct axienet_local *lp)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
u32 cr, sr;
|
||||||
|
|
||||||
|
cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
|
||||||
|
cr &= ~(XAXIDMA_CR_RUNSTOP_MASK | XAXIDMA_IRQ_ALL_MASK);
|
||||||
|
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr);
|
||||||
|
synchronize_irq(lp->rx_irq);
|
||||||
|
|
||||||
|
cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
|
||||||
|
cr &= ~(XAXIDMA_CR_RUNSTOP_MASK | XAXIDMA_IRQ_ALL_MASK);
|
||||||
|
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr);
|
||||||
|
synchronize_irq(lp->tx_irq);
|
||||||
|
|
||||||
|
/* Give DMAs a chance to halt gracefully */
|
||||||
|
sr = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
|
||||||
|
for (count = 0; !(sr & XAXIDMA_SR_HALT_MASK) && count < 5; ++count) {
|
||||||
|
msleep(20);
|
||||||
|
sr = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
sr = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
|
||||||
|
for (count = 0; !(sr & XAXIDMA_SR_HALT_MASK) && count < 5; ++count) {
|
||||||
|
msleep(20);
|
||||||
|
sr = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do a reset to ensure DMA is really stopped */
|
||||||
|
axienet_lock_mii(lp);
|
||||||
|
__axienet_device_reset(lp);
|
||||||
|
axienet_unlock_mii(lp);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* axienet_device_reset - Reset and initialize the Axi Ethernet hardware.
|
* axienet_device_reset - Reset and initialize the Axi Ethernet hardware.
|
||||||
* @ndev: Pointer to the net_device structure
|
* @ndev: Pointer to the net_device structure
|
||||||
@ -949,41 +981,27 @@ static void axienet_recv(struct net_device *ndev)
|
|||||||
*/
|
*/
|
||||||
static irqreturn_t axienet_tx_irq(int irq, void *_ndev)
|
static irqreturn_t axienet_tx_irq(int irq, void *_ndev)
|
||||||
{
|
{
|
||||||
u32 cr;
|
|
||||||
unsigned int status;
|
unsigned int status;
|
||||||
struct net_device *ndev = _ndev;
|
struct net_device *ndev = _ndev;
|
||||||
struct axienet_local *lp = netdev_priv(ndev);
|
struct axienet_local *lp = netdev_priv(ndev);
|
||||||
|
|
||||||
status = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
|
status = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
|
||||||
if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) {
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status);
|
|
||||||
axienet_start_xmit_done(lp->ndev);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (!(status & XAXIDMA_IRQ_ALL_MASK))
|
if (!(status & XAXIDMA_IRQ_ALL_MASK))
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
if (status & XAXIDMA_IRQ_ERROR_MASK) {
|
|
||||||
dev_err(&ndev->dev, "DMA Tx error 0x%x\n", status);
|
|
||||||
dev_err(&ndev->dev, "Current BD is at: 0x%x%08x\n",
|
|
||||||
(lp->tx_bd_v[lp->tx_bd_ci]).phys_msb,
|
|
||||||
(lp->tx_bd_v[lp->tx_bd_ci]).phys);
|
|
||||||
|
|
||||||
cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
|
axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status);
|
||||||
/* Disable coalesce, delay timer and error interrupts */
|
|
||||||
cr &= (~XAXIDMA_IRQ_ALL_MASK);
|
|
||||||
/* Write to the Tx channel control register */
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr);
|
|
||||||
|
|
||||||
cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
|
|
||||||
/* Disable coalesce, delay timer and error interrupts */
|
|
||||||
cr &= (~XAXIDMA_IRQ_ALL_MASK);
|
|
||||||
/* Write to the Rx channel control register */
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr);
|
|
||||||
|
|
||||||
|
if (unlikely(status & XAXIDMA_IRQ_ERROR_MASK)) {
|
||||||
|
netdev_err(ndev, "DMA Tx error 0x%x\n", status);
|
||||||
|
netdev_err(ndev, "Current BD is at: 0x%x%08x\n",
|
||||||
|
(lp->tx_bd_v[lp->tx_bd_ci]).phys_msb,
|
||||||
|
(lp->tx_bd_v[lp->tx_bd_ci]).phys);
|
||||||
schedule_work(&lp->dma_err_task);
|
schedule_work(&lp->dma_err_task);
|
||||||
axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status);
|
} else {
|
||||||
|
axienet_start_xmit_done(lp->ndev);
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -999,41 +1017,27 @@ out:
|
|||||||
*/
|
*/
|
||||||
static irqreturn_t axienet_rx_irq(int irq, void *_ndev)
|
static irqreturn_t axienet_rx_irq(int irq, void *_ndev)
|
||||||
{
|
{
|
||||||
u32 cr;
|
|
||||||
unsigned int status;
|
unsigned int status;
|
||||||
struct net_device *ndev = _ndev;
|
struct net_device *ndev = _ndev;
|
||||||
struct axienet_local *lp = netdev_priv(ndev);
|
struct axienet_local *lp = netdev_priv(ndev);
|
||||||
|
|
||||||
status = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
|
status = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
|
||||||
if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) {
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status);
|
|
||||||
axienet_recv(lp->ndev);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (!(status & XAXIDMA_IRQ_ALL_MASK))
|
if (!(status & XAXIDMA_IRQ_ALL_MASK))
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
if (status & XAXIDMA_IRQ_ERROR_MASK) {
|
|
||||||
dev_err(&ndev->dev, "DMA Rx error 0x%x\n", status);
|
|
||||||
dev_err(&ndev->dev, "Current BD is at: 0x%x%08x\n",
|
|
||||||
(lp->rx_bd_v[lp->rx_bd_ci]).phys_msb,
|
|
||||||
(lp->rx_bd_v[lp->rx_bd_ci]).phys);
|
|
||||||
|
|
||||||
cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
|
axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status);
|
||||||
/* Disable coalesce, delay timer and error interrupts */
|
|
||||||
cr &= (~XAXIDMA_IRQ_ALL_MASK);
|
|
||||||
/* Finally write to the Tx channel control register */
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr);
|
|
||||||
|
|
||||||
cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
|
|
||||||
/* Disable coalesce, delay timer and error interrupts */
|
|
||||||
cr &= (~XAXIDMA_IRQ_ALL_MASK);
|
|
||||||
/* write to the Rx channel control register */
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr);
|
|
||||||
|
|
||||||
|
if (unlikely(status & XAXIDMA_IRQ_ERROR_MASK)) {
|
||||||
|
netdev_err(ndev, "DMA Rx error 0x%x\n", status);
|
||||||
|
netdev_err(ndev, "Current BD is at: 0x%x%08x\n",
|
||||||
|
(lp->rx_bd_v[lp->rx_bd_ci]).phys_msb,
|
||||||
|
(lp->rx_bd_v[lp->rx_bd_ci]).phys);
|
||||||
schedule_work(&lp->dma_err_task);
|
schedule_work(&lp->dma_err_task);
|
||||||
axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status);
|
} else {
|
||||||
|
axienet_recv(lp->ndev);
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1151,8 +1155,6 @@ err_tx_irq:
|
|||||||
*/
|
*/
|
||||||
static int axienet_stop(struct net_device *ndev)
|
static int axienet_stop(struct net_device *ndev)
|
||||||
{
|
{
|
||||||
u32 cr, sr;
|
|
||||||
int count;
|
|
||||||
struct axienet_local *lp = netdev_priv(ndev);
|
struct axienet_local *lp = netdev_priv(ndev);
|
||||||
|
|
||||||
dev_dbg(&ndev->dev, "axienet_close()\n");
|
dev_dbg(&ndev->dev, "axienet_close()\n");
|
||||||
@ -1163,34 +1165,10 @@ static int axienet_stop(struct net_device *ndev)
|
|||||||
axienet_setoptions(ndev, lp->options &
|
axienet_setoptions(ndev, lp->options &
|
||||||
~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
|
~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
|
||||||
|
|
||||||
cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
|
axienet_dma_stop(lp);
|
||||||
cr &= ~(XAXIDMA_CR_RUNSTOP_MASK | XAXIDMA_IRQ_ALL_MASK);
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr);
|
|
||||||
|
|
||||||
cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
|
|
||||||
cr &= ~(XAXIDMA_CR_RUNSTOP_MASK | XAXIDMA_IRQ_ALL_MASK);
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr);
|
|
||||||
|
|
||||||
axienet_iow(lp, XAE_IE_OFFSET, 0);
|
axienet_iow(lp, XAE_IE_OFFSET, 0);
|
||||||
|
|
||||||
/* Give DMAs a chance to halt gracefully */
|
|
||||||
sr = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
|
|
||||||
for (count = 0; !(sr & XAXIDMA_SR_HALT_MASK) && count < 5; ++count) {
|
|
||||||
msleep(20);
|
|
||||||
sr = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
|
|
||||||
}
|
|
||||||
|
|
||||||
sr = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
|
|
||||||
for (count = 0; !(sr & XAXIDMA_SR_HALT_MASK) && count < 5; ++count) {
|
|
||||||
msleep(20);
|
|
||||||
sr = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do a reset to ensure DMA is really stopped */
|
|
||||||
axienet_lock_mii(lp);
|
|
||||||
__axienet_device_reset(lp);
|
|
||||||
axienet_unlock_mii(lp);
|
|
||||||
|
|
||||||
cancel_work_sync(&lp->dma_err_task);
|
cancel_work_sync(&lp->dma_err_task);
|
||||||
|
|
||||||
if (lp->eth_irq > 0)
|
if (lp->eth_irq > 0)
|
||||||
@ -1690,22 +1668,17 @@ static const struct phylink_mac_ops axienet_phylink_ops = {
|
|||||||
*/
|
*/
|
||||||
static void axienet_dma_err_handler(struct work_struct *work)
|
static void axienet_dma_err_handler(struct work_struct *work)
|
||||||
{
|
{
|
||||||
|
u32 i;
|
||||||
u32 axienet_status;
|
u32 axienet_status;
|
||||||
u32 cr, i;
|
struct axidma_bd *cur_p;
|
||||||
struct axienet_local *lp = container_of(work, struct axienet_local,
|
struct axienet_local *lp = container_of(work, struct axienet_local,
|
||||||
dma_err_task);
|
dma_err_task);
|
||||||
struct net_device *ndev = lp->ndev;
|
struct net_device *ndev = lp->ndev;
|
||||||
struct axidma_bd *cur_p;
|
|
||||||
|
|
||||||
axienet_setoptions(ndev, lp->options &
|
axienet_setoptions(ndev, lp->options &
|
||||||
~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
|
~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
|
||||||
/* When we do an Axi Ethernet reset, it resets the complete core
|
|
||||||
* including the MDIO. MDIO must be disabled before resetting.
|
axienet_dma_stop(lp);
|
||||||
* Hold MDIO bus lock to avoid MDIO accesses during the reset.
|
|
||||||
*/
|
|
||||||
axienet_lock_mii(lp);
|
|
||||||
__axienet_device_reset(lp);
|
|
||||||
axienet_unlock_mii(lp);
|
|
||||||
|
|
||||||
for (i = 0; i < lp->tx_bd_num; i++) {
|
for (i = 0; i < lp->tx_bd_num; i++) {
|
||||||
cur_p = &lp->tx_bd_v[i];
|
cur_p = &lp->tx_bd_v[i];
|
||||||
@ -1745,50 +1718,7 @@ static void axienet_dma_err_handler(struct work_struct *work)
|
|||||||
lp->tx_bd_tail = 0;
|
lp->tx_bd_tail = 0;
|
||||||
lp->rx_bd_ci = 0;
|
lp->rx_bd_ci = 0;
|
||||||
|
|
||||||
/* Start updating the Rx channel control register */
|
axienet_dma_start(lp);
|
||||||
cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
|
|
||||||
/* Update the interrupt coalesce count */
|
|
||||||
cr = ((cr & ~XAXIDMA_COALESCE_MASK) |
|
|
||||||
(XAXIDMA_DFT_RX_THRESHOLD << XAXIDMA_COALESCE_SHIFT));
|
|
||||||
/* Update the delay timer count */
|
|
||||||
cr = ((cr & ~XAXIDMA_DELAY_MASK) |
|
|
||||||
(XAXIDMA_DFT_RX_WAITBOUND << XAXIDMA_DELAY_SHIFT));
|
|
||||||
/* Enable coalesce, delay timer and error interrupts */
|
|
||||||
cr |= XAXIDMA_IRQ_ALL_MASK;
|
|
||||||
/* Finally write to the Rx channel control register */
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr);
|
|
||||||
|
|
||||||
/* Start updating the Tx channel control register */
|
|
||||||
cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
|
|
||||||
/* Update the interrupt coalesce count */
|
|
||||||
cr = (((cr & ~XAXIDMA_COALESCE_MASK)) |
|
|
||||||
(XAXIDMA_DFT_TX_THRESHOLD << XAXIDMA_COALESCE_SHIFT));
|
|
||||||
/* Update the delay timer count */
|
|
||||||
cr = (((cr & ~XAXIDMA_DELAY_MASK)) |
|
|
||||||
(XAXIDMA_DFT_TX_WAITBOUND << XAXIDMA_DELAY_SHIFT));
|
|
||||||
/* Enable coalesce, delay timer and error interrupts */
|
|
||||||
cr |= XAXIDMA_IRQ_ALL_MASK;
|
|
||||||
/* Finally write to the Tx channel control register */
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr);
|
|
||||||
|
|
||||||
/* Populate the tail pointer and bring the Rx Axi DMA engine out of
|
|
||||||
* halted state. This will make the Rx side ready for reception.
|
|
||||||
*/
|
|
||||||
axienet_dma_out_addr(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p);
|
|
||||||
cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET,
|
|
||||||
cr | XAXIDMA_CR_RUNSTOP_MASK);
|
|
||||||
axienet_dma_out_addr(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p +
|
|
||||||
(sizeof(*lp->rx_bd_v) * (lp->rx_bd_num - 1)));
|
|
||||||
|
|
||||||
/* Write to the RS (Run-stop) bit in the Tx channel control register.
|
|
||||||
* Tx channel is now ready to run. But only after we write to the
|
|
||||||
* tail pointer register that the Tx channel will start transmitting
|
|
||||||
*/
|
|
||||||
axienet_dma_out_addr(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p);
|
|
||||||
cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
|
|
||||||
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET,
|
|
||||||
cr | XAXIDMA_CR_RUNSTOP_MASK);
|
|
||||||
|
|
||||||
axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET);
|
axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET);
|
||||||
axienet_status &= ~XAE_RCW1_RX_MASK;
|
axienet_status &= ~XAE_RCW1_RX_MASK;
|
||||||
|
Loading…
Reference in New Issue
Block a user