Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,15 @@
# SPDX-License-Identifier: GPL-2.0-only
config ALTERA_TSE
tristate "Altera Triple-Speed Ethernet MAC support"
depends on HAS_DMA
depends on HAS_IOMEM
select PHYLIB
select PHYLINK
select PCS_LYNX
select MDIO_REGMAP
select REGMAP_MMIO
help
This driver supports the Altera Triple-Speed (TSE) Ethernet MAC.
To compile this driver as a module, choose M here. The module
will be called alteratse.
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the Altera device drivers.
#
obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
altera_tse-objs := altera_tse_main.o altera_tse_ethtool.o \
altera_msgdma.o altera_sgdma.o altera_utils.o
@@ -0,0 +1,196 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Altera TSE SGDMA and MSGDMA Linux driver
* Copyright (C) 2014 Altera Corporation. All rights reserved
*/
#include <linux/netdevice.h>
#include "altera_utils.h"
#include "altera_tse.h"
#include "altera_msgdmahw.h"
#include "altera_msgdma.h"
/* No initialization work to do for MSGDMA */
int msgdma_initialize(struct altera_tse_private *priv)
{
return 0;
}
void msgdma_uninitialize(struct altera_tse_private *priv)
{
}
void msgdma_start_rxdma(struct altera_tse_private *priv)
{
}
void msgdma_reset(struct altera_tse_private *priv)
{
int counter;
/* Reset Rx mSGDMA */
csrwr32(MSGDMA_CSR_STAT_MASK, priv->rx_dma_csr,
msgdma_csroffs(status));
csrwr32(MSGDMA_CSR_CTL_RESET, priv->rx_dma_csr,
msgdma_csroffs(control));
counter = 0;
while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
if (tse_bit_is_clear(priv->rx_dma_csr, msgdma_csroffs(status),
MSGDMA_CSR_STAT_RESETTING))
break;
udelay(1);
}
if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR)
netif_warn(priv, drv, priv->dev,
"TSE Rx mSGDMA resetting bit never cleared!\n");
/* clear all status bits */
csrwr32(MSGDMA_CSR_STAT_MASK, priv->rx_dma_csr, msgdma_csroffs(status));
/* Reset Tx mSGDMA */
csrwr32(MSGDMA_CSR_STAT_MASK, priv->tx_dma_csr,
msgdma_csroffs(status));
csrwr32(MSGDMA_CSR_CTL_RESET, priv->tx_dma_csr,
msgdma_csroffs(control));
counter = 0;
while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
if (tse_bit_is_clear(priv->tx_dma_csr, msgdma_csroffs(status),
MSGDMA_CSR_STAT_RESETTING))
break;
udelay(1);
}
if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR)
netif_warn(priv, drv, priv->dev,
"TSE Tx mSGDMA resetting bit never cleared!\n");
/* clear all status bits */
csrwr32(MSGDMA_CSR_STAT_MASK, priv->tx_dma_csr, msgdma_csroffs(status));
}
void msgdma_disable_rxirq(struct altera_tse_private *priv)
{
tse_clear_bit(priv->rx_dma_csr, msgdma_csroffs(control),
MSGDMA_CSR_CTL_GLOBAL_INTR);
}
void msgdma_enable_rxirq(struct altera_tse_private *priv)
{
tse_set_bit(priv->rx_dma_csr, msgdma_csroffs(control),
MSGDMA_CSR_CTL_GLOBAL_INTR);
}
void msgdma_disable_txirq(struct altera_tse_private *priv)
{
tse_clear_bit(priv->tx_dma_csr, msgdma_csroffs(control),
MSGDMA_CSR_CTL_GLOBAL_INTR);
}
void msgdma_enable_txirq(struct altera_tse_private *priv)
{
tse_set_bit(priv->tx_dma_csr, msgdma_csroffs(control),
MSGDMA_CSR_CTL_GLOBAL_INTR);
}
void msgdma_clear_rxirq(struct altera_tse_private *priv)
{
csrwr32(MSGDMA_CSR_STAT_IRQ, priv->rx_dma_csr, msgdma_csroffs(status));
}
void msgdma_clear_txirq(struct altera_tse_private *priv)
{
csrwr32(MSGDMA_CSR_STAT_IRQ, priv->tx_dma_csr, msgdma_csroffs(status));
}
/* return 0 to indicate transmit is pending */
int msgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer)
{
csrwr32(lower_32_bits(buffer->dma_addr), priv->tx_dma_desc,
msgdma_descroffs(read_addr_lo));
csrwr32(upper_32_bits(buffer->dma_addr), priv->tx_dma_desc,
msgdma_descroffs(read_addr_hi));
csrwr32(0, priv->tx_dma_desc, msgdma_descroffs(write_addr_lo));
csrwr32(0, priv->tx_dma_desc, msgdma_descroffs(write_addr_hi));
csrwr32(buffer->len, priv->tx_dma_desc, msgdma_descroffs(len));
csrwr32(0, priv->tx_dma_desc, msgdma_descroffs(burst_seq_num));
csrwr32(MSGDMA_DESC_TX_STRIDE, priv->tx_dma_desc,
msgdma_descroffs(stride));
csrwr32(MSGDMA_DESC_CTL_TX_SINGLE, priv->tx_dma_desc,
msgdma_descroffs(control));
return 0;
}
u32 msgdma_tx_completions(struct altera_tse_private *priv)
{
u32 ready = 0;
u32 inuse;
u32 status;
/* Get number of sent descriptors */
inuse = csrrd32(priv->tx_dma_csr, msgdma_csroffs(rw_fill_level))
& 0xffff;
if (inuse) { /* Tx FIFO is not empty */
ready = max_t(int,
priv->tx_prod - priv->tx_cons - inuse - 1, 0);
} else {
/* Check for buffered last packet */
status = csrrd32(priv->tx_dma_csr, msgdma_csroffs(status));
if (status & MSGDMA_CSR_STAT_BUSY)
ready = priv->tx_prod - priv->tx_cons - 1;
else
ready = priv->tx_prod - priv->tx_cons;
}
return ready;
}
/* Put buffer to the mSGDMA RX FIFO
*/
void msgdma_add_rx_desc(struct altera_tse_private *priv,
struct tse_buffer *rxbuffer)
{
u32 len = priv->rx_dma_buf_sz;
dma_addr_t dma_addr = rxbuffer->dma_addr;
u32 control = (MSGDMA_DESC_CTL_END_ON_EOP
| MSGDMA_DESC_CTL_END_ON_LEN
| MSGDMA_DESC_CTL_TR_COMP_IRQ
| MSGDMA_DESC_CTL_EARLY_IRQ
| MSGDMA_DESC_CTL_TR_ERR_IRQ
| MSGDMA_DESC_CTL_GO);
csrwr32(0, priv->rx_dma_desc, msgdma_descroffs(read_addr_lo));
csrwr32(0, priv->rx_dma_desc, msgdma_descroffs(read_addr_hi));
csrwr32(lower_32_bits(dma_addr), priv->rx_dma_desc,
msgdma_descroffs(write_addr_lo));
csrwr32(upper_32_bits(dma_addr), priv->rx_dma_desc,
msgdma_descroffs(write_addr_hi));
csrwr32(len, priv->rx_dma_desc, msgdma_descroffs(len));
csrwr32(0, priv->rx_dma_desc, msgdma_descroffs(burst_seq_num));
csrwr32(0x00010001, priv->rx_dma_desc, msgdma_descroffs(stride));
csrwr32(control, priv->rx_dma_desc, msgdma_descroffs(control));
}
/* status is returned on upper 16 bits,
* length is returned in lower 16 bits
*/
u32 msgdma_rx_status(struct altera_tse_private *priv)
{
u32 rxstatus = 0;
u32 pktlength;
u32 pktstatus;
if (csrrd32(priv->rx_dma_csr, msgdma_csroffs(resp_fill_level))
& 0xffff) {
pktlength = csrrd32(priv->rx_dma_resp,
msgdma_respoffs(bytes_transferred));
pktstatus = csrrd32(priv->rx_dma_resp,
msgdma_respoffs(status));
rxstatus = pktstatus;
rxstatus = rxstatus << 16;
rxstatus |= (pktlength & 0xffff);
}
return rxstatus;
}
@@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Altera TSE SGDMA and MSGDMA Linux driver
* Copyright (C) 2014 Altera Corporation. All rights reserved
*/
#ifndef __ALTERA_MSGDMA_H__
#define __ALTERA_MSGDMA_H__
void msgdma_reset(struct altera_tse_private *);
void msgdma_enable_txirq(struct altera_tse_private *);
void msgdma_enable_rxirq(struct altera_tse_private *);
void msgdma_disable_rxirq(struct altera_tse_private *);
void msgdma_disable_txirq(struct altera_tse_private *);
void msgdma_clear_rxirq(struct altera_tse_private *);
void msgdma_clear_txirq(struct altera_tse_private *);
u32 msgdma_tx_completions(struct altera_tse_private *);
void msgdma_add_rx_desc(struct altera_tse_private *, struct tse_buffer *);
int msgdma_tx_buffer(struct altera_tse_private *, struct tse_buffer *);
u32 msgdma_rx_status(struct altera_tse_private *);
int msgdma_initialize(struct altera_tse_private *);
void msgdma_uninitialize(struct altera_tse_private *);
void msgdma_start_rxdma(struct altera_tse_private *);
#endif /* __ALTERA_MSGDMA_H__ */
@@ -0,0 +1,147 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Altera TSE SGDMA and MSGDMA Linux driver
* Copyright (C) 2014 Altera Corporation. All rights reserved
*/
#ifndef __ALTERA_MSGDMAHW_H__
#define __ALTERA_MSGDMAHW_H__
/* mSGDMA extended descriptor format
*/
struct msgdma_extended_desc {
u32 read_addr_lo; /* data buffer source address low bits */
u32 write_addr_lo; /* data buffer destination address low bits */
u32 len; /* the number of bytes to transfer
* per descriptor
*/
u32 burst_seq_num; /* bit 31:24 write burst
* bit 23:16 read burst
* bit 15:0 sequence number
*/
u32 stride; /* bit 31:16 write stride
* bit 15:0 read stride
*/
u32 read_addr_hi; /* data buffer source address high bits */
u32 write_addr_hi; /* data buffer destination address high bits */
u32 control; /* characteristics of the transfer */
};
/* mSGDMA descriptor control field bit definitions
*/
#define MSGDMA_DESC_CTL_SET_CH(x) ((x) & 0xff)
#define MSGDMA_DESC_CTL_GEN_SOP BIT(8)
#define MSGDMA_DESC_CTL_GEN_EOP BIT(9)
#define MSGDMA_DESC_CTL_PARK_READS BIT(10)
#define MSGDMA_DESC_CTL_PARK_WRITES BIT(11)
#define MSGDMA_DESC_CTL_END_ON_EOP BIT(12)
#define MSGDMA_DESC_CTL_END_ON_LEN BIT(13)
#define MSGDMA_DESC_CTL_TR_COMP_IRQ BIT(14)
#define MSGDMA_DESC_CTL_EARLY_IRQ BIT(15)
#define MSGDMA_DESC_CTL_TR_ERR_IRQ (0xff << 16)
#define MSGDMA_DESC_CTL_EARLY_DONE BIT(24)
/* Writing ‘1’ to the ‘go’ bit commits the entire descriptor into the
* descriptor FIFO(s)
*/
#define MSGDMA_DESC_CTL_GO BIT(31)
/* Tx buffer control flags
*/
#define MSGDMA_DESC_CTL_TX_FIRST (MSGDMA_DESC_CTL_GEN_SOP | \
MSGDMA_DESC_CTL_GO)
#define MSGDMA_DESC_CTL_TX_MIDDLE (MSGDMA_DESC_CTL_GO)
#define MSGDMA_DESC_CTL_TX_LAST (MSGDMA_DESC_CTL_GEN_EOP | \
MSGDMA_DESC_CTL_TR_COMP_IRQ | \
MSGDMA_DESC_CTL_GO)
#define MSGDMA_DESC_CTL_TX_SINGLE (MSGDMA_DESC_CTL_GEN_SOP | \
MSGDMA_DESC_CTL_GEN_EOP | \
MSGDMA_DESC_CTL_TR_COMP_IRQ | \
MSGDMA_DESC_CTL_GO)
#define MSGDMA_DESC_CTL_RX_SINGLE (MSGDMA_DESC_CTL_END_ON_EOP | \
MSGDMA_DESC_CTL_END_ON_LEN | \
MSGDMA_DESC_CTL_TR_COMP_IRQ | \
MSGDMA_DESC_CTL_EARLY_IRQ | \
MSGDMA_DESC_CTL_TR_ERR_IRQ | \
MSGDMA_DESC_CTL_GO)
/* mSGDMA extended descriptor stride definitions
*/
#define MSGDMA_DESC_TX_STRIDE (0x00010001)
#define MSGDMA_DESC_RX_STRIDE (0x00010001)
/* mSGDMA dispatcher control and status register map
*/
struct msgdma_csr {
u32 status; /* Read/Clear */
u32 control; /* Read/Write */
u32 rw_fill_level; /* bit 31:16 - write fill level
* bit 15:0 - read fill level
*/
u32 resp_fill_level; /* bit 15:0 */
u32 rw_seq_num; /* bit 31:16 - write sequence number
* bit 15:0 - read sequence number
*/
u32 pad[3]; /* reserved */
};
/* mSGDMA CSR status register bit definitions
*/
#define MSGDMA_CSR_STAT_BUSY BIT(0)
#define MSGDMA_CSR_STAT_DESC_BUF_EMPTY BIT(1)
#define MSGDMA_CSR_STAT_DESC_BUF_FULL BIT(2)
#define MSGDMA_CSR_STAT_RESP_BUF_EMPTY BIT(3)
#define MSGDMA_CSR_STAT_RESP_BUF_FULL BIT(4)
#define MSGDMA_CSR_STAT_STOPPED BIT(5)
#define MSGDMA_CSR_STAT_RESETTING BIT(6)
#define MSGDMA_CSR_STAT_STOPPED_ON_ERR BIT(7)
#define MSGDMA_CSR_STAT_STOPPED_ON_EARLY BIT(8)
#define MSGDMA_CSR_STAT_IRQ BIT(9)
#define MSGDMA_CSR_STAT_MASK 0x3FF
#define MSGDMA_CSR_STAT_MASK_WITHOUT_IRQ 0x1FF
#define MSGDMA_CSR_STAT_BUSY_GET(v) GET_BIT_VALUE(v, 0)
#define MSGDMA_CSR_STAT_DESC_BUF_EMPTY_GET(v) GET_BIT_VALUE(v, 1)
#define MSGDMA_CSR_STAT_DESC_BUF_FULL_GET(v) GET_BIT_VALUE(v, 2)
#define MSGDMA_CSR_STAT_RESP_BUF_EMPTY_GET(v) GET_BIT_VALUE(v, 3)
#define MSGDMA_CSR_STAT_RESP_BUF_FULL_GET(v) GET_BIT_VALUE(v, 4)
#define MSGDMA_CSR_STAT_STOPPED_GET(v) GET_BIT_VALUE(v, 5)
#define MSGDMA_CSR_STAT_RESETTING_GET(v) GET_BIT_VALUE(v, 6)
#define MSGDMA_CSR_STAT_STOPPED_ON_ERR_GET(v) GET_BIT_VALUE(v, 7)
#define MSGDMA_CSR_STAT_STOPPED_ON_EARLY_GET(v) GET_BIT_VALUE(v, 8)
#define MSGDMA_CSR_STAT_IRQ_GET(v) GET_BIT_VALUE(v, 9)
/* mSGDMA CSR control register bit definitions
*/
#define MSGDMA_CSR_CTL_STOP BIT(0)
#define MSGDMA_CSR_CTL_RESET BIT(1)
#define MSGDMA_CSR_CTL_STOP_ON_ERR BIT(2)
#define MSGDMA_CSR_CTL_STOP_ON_EARLY BIT(3)
#define MSGDMA_CSR_CTL_GLOBAL_INTR BIT(4)
#define MSGDMA_CSR_CTL_STOP_DESCS BIT(5)
/* mSGDMA CSR fill level bits
*/
#define MSGDMA_CSR_WR_FILL_LEVEL_GET(v) (((v) & 0xffff0000) >> 16)
#define MSGDMA_CSR_RD_FILL_LEVEL_GET(v) ((v) & 0x0000ffff)
#define MSGDMA_CSR_RESP_FILL_LEVEL_GET(v) ((v) & 0x0000ffff)
/* mSGDMA response register map
*/
struct msgdma_response {
u32 bytes_transferred;
u32 status;
};
#define msgdma_respoffs(a) (offsetof(struct msgdma_response, a))
#define msgdma_csroffs(a) (offsetof(struct msgdma_csr, a))
#define msgdma_descroffs(a) (offsetof(struct msgdma_extended_desc, a))
/* mSGDMA response register bit definitions
*/
#define MSGDMA_RESP_EARLY_TERM BIT(8)
#define MSGDMA_RESP_ERR_MASK 0xFF
#endif /* __ALTERA_MSGDMA_H__*/
@@ -0,0 +1,527 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Altera TSE SGDMA and MSGDMA Linux driver
* Copyright (C) 2014 Altera Corporation. All rights reserved
*/
#include <linux/list.h>
#include "altera_utils.h"
#include "altera_tse.h"
#include "altera_sgdmahw.h"
#include "altera_sgdma.h"
static void sgdma_setup_descrip(struct sgdma_descrip __iomem *desc,
struct sgdma_descrip __iomem *ndesc,
dma_addr_t ndesc_phys,
dma_addr_t raddr,
dma_addr_t waddr,
u16 length,
int generate_eop,
int rfixed,
int wfixed);
static int sgdma_async_write(struct altera_tse_private *priv,
struct sgdma_descrip __iomem *desc);
static int sgdma_async_read(struct altera_tse_private *priv);
static dma_addr_t
sgdma_txphysaddr(struct altera_tse_private *priv,
struct sgdma_descrip __iomem *desc);
static dma_addr_t
sgdma_rxphysaddr(struct altera_tse_private *priv,
struct sgdma_descrip __iomem *desc);
static int sgdma_txbusy(struct altera_tse_private *priv);
static int sgdma_rxbusy(struct altera_tse_private *priv);
static void
queue_tx(struct altera_tse_private *priv, struct tse_buffer *buffer);
static void
queue_rx(struct altera_tse_private *priv, struct tse_buffer *buffer);
static struct tse_buffer *
dequeue_tx(struct altera_tse_private *priv);
static struct tse_buffer *
dequeue_rx(struct altera_tse_private *priv);
static struct tse_buffer *
queue_rx_peekhead(struct altera_tse_private *priv);
int sgdma_initialize(struct altera_tse_private *priv)
{
priv->txctrlreg = SGDMA_CTRLREG_ILASTD |
SGDMA_CTRLREG_INTEN;
priv->rxctrlreg = SGDMA_CTRLREG_IDESCRIP |
SGDMA_CTRLREG_INTEN |
SGDMA_CTRLREG_ILASTD;
INIT_LIST_HEAD(&priv->txlisthd);
INIT_LIST_HEAD(&priv->rxlisthd);
priv->rxdescphys = (dma_addr_t) 0;
priv->txdescphys = (dma_addr_t) 0;
priv->rxdescphys = dma_map_single(priv->device,
(void __force *)priv->rx_dma_desc,
priv->rxdescmem, DMA_BIDIRECTIONAL);
if (dma_mapping_error(priv->device, priv->rxdescphys)) {
sgdma_uninitialize(priv);
netdev_err(priv->dev, "error mapping rx descriptor memory\n");
return -EINVAL;
}
priv->txdescphys = dma_map_single(priv->device,
(void __force *)priv->tx_dma_desc,
priv->txdescmem, DMA_TO_DEVICE);
if (dma_mapping_error(priv->device, priv->txdescphys)) {
sgdma_uninitialize(priv);
netdev_err(priv->dev, "error mapping tx descriptor memory\n");
return -EINVAL;
}
/* Initialize descriptor memory to all 0's, sync memory to cache */
memset_io(priv->tx_dma_desc, 0, priv->txdescmem);
memset_io(priv->rx_dma_desc, 0, priv->rxdescmem);
dma_sync_single_for_device(priv->device, priv->txdescphys,
priv->txdescmem, DMA_TO_DEVICE);
dma_sync_single_for_device(priv->device, priv->rxdescphys,
priv->rxdescmem, DMA_TO_DEVICE);
return 0;
}
void sgdma_uninitialize(struct altera_tse_private *priv)
{
if (priv->rxdescphys)
dma_unmap_single(priv->device, priv->rxdescphys,
priv->rxdescmem, DMA_BIDIRECTIONAL);
if (priv->txdescphys)
dma_unmap_single(priv->device, priv->txdescphys,
priv->txdescmem, DMA_TO_DEVICE);
}
/* This function resets the SGDMA controller and clears the
* descriptor memory used for transmits and receives.
*/
void sgdma_reset(struct altera_tse_private *priv)
{
/* Initialize descriptor memory to 0 */
memset_io(priv->tx_dma_desc, 0, priv->txdescmem);
memset_io(priv->rx_dma_desc, 0, priv->rxdescmem);
csrwr32(SGDMA_CTRLREG_RESET, priv->tx_dma_csr, sgdma_csroffs(control));
csrwr32(0, priv->tx_dma_csr, sgdma_csroffs(control));
csrwr32(SGDMA_CTRLREG_RESET, priv->rx_dma_csr, sgdma_csroffs(control));
csrwr32(0, priv->rx_dma_csr, sgdma_csroffs(control));
}
/* For SGDMA, interrupts remain enabled after initially enabling,
* so no need to provide implementations for abstract enable
* and disable
*/
void sgdma_enable_rxirq(struct altera_tse_private *priv)
{
}
void sgdma_enable_txirq(struct altera_tse_private *priv)
{
}
void sgdma_disable_rxirq(struct altera_tse_private *priv)
{
}
void sgdma_disable_txirq(struct altera_tse_private *priv)
{
}
void sgdma_clear_rxirq(struct altera_tse_private *priv)
{
tse_set_bit(priv->rx_dma_csr, sgdma_csroffs(control),
SGDMA_CTRLREG_CLRINT);
}
void sgdma_clear_txirq(struct altera_tse_private *priv)
{
tse_set_bit(priv->tx_dma_csr, sgdma_csroffs(control),
SGDMA_CTRLREG_CLRINT);
}
/* transmits buffer through SGDMA. Returns number of buffers
* transmitted, 0 if not possible.
*
* tx_lock is held by the caller
*/
int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer)
{
struct sgdma_descrip __iomem *descbase =
(struct sgdma_descrip __iomem *)priv->tx_dma_desc;
struct sgdma_descrip __iomem *cdesc = &descbase[0];
struct sgdma_descrip __iomem *ndesc = &descbase[1];
/* wait 'til the tx sgdma is ready for the next transmit request */
if (sgdma_txbusy(priv))
return 0;
sgdma_setup_descrip(cdesc, /* current descriptor */
ndesc, /* next descriptor */
sgdma_txphysaddr(priv, ndesc),
buffer->dma_addr, /* address of packet to xmit */
0, /* write addr 0 for tx dma */
buffer->len, /* length of packet */
SGDMA_CONTROL_EOP, /* Generate EOP */
0, /* read fixed */
SGDMA_CONTROL_WR_FIXED); /* Generate SOP */
sgdma_async_write(priv, cdesc);
/* enqueue the request to the pending transmit queue */
queue_tx(priv, buffer);
return 1;
}
/* tx_lock held to protect access to queued tx list
*/
u32 sgdma_tx_completions(struct altera_tse_private *priv)
{
u32 ready = 0;
if (!sgdma_txbusy(priv) &&
((csrrd8(priv->tx_dma_desc, sgdma_descroffs(control))
& SGDMA_CONTROL_HW_OWNED) == 0) &&
(dequeue_tx(priv))) {
ready = 1;
}
return ready;
}
void sgdma_start_rxdma(struct altera_tse_private *priv)
{
sgdma_async_read(priv);
}
void sgdma_add_rx_desc(struct altera_tse_private *priv,
struct tse_buffer *rxbuffer)
{
queue_rx(priv, rxbuffer);
}
/* status is returned on upper 16 bits,
* length is returned in lower 16 bits
*/
u32 sgdma_rx_status(struct altera_tse_private *priv)
{
struct sgdma_descrip __iomem *base =
(struct sgdma_descrip __iomem *)priv->rx_dma_desc;
struct sgdma_descrip __iomem *desc = NULL;
struct tse_buffer *rxbuffer = NULL;
unsigned int rxstatus = 0;
u32 sts = csrrd32(priv->rx_dma_csr, sgdma_csroffs(status));
desc = &base[0];
if (sts & SGDMA_STSREG_EOP) {
unsigned int pktlength = 0;
unsigned int pktstatus = 0;
dma_sync_single_for_cpu(priv->device,
priv->rxdescphys,
SGDMA_DESC_LEN,
DMA_FROM_DEVICE);
pktlength = csrrd16(desc, sgdma_descroffs(bytes_xferred));
pktstatus = csrrd8(desc, sgdma_descroffs(status));
rxstatus = pktstatus & ~SGDMA_STATUS_EOP;
rxstatus = rxstatus << 16;
rxstatus |= (pktlength & 0xffff);
if (rxstatus) {
csrwr8(0, desc, sgdma_descroffs(status));
rxbuffer = dequeue_rx(priv);
if (rxbuffer == NULL)
netdev_info(priv->dev,
"sgdma rx and rx queue empty!\n");
/* Clear control */
csrwr32(0, priv->rx_dma_csr, sgdma_csroffs(control));
/* clear status */
csrwr32(0xf, priv->rx_dma_csr, sgdma_csroffs(status));
/* kick the rx sgdma after reaping this descriptor */
sgdma_async_read(priv);
} else {
/* If the SGDMA indicated an end of packet on recv,
* then it's expected that the rxstatus from the
* descriptor is non-zero - meaning a valid packet
* with a nonzero length, or an error has been
* indicated. if not, then all we can do is signal
* an error and return no packet received. Most likely
* there is a system design error, or an error in the
* underlying kernel (cache or cache management problem)
*/
netdev_err(priv->dev,
"SGDMA RX Error Info: %x, %x, %x\n",
sts, csrrd8(desc, sgdma_descroffs(status)),
rxstatus);
}
} else if (sts == 0) {
sgdma_async_read(priv);
}
return rxstatus;
}
/* Private functions */
static void sgdma_setup_descrip(struct sgdma_descrip __iomem *desc,
struct sgdma_descrip __iomem *ndesc,
dma_addr_t ndesc_phys,
dma_addr_t raddr,
dma_addr_t waddr,
u16 length,
int generate_eop,
int rfixed,
int wfixed)
{
/* Clear the next descriptor as not owned by hardware */
u32 ctrl = csrrd8(ndesc, sgdma_descroffs(control));
ctrl &= ~SGDMA_CONTROL_HW_OWNED;
csrwr8(ctrl, ndesc, sgdma_descroffs(control));
ctrl = SGDMA_CONTROL_HW_OWNED;
ctrl |= generate_eop;
ctrl |= rfixed;
ctrl |= wfixed;
/* Channel is implicitly zero, initialized to 0 by default */
csrwr32(lower_32_bits(raddr), desc, sgdma_descroffs(raddr));
csrwr32(lower_32_bits(waddr), desc, sgdma_descroffs(waddr));
csrwr32(0, desc, sgdma_descroffs(pad1));
csrwr32(0, desc, sgdma_descroffs(pad2));
csrwr32(lower_32_bits(ndesc_phys), desc, sgdma_descroffs(next));
csrwr8(ctrl, desc, sgdma_descroffs(control));
csrwr8(0, desc, sgdma_descroffs(status));
csrwr8(0, desc, sgdma_descroffs(wburst));
csrwr8(0, desc, sgdma_descroffs(rburst));
csrwr16(length, desc, sgdma_descroffs(bytes));
csrwr16(0, desc, sgdma_descroffs(bytes_xferred));
}
/* If hardware is busy, don't restart async read.
* if status register is 0 - meaning initial state, restart async read,
* probably for the first time when populating a receive buffer.
* If read status indicate not busy and a status, restart the async
* DMA read.
*/
static int sgdma_async_read(struct altera_tse_private *priv)
{
struct sgdma_descrip __iomem *descbase =
(struct sgdma_descrip __iomem *)priv->rx_dma_desc;
struct sgdma_descrip __iomem *cdesc = &descbase[0];
struct sgdma_descrip __iomem *ndesc = &descbase[1];
struct tse_buffer *rxbuffer = NULL;
if (!sgdma_rxbusy(priv)) {
rxbuffer = queue_rx_peekhead(priv);
if (rxbuffer == NULL) {
netdev_err(priv->dev, "no rx buffers available\n");
return 0;
}
sgdma_setup_descrip(cdesc, /* current descriptor */
ndesc, /* next descriptor */
sgdma_rxphysaddr(priv, ndesc),
0, /* read addr 0 for rx dma */
rxbuffer->dma_addr, /* write addr for rx dma */
0, /* read 'til EOP */
0, /* EOP: NA for rx dma */
0, /* read fixed: NA for rx dma */
0); /* SOP: NA for rx DMA */
dma_sync_single_for_device(priv->device,
priv->rxdescphys,
SGDMA_DESC_LEN,
DMA_TO_DEVICE);
csrwr32(lower_32_bits(sgdma_rxphysaddr(priv, cdesc)),
priv->rx_dma_csr,
sgdma_csroffs(next_descrip));
csrwr32((priv->rxctrlreg | SGDMA_CTRLREG_START),
priv->rx_dma_csr,
sgdma_csroffs(control));
return 1;
}
return 0;
}
static int sgdma_async_write(struct altera_tse_private *priv,
struct sgdma_descrip __iomem *desc)
{
if (sgdma_txbusy(priv))
return 0;
/* clear control and status */
csrwr32(0, priv->tx_dma_csr, sgdma_csroffs(control));
csrwr32(0x1f, priv->tx_dma_csr, sgdma_csroffs(status));
dma_sync_single_for_device(priv->device, priv->txdescphys,
SGDMA_DESC_LEN, DMA_TO_DEVICE);
csrwr32(lower_32_bits(sgdma_txphysaddr(priv, desc)),
priv->tx_dma_csr,
sgdma_csroffs(next_descrip));
csrwr32((priv->txctrlreg | SGDMA_CTRLREG_START),
priv->tx_dma_csr,
sgdma_csroffs(control));
return 1;
}
static dma_addr_t
sgdma_txphysaddr(struct altera_tse_private *priv,
struct sgdma_descrip __iomem *desc)
{
dma_addr_t paddr = priv->txdescmem_busaddr;
uintptr_t offs = (uintptr_t)desc - (uintptr_t)priv->tx_dma_desc;
return (dma_addr_t)((uintptr_t)paddr + offs);
}
static dma_addr_t
sgdma_rxphysaddr(struct altera_tse_private *priv,
struct sgdma_descrip __iomem *desc)
{
dma_addr_t paddr = priv->rxdescmem_busaddr;
uintptr_t offs = (uintptr_t)desc - (uintptr_t)priv->rx_dma_desc;
return (dma_addr_t)((uintptr_t)paddr + offs);
}
#define list_remove_head(list, entry, type, member) \
do { \
entry = NULL; \
if (!list_empty(list)) { \
entry = list_entry((list)->next, type, member); \
list_del_init(&entry->member); \
} \
} while (0)
#define list_peek_head(list, entry, type, member) \
do { \
entry = NULL; \
if (!list_empty(list)) { \
entry = list_entry((list)->next, type, member); \
} \
} while (0)
/* adds a tse_buffer to the tail of a tx buffer list.
* assumes the caller is managing and holding a mutual exclusion
* primitive to avoid simultaneous pushes/pops to the list.
*/
static void
queue_tx(struct altera_tse_private *priv, struct tse_buffer *buffer)
{
list_add_tail(&buffer->lh, &priv->txlisthd);
}
/* adds a tse_buffer to the tail of a rx buffer list
* assumes the caller is managing and holding a mutual exclusion
* primitive to avoid simultaneous pushes/pops to the list.
*/
static void
queue_rx(struct altera_tse_private *priv, struct tse_buffer *buffer)
{
list_add_tail(&buffer->lh, &priv->rxlisthd);
}
/* dequeues a tse_buffer from the transmit buffer list, otherwise
* returns NULL if empty.
* assumes the caller is managing and holding a mutual exclusion
* primitive to avoid simultaneous pushes/pops to the list.
*/
static struct tse_buffer *
dequeue_tx(struct altera_tse_private *priv)
{
struct tse_buffer *buffer = NULL;
list_remove_head(&priv->txlisthd, buffer, struct tse_buffer, lh);
return buffer;
}
/* dequeues a tse_buffer from the receive buffer list, otherwise
* returns NULL if empty
* assumes the caller is managing and holding a mutual exclusion
* primitive to avoid simultaneous pushes/pops to the list.
*/
static struct tse_buffer *
dequeue_rx(struct altera_tse_private *priv)
{
struct tse_buffer *buffer = NULL;
list_remove_head(&priv->rxlisthd, buffer, struct tse_buffer, lh);
return buffer;
}
/* dequeues a tse_buffer from the receive buffer list, otherwise
* returns NULL if empty
* assumes the caller is managing and holding a mutual exclusion
* primitive to avoid simultaneous pushes/pops to the list while the
* head is being examined.
*/
static struct tse_buffer *
queue_rx_peekhead(struct altera_tse_private *priv)
{
struct tse_buffer *buffer = NULL;
list_peek_head(&priv->rxlisthd, buffer, struct tse_buffer, lh);
return buffer;
}
/* check and return rx sgdma status without polling
*/
static int sgdma_rxbusy(struct altera_tse_private *priv)
{
return csrrd32(priv->rx_dma_csr, sgdma_csroffs(status))
& SGDMA_STSREG_BUSY;
}
/* waits for the tx sgdma to finish it's current operation, returns 0
* when it transitions to nonbusy, returns 1 if the operation times out
*/
static int sgdma_txbusy(struct altera_tse_private *priv)
{
int delay = 0;
/* if DMA is busy, wait for current transaction to finish */
while ((csrrd32(priv->tx_dma_csr, sgdma_csroffs(status))
& SGDMA_STSREG_BUSY) && (delay++ < 100))
udelay(1);
if (csrrd32(priv->tx_dma_csr, sgdma_csroffs(status))
& SGDMA_STSREG_BUSY) {
netdev_err(priv->dev, "timeout waiting for tx dma\n");
return 1;
}
return 0;
}
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Altera TSE SGDMA and MSGDMA Linux driver
* Copyright (C) 2014 Altera Corporation. All rights reserved
*/
#ifndef __ALTERA_SGDMA_H__
#define __ALTERA_SGDMA_H__
void sgdma_reset(struct altera_tse_private *);
void sgdma_enable_txirq(struct altera_tse_private *);
void sgdma_enable_rxirq(struct altera_tse_private *);
void sgdma_disable_rxirq(struct altera_tse_private *);
void sgdma_disable_txirq(struct altera_tse_private *);
void sgdma_clear_rxirq(struct altera_tse_private *);
void sgdma_clear_txirq(struct altera_tse_private *);
int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *);
u32 sgdma_tx_completions(struct altera_tse_private *);
void sgdma_add_rx_desc(struct altera_tse_private *priv, struct tse_buffer *);
void sgdma_status(struct altera_tse_private *);
u32 sgdma_rx_status(struct altera_tse_private *);
int sgdma_initialize(struct altera_tse_private *);
void sgdma_uninitialize(struct altera_tse_private *);
void sgdma_start_rxdma(struct altera_tse_private *);
#endif /* __ALTERA_SGDMA_H__ */
@@ -0,0 +1,116 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Altera TSE SGDMA and MSGDMA Linux driver
* Copyright (C) 2014 Altera Corporation. All rights reserved
*/
#ifndef __ALTERA_SGDMAHW_H__
#define __ALTERA_SGDMAHW_H__
/* SGDMA descriptor structure */
struct sgdma_descrip {
u32 raddr; /* address of data to be read */
u32 pad1;
u32 waddr;
u32 pad2;
u32 next;
u32 pad3;
u16 bytes;
u8 rburst;
u8 wburst;
u16 bytes_xferred; /* 16 bits, bytes xferred */
/* bit 0: error
* bit 1: length error
* bit 2: crc error
* bit 3: truncated error
* bit 4: phy error
* bit 5: collision error
* bit 6: reserved
* bit 7: status eop for recv case
*/
u8 status;
/* bit 0: eop
* bit 1: read_fixed
* bit 2: write fixed
* bits 3,4,5,6: Channel (always 0)
* bit 7: hardware owned
*/
u8 control;
} __packed;
#define SGDMA_DESC_LEN sizeof(struct sgdma_descrip)
#define SGDMA_STATUS_ERR BIT(0)
#define SGDMA_STATUS_LENGTH_ERR BIT(1)
#define SGDMA_STATUS_CRC_ERR BIT(2)
#define SGDMA_STATUS_TRUNC_ERR BIT(3)
#define SGDMA_STATUS_PHY_ERR BIT(4)
#define SGDMA_STATUS_COLL_ERR BIT(5)
#define SGDMA_STATUS_EOP BIT(7)
#define SGDMA_CONTROL_EOP BIT(0)
#define SGDMA_CONTROL_RD_FIXED BIT(1)
#define SGDMA_CONTROL_WR_FIXED BIT(2)
/* Channel is always 0, so just zero initialize it */
#define SGDMA_CONTROL_HW_OWNED BIT(7)
/* SGDMA register space */
struct sgdma_csr {
/* bit 0: error
* bit 1: eop
* bit 2: descriptor completed
* bit 3: chain completed
* bit 4: busy
* remainder reserved
*/
u32 status;
u32 pad1[3];
/* bit 0: interrupt on error
* bit 1: interrupt on eop
* bit 2: interrupt after every descriptor
* bit 3: interrupt after last descrip in a chain
* bit 4: global interrupt enable
* bit 5: starts descriptor processing
* bit 6: stop core on dma error
* bit 7: interrupt on max descriptors
* bits 8-15: max descriptors to generate interrupt
* bit 16: Software reset
* bit 17: clears owned by hardware if 0, does not clear otherwise
* bit 18: enables descriptor polling mode
* bit 19-26: clocks before polling again
* bit 27-30: reserved
* bit 31: clear interrupt
*/
u32 control;
u32 pad2[3];
u32 next_descrip;
u32 pad3[3];
};
#define sgdma_csroffs(a) (offsetof(struct sgdma_csr, a))
#define sgdma_descroffs(a) (offsetof(struct sgdma_descrip, a))
#define SGDMA_STSREG_ERR BIT(0) /* Error */
#define SGDMA_STSREG_EOP BIT(1) /* EOP */
#define SGDMA_STSREG_DESCRIP BIT(2) /* Descriptor completed */
#define SGDMA_STSREG_CHAIN BIT(3) /* Chain completed */
#define SGDMA_STSREG_BUSY BIT(4) /* Controller busy */
#define SGDMA_CTRLREG_IOE BIT(0) /* Interrupt on error */
#define SGDMA_CTRLREG_IOEOP BIT(1) /* Interrupt on EOP */
#define SGDMA_CTRLREG_IDESCRIP BIT(2) /* Interrupt after every descriptor */
#define SGDMA_CTRLREG_ILASTD BIT(3) /* Interrupt after last descriptor */
#define SGDMA_CTRLREG_INTEN BIT(4) /* Global Interrupt enable */
#define SGDMA_CTRLREG_START BIT(5) /* starts descriptor processing */
#define SGDMA_CTRLREG_STOPERR BIT(6) /* stop on dma error */
#define SGDMA_CTRLREG_INTMAX BIT(7) /* Interrupt on max descriptors */
#define SGDMA_CTRLREG_RESET BIT(16)/* Software reset */
#define SGDMA_CTRLREG_COBHW BIT(17)/* Clears owned by hardware */
#define SGDMA_CTRLREG_POLL BIT(18)/* enables descriptor polling mode */
#define SGDMA_CTRLREG_CLRINT BIT(31)/* Clears interrupt */
#endif /* __ALTERA_SGDMAHW_H__ */
@@ -0,0 +1,528 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Altera Triple-Speed Ethernet MAC driver
* Copyright (C) 2008-2014 Altera Corporation. All rights reserved
*
* Contributors:
* Dalon Westergreen
* Thomas Chou
* Ian Abbott
* Yuriy Kozlov
* Tobias Klauser
* Andriy Smolskyy
* Roman Bulgakov
* Dmytro Mytarchuk
* Matthew Gerlach
*
* Original driver contributed by SLS.
* Major updates contributed by GlobalLogic
*/
#ifndef __ALTERA_TSE_H__
#define __ALTERA_TSE_H__
#define ALTERA_TSE_RESOURCE_NAME "altera_tse"
#include <linux/bitops.h>
#include <linux/if_vlan.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/phy.h>
#include <linux/phylink.h>
#define ALTERA_TSE_SW_RESET_WATCHDOG_CNTR 10000
#define ALTERA_TSE_MAC_FIFO_WIDTH 4 /* TX/RX FIFO width in
* bytes
*/
/* Rx FIFO default settings */
#define ALTERA_TSE_RX_SECTION_EMPTY 16
#define ALTERA_TSE_RX_SECTION_FULL 0
#define ALTERA_TSE_RX_ALMOST_EMPTY 8
#define ALTERA_TSE_RX_ALMOST_FULL 8
/* Tx FIFO default settings */
#define ALTERA_TSE_TX_SECTION_EMPTY 16
#define ALTERA_TSE_TX_SECTION_FULL 0
#define ALTERA_TSE_TX_ALMOST_EMPTY 8
#define ALTERA_TSE_TX_ALMOST_FULL 3
/* MAC function configuration default settings */
#define ALTERA_TSE_TX_IPG_LENGTH 12
#define ALTERA_TSE_PAUSE_QUANTA 0xffff
#define GET_BIT_VALUE(v, bit) (((v) >> (bit)) & 0x1)
/* MAC Command_Config Register Bit Definitions
*/
#define MAC_CMDCFG_TX_ENA BIT(0)
#define MAC_CMDCFG_RX_ENA BIT(1)
#define MAC_CMDCFG_XON_GEN BIT(2)
#define MAC_CMDCFG_ETH_SPEED BIT(3)
#define MAC_CMDCFG_PROMIS_EN BIT(4)
#define MAC_CMDCFG_PAD_EN BIT(5)
#define MAC_CMDCFG_CRC_FWD BIT(6)
#define MAC_CMDCFG_PAUSE_FWD BIT(7)
#define MAC_CMDCFG_PAUSE_IGNORE BIT(8)
#define MAC_CMDCFG_TX_ADDR_INS BIT(9)
#define MAC_CMDCFG_HD_ENA BIT(10)
#define MAC_CMDCFG_EXCESS_COL BIT(11)
#define MAC_CMDCFG_LATE_COL BIT(12)
#define MAC_CMDCFG_SW_RESET BIT(13)
#define MAC_CMDCFG_MHASH_SEL BIT(14)
#define MAC_CMDCFG_LOOP_ENA BIT(15)
#define MAC_CMDCFG_TX_ADDR_SEL(v) (((v) & 0x7) << 16)
#define MAC_CMDCFG_MAGIC_ENA BIT(19)
#define MAC_CMDCFG_SLEEP BIT(20)
#define MAC_CMDCFG_WAKEUP BIT(21)
#define MAC_CMDCFG_XOFF_GEN BIT(22)
#define MAC_CMDCFG_CNTL_FRM_ENA BIT(23)
#define MAC_CMDCFG_NO_LGTH_CHECK BIT(24)
#define MAC_CMDCFG_ENA_10 BIT(25)
#define MAC_CMDCFG_RX_ERR_DISC BIT(26)
#define MAC_CMDCFG_DISABLE_READ_TIMEOUT BIT(27)
#define MAC_CMDCFG_CNT_RESET BIT(31)
#define MAC_CMDCFG_TX_ENA_GET(v) GET_BIT_VALUE(v, 0)
#define MAC_CMDCFG_RX_ENA_GET(v) GET_BIT_VALUE(v, 1)
#define MAC_CMDCFG_XON_GEN_GET(v) GET_BIT_VALUE(v, 2)
#define MAC_CMDCFG_ETH_SPEED_GET(v) GET_BIT_VALUE(v, 3)
#define MAC_CMDCFG_PROMIS_EN_GET(v) GET_BIT_VALUE(v, 4)
#define MAC_CMDCFG_PAD_EN_GET(v) GET_BIT_VALUE(v, 5)
#define MAC_CMDCFG_CRC_FWD_GET(v) GET_BIT_VALUE(v, 6)
#define MAC_CMDCFG_PAUSE_FWD_GET(v) GET_BIT_VALUE(v, 7)
#define MAC_CMDCFG_PAUSE_IGNORE_GET(v) GET_BIT_VALUE(v, 8)
#define MAC_CMDCFG_TX_ADDR_INS_GET(v) GET_BIT_VALUE(v, 9)
#define MAC_CMDCFG_HD_ENA_GET(v) GET_BIT_VALUE(v, 10)
#define MAC_CMDCFG_EXCESS_COL_GET(v) GET_BIT_VALUE(v, 11)
#define MAC_CMDCFG_LATE_COL_GET(v) GET_BIT_VALUE(v, 12)
#define MAC_CMDCFG_SW_RESET_GET(v) GET_BIT_VALUE(v, 13)
#define MAC_CMDCFG_MHASH_SEL_GET(v) GET_BIT_VALUE(v, 14)
#define MAC_CMDCFG_LOOP_ENA_GET(v) GET_BIT_VALUE(v, 15)
#define MAC_CMDCFG_TX_ADDR_SEL_GET(v) (((v) >> 16) & 0x7)
#define MAC_CMDCFG_MAGIC_ENA_GET(v) GET_BIT_VALUE(v, 19)
#define MAC_CMDCFG_SLEEP_GET(v) GET_BIT_VALUE(v, 20)
#define MAC_CMDCFG_WAKEUP_GET(v) GET_BIT_VALUE(v, 21)
#define MAC_CMDCFG_XOFF_GEN_GET(v) GET_BIT_VALUE(v, 22)
#define MAC_CMDCFG_CNTL_FRM_ENA_GET(v) GET_BIT_VALUE(v, 23)
#define MAC_CMDCFG_NO_LGTH_CHECK_GET(v) GET_BIT_VALUE(v, 24)
#define MAC_CMDCFG_ENA_10_GET(v) GET_BIT_VALUE(v, 25)
#define MAC_CMDCFG_RX_ERR_DISC_GET(v) GET_BIT_VALUE(v, 26)
#define MAC_CMDCFG_DISABLE_READ_TIMEOUT_GET(v) GET_BIT_VALUE(v, 27)
#define MAC_CMDCFG_CNT_RESET_GET(v) GET_BIT_VALUE(v, 31)
/* MDIO registers within MAC register Space
*/
struct altera_tse_mdio {
u32 control; /* PHY device operation control register */
u32 status; /* PHY device operation status register */
u32 phy_id1; /* Bits 31:16 of PHY identifier */
u32 phy_id2; /* Bits 15:0 of PHY identifier */
u32 auto_negotiation_advertisement; /* Auto-negotiation
* advertisement
* register
*/
u32 remote_partner_base_page_ability;
u32 reg6;
u32 reg7;
u32 reg8;
u32 reg9;
u32 rega;
u32 regb;
u32 regc;
u32 regd;
u32 rege;
u32 regf;
u32 reg10;
u32 reg11;
u32 reg12;
u32 reg13;
u32 reg14;
u32 reg15;
u32 reg16;
u32 reg17;
u32 reg18;
u32 reg19;
u32 reg1a;
u32 reg1b;
u32 reg1c;
u32 reg1d;
u32 reg1e;
u32 reg1f;
};
/* MAC register Space. Note that some of these registers may or may not be
* present depending upon options chosen by the user when the core was
* configured and built. Please consult the Altera Triple Speed Ethernet User
* Guide for details.
*/
struct altera_tse_mac {
/* Bits 15:0: MegaCore function revision (0x0800). Bit 31:16: Customer
* specific revision
*/
u32 megacore_revision;
/* Provides a memory location for user applications to test the device
* memory operation.
*/
u32 scratch_pad;
/* The host processor uses this register to control and configure the
* MAC block
*/
u32 command_config;
/* 32-bit primary MAC address word 0 bits 0 to 31 of the primary
* MAC address
*/
u32 mac_addr_0;
/* 32-bit primary MAC address word 1 bits 32 to 47 of the primary
* MAC address
*/
u32 mac_addr_1;
/* 14-bit maximum frame length. The MAC receive logic */
u32 frm_length;
/* The pause quanta is used in each pause frame sent to a remote
* Ethernet device, in increments of 512 Ethernet bit times
*/
u32 pause_quanta;
/* 12-bit receive FIFO section-empty threshold */
u32 rx_section_empty;
/* 12-bit receive FIFO section-full threshold */
u32 rx_section_full;
/* 12-bit transmit FIFO section-empty threshold */
u32 tx_section_empty;
/* 12-bit transmit FIFO section-full threshold */
u32 tx_section_full;
/* 12-bit receive FIFO almost-empty threshold */
u32 rx_almost_empty;
/* 12-bit receive FIFO almost-full threshold */
u32 rx_almost_full;
/* 12-bit transmit FIFO almost-empty threshold */
u32 tx_almost_empty;
/* 12-bit transmit FIFO almost-full threshold */
u32 tx_almost_full;
/* MDIO address of PHY Device 0. Bits 0 to 4 hold a 5-bit PHY address */
u32 mdio_phy0_addr;
/* MDIO address of PHY Device 1. Bits 0 to 4 hold a 5-bit PHY address */
u32 mdio_phy1_addr;
/* Bit[15:0]—16-bit holdoff quanta */
u32 holdoff_quant;
/* only if 100/1000 BaseX PCS, reserved otherwise */
u32 reserved1[5];
/* Minimum IPG between consecutive transmit frame in terms of bytes */
u32 tx_ipg_length;
/* IEEE 802.3 oEntity Managed Object Support */
/* The MAC addresses */
u32 mac_id_1;
u32 mac_id_2;
/* Number of frames transmitted without error including pause frames */
u32 frames_transmitted_ok;
/* Number of frames received without error including pause frames */
u32 frames_received_ok;
/* Number of frames received with a CRC error */
u32 frames_check_sequence_errors;
/* Frame received with an alignment error */
u32 alignment_errors;
/* Sum of payload and padding octets of frames transmitted without
* error
*/
u32 octets_transmitted_ok;
/* Sum of payload and padding octets of frames received without error */
u32 octets_received_ok;
/* IEEE 802.3 oPausedEntity Managed Object Support */
/* Number of transmitted pause frames */
u32 tx_pause_mac_ctrl_frames;
/* Number of Received pause frames */
u32 rx_pause_mac_ctrl_frames;
/* IETF MIB (MIB-II) Object Support */
/* Number of frames received with error */
u32 if_in_errors;
/* Number of frames transmitted with error */
u32 if_out_errors;
/* Number of valid received unicast frames */
u32 if_in_ucast_pkts;
/* Number of valid received multicasts frames (without pause) */
u32 if_in_multicast_pkts;
/* Number of valid received broadcast frames */
u32 if_in_broadcast_pkts;
u32 if_out_discards;
/* The number of valid unicast frames transmitted */
u32 if_out_ucast_pkts;
/* The number of valid multicast frames transmitted,
* excluding pause frames
*/
u32 if_out_multicast_pkts;
u32 if_out_broadcast_pkts;
/* IETF RMON MIB Object Support */
/* Counts the number of dropped packets due to internal errors
* of the MAC client.
*/
u32 ether_stats_drop_events;
/* Total number of bytes received. Good and bad frames. */
u32 ether_stats_octets;
/* Total number of packets received. Counts good and bad packets. */
u32 ether_stats_pkts;
/* Number of packets received with less than 64 bytes. */
u32 ether_stats_undersize_pkts;
/* The number of frames received that are longer than the
* value configured in the frm_length register
*/
u32 ether_stats_oversize_pkts;
/* Number of received packet with 64 bytes */
u32 ether_stats_pkts_64_octets;
/* Frames (good and bad) with 65 to 127 bytes */
u32 ether_stats_pkts_65to127_octets;
/* Frames (good and bad) with 128 to 255 bytes */
u32 ether_stats_pkts_128to255_octets;
/* Frames (good and bad) with 256 to 511 bytes */
u32 ether_stats_pkts_256to511_octets;
/* Frames (good and bad) with 512 to 1023 bytes */
u32 ether_stats_pkts_512to1023_octets;
/* Frames (good and bad) with 1024 to 1518 bytes */
u32 ether_stats_pkts_1024to1518_octets;
/* Any frame length from 1519 to the maximum length configured in the
* frm_length register, if it is greater than 1518
*/
u32 ether_stats_pkts_1519tox_octets;
/* Too long frames with CRC error */
u32 ether_stats_jabbers;
/* Too short frames with CRC error */
u32 ether_stats_fragments;
u32 reserved2;
/* FIFO control register */
u32 tx_cmd_stat;
u32 rx_cmd_stat;
/* Extended Statistics Counters */
u32 msb_octets_transmitted_ok;
u32 msb_octets_received_ok;
u32 msb_ether_stats_octets;
u32 reserved3;
/* Multicast address resolution table, mapped in the controller address
* space
*/
u32 hash_table[64];
/* Registers 0 to 31 within PHY device 0/1 connected to the MDIO PHY
* management interface
*/
struct altera_tse_mdio mdio_phy0;
struct altera_tse_mdio mdio_phy1;
/* 4 Supplemental MAC Addresses */
u32 supp_mac_addr_0_0;
u32 supp_mac_addr_0_1;
u32 supp_mac_addr_1_0;
u32 supp_mac_addr_1_1;
u32 supp_mac_addr_2_0;
u32 supp_mac_addr_2_1;
u32 supp_mac_addr_3_0;
u32 supp_mac_addr_3_1;
u32 reserved4[8];
/* IEEE 1588v2 Feature */
u32 tx_period;
u32 tx_adjust_fns;
u32 tx_adjust_ns;
u32 rx_period;
u32 rx_adjust_fns;
u32 rx_adjust_ns;
u32 reserved5[42];
};
#define tse_csroffs(a) (offsetof(struct altera_tse_mac, a))
/* Transmit and Receive Command Registers Bit Definitions
*/
#define ALTERA_TSE_TX_CMD_STAT_OMIT_CRC BIT(17)
#define ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16 BIT(18)
#define ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16 BIT(25)
/* Wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer
*/
struct tse_buffer {
struct list_head lh;
struct sk_buff *skb;
dma_addr_t dma_addr;
u32 len;
int mapped_as_page;
};
struct altera_tse_private;
#define ALTERA_DTYPE_SGDMA 1
#define ALTERA_DTYPE_MSGDMA 2
/* standard DMA interface for SGDMA and MSGDMA */
struct altera_dmaops {
int altera_dtype;
int dmamask;
void (*reset_dma)(struct altera_tse_private *);
void (*enable_txirq)(struct altera_tse_private *);
void (*enable_rxirq)(struct altera_tse_private *);
void (*disable_txirq)(struct altera_tse_private *);
void (*disable_rxirq)(struct altera_tse_private *);
void (*clear_txirq)(struct altera_tse_private *);
void (*clear_rxirq)(struct altera_tse_private *);
int (*tx_buffer)(struct altera_tse_private *, struct tse_buffer *);
u32 (*tx_completions)(struct altera_tse_private *);
void (*add_rx_desc)(struct altera_tse_private *, struct tse_buffer *);
u32 (*get_rx_status)(struct altera_tse_private *);
int (*init_dma)(struct altera_tse_private *);
void (*uninit_dma)(struct altera_tse_private *);
void (*start_rxdma)(struct altera_tse_private *);
};
/* This structure is private to each device.
*/
struct altera_tse_private {
struct net_device *dev;
struct device *device;
struct napi_struct napi;
/* MAC address space */
struct altera_tse_mac __iomem *mac_dev;
/* mSGDMA Rx Dispatcher address space */
void __iomem *rx_dma_csr;
void __iomem *rx_dma_desc;
void __iomem *rx_dma_resp;
/* mSGDMA Tx Dispatcher address space */
void __iomem *tx_dma_csr;
void __iomem *tx_dma_desc;
/* SGMII PCS address space */
void __iomem *pcs_base;
/* Rx buffers queue */
struct tse_buffer *rx_ring;
u32 rx_cons;
u32 rx_prod;
u32 rx_ring_size;
u32 rx_dma_buf_sz;
/* Tx ring buffer */
struct tse_buffer *tx_ring;
u32 tx_prod;
u32 tx_cons;
u32 tx_ring_size;
/* Interrupts */
u32 tx_irq;
u32 rx_irq;
/* RX/TX MAC FIFO configs */
u32 tx_fifo_depth;
u32 rx_fifo_depth;
/* Hash filter settings */
u32 hash_filter;
u32 added_unicast;
/* Descriptor memory info for managing SGDMA */
u32 txdescmem;
u32 rxdescmem;
dma_addr_t rxdescmem_busaddr;
dma_addr_t txdescmem_busaddr;
u32 txctrlreg;
u32 rxctrlreg;
dma_addr_t rxdescphys;
dma_addr_t txdescphys;
struct list_head txlisthd;
struct list_head rxlisthd;
/* MAC command_config register protection */
spinlock_t mac_cfg_lock;
/* Tx path protection */
spinlock_t tx_lock;
/* Rx DMA & interrupt control protection */
spinlock_t rxdma_irq_lock;
/* PHY */
int phy_addr; /* PHY's MDIO address, -1 for autodetection */
phy_interface_t phy_iface;
struct mii_bus *mdio;
int oldspeed;
int oldduplex;
int oldlink;
/* ethtool msglvl option */
u32 msg_enable;
const struct altera_dmaops *dmaops;
struct phylink *phylink;
struct phylink_config phylink_config;
struct phylink_pcs *pcs;
};
/* Function prototypes
*/
void altera_tse_set_ethtool_ops(struct net_device *);
static inline
u32 csrrd32(void __iomem *mac, size_t offs)
{
void __iomem *paddr = (void __iomem *)((uintptr_t)mac + offs);
return readl(paddr);
}
static inline
u16 csrrd16(void __iomem *mac, size_t offs)
{
void __iomem *paddr = (void __iomem *)((uintptr_t)mac + offs);
return readw(paddr);
}
static inline
u8 csrrd8(void __iomem *mac, size_t offs)
{
void __iomem *paddr = (void __iomem *)((uintptr_t)mac + offs);
return readb(paddr);
}
static inline
void csrwr32(u32 val, void __iomem *mac, size_t offs)
{
void __iomem *paddr = (void __iomem *)((uintptr_t)mac + offs);
writel(val, paddr);
}
static inline
void csrwr16(u16 val, void __iomem *mac, size_t offs)
{
void __iomem *paddr = (void __iomem *)((uintptr_t)mac + offs);
writew(val, paddr);
}
static inline
void csrwr8(u8 val, void __iomem *mac, size_t offs)
{
void __iomem *paddr = (void __iomem *)((uintptr_t)mac + offs);
writeb(val, paddr);
}
#endif /* __ALTERA_TSE_H__ */
@@ -0,0 +1,258 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Ethtool support for Altera Triple-Speed Ethernet MAC driver
* Copyright (C) 2008-2014 Altera Corporation. All rights reserved
*
* Contributors:
* Dalon Westergreen
* Thomas Chou
* Ian Abbott
* Yuriy Kozlov
* Tobias Klauser
* Andriy Smolskyy
* Roman Bulgakov
* Dmytro Mytarchuk
*
* Original driver contributed by SLS.
* Major updates contributed by GlobalLogic
*/
#include <linux/ethtool.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/phy.h>
#include "altera_tse.h"
#define TSE_STATS_LEN 31
#define TSE_NUM_REGS 128
static char const stat_gstrings[][ETH_GSTRING_LEN] = {
"tx_packets",
"rx_packets",
"rx_crc_errors",
"rx_align_errors",
"tx_bytes",
"rx_bytes",
"tx_pause",
"rx_pause",
"rx_errors",
"tx_errors",
"rx_unicast",
"rx_multicast",
"rx_broadcast",
"tx_discards",
"tx_unicast",
"tx_multicast",
"tx_broadcast",
"ether_drops",
"rx_total_bytes",
"rx_total_packets",
"rx_undersize",
"rx_oversize",
"rx_64_bytes",
"rx_65_127_bytes",
"rx_128_255_bytes",
"rx_256_511_bytes",
"rx_512_1023_bytes",
"rx_1024_1518_bytes",
"rx_gte_1519_bytes",
"rx_jabbers",
"rx_runts",
};
static void tse_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct altera_tse_private *priv = netdev_priv(dev);
u32 rev = ioread32(&priv->mac_dev->megacore_revision);
strcpy(info->driver, "altera_tse");
snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "v%d.%d",
rev & 0xFFFF, (rev & 0xFFFF0000) >> 16);
sprintf(info->bus_info, "platform");
}
/* Fill in a buffer with the strings which correspond to the
* stats
*/
static void tse_gstrings(struct net_device *dev, u32 stringset, u8 *buf)
{
memcpy(buf, stat_gstrings, TSE_STATS_LEN * ETH_GSTRING_LEN);
}
static void tse_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
u64 *buf)
{
struct altera_tse_private *priv = netdev_priv(dev);
u64 ext;
buf[0] = csrrd32(priv->mac_dev,
tse_csroffs(frames_transmitted_ok));
buf[1] = csrrd32(priv->mac_dev,
tse_csroffs(frames_received_ok));
buf[2] = csrrd32(priv->mac_dev,
tse_csroffs(frames_check_sequence_errors));
buf[3] = csrrd32(priv->mac_dev,
tse_csroffs(alignment_errors));
/* Extended aOctetsTransmittedOK counter */
ext = (u64) csrrd32(priv->mac_dev,
tse_csroffs(msb_octets_transmitted_ok)) << 32;
ext |= csrrd32(priv->mac_dev,
tse_csroffs(octets_transmitted_ok));
buf[4] = ext;
/* Extended aOctetsReceivedOK counter */
ext = (u64) csrrd32(priv->mac_dev,
tse_csroffs(msb_octets_received_ok)) << 32;
ext |= csrrd32(priv->mac_dev,
tse_csroffs(octets_received_ok));
buf[5] = ext;
buf[6] = csrrd32(priv->mac_dev,
tse_csroffs(tx_pause_mac_ctrl_frames));
buf[7] = csrrd32(priv->mac_dev,
tse_csroffs(rx_pause_mac_ctrl_frames));
buf[8] = csrrd32(priv->mac_dev,
tse_csroffs(if_in_errors));
buf[9] = csrrd32(priv->mac_dev,
tse_csroffs(if_out_errors));
buf[10] = csrrd32(priv->mac_dev,
tse_csroffs(if_in_ucast_pkts));
buf[11] = csrrd32(priv->mac_dev,
tse_csroffs(if_in_multicast_pkts));
buf[12] = csrrd32(priv->mac_dev,
tse_csroffs(if_in_broadcast_pkts));
buf[13] = csrrd32(priv->mac_dev,
tse_csroffs(if_out_discards));
buf[14] = csrrd32(priv->mac_dev,
tse_csroffs(if_out_ucast_pkts));
buf[15] = csrrd32(priv->mac_dev,
tse_csroffs(if_out_multicast_pkts));
buf[16] = csrrd32(priv->mac_dev,
tse_csroffs(if_out_broadcast_pkts));
buf[17] = csrrd32(priv->mac_dev,
tse_csroffs(ether_stats_drop_events));
/* Extended etherStatsOctets counter */
ext = (u64) csrrd32(priv->mac_dev,
tse_csroffs(msb_ether_stats_octets)) << 32;
ext |= csrrd32(priv->mac_dev,
tse_csroffs(ether_stats_octets));
buf[18] = ext;
buf[19] = csrrd32(priv->mac_dev,
tse_csroffs(ether_stats_pkts));
buf[20] = csrrd32(priv->mac_dev,
tse_csroffs(ether_stats_undersize_pkts));
buf[21] = csrrd32(priv->mac_dev,
tse_csroffs(ether_stats_oversize_pkts));
buf[22] = csrrd32(priv->mac_dev,
tse_csroffs(ether_stats_pkts_64_octets));
buf[23] = csrrd32(priv->mac_dev,
tse_csroffs(ether_stats_pkts_65to127_octets));
buf[24] = csrrd32(priv->mac_dev,
tse_csroffs(ether_stats_pkts_128to255_octets));
buf[25] = csrrd32(priv->mac_dev,
tse_csroffs(ether_stats_pkts_256to511_octets));
buf[26] = csrrd32(priv->mac_dev,
tse_csroffs(ether_stats_pkts_512to1023_octets));
buf[27] = csrrd32(priv->mac_dev,
tse_csroffs(ether_stats_pkts_1024to1518_octets));
buf[28] = csrrd32(priv->mac_dev,
tse_csroffs(ether_stats_pkts_1519tox_octets));
buf[29] = csrrd32(priv->mac_dev,
tse_csroffs(ether_stats_jabbers));
buf[30] = csrrd32(priv->mac_dev,
tse_csroffs(ether_stats_fragments));
}
static int tse_sset_count(struct net_device *dev, int sset)
{
switch (sset) {
case ETH_SS_STATS:
return TSE_STATS_LEN;
default:
return -EOPNOTSUPP;
}
}
static u32 tse_get_msglevel(struct net_device *dev)
{
struct altera_tse_private *priv = netdev_priv(dev);
return priv->msg_enable;
}
static void tse_set_msglevel(struct net_device *dev, uint32_t data)
{
struct altera_tse_private *priv = netdev_priv(dev);
priv->msg_enable = data;
}
static int tse_reglen(struct net_device *dev)
{
return TSE_NUM_REGS * sizeof(u32);
}
static void tse_get_regs(struct net_device *dev, struct ethtool_regs *regs,
void *regbuf)
{
struct altera_tse_private *priv = netdev_priv(dev);
u32 *buf = regbuf;
int i;
/* Set version to a known value, so ethtool knows
* how to do any special formatting of this data.
* This version number will need to change if and
* when this register table is changed.
*
* version[31:0] = 1: Dump the first 128 TSE Registers
* Upper bits are all 0 by default
*
* Upper 16-bits will indicate feature presence for
* Ethtool register decoding in future version.
*/
regs->version = 1;
for (i = 0; i < TSE_NUM_REGS; i++)
buf[i] = csrrd32(priv->mac_dev, i * 4);
}
static int tse_ethtool_set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *cmd)
{
struct altera_tse_private *priv = netdev_priv(dev);
return phylink_ethtool_ksettings_set(priv->phylink, cmd);
}
static int tse_ethtool_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *cmd)
{
struct altera_tse_private *priv = netdev_priv(dev);
return phylink_ethtool_ksettings_get(priv->phylink, cmd);
}
static const struct ethtool_ops tse_ethtool_ops = {
.get_drvinfo = tse_get_drvinfo,
.get_regs_len = tse_reglen,
.get_regs = tse_get_regs,
.get_link = ethtool_op_get_link,
.get_strings = tse_gstrings,
.get_sset_count = tse_sset_count,
.get_ethtool_stats = tse_fill_stats,
.get_msglevel = tse_get_msglevel,
.set_msglevel = tse_set_msglevel,
.get_link_ksettings = tse_ethtool_get_link_ksettings,
.set_link_ksettings = tse_ethtool_set_link_ksettings,
.get_ts_info = ethtool_op_get_ts_info,
};
void altera_tse_set_ethtool_ops(struct net_device *netdev)
{
netdev->ethtool_ops = &tse_ethtool_ops;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Altera TSE SGDMA and MSGDMA Linux driver
* Copyright (C) 2014 Altera Corporation. All rights reserved
*/
#include "altera_tse.h"
#include "altera_utils.h"
void tse_set_bit(void __iomem *ioaddr, size_t offs, u32 bit_mask)
{
u32 value = csrrd32(ioaddr, offs);
value |= bit_mask;
csrwr32(value, ioaddr, offs);
}
void tse_clear_bit(void __iomem *ioaddr, size_t offs, u32 bit_mask)
{
u32 value = csrrd32(ioaddr, offs);
value &= ~bit_mask;
csrwr32(value, ioaddr, offs);
}
int tse_bit_is_set(void __iomem *ioaddr, size_t offs, u32 bit_mask)
{
u32 value = csrrd32(ioaddr, offs);
return (value & bit_mask) ? 1 : 0;
}
int tse_bit_is_clear(void __iomem *ioaddr, size_t offs, u32 bit_mask)
{
u32 value = csrrd32(ioaddr, offs);
return (value & bit_mask) ? 0 : 1;
}
@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Altera TSE SGDMA and MSGDMA Linux driver
* Copyright (C) 2014 Altera Corporation. All rights reserved
*/
#ifndef __ALTERA_UTILS_H__
#define __ALTERA_UTILS_H__
#include <linux/compiler.h>
#include <linux/types.h>
void tse_set_bit(void __iomem *ioaddr, size_t offs, u32 bit_mask);
void tse_clear_bit(void __iomem *ioaddr, size_t offs, u32 bit_mask);
int tse_bit_is_set(void __iomem *ioaddr, size_t offs, u32 bit_mask);
int tse_bit_is_clear(void __iomem *ioaddr, size_t offs, u32 bit_mask);
#endif /* __ALTERA_UTILS_H__*/