18585bdadSSean Anderson // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later
257ba4c9bSIgal Liberman /*
357ba4c9bSIgal Liberman * Copyright 2008 - 2015 Freescale Semiconductor Inc.
457ba4c9bSIgal Liberman */
557ba4c9bSIgal Liberman
657ba4c9bSIgal Liberman #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
757ba4c9bSIgal Liberman
857ba4c9bSIgal Liberman #include "fman_tgec.h"
957ba4c9bSIgal Liberman #include "fman.h"
10302376feSSean Anderson #include "mac.h"
1157ba4c9bSIgal Liberman
1257ba4c9bSIgal Liberman #include <linux/slab.h>
1357ba4c9bSIgal Liberman #include <linux/bitrev.h>
1457ba4c9bSIgal Liberman #include <linux/io.h>
1557ba4c9bSIgal Liberman #include <linux/crc32.h>
16*5d93cfcfSSean Anderson #include <linux/netdevice.h>
1757ba4c9bSIgal Liberman
1857ba4c9bSIgal Liberman /* Transmit Inter-Packet Gap Length Register (TX_IPG_LENGTH) */
1957ba4c9bSIgal Liberman #define TGEC_TX_IPG_LENGTH_MASK 0x000003ff
2057ba4c9bSIgal Liberman
2157ba4c9bSIgal Liberman /* Command and Configuration Register (COMMAND_CONFIG) */
220fab782aSYangbo Lu #define CMD_CFG_EN_TIMESTAMP 0x00100000
2357ba4c9bSIgal Liberman #define CMD_CFG_NO_LEN_CHK 0x00020000
2457ba4c9bSIgal Liberman #define CMD_CFG_PAUSE_IGNORE 0x00000100
2557ba4c9bSIgal Liberman #define CMF_CFG_CRC_FWD 0x00000040
2657ba4c9bSIgal Liberman #define CMD_CFG_PROMIS_EN 0x00000010
2757ba4c9bSIgal Liberman #define CMD_CFG_RX_EN 0x00000002
2857ba4c9bSIgal Liberman #define CMD_CFG_TX_EN 0x00000001
2957ba4c9bSIgal Liberman
3057ba4c9bSIgal Liberman /* Interrupt Mask Register (IMASK) */
3157ba4c9bSIgal Liberman #define TGEC_IMASK_MDIO_SCAN_EVENT 0x00010000
3257ba4c9bSIgal Liberman #define TGEC_IMASK_MDIO_CMD_CMPL 0x00008000
3357ba4c9bSIgal Liberman #define TGEC_IMASK_REM_FAULT 0x00004000
3457ba4c9bSIgal Liberman #define TGEC_IMASK_LOC_FAULT 0x00002000
3557ba4c9bSIgal Liberman #define TGEC_IMASK_TX_ECC_ER 0x00001000
3657ba4c9bSIgal Liberman #define TGEC_IMASK_TX_FIFO_UNFL 0x00000800
3757ba4c9bSIgal Liberman #define TGEC_IMASK_TX_FIFO_OVFL 0x00000400
3857ba4c9bSIgal Liberman #define TGEC_IMASK_TX_ER 0x00000200
3957ba4c9bSIgal Liberman #define TGEC_IMASK_RX_FIFO_OVFL 0x00000100
4057ba4c9bSIgal Liberman #define TGEC_IMASK_RX_ECC_ER 0x00000080
4157ba4c9bSIgal Liberman #define TGEC_IMASK_RX_JAB_FRM 0x00000040
4257ba4c9bSIgal Liberman #define TGEC_IMASK_RX_OVRSZ_FRM 0x00000020
4357ba4c9bSIgal Liberman #define TGEC_IMASK_RX_RUNT_FRM 0x00000010
4457ba4c9bSIgal Liberman #define TGEC_IMASK_RX_FRAG_FRM 0x00000008
4557ba4c9bSIgal Liberman #define TGEC_IMASK_RX_LEN_ER 0x00000004
4657ba4c9bSIgal Liberman #define TGEC_IMASK_RX_CRC_ER 0x00000002
4757ba4c9bSIgal Liberman #define TGEC_IMASK_RX_ALIGN_ER 0x00000001
4857ba4c9bSIgal Liberman
4957ba4c9bSIgal Liberman /* Hashtable Control Register (HASHTABLE_CTRL) */
5057ba4c9bSIgal Liberman #define TGEC_HASH_MCAST_SHIFT 23
5157ba4c9bSIgal Liberman #define TGEC_HASH_MCAST_EN 0x00000200
5257ba4c9bSIgal Liberman #define TGEC_HASH_ADR_MSK 0x000001ff
5357ba4c9bSIgal Liberman
5457ba4c9bSIgal Liberman #define DEFAULT_TX_IPG_LENGTH 12
5557ba4c9bSIgal Liberman #define DEFAULT_MAX_FRAME_LENGTH 0x600
5657ba4c9bSIgal Liberman #define DEFAULT_PAUSE_QUANT 0xf000
5757ba4c9bSIgal Liberman
5857ba4c9bSIgal Liberman /* number of pattern match registers (entries) */
5957ba4c9bSIgal Liberman #define TGEC_NUM_OF_PADDRS 1
6057ba4c9bSIgal Liberman
6157ba4c9bSIgal Liberman /* Group address bit indication */
6257ba4c9bSIgal Liberman #define GROUP_ADDRESS 0x0000010000000000LL
6357ba4c9bSIgal Liberman
6457ba4c9bSIgal Liberman /* Hash table size (= 32 bits*8 regs) */
6557ba4c9bSIgal Liberman #define TGEC_HASH_TABLE_SIZE 512
6657ba4c9bSIgal Liberman
6757ba4c9bSIgal Liberman /* tGEC memory map */
6857ba4c9bSIgal Liberman struct tgec_regs {
6957ba4c9bSIgal Liberman u32 tgec_id; /* 0x000 Controller ID */
7057ba4c9bSIgal Liberman u32 reserved001[1]; /* 0x004 */
7157ba4c9bSIgal Liberman u32 command_config; /* 0x008 Control and configuration */
7257ba4c9bSIgal Liberman u32 mac_addr_0; /* 0x00c Lower 32 bits of the MAC adr */
7357ba4c9bSIgal Liberman u32 mac_addr_1; /* 0x010 Upper 16 bits of the MAC adr */
7457ba4c9bSIgal Liberman u32 maxfrm; /* 0x014 Maximum frame length */
7557ba4c9bSIgal Liberman u32 pause_quant; /* 0x018 Pause quanta */
7657ba4c9bSIgal Liberman u32 rx_fifo_sections; /* 0x01c */
7757ba4c9bSIgal Liberman u32 tx_fifo_sections; /* 0x020 */
7857ba4c9bSIgal Liberman u32 rx_fifo_almost_f_e; /* 0x024 */
7957ba4c9bSIgal Liberman u32 tx_fifo_almost_f_e; /* 0x028 */
8057ba4c9bSIgal Liberman u32 hashtable_ctrl; /* 0x02c Hash table control */
8157ba4c9bSIgal Liberman u32 mdio_cfg_status; /* 0x030 */
8257ba4c9bSIgal Liberman u32 mdio_command; /* 0x034 */
8357ba4c9bSIgal Liberman u32 mdio_data; /* 0x038 */
8457ba4c9bSIgal Liberman u32 mdio_regaddr; /* 0x03c */
8557ba4c9bSIgal Liberman u32 status; /* 0x040 */
8657ba4c9bSIgal Liberman u32 tx_ipg_len; /* 0x044 Transmitter inter-packet-gap */
8757ba4c9bSIgal Liberman u32 mac_addr_2; /* 0x048 Lower 32 bits of 2nd MAC adr */
8857ba4c9bSIgal Liberman u32 mac_addr_3; /* 0x04c Upper 16 bits of 2nd MAC adr */
8957ba4c9bSIgal Liberman u32 rx_fifo_ptr_rd; /* 0x050 */
9057ba4c9bSIgal Liberman u32 rx_fifo_ptr_wr; /* 0x054 */
9157ba4c9bSIgal Liberman u32 tx_fifo_ptr_rd; /* 0x058 */
9257ba4c9bSIgal Liberman u32 tx_fifo_ptr_wr; /* 0x05c */
9357ba4c9bSIgal Liberman u32 imask; /* 0x060 Interrupt mask */
9457ba4c9bSIgal Liberman u32 ievent; /* 0x064 Interrupt event */
9557ba4c9bSIgal Liberman u32 udp_port; /* 0x068 Defines a UDP Port number */
9657ba4c9bSIgal Liberman u32 type_1588v2; /* 0x06c Type field for 1588v2 */
9757ba4c9bSIgal Liberman u32 reserved070[4]; /* 0x070 */
9857ba4c9bSIgal Liberman /* 10Ge Statistics Counter */
9957ba4c9bSIgal Liberman u32 tfrm_u; /* 80 aFramesTransmittedOK */
10057ba4c9bSIgal Liberman u32 tfrm_l; /* 84 aFramesTransmittedOK */
10157ba4c9bSIgal Liberman u32 rfrm_u; /* 88 aFramesReceivedOK */
10257ba4c9bSIgal Liberman u32 rfrm_l; /* 8c aFramesReceivedOK */
10357ba4c9bSIgal Liberman u32 rfcs_u; /* 90 aFrameCheckSequenceErrors */
10457ba4c9bSIgal Liberman u32 rfcs_l; /* 94 aFrameCheckSequenceErrors */
10557ba4c9bSIgal Liberman u32 raln_u; /* 98 aAlignmentErrors */
10657ba4c9bSIgal Liberman u32 raln_l; /* 9c aAlignmentErrors */
10757ba4c9bSIgal Liberman u32 txpf_u; /* A0 aPAUSEMACCtrlFramesTransmitted */
10857ba4c9bSIgal Liberman u32 txpf_l; /* A4 aPAUSEMACCtrlFramesTransmitted */
10957ba4c9bSIgal Liberman u32 rxpf_u; /* A8 aPAUSEMACCtrlFramesReceived */
11057ba4c9bSIgal Liberman u32 rxpf_l; /* Ac aPAUSEMACCtrlFramesReceived */
11157ba4c9bSIgal Liberman u32 rlong_u; /* B0 aFrameTooLongErrors */
11257ba4c9bSIgal Liberman u32 rlong_l; /* B4 aFrameTooLongErrors */
11357ba4c9bSIgal Liberman u32 rflr_u; /* B8 aInRangeLengthErrors */
11457ba4c9bSIgal Liberman u32 rflr_l; /* Bc aInRangeLengthErrors */
11557ba4c9bSIgal Liberman u32 tvlan_u; /* C0 VLANTransmittedOK */
11657ba4c9bSIgal Liberman u32 tvlan_l; /* C4 VLANTransmittedOK */
11757ba4c9bSIgal Liberman u32 rvlan_u; /* C8 VLANReceivedOK */
11857ba4c9bSIgal Liberman u32 rvlan_l; /* Cc VLANReceivedOK */
11957ba4c9bSIgal Liberman u32 toct_u; /* D0 if_out_octets */
12057ba4c9bSIgal Liberman u32 toct_l; /* D4 if_out_octets */
12157ba4c9bSIgal Liberman u32 roct_u; /* D8 if_in_octets */
12257ba4c9bSIgal Liberman u32 roct_l; /* Dc if_in_octets */
12357ba4c9bSIgal Liberman u32 ruca_u; /* E0 if_in_ucast_pkts */
12457ba4c9bSIgal Liberman u32 ruca_l; /* E4 if_in_ucast_pkts */
12557ba4c9bSIgal Liberman u32 rmca_u; /* E8 ifInMulticastPkts */
12657ba4c9bSIgal Liberman u32 rmca_l; /* Ec ifInMulticastPkts */
12757ba4c9bSIgal Liberman u32 rbca_u; /* F0 ifInBroadcastPkts */
12857ba4c9bSIgal Liberman u32 rbca_l; /* F4 ifInBroadcastPkts */
12957ba4c9bSIgal Liberman u32 terr_u; /* F8 if_out_errors */
13057ba4c9bSIgal Liberman u32 terr_l; /* Fc if_out_errors */
13157ba4c9bSIgal Liberman u32 reserved100[2]; /* 100-108 */
13257ba4c9bSIgal Liberman u32 tuca_u; /* 108 if_out_ucast_pkts */
13357ba4c9bSIgal Liberman u32 tuca_l; /* 10c if_out_ucast_pkts */
13457ba4c9bSIgal Liberman u32 tmca_u; /* 110 ifOutMulticastPkts */
13557ba4c9bSIgal Liberman u32 tmca_l; /* 114 ifOutMulticastPkts */
13657ba4c9bSIgal Liberman u32 tbca_u; /* 118 ifOutBroadcastPkts */
13757ba4c9bSIgal Liberman u32 tbca_l; /* 11c ifOutBroadcastPkts */
13857ba4c9bSIgal Liberman u32 rdrp_u; /* 120 etherStatsDropEvents */
13957ba4c9bSIgal Liberman u32 rdrp_l; /* 124 etherStatsDropEvents */
14057ba4c9bSIgal Liberman u32 reoct_u; /* 128 etherStatsOctets */
14157ba4c9bSIgal Liberman u32 reoct_l; /* 12c etherStatsOctets */
14257ba4c9bSIgal Liberman u32 rpkt_u; /* 130 etherStatsPkts */
14357ba4c9bSIgal Liberman u32 rpkt_l; /* 134 etherStatsPkts */
14457ba4c9bSIgal Liberman u32 trund_u; /* 138 etherStatsUndersizePkts */
14557ba4c9bSIgal Liberman u32 trund_l; /* 13c etherStatsUndersizePkts */
14657ba4c9bSIgal Liberman u32 r64_u; /* 140 etherStatsPkts64Octets */
14757ba4c9bSIgal Liberman u32 r64_l; /* 144 etherStatsPkts64Octets */
14857ba4c9bSIgal Liberman u32 r127_u; /* 148 etherStatsPkts65to127Octets */
14957ba4c9bSIgal Liberman u32 r127_l; /* 14c etherStatsPkts65to127Octets */
15057ba4c9bSIgal Liberman u32 r255_u; /* 150 etherStatsPkts128to255Octets */
15157ba4c9bSIgal Liberman u32 r255_l; /* 154 etherStatsPkts128to255Octets */
15257ba4c9bSIgal Liberman u32 r511_u; /* 158 etherStatsPkts256to511Octets */
15357ba4c9bSIgal Liberman u32 r511_l; /* 15c etherStatsPkts256to511Octets */
15457ba4c9bSIgal Liberman u32 r1023_u; /* 160 etherStatsPkts512to1023Octets */
15557ba4c9bSIgal Liberman u32 r1023_l; /* 164 etherStatsPkts512to1023Octets */
15657ba4c9bSIgal Liberman u32 r1518_u; /* 168 etherStatsPkts1024to1518Octets */
15757ba4c9bSIgal Liberman u32 r1518_l; /* 16c etherStatsPkts1024to1518Octets */
15857ba4c9bSIgal Liberman u32 r1519x_u; /* 170 etherStatsPkts1519toX */
15957ba4c9bSIgal Liberman u32 r1519x_l; /* 174 etherStatsPkts1519toX */
16057ba4c9bSIgal Liberman u32 trovr_u; /* 178 etherStatsOversizePkts */
16157ba4c9bSIgal Liberman u32 trovr_l; /* 17c etherStatsOversizePkts */
16257ba4c9bSIgal Liberman u32 trjbr_u; /* 180 etherStatsJabbers */
16357ba4c9bSIgal Liberman u32 trjbr_l; /* 184 etherStatsJabbers */
16457ba4c9bSIgal Liberman u32 trfrg_u; /* 188 etherStatsFragments */
16557ba4c9bSIgal Liberman u32 trfrg_l; /* 18C etherStatsFragments */
16657ba4c9bSIgal Liberman u32 rerr_u; /* 190 if_in_errors */
16757ba4c9bSIgal Liberman u32 rerr_l; /* 194 if_in_errors */
16857ba4c9bSIgal Liberman };
16957ba4c9bSIgal Liberman
17057ba4c9bSIgal Liberman struct tgec_cfg {
17157ba4c9bSIgal Liberman bool pause_ignore;
17257ba4c9bSIgal Liberman bool promiscuous_mode_enable;
17357ba4c9bSIgal Liberman u16 max_frame_length;
17457ba4c9bSIgal Liberman u16 pause_quant;
17557ba4c9bSIgal Liberman u32 tx_ipg_length;
17657ba4c9bSIgal Liberman };
17757ba4c9bSIgal Liberman
17857ba4c9bSIgal Liberman struct fman_mac {
17957ba4c9bSIgal Liberman /* Pointer to the memory mapped registers. */
18057ba4c9bSIgal Liberman struct tgec_regs __iomem *regs;
18157ba4c9bSIgal Liberman /* MAC address of device; */
18257ba4c9bSIgal Liberman u64 addr;
18357ba4c9bSIgal Liberman u16 max_speed;
1845b6acb55SSean Anderson struct mac_device *dev_id; /* device cookie used by the exception cbs */
18557ba4c9bSIgal Liberman fman_mac_exception_cb *exception_cb;
18657ba4c9bSIgal Liberman fman_mac_exception_cb *event_cb;
18757ba4c9bSIgal Liberman /* pointer to driver's global address hash table */
18857ba4c9bSIgal Liberman struct eth_hash_t *multicast_addr_hash;
18957ba4c9bSIgal Liberman /* pointer to driver's individual address hash table */
19057ba4c9bSIgal Liberman struct eth_hash_t *unicast_addr_hash;
19157ba4c9bSIgal Liberman u8 mac_id;
19257ba4c9bSIgal Liberman u32 exceptions;
19357ba4c9bSIgal Liberman struct tgec_cfg *cfg;
19457ba4c9bSIgal Liberman void *fm;
19557ba4c9bSIgal Liberman struct fman_rev_info fm_rev_info;
196c893238eSRadu Bulie bool allmulti_enabled;
19757ba4c9bSIgal Liberman };
19857ba4c9bSIgal Liberman
set_mac_address(struct tgec_regs __iomem * regs,const u8 * adr)19976660757SJakub Kicinski static void set_mac_address(struct tgec_regs __iomem *regs, const u8 *adr)
20057ba4c9bSIgal Liberman {
20157ba4c9bSIgal Liberman u32 tmp0, tmp1;
20257ba4c9bSIgal Liberman
20357ba4c9bSIgal Liberman tmp0 = (u32)(adr[0] | adr[1] << 8 | adr[2] << 16 | adr[3] << 24);
20457ba4c9bSIgal Liberman tmp1 = (u32)(adr[4] | adr[5] << 8);
20557ba4c9bSIgal Liberman iowrite32be(tmp0, ®s->mac_addr_0);
20657ba4c9bSIgal Liberman iowrite32be(tmp1, ®s->mac_addr_1);
20757ba4c9bSIgal Liberman }
20857ba4c9bSIgal Liberman
set_dflts(struct tgec_cfg * cfg)20957ba4c9bSIgal Liberman static void set_dflts(struct tgec_cfg *cfg)
21057ba4c9bSIgal Liberman {
21157ba4c9bSIgal Liberman cfg->promiscuous_mode_enable = false;
21257ba4c9bSIgal Liberman cfg->pause_ignore = false;
21357ba4c9bSIgal Liberman cfg->tx_ipg_length = DEFAULT_TX_IPG_LENGTH;
21457ba4c9bSIgal Liberman cfg->max_frame_length = DEFAULT_MAX_FRAME_LENGTH;
21557ba4c9bSIgal Liberman cfg->pause_quant = DEFAULT_PAUSE_QUANT;
21657ba4c9bSIgal Liberman }
21757ba4c9bSIgal Liberman
init(struct tgec_regs __iomem * regs,struct tgec_cfg * cfg,u32 exception_mask)21857ba4c9bSIgal Liberman static int init(struct tgec_regs __iomem *regs, struct tgec_cfg *cfg,
21957ba4c9bSIgal Liberman u32 exception_mask)
22057ba4c9bSIgal Liberman {
22157ba4c9bSIgal Liberman u32 tmp;
22257ba4c9bSIgal Liberman
22357ba4c9bSIgal Liberman /* Config */
22457ba4c9bSIgal Liberman tmp = CMF_CFG_CRC_FWD;
22557ba4c9bSIgal Liberman if (cfg->promiscuous_mode_enable)
22657ba4c9bSIgal Liberman tmp |= CMD_CFG_PROMIS_EN;
22757ba4c9bSIgal Liberman if (cfg->pause_ignore)
22857ba4c9bSIgal Liberman tmp |= CMD_CFG_PAUSE_IGNORE;
22957ba4c9bSIgal Liberman /* Payload length check disable */
23057ba4c9bSIgal Liberman tmp |= CMD_CFG_NO_LEN_CHK;
23157ba4c9bSIgal Liberman iowrite32be(tmp, ®s->command_config);
23257ba4c9bSIgal Liberman
23357ba4c9bSIgal Liberman /* Max Frame Length */
23457ba4c9bSIgal Liberman iowrite32be((u32)cfg->max_frame_length, ®s->maxfrm);
23557ba4c9bSIgal Liberman /* Pause Time */
23657ba4c9bSIgal Liberman iowrite32be(cfg->pause_quant, ®s->pause_quant);
23757ba4c9bSIgal Liberman
23857ba4c9bSIgal Liberman /* clear all pending events and set-up interrupts */
23957ba4c9bSIgal Liberman iowrite32be(0xffffffff, ®s->ievent);
24057ba4c9bSIgal Liberman iowrite32be(ioread32be(®s->imask) | exception_mask, ®s->imask);
24157ba4c9bSIgal Liberman
24257ba4c9bSIgal Liberman return 0;
24357ba4c9bSIgal Liberman }
24457ba4c9bSIgal Liberman
check_init_parameters(struct fman_mac * tgec)24557ba4c9bSIgal Liberman static int check_init_parameters(struct fman_mac *tgec)
24657ba4c9bSIgal Liberman {
24757ba4c9bSIgal Liberman if (!tgec->exception_cb) {
24857ba4c9bSIgal Liberman pr_err("uninitialized exception_cb\n");
24957ba4c9bSIgal Liberman return -EINVAL;
25057ba4c9bSIgal Liberman }
25157ba4c9bSIgal Liberman if (!tgec->event_cb) {
25257ba4c9bSIgal Liberman pr_err("uninitialized event_cb\n");
25357ba4c9bSIgal Liberman return -EINVAL;
25457ba4c9bSIgal Liberman }
25557ba4c9bSIgal Liberman
25657ba4c9bSIgal Liberman return 0;
25757ba4c9bSIgal Liberman }
25857ba4c9bSIgal Liberman
get_exception_flag(enum fman_mac_exceptions exception)25957ba4c9bSIgal Liberman static int get_exception_flag(enum fman_mac_exceptions exception)
26057ba4c9bSIgal Liberman {
26157ba4c9bSIgal Liberman u32 bit_mask;
26257ba4c9bSIgal Liberman
26357ba4c9bSIgal Liberman switch (exception) {
26457ba4c9bSIgal Liberman case FM_MAC_EX_10G_MDIO_SCAN_EVENT:
26557ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_MDIO_SCAN_EVENT;
26657ba4c9bSIgal Liberman break;
26757ba4c9bSIgal Liberman case FM_MAC_EX_10G_MDIO_CMD_CMPL:
26857ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_MDIO_CMD_CMPL;
26957ba4c9bSIgal Liberman break;
27057ba4c9bSIgal Liberman case FM_MAC_EX_10G_REM_FAULT:
27157ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_REM_FAULT;
27257ba4c9bSIgal Liberman break;
27357ba4c9bSIgal Liberman case FM_MAC_EX_10G_LOC_FAULT:
27457ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_LOC_FAULT;
27557ba4c9bSIgal Liberman break;
27657ba4c9bSIgal Liberman case FM_MAC_EX_10G_TX_ECC_ER:
27757ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_TX_ECC_ER;
27857ba4c9bSIgal Liberman break;
27957ba4c9bSIgal Liberman case FM_MAC_EX_10G_TX_FIFO_UNFL:
28057ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_TX_FIFO_UNFL;
28157ba4c9bSIgal Liberman break;
28257ba4c9bSIgal Liberman case FM_MAC_EX_10G_TX_FIFO_OVFL:
28357ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_TX_FIFO_OVFL;
28457ba4c9bSIgal Liberman break;
28557ba4c9bSIgal Liberman case FM_MAC_EX_10G_TX_ER:
28657ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_TX_ER;
28757ba4c9bSIgal Liberman break;
28857ba4c9bSIgal Liberman case FM_MAC_EX_10G_RX_FIFO_OVFL:
28957ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_RX_FIFO_OVFL;
29057ba4c9bSIgal Liberman break;
29157ba4c9bSIgal Liberman case FM_MAC_EX_10G_RX_ECC_ER:
29257ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_RX_ECC_ER;
29357ba4c9bSIgal Liberman break;
29457ba4c9bSIgal Liberman case FM_MAC_EX_10G_RX_JAB_FRM:
29557ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_RX_JAB_FRM;
29657ba4c9bSIgal Liberman break;
29757ba4c9bSIgal Liberman case FM_MAC_EX_10G_RX_OVRSZ_FRM:
29857ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_RX_OVRSZ_FRM;
29957ba4c9bSIgal Liberman break;
30057ba4c9bSIgal Liberman case FM_MAC_EX_10G_RX_RUNT_FRM:
30157ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_RX_RUNT_FRM;
30257ba4c9bSIgal Liberman break;
30357ba4c9bSIgal Liberman case FM_MAC_EX_10G_RX_FRAG_FRM:
30457ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_RX_FRAG_FRM;
30557ba4c9bSIgal Liberman break;
30657ba4c9bSIgal Liberman case FM_MAC_EX_10G_RX_LEN_ER:
30757ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_RX_LEN_ER;
30857ba4c9bSIgal Liberman break;
30957ba4c9bSIgal Liberman case FM_MAC_EX_10G_RX_CRC_ER:
31057ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_RX_CRC_ER;
31157ba4c9bSIgal Liberman break;
31257ba4c9bSIgal Liberman case FM_MAC_EX_10G_RX_ALIGN_ER:
31357ba4c9bSIgal Liberman bit_mask = TGEC_IMASK_RX_ALIGN_ER;
31457ba4c9bSIgal Liberman break;
31557ba4c9bSIgal Liberman default:
31657ba4c9bSIgal Liberman bit_mask = 0;
31757ba4c9bSIgal Liberman break;
31857ba4c9bSIgal Liberman }
31957ba4c9bSIgal Liberman
32057ba4c9bSIgal Liberman return bit_mask;
32157ba4c9bSIgal Liberman }
32257ba4c9bSIgal Liberman
tgec_err_exception(void * handle)32357ba4c9bSIgal Liberman static void tgec_err_exception(void *handle)
32457ba4c9bSIgal Liberman {
32557ba4c9bSIgal Liberman struct fman_mac *tgec = (struct fman_mac *)handle;
32657ba4c9bSIgal Liberman struct tgec_regs __iomem *regs = tgec->regs;
32757ba4c9bSIgal Liberman u32 event;
32857ba4c9bSIgal Liberman
32957ba4c9bSIgal Liberman /* do not handle MDIO events */
33057ba4c9bSIgal Liberman event = ioread32be(®s->ievent) &
33157ba4c9bSIgal Liberman ~(TGEC_IMASK_MDIO_SCAN_EVENT |
33257ba4c9bSIgal Liberman TGEC_IMASK_MDIO_CMD_CMPL);
33357ba4c9bSIgal Liberman
33457ba4c9bSIgal Liberman event &= ioread32be(®s->imask);
33557ba4c9bSIgal Liberman
33657ba4c9bSIgal Liberman iowrite32be(event, ®s->ievent);
33757ba4c9bSIgal Liberman
33857ba4c9bSIgal Liberman if (event & TGEC_IMASK_REM_FAULT)
33957ba4c9bSIgal Liberman tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_REM_FAULT);
34057ba4c9bSIgal Liberman if (event & TGEC_IMASK_LOC_FAULT)
34157ba4c9bSIgal Liberman tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_LOC_FAULT);
34257ba4c9bSIgal Liberman if (event & TGEC_IMASK_TX_ECC_ER)
34357ba4c9bSIgal Liberman tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_TX_ECC_ER);
34457ba4c9bSIgal Liberman if (event & TGEC_IMASK_TX_FIFO_UNFL)
34557ba4c9bSIgal Liberman tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_TX_FIFO_UNFL);
34657ba4c9bSIgal Liberman if (event & TGEC_IMASK_TX_FIFO_OVFL)
34757ba4c9bSIgal Liberman tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_TX_FIFO_OVFL);
34857ba4c9bSIgal Liberman if (event & TGEC_IMASK_TX_ER)
34957ba4c9bSIgal Liberman tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_TX_ER);
35057ba4c9bSIgal Liberman if (event & TGEC_IMASK_RX_FIFO_OVFL)
35157ba4c9bSIgal Liberman tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_FIFO_OVFL);
35257ba4c9bSIgal Liberman if (event & TGEC_IMASK_RX_ECC_ER)
35357ba4c9bSIgal Liberman tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_ECC_ER);
35457ba4c9bSIgal Liberman if (event & TGEC_IMASK_RX_JAB_FRM)
35557ba4c9bSIgal Liberman tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_JAB_FRM);
35657ba4c9bSIgal Liberman if (event & TGEC_IMASK_RX_OVRSZ_FRM)
35757ba4c9bSIgal Liberman tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_OVRSZ_FRM);
35857ba4c9bSIgal Liberman if (event & TGEC_IMASK_RX_RUNT_FRM)
35957ba4c9bSIgal Liberman tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_RUNT_FRM);
36057ba4c9bSIgal Liberman if (event & TGEC_IMASK_RX_FRAG_FRM)
36157ba4c9bSIgal Liberman tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_FRAG_FRM);
36257ba4c9bSIgal Liberman if (event & TGEC_IMASK_RX_LEN_ER)
36357ba4c9bSIgal Liberman tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_LEN_ER);
36457ba4c9bSIgal Liberman if (event & TGEC_IMASK_RX_CRC_ER)
36557ba4c9bSIgal Liberman tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_CRC_ER);
36657ba4c9bSIgal Liberman if (event & TGEC_IMASK_RX_ALIGN_ER)
36757ba4c9bSIgal Liberman tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_ALIGN_ER);
36857ba4c9bSIgal Liberman }
36957ba4c9bSIgal Liberman
free_init_resources(struct fman_mac * tgec)37057ba4c9bSIgal Liberman static void free_init_resources(struct fman_mac *tgec)
37157ba4c9bSIgal Liberman {
37257ba4c9bSIgal Liberman fman_unregister_intr(tgec->fm, FMAN_MOD_MAC, tgec->mac_id,
37357ba4c9bSIgal Liberman FMAN_INTR_TYPE_ERR);
37457ba4c9bSIgal Liberman
37557ba4c9bSIgal Liberman /* release the driver's group hash table */
37657ba4c9bSIgal Liberman free_hash_table(tgec->multicast_addr_hash);
37757ba4c9bSIgal Liberman tgec->multicast_addr_hash = NULL;
37857ba4c9bSIgal Liberman
37957ba4c9bSIgal Liberman /* release the driver's individual hash table */
38057ba4c9bSIgal Liberman free_hash_table(tgec->unicast_addr_hash);
38157ba4c9bSIgal Liberman tgec->unicast_addr_hash = NULL;
38257ba4c9bSIgal Liberman }
38357ba4c9bSIgal Liberman
tgec_enable(struct fman_mac * tgec)3841257c962SSean Anderson static int tgec_enable(struct fman_mac *tgec)
38557ba4c9bSIgal Liberman {
38657ba4c9bSIgal Liberman return 0;
38757ba4c9bSIgal Liberman }
38857ba4c9bSIgal Liberman
tgec_disable(struct fman_mac * tgec)389901bdff2SSean Anderson static void tgec_disable(struct fman_mac *tgec)
39057ba4c9bSIgal Liberman {
39157ba4c9bSIgal Liberman }
39257ba4c9bSIgal Liberman
tgec_set_promiscuous(struct fman_mac * tgec,bool new_val)3931257c962SSean Anderson static int tgec_set_promiscuous(struct fman_mac *tgec, bool new_val)
39457ba4c9bSIgal Liberman {
39557ba4c9bSIgal Liberman struct tgec_regs __iomem *regs = tgec->regs;
39657ba4c9bSIgal Liberman u32 tmp;
39757ba4c9bSIgal Liberman
39857ba4c9bSIgal Liberman tmp = ioread32be(®s->command_config);
39957ba4c9bSIgal Liberman if (new_val)
40057ba4c9bSIgal Liberman tmp |= CMD_CFG_PROMIS_EN;
40157ba4c9bSIgal Liberman else
40257ba4c9bSIgal Liberman tmp &= ~CMD_CFG_PROMIS_EN;
40357ba4c9bSIgal Liberman iowrite32be(tmp, ®s->command_config);
40457ba4c9bSIgal Liberman
40557ba4c9bSIgal Liberman return 0;
40657ba4c9bSIgal Liberman }
40757ba4c9bSIgal Liberman
tgec_set_tx_pause_frames(struct fman_mac * tgec,u8 __maybe_unused priority,u16 pause_time,u16 __maybe_unused thresh_time)4081257c962SSean Anderson static int tgec_set_tx_pause_frames(struct fman_mac *tgec,
4091257c962SSean Anderson u8 __maybe_unused priority, u16 pause_time,
4101257c962SSean Anderson u16 __maybe_unused thresh_time)
41157ba4c9bSIgal Liberman {
41257ba4c9bSIgal Liberman struct tgec_regs __iomem *regs = tgec->regs;
41357ba4c9bSIgal Liberman
41457ba4c9bSIgal Liberman iowrite32be((u32)pause_time, ®s->pause_quant);
41557ba4c9bSIgal Liberman
41657ba4c9bSIgal Liberman return 0;
41757ba4c9bSIgal Liberman }
41857ba4c9bSIgal Liberman
tgec_accept_rx_pause_frames(struct fman_mac * tgec,bool en)4191257c962SSean Anderson static int tgec_accept_rx_pause_frames(struct fman_mac *tgec, bool en)
42057ba4c9bSIgal Liberman {
42157ba4c9bSIgal Liberman struct tgec_regs __iomem *regs = tgec->regs;
42257ba4c9bSIgal Liberman u32 tmp;
42357ba4c9bSIgal Liberman
42457ba4c9bSIgal Liberman tmp = ioread32be(®s->command_config);
42557ba4c9bSIgal Liberman if (!en)
42657ba4c9bSIgal Liberman tmp |= CMD_CFG_PAUSE_IGNORE;
42757ba4c9bSIgal Liberman else
42857ba4c9bSIgal Liberman tmp &= ~CMD_CFG_PAUSE_IGNORE;
42957ba4c9bSIgal Liberman iowrite32be(tmp, ®s->command_config);
43057ba4c9bSIgal Liberman
43157ba4c9bSIgal Liberman return 0;
43257ba4c9bSIgal Liberman }
43357ba4c9bSIgal Liberman
tgec_mac_config(struct phylink_config * config,unsigned int mode,const struct phylink_link_state * state)434*5d93cfcfSSean Anderson static void tgec_mac_config(struct phylink_config *config, unsigned int mode,
435*5d93cfcfSSean Anderson const struct phylink_link_state *state)
436*5d93cfcfSSean Anderson {
437*5d93cfcfSSean Anderson }
438*5d93cfcfSSean Anderson
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)439*5d93cfcfSSean Anderson static void tgec_link_up(struct phylink_config *config, struct phy_device *phy,
440*5d93cfcfSSean Anderson unsigned int mode, phy_interface_t interface,
441*5d93cfcfSSean Anderson int speed, int duplex, bool tx_pause, bool rx_pause)
442*5d93cfcfSSean Anderson {
443*5d93cfcfSSean Anderson struct mac_device *mac_dev = fman_config_to_mac(config);
444*5d93cfcfSSean Anderson struct fman_mac *tgec = mac_dev->fman_mac;
445*5d93cfcfSSean Anderson struct tgec_regs __iomem *regs = tgec->regs;
446*5d93cfcfSSean Anderson u16 pause_time = tx_pause ? FSL_FM_PAUSE_TIME_ENABLE :
447*5d93cfcfSSean Anderson FSL_FM_PAUSE_TIME_DISABLE;
448*5d93cfcfSSean Anderson u32 tmp;
449*5d93cfcfSSean Anderson
450*5d93cfcfSSean Anderson tgec_set_tx_pause_frames(tgec, 0, pause_time, 0);
451*5d93cfcfSSean Anderson tgec_accept_rx_pause_frames(tgec, rx_pause);
452*5d93cfcfSSean Anderson mac_dev->update_speed(mac_dev, speed);
453*5d93cfcfSSean Anderson
454*5d93cfcfSSean Anderson tmp = ioread32be(®s->command_config);
455*5d93cfcfSSean Anderson tmp |= CMD_CFG_RX_EN | CMD_CFG_TX_EN;
456*5d93cfcfSSean Anderson iowrite32be(tmp, ®s->command_config);
457*5d93cfcfSSean Anderson }
458*5d93cfcfSSean Anderson
tgec_link_down(struct phylink_config * config,unsigned int mode,phy_interface_t interface)459*5d93cfcfSSean Anderson static void tgec_link_down(struct phylink_config *config, unsigned int mode,
460*5d93cfcfSSean Anderson phy_interface_t interface)
461*5d93cfcfSSean Anderson {
462*5d93cfcfSSean Anderson struct fman_mac *tgec = fman_config_to_mac(config)->fman_mac;
463*5d93cfcfSSean Anderson struct tgec_regs __iomem *regs = tgec->regs;
464*5d93cfcfSSean Anderson u32 tmp;
465*5d93cfcfSSean Anderson
466*5d93cfcfSSean Anderson tmp = ioread32be(®s->command_config);
467*5d93cfcfSSean Anderson tmp &= ~(CMD_CFG_RX_EN | CMD_CFG_TX_EN);
468*5d93cfcfSSean Anderson iowrite32be(tmp, ®s->command_config);
469*5d93cfcfSSean Anderson }
470*5d93cfcfSSean Anderson
471*5d93cfcfSSean Anderson static const struct phylink_mac_ops tgec_mac_ops = {
472*5d93cfcfSSean Anderson .mac_config = tgec_mac_config,
473*5d93cfcfSSean Anderson .mac_link_up = tgec_link_up,
474*5d93cfcfSSean Anderson .mac_link_down = tgec_link_down,
475*5d93cfcfSSean Anderson };
476*5d93cfcfSSean Anderson
tgec_modify_mac_address(struct fman_mac * tgec,const enet_addr_t * p_enet_addr)4771257c962SSean Anderson static int tgec_modify_mac_address(struct fman_mac *tgec,
4781257c962SSean Anderson const enet_addr_t *p_enet_addr)
47957ba4c9bSIgal Liberman {
48057ba4c9bSIgal Liberman tgec->addr = ENET_ADDR_TO_UINT64(*p_enet_addr);
48176660757SJakub Kicinski set_mac_address(tgec->regs, (const u8 *)(*p_enet_addr));
48257ba4c9bSIgal Liberman
48357ba4c9bSIgal Liberman return 0;
48457ba4c9bSIgal Liberman }
48557ba4c9bSIgal Liberman
tgec_add_hash_mac_address(struct fman_mac * tgec,enet_addr_t * eth_addr)4861257c962SSean Anderson static int tgec_add_hash_mac_address(struct fman_mac *tgec,
4871257c962SSean Anderson enet_addr_t *eth_addr)
48857ba4c9bSIgal Liberman {
48957ba4c9bSIgal Liberman struct tgec_regs __iomem *regs = tgec->regs;
49057ba4c9bSIgal Liberman struct eth_hash_entry *hash_entry;
49157ba4c9bSIgal Liberman u32 crc = 0xFFFFFFFF, hash;
49257ba4c9bSIgal Liberman u64 addr;
49357ba4c9bSIgal Liberman
49457ba4c9bSIgal Liberman addr = ENET_ADDR_TO_UINT64(*eth_addr);
49557ba4c9bSIgal Liberman
49657ba4c9bSIgal Liberman if (!(addr & GROUP_ADDRESS)) {
49757ba4c9bSIgal Liberman /* Unicast addresses not supported in hash */
49857ba4c9bSIgal Liberman pr_err("Unicast Address\n");
49957ba4c9bSIgal Liberman return -EINVAL;
50057ba4c9bSIgal Liberman }
50157ba4c9bSIgal Liberman /* CRC calculation */
50257ba4c9bSIgal Liberman crc = crc32_le(crc, (u8 *)eth_addr, ETH_ALEN);
50357ba4c9bSIgal Liberman crc = bitrev32(crc);
50457ba4c9bSIgal Liberman /* Take 9 MSB bits */
50557ba4c9bSIgal Liberman hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK;
50657ba4c9bSIgal Liberman
50757ba4c9bSIgal Liberman /* Create element to be added to the driver hash table */
5080d9c9a23SScott Wood hash_entry = kmalloc(sizeof(*hash_entry), GFP_ATOMIC);
50957ba4c9bSIgal Liberman if (!hash_entry)
51057ba4c9bSIgal Liberman return -ENOMEM;
51157ba4c9bSIgal Liberman hash_entry->addr = addr;
51257ba4c9bSIgal Liberman INIT_LIST_HEAD(&hash_entry->node);
51357ba4c9bSIgal Liberman
51457ba4c9bSIgal Liberman list_add_tail(&hash_entry->node,
51557ba4c9bSIgal Liberman &tgec->multicast_addr_hash->lsts[hash]);
51657ba4c9bSIgal Liberman iowrite32be((hash | TGEC_HASH_MCAST_EN), ®s->hashtable_ctrl);
51757ba4c9bSIgal Liberman
51857ba4c9bSIgal Liberman return 0;
51957ba4c9bSIgal Liberman }
52057ba4c9bSIgal Liberman
tgec_set_allmulti(struct fman_mac * tgec,bool enable)5211257c962SSean Anderson static int tgec_set_allmulti(struct fman_mac *tgec, bool enable)
522c893238eSRadu Bulie {
523c893238eSRadu Bulie u32 entry;
524c893238eSRadu Bulie struct tgec_regs __iomem *regs = tgec->regs;
525c893238eSRadu Bulie
526c893238eSRadu Bulie if (enable) {
527c893238eSRadu Bulie for (entry = 0; entry < TGEC_HASH_TABLE_SIZE; entry++)
528c893238eSRadu Bulie iowrite32be(entry | TGEC_HASH_MCAST_EN,
529c893238eSRadu Bulie ®s->hashtable_ctrl);
530c893238eSRadu Bulie } else {
531c893238eSRadu Bulie for (entry = 0; entry < TGEC_HASH_TABLE_SIZE; entry++)
532c893238eSRadu Bulie iowrite32be(entry & ~TGEC_HASH_MCAST_EN,
533c893238eSRadu Bulie ®s->hashtable_ctrl);
534c893238eSRadu Bulie }
535c893238eSRadu Bulie
536c893238eSRadu Bulie tgec->allmulti_enabled = enable;
537c893238eSRadu Bulie
538c893238eSRadu Bulie return 0;
539c893238eSRadu Bulie }
540c893238eSRadu Bulie
tgec_set_tstamp(struct fman_mac * tgec,bool enable)5411257c962SSean Anderson static int tgec_set_tstamp(struct fman_mac *tgec, bool enable)
5420fab782aSYangbo Lu {
5430fab782aSYangbo Lu struct tgec_regs __iomem *regs = tgec->regs;
5440fab782aSYangbo Lu u32 tmp;
5450fab782aSYangbo Lu
5460fab782aSYangbo Lu tmp = ioread32be(®s->command_config);
5470fab782aSYangbo Lu
5480fab782aSYangbo Lu if (enable)
5490fab782aSYangbo Lu tmp |= CMD_CFG_EN_TIMESTAMP;
5500fab782aSYangbo Lu else
5510fab782aSYangbo Lu tmp &= ~CMD_CFG_EN_TIMESTAMP;
5520fab782aSYangbo Lu
5530fab782aSYangbo Lu iowrite32be(tmp, ®s->command_config);
5540fab782aSYangbo Lu
5550fab782aSYangbo Lu return 0;
5560fab782aSYangbo Lu }
5570fab782aSYangbo Lu
tgec_del_hash_mac_address(struct fman_mac * tgec,enet_addr_t * eth_addr)5581257c962SSean Anderson static int tgec_del_hash_mac_address(struct fman_mac *tgec,
5591257c962SSean Anderson enet_addr_t *eth_addr)
56057ba4c9bSIgal Liberman {
56157ba4c9bSIgal Liberman struct tgec_regs __iomem *regs = tgec->regs;
56257ba4c9bSIgal Liberman struct eth_hash_entry *hash_entry = NULL;
56357ba4c9bSIgal Liberman struct list_head *pos;
56457ba4c9bSIgal Liberman u32 crc = 0xFFFFFFFF, hash;
56557ba4c9bSIgal Liberman u64 addr;
56657ba4c9bSIgal Liberman
56757ba4c9bSIgal Liberman addr = ((*(u64 *)eth_addr) >> 16);
56857ba4c9bSIgal Liberman
56957ba4c9bSIgal Liberman /* CRC calculation */
57057ba4c9bSIgal Liberman crc = crc32_le(crc, (u8 *)eth_addr, ETH_ALEN);
57157ba4c9bSIgal Liberman crc = bitrev32(crc);
57257ba4c9bSIgal Liberman /* Take 9 MSB bits */
57357ba4c9bSIgal Liberman hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK;
57457ba4c9bSIgal Liberman
57557ba4c9bSIgal Liberman list_for_each(pos, &tgec->multicast_addr_hash->lsts[hash]) {
57657ba4c9bSIgal Liberman hash_entry = ETH_HASH_ENTRY_OBJ(pos);
577cc5d229aSFlorinel Iordache if (hash_entry && hash_entry->addr == addr) {
57857ba4c9bSIgal Liberman list_del_init(&hash_entry->node);
57957ba4c9bSIgal Liberman kfree(hash_entry);
58057ba4c9bSIgal Liberman break;
58157ba4c9bSIgal Liberman }
58257ba4c9bSIgal Liberman }
583c893238eSRadu Bulie
584c893238eSRadu Bulie if (!tgec->allmulti_enabled) {
58557ba4c9bSIgal Liberman if (list_empty(&tgec->multicast_addr_hash->lsts[hash]))
58657ba4c9bSIgal Liberman iowrite32be((hash & ~TGEC_HASH_MCAST_EN),
58757ba4c9bSIgal Liberman ®s->hashtable_ctrl);
588c893238eSRadu Bulie }
58957ba4c9bSIgal Liberman
59057ba4c9bSIgal Liberman return 0;
59157ba4c9bSIgal Liberman }
59257ba4c9bSIgal Liberman
tgec_set_exception(struct fman_mac * tgec,enum fman_mac_exceptions exception,bool enable)5931257c962SSean Anderson static int tgec_set_exception(struct fman_mac *tgec,
59457ba4c9bSIgal Liberman enum fman_mac_exceptions exception, bool enable)
59557ba4c9bSIgal Liberman {
59657ba4c9bSIgal Liberman struct tgec_regs __iomem *regs = tgec->regs;
59757ba4c9bSIgal Liberman u32 bit_mask = 0;
59857ba4c9bSIgal Liberman
59957ba4c9bSIgal Liberman bit_mask = get_exception_flag(exception);
60057ba4c9bSIgal Liberman if (bit_mask) {
60157ba4c9bSIgal Liberman if (enable)
60257ba4c9bSIgal Liberman tgec->exceptions |= bit_mask;
60357ba4c9bSIgal Liberman else
60457ba4c9bSIgal Liberman tgec->exceptions &= ~bit_mask;
60557ba4c9bSIgal Liberman } else {
60657ba4c9bSIgal Liberman pr_err("Undefined exception\n");
60757ba4c9bSIgal Liberman return -EINVAL;
60857ba4c9bSIgal Liberman }
60957ba4c9bSIgal Liberman if (enable)
61057ba4c9bSIgal Liberman iowrite32be(ioread32be(®s->imask) | bit_mask, ®s->imask);
61157ba4c9bSIgal Liberman else
61257ba4c9bSIgal Liberman iowrite32be(ioread32be(®s->imask) & ~bit_mask, ®s->imask);
61357ba4c9bSIgal Liberman
61457ba4c9bSIgal Liberman return 0;
61557ba4c9bSIgal Liberman }
61657ba4c9bSIgal Liberman
tgec_init(struct fman_mac * tgec)6171257c962SSean Anderson static int tgec_init(struct fman_mac *tgec)
61857ba4c9bSIgal Liberman {
61957ba4c9bSIgal Liberman struct tgec_cfg *cfg;
62057ba4c9bSIgal Liberman enet_addr_t eth_addr;
62157ba4c9bSIgal Liberman int err;
62257ba4c9bSIgal Liberman
62357ba4c9bSIgal Liberman if (DEFAULT_RESET_ON_INIT &&
62457ba4c9bSIgal Liberman (fman_reset_mac(tgec->fm, tgec->mac_id) != 0)) {
62557ba4c9bSIgal Liberman pr_err("Can't reset MAC!\n");
62657ba4c9bSIgal Liberman return -EINVAL;
62757ba4c9bSIgal Liberman }
62857ba4c9bSIgal Liberman
62957ba4c9bSIgal Liberman err = check_init_parameters(tgec);
63057ba4c9bSIgal Liberman if (err)
63157ba4c9bSIgal Liberman return err;
63257ba4c9bSIgal Liberman
63357ba4c9bSIgal Liberman cfg = tgec->cfg;
63457ba4c9bSIgal Liberman
635f3353b99SMadalin Bucur if (tgec->addr) {
63657ba4c9bSIgal Liberman MAKE_ENET_ADDR_FROM_UINT64(tgec->addr, eth_addr);
63776660757SJakub Kicinski set_mac_address(tgec->regs, (const u8 *)eth_addr);
638f3353b99SMadalin Bucur }
63957ba4c9bSIgal Liberman
64057ba4c9bSIgal Liberman /* interrupts */
64157ba4c9bSIgal Liberman /* FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005 Errata workaround */
64257ba4c9bSIgal Liberman if (tgec->fm_rev_info.major <= 2)
64357ba4c9bSIgal Liberman tgec->exceptions &= ~(TGEC_IMASK_REM_FAULT |
64457ba4c9bSIgal Liberman TGEC_IMASK_LOC_FAULT);
64557ba4c9bSIgal Liberman
64657ba4c9bSIgal Liberman err = init(tgec->regs, cfg, tgec->exceptions);
64757ba4c9bSIgal Liberman if (err) {
64857ba4c9bSIgal Liberman free_init_resources(tgec);
64957ba4c9bSIgal Liberman pr_err("TGEC version doesn't support this i/f mode\n");
65057ba4c9bSIgal Liberman return err;
65157ba4c9bSIgal Liberman }
65257ba4c9bSIgal Liberman
65357ba4c9bSIgal Liberman /* Max Frame Length */
65457ba4c9bSIgal Liberman err = fman_set_mac_max_frame(tgec->fm, tgec->mac_id,
65557ba4c9bSIgal Liberman cfg->max_frame_length);
65657ba4c9bSIgal Liberman if (err) {
65757ba4c9bSIgal Liberman pr_err("Setting max frame length FAILED\n");
65857ba4c9bSIgal Liberman free_init_resources(tgec);
65957ba4c9bSIgal Liberman return -EINVAL;
66057ba4c9bSIgal Liberman }
66157ba4c9bSIgal Liberman
66257ba4c9bSIgal Liberman /* FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 Errata workaround */
66357ba4c9bSIgal Liberman if (tgec->fm_rev_info.major == 2) {
66457ba4c9bSIgal Liberman struct tgec_regs __iomem *regs = tgec->regs;
66557ba4c9bSIgal Liberman u32 tmp;
66657ba4c9bSIgal Liberman
66757ba4c9bSIgal Liberman /* restore the default tx ipg Length */
66857ba4c9bSIgal Liberman tmp = (ioread32be(®s->tx_ipg_len) &
66957ba4c9bSIgal Liberman ~TGEC_TX_IPG_LENGTH_MASK) | 12;
67057ba4c9bSIgal Liberman
67157ba4c9bSIgal Liberman iowrite32be(tmp, ®s->tx_ipg_len);
67257ba4c9bSIgal Liberman }
67357ba4c9bSIgal Liberman
67457ba4c9bSIgal Liberman tgec->multicast_addr_hash = alloc_hash_table(TGEC_HASH_TABLE_SIZE);
67557ba4c9bSIgal Liberman if (!tgec->multicast_addr_hash) {
67657ba4c9bSIgal Liberman free_init_resources(tgec);
67757ba4c9bSIgal Liberman pr_err("allocation hash table is FAILED\n");
67857ba4c9bSIgal Liberman return -ENOMEM;
67957ba4c9bSIgal Liberman }
68057ba4c9bSIgal Liberman
68157ba4c9bSIgal Liberman tgec->unicast_addr_hash = alloc_hash_table(TGEC_HASH_TABLE_SIZE);
68257ba4c9bSIgal Liberman if (!tgec->unicast_addr_hash) {
68357ba4c9bSIgal Liberman free_init_resources(tgec);
68457ba4c9bSIgal Liberman pr_err("allocation hash table is FAILED\n");
68557ba4c9bSIgal Liberman return -ENOMEM;
68657ba4c9bSIgal Liberman }
68757ba4c9bSIgal Liberman
68857ba4c9bSIgal Liberman fman_register_intr(tgec->fm, FMAN_MOD_MAC, tgec->mac_id,
68957ba4c9bSIgal Liberman FMAN_INTR_TYPE_ERR, tgec_err_exception, tgec);
69057ba4c9bSIgal Liberman
69157ba4c9bSIgal Liberman kfree(cfg);
69257ba4c9bSIgal Liberman tgec->cfg = NULL;
69357ba4c9bSIgal Liberman
69457ba4c9bSIgal Liberman return 0;
69557ba4c9bSIgal Liberman }
69657ba4c9bSIgal Liberman
tgec_free(struct fman_mac * tgec)6971257c962SSean Anderson static int tgec_free(struct fman_mac *tgec)
69857ba4c9bSIgal Liberman {
69957ba4c9bSIgal Liberman free_init_resources(tgec);
70057ba4c9bSIgal Liberman
70157ba4c9bSIgal Liberman kfree(tgec->cfg);
70257ba4c9bSIgal Liberman kfree(tgec);
70357ba4c9bSIgal Liberman
70457ba4c9bSIgal Liberman return 0;
70557ba4c9bSIgal Liberman }
70657ba4c9bSIgal Liberman
tgec_config(struct mac_device * mac_dev,struct fman_mac_params * params)7075b6acb55SSean Anderson static struct fman_mac *tgec_config(struct mac_device *mac_dev,
7085b6acb55SSean Anderson struct fman_mac_params *params)
70957ba4c9bSIgal Liberman {
71057ba4c9bSIgal Liberman struct fman_mac *tgec;
71157ba4c9bSIgal Liberman struct tgec_cfg *cfg;
71257ba4c9bSIgal Liberman
71357ba4c9bSIgal Liberman /* allocate memory for the UCC GETH data structure. */
71457ba4c9bSIgal Liberman tgec = kzalloc(sizeof(*tgec), GFP_KERNEL);
71557ba4c9bSIgal Liberman if (!tgec)
71657ba4c9bSIgal Liberman return NULL;
71757ba4c9bSIgal Liberman
71857ba4c9bSIgal Liberman /* allocate memory for the 10G MAC driver parameters data structure. */
71957ba4c9bSIgal Liberman cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
72057ba4c9bSIgal Liberman if (!cfg) {
72157ba4c9bSIgal Liberman tgec_free(tgec);
72257ba4c9bSIgal Liberman return NULL;
72357ba4c9bSIgal Liberman }
72457ba4c9bSIgal Liberman
72557ba4c9bSIgal Liberman /* Plant parameter structure pointer */
72657ba4c9bSIgal Liberman tgec->cfg = cfg;
72757ba4c9bSIgal Liberman
72857ba4c9bSIgal Liberman set_dflts(cfg);
72957ba4c9bSIgal Liberman
73019c788b1SSean Anderson tgec->regs = mac_dev->vaddr;
73119c788b1SSean Anderson tgec->addr = ENET_ADDR_TO_UINT64(mac_dev->addr);
73257ba4c9bSIgal Liberman tgec->mac_id = params->mac_id;
73357ba4c9bSIgal Liberman tgec->exceptions = (TGEC_IMASK_MDIO_SCAN_EVENT |
73457ba4c9bSIgal Liberman TGEC_IMASK_REM_FAULT |
73557ba4c9bSIgal Liberman TGEC_IMASK_LOC_FAULT |
73657ba4c9bSIgal Liberman TGEC_IMASK_TX_ECC_ER |
73757ba4c9bSIgal Liberman TGEC_IMASK_TX_FIFO_UNFL |
73857ba4c9bSIgal Liberman TGEC_IMASK_TX_FIFO_OVFL |
73957ba4c9bSIgal Liberman TGEC_IMASK_TX_ER |
74057ba4c9bSIgal Liberman TGEC_IMASK_RX_FIFO_OVFL |
74157ba4c9bSIgal Liberman TGEC_IMASK_RX_ECC_ER |
74257ba4c9bSIgal Liberman TGEC_IMASK_RX_JAB_FRM |
74357ba4c9bSIgal Liberman TGEC_IMASK_RX_OVRSZ_FRM |
74457ba4c9bSIgal Liberman TGEC_IMASK_RX_RUNT_FRM |
74557ba4c9bSIgal Liberman TGEC_IMASK_RX_FRAG_FRM |
74657ba4c9bSIgal Liberman TGEC_IMASK_RX_CRC_ER |
74757ba4c9bSIgal Liberman TGEC_IMASK_RX_ALIGN_ER);
74857ba4c9bSIgal Liberman tgec->exception_cb = params->exception_cb;
74957ba4c9bSIgal Liberman tgec->event_cb = params->event_cb;
75019c788b1SSean Anderson tgec->dev_id = mac_dev;
75157ba4c9bSIgal Liberman tgec->fm = params->fm;
75257ba4c9bSIgal Liberman
75357ba4c9bSIgal Liberman /* Save FMan revision */
75457ba4c9bSIgal Liberman fman_get_revision(tgec->fm, &tgec->fm_rev_info);
75557ba4c9bSIgal Liberman
75657ba4c9bSIgal Liberman return tgec;
75757ba4c9bSIgal Liberman }
758302376feSSean Anderson
tgec_initialization(struct mac_device * mac_dev,struct device_node * mac_node,struct fman_mac_params * params)759302376feSSean Anderson int tgec_initialization(struct mac_device *mac_dev,
760c6b7b1b5SSean Anderson struct device_node *mac_node,
761c6b7b1b5SSean Anderson struct fman_mac_params *params)
762302376feSSean Anderson {
763302376feSSean Anderson int err;
76444988627SSean Anderson struct fman_mac *tgec;
765302376feSSean Anderson
766*5d93cfcfSSean Anderson mac_dev->phylink_ops = &tgec_mac_ops;
767302376feSSean Anderson mac_dev->set_promisc = tgec_set_promiscuous;
768302376feSSean Anderson mac_dev->change_addr = tgec_modify_mac_address;
769302376feSSean Anderson mac_dev->add_hash_mac_addr = tgec_add_hash_mac_address;
770302376feSSean Anderson mac_dev->remove_hash_mac_addr = tgec_del_hash_mac_address;
771302376feSSean Anderson mac_dev->set_exception = tgec_set_exception;
772302376feSSean Anderson mac_dev->set_allmulti = tgec_set_allmulti;
773302376feSSean Anderson mac_dev->set_tstamp = tgec_set_tstamp;
774302376feSSean Anderson mac_dev->set_multi = fman_set_multi;
775302376feSSean Anderson mac_dev->enable = tgec_enable;
776302376feSSean Anderson mac_dev->disable = tgec_disable;
777302376feSSean Anderson
77819c788b1SSean Anderson mac_dev->fman_mac = tgec_config(mac_dev, params);
779302376feSSean Anderson if (!mac_dev->fman_mac) {
780302376feSSean Anderson err = -EINVAL;
781302376feSSean Anderson goto _return;
782302376feSSean Anderson }
783302376feSSean Anderson
784*5d93cfcfSSean Anderson /* The internal connection to the serdes is XGMII, but this isn't
785*5d93cfcfSSean Anderson * really correct for the phy mode (which is the external connection).
786*5d93cfcfSSean Anderson * However, this is how all older device trees say that they want
787*5d93cfcfSSean Anderson * XAUI, so just convert it for them.
788*5d93cfcfSSean Anderson */
789*5d93cfcfSSean Anderson if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII)
790*5d93cfcfSSean Anderson mac_dev->phy_if = PHY_INTERFACE_MODE_XAUI;
791*5d93cfcfSSean Anderson
792*5d93cfcfSSean Anderson __set_bit(PHY_INTERFACE_MODE_XAUI,
793*5d93cfcfSSean Anderson mac_dev->phylink_config.supported_interfaces);
794*5d93cfcfSSean Anderson mac_dev->phylink_config.mac_capabilities =
795*5d93cfcfSSean Anderson MAC_SYM_PAUSE | MAC_ASYM_PAUSE | MAC_10000FD;
796*5d93cfcfSSean Anderson
79744988627SSean Anderson tgec = mac_dev->fman_mac;
79844988627SSean Anderson tgec->cfg->max_frame_length = fman_get_max_frm();
79944988627SSean Anderson err = tgec_init(tgec);
800302376feSSean Anderson if (err < 0)
801302376feSSean Anderson goto _return_fm_mac_free;
802302376feSSean Anderson
803302376feSSean Anderson /* For 10G MAC, disable Tx ECC exception */
80444988627SSean Anderson err = tgec_set_exception(tgec, FM_MAC_EX_10G_TX_ECC_ER, false);
805302376feSSean Anderson if (err < 0)
806302376feSSean Anderson goto _return_fm_mac_free;
807302376feSSean Anderson
80844988627SSean Anderson pr_info("FMan XGEC version: 0x%08x\n",
80944988627SSean Anderson ioread32be(&tgec->regs->tgec_id));
810302376feSSean Anderson goto _return;
811302376feSSean Anderson
812302376feSSean Anderson _return_fm_mac_free:
813302376feSSean Anderson tgec_free(mac_dev->fman_mac);
814302376feSSean Anderson
815302376feSSean Anderson _return:
816302376feSSean Anderson return err;
817302376feSSean Anderson }
818