/* Imask include both error and notification/event bits. * Leaving only error bits enabled by imask. * The imask error bits are shifted by 16 bits offset from * their corresponding location in the ievent - hence the >> 16
*/
event &= ((imask & MEMAC_ALL_ERRS_IMASK) >> 16);
iowrite32be(event, ®s->ievent);
if (event & MEMAC_IEVNT_TS_ECC_ER)
memac->exception_cb(memac->dev_id, FM_MAC_EX_TS_FIFO_ECC_ERR); if (event & MEMAC_IEVNT_TX_ECC_ER)
memac->exception_cb(memac->dev_id, FM_MAC_EX_10G_TX_ECC_ER); if (event & MEMAC_IEVNT_RX_ECC_ER)
memac->exception_cb(memac->dev_id, FM_MAC_EX_10G_RX_ECC_ER);
}
/* Imask include both error and notification/event bits. * Leaving only error bits enabled by imask. * The imask error bits are shifted by 16 bits offset from * their corresponding location in the ievent - hence the >> 16
*/
event &= ((imask & MEMAC_ALL_ERRS_IMASK) >> 16);
iowrite32be(event, ®s->ievent);
if (event & MEMAC_IEVNT_MGI)
memac->exception_cb(memac->dev_id,
FM_MAC_EX_MAGIC_PACKET_INDICATION);
}
staticint memac_enable(struct fman_mac *memac)
{ int ret;
ret = phy_init(memac->serdes); if (ret) {
dev_err(memac->dev_id->dev, "could not initialize serdes: %pe\n", ERR_PTR(ret)); return ret;
}
ret = phy_power_on(memac->serdes); if (ret) {
dev_err(memac->dev_id->dev, "could not power on serdes: %pe\n", ERR_PTR(ret));
phy_exit(memac->serdes);
}
if (phy_interface_mode_is_rgmii(interface) &&
memac->rgmii_no_half_duplex)
caps &= ~(MAC_10HD | MAC_100HD);
return caps;
}
/** * memac_if_mode() - Convert an interface mode into an IF_MODE config * @interface: A phy interface mode * * Return: A configuration word, suitable for programming into the lower bits * of %IF_MODE.
*/ static u32 memac_if_mode(phy_interface_t interface)
{ switch (interface) { case PHY_INTERFACE_MODE_MII: return IF_MODE_MII; case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: return IF_MODE_GMII | IF_MODE_RGMII; case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_QSGMII: return IF_MODE_GMII; case PHY_INTERFACE_MODE_10GBASER: return IF_MODE_10G; default:
WARN_ON_ONCE(1); return 0;
}
}
switch (iface) { case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_QSGMII: case PHY_INTERFACE_MODE_10GBASER: return phy_set_mode_ext(memac->serdes, PHY_MODE_ETHERNET,
iface); default: return 0;
}
}
if (!(addr & GROUP_ADDRESS)) { /* Unicast addresses not supported in hash */
pr_err("Unicast Address\n"); return -EINVAL;
}
hash = get_mac_addr_hash_code(addr) & HASH_CTRL_ADDR_MASK;
/* Create element to be added to the driver hash table */
hash_entry = kmalloc(sizeof(*hash_entry), GFP_ATOMIC); if (!hash_entry) return -ENOMEM;
hash_entry->addr = addr;
INIT_LIST_HEAD(&hash_entry->node);
if (!memac->allmulti_enabled) { if (list_empty(&memac->multicast_addr_hash->lsts[hash]))
iowrite32be(hash & ~HASH_CTRL_MCAST_EN,
®s->hashtable_ctrl);
}
err = check_init_parameters(memac); if (err) return err;
memac_drv_param = memac->memac_drv_param;
/* First, reset the MAC if desired. */ if (memac_drv_param->reset_on_init) {
err = reset(memac->regs); if (err) {
pr_err("mEMAC reset failed\n"); return err;
}
}
/* MAC Address */ if (memac->addr != 0) {
MAKE_ENET_ADDR_FROM_UINT64(memac->addr, eth_addr);
add_addr_in_paddr(memac->regs, (const u8 *)eth_addr, 0);
}
/* FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 errata workaround * Exists only in FMan 6.0 and 6.3.
*/ if ((memac->fm_rev_info.major == 6) &&
((memac->fm_rev_info.minor == 0) ||
(memac->fm_rev_info.minor == 3))) { /* MAC strips CRC from received frames - this workaround * should decrease the likelihood of bug appearance
*/
reg32 = ioread32be(&memac->regs->command_config);
reg32 &= ~CMD_CFG_CRC_FWD;
iowrite32be(reg32, &memac->regs->command_config);
}
/* Max Frame Length */
err = fman_set_mac_max_frame(memac->fm, memac->mac_id,
memac_drv_param->max_frame_length); if (err) {
pr_err("settings Mac max frame length is FAILED\n"); return err;
}
memac->multicast_addr_hash = alloc_hash_table(HASH_TABLE_SIZE); if (!memac->multicast_addr_hash) {
free_init_resources(memac);
pr_err("allocation hash table is FAILED\n"); return -ENOMEM;
}
memac->unicast_addr_hash = alloc_hash_table(HASH_TABLE_SIZE); if (!memac->unicast_addr_hash) {
free_init_resources(memac);
pr_err("allocation hash table is FAILED\n"); return -ENOMEM;
}
staticbool memac_supports(struct mac_device *mac_dev, phy_interface_t iface)
{ /* If there's no serdes device, assume that it's been configured for * whatever the default interface mode is.
*/ if (!mac_dev->fman_mac->serdes) return mac_dev->phy_if == iface; /* Otherwise, ask the serdes */ return !phy_validate(mac_dev->fman_mac->serdes, PHY_MODE_ETHERNET,
iface, NULL);
}
/* 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 * 10GBASE-R (aka XFI), so just convert it for them.
*/ if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII)
mac_dev->phy_if = PHY_INTERFACE_MODE_10GBASER;
/* For compatibility, if pcs-handle-names is missing, we assume this * phy is the first one in pcsphy-handle
*/
err = of_property_match_string(mac_node, "pcs-handle-names", "sgmii"); if (err == -EINVAL || err == -ENODATA)
pcs = memac_pcs_create(mac_node, 0); elseif (err < 0) goto _return_fm_mac_free; else
pcs = memac_pcs_create(mac_node, err);
/* If err is set here, it means that pcs-handle-names was missing above * (and therefore that xfi_pcs cannot be set). If we are defaulting to * XGMII, assume this is for XFI. Otherwise, assume it is for SGMII.
*/ if (err && mac_dev->phy_if == PHY_INTERFACE_MODE_10GBASER)
memac->xfi_pcs = pcs; else
memac->sgmii_pcs = pcs;
memac->serdes = devm_of_phy_optional_get(mac_dev->dev, mac_node, "serdes"); if (!memac->serdes) {
dev_dbg(mac_dev->dev, "could not get (optional) serdes\n");
} elseif (IS_ERR(memac->serdes)) {
err = PTR_ERR(memac->serdes); goto _return_fm_mac_free;
}
/* TODO: The following interface modes are supported by (some) hardware * but not by this driver: * - 1000BASE-KX * - 10GBASE-KR * - XAUI/HiGig
*/
supported = mac_dev->phylink_config.supported_interfaces;
/* Note that half duplex is only supported on 10/100M interfaces. */
if (memac->sgmii_pcs &&
memac_supports(mac_dev, PHY_INTERFACE_MODE_2500BASEX))
__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);
if (memac->qsgmii_pcs &&
memac_supports(mac_dev, PHY_INTERFACE_MODE_QSGMII))
__set_bit(PHY_INTERFACE_MODE_QSGMII, supported); elseif (mac_dev->phy_if == PHY_INTERFACE_MODE_QSGMII)
dev_warn(mac_dev->dev, "no QSGMII pcs specified\n");
if (memac->xfi_pcs &&
memac_supports(mac_dev, PHY_INTERFACE_MODE_10GBASER)) {
__set_bit(PHY_INTERFACE_MODE_10GBASER, supported);
} else { /* From what I can tell, no 10g macs support RGMII. */
phy_interface_set_rgmii(supported);
__set_bit(PHY_INTERFACE_MODE_MII, supported);
}
/* These SoCs don't support half duplex at all; there's no different * FMan version or compatible, so we just have to check the machine * compatible instead
*/ if (of_machine_is_compatible("fsl,ls1043a") ||
of_machine_is_compatible("fsl,ls1046a") ||
of_machine_is_compatible("fsl,B4QDS"))
capabilities &= ~(MAC_10HD | MAC_100HD);
/* The T2080 and T4240 don't support half duplex RGMII. There is no * other way to identify these SoCs, so just use the machine * compatible.
*/ if (of_machine_is_compatible("fsl,T2080QDS") ||
of_machine_is_compatible("fsl,T2080RDB") ||
of_machine_is_compatible("fsl,T2081QDS") ||
of_machine_is_compatible("fsl,T4240QDS") ||
of_machine_is_compatible("fsl,T4240RDB"))
memac->rgmii_no_half_duplex = true;
/* Most boards should use MLO_AN_INBAND, but existing boards don't have * a managed property. Default to MLO_AN_INBAND rather than MLO_AN_PHY. * Phylink will allow this to be overriden by a fixed link. We need to * be careful and not enable this if we are using MII or RGMII, since * those configurations modes don't use in-band autonegotiation.
*/ if (!of_property_present(mac_node, "managed") &&
mac_dev->phy_if != PHY_INTERFACE_MODE_MII &&
!phy_interface_mode_is_rgmii(mac_dev->phy_if))
mac_dev->phylink_config.default_an_inband = true;
err = memac_init(mac_dev->fman_mac); if (err < 0) goto _return_fm_mac_free;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.