Commit c156633f authored by Sergei Shtylyov's avatar Sergei Shtylyov Committed by David S. Miller
Browse files

Renesas Ethernet AVB driver proper



Ethernet AVB includes an Gigabit Ethernet controller (E-MAC) that is basically
compatible with SuperH Gigabit Ethernet E-MAC.  Ethernet AVB has  a  dedicated
direct memory access controller (AVB-DMAC) that is a new design compared to the
SuperH E-DMAC. The AVB-DMAC is compliant with 3 standards formulated for IEEE
802.1BA: IEEE 802.1AS timing and synchronization protocol, IEEE 802.1Qav real-
time transfer, and the IEEE 802.1Qat stream reservation protocol.

The  driver only supports device tree probing, so the binding document is
included in this patch.

Based on the original patches by Mitsuhiro Kimura.
Signed-off-by: default avatarMitsuhiro Kimura <mitsuhiro.kimura.kc@renesas.com>
Signed-off-by: default avatarSergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2b0a8c9e
* Renesas Electronics Ethernet AVB
This file provides information on what the device node for the Ethernet AVB
interface contains.
Required properties:
- compatible: "renesas,etheravb-r8a7790" if the device is a part of R8A7790 SoC.
"renesas,etheravb-r8a7794" if the device is a part of R8A7794 SoC.
- reg: offset and length of (1) the register block and (2) the stream buffer.
- interrupts: interrupt specifier for the sole interrupt.
- phy-mode: see ethernet.txt file in the same directory.
- phy-handle: see ethernet.txt file in the same directory.
- #address-cells: number of address cells for the MDIO bus, must be equal to 1.
- #size-cells: number of size cells on the MDIO bus, must be equal to 0.
- clocks: clock phandle and specifier pair.
- pinctrl-0: phandle, referring to a default pin configuration node.
Optional properties:
- interrupt-parent: the phandle for the interrupt controller that services
interrupts for this device.
- pinctrl-names: pin configuration state name ("default").
- renesas,no-ether-link: boolean, specify when a board does not provide a proper
AVB_LINK signal.
- renesas,ether-link-active-low: boolean, specify when the AVB_LINK signal is
active-low instead of normal active-high.
Example:
ethernet@e6800000 {
compatible = "renesas,etheravb-r8a7790";
reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>;
interrupt-parent = <&gic>;
interrupts = <0 163 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp8_clks R8A7790_CLK_ETHERAVB>;
phy-mode = "rmii";
phy-handle = <&phy0>;
pinctrl-0 = <&ether_pins>;
pinctrl-names = "default";
renesas,no-ether-link;
#address-cells = <1>;
#size-cells = <0>;
phy0: ethernet-phy@0 {
reg = <0>;
interrupt-parent = <&gpio2>;
interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
};
};
......@@ -2,6 +2,21 @@
# Renesas device configuration
#
config NET_VENDOR_RENESAS
bool "Renesas devices"
default y
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about Renesas devices. If you say Y, you will be asked
for your specific device in the following questions.
if NET_VENDOR_RENESAS
config SH_ETH
tristate "Renesas SuperH Ethernet support"
depends on HAS_DMA
......@@ -15,3 +30,19 @@ config SH_ETH
This driver supporting CPUs are:
- SH7619, SH7710, SH7712, SH7724, SH7734, SH7763, SH7757,
R8A7740, R8A777x and R8A779x.
config RAVB
tristate "Renesas Ethernet AVB support"
depends on HAS_DMA
depends on ARCH_SHMOBILE || COMPILE_TEST
select CRC32
select MII
select MDIO_BITBANG
select PHYLIB
select PTP_1588_CLOCK
help
Renesas Ethernet AVB device driver.
This driver supports the following SoCs:
- R8A779x.
endif # NET_VENDOR_RENESAS
......@@ -3,3 +3,4 @@
#
obj-$(CONFIG_SH_ETH) += sh_eth.o
obj-$(CONFIG_RAVB) += ravb.o
/* Renesas Ethernet AVB device driver
*
* Copyright (C) 2014-2015 Renesas Electronics Corporation
* Copyright (C) 2015 Renesas Solutions Corp.
* Copyright (C) 2015 Cogent Embedded, Inc. <source@cogentembedded.com>
*
* Based on the SuperH Ethernet driver
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*/
#include <linux/cache.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/net_tstamp.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include "ravb.h"
#define RAVB_DEF_MSG_ENABLE \
(NETIF_MSG_LINK | \
NETIF_MSG_TIMER | \
NETIF_MSG_RX_ERR | \
NETIF_MSG_TX_ERR)
static int ravb_wait(struct net_device *ndev, enum ravb_reg reg, u32 mask,
u32 value)
{
int i;
for (i = 0; i < 10000; i++) {
if ((ravb_read(ndev, reg) & mask) == value)
return 0;
udelay(10);
}
return -ETIMEDOUT;
}
static int ravb_config(struct net_device *ndev)
{
int error;
/* Set config mode */
ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_OPC) | CCC_OPC_CONFIG,
CCC);
/* Check if the operating mode is changed to the config mode */
error = ravb_wait(ndev, CSR, CSR_OPS, CSR_OPS_CONFIG);
if (error)
netdev_err(ndev, "failed to switch device to config mode\n");
return error;
}
static void ravb_set_duplex(struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
u32 ecmr = ravb_read(ndev, ECMR);
if (priv->duplex) /* Full */
ecmr |= ECMR_DM;
else /* Half */
ecmr &= ~ECMR_DM;
ravb_write(ndev, ecmr, ECMR);
}
static void ravb_set_rate(struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
switch (priv->speed) {
case 100: /* 100BASE */
ravb_write(ndev, GECMR_SPEED_100, GECMR);
break;
case 1000: /* 1000BASE */
ravb_write(ndev, GECMR_SPEED_1000, GECMR);
break;
default:
break;
}
}
static void ravb_set_buffer_align(struct sk_buff *skb)
{
u32 reserve = (unsigned long)skb->data & (RAVB_ALIGN - 1);
if (reserve)
skb_reserve(skb, RAVB_ALIGN - reserve);
}
/* Get MAC address from the MAC address registers
*
* Ethernet AVB device doesn't have ROM for MAC address.
* This function gets the MAC address that was used by a bootloader.
*/
static void ravb_read_mac_address(struct net_device *ndev, const u8 *mac)
{
if (mac) {
ether_addr_copy(ndev->dev_addr, mac);
} else {
ndev->dev_addr[0] = (ravb_read(ndev, MAHR) >> 24);
ndev->dev_addr[1] = (ravb_read(ndev, MAHR) >> 16) & 0xFF;
ndev->dev_addr[2] = (ravb_read(ndev, MAHR) >> 8) & 0xFF;
ndev->dev_addr[3] = (ravb_read(ndev, MAHR) >> 0) & 0xFF;
ndev->dev_addr[4] = (ravb_read(ndev, MALR) >> 8) & 0xFF;
ndev->dev_addr[5] = (ravb_read(ndev, MALR) >> 0) & 0xFF;
}
}
static void ravb_mdio_ctrl(struct mdiobb_ctrl *ctrl, u32 mask, int set)
{
struct ravb_private *priv = container_of(ctrl, struct ravb_private,
mdiobb);
u32 pir = ravb_read(priv->ndev, PIR);
if (set)
pir |= mask;
else
pir &= ~mask;
ravb_write(priv->ndev, pir, PIR);
}
/* MDC pin control */
static void ravb_set_mdc(struct mdiobb_ctrl *ctrl, int level)
{
ravb_mdio_ctrl(ctrl, PIR_MDC, level);
}
/* Data I/O pin control */
static void ravb_set_mdio_dir(struct mdiobb_ctrl *ctrl, int output)
{
ravb_mdio_ctrl(ctrl, PIR_MMD, output);
}
/* Set data bit */
static void ravb_set_mdio_data(struct mdiobb_ctrl *ctrl, int value)
{
ravb_mdio_ctrl(ctrl, PIR_MDO, value);
}
/* Get data bit */
static int ravb_get_mdio_data(struct mdiobb_ctrl *ctrl)
{
struct ravb_private *priv = container_of(ctrl, struct ravb_private,
mdiobb);
return (ravb_read(priv->ndev, PIR) & PIR_MDI) != 0;
}
/* MDIO bus control struct */
static struct mdiobb_ops bb_ops = {
.owner = THIS_MODULE,
.set_mdc = ravb_set_mdc,
.set_mdio_dir = ravb_set_mdio_dir,
.set_mdio_data = ravb_set_mdio_data,
.get_mdio_data = ravb_get_mdio_data,
};
/* Free skb's and DMA buffers for Ethernet AVB */
static void ravb_ring_free(struct net_device *ndev, int q)
{
struct ravb_private *priv = netdev_priv(ndev);
int ring_size;
int i;
/* Free RX skb ringbuffer */
if (priv->rx_skb[q]) {
for (i = 0; i < priv->num_rx_ring[q]; i++)
dev_kfree_skb(priv->rx_skb[q][i]);
}
kfree(priv->rx_skb[q]);
priv->rx_skb[q] = NULL;
/* Free TX skb ringbuffer */
if (priv->tx_skb[q]) {
for (i = 0; i < priv->num_tx_ring[q]; i++)
dev_kfree_skb(priv->tx_skb[q][i]);
}
kfree(priv->tx_skb[q]);
priv->tx_skb[q] = NULL;
/* Free aligned TX buffers */
if (priv->tx_buffers[q]) {
for (i = 0; i < priv->num_tx_ring[q]; i++)
kfree(priv->tx_buffers[q][i]);
}
kfree(priv->tx_buffers[q]);
priv->tx_buffers[q] = NULL;
if (priv->rx_ring[q]) {
ring_size = sizeof(struct ravb_ex_rx_desc) *
(priv->num_rx_ring[q] + 1);
dma_free_coherent(NULL, ring_size, priv->rx_ring[q],
priv->rx_desc_dma[q]);
priv->rx_ring[q] = NULL;
}
if (priv->tx_ring[q]) {
ring_size = sizeof(struct ravb_tx_desc) *
(priv->num_tx_ring[q] + 1);
dma_free_coherent(NULL, ring_size, priv->tx_ring[q],
priv->tx_desc_dma[q]);
priv->tx_ring[q] = NULL;
}
}
/* Format skb and descriptor buffer for Ethernet AVB */
static void ravb_ring_format(struct net_device *ndev, int q)
{
struct ravb_private *priv = netdev_priv(ndev);
struct ravb_ex_rx_desc *rx_desc = NULL;
struct ravb_tx_desc *tx_desc = NULL;
struct ravb_desc *desc = NULL;
int rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q];
int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q];
struct sk_buff *skb;
dma_addr_t dma_addr;
void *buffer;
int i;
priv->cur_rx[q] = 0;
priv->cur_tx[q] = 0;
priv->dirty_rx[q] = 0;
priv->dirty_tx[q] = 0;
memset(priv->rx_ring[q], 0, rx_ring_size);
/* Build RX ring buffer */
for (i = 0; i < priv->num_rx_ring[q]; i++) {
priv->rx_skb[q][i] = NULL;
skb = netdev_alloc_skb(ndev, PKT_BUF_SZ + RAVB_ALIGN - 1);
if (!skb)
break;
ravb_set_buffer_align(skb);
/* RX descriptor */
rx_desc = &priv->rx_ring[q][i];
/* The size of the buffer should be on 16-byte boundary. */
rx_desc->ds_cc = cpu_to_le16(ALIGN(PKT_BUF_SZ, 16));
dma_addr = dma_map_single(&ndev->dev, skb->data,
ALIGN(PKT_BUF_SZ, 16),
DMA_FROM_DEVICE);
if (dma_mapping_error(&ndev->dev, dma_addr)) {
dev_kfree_skb(skb);
break;
}
priv->rx_skb[q][i] = skb;
rx_desc->dptr = cpu_to_le32(dma_addr);
rx_desc->die_dt = DT_FEMPTY;
}
rx_desc = &priv->rx_ring[q][i];
rx_desc->dptr = cpu_to_le32((u32)priv->rx_desc_dma[q]);
rx_desc->die_dt = DT_LINKFIX; /* type */
priv->dirty_rx[q] = (u32)(i - priv->num_rx_ring[q]);
memset(priv->tx_ring[q], 0, tx_ring_size);
/* Build TX ring buffer */
for (i = 0; i < priv->num_tx_ring[q]; i++) {
priv->tx_skb[q][i] = NULL;
priv->tx_buffers[q][i] = NULL;
buffer = kmalloc(PKT_BUF_SZ + RAVB_ALIGN - 1, GFP_KERNEL);
if (!buffer)
break;
/* Aligned TX buffer */
priv->tx_buffers[q][i] = buffer;
tx_desc = &priv->tx_ring[q][i];
tx_desc->die_dt = DT_EEMPTY;
}
tx_desc = &priv->tx_ring[q][i];
tx_desc->dptr = cpu_to_le32((u32)priv->tx_desc_dma[q]);
tx_desc->die_dt = DT_LINKFIX; /* type */
/* RX descriptor base address for best effort */
desc = &priv->desc_bat[RX_QUEUE_OFFSET + q];
desc->die_dt = DT_LINKFIX; /* type */
desc->dptr = cpu_to_le32((u32)priv->rx_desc_dma[q]);
/* TX descriptor base address for best effort */
desc = &priv->desc_bat[q];
desc->die_dt = DT_LINKFIX; /* type */
desc->dptr = cpu_to_le32((u32)priv->tx_desc_dma[q]);
}
/* Init skb and descriptor buffer for Ethernet AVB */
static int ravb_ring_init(struct net_device *ndev, int q)
{
struct ravb_private *priv = netdev_priv(ndev);
int ring_size;
/* Allocate RX and TX skb rings */
priv->rx_skb[q] = kcalloc(priv->num_rx_ring[q],
sizeof(*priv->rx_skb[q]), GFP_KERNEL);
priv->tx_skb[q] = kcalloc(priv->num_tx_ring[q],
sizeof(*priv->tx_skb[q]), GFP_KERNEL);
if (!priv->rx_skb[q] || !priv->tx_skb[q])
goto error;
/* Allocate rings for the aligned buffers */
priv->tx_buffers[q] = kcalloc(priv->num_tx_ring[q],
sizeof(*priv->tx_buffers[q]), GFP_KERNEL);
if (!priv->tx_buffers[q])
goto error;
/* Allocate all RX descriptors. */
ring_size = sizeof(struct ravb_ex_rx_desc) * (priv->num_rx_ring[q] + 1);
priv->rx_ring[q] = dma_alloc_coherent(NULL, ring_size,
&priv->rx_desc_dma[q],
GFP_KERNEL);
if (!priv->rx_ring[q])
goto error;
priv->dirty_rx[q] = 0;
/* Allocate all TX descriptors. */
ring_size = sizeof(struct ravb_tx_desc) * (priv->num_tx_ring[q] + 1);
priv->tx_ring[q] = dma_alloc_coherent(NULL, ring_size,
&priv->tx_desc_dma[q],
GFP_KERNEL);
if (!priv->tx_ring[q])
goto error;
return 0;
error:
ravb_ring_free(ndev, q);
return -ENOMEM;
}
/* E-MAC init function */
static void ravb_emac_init(struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
u32 ecmr;
/* Receive frame limit set register */
ravb_write(ndev, ndev->mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN, RFLR);
/* PAUSE prohibition */
ecmr = ravb_read(ndev, ECMR);
ecmr &= ECMR_DM;
ecmr |= ECMR_ZPF | (priv->duplex ? ECMR_DM : 0) | ECMR_TE | ECMR_RE;
ravb_write(ndev, ecmr, ECMR);
ravb_set_rate(ndev);
/* Set MAC address */
ravb_write(ndev,
(ndev->dev_addr[0] << 24) | (ndev->dev_addr[1] << 16) |
(ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]), MAHR);
ravb_write(ndev,
(ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]), MALR);
ravb_write(ndev, 1, MPR);
/* E-MAC status register clear */
ravb_write(ndev, ECSR_ICD | ECSR_MPD, ECSR);
/* E-MAC interrupt enable register */
ravb_write(ndev, ECSIPR_ICDIP | ECSIPR_MPDIP | ECSIPR_LCHNGIP, ECSIPR);
}
/* Device init function for Ethernet AVB */
static int ravb_dmac_init(struct net_device *ndev)
{
int error;
/* Set CONFIG mode */
error = ravb_config(ndev);
if (error)
return error;
error = ravb_ring_init(ndev, RAVB_BE);
if (error)
return error;
error = ravb_ring_init(ndev, RAVB_NC);
if (error) {
ravb_ring_free(ndev, RAVB_BE);
return error;
}
/* Descriptor format */
ravb_ring_format(ndev, RAVB_BE);
ravb_ring_format(ndev, RAVB_NC);
#if defined(__LITTLE_ENDIAN)
ravb_write(ndev, ravb_read(ndev, CCC) & ~CCC_BOC, CCC);
#else
ravb_write(ndev, ravb_read(ndev, CCC) | CCC_BOC, CCC);
#endif
/* Set AVB RX */
ravb_write(ndev, RCR_EFFS | RCR_ENCF | RCR_ETS0 | 0x18000000, RCR);
/* Set FIFO size */
ravb_write(ndev, TGC_TQP_AVBMODE1 | 0x00222200, TGC);
/* Timestamp enable */
ravb_write(ndev, TCCR_TFEN, TCCR);
/* Interrupt enable: */
/* Frame receive */
ravb_write(ndev, RIC0_FRE0 | RIC0_FRE1, RIC0);
/* Receive FIFO full warning */
ravb_write(ndev, RIC1_RFWE, RIC1);
/* Receive FIFO full error, descriptor empty */
ravb_write(ndev, RIC2_QFE0 | RIC2_QFE1 | RIC2_RFFE, RIC2);
/* Frame transmitted, timestamp FIFO updated */
ravb_write(ndev, TIC_FTE0 | TIC_FTE1 | TIC_TFUE, TIC);
/* Setting the control will start the AVB-DMAC process. */
ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_OPC) | CCC_OPC_OPERATION,
CCC);
return 0;
}
/* Free TX skb function for AVB-IP */
static int ravb_tx_free(struct net_device *ndev, int q)
{
struct ravb_private *priv = netdev_priv(ndev);
struct net_device_stats *stats = &priv->stats[q];
struct ravb_tx_desc *desc;
int free_num = 0;
int entry = 0;
u32 size;
for (; priv->cur_tx[q] - priv->dirty_tx[q] > 0; priv->dirty_tx[q]++) {
entry = priv->dirty_tx[q] % priv->num_tx_ring[q];
desc = &priv->tx_ring[q][entry];
if (desc->die_dt != DT_FEMPTY)
break;
/* Descriptor type must be checked before all other reads */
dma_rmb();
size = le16_to_cpu(desc->ds_tagl) & TX_DS;
/* Free the original skb. */
if (priv->tx_skb[q][entry]) {
dma_unmap_single(&ndev->dev, le32_to_cpu(desc->dptr),
size, DMA_TO_DEVICE);
dev_kfree_skb_any(priv->tx_skb[q][entry]);
priv->tx_skb[q][entry] = NULL;
free_num++;
}
stats->tx_packets++;
stats->tx_bytes += size;
desc->die_dt = DT_EEMPTY;
}
return free_num;
}
static void ravb_get_tx_tstamp(struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
struct ravb_tstamp_skb *ts_skb, *ts_skb2;
struct skb_shared_hwtstamps shhwtstamps;
struct sk_buff *skb;
struct timespec64 ts;
u16 tag, tfa_tag;
int count;
u32 tfa2;
count = (ravb_read(ndev, TSR) & TSR_TFFL) >> 8;
while (count--) {
tfa2 = ravb_read(ndev, TFA2);
tfa_tag = (tfa2 & TFA2_TST) >> 16;
ts.tv_nsec = (u64)ravb_read(ndev, TFA0);
ts.tv_sec = ((u64)(tfa2 & TFA2_TSV) << 32) |
ravb_read(ndev, TFA1);
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
shhwtstamps.hwtstamp = timespec64_to_ktime(ts);
list_for_each_entry_safe(ts_skb, ts_skb2, &priv->ts_skb_list,
list) {
skb = ts_skb->skb;
tag = ts_skb->tag;
list_del(&ts_skb->list);
kfree(ts_skb);
if (tag == tfa_tag) {
skb_tstamp_tx(skb, &shhwtstamps);
break;
}
}
ravb_write(ndev, ravb_read(ndev, TCCR) | TCCR_TFR, TCCR);
}
}
/* Packet receive function for Ethernet AVB */
static bool ravb_rx(struct net_device *ndev, int *quota, int q)
{
struct ravb_private *priv = netdev_priv(ndev);
int entry = priv->cur_rx[q] % priv->num_rx_ring[q];
int boguscnt = (priv->dirty_rx[q] + priv->num_rx_ring[q]) -
priv->cur_rx[q];
struct net_device_stats *stats = &priv->stats[q];
struct ravb_ex_rx_desc *desc;