Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux-2.6-microblaze.git] / drivers / net / ethernet / broadcom / bnxt / bnxt.c
index 8bc7e49..0bb9d7b 100644 (file)
@@ -1,7 +1,7 @@
 /* Broadcom NetXtreme-C/E network driver.
  *
  * Copyright (c) 2014-2016 Broadcom Corporation
- * Copyright (c) 2016-2018 Broadcom Limited
+ * Copyright (c) 2016-2019 Broadcom Limited
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,6 +31,7 @@
 #include <asm/page.h>
 #include <linux/time.h>
 #include <linux/mii.h>
+#include <linux/mdio.h>
 #include <linux/if.h>
 #include <linux/if_vlan.h>
 #include <linux/if_bridge.h>
@@ -112,6 +113,7 @@ enum board_idx {
        BCM57454,
        BCM5745x_NPAR,
        BCM57508,
+       BCM57504,
        BCM58802,
        BCM58804,
        BCM58808,
@@ -155,6 +157,7 @@ static const struct {
        [BCM57454] = { "Broadcom BCM57454 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb Ethernet" },
        [BCM5745x_NPAR] = { "Broadcom BCM5745x NetXtreme-E Ethernet Partition" },
        [BCM57508] = { "Broadcom BCM57508 NetXtreme-E 10Gb/25Gb/50Gb/100Gb/200Gb Ethernet" },
+       [BCM57504] = { "Broadcom BCM57504 NetXtreme-E 10Gb/25Gb/50Gb/100Gb/200Gb Ethernet" },
        [BCM58802] = { "Broadcom BCM58802 NetXtreme-S 10Gb/25Gb/40Gb/50Gb Ethernet" },
        [BCM58804] = { "Broadcom BCM58804 NetXtreme-S 10Gb/25Gb/40Gb/50Gb/100Gb Ethernet" },
        [BCM58808] = { "Broadcom BCM58808 NetXtreme-S 10Gb/25Gb/40Gb/50Gb/100Gb Ethernet" },
@@ -201,6 +204,7 @@ static const struct pci_device_id bnxt_pci_tbl[] = {
        { PCI_VDEVICE(BROADCOM, 0x16f0), .driver_data = BCM58808 },
        { PCI_VDEVICE(BROADCOM, 0x16f1), .driver_data = BCM57452 },
        { PCI_VDEVICE(BROADCOM, 0x1750), .driver_data = BCM57508 },
+       { PCI_VDEVICE(BROADCOM, 0x1751), .driver_data = BCM57504 },
        { PCI_VDEVICE(BROADCOM, 0xd802), .driver_data = BCM58802 },
        { PCI_VDEVICE(BROADCOM, 0xd804), .driver_data = BCM58804 },
 #ifdef CONFIG_BNXT_SRIOV
@@ -500,6 +504,12 @@ normal_tx:
        }
 
        length >>= 9;
+       if (unlikely(length >= ARRAY_SIZE(bnxt_lhint_arr))) {
+               dev_warn_ratelimited(&pdev->dev, "Dropped oversize %d bytes TX packet.\n",
+                                    skb->len);
+               i = 0;
+               goto tx_dma_error;
+       }
        flags |= bnxt_lhint_arr[length];
        txbd->tx_bd_len_flags_type = cpu_to_le32(flags);
 
@@ -3903,7 +3913,7 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,
                        if (len)
                                break;
                        /* on first few passes, just barely sleep */
-                       if (i < DFLT_HWRM_CMD_TIMEOUT)
+                       if (i < HWRM_SHORT_TIMEOUT_COUNTER)
                                usleep_range(HWRM_SHORT_MIN_TIMEOUT,
                                             HWRM_SHORT_MAX_TIMEOUT);
                        else
@@ -3926,7 +3936,7 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,
                        dma_rmb();
                        if (*valid)
                                break;
-                       udelay(1);
+                       usleep_range(1, 5);
                }
 
                if (j >= HWRM_VALID_BIT_DELAY_USEC) {
@@ -6680,6 +6690,10 @@ static int bnxt_hwrm_ver_get(struct bnxt *bp)
            VER_GET_RESP_DEV_CAPS_CFG_FLOW_HANDLE_64BIT_SUPPORTED)
                bp->fw_cap |= BNXT_FW_CAP_OVS_64BIT_HANDLE;
 
+       if (dev_caps_cfg &
+           VER_GET_RESP_DEV_CAPS_CFG_TRUSTED_VF_SUPPORTED)
+               bp->fw_cap |= BNXT_FW_CAP_TRUSTED_VF;
+
 hwrm_ver_get_exit:
        mutex_unlock(&bp->hwrm_cmd_lock);
        return rc;
@@ -8614,24 +8628,88 @@ static int bnxt_close(struct net_device *dev)
        return 0;
 }
 
