|
@@ -864,6 +864,194 @@ static int liquidio_stop(struct net_device *netdev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * \brief Converts a mask based on net device flags
|
|
|
+ * @param netdev network device
|
|
|
+ *
|
|
|
+ * This routine generates a octnet_ifflags mask from the net device flags
|
|
|
+ * received from the OS.
|
|
|
+ */
|
|
|
+static enum octnet_ifflags get_new_flags(struct net_device *netdev)
|
|
|
+{
|
|
|
+ enum octnet_ifflags f = OCTNET_IFFLAG_UNICAST;
|
|
|
+
|
|
|
+ if (netdev->flags & IFF_PROMISC)
|
|
|
+ f |= OCTNET_IFFLAG_PROMISC;
|
|
|
+
|
|
|
+ if (netdev->flags & IFF_ALLMULTI)
|
|
|
+ f |= OCTNET_IFFLAG_ALLMULTI;
|
|
|
+
|
|
|
+ if (netdev->flags & IFF_MULTICAST) {
|
|
|
+ f |= OCTNET_IFFLAG_MULTICAST;
|
|
|
+
|
|
|
+ /* Accept all multicast addresses if there are more than we
|
|
|
+ * can handle
|
|
|
+ */
|
|
|
+ if (netdev_mc_count(netdev) > MAX_OCTEON_MULTICAST_ADDR)
|
|
|
+ f |= OCTNET_IFFLAG_ALLMULTI;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (netdev->flags & IFF_BROADCAST)
|
|
|
+ f |= OCTNET_IFFLAG_BROADCAST;
|
|
|
+
|
|
|
+ return f;
|
|
|
+}
|
|
|
+
|
|
|
+static void liquidio_set_uc_list(struct net_device *netdev)
|
|
|
+{
|
|
|
+ struct lio *lio = GET_LIO(netdev);
|
|
|
+ struct octeon_device *oct = lio->oct_dev;
|
|
|
+ struct octnic_ctrl_pkt nctrl;
|
|
|
+ struct netdev_hw_addr *ha;
|
|
|
+ u64 *mac;
|
|
|
+
|
|
|
+ if (lio->netdev_uc_count == netdev_uc_count(netdev))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (netdev_uc_count(netdev) > MAX_NCTRL_UDD) {
|
|
|
+ dev_err(&oct->pci_dev->dev, "too many MAC addresses in netdev uc list\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ lio->netdev_uc_count = netdev_uc_count(netdev);
|
|
|
+
|
|
|
+ memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));
|
|
|
+ nctrl.ncmd.s.cmd = OCTNET_CMD_SET_UC_LIST;
|
|
|
+ nctrl.ncmd.s.more = lio->netdev_uc_count;
|
|
|
+ nctrl.ncmd.s.param1 = oct->vf_num;
|
|
|
+ nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
|
|
|
+ nctrl.netpndev = (u64)netdev;
|
|
|
+ nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
|
|
|
+
|
|
|
+ /* copy all the addresses into the udd */
|
|
|
+ mac = &nctrl.udd[0];
|
|
|
+ netdev_for_each_uc_addr(ha, netdev) {
|
|
|
+ ether_addr_copy(((u8 *)mac) + 2, ha->addr);
|
|
|
+ mac++;
|
|
|
+ }
|
|
|
+
|
|
|
+ octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * \brief Net device set_multicast_list
|
|
|
+ * @param netdev network device
|
|
|
+ */
|
|
|
+static void liquidio_set_mcast_list(struct net_device *netdev)
|
|
|
+{
|
|
|
+ int mc_count = min(netdev_mc_count(netdev), MAX_OCTEON_MULTICAST_ADDR);
|
|
|
+ struct lio *lio = GET_LIO(netdev);
|
|
|
+ struct octeon_device *oct = lio->oct_dev;
|
|
|
+ struct octnic_ctrl_pkt nctrl;
|
|
|
+ struct netdev_hw_addr *ha;
|
|
|
+ u64 *mc;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));
|
|
|
+
|
|
|
+ /* Create a ctrl pkt command to be sent to core app. */
|
|
|
+ nctrl.ncmd.u64 = 0;
|
|
|
+ nctrl.ncmd.s.cmd = OCTNET_CMD_SET_MULTI_LIST;
|
|
|
+ nctrl.ncmd.s.param1 = get_new_flags(netdev);
|
|
|
+ nctrl.ncmd.s.param2 = mc_count;
|
|
|
+ nctrl.ncmd.s.more = mc_count;
|
|
|
+ nctrl.netpndev = (u64)netdev;
|
|
|
+ nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
|
|
|
+
|
|
|
+ /* copy all the addresses into the udd */
|
|
|
+ mc = &nctrl.udd[0];
|
|
|
+ netdev_for_each_mc_addr(ha, netdev) {
|
|
|
+ *mc = 0;
|
|
|
+ ether_addr_copy(((u8 *)mc) + 2, ha->addr);
|
|
|
+ /* no need to swap bytes */
|
|
|
+ if (++mc > &nctrl.udd[mc_count])
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
|
|
|
+
|
|
|
+ /* Apparently, any activity in this call from the kernel has to
|
|
|
+ * be atomic. So we won't wait for response.
|
|
|
+ */
|
|
|
+ nctrl.wait_time = 0;
|
|
|
+
|
|
|
+ ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(&oct->pci_dev->dev, "DEVFLAGS change failed in core (ret: 0x%x)\n",
|
|
|
+ ret);
|
|
|
+ }
|
|
|
+
|
|
|
+ liquidio_set_uc_list(netdev);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * \brief Net device set_mac_address
|
|
|
+ * @param netdev network device
|
|
|
+ */
|
|
|
+static int liquidio_set_mac(struct net_device *netdev, void *p)
|
|
|
+{
|
|
|
+ struct sockaddr *addr = (struct sockaddr *)p;
|
|
|
+ struct lio *lio = GET_LIO(netdev);
|
|
|
+ struct octeon_device *oct = lio->oct_dev;
|
|
|
+ struct octnic_ctrl_pkt nctrl;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (!is_valid_ether_addr(addr->sa_data))
|
|
|
+ return -EADDRNOTAVAIL;
|
|
|
+
|
|
|
+ if (ether_addr_equal(addr->sa_data, netdev->dev_addr))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (lio->linfo.macaddr_is_admin_asgnd)
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));
|
|
|
+
|
|
|
+ nctrl.ncmd.u64 = 0;
|
|
|
+ nctrl.ncmd.s.cmd = OCTNET_CMD_CHANGE_MACADDR;
|
|
|
+ nctrl.ncmd.s.param1 = 0;
|
|
|
+ nctrl.ncmd.s.more = 1;
|
|
|
+ nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
|
|
|
+ nctrl.netpndev = (u64)netdev;
|
|
|
+ nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
|
|
|
+ nctrl.wait_time = 100;
|
|
|
+
|
|
|
+ nctrl.udd[0] = 0;
|
|
|
+ /* The MAC Address is presented in network byte order. */
|
|
|
+ ether_addr_copy((u8 *)&nctrl.udd[0] + 2, addr->sa_data);
|
|
|
+
|
|
|
+ ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(&oct->pci_dev->dev, "MAC Address change failed\n");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
|
|
|
+ ether_addr_copy(((u8 *)&lio->linfo.hw_addr) + 2, addr->sa_data);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * \brief Net device change_mtu
|
|
|
+ * @param netdev network device
|
|
|
+ */
|
|
|
+static int liquidio_change_mtu(struct net_device *netdev, int new_mtu)
|
|
|
+{
|
|
|
+ struct lio *lio = GET_LIO(netdev);
|
|
|
+ struct octeon_device *oct = lio->oct_dev;
|
|
|
+
|
|
|
+ lio->mtu = new_mtu;
|
|
|
+
|
|
|
+ netif_info(lio, probe, lio->netdev, "MTU Changed from %d to %d\n",
|
|
|
+ netdev->mtu, new_mtu);
|
|
|
+ dev_info(&oct->pci_dev->dev, "%s MTU Changed from %d to %d\n",
|
|
|
+ netdev->name, netdev->mtu, new_mtu);
|
|
|
+
|
|
|
+ netdev->mtu = new_mtu;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/** Sending command to enable/disable RX checksum offload
|
|
|
* @param netdev pointer to network device
|
|
|
* @param command OCTNET_CMD_TNL_RX_CSUM_CTL
|
|
@@ -966,6 +1154,9 @@ static int liquidio_set_features(struct net_device *netdev,
|
|
|
static const struct net_device_ops lionetdevops = {
|
|
|
.ndo_open = liquidio_open,
|
|
|
.ndo_stop = liquidio_stop,
|
|
|
+ .ndo_set_mac_address = liquidio_set_mac,
|
|
|
+ .ndo_set_rx_mode = liquidio_set_mcast_list,
|
|
|
+ .ndo_change_mtu = liquidio_change_mtu,
|
|
|
.ndo_fix_features = liquidio_fix_features,
|
|
|
.ndo_set_features = liquidio_set_features,
|
|
|
.ndo_select_queue = select_q,
|
|
@@ -1165,6 +1356,10 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
|
|
|
|
|
|
netdev->hw_features = lio->dev_capability;
|
|
|
|
|
|
+ /* MTU range: 68 - 16000 */
|
|
|
+ netdev->min_mtu = LIO_MIN_MTU_SIZE;
|
|
|
+ netdev->max_mtu = LIO_MAX_MTU_SIZE;
|
|
|
+
|
|
|
/* Point to the properties for octeon device to which this
|
|
|
* interface belongs.
|
|
|
*/
|