aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/ibm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/ibm')
-rw-r--r--drivers/net/ethernet/ibm/Kconfig10
-rw-r--r--drivers/net/ethernet/ibm/Makefile1
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea.h27
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_ethtool.c43
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_hw.h27
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_main.c684
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_phyp.c14
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_phyp.h24
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_qmr.c57
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_qmr.h4
-rw-r--r--drivers/net/ethernet/ibm/emac/core.c129
-rw-r--r--drivers/net/ethernet/ibm/emac/core.h16
-rw-r--r--drivers/net/ethernet/ibm/emac/debug.c4
-rw-r--r--drivers/net/ethernet/ibm/emac/debug.h16
-rw-r--r--drivers/net/ethernet/ibm/emac/emac.h4
-rw-r--r--drivers/net/ethernet/ibm/emac/mal.c59
-rw-r--r--drivers/net/ethernet/ibm/emac/mal.h22
-rw-r--r--drivers/net/ethernet/ibm/emac/phy.c2
-rw-r--r--drivers/net/ethernet/ibm/emac/phy.h2
-rw-r--r--drivers/net/ethernet/ibm/emac/rgmii.c35
-rw-r--r--drivers/net/ethernet/ibm/emac/rgmii.h20
-rw-r--r--drivers/net/ethernet/ibm/emac/tah.c28
-rw-r--r--drivers/net/ethernet/ibm/emac/tah.h16
-rw-r--r--drivers/net/ethernet/ibm/emac/zmii.c32
-rw-r--r--drivers/net/ethernet/ibm/emac/zmii.h20
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c133
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.h23
-rw-r--r--drivers/net/ethernet/ibm/iseries_veth.c1710
28 files changed, 601 insertions, 2561 deletions
diff --git a/drivers/net/ethernet/ibm/Kconfig b/drivers/net/ethernet/ibm/Kconfig
index 9e16f3fa97b..563a1ac71db 100644
--- a/drivers/net/ethernet/ibm/Kconfig
+++ b/drivers/net/ethernet/ibm/Kconfig
@@ -5,8 +5,7 @@
config NET_VENDOR_IBM
bool "IBM devices"
default y
- depends on MCA || PPC_PSERIES || PPC_PSERIES || PPC_DCR || \
- (IBMEBUS && INET && SPARSEMEM)
+ depends on PPC_PSERIES || PPC_DCR || (IBMEBUS && SPARSEMEM)
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -29,16 +28,11 @@ config IBMVETH
To compile this driver as a module, choose M here. The module will
be called ibmveth.
-config ISERIES_VETH
- tristate "iSeries Virtual Ethernet driver support"
- depends on PPC_ISERIES
-
source "drivers/net/ethernet/ibm/emac/Kconfig"
config EHEA
tristate "eHEA Ethernet support"
- depends on IBMEBUS && INET && SPARSEMEM
- select INET_LRO
+ depends on IBMEBUS && SPARSEMEM
---help---
This driver supports the IBM pSeries eHEA ethernet adapter.
diff --git a/drivers/net/ethernet/ibm/Makefile b/drivers/net/ethernet/ibm/Makefile
index 5a7d4e9ac80..2f04e71a592 100644
--- a/drivers/net/ethernet/ibm/Makefile
+++ b/drivers/net/ethernet/ibm/Makefile
@@ -3,6 +3,5 @@
#
obj-$(CONFIG_IBMVETH) += ibmveth.o
-obj-$(CONFIG_ISERIES_VETH) += iseries_veth.o
obj-$(CONFIG_IBM_EMAC) += emac/
obj-$(CONFIG_EHEA) += ehea/
diff --git a/drivers/net/ethernet/ibm/ehea/ehea.h b/drivers/net/ethernet/ibm/ehea/ehea.h
index 0b8e6a97a98..6be7b9839f3 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea.h
+++ b/drivers/net/ethernet/ibm/ehea/ehea.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/net/ehea/ehea.h
+ * linux/drivers/net/ethernet/ibm/ehea/ehea.h
*
* eHEA ethernet device driver for IBM eServer System p
*
@@ -33,10 +33,8 @@
#include <linux/ethtool.h>
#include <linux/vmalloc.h>
#include <linux/if_vlan.h>
-#include <linux/inet_lro.h>
#include <asm/ibmebus.h>
-#include <asm/abs_addr.h>
#include <asm/io.h>
#define DRV_NAME "ehea"
@@ -58,15 +56,13 @@
#define EHEA_MIN_ENTRIES_QP 127
#define EHEA_SMALL_QUEUES
-#define EHEA_NUM_TX_QP 1
-#define EHEA_LRO_MAX_AGGR 64
#ifdef EHEA_SMALL_QUEUES
#define EHEA_MAX_CQE_COUNT 1023
#define EHEA_DEF_ENTRIES_SQ 1023
-#define EHEA_DEF_ENTRIES_RQ1 4095
+#define EHEA_DEF_ENTRIES_RQ1 1023
#define EHEA_DEF_ENTRIES_RQ2 1023
-#define EHEA_DEF_ENTRIES_RQ3 1023
+#define EHEA_DEF_ENTRIES_RQ3 511
#else
#define EHEA_MAX_CQE_COUNT 4080
#define EHEA_DEF_ENTRIES_SQ 4080
@@ -83,18 +79,16 @@
#define EHEA_SG_RQ3 0
#define EHEA_MAX_PACKET_SIZE 9022 /* for jumbo frames */
-#define EHEA_RQ2_PKT_SIZE 1522
+#define EHEA_RQ2_PKT_SIZE 2048
#define EHEA_L_PKT_SIZE 256 /* low latency */
-#define MAX_LRO_DESCRIPTORS 8
-
/* Send completion signaling */
/* Protection Domain Identifier */
#define EHEA_PD_ID 0xaabcdeff
#define EHEA_RQ2_THRESHOLD 1
-#define EHEA_RQ3_THRESHOLD 9 /* use RQ3 threshold of 1522 bytes */
+#define EHEA_RQ3_THRESHOLD 4 /* use RQ3 threshold of 2048 bytes */
#define EHEA_SPEED_10G 10000
#define EHEA_SPEED_1G 1000
@@ -363,7 +357,6 @@ struct ehea_port_res {
struct port_stats p_stats;
struct ehea_mr send_mr; /* send memory region */
struct ehea_mr recv_mr; /* receive memory region */
- spinlock_t xmit_lock;
struct ehea_port *port;
char int_recv_name[EHEA_IRQ_NAME_SIZE];
char int_send_name[EHEA_IRQ_NAME_SIZE];
@@ -376,8 +369,6 @@ struct ehea_port_res {
struct ehea_q_skb_arr rq3_skba;
struct ehea_q_skb_arr sq_skba;
int sq_skba_size;
- spinlock_t netif_queue;
- int queue_stopped;
int swqe_refill_th;
atomic_t swqe_avail;
int swqe_ll_count;
@@ -386,9 +377,6 @@ struct ehea_port_res {
u64 tx_bytes;
u64 rx_packets;
u64 rx_bytes;
- u32 poll_counter;
- struct net_lro_mgr lro_mgr;
- struct net_lro_desc lro_desc[MAX_LRO_DESCRIPTORS];
int sq_restart_flag;
};
@@ -453,7 +441,7 @@ struct ehea_bcmc_reg_array {
struct ehea_port {
struct ehea_adapter *adapter; /* adapter that owns this port */
struct net_device *netdev;
- struct net_device_stats stats;
+ struct rtnl_link_stats64 stats;
struct ehea_port_res port_res[EHEA_MAX_PORT_RES];
struct platform_device ofdev; /* Open Firmware Device */
struct ehea_mc_list *mc_list; /* Multicast MAC addresses */
@@ -464,8 +452,6 @@ struct ehea_port {
char int_aff_name[EHEA_IRQ_NAME_SIZE];
int allmulti; /* Indicates IFF_ALLMULTI state */
int promisc; /* Indicates IFF_PROMISC state */
- int num_tx_qps;
- int num_add_tx_qps;
int num_mcs;
int resets;
unsigned long flags;
@@ -475,7 +461,6 @@ struct ehea_port {
u32 msg_enable;
u32 sig_comp_iv;
u32 state;
- u32 lro_max_aggr;
u8 phy_link;
u8 full_duplex;
u8 autoneg;
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c b/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
index 7f642aef5e8..85a3866459c 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/net/ehea/ehea_ethtool.c
+ * linux/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
*
* eHEA ethernet device driver for IBM eServer System p
*
@@ -63,8 +63,8 @@ static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->duplex = port->full_duplex == 1 ?
DUPLEX_FULL : DUPLEX_HALF;
} else {
- speed = ~0;
- cmd->duplex = -1;
+ speed = SPEED_UNKNOWN;
+ cmd->duplex = DUPLEX_UNKNOWN;
}
ethtool_cmd_speed_set(cmd, speed);
@@ -180,7 +180,7 @@ static void ehea_set_msglevel(struct net_device *dev, u32 value)
port->msg_enable = value;
}
-static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
+static const char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
{"sig_comp_iv"},
{"swqe_refill_th"},
{"port resets"},
@@ -189,7 +189,6 @@ static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
{"IP cksum errors"},
{"Frame cksum errors"},
{"num SQ stopped"},
- {"SQ stopped"},
{"PR0 free_swqes"},
{"PR1 free_swqes"},
{"PR2 free_swqes"},
@@ -198,9 +197,14 @@ static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
{"PR5 free_swqes"},
{"PR6 free_swqes"},
{"PR7 free_swqes"},
- {"LRO aggregated"},
- {"LRO flushed"},
- {"LRO no_desc"},
+ {"PR8 free_swqes"},
+ {"PR9 free_swqes"},
+ {"PR10 free_swqes"},
+ {"PR11 free_swqes"},
+ {"PR12 free_swqes"},
+ {"PR13 free_swqes"},
+ {"PR14 free_swqes"},
+ {"PR15 free_swqes"},
};
static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -255,28 +259,11 @@ static void ehea_get_ethtool_stats(struct net_device *dev,
tmp += port->port_res[k].p_stats.queue_stopped;
data[i++] = tmp;
- for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
- tmp |= port->port_res[k].queue_stopped;
- data[i++] = tmp;
-
- for (k = 0; k < 8; k++)
+ for (k = 0; k < 16; k++)
data[i++] = atomic_read(&port->port_res[k].swqe_avail);
-
- for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
- tmp |= port->port_res[k].lro_mgr.stats.aggregated;
- data[i++] = tmp;
-
- for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
- tmp |= port->port_res[k].lro_mgr.stats.flushed;
- data[i++] = tmp;
-
- for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
- tmp |= port->port_res[k].lro_mgr.stats.no_desc;
- data[i++] = tmp;
-
}
-const struct ethtool_ops ehea_ethtool_ops = {
+static const struct ethtool_ops ehea_ethtool_ops = {
.get_settings = ehea_get_settings,
.get_drvinfo = ehea_get_drvinfo,
.get_msglevel = ehea_get_msglevel,
@@ -291,5 +278,5 @@ const struct ethtool_ops ehea_ethtool_ops = {
void ehea_set_ethtool_ops(struct net_device *netdev)
{
- SET_ETHTOOL_OPS(netdev, &ehea_ethtool_ops);
+ netdev->ethtool_ops = &ehea_ethtool_ops;
}
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_hw.h b/drivers/net/ethernet/ibm/ehea/ehea_hw.h
index 567981b4b2c..180d4128a71 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_hw.h
+++ b/drivers/net/ethernet/ibm/ehea/ehea_hw.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/net/ehea/ehea_hw.h
+ * linux/drivers/net/ethernet/ibm/ehea/ehea_hw.h
*
* eHEA ethernet device driver for IBM eServer System p
*
@@ -210,36 +210,11 @@ static inline void epa_store_acc(struct h_epa epa, u32 offset, u64 value)
__raw_writeq(value, (void __iomem *)(epa.addr + offset));
}
-#define epa_store_eq(epa, offset, value)\
- epa_store(epa, EQTEMM_OFFSET(offset), value)
-#define epa_load_eq(epa, offset)\
- epa_load(epa, EQTEMM_OFFSET(offset))
-
#define epa_store_cq(epa, offset, value)\
epa_store(epa, CQTEMM_OFFSET(offset), value)
#define epa_load_cq(epa, offset)\
epa_load(epa, CQTEMM_OFFSET(offset))
-#define epa_store_qp(epa, offset, value)\
- epa_store(epa, QPTEMM_OFFSET(offset), value)
-#define epa_load_qp(epa, offset)\
- epa_load(epa, QPTEMM_OFFSET(offset))
-
-#define epa_store_qped(epa, offset, value)\
- epa_store(epa, QPEDMM_OFFSET(offset), value)
-#define epa_load_qped(epa, offset)\
- epa_load(epa, QPEDMM_OFFSET(offset))
-
-#define epa_store_mrmw(epa, offset, value)\
- epa_store(epa, MRMWMM_OFFSET(offset), value)
-#define epa_load_mrmw(epa, offset)\
- epa_load(epa, MRMWMM_OFFSET(offset))
-
-#define epa_store_base(epa, offset, value)\
- epa_store(epa, HCAGR_OFFSET(offset), value)
-#define epa_load_base(epa, offset)\
- epa_load(epa, HCAGR_OFFSET(offset))
-
static inline void ehea_update_sqa(struct ehea_qp *qp, u16 nr_wqes)
{
struct h_epa epa = qp->epas.kernel;
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index dfefe809c48..a0b418e007a 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/net/ehea/ehea_main.c
+ * linux/drivers/net/ethernet/ibm/ehea/ehea_main.c
*
* eHEA ethernet device driver for IBM eServer System p
*
@@ -28,6 +28,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/device.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
@@ -61,10 +62,7 @@ static int rq1_entries = EHEA_DEF_ENTRIES_RQ1;
static int rq2_entries = EHEA_DEF_ENTRIES_RQ2;
static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
static int sq_entries = EHEA_DEF_ENTRIES_SQ;
-static int use_mcs;
-static int use_lro;
-static int lro_max_aggr = EHEA_LRO_MAX_AGGR;
-static int num_tx_qps = EHEA_NUM_TX_QP;
+static int use_mcs = 1;
static int prop_carrier_state;
module_param(msg_level, int, 0);
@@ -74,45 +72,49 @@ module_param(rq3_entries, int, 0);
module_param(sq_entries, int, 0);
module_param(prop_carrier_state, int, 0);
module_param(use_mcs, int, 0);
-module_param(use_lro, int, 0);
-module_param(lro_max_aggr, int, 0);
-module_param(num_tx_qps, int, 0);
-MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS");
MODULE_PARM_DESC(msg_level, "msg_level");
MODULE_PARM_DESC(prop_carrier_state, "Propagate carrier state of physical "
"port to stack. 1:yes, 0:no. Default = 0 ");
MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 "
- "[2^x - 1], x = [6..14]. Default = "
+ "[2^x - 1], x = [7..14]. Default = "
__MODULE_STRING(EHEA_DEF_ENTRIES_RQ3) ")");
MODULE_PARM_DESC(rq2_entries, "Number of entries for Receive Queue 2 "
- "[2^x - 1], x = [6..14]. Default = "
+ "[2^x - 1], x = [7..14]. Default = "
__MODULE_STRING(EHEA_DEF_ENTRIES_RQ2) ")");
MODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 "
- "[2^x - 1], x = [6..14]. Default = "
+ "[2^x - 1], x = [7..14]. Default = "
__MODULE_STRING(EHEA_DEF_ENTRIES_RQ1) ")");
MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue "
- "[2^x - 1], x = [6..14]. Default = "
+ "[2^x - 1], x = [7..14]. Default = "
__MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")");
-MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 0 ");
-
-MODULE_PARM_DESC(lro_max_aggr, " LRO: Max packets to be aggregated. Default = "
- __MODULE_STRING(EHEA_LRO_MAX_AGGR));
-MODULE_PARM_DESC(use_lro, " Large Receive Offload, 1: enable, 0: disable, "
- "Default = 0");
+MODULE_PARM_DESC(use_mcs, " Multiple receive queues, 1: enable, 0: disable, "
+ "Default = 1");
static int port_name_cnt;
static LIST_HEAD(adapter_list);
static unsigned long ehea_driver_flags;
static DEFINE_MUTEX(dlpar_mem_lock);
-struct ehea_fw_handle_array ehea_fw_handles;
-struct ehea_bcmc_reg_array ehea_bcmc_regs;
+static struct ehea_fw_handle_array ehea_fw_handles;
+static struct ehea_bcmc_reg_array ehea_bcmc_regs;
-static int __devinit ehea_probe_adapter(struct platform_device *dev,
- const struct of_device_id *id);
+static int ehea_probe_adapter(struct platform_device *dev);
-static int __devexit ehea_remove(struct platform_device *dev);
+static int ehea_remove(struct platform_device *dev);
+
+static struct of_device_id ehea_module_device_table[] = {
+ {
+ .name = "lhea",
+ .compatible = "IBM,lhea",
+ },
+ {
+ .type = "network",
+ .compatible = "IBM,lhea-ethernet",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ehea_module_device_table);
static struct of_device_id ehea_device_table[] = {
{
@@ -121,9 +123,8 @@ static struct of_device_id ehea_device_table[] = {
},
{},
};
-MODULE_DEVICE_TABLE(of, ehea_device_table);
-static struct of_platform_driver ehea_driver = {
+static struct platform_driver ehea_driver = {
.driver = {
.name = "ehea",
.owner = THIS_MODULE,
@@ -144,7 +145,7 @@ void ehea_dump(void *adr, int len, char *msg)
}
}
-void ehea_schedule_port_reset(struct ehea_port *port)
+static void ehea_schedule_port_reset(struct ehea_port *port)
{
if (!test_bit(__EHEA_DISABLE_PORT_RESET, &port->flags))
schedule_work(&port->reset_task);
@@ -173,7 +174,7 @@ static void ehea_update_firmware_handles(void)
continue;
num_ports++;
- num_portres += port->num_def_qps + port->num_add_tx_qps;
+ num_portres += port->num_def_qps;
}
}
@@ -199,9 +200,7 @@ static void ehea_update_firmware_handles(void)
(num_ports == 0))
continue;
- for (l = 0;
- l < port->num_def_qps + port->num_add_tx_qps;
- l++) {
+ for (l = 0; l < port->num_def_qps; l++) {
struct ehea_port_res *pr = &port->port_res[l];
arr[i].adh = adapter->handle;
@@ -303,16 +302,18 @@ static void ehea_update_bcmc_registrations(void)
arr[i].adh = adapter->handle;
arr[i].port_id = port->logical_port_id;
- arr[i].reg_type = EHEA_BCMC_SCOPE_ALL |
- EHEA_BCMC_MULTICAST |
+ arr[i].reg_type = EHEA_BCMC_MULTICAST |
EHEA_BCMC_UNTAGGED;
+ if (mc_entry->macaddr == 0)
+ arr[i].reg_type |= EHEA_BCMC_SCOPE_ALL;
arr[i++].macaddr = mc_entry->macaddr;
arr[i].adh = adapter->handle;
arr[i].port_id = port->logical_port_id;
- arr[i].reg_type = EHEA_BCMC_SCOPE_ALL |
- EHEA_BCMC_MULTICAST |
+ arr[i].reg_type = EHEA_BCMC_MULTICAST |
EHEA_BCMC_VLANID_ALL;
+ if (mc_entry->macaddr == 0)
+ arr[i].reg_type |= EHEA_BCMC_SCOPE_ALL;
arr[i++].macaddr = mc_entry->macaddr;
num_registrations -= 2;
}
@@ -327,10 +328,10 @@ out:
spin_unlock_irqrestore(&ehea_bcmc_regs.lock, flags);
}
-static struct net_device_stats *ehea_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *ehea_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
{
struct ehea_port *port = netdev_priv(dev);
- struct net_device_stats *stats = &port->stats;
u64 rx_packets = 0, tx_packets = 0, rx_bytes = 0, tx_bytes = 0;
int i;
@@ -339,7 +340,7 @@ static struct net_device_stats *ehea_get_stats(struct net_device *dev)
rx_bytes += port->port_res[i].rx_bytes;
}
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ for (i = 0; i < port->num_def_qps; i++) {
tx_packets += port->port_res[i].tx_packets;
tx_bytes += port->port_res[i].tx_bytes;
}
@@ -349,7 +350,9 @@ static struct net_device_stats *ehea_get_stats(struct net_device *dev)
stats->tx_bytes = tx_bytes;
stats->rx_packets = rx_packets;
- return &port->stats;
+ stats->multicast = port->stats.multicast;
+ stats->rx_errors = port->stats.rx_errors;
+ return stats;
}
static void ehea_update_stats(struct work_struct *work)
@@ -357,7 +360,7 @@ static void ehea_update_stats(struct work_struct *work)
struct ehea_port *port =
container_of(work, struct ehea_port, stats_work.work);
struct net_device *dev = port->netdev;
- struct net_device_stats *stats = &port->stats;
+ struct rtnl_link_stats64 *stats = &port->stats;
struct hcp_ehea_port_cb2 *cb2;
u64 hret;
@@ -384,7 +387,8 @@ static void ehea_update_stats(struct work_struct *work)
out_herr:
free_page((unsigned long)cb2);
resched:
- schedule_delayed_work(&port->stats_work, msecs_to_jiffies(1000));
+ schedule_delayed_work(&port->stats_work,
+ round_jiffies_relative(msecs_to_jiffies(1000)));
}
static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes)
@@ -410,7 +414,6 @@ static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes)
skb_arr_rq1[index] = netdev_alloc_skb(dev,
EHEA_L_PKT_SIZE);
if (!skb_arr_rq1[index]) {
- netdev_info(dev, "Unable to allocate enough skb in the array\n");
pr->rq1_skba.os_skbs = fill_wqes - i;
break;
}
@@ -440,10 +443,8 @@ static void ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a)
for (i = 0; i < nr_rq1a; i++) {
skb_arr_rq1[i] = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE);
- if (!skb_arr_rq1[i]) {
- netdev_info(dev, "Not enough memory to allocate skb array\n");
+ if (!skb_arr_rq1[i])
break;
- }
}
/* Ring doorbell */
ehea_update_rq1a(pr->qp, i - 1);
@@ -490,7 +491,7 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
skb_arr[index] = skb;
tmp_addr = ehea_map_vaddr(skb->data);
if (tmp_addr == -1) {
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
q_skba->os_skbs = fill_wqes - i;
ret = 0;
break;
@@ -551,7 +552,8 @@ static inline int ehea_check_cqe(struct ehea_cqe *cqe, int *rq_num)
}
static inline void ehea_fill_skb(struct net_device *dev,
- struct sk_buff *skb, struct ehea_cqe *cqe)
+ struct sk_buff *skb, struct ehea_cqe *cqe,
+ struct ehea_port_res *pr)
{
int length = cqe->num_bytes_transfered - 4; /*remove CRC */
@@ -565,6 +567,8 @@ static inline void ehea_fill_skb(struct net_device *dev,
skb->csum = csum_unfold(~cqe->inet_checksum_value);
} else
skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ skb_record_rx_queue(skb, pr - &pr->port->port_res[0]);
}
static inline struct sk_buff *get_skb_by_index(struct sk_buff **skb_array,
@@ -657,49 +661,6 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
return 0;
}
-static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
- void **tcph, u64 *hdr_flags, void *priv)
-{
- struct ehea_cqe *cqe = priv;
- unsigned int ip_len;
- struct iphdr *iph;
-
- /* non tcp/udp packets */
- if (!cqe->header_length)
- return -1;
-
- /* non tcp packet */
- skb_reset_network_header(skb);
- iph = ip_hdr(skb);
- if (iph->protocol != IPPROTO_TCP)
- return -1;
-
- ip_len = ip_hdrlen(skb);
- skb_set_transport_header(skb, ip_len);
- *tcph = tcp_hdr(skb);
-
- /* check if ip header and tcp header are complete */
- if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb))
- return -1;
-
- *hdr_flags = LRO_IPV4 | LRO_TCP;
- *iphdr = iph;
-
- return 0;
-}
-
-static void ehea_proc_skb(struct ehea_port_res *pr, struct ehea_cqe *cqe,
- struct sk_buff *skb)
-{
- if (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
- __vlan_hwaccel_put_tag(skb, cqe->vlan_tag);
-
- if (skb->dev->features & NETIF_F_LRO)
- lro_receive_skb(&pr->lro_mgr, skb, cqe);
- else
- netif_receive_skb(skb);
-}
-
static int ehea_proc_rwqes(struct net_device *dev,
struct ehea_port_res *pr,
int budget)
@@ -743,14 +704,12 @@ static int ehea_proc_rwqes(struct net_device *dev,
skb = netdev_alloc_skb(dev,
EHEA_L_PKT_SIZE);
- if (!skb) {
- netdev_err(dev, "Not enough memory to allocate skb\n");
+ if (!skb)
break;
- }
}
skb_copy_to_linear_data(skb, ((char *)cqe) + 64,
cqe->num_bytes_transfered - 4);
- ehea_fill_skb(dev, skb, cqe);
+ ehea_fill_skb(dev, skb, cqe, pr);
} else if (rq == 2) {
/* RQ2 */
skb = get_skb_by_index(skb_arr_rq2,
@@ -760,7 +719,7 @@ static int ehea_proc_rwqes(struct net_device *dev,
"rq2: skb=NULL\n");
break;
}
- ehea_fill_skb(dev, skb, cqe);
+ ehea_fill_skb(dev, skb, cqe, pr);
processed_rq2++;
} else {
/* RQ3 */
@@ -771,12 +730,17 @@ static int ehea_proc_rwqes(struct net_device *dev,
"rq3: skb=NULL\n");
break;
}
- ehea_fill_skb(dev, skb, cqe);
+ ehea_fill_skb(dev, skb, cqe, pr);
processed_rq3++;
}
processed_bytes += skb->len;
- ehea_proc_skb(pr, cqe, skb);
+
+ if (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+ cqe->vlan_tag);
+
+ napi_gro_receive(&pr->napi, skb);
} else {
pr->p_stats.poll_receive_errors++;
port_reset = ehea_treat_poll_error(pr, rq, cqe,
@@ -787,8 +751,6 @@ static int ehea_proc_rwqes(struct net_device *dev,
}
cqe = ehea_poll_rq1(qp, &wqe_index);
}
- if (dev->features & NETIF_F_LRO)
- lro_flush_all(&pr->lro_mgr);
pr->rx_packets += processed;
pr->rx_bytes += processed_bytes;
@@ -806,7 +768,7 @@ static void reset_sq_restart_flag(struct ehea_port *port)
{
int i;
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ for (i = 0; i < port->num_def_qps; i++) {
struct ehea_port_res *pr = &port->port_res[i];
pr->sq_restart_flag = 0;
}
@@ -819,7 +781,7 @@ static void check_sqs(struct ehea_port *port)
int swqe_index;
int i, k;
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ for (i = 0; i < port->num_def_qps; i++) {
struct ehea_port_res *pr = &port->port_res[i];
int ret;
k = 0;
@@ -857,7 +819,8 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
int cqe_counter = 0;
int swqe_av = 0;
int index;
- unsigned long flags;
+ struct netdev_queue *txq = netdev_get_tx_queue(pr->port->netdev,
+ pr - &pr->port->port_res[0]);
cqe = ehea_poll_cq(send_cq);
while (cqe && (quota > 0)) {
@@ -894,7 +857,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
skb = pr->sq_skba.arr[index];
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
pr->sq_skba.arr[index] = NULL;
}
@@ -907,20 +870,20 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
ehea_update_feca(send_cq, cqe_counter);
atomic_add(swqe_av, &pr->swqe_avail);
- spin_lock_irqsave(&pr->netif_queue, flags);
-
- if (pr->queue_stopped && (atomic_read(&pr->swqe_avail)
- >= pr->swqe_refill_th)) {
- netif_wake_queue(pr->port->netdev);
- pr->queue_stopped = 0;
+ if (unlikely(netif_tx_queue_stopped(txq) &&
+ (atomic_read(&pr->swqe_avail) >= pr->swqe_refill_th))) {
+ __netif_tx_lock(txq, smp_processor_id());
+ if (netif_tx_queue_stopped(txq) &&
+ (atomic_read(&pr->swqe_avail) >= pr->swqe_refill_th))
+ netif_tx_wake_queue(txq);
+ __netif_tx_unlock(txq);
}
- spin_unlock_irqrestore(&pr->netif_queue, flags);
+
wake_up(&pr->port->swqe_avail_wq);
return cqe;
}
-#define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16
#define EHEA_POLL_MAX_CQES 65535
static int ehea_poll(struct napi_struct *napi, int budget)
@@ -930,18 +893,13 @@ static int ehea_poll(struct napi_struct *napi, int budget)
struct net_device *dev = pr->port->netdev;
struct ehea_cqe *cqe;
struct ehea_cqe *cqe_skb = NULL;
- int force_irq, wqe_index;
+ int wqe_index;
int rx = 0;
- force_irq = (pr->poll_counter > EHEA_NAPI_POLL_NUM_BEFORE_IRQ);
cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES);
+ rx += ehea_proc_rwqes(dev, pr, budget - rx);
- if (!force_irq)
- rx += ehea_proc_rwqes(dev, pr, budget - rx);
-
- while ((rx != budget) || force_irq) {
- pr->poll_counter = 0;
- force_irq = 0;
+ while (rx != budget) {
napi_complete(napi);
ehea_reset_cq_ep(pr->recv_cq);
ehea_reset_cq_ep(pr->send_cq);
@@ -961,7 +919,6 @@ static int ehea_poll(struct napi_struct *napi, int budget)
rx += ehea_proc_rwqes(dev, pr, budget - rx);
}
- pr->poll_counter++;
return rx;
}
@@ -1113,13 +1070,6 @@ int ehea_sense_port_attr(struct ehea_port *port)
goto out_free;
}
- port->num_tx_qps = num_tx_qps;
-
- if (port->num_def_qps >= port->num_tx_qps)
- port->num_add_tx_qps = 0;
- else
- port->num_add_tx_qps = port->num_tx_qps - port->num_def_qps;
-
ret = 0;
out_free:
if (ret || netif_msg_probe(port))
@@ -1251,7 +1201,7 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
netif_info(port, link, dev,
"Logical port down\n");
netif_carrier_off(dev);
- netif_stop_queue(dev);
+ netif_tx_disable(dev);
}
if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PORT_UP, eqe)) {
@@ -1282,7 +1232,7 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
case EHEA_EC_PORT_MALFUNC:
netdev_info(dev, "Port malfunction\n");
netif_carrier_off(dev);
- netif_stop_queue(dev);
+ netif_tx_disable(dev);
break;
default:
netdev_err(dev, "unknown event code %x, eqe=0x%llX\n", ec, eqe);
@@ -1348,7 +1298,7 @@ static int ehea_reg_interrupts(struct net_device *dev)
ret = ibmebus_request_irq(port->qp_eq->attr.ist1,
ehea_qp_aff_irq_handler,
- IRQF_DISABLED, port->int_aff_name, port);
+ 0, port->int_aff_name, port);
if (ret) {
netdev_err(dev, "failed registering irq for qp_aff_irq_handler:ist=%X\n",
port->qp_eq->attr.ist1);
@@ -1360,14 +1310,13 @@ static int ehea_reg_interrupts(struct net_device *dev)
port->qp_eq->attr.ist1);
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ for (i = 0; i < port->num_def_qps; i++) {
pr = &port->port_res[i];
snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1,
"%s-queue%d", dev->name, i);
ret = ibmebus_request_irq(pr->eq->attr.ist1,
ehea_recv_irq_handler,
- IRQF_DISABLED, pr->int_send_name,
- pr);
+ 0, pr->int_send_name, pr);
if (ret) {
netdev_err(dev, "failed registering irq for ehea_queue port_res_nr:%d, ist=%X\n",
i, pr->eq->attr.ist1);
@@ -1403,7 +1352,7 @@ static void ehea_free_interrupts(struct net_device *dev)
/* send */
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ for (i = 0; i < port->num_def_qps; i++) {
pr = &port->port_res[i];
ibmebus_free_irq(pr->eq->attr.ist1, pr);
netif_info(port, intr, dev,
@@ -1466,7 +1415,7 @@ out:
return ret;
}
-int ehea_gen_smrs(struct ehea_port_res *pr)
+static int ehea_gen_smrs(struct ehea_port_res *pr)
{
int ret;
struct ehea_adapter *adapter = pr->port->adapter;
@@ -1488,7 +1437,7 @@ out:
return -EIO;
}
-int ehea_rem_smrs(struct ehea_port_res *pr)
+static int ehea_rem_smrs(struct ehea_port_res *pr)
{
if ((ehea_rem_mr(&pr->send_mr)) ||
(ehea_rem_mr(&pr->recv_mr)))
@@ -1534,8 +1483,6 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
pr->rx_packets = rx_packets;
pr->port = port;
- spin_lock_init(&pr->xmit_lock);
- spin_lock_init(&pr->netif_queue);
pr->eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
if (!pr->eq) {
@@ -1626,15 +1573,6 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
netif_napi_add(pr->port->netdev, &pr->napi, ehea_poll, 64);
- pr->lro_mgr.max_aggr = pr->port->lro_max_aggr;
- pr->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS;
- pr->lro_mgr.lro_arr = pr->lro_desc;
- pr->lro_mgr.get_skb_header = get_skb_hdr;
- pr->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
- pr->lro_mgr.dev = port->netdev;
- pr->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
- pr->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
-
ret = 0;
goto out;
@@ -1691,96 +1629,35 @@ static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr)
return ret;
}
-/*
- * The write_* functions store information in swqe which is used by
- * the hardware to calculate the ip/tcp/udp checksum
- */
-
-static inline void write_ip_start_end(struct ehea_swqe *swqe,
- const struct sk_buff *skb)
-{
- swqe->ip_start = skb_network_offset(skb);
- swqe->ip_end = (u8)(swqe->ip_start + ip_hdrlen(skb) - 1);
-}
-
-static inline void write_tcp_offset_end(struct ehea_swqe *swqe,
- const struct sk_buff *skb)
-{
- swqe->tcp_offset =
- (u8)(swqe->ip_end + 1 + offsetof(struct tcphdr, check));
-
- swqe->tcp_end = (u16)skb->len - 1;
-}
-
-static inline void write_udp_offset_end(struct ehea_swqe *swqe,
- const struct sk_buff *skb)
-{
- swqe->tcp_offset =
- (u8)(swqe->ip_end + 1 + offsetof(struct udphdr, check));
-
- swqe->tcp_end = (u16)skb->len - 1;
-}
-
-
-static void write_swqe2_TSO(struct sk_buff *skb,
- struct ehea_swqe *swqe, u32 lkey)
-{
- struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry;
- u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
- int skb_data_size = skb_headlen(skb);
- int headersize;
-
- /* Packet is TCP with TSO enabled */
- swqe->tx_control |= EHEA_SWQE_TSO;
- swqe->mss = skb_shinfo(skb)->gso_size;
- /* copy only eth/ip/tcp headers to immediate data and
- * the rest of skb->data to sg1entry
- */
- headersize = ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb);
-
- skb_data_size = skb_headlen(skb);
-
- if (skb_data_size >= headersize) {
- /* copy immediate data */
- skb_copy_from_linear_data(skb, imm_data, headersize);
- swqe->immediate_data_length = headersize;
-
- if (skb_data_size > headersize) {
- /* set sg1entry data */
- sg1entry->l_key = lkey;
- sg1entry->len = skb_data_size - headersize;
- sg1entry->vaddr =
- ehea_map_vaddr(skb->data + headersize);
- swqe->descriptors++;
- }
- } else
- pr_err("cannot handle fragmented headers\n");
-}
-
-static void write_swqe2_nonTSO(struct sk_buff *skb,
- struct ehea_swqe *swqe, u32 lkey)
+static void write_swqe2_immediate(struct sk_buff *skb, struct ehea_swqe *swqe,
+ u32 lkey)
{
int skb_data_size = skb_headlen(skb);
u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry;
+ unsigned int immediate_len = SWQE2_MAX_IMM;
- /* Packet is any nonTSO type
- *
- * Copy as much as possible skb->data to immediate data and
- * the rest to sg1entry
- */
- if (skb_data_size >= SWQE2_MAX_IMM) {
- /* copy immediate data */
- skb_copy_from_linear_data(skb, imm_data, SWQE2_MAX_IMM);
+ swqe->descriptors = 0;
- swqe->immediate_data_length = SWQE2_MAX_IMM;
+ if (skb_is_gso(skb)) {
+ swqe->tx_control |= EHEA_SWQE_TSO;
+ swqe->mss = skb_shinfo(skb)->gso_size;
+ /*
+ * For TSO packets we only copy the headers into the
+ * immediate area.
+ */
+ immediate_len = ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb);
+ }
- if (skb_data_size > SWQE2_MAX_IMM) {
- /* copy sg1entry data */
+ if (skb_is_gso(skb) || skb_data_size >= SWQE2_MAX_IMM) {
+ skb_copy_from_linear_data(skb, imm_data, immediate_len);
+ swqe->immediate_data_length = immediate_len;
+
+ if (skb_data_size > immediate_len) {
sg1entry->l_key = lkey;
- sg1entry->len = skb_data_size - SWQE2_MAX_IMM;
+ sg1entry->len = skb_data_size - immediate_len;
sg1entry->vaddr =
- ehea_map_vaddr(skb->data + SWQE2_MAX_IMM);
+ ehea_map_vaddr(skb->data + immediate_len);
swqe->descriptors++;
}
} else {
@@ -1799,13 +1676,9 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
nfrags = skb_shinfo(skb)->nr_frags;
sg1entry = &swqe->u.immdata_desc.sg_entry;
sg_list = (struct ehea_vsgentry *)&swqe->u.immdata_desc.sg_list;
- swqe->descriptors = 0;
sg1entry_contains_frag_data = 0;
- if ((dev->features & NETIF_F_TSO) && skb_shinfo(skb)->gso_size)
- write_swqe2_TSO(skb, swqe, lkey);
- else
- write_swqe2_nonTSO(skb, swqe, lkey);
+ write_swqe2_immediate(skb, swqe, lkey);
/* write descriptors */
if (nfrags > 0) {
@@ -1815,7 +1688,7 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
/* copy sg1entry data */
sg1entry->l_key = lkey;
- sg1entry->len = frag->size;
+ sg1entry->len = skb_frag_size(frag);
sg1entry->vaddr =
ehea_map_vaddr(skb_frag_address(frag));
swqe->descriptors++;
@@ -1828,7 +1701,7 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
sgentry = &sg_list[i - sg1entry_contains_frag_data];
sgentry->l_key = lkey;
- sgentry->len = frag->size;
+ sgentry->len = skb_frag_size(frag);
sgentry->vaddr = ehea_map_vaddr(skb_frag_address(frag));
swqe->descriptors++;
}
@@ -1974,8 +1847,9 @@ static u64 ehea_multicast_reg_helper(struct ehea_port *port, u64 mc_mac_addr,
u64 hret;
u8 reg_type;
- reg_type = EHEA_BCMC_SCOPE_ALL | EHEA_BCMC_MULTICAST
- | EHEA_BCMC_UNTAGGED;
+ reg_type = EHEA_BCMC_MULTICAST | EHEA_BCMC_UNTAGGED;
+ if (mc_mac_addr == 0)
+ reg_type |= EHEA_BCMC_SCOPE_ALL;
hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
port->logical_port_id,
@@ -1983,8 +1857,9 @@ static u64 ehea_multicast_reg_helper(struct ehea_port *port, u64 mc_mac_addr,
if (hret)
goto out;
- reg_type = EHEA_BCMC_SCOPE_ALL | EHEA_BCMC_MULTICAST
- | EHEA_BCMC_VLANID_ALL;
+ reg_type = EHEA_BCMC_MULTICAST | EHEA_BCMC_VLANID_ALL;
+ if (mc_mac_addr == 0)
+ reg_type |= EHEA_BCMC_SCOPE_ALL;
hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
port->logical_port_id,
@@ -2034,7 +1909,7 @@ static void ehea_allmulti(struct net_device *dev, int enable)
netdev_err(dev,
"failed enabling IFF_ALLMULTI\n");
}
- } else
+ } else {
if (!enable) {
/* Disable ALLMULTI */
hret = ehea_multicast_reg_helper(port, 0, H_DEREG_BCMC);
@@ -2044,6 +1919,7 @@ static void ehea_allmulti(struct net_device *dev, int enable)
netdev_err(dev,
"failed disabling IFF_ALLMULTI\n");
}
+ }
}
static void ehea_add_multicast_entry(struct ehea_port *port, u8 *mc_mac_addr)
@@ -2052,10 +1928,8 @@ static void ehea_add_multicast_entry(struct ehea_port *port, u8 *mc_mac_addr)
u64 hret;
ehea_mcl_entry = kzalloc(sizeof(*ehea_mcl_entry), GFP_ATOMIC);
- if (!ehea_mcl_entry) {
- pr_err("no mem for mcl_entry\n");
+ if (!ehea_mcl_entry)
return;
- }
INIT_LIST_HEAD(&ehea_mcl_entry->list);
@@ -2077,11 +1951,7 @@ static void ehea_set_multicast_list(struct net_device *dev)
struct netdev_hw_addr *ha;
int ret;
- if (port->promisc) {
- ehea_promiscuous(dev, 1);
- return;
- }
- ehea_promiscuous(dev, 0);
+ ehea_promiscuous(dev, !!(dev->flags & IFF_PROMISC));
if (dev->flags & IFF_ALLMULTI) {
ehea_allmulti(dev, 1);
@@ -2120,41 +1990,44 @@ static int ehea_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev,
- struct ehea_swqe *swqe, u32 lkey)
+static void xmit_common(struct sk_buff *skb, struct ehea_swqe *swqe)
{
- if (skb->protocol == htons(ETH_P_IP)) {
- const struct iphdr *iph = ip_hdr(skb);
+ swqe->tx_control |= EHEA_SWQE_IMM_DATA_PRESENT | EHEA_SWQE_CRC;
- /* IPv4 */
- swqe->tx_control |= EHEA_SWQE_CRC
- | EHEA_SWQE_IP_CHECKSUM
- | EHEA_SWQE_TCP_CHECKSUM
- | EHEA_SWQE_IMM_DATA_PRESENT
- | EHEA_SWQE_DESCRIPTORS_PRESENT;
+ if (skb->protocol != htons(ETH_P_IP))
+ return;
- write_ip_start_end(swqe, skb);
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ swqe->tx_control |= EHEA_SWQE_IP_CHECKSUM;
- if (iph->protocol == IPPROTO_UDP) {
- if ((iph->frag_off & IP_MF) ||
- (iph->frag_off & IP_OFFSET))
- /* IP fragment, so don't change cs */
- swqe->tx_control &= ~EHEA_SWQE_TCP_CHECKSUM;
- else
- write_udp_offset_end(swqe, skb);
- } else if (iph->protocol == IPPROTO_TCP) {
- write_tcp_offset_end(swqe, skb);
- }
+ swqe->ip_start = skb_network_offset(skb);
+ swqe->ip_end = swqe->ip_start + ip_hdrlen(skb) - 1;
- /* icmp (big data) and ip segmentation packets (all other ip
- packets) do not require any special handling */
+ switch (ip_hdr(skb)->protocol) {
+ case IPPROTO_UDP:
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ swqe->tx_control |= EHEA_SWQE_TCP_CHECKSUM;
- } else {
- /* Other Ethernet Protocol */
- swqe->tx_control |= EHEA_SWQE_CRC
- | EHEA_SWQE_IMM_DATA_PRESENT
- | EHEA_SWQE_DESCRIPTORS_PRESENT;
+ swqe->tcp_offset = swqe->ip_end + 1 +
+ offsetof(struct udphdr, check);
+ break;
+
+ case IPPROTO_TCP:
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ swqe->tx_control |= EHEA_SWQE_TCP_CHECKSUM;
+
+ swqe->tcp_offset = swqe->ip_end + 1 +
+ offsetof(struct tcphdr, check);
+ break;
}
+}
+
+static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev,
+ struct ehea_swqe *swqe, u32 lkey)
+{
+ swqe->tx_control |= EHEA_SWQE_DESCRIPTORS_PRESENT;
+
+ xmit_common(skb, swqe);
write_swqe2_data(skb, dev, swqe, lkey);
}
@@ -2162,105 +2035,30 @@ static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev,
static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
struct ehea_swqe *swqe)
{
- int nfrags = skb_shinfo(skb)->nr_frags;
u8 *imm_data = &swqe->u.immdata_nodesc.immediate_data[0];
- skb_frag_t *frag;
- int i;
-
- if (skb->protocol == htons(ETH_P_IP)) {
- const struct iphdr *iph = ip_hdr(skb);
-
- /* IPv4 */
- write_ip_start_end(swqe, skb);
- if (iph->protocol == IPPROTO_TCP) {
- swqe->tx_control |= EHEA_SWQE_CRC
- | EHEA_SWQE_IP_CHECKSUM
- | EHEA_SWQE_TCP_CHECKSUM
- | EHEA_SWQE_IMM_DATA_PRESENT;
+ xmit_common(skb, swqe);
- write_tcp_offset_end(swqe, skb);
-
- } else if (iph->protocol == IPPROTO_UDP) {
- if ((iph->frag_off & IP_MF) ||
- (iph->frag_off & IP_OFFSET))
- /* IP fragment, so don't change cs */
- swqe->tx_control |= EHEA_SWQE_CRC
- | EHEA_SWQE_IMM_DATA_PRESENT;
- else {
- swqe->tx_control |= EHEA_SWQE_CRC
- | EHEA_SWQE_IP_CHECKSUM
- | EHEA_SWQE_TCP_CHECKSUM
- | EHEA_SWQE_IMM_DATA_PRESENT;
-
- write_udp_offset_end(swqe, skb);
- }
- } else {
- /* icmp (big data) and
- ip segmentation packets (all other ip packets) */
- swqe->tx_control |= EHEA_SWQE_CRC
- | EHEA_SWQE_IP_CHECKSUM
- | EHEA_SWQE_IMM_DATA_PRESENT;
- }
- } else {
- /* Other Ethernet Protocol */
- swqe->tx_control |= EHEA_SWQE_CRC | EHEA_SWQE_IMM_DATA_PRESENT;
- }
- /* copy (immediate) data */
- if (nfrags == 0) {
- /* data is in a single piece */
+ if (!skb->data_len)
skb_copy_from_linear_data(skb, imm_data, skb->len);
- } else {
- /* first copy data from the skb->data buffer ... */
- skb_copy_from_linear_data(skb, imm_data,
- skb_headlen(skb));
- imm_data += skb_headlen(skb);
+ else
+ skb_copy_bits(skb, 0, imm_data, skb->len);
- /* ... then copy data from the fragments */
- for (i = 0; i < nfrags; i++) {
- frag = &skb_shinfo(skb)->frags[i];
- memcpy(imm_data, skb_frag_address(frag), frag->size);
- imm_data += frag->size;
- }
- }
swqe->immediate_data_length = skb->len;
- dev_kfree_skb(skb);
-}
-
-static inline int ehea_hash_skb(struct sk_buff *skb, int num_qps)
-{
- struct tcphdr *tcp;
- u32 tmp;
-
- if ((skb->protocol == htons(ETH_P_IP)) &&
- (ip_hdr(skb)->protocol == IPPROTO_TCP)) {
- tcp = (struct tcphdr *)(skb_network_header(skb) +
- (ip_hdr(skb)->ihl * 4));
- tmp = (tcp->source + (tcp->dest << 16)) % 31;
- tmp += ip_hdr(skb)->daddr % 31;
- return tmp % num_qps;
- } else
- return 0;
+ dev_consume_skb_any(skb);
}
static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ehea_port *port = netdev_priv(dev);
struct ehea_swqe *swqe;
- unsigned long flags;
u32 lkey;
int swqe_index;
struct ehea_port_res *pr;
+ struct netdev_queue *txq;
- pr = &port->port_res[ehea_hash_skb(skb, port->num_tx_qps)];
-
- if (!spin_trylock(&pr->xmit_lock))
- return NETDEV_TX_BUSY;
-
- if (pr->queue_stopped) {
- spin_unlock(&pr->xmit_lock);
- return NETDEV_TX_BUSY;
- }
+ pr = &port->port_res[skb_get_queue_mapping(skb)];
+ txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
swqe = ehea_get_swqe(pr->qp, &swqe_index);
memset(swqe, 0, SWQE_HEADER_SIZE);
@@ -2310,38 +2108,33 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
ehea_dump(swqe, 512, "swqe");
if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) {
- netif_stop_queue(dev);
+ netif_tx_stop_queue(txq);
swqe->tx_control |= EHEA_SWQE_PURGE;
}
ehea_post_swqe(pr->qp, swqe);
if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
- spin_lock_irqsave(&pr->netif_queue, flags);
- if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
- pr->p_stats.queue_stopped++;
- netif_stop_queue(dev);
- pr->queue_stopped = 1;
- }
- spin_unlock_irqrestore(&pr->netif_queue, flags);
+ pr->p_stats.queue_stopped++;
+ netif_tx_stop_queue(txq);
}
- dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
- spin_unlock(&pr->xmit_lock);
return NETDEV_TX_OK;
}
-static void ehea_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+static int ehea_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
{
struct ehea_port *port = netdev_priv(dev);
struct ehea_adapter *adapter = port->adapter;
struct hcp_ehea_port_cb1 *cb1;
int index;
u64 hret;
+ int err = 0;
cb1 = (void *)get_zeroed_page(GFP_KERNEL);
if (!cb1) {
pr_err("no mem for cb1\n");
+ err = -ENOMEM;
goto out;
}
@@ -2349,6 +2142,7 @@ static void ehea_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
H_PORT_CB1, H_PORT_CB1_ALL, cb1);
if (hret != H_SUCCESS) {
pr_err("query_ehea_port failed\n");
+ err = -EINVAL;
goto out;
}
@@ -2357,24 +2151,28 @@ static void ehea_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
H_PORT_CB1, H_PORT_CB1_ALL, cb1);
- if (hret != H_SUCCESS)
+ if (hret != H_SUCCESS) {
pr_err("modify_ehea_port failed\n");
+ err = -EINVAL;
+ }
out:
free_page((unsigned long)cb1);
- return;
+ return err;
}
-static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+static int ehea_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
{
struct ehea_port *port = netdev_priv(dev);
struct ehea_adapter *adapter = port->adapter;
struct hcp_ehea_port_cb1 *cb1;
int index;
u64 hret;
+ int err = 0;
cb1 = (void *)get_zeroed_page(GFP_KERNEL);
if (!cb1) {
pr_err("no mem for cb1\n");
+ err = -ENOMEM;
goto out;
}
@@ -2382,6 +2180,7 @@ static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
H_PORT_CB1, H_PORT_CB1_ALL, cb1);
if (hret != H_SUCCESS) {
pr_err("query_ehea_port failed\n");
+ err = -EINVAL;
goto out;
}
@@ -2390,13 +2189,16 @@ static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
H_PORT_CB1, H_PORT_CB1_ALL, cb1);
- if (hret != H_SUCCESS)
+ if (hret != H_SUCCESS) {
pr_err("modify_ehea_port failed\n");
+ err = -EINVAL;
+ }
out:
free_page((unsigned long)cb1);
+ return err;
}
-int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
+static int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
{
int ret = -EIO;
u64 hret;
@@ -2471,8 +2273,7 @@ out:
return ret;
}
-static int ehea_port_res_setup(struct ehea_port *port, int def_qps,
- int add_tx_qps)
+static int ehea_port_res_setup(struct ehea_port *port, int def_qps)
{
int ret, i;
struct port_res_cfg pr_cfg, pr_cfg_small_rx;
@@ -2505,7 +2306,7 @@ static int ehea_port_res_setup(struct ehea_port *port, int def_qps,
if (ret)
goto out_clean_pr;
}
- for (i = def_qps; i < def_qps + add_tx_qps; i++) {
+ for (i = def_qps; i < def_qps; i++) {
ret = ehea_init_port_res(port, &port->port_res[i],
&pr_cfg_small_rx, i);
if (ret)
@@ -2528,7 +2329,7 @@ static int ehea_clean_all_portres(struct ehea_port *port)
int ret = 0;
int i;
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
+ for (i = 0; i < port->num_def_qps; i++)
ret |= ehea_clean_portres(port, &port->port_res[i]);
ret |= ehea_destroy_eq(port->qp_eq);
@@ -2560,8 +2361,7 @@ static int ehea_up(struct net_device *dev)
if (port->state == EHEA_PORT_UP)
return 0;
- ret = ehea_port_res_setup(port, port->num_def_qps,
- port->num_add_tx_qps);
+ ret = ehea_port_res_setup(port, port->num_def_qps);
if (ret) {
netdev_err(dev, "port_res_failed\n");
goto out;
@@ -2580,7 +2380,7 @@ static int ehea_up(struct net_device *dev)
goto out_clean_pr;
}
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ for (i = 0; i < port->num_def_qps; i++) {
ret = ehea_activate_qp(port->adapter, port->port_res[i].qp);
if (ret) {
netdev_err(dev, "activate_qp failed\n");
@@ -2626,7 +2426,7 @@ static void port_napi_disable(struct ehea_port *port)
{
int i;
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
+ for (i = 0; i < port->num_def_qps; i++)
napi_disable(&port->port_res[i].napi);
}
@@ -2634,7 +2434,7 @@ static void port_napi_enable(struct ehea_port *port)
{
int i;
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
+ for (i = 0; i < port->num_def_qps; i++)
napi_enable(&port->port_res[i].napi);
}
@@ -2650,11 +2450,12 @@ static int ehea_open(struct net_device *dev)
ret = ehea_up(dev);
if (!ret) {
port_napi_enable(port);
- netif_start_queue(dev);
+ netif_tx_start_all_queues(dev);
}
mutex_unlock(&port->port_lock);
- schedule_delayed_work(&port->stats_work, msecs_to_jiffies(1000));
+ schedule_delayed_work(&port->stats_work,
+ round_jiffies_relative(msecs_to_jiffies(1000)));
return ret;
}
@@ -2668,6 +2469,7 @@ static int ehea_down(struct net_device *dev)
return 0;
ehea_drop_multicast_list(dev);
+ ehea_allmulti(dev, 0);
ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
ehea_free_interrupts(dev);
@@ -2696,7 +2498,7 @@ static int ehea_stop(struct net_device *dev)
cancel_work_sync(&port->reset_task);
cancel_delayed_work_sync(&port->stats_work);
mutex_lock(&port->port_lock);
- netif_stop_queue(dev);
+ netif_tx_stop_all_queues(dev);
port_napi_disable(port);
ret = ehea_down(dev);
mutex_unlock(&port->port_lock);
@@ -2722,7 +2524,7 @@ static void ehea_flush_sq(struct ehea_port *port)
{
int i;
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ for (i = 0; i < port->num_def_qps; i++) {
struct ehea_port_res *pr = &port->port_res[i];
int swqe_max = pr->sq_skba_size - 2 - pr->swqe_ll_count;
int ret;
@@ -2738,7 +2540,7 @@ static void ehea_flush_sq(struct ehea_port *port)
}
}
-int ehea_stop_qps(struct net_device *dev)
+static int ehea_stop_qps(struct net_device *dev)
{
struct ehea_port *port = netdev_priv(dev);
struct ehea_adapter *adapter = port->adapter;
@@ -2756,7 +2558,7 @@ int ehea_stop_qps(struct net_device *dev)
goto out;
}
- for (i = 0; i < (port->num_def_qps + port->num_add_tx_qps); i++) {
+ for (i = 0; i < (port->num_def_qps); i++) {
struct ehea_port_res *pr = &port->port_res[i];
struct ehea_qp *qp = pr->qp;
@@ -2807,7 +2609,7 @@ out:
return ret;
}
-void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res *pr)
+static void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res *pr)
{
struct ehea_qp qp = *orig_qp;
struct ehea_qp_init_attr *init_attr = &qp.init_attr;
@@ -2840,7 +2642,7 @@ void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res *pr)
}
}
-int ehea_restart_qps(struct net_device *dev)
+static int ehea_restart_qps(struct net_device *dev)
{
struct ehea_port *port = netdev_priv(dev);
struct ehea_adapter *adapter = port->adapter;
@@ -2858,7 +2660,7 @@ int ehea_restart_qps(struct net_device *dev)
goto out;
}
- for (i = 0; i < (port->num_def_qps + port->num_add_tx_qps); i++) {
+ for (i = 0; i < (port->num_def_qps); i++) {
struct ehea_port_res *pr = &port->port_res[i];
struct ehea_qp *qp = pr->qp;
@@ -2920,7 +2722,7 @@ static void ehea_reset_port(struct work_struct *work)
mutex_lock(&dlpar_mem_lock);
port->resets++;
mutex_lock(&port->port_lock);
- netif_stop_queue(dev);
+ netif_tx_disable(dev);
port_napi_disable(port);
@@ -2936,7 +2738,7 @@ static void ehea_reset_port(struct work_struct *work)
port_napi_enable(port);
- netif_wake_queue(dev);
+ netif_tx_wake_all_queues(dev);
out:
mutex_unlock(&port->port_lock);
mutex_unlock(&dlpar_mem_lock);
@@ -2963,7 +2765,7 @@ static void ehea_rereg_mrs(void)
if (dev->flags & IFF_UP) {
mutex_lock(&port->port_lock);
- netif_stop_queue(dev);
+ netif_tx_disable(dev);
ehea_flush_sq(port);
ret = ehea_stop_qps(dev);
if (ret) {
@@ -3008,7 +2810,7 @@ static void ehea_rereg_mrs(void)
if (!ret) {
check_sqs(port);
port_napi_enable(port);
- netif_wake_queue(dev);
+ netif_tx_wake_all_queues(dev);
} else {
netdev_err(dev, "Unable to restart QPS\n");
}
@@ -3031,7 +2833,7 @@ static void ehea_tx_watchdog(struct net_device *dev)
ehea_schedule_port_reset(port);
}
-int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
+static int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
{
struct hcp_query_ehea *cb;
u64 hret;
@@ -3059,7 +2861,7 @@ out:
return ret;
}
-int ehea_get_jumboframe_status(struct ehea_port *port, int *jumbo)
+static int ehea_get_jumboframe_status(struct ehea_port *port, int *jumbo)
{
struct hcp_ehea_port_cb4 *cb4;
u64 hret;
@@ -3112,7 +2914,7 @@ static ssize_t ehea_show_port_id(struct device *dev,
static DEVICE_ATTR(log_port_id, S_IRUSR | S_IRGRP | S_IROTH, ehea_show_port_id,
NULL);
-static void __devinit logical_port_release(struct device *dev)
+static void logical_port_release(struct device *dev)
{
struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev);
of_node_put(port->ofdev.dev.of_node);
@@ -3163,7 +2965,7 @@ static const struct net_device_ops ehea_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ehea_netpoll,
#endif
- .ndo_get_stats = ehea_get_stats,
+ .ndo_get_stats64 = ehea_get_stats64,
.ndo_set_mac_address = ehea_set_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_rx_mode = ehea_set_multicast_list,
@@ -3173,7 +2975,7 @@ static const struct net_device_ops ehea_netdev_ops = {
.ndo_tx_timeout = ehea_tx_watchdog,
};
-struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
+static struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
u32 logical_port_id,
struct device_node *dn)
{
@@ -3184,10 +2986,9 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
int jumbo;
/* allocate memory for the port structures */
- dev = alloc_etherdev(sizeof(struct ehea_port));
+ dev = alloc_etherdev_mq(sizeof(struct ehea_port), EHEA_MAX_PORT_RES);
if (!dev) {
- pr_err("no mem for net_device\n");
ret = -ENOMEM;
goto out_err;
}
@@ -3216,6 +3017,9 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
if (ret)
goto out_free_mc_list;
+ netif_set_real_num_rx_queues(dev, port->num_def_qps);
+ netif_set_real_num_tx_queues(dev, port->num_def_qps);
+
port_dev = ehea_register_port(port, dn);
if (!port_dev)
goto out_free_mc_list;
@@ -3228,17 +3032,16 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
dev->netdev_ops = &ehea_netdev_ops;
ehea_set_ethtool_ops(dev);
- dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
- | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_LRO;
- dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
- | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX
- | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER
- | NETIF_F_LLTX | NETIF_F_RXCSUM;
+ dev->hw_features = NETIF_F_SG | NETIF_F_TSO |
+ NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_CTAG_TX;
+ dev->features = NETIF_F_SG | NETIF_F_TSO |
+ NETIF_F_HIGHDMA | NETIF_F_IP_CSUM |
+ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXCSUM;
+ dev->vlan_features = NETIF_F_SG | NETIF_F_TSO | NETIF_F_HIGHDMA |
+ NETIF_F_IP_CSUM;
dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
- if (use_lro)
- dev->features |= NETIF_F_LRO;
-
INIT_WORK(&port->reset_task, ehea_reset_port);
INIT_DELAYED_WORK(&port->stats_work, ehea_update_stats);
@@ -3252,8 +3055,6 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
goto out_unreg_port;
}
- port->lro_max_aggr = lro_max_aggr;
-
ret = ehea_get_jumboframe_status(port, &jumbo);
if (ret)
netdev_err(dev, "failed determining jumbo frame status\n");
@@ -3444,7 +3245,7 @@ static ssize_t ehea_remove_port(struct device *dev,
static DEVICE_ATTR(probe_port, S_IWUSR, NULL, ehea_probe_port);
static DEVICE_ATTR(remove_port, S_IWUSR, NULL, ehea_remove_port);
-int ehea_create_device_sysfs(struct platform_device *dev)
+static int ehea_create_device_sysfs(struct platform_device *dev)
{
int ret = device_create_file(&dev->dev, &dev_attr_probe_port);
if (ret)
@@ -3455,25 +3256,25 @@ out:
return ret;
}
-void ehea_remove_device_sysfs(struct platform_device *dev)
+static void ehea_remove_device_sysfs(struct platform_device *dev)
{
device_remove_file(&dev->dev, &dev_attr_probe_port);
device_remove_file(&dev->dev, &dev_attr_remove_port);
}
-static int __devinit ehea_probe_adapter(struct platform_device *dev,
- const struct of_device_id *id)
+static int ehea_probe_adapter(struct platform_device *dev)
{
struct ehea_adapter *adapter;
const u64 *adapter_handle;
int ret;
+ int i;
if (!dev || !dev->dev.of_node) {
pr_err("Invalid ibmebus device probed\n");
return -EINVAL;
}
- adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+ adapter = devm_kzalloc(&dev->dev, sizeof(*adapter), GFP_KERNEL);
if (!adapter) {
ret = -ENOMEM;
dev_err(&dev->dev, "no mem for ehea_adapter\n");
@@ -3498,7 +3299,7 @@ static int __devinit ehea_probe_adapter(struct platform_device *dev,
adapter->pd = EHEA_PD_ID;
- dev_set_drvdata(&dev->dev, adapter);
+ platform_set_drvdata(dev, adapter);
/* initialize adapter and ports */
@@ -3520,17 +3321,9 @@ static int __devinit ehea_probe_adapter(struct platform_device *dev,
tasklet_init(&adapter->neq_tasklet, ehea_neq_tasklet,
(unsigned long)adapter);
- ret = ibmebus_request_irq(adapter->neq->attr.ist1,
- ehea_interrupt_neq, IRQF_DISABLED,
- "ehea_neq", adapter);
- if (ret) {
- dev_err(&dev->dev, "requesting NEQ IRQ failed\n");
- goto out_kill_eq;
- }
-
ret = ehea_create_device_sysfs(dev);
if (ret)
- goto out_free_irq;
+ goto out_kill_eq;
ret = ehea_setup_ports(adapter);
if (ret) {
@@ -3538,21 +3331,35 @@ static int __devinit ehea_probe_adapter(struct platform_device *dev,
goto out_rem_dev_sysfs;
}
+ ret = ibmebus_request_irq(adapter->neq->attr.ist1,
+ ehea_interrupt_neq, 0,
+ "ehea_neq", adapter);
+ if (ret) {
+ dev_err(&dev->dev, "requesting NEQ IRQ failed\n");
+ goto out_shutdown_ports;
+ }
+
+ /* Handle any events that might be pending. */
+ tasklet_hi_schedule(&adapter->neq_tasklet);
+
ret = 0;
goto out;
+out_shutdown_ports:
+ for (i = 0; i < EHEA_MAX_PORTS; i++)
+ if (adapter->port[i]) {
+ ehea_shutdown_single_port(adapter->port[i]);
+ adapter->port[i] = NULL;
+ }
+
out_rem_dev_sysfs:
ehea_remove_device_sysfs(dev);
-out_free_irq:
- ibmebus_free_irq(adapter->neq->attr.ist1, adapter);
-
out_kill_eq:
ehea_destroy_eq(adapter->neq);
out_free_ad:
list_del(&adapter->list);
- kfree(adapter);
out:
ehea_update_firmware_handles();
@@ -3560,9 +3367,9 @@ out:
return ret;
}
-static int __devexit ehea_remove(struct platform_device *dev)
+static int ehea_remove(struct platform_device *dev)
{
- struct ehea_adapter *adapter = dev_get_drvdata(&dev->dev);
+ struct ehea_adapter *adapter = platform_get_drvdata(dev);
int i;
for (i = 0; i < EHEA_MAX_PORTS; i++)
@@ -3579,14 +3386,13 @@ static int __devexit ehea_remove(struct platform_device *dev)
ehea_destroy_eq(adapter->neq);
ehea_remove_adapter_mr(adapter);
list_del(&adapter->list);
- kfree(adapter);
ehea_update_firmware_handles();
return 0;
}
-void ehea_crash_handler(void)
+static void ehea_crash_handler(void)
{
int i;
@@ -3698,7 +3504,7 @@ static ssize_t ehea_show_capabilities(struct device_driver *drv,
static DRIVER_ATTR(capabilities, S_IRUSR | S_IRGRP | S_IROTH,
ehea_show_capabilities, NULL);
-int __init ehea_module_init(void)
+static int __init ehea_module_init(void)
{
int ret;
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_phyp.c b/drivers/net/ethernet/ibm/ehea/ehea_phyp.c
index 0506967b904..d3a130ccdcc 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_phyp.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_phyp.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/net/ehea/ehea_phyp.c
+ * linux/drivers/net/ethernet/ibm/ehea/ehea_phyp.c
*
* eHEA ethernet device driver for IBM eServer System p
*
@@ -141,7 +141,7 @@ u64 ehea_h_query_ehea_qp(const u64 adapter_handle, const u8 qp_category,
qp_category, /* R5 */
qp_handle, /* R6 */
sel_mask, /* R7 */
- virt_to_abs(cb_addr), /* R8 */
+ __pa(cb_addr), /* R8 */
0, 0);
}
@@ -415,7 +415,7 @@ u64 ehea_h_modify_ehea_qp(const u64 adapter_handle, const u8 cat,
(u64) cat, /* R5 */
qp_handle, /* R6 */
sel_mask, /* R7 */
- virt_to_abs(cb_addr), /* R8 */
+ __pa(cb_addr), /* R8 */
0, 0, 0, 0); /* R9-R12 */
*inv_attr_id = outs[0];
@@ -528,7 +528,7 @@ u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr)
{
u64 hret, cb_logaddr;
- cb_logaddr = virt_to_abs(cb_addr);
+ cb_logaddr = __pa(cb_addr);
hret = ehea_plpar_hcall_norets(H_QUERY_HEA,
adapter_handle, /* R4 */
@@ -545,7 +545,7 @@ u64 ehea_h_query_ehea_port(const u64 adapter_handle, const u16 port_num,
void *cb_addr)
{
u64 port_info;
- u64 cb_logaddr = virt_to_abs(cb_addr);
+ u64 cb_logaddr = __pa(cb_addr);
u64 arr_index = 0;
port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat)
@@ -567,7 +567,7 @@ u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num,
unsigned long outs[PLPAR_HCALL9_BUFSIZE];
u64 port_info;
u64 arr_index = 0;
- u64 cb_logaddr = virt_to_abs(cb_addr);
+ u64 cb_logaddr = __pa(cb_addr);
port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat)
| EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num);
@@ -621,6 +621,6 @@ u64 ehea_h_error_data(const u64 adapter_handle, const u64 ressource_handle,
return ehea_plpar_hcall_norets(H_ERROR_DATA,
adapter_handle, /* R4 */
ressource_handle, /* R5 */
- virt_to_abs(rblock), /* R6 */
+ __pa(rblock), /* R6 */
0, 0, 0, 0); /* R7-R12 */
}
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_phyp.h b/drivers/net/ethernet/ibm/ehea/ehea_phyp.h
index 2f8174c248b..99b6c2a38db 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_phyp.h
+++ b/drivers/net/ethernet/ibm/ehea/ehea_phyp.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/net/ehea/ehea_phyp.h
+ * linux/drivers/net/ethernet/ibm/ehea/ehea_phyp.h
*
* eHEA ethernet device driver for IBM eServer System p
*
@@ -39,26 +39,6 @@
* hcp_* - structures, variables and functions releated to Hypervisor Calls
*/
-static inline u32 get_longbusy_msecs(int long_busy_ret_code)
-{
- switch (long_busy_ret_code) {
- case H_LONG_BUSY_ORDER_1_MSEC:
- return 1;
- case H_LONG_BUSY_ORDER_10_MSEC:
- return 10;
- case H_LONG_BUSY_ORDER_100_MSEC:
- return 100;
- case H_LONG_BUSY_ORDER_1_SEC:
- return 1000;
- case H_LONG_BUSY_ORDER_10_SEC:
- return 10000;
- case H_LONG_BUSY_ORDER_100_SEC:
- return 100000;
- default:
- return 1;
- }
-}
-
/* Number of pages which can be registered at once by H_REGISTER_HEA_RPAGES */
#define EHEA_MAX_RPAGE 512
@@ -450,7 +430,7 @@ u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num,
void *cb_addr);
#define H_REGBCMC_PN EHEA_BMASK_IBM(48, 63)
-#define H_REGBCMC_REGTYPE EHEA_BMASK_IBM(61, 63)
+#define H_REGBCMC_REGTYPE EHEA_BMASK_IBM(60, 63)
#define H_REGBCMC_MACADDR EHEA_BMASK_IBM(16, 63)
#define H_REGBCMC_VLANID EHEA_BMASK_IBM(52, 63)
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
index 95b9f4fa811..a0820f72b25 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/net/ehea/ehea_qmr.c
+ * linux/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
*
* eHEA ethernet device driver for IBM eServer System p
*
@@ -34,9 +34,7 @@
#include "ehea_phyp.h"
#include "ehea_qmr.h"
-struct ehea_bmap *ehea_bmap = NULL;
-
-
+static struct ehea_bmap *ehea_bmap;
static void *hw_qpageit_get_inc(struct hw_queue *queue)
{
@@ -66,11 +64,10 @@ static int hw_queue_ctor(struct hw_queue *queue, const u32 nr_of_pages,
}
queue->queue_length = nr_of_pages * pagesize;
- queue->queue_pages = kmalloc(nr_of_pages * sizeof(void *), GFP_KERNEL);
- if (!queue->queue_pages) {
- pr_err("no mem for queue_pages\n");
+ queue->queue_pages = kmalloc_array(nr_of_pages, sizeof(void *),
+ GFP_KERNEL);
+ if (!queue->queue_pages)
return -ENOMEM;
- }
/*
* allocate pages for queue:
@@ -106,12 +103,14 @@ out_nomem:
static void hw_queue_dtor(struct hw_queue *queue)
{
- int pages_per_kpage = PAGE_SIZE / queue->pagesize;
+ int pages_per_kpage;
int i, nr_pages;
if (!queue || !queue->queue_pages)
return;
+ pages_per_kpage = PAGE_SIZE / queue->pagesize;
+
nr_pages = queue->queue_length / queue->pagesize;
for (i = 0; i < nr_pages; i += pages_per_kpage)
@@ -131,10 +130,8 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
void *vpage;
cq = kzalloc(sizeof(*cq), GFP_KERNEL);
- if (!cq) {
- pr_err("no mem for cq\n");
+ if (!cq)
goto out_nomem;
- }
cq->attr.max_nr_of_cqes = nr_of_cqe;
cq->attr.cq_token = cq_token;
@@ -165,7 +162,7 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
goto out_kill_hwq;
}
- rpage = virt_to_abs(vpage);
+ rpage = __pa(vpage);
hret = ehea_h_register_rpage(adapter->handle,
0, EHEA_CQ_REGISTER_ORIG,
cq->fw_handle, rpage, 1);
@@ -212,7 +209,7 @@ out_nomem:
return NULL;
}
-u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force)
+static u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force)
{
u64 hret;
u64 adapter_handle = cq->adapter->handle;
@@ -259,10 +256,8 @@ struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
struct ehea_eq *eq;
eq = kzalloc(sizeof(*eq), GFP_KERNEL);
- if (!eq) {
- pr_err("no mem for eq\n");
+ if (!eq)
return NULL;
- }
eq->adapter = adapter;
eq->attr.type = type;
@@ -292,7 +287,7 @@ struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
goto out_kill_hwq;
}
- rpage = virt_to_abs(vpage);
+ rpage = __pa(vpage);
hret = ehea_h_register_rpage(adapter->handle, 0,
EHEA_EQ_REGISTER_ORIG,
@@ -337,7 +332,7 @@ struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq)
return eqe;
}
-u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force)
+static u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force)
{
u64 hret;
unsigned long flags;
@@ -378,10 +373,8 @@ int ehea_destroy_eq(struct ehea_eq *eq)
return 0;
}
-/**
- * allocates memory for a queue and registers pages in phyp
- */
-int ehea_qp_alloc_register(struct ehea_qp *qp, struct hw_queue *hw_queue,
+/* allocates memory for a queue and registers pages in phyp */
+static int ehea_qp_alloc_register(struct ehea_qp *qp, struct hw_queue *hw_queue,
int nr_pages, int wqe_size, int act_nr_sges,
struct ehea_adapter *adapter, int h_call_q_selector)
{
@@ -399,7 +392,7 @@ int ehea_qp_alloc_register(struct ehea_qp *qp, struct hw_queue *hw_queue,
pr_err("hw_qpageit_get_inc failed\n");
goto out_kill_hwq;
}
- rpage = virt_to_abs(vpage);
+ rpage = __pa(vpage);
hret = ehea_h_register_rpage(adapter->handle,
0, h_call_q_selector,
qp->fw_handle, rpage, 1);
@@ -432,10 +425,8 @@ struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter,
qp = kzalloc(sizeof(*qp), GFP_KERNEL);
- if (!qp) {
- pr_err("no mem for qp\n");
+ if (!qp)
return NULL;
- }
qp->adapter = adapter;
@@ -516,7 +507,7 @@ out_freemem:
return NULL;
}
-u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force)
+static u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force)
{
u64 hret;
struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
@@ -794,7 +785,7 @@ u64 ehea_map_vaddr(void *caddr)
if (!ehea_bmap)
return EHEA_INVAL_ADDR;
- index = virt_to_abs(caddr) >> SECTION_SIZE_BITS;
+ index = __pa(caddr) >> SECTION_SIZE_BITS;
top = (index >> EHEA_TOP_INDEX_SHIFT) & EHEA_INDEX_MASK;
if (!ehea_bmap->top[top])
return EHEA_INVAL_ADDR;
@@ -816,7 +807,7 @@ static inline void *ehea_calc_sectbase(int top, int dir, int idx)
unsigned long ret = idx;
ret |= dir << EHEA_DIR_INDEX_SHIFT;
ret |= top << EHEA_TOP_INDEX_SHIFT;
- return abs_to_virt(ret << SECTION_SIZE_BITS);
+ return __va(ret << SECTION_SIZE_BITS);
}
static u64 ehea_reg_mr_section(int top, int dir, int idx, u64 *pt,
@@ -826,7 +817,7 @@ static u64 ehea_reg_mr_section(int top, int dir, int idx, u64 *pt,
void *pg;
u64 j, m, hret;
unsigned long k = 0;
- u64 pt_abs = virt_to_abs(pt);
+ u64 pt_abs = __pa(pt);
void *sectbase = ehea_calc_sectbase(top, dir, idx);
@@ -834,7 +825,7 @@ static u64 ehea_reg_mr_section(int top, int dir, int idx, u64 *pt,
for (m = 0; m < EHEA_MAX_RPAGE; m++) {
pg = sectbase + ((k++) * EHEA_PAGESIZE);
- pt[m] = virt_to_abs(pg);
+ pt[m] = __pa(pg);
}
hret = ehea_h_register_rpage_mr(adapter->handle, mr->handle, 0,
0, pt_abs, EHEA_MAX_RPAGE);
@@ -976,7 +967,7 @@ int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr,
return 0;
}
-void print_error_data(u64 *data)
+static void print_error_data(u64 *data)
{
int length;
u64 type = EHEA_BMASK_GET(ERROR_DATA_TYPE, data[2]);
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_qmr.h b/drivers/net/ethernet/ibm/ehea/ehea_qmr.h
index fddff8ec8cf..8e4a70c20ab 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_qmr.h
+++ b/drivers/net/ethernet/ibm/ehea/ehea_qmr.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/net/ehea/ehea_qmr.h
+ * linux/drivers/net/ethernet/ibm/ehea/ehea_qmr.h
*
* eHEA ethernet device driver for IBM eServer System p
*
@@ -107,7 +107,7 @@ struct ehea_swqe {
u8 immediate_data_length;
u8 tcp_offset;
u8 reserved2;
- u16 tcp_end;
+ u16 reserved2b;
u8 wrap_tag;
u8 descriptors; /* number of valid descriptors in WQE */
u16 reserved3;
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index 6b3a033d9de..87bd953cc2e 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_newemac/core.c
+ * drivers/net/ethernet/ibm/emac/core.c
*
* Driver for PowerPC 4xx on-chip ethernet controller.
*
@@ -39,6 +39,8 @@
#include <linux/bitops.h>
#include <linux/workqueue.h>
#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/of_net.h>
#include <linux/slab.h>
@@ -359,10 +361,26 @@ static int emac_reset(struct emac_instance *dev)
}
#ifdef CONFIG_PPC_DCR_NATIVE
- /* Enable internal clock source */
- if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX))
- dcri_clrset(SDR0, SDR0_ETH_CFG,
- 0, SDR0_ETH_CFG_ECS << dev->cell_index);
+ /*
+ * PPC460EX/GT Embedded Processor Advanced User's Manual
+ * section 28.10.1 Mode Register 0 (EMACx_MR0) states:
+ * Note: The PHY must provide a TX Clk in order to perform a soft reset
+ * of the EMAC. If none is present, select the internal clock
+ * (SDR0_ETH_CFG[EMACx_PHY_CLK] = 1).
+ * After a soft reset, select the external clock.
+ */
+ if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) {
+ if (dev->phy_address == 0xffffffff &&
+ dev->phy_map == 0xffffffff) {
+ /* No PHY: select internal loop clock before reset */
+ dcri_clrset(SDR0, SDR0_ETH_CFG,
+ 0, SDR0_ETH_CFG_ECS << dev->cell_index);
+ } else {
+ /* PHY present: select external clock before reset */
+ dcri_clrset(SDR0, SDR0_ETH_CFG,
+ SDR0_ETH_CFG_ECS << dev->cell_index, 0);
+ }
+ }
#endif
out_be32(&p->mr0, EMAC_MR0_SRST);
@@ -370,10 +388,14 @@ static int emac_reset(struct emac_instance *dev)
--n;
#ifdef CONFIG_PPC_DCR_NATIVE
- /* Enable external clock source */
- if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX))
- dcri_clrset(SDR0, SDR0_ETH_CFG,
- SDR0_ETH_CFG_ECS << dev->cell_index, 0);
+ if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) {
+ if (dev->phy_address == 0xffffffff &&
+ dev->phy_map == 0xffffffff) {
+ /* No PHY: restore external clock source after reset */
+ dcri_clrset(SDR0, SDR0_ETH_CFG,
+ SDR0_ETH_CFG_ECS << dev->cell_index, 0);
+ }
+ }
#endif
if (n) {
@@ -434,6 +456,11 @@ static inline u32 emac_iff2rmr(struct net_device *ndev)
else if (!netdev_mc_empty(ndev))
r |= EMAC_RMR_MAE;
+ if (emac_has_feature(dev, EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE)) {
+ r &= ~EMAC4_RMR_MJS_MASK;
+ r |= EMAC4_RMR_MJS(ndev->mtu);
+ }
+
return r;
}
@@ -965,6 +992,7 @@ static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu)
int rx_sync_size = emac_rx_sync_size(new_mtu);
int rx_skb_size = emac_rx_skb_size(new_mtu);
int i, ret = 0;
+ int mr1_jumbo_bit_change = 0;
mutex_lock(&dev->link_lock);
emac_netif_stop(dev);
@@ -1013,7 +1041,15 @@ static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu)
}
skip:
/* Check if we need to change "Jumbo" bit in MR1 */
- if ((new_mtu > ETH_DATA_LEN) ^ (dev->ndev->mtu > ETH_DATA_LEN)) {
+ if (emac_has_feature(dev, EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE)) {
+ mr1_jumbo_bit_change = (new_mtu > ETH_DATA_LEN) ||
+ (dev->ndev->mtu > ETH_DATA_LEN);
+ } else {
+ mr1_jumbo_bit_change = (new_mtu > ETH_DATA_LEN) ^
+ (dev->ndev->mtu > ETH_DATA_LEN);
+ }
+
+ if (mr1_jumbo_bit_change) {
/* This is to prevent starting RX channel in emac_rx_enable() */
set_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);
@@ -1453,7 +1489,7 @@ static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev)
/* skb fragments */
for (i = 0; i < nr_frags; ++i) {
struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
- len = frag->size;
+ len = skb_frag_size(frag);
if (unlikely(dev->tx_cnt + mal_tx_chunks(len) >= NUM_TX_BUFF))
goto undo_frame;
@@ -2176,11 +2212,10 @@ static void emac_ethtool_get_drvinfo(struct net_device *ndev,
{
struct emac_instance *dev = netdev_priv(ndev);
- strcpy(info->driver, "ibm_emac");
- strcpy(info->version, DRV_VERSION);
- info->fw_version[0] = '\0';
- sprintf(info->bus_info, "PPC 4xx EMAC-%d %s",
- dev->cell_index, dev->ofdev->dev.of_node->full_name);
+ strlcpy(info->driver, "ibm_emac", sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ snprintf(info->bus_info, sizeof(info->bus_info), "PPC 4xx EMAC-%d %s",
+ dev->cell_index, dev->ofdev->dev.of_node->full_name);
info->regdump_len = emac_ethtool_get_regs_len(ndev);
}
@@ -2247,8 +2282,8 @@ struct emac_depentry {
#define EMAC_DEP_PREV_IDX 5
#define EMAC_DEP_COUNT 6
-static int __devinit emac_check_deps(struct emac_instance *dev,
- struct emac_depentry *deps)
+static int emac_check_deps(struct emac_instance *dev,
+ struct emac_depentry *deps)
{
int i, there = 0;
struct device_node *np;
@@ -2279,7 +2314,7 @@ static int __devinit emac_check_deps(struct emac_instance *dev,
if (deps[i].ofdev == NULL)
continue;
if (deps[i].drvdata == NULL)
- deps[i].drvdata = dev_get_drvdata(&deps[i].ofdev->dev);
+ deps[i].drvdata = platform_get_drvdata(deps[i].ofdev);
if (deps[i].drvdata != NULL)
there++;
}
@@ -2300,8 +2335,8 @@ static void emac_put_deps(struct emac_instance *dev)
of_dev_put(dev->tah_dev);
}
-static int __devinit emac_of_bus_notify(struct notifier_block *nb,
- unsigned long action, void *data)
+static int emac_of_bus_notify(struct notifier_block *nb, unsigned long action,
+ void *data)
{
/* We are only intereted in device addition */
if (action == BUS_NOTIFY_BOUND_DRIVER)
@@ -2309,11 +2344,11 @@ static int __devinit emac_of_bus_notify(struct notifier_block *nb,
return 0;
}
-static struct notifier_block emac_of_bus_notifier __devinitdata = {
+static struct notifier_block emac_of_bus_notifier = {
.notifier_call = emac_of_bus_notify
};
-static int __devinit emac_wait_deps(struct emac_instance *dev)
+static int emac_wait_deps(struct emac_instance *dev)
{
struct emac_depentry deps[EMAC_DEP_COUNT];
int i, err;
@@ -2353,8 +2388,8 @@ static int __devinit emac_wait_deps(struct emac_instance *dev)
return err;
}
-static int __devinit emac_read_uint_prop(struct device_node *np, const char *name,
- u32 *val, int fatal)
+static int emac_read_uint_prop(struct device_node *np, const char *name,
+ u32 *val, int fatal)
{
int len;
const u32 *prop = of_get_property(np, name, &len);
@@ -2368,7 +2403,7 @@ static int __devinit emac_read_uint_prop(struct device_node *np, const char *nam
return 0;
}
-static int __devinit emac_init_phy(struct emac_instance *dev)
+static int emac_init_phy(struct emac_instance *dev)
{
struct device_node *np = dev->ofdev->dev.of_node;
struct net_device *ndev = dev->ndev;
@@ -2471,6 +2506,7 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
/* Disable any PHY features not supported by the platform */
dev->phy.def->features &= ~dev->phy_feat_exc;
+ dev->phy.features &= ~dev->phy_feat_exc;
/* Setup initial link parameters */
if (dev->phy.features & SUPPORTED_Autoneg) {
@@ -2503,7 +2539,7 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
return 0;
}
-static int __devinit emac_init_config(struct emac_instance *dev)
+static int emac_init_config(struct emac_instance *dev)
{
struct device_node *np = dev->ofdev->dev.of_node;
const void *p;
@@ -2568,6 +2604,11 @@ static int __devinit emac_init_config(struct emac_instance *dev)
if (of_device_is_compatible(np, "ibm,emac-405ex") ||
of_device_is_compatible(np, "ibm,emac-405exr"))
dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX;
+ if (of_device_is_compatible(np, "ibm,emac-apm821xx")) {
+ dev->features |= (EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE |
+ EMAC_FTR_APM821XX_NO_HALF_DUPLEX |
+ EMAC_FTR_460EX_PHY_CLK_FIX);
+ }
} else if (of_device_is_compatible(np, "ibm,emac4")) {
dev->features |= EMAC_FTR_EMAC4;
if (of_device_is_compatible(np, "ibm,emac-440gx"))
@@ -2637,7 +2678,7 @@ static int __devinit emac_init_config(struct emac_instance *dev)
np->full_name);
return -ENXIO;
}
- memcpy(dev->ndev->dev_addr, p, 6);
+ memcpy(dev->ndev->dev_addr, p, ETH_ALEN);
/* IAHT and GAHT filter parameterization */
if (emac_has_feature(dev, EMAC_FTR_EMAC4SYNC)) {
@@ -2683,7 +2724,7 @@ static const struct net_device_ops emac_gige_netdev_ops = {
.ndo_change_mtu = emac_change_mtu,
};
-static int __devinit emac_probe(struct platform_device *ofdev)
+static int emac_probe(struct platform_device *ofdev)
{
struct net_device *ndev;
struct emac_instance *dev;
@@ -2706,11 +2747,9 @@ static int __devinit emac_probe(struct platform_device *ofdev)
/* Allocate our net_device structure */
err = -ENOMEM;
ndev = alloc_etherdev(sizeof(struct emac_instance));
- if (!ndev) {
- printk(KERN_ERR "%s: could not allocate ethernet device!\n",
- np->full_name);
+ if (!ndev)
goto err_gone;
- }
+
dev = netdev_priv(ndev);
dev->ndev = ndev;
dev->ofdev = ofdev;
@@ -2762,9 +2801,9 @@ static int __devinit emac_probe(struct platform_device *ofdev)
/* display more info about what's missing ? */
goto err_reg_unmap;
}
- dev->mal = dev_get_drvdata(&dev->mal_dev->dev);
+ dev->mal = platform_get_drvdata(dev->mal_dev);
if (dev->mdio_dev != NULL)
- dev->mdio_instance = dev_get_drvdata(&dev->mdio_dev->dev);
+ dev->mdio_instance = platform_get_drvdata(dev->mdio_dev);
/* Register with MAL */
dev->commac.ops = &emac_commac_ops;
@@ -2818,6 +2857,13 @@ static int __devinit emac_probe(struct platform_device *ofdev)
dev->stop_timeout = STOP_TIMEOUT_100;
INIT_DELAYED_WORK(&dev->link_work, emac_link_timer);
+ /* Some SoCs like APM821xx does not support Half Duplex mode. */
+ if (emac_has_feature(dev, EMAC_FTR_APM821XX_NO_HALF_DUPLEX)) {
+ dev->phy_feat_exc = (SUPPORTED_1000baseT_Half |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_10baseT_Half);
+ }
+
/* Find PHY if any */
err = emac_init_phy(dev);
if (err != 0)
@@ -2833,7 +2879,7 @@ static int __devinit emac_probe(struct platform_device *ofdev)
dev->commac.ops = &emac_commac_sg_ops;
} else
ndev->netdev_ops = &emac_netdev_ops;
- SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops);
+ ndev->ethtool_ops = &emac_ethtool_ops;
netif_carrier_off(ndev);
@@ -2848,7 +2894,7 @@ static int __devinit emac_probe(struct platform_device *ofdev)
* fully initialized
*/
wmb();
- dev_set_drvdata(&ofdev->dev, dev);
+ platform_set_drvdata(ofdev, dev);
/* There's a new kid in town ! Let's tell everybody */
wake_up_all(&emac_probe_wait);
@@ -2905,14 +2951,12 @@ static int __devinit emac_probe(struct platform_device *ofdev)
return err;
}
-static int __devexit emac_remove(struct platform_device *ofdev)
+static int emac_remove(struct platform_device *ofdev)
{
- struct emac_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct emac_instance *dev = platform_get_drvdata(ofdev);
DBG(dev, "remove" NL);
- dev_set_drvdata(&ofdev->dev, NULL);
-
unregister_netdev(dev->ndev);
cancel_work_sync(&dev->reset_work);
@@ -2924,6 +2968,9 @@ static int __devexit emac_remove(struct platform_device *ofdev)
if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
zmii_detach(dev->zmii_dev, dev->zmii_port);
+ busy_phy_map &= ~(1 << dev->phy.address);
+ DBG(dev, "busy_phy_map now %#x" NL, busy_phy_map);
+
mal_unregister_commac(dev->mal, &dev->commac);
emac_put_deps(dev);
diff --git a/drivers/net/ethernet/ibm/emac/core.h b/drivers/net/ethernet/ibm/emac/core.h
index fa3ec57935f..67f342a9f65 100644
--- a/drivers/net/ethernet/ibm/emac/core.h
+++ b/drivers/net/ethernet/ibm/emac/core.h
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_newemac/core.h
+ * drivers/net/ethernet/ibm/emac/core.h
*
* Driver for PowerPC 4xx on-chip ethernet controller.
*
@@ -26,7 +26,6 @@
#define __IBM_NEWEMAC_CORE_H
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/list.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
@@ -325,7 +324,14 @@ struct emac_instance {
* Set if we need phy clock workaround for 460ex or 460gt
*/
#define EMAC_FTR_460EX_PHY_CLK_FIX 0x00000400
-
+/*
+ * APM821xx requires Jumbo frame size set explicitly
+ */
+#define EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE 0x00000800
+/*
+ * APM821xx does not support Half Duplex mode
+ */
+#define EMAC_FTR_APM821XX_NO_HALF_DUPLEX 0x00001000
/* Right now, we don't quite handle the always/possible masks on the
* most optimal way as we don't have a way to say something like
@@ -353,7 +359,9 @@ enum {
EMAC_FTR_NO_FLOW_CONTROL_40x |
#endif
EMAC_FTR_460EX_PHY_CLK_FIX |
- EMAC_FTR_440EP_PHY_CLK_FIX,
+ EMAC_FTR_440EP_PHY_CLK_FIX |
+ EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE |
+ EMAC_FTR_APM821XX_NO_HALF_DUPLEX,
};
static inline int emac_has_feature(struct emac_instance *dev,
diff --git a/drivers/net/ethernet/ibm/emac/debug.c b/drivers/net/ethernet/ibm/emac/debug.c
index 8c6c1e2a875..a559f326bf6 100644
--- a/drivers/net/ethernet/ibm/emac/debug.c
+++ b/drivers/net/ethernet/ibm/emac/debug.c
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_newemac/debug.c
+ * drivers/net/ethernet/ibm/emac/debug.c
*
* Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
*
@@ -245,7 +245,7 @@ static void emac_sysrq_handler(int key)
static struct sysrq_key_op emac_sysrq_op = {
.handler = emac_sysrq_handler,
- .help_msg = "emaC",
+ .help_msg = "emac(c)",
.action_msg = "Show EMAC(s) status",
};
diff --git a/drivers/net/ethernet/ibm/emac/debug.h b/drivers/net/ethernet/ibm/emac/debug.h
index 90477fe69d0..9c45efe4c8f 100644
--- a/drivers/net/ethernet/ibm/emac/debug.h
+++ b/drivers/net/ethernet/ibm/emac/debug.h
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_newemac/debug.h
+ * drivers/net/ethernet/ibm/emac/debug.h
*
* Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
*
@@ -29,13 +29,13 @@
struct emac_instance;
struct mal_instance;
-extern void emac_dbg_register(struct emac_instance *dev);
-extern void emac_dbg_unregister(struct emac_instance *dev);
-extern void mal_dbg_register(struct mal_instance *mal);
-extern void mal_dbg_unregister(struct mal_instance *mal);
-extern int emac_init_debug(void) __init;
-extern void emac_fini_debug(void) __exit;
-extern void emac_dbg_dump_all(void);
+void emac_dbg_register(struct emac_instance *dev);
+void emac_dbg_unregister(struct emac_instance *dev);
+void mal_dbg_register(struct mal_instance *mal);
+void mal_dbg_unregister(struct mal_instance *mal);
+int emac_init_debug(void) __init;
+void emac_fini_debug(void) __exit;
+void emac_dbg_dump_all(void);
# define DBG_LEVEL 1
diff --git a/drivers/net/ethernet/ibm/emac/emac.h b/drivers/net/ethernet/ibm/emac/emac.h
index 1568278d759..5afcc27ceeb 100644
--- a/drivers/net/ethernet/ibm/emac/emac.h
+++ b/drivers/net/ethernet/ibm/emac/emac.h
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_newemac/emac.h
+ * drivers/net/ethernet/ibm/emac/emac.h
*
* Register definitions for PowerPC 4xx on-chip ethernet contoller
*
@@ -212,6 +212,8 @@ struct emac_regs {
#define EMAC4_RMR_RFAF_64_1024 0x00000006
#define EMAC4_RMR_RFAF_128_2048 0x00000007
#define EMAC4_RMR_BASE EMAC4_RMR_RFAF_128_2048
+#define EMAC4_RMR_MJS_MASK 0x0001fff8
+#define EMAC4_RMR_MJS(s) (((s) << 3) & EMAC4_RMR_MJS_MASK)
/* EMACx_ISR & EMACx_ISER */
#define EMAC4_ISR_TXPE 0x20000000
diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c
index f3c50b97ec6..63eb959a28a 100644
--- a/drivers/net/ethernet/ibm/emac/mal.c
+++ b/drivers/net/ethernet/ibm/emac/mal.c
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_newemac/mal.c
+ * drivers/net/ethernet/ibm/emac/mal.c
*
* Memory Access Layer (MAL) support
*
@@ -27,14 +27,14 @@
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/of_irq.h>
#include "core.h"
#include <asm/dcr-regs.h>
static int mal_count;
-int __devinit mal_register_commac(struct mal_instance *mal,
- struct mal_commac *commac)
+int mal_register_commac(struct mal_instance *mal, struct mal_commac *commac)
{
unsigned long flags;
@@ -264,7 +264,9 @@ static inline void mal_schedule_poll(struct mal_instance *mal)
{
if (likely(napi_schedule_prep(&mal->napi))) {
MAL_DBG2(mal, "schedule_poll" NL);
+ spin_lock(&mal->lock);
mal_disable_eob_irq(mal);
+ spin_unlock(&mal->lock);
__napi_schedule(&mal->napi);
} else
MAL_DBG2(mal, "already in poll" NL);
@@ -443,15 +445,13 @@ static int mal_poll(struct napi_struct *napi, int budget)
if (unlikely(mc->ops->peek_rx(mc->dev) ||
test_bit(MAL_COMMAC_RX_STOPPED, &mc->flags))) {
MAL_DBG2(mal, "rotting packet" NL);
- if (napi_reschedule(napi))
- mal_disable_eob_irq(mal);
- else
- MAL_DBG2(mal, "already in poll list" NL);
-
- if (budget > 0)
- goto again;
- else
+ if (!napi_reschedule(napi))
goto more_work;
+
+ spin_lock_irqsave(&mal->lock, flags);
+ mal_disable_eob_irq(mal);
+ spin_unlock_irqrestore(&mal->lock, flags);
+ goto again;
}
mc->ops->poll_tx(mc->dev);
}
@@ -517,7 +517,7 @@ void *mal_dump_regs(struct mal_instance *mal, void *buf)
return regs + 1;
}
-static int __devinit mal_probe(struct platform_device *ofdev)
+static int mal_probe(struct platform_device *ofdev)
{
struct mal_instance *mal;
int err = 0, i, bd_size;
@@ -529,12 +529,9 @@ static int __devinit mal_probe(struct platform_device *ofdev)
irq_handler_t hdlr_serr, hdlr_txde, hdlr_rxde;
mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL);
- if (!mal) {
- printk(KERN_ERR
- "mal%d: out of memory allocating MAL structure!\n",
- index);
+ if (!mal)
return -ENOMEM;
- }
+
mal->index = index;
mal->ofdev = ofdev;
mal->version = of_device_is_compatible(ofdev->dev.of_node, "ibm,mcmal2") ? 2 : 1;
@@ -641,17 +638,12 @@ static int __devinit mal_probe(struct platform_device *ofdev)
bd_size = sizeof(struct mal_descriptor) *
(NUM_TX_BUFF * mal->num_tx_chans +
NUM_RX_BUFF * mal->num_rx_chans);
- mal->bd_virt =
- dma_alloc_coherent(&ofdev->dev, bd_size, &mal->bd_dma,
- GFP_KERNEL);
+ mal->bd_virt = dma_zalloc_coherent(&ofdev->dev, bd_size, &mal->bd_dma,
+ GFP_KERNEL);
if (mal->bd_virt == NULL) {
- printk(KERN_ERR
- "mal%d: out of memory allocating RX/TX descriptors!\n",
- index);
err = -ENOMEM;
goto fail_unmap;
}
- memset(mal->bd_virt, 0, bd_size);
for (i = 0; i < mal->num_tx_chans; ++i)
set_mal_dcrn(mal, MAL_TXCTPR(i), mal->bd_dma +
@@ -690,10 +682,7 @@ static int __devinit mal_probe(struct platform_device *ofdev)
goto fail6;
/* Enable all MAL SERR interrupt sources */
- if (mal->version == 2)
- set_mal_dcrn(mal, MAL_IER, MAL2_IER_EVENTS);
- else
- set_mal_dcrn(mal, MAL_IER, MAL1_IER_EVENTS);
+ set_mal_dcrn(mal, MAL_IER, MAL_IER_EVENTS);
/* Enable EOB interrupt */
mal_enable_eob_irq(mal);
@@ -705,7 +694,7 @@ static int __devinit mal_probe(struct platform_device *ofdev)
/* Advertise this instance to the rest of the world */
wmb();
- dev_set_drvdata(&ofdev->dev, mal);
+ platform_set_drvdata(ofdev, mal);
mal_dbg_register(mal);
@@ -729,24 +718,20 @@ static int __devinit mal_probe(struct platform_device *ofdev)
return err;
}
-static int __devexit mal_remove(struct platform_device *ofdev)
+static int mal_remove(struct platform_device *ofdev)
{
- struct mal_instance *mal = dev_get_drvdata(&ofdev->dev);
+ struct mal_instance *mal = platform_get_drvdata(ofdev);
MAL_DBG(mal, "remove" NL);
/* Synchronize with scheduled polling */
napi_disable(&mal->napi);
- if (!list_empty(&mal->list)) {
+ if (!list_empty(&mal->list))
/* This is *very* bad */
- printk(KERN_EMERG
+ WARN(1, KERN_EMERG
"mal%d: commac list is not empty on remove!\n",
mal->index);
- WARN_ON(1);
- }
-
- dev_set_drvdata(&ofdev->dev, NULL);
free_irq(mal->serr_irq, mal);
free_irq(mal->txde_irq, mal);
diff --git a/drivers/net/ethernet/ibm/emac/mal.h b/drivers/net/ethernet/ibm/emac/mal.h
index d06f985bda3..eeade2ea833 100644
--- a/drivers/net/ethernet/ibm/emac/mal.h
+++ b/drivers/net/ethernet/ibm/emac/mal.h
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_newemac/mal.h
+ * drivers/net/ethernet/ibm/emac/mal.h
*
* Memory Access Layer (MAL) support
*
@@ -95,24 +95,20 @@
#define MAL_IER 0x02
+/* MAL IER bits */
#define MAL_IER_DE 0x00000010
#define MAL_IER_OTE 0x00000004
#define MAL_IER_OE 0x00000002
#define MAL_IER_PE 0x00000001
-/* MAL V1 IER bits */
-#define MAL1_IER_NWE 0x00000008
-#define MAL1_IER_SOC_EVENTS MAL1_IER_NWE
-#define MAL1_IER_EVENTS (MAL1_IER_SOC_EVENTS | MAL_IER_DE | \
- MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE)
-/* MAL V2 IER bits */
-#define MAL2_IER_PT 0x00000080
-#define MAL2_IER_PRE 0x00000040
-#define MAL2_IER_PWE 0x00000020
-#define MAL2_IER_SOC_EVENTS (MAL2_IER_PT | MAL2_IER_PRE | MAL2_IER_PWE)
-#define MAL2_IER_EVENTS (MAL2_IER_SOC_EVENTS | MAL_IER_DE | \
- MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE)
+/* PLB read/write/timeout errors */
+#define MAL_IER_PTE 0x00000080
+#define MAL_IER_PRE 0x00000040
+#define MAL_IER_PWE 0x00000020
+#define MAL_IER_SOC_EVENTS (MAL_IER_PTE | MAL_IER_PRE | MAL_IER_PWE)
+#define MAL_IER_EVENTS (MAL_IER_SOC_EVENTS | MAL_IER_DE | \
+ MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE)
#define MAL_TXCASR 0x04
#define MAL_TXCARR 0x05
diff --git a/drivers/net/ethernet/ibm/emac/phy.c b/drivers/net/ethernet/ibm/emac/phy.c
index ab4e5969fe6..d3b9d103353 100644
--- a/drivers/net/ethernet/ibm/emac/phy.c
+++ b/drivers/net/ethernet/ibm/emac/phy.c
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_newemac/phy.c
+ * drivers/net/ethernet/ibm/emac/phy.c
*
* Driver for PowerPC 4xx on-chip ethernet controller, PHY support.
* Borrowed from sungem_phy.c, though I only kept the generic MII
diff --git a/drivers/net/ethernet/ibm/emac/phy.h b/drivers/net/ethernet/ibm/emac/phy.h
index 5d2bf4cbe50..d7e41ec3746 100644
--- a/drivers/net/ethernet/ibm/emac/phy.h
+++ b/drivers/net/ethernet/ibm/emac/phy.h
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_newemac/phy.h
+ * drivers/net/ethernet/ibm/emac/phy.h
*
* Driver for PowerPC 4xx on-chip ethernet controller, PHY support
*
diff --git a/drivers/net/ethernet/ibm/emac/rgmii.c b/drivers/net/ethernet/ibm/emac/rgmii.c
index 4fa53f3def6..a01182cce96 100644
--- a/drivers/net/ethernet/ibm/emac/rgmii.c
+++ b/drivers/net/ethernet/ibm/emac/rgmii.c
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_newemac/rgmii.c
+ * drivers/net/ethernet/ibm/emac/rgmii.c
*
* Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
*
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/ethtool.h>
+#include <linux/of_address.h>
#include <asm/io.h>
#include "emac.h"
@@ -44,6 +45,7 @@
/* RGMIIx_SSR */
#define RGMII_SSR_MASK(idx) (0x7 << ((idx) * 8))
+#define RGMII_SSR_10(idx) (0x1 << ((idx) * 8))
#define RGMII_SSR_100(idx) (0x2 << ((idx) * 8))
#define RGMII_SSR_1000(idx) (0x4 << ((idx) * 8))
@@ -93,9 +95,9 @@ static inline u32 rgmii_mode_mask(int mode, int input)
}
}
-int __devinit rgmii_attach(struct platform_device *ofdev, int input, int mode)
+int rgmii_attach(struct platform_device *ofdev, int input, int mode)
{
- struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_instance *dev = platform_get_drvdata(ofdev);
struct rgmii_regs __iomem *p = dev->base;
RGMII_DBG(dev, "attach(%d)" NL, input);
@@ -124,7 +126,7 @@ int __devinit rgmii_attach(struct platform_device *ofdev, int input, int mode)
void rgmii_set_speed(struct platform_device *ofdev, int input, int speed)
{
- struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_instance *dev = platform_get_drvdata(ofdev);
struct rgmii_regs __iomem *p = dev->base;
u32 ssr;
@@ -138,6 +140,8 @@ void rgmii_set_speed(struct platform_device *ofdev, int input, int speed)
ssr |= RGMII_SSR_1000(input);
else if (speed == SPEED_100)
ssr |= RGMII_SSR_100(input);
+ else if (speed == SPEED_10)
+ ssr |= RGMII_SSR_10(input);
out_be32(&p->ssr, ssr);
@@ -146,7 +150,7 @@ void rgmii_set_speed(struct platform_device *ofdev, int input, int speed)
void rgmii_get_mdio(struct platform_device *ofdev, int input)
{
- struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_instance *dev = platform_get_drvdata(ofdev);
struct rgmii_regs __iomem *p = dev->base;
u32 fer;
@@ -167,7 +171,7 @@ void rgmii_get_mdio(struct platform_device *ofdev, int input)
void rgmii_put_mdio(struct platform_device *ofdev, int input)
{
- struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_instance *dev = platform_get_drvdata(ofdev);
struct rgmii_regs __iomem *p = dev->base;
u32 fer;
@@ -188,7 +192,7 @@ void rgmii_put_mdio(struct platform_device *ofdev, int input)
void rgmii_detach(struct platform_device *ofdev, int input)
{
- struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_instance *dev = platform_get_drvdata(ofdev);
struct rgmii_regs __iomem *p;
BUG_ON(!dev || dev->users == 0);
@@ -214,7 +218,7 @@ int rgmii_get_regs_len(struct platform_device *ofdev)
void *rgmii_dump_regs(struct platform_device *ofdev, void *buf)
{
- struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_instance *dev = platform_get_drvdata(ofdev);
struct emac_ethtool_regs_subhdr *hdr = buf;
struct rgmii_regs *regs = (struct rgmii_regs *)(hdr + 1);
@@ -228,7 +232,7 @@ void *rgmii_dump_regs(struct platform_device *ofdev, void *buf)
}
-static int __devinit rgmii_probe(struct platform_device *ofdev)
+static int rgmii_probe(struct platform_device *ofdev)
{
struct device_node *np = ofdev->dev.of_node;
struct rgmii_instance *dev;
@@ -237,11 +241,8 @@ static int __devinit rgmii_probe(struct platform_device *ofdev)
rc = -ENOMEM;
dev = kzalloc(sizeof(struct rgmii_instance), GFP_KERNEL);
- if (dev == NULL) {
- printk(KERN_ERR "%s: could not allocate RGMII device!\n",
- np->full_name);
+ if (dev == NULL)
goto err_gone;
- }
mutex_init(&dev->lock);
dev->ofdev = ofdev;
@@ -282,7 +283,7 @@ static int __devinit rgmii_probe(struct platform_device *ofdev)
(dev->flags & EMAC_RGMII_FLAG_HAS_MDIO) ? "" : "out");
wmb();
- dev_set_drvdata(&ofdev->dev, dev);
+ platform_set_drvdata(ofdev, dev);
return 0;
@@ -292,11 +293,9 @@ static int __devinit rgmii_probe(struct platform_device *ofdev)
return rc;
}
-static int __devexit rgmii_remove(struct platform_device *ofdev)
+static int rgmii_remove(struct platform_device *ofdev)
{
- struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
-
- dev_set_drvdata(&ofdev->dev, NULL);
+ struct rgmii_instance *dev = platform_get_drvdata(ofdev);
WARN_ON(dev->users != 0);
diff --git a/drivers/net/ethernet/ibm/emac/rgmii.h b/drivers/net/ethernet/ibm/emac/rgmii.h
index 9296b6c5f92..d4f1374d190 100644
--- a/drivers/net/ethernet/ibm/emac/rgmii.h
+++ b/drivers/net/ethernet/ibm/emac/rgmii.h
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_newemac/rgmii.h
+ * drivers/net/ethernet/ibm/emac/rgmii.h
*
* Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
*
@@ -56,15 +56,15 @@ struct rgmii_instance {
#ifdef CONFIG_IBM_EMAC_RGMII
-extern int rgmii_init(void);
-extern void rgmii_exit(void);
-extern int rgmii_attach(struct platform_device *ofdev, int input, int mode);
-extern void rgmii_detach(struct platform_device *ofdev, int input);
-extern void rgmii_get_mdio(struct platform_device *ofdev, int input);
-extern void rgmii_put_mdio(struct platform_device *ofdev, int input);
-extern void rgmii_set_speed(struct platform_device *ofdev, int input, int speed);
-extern int rgmii_get_regs_len(struct platform_device *ofdev);
-extern void *rgmii_dump_regs(struct platform_device *ofdev, void *buf);
+int rgmii_init(void);
+void rgmii_exit(void);
+int rgmii_attach(struct platform_device *ofdev, int input, int mode);
+void rgmii_detach(struct platform_device *ofdev, int input);
+void rgmii_get_mdio(struct platform_device *ofdev, int input);
+void rgmii_put_mdio(struct platform_device *ofdev, int input);
+void rgmii_set_speed(struct platform_device *ofdev, int input, int speed);
+int rgmii_get_regs_len(struct platform_device *ofdev);
+void *rgmii_dump_regs(struct platform_device *ofdev, void *buf);
#else
diff --git a/drivers/net/ethernet/ibm/emac/tah.c b/drivers/net/ethernet/ibm/emac/tah.c
index 5f51bf7c9dc..9f24769ed82 100644
--- a/drivers/net/ethernet/ibm/emac/tah.c
+++ b/drivers/net/ethernet/ibm/emac/tah.c
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_newemac/tah.c
+ * drivers/net/ethernet/ibm/emac/tah.c
*
* Driver for PowerPC 4xx on-chip ethernet controller, TAH support.
*
@@ -18,14 +18,15 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
+#include <linux/of_address.h>
#include <asm/io.h>
#include "emac.h"
#include "core.h"
-int __devinit tah_attach(struct platform_device *ofdev, int channel)
+int tah_attach(struct platform_device *ofdev, int channel)
{
- struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct tah_instance *dev = platform_get_drvdata(ofdev);
mutex_lock(&dev->lock);
/* Reset has been done at probe() time... nothing else to do for now */
@@ -37,7 +38,7 @@ int __devinit tah_attach(struct platform_device *ofdev, int channel)
void tah_detach(struct platform_device *ofdev, int channel)
{
- struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct tah_instance *dev = platform_get_drvdata(ofdev);
mutex_lock(&dev->lock);
--dev->users;
@@ -46,7 +47,7 @@ void tah_detach(struct platform_device *ofdev, int channel)
void tah_reset(struct platform_device *ofdev)
{
- struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct tah_instance *dev = platform_get_drvdata(ofdev);
struct tah_regs __iomem *p = dev->base;
int n;
@@ -74,7 +75,7 @@ int tah_get_regs_len(struct platform_device *ofdev)
void *tah_dump_regs(struct platform_device *ofdev, void *buf)
{
- struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct tah_instance *dev = platform_get_drvdata(ofdev);
struct emac_ethtool_regs_subhdr *hdr = buf;
struct tah_regs *regs = (struct tah_regs *)(hdr + 1);
@@ -87,7 +88,7 @@ void *tah_dump_regs(struct platform_device *ofdev, void *buf)
return regs + 1;
}
-static int __devinit tah_probe(struct platform_device *ofdev)
+static int tah_probe(struct platform_device *ofdev)
{
struct device_node *np = ofdev->dev.of_node;
struct tah_instance *dev;
@@ -96,11 +97,8 @@ static int __devinit tah_probe(struct platform_device *ofdev)
rc = -ENOMEM;
dev = kzalloc(sizeof(struct tah_instance), GFP_KERNEL);
- if (dev == NULL) {
- printk(KERN_ERR "%s: could not allocate TAH device!\n",
- np->full_name);
+ if (dev == NULL)
goto err_gone;
- }
mutex_init(&dev->lock);
dev->ofdev = ofdev;
@@ -121,7 +119,7 @@ static int __devinit tah_probe(struct platform_device *ofdev)
goto err_free;
}
- dev_set_drvdata(&ofdev->dev, dev);
+ platform_set_drvdata(ofdev, dev);
/* Initialize TAH and enable IPv4 checksum verification, no TSO yet */
tah_reset(ofdev);
@@ -138,11 +136,9 @@ static int __devinit tah_probe(struct platform_device *ofdev)
return rc;
}
-static int __devexit tah_remove(struct platform_device *ofdev)
+static int tah_remove(struct platform_device *ofdev)
{
- struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
-
- dev_set_drvdata(&ofdev->dev, NULL);
+ struct tah_instance *dev = platform_get_drvdata(ofdev);
WARN_ON(dev->users != 0);
diff --git a/drivers/net/ethernet/ibm/emac/tah.h b/drivers/net/ethernet/ibm/emac/tah.h
index 3437ab4964c..4d5f336f07b 100644
--- a/drivers/net/ethernet/ibm/emac/tah.h
+++ b/drivers/net/ethernet/ibm/emac/tah.h
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_newemac/tah.h
+ * drivers/net/ethernet/ibm/emac/tah.h
*
* Driver for PowerPC 4xx on-chip ethernet controller, TAH support.
*
@@ -72,13 +72,13 @@ struct tah_instance {
#ifdef CONFIG_IBM_EMAC_TAH
-extern int tah_init(void);
-extern void tah_exit(void);
-extern int tah_attach(struct platform_device *ofdev, int channel);
-extern void tah_detach(struct platform_device *ofdev, int channel);
-extern void tah_reset(struct platform_device *ofdev);
-extern int tah_get_regs_len(struct platform_device *ofdev);
-extern void *tah_dump_regs(struct platform_device *ofdev, void *buf);
+int tah_init(void);
+void tah_exit(void);
+int tah_attach(struct platform_device *ofdev, int channel);
+void tah_detach(struct platform_device *ofdev, int channel);
+void tah_reset(struct platform_device *ofdev);
+int tah_get_regs_len(struct platform_device *ofdev);
+void *tah_dump_regs(struct platform_device *ofdev, void *buf);
#else
diff --git a/drivers/net/ethernet/ibm/emac/zmii.c b/drivers/net/ethernet/ibm/emac/zmii.c
index 97449e786d6..9ca67a38c06 100644
--- a/drivers/net/ethernet/ibm/emac/zmii.c
+++ b/drivers/net/ethernet/ibm/emac/zmii.c
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_newemac/zmii.c
+ * drivers/net/ethernet/ibm/emac/zmii.c
*
* Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support.
*
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/ethtool.h>
+#include <linux/of_address.h>
#include <asm/io.h>
#include "emac.h"
@@ -82,9 +83,9 @@ static inline u32 zmii_mode_mask(int mode, int input)
}
}
-int __devinit zmii_attach(struct platform_device *ofdev, int input, int *mode)
+int zmii_attach(struct platform_device *ofdev, int input, int *mode)
{
- struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct zmii_instance *dev = platform_get_drvdata(ofdev);
struct zmii_regs __iomem *p = dev->base;
ZMII_DBG(dev, "init(%d, %d)" NL, input, *mode);
@@ -150,7 +151,7 @@ int __devinit zmii_attach(struct platform_device *ofdev, int input, int *mode)
void zmii_get_mdio(struct platform_device *ofdev, int input)
{
- struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct zmii_instance *dev = platform_get_drvdata(ofdev);
u32 fer;
ZMII_DBG2(dev, "get_mdio(%d)" NL, input);
@@ -163,7 +164,7 @@ void zmii_get_mdio(struct platform_device *ofdev, int input)
void zmii_put_mdio(struct platform_device *ofdev, int input)
{
- struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct zmii_instance *dev = platform_get_drvdata(ofdev);
ZMII_DBG2(dev, "put_mdio(%d)" NL, input);
mutex_unlock(&dev->lock);
@@ -172,7 +173,7 @@ void zmii_put_mdio(struct platform_device *ofdev, int input)
void zmii_set_speed(struct platform_device *ofdev, int input, int speed)
{
- struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct zmii_instance *dev = platform_get_drvdata(ofdev);
u32 ssr;
mutex_lock(&dev->lock);
@@ -193,7 +194,7 @@ void zmii_set_speed(struct platform_device *ofdev, int input, int speed)
void zmii_detach(struct platform_device *ofdev, int input)
{
- struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct zmii_instance *dev = platform_get_drvdata(ofdev);
BUG_ON(!dev || dev->users == 0);
@@ -218,7 +219,7 @@ int zmii_get_regs_len(struct platform_device *ofdev)
void *zmii_dump_regs(struct platform_device *ofdev, void *buf)
{
- struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct zmii_instance *dev = platform_get_drvdata(ofdev);
struct emac_ethtool_regs_subhdr *hdr = buf;
struct zmii_regs *regs = (struct zmii_regs *)(hdr + 1);
@@ -231,7 +232,7 @@ void *zmii_dump_regs(struct platform_device *ofdev, void *buf)
return regs + 1;
}
-static int __devinit zmii_probe(struct platform_device *ofdev)
+static int zmii_probe(struct platform_device *ofdev)
{
struct device_node *np = ofdev->dev.of_node;
struct zmii_instance *dev;
@@ -240,11 +241,8 @@ static int __devinit zmii_probe(struct platform_device *ofdev)
rc = -ENOMEM;
dev = kzalloc(sizeof(struct zmii_instance), GFP_KERNEL);
- if (dev == NULL) {
- printk(KERN_ERR "%s: could not allocate ZMII device!\n",
- np->full_name);
+ if (dev == NULL)
goto err_gone;
- }
mutex_init(&dev->lock);
dev->ofdev = ofdev;
@@ -275,7 +273,7 @@ static int __devinit zmii_probe(struct platform_device *ofdev)
printk(KERN_INFO
"ZMII %s initialized\n", ofdev->dev.of_node->full_name);
wmb();
- dev_set_drvdata(&ofdev->dev, dev);
+ platform_set_drvdata(ofdev, dev);
return 0;
@@ -285,11 +283,9 @@ static int __devinit zmii_probe(struct platform_device *ofdev)
return rc;
}
-static int __devexit zmii_remove(struct platform_device *ofdev)
+static int zmii_remove(struct platform_device *ofdev)
{
- struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
-
- dev_set_drvdata(&ofdev->dev, NULL);
+ struct zmii_instance *dev = platform_get_drvdata(ofdev);
WARN_ON(dev->users != 0);
diff --git a/drivers/net/ethernet/ibm/emac/zmii.h b/drivers/net/ethernet/ibm/emac/zmii.h
index ceaed823a83..0959c55b145 100644
--- a/drivers/net/ethernet/ibm/emac/zmii.h
+++ b/drivers/net/ethernet/ibm/emac/zmii.h
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_newemac/zmii.h
+ * drivers/net/ethernet/ibm/emac/zmii.h
*
* Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support.
*
@@ -53,15 +53,15 @@ struct zmii_instance {
#ifdef CONFIG_IBM_EMAC_ZMII
-extern int zmii_init(void);
-extern void zmii_exit(void);
-extern int zmii_attach(struct platform_device *ofdev, int input, int *mode);
-extern void zmii_detach(struct platform_device *ofdev, int input);
-extern void zmii_get_mdio(struct platform_device *ofdev, int input);
-extern void zmii_put_mdio(struct platform_device *ofdev, int input);
-extern void zmii_set_speed(struct platform_device *ofdev, int input, int speed);
-extern int zmii_get_regs_len(struct platform_device *ocpdev);
-extern void *zmii_dump_regs(struct platform_device *ofdev, void *buf);
+int zmii_init(void);
+void zmii_exit(void);
+int zmii_attach(struct platform_device *ofdev, int input, int *mode);
+void zmii_detach(struct platform_device *ofdev, int input);
+void zmii_get_mdio(struct platform_device *ofdev, int input);
+void zmii_put_mdio(struct platform_device *ofdev, int input);
+void zmii_set_speed(struct platform_device *ofdev, int input, int speed);
+int zmii_get_regs_len(struct platform_device *ocpdev);
+void *zmii_dump_regs(struct platform_device *ofdev, void *buf);
#else
# define zmii_init() 0
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 4da972eaabb..c9127562bd2 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -12,8 +12,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) IBM Corporation, 2003, 2010
*
@@ -106,7 +105,7 @@ struct ibmveth_stat ibmveth_stats[] = {
/* simple methods of getting data from the current rxq entry */
static inline u32 ibmveth_rxq_flags(struct ibmveth_adapter *adapter)
{
- return adapter->rx_queue.queue_addr[adapter->rx_queue.index].flags_off;
+ return be32_to_cpu(adapter->rx_queue.queue_addr[adapter->rx_queue.index].flags_off);
}
static inline int ibmveth_rxq_toggle(struct ibmveth_adapter *adapter)
@@ -132,7 +131,7 @@ static inline int ibmveth_rxq_frame_offset(struct ibmveth_adapter *adapter)
static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)
{
- return adapter->rx_queue.queue_addr[adapter->rx_queue.index].length;
+ return be32_to_cpu(adapter->rx_queue.queue_addr[adapter->rx_queue.index].length);
}
static inline int ibmveth_rxq_csum_good(struct ibmveth_adapter *adapter)
@@ -472,14 +471,9 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
}
if (adapter->rx_queue.queue_addr != NULL) {
- if (!dma_mapping_error(dev, adapter->rx_queue.queue_dma)) {
- dma_unmap_single(dev,
- adapter->rx_queue.queue_dma,
- adapter->rx_queue.queue_len,
- DMA_BIDIRECTIONAL);
- adapter->rx_queue.queue_dma = DMA_ERROR_CODE;
- }
- kfree(adapter->rx_queue.queue_addr);
+ dma_free_coherent(dev, adapter->rx_queue.queue_len,
+ adapter->rx_queue.queue_addr,
+ adapter->rx_queue.queue_dma);
adapter->rx_queue.queue_addr = NULL;
}
@@ -528,10 +522,21 @@ retry:
return rc;
}
+static u64 ibmveth_encode_mac_addr(u8 *mac)
+{
+ int i;
+ u64 encoded = 0;
+
+ for (i = 0; i < ETH_ALEN; i++)
+ encoded = (encoded << 8) | mac[i];
+
+ return encoded;
+}
+
static int ibmveth_open(struct net_device *netdev)
{
struct ibmveth_adapter *adapter = netdev_priv(netdev);
- u64 mac_address = 0;
+ u64 mac_address;
int rxq_entries = 1;
unsigned long lpar_rc;
int rc;
@@ -556,30 +561,25 @@ static int ibmveth_open(struct net_device *netdev)
goto err_out;
}
+ dev = &adapter->vdev->dev;
+
adapter->rx_queue.queue_len = sizeof(struct ibmveth_rx_q_entry) *
rxq_entries;
- adapter->rx_queue.queue_addr = kmalloc(adapter->rx_queue.queue_len,
- GFP_KERNEL);
-
+ adapter->rx_queue.queue_addr =
+ dma_alloc_coherent(dev, adapter->rx_queue.queue_len,
+ &adapter->rx_queue.queue_dma, GFP_KERNEL);
if (!adapter->rx_queue.queue_addr) {
- netdev_err(netdev, "unable to allocate rx queue pages\n");
rc = -ENOMEM;
goto err_out;
}
- dev = &adapter->vdev->dev;
-
adapter->buffer_list_dma = dma_map_single(dev,
adapter->buffer_list_addr, 4096, DMA_BIDIRECTIONAL);
adapter->filter_list_dma = dma_map_single(dev,
adapter->filter_list_addr, 4096, DMA_BIDIRECTIONAL);
- adapter->rx_queue.queue_dma = dma_map_single(dev,
- adapter->rx_queue.queue_addr,
- adapter->rx_queue.queue_len, DMA_BIDIRECTIONAL);
if ((dma_mapping_error(dev, adapter->buffer_list_dma)) ||
- (dma_mapping_error(dev, adapter->filter_list_dma)) ||
- (dma_mapping_error(dev, adapter->rx_queue.queue_dma))) {
+ (dma_mapping_error(dev, adapter->filter_list_dma))) {
netdev_err(netdev, "unable to map filter or buffer list "
"pages\n");
rc = -ENOMEM;
@@ -590,8 +590,7 @@ static int ibmveth_open(struct net_device *netdev)
adapter->rx_queue.num_slots = rxq_entries;
adapter->rx_queue.toggle = 1;
- memcpy(&mac_address, netdev->dev_addr, netdev->addr_len);
- mac_address = mac_address >> 16;
+ mac_address = ibmveth_encode_mac_addr(netdev->dev_addr);
rxq_desc.fields.flags_len = IBMVETH_BUF_VALID |
adapter->rx_queue.queue_len;
@@ -645,7 +644,6 @@ static int ibmveth_open(struct net_device *netdev)
adapter->bounce_buffer =
kmalloc(netdev->mtu + IBMVETH_BUFF_OH, GFP_KERNEL);
if (!adapter->bounce_buffer) {
- netdev_err(netdev, "unable to allocate bounce buffer\n");
rc = -ENOMEM;
goto err_out_free_irq;
}
@@ -730,12 +728,12 @@ static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static void netdev_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strncpy(info->driver, ibmveth_driver_name, sizeof(info->driver) - 1);
- strncpy(info->version, ibmveth_driver_version,
- sizeof(info->version) - 1);
+ strlcpy(info->driver, ibmveth_driver_name, sizeof(info->driver));
+ strlcpy(info->version, ibmveth_driver_version, sizeof(info->version));
}
-static u32 ibmveth_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t ibmveth_fix_features(struct net_device *dev,
+ netdev_features_t features)
{
/*
* Since the ibmveth firmware interface does not have the
@@ -838,7 +836,8 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data)
return rc1 ? rc1 : rc2;
}
-static int ibmveth_set_features(struct net_device *dev, u32 features)
+static int ibmveth_set_features(struct net_device *dev,
+ netdev_features_t features)
{
struct ibmveth_adapter *adapter = netdev_priv(dev);
int rx_csum = !!(features & NETIF_F_RXCSUM);
@@ -1014,15 +1013,15 @@ retry_bounce:
/* Map the frags */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
dma_addr = skb_frag_dma_map(&adapter->vdev->dev, frag, 0,
- frag->size, DMA_TO_DEVICE);
+ skb_frag_size(frag), DMA_TO_DEVICE);
if (dma_mapping_error(&adapter->vdev->dev, dma_addr))
goto map_failed_frags;
- descs[i+1].fields.flags_len = desc_flags | frag->size;
+ descs[i+1].fields.flags_len = desc_flags | skb_frag_size(frag);
descs[i+1].fields.address = dma_addr;
}
@@ -1045,7 +1044,7 @@ retry_bounce:
DMA_TO_DEVICE);
out:
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
return NETDEV_TX_OK;
map_failed_frags:
@@ -1073,7 +1072,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
unsigned long lpar_rc;
restart_poll:
- do {
+ while (frames_processed < budget) {
if (!ibmveth_rxq_pending_buffer(adapter))
break;
@@ -1122,7 +1121,7 @@ restart_poll:
netdev->stats.rx_bytes += length;
frames_processed++;
}
- } while (frames_processed < budget);
+ }
ibmveth_replenish_task(adapter);
@@ -1194,8 +1193,8 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
/* add the addresses to the filter table */
netdev_for_each_mc_addr(ha, netdev) {
/* add the multicast address to the filter table */
- unsigned long mcast_addr = 0;
- memcpy(((char *)&mcast_addr)+2, ha->addr, 6);
+ u64 mcast_addr;
+ mcast_addr = ibmveth_encode_mac_addr(ha->addr);
lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
IbmVethMcastAddFilter,
mcast_addr);
@@ -1286,18 +1285,21 @@ static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev)
{
struct net_device *netdev = dev_get_drvdata(&vdev->dev);
struct ibmveth_adapter *adapter;
+ struct iommu_table *tbl;
unsigned long ret;
int i;
int rxqentries = 1;
+ tbl = get_iommu_table_base(&vdev->dev);
+
/* netdev inits at probe time along with the structures we need below*/
if (netdev == NULL)
- return IOMMU_PAGE_ALIGN(IBMVETH_IO_ENTITLEMENT_DEFAULT);
+ return IOMMU_PAGE_ALIGN(IBMVETH_IO_ENTITLEMENT_DEFAULT, tbl);
adapter = netdev_priv(netdev);
ret = IBMVETH_BUFF_LIST_SIZE + IBMVETH_FILT_LIST_SIZE;
- ret += IOMMU_PAGE_ALIGN(netdev->mtu);
+ ret += IOMMU_PAGE_ALIGN(netdev->mtu, tbl);
for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
/* add the size of the active receive buffers */
@@ -1305,11 +1307,12 @@ static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev)
ret +=
adapter->rx_buff_pool[i].size *
IOMMU_PAGE_ALIGN(adapter->rx_buff_pool[i].
- buff_size);
+ buff_size, tbl);
rxqentries += adapter->rx_buff_pool[i].size;
}
/* add the size of the receive queue entries */
- ret += IOMMU_PAGE_ALIGN(rxqentries * sizeof(struct ibmveth_rx_q_entry));
+ ret += IOMMU_PAGE_ALIGN(
+ rxqentries * sizeof(struct ibmveth_rx_q_entry), tbl);
return ret;
}
@@ -1330,10 +1333,9 @@ static const struct net_device_ops ibmveth_netdev_ops = {
#endif
};
-static int __devinit ibmveth_probe(struct vio_dev *dev,
- const struct vio_device_id *id)
+static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
{
- int rc, i;
+ int rc, i, mac_len;
struct net_device *netdev;
struct ibmveth_adapter *adapter;
unsigned char *mac_addr_p;
@@ -1343,11 +1345,19 @@ static int __devinit ibmveth_probe(struct vio_dev *dev,
dev->unit_address);
mac_addr_p = (unsigned char *)vio_get_attribute(dev, VETH_MAC_ADDR,
- NULL);
+ &mac_len);
if (!mac_addr_p) {
dev_err(&dev->dev, "Can't find VETH_MAC_ADDR attribute\n");
return -EINVAL;
}
+ /* Workaround for old/broken pHyp */
+ if (mac_len == 8)
+ mac_addr_p += 2;
+ else if (mac_len != 6) {
+ dev_err(&dev->dev, "VETH_MAC_ADDR attribute wrong len %d\n",
+ mac_len);
+ return -EINVAL;
+ }
mcastFilterSize_p = (unsigned int *)vio_get_attribute(dev,
VETH_MCAST_FILTER_SIZE, NULL);
@@ -1372,20 +1382,6 @@ static int __devinit ibmveth_probe(struct vio_dev *dev,
netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16);
- /*
- * Some older boxes running PHYP non-natively have an OF that returns
- * a 8-byte local-mac-address field (and the first 2 bytes have to be
- * ignored) while newer boxes' OF return a 6-byte field. Note that
- * IEEE 1275 specifies that local-mac-address must be a 6-byte field.
- * The RPA doc specifies that the first byte must be 10b, so we'll
- * just look for it to solve this 8 vs. 6 byte field issue
- */
- if ((*mac_addr_p & 0x3) != 0x02)
- mac_addr_p += 2;
-
- adapter->mac_addr = 0;
- memcpy(&adapter->mac_addr, mac_addr_p, 6);
-
netdev->irq = dev->irq;
netdev->netdev_ops = &ibmveth_netdev_ops;
netdev->ethtool_ops = &netdev_ethtool_ops;
@@ -1394,7 +1390,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev,
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
netdev->features |= netdev->hw_features;
- memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len);
+ memcpy(netdev->dev_addr, mac_addr_p, ETH_ALEN);
for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
struct kobject *kobj = &adapter->rx_buff_pool[i].kobj;
@@ -1432,7 +1428,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev,
return 0;
}
-static int __devexit ibmveth_remove(struct vio_dev *dev)
+static int ibmveth_remove(struct vio_dev *dev)
{
struct net_device *netdev = dev_get_drvdata(&dev->dev);
struct ibmveth_adapter *adapter = netdev_priv(netdev);
@@ -1599,7 +1595,7 @@ static int ibmveth_resume(struct device *dev)
return 0;
}
-static struct vio_device_id ibmveth_device_table[] __devinitdata = {
+static struct vio_device_id ibmveth_device_table[] = {
{ "network", "IBM,l-lan"},
{ "", "" }
};
@@ -1614,11 +1610,8 @@ static struct vio_driver ibmveth_driver = {
.probe = ibmveth_probe,
.remove = ibmveth_remove,
.get_desired_dma = ibmveth_get_desired_dma,
- .driver = {
- .name = ibmveth_driver_name,
- .owner = THIS_MODULE,
- .pm = &ibmveth_pm_ops,
- }
+ .name = ibmveth_driver_name,
+ .pm = &ibmveth_pm_ops,
};
static int __init ibmveth_module_init(void)
diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h
index 43a794fab9f..1f37499d439 100644
--- a/drivers/net/ethernet/ibm/ibmveth.h
+++ b/drivers/net/ethernet/ibm/ibmveth.h
@@ -12,8 +12,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) IBM Corporation, 2003, 2010
*
@@ -139,7 +138,6 @@ struct ibmveth_adapter {
struct napi_struct napi;
struct net_device_stats stats;
unsigned int mcastFilterSize;
- unsigned long mac_addr;
void * buffer_list_addr;
void * filter_list_addr;
dma_addr_t buffer_list_dma;
@@ -164,14 +162,26 @@ struct ibmveth_adapter {
u64 tx_send_failed;
};
+/*
+ * We pass struct ibmveth_buf_desc_fields to the hypervisor in registers,
+ * so we don't need to byteswap the two elements. However since we use
+ * a union (ibmveth_buf_desc) to convert from the struct to a u64 we
+ * do end up with endian specific ordering of the elements and that
+ * needs correcting.
+ */
struct ibmveth_buf_desc_fields {
+#ifdef __BIG_ENDIAN
+ u32 flags_len;
+ u32 address;
+#else
+ u32 address;
u32 flags_len;
+#endif
#define IBMVETH_BUF_VALID 0x80000000
#define IBMVETH_BUF_TOGGLE 0x40000000
#define IBMVETH_BUF_NO_CSUM 0x02000000
#define IBMVETH_BUF_CSUM_GOOD 0x01000000
#define IBMVETH_BUF_LEN_MASK 0x00FFFFFF
- u32 address;
};
union ibmveth_buf_desc {
@@ -180,7 +190,7 @@ union ibmveth_buf_desc {
};
struct ibmveth_rx_q_entry {
- u32 flags_off;
+ __be32 flags_off;
#define IBMVETH_RXQ_TOGGLE 0x80000000
#define IBMVETH_RXQ_TOGGLE_SHIFT 31
#define IBMVETH_RXQ_VALID 0x40000000
@@ -188,7 +198,8 @@ struct ibmveth_rx_q_entry {
#define IBMVETH_RXQ_CSUM_GOOD 0x01000000
#define IBMVETH_RXQ_OFF_MASK 0x0000FFFF
- u32 length;
+ __be32 length;
+ /* correlator is only used by the OS, no need to byte swap */
u64 correlator;
};
diff --git a/drivers/net/ethernet/ibm/iseries_veth.c b/drivers/net/ethernet/ibm/iseries_veth.c
deleted file mode 100644
index 4326681df38..00000000000
--- a/drivers/net/ethernet/ibm/iseries_veth.c
+++ /dev/null
@@ -1,1710 +0,0 @@
-/* File veth.c created by Kyle A. Lucke on Mon Aug 7 2000. */
-/*
- * IBM eServer iSeries Virtual Ethernet Device Driver
- * Copyright (C) 2001 Kyle A. Lucke (klucke@us.ibm.com), IBM Corp.
- * Substantially cleaned up by:
- * Copyright (C) 2003 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
- * Copyright (C) 2004-2005 Michael Ellerman, IBM Corporation.
- *
- * 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 the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- *
- *
- * This module implements the virtual ethernet device for iSeries LPAR
- * Linux. It uses hypervisor message passing to implement an
- * ethernet-like network device communicating between partitions on
- * the iSeries.
- *
- * The iSeries LPAR hypervisor currently allows for up to 16 different
- * virtual ethernets. These are all dynamically configurable on
- * OS/400 partitions, but dynamic configuration is not supported under
- * Linux yet. An ethXX network device will be created for each
- * virtual ethernet this partition is connected to.
- *
- * - This driver is responsible for routing packets to and from other
- * partitions. The MAC addresses used by the virtual ethernets
- * contains meaning and must not be modified.
- *
- * - Having 2 virtual ethernets to the same remote partition DOES NOT
- * double the available bandwidth. The 2 devices will share the
- * available hypervisor bandwidth.
- *
- * - If you send a packet to your own mac address, it will just be
- * dropped, you won't get it on the receive side.
- *
- * - Multicast is implemented by sending the frame frame to every
- * other partition. It is the responsibility of the receiving
- * partition to filter the addresses desired.
- *
- * Tunable parameters:
- *
- * VETH_NUMBUFFERS: This compile time option defaults to 120. It
- * controls how much memory Linux will allocate per remote partition
- * it is communicating with. It can be thought of as the maximum
- * number of packets outstanding to a remote partition at a time.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/mm.h>
-#include <linux/ethtool.h>
-#include <linux/if_ether.h>
-#include <linux/slab.h>
-
-#include <asm/abs_addr.h>
-#include <asm/iseries/mf.h>
-#include <asm/uaccess.h>
-#include <asm/firmware.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iommu.h>
-#include <asm/vio.h>
-
-#undef DEBUG
-
-MODULE_AUTHOR("Kyle Lucke <klucke@us.ibm.com>");
-MODULE_DESCRIPTION("iSeries Virtual ethernet driver");
-MODULE_LICENSE("GPL");
-
-#define VETH_EVENT_CAP (0)
-#define VETH_EVENT_FRAMES (1)
-#define VETH_EVENT_MONITOR (2)
-#define VETH_EVENT_FRAMES_ACK (3)
-
-#define VETH_MAX_ACKS_PER_MSG (20)
-#define VETH_MAX_FRAMES_PER_MSG (6)
-
-struct veth_frames_data {
- u32 addr[VETH_MAX_FRAMES_PER_MSG];
- u16 len[VETH_MAX_FRAMES_PER_MSG];
- u32 eofmask;
-};
-#define VETH_EOF_SHIFT (32-VETH_MAX_FRAMES_PER_MSG)
-
-struct veth_frames_ack_data {
- u16 token[VETH_MAX_ACKS_PER_MSG];
-};
-
-struct veth_cap_data {
- u8 caps_version;
- u8 rsvd1;
- u16 num_buffers;
- u16 ack_threshold;
- u16 rsvd2;
- u32 ack_timeout;
- u32 rsvd3;
- u64 rsvd4[3];
-};
-
-struct veth_lpevent {
- struct HvLpEvent base_event;
- union {
- struct veth_cap_data caps_data;
- struct veth_frames_data frames_data;
- struct veth_frames_ack_data frames_ack_data;
- } u;
-
-};
-
-#define DRV_NAME "iseries_veth"
-#define DRV_VERSION "2.0"
-
-#define VETH_NUMBUFFERS (120)
-#define VETH_ACKTIMEOUT (1000000) /* microseconds */
-#define VETH_MAX_MCAST (12)
-
-#define VETH_MAX_MTU (9000)
-
-#if VETH_NUMBUFFERS < 10
-#define ACK_THRESHOLD (1)
-#elif VETH_NUMBUFFERS < 20
-#define ACK_THRESHOLD (4)
-#elif VETH_NUMBUFFERS < 40
-#define ACK_THRESHOLD (10)
-#else
-#define ACK_THRESHOLD (20)
-#endif
-
-#define VETH_STATE_SHUTDOWN (0x0001)
-#define VETH_STATE_OPEN (0x0002)
-#define VETH_STATE_RESET (0x0004)
-#define VETH_STATE_SENTMON (0x0008)
-#define VETH_STATE_SENTCAPS (0x0010)
-#define VETH_STATE_GOTCAPACK (0x0020)
-#define VETH_STATE_GOTCAPS (0x0040)
-#define VETH_STATE_SENTCAPACK (0x0080)
-#define VETH_STATE_READY (0x0100)
-
-struct veth_msg {
- struct veth_msg *next;
- struct veth_frames_data data;
- int token;
- int in_use;
- struct sk_buff *skb;
- struct device *dev;
-};
-
-struct veth_lpar_connection {
- HvLpIndex remote_lp;
- struct delayed_work statemachine_wq;
- struct veth_msg *msgs;
- int num_events;
- struct veth_cap_data local_caps;
-
- struct kobject kobject;
- struct timer_list ack_timer;
-
- struct timer_list reset_timer;
- unsigned int reset_timeout;
- unsigned long last_contact;
- int outstanding_tx;
-
- spinlock_t lock;
- unsigned long state;
- HvLpInstanceId src_inst;
- HvLpInstanceId dst_inst;
- struct veth_lpevent cap_event, cap_ack_event;
- u16 pending_acks[VETH_MAX_ACKS_PER_MSG];
- u32 num_pending_acks;
-
- int num_ack_events;
- struct veth_cap_data remote_caps;
- u32 ack_timeout;
-
- struct veth_msg *msg_stack_head;
-};
-
-struct veth_port {
- struct device *dev;
- u64 mac_addr;
- HvLpIndexMap lpar_map;
-
- /* queue_lock protects the stopped_map and dev's queue. */
- spinlock_t queue_lock;
- HvLpIndexMap stopped_map;
-
- /* mcast_gate protects promiscuous, num_mcast & mcast_addr. */
- rwlock_t mcast_gate;
- int promiscuous;
- int num_mcast;
- u64 mcast_addr[VETH_MAX_MCAST];
-
- struct kobject kobject;
-};
-
-static HvLpIndex this_lp;
-static struct veth_lpar_connection *veth_cnx[HVMAXARCHITECTEDLPS]; /* = 0 */
-static struct net_device *veth_dev[HVMAXARCHITECTEDVIRTUALLANS]; /* = 0 */
-
-static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void veth_recycle_msg(struct veth_lpar_connection *, struct veth_msg *);
-static void veth_wake_queues(struct veth_lpar_connection *cnx);
-static void veth_stop_queues(struct veth_lpar_connection *cnx);
-static void veth_receive(struct veth_lpar_connection *, struct veth_lpevent *);
-static void veth_release_connection(struct kobject *kobject);
-static void veth_timed_ack(unsigned long ptr);
-static void veth_timed_reset(unsigned long ptr);
-
-/*
- * Utility functions
- */
-
-#define veth_info(fmt, args...) \
- printk(KERN_INFO DRV_NAME ": " fmt, ## args)
-
-#define veth_error(fmt, args...) \
- printk(KERN_ERR DRV_NAME ": Error: " fmt, ## args)
-
-#ifdef DEBUG
-#define veth_debug(fmt, args...) \
- printk(KERN_DEBUG DRV_NAME ": " fmt, ## args)
-#else
-#define veth_debug(fmt, args...) do {} while (0)
-#endif
-
-/* You must hold the connection's lock when you call this function. */
-static inline void veth_stack_push(struct veth_lpar_connection *cnx,
- struct veth_msg *msg)
-{
- msg->next = cnx->msg_stack_head;
- cnx->msg_stack_head = msg;
-}
-
-/* You must hold the connection's lock when you call this function. */
-static inline struct veth_msg *veth_stack_pop(struct veth_lpar_connection *cnx)
-{
- struct veth_msg *msg;
-
- msg = cnx->msg_stack_head;
- if (msg)
- cnx->msg_stack_head = cnx->msg_stack_head->next;
-
- return msg;
-}
-
-/* You must hold the connection's lock when you call this function. */
-static inline int veth_stack_is_empty(struct veth_lpar_connection *cnx)
-{
- return cnx->msg_stack_head == NULL;
-}
-
-static inline HvLpEvent_Rc
-veth_signalevent(struct veth_lpar_connection *cnx, u16 subtype,
- HvLpEvent_AckInd ackind, HvLpEvent_AckType acktype,
- u64 token,
- u64 data1, u64 data2, u64 data3, u64 data4, u64 data5)
-{
- return HvCallEvent_signalLpEventFast(cnx->remote_lp,
- HvLpEvent_Type_VirtualLan,
- subtype, ackind, acktype,
- cnx->src_inst,
- cnx->dst_inst,
- token, data1, data2, data3,
- data4, data5);
-}
-
-static inline HvLpEvent_Rc veth_signaldata(struct veth_lpar_connection *cnx,
- u16 subtype, u64 token, void *data)
-{
- u64 *p = (u64 *) data;
-
- return veth_signalevent(cnx, subtype, HvLpEvent_AckInd_NoAck,
- HvLpEvent_AckType_ImmediateAck,
- token, p[0], p[1], p[2], p[3], p[4]);
-}
-
-struct veth_allocation {
- struct completion c;
- int num;
-};
-
-static void veth_complete_allocation(void *parm, int number)
-{
- struct veth_allocation *vc = (struct veth_allocation *)parm;
-
- vc->num = number;
- complete(&vc->c);
-}
-
-static int veth_allocate_events(HvLpIndex rlp, int number)
-{
- struct veth_allocation vc =
- { COMPLETION_INITIALIZER_ONSTACK(vc.c), 0 };
-
- mf_allocate_lp_events(rlp, HvLpEvent_Type_VirtualLan,
- sizeof(struct veth_lpevent), number,
- &veth_complete_allocation, &vc);
- wait_for_completion(&vc.c);
-
- return vc.num;
-}
-
-/*
- * sysfs support
- */
-
-struct veth_cnx_attribute {
- struct attribute attr;
- ssize_t (*show)(struct veth_lpar_connection *, char *buf);
- ssize_t (*store)(struct veth_lpar_connection *, const char *buf);
-};
-
-static ssize_t veth_cnx_attribute_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- struct veth_cnx_attribute *cnx_attr;
- struct veth_lpar_connection *cnx;
-
- cnx_attr = container_of(attr, struct veth_cnx_attribute, attr);
- cnx = container_of(kobj, struct veth_lpar_connection, kobject);
-
- if (!cnx_attr->show)
- return -EIO;
-
- return cnx_attr->show(cnx, buf);
-}
-
-#define CUSTOM_CNX_ATTR(_name, _format, _expression) \
-static ssize_t _name##_show(struct veth_lpar_connection *cnx, char *buf)\
-{ \
- return sprintf(buf, _format, _expression); \
-} \
-struct veth_cnx_attribute veth_cnx_attr_##_name = __ATTR_RO(_name)
-
-#define SIMPLE_CNX_ATTR(_name) \
- CUSTOM_CNX_ATTR(_name, "%lu\n", (unsigned long)cnx->_name)
-
-SIMPLE_CNX_ATTR(outstanding_tx);
-SIMPLE_CNX_ATTR(remote_lp);
-SIMPLE_CNX_ATTR(num_events);
-SIMPLE_CNX_ATTR(src_inst);
-SIMPLE_CNX_ATTR(dst_inst);
-SIMPLE_CNX_ATTR(num_pending_acks);
-SIMPLE_CNX_ATTR(num_ack_events);
-CUSTOM_CNX_ATTR(ack_timeout, "%d\n", jiffies_to_msecs(cnx->ack_timeout));
-CUSTOM_CNX_ATTR(reset_timeout, "%d\n", jiffies_to_msecs(cnx->reset_timeout));
-CUSTOM_CNX_ATTR(state, "0x%.4lX\n", cnx->state);
-CUSTOM_CNX_ATTR(last_contact, "%d\n", cnx->last_contact ?
- jiffies_to_msecs(jiffies - cnx->last_contact) : 0);
-
-#define GET_CNX_ATTR(_name) (&veth_cnx_attr_##_name.attr)
-
-static struct attribute *veth_cnx_default_attrs[] = {
- GET_CNX_ATTR(outstanding_tx),
- GET_CNX_ATTR(remote_lp),
- GET_CNX_ATTR(num_events),
- GET_CNX_ATTR(reset_timeout),
- GET_CNX_ATTR(last_contact),
- GET_CNX_ATTR(state),
- GET_CNX_ATTR(src_inst),
- GET_CNX_ATTR(dst_inst),
- GET_CNX_ATTR(num_pending_acks),
- GET_CNX_ATTR(num_ack_events),
- GET_CNX_ATTR(ack_timeout),
- NULL
-};
-
-static const struct sysfs_ops veth_cnx_sysfs_ops = {
- .show = veth_cnx_attribute_show
-};
-
-static struct kobj_type veth_lpar_connection_ktype = {
- .release = veth_release_connection,
- .sysfs_ops = &veth_cnx_sysfs_ops,
- .default_attrs = veth_cnx_default_attrs
-};
-
-struct veth_port_attribute {
- struct attribute attr;
- ssize_t (*show)(struct veth_port *, char *buf);
- ssize_t (*store)(struct veth_port *, const char *buf);
-};
-
-static ssize_t veth_port_attribute_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- struct veth_port_attribute *port_attr;
- struct veth_port *port;
-
- port_attr = container_of(attr, struct veth_port_attribute, attr);
- port = container_of(kobj, struct veth_port, kobject);
-
- if (!port_attr->show)
- return -EIO;
-
- return port_attr->show(port, buf);
-}
-
-#define CUSTOM_PORT_ATTR(_name, _format, _expression) \
-static ssize_t _name##_show(struct veth_port *port, char *buf) \
-{ \
- return sprintf(buf, _format, _expression); \
-} \
-struct veth_port_attribute veth_port_attr_##_name = __ATTR_RO(_name)
-
-#define SIMPLE_PORT_ATTR(_name) \
- CUSTOM_PORT_ATTR(_name, "%lu\n", (unsigned long)port->_name)
-
-SIMPLE_PORT_ATTR(promiscuous);
-SIMPLE_PORT_ATTR(num_mcast);
-CUSTOM_PORT_ATTR(lpar_map, "0x%X\n", port->lpar_map);
-CUSTOM_PORT_ATTR(stopped_map, "0x%X\n", port->stopped_map);
-CUSTOM_PORT_ATTR(mac_addr, "0x%llX\n", port->mac_addr);
-
-#define GET_PORT_ATTR(_name) (&veth_port_attr_##_name.attr)
-static struct attribute *veth_port_default_attrs[] = {
- GET_PORT_ATTR(mac_addr),
- GET_PORT_ATTR(lpar_map),
- GET_PORT_ATTR(stopped_map),
- GET_PORT_ATTR(promiscuous),
- GET_PORT_ATTR(num_mcast),
- NULL
-};
-
-static const struct sysfs_ops veth_port_sysfs_ops = {
- .show = veth_port_attribute_show
-};
-
-static struct kobj_type veth_port_ktype = {
- .sysfs_ops = &veth_port_sysfs_ops,
- .default_attrs = veth_port_default_attrs
-};
-
-/*
- * LPAR connection code
- */
-
-static inline void veth_kick_statemachine(struct veth_lpar_connection *cnx)
-{
- schedule_delayed_work(&cnx->statemachine_wq, 0);
-}
-
-static void veth_take_cap(struct veth_lpar_connection *cnx,
- struct veth_lpevent *event)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cnx->lock, flags);
- /* Receiving caps may mean the other end has just come up, so
- * we need to reload the instance ID of the far end */
- cnx->dst_inst =
- HvCallEvent_getTargetLpInstanceId(cnx->remote_lp,
- HvLpEvent_Type_VirtualLan);
-
- if (cnx->state & VETH_STATE_GOTCAPS) {
- veth_error("Received a second capabilities from LPAR %d.\n",
- cnx->remote_lp);
- event->base_event.xRc = HvLpEvent_Rc_BufferNotAvailable;
- HvCallEvent_ackLpEvent((struct HvLpEvent *) event);
- } else {
- memcpy(&cnx->cap_event, event, sizeof(cnx->cap_event));
- cnx->state |= VETH_STATE_GOTCAPS;
- veth_kick_statemachine(cnx);
- }
- spin_unlock_irqrestore(&cnx->lock, flags);
-}
-
-static void veth_take_cap_ack(struct veth_lpar_connection *cnx,
- struct veth_lpevent *event)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cnx->lock, flags);
- if (cnx->state & VETH_STATE_GOTCAPACK) {
- veth_error("Received a second capabilities ack from LPAR %d.\n",
- cnx->remote_lp);
- } else {
- memcpy(&cnx->cap_ack_event, event,
- sizeof(cnx->cap_ack_event));
- cnx->state |= VETH_STATE_GOTCAPACK;
- veth_kick_statemachine(cnx);
- }
- spin_unlock_irqrestore(&cnx->lock, flags);
-}
-
-static void veth_take_monitor_ack(struct veth_lpar_connection *cnx,
- struct veth_lpevent *event)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cnx->lock, flags);
- veth_debug("cnx %d: lost connection.\n", cnx->remote_lp);
-
- /* Avoid kicking the statemachine once we're shutdown.
- * It's unnecessary and it could break veth_stop_connection(). */
-
- if (! (cnx->state & VETH_STATE_SHUTDOWN)) {
- cnx->state |= VETH_STATE_RESET;
- veth_kick_statemachine(cnx);
- }
- spin_unlock_irqrestore(&cnx->lock, flags);
-}
-
-static void veth_handle_ack(struct veth_lpevent *event)
-{
- HvLpIndex rlp = event->base_event.xTargetLp;
- struct veth_lpar_connection *cnx = veth_cnx[rlp];
-
- BUG_ON(! cnx);
-
- switch (event->base_event.xSubtype) {
- case VETH_EVENT_CAP:
- veth_take_cap_ack(cnx, event);
- break;
- case VETH_EVENT_MONITOR:
- veth_take_monitor_ack(cnx, event);
- break;
- default:
- veth_error("Unknown ack type %d from LPAR %d.\n",
- event->base_event.xSubtype, rlp);
- }
-}
-
-static void veth_handle_int(struct veth_lpevent *event)
-{
- HvLpIndex rlp = event->base_event.xSourceLp;
- struct veth_lpar_connection *cnx = veth_cnx[rlp];
- unsigned long flags;
- int i, acked = 0;
-
- BUG_ON(! cnx);
-
- switch (event->base_event.xSubtype) {
- case VETH_EVENT_CAP:
- veth_take_cap(cnx, event);
- break;
- case VETH_EVENT_MONITOR:
- /* do nothing... this'll hang out here til we're dead,
- * and the hypervisor will return it for us. */
- break;
- case VETH_EVENT_FRAMES_ACK:
- spin_lock_irqsave(&cnx->lock, flags);
-
- for (i = 0; i < VETH_MAX_ACKS_PER_MSG; ++i) {
- u16 msgnum = event->u.frames_ack_data.token[i];
-
- if (msgnum < VETH_NUMBUFFERS) {
- veth_recycle_msg(cnx, cnx->msgs + msgnum);
- cnx->outstanding_tx--;
- acked++;
- }
- }
-
- if (acked > 0) {
- cnx->last_contact = jiffies;
- veth_wake_queues(cnx);
- }
-
- spin_unlock_irqrestore(&cnx->lock, flags);
- break;
- case VETH_EVENT_FRAMES:
- veth_receive(cnx, event);
- break;
- default:
- veth_error("Unknown interrupt type %d from LPAR %d.\n",
- event->base_event.xSubtype, rlp);
- }
-}
-
-static void veth_handle_event(struct HvLpEvent *event)
-{
- struct veth_lpevent *veth_event = (struct veth_lpevent *)event;
-
- if (hvlpevent_is_ack(event))
- veth_handle_ack(veth_event);
- else
- veth_handle_int(veth_event);
-}
-
-static int veth_process_caps(struct veth_lpar_connection *cnx)
-{
- struct veth_cap_data *remote_caps = &cnx->remote_caps;
- int num_acks_needed;
-
- /* Convert timer to jiffies */
- cnx->ack_timeout = remote_caps->ack_timeout * HZ / 1000000;
-
- if ( (remote_caps->num_buffers == 0) ||
- (remote_caps->ack_threshold > VETH_MAX_ACKS_PER_MSG) ||
- (remote_caps->ack_threshold == 0) ||
- (cnx->ack_timeout == 0) ) {
- veth_error("Received incompatible capabilities from LPAR %d.\n",
- cnx->remote_lp);
- return HvLpEvent_Rc_InvalidSubtypeData;
- }
-
- num_acks_needed = (remote_caps->num_buffers
- / remote_caps->ack_threshold) + 1;
-
- /* FIXME: locking on num_ack_events? */
- if (cnx->num_ack_events < num_acks_needed) {
- int num;
-
- num = veth_allocate_events(cnx->remote_lp,
- num_acks_needed-cnx->num_ack_events);
- if (num > 0)
- cnx->num_ack_events += num;
-
- if (cnx->num_ack_events < num_acks_needed) {
- veth_error("Couldn't allocate enough ack events "
- "for LPAR %d.\n", cnx->remote_lp);
-
- return HvLpEvent_Rc_BufferNotAvailable;
- }
- }
-
-
- return HvLpEvent_Rc_Good;
-}
-
-/* FIXME: The gotos here are a bit dubious */
-static void veth_statemachine(struct work_struct *work)
-{
- struct veth_lpar_connection *cnx =
- container_of(work, struct veth_lpar_connection,
- statemachine_wq.work);
- int rlp = cnx->remote_lp;
- int rc;
-
- spin_lock_irq(&cnx->lock);
-
- restart:
- if (cnx->state & VETH_STATE_RESET) {
- if (cnx->state & VETH_STATE_OPEN)
- HvCallEvent_closeLpEventPath(cnx->remote_lp,
- HvLpEvent_Type_VirtualLan);
-
- /*
- * Reset ack data. This prevents the ack_timer actually
- * doing anything, even if it runs one more time when
- * we drop the lock below.
- */
- memset(&cnx->pending_acks, 0xff, sizeof (cnx->pending_acks));
- cnx->num_pending_acks = 0;
-
- cnx->state &= ~(VETH_STATE_RESET | VETH_STATE_SENTMON
- | VETH_STATE_OPEN | VETH_STATE_SENTCAPS
- | VETH_STATE_GOTCAPACK | VETH_STATE_GOTCAPS
- | VETH_STATE_SENTCAPACK | VETH_STATE_READY);
-
- /* Clean up any leftover messages */
- if (cnx->msgs) {
- int i;
- for (i = 0; i < VETH_NUMBUFFERS; ++i)
- veth_recycle_msg(cnx, cnx->msgs + i);
- }
-
- cnx->outstanding_tx = 0;
- veth_wake_queues(cnx);
-
- /* Drop the lock so we can do stuff that might sleep or
- * take other locks. */
- spin_unlock_irq(&cnx->lock);
-
- del_timer_sync(&cnx->ack_timer);
- del_timer_sync(&cnx->reset_timer);
-
- spin_lock_irq(&cnx->lock);
-
- if (cnx->state & VETH_STATE_RESET)
- goto restart;
-
- /* Hack, wait for the other end to reset itself. */
- if (! (cnx->state & VETH_STATE_SHUTDOWN)) {
- schedule_delayed_work(&cnx->statemachine_wq, 5 * HZ);
- goto out;
- }
- }
-
- if (cnx->state & VETH_STATE_SHUTDOWN)
- /* It's all over, do nothing */
- goto out;
-
- if ( !(cnx->state & VETH_STATE_OPEN) ) {
- if (! cnx->msgs || (cnx->num_events < (2 + VETH_NUMBUFFERS)) )
- goto cant_cope;
-
- HvCallEvent_openLpEventPath(rlp, HvLpEvent_Type_VirtualLan);
- cnx->src_inst =
- HvCallEvent_getSourceLpInstanceId(rlp,
- HvLpEvent_Type_VirtualLan);
- cnx->dst_inst =
- HvCallEvent_getTargetLpInstanceId(rlp,
- HvLpEvent_Type_VirtualLan);
- cnx->state |= VETH_STATE_OPEN;
- }
-
- if ( (cnx->state & VETH_STATE_OPEN) &&
- !(cnx->state & VETH_STATE_SENTMON) ) {
- rc = veth_signalevent(cnx, VETH_EVENT_MONITOR,
- HvLpEvent_AckInd_DoAck,
- HvLpEvent_AckType_DeferredAck,
- 0, 0, 0, 0, 0, 0);
-
- if (rc == HvLpEvent_Rc_Good) {
- cnx->state |= VETH_STATE_SENTMON;
- } else {
- if ( (rc != HvLpEvent_Rc_PartitionDead) &&
- (rc != HvLpEvent_Rc_PathClosed) )
- veth_error("Error sending monitor to LPAR %d, "
- "rc = %d\n", rlp, rc);
-
- /* Oh well, hope we get a cap from the other
- * end and do better when that kicks us */
- goto out;
- }
- }
-
- if ( (cnx->state & VETH_STATE_OPEN) &&
- !(cnx->state & VETH_STATE_SENTCAPS)) {
- u64 *rawcap = (u64 *)&cnx->local_caps;
-
- rc = veth_signalevent(cnx, VETH_EVENT_CAP,
- HvLpEvent_AckInd_DoAck,
- HvLpEvent_AckType_ImmediateAck,
- 0, rawcap[0], rawcap[1], rawcap[2],
- rawcap[3], rawcap[4]);
-
- if (rc == HvLpEvent_Rc_Good) {
- cnx->state |= VETH_STATE_SENTCAPS;
- } else {
- if ( (rc != HvLpEvent_Rc_PartitionDead) &&
- (rc != HvLpEvent_Rc_PathClosed) )
- veth_error("Error sending caps to LPAR %d, "
- "rc = %d\n", rlp, rc);
-
- /* Oh well, hope we get a cap from the other
- * end and do better when that kicks us */
- goto out;
- }
- }
-
- if ((cnx->state & VETH_STATE_GOTCAPS) &&
- !(cnx->state & VETH_STATE_SENTCAPACK)) {
- struct veth_cap_data *remote_caps = &cnx->remote_caps;
-
- memcpy(remote_caps, &cnx->cap_event.u.caps_data,
- sizeof(*remote_caps));
-
- spin_unlock_irq(&cnx->lock);
- rc = veth_process_caps(cnx);
- spin_lock_irq(&cnx->lock);
-
- /* We dropped the lock, so recheck for anything which
- * might mess us up */
- if (cnx->state & (VETH_STATE_RESET|VETH_STATE_SHUTDOWN))
- goto restart;
-
- cnx->cap_event.base_event.xRc = rc;
- HvCallEvent_ackLpEvent((struct HvLpEvent *)&cnx->cap_event);
- if (rc == HvLpEvent_Rc_Good)
- cnx->state |= VETH_STATE_SENTCAPACK;
- else
- goto cant_cope;
- }
-
- if ((cnx->state & VETH_STATE_GOTCAPACK) &&
- (cnx->state & VETH_STATE_GOTCAPS) &&
- !(cnx->state & VETH_STATE_READY)) {
- if (cnx->cap_ack_event.base_event.xRc == HvLpEvent_Rc_Good) {
- /* Start the ACK timer */
- cnx->ack_timer.expires = jiffies + cnx->ack_timeout;
- add_timer(&cnx->ack_timer);
- cnx->state |= VETH_STATE_READY;
- } else {
- veth_error("Caps rejected by LPAR %d, rc = %d\n",
- rlp, cnx->cap_ack_event.base_event.xRc);
- goto cant_cope;
- }
- }
-
- out:
- spin_unlock_irq(&cnx->lock);
- return;
-
- cant_cope:
- /* FIXME: we get here if something happens we really can't
- * cope with. The link will never work once we get here, and
- * all we can do is not lock the rest of the system up */
- veth_error("Unrecoverable error on connection to LPAR %d, shutting down"
- " (state = 0x%04lx)\n", rlp, cnx->state);
- cnx->state |= VETH_STATE_SHUTDOWN;
- spin_unlock_irq(&cnx->lock);
-}
-
-static int veth_init_connection(u8 rlp)
-{
- struct veth_lpar_connection *cnx;
- struct veth_msg *msgs;
- int i;
-
- if ( (rlp == this_lp) ||
- ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) )
- return 0;
-
- cnx = kzalloc(sizeof(*cnx), GFP_KERNEL);
- if (! cnx)
- return -ENOMEM;
-
- cnx->remote_lp = rlp;
- spin_lock_init(&cnx->lock);
- INIT_DELAYED_WORK(&cnx->statemachine_wq, veth_statemachine);
-
- init_timer(&cnx->ack_timer);
- cnx->ack_timer.function = veth_timed_ack;
- cnx->ack_timer.data = (unsigned long) cnx;
-
- init_timer(&cnx->reset_timer);
- cnx->reset_timer.function = veth_timed_reset;
- cnx->reset_timer.data = (unsigned long) cnx;
- cnx->reset_timeout = 5 * HZ * (VETH_ACKTIMEOUT / 1000000);
-
- memset(&cnx->pending_acks, 0xff, sizeof (cnx->pending_acks));
-
- veth_cnx[rlp] = cnx;
-
- /* This gets us 1 reference, which is held on behalf of the driver
- * infrastructure. It's released at module unload. */
- kobject_init(&cnx->kobject, &veth_lpar_connection_ktype);
-
- msgs = kcalloc(VETH_NUMBUFFERS, sizeof(struct veth_msg), GFP_KERNEL);
- if (! msgs) {
- veth_error("Can't allocate buffers for LPAR %d.\n", rlp);
- return -ENOMEM;
- }
-
- cnx->msgs = msgs;
-
- for (i = 0; i < VETH_NUMBUFFERS; i++) {
- msgs[i].token = i;
- veth_stack_push(cnx, msgs + i);
- }
-
- cnx->num_events = veth_allocate_events(rlp, 2 + VETH_NUMBUFFERS);
-
- if (cnx->num_events < (2 + VETH_NUMBUFFERS)) {
- veth_error("Can't allocate enough events for LPAR %d.\n", rlp);
- return -ENOMEM;
- }
-
- cnx->local_caps.num_buffers = VETH_NUMBUFFERS;
- cnx->local_caps.ack_threshold = ACK_THRESHOLD;
- cnx->local_caps.ack_timeout = VETH_ACKTIMEOUT;
-
- return 0;
-}
-
-static void veth_stop_connection(struct veth_lpar_connection *cnx)
-{
- if (!cnx)
- return;
-
- spin_lock_irq(&cnx->lock);
- cnx->state |= VETH_STATE_RESET | VETH_STATE_SHUTDOWN;
- veth_kick_statemachine(cnx);
- spin_unlock_irq(&cnx->lock);
-
- /* ensure the statemachine runs now and waits for its completion */
- flush_delayed_work_sync(&cnx->statemachine_wq);
-}
-
-static void veth_destroy_connection(struct veth_lpar_connection *cnx)
-{
- if (!cnx)
- return;
-
- if (cnx->num_events > 0)
- mf_deallocate_lp_events(cnx->remote_lp,
- HvLpEvent_Type_VirtualLan,
- cnx->num_events,
- NULL, NULL);
- if (cnx->num_ack_events > 0)
- mf_deallocate_lp_events(cnx->remote_lp,
- HvLpEvent_Type_VirtualLan,
- cnx->num_ack_events,
- NULL, NULL);
-
- kfree(cnx->msgs);
- veth_cnx[cnx->remote_lp] = NULL;
- kfree(cnx);
-}
-
-static void veth_release_connection(struct kobject *kobj)
-{
- struct veth_lpar_connection *cnx;
- cnx = container_of(kobj, struct veth_lpar_connection, kobject);
- veth_stop_connection(cnx);
- veth_destroy_connection(cnx);
-}
-
-/*
- * net_device code
- */
-
-static int veth_open(struct net_device *dev)
-{
- netif_start_queue(dev);
- return 0;
-}
-
-static int veth_close(struct net_device *dev)
-{
- netif_stop_queue(dev);
- return 0;
-}
-
-static int veth_change_mtu(struct net_device *dev, int new_mtu)
-{
- if ((new_mtu < 68) || (new_mtu > VETH_MAX_MTU))
- return -EINVAL;
- dev->mtu = new_mtu;
- return 0;
-}
-
-static void veth_set_multicast_list(struct net_device *dev)
-{
- struct veth_port *port = netdev_priv(dev);
- unsigned long flags;
-
- write_lock_irqsave(&port->mcast_gate, flags);
-
- if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
- (netdev_mc_count(dev) > VETH_MAX_MCAST)) {
- port->promiscuous = 1;
- } else {
- struct netdev_hw_addr *ha;
-
- port->promiscuous = 0;
-
- /* Update table */
- port->num_mcast = 0;
-
- netdev_for_each_mc_addr(ha, dev) {
- u8 *addr = ha->addr;
- u64 xaddr = 0;
-
- memcpy(&xaddr, addr, ETH_ALEN);
- port->mcast_addr[port->num_mcast] = xaddr;
- port->num_mcast++;
- }
- }
-
- write_unlock_irqrestore(&port->mcast_gate, flags);
-}
-
-static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
- strncpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
- info->driver[sizeof(info->driver) - 1] = '\0';
- strncpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
- info->version[sizeof(info->version) - 1] = '\0';
-}
-
-static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
- ecmd->supported = (SUPPORTED_1000baseT_Full
- | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
- ecmd->advertising = (SUPPORTED_1000baseT_Full
- | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
- ecmd->port = PORT_FIBRE;
- ecmd->transceiver = XCVR_INTERNAL;
- ecmd->phy_address = 0;
- ecmd->speed = SPEED_1000;
- ecmd->duplex = DUPLEX_FULL;
- ecmd->autoneg = AUTONEG_ENABLE;
- ecmd->maxtxpkt = 120;
- ecmd->maxrxpkt = 120;
- return 0;
-}
-
-static const struct ethtool_ops ops = {
- .get_drvinfo = veth_get_drvinfo,
- .get_settings = veth_get_settings,
- .get_link = ethtool_op_get_link,
-};
-
-static const struct net_device_ops veth_netdev_ops = {
- .ndo_open = veth_open,
- .ndo_stop = veth_close,
- .ndo_start_xmit = veth_start_xmit,
- .ndo_change_mtu = veth_change_mtu,
- .ndo_set_rx_mode = veth_set_multicast_list,
- .ndo_set_mac_address = NULL,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static struct net_device *veth_probe_one(int vlan,
- struct vio_dev *vio_dev)
-{
- struct net_device *dev;
- struct veth_port *port;
- struct device *vdev = &vio_dev->dev;
- int i, rc;
- const unsigned char *mac_addr;
-
- mac_addr = vio_get_attribute(vio_dev, "local-mac-address", NULL);
- if (mac_addr == NULL)
- mac_addr = vio_get_attribute(vio_dev, "mac-address", NULL);
- if (mac_addr == NULL) {
- veth_error("Unable to fetch MAC address from device tree.\n");
- return NULL;
- }
-
- dev = alloc_etherdev(sizeof (struct veth_port));
- if (! dev) {
- veth_error("Unable to allocate net_device structure!\n");
- return NULL;
- }
-
- port = netdev_priv(dev);
-
- spin_lock_init(&port->queue_lock);
- rwlock_init(&port->mcast_gate);
- port->stopped_map = 0;
-
- for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
- HvLpVirtualLanIndexMap map;
-
- if (i == this_lp)
- continue;
- map = HvLpConfig_getVirtualLanIndexMapForLp(i);
- if (map & (0x8000 >> vlan))
- port->lpar_map |= (1 << i);
- }
- port->dev = vdev;
-
- memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
-
- dev->mtu = VETH_MAX_MTU;
-
- memcpy(&port->mac_addr, mac_addr, ETH_ALEN);
-
- dev->netdev_ops = &veth_netdev_ops;
- SET_ETHTOOL_OPS(dev, &ops);
-
- SET_NETDEV_DEV(dev, vdev);
-
- rc = register_netdev(dev);
- if (rc != 0) {
- veth_error("Failed registering net device for vlan%d.\n", vlan);
- free_netdev(dev);
- return NULL;
- }
-
- kobject_init(&port->kobject, &veth_port_ktype);
- if (0 != kobject_add(&port->kobject, &dev->dev.kobj, "veth_port"))
- veth_error("Failed adding port for %s to sysfs.\n", dev->name);
-
- veth_info("%s attached to iSeries vlan %d (LPAR map = 0x%.4X)\n",
- dev->name, vlan, port->lpar_map);
-
- return dev;
-}
-
-/*
- * Tx path
- */
-
-static int veth_transmit_to_one(struct sk_buff *skb, HvLpIndex rlp,
- struct net_device *dev)
-{
- struct veth_lpar_connection *cnx = veth_cnx[rlp];
- struct veth_port *port = netdev_priv(dev);
- HvLpEvent_Rc rc;
- struct veth_msg *msg = NULL;
- unsigned long flags;
-
- if (! cnx)
- return 0;
-
- spin_lock_irqsave(&cnx->lock, flags);
-
- if (! (cnx->state & VETH_STATE_READY))
- goto no_error;
-
- if ((skb->len - ETH_HLEN) > VETH_MAX_MTU)
- goto drop;
-
- msg = veth_stack_pop(cnx);
- if (! msg)
- goto drop;
-
- msg->in_use = 1;
- msg->skb = skb_get(skb);
-
- msg->data.addr[0] = dma_map_single(port->dev, skb->data,
- skb->len, DMA_TO_DEVICE);
-
- if (dma_mapping_error(port->dev, msg->data.addr[0]))
- goto recycle_and_drop;
-
- msg->dev = port->dev;
- msg->data.len[0] = skb->len;
- msg->data.eofmask = 1 << VETH_EOF_SHIFT;
-
- rc = veth_signaldata(cnx, VETH_EVENT_FRAMES, msg->token, &msg->data);
-
- if (rc != HvLpEvent_Rc_Good)
- goto recycle_and_drop;
-
- /* If the timer's not already running, start it now. */
- if (0 == cnx->outstanding_tx)
- mod_timer(&cnx->reset_timer, jiffies + cnx->reset_timeout);
-
- cnx->last_contact = jiffies;
- cnx->outstanding_tx++;
-
- if (veth_stack_is_empty(cnx))
- veth_stop_queues(cnx);
-
- no_error:
- spin_unlock_irqrestore(&cnx->lock, flags);
- return 0;
-
- recycle_and_drop:
- veth_recycle_msg(cnx, msg);
- drop:
- spin_unlock_irqrestore(&cnx->lock, flags);
- return 1;
-}
-
-static void veth_transmit_to_many(struct sk_buff *skb,
- HvLpIndexMap lpmask,
- struct net_device *dev)
-{
- int i, success, error;
-
- success = error = 0;
-
- for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
- if ((lpmask & (1 << i)) == 0)
- continue;
-
- if (veth_transmit_to_one(skb, i, dev))
- error = 1;
- else
- success = 1;
- }
-
- if (error)
- dev->stats.tx_errors++;
-
- if (success) {
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
- }
-}
-
-static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- unsigned char *frame = skb->data;
- struct veth_port *port = netdev_priv(dev);
- HvLpIndexMap lpmask;
-
- if (is_unicast_ether_addr(frame)) {
- /* unicast packet */
- HvLpIndex rlp = frame[5];
-
- if ( ! ((1 << rlp) & port->lpar_map) ) {
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- lpmask = 1 << rlp;
- } else {
- lpmask = port->lpar_map;
- }
-
- veth_transmit_to_many(skb, lpmask, dev);
-
- dev_kfree_skb(skb);
-
- return NETDEV_TX_OK;
-}
-
-/* You must hold the connection's lock when you call this function. */
-static void veth_recycle_msg(struct veth_lpar_connection *cnx,
- struct veth_msg *msg)
-{
- u32 dma_address, dma_length;
-
- if (msg->in_use) {
- msg->in_use = 0;
- dma_address = msg->data.addr[0];
- dma_length = msg->data.len[0];
-
- if (!dma_mapping_error(msg->dev, dma_address))
- dma_unmap_single(msg->dev, dma_address, dma_length,
- DMA_TO_DEVICE);
-
- if (msg->skb) {
- dev_kfree_skb_any(msg->skb);
- msg->skb = NULL;
- }
-
- memset(&msg->data, 0, sizeof(msg->data));
- veth_stack_push(cnx, msg);
- } else if (cnx->state & VETH_STATE_OPEN) {
- veth_error("Non-pending frame (# %d) acked by LPAR %d.\n",
- cnx->remote_lp, msg->token);
- }
-}
-
-static void veth_wake_queues(struct veth_lpar_connection *cnx)
-{
- int i;
-
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
- struct net_device *dev = veth_dev[i];
- struct veth_port *port;
- unsigned long flags;
-
- if (! dev)
- continue;
-
- port = netdev_priv(dev);
-
- if (! (port->lpar_map & (1<<cnx->remote_lp)))
- continue;
-
- spin_lock_irqsave(&port->queue_lock, flags);
-
- port->stopped_map &= ~(1 << cnx->remote_lp);
-
- if (0 == port->stopped_map && netif_queue_stopped(dev)) {
- veth_debug("cnx %d: woke queue for %s.\n",
- cnx->remote_lp, dev->name);
- netif_wake_queue(dev);
- }
- spin_unlock_irqrestore(&port->queue_lock, flags);
- }
-}
-
-static void veth_stop_queues(struct veth_lpar_connection *cnx)
-{
- int i;
-
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
- struct net_device *dev = veth_dev[i];
- struct veth_port *port;
-
- if (! dev)
- continue;
-
- port = netdev_priv(dev);
-
- /* If this cnx is not on the vlan for this port, continue */
- if (! (port->lpar_map & (1 << cnx->remote_lp)))
- continue;
-
- spin_lock(&port->queue_lock);
-
- netif_stop_queue(dev);
- port->stopped_map |= (1 << cnx->remote_lp);
-
- veth_debug("cnx %d: stopped queue for %s, map = 0x%x.\n",
- cnx->remote_lp, dev->name, port->stopped_map);
-
- spin_unlock(&port->queue_lock);
- }
-}
-
-static void veth_timed_reset(unsigned long ptr)
-{
- struct veth_lpar_connection *cnx = (struct veth_lpar_connection *)ptr;
- unsigned long trigger_time, flags;
-
- /* FIXME is it possible this fires after veth_stop_connection()?
- * That would reschedule the statemachine for 5 seconds and probably
- * execute it after the module's been unloaded. Hmm. */
-
- spin_lock_irqsave(&cnx->lock, flags);
-
- if (cnx->outstanding_tx > 0) {
- trigger_time = cnx->last_contact + cnx->reset_timeout;
-
- if (trigger_time < jiffies) {
- cnx->state |= VETH_STATE_RESET;
- veth_kick_statemachine(cnx);
- veth_error("%d packets not acked by LPAR %d within %d "
- "seconds, resetting.\n",
- cnx->outstanding_tx, cnx->remote_lp,
- cnx->reset_timeout / HZ);
- } else {
- /* Reschedule the timer */
- trigger_time = jiffies + cnx->reset_timeout;
- mod_timer(&cnx->reset_timer, trigger_time);
- }
- }
-
- spin_unlock_irqrestore(&cnx->lock, flags);
-}
-
-/*
- * Rx path
- */
-
-static inline int veth_frame_wanted(struct veth_port *port, u64 mac_addr)
-{
- int wanted = 0;
- int i;
- unsigned long flags;
-
- if ( (mac_addr == port->mac_addr) || (mac_addr == 0xffffffffffff0000) )
- return 1;
-
- read_lock_irqsave(&port->mcast_gate, flags);
-
- if (port->promiscuous) {
- wanted = 1;
- goto out;
- }
-
- for (i = 0; i < port->num_mcast; ++i) {
- if (port->mcast_addr[i] == mac_addr) {
- wanted = 1;
- break;
- }
- }
-
- out:
- read_unlock_irqrestore(&port->mcast_gate, flags);
-
- return wanted;
-}
-
-struct dma_chunk {
- u64 addr;
- u64 size;
-};
-
-#define VETH_MAX_PAGES_PER_FRAME ( (VETH_MAX_MTU+PAGE_SIZE-2)/PAGE_SIZE + 1 )
-
-static inline void veth_build_dma_list(struct dma_chunk *list,
- unsigned char *p, unsigned long length)
-{
- unsigned long done;
- int i = 1;
-
- /* FIXME: skbs are contiguous in real addresses. Do we
- * really need to break it into PAGE_SIZE chunks, or can we do
- * it just at the granularity of iSeries real->absolute
- * mapping? Indeed, given the way the allocator works, can we
- * count on them being absolutely contiguous? */
- list[0].addr = iseries_hv_addr(p);
- list[0].size = min(length,
- PAGE_SIZE - ((unsigned long)p & ~PAGE_MASK));
-
- done = list[0].size;
- while (done < length) {
- list[i].addr = iseries_hv_addr(p + done);
- list[i].size = min(length-done, PAGE_SIZE);
- done += list[i].size;
- i++;
- }
-}
-
-static void veth_flush_acks(struct veth_lpar_connection *cnx)
-{
- HvLpEvent_Rc rc;
-
- rc = veth_signaldata(cnx, VETH_EVENT_FRAMES_ACK,
- 0, &cnx->pending_acks);
-
- if (rc != HvLpEvent_Rc_Good)
- veth_error("Failed acking frames from LPAR %d, rc = %d\n",
- cnx->remote_lp, (int)rc);
-
- cnx->num_pending_acks = 0;
- memset(&cnx->pending_acks, 0xff, sizeof(cnx->pending_acks));
-}
-
-static void veth_receive(struct veth_lpar_connection *cnx,
- struct veth_lpevent *event)
-{
- struct veth_frames_data *senddata = &event->u.frames_data;
- int startchunk = 0;
- int nchunks;
- unsigned long flags;
- HvLpDma_Rc rc;
-
- do {
- u16 length = 0;
- struct sk_buff *skb;
- struct dma_chunk local_list[VETH_MAX_PAGES_PER_FRAME];
- struct dma_chunk remote_list[VETH_MAX_FRAMES_PER_MSG];
- u64 dest;
- HvLpVirtualLanIndex vlan;
- struct net_device *dev;
- struct veth_port *port;
-
- /* FIXME: do we need this? */
- memset(local_list, 0, sizeof(local_list));
- memset(remote_list, 0, sizeof(VETH_MAX_FRAMES_PER_MSG));
-
- /* a 0 address marks the end of the valid entries */
- if (senddata->addr[startchunk] == 0)
- break;
-
- /* make sure that we have at least 1 EOF entry in the
- * remaining entries */
- if (! (senddata->eofmask >> (startchunk + VETH_EOF_SHIFT))) {
- veth_error("Missing EOF fragment in event "
- "eofmask = 0x%x startchunk = %d\n",
- (unsigned)senddata->eofmask,
- startchunk);
- break;
- }
-
- /* build list of chunks in this frame */
- nchunks = 0;
- do {
- remote_list[nchunks].addr =
- (u64) senddata->addr[startchunk+nchunks] << 32;
- remote_list[nchunks].size =
- senddata->len[startchunk+nchunks];
- length += remote_list[nchunks].size;
- } while (! (senddata->eofmask &
- (1 << (VETH_EOF_SHIFT + startchunk + nchunks++))));
-
- /* length == total length of all chunks */
- /* nchunks == # of chunks in this frame */
-
- if ((length - ETH_HLEN) > VETH_MAX_MTU) {
- veth_error("Received oversize frame from LPAR %d "
- "(length = %d)\n",
- cnx->remote_lp, length);
- continue;
- }
-
- skb = alloc_skb(length, GFP_ATOMIC);
- if (!skb)
- continue;
-
- veth_build_dma_list(local_list, skb->data, length);
-
- rc = HvCallEvent_dmaBufList(HvLpEvent_Type_VirtualLan,
- event->base_event.xSourceLp,
- HvLpDma_Direction_RemoteToLocal,
- cnx->src_inst,
- cnx->dst_inst,
- HvLpDma_AddressType_RealAddress,
- HvLpDma_AddressType_TceIndex,
- iseries_hv_addr(&local_list),
- iseries_hv_addr(&remote_list),
- length);
- if (rc != HvLpDma_Rc_Good) {
- dev_kfree_skb_irq(skb);
- continue;
- }
-
- vlan = skb->data[9];
- dev = veth_dev[vlan];
- if (! dev) {
- /*
- * Some earlier versions of the driver sent
- * broadcasts down all connections, even to lpars
- * that weren't on the relevant vlan. So ignore
- * packets belonging to a vlan we're not on.
- * We can also be here if we receive packets while
- * the driver is going down, because then dev is NULL.
- */
- dev_kfree_skb_irq(skb);
- continue;
- }
-
- port = netdev_priv(dev);
- dest = *((u64 *) skb->data) & 0xFFFFFFFFFFFF0000;
-
- if ((vlan > HVMAXARCHITECTEDVIRTUALLANS) || !port) {
- dev_kfree_skb_irq(skb);
- continue;
- }
- if (! veth_frame_wanted(port, dest)) {
- dev_kfree_skb_irq(skb);
- continue;
- }
-
- skb_put(skb, length);
- skb->protocol = eth_type_trans(skb, dev);
- skb_checksum_none_assert(skb);
- netif_rx(skb); /* send it up */
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += length;
- } while (startchunk += nchunks, startchunk < VETH_MAX_FRAMES_PER_MSG);
-
- /* Ack it */
- spin_lock_irqsave(&cnx->lock, flags);
- BUG_ON(cnx->num_pending_acks > VETH_MAX_ACKS_PER_MSG);
-
- cnx->pending_acks[cnx->num_pending_acks++] =
- event->base_event.xCorrelationToken;
-
- if ( (cnx->num_pending_acks >= cnx->remote_caps.ack_threshold) ||
- (cnx->num_pending_acks >= VETH_MAX_ACKS_PER_MSG) )
- veth_flush_acks(cnx);
-
- spin_unlock_irqrestore(&cnx->lock, flags);
-}
-
-static void veth_timed_ack(unsigned long ptr)
-{
- struct veth_lpar_connection *cnx = (struct veth_lpar_connection *) ptr;
- unsigned long flags;
-
- /* Ack all the events */
- spin_lock_irqsave(&cnx->lock, flags);
- if (cnx->num_pending_acks > 0)
- veth_flush_acks(cnx);
-
- /* Reschedule the timer */
- cnx->ack_timer.expires = jiffies + cnx->ack_timeout;
- add_timer(&cnx->ack_timer);
- spin_unlock_irqrestore(&cnx->lock, flags);
-}
-
-static int veth_remove(struct vio_dev *vdev)
-{
- struct veth_lpar_connection *cnx;
- struct net_device *dev;
- struct veth_port *port;
- int i;
-
- dev = veth_dev[vdev->unit_address];
-
- if (! dev)
- return 0;
-
- port = netdev_priv(dev);
-
- for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
- cnx = veth_cnx[i];
-
- if (cnx && (port->lpar_map & (1 << i))) {
- /* Drop our reference to connections on our VLAN */
- kobject_put(&cnx->kobject);
- }
- }
-
- veth_dev[vdev->unit_address] = NULL;
- kobject_del(&port->kobject);
- kobject_put(&port->kobject);
- unregister_netdev(dev);
- free_netdev(dev);
-
- return 0;
-}
-
-static int veth_probe(struct vio_dev *vdev, const struct vio_device_id *id)
-{
- int i = vdev->unit_address;
- struct net_device *dev;
- struct veth_port *port;
-
- dev = veth_probe_one(i, vdev);
- if (dev == NULL) {
- veth_remove(vdev);
- return 1;
- }
- veth_dev[i] = dev;
-
- port = netdev_priv(dev);
-
- /* Start the state machine on each connection on this vlan. If we're
- * the first dev to do so this will commence link negotiation */
- for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
- struct veth_lpar_connection *cnx;
-
- if (! (port->lpar_map & (1 << i)))
- continue;
-
- cnx = veth_cnx[i];
- if (!cnx)
- continue;
-
- kobject_get(&cnx->kobject);
- veth_kick_statemachine(cnx);
- }
-
- return 0;
-}
-
-/**
- * veth_device_table: Used by vio.c to match devices that we
- * support.
- */
-static struct vio_device_id veth_device_table[] __devinitdata = {
- { "network", "IBM,iSeries-l-lan" },
- { "", "" }
-};
-MODULE_DEVICE_TABLE(vio, veth_device_table);
-
-static struct vio_driver veth_driver = {
- .id_table = veth_device_table,
- .probe = veth_probe,
- .remove = veth_remove,
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
- }
-};
-
-/*
- * Module initialization/cleanup
- */
-
-static void __exit veth_module_cleanup(void)
-{
- int i;
- struct veth_lpar_connection *cnx;
-
- /* Disconnect our "irq" to stop events coming from the Hypervisor. */
- HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan);
-
- for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
- cnx = veth_cnx[i];
-
- if (!cnx)
- continue;
-
- /* Cancel work queued from Hypervisor callbacks */
- cancel_delayed_work_sync(&cnx->statemachine_wq);
- /* Remove the connection from sysfs */
- kobject_del(&cnx->kobject);
- /* Drop the driver's reference to the connection */
- kobject_put(&cnx->kobject);
- }
-
- /* Unregister the driver, which will close all the netdevs and stop
- * the connections when they're no longer referenced. */
- vio_unregister_driver(&veth_driver);
-}
-module_exit(veth_module_cleanup);
-
-static int __init veth_module_init(void)
-{
- int i;
- int rc;
-
- if (!firmware_has_feature(FW_FEATURE_ISERIES))
- return -ENODEV;
-
- this_lp = HvLpConfig_getLpIndex_outline();
-
- for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
- rc = veth_init_connection(i);
- if (rc != 0)
- goto error;
- }
-
- HvLpEvent_registerHandler(HvLpEvent_Type_VirtualLan,
- &veth_handle_event);
-
- rc = vio_register_driver(&veth_driver);
- if (rc != 0)
- goto error;
-
- for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
- struct kobject *kobj;
-
- if (!veth_cnx[i])
- continue;
-
- kobj = &veth_cnx[i]->kobject;
- /* If the add failes, complain but otherwise continue */
- if (0 != driver_add_kobj(&veth_driver.driver, kobj,
- "cnx%.2d", veth_cnx[i]->remote_lp))
- veth_error("cnx %d: Failed adding to sysfs.\n", i);
- }
-
- return 0;
-
-error:
- for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
- veth_destroy_connection(veth_cnx[i]);
- }
-
- return rc;
-}
-module_init(veth_module_init);