提交 217e606b 编写于 作者: D David S. Miller

Merge branch 'apm_xgene'

Iyappan Subramanian says:

====================
net: Add APM X-Gene SoC Ethernet driver support

Adding APM X-Gene SoC Ethernet driver.

v10: Address comments from v9 review
* Documentation: aligned descriptions
* simplified struct platform_driver initialization
* fixed xgene_enet_mdio_config error path
* fixed xgene_enet_init_hw error path
* removed statistics spin_lock as it is not required
* changed raw_desc fields to type __le64
* defined helper macros for set/get raw_descriptor fields

v9: Address comments from v8 review
* changed to direct read/write, byteswap into raw descriptor
* fixed xgene_enet_create_desc_ring() error handling
* removed references to IS_ERR_OR_NULL
* disabled half duplex on phy_devce supported/advertising
* simplified xgene_enet_adjust_link() function
* fixed sparse tool compilation warnings

v8: Address comments from v7 review
* changed angle bracket to double quotes in header file include.

v7: Address comments from v6 review
* fixed skb memory leak when dma_map_single fails in xmit.

v6: Address comments from v5 review
* added basic ethtool support
* added ndo_get_stats64 call back
* deleted priting Rx error messages
* renamed set_bits to xgene_set_bits to fix kbuild error (make ARCH=powerpc)

v5: Address comments from v4 review
* Documentation: Added phy-handle, reg-names and changed mdio part
* dtb: Added reg-names supplemental property
* changed platform_get_resource to platform_get_resource_byname
* added separate tx/rx set_desc/get_desc functions to do raw_write/raw_read
* removed set_desc/get_desc table lookup logic
* added error handling logic based on per packet descriptor bits
* added software managed Rx packet and error counters
* added busy wait for register read/writes
* changed mdio_bus->id to avoid conflict
* fixed mdio_bus leak in case of mdio_config error
* changed phy reg hard coded value to MII_BMSR
* changed phy addr hard coded value to phy_device->addr
* added paranthesis around macro arguments
* converted helper macros to inline functions
* changed use of goto's only to common work such as cleanup

v4: Address comments from v3 review
* MAINTAINERS: changed status to supported
* Kconfig: made default to no
* changed to bool data type wherever applicable
* cleaned up single bit set and masking code
* removed statistics counters masking
* removed unnecessary OOM message printing
* fixed dma_map_single and dma_unmap_single size parameter
* changed set bits macro body using new set_bits function

v3: Address comments from v2 review
* cleaned up set_desc and get_desc functions
* added dtb mdio node and phy-handle subnode
* renamed dtb phy-mode to phy-connection-type
* added of_phy_connect call to connec to PHY
* added empty line after last local variable declaration
* removed type casting when not required
* removed inline keyword from source files
* removed CONFIG_CPU_BIG_ENDIAN ifdef

v2
* Completely redesigned ethernet driver
* Added support to work with big endian kernel
* Renamed dtb phyid entry to phy_addr
* Changed dtb local-mac-address entry to byte string format
* Renamed dtb eth8clk entry to menetclk

