summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2013-12-14 02:43:39 (GMT)
committerScott Wood <scottwood@freescale.com>2013-12-14 02:45:02 (GMT)
commit5709059c4e110944712dc1f3d66a203a924c151a (patch)
tree3f5ff4c45d2b1089c3f4504771a78e847b3ac073 /drivers
parentb7c81aa3ab2ac2c140e278b6d0e9a0b95112cf0b (diff)
parent3dea020415467452d6ca2e907e21af07954741cf (diff)
downloadlinux-fsl-qoriq-5709059c4e110944712dc1f3d66a203a924c151a.tar.xz
Merge remote-tracking branch 'origin/master' into merge
Conflicts: arch/powerpc/boot/dts/b4qds.dts drivers/crypto/caam/Makefile
Diffstat (limited to 'drivers')
-rw-r--r--drivers/crypto/caam/Kconfig5
-rw-r--r--drivers/crypto/caam/Makefile1
-rw-r--r--drivers/crypto/caam/fsl_jr_uio.c267
-rw-r--r--drivers/crypto/caam/fsl_jr_uio.h20
-rw-r--r--drivers/net/ethernet/freescale/dpa/dpaa_eth.c104
-rw-r--r--drivers/net/ethernet/freescale/dpa/dpaa_eth.h25
-rw-r--r--drivers/net/ethernet/freescale/dpa/dpaa_eth_common.c5
-rw-r--r--drivers/net/ethernet/freescale/dpa/dpaa_eth_common.h12
-rw-r--r--drivers/net/ethernet/freescale/dpa/dpaa_eth_macless.c124
-rw-r--r--drivers/net/ethernet/freescale/dpa/dpaa_eth_non_sg.c7
-rw-r--r--drivers/net/ethernet/freescale/dpa/dpaa_eth_proxy.c106
-rw-r--r--drivers/net/ethernet/freescale/dpa/dpaa_eth_sg.c7
-rw-r--r--drivers/net/ethernet/freescale/dpa/mac-api.c41
-rw-r--r--drivers/net/ethernet/freescale/dpa/mac.h5
-rw-r--r--drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_fm.h3
-rw-r--r--drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.c73
-rw-r--r--drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.h4
-rw-r--r--drivers/net/ethernet/freescale/xgmac_mdio.c2
-rw-r--r--drivers/staging/fsl_qbman/bman_driver.c20
-rw-r--r--drivers/staging/fsl_qbman/bman_high.c25
-rw-r--r--drivers/staging/fsl_qbman/bman_private.h8
-rw-r--r--drivers/staging/fsl_qbman/qman_driver.c43
-rw-r--r--drivers/staging/fsl_qbman/qman_high.c50
-rw-r--r--drivers/staging/fsl_qbman/qman_private.h8
-rw-r--r--drivers/tdm/test/Kconfig7
-rw-r--r--drivers/tdm/test/Makefile1
-rw-r--r--drivers/tdm/test/tdm_loopback_test.c251
27 files changed, 1058 insertions, 166 deletions
diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig
index e7555ff..19420cd 100644
--- a/drivers/crypto/caam/Kconfig
+++ b/drivers/crypto/caam/Kconfig
@@ -119,3 +119,8 @@ config CRYPTO_DEV_FSL_CAAM_DEBUG
help
Selecting this will enable printing of various debug
information in the CAAM driver.
+
+config CRYPTO_DEV_FSL_CAAM_JR_UIO
+ tristate "Freescale Job Ring UIO support"
+ depends on CRYPTO_DEV_FSL_CAAM
+ default n
diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile
index 550758a..2252efd 100644
--- a/drivers/crypto/caam/Makefile
+++ b/drivers/crypto/caam/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR) += caam_jr.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR_UIO) += fsl_jr_uio.o
caam-objs := ctrl.o
caam_jr-objs := jr.o key_gen.o error.o
diff --git a/drivers/crypto/caam/fsl_jr_uio.c b/drivers/crypto/caam/fsl_jr_uio.c
new file mode 100644
index 0000000..b99cb52
--- /dev/null
+++ b/drivers/crypto/caam/fsl_jr_uio.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/uio_driver.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include "regs.h"
+#include "fsl_jr_uio.h"
+
+static const char jr_uio_version[] = "fsl JR UIO driver v1.0";
+
+#define NAME_LENGTH 30
+#define JR_INDEX_OFFSET 12
+
+static const char uio_device_name[] = "fsl-jr";
+static LIST_HEAD(jr_list);
+
+struct jr_uio_info {
+ atomic_t ref; /* exclusive, only one open() at a time */
+ struct uio_info uio;
+ char name[NAME_LENGTH];
+};
+
+struct jr_dev {
+ u32 revision;
+ u32 index;
+ u32 irq;
+ struct caam_job_ring __iomem *global_regs;
+ struct device *dev;
+ struct resource res;
+ struct jr_uio_info info;
+ struct list_head node;
+ struct list_head jr_list;
+};
+
+static int jr_uio_open(struct uio_info *info, struct inode *inode)
+{
+ struct jr_uio_info *uio_info = container_of(info,
+ struct jr_uio_info, uio);
+
+ if (!atomic_dec_and_test(&uio_info->ref)) {
+ pr_err("%s: failing non-exclusive open()\n", uio_info->name);
+ atomic_inc(&uio_info->ref);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int jr_uio_release(struct uio_info *info, struct inode *inode)
+{
+ struct jr_uio_info *uio_info = container_of(info,
+ struct jr_uio_info, uio);
+ atomic_inc(&uio_info->ref);
+
+ return 0;
+}
+
+static irqreturn_t jr_uio_irq_handler(int irq, struct uio_info *dev_info)
+{
+ struct jr_dev *jrdev = dev_info->priv;
+ u32 irqstate;
+ irqstate = rd_reg32(&jrdev->global_regs->jrintstatus);
+ if (!irqstate) {
+ dev_warn(jrdev->dev, "Spurious interrupt received\n");
+ return IRQ_NONE;
+ }
+
+ if (irqstate & JRINT_JR_ERROR)
+ dev_info(jrdev->dev, "uio job ring error - irqstate: %08x\n",
+ irqstate);
+
+ /*mask valid interrupts */
+ setbits32(&jrdev->global_regs->rconfig_lo, JRCFG_IMSK);
+
+ /* Have valid interrupt at this point, just ACK and trigger */
+ wr_reg32(&jrdev->global_regs->jrintstatus, irqstate);
+
+ return IRQ_HANDLED;
+}
+
+static int jr_uio_irqcontrol(struct uio_info *dev_info, int irqon)
+{
+ struct jr_dev *jrdev = dev_info->priv;
+
+ switch (irqon) {
+ case SEC_UIO_SIMULATE_IRQ_CMD:
+ uio_event_notify(dev_info);
+ break;
+ case SEC_UIO_ENABLE_IRQ_CMD:
+ /* Enable Job Ring interrupt */
+ clrbits32(&jrdev->global_regs->rconfig_lo, JRCFG_IMSK);
+ break;
+ case SEC_UIO_DISABLE_IRQ_CMD:
+ /* Disable Job Ring interrupt */
+ setbits32(&jrdev->global_regs->rconfig_lo, JRCFG_IMSK);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int __init jr_uio_init(struct jr_dev *uio_dev)
+{
+ int ret;
+ struct jr_uio_info *info;
+
+ info = &uio_dev->info;
+ atomic_set(&info->ref, 1);
+ info->uio.version = jr_uio_version;
+ info->uio.name = uio_dev->info.name;
+ info->uio.mem[0].name = "JR config space";
+ info->uio.mem[0].addr = uio_dev->res.start;
+ info->uio.mem[0].size = uio_dev->res.end - uio_dev->res.start + 1;
+ info->uio.mem[0].internal_addr = uio_dev->global_regs;
+ info->uio.mem[0].memtype = UIO_MEM_PHYS;
+ info->uio.irq = uio_dev->irq;
+ info->uio.irq_flags = IRQF_SHARED;
+ info->uio.handler = jr_uio_irq_handler;
+ info->uio.irqcontrol = jr_uio_irqcontrol;
+ info->uio.open = jr_uio_open;
+ info->uio.release = jr_uio_release;
+ info->uio.priv = uio_dev;
+
+ ret = uio_register_device(uio_dev->dev, &info->uio);
+ if (ret) {
+ pr_err("jr_uio: UIO registration failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id jr_ids[] = {
+ { .compatible = "fsl,sec-v4.0-job-ring", },
+ { .compatible = "fsl,sec-v4.4-job-ring", },
+ { .compatible = "fsl,sec-v5.0-job-ring", },
+ { .compatible = "fsl,sec-v6.0-job-ring", },
+ {},
+};
+
+static int fsl_jr_probe(struct platform_device *dev)
+{
+ struct resource regs;
+ struct jr_dev *jr_dev;
+ struct device_node *jr_node;
+ int ret, count = 0;
+ struct list_head *p;
+
+ jr_node = dev->dev.of_node;
+ if (!jr_node) {
+ dev_err(&dev->dev, "Device OF-Node is NULL\n");
+ return -EFAULT;
+ }
+
+ jr_dev = kzalloc(sizeof(struct jr_dev), GFP_KERNEL);
+ if (!jr_dev) {
+ dev_err(&dev->dev, "kzalloc failed\n");
+ return -ENOMEM;
+ }
+
+ /* Creat name and index */
+ list_for_each(p, &jr_list) {
+ count++;
+ }
+ jr_dev->index = count;
+
+ snprintf(jr_dev->info.name, sizeof(jr_dev->info.name) - 1,
+ "%s%d", uio_device_name, jr_dev->index);
+
+ jr_dev->dev = &dev->dev;
+ platform_set_drvdata(dev, jr_dev);
+
+ /* Get the resource from dtb node */
+ ret = of_address_to_resource(jr_node, 0, &regs);
+ if (unlikely(ret < 0)) {
+ dev_err(&dev->dev, "OF-Address-to-resource Failed\n");
+ ret = -EFAULT;
+ goto abort;
+ }
+
+ jr_dev->res = regs;
+
+ jr_dev->global_regs = of_iomap(jr_node, 0);
+
+ jr_dev->irq = irq_of_parse_and_map(jr_node, 0);
+ dev_dbg(jr_dev->dev, "errirq: %d\n", jr_dev->irq);
+
+ /* Register UIO */
+ ret = jr_uio_init(jr_dev);
+ if (ret) {
+ dev_err(&dev->dev, "UIO init Failed\n");
+ goto abort_iounmap;
+ }
+
+ list_add_tail(&jr_dev->node, &jr_list);
+
+ dev_info(jr_dev->dev, "UIO device full name %s initialized\n",
+ jr_dev->info.name);
+
+ return 0;
+
+abort_iounmap:
+ iounmap(jr_dev->global_regs);
+abort:
+ kfree(jr_dev);
+ return ret;
+}
+
+static int fsl_jr_remove(struct platform_device *dev)
+{
+ struct jr_dev *jr_dev = platform_get_drvdata(dev);
+
+ if (!jr_dev)
+ return 0;
+
+ list_del(&jr_dev->node);
+ uio_unregister_device(&jr_dev->info.uio);
+ platform_set_drvdata(dev, NULL);
+ iounmap(jr_dev->global_regs);
+ kfree(jr_dev);
+
+ return 0;
+}
+
+static struct platform_driver fsl_jr_driver = {
+ .driver = {
+ .name = "fsl-jr-uio",
+ .owner = THIS_MODULE,
+ .of_match_table = jr_ids,
+ },
+ .probe = fsl_jr_probe,
+ .remove = fsl_jr_remove,
+};
+
+static __init int fsl_jr_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&fsl_jr_driver);
+ if (unlikely(ret < 0))
+ pr_warn(": %s:%hu:%s(): platform_driver_register() = %d\n",
+ __FILE__, __LINE__, __func__, ret);
+
+ return ret;
+}
+
+static void __exit fsl_jr_exit(void)
+{
+ platform_driver_unregister(&fsl_jr_driver);
+}
+
+module_init(fsl_jr_init);
+module_exit(fsl_jr_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ruchika Gupta <ruchika.gupta@freescale.com>");
+MODULE_DESCRIPTION("FSL SEC UIO Driver");
diff --git a/drivers/crypto/caam/fsl_jr_uio.h b/drivers/crypto/caam/fsl_jr_uio.h
new file mode 100644
index 0000000..2c4b7c4
--- /dev/null
+++ b/drivers/crypto/caam/fsl_jr_uio.h
@@ -0,0 +1,20 @@
+/*
+ * CAAM Job RING UIO support header file
+ *
+ * Copyright 2013 Freescale Semiconductor, Inc
+ */
+
+#ifndef FSL_JR_UIO_H
+#define FSL_JR_UIO_H
+
+/** UIO command used by user-space driver to request
+ * disabling IRQs on a certain job ring */
+#define SEC_UIO_DISABLE_IRQ_CMD 0
+/** UIO command used by user-space driver to request
+ * enabling IRQs on a certain job ring */
+#define SEC_UIO_ENABLE_IRQ_CMD 1
+/** UIO command used by user-space driver to request SEC kernel driver
+ * to simulate that an IRQ is generated on a certain job ring */
+#define SEC_UIO_SIMULATE_IRQ_CMD 2
+
+#endif
diff --git a/drivers/net/ethernet/freescale/dpa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpa/dpaa_eth.c
index 9cd3214..11d87bf 100644
--- a/drivers/net/ethernet/freescale/dpa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpa/dpaa_eth.c
@@ -116,6 +116,8 @@ int dpa_free_pcd_fqids(struct device *, uint32_t) __attribute__((weak));
uint8_t dpa_priv_common_bpid;
+extern u16 qman_portal_max;
+
/* A set of callbacks for hooking into the fastpath at different points. */
struct dpaa_eth_hooks_s dpaa_eth_hooks;
/*
@@ -275,12 +277,15 @@ void __hot _dpa_process_parse_results(const fm_prs_result_t *parse_results,
static int dpaa_eth_poll(struct napi_struct *napi, int budget)
{
- int cleaned = qman_poll_dqrr(budget);
+ struct dpa_napi_portal *np =
+ container_of(napi, struct dpa_napi_portal, napi);
+
+ int cleaned = qman_p_poll_dqrr(np->p, budget);
if (cleaned < budget) {
int tmp;
napi_complete(napi);
- tmp = qman_irqsource_add(QM_PIRQ_DQRI);
+ tmp = qman_p_irqsource_add(np->p, QM_PIRQ_DQRI);
BUG_ON(tmp);
}
@@ -337,7 +342,7 @@ priv_rx_error_dqrr(struct qman_portal *portal,
percpu_priv = __this_cpu_ptr(priv->percpu_priv);
- if (dpaa_eth_napi_schedule(percpu_priv))
+ if (dpaa_eth_napi_schedule(percpu_priv, portal))
return qman_cb_dqrr_stop;
if (unlikely(dpaa_eth_refill_bpools(priv->dpa_bp)))
@@ -371,7 +376,7 @@ priv_rx_default_dqrr(struct qman_portal *portal,
/* IRQ handler, non-migratable; safe to use __this_cpu_ptr here */
percpu_priv = __this_cpu_ptr(priv->percpu_priv);
- if (unlikely(dpaa_eth_napi_schedule(percpu_priv)))
+ if (unlikely(dpaa_eth_napi_schedule(percpu_priv, portal)))
return qman_cb_dqrr_stop;
/* Vale of plenty: make sure we didn't run out of buffers */
@@ -383,7 +388,7 @@ priv_rx_default_dqrr(struct qman_portal *portal,
*/
dpa_fd_release(net_dev, &dq->fd);
else
- _dpa_rx(net_dev, priv, percpu_priv, &dq->fd, fq->fqid);
+ _dpa_rx(net_dev, portal, priv, percpu_priv, &dq->fd, fq->fqid);
return qman_cb_dqrr_consume;
}
@@ -402,7 +407,7 @@ priv_tx_conf_error_dqrr(struct qman_portal *portal,
percpu_priv = __this_cpu_ptr(priv->percpu_priv);
- if (dpaa_eth_napi_schedule(percpu_priv))
+ if (dpaa_eth_napi_schedule(percpu_priv, portal))
return qman_cb_dqrr_stop;
_dpa_tx_error(net_dev, priv, percpu_priv, &dq->fd, fq->fqid);
@@ -428,7 +433,7 @@ priv_tx_conf_default_dqrr(struct qman_portal *portal,
/* Non-migratable context, safe to use __this_cpu_ptr */
percpu_priv = __this_cpu_ptr(priv->percpu_priv);
- if (dpaa_eth_napi_schedule(percpu_priv))
+ if (dpaa_eth_napi_schedule(percpu_priv, portal))
return qman_cb_dqrr_stop;
_dpa_tx_conf(net_dev, priv, percpu_priv, &dq->fd, fq->fqid);
@@ -479,22 +484,26 @@ static const dpa_fq_cbs_t private_fq_cbs = {
static void dpaa_eth_napi_enable(struct dpa_priv_s *priv)
{
struct dpa_percpu_priv_s *percpu_priv;
- int i;
+ int i, j;
for_each_possible_cpu(i) {
percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
- napi_enable(&percpu_priv->napi);
+
+ for (j = 0; j < qman_portal_max; j++)
+ napi_enable(&percpu_priv->np[j].napi);
}
}
static void dpaa_eth_napi_disable(struct dpa_priv_s *priv)
{
struct dpa_percpu_priv_s *percpu_priv;
- int i;
+ int i, j;
for_each_possible_cpu(i) {
percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
- napi_disable(&percpu_priv->napi);
+
+ for (j = 0; j < qman_portal_max; j++)
+ napi_disable(&percpu_priv->np[j].napi);
}
}
@@ -543,11 +552,17 @@ static void dpaa_eth_poll_controller(struct net_device *net_dev)
struct dpa_priv_s *priv = netdev_priv(net_dev);
struct dpa_percpu_priv_s *percpu_priv =
__this_cpu_ptr(priv->percpu_priv);
- struct napi_struct napi = percpu_priv->napi;
+ struct qman_portal *p;
+ const struct qman_portal_config *pc;
+ struct dpa_napi_portal *np;
+
+ p = (struct qman_portal *)qman_get_affine_portal(smp_processor_id());
+ pc = qman_p_get_portal_config(p);
+ np = &percpu_priv->np[pc->index];
- qman_irqsource_remove(QM_PIRQ_DQRI);
- qman_poll_dqrr(napi.weight);
- qman_irqsource_add(QM_PIRQ_DQRI);
+ qman_p_irqsource_remove(np->p, QM_PIRQ_DQRI);
+ qman_p_poll_dqrr(np->p, np->napi.weight);
+ qman_p_irqsource_add(np->p, QM_PIRQ_DQRI);
}
#endif
@@ -573,6 +588,50 @@ static const struct net_device_ops dpa_private_ops = {
#endif
};
+static int dpa_private_napi_add(struct net_device *net_dev)
+{
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+ struct dpa_percpu_priv_s *percpu_priv;
+ int i, cpu;
+
+ for_each_possible_cpu(cpu) {
+ percpu_priv = per_cpu_ptr(priv->percpu_priv, cpu);
+
+ percpu_priv->np = devm_kzalloc(net_dev->dev.parent,
+ qman_portal_max * sizeof(struct dpa_napi_portal),
+ GFP_KERNEL);
+
+ if (unlikely(percpu_priv->np == NULL)) {
+ dev_err(net_dev->dev.parent, "devm_kzalloc() failed\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < qman_portal_max; i++)
+ netif_napi_add(net_dev, &percpu_priv->np[i].napi,
+ dpaa_eth_poll, DPA_NAPI_WEIGHT);
+ }
+
+ return 0;
+}
+
+void dpa_private_napi_del(struct net_device *net_dev)
+{
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+ struct dpa_percpu_priv_s *percpu_priv;
+ int i, cpu;
+
+ for_each_possible_cpu(cpu) {
+ percpu_priv = per_cpu_ptr(priv->percpu_priv, cpu);
+
+ if (percpu_priv->np) {
+ for (i = 0; i < qman_portal_max; i++)
+ netif_napi_del(&percpu_priv->np[i].napi);
+
+ devm_kfree(net_dev->dev.parent, percpu_priv->np);
+ }
+ }
+}
+
static int dpa_private_netdev_init(struct device_node *dpa_node,
struct net_device *net_dev)
{
@@ -587,13 +646,9 @@ static int dpa_private_netdev_init(struct device_node *dpa_node,
for_each_possible_cpu(i) {
percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
percpu_priv->net_dev = net_dev;
-
- netif_napi_add(net_dev, &percpu_priv->napi, dpaa_eth_poll,
- DPA_NAPI_WEIGHT);
}
net_dev->netdev_ops = &dpa_private_ops;
-
mac_addr = priv->mac_dev->addr;
net_dev->mem_start = priv->mac_dev->res->start;
@@ -827,6 +882,12 @@ dpaa_eth_priv_probe(struct platform_device *_of_dev)
memset(percpu_priv, 0, sizeof(*percpu_priv));
}
+ /* Initialize NAPI */
+ err = dpa_private_napi_add(net_dev);
+
+ if (err < 0)
+ goto napi_add_failed;
+
err = dpa_private_netdev_init(dpa_node, net_dev);
if (err < 0)
@@ -838,9 +899,12 @@ dpaa_eth_priv_probe(struct platform_device *_of_dev)
return 0;
+napi_add_failed:
netdev_init_failed:
- if (net_dev)
+ if (net_dev) {
+ dpa_private_napi_del(net_dev);
free_percpu(priv->percpu_priv);
+ }
alloc_percpu_failed:
fq_alloc_failed:
if (net_dev) {
diff --git a/drivers/net/ethernet/freescale/dpa/dpaa_eth.h b/drivers/net/ethernet/freescale/dpa/dpaa_eth.h
index d179fda..6844d9a 100644
--- a/drivers/net/ethernet/freescale/dpa/dpaa_eth.h
+++ b/drivers/net/ethernet/freescale/dpa/dpaa_eth.h
@@ -380,9 +380,14 @@ struct dpa_ern_cnt {
u64 orp_zero; /* ORP disabled */
};
+struct dpa_napi_portal {
+ struct napi_struct napi;
+ struct qman_portal *p;
+};
+
struct dpa_percpu_priv_s {
struct net_device *net_dev;
- struct napi_struct napi;
+ struct dpa_napi_portal *np;
u64 in_interrupt;
u64 tx_returned;
u64 tx_confirm;
@@ -453,6 +458,8 @@ struct dpa_priv_s {
struct dpa_buffer_layout_s *buf_layout;
uint16_t rx_headroom;
char if_type[30];
+
+ void *peer;
};
struct fm_port_fqs {
@@ -466,6 +473,7 @@ struct fm_port_fqs {
int dpa_bp_priv_seed(struct dpa_bp *dpa_bp);
int dpaa_eth_refill_bpools(struct dpa_bp *dpa_bp);
void __hot _dpa_rx(struct net_device *net_dev,
+ struct qman_portal *portal,
const struct dpa_priv_s *priv,
struct dpa_percpu_priv_s *percpu_priv,
const struct qm_fd *fd,
@@ -496,7 +504,8 @@ int _dpa_bp_add_8_bufs(const struct dpa_bp *dpa_bp);
int dpa_enable_tx_csum(struct dpa_priv_s *priv,
struct sk_buff *skb, struct qm_fd *fd, char *parse_results);
-static inline int dpaa_eth_napi_schedule(struct dpa_percpu_priv_s *percpu_priv)
+static inline int dpaa_eth_napi_schedule(struct dpa_percpu_priv_s *percpu_priv,
+ struct qman_portal *portal)
{
/* In case of threaded ISR for RT enable kernel,
* in_irq() does not return appropriate value, so use
@@ -504,9 +513,15 @@ static inline int dpaa_eth_napi_schedule(struct dpa_percpu_priv_s *percpu_priv)
*/
if (unlikely(in_irq() || !in_serving_softirq())) {
/* Disable QMan IRQ and invoke NAPI */
- int ret = qman_irqsource_remove(QM_PIRQ_DQRI);
+ int ret = qman_p_irqsource_remove(portal, QM_PIRQ_DQRI);
if (likely(!ret)) {
- napi_schedule(&percpu_priv->napi);
+ const struct qman_portal_config *pc =
+ qman_p_get_portal_config(portal);
+ struct dpa_napi_portal *np =
+ &percpu_priv->np[pc->index];
+
+ np->p = portal;
+ napi_schedule(&np->napi);
percpu_priv->in_interrupt++;
return 1;
}
@@ -570,6 +585,8 @@ int fm_mac_dump_regs(struct mac_device *h_dev, char *buf, int n);
void dpaa_eth_sysfs_remove(struct device *dev);
void dpaa_eth_sysfs_init(struct device *dev);
+void dpa_private_napi_del(struct net_device *net_dev);
+
/* Equivalent to a memset(0), but works faster */
static inline void clear_fd(struct qm_fd *fd)
{
diff --git a/drivers/net/ethernet/freescale/dpa/dpaa_eth_common.c b/drivers/net/ethernet/freescale/dpa/dpaa_eth_common.c
index c599052..0d1de6c 100644
--- a/drivers/net/ethernet/freescale/dpa/dpaa_eth_common.c
+++ b/drivers/net/ethernet/freescale/dpa/dpaa_eth_common.c
@@ -129,7 +129,7 @@ int __cold dpa_start(struct net_device *net_dev)
priv = netdev_priv(net_dev);
mac_dev = priv->mac_dev;
- err = mac_dev->init_phy(net_dev);
+ err = mac_dev->init_phy(net_dev, priv->mac_dev);
if (err < 0) {
if (netif_msg_ifup(priv))
netdev_err(net_dev, "init_phy() = %d\n", err);
@@ -471,6 +471,7 @@ int __cold dpa_remove(struct platform_device *of_dev)
err = dpa_fq_free(dev, &priv->dpa_fq_list);
+ dpa_private_napi_del(net_dev);
free_percpu(priv->percpu_priv);
dpa_bp_free(priv, priv->dpa_bp);
@@ -613,7 +614,7 @@ void dpa_set_rx_mode(struct net_device *net_dev)
_errno);
}
- _errno = priv->mac_dev->set_multi(net_dev);
+ _errno = priv->mac_dev->set_multi(net_dev, priv->mac_dev);
if (unlikely(_errno < 0) && netif_msg_drv(priv))
netdev_err(net_dev, "mac_dev->set_multi() = %d\n", _errno);
}
diff --git a/drivers/net/ethernet/freescale/dpa/dpaa_eth_common.h b/drivers/net/ethernet/freescale/dpa/dpaa_eth_common.h
index 6ee9825..9964915 100644
--- a/drivers/net/ethernet/freescale/dpa/dpaa_eth_common.h
+++ b/drivers/net/ethernet/freescale/dpa/dpaa_eth_common.h
@@ -125,4 +125,16 @@ void count_ern(struct dpa_percpu_priv_s *percpu_priv,
int dpa_enable_tx_csum(struct dpa_priv_s *priv,
struct sk_buff *skb, struct qm_fd *fd, char *parse_results);
+struct proxy_device {
+ struct mac_device *mac_dev;
+};
+
+/* mac device control functions exposed by proxy interface*/
+int dpa_proxy_start(struct net_device *net_dev);
+int dpa_proxy_stop(struct proxy_device *proxy_dev, struct net_device *net_dev);
+int dpa_proxy_set_mac_address(struct proxy_device *proxy_dev,
+ struct net_device *net_dev);
+int dpa_proxy_set_rx_mode(struct proxy_device *proxy_dev,
+ struct net_device *net_dev);
+
#endif /* __DPAA_ETH_COMMON_H */
diff --git a/drivers/net/ethernet/freescale/dpa/dpaa_eth_macless.c b/drivers/net/ethernet/freescale/dpa/dpaa_eth_macless.c
index 8065a81..119f891 100644
--- a/drivers/net/ethernet/freescale/dpa/dpaa_eth_macless.c
+++ b/drivers/net/ethernet/freescale/dpa/dpaa_eth_macless.c
@@ -76,7 +76,10 @@ int __hot dpa_shared_tx(struct sk_buff *skb, struct net_device *net_dev);
/* forward declarations */
static int __cold dpa_macless_start(struct net_device *net_dev);
static int __cold dpa_macless_stop(struct net_device *net_dev);
-static int dpa_set_macless_address(struct net_device *net_dev, void *addr);
+static int __cold dpa_macless_set_address(struct net_device *net_dev,
+ void *addr);
+static void __cold dpa_macless_set_rx_mode(struct net_device *net_dev);
+
static int dpaa_eth_macless_probe(struct platform_device *_of_dev);
static netdev_features_t
dpa_macless_fix_features(struct net_device *dev, netdev_features_t features);
@@ -89,7 +92,8 @@ static const struct net_device_ops dpa_macless_ops = {
.ndo_stop = dpa_macless_stop,
.ndo_tx_timeout = dpa_timeout,
.ndo_get_stats64 = dpa_get_stats64,
- .ndo_set_mac_address = dpa_set_macless_address,
+ .ndo_set_mac_address = dpa_macless_set_address,
+ .ndo_set_rx_mode = dpa_macless_set_rx_mode,
.ndo_validate_addr = eth_validate_addr,
#ifdef CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
.ndo_select_queue = dpa_select_queue,
@@ -125,37 +129,66 @@ static const char macless_frame_queues[][25] = {
static int __cold dpa_macless_start(struct net_device *net_dev)
{
+ const struct dpa_priv_s *priv = netdev_priv(net_dev);
+ struct proxy_device *proxy_dev = (struct proxy_device *)priv->peer;
+
netif_tx_start_all_queues(net_dev);
+ if (proxy_dev)
+ dpa_proxy_start(net_dev);
+
+
return 0;
}
static int __cold dpa_macless_stop(struct net_device *net_dev)
{
+ const struct dpa_priv_s *priv = netdev_priv(net_dev);
+ struct proxy_device *proxy_dev = (struct proxy_device *)priv->peer;
+
netif_tx_stop_all_queues(net_dev);
+ if (proxy_dev)
+ dpa_proxy_stop(proxy_dev, net_dev);
+
return 0;
}
-static int dpa_set_macless_address(struct net_device *net_dev, void *addr)
+static int dpa_macless_set_address(struct net_device *net_dev, void *addr)
{
- const struct dpa_priv_s *priv;
+ const struct dpa_priv_s *priv = netdev_priv(net_dev);
+ struct proxy_device *proxy_dev = (struct proxy_device *)priv->peer;
int _errno;
- priv = netdev_priv(net_dev);
-
_errno = eth_mac_addr(net_dev, addr);
if (_errno < 0) {
if (netif_msg_drv(priv))
- netdev_err(net_dev,
- "eth_mac_addr() = %d\n",
- _errno);
+ netdev_err(net_dev, "eth_mac_addr() = %d\n", _errno);
return _errno;
}
+ if (proxy_dev) {
+ _errno = dpa_proxy_set_mac_address(proxy_dev, net_dev);
+ if (_errno < 0) {
+ if (netif_msg_drv(priv))
+ netdev_err(net_dev, "proxy_set_mac_address() = %d\n",
+ _errno);
+ return _errno;
+ }
+ }
+
return 0;
}
+static void __cold dpa_macless_set_rx_mode(struct net_device *net_dev)
+{
+ const struct dpa_priv_s *priv = netdev_priv(net_dev);
+ struct proxy_device *proxy_dev = (struct proxy_device *)priv->peer;
+
+ if (proxy_dev)
+ dpa_proxy_set_rx_mode(proxy_dev, net_dev);
+}
+
static netdev_features_t
dpa_macless_fix_features(struct net_device *dev, netdev_features_t features)
{
@@ -178,20 +211,32 @@ static int dpa_macless_netdev_init(struct device_node *dpa_node,
struct net_device *net_dev)
{
struct dpa_priv_s *priv = netdev_priv(net_dev);
+ struct proxy_device *proxy_dev = (struct proxy_device *)priv->peer;
struct device *dev = net_dev->dev.parent;
const uint8_t *mac_addr;
net_dev->netdev_ops = &dpa_macless_ops;
- /* Get the MAC address */
- mac_addr = of_get_mac_address(dpa_node);
- if (mac_addr == NULL) {
- if (netif_msg_probe(priv))
- dev_err(dev, "No MAC address found!\n");
- return -EINVAL;
- }
+ if (proxy_dev) {
+ struct mac_device *mac_dev = proxy_dev->mac_dev;
+ net_dev->mem_start = mac_dev->res->start;
+ net_dev->mem_end = mac_dev->res->end;
+
+ return dpa_netdev_init(dpa_node, net_dev, mac_dev->addr,
+ tx_timeout);
+ } else {
+ /* Get the MAC address from device tree */
+ mac_addr = of_get_mac_address(dpa_node);
+
+ if (mac_addr == NULL) {
+ if (netif_msg_probe(priv))
+ dev_err(dev, "No MAC address found!\n");
+ return -EINVAL;
+ }
- return dpa_netdev_init(dpa_node, net_dev, mac_addr, tx_timeout);
+ return dpa_netdev_init(dpa_node, net_dev, mac_addr,
+ tx_timeout);
+ }
}
/* Probing of FQs for MACless ports */
@@ -223,6 +268,41 @@ static int dpa_fq_probe_macless(struct device *dev, struct list_head *list,
return 0;
}
+struct proxy_device *dpa_macless_proxy_probe(struct platform_device *_of_dev)
+{
+ struct device *dev;
+ const phandle *proxy_prop;
+ struct proxy_device *proxy_dev;
+ struct device_node *proxy_node;
+ struct platform_device *proxy_pdev;
+ int lenp;
+
+ dev = &_of_dev->dev;
+
+ proxy_prop = of_get_property(dev->of_node, "proxy", &lenp);
+ if (!proxy_prop)
+ return NULL;
+
+ proxy_node = of_find_node_by_phandle(*proxy_prop);
+ if (!proxy_node) {
+ dev_err(dev, "Cannot find proxy node\n");
+ return NULL;
+ }
+
+ proxy_pdev = of_find_device_by_node(proxy_node);
+ if (!proxy_pdev) {
+ of_node_put(proxy_node);
+ dev_err(dev, "Cannot find device represented by proxy node\n");
+ return NULL;
+ }
+
+ proxy_dev = dev_get_drvdata(&proxy_pdev->dev);
+
+ of_node_put(proxy_node);
+
+ return proxy_dev;
+}
+
static int dpaa_eth_macless_probe(struct platform_device *_of_dev)
{
int err = 0, i;
@@ -234,6 +314,7 @@ static int dpaa_eth_macless_probe(struct platform_device *_of_dev)
struct net_device *net_dev = NULL;
struct dpa_priv_s *priv = NULL;
struct dpa_percpu_priv_s *percpu_priv;
+ static struct proxy_device *proxy_dev;
struct fm_port_fqs port_fqs;
struct task_struct *kth;
static u8 macless_idx;
@@ -250,6 +331,8 @@ static int dpaa_eth_macless_probe(struct platform_device *_of_dev)
if (IS_ERR(dpa_bp))
return PTR_ERR(dpa_bp);
+ proxy_dev = dpa_macless_proxy_probe(_of_dev);
+
dpa_bp->seed_cb = dpa_bp_shared_port_seed;
/* Allocate this early, so we can store relevant information in
@@ -270,6 +353,8 @@ static int dpaa_eth_macless_probe(struct platform_device *_of_dev)
sprintf(priv->if_type, "macless%d", macless_idx++);
priv->msg_enable = netif_msg_init(debug, -1);
+ /* control over proxy's mac device */
+ priv->peer = (void *)proxy_dev;
INIT_LIST_HEAD(&priv->dpa_fq_list);
@@ -397,7 +482,10 @@ static int __init __cold dpa_macless_load(void)
return _errno;
}
-module_init(dpa_macless_load);
+/* waits for proxy to initialize first, in case MAC device reference
+ * is needed
+ */
+late_initcall(dpa_macless_load);
static void __exit __cold dpa_macless_unload(void)
{
diff --git a/drivers/net/ethernet/freescale/dpa/dpaa_eth_non_sg.c b/drivers/net/ethernet/freescale/dpa/dpaa_eth_non_sg.c
index f1f9fce..d608881 100644
--- a/drivers/net/ethernet/freescale/dpa/dpaa_eth_non_sg.c
+++ b/drivers/net/ethernet/freescale/dpa/dpaa_eth_non_sg.c
@@ -294,6 +294,7 @@ static int dpa_process_one(struct dpa_percpu_priv_s *percpu_priv,
}
void __hot _dpa_rx(struct net_device *net_dev,
+ struct qman_portal *portal,
const struct dpa_priv_s *priv,
struct dpa_percpu_priv_s *percpu_priv,
const struct qm_fd *fd,
@@ -370,8 +371,12 @@ void __hot _dpa_rx(struct net_device *net_dev,
if (use_gro) {
gro_result_t gro_result;
+ const struct qman_portal_config *pc =
+ qman_p_get_portal_config(portal);
+ struct dpa_napi_portal *np = &percpu_priv->np[pc->index];
- gro_result = napi_gro_receive(&percpu_priv->napi, skb);
+ np->p = portal;
+ gro_result = napi_gro_receive(&np->napi, skb);
/* If frame is dropped by the stack, rx_dropped counter is
* incremented automatically, so no need for us to update it
*/
diff --git a/drivers/net/ethernet/freescale/dpa/dpaa_eth_proxy.c b/drivers/net/ethernet/freescale/dpa/dpaa_eth_proxy.c
index adb1125..1c1a121 100644
--- a/drivers/net/ethernet/freescale/dpa/dpaa_eth_proxy.c
+++ b/drivers/net/ethernet/freescale/dpa/dpaa_eth_proxy.c
@@ -74,6 +74,8 @@ static struct platform_driver dpa_proxy_driver = {
.remove = dpa_eth_proxy_remove
};
+static struct proxy_device *proxy_dev;
+
static int dpaa_eth_proxy_probe(struct platform_device *_of_dev)
{
int err = 0, i;
@@ -102,6 +104,15 @@ static int dpaa_eth_proxy_probe(struct platform_device *_of_dev)
if (IS_ERR(mac_dev))
return PTR_ERR(mac_dev);
+ proxy_dev = devm_kzalloc(dev, sizeof(*proxy_dev), GFP_KERNEL);
+ if (!proxy_dev) {
+ dev_err(dev, "devm_kzalloc() failed\n");
+ return -ENOMEM;
+ }
+
+ proxy_dev->mac_dev = mac_dev;
+ dev_set_drvdata(dev, proxy_dev);
+
/* We have physical ports, so we need to establish
* the buffer layout.
*/
@@ -150,8 +161,103 @@ static int dpaa_eth_proxy_probe(struct platform_device *_of_dev)
return 0; /* Proxy interface initialization ended */
}
+int dpa_proxy_set_mac_address(struct proxy_device *proxy_dev,
+ struct net_device *net_dev)
+{
+ struct mac_device *mac_dev;
+ int _errno;
+
+ mac_dev = proxy_dev->mac_dev;
+
+ _errno = mac_dev->change_addr(mac_dev->get_mac_handle(mac_dev),
+ net_dev->dev_addr);
+ if (_errno < 0)
+ return _errno;
+
+ return 0;
+}
+
+int dpa_proxy_set_rx_mode(struct proxy_device *proxy_dev,
+ struct net_device *net_dev)
+{
+ struct mac_device *mac_dev = proxy_dev->mac_dev;
+ int _errno;
+
+ _errno = mac_dev->set_multi(net_dev, mac_dev);
+ if (unlikely(_errno < 0))
+ return _errno;
+
+ return 0;
+}
+
+int dpa_proxy_start(struct net_device *net_dev)
+{
+ struct mac_device *mac_dev;
+ const struct dpa_priv_s *priv;
+ struct proxy_device *proxy_dev;
+ int _errno;
+ int i;
+
+ priv = netdev_priv(net_dev);
+ proxy_dev = (struct proxy_device *)priv->peer;
+ mac_dev = proxy_dev->mac_dev;
+
+ _errno = mac_dev->init_phy(net_dev, mac_dev);
+ if (_errno < 0) {
+ if (netif_msg_drv(priv))
+ netdev_err(net_dev, "init_phy() = %d\n",
+ _errno);
+ return _errno;
+ }
+
+ for_each_port_device(i, mac_dev->port_dev)
+ fm_port_enable(mac_dev->port_dev[i]);
+
+ _errno = mac_dev->start(mac_dev);
+ if (_errno < 0) {
+ if (netif_msg_drv(priv))
+ netdev_err(net_dev, "mac_dev->start() = %d\n",
+ _errno);
+ return _errno;
+ }
+
+ return _errno;
+}
+
+int dpa_proxy_stop(struct proxy_device *proxy_dev, struct net_device *net_dev)
+{
+ struct mac_device *mac_dev = proxy_dev->mac_dev;
+ const struct dpa_priv_s *priv = netdev_priv(net_dev);
+ int _errno, i;
+
+ _errno = mac_dev->stop(mac_dev);
+ if (_errno < 0) {
+ if (netif_msg_drv(priv))
+ netdev_err(net_dev, "mac_dev->stop() = %d\n",
+ _errno);
+ return _errno;
+ }
+
+ for_each_port_device(i, mac_dev->port_dev)
+ fm_port_disable(mac_dev->port_dev[i]);
+
+ if (mac_dev->phy_dev)
+ phy_disconnect(mac_dev->phy_dev);
+ mac_dev->phy_dev = NULL;
+
+ return _errno;
+}
+
static int __cold dpa_eth_proxy_remove(struct platform_device *of_dev)
{
+ struct device *dev;
+
+ dev = &of_dev->dev;
+ dev_set_drvdata(dev, NULL);
+
+ if (proxy_dev)
+ kfree(proxy_dev);
+
return 0;
}
diff --git a/drivers/net/ethernet/freescale/dpa/dpaa_eth_sg.c b/drivers/net/ethernet/freescale/dpa/dpaa_eth_sg.c
index 38580c9..eade30a 100644
--- a/drivers/net/ethernet/freescale/dpa/dpaa_eth_sg.c
+++ b/drivers/net/ethernet/freescale/dpa/dpaa_eth_sg.c
@@ -505,6 +505,7 @@ static struct sk_buff *__hot sg_fd_to_skb(const struct dpa_priv_s *priv,
}
void __hot _dpa_rx(struct net_device *net_dev,
+ struct qman_portal *portal,
const struct dpa_priv_s *priv,
struct dpa_percpu_priv_s *percpu_priv,
const struct qm_fd *fd,
@@ -573,8 +574,12 @@ void __hot _dpa_rx(struct net_device *net_dev,
if (use_gro) {
gro_result_t gro_result;
+ const struct qman_portal_config *pc =
+ qman_p_get_portal_config(portal);
+ struct dpa_napi_portal *np = &percpu_priv->np[pc->index];
- gro_result = napi_gro_receive(&percpu_priv->napi, skb);
+ np->p = portal;
+ gro_result = napi_gro_receive(&np->napi, skb);
/* If frame is dropped by the stack, rx_dropped counter is
* incremented automatically, so no need for us to update it
*/
diff --git a/drivers/net/ethernet/freescale/dpa/mac-api.c b/drivers/net/ethernet/freescale/dpa/mac-api.c
index 438fe1f..09889e4 100644
--- a/drivers/net/ethernet/freescale/dpa/mac-api.c
+++ b/drivers/net/ethernet/freescale/dpa/mac-api.c
@@ -41,6 +41,7 @@
#include <linux/netdevice.h>
#include "dpaa_eth.h"
+#include "dpaa_eth_common.h"
#include "mac.h"
#include "lnxwrp_fsl_fman.h"
@@ -285,17 +286,14 @@ static int __cold stop(struct mac_device *mac_dev)
return fm_mac_disable(mac_dev->get_mac_handle(mac_dev));
}
-static int __cold set_multi(struct net_device *net_dev)
+static int __cold set_multi(struct net_device *net_dev,
+ struct mac_device *mac_dev)
{
- struct dpa_priv_s *priv;
- struct mac_device *mac_dev;
struct mac_priv_s *mac_priv;
struct mac_address *old_addr, *tmp;
struct netdev_hw_addr *ha;
int _errno;
- priv = netdev_priv(net_dev);
- mac_dev = priv->mac_dev;
mac_priv = macdev_priv(mac_dev);
/* Clear previous address list */
@@ -330,7 +328,9 @@ static int __cold set_multi(struct net_device *net_dev)
static void adjust_link(struct net_device *net_dev)
{
struct dpa_priv_s *priv = netdev_priv(net_dev);
- struct mac_device *mac_dev = priv->mac_dev;
+ struct proxy_device *proxy_dev = (struct proxy_device *)priv->peer;
+ struct mac_device *mac_dev = proxy_dev ? proxy_dev->mac_dev :
+ priv->mac_dev;
struct phy_device *phy_dev = mac_dev->phy_dev;
fm_mac_adjust_link(mac_dev->get_mac_handle(mac_dev),
@@ -340,15 +340,11 @@ static void adjust_link(struct net_device *net_dev)
/* Initializes driver's PHY state, and attaches to the PHY.
* Returns 0 on success.
*/
-static int dtsec_init_phy(struct net_device *net_dev)
+static int dtsec_init_phy(struct net_device *net_dev,
+ struct mac_device *mac_dev)
{
- struct dpa_priv_s *priv;
- struct mac_device *mac_dev;
struct phy_device *phy_dev;
- priv = netdev_priv(net_dev);
- mac_dev = priv->mac_dev;
-
if (!mac_dev->phy_node)
phy_dev = phy_connect(net_dev, mac_dev->fixed_bus_id,
&adjust_link, 0, mac_dev->phy_if);
@@ -364,18 +360,17 @@ static int dtsec_init_phy(struct net_device *net_dev)
}
/* Remove any features not supported by the controller */
- phy_dev->supported &= priv->mac_dev->if_support;
+ phy_dev->supported &= mac_dev->if_support;
phy_dev->advertising = phy_dev->supported;
- priv->mac_dev->phy_dev = phy_dev;
+ mac_dev->phy_dev = phy_dev;
return 0;
}
-static int xgmac_init_phy(struct net_device *net_dev)
+static int xgmac_init_phy(struct net_device *net_dev,
+ struct mac_device *mac_dev)
{
- struct dpa_priv_s *priv = netdev_priv(net_dev);
- struct mac_device *mac_dev = priv->mac_dev;
struct phy_device *phy_dev;
if (!mac_dev->phy_node)
@@ -392,7 +387,7 @@ static int xgmac_init_phy(struct net_device *net_dev)
return phy_dev == NULL ? -ENODEV : PTR_ERR(phy_dev);
}
- phy_dev->supported &= priv->mac_dev->if_support;
+ phy_dev->supported &= mac_dev->if_support;
phy_dev->advertising = phy_dev->supported;
mac_dev->phy_dev = phy_dev;
@@ -400,15 +395,11 @@ static int xgmac_init_phy(struct net_device *net_dev)
return 0;
}
-static int memac_init_phy(struct net_device *net_dev)
+static int memac_init_phy(struct net_device *net_dev,
+ struct mac_device *mac_dev)
{
- struct dpa_priv_s *priv;
- struct mac_device *mac_dev;
struct phy_device *phy_dev;
- priv = netdev_priv(net_dev);
- mac_dev = priv->mac_dev;
-
if (macdev2enetinterface(mac_dev) == e_ENET_MODE_XGMII_10000) {
if (!mac_dev->phy_node) {
mac_dev->phy_dev = NULL;
@@ -434,7 +425,7 @@ static int memac_init_phy(struct net_device *net_dev)
}
/* Remove any features not supported by the controller */
- phy_dev->supported &= priv->mac_dev->if_support;
+ phy_dev->supported &= mac_dev->if_support;
phy_dev->advertising = phy_dev->supported;
mac_dev->phy_dev = phy_dev;
diff --git a/drivers/net/ethernet/freescale/dpa/mac.h b/drivers/net/ethernet/freescale/dpa/mac.h
index 270ee90..37abc7f 100644
--- a/drivers/net/ethernet/freescale/dpa/mac.h
+++ b/drivers/net/ethernet/freescale/dpa/mac.h
@@ -72,13 +72,14 @@ struct mac_device {
u32 tx_pause;
struct fm_mac_dev *(*get_mac_handle)(struct mac_device *mac_dev);
- int (*init_phy)(struct net_device *net_dev);
+ int (*init_phy)(struct net_device *net_dev, struct mac_device *mac_dev);
int (*init)(struct mac_device *mac_dev);
int (*start)(struct mac_device *mac_dev);
int (*stop)(struct mac_device *mac_dev);
int (*set_promisc)(struct fm_mac_dev *fm_mac_dev, bool enable);
int (*change_addr)(struct fm_mac_dev *fm_mac_dev, uint8_t *addr);
- int (*set_multi)(struct net_device *net_dev);
+ int (*set_multi)(struct net_device *net_dev,
+ struct mac_device *mac_dev);
int (*uninit)(struct fm_mac_dev *fm_mac_dev);
int (*ptp_enable)(struct fm_mac_dev *fm_mac_dev);
int (*ptp_disable)(struct fm_mac_dev *fm_mac_dev);
diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_fm.h b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_fm.h
index 99cbfa4..30b6bf2 100644
--- a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_fm.h
+++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_fm.h
@@ -115,6 +115,9 @@ typedef struct {
struct device_attribute *dev_attr_regs;
struct device_attribute *dev_attr_bmi_regs;
struct device_attribute *dev_attr_qmi_regs;
+#if (DPAA_VERSION >= 11)
+ struct device_attribute *dev_attr_ipv4_opt;
+#endif
} t_LnxWrpFmPortDev;
typedef struct {
diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.c b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.c
index 8a8589d..848cea9 100644
--- a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.c
+++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.c
@@ -278,7 +278,47 @@ static ssize_t show_fm_port_regs(struct device *dev,
}
+#if (DPAA_VERSION >= 11)
+static ssize_t show_fm_port_ipv4_options(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev =
+ (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
+#endif
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ local_irq_save(flags);
+
+ if (!p_LnxWrpFmPortDev->h_Dev) {
+ n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n");
+ return n;
+ } else {
+ n = snprintf(buf, PAGE_SIZE,
+ "Counter for fragmented pkt with IP header options\n");
+ n = fm_port_dump_ipv4_opt(p_LnxWrpFmPortDev->h_Dev, buf, n);
+ }
+
+ local_irq_restore(flags);
+ return n;
+#else
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+
+ return n;
+#endif
+}
+
+#endif
static ssize_t show_fm_port_bmi_regs(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -361,6 +401,9 @@ static ssize_t show_fm_port_qmi_regs(struct device *dev,
static DEVICE_ATTR(fm_port_regs, 0x644, show_fm_port_regs, NULL);
static DEVICE_ATTR(fm_port_qmi_regs, 0x644, show_fm_port_qmi_regs, NULL);
static DEVICE_ATTR(fm_port_bmi_regs, 0x644, show_fm_port_bmi_regs, NULL);
+#if (DPAA_VERSION >= 11)
+static DEVICE_ATTR(fm_port_ipv4_opt, 0x644, show_fm_port_ipv4_options, NULL);
+#endif
int fm_port_sysfs_create(struct device *dev)
{
@@ -377,7 +420,9 @@ int fm_port_sysfs_create(struct device *dev)
p_LnxWrpFmPortDev->dev_attr_regs = &dev_attr_fm_port_regs;
p_LnxWrpFmPortDev->dev_attr_qmi_regs = &dev_attr_fm_port_qmi_regs;
p_LnxWrpFmPortDev->dev_attr_bmi_regs = &dev_attr_fm_port_bmi_regs;
-
+#if (DPAA_VERSION >= 11)
+ p_LnxWrpFmPortDev->dev_attr_ipv4_opt = &dev_attr_fm_port_ipv4_opt;
+#endif
/* Registers dump entry - in future will be moved to debugfs */
if (device_create_file(dev, &dev_attr_fm_port_regs) != 0)
return -EIO;
@@ -385,7 +430,11 @@ int fm_port_sysfs_create(struct device *dev)
return -EIO;
if (device_create_file(dev, &dev_attr_fm_port_bmi_regs) != 0)
return -EIO;
-
+#if (DPAA_VERSION >= 11)
+ if (device_create_file(dev, &dev_attr_fm_port_ipv4_opt) != 0)
+ return -EIO;
+#endif
+
/* FM Ports statistics */
switch (p_LnxWrpFmPortDev->settings.param.portType) {
case e_FM_PORT_TYPE_TX:
@@ -452,6 +501,9 @@ void fm_port_sysfs_destroy(struct device *dev)
device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_regs);
device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_qmi_regs);
device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_bmi_regs);
+#if (DPAA_VERSION >= 11)
+ device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_ipv4_opt);
+#endif
}
@@ -493,6 +545,23 @@ int fm_port_dump_regs(void *h_dev, char *buf, int nn)
return n;
}
+#if (DPAA_VERSION >= 11)
+
+int fm_port_dump_ipv4_opt(void *h_dev, char *buf, int nn)
+{
+ t_FmPort *p_FmPort;
+ int n = nn;
+
+ p_FmPort = (t_FmPort *)h_dev;
+
+ FM_DMP_V32(buf, n, p_FmPort->p_ParamsPage, ipfOptionsCounter);
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+
+ return n;
+}
+#endif
+
int fm_port_dump_regs_bmi(void *h_dev, char *buf, int nn)
{
t_FmPort *p_FmPort;
diff --git a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.h b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.h
index 525e46c..1e7636f 100644
--- a/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.h
+++ b/drivers/net/ethernet/freescale/fman/src/wrapper/lnxwrp_sysfs_fm_port.h
@@ -49,4 +49,8 @@ int fm_port_dump_regs(void *h_dev, char *buf, int n);
int fm_port_dump_regs_bmi(void *h_dev, char *buf, int n);
int fm_port_dump_regs_qmi(void *h_dev, char *buf, int n);
+#if (DPAA_VERSION >= 11)
+int fm_port_dump_ipv4_opt(void *h_dev, char *buf, int n);
+#endif
+
#endif /* LNXWRP_SYSFS_FM_PORT_H_ */
diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c
index b555b5f..7e21e6c 100644
--- a/drivers/net/ethernet/freescale/xgmac_mdio.c
+++ b/drivers/net/ethernet/freescale/xgmac_mdio.c
@@ -181,6 +181,8 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
return ret;
}
+ out_be32(&regs->mdio_addr, regnum);
+
/* Initiate the read */
out_be32(&regs->mdio_ctl, mdio_ctl | MDIO_CTL_READ);
diff --git a/drivers/staging/fsl_qbman/bman_driver.c b/drivers/staging/fsl_qbman/bman_driver.c
index a32fadb..40bfc01 100644
--- a/drivers/staging/fsl_qbman/bman_driver.c
+++ b/drivers/staging/fsl_qbman/bman_driver.c
@@ -141,11 +141,11 @@ static struct bm_portal_config * __init parse_pcfg(struct device_node *node)
} else if (of_device_is_compatible(node, "fsl,bman-portal-2.1.2")) {
bman_ip_rev = BMAN_REV21;
bman_pool_max = 64;
- bman_portal_max = 10;
+ bman_portal_max = 18;
} else if (of_device_is_compatible(node, "fsl,bman-portal-2.1.3")) {
bman_ip_rev = BMAN_REV21;
bman_pool_max = 64;
- bman_portal_max = 18;
+ bman_portal_max = 10;
}
ret = of_address_to_resource(node, DPA_PORTAL_CE,
@@ -299,18 +299,26 @@ __setup("bportals=", parse_bportals);
static void bman_offline_cpu(unsigned int cpu)
{
struct bman_portal *p;
+ const struct bm_portal_config *pcfg;
p = (struct bman_portal *)affine_bportals[cpu];
- if (p && (!bman_portal_is_sharing_redirect(p)))
- bman_migrate_portal(p);
+ if (p) {
+ pcfg = bman_get_bm_portal_config(p);
+ if (pcfg)
+ irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(0));
+ }
}
#ifdef CONFIG_HOTPLUG_CPU
static void bman_online_cpu(unsigned int cpu)
{
struct bman_portal *p;
+ const struct bm_portal_config *pcfg;
p = (struct bman_portal *)affine_bportals[cpu];
- if (p && (!bman_portal_is_sharing_redirect(p)))
- bman_migrate_portal_back(p, cpu);
+ if (p) {
+ pcfg = bman_get_bm_portal_config(p);
+ if (pcfg)
+ irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(cpu));
+ }
}
static int __cpuinit bman_hotplug_cpu_callback(struct notifier_block *nfb,
diff --git a/drivers/staging/fsl_qbman/bman_high.c b/drivers/staging/fsl_qbman/bman_high.c
index d070d34..da46a5a 100644
--- a/drivers/staging/fsl_qbman/bman_high.c
+++ b/drivers/staging/fsl_qbman/bman_high.c
@@ -1048,27 +1048,8 @@ int bman_shutdown_pool(u32 bpid)
}
EXPORT_SYMBOL(bman_shutdown_pool);
-int bman_portal_is_sharing_redirect(struct bman_portal *portal)
+const struct bm_portal_config *bman_get_bm_portal_config(
+ struct bman_portal *portal)
{
- return portal->sharing_redirect ? 1 : 0;
+ return portal->sharing_redirect ? NULL : portal->config;
}
-
-/* Migrate the portal to the boot cpu(cpu0) for offline cpu */
-void bman_migrate_portal(struct bman_portal *portal)
-{
- unsigned long irqflags __maybe_unused;
- PORTAL_IRQ_LOCK(portal, irqflags);
- irq_set_affinity(portal->config->public_cfg.irq, cpumask_of(0));
- PORTAL_IRQ_UNLOCK(portal, irqflags);
-}
-
-#ifdef CONFIG_HOTPLUG_CPU
-/* Migrate the portal back to the affined cpu once that cpu reappears.*/
-void bman_migrate_portal_back(struct bman_portal *portal, unsigned int cpu)
-{
- unsigned long irqflags __maybe_unused;
- PORTAL_IRQ_LOCK(portal, irqflags);
- irq_set_affinity(portal->config->public_cfg.irq, cpumask_of(cpu));
- PORTAL_IRQ_UNLOCK(portal, irqflags);
-}
-#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/drivers/staging/fsl_qbman/bman_private.h b/drivers/staging/fsl_qbman/bman_private.h
index 22e4a8c..e24588b 100644
--- a/drivers/staging/fsl_qbman/bman_private.h
+++ b/drivers/staging/fsl_qbman/bman_private.h
@@ -156,10 +156,6 @@ u32 bm_pool_free_buffers(u32 bpid);
__init int bman_init(void);
__init int bman_resource_init(void);
-/* Portal migration */
-int bman_portal_is_sharing_redirect(struct bman_portal *portal);
-void bman_migrate_portal(struct bman_portal *portal);
-#ifdef CONFIG_HOTPLUG_CPU
-void bman_migrate_portal_back(struct bman_portal *portal, unsigned int cpu);
-#endif /* CONFIG_HOTPLUG_CPU */
+const struct bm_portal_config *bman_get_bm_portal_config(
+ struct bman_portal *portal);
#endif /* CONFIG_FSL_BMAN_CONFIG */
diff --git a/drivers/staging/fsl_qbman/qman_driver.c b/drivers/staging/fsl_qbman/qman_driver.c
index fc5855c..cf1c3b3 100644
--- a/drivers/staging/fsl_qbman/qman_driver.c
+++ b/drivers/staging/fsl_qbman/qman_driver.c
@@ -639,21 +639,56 @@ static int __init parse_qportals(char *str)
}
__setup("qportals=", parse_qportals);
+static void qman_portal_update_sdest(const struct qm_portal_config *pcfg,
+ unsigned int cpu)
+{
+ struct iommu_stash_attribute stash_attr;
+ int ret;
+
+ if (pcfg->iommu_domain) {
+ stash_attr.cpu = cpu;
+ stash_attr.cache = IOMMU_ATTR_CACHE_L1;
+ stash_attr.window = ~(u32)0;
+ ret = iommu_domain_set_attr(pcfg->iommu_domain,
+ DOMAIN_ATTR_PAMU_STASH, &stash_attr);
+ if (ret < 0) {
+ pr_err("Failed to update pamu stash setting\n");
+ return;
+ }
+ }
+#ifdef CONFIG_FSL_QMAN_CONFIG
+ if (qman_set_sdest(pcfg->public_cfg.channel, cpu))
+#endif
+ pr_warning("Failed to update portal's stash request queue\n");
+}
+
static void qman_offline_cpu(unsigned int cpu)
{
struct qman_portal *p;
+ const struct qm_portal_config *pcfg;
p = (struct qman_portal *)affine_portals[cpu];
- if (p && (!qman_portal_is_sharing_redirect(p)))
- qman_migrate_portal(p);
+ if (p) {
+ pcfg = qman_get_qm_portal_config(p);
+ if (pcfg) {
+ irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(0));
+ qman_portal_update_sdest(pcfg, 0);
+ }
+ }
}
#ifdef CONFIG_HOTPLUG_CPU
static void qman_online_cpu(unsigned int cpu)
{
struct qman_portal *p;
+ const struct qm_portal_config *pcfg;
p = (struct qman_portal *)affine_portals[cpu];
- if (p && (!qman_portal_is_sharing_redirect(p)))
- qman_migrate_portal_back(p, cpu);
+ if (p) {
+ pcfg = qman_get_qm_portal_config(p);
+ if (pcfg) {
+ irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(cpu));
+ qman_portal_update_sdest(pcfg, cpu);
+ }
+ }
}
static int __cpuinit qman_hotplug_cpu_callback(struct notifier_block *nfb,
diff --git a/drivers/staging/fsl_qbman/qman_high.c b/drivers/staging/fsl_qbman/qman_high.c
index 0d4305f..5fecfc1 100644
--- a/drivers/staging/fsl_qbman/qman_high.c
+++ b/drivers/staging/fsl_qbman/qman_high.c
@@ -4897,52 +4897,8 @@ int qman_shutdown_fq(u32 fqid)
return ret;
}
-static void qman_portal_update_sdest(const struct qm_portal_config *pcfg,
- unsigned int cpu)
+const struct qm_portal_config *qman_get_qm_portal_config(
+ struct qman_portal *portal)
{
- struct iommu_stash_attribute stash_attr;
- int ret;
-
- if (pcfg->iommu_domain) {
- stash_attr.cpu = cpu;
- stash_attr.cache = IOMMU_ATTR_CACHE_L1;
- stash_attr.window = ~(u32)0;
- ret = iommu_domain_set_attr(pcfg->iommu_domain,
- DOMAIN_ATTR_PAMU_STASH, &stash_attr);
- if (ret < 0) {
- pr_err("Failed to update pamu stash setting\n");
- return;
- }
- }
-#ifdef CONFIG_FSL_QMAN_CONFIG
- if (qman_set_sdest(pcfg->public_cfg.channel, cpu))
-#endif
- pr_warning("Failed to update portal's stash request queue\n");
-}
-
-int qman_portal_is_sharing_redirect(struct qman_portal *portal)
-{
- return portal->sharing_redirect ? 1 : 0;
-}
-
-/* Migrate the portal to the boot cpu(cpu0) for offline cpu */
-void qman_migrate_portal(struct qman_portal *portal)
-{
- unsigned long irqflags __maybe_unused;
- PORTAL_IRQ_LOCK(portal, irqflags);
- irq_set_affinity(portal->config->public_cfg.irq, cpumask_of(0));
- qman_portal_update_sdest(portal->config, 0);
- PORTAL_IRQ_UNLOCK(portal, irqflags);
-}
-
-#ifdef CONFIG_HOTPLUG_CPU
-/* Migrate the portal back to the affined cpu once that cpu appears.*/
-void qman_migrate_portal_back(struct qman_portal *portal, unsigned int cpu)
-{
- unsigned long irqflags __maybe_unused;
- PORTAL_IRQ_LOCK(portal, irqflags);
- qman_portal_update_sdest(portal->config, cpu);
- irq_set_affinity(portal->config->public_cfg.irq, cpumask_of(cpu));
- PORTAL_IRQ_UNLOCK(portal, irqflags);
+ return portal->sharing_redirect ? NULL : portal->config;
}
-#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/drivers/staging/fsl_qbman/qman_private.h b/drivers/staging/fsl_qbman/qman_private.h
index e7c77b6..7539032 100644
--- a/drivers/staging/fsl_qbman/qman_private.h
+++ b/drivers/staging/fsl_qbman/qman_private.h
@@ -390,10 +390,6 @@ int qman_ceetm_query_ccgr(struct qm_mcc_ceetm_ccgr_query *ccgr_query,
struct qm_mcr_ceetm_ccgr_query *response);
int qman_ceetm_get_xsfdr(enum qm_dc_portal portal, unsigned int *num);
-/* Portal migration */
extern void *affine_portals[NR_CPUS];
-int qman_portal_is_sharing_redirect(struct qman_portal *portal);
-void qman_migrate_portal(struct qman_portal *portal);
-#ifdef CONFIG_HOTPLUG_CPU
-void qman_migrate_portal_back(struct qman_portal *portal, unsigned int cpu);
-#endif /* CONFIG_HOTPLUG_CPU */
+const struct qm_portal_config *qman_get_qm_portal_config(
+ struct qman_portal *portal);
diff --git a/drivers/tdm/test/Kconfig b/drivers/tdm/test/Kconfig
index 81fc3f4..39f9581 100644
--- a/drivers/tdm/test/Kconfig
+++ b/drivers/tdm/test/Kconfig
@@ -19,4 +19,11 @@ config UCC_TDM_TEST
This UCC TDM test module is a small test module to test
ucc tdm transfer and receive data via ucc1.
+config TDM_LOOPBACK_TEST
+ tristate "TDM Loopback test Module"
+ depends on FSL_SOC
+ ---help---
+ This TDM Loopback test module is a small test module which
+ performs a simple internal loopback testing.
+
endmenu
diff --git a/drivers/tdm/test/Makefile b/drivers/tdm/test/Makefile
index c229934..47bb4ef 100644
--- a/drivers/tdm/test/Makefile
+++ b/drivers/tdm/test/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_TDM_TEST) += tdm_test.o
obj-$(CONFIG_UCC_TDM_TEST) += ucc_tdm_test.o
+obj-$(CONFIG_TDM_LOOPBACK_TEST) += tdm_loopback_test.o
diff --git a/drivers/tdm/test/tdm_loopback_test.c b/drivers/tdm/test/tdm_loopback_test.c
new file mode 100644
index 0000000..49554aa
--- /dev/null
+++ b/drivers/tdm/test/tdm_loopback_test.c
@@ -0,0 +1,251 @@
+/*
+ *
+ * Copyright 2011-2012 Freescale Semiconductor, Inc.
+ *
+ * TDM Loopback Test Module.
+ * This TDM test module is a small test module which registers with the
+ * TDM framework and transfer and receive data in loopback mode and also
+ * compares if the data sent is received correctly.
+ *
+ * Author: Sandeep Kumar Singh <sandeep@freescale.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, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/param.h>
+#include <linux/tdm.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/tdm.h>
+
+
+#define DRV_DESC "Test Module for Freescale Platforms with TDM support"
+#define DRV_NAME "tdm_test"
+
+
+#define POLL_COUNT 38
+#define TDM_FRAME_LENGTH NUM_SAMPLES_PER_FRAME
+#define TDM_E_OK 0
+#define BUF_COUNT 7
+
+#define DEBUG 0
+
+int poll_count = POLL_COUNT;
+module_param(poll_count, int, 0);
+
+static struct task_struct *tdm_thread_task;
+static struct tdm_driver test_tdmdev_driver;
+struct tdm_port *tdmport;
+int tdm_thread_state;
+
+static int tdm_check_data(unsigned short *tx_data, unsigned short *rx_data)
+{
+ int i, error = 0;
+ static int call_count;
+
+ for (i = 1; i < TDM_FRAME_LENGTH; i++) {
+ if (tx_data[i] != rx_data[i])
+ error++;
+ else
+ continue;
+ }
+
+ pr_info("Iteration: %d\n", ++call_count);
+#if DEBUG
+ pr_info("TX DATA:\n");
+ for (i = 0; i < TDM_FRAME_LENGTH; i++) {
+ pr_info("%5x ", tx_data[i]);
+ if (i%20 == 19)
+ pr_info("\n");
+ }
+ pr_info("RX DATA:\n");
+ for (i = 0; i < TDM_FRAME_LENGTH; i++) {
+ pr_info("%5x ", rx_data[i]);
+ if (i%20 == 19)
+ pr_info("\n");
+ }
+#endif
+ if (error)
+ pr_info("TX and RX buffer do NOT match. Err_count:"
+ "%d\n", error);
+ else
+ pr_info("TX and RX buffer MATCH\n");
+
+ return error;
+}
+
+
+static int tdm_thread(void *ptr)
+{
+ void *h_port;
+ void *h_channel1;
+ int ret = TDM_E_OK;
+ int poll = 0;
+ int i = 0, j = 0;
+ int index = 0;
+ int error_count = 0;
+ int buffer_size;
+ uint16_t size = TDM_FRAME_LENGTH;
+ u16 ch1_id = 0;
+ unsigned short *tx_data[BUF_COUNT];
+ unsigned short *rx_data[BUF_COUNT];
+
+ tdm_thread_state = 1;
+
+ /* Open port */
+ ret = tdm_port_open(&test_tdmdev_driver, &h_port);
+ pr_debug("%s tdm_port_open ret = %d\n", __func__, ret);
+ if ((ret != TDM_E_OK) || (h_port == NULL)) {
+ pr_err("Error in tdm_port_open- ret %x\n", ret);
+ goto port1_failed;
+ }
+ /* Open Channel 1*/
+ ret = tdm_channel_open(ch1_id, 1, h_port, &h_channel1);
+ if ((ret != TDM_E_OK) || (h_channel1 == NULL)) {
+ pr_err("Error in tdm_channel_open(%d)- ret %x\n", ch1_id, ret);
+ goto ch1_failed;
+ }
+
+ buffer_size = sizeof(unsigned short)*BUF_COUNT*TDM_FRAME_LENGTH;
+ tx_data[0] = kmalloc(buffer_size, GFP_KERNEL);
+ rx_data[0] = kmalloc(buffer_size, GFP_KERNEL);
+
+ if ((tx_data[0] == NULL) || (rx_data[0] == NULL)) {
+ pr_err("Failed to get memory for buffer");
+ return 0;
+ }
+ for (i = 0; i < BUF_COUNT-1; i++) {
+ tx_data[i+1] = tx_data[i] + TDM_FRAME_LENGTH;
+ rx_data[i+1] = rx_data[i] + TDM_FRAME_LENGTH;
+ }
+ while ((poll < poll_count) && !kthread_should_stop()) {
+
+ poll++;
+ while (tdm_ch_poll(h_channel1, 10) != TDM_E_OK)
+ continue;
+ for (i = 0; i < TDM_FRAME_LENGTH; i++)
+ tx_data[index][i] = j*TDM_FRAME_LENGTH+i;
+
+ ret = tdm_channel_write(h_port, h_channel1, tx_data[index],
+ size);
+ if (ret != TDM_E_OK)
+ pr_info("Error in tdm_channel_write\n");
+ ret = tdm_channel_read(h_port, h_channel1, rx_data[index],
+ &size);
+ if (ret != TDM_E_OK)
+ pr_info("Error in tdm_channel_read\n");
+ /*
+ * There is a delay of 6 frame between transmitted data and
+ * received data. Hence we compare tx_data[0] with rx data[6]
+ * and so on
+ */
+ if (j++ > BUF_COUNT)
+ error_count += tdm_check_data(tx_data[(index + 1)
+ %BUF_COUNT], rx_data[index]);
+ index++;
+ index = index%BUF_COUNT;
+
+ }
+ pr_info("\nTDM Loppback test completed.\n");
+ if (error_count == 0)
+ pr_info("TDM loopback test PASSED!\n");
+ else
+ pr_info("TDM loopback test FAILED!\n");
+
+ ret = tdm_channel_close(ch1_id, 1, h_port, h_channel1);
+ if (ret != TDM_E_OK) {
+ pr_err("Error in tdm_channel_close(%d)- ret %x\n", ch1_id, ret);
+ ret = -ENXIO;
+ }
+
+ ret = tdm_port_close(h_port);
+ pr_debug("%s tdm_port_close ret = %d\n", __func__, ret);
+ if (ret != TDM_E_OK) {
+ pr_err("Error in tdm_port_close- ret %x\n", ret);
+ ret = -ENXIO;
+ }
+
+ tdm_thread_state = 0;
+
+ return ret;
+
+ch1_failed:
+ tdm_channel_close(ch1_id, 1, h_port, h_channel1);
+port1_failed:
+ tdm_port_close(h_port);
+ return -ENXIO;
+}
+
+static int test_attach_adapter(struct tdm_adapter *adap)
+{
+ tdm_thread_state = 0;
+ tdm_thread_task = kthread_run(tdm_thread, NULL, "tdm_thread");
+
+ return 0;
+}
+
+static int test_detach_adapter(struct tdm_adapter *adap)
+{
+ if (tdm_thread_state)
+ kthread_stop(tdm_thread_task);
+
+ return 0;
+}
+
+static const struct tdm_device_id tdm_loopback_test_id[] = {
+ { "fsl_tdm", 0 },
+ { }
+};
+
+static struct tdm_driver test_tdmdev_driver = {
+ .attach_adapter = test_attach_adapter,
+ .detach_adapter = test_detach_adapter,
+ .id_table = tdm_loopback_test_id,
+};
+
+static int __init tdm_loopback_test_init(void)
+{
+ int ret;
+ pr_info("TDM LOOPBACK TEST: \n");
+ test_tdmdev_driver.id = 1;
+
+ /* create a binding with TDM driver */
+ ret = tdm_add_driver(&test_tdmdev_driver);
+ if (ret == 0)
+ pr_info("TDM LOOPBACK TEST module installed\n");
+ else
+ pr_err("%s tdm_port_init failed\n", __func__);
+ return ret;
+}
+
+static void __exit tdm_loopback_test_exit(void)
+{
+ tdm_unregister_driver(&test_tdmdev_driver);
+ pr_info("TDM LOOPBACK TEST module un-installed\n");
+}
+
+module_init(tdm_loopback_test_init);
+module_exit(tdm_loopback_test_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sandeep Kumar Singh <sandeep@freescale.com>");
+MODULE_DESCRIPTION("Test Loopback Test Module for Freescale Platforms"
+" with TDM support");