diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/fman/fman_tgec.c')
| -rw-r--r-- | drivers/net/ethernet/freescale/fman/fman_tgec.c | 269 |
1 files changed, 128 insertions, 141 deletions
diff --git a/drivers/net/ethernet/freescale/fman/fman_tgec.c b/drivers/net/ethernet/freescale/fman/fman_tgec.c index 41946b16f6c7..fecfca6eba03 100644 --- a/drivers/net/ethernet/freescale/fman/fman_tgec.c +++ b/drivers/net/ethernet/freescale/fman/fman_tgec.c @@ -1,44 +1,19 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later /* - * Copyright 2008-2015 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. + * Copyright 2008 - 2015 Freescale Semiconductor Inc. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include "fman_tgec.h" #include "fman.h" +#include "mac.h" #include <linux/slab.h> #include <linux/bitrev.h> #include <linux/io.h> #include <linux/crc32.h> +#include <linux/netdevice.h> /* Transmit Inter-Packet Gap Length Register (TX_IPG_LENGTH) */ #define TGEC_TX_IPG_LENGTH_MASK 0x000003ff @@ -206,7 +181,7 @@ struct fman_mac { /* MAC address of device; */ u64 addr; u16 max_speed; - void *dev_id; /* device cookie used by the exception cbs */ + struct mac_device *dev_id; /* device cookie used by the exception cbs */ fman_mac_exception_cb *exception_cb; fman_mac_exception_cb *event_cb; /* pointer to driver's global address hash table */ @@ -221,7 +196,7 @@ struct fman_mac { bool allmulti_enabled; }; -static void set_mac_address(struct tgec_regs __iomem *regs, u8 *adr) +static void set_mac_address(struct tgec_regs __iomem *regs, const u8 *adr) { u32 tmp0, tmp1; @@ -269,10 +244,6 @@ static int init(struct tgec_regs __iomem *regs, struct tgec_cfg *cfg, static int check_init_parameters(struct fman_mac *tgec) { - if (tgec->max_speed < SPEED_10000) { - pr_err("10G MAC driver only support 10G speed\n"); - return -EINVAL; - } if (!tgec->exception_cb) { pr_err("uninitialized exception_cb\n"); return -EINVAL; @@ -410,131 +381,116 @@ static void free_init_resources(struct fman_mac *tgec) tgec->unicast_addr_hash = NULL; } -static bool is_init_done(struct tgec_cfg *cfg) +static int tgec_enable(struct fman_mac *tgec) { - /* Checks if tGEC driver parameters were initialized */ - if (!cfg) - return true; + return 0; +} - return false; +static void tgec_disable(struct fman_mac *tgec) +{ } -int tgec_enable(struct fman_mac *tgec, enum comm_mode mode) +static int tgec_set_promiscuous(struct fman_mac *tgec, bool new_val) { struct tgec_regs __iomem *regs = tgec->regs; u32 tmp; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - tmp = ioread32be(®s->command_config); - if (mode & COMM_MODE_RX) - tmp |= CMD_CFG_RX_EN; - if (mode & COMM_MODE_TX) - tmp |= CMD_CFG_TX_EN; + if (new_val) + tmp |= CMD_CFG_PROMIS_EN; + else + tmp &= ~CMD_CFG_PROMIS_EN; iowrite32be(tmp, ®s->command_config); return 0; } -int tgec_disable(struct fman_mac *tgec, enum comm_mode mode) +static int tgec_set_tx_pause_frames(struct fman_mac *tgec, + u8 __maybe_unused priority, u16 pause_time, + u16 __maybe_unused thresh_time) { struct tgec_regs __iomem *regs = tgec->regs; - u32 tmp; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - - tmp = ioread32be(®s->command_config); - if (mode & COMM_MODE_RX) - tmp &= ~CMD_CFG_RX_EN; - if (mode & COMM_MODE_TX) - tmp &= ~CMD_CFG_TX_EN; - iowrite32be(tmp, ®s->command_config); + iowrite32be((u32)pause_time, ®s->pause_quant); return 0; } -int tgec_set_promiscuous(struct fman_mac *tgec, bool new_val) +static int tgec_accept_rx_pause_frames(struct fman_mac *tgec, bool en) { struct tgec_regs __iomem *regs = tgec->regs; u32 tmp; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - tmp = ioread32be(®s->command_config); - if (new_val) - tmp |= CMD_CFG_PROMIS_EN; + if (!en) + tmp |= CMD_CFG_PAUSE_IGNORE; else - tmp &= ~CMD_CFG_PROMIS_EN; + tmp &= ~CMD_CFG_PAUSE_IGNORE; iowrite32be(tmp, ®s->command_config); return 0; } -int tgec_cfg_max_frame_len(struct fman_mac *tgec, u16 new_val) +static void tgec_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) { - if (is_init_done(tgec->cfg)) - return -EINVAL; - - tgec->cfg->max_frame_length = new_val; - - return 0; } -int tgec_set_tx_pause_frames(struct fman_mac *tgec, u8 __maybe_unused priority, - u16 pause_time, u16 __maybe_unused thresh_time) +static void tgec_link_up(struct phylink_config *config, struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, bool tx_pause, bool rx_pause) { + struct mac_device *mac_dev = fman_config_to_mac(config); + struct fman_mac *tgec = mac_dev->fman_mac; struct tgec_regs __iomem *regs = tgec->regs; + u16 pause_time = tx_pause ? FSL_FM_PAUSE_TIME_ENABLE : + FSL_FM_PAUSE_TIME_DISABLE; + u32 tmp; - if (!is_init_done(tgec->cfg)) - return -EINVAL; + tgec_set_tx_pause_frames(tgec, 0, pause_time, 0); + tgec_accept_rx_pause_frames(tgec, rx_pause); + mac_dev->update_speed(mac_dev, speed); - iowrite32be((u32)pause_time, ®s->pause_quant); - - return 0; + tmp = ioread32be(®s->command_config); + tmp |= CMD_CFG_RX_EN | CMD_CFG_TX_EN; + iowrite32be(tmp, ®s->command_config); } -int tgec_accept_rx_pause_frames(struct fman_mac *tgec, bool en) +static void tgec_link_down(struct phylink_config *config, unsigned int mode, + phy_interface_t interface) { + struct fman_mac *tgec = fman_config_to_mac(config)->fman_mac; struct tgec_regs __iomem *regs = tgec->regs; u32 tmp; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - tmp = ioread32be(®s->command_config); - if (!en) - tmp |= CMD_CFG_PAUSE_IGNORE; - else - tmp &= ~CMD_CFG_PAUSE_IGNORE; + tmp &= ~(CMD_CFG_RX_EN | CMD_CFG_TX_EN); iowrite32be(tmp, ®s->command_config); - - return 0; } -int tgec_modify_mac_address(struct fman_mac *tgec, enet_addr_t *p_enet_addr) -{ - if (!is_init_done(tgec->cfg)) - return -EINVAL; +static const struct phylink_mac_ops tgec_mac_ops = { + .mac_config = tgec_mac_config, + .mac_link_up = tgec_link_up, + .mac_link_down = tgec_link_down, +}; +static int tgec_modify_mac_address(struct fman_mac *tgec, + const enet_addr_t *p_enet_addr) +{ tgec->addr = ENET_ADDR_TO_UINT64(*p_enet_addr); - set_mac_address(tgec->regs, (u8 *)(*p_enet_addr)); + set_mac_address(tgec->regs, (const u8 *)(*p_enet_addr)); return 0; } -int tgec_add_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr) +static int tgec_add_hash_mac_address(struct fman_mac *tgec, + enet_addr_t *eth_addr) { struct tgec_regs __iomem *regs = tgec->regs; struct eth_hash_entry *hash_entry; u32 crc = 0xFFFFFFFF, hash; u64 addr; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - addr = ENET_ADDR_TO_UINT64(*eth_addr); if (!(addr & GROUP_ADDRESS)) { @@ -562,14 +518,11 @@ int tgec_add_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr) return 0; } -int tgec_set_allmulti(struct fman_mac *tgec, bool enable) +static int tgec_set_allmulti(struct fman_mac *tgec, bool enable) { u32 entry; struct tgec_regs __iomem *regs = tgec->regs; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - if (enable) { for (entry = 0; entry < TGEC_HASH_TABLE_SIZE; entry++) iowrite32be(entry | TGEC_HASH_MCAST_EN, @@ -585,14 +538,11 @@ int tgec_set_allmulti(struct fman_mac *tgec, bool enable) return 0; } -int tgec_set_tstamp(struct fman_mac *tgec, bool enable) +static int tgec_set_tstamp(struct fman_mac *tgec, bool enable) { struct tgec_regs __iomem *regs = tgec->regs; u32 tmp; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - tmp = ioread32be(®s->command_config); if (enable) @@ -605,7 +555,8 @@ int tgec_set_tstamp(struct fman_mac *tgec, bool enable) return 0; } -int tgec_del_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr) +static int tgec_del_hash_mac_address(struct fman_mac *tgec, + enet_addr_t *eth_addr) { struct tgec_regs __iomem *regs = tgec->regs; struct eth_hash_entry *hash_entry = NULL; @@ -613,9 +564,6 @@ int tgec_del_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr) u32 crc = 0xFFFFFFFF, hash; u64 addr; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - addr = ((*(u64 *)eth_addr) >> 16); /* CRC calculation */ @@ -642,27 +590,12 @@ int tgec_del_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr) return 0; } -int tgec_get_version(struct fman_mac *tgec, u32 *mac_version) -{ - struct tgec_regs __iomem *regs = tgec->regs; - - if (!is_init_done(tgec->cfg)) - return -EINVAL; - - *mac_version = ioread32be(®s->tgec_id); - - return 0; -} - -int tgec_set_exception(struct fman_mac *tgec, - enum fman_mac_exceptions exception, bool enable) +static int tgec_set_exception(struct fman_mac *tgec, + enum fman_mac_exceptions exception, bool enable) { struct tgec_regs __iomem *regs = tgec->regs; u32 bit_mask = 0; - if (!is_init_done(tgec->cfg)) - return -EINVAL; - bit_mask = get_exception_flag(exception); if (bit_mask) { if (enable) @@ -681,15 +614,12 @@ int tgec_set_exception(struct fman_mac *tgec, return 0; } -int tgec_init(struct fman_mac *tgec) +static int tgec_init(struct fman_mac *tgec) { struct tgec_cfg *cfg; enet_addr_t eth_addr; int err; - if (is_init_done(tgec->cfg)) - return -EINVAL; - if (DEFAULT_RESET_ON_INIT && (fman_reset_mac(tgec->fm, tgec->mac_id) != 0)) { pr_err("Can't reset MAC!\n"); @@ -704,7 +634,7 @@ int tgec_init(struct fman_mac *tgec) if (tgec->addr) { MAKE_ENET_ADDR_FROM_UINT64(tgec->addr, eth_addr); - set_mac_address(tgec->regs, (u8 *)eth_addr); + set_mac_address(tgec->regs, (const u8 *)eth_addr); } /* interrupts */ @@ -764,7 +694,7 @@ int tgec_init(struct fman_mac *tgec) return 0; } -int tgec_free(struct fman_mac *tgec) +static int tgec_free(struct fman_mac *tgec) { free_init_resources(tgec); @@ -774,13 +704,12 @@ int tgec_free(struct fman_mac *tgec) return 0; } -struct fman_mac *tgec_config(struct fman_mac_params *params) +static struct fman_mac *tgec_config(struct mac_device *mac_dev, + struct fman_mac_params *params) { struct fman_mac *tgec; struct tgec_cfg *cfg; - void __iomem *base_addr; - base_addr = params->base_addr; /* allocate memory for the UCC GETH data structure. */ tgec = kzalloc(sizeof(*tgec), GFP_KERNEL); if (!tgec) @@ -798,9 +727,8 @@ struct fman_mac *tgec_config(struct fman_mac_params *params) set_dflts(cfg); - tgec->regs = base_addr; - tgec->addr = ENET_ADDR_TO_UINT64(params->addr); - tgec->max_speed = params->max_speed; + tgec->regs = mac_dev->vaddr; + tgec->addr = ENET_ADDR_TO_UINT64(mac_dev->addr); tgec->mac_id = params->mac_id; tgec->exceptions = (TGEC_IMASK_MDIO_SCAN_EVENT | TGEC_IMASK_REM_FAULT | @@ -819,7 +747,7 @@ struct fman_mac *tgec_config(struct fman_mac_params *params) TGEC_IMASK_RX_ALIGN_ER); tgec->exception_cb = params->exception_cb; tgec->event_cb = params->event_cb; - tgec->dev_id = params->dev_id; + tgec->dev_id = mac_dev; tgec->fm = params->fm; /* Save FMan revision */ @@ -827,3 +755,62 @@ struct fman_mac *tgec_config(struct fman_mac_params *params) return tgec; } + +int tgec_initialization(struct mac_device *mac_dev, + struct device_node *mac_node, + struct fman_mac_params *params) +{ + int err; + struct fman_mac *tgec; + + mac_dev->phylink_ops = &tgec_mac_ops; + mac_dev->set_promisc = tgec_set_promiscuous; + mac_dev->change_addr = tgec_modify_mac_address; + mac_dev->add_hash_mac_addr = tgec_add_hash_mac_address; + mac_dev->remove_hash_mac_addr = tgec_del_hash_mac_address; + mac_dev->set_exception = tgec_set_exception; + mac_dev->set_allmulti = tgec_set_allmulti; + mac_dev->set_tstamp = tgec_set_tstamp; + mac_dev->enable = tgec_enable; + mac_dev->disable = tgec_disable; + + mac_dev->fman_mac = tgec_config(mac_dev, params); + if (!mac_dev->fman_mac) { + err = -EINVAL; + goto _return; + } + + /* The internal connection to the serdes is XGMII, but this isn't + * really correct for the phy mode (which is the external connection). + * However, this is how all older device trees say that they want + * XAUI, so just convert it for them. + */ + if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII) + mac_dev->phy_if = PHY_INTERFACE_MODE_XAUI; + + __set_bit(PHY_INTERFACE_MODE_XAUI, + mac_dev->phylink_config.supported_interfaces); + mac_dev->phylink_config.mac_capabilities = + MAC_SYM_PAUSE | MAC_ASYM_PAUSE | MAC_10000FD; + + tgec = mac_dev->fman_mac; + tgec->cfg->max_frame_length = fman_get_max_frm(); + err = tgec_init(tgec); + if (err < 0) + goto _return_fm_mac_free; + + /* For 10G MAC, disable Tx ECC exception */ + err = tgec_set_exception(tgec, FM_MAC_EX_10G_TX_ECC_ER, false); + if (err < 0) + goto _return_fm_mac_free; + + pr_info("FMan XGEC version: 0x%08x\n", + ioread32be(&tgec->regs->tgec_id)); + goto _return; + +_return_fm_mac_free: + tgec_free(mac_dev->fman_mac); + +_return: + return err; +} |
