From 50a212ec906f7524620675f0c57357691c26c81f Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Wed, 16 Oct 2024 01:20:19 +0000
Subject: [PATCH] 修改GPIO导出默认初始值
---
kernel/drivers/net/wan/fsl_ucc_hdlc.c | 209 ++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 169 insertions(+), 40 deletions(-)
diff --git a/kernel/drivers/net/wan/fsl_ucc_hdlc.c b/kernel/drivers/net/wan/fsl_ucc_hdlc.c
index 5df6e85..bc3650c 100644
--- a/kernel/drivers/net/wan/fsl_ucc_hdlc.c
+++ b/kernel/drivers/net/wan/fsl_ucc_hdlc.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/* Freescale QUICC Engine HDLC Device Driver
*
* Copyright 2016 Freescale Semiconductor Inc.
- *
- * 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.
*/
#include <linux/delay.h>
@@ -36,6 +32,9 @@
#define DRV_NAME "ucc_hdlc"
#define TDM_PPPOHT_SLIC_MAXIN
+#define RX_BD_ERRORS (R_CD_S | R_OV_S | R_CR_S | R_AB_S | R_NO_S | R_LG_S)
+
+static int uhdlc_close(struct net_device *dev);
static struct ucc_tdm_info utdm_primary_info = {
.uf_info = {
@@ -87,8 +86,8 @@
int ret, i;
void *bd_buffer;
dma_addr_t bd_dma_addr;
- u32 riptr;
- u32 tiptr;
+ s32 riptr;
+ s32 tiptr;
u32 gumr;
ut_info = priv->ut_info;
@@ -97,6 +96,12 @@
if (priv->tsa) {
uf_info->tsa = 1;
uf_info->ctsp = 1;
+ uf_info->cds = 1;
+ uf_info->ctss = 1;
+ } else {
+ uf_info->cds = 0;
+ uf_info->ctsp = 0;
+ uf_info->ctss = 0;
}
/* This sets HPM register in CMXUCR register which configures a
@@ -192,7 +197,7 @@
priv->ucc_pram_offset = qe_muram_alloc(sizeof(struct ucc_hdlc_param),
ALIGNMENT_OF_UCC_HDLC_PRAM);
- if (IS_ERR_VALUE(priv->ucc_pram_offset)) {
+ if (priv->ucc_pram_offset < 0) {
dev_err(priv->dev, "Can not allocate MURAM for hdlc parameter.\n");
ret = -ENOMEM;
goto free_tx_bd;
@@ -234,14 +239,14 @@
/* Alloc riptr, tiptr */
riptr = qe_muram_alloc(32, 32);
- if (IS_ERR_VALUE(riptr)) {
+ if (riptr < 0) {
dev_err(priv->dev, "Cannot allocate MURAM mem for Receive internal temp data pointer\n");
ret = -ENOMEM;
goto free_tx_skbuff;
}
tiptr = qe_muram_alloc(32, 32);
- if (IS_ERR_VALUE(tiptr)) {
+ if (tiptr < 0) {
dev_err(priv->dev, "Cannot allocate MURAM mem for Transmit internal temp data pointer\n");
ret = -ENOMEM;
goto free_riptr;
@@ -274,17 +279,16 @@
iowrite16be(MAX_FRAME_LENGTH, &priv->ucc_pram->mflr);
iowrite16be(DEFAULT_RFTHR, &priv->ucc_pram->rfthr);
iowrite16be(DEFAULT_RFTHR, &priv->ucc_pram->rfcnt);
- iowrite16be(DEFAULT_ADDR_MASK, &priv->ucc_pram->hmask);
+ iowrite16be(priv->hmask, &priv->ucc_pram->hmask);
iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr1);
iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr2);
iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr3);
iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr4);
/* Get BD buffer */
- bd_buffer = dma_zalloc_coherent(priv->dev,
- (RX_BD_RING_LEN + TX_BD_RING_LEN) *
- MAX_RX_BUF_LENGTH,
- &bd_dma_addr, GFP_KERNEL);
+ bd_buffer = dma_alloc_coherent(priv->dev,
+ (RX_BD_RING_LEN + TX_BD_RING_LEN) * MAX_RX_BUF_LENGTH,
+ &bd_dma_addr, GFP_KERNEL);
if (!bd_buffer) {
dev_err(priv->dev, "Could not allocate buffer descriptors\n");
@@ -384,11 +388,16 @@
dev->stats.tx_bytes += skb->len;
break;
+ case ARPHRD_ETHER:
+ dev->stats.tx_bytes += skb->len;
+ break;
+
default:
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
return -ENOMEM;
}
+ netdev_sent_queue(dev, skb->len);
spin_lock_irqsave(&priv->lock, flags);
/* Start from the next BD that should be filled */
@@ -429,12 +438,27 @@
return NETDEV_TX_OK;
}
+static int hdlc_tx_restart(struct ucc_hdlc_private *priv)
+{
+ u32 cecr_subblock;
+
+ cecr_subblock =
+ ucc_fast_get_qe_cr_subblock(priv->ut_info->uf_info.ucc_num);
+
+ qe_issue_cmd(QE_RESTART_TX, cecr_subblock,
+ QE_CR_PROTOCOL_UNSPECIFIED, 0);
+ return 0;
+}
+
static int hdlc_tx_done(struct ucc_hdlc_private *priv)
{
/* Start from the next BD that should be filled */
struct net_device *dev = priv->ndev;
+ unsigned int bytes_sent = 0;
+ int howmany = 0;
struct qe_bd *bd; /* BD pointer */
u16 bd_status;
+ int tx_restart = 0;
bd = priv->dirty_tx;
bd_status = ioread16be(&bd->status);
@@ -443,6 +467,15 @@
while ((bd_status & T_R_S) == 0) {
struct sk_buff *skb;
+ if (bd_status & T_UN_S) { /* Underrun */
+ dev->stats.tx_fifo_errors++;
+ tx_restart = 1;
+ }
+ if (bd_status & T_CT_S) { /* Carrier lost */
+ dev->stats.tx_carrier_errors++;
+ tx_restart = 1;
+ }
+
/* BD contains already transmitted buffer. */
/* Handle the transmitted buffer and release */
/* the BD to be used with the current frame */
@@ -450,11 +483,13 @@
skb = priv->tx_skbuff[priv->skb_dirtytx];
if (!skb)
break;
+ howmany++;
+ bytes_sent += skb->len;
dev->stats.tx_packets++;
memset(priv->tx_buffer +
(be32_to_cpu(bd->buf) - priv->dma_tx_addr),
0, skb->len);
- dev_kfree_skb_irq(skb);
+ dev_consume_skb_irq(skb);
priv->tx_skbuff[priv->skb_dirtytx] = NULL;
priv->skb_dirtytx =
@@ -474,6 +509,10 @@
}
priv->dirty_tx = bd;
+ if (tx_restart)
+ hdlc_tx_restart(priv);
+
+ netdev_completed_queue(dev, howmany, bytes_sent);
return 0;
}
@@ -492,11 +531,22 @@
/* while there are received buffers and BD is full (~R_E) */
while (!((bd_status & (R_E_S)) || (--rx_work_limit < 0))) {
- if (bd_status & R_OV_S)
- dev->stats.rx_over_errors++;
- if (bd_status & R_CR_S) {
- dev->stats.rx_crc_errors++;
- dev->stats.rx_dropped++;
+ if (bd_status & (RX_BD_ERRORS)) {
+ dev->stats.rx_errors++;
+
+ if (bd_status & R_CD_S)
+ dev->stats.collisions++;
+ if (bd_status & R_OV_S)
+ dev->stats.rx_fifo_errors++;
+ if (bd_status & R_CR_S)
+ dev->stats.rx_crc_errors++;
+ if (bd_status & R_AB_S)
+ dev->stats.rx_over_errors++;
+ if (bd_status & R_NO_S)
+ dev->stats.rx_frame_errors++;
+ if (bd_status & R_LG_S)
+ dev->stats.rx_length_errors++;
+
goto recycle;
}
bdbuffer = priv->rx_buffer +
@@ -521,6 +571,7 @@
break;
case ARPHRD_PPP:
+ case ARPHRD_ETHER:
length -= HDLC_CRC_SIZE;
skb = dev_alloc_skb(length);
@@ -544,7 +595,7 @@
netif_receive_skb(skb);
recycle:
- iowrite16be(bd_status | R_E_S | R_I_S, &bd->status);
+ iowrite16be((bd_status & R_W_S) | R_E_S | R_I_S, &bd->status);
/* update to point at the next bd */
if (bd_status & R_W_S) {
@@ -583,8 +634,8 @@
if (howmany < budget) {
napi_complete_done(napi, howmany);
- qe_setbits32(priv->uccf->p_uccm,
- (UCCE_HDLC_RX_EVENTS | UCCE_HDLC_TX_EVENTS) << 16);
+ qe_setbits_be32(priv->uccf->p_uccm,
+ (UCCE_HDLC_RX_EVENTS | UCCE_HDLC_TX_EVENTS) << 16);
}
return howmany;
@@ -595,11 +646,9 @@
struct ucc_hdlc_private *priv = (struct ucc_hdlc_private *)dev_id;
struct net_device *dev = priv->ndev;
struct ucc_fast_private *uccf;
- struct ucc_tdm_info *ut_info;
u32 ucce;
u32 uccm;
- ut_info = priv->ut_info;
uccf = priv->uccf;
ucce = ioread32be(uccf->p_ucce);
@@ -620,7 +669,7 @@
/* Errors and other events */
if (ucce >> 16 & UCC_HDLC_UCCE_BSY)
- dev->stats.rx_errors++;
+ dev->stats.rx_missed_errors++;
if (ucce >> 16 & UCC_HDLC_UCCE_TXE)
dev->stats.tx_errors++;
@@ -661,6 +710,7 @@
hdlc_device *hdlc = dev_to_hdlc(dev);
struct ucc_hdlc_private *priv = hdlc->priv;
struct ucc_tdm *utdm = priv->utdm;
+ int rc = 0;
if (priv->hdlc_busy != 1) {
if (request_irq(priv->ut_info->uf_info.irq,
@@ -682,17 +732,21 @@
priv->hdlc_busy = 1;
netif_device_attach(priv->ndev);
napi_enable(&priv->napi);
+ netdev_reset_queue(dev);
netif_start_queue(dev);
- hdlc_open(dev);
+
+ rc = hdlc_open(dev);
+ if (rc)
+ uhdlc_close(dev);
}
- return 0;
+ return rc;
}
static void uhdlc_memclean(struct ucc_hdlc_private *priv)
{
- qe_muram_free(priv->ucc_pram->riptr);
- qe_muram_free(priv->ucc_pram->tiptr);
+ qe_muram_free(ioread16be(&priv->ucc_pram->riptr));
+ qe_muram_free(ioread16be(&priv->ucc_pram->tiptr));
if (priv->rx_bd_base) {
dma_free_coherent(priv->dev,
@@ -773,7 +827,10 @@
free_irq(priv->ut_info->uf_info.irq, priv);
netif_stop_queue(dev);
+ netdev_reset_queue(dev);
priv->hdlc_busy = 0;
+
+ hdlc_close(dev);
return 0;
}
@@ -789,6 +846,7 @@
if (parity != PARITY_NONE &&
parity != PARITY_CRC32_PR1_CCITT &&
+ parity != PARITY_CRC16_PR0_CCITT &&
parity != PARITY_CRC16_PR1_CCITT)
return -EINVAL;
@@ -829,7 +887,6 @@
static int uhdlc_suspend(struct device *dev)
{
struct ucc_hdlc_private *priv = dev_get_drvdata(dev);
- struct ucc_tdm_info *ut_info;
struct ucc_fast __iomem *uf_regs;
if (!priv)
@@ -841,7 +898,6 @@
netif_device_detach(priv->ndev);
napi_disable(&priv->napi);
- ut_info = priv->ut_info;
uf_regs = priv->uf_regs;
/* backup gumr guemr*/
@@ -874,7 +930,7 @@
struct ucc_fast __iomem *uf_regs;
struct ucc_fast_private *uccf;
struct ucc_fast_info *uf_info;
- int ret, i;
+ int i;
u32 cecr_subblock;
u16 bd_status;
@@ -919,16 +975,16 @@
/* Write to QE CECR, UCCx channel to Stop Transmission */
cecr_subblock = ucc_fast_get_qe_cr_subblock(uf_info->ucc_num);
- ret = qe_issue_cmd(QE_STOP_TX, cecr_subblock,
- (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
+ qe_issue_cmd(QE_STOP_TX, cecr_subblock,
+ (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
/* Set UPSMR normal mode */
iowrite32be(0, &uf_regs->upsmr);
/* init parameter base */
cecr_subblock = ucc_fast_get_qe_cr_subblock(uf_info->ucc_num);
- ret = qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, cecr_subblock,
- QE_CR_PROTOCOL_UNSPECIFIED, priv->ucc_pram_offset);
+ qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, cecr_subblock,
+ QE_CR_PROTOCOL_UNSPECIFIED, priv->ucc_pram_offset);
priv->ucc_pram = (struct ucc_hdlc_param __iomem *)
qe_muram_addr(priv->ucc_pram_offset);
@@ -996,12 +1052,66 @@
#define HDLC_PM_OPS NULL
#endif
+static void uhdlc_tx_timeout(struct net_device *ndev, unsigned int txqueue)
+{
+ netdev_err(ndev, "%s\n", __func__);
+}
+
static const struct net_device_ops uhdlc_ops = {
.ndo_open = uhdlc_open,
.ndo_stop = uhdlc_close,
.ndo_start_xmit = hdlc_start_xmit,
.ndo_do_ioctl = uhdlc_ioctl,
+ .ndo_tx_timeout = uhdlc_tx_timeout,
};
+
+static int hdlc_map_iomem(char *name, int init_flag, void __iomem **ptr)
+{
+ struct device_node *np;
+ struct platform_device *pdev;
+ struct resource *res;
+ static int siram_init_flag;
+ int ret = 0;
+
+ np = of_find_compatible_node(NULL, NULL, name);
+ if (!np)
+ return -EINVAL;
+
+ pdev = of_find_device_by_node(np);
+ if (!pdev) {
+ pr_err("%pOFn: failed to lookup pdev\n", np);
+ of_node_put(np);
+ return -EINVAL;
+ }
+
+ of_node_put(np);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -EINVAL;
+ goto error_put_device;
+ }
+ *ptr = ioremap(res->start, resource_size(res));
+ if (!*ptr) {
+ ret = -ENOMEM;
+ goto error_put_device;
+ }
+
+ /* We've remapped the addresses, and we don't need the device any
+ * more, so we should release it.
+ */
+ put_device(&pdev->dev);
+
+ if (init_flag && siram_init_flag == 0) {
+ memset_io(*ptr, 0, resource_size(res));
+ siram_init_flag = 1;
+ }
+ return 0;
+
+error_put_device:
+ put_device(&pdev->dev);
+
+ return ret;
+}
static int ucc_hdlc_probe(struct platform_device *pdev)
{
@@ -1024,7 +1134,7 @@
}
ucc_num = val - 1;
- if ((ucc_num > 3) || (ucc_num < 0)) {
+ if (ucc_num > (UCC_MAX_NUM - 1) || ucc_num < 0) {
dev_err(&pdev->dev, ": Invalid UCC num\n");
return -EINVAL;
}
@@ -1097,12 +1207,24 @@
ret = ucc_of_parse_tdm(np, utdm, ut_info);
if (ret)
goto free_utdm;
+
+ ret = hdlc_map_iomem("fsl,t1040-qe-si", 0,
+ (void __iomem **)&utdm->si_regs);
+ if (ret)
+ goto free_utdm;
+ ret = hdlc_map_iomem("fsl,t1040-qe-siram", 1,
+ (void __iomem **)&utdm->siram);
+ if (ret)
+ goto unmap_si_regs;
}
+
+ if (of_property_read_u16(np, "fsl,hmask", &uhdlc_priv->hmask))
+ uhdlc_priv->hmask = DEFAULT_ADDR_MASK;
ret = uhdlc_init(uhdlc_priv);
if (ret) {
dev_err(&pdev->dev, "Failed to init uhdlc\n");
- goto free_utdm;
+ goto undo_uhdlc_init;
}
dev = alloc_hdlcdev(uhdlc_priv);
@@ -1116,6 +1238,7 @@
hdlc = dev_to_hdlc(dev);
dev->tx_queue_len = 16;
dev->netdev_ops = &uhdlc_ops;
+ dev->watchdog_timeo = 2 * HZ;
hdlc->attach = ucc_hdlc_attach;
hdlc->xmit = ucc_hdlc_tx;
netif_napi_add(dev, &uhdlc_priv->napi, ucc_hdlc_poll, 32);
@@ -1130,6 +1253,11 @@
free_dev:
free_netdev(dev);
undo_uhdlc_init:
+ if (utdm)
+ iounmap(utdm->siram);
+unmap_si_regs:
+ if (utdm)
+ iounmap(utdm->si_regs);
free_utdm:
if (uhdlc_priv->tsa)
kfree(utdm);
@@ -1181,3 +1309,4 @@
module_platform_driver(ucc_hdlc_driver);
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRV_DESC);
--
Gitblit v1.6.2