summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h4
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c6
-rw-r--r--drivers/net/ethernet/broadcom/cnic.c4
-rw-r--r--drivers/net/ethernet/broadcom/cnic_if.h3
-rw-r--r--drivers/net/ethernet/calxeda/xgmac.c2
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h3
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.c13
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.h15
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c163
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c28
-rw-r--r--drivers/net/ethernet/freescale/fec.h10
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c100
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cmd.c200
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c78
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.c16
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h28
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/port.c19
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c44
-rw-r--r--drivers/net/ethernet/ti/cpsw.c163
-rw-r--r--drivers/net/ethernet/ti/davinci_cpdma.c31
-rw-r--r--drivers/net/ethernet/ti/davinci_cpdma.h2
-rw-r--r--drivers/net/ethernet/ti/davinci_emac.c6
-rw-r--r--drivers/net/ethernet/ti/davinci_mdio.c1
23 files changed, 824 insertions, 115 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
index 40f22c6794cd..84aecdf06f7a 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
@@ -386,4 +386,8 @@
#define UNDEF_IRO 0x80000000
+/* used for defining the amount of FCoE tasks supported for PF */
+#define MAX_FCOE_FUNCS_PER_ENGINE 2
+#define MAX_NUM_FCOE_TASKS_PER_ENGINE 4096
+
#endif /* BNX2X_FW_DEFS_H */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index fbfff1b3365e..927f83af9d5c 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -10791,6 +10791,12 @@ static void bnx2x_get_fcoe_info(struct bnx2x *bp)
(max_fcoe_conn & BNX2X_MAX_FCOE_INIT_CONN_MASK) >>
BNX2X_MAX_FCOE_INIT_CONN_SHIFT;
+ /* Calculate the number of maximum allowed FCoE tasks */
+ bp->cnic_eth_dev.max_fcoe_exchanges = MAX_NUM_FCOE_TASKS_PER_ENGINE;
+ if (IS_MF(bp) || CHIP_MODE_IS_4_PORT(bp))
+ bp->cnic_eth_dev.max_fcoe_exchanges /=
+ MAX_FCOE_FUNCS_PER_ENGINE;
+
/* Read the WWN: */
if (!IS_MF(bp)) {
/* Port info */
diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index 149a3a038491..40649a8bf390 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -5544,8 +5544,10 @@ static struct cnic_dev *init_bnx2x_cnic(struct net_device *dev)
if (!(ethdev->drv_state & CNIC_DRV_STATE_NO_ISCSI))
cdev->max_iscsi_conn = ethdev->max_iscsi_conn;
- if (CNIC_SUPPORTS_FCOE(cp))
+ if (CNIC_SUPPORTS_FCOE(cp)) {
cdev->max_fcoe_conn = ethdev->max_fcoe_conn;
+ cdev->max_fcoe_exchanges = ethdev->max_fcoe_exchanges;
+ }
if (cdev->max_fcoe_conn > BNX2X_FCOE_NUM_CONNECTIONS)
cdev->max_fcoe_conn = BNX2X_FCOE_NUM_CONNECTIONS;
diff --git a/drivers/net/ethernet/broadcom/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h
index 0c9367a0f57d..ec9bb9ad4bb3 100644
--- a/drivers/net/ethernet/broadcom/cnic_if.h
+++ b/drivers/net/ethernet/broadcom/cnic_if.h
@@ -195,6 +195,7 @@ struct cnic_eth_dev {
u32 max_fcoe_conn;
u32 max_rdma_conn;
u32 fcoe_init_cid;
+ u32 max_fcoe_exchanges;
u32 fcoe_wwn_port_name_hi;
u32 fcoe_wwn_port_name_lo;
u32 fcoe_wwn_node_name_hi;
@@ -313,6 +314,8 @@ struct cnic_dev {
int max_fcoe_conn;
int max_rdma_conn;
+ int max_fcoe_exchanges;
+
union drv_info_to_mcp *stats_addr;
struct fcoe_capabilities *fcoe_cap;
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index 791e5ff305d8..4a1f2fa812ab 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -1482,7 +1482,7 @@ static int xgmac_set_features(struct net_device *dev, netdev_features_t features
u32 ctrl;
struct xgmac_priv *priv = netdev_priv(dev);
void __iomem *ioaddr = priv->base;
- u32 changed = dev->features ^ features;
+ netdev_features_t changed = dev->features ^ features;
if (!(changed & NETIF_F_RXCSUM))
return 0;
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index e2d5ced7e733..9045903dcda3 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -293,7 +293,7 @@ struct be_drv_stats {
u32 rx_in_range_errors;
u32 rx_out_range_errors;
u32 rx_frame_too_long;
- u32 rx_address_mismatch_drops;
+ u32 rx_address_filtered;
u32 rx_dropped_too_small;
u32 rx_dropped_too_short;
u32 rx_dropped_header_too_small;
@@ -447,6 +447,7 @@ struct be_adapter {
u16 max_event_queues;
u32 if_cap_flags;
u8 pf_number;
+ u64 rss_flags;
};
#define be_physfn(adapter) (!adapter->virtfn)
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index d6291aba2524..d837e4c7ae8b 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -1898,7 +1898,8 @@ int be_cmd_reset_function(struct be_adapter *adapter)
return status;
}
-int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size)
+int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable,
+ u32 rss_hash_opts, u16 table_size)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_rss_config *req;
@@ -1917,16 +1918,12 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size)
OPCODE_ETH_RSS_CONFIG, sizeof(*req), wrb, NULL);
req->if_id = cpu_to_le32(adapter->if_handle);
- req->enable_rss = cpu_to_le16(RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_IPV4 |
- RSS_ENABLE_TCP_IPV6 | RSS_ENABLE_IPV6);
+ req->enable_rss = cpu_to_le16(rss_hash_opts);
+ req->cpu_table_size_log2 = cpu_to_le16(fls(table_size) - 1);
- if (lancer_chip(adapter) || skyhawk_chip(adapter)) {
+ if (lancer_chip(adapter) || skyhawk_chip(adapter))
req->hdr.version = 1;
- req->enable_rss |= cpu_to_le16(RSS_ENABLE_UDP_IPV4 |
- RSS_ENABLE_UDP_IPV6);
- }
- req->cpu_table_size_log2 = cpu_to_le16(fls(table_size) - 1);
memcpy(req->cpu_table, rsstable, table_size);
memcpy(req->hash, myhash, sizeof(myhash));
be_dws_cpu_to_le(req->hash, sizeof(req->hash));
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 460332021590..0fc9b4775699 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -590,8 +590,8 @@ struct be_port_rxf_stats_v0 {
u32 rx_in_range_errors; /* dword 10*/
u32 rx_out_range_errors; /* dword 11*/
u32 rx_frame_too_long; /* dword 12*/
- u32 rx_address_mismatch_drops; /* dword 13*/
- u32 rx_vlan_mismatch_drops; /* dword 14*/
+ u32 rx_address_filtered; /* dword 13*/
+ u32 rx_vlan_filtered; /* dword 14*/
u32 rx_dropped_too_small; /* dword 15*/
u32 rx_dropped_too_short; /* dword 16*/
u32 rx_dropped_header_too_small; /* dword 17*/
@@ -797,8 +797,8 @@ struct lancer_pport_stats {
u32 rx_control_frames_unknown_opcode_hi;
u32 rx_in_range_errors;
u32 rx_out_of_range_errors;
- u32 rx_address_mismatch_drops;
- u32 rx_vlan_mismatch_drops;
+ u32 rx_address_filtered;
+ u32 rx_vlan_filtered;
u32 rx_dropped_too_small;
u32 rx_dropped_too_short;
u32 rx_dropped_header_too_small;
@@ -1090,6 +1090,9 @@ struct be_cmd_resp_query_fw_cfg {
#define RSS_ENABLE_UDP_IPV4 0x10
#define RSS_ENABLE_UDP_IPV6 0x20
+#define L3_RSS_FLAGS (RXH_IP_DST | RXH_IP_SRC)
+#define L4_RSS_FLAGS (RXH_L4_B_0_1 | RXH_L4_B_2_3)
+
struct be_cmd_req_rss_config {
struct be_cmd_req_hdr hdr;
u32 if_id;
@@ -1573,7 +1576,7 @@ struct be_port_rxf_stats_v1 {
u32 rx_in_range_errors;
u32 rx_out_range_errors;
u32 rx_frame_too_long;
- u32 rx_address_mismatch_drops;
+ u32 rx_address_filtered;
u32 rx_dropped_too_small;
u32 rx_dropped_too_short;
u32 rx_dropped_header_too_small;
@@ -1860,7 +1863,7 @@ extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num,
u32 *function_mode, u32 *function_caps, u16 *asic_rev);
extern int be_cmd_reset_function(struct be_adapter *adapter);
extern int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable,
- u16 table_size);
+ u32 rss_hash_opts, u16 table_size);
extern int be_process_mcc(struct be_adapter *adapter);
extern int be_cmd_set_beacon_state(struct be_adapter *adapter,
u8 port_num, u8 beacon, u8 status, u8 state);
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index 07b7f27cb0b9..ec3050b3133e 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -54,7 +54,7 @@ static const struct be_ethtool_stat et_stats[] = {
/* Received packets dropped when they don't pass the unicast or
* multicast address filtering.
*/
- {DRVSTAT_INFO(rx_address_mismatch_drops)},
+ {DRVSTAT_INFO(rx_address_filtered)},
/* Received packets dropped when IP packet length field is less than
* the IP header length field.
*/
@@ -755,6 +755,12 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
int status;
u8 link_status = 0;
+ if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC) {
+ dev_err(&adapter->pdev->dev, "Self test not supported\n");
+ test->flags |= ETH_TEST_FL_FAILED;
+ return;
+ }
+
memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);
if (test->flags & ETH_TEST_FL_OFFLINE) {
@@ -934,6 +940,159 @@ static void be_set_msg_level(struct net_device *netdev, u32 level)
return;
}
+static u64 be_get_rss_hash_opts(struct be_adapter *adapter, u64 flow_type)
+{
+ u64 data = 0;
+
+ switch (flow_type) {
+ case TCP_V4_FLOW:
+ if (adapter->rss_flags & RSS_ENABLE_IPV4)
+ data |= RXH_IP_DST | RXH_IP_SRC;
+ if (adapter->rss_flags & RSS_ENABLE_TCP_IPV4)
+ data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ case UDP_V4_FLOW:
+ if (adapter->rss_flags & RSS_ENABLE_IPV4)
+ data |= RXH_IP_DST | RXH_IP_SRC;
+ if (adapter->rss_flags & RSS_ENABLE_UDP_IPV4)
+ data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ case TCP_V6_FLOW:
+ if (adapter->rss_flags & RSS_ENABLE_IPV6)
+ data |= RXH_IP_DST | RXH_IP_SRC;
+ if (adapter->rss_flags & RSS_ENABLE_TCP_IPV6)
+ data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ case UDP_V6_FLOW:
+ if (adapter->rss_flags & RSS_ENABLE_IPV6)
+ data |= RXH_IP_DST | RXH_IP_SRC;
+ if (adapter->rss_flags & RSS_ENABLE_UDP_IPV6)
+ data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ }
+
+ return data;
+}
+
+static int be_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
+ u32 *rule_locs)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+
+ if (!be_multi_rxq(adapter)) {
+ dev_info(&adapter->pdev->dev,
+ "ethtool::get_rxnfc: RX flow hashing is disabled\n");
+ return -EINVAL;
+ }
+
+ switch (cmd->cmd) {
+ case ETHTOOL_GRXFH:
+ cmd->data = be_get_rss_hash_opts(adapter, cmd->flow_type);
+ break;
+ case ETHTOOL_GRXRINGS:
+ cmd->data = adapter->num_rx_qs - 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int be_set_rss_hash_opts(struct be_adapter *adapter,
+ struct ethtool_rxnfc *cmd)
+{
+ struct be_rx_obj *rxo;
+ int status = 0, i, j;
+ u8 rsstable[128];
+ u32 rss_flags = adapter->rss_flags;
+
+ if (cmd->data != L3_RSS_FLAGS &&
+ cmd->data != (L3_RSS_FLAGS | L4_RSS_FLAGS))
+ return -EINVAL;
+
+ switch (cmd->flow_type) {
+ case TCP_V4_FLOW:
+ if (cmd->data == L3_RSS_FLAGS)
+ rss_flags &= ~RSS_ENABLE_TCP_IPV4;
+ else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS))
+ rss_flags |= RSS_ENABLE_IPV4 |
+ RSS_ENABLE_TCP_IPV4;
+ break;
+ case TCP_V6_FLOW:
+ if (cmd->data == L3_RSS_FLAGS)
+ rss_flags &= ~RSS_ENABLE_TCP_IPV6;
+ else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS))
+ rss_flags |= RSS_ENABLE_IPV6 |
+ RSS_ENABLE_TCP_IPV6;
+ break;
+ case UDP_V4_FLOW:
+ if ((cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS)) &&
+ BEx_chip(adapter))
+ return -EINVAL;
+
+ if (cmd->data == L3_RSS_FLAGS)
+ rss_flags &= ~RSS_ENABLE_UDP_IPV4;
+ else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS))
+ rss_flags |= RSS_ENABLE_IPV4 |
+ RSS_ENABLE_UDP_IPV4;
+ break;
+ case UDP_V6_FLOW:
+ if ((cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS)) &&
+ BEx_chip(adapter))
+ return -EINVAL;
+
+ if (cmd->data == L3_RSS_FLAGS)
+ rss_flags &= ~RSS_ENABLE_UDP_IPV6;
+ else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS))
+ rss_flags |= RSS_ENABLE_IPV6 |
+ RSS_ENABLE_UDP_IPV6;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (rss_flags == adapter->rss_flags)
+ return status;
+
+ if (be_multi_rxq(adapter)) {
+ for (j = 0; j < 128; j += adapter->num_rx_qs - 1) {
+ for_all_rss_queues(adapter, rxo, i) {
+ if ((j + i) >= 128)
+ break;
+ rsstable[j + i] = rxo->rss_id;
+ }
+ }
+ }
+ status = be_cmd_rss_config(adapter, rsstable, rss_flags, 128);
+ if (!status)
+ adapter->rss_flags = rss_flags;
+
+ return status;
+}
+
+static int be_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ int status = 0;
+
+ if (!be_multi_rxq(adapter)) {
+ dev_err(&adapter->pdev->dev,
+ "ethtool::set_rxnfc: RX flow hashing is disabled\n");
+ return -EINVAL;
+ }
+
+ switch (cmd->cmd) {
+ case ETHTOOL_SRXFH:
+ status = be_set_rss_hash_opts(adapter, cmd);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return status;
+}
+
const struct ethtool_ops be_ethtool_ops = {
.get_settings = be_get_settings,
.get_drvinfo = be_get_drvinfo,
@@ -957,4 +1116,6 @@ const struct ethtool_ops be_ethtool_ops = {
.get_regs = be_get_regs,
.flash_device = be_do_flash,
.self_test = be_self_test,
+ .get_rxnfc = be_get_rxnfc,
+ .set_rxnfc = be_set_rxnfc,
};
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 654e7820daa0..43d5c1e29fc7 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -353,9 +353,9 @@ static void populate_be_v0_stats(struct be_adapter *adapter)
drvs->rx_input_fifo_overflow_drop = port_stats->rx_input_fifo_overflow;
drvs->rx_dropped_header_too_small =
port_stats->rx_dropped_header_too_small;
- drvs->rx_address_mismatch_drops =
- port_stats->rx_address_mismatch_drops +
- port_stats->rx_vlan_mismatch_drops;
+ drvs->rx_address_filtered =
+ port_stats->rx_address_filtered +
+ port_stats->rx_vlan_filtered;
drvs->rx_alignment_symbol_errors =
port_stats->rx_alignment_symbol_errors;
@@ -404,7 +404,7 @@ static void populate_be_v1_stats(struct be_adapter *adapter)
port_stats->rx_dropped_header_too_small;
drvs->rx_input_fifo_overflow_drop =
port_stats->rx_input_fifo_overflow_drop;
- drvs->rx_address_mismatch_drops = port_stats->rx_address_mismatch_drops;
+ drvs->rx_address_filtered = port_stats->rx_address_filtered;
drvs->rx_alignment_symbol_errors =
port_stats->rx_alignment_symbol_errors;
drvs->rxpp_fifo_overflow_drop = port_stats->rxpp_fifo_overflow_drop;
@@ -445,9 +445,9 @@ static void populate_lancer_stats(struct be_adapter *adapter)
drvs->rx_dropped_header_too_small =
pport_stats->rx_dropped_header_too_small;
drvs->rx_input_fifo_overflow_drop = pport_stats->rx_fifo_overflow;
- drvs->rx_address_mismatch_drops =
- pport_stats->rx_address_mismatch_drops +
- pport_stats->rx_vlan_mismatch_drops;
+ drvs->rx_address_filtered =
+ pport_stats->rx_address_filtered +
+ pport_stats->rx_vlan_filtered;
drvs->rx_alignment_symbol_errors = pport_stats->rx_symbol_errors_lo;
drvs->rxpp_fifo_overflow_drop = pport_stats->rx_fifo_overflow;
drvs->tx_pauseframes = pport_stats->tx_pause_frames_lo;
@@ -2510,9 +2510,19 @@ static int be_rx_qs_create(struct be_adapter *adapter)
rsstable[j + i] = rxo->rss_id;
}
}
- rc = be_cmd_rss_config(adapter, rsstable, 128);
- if (rc)
+ adapter->rss_flags = RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_IPV4 |
+ RSS_ENABLE_TCP_IPV6 | RSS_ENABLE_IPV6;
+
+ if (!BEx_chip(adapter))
+ adapter->rss_flags |= RSS_ENABLE_UDP_IPV4 |
+ RSS_ENABLE_UDP_IPV6;
+
+ rc = be_cmd_rss_config(adapter, rsstable, adapter->rss_flags,
+ 128);
+ if (rc) {
+ adapter->rss_flags = 0;
return rc;
+ }
}
/* First time posting */
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index eb4372962839..d44f65bac1d4 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -52,6 +52,7 @@
#define FEC_R_FIFO_RSEM 0x194 /* Receive FIFO section empty threshold */
#define FEC_R_FIFO_RAEM 0x198 /* Receive FIFO almost empty threshold */
#define FEC_R_FIFO_RAFL 0x19c /* Receive FIFO almost full threshold */
+#define FEC_RACC 0x1C4 /* Receive Accelerator function */
#define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */
#define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */
@@ -164,9 +165,11 @@ struct bufdesc_ex {
#define BD_ENET_TX_CSL ((ushort)0x0001)
#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */
-/*enhanced buffer desciptor control/status used by Ethernet transmit*/
+/*enhanced buffer descriptor control/status used by Ethernet transmit*/
#define BD_ENET_TX_INT 0x40000000
#define BD_ENET_TX_TS 0x20000000
+#define BD_ENET_TX_PINS 0x10000000
+#define BD_ENET_TX_IINS 0x08000000
/* This device has up to three irqs on some platforms */
@@ -190,6 +193,10 @@ struct bufdesc_ex {
#define BD_ENET_RX_INT 0x00800000
#define BD_ENET_RX_PTP ((ushort)0x0400)
+#define BD_ENET_RX_ICE 0x00000020
+#define BD_ENET_RX_PCR 0x00000010
+#define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
+#define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
/* The FEC buffer descriptors track the ring buffers. The rx_bd_base and
* tx_bd_base always point to the base of the buffer descriptors. The
@@ -247,6 +254,7 @@ struct fec_enet_private {
int pause_flag;
struct napi_struct napi;
+ int csum_flags;
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_caps;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 2451ab1b5a83..b9748f14ea78 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -34,6 +34,12 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <net/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/icmp.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/bitops.h>
@@ -176,6 +182,11 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
#define PKT_MINBUF_SIZE 64
#define PKT_MAXBLR_SIZE 1520
+/* FEC receive acceleration */
+#define FEC_RACC_IPDIS (1 << 1)
+#define FEC_RACC_PRODIS (1 << 2)
+#define FEC_RACC_OPTIONS (FEC_RACC_IPDIS | FEC_RACC_PRODIS)
+
/*
* The 5270/5271/5280/5282/532x RX control register also contains maximum frame
* size bits. Other FEC hardware does not, so we need to take that into
@@ -236,6 +247,21 @@ static void *swap_buffer(void *bufaddr, int len)
return bufaddr;
}
+static int
+fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
+{
+ /* Only run for packets requiring a checksum. */
+ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ return 0;
+
+ if (unlikely(skb_cow_head(skb, 0)))
+ return -1;
+
+ *(__sum16 *)(skb->head + skb->csum_start + skb->csum_offset) = 0;
+
+ return 0;
+}
+
static netdev_tx_t
fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
@@ -248,7 +274,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
unsigned int index;
if (!fep->link) {
- /* Link is down or autonegotiation is in progress. */
+ /* Link is down or auto-negotiation is in progress. */
return NETDEV_TX_BUSY;
}
@@ -265,6 +291,12 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
return NETDEV_TX_BUSY;
}
+ /* Protocol checksum off-load for TCP and UDP. */
+ if (fec_enet_clear_csum(skb, ndev)) {
+ kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
/* Clear all of the status flags */
status &= ~BD_ENET_TX_STATS;
@@ -321,8 +353,14 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
ebdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
} else {
-
ebdp->cbd_esc = BD_ENET_TX_INT;
+
+ /* Enable protocol checksum flags
+ * We do not bother with the IP Checksum bits as they
+ * are done by the kernel
+ */
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ ebdp->cbd_esc |= BD_ENET_TX_PINS;
}
}
/* If this was the last BD in the ring, start at the beginning again. */
@@ -402,6 +440,7 @@ fec_restart(struct net_device *ndev, int duplex)
const struct platform_device_id *id_entry =
platform_get_device_id(fep->pdev);
int i;
+ u32 val;
u32 temp_mac[2];
u32 rcntl = OPT_FRAME_SIZE | 0x04;
u32 ecntl = 0x2; /* ETHEREN */
@@ -468,6 +507,14 @@ fec_restart(struct net_device *ndev, int duplex)
/* Set MII speed */
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
+ /* set RX checksum */
+ val = readl(fep->hwp + FEC_RACC);
+ if (fep->csum_flags & FLAG_RX_CSUM_ENABLED)
+ val |= FEC_RACC_OPTIONS;
+ else
+ val &= ~FEC_RACC_OPTIONS;
+ writel(val, fep->hwp + FEC_RACC);
+
/*
* The phy interface and speed need to get configured
* differently on enet-mac.
@@ -525,7 +572,7 @@ fec_restart(struct net_device *ndev, int duplex)
fep->phy_dev && fep->phy_dev->pause)) {
rcntl |= FEC_ENET_FCE;
- /* set FIFO thresh hold parameter to reduce overrun */
+ /* set FIFO threshold parameter to reduce overrun */
writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM);
writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL);
writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM);
@@ -813,6 +860,18 @@ fec_enet_rx(struct net_device *ndev, int budget)
spin_unlock_irqrestore(&fep->tmreg_lock, flags);
}
+ if (fep->bufdesc_ex &&
+ (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
+ struct bufdesc_ex *ebdp =
+ (struct bufdesc_ex *)bdp;
+ if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) {
+ /* don't check it */
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ skb_checksum_none_assert(skb);
+ }
+ }
+
if (!skb_defer_rx_timestamp(skb))
napi_gro_receive(&fep->napi, skb);
}
@@ -1614,6 +1673,33 @@ static void fec_poll_controller(struct net_device *dev)
}
#endif
+static int fec_set_features(struct net_device *netdev,
+ netdev_features_t features)
+{
+ struct fec_enet_private *fep = netdev_priv(netdev);
+ netdev_features_t changed = features ^ netdev->features;
+
+ netdev->features = features;
+
+ /* Receive checksum has been changed */
+ if (changed & NETIF_F_RXCSUM) {
+ if (features & NETIF_F_RXCSUM)
+ fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
+ else
+ fep->csum_flags &= ~FLAG_RX_CSUM_ENABLED;
+
+ if (netif_running(netdev)) {
+ fec_stop(netdev);
+ fec_restart(netdev, fep->phy_dev->duplex);
+ netif_wake_queue(netdev);
+ } else {
+ fec_restart(netdev, fep->phy_dev->duplex);
+ }
+ }
+
+ return 0;
+}
+
static const struct net_device_ops fec_netdev_ops = {
.ndo_open = fec_enet_open,
.ndo_stop = fec_enet_close,
@@ -1627,6 +1713,7 @@ static const struct net_device_ops fec_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = fec_poll_controller,
#endif
+ .ndo_set_features = fec_set_features,
};
/*
@@ -1668,6 +1755,13 @@ static int fec_enet_init(struct net_device *ndev)
writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT);
+ /* enable hw accelerator */
+ ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
+ | NETIF_F_RXCSUM);
+ ndev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
+ | NETIF_F_RXCSUM);
+ fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
+
fec_restart(ndev, 0);
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
index 05267d716e86..1df56cc50ee9 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
@@ -1490,6 +1490,69 @@ out:
return ret;
}
+static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave)
+{
+ int port, err;
+ struct mlx4_vport_state *vp_admin;
+ struct mlx4_vport_oper_state *vp_oper;
+
+ for (port = 1; port <= MLX4_MAX_PORTS; port++) {
+ vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
+ vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
+ vp_oper->state = *vp_admin;
+ if (MLX4_VGT != vp_admin->default_vlan) {
+ err = __mlx4_register_vlan(&priv->dev, port,
+ vp_admin->default_vlan, &(vp_oper->vlan_idx));
+ if (err) {
+ vp_oper->vlan_idx = NO_INDX;
+ mlx4_warn((&priv->dev),
+ "No vlan resorces slave %d, port %d\n",
+ slave, port);
+ return err;
+ }
+ mlx4_dbg((&(priv->dev)), "alloc vlan %d idx %d slave %d port %d\n",
+ (int)(vp_oper->state.default_vlan),
+ vp_oper->vlan_idx, slave, port);
+ }
+ if (vp_admin->spoofchk) {
+ vp_oper->mac_idx = __mlx4_register_mac(&priv->dev,
+ port,
+ vp_admin->mac);
+ if (0 > vp_oper->mac_idx) {
+ err = vp_oper->mac_idx;
+ vp_oper->mac_idx = NO_INDX;
+ mlx4_warn((&priv->dev),
+ "No mac resorces slave %d, port %d\n",
+ slave, port);
+ return err;
+ }
+ mlx4_dbg((&(priv->dev)), "alloc mac %llx idx %d slave %d port %d\n",
+ vp_oper->state.mac, vp_oper->mac_idx, slave, port);
+ }
+ }
+ return 0;
+}
+
+static void mlx4_master_deactivate_admin_state(struct mlx4_priv *priv, int slave)
+{
+ int port;
+ struct mlx4_vport_oper_state *vp_oper;
+
+ for (port = 1; port <= MLX4_MAX_PORTS; port++) {
+ vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
+ if (NO_INDX != vp_oper->vlan_idx) {
+ __mlx4_unregister_vlan(&priv->dev,
+ port, vp_oper->vlan_idx);
+ vp_oper->vlan_idx = NO_INDX;
+ }
+ if (NO_INDX != vp_oper->mac_idx) {
+ __mlx4_unregister_mac(&priv->dev, port, vp_oper->mac_idx);
+ vp_oper->mac_idx = NO_INDX;
+ }
+ }
+ return;
+}
+
static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
u16 param, u8 toggle)
{
@@ -1510,6 +1573,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
if (cmd == MLX4_COMM_CMD_RESET) {
mlx4_warn(dev, "Received reset from slave:%d\n", slave);
slave_state[slave].active = false;
+ mlx4_master_deactivate_admin_state(priv, slave);
for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) {
slave_state[slave].event_eq[i].eqn = -1;
slave_state[slave].event_eq[i].token = 0;
@@ -1556,6 +1620,8 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2)
goto reset_slave;
slave_state[slave].vhcr_dma |= param;
+ if (mlx4_master_activate_admin_state(priv, slave))
+ goto reset_slave;
slave_state[slave].active = true;
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, slave);
break;
@@ -1732,6 +1798,18 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
if (!priv->mfunc.master.slave_state)
goto err_comm;
+ priv->mfunc.master.vf_admin =
+ kzalloc(dev->num_slaves *
+ sizeof(struct mlx4_vf_admin_state), GFP_KERNEL);
+ if (!priv->mfunc.master.vf_admin)
+ goto err_comm_admin;
+
+ priv->mfunc.master.vf_oper =
+ kzalloc(dev->num_slaves *
+ sizeof(struct mlx4_vf_oper_state), GFP_KERNEL);
+ if (!priv->mfunc.master.vf_oper)
+ goto err_comm_oper;
+
for (i = 0; i < dev->num_slaves; ++i) {
s_state = &priv->mfunc.master.slave_state[i];
s_state->last_cmd = MLX4_COMM_CMD_RESET;
@@ -1752,6 +1830,10 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
goto err_slaves;
}
INIT_LIST_HEAD(&s_state->mcast_filters[port]);
+ priv->mfunc.master.vf_admin[i].vport[port].default_vlan = MLX4_VGT;
+ priv->mfunc.master.vf_oper[i].vport[port].state.default_vlan = MLX4_VGT;
+ priv->mfunc.master.vf_oper[i].vport[port].vlan_idx = NO_INDX;
+ priv->mfunc.master.vf_oper[i].vport[port].mac_idx = NO_INDX;
}
spin_lock_init(&s_state->lock);
}
@@ -1800,6 +1882,10 @@ err_slaves:
for (port = 1; port <= MLX4_MAX_PORTS; port++)
kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]);
}
+ kfree(priv->mfunc.master.vf_oper);
+err_comm_oper:
+ kfree(priv->mfunc.master.vf_admin);
+err_comm_admin:
kfree(priv->mfunc.master.slave_state);
err_comm:
iounmap(priv->mfunc.comm);
@@ -1874,6 +1960,8 @@ void mlx4_multi_func_cleanup(struct mlx4_dev *dev)
kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]);
}
kfree(priv->mfunc.master.slave_state);
+ kfree(priv->mfunc.master.vf_admin);
+ kfree(priv->mfunc.master.vf_oper);
}
iounmap(priv->mfunc.comm);
@@ -1984,3 +2072,115 @@ u32 mlx4_comm_get_version(void)
{
return ((u32) CMD_CHAN_IF_REV << 8) | (u32) CMD_CHAN_VER;
}
+
+static int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf)
+{
+ if ((vf < 0) || (vf >= dev->num_vfs)) {
+ mlx4_err(dev, "Bad vf number:%d (number of activated vf: %d)\n", vf, dev->num_vfs);
+ return -EINVAL;
+ }
+
+ return vf+1;
+}
+
+int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_vport_state *s_info;
+ int slave;
+
+ if (!mlx4_is_master(dev))
+ return -EPROTONOSUPPORT;
+
+ slave = mlx4_get_slave_indx(dev, vf);
+ if (slave < 0)
+ return -EINVAL;
+
+ s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
+ s_info->mac = mac;
+ mlx4_info(dev, "default mac on vf %d port %d to %llX will take afect only after vf restart\n",
+ vf, port, s_info->mac);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_set_vf_mac);
+
+int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_vport_state *s_info;
+ int slave;
+
+ if ((!mlx4_is_master(dev)) ||
+ !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VLAN_CONTROL))
+ return -EPROTONOSUPPORT;
+
+ if ((vlan > 4095) || (qos > 7))
+ return -EINVAL;
+
+ slave = mlx4_get_slave_indx(dev, vf);
+ if (slave < 0)
+ return -EINVAL;
+
+ s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
+ if ((0 == vlan) && (0 == qos))
+ s_info->default_vlan = MLX4_VGT;
+ else
+ s_info->default_vlan = vlan;
+ s_info->default_qos = qos;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan);
+
+int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_vport_state *s_info;
+ int slave;
+
+ if ((!mlx4_is_master(dev)) ||
+ !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FSM))
+ return -EPROTONOSUPPORT;
+
+ slave = mlx4_get_slave_indx(dev, vf);
+ if (slave < 0)
+ return -EINVAL;
+
+ s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
+ s_info->spoofchk = setting;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_set_vf_spoofchk);
+
+int mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_info *ivf)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_vport_state *s_info;
+ int slave;
+
+ if (!mlx4_is_master(dev))
+ return -EPROTONOSUPPORT;
+
+ slave = mlx4_get_slave_indx(dev, vf);
+ if (slave < 0)
+ return -EINVAL;
+
+ s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
+ ivf->vf = vf;
+
+ /* need to convert it to a func */
+ ivf->mac[0] = ((s_info->mac >> (5*8)) & 0xff);
+ ivf->mac[1] = ((s_info->mac >> (4*8)) & 0xff);
+ ivf->mac[2] = ((s_info->mac >> (3*8)) & 0xff);
+ ivf->mac[3] = ((s_info->mac >> (2*8)) & 0xff);
+ ivf->mac[4] = ((s_info->mac >> (1*8)) & 0xff);
+ ivf->mac[5] = ((s_info->mac) & 0xff);
+
+ ivf->vlan = s_info->default_vlan;
+ ivf->qos = s_info->default_qos;
+ ivf->tx_rate = s_info->tx_rate;
+ ivf->spoofchk = s_info->spoofchk;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_get_vf_config);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index f4f88b846020..a69a908614e6 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -1373,7 +1373,8 @@ static void mlx4_en_service_task(struct work_struct *work)
mutex_lock(&mdev->state_lock);
if (mdev->device_up) {
- mlx4_en_ptp_overflow_check(mdev);
+ if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
+ mlx4_en_ptp_overflow_check(mdev);
queue_delayed_work(mdev->workqueue, &priv->service_task,
SERVICE_TASK_DELAY);
@@ -2023,6 +2024,42 @@ static int mlx4_en_set_features(struct net_device *netdev,
}
+static int mlx4_en_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
+{
+ struct mlx4_en_priv *en_priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = en_priv->mdev;
+ u64 mac_u64 = mlx4_en_mac_to_u64(mac);
+
+ if (!is_valid_ether_addr(mac))
+ return -EINVAL;
+
+ return mlx4_set_vf_mac(mdev->dev, en_priv->port, queue, mac_u64);
+}
+
+static int mlx4_en_set_vf_vlan(struct net_device *dev, int vf, u16 vlan, u8 qos)
+{
+ struct mlx4_en_priv *en_priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = en_priv->mdev;
+
+ return mlx4_set_vf_vlan(mdev->dev, en_priv->port, vf, vlan, qos);
+}
+
+static int mlx4_en_set_vf_spoofchk(struct net_device *dev, int vf, bool setting)
+{
+ struct mlx4_en_priv *en_priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = en_priv->mdev;
+
+ return mlx4_set_vf_spoofchk(mdev->dev, en_priv->port, vf, setting);
+}
+
+static int mlx4_en_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivf)
+{
+ struct mlx4_en_priv *en_priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = en_priv->mdev;
+
+ return mlx4_get_vf_config(mdev->dev, en_priv->port, vf, ivf);
+}
+
static const struct net_device_ops mlx4_netdev_ops = {
.ndo_open = mlx4_en_open,
.ndo_stop = mlx4_en_close,
@@ -2047,6 +2084,33 @@ static const struct net_device_ops mlx4_netdev_ops = {
#endif
};
+static const struct net_device_ops mlx4_netdev_ops_master = {
+ .ndo_open = mlx4_en_open,
+ .ndo_stop = mlx4_en_close,
+ .ndo_start_xmit = mlx4_en_xmit,
+ .ndo_select_queue = mlx4_en_select_queue,
+ .ndo_get_stats = mlx4_en_get_stats,
+ .ndo_set_rx_mode = mlx4_en_set_rx_mode,
+ .ndo_set_mac_address = mlx4_en_set_mac,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = mlx4_en_change_mtu,
+ .ndo_tx_timeout = mlx4_en_tx_timeout,
+ .ndo_vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid,
+ .ndo_set_vf_mac = mlx4_en_set_vf_mac,
+ .ndo_set_vf_vlan = mlx4_en_set_vf_vlan,
+ .ndo_set_vf_spoofchk = mlx4_en_set_vf_spoofchk,
+ .ndo_get_vf_config = mlx4_en_get_vf_config,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = mlx4_en_netpoll,
+#endif
+ .ndo_set_features = mlx4_en_set_features,
+ .ndo_setup_tc = mlx4_en_setup_tc,
+#ifdef CONFIG_RFS_ACCEL
+ .ndo_rx_flow_steer = mlx4_en_filter_rfs,
+#endif
+};
+
int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
struct mlx4_en_port_profile *prof)
{
@@ -2163,7 +2227,10 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
/*
* Initialize netdev entry points
*/
- dev->netdev_ops = &mlx4_netdev_ops;
+ if (mlx4_is_master(priv->mdev->dev))
+ dev->netdev_ops = &mlx4_netdev_ops_master;
+ else
+ dev->netdev_ops = &mlx4_netdev_ops;
dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT;
netif_set_real_num_tx_queues(dev, priv->tx_ring_num);
netif_set_real_num_rx_queues(dev, priv->rx_ring_num);
@@ -2228,8 +2295,11 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
}
mlx4_en_set_default_moderation(priv);
queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
- queue_delayed_work(mdev->workqueue, &priv->service_task,
- SERVICE_TASK_DELAY);
+
+ if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
+ queue_delayed_work(mdev->workqueue, &priv->service_task,
+ SERVICE_TASK_DELAY);
+
return 0;
out:
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index 6776c257bd34..b147bdd40768 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -468,6 +468,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
#define QUERY_DEV_CAP_RSVD_XRC_OFFSET 0x66
#define QUERY_DEV_CAP_MAX_XRC_OFFSET 0x67
#define QUERY_DEV_CAP_MAX_COUNTERS_OFFSET 0x68
+#define QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET 0x70
#define QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET 0x76
#define QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET 0x77
#define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET 0x80
@@ -655,6 +656,12 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
MLX4_GET(dev_cap->max_counters, outbox,
QUERY_DEV_CAP_MAX_COUNTERS_OFFSET);
+ MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
+ if (field32 & (1 << 26))
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VLAN_CONTROL;
+ if (field32 & (1 << 20))
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FSM;
+
if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
for (i = 1; i <= dev_cap->num_ports; ++i) {
MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
@@ -784,6 +791,11 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
flags &= ~MLX4_DEV_CAP_FLAG_MEM_WINDOW;
MLX4_PUT(outbox->buf, flags, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
+ /* For guests, disable timestamp */
+ MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
+ field &= 0x7f;
+ MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
+
/* For guests, report Blueflame disabled */
MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_BF_OFFSET);
field &= 0x7f;
@@ -811,6 +823,7 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_cmd_mailbox *outbox,
struct mlx4_cmd_info *cmd)
{
+ struct mlx4_priv *priv = mlx4_priv(dev);
u64 def_mac;
u8 port_type;
u16 short_field;
@@ -828,6 +841,9 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
/* set slave default_mac address */
MLX4_GET(def_mac, outbox->buf, QUERY_PORT_MAC_OFFSET);
def_mac += slave << 8;
+ /* if config MAC in DB use it */
+ if (priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac)
+ def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac;
MLX4_PUT(outbox->buf, def_mac, QUERY_PORT_MAC_OFFSET);
/* get port type - currently only eth is enabled */
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index 0567f01938ed..eac3dae10efe 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -473,6 +473,30 @@ struct mlx4_slave_state {
enum slave_port_state port_state[MLX4_MAX_PORTS + 1];
};
+#define MLX4_VGT 4095
+#define NO_INDX (-1)
+
+struct mlx4_vport_state {
+ u64 mac;
+ u16 default_vlan;
+ u8 default_qos;
+ u32 tx_rate;
+ bool spoofchk;
+};
+
+struct mlx4_vf_admin_state {
+ struct mlx4_vport_state vport[MLX4_MAX_PORTS + 1];
+};
+
+struct mlx4_vport_oper_state {
+ struct mlx4_vport_state state;
+ int mac_idx;
+ int vlan_idx;
+};
+struct mlx4_vf_oper_state {
+ struct mlx4_vport_oper_state vport[MLX4_MAX_PORTS + 1];
+};
+
struct slave_list {
struct mutex mutex;
struct list_head res_list[MLX4_NUM_OF_RESOURCE_TYPE];
@@ -503,6 +527,8 @@ struct mlx4_master_qp0_state {
struct mlx4_mfunc_master_ctx {
struct mlx4_slave_state *slave_state;
+ struct mlx4_vf_admin_state *vf_admin;
+ struct mlx4_vf_oper_state *vf_oper;
struct mlx4_master_qp0_state qp0_state[MLX4_MAX_PORTS + 1];
int init_port_ref[MLX4_MAX_PORTS + 1];
u16 max_mtu[MLX4_MAX_PORTS + 1];
@@ -1131,6 +1157,8 @@ int mlx4_change_port_types(struct mlx4_dev *dev,
void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table);
void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table);
+void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index);
+int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index);
int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz);
/* resource tracker functions*/
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
index 4b6aad39e72c..946e0af5faef 100644
--- a/drivers/net/ethernet/mellanox/mlx4/port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -141,8 +141,9 @@ int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
}
if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
- /* MAC already registered, Must not have duplicates */
- err = -EEXIST;
+ /* MAC already registered, increment ref count */
+ err = i;
+ ++table->refs[i];
goto out;
}
}
@@ -165,7 +166,7 @@ int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
table->entries[free] = 0;
goto out;
}
-
+ table->refs[free] = 1;
err = free;
++table->total;
out:
@@ -206,12 +207,16 @@ void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
struct mlx4_mac_table *table = &info->mac_table;
int index;
- index = find_index(dev, table, mac);
-
mutex_lock(&table->mutex);
+ index = find_index(dev, table, mac);
if (validate_index(dev, table, index))
goto out;
+ if (--table->refs[index]) {
+ mlx4_dbg(dev, "Have more references for index %d,"
+ "no need to modify mac table\n", index);
+ goto out;
+ }
table->entries[index] = 0;
mlx4_set_port_mac_table(dev, port, table->entries);
@@ -305,7 +310,7 @@ int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
}
EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
-static int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
+int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
int *index)
{
struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
@@ -379,7 +384,7 @@ int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
}
EXPORT_SYMBOL_GPL(mlx4_register_vlan);
-static void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index)
+void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index)
{
struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index f2d64435d8ef..e12e0d2e0ee0 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -353,6 +353,47 @@ static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox,
}
}
+static int update_vport_qp_param(struct mlx4_dev *dev,
+ struct mlx4_cmd_mailbox *inbox,
+ u8 slave)
+{
+ struct mlx4_qp_context *qpc = inbox->buf + 8;
+ struct mlx4_vport_oper_state *vp_oper;
+ struct mlx4_priv *priv;
+ u32 qp_type;
+ int port;
+
+ port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1;
+ priv = mlx4_priv(dev);
+ vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
+
+ if (MLX4_VGT != vp_oper->state.default_vlan) {
+ qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
+ if (MLX4_QP_ST_RC == qp_type)
+ return -EINVAL;
+
+ qpc->pri_path.vlan_index = vp_oper->vlan_idx;
+ qpc->pri_path.fl = (1 << 6) | (1 << 2); /* set cv bit and hide_cqe_vlan bit*/
+ qpc->pri_path.feup |= 1 << 3; /* set fvl bit */
+ qpc->pri_path.sched_queue &= 0xC7;
+ qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3;
+ mlx4_dbg(dev, "qp %d port %d Q 0x%x set vlan to %d vidx %d feup %x fl %x\n",
+ be32_to_cpu(qpc->local_qpn) & 0xffffff, port,
+ (int)(qpc->pri_path.sched_queue), vp_oper->state.default_vlan,
+ vp_oper->vlan_idx, (int)(qpc->pri_path.feup),
+ (int)(qpc->pri_path.fl));
+ }
+ if (vp_oper->state.spoofchk) {
+ qpc->pri_path.feup |= 1 << 5; /* set fsm bit */;
+ qpc->pri_path.grh_mylmc = (0x80 & qpc->pri_path.grh_mylmc) + vp_oper->mac_idx;
+ mlx4_dbg(dev, "spoof qp %d port %d feup 0x%x, myLmc 0x%x mindx %d\n",
+ be32_to_cpu(qpc->local_qpn) & 0xffffff, port,
+ (int)qpc->pri_path.feup, (int)qpc->pri_path.grh_mylmc,
+ vp_oper->mac_idx);
+ }
+ return 0;
+}
+
static int mpt_mask(struct mlx4_dev *dev)
{
return dev->caps.num_mpts - 1;
@@ -2798,6 +2839,9 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
update_pkey_index(dev, slave, inbox);
update_gid(dev, inbox, (u8)slave);
adjust_proxy_tun_qkey(dev, vhcr, qpc);
+ err = update_vport_qp_param(dev, inbox, slave);
+ if (err)
+ return err;
return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
}
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 25c364209a21..4e2d224dd680 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -348,6 +348,7 @@ struct cpsw_priv {
/* snapshot of IRQ numbers */
u32 irqs_table[4];
u32 num_irqs;
+ bool irq_enabled;
struct cpts *cpts;
u32 emac_port;
};
@@ -355,12 +356,15 @@ struct cpsw_priv {
#define napi_to_priv(napi) container_of(napi, struct cpsw_priv, napi)
#define for_each_slave(priv, func, arg...) \
do { \
- int idx; \
+ struct cpsw_slave *slave; \
+ int n; \
if (priv->data.dual_emac) \
(func)((priv)->slaves + priv->emac_port, ##arg);\
else \
- for (idx = 0; idx < (priv)->data.slaves; idx++) \
- (func)((priv)->slaves + idx, ##arg); \
+ for (n = (priv)->data.slaves, \
+ slave = (priv)->slaves; \
+ n; n--) \
+ (func)(slave++, ##arg); \
} while (0)
#define cpsw_get_slave_ndev(priv, __slave_no__) \
(priv->slaves[__slave_no__].ndev)
@@ -468,62 +472,69 @@ void cpsw_tx_handler(void *token, int len, int status)
void cpsw_rx_handler(void *token, int len, int status)
{
struct sk_buff *skb = token;
+ struct sk_buff *new_skb;
struct net_device *ndev = skb->dev;
struct cpsw_priv *priv = netdev_priv(ndev);
int ret = 0;
cpsw_dual_emac_src_port_detect(status, priv, ndev, skb);
- /* free and bail if we are shutting down */
- if (unlikely(!netif_running(ndev)) ||
- unlikely(!netif_carrier_ok(ndev))) {
+ if (unlikely(status < 0)) {
+ /* the interface is going down, skbs are purged */
dev_kfree_skb_any(skb);
return;
}
- if (likely(status >= 0)) {
+
+ new_skb = netdev_alloc_skb_ip_align(ndev, priv->rx_packet_max);
+ if (new_skb) {
skb_put(skb, len);
cpts_rx_timestamp(priv->cpts, skb);
skb->protocol = eth_type_trans(skb, ndev);
netif_receive_skb(skb);
priv->stats.rx_bytes += len;
priv->stats.rx_packets++;
- skb = NULL;
- }
-
- if (unlikely(!netif_running(ndev))) {
- if (skb)
- dev_kfree_skb_any(skb);
- return;
+ } else {
+ priv->stats.rx_dropped++;
+ new_skb = skb;
}
- if (likely(!skb)) {
- skb = netdev_alloc_skb_ip_align(ndev, priv->rx_packet_max);
- if (WARN_ON(!skb))
- return;
-
- ret = cpdma_chan_submit(priv->rxch, skb, skb->data,
- skb_tailroom(skb), 0, GFP_KERNEL);
- }
- WARN_ON(ret < 0);
+ ret = cpdma_chan_submit(priv->rxch, new_skb, new_skb->data,
+ skb_tailroom(new_skb), 0);
+ if (WARN_ON(ret < 0))
+ dev_kfree_skb_any(new_skb);
}
static irqreturn_t cpsw_interrupt(int irq, void *dev_id)
{
struct cpsw_priv *priv = dev_id;
+ u32 rx, tx, rx_thresh;
- if (likely(netif_running(priv->ndev))) {
- cpsw_intr_disable(priv);
+ rx_thresh = __raw_readl(&priv->wr_regs->rx_thresh_stat);
+ rx = __raw_readl(&priv->wr_regs->rx_stat);
+ tx = __raw_readl(&priv->wr_regs->tx_stat);
+ if (!rx_thresh && !rx && !tx)
+ return IRQ_NONE;
+
+ cpsw_intr_disable(priv);
+ if (priv->irq_enabled == true) {
cpsw_disable_irq(priv);
+ priv->irq_enabled = false;
+ }
+
+ if (netif_running(priv->ndev)) {
napi_schedule(&priv->napi);
- } else {
- priv = cpsw_get_slave_priv(priv, 1);
- if (likely(priv) && likely(netif_running(priv->ndev))) {
- cpsw_intr_disable(priv);
- cpsw_disable_irq(priv);
- napi_schedule(&priv->napi);
- }
+ return IRQ_HANDLED;
}
- return IRQ_HANDLED;
+
+ priv = cpsw_get_slave_priv(priv, 1);
+ if (!priv)
+ return IRQ_NONE;
+
+ if (netif_running(priv->ndev)) {
+ napi_schedule(&priv->napi);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
}
static int cpsw_poll(struct napi_struct *napi, int budget)
@@ -537,10 +548,16 @@ static int cpsw_poll(struct napi_struct *napi, int budget)
num_rx = cpdma_chan_process(priv->rxch, budget);
if (num_rx < budget) {
+ struct cpsw_priv *prim_cpsw;
+
napi_complete(napi);
cpsw_intr_enable(priv);
cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
- cpsw_enable_irq(priv);
+ prim_cpsw = cpsw_get_slave_priv(priv, 0);
+ if (prim_cpsw->irq_enabled == false) {
+ cpsw_enable_irq(priv);
+ prim_cpsw->irq_enabled = true;
+ }
}
if (num_rx || num_tx)
@@ -736,14 +753,14 @@ static inline int cpsw_tx_packet_submit(struct net_device *ndev,
{
if (!priv->data.dual_emac)
return cpdma_chan_submit(priv->txch, skb, skb->data,
- skb->len, 0, GFP_KERNEL);
+ skb->len, 0);
if (ndev == cpsw_get_slave_ndev(priv, 0))
return cpdma_chan_submit(priv->txch, skb, skb->data,
- skb->len, 1, GFP_KERNEL);
+ skb->len, 1);
else
return cpdma_chan_submit(priv->txch, skb, skb->data,
- skb->len, 2, GFP_KERNEL);
+ skb->len, 2);
}
static inline void cpsw_add_dual_emac_def_ale_entries(
@@ -867,9 +884,19 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
}
}
+static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
+{
+ if (!slave->phy)
+ return;
+ phy_stop(slave->phy);
+ phy_disconnect(slave->phy);
+ slave->phy = NULL;
+}
+
static int cpsw_ndo_open(struct net_device *ndev)
{
struct cpsw_priv *priv = netdev_priv(ndev);
+ struct cpsw_priv *prim_cpsw;
int i, ret;
u32 reg;
@@ -912,14 +939,16 @@ static int cpsw_ndo_open(struct net_device *ndev)
struct sk_buff *skb;
ret = -ENOMEM;
- skb = netdev_alloc_skb_ip_align(priv->ndev,
- priv->rx_packet_max);
+ skb = __netdev_alloc_skb_ip_align(priv->ndev,
+ priv->rx_packet_max, GFP_KERNEL);
if (!skb)
- break;
+ goto err_cleanup;
ret = cpdma_chan_submit(priv->rxch, skb, skb->data,
- skb_tailroom(skb), 0, GFP_KERNEL);
- if (WARN_ON(ret < 0))
- break;
+ skb_tailroom(skb), 0);
+ if (ret < 0) {
+ kfree_skb(skb);
+ goto err_cleanup;
+ }
}
/* continue even if we didn't manage to submit all
* receive descs
@@ -935,6 +964,14 @@ static int cpsw_ndo_open(struct net_device *ndev)
cpsw_set_coalesce(ndev, &coal);
}
+ prim_cpsw = cpsw_get_slave_priv(priv, 0);
+ if (prim_cpsw->irq_enabled == false) {
+ if ((priv == prim_cpsw) || !netif_running(prim_cpsw->ndev)) {
+ prim_cpsw->irq_enabled = true;
+ cpsw_enable_irq(prim_cpsw);
+ }
+ }
+
cpdma_ctlr_start(priv->dma);
cpsw_intr_enable(priv);
napi_enable(&priv->napi);
@@ -944,15 +981,13 @@ static int cpsw_ndo_open(struct net_device *ndev)
if (priv->data.dual_emac)
priv->slaves[priv->emac_port].open_stat = true;
return 0;
-}
-static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
-{
- if (!slave->phy)
- return;
- phy_stop(slave->phy);
- phy_disconnect(slave->phy);
- slave->phy = NULL;
+err_cleanup:
+ cpdma_ctlr_stop(priv->dma);
+ for_each_slave(priv, cpsw_slave_stop, priv);
+ pm_runtime_put_sync(&priv->pdev->dev);
+ netif_carrier_off(priv->ndev);
+ return ret;
}
static int cpsw_ndo_stop(struct net_device *ndev)
@@ -1598,7 +1633,7 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
priv_sl2->irqs_table[i] = priv->irqs_table[i];
priv_sl2->num_irqs = priv->num_irqs;
}
-
+ priv->irq_enabled = true;
ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
ndev->netdev_ops = &cpsw_netdev_ops;
@@ -1619,7 +1654,7 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
static int cpsw_probe(struct platform_device *pdev)
{
- struct cpsw_platform_data *data = pdev->dev.platform_data;
+ struct cpsw_platform_data *data;
struct net_device *ndev;
struct cpsw_priv *priv;
struct cpdma_params dma_params;
@@ -1832,7 +1867,7 @@ static int cpsw_probe(struct platform_device *pdev)
goto clean_ale_ret;
}
priv->irqs_table[k] = i;
- priv->num_irqs = k;
+ priv->num_irqs = k + 1;
}
k++;
}
@@ -1870,7 +1905,8 @@ static int cpsw_probe(struct platform_device *pdev)
return 0;
clean_irq_ret:
- free_irq(ndev->irq, priv);
+ for (i = 0; i < priv->num_irqs; i++)
+ free_irq(priv->irqs_table[i], priv);
clean_ale_ret:
cpsw_ale_destroy(priv->ale);
clean_dma_ret:
@@ -1893,7 +1929,8 @@ clean_slave_ret:
pm_runtime_disable(&pdev->dev);
kfree(priv->slaves);
clean_ndev_ret:
- free_netdev(ndev);
+ kfree(priv->data.slave_data);
+ free_netdev(priv->ndev);
return ret;
}
@@ -1901,12 +1938,17 @@ static int cpsw_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct cpsw_priv *priv = netdev_priv(ndev);
+ int i;
- pr_info("removing device");
platform_set_drvdata(pdev, NULL);
+ if (priv->data.dual_emac)
+ unregister_netdev(cpsw_get_slave_ndev(priv, 1));
+ unregister_netdev(ndev);
cpts_unregister(priv->cpts);
- free_irq(ndev->irq, priv);
+ for (i = 0; i < priv->num_irqs; i++)
+ free_irq(priv->irqs_table[i], priv);
+
cpsw_ale_destroy(priv->ale);
cpdma_chan_destroy(priv->txch);
cpdma_chan_destroy(priv->rxch);
@@ -1920,8 +1962,10 @@ static int cpsw_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
clk_put(priv->clk);
kfree(priv->slaves);
+ kfree(priv->data.slave_data);
+ if (priv->data.dual_emac)
+ free_netdev(cpsw_get_slave_ndev(priv, 1));
free_netdev(ndev);
-
return 0;
}
@@ -1957,6 +2001,7 @@ static const struct of_device_id cpsw_of_mtable[] = {
{ .compatible = "ti,cpsw", },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, cpsw_of_mtable);
static struct platform_driver cpsw_driver = {
.driver = {
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
index ee13dc78430c..49dfd592ac1e 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.c
+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
+#include <linux/delay.h>
#include "davinci_cpdma.h"
@@ -312,14 +313,16 @@ int cpdma_ctlr_start(struct cpdma_ctlr *ctlr)
}
if (ctlr->params.has_soft_reset) {
- unsigned long timeout = jiffies + HZ/10;
+ unsigned timeout = 10 * 100;
dma_reg_write(ctlr, CPDMA_SOFTRESET, 1);
- while (time_before(jiffies, timeout)) {
+ while (timeout) {
if (dma_reg_read(ctlr, CPDMA_SOFTRESET) == 0)
break;
+ udelay(10);
+ timeout--;
}
- WARN_ON(!time_before(jiffies, timeout));
+ WARN_ON(!timeout);
}
for (i = 0; i < ctlr->num_chan; i++) {
@@ -673,7 +676,7 @@ static void __cpdma_chan_submit(struct cpdma_chan *chan,
}
int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
- int len, int directed, gfp_t gfp_mask)
+ int len, int directed)
{
struct cpdma_ctlr *ctlr = chan->ctlr;
struct cpdma_desc __iomem *desc;
@@ -773,6 +776,7 @@ static int __cpdma_chan_process(struct cpdma_chan *chan)
struct cpdma_ctlr *ctlr = chan->ctlr;
struct cpdma_desc __iomem *desc;
int status, outlen;
+ int cb_status = 0;
struct cpdma_desc_pool *pool = ctlr->pool;
dma_addr_t desc_dma;
unsigned long flags;
@@ -808,8 +812,12 @@ static int __cpdma_chan_process(struct cpdma_chan *chan)
}
spin_unlock_irqrestore(&chan->lock, flags);
+ if (unlikely(status & CPDMA_DESC_TD_COMPLETE))
+ cb_status = -ENOSYS;
+ else
+ cb_status = status;
- __cpdma_chan_free(chan, desc, outlen, status);
+ __cpdma_chan_free(chan, desc, outlen, cb_status);
return status;
unlock_ret:
@@ -868,7 +876,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan)
struct cpdma_desc_pool *pool = ctlr->pool;
unsigned long flags;
int ret;
- unsigned long timeout;
+ unsigned timeout;
spin_lock_irqsave(&chan->lock, flags);
if (chan->state != CPDMA_STATE_ACTIVE) {
@@ -883,14 +891,15 @@ int cpdma_chan_stop(struct cpdma_chan *chan)
dma_reg_write(ctlr, chan->td, chan_linear(chan));
/* wait for teardown complete */
- timeout = jiffies + HZ/10; /* 100 msec */
- while (time_before(jiffies, timeout)) {
+ timeout = 100 * 100; /* 100 ms */
+ while (timeout) {
u32 cp = chan_read(chan, cp);
if ((cp & CPDMA_TEARDOWN_VALUE) == CPDMA_TEARDOWN_VALUE)
break;
- cpu_relax();
+ udelay(10);
+ timeout--;
}
- WARN_ON(!time_before(jiffies, timeout));
+ WARN_ON(!timeout);
chan_write(chan, cp, CPDMA_TEARDOWN_VALUE);
/* handle completed packets */
@@ -1031,3 +1040,5 @@ unlock_ret:
return ret;
}
EXPORT_SYMBOL_GPL(cpdma_control_set);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.h b/drivers/net/ethernet/ti/davinci_cpdma.h
index d9bcc6032fdc..86dee487f2f0 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.h
+++ b/drivers/net/ethernet/ti/davinci_cpdma.h
@@ -89,7 +89,7 @@ int cpdma_chan_dump(struct cpdma_chan *chan);
int cpdma_chan_get_stats(struct cpdma_chan *chan,
struct cpdma_chan_stats *stats);
int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
- int len, int directed, gfp_t gfp_mask);
+ int len, int directed);
int cpdma_chan_process(struct cpdma_chan *chan, int quota);
int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable);
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
index 6a0b47715a84..860e15ddfbcb 100644
--- a/drivers/net/ethernet/ti/davinci_emac.c
+++ b/drivers/net/ethernet/ti/davinci_emac.c
@@ -1037,7 +1037,7 @@ static void emac_rx_handler(void *token, int len, int status)
recycle:
ret = cpdma_chan_submit(priv->rxchan, skb, skb->data,
- skb_tailroom(skb), 0, GFP_KERNEL);
+ skb_tailroom(skb), 0);
WARN_ON(ret == -ENOMEM);
if (unlikely(ret < 0))
@@ -1092,7 +1092,7 @@ static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev)
skb_tx_timestamp(skb);
ret_code = cpdma_chan_submit(priv->txchan, skb, skb->data, skb->len,
- 0, GFP_KERNEL);
+ 0);
if (unlikely(ret_code != 0)) {
if (netif_msg_tx_err(priv) && net_ratelimit())
dev_err(emac_dev, "DaVinci EMAC: desc submit failed");
@@ -1558,7 +1558,7 @@ static int emac_dev_open(struct net_device *ndev)
break;
ret = cpdma_chan_submit(priv->rxchan, skb, skb->data,
- skb_tailroom(skb), 0, GFP_KERNEL);
+ skb_tailroom(skb), 0);
if (WARN_ON(ret < 0))
break;
}
diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c
index d04a622b08d4..12aec173564c 100644
--- a/drivers/net/ethernet/ti/davinci_mdio.c
+++ b/drivers/net/ethernet/ti/davinci_mdio.c
@@ -485,6 +485,7 @@ static const struct of_device_id davinci_mdio_of_mtable[] = {
{ .compatible = "ti,davinci_mdio", },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, davinci_mdio_of_mtable);
static struct platform_driver davinci_mdio_driver = {
.driver = {