mirror of
https://git.rtems.org/rtems-libbsd/
synced 2025-06-06 00:30:22 +08:00
sdk_dpaa: Import from QorIQ SDK Linux
http://git.freescale.com/git/cgit.cgi/ppc/sdk/linux.git Commit 1ae843c08261402b2c35d83422e4fa1e313611f4 (fsl-sdk-v2.0-1703). Update #3277.
This commit is contained in:
parent
0f6ff4a923
commit
f5ed3aa620
265
linux/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c
Normal file
265
linux/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c
Normal file
@ -0,0 +1,265 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/* Copyright 2008-2013 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Freescale Semiconductor nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* ALTERNATIVELY, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") as published by the Free Software
|
||||
* Foundation, either version 2 of that License or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
|
||||
#define pr_fmt(fmt) \
|
||||
KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
|
||||
KBUILD_BASENAME".c", __LINE__, __func__
|
||||
#else
|
||||
#define pr_fmt(fmt) \
|
||||
KBUILD_MODNAME ": " fmt
|
||||
#endif
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/sort.h>
|
||||
#include <linux/fsl_qman.h>
|
||||
#include "dpaa_eth.h"
|
||||
#include "dpaa_eth_common.h"
|
||||
#include "dpaa_eth_base.h"
|
||||
|
||||
#define DPA_DESCRIPTION "FSL DPAA Advanced drivers:"
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
||||
uint8_t advanced_debug = -1;
|
||||
module_param(advanced_debug, byte, S_IRUGO);
|
||||
MODULE_PARM_DESC(advanced_debug, "Module/Driver verbosity level");
|
||||
EXPORT_SYMBOL(advanced_debug);
|
||||
|
||||
static int dpa_bp_cmp(const void *dpa_bp0, const void *dpa_bp1)
|
||||
{
|
||||
return ((struct dpa_bp *)dpa_bp0)->size -
|
||||
((struct dpa_bp *)dpa_bp1)->size;
|
||||
}
|
||||
|
||||
struct dpa_bp * __cold __must_check /* __attribute__((nonnull)) */
|
||||
dpa_bp_probe(struct platform_device *_of_dev, size_t *count)
|
||||
{
|
||||
int i, lenp, na, ns, err;
|
||||
struct device *dev;
|
||||
struct device_node *dev_node;
|
||||
const __be32 *bpool_cfg;
|
||||
struct dpa_bp *dpa_bp;
|
||||
u32 bpid;
|
||||
|
||||
dev = &_of_dev->dev;
|
||||
|
||||
*count = of_count_phandle_with_args(dev->of_node,
|
||||
"fsl,bman-buffer-pools", NULL);
|
||||
if (*count < 1) {
|
||||
dev_err(dev, "missing fsl,bman-buffer-pools device tree entry\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
dpa_bp = devm_kzalloc(dev, *count * sizeof(*dpa_bp), GFP_KERNEL);
|
||||
if (dpa_bp == NULL) {
|
||||
dev_err(dev, "devm_kzalloc() failed\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
dev_node = of_find_node_by_path("/");
|
||||
if (unlikely(dev_node == NULL)) {
|
||||
dev_err(dev, "of_find_node_by_path(/) failed\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
na = of_n_addr_cells(dev_node);
|
||||
ns = of_n_size_cells(dev_node);
|
||||
|
||||
for (i = 0; i < *count; i++) {
|
||||
of_node_put(dev_node);
|
||||
|
||||
dev_node = of_parse_phandle(dev->of_node,
|
||||
"fsl,bman-buffer-pools", i);
|
||||
if (dev_node == NULL) {
|
||||
dev_err(dev, "of_find_node_by_phandle() failed\n");
|
||||
return ERR_PTR(-EFAULT);
|
||||
}
|
||||
|
||||
if (unlikely(!of_device_is_compatible(dev_node, "fsl,bpool"))) {
|
||||
dev_err(dev,
|
||||
"!of_device_is_compatible(%s, fsl,bpool)\n",
|
||||
dev_node->full_name);
|
||||
dpa_bp = ERR_PTR(-EINVAL);
|
||||
goto _return_of_node_put;
|
||||
}
|
||||
|
||||
err = of_property_read_u32(dev_node, "fsl,bpid", &bpid);
|
||||
if (err) {
|
||||
dev_err(dev, "Cannot find buffer pool ID in the device tree\n");
|
||||
dpa_bp = ERR_PTR(-EINVAL);
|
||||
goto _return_of_node_put;
|
||||
}
|
||||
dpa_bp[i].bpid = (uint8_t)bpid;
|
||||
|
||||
bpool_cfg = of_get_property(dev_node, "fsl,bpool-ethernet-cfg",
|
||||
&lenp);
|
||||
if (bpool_cfg && (lenp == (2 * ns + na) * sizeof(*bpool_cfg))) {
|
||||
const uint32_t *seed_pool;
|
||||
|
||||
dpa_bp[i].config_count =
|
||||
(int)of_read_number(bpool_cfg, ns);
|
||||
dpa_bp[i].size =
|
||||
(size_t)of_read_number(bpool_cfg + ns, ns);
|
||||
dpa_bp[i].paddr =
|
||||
of_read_number(bpool_cfg + 2 * ns, na);
|
||||
|
||||
seed_pool = of_get_property(dev_node,
|
||||
"fsl,bpool-ethernet-seeds", &lenp);
|
||||
dpa_bp[i].seed_pool = !!seed_pool;
|
||||
|
||||
} else {
|
||||
dev_err(dev,
|
||||
"Missing/invalid fsl,bpool-ethernet-cfg device tree entry for node %s\n",
|
||||
dev_node->full_name);
|
||||
dpa_bp = ERR_PTR(-EINVAL);
|
||||
goto _return_of_node_put;
|
||||
}
|
||||
}
|
||||
|
||||
sort(dpa_bp, *count, sizeof(*dpa_bp), dpa_bp_cmp, NULL);
|
||||
|
||||
return dpa_bp;
|
||||
|
||||
_return_of_node_put:
|
||||
if (dev_node)
|
||||
of_node_put(dev_node);
|
||||
|
||||
return dpa_bp;
|
||||
}
|
||||
EXPORT_SYMBOL(dpa_bp_probe);
|
||||
|
||||
int dpa_bp_shared_port_seed(struct dpa_bp *bp)
|
||||
{
|
||||
void __iomem **ptr;
|
||||
|
||||
/* In MAC-less and Shared-MAC scenarios the physical
|
||||
* address of the buffer pool in device tree is set
|
||||
* to 0 to specify that another entity (USDPAA) will
|
||||
* allocate and seed the buffers
|
||||
*/
|
||||
if (!bp->paddr)
|
||||
return 0;
|
||||
|
||||
/* allocate memory region for buffers */
|
||||
devm_request_mem_region(bp->dev, bp->paddr,
|
||||
bp->size * bp->config_count, KBUILD_MODNAME);
|
||||
/* managed ioremap unmapping */
|
||||
ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -EIO;
|
||||
#ifndef CONFIG_PPC
|
||||
bp->vaddr = ioremap_cache_ns(bp->paddr, bp->size * bp->config_count);
|
||||
#else
|
||||
bp->vaddr = ioremap_prot(bp->paddr, bp->size * bp->config_count, 0);
|
||||
#endif
|
||||
if (bp->vaddr == NULL) {
|
||||
pr_err("Could not map memory for pool %d\n", bp->bpid);
|
||||
devres_free(ptr);
|
||||
return -EIO;
|
||||
}
|
||||
*ptr = bp->vaddr;
|
||||
devres_add(bp->dev, ptr);
|
||||
|
||||
/* seed pool with buffers from that memory region */
|
||||
if (bp->seed_pool) {
|
||||
int count = bp->target_count;
|
||||
dma_addr_t addr = bp->paddr;
|
||||
|
||||
while (count) {
|
||||
struct bm_buffer bufs[8];
|
||||
uint8_t num_bufs = 0;
|
||||
|
||||
do {
|
||||
BUG_ON(addr > 0xffffffffffffull);
|
||||
bufs[num_bufs].bpid = bp->bpid;
|
||||
bm_buffer_set64(&bufs[num_bufs++], addr);
|
||||
addr += bp->size;
|
||||
|
||||
} while (--count && (num_bufs < 8));
|
||||
|
||||
while (bman_release(bp->pool, bufs, num_bufs, 0))
|
||||
cpu_relax();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dpa_bp_shared_port_seed);
|
||||
|
||||
int dpa_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp,
|
||||
size_t count)
|
||||
{
|
||||
struct dpa_priv_s *priv = netdev_priv(net_dev);
|
||||
int i;
|
||||
|
||||
priv->dpa_bp = dpa_bp;
|
||||
priv->bp_count = count;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
int err;
|
||||
err = dpa_bp_alloc(&dpa_bp[i]);
|
||||
if (err < 0) {
|
||||
dpa_bp_free(priv);
|
||||
priv->dpa_bp = NULL;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dpa_bp_create);
|
||||
|
||||
static int __init __cold dpa_advanced_load(void)
|
||||
{
|
||||
pr_info(DPA_DESCRIPTION "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(dpa_advanced_load);
|
||||
|
||||
static void __exit __cold dpa_advanced_unload(void)
|
||||
{
|
||||
pr_debug(KBUILD_MODNAME ": -> %s:%s()\n",
|
||||
KBUILD_BASENAME".c", __func__);
|
||||
|
||||
}
|
||||
module_exit(dpa_advanced_unload);
|
@ -0,0 +1,50 @@
|
||||
/* Copyright 2008-2013 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Freescale Semiconductor nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* ALTERNATIVELY, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") as published by the Free Software
|
||||
* Foundation, either version 2 of that License or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __DPAA_ETH_BASE_H
|
||||
#define __DPAA_ETH_BASE_H
|
||||
|
||||
#include <linux/etherdevice.h> /* struct net_device */
|
||||
#include <linux/fsl_bman.h> /* struct bm_buffer */
|
||||
#include <linux/of_platform.h> /* struct platform_device */
|
||||
#include <linux/net_tstamp.h> /* struct hwtstamp_config */
|
||||
|
||||
extern uint8_t advanced_debug;
|
||||
extern const struct dpa_fq_cbs_t shared_fq_cbs;
|
||||
extern int __hot dpa_shared_tx(struct sk_buff *skb, struct net_device *net_dev);
|
||||
|
||||
struct dpa_bp * __cold __must_check /* __attribute__((nonnull)) */
|
||||
dpa_bp_probe(struct platform_device *_of_dev, size_t *count);
|
||||
int dpa_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp,
|
||||
size_t count);
|
||||
int dpa_bp_shared_port_seed(struct dpa_bp *bp);
|
||||
|
||||
#endif /* __DPAA_ETH_BASE_H */
|
229
linux/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
Normal file
229
linux/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
Normal file
@ -0,0 +1,229 @@
|
||||
/* Copyright 2008-2013 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Freescale Semiconductor nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* ALTERNATIVELY, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") as published by the Free Software
|
||||
* Foundation, either version 2 of that License or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __DPAA_ETH_COMMON_H
|
||||
#define __DPAA_ETH_COMMON_H
|
||||
|
||||
#include <linux/etherdevice.h> /* struct net_device */
|
||||
#include <linux/fsl_bman.h> /* struct bm_buffer */
|
||||
#include <linux/of_platform.h> /* struct platform_device */
|
||||
#include <linux/net_tstamp.h> /* struct hwtstamp_config */
|
||||
|
||||
#include "dpaa_eth.h"
|
||||
#include "lnxwrp_fsl_fman.h"
|
||||
|
||||
#define dpaa_eth_init_port(type, port, param, errq_id, defq_id, buf_layout,\
|
||||
frag_enabled) \
|
||||
{ \
|
||||
param.errq = errq_id; \
|
||||
param.defq = defq_id; \
|
||||
param.priv_data_size = buf_layout->priv_data_size; \
|
||||
param.parse_results = buf_layout->parse_results; \
|
||||
param.hash_results = buf_layout->hash_results; \
|
||||
param.frag_enable = frag_enabled; \
|
||||
param.time_stamp = buf_layout->time_stamp; \
|
||||
param.manip_extra_space = buf_layout->manip_extra_space; \
|
||||
param.data_align = buf_layout->data_align; \
|
||||
fm_set_##type##_port_params(port, ¶m); \
|
||||
}
|
||||
|
||||
#define DPA_SGT_MAX_ENTRIES 16 /* maximum number of entries in SG Table */
|
||||
|
||||
#define DPA_SGT_ENTRIES_THRESHOLD DPA_SGT_MAX_ENTRIES
|
||||
#ifndef CONFIG_PPC
|
||||
/* each S/G entry can be divided into two S/G entries during errata W/A */
|
||||
#define DPA_SGT_4K_ENTRIES_THRESHOLD 7
|
||||
#endif
|
||||
|
||||
#define DPA_BUFF_RELEASE_MAX 8 /* maximum number of buffers released at once */
|
||||
|
||||
#define DPA_RX_PCD_HI_PRIO_FQ_INIT_FAIL(dpa_fq, _errno) \
|
||||
(((dpa_fq)->fq_type == FQ_TYPE_RX_PCD_HI_PRIO) && \
|
||||
(_errno == -EIO))
|
||||
/* return codes for the dpaa-eth hooks */
|
||||
enum dpaa_eth_hook_result {
|
||||
/* fd/skb was retained by the hook.
|
||||
*
|
||||
* On the Rx path, this means the Ethernet driver will _not_
|
||||
* deliver the skb to the stack. Instead, the hook implementation
|
||||
* is expected to properly dispose of the skb.
|
||||
*
|
||||
* On the Tx path, the Ethernet driver's dpa_tx() function will
|
||||
* immediately return NETDEV_TX_OK. The hook implementation is expected
|
||||
* to free the skb. *DO*NOT* release it to BMan, or enqueue it to FMan,
|
||||
* unless you know exactly what you're doing!
|
||||
*
|
||||
* On the confirmation/error paths, the Ethernet driver will _not_
|
||||
* perform any fd cleanup, nor update the interface statistics.
|
||||
*/
|
||||
DPAA_ETH_STOLEN,
|
||||
/* fd/skb was returned to the Ethernet driver for regular processing.
|
||||
* The hook is not allowed to, for instance, reallocate the skb (as if
|
||||
* by linearizing, copying, cloning or reallocating the headroom).
|
||||
*/
|
||||
DPAA_ETH_CONTINUE
|
||||
};
|
||||
|
||||
typedef enum dpaa_eth_hook_result (*dpaa_eth_ingress_hook_t)(
|
||||
struct sk_buff *skb, struct net_device *net_dev, u32 fqid);
|
||||
typedef enum dpaa_eth_hook_result (*dpaa_eth_egress_hook_t)(
|
||||
struct sk_buff *skb, struct net_device *net_dev);
|
||||
typedef enum dpaa_eth_hook_result (*dpaa_eth_confirm_hook_t)(
|
||||
struct net_device *net_dev, const struct qm_fd *fd, u32 fqid);
|
||||
|
||||
/* used in napi related functions */
|
||||
extern u16 qman_portal_max;
|
||||
|
||||
/* from dpa_ethtool.c */
|
||||
extern const struct ethtool_ops dpa_ethtool_ops;
|
||||
|
||||
#ifdef CONFIG_FSL_DPAA_HOOKS
|
||||
/* Various hooks used for unit-testing and/or fastpath optimizations.
|
||||
* Currently only one set of such hooks is supported.
|
||||
*/
|
||||
struct dpaa_eth_hooks_s {
|
||||
/* Invoked on the Tx private path, immediately after receiving the skb
|
||||
* from the stack.
|
||||
*/
|
||||
dpaa_eth_egress_hook_t tx;
|
||||
|
||||
/* Invoked on the Rx private path, right before passing the skb
|
||||
* up the stack. At that point, the packet's protocol id has already
|
||||
* been set. The skb's data pointer is now at the L3 header, and
|
||||
* skb->mac_header points to the L2 header. skb->len has been adjusted
|
||||
* to be the length of L3+payload (i.e., the length of the
|
||||
* original frame minus the L2 header len).
|
||||
* For more details on what the skb looks like, see eth_type_trans().
|
||||
*/
|
||||
dpaa_eth_ingress_hook_t rx_default;
|
||||
|
||||
/* Driver hook for the Rx error private path. */
|
||||
dpaa_eth_confirm_hook_t rx_error;
|
||||
/* Driver hook for the Tx confirmation private path. */
|
||||
dpaa_eth_confirm_hook_t tx_confirm;
|
||||
/* Driver hook for the Tx error private path. */
|
||||
dpaa_eth_confirm_hook_t tx_error;
|
||||
};
|
||||
|
||||
void fsl_dpaa_eth_set_hooks(struct dpaa_eth_hooks_s *hooks);
|
||||
|
||||
extern struct dpaa_eth_hooks_s dpaa_eth_hooks;
|
||||
#endif
|
||||
|
||||
int dpa_netdev_init(struct net_device *net_dev,
|
||||
const uint8_t *mac_addr,
|
||||
uint16_t tx_timeout);
|
||||
int __cold dpa_start(struct net_device *net_dev);
|
||||
int __cold dpa_stop(struct net_device *net_dev);
|
||||
void __cold dpa_timeout(struct net_device *net_dev);
|
||||
struct rtnl_link_stats64 * __cold
|
||||
dpa_get_stats64(struct net_device *net_dev,
|
||||
struct rtnl_link_stats64 *stats);
|
||||
int dpa_change_mtu(struct net_device *net_dev, int new_mtu);
|
||||
int dpa_ndo_init(struct net_device *net_dev);
|
||||
int dpa_set_features(struct net_device *dev, netdev_features_t features);
|
||||
netdev_features_t dpa_fix_features(struct net_device *dev,
|
||||
netdev_features_t features);
|
||||
#ifdef CONFIG_FSL_DPAA_TS
|
||||
u64 dpa_get_timestamp_ns(const struct dpa_priv_s *priv,
|
||||
enum port_type rx_tx, const void *data);
|
||||
/* Updates the skb shared hw timestamp from the hardware timestamp */
|
||||
int dpa_get_ts(const struct dpa_priv_s *priv, enum port_type rx_tx,
|
||||
struct skb_shared_hwtstamps *shhwtstamps, const void *data);
|
||||
#endif /* CONFIG_FSL_DPAA_TS */
|
||||
int dpa_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
|
||||
int __cold dpa_remove(struct platform_device *of_dev);
|
||||
struct mac_device * __cold __must_check
|
||||
__attribute__((nonnull)) dpa_mac_probe(struct platform_device *_of_dev);
|
||||
int dpa_set_mac_address(struct net_device *net_dev, void *addr);
|
||||
void dpa_set_rx_mode(struct net_device *net_dev);
|
||||
void dpa_set_buffers_layout(struct mac_device *mac_dev,
|
||||
struct dpa_buffer_layout_s *layout);
|
||||
int __attribute__((nonnull))
|
||||
dpa_bp_alloc(struct dpa_bp *dpa_bp);
|
||||
void __cold __attribute__((nonnull))
|
||||
dpa_bp_free(struct dpa_priv_s *priv);
|
||||
struct dpa_bp *dpa_bpid2pool(int bpid);
|
||||
void dpa_bpid2pool_map(int bpid, struct dpa_bp *dpa_bp);
|
||||
bool dpa_bpid2pool_use(int bpid);
|
||||
void dpa_bp_drain(struct dpa_bp *bp);
|
||||
#ifdef CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
|
||||
u16 dpa_select_queue(struct net_device *net_dev, struct sk_buff *skb,
|
||||
void *accel_priv, select_queue_fallback_t fallback);
|
||||
#endif
|
||||
struct dpa_fq *dpa_fq_alloc(struct device *dev,
|
||||
u32 fq_start,
|
||||
u32 fq_count,
|
||||
struct list_head *list,
|
||||
enum dpa_fq_type fq_type);
|
||||
int dpa_fq_probe_mac(struct device *dev, struct list_head *list,
|
||||
struct fm_port_fqs *port_fqs,
|
||||
bool tx_conf_fqs_per_core,
|
||||
enum port_type ptype);
|
||||
int dpa_get_channel(void);
|
||||
void dpa_release_channel(void);
|
||||
int dpaa_eth_add_channel(void *__arg);
|
||||
int dpaa_eth_cgr_init(struct dpa_priv_s *priv);
|
||||
void dpa_fq_setup(struct dpa_priv_s *priv, const struct dpa_fq_cbs_t *fq_cbs,
|
||||
struct fm_port *tx_port);
|
||||
int dpa_fq_init(struct dpa_fq *dpa_fq, bool td_enable);
|
||||
int dpa_fqs_init(struct device *dev, struct list_head *list, bool td_enable);
|
||||
int __cold __attribute__((nonnull))
|
||||
dpa_fq_free(struct device *dev, struct list_head *list);
|
||||
void dpaa_eth_init_ports(struct mac_device *mac_dev,
|
||||
struct dpa_bp *bp, size_t count,
|
||||
struct fm_port_fqs *port_fqs,
|
||||
struct dpa_buffer_layout_s *buf_layout,
|
||||
struct device *dev);
|
||||
void dpa_release_sgt(struct qm_sg_entry *sgt);
|
||||
void __attribute__((nonnull))
|
||||
dpa_fd_release(const struct net_device *net_dev, const struct qm_fd *fd);
|
||||
void count_ern(struct dpa_percpu_priv_s *percpu_priv,
|
||||
const struct qm_mr_entry *msg);
|
||||
int dpa_enable_tx_csum(struct dpa_priv_s *priv,
|
||||
struct sk_buff *skb, struct qm_fd *fd, char *parse_results);
|
||||
#ifdef CONFIG_FSL_DPAA_CEETM
|
||||
void dpa_enable_ceetm(struct net_device *dev);
|
||||
void dpa_disable_ceetm(struct net_device *dev);
|
||||
#endif
|
||||
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 */
|
498
linux/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_macless.c
Normal file
498
linux/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_macless.c
Normal file
@ -0,0 +1,498 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/* Copyright 2008-2013 Freescale Semiconductor Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Freescale Semiconductor nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* ALTERNATIVELY, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") as published by the Free Software
|
||||
* Foundation, either version 2 of that License or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
|
||||
#define pr_fmt(fmt) \
|
||||
KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
|
||||
KBUILD_BASENAME".c", __LINE__, __func__
|
||||
#else
|
||||
#define pr_fmt(fmt) \
|
||||
KBUILD_MODNAME ": " fmt
|
||||
#endif
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/fsl_qman.h>
|
||||
#include "dpaa_eth.h"
|
||||
#include "dpaa_eth_common.h"
|
||||
#include "dpaa_eth_base.h"
|
||||
#include "lnxwrp_fsl_fman.h" /* fm_get_rx_extra_headroom(), fm_get_max_frm() */
|
||||
#include "mac.h"
|
||||
|
||||
/* For MAC-based interfaces, we compute the tx needed headroom from the
|
||||
* associated Tx port's buffer layout settings.
|
||||
* For MACless interfaces just use a default value.
|
||||
*/
|
||||
#define DPA_DEFAULT_TX_HEADROOM 64
|
||||
|
||||
#define DPA_DESCRIPTION "FSL DPAA MACless Ethernet driver"
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
||||
MODULE_DESCRIPTION(DPA_DESCRIPTION);
|
||||
|
||||
/* This has to work in tandem with the DPA_CS_THRESHOLD_xxx values. */
|
||||
static uint16_t macless_tx_timeout = 1000;
|
||||
module_param(macless_tx_timeout, ushort, S_IRUGO);
|
||||
MODULE_PARM_DESC(macless_tx_timeout, "The MACless Tx timeout in ms");
|
||||
|
||||
/* 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 __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);
|
||||
|
||||
static const struct net_device_ops dpa_macless_ops = {
|
||||
.ndo_open = dpa_macless_start,
|
||||
.ndo_start_xmit = dpa_shared_tx,
|
||||
.ndo_stop = dpa_macless_stop,
|
||||
.ndo_tx_timeout = dpa_timeout,
|
||||
.ndo_get_stats64 = dpa_get_stats64,
|
||||
.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,
|
||||
#endif
|
||||
.ndo_change_mtu = dpa_change_mtu,
|
||||
.ndo_init = dpa_ndo_init,
|
||||
.ndo_set_features = dpa_set_features,
|
||||
.ndo_fix_features = dpa_macless_fix_features,
|
||||
};
|
||||
|
||||
static const struct of_device_id dpa_macless_match[] = {
|
||||
{
|
||||
.compatible = "fsl,dpa-ethernet-macless"
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dpa_macless_match);
|
||||
|
||||
static struct platform_driver dpa_macless_driver = {
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME "-macless",
|
||||
.of_match_table = dpa_macless_match,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = dpaa_eth_macless_probe,
|
||||
.remove = dpa_remove
|
||||
};
|
||||
|
||||
static const char macless_frame_queues[][25] = {
|
||||
[RX] = "fsl,qman-frame-queues-rx",
|
||||
[TX] = "fsl,qman-frame-queues-tx"
|
||||
};
|
||||
|
||||
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_macless_set_address(struct net_device *net_dev, void *addr)
|
||||
{
|
||||
const struct dpa_priv_s *priv = netdev_priv(net_dev);
|
||||
struct proxy_device *proxy_dev = (struct proxy_device *)priv->peer;
|
||||
int _errno;
|
||||
|
||||
_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);
|
||||
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)
|
||||
{
|
||||
netdev_features_t unsupported_features = 0;
|
||||
|
||||
/* In theory we should never be requested to enable features that
|
||||
* we didn't set in netdev->features and netdev->hw_features at probe
|
||||
* time, but double check just to be on the safe side.
|
||||
*/
|
||||
unsupported_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
|
||||
/* We don't support enabling Rx csum through ethtool yet */
|
||||
unsupported_features |= NETIF_F_RXCSUM;
|
||||
|
||||
features &= ~unsupported_features;
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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(net_dev, mac_dev->addr,
|
||||
macless_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(net_dev, mac_addr,
|
||||
macless_tx_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/* Probing of FQs for MACless ports */
|
||||
static int dpa_fq_probe_macless(struct device *dev, struct list_head *list,
|
||||
enum port_type ptype)
|
||||
{
|
||||
struct device_node *np = dev->of_node;
|
||||
const struct fqid_cell *fqids;
|
||||
int num_ranges;
|
||||
int i, lenp;
|
||||
|
||||
fqids = of_get_property(np, macless_frame_queues[ptype], &lenp);
|
||||
if (fqids == NULL) {
|
||||
dev_err(dev, "Need FQ definition in dts for MACless devices\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
num_ranges = lenp / sizeof(*fqids);
|
||||
|
||||
/* All ranges defined in the device tree are used as Rx/Tx queues */
|
||||
for (i = 0; i < num_ranges; i++) {
|
||||
if (!dpa_fq_alloc(dev, be32_to_cpu(fqids[i].start),
|
||||
be32_to_cpu(fqids[i].count), list,
|
||||
ptype == RX ? FQ_TYPE_RX_PCD : FQ_TYPE_TX)) {
|
||||
dev_err(dev, "_dpa_fq_alloc() failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static 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, channel;
|
||||
struct device *dev;
|
||||
struct device_node *dpa_node;
|
||||
struct dpa_bp *dpa_bp;
|
||||
size_t count;
|
||||
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 task_struct *kth;
|
||||
static u8 macless_idx;
|
||||
|
||||
dev = &_of_dev->dev;
|
||||
|
||||
dpa_node = dev->of_node;
|
||||
|
||||
if (!of_device_is_available(dpa_node))
|
||||
return -ENODEV;
|
||||
|
||||
/* Get the buffer pools assigned to this interface */
|
||||
dpa_bp = dpa_bp_probe(_of_dev, &count);
|
||||
if (IS_ERR(dpa_bp))
|
||||
return PTR_ERR(dpa_bp);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
dpa_bp[i].seed_cb = dpa_bp_shared_port_seed;
|
||||
|
||||
proxy_dev = dpa_macless_proxy_probe(_of_dev);
|
||||
|
||||
|
||||
/* Allocate this early, so we can store relevant information in
|
||||
* the private area (needed by 1588 code in dpa_mac_probe)
|
||||
*/
|
||||
net_dev = alloc_etherdev_mq(sizeof(*priv), DPAA_ETH_TX_QUEUES);
|
||||
if (!net_dev) {
|
||||
dev_err(dev, "alloc_etherdev_mq() failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Do this here, so we can be verbose early */
|
||||
SET_NETDEV_DEV(net_dev, dev);
|
||||
dev_set_drvdata(dev, net_dev);
|
||||
|
||||
priv = netdev_priv(net_dev);
|
||||
priv->net_dev = net_dev;
|
||||
sprintf(priv->if_type, "macless%d", macless_idx++);
|
||||
|
||||
priv->msg_enable = netif_msg_init(advanced_debug, -1);
|
||||
|
||||
priv->peer = NULL;
|
||||
priv->mac_dev = NULL;
|
||||
if (proxy_dev) {
|
||||
/* This is a temporary solution for the need of
|
||||
* having main driver upstreamability: adjust_link
|
||||
* is a general function that should work for both
|
||||
* private driver and macless driver with MAC device
|
||||
* control capabilities even if the last will not be
|
||||
* upstreamable.
|
||||
* TODO: find a convenient solution (wrapper over
|
||||
* main priv structure, etc.)
|
||||
*/
|
||||
priv->mac_dev = proxy_dev->mac_dev;
|
||||
|
||||
/* control over proxy's mac device */
|
||||
priv->peer = (void *)proxy_dev;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&priv->dpa_fq_list);
|
||||
|
||||
err = dpa_fq_probe_macless(dev, &priv->dpa_fq_list, RX);
|
||||
if (!err)
|
||||
err = dpa_fq_probe_macless(dev, &priv->dpa_fq_list,
|
||||
TX);
|
||||
if (err < 0)
|
||||
goto fq_probe_failed;
|
||||
|
||||
/* bp init */
|
||||
priv->bp_count = count;
|
||||
err = dpa_bp_create(net_dev, dpa_bp, count);
|
||||
if (err < 0)
|
||||
goto bp_create_failed;
|
||||
|
||||
channel = dpa_get_channel();
|
||||
|
||||
if (channel < 0) {
|
||||
err = channel;
|
||||
goto get_channel_failed;
|
||||
}
|
||||
|
||||
priv->channel = (uint16_t)channel;
|
||||
|
||||
/* Start a thread that will walk the cpus with affine portals
|
||||
* and add this pool channel to each's dequeue mask.
|
||||
*/
|
||||
kth = kthread_run(dpaa_eth_add_channel,
|
||||
(void *)(unsigned long)priv->channel,
|
||||
"dpaa_%p:%d", net_dev, priv->channel);
|
||||
if (!kth) {
|
||||
err = -ENOMEM;
|
||||
goto add_channel_failed;
|
||||
}
|
||||
|
||||
dpa_fq_setup(priv, &shared_fq_cbs, NULL);
|
||||
|
||||
/* Add the FQs to the interface, and make them active */
|
||||
/* For MAC-less devices we only get here for RX frame queues
|
||||
* initialization, which are the TX queues of the other
|
||||
* partition.
|
||||
* It is safe to rely on one partition to set the FQ taildrop
|
||||
* threshold for the TX queues of the other partition
|
||||
* because the ERN notifications will be received by the
|
||||
* partition doing qman_enqueue.
|
||||
*/
|
||||
err = dpa_fqs_init(dev, &priv->dpa_fq_list, true);
|
||||
if (err < 0)
|
||||
goto fq_alloc_failed;
|
||||
|
||||
priv->tx_headroom = DPA_DEFAULT_TX_HEADROOM;
|
||||
|
||||
priv->percpu_priv = devm_alloc_percpu(dev, *priv->percpu_priv);
|
||||
|
||||
if (priv->percpu_priv == NULL) {
|
||||
dev_err(dev, "devm_alloc_percpu() failed\n");
|
||||
err = -ENOMEM;
|
||||
goto alloc_percpu_failed;
|
||||
}
|
||||
for_each_possible_cpu(i) {
|
||||
percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
|
||||
memset(percpu_priv, 0, sizeof(*percpu_priv));
|
||||
}
|
||||
|
||||
err = dpa_macless_netdev_init(dpa_node, net_dev);
|
||||
if (err < 0)
|
||||
goto netdev_init_failed;
|
||||
|
||||
dpaa_eth_sysfs_init(&net_dev->dev);
|
||||
|
||||
pr_info("fsl_dpa_macless: Probed %s interface as %s\n",
|
||||
priv->if_type, net_dev->name);
|
||||
|
||||
return 0;
|
||||
|
||||
netdev_init_failed:
|
||||
alloc_percpu_failed:
|
||||
fq_alloc_failed:
|
||||
if (net_dev)
|
||||
dpa_fq_free(dev, &priv->dpa_fq_list);
|
||||
add_channel_failed:
|
||||
get_channel_failed:
|
||||
if (net_dev)
|
||||
dpa_bp_free(priv);
|
||||
bp_create_failed:
|
||||
fq_probe_failed:
|
||||
dev_set_drvdata(dev, NULL);
|
||||
if (net_dev)
|
||||
free_netdev(net_dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init __cold dpa_macless_load(void)
|
||||
{
|
||||
int _errno;
|
||||
|
||||
pr_info(DPA_DESCRIPTION "\n");
|
||||
|
||||
/* Initialize dpaa_eth mirror values */
|
||||
dpa_rx_extra_headroom = fm_get_rx_extra_headroom();
|
||||
dpa_max_frm = fm_get_max_frm();
|
||||
|
||||
_errno = platform_driver_register(&dpa_macless_driver);
|
||||
if (unlikely(_errno < 0)) {
|
||||
pr_err(KBUILD_MODNAME
|
||||
": %s:%hu:%s(): platform_driver_register() = %d\n",
|
||||
KBUILD_BASENAME".c", __LINE__, __func__, _errno);
|
||||
}
|
||||
|
||||
pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
|
||||
KBUILD_BASENAME".c", __func__);
|
||||
|
||||
return _errno;
|
||||
}
|
||||
module_init(dpa_macless_load);
|
||||
|
||||
static void __exit __cold dpa_macless_unload(void)
|
||||
{
|
||||
platform_driver_unregister(&dpa_macless_driver);
|
||||
|
||||
pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
|
||||
KBUILD_BASENAME".c", __func__);
|
||||
}
|
||||
module_exit(dpa_macless_unload);
|
Loading…
x
Reference in New Issue
Block a user