v1
* Initial version
====================
Signed-off-by: NIyappan Subramanian <isubramanian@apm.com>
Signed-off-by: NRavi Patel <rapatel@apm.com>
Signed-off-by: NKeyur Chudgar <kchudgar@apm.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
APM X-Gene SoC Ethernet nodes
Ethernet nodes are defined to describe on-chip ethernet interfaces in
APM X-Gene SoC.
Required properties:
- compatible: Should be "apm,xgene-enet"
- reg: Address and length of the register set for the device. It contains the
information of registers in the same order as described by reg-names
- reg-names: Should contain the register set names
- "enet_csr": Ethernet control and status register address space
- "ring_csr": Descriptor ring control and status register address space
- "ring_cmd": Descriptor ring command register address space
- interrupts: Ethernet main interrupt
- clocks: Reference to the clock entry.
- local-mac-address: MAC address assigned to this device
- phy-connection-type: Interface type between ethernet device and PHY device
- phy-handle: Reference to a PHY node connected to this device
- mdio: Device tree subnode with the following required properties:
- compatible: Must be "apm,xgene-mdio".
- #address-cells: Must be <1>.
- #size-cells: Must be <0>.
For the phy on the mdio bus, there must be a node with the following fields:
- compatible: PHY identifier. Please refer ./phy.txt for the format.
- reg: The ID number for the phy.
Optional properties:
- status: Should be "ok" or "disabled" for enabled/disabled. Default is "ok".
Example:
menetclk: menetclk {
compatible = "apm,xgene-device-clock";
clock-output-names = "menetclk";
status = "ok";
};
menet: ethernet@17020000 {
compatible = "apm,xgene-enet";
status = "disabled";
reg = <0x0 0x17020000 0x0 0xd100>,
<0x0 0X17030000 0x0 0X400>,
<0x0 0X10000000 0x0 0X200>;
reg-names = "enet_csr", "ring_csr", "ring_cmd";
interrupts = <0x0 0x3c 0x4>;
clocks = <&menetclk 0>;
local-mac-address = [00 01 73 00 00 01];
phy-connection-type = "rgmii";
phy-handle = <&menetphy>;
mdio {
compatible = "apm,xgene-mdio";
#address-cells = <1>;
#size-cells = <0>;
menetphy: menetphy@3 {
compatible = "ethernet-phy-id001c.c915";
reg = <0x3>;
};
};
};
/* Board-specific peripheral configurations */
&menet {
status = "ok";
};
......@@ -719,6 +719,14 @@ S: Maintained
F: drivers/net/appletalk/
F: net/appletalk/
APPLIED MICRO (APM) X-GENE SOC ETHERNET DRIVER
M: Iyappan Subramanian <isubramanian@apm.com>
M: Keyur Chudgar <kchudgar@apm.com>
M: Ravi Patel <rapatel@apm.com>
S: Supported
F: drivers/net/ethernet/apm/xgene/
F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt
APTINA CAMERA SENSOR PLL
M: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
L: linux-media@vger.kernel.org
......
......@@ -28,3 +28,7 @@ memory {
&serial0 {
status = "ok";
};
&menet {
status = "ok";
};
......@@ -167,14 +167,13 @@ ethclk: ethclk {
clock-output-names = "ethclk";
};
eth8clk: eth8clk {
menetclk: menetclk {
compatible = "apm,xgene-device-clock";
#clock-cells = <1>;
clocks = <&ethclk 0>;
clock-names = "eth8clk";
reg = <0x0 0x1702C000 0x0 0x1000>;
reg-names = "csr-reg";
clock-output-names = "eth8clk";
clock-output-names = "menetclk";
};
sataphy1clk: sataphy1clk@1f21c000 {
......@@ -397,5 +396,30 @@ rtc: rtc@10510000 {
#clock-cells = <1>;
clocks = <&rtcclk 0>;
};
menet: ethernet@17020000 {
compatible = "apm,xgene-enet";
status = "disabled";
reg = <0x0 0x17020000 0x0 0xd100>,
<0x0 0X17030000 0x0 0X400>,
<0x0 0X10000000 0x0 0X200>;
reg-names = "enet_csr", "ring_csr", "ring_cmd";
interrupts = <0x0 0x3c 0x4>;
dma-coherent;
clocks = <&menetclk 0>;
local-mac-address = [00 01 73 00 00 01];
phy-connection-type = "rgmii";
phy-handle = <&menetphy>;
mdio {
compatible = "apm,xgene-mdio";
#address-cells = <1>;
#size-cells = <0>;
menetphy: menetphy@3 {
compatible = "ethernet-phy-id001c.c915";
reg = <0x3>;
};
};
};
};
};
......@@ -24,6 +24,7 @@ source "drivers/net/ethernet/allwinner/Kconfig"
source "drivers/net/ethernet/alteon/Kconfig"
source "drivers/net/ethernet/altera/Kconfig"
source "drivers/net/ethernet/amd/Kconfig"
source "drivers/net/ethernet/apm/Kconfig"
source "drivers/net/ethernet/apple/Kconfig"
source "drivers/net/ethernet/arc/Kconfig"
source "drivers/net/ethernet/atheros/Kconfig"
......
......@@ -10,6 +10,7 @@ obj-$(CONFIG_NET_VENDOR_ALLWINNER) += allwinner/
obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/
obj-$(CONFIG_ALTERA_TSE) += altera/
obj-$(CONFIG_NET_VENDOR_AMD) += amd/
obj-$(CONFIG_NET_XGENE) += apm/
obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
obj-$(CONFIG_NET_VENDOR_ARC) += arc/
obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/
......
source "drivers/net/ethernet/apm/xgene/Kconfig"
#
# Makefile for APM X-GENE Ethernet driver.
#
obj-$(CONFIG_NET_XGENE) += xgene/
config NET_XGENE
tristate "APM X-Gene SoC Ethernet Driver"
select PHYLIB
help
This is the Ethernet driver for the on-chip ethernet interface on the
APM X-Gene SoC.
To compile this driver as a module, choose M here. This module will
be called xgene_enet.
#
# Makefile for APM X-Gene Ethernet Driver.
#
xgene-enet-objs := xgene_enet_hw.o xgene_enet_main.o xgene_enet_ethtool.o
obj-$(CONFIG_NET_XGENE) += xgene-enet.o
/* Applied Micro X-Gene SoC Ethernet Driver
*
* Copyright (c) 2014, Applied Micro Circuits Corporation
* Authors: Iyappan Subramanian <isubramanian@apm.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/ethtool.h>
#include "xgene_enet_main.h"
struct xgene_gstrings_stats {
char name[ETH_GSTRING_LEN];
int offset;
};
#define XGENE_STAT(m) { #m, offsetof(struct xgene_enet_pdata, stats.m) }
static const struct xgene_gstrings_stats gstrings_stats[] = {
XGENE_STAT(rx_packets),
XGENE_STAT(tx_packets),
XGENE_STAT(rx_bytes),
XGENE_STAT(tx_bytes),
XGENE_STAT(rx_errors),
XGENE_STAT(tx_errors),
XGENE_STAT(rx_length_errors),
XGENE_STAT(rx_crc_errors),
XGENE_STAT(rx_frame_errors),
XGENE_STAT(rx_fifo_errors)
};
#define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats)
static void xgene_get_drvinfo(struct net_device *ndev,
struct ethtool_drvinfo *info)
{
struct xgene_enet_pdata *pdata = netdev_priv(ndev);
struct platform_device *pdev = pdata->pdev;
strcpy(info->driver, "xgene_enet");
strcpy(info->version, XGENE_DRV_VERSION);
snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "N/A");
sprintf(info->bus_info, "%s", pdev->name);
}
static int xgene_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
{
struct xgene_enet_pdata *pdata = netdev_priv(ndev);
struct phy_device *phydev = pdata->phy_dev;
if (phydev == NULL)
return -ENODEV;
return phy_ethtool_gset(phydev, cmd);
}
static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
{
struct xgene_enet_pdata *pdata = netdev_priv(ndev);
struct phy_device *phydev = pdata->phy_dev;
if (phydev == NULL)
return -ENODEV;
return phy_ethtool_sset(phydev, cmd);
}
static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
{
int i;
u8 *p = data;
if (stringset != ETH_SS_STATS)
return;
for (i = 0; i < XGENE_STATS_LEN; i++) {
memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
}
static int xgene_get_sset_count(struct net_device *ndev, int sset)
{
if (sset != ETH_SS_STATS)
return -EINVAL;
return XGENE_STATS_LEN;
}
static void xgene_get_ethtool_stats(struct net_device *ndev,
struct ethtool_stats *dummy,
u64 *data)
{
void *pdata = netdev_priv(ndev);
int i;
for (i = 0; i < XGENE_STATS_LEN; i++)
*data++ = *(u64 *)(pdata + gstrings_stats[i].offset);
}
static const struct ethtool_ops xgene_ethtool_ops = {
.get_drvinfo = xgene_get_drvinfo,
.get_settings = xgene_get_settings,
.set_settings = xgene_set_settings,
.get_link = ethtool_op_get_link,
.get_strings = xgene_get_strings,
.get_sset_count = xgene_get_sset_count,
.get_ethtool_stats = xgene_get_ethtool_stats
};
void xgene_enet_set_ethtool_ops(struct net_device *ndev)
{
ndev->ethtool_ops = &xgene_ethtool_ops;
}
/* Applied Micro X-Gene SoC Ethernet Driver
*
* Copyright (c) 2014, Applied Micro Circuits Corporation
* Authors: Iyappan Subramanian <isubramanian@apm.com>
* Ravi Patel <rapatel@apm.com>
* Keyur Chudgar <kchudgar@apm.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "xgene_enet_main.h"
#include "xgene_enet_hw.h"
static void xgene_enet_ring_init(struct xgene_enet_desc_ring *ring)
{
u32 *ring_cfg = ring->state;
u64 addr = ring->dma;
enum xgene_enet_ring_cfgsize cfgsize = ring->cfgsize;
ring_cfg[4] |= (1 << SELTHRSH_POS) &
CREATE_MASK(SELTHRSH_POS, SELTHRSH_LEN);
ring_cfg[3] |= ACCEPTLERR;
ring_cfg[2] |= QCOHERENT;
addr >>= 8;
ring_cfg[2] |= (addr << RINGADDRL_POS) &
CREATE_MASK_ULL(RINGADDRL_POS, RINGADDRL_LEN);
addr >>= RINGADDRL_LEN;
ring_cfg[3] |= addr & CREATE_MASK_ULL(RINGADDRH_POS, RINGADDRH_LEN);
ring_cfg[3] |= ((u32)cfgsize << RINGSIZE_POS) &
CREATE_MASK(RINGSIZE_POS, RINGSIZE_LEN);
}
static void xgene_enet_ring_set_type(struct xgene_enet_desc_ring *ring)
{
u32 *ring_cfg = ring->state;
bool is_bufpool;
u32 val;
is_bufpool = xgene_enet_is_bufpool(ring->id);
val = (is_bufpool) ? RING_BUFPOOL : RING_REGULAR;
ring_cfg[4] |= (val << RINGTYPE_POS) &
CREATE_MASK(RINGTYPE_POS, RINGTYPE_LEN);
if (is_bufpool) {
ring_cfg[3] |= (BUFPOOL_MODE << RINGMODE_POS) &
CREATE_MASK(RINGMODE_POS, RINGMODE_LEN);
}
}
static void xgene_enet_ring_set_recombbuf(struct xgene_enet_desc_ring *ring)
{
u32 *ring_cfg = ring->state;
ring_cfg[3] |= RECOMBBUF;
ring_cfg[3] |= (0xf << RECOMTIMEOUTL_POS) &
CREATE_MASK(RECOMTIMEOUTL_POS, RECOMTIMEOUTL_LEN);
ring_cfg[4] |= 0x7 & CREATE_MASK(RECOMTIMEOUTH_POS, RECOMTIMEOUTH_LEN);
}
static void xgene_enet_ring_wr32(struct xgene_enet_desc_ring *ring,
u32 offset, u32 data)
{
struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
iowrite32(data, pdata->ring_csr_addr + offset);
}
static void xgene_enet_ring_rd32(struct xgene_enet_desc_ring *ring,
u32 offset, u32 *data)
{
struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
*data = ioread32(pdata->ring_csr_addr + offset);
}
static void xgene_enet_write_ring_state(struct xgene_enet_desc_ring *ring)
{
int i;
xgene_enet_ring_wr32(ring, CSR_RING_CONFIG, ring->num);
for (i = 0; i < NUM_RING_CONFIG; i++) {
xgene_enet_ring_wr32(ring, CSR_RING_WR_BASE + (i * 4),
ring->state[i]);
}
}
static void xgene_enet_clr_ring_state(struct xgene_enet_desc_ring *ring)
{
memset(ring->state, 0, sizeof(u32) * NUM_RING_CONFIG);
xgene_enet_write_ring_state(ring);
}
static void xgene_enet_set_ring_state(struct xgene_enet_desc_ring *ring)
{
xgene_enet_ring_set_type(ring);
if (xgene_enet_ring_owner(ring->id) == RING_OWNER_ETH0)
xgene_enet_ring_set_recombbuf(ring);
xgene_enet_ring_init(ring);
xgene_enet_write_ring_state(ring);
}
static void xgene_enet_set_ring_id(struct xgene_enet_desc_ring *ring)
{
u32 ring_id_val, ring_id_buf;
bool is_bufpool;
is_bufpool = xgene_enet_is_bufpool(ring->id);
ring_id_val = ring->id & GENMASK(9, 0);
ring_id_val |= OVERWRITE;
ring_id_buf = (ring->num << 9) & GENMASK(18, 9);
ring_id_buf |= PREFETCH_BUF_EN;
if (is_bufpool)
ring_id_buf |= IS_BUFFER_POOL;
xgene_enet_ring_wr32(ring, CSR_RING_ID, ring_id_val);
xgene_enet_ring_wr32(ring, CSR_RING_ID_BUF, ring_id_buf);
}
static void xgene_enet_clr_desc_ring_id(struct xgene_enet_desc_ring *ring)
{
u32 ring_id;
ring_id = ring->id | OVERWRITE;
xgene_enet_ring_wr32(ring, CSR_RING_ID, ring_id);
xgene_enet_ring_wr32(ring, CSR_RING_ID_BUF, 0);
}
struct xgene_enet_desc_ring *xgene_enet_setup_ring(
struct xgene_enet_desc_ring *ring)
{
u32 size = ring->size;
u32 i, data;
bool is_bufpool;
xgene_enet_clr_ring_state(ring);
xgene_enet_set_ring_state(ring);
xgene_enet_set_ring_id(ring);
ring->slots = xgene_enet_get_numslots(ring->id, size);
is_bufpool = xgene_enet_is_bufpool(ring->id);
if (is_bufpool || xgene_enet_ring_owner(ring->id) != RING_OWNER_CPU)
return ring;
for (i = 0; i < ring->slots; i++)
xgene_enet_mark_desc_slot_empty(&ring->raw_desc[i]);
xgene_enet_ring_rd32(ring, CSR_RING_NE_INT_MODE, &data);
data |= BIT(31 - xgene_enet_ring_bufnum(ring->id));
xgene_enet_ring_wr32(ring, CSR_RING_NE_INT_MODE, data);
return ring;
}
void xgene_enet_clear_ring(struct xgene_enet_desc_ring *ring)
{
u32 data;
bool is_bufpool;
is_bufpool = xgene_enet_is_bufpool(ring->id);
if (is_bufpool || xgene_enet_ring_owner(ring->id) != RING_OWNER_CPU)
goto out;
xgene_enet_ring_rd32(ring, CSR_RING_NE_INT_MODE, &data);
data &= ~BIT(31 - xgene_enet_ring_bufnum(ring->id));
xgene_enet_ring_wr32(ring, CSR_RING_NE_INT_MODE, data);
out:
xgene_enet_clr_desc_ring_id(ring);
xgene_enet_clr_ring_state(ring);
}
void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring,
struct xgene_enet_pdata *pdata,
enum xgene_enet_err_code status)
{
struct rtnl_link_stats64 *stats = &pdata->stats;
switch (status) {
case INGRESS_CRC:
stats->rx_crc_errors++;
break;
case INGRESS_CHECKSUM:
case INGRESS_CHECKSUM_COMPUTE:
stats->rx_errors++;
break;
case INGRESS_TRUNC_FRAME:
stats->rx_frame_errors++;
break;
case INGRESS_PKT_LEN:
stats->rx_length_errors++;
break;
case INGRESS_PKT_UNDER:
stats->rx_frame_errors++;
break;
case INGRESS_FIFO_OVERRUN:
stats->rx_fifo_errors++;
break;
default:
break;
}
}
static void xgene_enet_wr_csr(struct xgene_enet_pdata *pdata,
u32 offset, u32 val)
{
void __iomem *addr = pdata->eth_csr_addr + offset;
iowrite32(val, addr);
}
static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *pdata,
u32 offset, u32 val)
{
void __iomem *addr = pdata->eth_ring_if_addr + offset;
iowrite32(val, addr);
}
static void xgene_enet_wr_diag_csr(struct xgene_enet_pdata *pdata,
u32 offset, u32 val)
{
void __iomem *addr = pdata->eth_diag_csr_addr + offset;
iowrite32(val, addr);
}
static void xgene_enet_wr_mcx_csr(struct xgene_enet_pdata *pdata,
u32 offset, u32 val)
{
void __iomem *addr = pdata->mcx_mac_csr_addr + offset;
iowrite32(val, addr);
}
static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr,
void __iomem *cmd, void __iomem *cmd_done,
u32 wr_addr, u32 wr_data)
{
u32 done;
u8 wait = 10;
iowrite32(wr_addr, addr);
iowrite32(wr_data, wr);
iowrite32(XGENE_ENET_WR_CMD, cmd);
/* wait for write command to complete */
while (!(done = ioread32(cmd_done)) && wait--)
udelay(1);
if (!done)
return false;
iowrite32(0, cmd);
return true;
}
static void xgene_enet_wr_mcx_mac(struct xgene_enet_pdata *pdata,
u32 wr_addr, u32 wr_data)
{
void __iomem *addr, *wr, *cmd, *cmd_done;
addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET;
wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET;
cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET;
cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET;
if (!xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data))
netdev_err(pdata->ndev, "MCX mac write failed, addr: %04x\n",
wr_addr);
}
static void xgene_enet_rd_csr(struct xgene_enet_pdata *pdata,
u32 offset, u32 *val)
{
void __iomem *addr = pdata->eth_csr_addr + offset;
*val = ioread32(addr);
}
static void xgene_enet_rd_diag_csr(struct xgene_enet_pdata *pdata,
u32 offset, u32 *val)
{
void __iomem *addr = pdata->eth_diag_csr_addr + offset;
*val = ioread32(addr);
}
static void xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *pdata,
u32 offset, u32 *val)
{
void __iomem *addr = pdata->mcx_mac_csr_addr + offset;
*val = ioread32(addr);
}
static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd,
void __iomem *cmd, void __iomem *cmd_done,
u32 rd_addr, u32 *rd_data)
{
u32 done;
u8 wait = 10;
iowrite32(rd_addr, addr);
iowrite32(XGENE_ENET_RD_CMD, cmd);
/* wait for read command to complete */
while (!(done = ioread32(cmd_done)) && wait--)
udelay(1);
if (!done)
return false;
*rd_data = ioread32(rd);
iowrite32(0, cmd);
return true;
}
static void xgene_enet_rd_mcx_mac(struct xgene_enet_pdata *pdata,
u32 rd_addr, u32 *rd_data)
{
void __iomem *addr, *rd, *cmd, *cmd_done;
addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET;
rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET;
cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET;
cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET;
if (!xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data))
netdev_err(pdata->ndev, "MCX mac read failed, addr: %04x\n",
rd_addr);
}
static int xgene_mii_phy_write(struct xgene_enet_pdata *pdata, int phy_id,
u32 reg, u16 data)
{
u32 addr = 0, wr_data = 0;
u32 done;
u8 wait = 10;
PHY_ADDR_SET(&addr, phy_id);
REG_ADDR_SET(&addr, reg);
xgene_enet_wr_mcx_mac(pdata, MII_MGMT_ADDRESS_ADDR, addr);
PHY_CONTROL_SET(&wr_data, data);
xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONTROL_ADDR, wr_data);
do {
usleep_range(5, 10);
xgene_enet_rd_mcx_mac(pdata, MII_MGMT_INDICATORS_ADDR, &done);
} while ((done & BUSY_MASK) && wait--);
if (done & BUSY_MASK) {
netdev_err(pdata->ndev, "MII_MGMT write failed\n");
return -EBUSY;
}
return 0;
}
static int xgene_mii_phy_read(struct xgene_enet_pdata *pdata,
u8 phy_id, u32 reg)
{
u32 addr = 0;
u32 data, done;
u8 wait = 10;
PHY_ADDR_SET(&addr, phy_id);
REG_ADDR_SET(&addr, reg);
xgene_enet_wr_mcx_mac(pdata, MII_MGMT_ADDRESS_ADDR, addr);
xgene_enet_wr_mcx_mac(pdata, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK);
do {
usleep_range(5, 10);
xgene_enet_rd_mcx_mac(pdata, MII_MGMT_INDICATORS_ADDR, &done);
} while ((done & BUSY_MASK) && wait--);
if (done & BUSY_MASK) {
netdev_err(pdata->ndev, "MII_MGMT read failed\n");
return -EBUSY;
}
xgene_enet_rd_mcx_mac(pdata, MII_MGMT_STATUS_ADDR, &data);
xgene_enet_wr_mcx_mac(pdata, MII_MGMT_COMMAND_ADDR, 0);
return data;
}
void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata)
{
u32 addr0, addr1;
u8 *dev_addr = pdata->ndev->dev_addr;
addr0 = (dev_addr[3] << 24) | (dev_addr[2] << 16) |
(dev_addr[1] << 8) | dev_addr[0];
addr1 = (dev_addr[5] << 24) | (dev_addr[4] << 16);
addr1 |= pdata->phy_addr & 0xFFFF;
xgene_enet_wr_mcx_mac(pdata, STATION_ADDR0_ADDR, addr0);
xgene_enet_wr_mcx_mac(pdata, STATION_ADDR1_ADDR, addr1);
}
static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata)
{
struct net_device *ndev = pdata->ndev;
u32 data;
u8 wait = 10;
xgene_enet_wr_diag_csr(pdata, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0);
do {
usleep_range(100, 110);
xgene_enet_rd_diag_csr(pdata, ENET_BLOCK_MEM_RDY_ADDR, &data);
} while ((data != 0xffffffff) && wait--);
if (data != 0xffffffff) {
netdev_err(ndev, "Failed to release memory from shutdown\n");
return -ENODEV;
}
return 0;
}
void xgene_gmac_reset(struct xgene_enet_pdata *pdata)
{
xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET1);
xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, 0);
}
void xgene_gmac_init(struct xgene_enet_pdata *pdata, int speed)
{
u32 value, mc2;
u32 intf_ctl, rgmii;
u32 icm0, icm2;
xgene_gmac_reset(pdata);
xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, &icm0);
xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, &icm2);
xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_2_ADDR, &mc2);
xgene_enet_rd_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, &intf_ctl);
xgene_enet_rd_csr(pdata, RGMII_REG_0_ADDR, &rgmii);
switch (speed) {
case SPEED_10:
ENET_INTERFACE_MODE2_SET(&mc2, 1);
CFG_MACMODE_SET(&icm0, 0);
CFG_WAITASYNCRD_SET(&icm2, 500);
rgmii &= ~CFG_SPEED_1250;
break;
case SPEED_100:
ENET_INTERFACE_MODE2_SET(&mc2, 1);
intf_ctl |= ENET_LHD_MODE;
CFG_MACMODE_SET(&icm0, 1);
CFG_WAITASYNCRD_SET(&icm2, 80);
rgmii &= ~CFG_SPEED_1250;
break;
default:
ENET_INTERFACE_MODE2_SET(&mc2, 2);
intf_ctl |= ENET_GHD_MODE;
CFG_TXCLK_MUXSEL0_SET(&rgmii, 4);
xgene_enet_rd_csr(pdata, DEBUG_REG_ADDR, &value);
value |= CFG_BYPASS_UNISEC_TX | CFG_BYPASS_UNISEC_RX;
xgene_enet_wr_csr(pdata, DEBUG_REG_ADDR, value);
break;
}
mc2 |= FULL_DUPLEX2;
xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2);
xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl);
xgene_gmac_set_mac_addr(pdata);
/* Adjust MDC clock frequency */
xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &value);
MGMT_CLOCK_SEL_SET(&value, 7);
xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, value);
/* Enable drop if bufpool not available */
xgene_enet_rd_csr(pdata, RSIF_CONFIG_REG_ADDR, &value);
value |= CFG_RSIF_FPBUFF_TIMEOUT_EN;
xgene_enet_wr_csr(pdata, RSIF_CONFIG_REG_ADDR, value);
/* Rtype should be copied from FP */
xgene_enet_wr_csr(pdata, RSIF_RAM_DBG_REG0_ADDR, 0);
xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii);
/* Rx-Tx traffic resume */
xgene_enet_wr_csr(pdata, CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0);
xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, icm0);
xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, icm2);
xgene_enet_rd_mcx_csr(pdata, RX_DV_GATE_REG_0_ADDR, &value);
value &= ~TX_DV_GATE_EN0;
value &= ~RX_DV_GATE_EN0;
value |= RESUME_RX0;
xgene_enet_wr_mcx_csr(pdata, RX_DV_GATE_REG_0_ADDR, value);
xgene_enet_wr_csr(pdata, CFG_BYPASS_ADDR, RESUME_TX);
}
static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata)
{
u32 val = 0xffffffff;
xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQASSOC_ADDR, val);
xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPQASSOC_ADDR, val);
xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEWQASSOC_ADDR, val);
xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEFPQASSOC_ADDR, val);
}
void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata,
u32 dst_ring_num, u16 bufpool_id)
{
u32 cb;
u32 fpsel;
fpsel = xgene_enet_ring_bufnum(bufpool_id) - 0x20;
xgene_enet_rd_csr(pdata, CLE_BYPASS_REG0_0_ADDR, &cb);
cb |= CFG_CLE_BYPASS_EN0;
CFG_CLE_IP_PROTOCOL0_SET(&cb, 3);
xgene_enet_wr_csr(pdata, CLE_BYPASS_REG0_0_ADDR, cb);
xgene_enet_rd_csr(pdata, CLE_BYPASS_REG1_0_ADDR, &cb);
CFG_CLE_DSTQID0_SET(&cb, dst_ring_num);
CFG_CLE_FPSEL0_SET(&cb, fpsel);
xgene_enet_wr_csr(pdata, CLE_BYPASS_REG1_0_ADDR, cb);
}
void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata)
{
u32 data;
xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | RX_EN);
}
void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata)
{
u32 data;
xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | TX_EN);
}
void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata)
{
u32 data;
xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~RX_EN);
}
void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata)
{
u32 data;
xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~TX_EN);
}
void xgene_enet_reset(struct xgene_enet_pdata *pdata)
{
u32 val;
clk_prepare_enable(pdata->clk);
clk_disable_unprepare(pdata->clk);
clk_prepare_enable(pdata->clk);
xgene_enet_ecc_init(pdata);
xgene_enet_config_ring_if_assoc(pdata);
/* Enable auto-incr for scanning */
xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &val);
val |= SCAN_AUTO_INCR;
MGMT_CLOCK_SEL_SET(&val, 1);
xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, val);
}
void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
{
clk_disable_unprepare(pdata->clk);
}
static int xgene_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
{
struct xgene_enet_pdata *pdata = bus->priv;
u32 val;
val = xgene_mii_phy_read(pdata, mii_id, regnum);
netdev_dbg(pdata->ndev, "mdio_rd: bus=%d reg=%d val=%x\n",
mii_id, regnum, val);
return val;
}
static int xgene_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
u16 val)
{
struct xgene_enet_pdata *pdata = bus->priv;
netdev_dbg(pdata->ndev, "mdio_wr: bus=%d reg=%d val=%x\n",
mii_id, regnum, val);
return xgene_mii_phy_write(pdata, mii_id, regnum, val);
}
static void xgene_enet_adjust_link(struct net_device *ndev)
{
struct xgene_enet_pdata *pdata = netdev_priv(ndev);
struct phy_device *phydev = pdata->phy_dev;
if (phydev->link) {
if (pdata->phy_speed != phydev->speed) {
xgene_gmac_init(pdata, phydev->speed);
xgene_gmac_rx_enable(pdata);
xgene_gmac_tx_enable(pdata);
pdata->phy_speed = phydev->speed;
phy_print_status(phydev);
}
} else {
xgene_gmac_rx_disable(pdata);
xgene_gmac_tx_disable(pdata);
pdata->phy_speed = SPEED_UNKNOWN;
phy_print_status(phydev);
}
}
static int xgene_enet_phy_connect(struct net_device *ndev)
{
struct xgene_enet_pdata *pdata = netdev_priv(ndev);
struct device_node *phy_np;
struct phy_device *phy_dev;
struct device *dev = &pdata->pdev->dev;
phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0);
if (!phy_np) {
netdev_dbg(ndev, "No phy-handle found\n");
return -ENODEV;
}
phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link,
0, pdata->phy_mode);
if (!phy_dev) {
netdev_err(ndev, "Could not connect to PHY\n");
return -ENODEV;
}
pdata->phy_speed = SPEED_UNKNOWN;
phy_dev->supported &= ~SUPPORTED_10baseT_Half &
~SUPPORTED_100baseT_Half &
~SUPPORTED_1000baseT_Half;
phy_dev->advertising = phy_dev->supported;
pdata->phy_dev = phy_dev;
return 0;
}
int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata)
{
struct net_device *ndev = pdata->ndev;
struct device *dev = &pdata->pdev->dev;
struct device_node *child_np;
struct device_node *mdio_np = NULL;
struct mii_bus *mdio_bus;
int ret;
for_each_child_of_node(dev->of_node, child_np) {
if (of_device_is_compatible(child_np, "apm,xgene-mdio")) {
mdio_np = child_np;
break;
}
}
if (!mdio_np) {
netdev_dbg(ndev, "No mdio node in the dts\n");
return -ENXIO;
}
mdio_bus = mdiobus_alloc();
if (!mdio_bus)
return -ENOMEM;
mdio_bus->name = "APM X-Gene MDIO bus";
mdio_bus->read = xgene_enet_mdio_read;
mdio_bus->write = xgene_enet_mdio_write;
snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "xgene-mii",
ndev->name);
mdio_bus->priv = pdata;
mdio_bus->parent = &ndev->dev;
ret = of_mdiobus_register(mdio_bus, mdio_np);
if (ret) {
netdev_err(ndev, "Failed to register MDIO bus\n");
mdiobus_free(mdio_bus);
return ret;
}
pdata->mdio_bus = mdio_bus;
ret = xgene_enet_phy_connect(ndev);
if (ret)
xgene_enet_mdio_remove(pdata);
return ret;
}
void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata)
{
mdiobus_unregister(pdata->mdio_bus);
mdiobus_free(pdata->mdio_bus);
pdata->mdio_bus = NULL;
}
/* Applied Micro X-Gene SoC Ethernet Driver
*
* Copyright (c) 2014, Applied Micro Circuits Corporation
* Authors: Iyappan Subramanian <isubramanian@apm.com>
* Ravi Patel <rapatel@apm.com>
* Keyur Chudgar <kchudgar@apm.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __XGENE_ENET_HW_H__
#define __XGENE_ENET_HW_H__
#include "xgene_enet_main.h"
struct xgene_enet_pdata;
struct xgene_enet_stats;
/* clears and then set bits */
static inline void xgene_set_bits(u32 *dst, u32 val, u32 start, u32 len)
{
u32 end = start + len - 1;
u32 mask = GENMASK(end, start);
*dst &= ~mask;
*dst |= (val << start) & mask;
}
static inline u32 xgene_get_bits(u32 val, u32 start, u32 end)
{
return (val & GENMASK(end, start)) >> start;
}
#define CSR_RING_ID 0x0008
#define OVERWRITE BIT(31)
#define IS_BUFFER_POOL BIT(20)
#define PREFETCH_BUF_EN BIT(21)
#define CSR_RING_ID_BUF 0x000c
#define CSR_RING_NE_INT_MODE 0x017c
#define CSR_RING_CONFIG 0x006c
#define CSR_RING_WR_BASE 0x0070
#define NUM_RING_CONFIG 5
#define BUFPOOL_MODE 3
#define RM3 3
#define INC_DEC_CMD_ADDR 0x002c
#define UDP_HDR_SIZE 2
#define BUF_LEN_CODE_2K 0x5000
#define CREATE_MASK(pos, len) GENMASK((pos)+(len)-1, (pos))
#define CREATE_MASK_ULL(pos, len) GENMASK_ULL((pos)+(len)-1, (pos))
/* Empty slot soft signature */
#define EMPTY_SLOT_INDEX 1
#define EMPTY_SLOT ~0ULL
#define WORK_DESC_SIZE 32
#define BUFPOOL_DESC_SIZE 16
#define RING_OWNER_MASK GENMASK(9, 6)
#define RING_BUFNUM_MASK GENMASK(5, 0)
#define SELTHRSH_POS 3
#define SELTHRSH_LEN 3
#define RINGADDRL_POS 5
#define RINGADDRL_LEN 27
#define RINGADDRH_POS 0
#define RINGADDRH_LEN 6
#define RINGSIZE_POS 23
#define RINGSIZE_LEN 3
#define RINGTYPE_POS 19
#define RINGTYPE_LEN 2
#define RINGMODE_POS 20
#define RINGMODE_LEN 3
#define RECOMTIMEOUTL_POS 28
#define RECOMTIMEOUTL_LEN 3
#define RECOMTIMEOUTH_POS 0
#define RECOMTIMEOUTH_LEN 2
#define NUMMSGSINQ_POS 1
#define NUMMSGSINQ_LEN 16
#define ACCEPTLERR BIT(19)
#define QCOHERENT BIT(4)
#define RECOMBBUF BIT(27)
#define BLOCK_ETH_CSR_OFFSET 0x2000
#define BLOCK_ETH_RING_IF_OFFSET 0x9000
#define BLOCK_ETH_CLKRST_CSR_OFFSET 0xC000
#define BLOCK_ETH_DIAG_CSR_OFFSET 0xD000
#define BLOCK_ETH_MAC_OFFSET 0x0000
#define BLOCK_ETH_STATS_OFFSET 0x0014
#define BLOCK_ETH_MAC_CSR_OFFSET 0x2800
#define MAC_ADDR_REG_OFFSET 0x00
#define MAC_COMMAND_REG_OFFSET 0x04
#define MAC_WRITE_REG_OFFSET 0x08
#define MAC_READ_REG_OFFSET 0x0c
#define MAC_COMMAND_DONE_REG_OFFSET 0x10
#define STAT_ADDR_REG_OFFSET 0x00
#define STAT_COMMAND_REG_OFFSET 0x04
#define STAT_WRITE_REG_OFFSET 0x08
#define STAT_READ_REG_OFFSET 0x0c
#define STAT_COMMAND_DONE_REG_OFFSET 0x10
#define MII_MGMT_CONFIG_ADDR 0x20
#define MII_MGMT_COMMAND_ADDR 0x24
#define MII_MGMT_ADDRESS_ADDR 0x28
#define MII_MGMT_CONTROL_ADDR 0x2c
#define MII_MGMT_STATUS_ADDR 0x30
#define MII_MGMT_INDICATORS_ADDR 0x34
#define BUSY_MASK BIT(0)
#define READ_CYCLE_MASK BIT(0)
#define PHY_CONTROL_SET(dst, val) xgene_set_bits(dst, val, 0, 16)
#define ENET_SPARE_CFG_REG_ADDR 0x0750
#define RSIF_CONFIG_REG_ADDR 0x0010
#define RSIF_RAM_DBG_REG0_ADDR 0x0048
#define RGMII_REG_0_ADDR 0x07e0
#define CFG_LINK_AGGR_RESUME_0_ADDR 0x07c8
#define DEBUG_REG_ADDR 0x0700
#define CFG_BYPASS_ADDR 0x0294
#define CLE_BYPASS_REG0_0_ADDR 0x0490
#define CLE_BYPASS_REG1_0_ADDR 0x0494
#define CFG_RSIF_FPBUFF_TIMEOUT_EN BIT(31)
#define RESUME_TX BIT(0)
#define CFG_SPEED_1250 BIT(24)
#define TX_PORT0 BIT(0)
#define CFG_BYPASS_UNISEC_TX BIT(2)
#define CFG_BYPASS_UNISEC_RX BIT(1)
#define CFG_CLE_BYPASS_EN0 BIT(31)
#define CFG_TXCLK_MUXSEL0_SET(dst, val) xgene_set_bits(dst, val, 29, 3)
#define CFG_CLE_IP_PROTOCOL0_SET(dst, val) xgene_set_bits(dst, val, 16, 2)
#define CFG_CLE_DSTQID0_SET(dst, val) xgene_set_bits(dst, val, 0, 12)
#define CFG_CLE_FPSEL0_SET(dst, val) xgene_set_bits(dst, val, 16, 4)
#define CFG_MACMODE_SET(dst, val) xgene_set_bits(dst, val, 18, 2)
#define CFG_WAITASYNCRD_SET(dst, val) xgene_set_bits(dst, val, 0, 16)
#define ICM_CONFIG0_REG_0_ADDR 0x0400
#define ICM_CONFIG2_REG_0_ADDR 0x0410
#define RX_DV_GATE_REG_0_ADDR 0x05fc
#define TX_DV_GATE_EN0 BIT(2)
#define RX_DV_GATE_EN0 BIT(1)
#define RESUME_RX0 BIT(0)
#define ENET_CFGSSQMIWQASSOC_ADDR 0xe0
#define ENET_CFGSSQMIFPQASSOC_ADDR 0xdc
#define ENET_CFGSSQMIQMLITEFPQASSOC_ADDR 0xf0
#define ENET_CFGSSQMIQMLITEWQASSOC_ADDR 0xf4
#define ENET_CFG_MEM_RAM_SHUTDOWN_ADDR 0x70
#define ENET_BLOCK_MEM_RDY_ADDR 0x74
#define MAC_CONFIG_1_ADDR 0x00
#define MAC_CONFIG_2_ADDR 0x04
#define MAX_FRAME_LEN_ADDR 0x10
#define INTERFACE_CONTROL_ADDR 0x38
#define STATION_ADDR0_ADDR 0x40
#define STATION_ADDR1_ADDR 0x44
#define PHY_ADDR_SET(dst, val) xgene_set_bits(dst, val, 8, 5)
#define REG_ADDR_SET(dst, val) xgene_set_bits(dst, val, 0, 5)
#define ENET_INTERFACE_MODE2_SET(dst, val) xgene_set_bits(dst, val, 8, 2)
#define MGMT_CLOCK_SEL_SET(dst, val) xgene_set_bits(dst, val, 0, 3)
#define SOFT_RESET1 BIT(31)
#define TX_EN BIT(0)
#define RX_EN BIT(2)
#define ENET_LHD_MODE BIT(25)
#define ENET_GHD_MODE BIT(26)
#define FULL_DUPLEX2 BIT(0)
#define SCAN_AUTO_INCR BIT(5)
#define TBYT_ADDR 0x38
#define TPKT_ADDR 0x39
#define TDRP_ADDR 0x45
#define TFCS_ADDR 0x47
#define TUND_ADDR 0x4a
#define TSO_IPPROTO_TCP 1
#define FULL_DUPLEX 2
#define USERINFO_POS 0
#define USERINFO_LEN 32
#define FPQNUM_POS 32
#define FPQNUM_LEN 12
#define LERR_POS 60
#define LERR_LEN 3
#define STASH_POS 52
#define STASH_LEN 2
#define BUFDATALEN_POS 48
#define BUFDATALEN_LEN 12
#define DATAADDR_POS 0
#define DATAADDR_LEN 42
#define COHERENT_POS 63
#define HENQNUM_POS 48
#define HENQNUM_LEN 12
#define TYPESEL_POS 44
#define TYPESEL_LEN 4
#define ETHHDR_POS 12
#define ETHHDR_LEN 8
#define IC_POS 35 /* Insert CRC */
#define TCPHDR_POS 0
#define TCPHDR_LEN 6
#define IPHDR_POS 6
#define IPHDR_LEN 6
#define EC_POS 22 /* Enable checksum */
#define EC_LEN 1
#define IS_POS 24 /* IP protocol select */
#define IS_LEN 1
#define TYPE_ETH_WORK_MESSAGE_POS 44
struct xgene_enet_raw_desc {
__le64 m0;
__le64 m1;
__le64 m2;
__le64 m3;
};
struct xgene_enet_raw_desc16 {
__le64 m0;
__le64 m1;
};
static inline void xgene_enet_mark_desc_slot_empty(void *desc_slot_ptr)
{
__le64 *desc_slot = desc_slot_ptr;
desc_slot[EMPTY_SLOT_INDEX] = cpu_to_le64(EMPTY_SLOT);
}
static inline bool xgene_enet_is_desc_slot_empty(void *desc_slot_ptr)
{
__le64 *desc_slot = desc_slot_ptr;
return (desc_slot[EMPTY_SLOT_INDEX] == cpu_to_le64(EMPTY_SLOT));
}
enum xgene_enet_ring_cfgsize {
RING_CFGSIZE_512B,
RING_CFGSIZE_2KB,
RING_CFGSIZE_16KB,
RING_CFGSIZE_64KB,
RING_CFGSIZE_512KB,
RING_CFGSIZE_INVALID
};
enum xgene_enet_ring_type {
RING_DISABLED,
RING_REGULAR,
RING_BUFPOOL
};
enum xgene_ring_owner {
RING_OWNER_ETH0,
RING_OWNER_CPU = 15,
RING_OWNER_INVALID
};
enum xgene_enet_ring_bufnum {
RING_BUFNUM_REGULAR = 0x0,
RING_BUFNUM_BUFPOOL = 0x20,
RING_BUFNUM_INVALID
};
enum xgene_enet_cmd {
XGENE_ENET_WR_CMD = BIT(31),
XGENE_ENET_RD_CMD = BIT(30)
};
enum xgene_enet_err_code {
HBF_READ_DATA = 3,
HBF_LL_READ = 4,
BAD_WORK_MSG = 6,
BUFPOOL_TIMEOUT = 15,
INGRESS_CRC = 16,
INGRESS_CHECKSUM = 17,
INGRESS_TRUNC_FRAME = 18,
INGRESS_PKT_LEN = 19,
INGRESS_PKT_UNDER = 20,
INGRESS_FIFO_OVERRUN = 21,
INGRESS_CHECKSUM_COMPUTE = 26,
ERR_CODE_INVALID
};
static inline enum xgene_ring_owner xgene_enet_ring_owner(u16 id)
{
return (id & RING_OWNER_MASK) >> 6;
}
static inline u8 xgene_enet_ring_bufnum(u16 id)
{
return id & RING_BUFNUM_MASK;
}
static inline bool xgene_enet_is_bufpool(u16 id)
{
return ((id & RING_BUFNUM_MASK) >= 0x20) ? true : false;
}
static inline u16 xgene_enet_get_numslots(u16 id, u32 size)
{
bool is_bufpool = xgene_enet_is_bufpool(id);
return (is_bufpool) ? size / BUFPOOL_DESC_SIZE :
size / WORK_DESC_SIZE;
}
struct xgene_enet_desc_ring *xgene_enet_setup_ring(
struct xgene_enet_desc_ring *ring);
void xgene_enet_clear_ring(struct xgene_enet_desc_ring *ring);
void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring,
struct xgene_enet_pdata *pdata,
enum xgene_enet_err_code status);
void xgene_enet_reset(struct xgene_enet_pdata *priv);
void xgene_gmac_reset(struct xgene_enet_pdata *priv);
void xgene_gmac_init(struct xgene_enet_pdata *priv, int speed);
void xgene_gmac_tx_enable(struct xgene_enet_pdata *priv);
void xgene_gmac_rx_enable(struct xgene_enet_pdata *priv);
void xgene_gmac_tx_disable(struct xgene_enet_pdata *priv);
void xgene_gmac_rx_disable(struct xgene_enet_pdata *priv);
void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata);
void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata,
u32 dst_ring_num, u16 bufpool_id);
void xgene_gport_shutdown(struct xgene_enet_pdata *priv);
void xgene_gmac_get_tx_stats(struct xgene_enet_pdata *pdata);
int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata);
void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata);
#endif /* __XGENE_ENET_HW_H__ */
此差异已折叠。
/* Applied Micro X-Gene SoC Ethernet Driver
*
* Copyright (c) 2014, Applied Micro Circuits Corporation
* Authors: Iyappan Subramanian <isubramanian@apm.com>
* Ravi Patel <rapatel@apm.com>
* Keyur Chudgar <kchudgar@apm.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __XGENE_ENET_MAIN_H__
#define __XGENE_ENET_MAIN_H__
#include <linux/clk.h>
#include <linux/of_platform.h>
#include <linux/of_net.h>
#include <linux/of_mdio.h>
#include <linux/module.h>
#include <net/ip.h>
#include <linux/prefetch.h>
#include <linux/if_vlan.h>
#include <linux/phy.h>
#include "xgene_enet_hw.h"
#define XGENE_DRV_VERSION "v1.0"
#define XGENE_ENET_MAX_MTU 1536
#define SKB_BUFFER_SIZE (XGENE_ENET_MAX_MTU - NET_IP_ALIGN)
#define NUM_PKT_BUF 64
#define NUM_BUFPOOL 32
/* software context of a descriptor ring */
struct xgene_enet_desc_ring {
struct net_device *ndev;
u16 id;
u16 num;
u16 head;
u16 tail;
u16 slots;
u16 irq;
u32 size;
u32 state[NUM_RING_CONFIG];
void __iomem *cmd_base;
void __iomem *cmd;
dma_addr_t dma;
u16 dst_ring_num;
u8 nbufpool;
struct sk_buff *(*rx_skb);
struct sk_buff *(*cp_skb);
enum xgene_enet_ring_cfgsize cfgsize;
struct xgene_enet_desc_ring *cp_ring;
struct xgene_enet_desc_ring *buf_pool;
struct napi_struct napi;
union {
void *desc_addr;
struct xgene_enet_raw_desc *raw_desc;
struct xgene_enet_raw_desc16 *raw_desc16;
};
};
/* ethernet private data */
struct xgene_enet_pdata {
struct net_device *ndev;
struct mii_bus *mdio_bus;
struct phy_device *phy_dev;
int phy_speed;
struct clk *clk;
struct platform_device *pdev;
struct xgene_enet_desc_ring *tx_ring;
struct xgene_enet_desc_ring *rx_ring;
char *dev_name;
u32 rx_buff_cnt;
u32 tx_qcnt_hi;
u32 cp_qcnt_hi;
u32 cp_qcnt_low;
u32 rx_irq;
void __iomem *eth_csr_addr;
void __iomem *eth_ring_if_addr;
void __iomem *eth_diag_csr_addr;
void __iomem *mcx_mac_addr;
void __iomem *mcx_stats_addr;
void __iomem *mcx_mac_csr_addr;
void __iomem *base_addr;
void __iomem *ring_csr_addr;
void __iomem *ring_cmd_addr;
u32 phy_addr;
int phy_mode;
u32 speed;
u16 rm;
struct rtnl_link_stats64 stats;
};
/* Set the specified value into a bit-field defined by its starting position
* and length within a single u64.
*/
static inline u64 xgene_enet_set_field_value(int pos, int len, u64 val)
{
return (val & ((1ULL << len) - 1)) << pos;
}
#define SET_VAL(field, val) \
xgene_enet_set_field_value(field ## _POS, field ## _LEN, val)
#define SET_BIT(field) \
xgene_enet_set_field_value(field ## _POS, 1, 1)
/* Get the value from a bit-field defined by its starting position
* and length within the specified u64.
*/
static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src)
{
return (src >> pos) & ((1ULL << len) - 1);
}
#define GET_VAL(field, src) \
xgene_enet_get_field_value(field ## _POS, field ## _LEN, src)
static inline struct device *ndev_to_dev(struct net_device *ndev)
{
return ndev->dev.parent;
}
void xgene_enet_set_ethtool_ops(struct net_device *netdev);
#endif /* __XGENE_ENET_MAIN_H__ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册