+static int bnxt_hwrm_port_phy_read(struct bnxt *bp, u16 phy_addr, u16 reg,
+                                  u16 *val)
+{
+       struct hwrm_port_phy_mdio_read_output *resp = bp->hwrm_cmd_resp_addr;
+       struct hwrm_port_phy_mdio_read_input req = {0};
+       int rc;
+
+       if (bp->hwrm_spec_code < 0x10a00)
+               return -EOPNOTSUPP;
+
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_MDIO_READ, -1, -1);
+       req.port_id = cpu_to_le16(bp->pf.port_id);
+       req.phy_addr = phy_addr;
+       req.reg_addr = cpu_to_le16(reg & 0x1f);
+       if (bp->link_info.support_speeds & BNXT_LINK_SPEED_MSK_10GB) {
+               req.cl45_mdio = 1;
+               req.phy_addr = mdio_phy_id_prtad(phy_addr);
+               req.dev_addr = mdio_phy_id_devad(phy_addr);
+               req.reg_addr = cpu_to_le16(reg);
+       }
+
+       mutex_lock(&bp->hwrm_cmd_lock);
+       rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+       if (!rc)
+               *val = le16_to_cpu(resp->reg_data);
+       mutex_unlock(&bp->hwrm_cmd_lock);
+       return rc;
+}
+
+static int bnxt_hwrm_port_phy_write(struct bnxt *bp, u16 phy_addr, u16 reg,
+                                   u16 val)
+{
+       struct hwrm_port_phy_mdio_write_input req = {0};
+
+       if (bp->hwrm_spec_code < 0x10a00)
+               return -EOPNOTSUPP;
+
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_MDIO_WRITE, -1, -1);
+       req.port_id = cpu_to_le16(bp->pf.port_id);
+       req.phy_addr = phy_addr;
+       req.reg_addr = cpu_to_le16(reg & 0x1f);
+       if (bp->link_info.support_speeds & BNXT_LINK_SPEED_MSK_10GB) {
+               req.cl45_mdio = 1;
+               req.phy_addr = mdio_phy_id_prtad(phy_addr);
+               req.dev_addr = mdio_phy_id_devad(phy_addr);
+               req.reg_addr = cpu_to_le16(reg);
+       }
+       req.reg_data = cpu_to_le16(val);
+
+       return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+}
+
 /* rtnl_lock held */
 static int bnxt_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
+       struct mii_ioctl_data *mdio = if_mii(ifr);
+       struct bnxt *bp = netdev_priv(dev);
+       int rc;
+
        switch (cmd) {
        case SIOCGMIIPHY:
+               mdio->phy_id = bp->link_info.phy_addr;
+
                /* fallthru */
        case SIOCGMIIREG: {
+               u16 mii_regval = 0;
+
                if (!netif_running(dev))
                        return -EAGAIN;
 
-               return 0;
+               rc = bnxt_hwrm_port_phy_read(bp, mdio->phy_id, mdio->reg_num,
+                                            &mii_regval);
+               mdio->val_out = mii_regval;
+               return rc;
        }
 
        case SIOCSMIIREG:
                if (!netif_running(dev))
                        return -EAGAIN;
 
-               return 0;
+               return bnxt_hwrm_port_phy_write(bp, mdio->phy_id, mdio->reg_num,
+                                               mdio->val_in);
 
        default:
                /* do nothing */
@@ -9987,8 +10065,11 @@ static int bnxt_get_phys_port_name(struct net_device *dev, char *buf,
        return 0;
 }
 
-int bnxt_port_attr_get(struct bnxt *bp, struct switchdev_attr *attr)
+int bnxt_get_port_parent_id(struct net_device *dev,
+                           struct netdev_phys_item_id *ppid)
 {
+       struct bnxt *bp = netdev_priv(dev);
+
        if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV)
                return -EOPNOTSUPP;
 
@@ -9996,27 +10077,12 @@ int bnxt_port_attr_get(struct bnxt *bp, struct switchdev_attr *attr)
        if (!BNXT_PF(bp))
                return -EOPNOTSUPP;
 
-       switch (attr->id) {
-       case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
-               attr->u.ppid.id_len = sizeof(bp->switch_id);
-               memcpy(attr->u.ppid.id, bp->switch_id, attr->u.ppid.id_len);
-               break;
-       default:
-               return -EOPNOTSUPP;
-       }
-       return 0;
-}
+       ppid->id_len = sizeof(bp->switch_id);
+       memcpy(ppid->id, bp->switch_id, ppid->id_len);
 
-static int bnxt_swdev_port_attr_get(struct net_device *dev,
-                                   struct switchdev_attr *attr)
-{
-       return bnxt_port_attr_get(netdev_priv(dev), attr);
+       return 0;
 }
 
-static const struct switchdev_ops bnxt_switchdev_ops = {
-       .switchdev_port_attr_get        = bnxt_swdev_port_attr_get
-};
-
 static const struct net_device_ops bnxt_netdev_ops = {
        .ndo_open               = bnxt_open,
        .ndo_start_xmit         = bnxt_start_xmit,
@@ -10048,6 +10114,7 @@ static const struct net_device_ops bnxt_netdev_ops = {
        .ndo_bpf                = bnxt_xdp,
        .ndo_bridge_getlink     = bnxt_bridge_getlink,
        .ndo_bridge_setlink     = bnxt_bridge_setlink,
+       .ndo_get_port_parent_id = bnxt_get_port_parent_id,
        .ndo_get_phys_port_name = bnxt_get_phys_port_name
 };
 
@@ -10406,7 +10473,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        dev->netdev_ops = &bnxt_netdev_ops;
        dev->watchdog_timeo = BNXT_TX_TIMEOUT;
        dev->ethtool_ops = &bnxt_ethtool_ops;
-       SWITCHDEV_SET_OPS(dev, &bnxt_switchdev_ops);
        pci_set_drvdata(pdev, dev);
 
        rc = bnxt_alloc_hwrm_resources(bp);