diff options
Diffstat (limited to 'drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c')
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 288 |
1 files changed, 255 insertions, 33 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 53309f659951..86f92e31e8aa 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -79,6 +79,7 @@ #include "l2t.h" #include "sched.h" #include "cxgb4_tc_u32.h" +#include "cxgb4_ptp.h" char cxgb4_driver_name[] = KBUILD_MODNAME; @@ -824,9 +825,12 @@ static int setup_sge_queues(struct adapter *adap) { int err, i, j; struct sge *s = &adap->sge; - struct sge_uld_rxq_info *rxq_info = s->uld_rxq_info[CXGB4_ULD_RDMA]; + struct sge_uld_rxq_info *rxq_info = NULL; unsigned int cmplqid = 0; + if (is_uld(adap)) + rxq_info = s->uld_rxq_info[CXGB4_ULD_RDMA]; + for_each_port(adap, i) { struct net_device *dev = adap->port[i]; struct port_info *pi = netdev_priv(dev); @@ -840,8 +844,8 @@ static int setup_sge_queues(struct adapter *adap) adap->msi_idx, &q->fl, t4_ethrx_handler, NULL, - t4_get_mps_bg_map(adap, - pi->tx_chan)); + t4_get_tp_ch_map(adap, + pi->tx_chan)); if (err) goto freeout; q->rspq.idx = j; @@ -869,6 +873,14 @@ static int setup_sge_queues(struct adapter *adap) goto freeout; } + if (!is_t4(adap->params.chip)) { + err = t4_sge_alloc_eth_txq(adap, &s->ptptxq, adap->port[0], + netdev_get_tx_queue(adap->port[0], 0) + , s->fw_evtq.cntxt_id); + if (err) + goto freeout; + } + t4_write_reg(adap, is_t4(adap->params.chip) ? MPS_TRC_RSS_CONTROL_A : MPS_T5_TRC_RSS_CONTROL_A, @@ -891,7 +903,7 @@ static u16 cxgb_select_queue(struct net_device *dev, struct sk_buff *skb, * The skb's priority is determined via the VLAN Tag Priority Code * Point field. */ - if (cxgb4_dcb_enabled(dev)) { + if (cxgb4_dcb_enabled(dev) && !is_kdump_kernel()) { u16 vlan_tci; int err; @@ -1093,10 +1105,12 @@ int cxgb4_alloc_stid(struct tid_info *t, int family, void *data) * This is equivalent to 4 TIDs. With CLIP enabled it * needs 2 TIDs. */ - if (family == PF_INET) - t->stids_in_use++; - else + if (family == PF_INET6) { t->stids_in_use += 2; + t->v6_stids_in_use += 2; + } else { + t->stids_in_use++; + } } spin_unlock_bh(&t->stid_lock); return stid; @@ -1150,13 +1164,16 @@ void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family) bitmap_release_region(t->stid_bmap, stid, 1); t->stid_tab[stid].data = NULL; if (stid < t->nstids) { - if (family == PF_INET) - t->stids_in_use--; - else + if (family == PF_INET6) { t->stids_in_use -= 2; + t->v6_stids_in_use -= 2; + } else { + t->stids_in_use--; + } } else { t->sftids_in_use--; } + spin_unlock_bh(&t->stid_lock); } EXPORT_SYMBOL(cxgb4_free_stid); @@ -1170,7 +1187,7 @@ static void mk_tid_release(struct sk_buff *skb, unsigned int chan, struct cpl_tid_release *req; set_wr_txq(skb, CPL_PRIORITY_SETUP, chan); - req = (struct cpl_tid_release *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); INIT_TP_WR(req, tid); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid)); } @@ -1232,7 +1249,8 @@ static void process_tid_release_list(struct work_struct *work) * Release a TID and inform HW. If we are unable to allocate the release * message we defer to a work queue. */ -void cxgb4_remove_tid(struct tid_info *t, unsigned int chan, unsigned int tid) +void cxgb4_remove_tid(struct tid_info *t, unsigned int chan, unsigned int tid, + unsigned short family) { struct sk_buff *skb; struct adapter *adap = container_of(t, struct adapter, tids); @@ -1241,10 +1259,18 @@ void cxgb4_remove_tid(struct tid_info *t, unsigned int chan, unsigned int tid) if (t->tid_tab[tid]) { t->tid_tab[tid] = NULL; - if (t->hash_base && (tid >= t->hash_base)) - atomic_dec(&t->hash_tids_in_use); - else - atomic_dec(&t->tids_in_use); + atomic_dec(&t->conns_in_use); + if (t->hash_base && (tid >= t->hash_base)) { + if (family == AF_INET6) + atomic_sub(2, &t->hash_tids_in_use); + else + atomic_dec(&t->hash_tids_in_use); + } else { + if (family == AF_INET6) + atomic_sub(2, &t->tids_in_use); + else + atomic_dec(&t->tids_in_use); + } } skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC); @@ -1292,10 +1318,12 @@ static int tid_init(struct tid_info *t) spin_lock_init(&t->ftid_lock); t->stids_in_use = 0; + t->v6_stids_in_use = 0; t->sftids_in_use = 0; t->afree = NULL; t->atids_in_use = 0; atomic_set(&t->tids_in_use, 0); + atomic_set(&t->conns_in_use, 0); atomic_set(&t->hash_tids_in_use, 0); /* Setup the free list for atid_tab and clear the stid bitmap. */ @@ -1343,7 +1371,7 @@ int cxgb4_create_server(const struct net_device *dev, unsigned int stid, return -ENOMEM; adap = netdev2adap(dev); - req = (struct cpl_pass_open_req *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); INIT_TP_WR(req, 0); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, stid)); req->local_port = sport; @@ -1384,7 +1412,7 @@ int cxgb4_create_server6(const struct net_device *dev, unsigned int stid, return -ENOMEM; adap = netdev2adap(dev); - req = (struct cpl_pass_open_req6 *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); INIT_TP_WR(req, 0); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ6, stid)); req->local_port = sport; @@ -1416,7 +1444,7 @@ int cxgb4_remove_server(const struct net_device *dev, unsigned int stid, if (!skb) return -ENOMEM; - req = (struct cpl_close_listsvr_req *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); INIT_TP_WR(req, 0); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, stid)); req->reply_ctrl = htons(NO_REPLY_V(0) | (ipv6 ? LISTSVR_IPV6_V(1) : @@ -2251,6 +2279,13 @@ static int cxgb_open(struct net_device *dev) return err; } + /* It's possible that the basic port information could have + * changed since we first read it. + */ + err = t4_update_port_info(pi); + if (err < 0) + return err; + err = link_start(dev); if (!err) netif_tx_start_all_queues(dev); @@ -2412,6 +2447,7 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) unsigned int mbox; int ret = 0, prtad, devad; struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; struct mii_ioctl_data *data = (struct mii_ioctl_data *)&req->ifr_data; switch (cmd) { @@ -2449,18 +2485,69 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) sizeof(pi->tstamp_config))) return -EFAULT; - switch (pi->tstamp_config.rx_filter) { - case HWTSTAMP_FILTER_NONE: + if (!is_t4(adapter->params.chip)) { + switch (pi->tstamp_config.tx_type) { + case HWTSTAMP_TX_OFF: + case HWTSTAMP_TX_ON: + break; + default: + return -ERANGE; + } + + switch (pi->tstamp_config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + pi->rxtstamp = false; + break; + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + cxgb4_ptprx_timestamping(pi, pi->port_id, + PTP_TS_L4); + break; + case HWTSTAMP_FILTER_PTP_V2_EVENT: + cxgb4_ptprx_timestamping(pi, pi->port_id, + PTP_TS_L2_L4); + break; + case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + pi->rxtstamp = true; + break; + default: + pi->tstamp_config.rx_filter = + HWTSTAMP_FILTER_NONE; + return -ERANGE; + } + + if ((pi->tstamp_config.tx_type == HWTSTAMP_TX_OFF) && + (pi->tstamp_config.rx_filter == + HWTSTAMP_FILTER_NONE)) { + if (cxgb4_ptp_txtype(adapter, pi->port_id) >= 0) + pi->ptp_enable = false; + } + + if (pi->tstamp_config.rx_filter != + HWTSTAMP_FILTER_NONE) { + if (cxgb4_ptp_redirect_rx_packet(adapter, + pi) >= 0) + pi->ptp_enable = true; + } + } else { + /* For T4 Adapters */ + switch (pi->tstamp_config.rx_filter) { + case HWTSTAMP_FILTER_NONE: pi->rxtstamp = false; break; - case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_ALL: pi->rxtstamp = true; break; - default: - pi->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; + default: + pi->tstamp_config.rx_filter = + HWTSTAMP_FILTER_NONE; return -ERANGE; + } } - return copy_to_user(req->ifr_data, &pi->tstamp_config, sizeof(pi->tstamp_config)) ? -EFAULT : 0; @@ -2562,6 +2649,8 @@ static int cxgb_get_vf_config(struct net_device *dev, if (vf >= adap->num_vfs) return -EINVAL; ivi->vf = vf; + ivi->max_tx_rate = adap->vfinfo[vf].tx_rate; + ivi->min_tx_rate = 0; ether_addr_copy(ivi->mac, adap->vfinfo[vf].vf_mac_addr); return 0; } @@ -2578,6 +2667,109 @@ static int cxgb_get_phys_port_id(struct net_device *dev, return 0; } +static int cxgb_set_vf_rate(struct net_device *dev, int vf, int min_tx_rate, + int max_tx_rate) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + struct fw_port_cmd port_cmd, port_rpl; + u32 link_status, speed = 0; + u32 fw_pfvf, fw_class; + int class_id = vf; + int link_ok, ret; + u16 pktsize; + + if (vf >= adap->num_vfs) + return -EINVAL; + + if (min_tx_rate) { + dev_err(adap->pdev_dev, + "Min tx rate (%d) (> 0) for VF %d is Invalid.\n", + min_tx_rate, vf); + return -EINVAL; + } + /* Retrieve link details for VF port */ + memset(&port_cmd, 0, sizeof(port_cmd)); + port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_READ_F | + FW_PORT_CMD_PORTID_V(pi->port_id)); + port_cmd.action_to_len16 = + cpu_to_be32(FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_GET_PORT_INFO) | + FW_LEN16(port_cmd)); + ret = t4_wr_mbox(adap, adap->mbox, &port_cmd, sizeof(port_cmd), + &port_rpl); + if (ret != FW_SUCCESS) { + dev_err(adap->pdev_dev, + "Failed to get link status for VF %d\n", vf); + return -EINVAL; + } + link_status = be32_to_cpu(port_rpl.u.info.lstatus_to_modtype); + link_ok = (link_status & FW_PORT_CMD_LSTATUS_F) != 0; + if (!link_ok) { + dev_err(adap->pdev_dev, "Link down for VF %d\n", vf); + return -EINVAL; + } + /* Determine link speed */ + if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M)) + speed = 100; + else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G)) + speed = 1000; + else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G)) + speed = 10000; + else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G)) + speed = 25000; + else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G)) + speed = 40000; + else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G)) + speed = 100000; + + if (max_tx_rate > speed) { + dev_err(adap->pdev_dev, + "Max tx rate %d for VF %d can't be > link-speed %u", + max_tx_rate, vf, speed); + return -EINVAL; + } + pktsize = be16_to_cpu(port_rpl.u.info.mtu); + /* subtract ethhdr size and 4 bytes crc since, f/w appends it */ + pktsize = pktsize - sizeof(struct ethhdr) - 4; + /* subtract ipv4 hdr size, tcp hdr size to get typical IPv4 MSS size */ + pktsize = pktsize - sizeof(struct iphdr) - sizeof(struct tcphdr); + /* configure Traffic Class for rate-limiting */ + ret = t4_sched_params(adap, SCHED_CLASS_TYPE_PACKET, + SCHED_CLASS_LEVEL_CL_RL, + SCHED_CLASS_MODE_CLASS, + SCHED_CLASS_RATEUNIT_BITS, + SCHED_CLASS_RATEMODE_ABS, + pi->port_id, class_id, 0, + max_tx_rate * 1000, 0, pktsize); + if (ret) { + dev_err(adap->pdev_dev, "Err %d for Traffic Class config\n", + ret); + return -EINVAL; + } + dev_info(adap->pdev_dev, + "Class %d with MSS %u configured with rate %u\n", + class_id, pktsize, max_tx_rate); + + /* bind VF to configured Traffic Class */ + fw_pfvf = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH)); + fw_class = class_id; + ret = t4_set_params(adap, adap->mbox, adap->pf, vf + 1, 1, &fw_pfvf, + &fw_class); + if (ret) { + dev_err(adap->pdev_dev, + "Err %d in binding VF %d to Traffic Class %d\n", + ret, vf, class_id); + return -EINVAL; + } + dev_info(adap->pdev_dev, "PF %d VF %d is bound to Class %d\n", + adap->pf, vf, class_id); + adap->vfinfo[vf].tx_rate = max_tx_rate; + return 0; +} + #endif static int cxgb_set_mac_addr(struct net_device *dev, void *p) @@ -2697,12 +2889,15 @@ static int cxgb_set_tx_maxrate(struct net_device *dev, int index, u32 rate) return err; } -static int cxgb_setup_tc(struct net_device *dev, u32 handle, __be16 proto, - struct tc_to_netdev *tc) +static int cxgb_setup_tc(struct net_device *dev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *tc) { struct port_info *pi = netdev2pinfo(dev); struct adapter *adap = netdev2adap(dev); + if (chain_index) + return -EOPNOTSUPP; + if (!(adap->flags & FULL_INIT_DONE)) { dev_err(adap->pdev_dev, "Failed to setup tc on port %d. Link Down?\n", @@ -2726,6 +2921,16 @@ static int cxgb_setup_tc(struct net_device *dev, u32 handle, __be16 proto, return -EOPNOTSUPP; } +static netdev_features_t cxgb_fix_features(struct net_device *dev, + netdev_features_t features) +{ + /* Disable GRO, if RX_CSUM is disabled */ + if (!(features & NETIF_F_RXCSUM)) + features &= ~NETIF_F_GRO; + + return features; +} + static const struct net_device_ops cxgb4_netdev_ops = { .ndo_open = cxgb_open, .ndo_stop = cxgb_close, @@ -2747,6 +2952,7 @@ static const struct net_device_ops cxgb4_netdev_ops = { #endif /* CONFIG_CHELSIO_T4_FCOE */ .ndo_set_tx_maxrate = cxgb_set_tx_maxrate, .ndo_setup_tc = cxgb_setup_tc, + .ndo_fix_features = cxgb_fix_features, }; #ifdef CONFIG_PCI_IOV @@ -2754,6 +2960,7 @@ static const struct net_device_ops cxgb4_mgmt_netdev_ops = { .ndo_open = dummy_open, .ndo_set_vf_mac = cxgb_set_vf_mac, .ndo_get_vf_config = cxgb_get_vf_config, + .ndo_set_vf_rate = cxgb_set_vf_rate, .ndo_get_phys_port_id = cxgb_get_phys_port_id, }; #endif @@ -4018,10 +4225,7 @@ static void cfg_queues(struct adapter *adap) /* Reduce memory usage in kdump environment, disable all offload. */ - if (is_kdump_kernel()) { - adap->params.offload = 0; - adap->params.crypto = 0; - } else if (is_uld(adap) && t4_uld_mem_alloc(adap)) { + if (is_kdump_kernel() || (is_uld(adap) && t4_uld_mem_alloc(adap))) { adap->params.offload = 0; adap->params.crypto = 0; } @@ -4042,7 +4246,7 @@ static void cfg_queues(struct adapter *adap) struct port_info *pi = adap2pinfo(adap, i); pi->first_qset = qidx; - pi->nqsets = 8; + pi->nqsets = is_kdump_kernel() ? 1 : 8; qidx += pi->nqsets; } #else /* !CONFIG_CHELSIO_T4_DCB */ @@ -4055,6 +4259,9 @@ static void cfg_queues(struct adapter *adap) if (q10g > netif_get_num_default_rss_queues()) q10g = netif_get_num_default_rss_queues(); + if (is_kdump_kernel()) + q10g = 1; + for_each_port(adap, i) { struct port_info *pi = adap2pinfo(adap, i); @@ -4094,6 +4301,9 @@ static void cfg_queues(struct adapter *adap) for (i = 0; i < ARRAY_SIZE(s->ctrlq); i++) s->ctrlq[i].q.size = 512; + if (!is_t4(adap->params.chip)) + s->ptptxq.q.size = 8; + init_rspq(adap, &s->fw_evtq, 0, 1, 1024, 64); init_rspq(adap, &s->intrq, 0, 1, 512, 64); } @@ -4960,6 +5170,8 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) netif_set_real_num_tx_queues(adapter->port[i], pi->nqsets); netif_set_real_num_rx_queues(adapter->port[i], pi->nqsets); + netif_carrier_off(adapter->port[i]); + err = register_netdev(adapter->port[i]); if (err) break; @@ -4990,6 +5202,9 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) mutex_unlock(&uld_mutex); } + if (!is_t4(adapter->params.chip)) + cxgb4_ptp_init(adapter); + print_adapter_info(adapter); setup_fw_sge_queues(adapter); return 0; @@ -5026,13 +5241,15 @@ sriov: &v, &port_vec); if (err < 0) { dev_err(adapter->pdev_dev, "Could not fetch port params\n"); - goto free_adapter; + goto free_mbox_log; } adapter->params.nports = hweight32(port_vec); pci_set_drvdata(pdev, adapter); return 0; +free_mbox_log: + kfree(adapter->mbox_log); free_adapter: kfree(adapter); free_pci_region: @@ -5097,6 +5314,9 @@ static void remove_one(struct pci_dev *pdev) debugfs_remove_recursive(adapter->debugfs_root); + if (!is_t4(adapter->params.chip)) + cxgb4_ptp_stop(adapter); + /* If we allocated filters, free up state associated with any * valid filters ... */ @@ -5132,6 +5352,7 @@ static void remove_one(struct pci_dev *pdev) unregister_netdev(adapter->port[0]); iounmap(adapter->regs); kfree(adapter->vfinfo); + kfree(adapter->mbox_log); kfree(adapter); pci_disable_sriov(pdev); pci_release_regions(pdev); @@ -5178,6 +5399,7 @@ static void shutdown_one(struct pci_dev *pdev) unregister_netdev(adapter->port[0]); iounmap(adapter->regs); kfree(adapter->vfinfo); + kfree(adapter->mbox_log); kfree(adapter); pci_disable_sriov(pdev); pci_release_regions(pdev); |