162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci /*
362306a36Sopenharmony_ci * drivers/net/ethernet/ec_bhf.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2014 Darek Marcinkiewicz <reksio@newterm.pl>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/* This is a driver for EtherCAT master module present on CCAT FPGA.
962306a36Sopenharmony_ci * Those can be found on Bechhoff CX50xx industrial PCs.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/moduleparam.h>
1562306a36Sopenharmony_ci#include <linux/pci.h>
1662306a36Sopenharmony_ci#include <linux/init.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/netdevice.h>
1962306a36Sopenharmony_ci#include <linux/etherdevice.h>
2062306a36Sopenharmony_ci#include <linux/ip.h>
2162306a36Sopenharmony_ci#include <linux/skbuff.h>
2262306a36Sopenharmony_ci#include <linux/hrtimer.h>
2362306a36Sopenharmony_ci#include <linux/interrupt.h>
2462306a36Sopenharmony_ci#include <linux/stat.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define TIMER_INTERVAL_NSEC	20000
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define INFO_BLOCK_SIZE		0x10
2962306a36Sopenharmony_ci#define INFO_BLOCK_TYPE		0x0
3062306a36Sopenharmony_ci#define INFO_BLOCK_REV		0x2
3162306a36Sopenharmony_ci#define INFO_BLOCK_BLK_CNT	0x4
3262306a36Sopenharmony_ci#define INFO_BLOCK_TX_CHAN	0x4
3362306a36Sopenharmony_ci#define INFO_BLOCK_RX_CHAN	0x5
3462306a36Sopenharmony_ci#define INFO_BLOCK_OFFSET	0x8
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define EC_MII_OFFSET		0x4
3762306a36Sopenharmony_ci#define EC_FIFO_OFFSET		0x8
3862306a36Sopenharmony_ci#define EC_MAC_OFFSET		0xc
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define MAC_FRAME_ERR_CNT	0x0
4162306a36Sopenharmony_ci#define MAC_RX_ERR_CNT		0x1
4262306a36Sopenharmony_ci#define MAC_CRC_ERR_CNT		0x2
4362306a36Sopenharmony_ci#define MAC_LNK_LST_ERR_CNT	0x3
4462306a36Sopenharmony_ci#define MAC_TX_FRAME_CNT	0x10
4562306a36Sopenharmony_ci#define MAC_RX_FRAME_CNT	0x14
4662306a36Sopenharmony_ci#define MAC_TX_FIFO_LVL		0x20
4762306a36Sopenharmony_ci#define MAC_DROPPED_FRMS	0x28
4862306a36Sopenharmony_ci#define MAC_CONNECTED_CCAT_FLAG	0x78
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define MII_MAC_ADDR		0x8
5162306a36Sopenharmony_ci#define MII_MAC_FILT_FLAG	0xe
5262306a36Sopenharmony_ci#define MII_LINK_STATUS		0xf
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define FIFO_TX_REG		0x0
5562306a36Sopenharmony_ci#define FIFO_TX_RESET		0x8
5662306a36Sopenharmony_ci#define FIFO_RX_REG		0x10
5762306a36Sopenharmony_ci#define FIFO_RX_ADDR_VALID	(1u << 31)
5862306a36Sopenharmony_ci#define FIFO_RX_RESET		0x18
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define DMA_CHAN_OFFSET		0x1000
6162306a36Sopenharmony_ci#define DMA_CHAN_SIZE		0x8
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define DMA_WINDOW_SIZE_MASK	0xfffffffc
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#define ETHERCAT_MASTER_ID	0x14
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic const struct pci_device_id ids[] = {
6862306a36Sopenharmony_ci	{ PCI_DEVICE(0x15ec, 0x5000), },
6962306a36Sopenharmony_ci	{ 0, }
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ids);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistruct rx_header {
7462306a36Sopenharmony_ci#define RXHDR_NEXT_ADDR_MASK	0xffffffu
7562306a36Sopenharmony_ci#define RXHDR_NEXT_VALID	(1u << 31)
7662306a36Sopenharmony_ci	__le32 next;
7762306a36Sopenharmony_ci#define RXHDR_NEXT_RECV_FLAG	0x1
7862306a36Sopenharmony_ci	__le32 recv;
7962306a36Sopenharmony_ci#define RXHDR_LEN_MASK		0xfffu
8062306a36Sopenharmony_ci	__le16 len;
8162306a36Sopenharmony_ci	__le16 port;
8262306a36Sopenharmony_ci	__le32 reserved;
8362306a36Sopenharmony_ci	u8 timestamp[8];
8462306a36Sopenharmony_ci} __packed;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#define PKT_PAYLOAD_SIZE	0x7e8
8762306a36Sopenharmony_cistruct rx_desc {
8862306a36Sopenharmony_ci	struct rx_header header;
8962306a36Sopenharmony_ci	u8 data[PKT_PAYLOAD_SIZE];
9062306a36Sopenharmony_ci} __packed;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistruct tx_header {
9362306a36Sopenharmony_ci	__le16 len;
9462306a36Sopenharmony_ci#define TX_HDR_PORT_0		0x1
9562306a36Sopenharmony_ci#define TX_HDR_PORT_1		0x2
9662306a36Sopenharmony_ci	u8 port;
9762306a36Sopenharmony_ci	u8 ts_enable;
9862306a36Sopenharmony_ci#define TX_HDR_SENT		0x1
9962306a36Sopenharmony_ci	__le32 sent;
10062306a36Sopenharmony_ci	u8 timestamp[8];
10162306a36Sopenharmony_ci} __packed;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistruct tx_desc {
10462306a36Sopenharmony_ci	struct tx_header header;
10562306a36Sopenharmony_ci	u8 data[PKT_PAYLOAD_SIZE];
10662306a36Sopenharmony_ci} __packed;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#define FIFO_SIZE		64
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic long polling_frequency = TIMER_INTERVAL_NSEC;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistruct bhf_dma {
11362306a36Sopenharmony_ci	u8 *buf;
11462306a36Sopenharmony_ci	size_t len;
11562306a36Sopenharmony_ci	dma_addr_t buf_phys;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	u8 *alloc;
11862306a36Sopenharmony_ci	size_t alloc_len;
11962306a36Sopenharmony_ci	dma_addr_t alloc_phys;
12062306a36Sopenharmony_ci};
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistruct ec_bhf_priv {
12362306a36Sopenharmony_ci	struct net_device *net_dev;
12462306a36Sopenharmony_ci	struct pci_dev *dev;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	void __iomem *io;
12762306a36Sopenharmony_ci	void __iomem *dma_io;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	struct hrtimer hrtimer;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	int tx_dma_chan;
13262306a36Sopenharmony_ci	int rx_dma_chan;
13362306a36Sopenharmony_ci	void __iomem *ec_io;
13462306a36Sopenharmony_ci	void __iomem *fifo_io;
13562306a36Sopenharmony_ci	void __iomem *mii_io;
13662306a36Sopenharmony_ci	void __iomem *mac_io;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	struct bhf_dma rx_buf;
13962306a36Sopenharmony_ci	struct rx_desc *rx_descs;
14062306a36Sopenharmony_ci	int rx_dnext;
14162306a36Sopenharmony_ci	int rx_dcount;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	struct bhf_dma tx_buf;
14462306a36Sopenharmony_ci	struct tx_desc *tx_descs;
14562306a36Sopenharmony_ci	int tx_dcount;
14662306a36Sopenharmony_ci	int tx_dnext;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	u64 stat_rx_bytes;
14962306a36Sopenharmony_ci	u64 stat_tx_bytes;
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci#define PRIV_TO_DEV(priv) (&(priv)->dev->dev)
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic void ec_bhf_reset(struct ec_bhf_priv *priv)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	iowrite8(0, priv->mac_io + MAC_FRAME_ERR_CNT);
15762306a36Sopenharmony_ci	iowrite8(0, priv->mac_io + MAC_RX_ERR_CNT);
15862306a36Sopenharmony_ci	iowrite8(0, priv->mac_io + MAC_CRC_ERR_CNT);
15962306a36Sopenharmony_ci	iowrite8(0, priv->mac_io + MAC_LNK_LST_ERR_CNT);
16062306a36Sopenharmony_ci	iowrite32(0, priv->mac_io + MAC_TX_FRAME_CNT);
16162306a36Sopenharmony_ci	iowrite32(0, priv->mac_io + MAC_RX_FRAME_CNT);
16262306a36Sopenharmony_ci	iowrite8(0, priv->mac_io + MAC_DROPPED_FRMS);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	iowrite8(0, priv->fifo_io + FIFO_TX_RESET);
16562306a36Sopenharmony_ci	iowrite8(0, priv->fifo_io + FIFO_RX_RESET);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	iowrite8(0, priv->mac_io + MAC_TX_FIFO_LVL);
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic void ec_bhf_send_packet(struct ec_bhf_priv *priv, struct tx_desc *desc)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	u32 len = le16_to_cpu(desc->header.len) + sizeof(desc->header);
17362306a36Sopenharmony_ci	u32 addr = (u8 *)desc - priv->tx_buf.buf;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	iowrite32((ALIGN(len, 8) << 24) | addr, priv->fifo_io + FIFO_TX_REG);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic int ec_bhf_desc_sent(struct tx_desc *desc)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	return le32_to_cpu(desc->header.sent) & TX_HDR_SENT;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic void ec_bhf_process_tx(struct ec_bhf_priv *priv)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	if (unlikely(netif_queue_stopped(priv->net_dev))) {
18662306a36Sopenharmony_ci		/* Make sure that we perceive changes to tx_dnext. */
18762306a36Sopenharmony_ci		smp_rmb();
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci		if (ec_bhf_desc_sent(&priv->tx_descs[priv->tx_dnext]))
19062306a36Sopenharmony_ci			netif_wake_queue(priv->net_dev);
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic int ec_bhf_pkt_received(struct rx_desc *desc)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	return le32_to_cpu(desc->header.recv) & RXHDR_NEXT_RECV_FLAG;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic void ec_bhf_add_rx_desc(struct ec_bhf_priv *priv, struct rx_desc *desc)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	iowrite32(FIFO_RX_ADDR_VALID | ((u8 *)(desc) - priv->rx_buf.buf),
20262306a36Sopenharmony_ci		  priv->fifo_io + FIFO_RX_REG);
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic void ec_bhf_process_rx(struct ec_bhf_priv *priv)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	struct rx_desc *desc = &priv->rx_descs[priv->rx_dnext];
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	while (ec_bhf_pkt_received(desc)) {
21062306a36Sopenharmony_ci		int pkt_size = (le16_to_cpu(desc->header.len) &
21162306a36Sopenharmony_ci			       RXHDR_LEN_MASK) - sizeof(struct rx_header) - 4;
21262306a36Sopenharmony_ci		u8 *data = desc->data;
21362306a36Sopenharmony_ci		struct sk_buff *skb;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		skb = netdev_alloc_skb_ip_align(priv->net_dev, pkt_size);
21662306a36Sopenharmony_ci		if (skb) {
21762306a36Sopenharmony_ci			skb_put_data(skb, data, pkt_size);
21862306a36Sopenharmony_ci			skb->protocol = eth_type_trans(skb, priv->net_dev);
21962306a36Sopenharmony_ci			priv->stat_rx_bytes += pkt_size;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci			netif_rx(skb);
22262306a36Sopenharmony_ci		} else {
22362306a36Sopenharmony_ci			dev_err_ratelimited(PRIV_TO_DEV(priv),
22462306a36Sopenharmony_ci					    "Couldn't allocate a skb_buff for a packet of size %u\n",
22562306a36Sopenharmony_ci					    pkt_size);
22662306a36Sopenharmony_ci		}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci		desc->header.recv = 0;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci		ec_bhf_add_rx_desc(priv, desc);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci		priv->rx_dnext = (priv->rx_dnext + 1) % priv->rx_dcount;
23362306a36Sopenharmony_ci		desc = &priv->rx_descs[priv->rx_dnext];
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic enum hrtimer_restart ec_bhf_timer_fun(struct hrtimer *timer)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	struct ec_bhf_priv *priv = container_of(timer, struct ec_bhf_priv,
24062306a36Sopenharmony_ci						hrtimer);
24162306a36Sopenharmony_ci	ec_bhf_process_rx(priv);
24262306a36Sopenharmony_ci	ec_bhf_process_tx(priv);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (!netif_running(priv->net_dev))
24562306a36Sopenharmony_ci		return HRTIMER_NORESTART;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	hrtimer_forward_now(timer, polling_frequency);
24862306a36Sopenharmony_ci	return HRTIMER_RESTART;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int ec_bhf_setup_offsets(struct ec_bhf_priv *priv)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	struct device *dev = PRIV_TO_DEV(priv);
25462306a36Sopenharmony_ci	unsigned block_count, i;
25562306a36Sopenharmony_ci	void __iomem *ec_info;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	block_count = ioread8(priv->io + INFO_BLOCK_BLK_CNT);
25862306a36Sopenharmony_ci	for (i = 0; i < block_count; i++) {
25962306a36Sopenharmony_ci		u16 type = ioread16(priv->io + i * INFO_BLOCK_SIZE +
26062306a36Sopenharmony_ci				    INFO_BLOCK_TYPE);
26162306a36Sopenharmony_ci		if (type == ETHERCAT_MASTER_ID)
26262306a36Sopenharmony_ci			break;
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci	if (i == block_count) {
26562306a36Sopenharmony_ci		dev_err(dev, "EtherCAT master with DMA block not found\n");
26662306a36Sopenharmony_ci		return -ENODEV;
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	ec_info = priv->io + i * INFO_BLOCK_SIZE;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	priv->tx_dma_chan = ioread8(ec_info + INFO_BLOCK_TX_CHAN);
27262306a36Sopenharmony_ci	priv->rx_dma_chan = ioread8(ec_info + INFO_BLOCK_RX_CHAN);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	priv->ec_io = priv->io + ioread32(ec_info + INFO_BLOCK_OFFSET);
27562306a36Sopenharmony_ci	priv->mii_io = priv->ec_io + ioread32(priv->ec_io + EC_MII_OFFSET);
27662306a36Sopenharmony_ci	priv->fifo_io = priv->ec_io + ioread32(priv->ec_io + EC_FIFO_OFFSET);
27762306a36Sopenharmony_ci	priv->mac_io = priv->ec_io + ioread32(priv->ec_io + EC_MAC_OFFSET);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	return 0;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic netdev_tx_t ec_bhf_start_xmit(struct sk_buff *skb,
28362306a36Sopenharmony_ci				     struct net_device *net_dev)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	struct ec_bhf_priv *priv = netdev_priv(net_dev);
28662306a36Sopenharmony_ci	struct tx_desc *desc;
28762306a36Sopenharmony_ci	unsigned len;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	desc = &priv->tx_descs[priv->tx_dnext];
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	skb_copy_and_csum_dev(skb, desc->data);
29262306a36Sopenharmony_ci	len = skb->len;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	memset(&desc->header, 0, sizeof(desc->header));
29562306a36Sopenharmony_ci	desc->header.len = cpu_to_le16(len);
29662306a36Sopenharmony_ci	desc->header.port = TX_HDR_PORT_0;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	ec_bhf_send_packet(priv, desc);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	priv->tx_dnext = (priv->tx_dnext + 1) % priv->tx_dcount;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (!ec_bhf_desc_sent(&priv->tx_descs[priv->tx_dnext])) {
30362306a36Sopenharmony_ci		/* Make sure that updates to tx_dnext are perceived
30462306a36Sopenharmony_ci		 * by timer routine.
30562306a36Sopenharmony_ci		 */
30662306a36Sopenharmony_ci		smp_wmb();
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci		netif_stop_queue(net_dev);
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	priv->stat_tx_bytes += len;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	dev_kfree_skb(skb);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	return NETDEV_TX_OK;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic int ec_bhf_alloc_dma_mem(struct ec_bhf_priv *priv,
31962306a36Sopenharmony_ci				struct bhf_dma *buf,
32062306a36Sopenharmony_ci				int channel,
32162306a36Sopenharmony_ci				int size)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	int offset = channel * DMA_CHAN_SIZE + DMA_CHAN_OFFSET;
32462306a36Sopenharmony_ci	struct device *dev = PRIV_TO_DEV(priv);
32562306a36Sopenharmony_ci	u32 mask;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	iowrite32(0xffffffff, priv->dma_io + offset);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	mask = ioread32(priv->dma_io + offset);
33062306a36Sopenharmony_ci	mask &= DMA_WINDOW_SIZE_MASK;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	/* We want to allocate a chunk of memory that is:
33362306a36Sopenharmony_ci	 * - aligned to the mask we just read
33462306a36Sopenharmony_ci	 * - is of size 2^mask bytes (at most)
33562306a36Sopenharmony_ci	 * In order to ensure that we will allocate buffer of
33662306a36Sopenharmony_ci	 * 2 * 2^mask bytes.
33762306a36Sopenharmony_ci	 */
33862306a36Sopenharmony_ci	buf->len = min_t(int, ~mask + 1, size);
33962306a36Sopenharmony_ci	buf->alloc_len = 2 * buf->len;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	buf->alloc = dma_alloc_coherent(dev, buf->alloc_len, &buf->alloc_phys,
34262306a36Sopenharmony_ci					GFP_KERNEL);
34362306a36Sopenharmony_ci	if (buf->alloc == NULL) {
34462306a36Sopenharmony_ci		dev_err(dev, "Failed to allocate buffer\n");
34562306a36Sopenharmony_ci		return -ENOMEM;
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	buf->buf_phys = (buf->alloc_phys + buf->len) & mask;
34962306a36Sopenharmony_ci	buf->buf = buf->alloc + (buf->buf_phys - buf->alloc_phys);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	iowrite32(0, priv->dma_io + offset + 4);
35262306a36Sopenharmony_ci	iowrite32(buf->buf_phys, priv->dma_io + offset);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	return 0;
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic void ec_bhf_setup_tx_descs(struct ec_bhf_priv *priv)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	int i = 0;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	priv->tx_dcount = priv->tx_buf.len / sizeof(struct tx_desc);
36262306a36Sopenharmony_ci	priv->tx_descs = (struct tx_desc *)priv->tx_buf.buf;
36362306a36Sopenharmony_ci	priv->tx_dnext = 0;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	for (i = 0; i < priv->tx_dcount; i++)
36662306a36Sopenharmony_ci		priv->tx_descs[i].header.sent = cpu_to_le32(TX_HDR_SENT);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic void ec_bhf_setup_rx_descs(struct ec_bhf_priv *priv)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	int i;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	priv->rx_dcount = priv->rx_buf.len / sizeof(struct rx_desc);
37462306a36Sopenharmony_ci	priv->rx_descs = (struct rx_desc *)priv->rx_buf.buf;
37562306a36Sopenharmony_ci	priv->rx_dnext = 0;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	for (i = 0; i < priv->rx_dcount; i++) {
37862306a36Sopenharmony_ci		struct rx_desc *desc = &priv->rx_descs[i];
37962306a36Sopenharmony_ci		u32 next;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci		if (i != priv->rx_dcount - 1)
38262306a36Sopenharmony_ci			next = (u8 *)(desc + 1) - priv->rx_buf.buf;
38362306a36Sopenharmony_ci		else
38462306a36Sopenharmony_ci			next = 0;
38562306a36Sopenharmony_ci		next |= RXHDR_NEXT_VALID;
38662306a36Sopenharmony_ci		desc->header.next = cpu_to_le32(next);
38762306a36Sopenharmony_ci		desc->header.recv = 0;
38862306a36Sopenharmony_ci		ec_bhf_add_rx_desc(priv, desc);
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic int ec_bhf_open(struct net_device *net_dev)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	struct ec_bhf_priv *priv = netdev_priv(net_dev);
39562306a36Sopenharmony_ci	struct device *dev = PRIV_TO_DEV(priv);
39662306a36Sopenharmony_ci	int err = 0;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	ec_bhf_reset(priv);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	err = ec_bhf_alloc_dma_mem(priv, &priv->rx_buf, priv->rx_dma_chan,
40162306a36Sopenharmony_ci				   FIFO_SIZE * sizeof(struct rx_desc));
40262306a36Sopenharmony_ci	if (err) {
40362306a36Sopenharmony_ci		dev_err(dev, "Failed to allocate rx buffer\n");
40462306a36Sopenharmony_ci		goto out;
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci	ec_bhf_setup_rx_descs(priv);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	err = ec_bhf_alloc_dma_mem(priv, &priv->tx_buf, priv->tx_dma_chan,
40962306a36Sopenharmony_ci				   FIFO_SIZE * sizeof(struct tx_desc));
41062306a36Sopenharmony_ci	if (err) {
41162306a36Sopenharmony_ci		dev_err(dev, "Failed to allocate tx buffer\n");
41262306a36Sopenharmony_ci		goto error_rx_free;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci	iowrite8(0, priv->mii_io + MII_MAC_FILT_FLAG);
41562306a36Sopenharmony_ci	ec_bhf_setup_tx_descs(priv);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	netif_start_queue(net_dev);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	hrtimer_init(&priv->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
42062306a36Sopenharmony_ci	priv->hrtimer.function = ec_bhf_timer_fun;
42162306a36Sopenharmony_ci	hrtimer_start(&priv->hrtimer, polling_frequency, HRTIMER_MODE_REL);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	return 0;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cierror_rx_free:
42662306a36Sopenharmony_ci	dma_free_coherent(dev, priv->rx_buf.alloc_len, priv->rx_buf.alloc,
42762306a36Sopenharmony_ci			  priv->rx_buf.alloc_len);
42862306a36Sopenharmony_ciout:
42962306a36Sopenharmony_ci	return err;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic int ec_bhf_stop(struct net_device *net_dev)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct ec_bhf_priv *priv = netdev_priv(net_dev);
43562306a36Sopenharmony_ci	struct device *dev = PRIV_TO_DEV(priv);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	hrtimer_cancel(&priv->hrtimer);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	ec_bhf_reset(priv);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	netif_tx_disable(net_dev);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	dma_free_coherent(dev, priv->tx_buf.alloc_len,
44462306a36Sopenharmony_ci			  priv->tx_buf.alloc, priv->tx_buf.alloc_phys);
44562306a36Sopenharmony_ci	dma_free_coherent(dev, priv->rx_buf.alloc_len,
44662306a36Sopenharmony_ci			  priv->rx_buf.alloc, priv->rx_buf.alloc_phys);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	return 0;
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic void
45262306a36Sopenharmony_ciec_bhf_get_stats(struct net_device *net_dev,
45362306a36Sopenharmony_ci		 struct rtnl_link_stats64 *stats)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	struct ec_bhf_priv *priv = netdev_priv(net_dev);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	stats->rx_errors = ioread8(priv->mac_io + MAC_RX_ERR_CNT) +
45862306a36Sopenharmony_ci				ioread8(priv->mac_io + MAC_CRC_ERR_CNT) +
45962306a36Sopenharmony_ci				ioread8(priv->mac_io + MAC_FRAME_ERR_CNT);
46062306a36Sopenharmony_ci	stats->rx_packets = ioread32(priv->mac_io + MAC_RX_FRAME_CNT);
46162306a36Sopenharmony_ci	stats->tx_packets = ioread32(priv->mac_io + MAC_TX_FRAME_CNT);
46262306a36Sopenharmony_ci	stats->rx_dropped = ioread8(priv->mac_io + MAC_DROPPED_FRMS);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	stats->tx_bytes = priv->stat_tx_bytes;
46562306a36Sopenharmony_ci	stats->rx_bytes = priv->stat_rx_bytes;
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic const struct net_device_ops ec_bhf_netdev_ops = {
46962306a36Sopenharmony_ci	.ndo_start_xmit		= ec_bhf_start_xmit,
47062306a36Sopenharmony_ci	.ndo_open		= ec_bhf_open,
47162306a36Sopenharmony_ci	.ndo_stop		= ec_bhf_stop,
47262306a36Sopenharmony_ci	.ndo_get_stats64	= ec_bhf_get_stats,
47362306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
47462306a36Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr
47562306a36Sopenharmony_ci};
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic int ec_bhf_probe(struct pci_dev *dev, const struct pci_device_id *id)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	struct net_device *net_dev;
48062306a36Sopenharmony_ci	struct ec_bhf_priv *priv;
48162306a36Sopenharmony_ci	void __iomem *dma_io;
48262306a36Sopenharmony_ci	u8 addr[ETH_ALEN];
48362306a36Sopenharmony_ci	void __iomem *io;
48462306a36Sopenharmony_ci	int err = 0;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	err = pci_enable_device(dev);
48762306a36Sopenharmony_ci	if (err)
48862306a36Sopenharmony_ci		return err;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	pci_set_master(dev);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	err = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
49362306a36Sopenharmony_ci	if (err) {
49462306a36Sopenharmony_ci		dev_err(&dev->dev,
49562306a36Sopenharmony_ci			"Required dma mask not supported, failed to initialize device\n");
49662306a36Sopenharmony_ci		goto err_disable_dev;
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	err = pci_request_regions(dev, "ec_bhf");
50062306a36Sopenharmony_ci	if (err) {
50162306a36Sopenharmony_ci		dev_err(&dev->dev, "Failed to request pci memory regions\n");
50262306a36Sopenharmony_ci		goto err_disable_dev;
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	io = pci_iomap(dev, 0, 0);
50662306a36Sopenharmony_ci	if (!io) {
50762306a36Sopenharmony_ci		dev_err(&dev->dev, "Failed to map pci card memory bar 0");
50862306a36Sopenharmony_ci		err = -EIO;
50962306a36Sopenharmony_ci		goto err_release_regions;
51062306a36Sopenharmony_ci	}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	dma_io = pci_iomap(dev, 2, 0);
51362306a36Sopenharmony_ci	if (!dma_io) {
51462306a36Sopenharmony_ci		dev_err(&dev->dev, "Failed to map pci card memory bar 2");
51562306a36Sopenharmony_ci		err = -EIO;
51662306a36Sopenharmony_ci		goto err_unmap;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	net_dev = alloc_etherdev(sizeof(struct ec_bhf_priv));
52062306a36Sopenharmony_ci	if (net_dev == NULL) {
52162306a36Sopenharmony_ci		err = -ENOMEM;
52262306a36Sopenharmony_ci		goto err_unmap_dma_io;
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	pci_set_drvdata(dev, net_dev);
52662306a36Sopenharmony_ci	SET_NETDEV_DEV(net_dev, &dev->dev);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	net_dev->features = 0;
52962306a36Sopenharmony_ci	net_dev->flags |= IFF_NOARP;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	net_dev->netdev_ops = &ec_bhf_netdev_ops;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	priv = netdev_priv(net_dev);
53462306a36Sopenharmony_ci	priv->net_dev = net_dev;
53562306a36Sopenharmony_ci	priv->io = io;
53662306a36Sopenharmony_ci	priv->dma_io = dma_io;
53762306a36Sopenharmony_ci	priv->dev = dev;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	err = ec_bhf_setup_offsets(priv);
54062306a36Sopenharmony_ci	if (err < 0)
54162306a36Sopenharmony_ci		goto err_free_net_dev;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	memcpy_fromio(addr, priv->mii_io + MII_MAC_ADDR, ETH_ALEN);
54462306a36Sopenharmony_ci	eth_hw_addr_set(net_dev, addr);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	err = register_netdev(net_dev);
54762306a36Sopenharmony_ci	if (err < 0)
54862306a36Sopenharmony_ci		goto err_free_net_dev;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	return 0;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cierr_free_net_dev:
55362306a36Sopenharmony_ci	free_netdev(net_dev);
55462306a36Sopenharmony_cierr_unmap_dma_io:
55562306a36Sopenharmony_ci	pci_iounmap(dev, dma_io);
55662306a36Sopenharmony_cierr_unmap:
55762306a36Sopenharmony_ci	pci_iounmap(dev, io);
55862306a36Sopenharmony_cierr_release_regions:
55962306a36Sopenharmony_ci	pci_release_regions(dev);
56062306a36Sopenharmony_cierr_disable_dev:
56162306a36Sopenharmony_ci	pci_disable_device(dev);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	return err;
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_cistatic void ec_bhf_remove(struct pci_dev *dev)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	struct net_device *net_dev = pci_get_drvdata(dev);
56962306a36Sopenharmony_ci	struct ec_bhf_priv *priv = netdev_priv(net_dev);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	unregister_netdev(net_dev);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	pci_iounmap(dev, priv->dma_io);
57462306a36Sopenharmony_ci	pci_iounmap(dev, priv->io);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	free_netdev(net_dev);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	pci_release_regions(dev);
57962306a36Sopenharmony_ci	pci_disable_device(dev);
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic struct pci_driver pci_driver = {
58362306a36Sopenharmony_ci	.name		= "ec_bhf",
58462306a36Sopenharmony_ci	.id_table	= ids,
58562306a36Sopenharmony_ci	.probe		= ec_bhf_probe,
58662306a36Sopenharmony_ci	.remove		= ec_bhf_remove,
58762306a36Sopenharmony_ci};
58862306a36Sopenharmony_cimodule_pci_driver(pci_driver);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cimodule_param(polling_frequency, long, 0444);
59162306a36Sopenharmony_ciMODULE_PARM_DESC(polling_frequency, "Polling timer frequency in ns");
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
59462306a36Sopenharmony_ciMODULE_AUTHOR("Dariusz Marcinkiewicz <reksio@newterm.pl>");
595