diff options
author | Scott Wood <scottwood@freescale.com> | 2013-12-14 02:43:39 (GMT) |
---|---|---|
committer | Scott Wood <scottwood@freescale.com> | 2013-12-14 02:45:02 (GMT) |
commit | 5709059c4e110944712dc1f3d66a203a924c151a (patch) | |
tree | 3f5ff4c45d2b1089c3f4504771a78e847b3ac073 /drivers | |
parent | b7c81aa3ab2ac2c140e278b6d0e9a0b95112cf0b (diff) | |
parent | 3dea020415467452d6ca2e907e21af07954741cf (diff) | |
download | linux-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')
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, ®s); + 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(®s->mdio_addr, regnum); + /* Initiate the read */ out_be32(®s->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"); |