From d2db9eea7901d83e494340c93d131fc1fd463e4c Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Fri, 9 Feb 2007 09:10:51 +0100 Subject: ehea: Fixed error recovery Error recovery for QP errors: Reset QPs and dump error information Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea_main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net/ehea/ehea_main.c') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 9de2d38a5321..1ef3846a5ea0 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -76,7 +76,7 @@ void ehea_dump(void *adr, int len, char *msg) { int x; unsigned char *deb = adr; for (x = 0; x < len; x += 16) { - printk(DRV_NAME "%s adr=%p ofs=%04x %016lx %016lx\n", msg, + printk(DRV_NAME " %s adr=%p ofs=%04x %016lx %016lx\n", msg, deb, x, *((u64*)&deb[0]), *((u64*)&deb[8])); deb += 16; } @@ -555,6 +555,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) { struct ehea_port *port = param; struct ehea_eqe *eqe; + struct ehea_qp *qp; u32 qp_token; eqe = ehea_poll_eq(port->qp_eq); @@ -563,9 +564,14 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry); ehea_error("QP aff_err: entry=0x%lx, token=0x%x", eqe->entry, qp_token); + + qp = port->port_res[qp_token].qp; + ehea_error_data(port->adapter, qp->fw_handle); eqe = ehea_poll_eq(port->qp_eq); } + queue_work(port->adapter->ehea_wq, &port->reset_task); + return IRQ_HANDLED; } -- cgit v1.2.1 From 5c15bdec5c38f4ccf73ef2585fc80a6164de9554 Mon Sep 17 00:00:00 2001 From: Dan Aloni Date: Fri, 2 Mar 2007 20:44:51 -0800 Subject: [VLAN]: Avoid a 4-order allocation. This patch splits the vlan_group struct into a multi-allocated struct. On x86_64, the size of the original struct is a little more than 32KB, causing a 4-order allocation, which is prune to problems caused by buddy-system external fragmentation conditions. I couldn't just use vmalloc() because vfree() cannot be called in the softirq context of the RCU callback. Signed-off-by: Dan Aloni Acked-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/ehea/ehea_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/ehea/ehea_main.c') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 88ad1c8bcee4..0e4042bc0a48 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -1939,8 +1939,7 @@ static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) int index; u64 hret; - if (port->vgrp) - port->vgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(port->vgrp, vid, NULL); cb1 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb1) { -- cgit v1.2.1 From c9bdd4b5257406b0608385d19c40b5511decf4f6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 12 Mar 2007 20:09:15 -0300 Subject: [IP]: Introduce ip_hdrlen() For the common sequence "skb->nh.iph->ihl * 4", removing a good number of open coded skb->nh.iph uses, now to go after the rest... Just out of curiosity, here are the idioms found to get the same result: skb->nh.iph->ihl << 2 skb->nh.iph->ihl<<2 skb->nh.iph->ihl * 4 skb->nh.iph->ihl*4 (skb->nh.iph)->ihl * sizeof(u32) Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- drivers/net/ehea/ehea_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/ehea/ehea_main.c') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 0e4042bc0a48..b1c90a4fe31e 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -1263,7 +1263,7 @@ static inline void write_ip_start_end(struct ehea_swqe *swqe, const struct sk_buff *skb) { swqe->ip_start = (u8)(((u64)skb->nh.iph) - ((u64)skb->data)); - swqe->ip_end = (u8)(swqe->ip_start + skb->nh.iph->ihl * 4 - 1); + swqe->ip_end = (u8)(swqe->ip_start + ip_hdrlen(skb) - 1); } static inline void write_tcp_offset_end(struct ehea_swqe *swqe, @@ -1300,7 +1300,7 @@ static void write_swqe2_TSO(struct sk_buff *skb, /* copy only eth/ip/tcp headers to immediate data and * the rest of skb->data to sg1entry */ - headersize = ETH_HLEN + (skb->nh.iph->ihl * 4) + (skb->h.th->doff * 4); + headersize = ETH_HLEN + ip_hdrlen(skb) + (skb->h.th->doff * 4); skb_data_size = skb->len - skb->data_len; -- cgit v1.2.1 From eddc9ec53be2ecdbf4efe0efd4a83052594f0ac0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 20 Apr 2007 22:47:35 -0700 Subject: [SK_BUFF]: Introduce ip_hdr(), remove skb->nh.iph Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- drivers/net/ehea/ehea_main.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/net/ehea/ehea_main.c') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index b1c90a4fe31e..0dc701e611e5 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -1262,7 +1262,7 @@ static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr) static inline void write_ip_start_end(struct ehea_swqe *swqe, const struct sk_buff *skb) { - swqe->ip_start = (u8)(((u64)skb->nh.iph) - ((u64)skb->data)); + swqe->ip_start = skb_network_offset(skb); swqe->ip_end = (u8)(swqe->ip_start + ip_hdrlen(skb) - 1); } @@ -1688,6 +1688,7 @@ static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev, struct ehea_swqe *swqe, u32 lkey) { if (skb->protocol == htons(ETH_P_IP)) { + const struct iphdr *iph = ip_hdr(skb); /* IPv4 */ swqe->tx_control |= EHEA_SWQE_CRC | EHEA_SWQE_IP_CHECKSUM @@ -1697,15 +1698,15 @@ static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev, write_ip_start_end(swqe, skb); - if (skb->nh.iph->protocol == IPPROTO_UDP) { - if ((skb->nh.iph->frag_off & IP_MF) || - (skb->nh.iph->frag_off & IP_OFFSET)) + 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 (skb->nh.iph->protocol == IPPROTO_TCP) { + } else if (iph->protocol == IPPROTO_TCP) { write_tcp_offset_end(swqe, skb); } @@ -1731,10 +1732,11 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev, int i; if (skb->protocol == htons(ETH_P_IP)) { + const struct iphdr *iph = ip_hdr(skb); /* IPv4 */ write_ip_start_end(swqe, skb); - if (skb->nh.iph->protocol == IPPROTO_TCP) { + if (iph->protocol == IPPROTO_TCP) { swqe->tx_control |= EHEA_SWQE_CRC | EHEA_SWQE_IP_CHECKSUM | EHEA_SWQE_TCP_CHECKSUM @@ -1742,9 +1744,9 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev, write_tcp_offset_end(swqe, skb); - } else if (skb->nh.iph->protocol == IPPROTO_UDP) { - if ((skb->nh.iph->frag_off & IP_MF) || - (skb->nh.iph->frag_off & IP_OFFSET)) + } 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; -- cgit v1.2.1 From ab6a5bb6b28a970104a34f0f6959b73cf61bdc72 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 18 Mar 2007 17:43:48 -0700 Subject: [TCP]: Introduce tcp_hdrlen() and tcp_optlen() The ip_hdrlen() buddy, created to reduce the number of skb->h.th-> uses and to avoid the longer, open coded equivalent. Ditched a no-op in bnx2 in the process. I wonder if we should have a BUG_ON(skb->h.th->doff < 5) in tcp_optlen()... Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- drivers/net/ehea/ehea_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/ehea/ehea_main.c') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 0dc701e611e5..63732d2305bb 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -1300,7 +1300,7 @@ static void write_swqe2_TSO(struct sk_buff *skb, /* copy only eth/ip/tcp headers to immediate data and * the rest of skb->data to sg1entry */ - headersize = ETH_HLEN + ip_hdrlen(skb) + (skb->h.th->doff * 4); + headersize = ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb); skb_data_size = skb->len - skb->data_len; -- cgit v1.2.1 From d626f62b11e00c16e81e4308ab93d3f13551812a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 27 Mar 2007 18:55:52 -0300 Subject: [SK_BUFF]: Introduce skb_copy_from_linear_data{_offset} To clearly state the intent of copying from linear sk_buffs, _offset being a overly long variant but interesting for the sake of saving some bytes. Signed-off-by: Arnaldo Carvalho de Melo --- drivers/net/ehea/ehea_main.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net/ehea/ehea_main.c') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 63732d2305bb..8b5392072632 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -1306,7 +1306,7 @@ static void write_swqe2_TSO(struct sk_buff *skb, if (skb_data_size >= headersize) { /* copy immediate data */ - memcpy(imm_data, skb->data, headersize); + skb_copy_from_linear_data(skb, imm_data, headersize); swqe->immediate_data_length = headersize; if (skb_data_size > headersize) { @@ -1337,7 +1337,7 @@ static void write_swqe2_nonTSO(struct sk_buff *skb, */ if (skb_data_size >= SWQE2_MAX_IMM) { /* copy immediate data */ - memcpy(imm_data, skb->data, SWQE2_MAX_IMM); + skb_copy_from_linear_data(skb, imm_data, SWQE2_MAX_IMM); swqe->immediate_data_length = SWQE2_MAX_IMM; @@ -1350,7 +1350,7 @@ static void write_swqe2_nonTSO(struct sk_buff *skb, swqe->descriptors++; } } else { - memcpy(imm_data, skb->data, skb_data_size); + skb_copy_from_linear_data(skb, imm_data, skb_data_size); swqe->immediate_data_length = skb_data_size; } } @@ -1772,10 +1772,11 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev, /* copy (immediate) data */ if (nfrags == 0) { /* data is in a single piece */ - memcpy(imm_data, skb->data, skb->len); + skb_copy_from_linear_data(skb, imm_data, skb->len); } else { /* first copy data from the skb->data buffer ... */ - memcpy(imm_data, skb->data, skb->len - skb->data_len); + skb_copy_from_linear_data(skb, imm_data, + skb->len - skb->data_len); imm_data += skb->len - skb->data_len; /* ... then copy data from the fragments */ -- cgit v1.2.1 From 27d7ff46a3498d3debc6ba68fb8014c702b81170 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 31 Mar 2007 11:55:19 -0300 Subject: [SK_BUFF]: Introduce skb_copy_to_linear_data{_offset} To clearly state the intent of copying to linear sk_buffs, _offset being a overly long variant but interesting for the sake of saving some bytes. Signed-off-by: Arnaldo Carvalho de Melo --- drivers/net/ehea/ehea_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/ehea/ehea_main.c') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 8b5392072632..58364a0ff378 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -391,8 +391,8 @@ static int ehea_poll(struct net_device *dev, int *budget) if (!skb) break; } - memcpy(skb->data, ((char*)cqe) + 64, - cqe->num_bytes_transfered - 4); + skb_copy_to_linear_data(skb, ((char*)cqe) + 64, + cqe->num_bytes_transfered - 4); ehea_fill_skb(dev, skb, cqe); } else if (rq == 2) { /* RQ2 */ skb = get_skb_by_index(skb_arr_rq2, -- cgit v1.2.1 From 1acf2318dd136edfbfa30f1f33b43f69f2e2ec6c Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Wed, 28 Feb 2007 18:34:02 +0100 Subject: ehea: dynamic add / remove port This patch introduces functionality to dynamically add / remove ehea ports via an userspace DLPAR tool. It creates a subnode for each logical port in the sysfs. Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea_main.c | 439 +++++++++++++++++++++++++++++++------------ 1 file changed, 318 insertions(+), 121 deletions(-) (limited to 'drivers/net/ehea/ehea_main.c') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 58364a0ff378..3527b391214d 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -580,7 +580,7 @@ static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter, { int i; - for (i = 0; i < adapter->num_ports; i++) + for (i = 0; i < EHEA_MAX_PORTS; i++) if (adapter->port[i]) if (adapter->port[i]->logical_port_id == logical_port) return adapter->port[i]; @@ -2276,8 +2276,6 @@ static void ehea_tx_watchdog(struct net_device *dev) int ehea_sense_adapter_attr(struct ehea_adapter *adapter) { struct hcp_query_ehea *cb; - struct device_node *lhea_dn = NULL; - struct device_node *eth_dn = NULL; u64 hret; int ret; @@ -2294,18 +2292,6 @@ int ehea_sense_adapter_attr(struct ehea_adapter *adapter) goto out_herr; } - /* Determine the number of available logical ports - * by counting the child nodes of the lhea OFDT entry - */ - adapter->num_ports = 0; - lhea_dn = of_find_node_by_name(lhea_dn, "lhea"); - do { - eth_dn = of_get_next_child(lhea_dn, eth_dn); - if (eth_dn) - adapter->num_ports++; - } while ( eth_dn ); - of_node_put(lhea_dn); - adapter->max_mc_mac = cb->max_mc_mac - 1; ret = 0; @@ -2315,79 +2301,150 @@ out: return ret; } -static int ehea_setup_single_port(struct ehea_port *port, - struct device_node *dn) +int ehea_get_jumboframe_status(struct ehea_port *port, int *jumbo) { - int ret; - u64 hret; - struct net_device *dev = port->netdev; - struct ehea_adapter *adapter = port->adapter; struct hcp_ehea_port_cb4 *cb4; - u32 *dn_log_port_id; - int jumbo = 0; - - sema_init(&port->port_lock, 1); - port->state = EHEA_PORT_DOWN; - port->sig_comp_iv = sq_entries / 10; - - if (!dn) { - ehea_error("bad device node: dn=%p", dn); - ret = -EINVAL; - goto out; - } - - port->of_dev_node = dn; - - /* Determine logical port id */ - dn_log_port_id = (u32*)get_property(dn, "ibm,hea-port-no", NULL); - - if (!dn_log_port_id) { - ehea_error("bad device node: dn_log_port_id=%p", - dn_log_port_id); - ret = -EINVAL; - goto out; - } - port->logical_port_id = *dn_log_port_id; - - port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL); - if (!port->mc_list) { - ret = -ENOMEM; - goto out; - } - - INIT_LIST_HEAD(&port->mc_list->list); + u64 hret; + int ret = 0; - ret = ehea_sense_port_attr(port); - if (ret) - goto out; + *jumbo = 0; - /* Enable Jumbo frames */ + /* (Try to) enable *jumbo frames */ cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb4) { ehea_error("no mem for cb4"); + ret = -ENOMEM; + goto out; } else { - hret = ehea_h_query_ehea_port(adapter->handle, + hret = ehea_h_query_ehea_port(port->adapter->handle, port->logical_port_id, H_PORT_CB4, H_PORT_CB4_JUMBO, cb4); - if (hret == H_SUCCESS) { if (cb4->jumbo_frame) - jumbo = 1; + *jumbo = 1; else { cb4->jumbo_frame = 1; - hret = ehea_h_modify_ehea_port(adapter->handle, + hret = ehea_h_modify_ehea_port(port->adapter-> + handle, port-> - logical_port_id, + logical_port_id, H_PORT_CB4, H_PORT_CB4_JUMBO, cb4); if (hret == H_SUCCESS) - jumbo = 1; + *jumbo = 1; } - } + } else + ret = -EINVAL; + kfree(cb4); } +out: + return ret; +} + +static ssize_t ehea_show_port_id(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev); + return sprintf(buf, "0x%X", port->logical_port_id); +} + +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) +{ + struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev); + of_node_put(port->ofdev.node); +} + +static struct device *ehea_register_port(struct ehea_port *port, + struct device_node *dn) +{ + int ret; + + port->ofdev.node = of_node_get(dn); + port->ofdev.dev.parent = &port->adapter->ebus_dev->ofdev.dev; + + sprintf(port->ofdev.dev.bus_id, "port%d", port->logical_port_id); + port->ofdev.dev.release = logical_port_release; + + ret = of_device_register(&port->ofdev); + if (ret) { + ehea_error("failed to register device. ret=%d", ret); + goto out; + } + + ret = device_create_file(&port->ofdev.dev, &dev_attr_log_port_id); + if (ret) { + ehea_error("failed to register attributes, ret=%d", ret); + goto out_unreg_of_dev; + } + + return &port->ofdev.dev; + +out_unreg_of_dev: + of_device_unregister(&port->ofdev); +out: + return NULL; +} + +static void ehea_unregister_port(struct ehea_port *port) +{ + device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id); + of_device_unregister(&port->ofdev); +} + +struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, + u32 logical_port_id, + struct device_node *dn) +{ + int ret; + struct net_device *dev; + struct ehea_port *port; + struct device *port_dev; + int jumbo; + + /* allocate memory for the port structures */ + dev = alloc_etherdev(sizeof(struct ehea_port)); + + if (!dev) { + ehea_error("no mem for net_device"); + ret = -ENOMEM; + goto out_err; + } + + port = netdev_priv(dev); + + sema_init(&port->port_lock, 1); + port->state = EHEA_PORT_DOWN; + port->sig_comp_iv = sq_entries / 10; + + port->adapter = adapter; + port->netdev = dev; + port->logical_port_id = logical_port_id; + + port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT); + + port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL); + if (!port->mc_list) { + ret = -ENOMEM; + goto out_free_ethdev; + } + + INIT_LIST_HEAD(&port->mc_list->list); + + ret = ehea_sense_port_attr(port); + if (ret) + goto out_free_mc_list; + + port_dev = ehea_register_port(port, dn); + if (!port_dev) + goto out_free_mc_list; + + SET_NETDEV_DEV(dev, port_dev); /* initialize net_device structure */ SET_MODULE_OWNER(dev); @@ -2420,79 +2477,216 @@ static int ehea_setup_single_port(struct ehea_port *port, ret = register_netdev(dev); if (ret) { ehea_error("register_netdev failed. ret=%d", ret); - goto out_free; + goto out_unreg_port; } + ret = ehea_get_jumboframe_status(port, &jumbo); + if (ret) + ehea_error("failed determining jumbo frame status for %s", + port->netdev->name); + ehea_info("%s: Jumbo frames are %sabled", dev->name, jumbo == 1 ? "en" : "dis"); - port->netdev = dev; - ret = 0; - goto out; + return port; -out_free: +out_unreg_port: + ehea_unregister_port(port); + +out_free_mc_list: kfree(port->mc_list); -out: - return ret; + +out_free_ethdev: + free_netdev(dev); + +out_err: + ehea_error("setting up logical port with id=%d failed, ret=%d", + logical_port_id, ret); + return NULL; +} + +static void ehea_shutdown_single_port(struct ehea_port *port) +{ + unregister_netdev(port->netdev); + ehea_unregister_port(port); + kfree(port->mc_list); + free_netdev(port->netdev); } static int ehea_setup_ports(struct ehea_adapter *adapter) { - int ret; + struct device_node *lhea_dn; + struct device_node *eth_dn = NULL; + + u32 *dn_log_port_id; int port_setup_ok = 0; - struct ehea_port *port; - struct device_node *dn = NULL; - struct net_device *dev; - int i; + int i = 0; + + lhea_dn = adapter->ebus_dev->ofdev.node; + do { + eth_dn = of_get_next_child(lhea_dn, eth_dn); + if (!eth_dn) + break; - /* get port properties for all ports */ - for (i = 0; i < adapter->num_ports; i++) { + dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", + NULL); + if (!dn_log_port_id) { + ehea_error("bad device node: eth_dn name=%s", + eth_dn->full_name); + continue; + } + adapter->port[i] = ehea_setup_single_port(adapter, + *dn_log_port_id, + eth_dn); if (adapter->port[i]) - continue; /* port already up and running */ + ehea_info("%s -> logical port id #%d", + adapter->port[i]->netdev->name, + *dn_log_port_id); + i++; + } while (eth_dn); + + of_node_put(lhea_dn); - /* allocate memory for the port structures */ - dev = alloc_etherdev(sizeof(struct ehea_port)); + /* Check for succesfully set up ports */ + for (i = 0; i < EHEA_MAX_PORTS; i++) + if (adapter->port[i]) + port_setup_ok++; - if (!dev) { - ehea_error("no mem for net_device"); + if (port_setup_ok) + return 0; /* At least some ports are setup correctly */ + + return -EINVAL; +} + +static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter, + u32 logical_port_id) +{ + struct device_node *lhea_dn; + struct device_node *eth_dn = NULL; + u32 *dn_log_port_id; + + lhea_dn = adapter->ebus_dev->ofdev.node; + do { + eth_dn = of_get_next_child(lhea_dn, eth_dn); + if (!eth_dn) break; - } - port = netdev_priv(dev); - port->adapter = adapter; - port->netdev = dev; - adapter->port[i] = port; - port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT); + dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", + NULL); - dn = of_find_node_by_name(dn, "ethernet"); - ret = ehea_setup_single_port(port, dn); - if (ret) { - /* Free mem for this port struct. The others will be - processed on rollback */ - free_netdev(dev); - adapter->port[i] = NULL; - ehea_error("eHEA port %d setup failed, ret=%d", i, ret); - } + if (dn_log_port_id) + if (*dn_log_port_id == logical_port_id) + return eth_dn; + + } while (eth_dn); + + of_node_put(lhea_dn); + + return NULL; +} + +static ssize_t ehea_probe_port(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ehea_adapter *adapter = dev->driver_data; + struct ehea_port *port; + struct device_node *eth_dn = NULL; + int i; + + u32 logical_port_id; + + sscanf(buf, "%X", &logical_port_id); + + port = ehea_get_port(adapter, logical_port_id); + + if (port) { + ehea_info("adding port with logical port id=%d failed. port " + "already configured as %s.", logical_port_id, + port->netdev->name); + return -EINVAL; } + + eth_dn = ehea_get_eth_dn(adapter, logical_port_id); - of_node_put(dn); + if (!eth_dn) { + ehea_info("no logical port with id %d found", logical_port_id); + return -EINVAL; + } + + port = ehea_setup_single_port(adapter, logical_port_id, eth_dn); - /* Check for succesfully set up ports */ - for (i = 0; i < adapter->num_ports; i++) - if (adapter->port[i]) - port_setup_ok++; + if (port) { + for (i=0; i < EHEA_MAX_PORTS; i++) + if (!adapter->port[i]) { + adapter->port[i] = port; + break; + } - if (port_setup_ok) - ret = 0; /* At least some ports are setup correctly */ - else - ret = -EINVAL; + ehea_info("added %s (logical port id=%d)", port->netdev->name, + logical_port_id); + } else + return -EIO; + return (ssize_t) count; +} + +static ssize_t ehea_remove_port(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ehea_adapter *adapter = dev->driver_data; + struct ehea_port *port; + int i; + u32 logical_port_id; + + sscanf(buf, "%X", &logical_port_id); + + port = ehea_get_port(adapter, logical_port_id); + + if (port) { + ehea_info("removed %s (logical port id=%d)", port->netdev->name, + logical_port_id); + + ehea_shutdown_single_port(port); + + for (i=0; i < EHEA_MAX_PORTS; i++) + if (adapter->port[i] == port) { + adapter->port[i] = NULL; + break; + } + } else { + ehea_error("removing port with logical port id=%d failed. port " + "not configured.", logical_port_id); + return -EINVAL; + } + + return (ssize_t) count; +} + +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 ibmebus_dev *dev) +{ + int ret = device_create_file(&dev->ofdev.dev, &dev_attr_probe_port); + if (ret) + goto out; + + ret = device_create_file(&dev->ofdev.dev, &dev_attr_remove_port); +out: return ret; } -static int __devinit ehea_probe(struct ibmebus_dev *dev, - const struct of_device_id *id) +void ehea_remove_device_sysfs(struct ibmebus_dev *dev) +{ + device_remove_file(&dev->ofdev.dev, &dev_attr_probe_port); + device_remove_file(&dev->ofdev.dev, &dev_attr_remove_port); +} + +static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, + const struct of_device_id *id) { struct ehea_adapter *adapter; u64 *adapter_handle; @@ -2505,6 +2699,8 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev, goto out; } + adapter->ebus_dev = dev; + adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle", NULL); if (adapter_handle) @@ -2534,7 +2730,6 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev, dev_err(&dev->ofdev.dev, "sense_adapter_attr failed: %d", ret); goto out_free_res; } - dev_info(&dev->ofdev.dev, "%d eHEA ports found\n", adapter->num_ports); adapter->neq = ehea_create_eq(adapter, EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1); @@ -2558,15 +2753,21 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev, if (!adapter->ehea_wq) goto out_free_irq; + if (ehea_create_device_sysfs(dev)) + goto out_kill_wq; + ret = ehea_setup_ports(adapter); if (ret) { dev_err(&dev->ofdev.dev, "setup_ports failed"); - goto out_kill_wq; + goto out_rem_dev_sysfs; } ret = 0; goto out; +out_rem_dev_sysfs: + ehea_remove_device_sysfs(dev); + out_kill_wq: destroy_workqueue(adapter->ehea_wq); @@ -2585,24 +2786,20 @@ out: return ret; } -static void ehea_shutdown_single_port(struct ehea_port *port) -{ - unregister_netdev(port->netdev); - kfree(port->mc_list); - free_netdev(port->netdev); -} - static int __devexit ehea_remove(struct ibmebus_dev *dev) { struct ehea_adapter *adapter = dev->ofdev.dev.driver_data; u64 hret; int i; - for (i = 0; i < adapter->num_ports; i++) + for (i = 0; i < EHEA_MAX_PORTS; i++) if (adapter->port[i]) { ehea_shutdown_single_port(adapter->port[i]); adapter->port[i] = NULL; } + + ehea_remove_device_sysfs(dev); + destroy_workqueue(adapter->ehea_wq); ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter); @@ -2658,7 +2855,7 @@ static struct of_device_id ehea_device_table[] = { static struct ibmebus_driver ehea_driver = { .name = "ehea", .id_table = ehea_device_table, - .probe = ehea_probe, + .probe = ehea_probe_adapter, .remove = ehea_remove, }; -- cgit v1.2.1 From 18604c54854549ee0ad65e27ca9cb91c96af784c Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Wed, 28 Feb 2007 18:34:10 +0100 Subject: ehea: NAPI multi queue TX/RX path for SMP This patch provides a functionality that allows parallel RX processing on multiple RX queues by using dummy netdevices. Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea_main.c | 280 ++++++++++++++++++++++++------------------- 1 file changed, 158 insertions(+), 122 deletions(-) (limited to 'drivers/net/ehea/ehea_main.c') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 3527b391214d..8d65eb772b28 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -51,13 +51,18 @@ 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 = 0; +static int num_tx_qps = EHEA_NUM_TX_QP; module_param(msg_level, int, 0); module_param(rq1_entries, int, 0); module_param(rq2_entries, int, 0); module_param(rq3_entries, int, 0); module_param(sq_entries, int, 0); +module_param(use_mcs, 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(rq3_entries, "Number of entries for Receive Queue 3 " "[2^x - 1], x = [6..14]. Default = " @@ -71,6 +76,7 @@ MODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 " MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue " "[2^x - 1], x = [6..14]. Default = " __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")"); +MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 "); void ehea_dump(void *adr, int len, char *msg) { int x; @@ -197,7 +203,7 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr, struct sk_buff *skb = netdev_alloc_skb(dev, packet_size); if (!skb) { ehea_error("%s: no mem for skb/%d wqes filled", - dev->name, i); + pr->port->netdev->name, i); q_skba->os_skbs = fill_wqes - i; ret = -ENOMEM; break; @@ -345,10 +351,11 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq, return 0; } -static int ehea_poll(struct net_device *dev, int *budget) +static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, + struct ehea_port_res *pr, + int *budget) { - struct ehea_port *port = netdev_priv(dev); - struct ehea_port_res *pr = &port->port_res[0]; + struct ehea_port *port = pr->port; struct ehea_qp *qp = pr->qp; struct ehea_cqe *cqe; struct sk_buff *skb; @@ -359,14 +366,12 @@ static int ehea_poll(struct net_device *dev, int *budget) int skb_arr_rq2_len = pr->rq2_skba.len; int skb_arr_rq3_len = pr->rq3_skba.len; int processed, processed_rq1, processed_rq2, processed_rq3; - int wqe_index, last_wqe_index, rq, intreq, my_quota, port_reset; + int wqe_index, last_wqe_index, rq, my_quota, port_reset; processed = processed_rq1 = processed_rq2 = processed_rq3 = 0; last_wqe_index = 0; my_quota = min(*budget, dev->quota); - my_quota = min(my_quota, EHEA_POLL_MAX_RWQE); - /* rq0 is low latency RQ */ cqe = ehea_poll_rq1(qp, &wqe_index); while ((my_quota > 0) && cqe) { ehea_inc_rq1(qp); @@ -386,7 +391,8 @@ static int ehea_poll(struct net_device *dev, int *budget) if (unlikely(!skb)) { if (netif_msg_rx_err(port)) ehea_error("LL rq1: skb=NULL"); - skb = netdev_alloc_skb(dev, + + skb = netdev_alloc_skb(port->netdev, EHEA_L_PKT_SIZE); if (!skb) break; @@ -402,7 +408,7 @@ static int ehea_poll(struct net_device *dev, int *budget) ehea_error("rq2: skb=NULL"); break; } - ehea_fill_skb(dev, skb, cqe); + ehea_fill_skb(port->netdev, skb, cqe); processed_rq2++; } else { /* RQ3 */ skb = get_skb_by_index(skb_arr_rq3, @@ -412,7 +418,7 @@ static int ehea_poll(struct net_device *dev, int *budget) ehea_error("rq3: skb=NULL"); break; } - ehea_fill_skb(dev, skb, cqe); + ehea_fill_skb(port->netdev, skb, cqe); processed_rq3++; } @@ -421,8 +427,7 @@ static int ehea_poll(struct net_device *dev, int *budget) cqe->vlan_tag); else netif_receive_skb(skb); - - } else { /* Error occured */ + } else { pr->p_state.poll_receive_errors++; port_reset = ehea_treat_poll_error(pr, rq, cqe, &processed_rq2, @@ -433,32 +438,18 @@ static int ehea_poll(struct net_device *dev, int *budget) cqe = ehea_poll_rq1(qp, &wqe_index); } - dev->quota -= processed; - *budget -= processed; - - pr->p_state.ehea_poll += 1; pr->rx_packets += processed; + *budget -= processed; ehea_refill_rq1(pr, last_wqe_index, processed_rq1); ehea_refill_rq2(pr, processed_rq2); ehea_refill_rq3(pr, processed_rq3); - intreq = ((pr->p_state.ehea_poll & 0xF) == 0xF); - - if (!cqe || intreq) { - netif_rx_complete(dev); - ehea_reset_cq_ep(pr->recv_cq); - ehea_reset_cq_n1(pr->recv_cq); - cqe = hw_qeit_get_valid(&qp->hw_rqueue1); - if (!cqe || intreq) - return 0; - if (!netif_rx_reschedule(dev, my_quota)) - return 0; - } - return 1; + cqe = ehea_poll_rq1(qp, &wqe_index); + return cqe; } -void free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr) +static void ehea_free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr) { struct sk_buff *skb; int index, max_index_mask, i; @@ -479,26 +470,19 @@ void free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr) } } -#define MAX_SENDCOMP_QUOTA 400 -void ehea_send_irq_tasklet(unsigned long data) +static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) { - struct ehea_port_res *pr = (struct ehea_port_res*)data; struct ehea_cq *send_cq = pr->send_cq; struct ehea_cqe *cqe; - int quota = MAX_SENDCOMP_QUOTA; + int quota = my_quota; int cqe_counter = 0; int swqe_av = 0; unsigned long flags; - do { - cqe = ehea_poll_cq(send_cq); - if (!cqe) { - ehea_reset_cq_ep(send_cq); - ehea_reset_cq_n1(send_cq); - cqe = ehea_poll_cq(send_cq); - if (!cqe) - break; - } + cqe = ehea_poll_cq(send_cq); + while(cqe && (quota > 0)) { + ehea_inc_cq(send_cq); + cqe_counter++; rmb(); if (cqe->status & EHEA_CQE_STAT_ERR_MASK) { @@ -515,16 +499,19 @@ void ehea_send_irq_tasklet(unsigned long data) if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id) == EHEA_SWQE2_TYPE)) - free_sent_skbs(cqe, pr); + ehea_free_sent_skbs(cqe, pr); swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); quota--; - } while (quota > 0); + + cqe = ehea_poll_cq(send_cq); + }; 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); @@ -532,22 +519,55 @@ void ehea_send_irq_tasklet(unsigned long data) } spin_unlock_irqrestore(&pr->netif_queue, flags); - if (unlikely(cqe)) - tasklet_hi_schedule(&pr->send_comp_task); + return cqe; } -static irqreturn_t ehea_send_irq_handler(int irq, void *param) +#define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16 + +static int ehea_poll(struct net_device *dev, int *budget) { - struct ehea_port_res *pr = param; - tasklet_hi_schedule(&pr->send_comp_task); - return IRQ_HANDLED; + struct ehea_port_res *pr = dev->priv; + struct ehea_cqe *cqe; + struct ehea_cqe *cqe_skb = NULL; + int force_irq, wqe_index; + + cqe = ehea_poll_rq1(pr->qp, &wqe_index); + cqe_skb = ehea_poll_cq(pr->send_cq); + + force_irq = (pr->poll_counter > EHEA_NAPI_POLL_NUM_BEFORE_IRQ); + + if ((!cqe && !cqe_skb) || force_irq) { + pr->poll_counter = 0; + netif_rx_complete(dev); + ehea_reset_cq_ep(pr->recv_cq); + ehea_reset_cq_ep(pr->send_cq); + ehea_reset_cq_n1(pr->recv_cq); + ehea_reset_cq_n1(pr->send_cq); + cqe = ehea_poll_rq1(pr->qp, &wqe_index); + cqe_skb = ehea_poll_cq(pr->send_cq); + + if (!cqe && !cqe_skb) + return 0; + + if (!netif_rx_reschedule(dev, dev->quota)) + return 0; + } + + cqe = ehea_proc_rwqes(dev, pr, budget); + cqe_skb = ehea_proc_cqes(pr, 300); + + if (cqe || cqe_skb) + pr->poll_counter++; + + return 1; } static irqreturn_t ehea_recv_irq_handler(int irq, void *param) { struct ehea_port_res *pr = param; - struct ehea_port *port = pr->port; - netif_rx_schedule(port->netdev); + + netif_rx_schedule(pr->d_netdev); + return IRQ_HANDLED; } @@ -650,19 +670,25 @@ int ehea_sense_port_attr(struct ehea_port *port) } port->autoneg = 1; + port->num_mcs = cb0->num_default_qps; /* Number of default QPs */ - port->num_def_qps = cb0->num_default_qps; + if (use_mcs) + port->num_def_qps = cb0->num_default_qps; + else + port->num_def_qps = 1; if (!port->num_def_qps) { ret = -EINVAL; goto out_free; } - if (port->num_def_qps >= EHEA_NUM_TX_QP) + 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 = EHEA_NUM_TX_QP - port->num_def_qps; + port->num_add_tx_qps = port->num_tx_qps - port->num_def_qps; ret = 0; out_free: @@ -882,23 +908,6 @@ static int ehea_reg_interrupts(struct net_device *dev) struct ehea_port_res *pr; int i, ret; - for (i = 0; i < port->num_def_qps; i++) { - pr = &port->port_res[i]; - snprintf(pr->int_recv_name, EHEA_IRQ_NAME_SIZE - 1 - , "%s-recv%d", dev->name, i); - ret = ibmebus_request_irq(NULL, pr->recv_eq->attr.ist1, - ehea_recv_irq_handler, - IRQF_DISABLED, pr->int_recv_name, pr); - if (ret) { - ehea_error("failed registering irq for ehea_recv_int:" - "port_res_nr:%d, ist=%X", i, - pr->recv_eq->attr.ist1); - goto out_free_seq; - } - if (netif_msg_ifup(port)) - ehea_info("irq_handle 0x%X for funct ehea_recv_int %d " - "registered", pr->recv_eq->attr.ist1, i); - } snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1, "%s-aff", dev->name); @@ -916,41 +925,41 @@ static int ehea_reg_interrupts(struct net_device *dev) ehea_info("irq_handle 0x%X for function qp_aff_irq_handler " "registered", port->qp_eq->attr.ist1); + for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { pr = &port->port_res[i]; snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1, - "%s-send%d", dev->name, i); - ret = ibmebus_request_irq(NULL, pr->send_eq->attr.ist1, - ehea_send_irq_handler, + "%s-queue%d", dev->name, i); + ret = ibmebus_request_irq(NULL, pr->eq->attr.ist1, + ehea_recv_irq_handler, IRQF_DISABLED, pr->int_send_name, pr); if (ret) { - ehea_error("failed registering irq for ehea_send " + ehea_error("failed registering irq for ehea_queue " "port_res_nr:%d, ist=%X", i, - pr->send_eq->attr.ist1); + pr->eq->attr.ist1); goto out_free_req; } if (netif_msg_ifup(port)) - ehea_info("irq_handle 0x%X for function ehea_send_int " - "%d registered", pr->send_eq->attr.ist1, i); + ehea_info("irq_handle 0x%X for function ehea_queue_int " + "%d registered", pr->eq->attr.ist1, i); } out: return ret; + out_free_req: while (--i >= 0) { - u32 ist = port->port_res[i].send_eq->attr.ist1; + u32 ist = port->port_res[i].eq->attr.ist1; ibmebus_free_irq(NULL, ist, &port->port_res[i]); } + out_free_qpeq: ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port); i = port->num_def_qps; -out_free_seq: - while (--i >= 0) { - u32 ist = port->port_res[i].recv_eq->attr.ist1; - ibmebus_free_irq(NULL, ist, &port->port_res[i]); - } + goto out; + } static void ehea_free_interrupts(struct net_device *dev) @@ -960,21 +969,13 @@ static void ehea_free_interrupts(struct net_device *dev) int i; /* send */ + for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { pr = &port->port_res[i]; - ibmebus_free_irq(NULL, pr->send_eq->attr.ist1, pr); + ibmebus_free_irq(NULL, pr->eq->attr.ist1, pr); if (netif_msg_intr(port)) ehea_info("free send irq for res %d with handle 0x%X", - i, pr->send_eq->attr.ist1); - } - - /* receive */ - for (i = 0; i < port->num_def_qps; i++) { - pr = &port->port_res[i]; - ibmebus_free_irq(NULL, pr->recv_eq->attr.ist1, pr); - if (netif_msg_intr(port)) - ehea_info("free recv irq for res %d with handle 0x%X", - i, pr->recv_eq->attr.ist1); + i, pr->eq->attr.ist1); } /* associated events */ @@ -1003,9 +1004,14 @@ static int ehea_configure_port(struct ehea_port *port) PXLY_RC_VLAN_FILTER) | EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1); - for (i = 0; i < port->num_def_qps; i++) - cb0->default_qpn_arr[i] = port->port_res[0].qp->init_attr.qp_nr; - + for (i = 0; i < port->num_mcs; i++) + if (use_mcs) + cb0->default_qpn_arr[i] = + port->port_res[i].qp->init_attr.qp_nr; + else + cb0->default_qpn_arr[i] = + port->port_res[0].qp->init_attr.qp_nr; + if (netif_msg_ifup(port)) ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port"); @@ -1108,20 +1114,14 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, spin_lock_init(&pr->xmit_lock); spin_lock_init(&pr->netif_queue); - pr->recv_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0); - if (!pr->recv_eq) { - ehea_error("create_eq failed (recv_eq)"); - goto out_free; - } - - pr->send_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0); - if (!pr->send_eq) { - ehea_error("create_eq failed (send_eq)"); + pr->eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0); + if (!pr->eq) { + ehea_error("create_eq failed (eq)"); goto out_free; } pr->recv_cq = ehea_create_cq(adapter, pr_cfg->max_entries_rcq, - pr->recv_eq->fw_handle, + pr->eq->fw_handle, port->logical_port_id); if (!pr->recv_cq) { ehea_error("create_cq failed (cq_recv)"); @@ -1129,7 +1129,7 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, } pr->send_cq = ehea_create_cq(adapter, pr_cfg->max_entries_scq, - pr->send_eq->fw_handle, + pr->eq->fw_handle, port->logical_port_id); if (!pr->send_cq) { ehea_error("create_cq failed (cq_send)"); @@ -1194,11 +1194,20 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, ret = -EIO; goto out_free; } - tasklet_init(&pr->send_comp_task, ehea_send_irq_tasklet, - (unsigned long)pr); + atomic_set(&pr->swqe_avail, init_attr->act_nr_send_wqes - 1); kfree(init_attr); + + pr->d_netdev = alloc_netdev(0, "", ether_setup); + if (!pr->d_netdev) + goto out_free; + pr->d_netdev->priv = pr; + pr->d_netdev->weight = 64; + pr->d_netdev->poll = ehea_poll; + set_bit(__LINK_STATE_START, &pr->d_netdev->state); + strcpy(pr->d_netdev->name, port->netdev->name); + ret = 0; goto out; @@ -1211,8 +1220,7 @@ out_free: ehea_destroy_qp(pr->qp); ehea_destroy_cq(pr->send_cq); ehea_destroy_cq(pr->recv_cq); - ehea_destroy_eq(pr->send_eq); - ehea_destroy_eq(pr->recv_eq); + ehea_destroy_eq(pr->eq); out: return ret; } @@ -1221,13 +1229,14 @@ static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr) { int ret, i; + free_netdev(pr->d_netdev); + ret = ehea_destroy_qp(pr->qp); if (!ret) { ehea_destroy_cq(pr->send_cq); ehea_destroy_cq(pr->recv_cq); - ehea_destroy_eq(pr->send_eq); - ehea_destroy_eq(pr->recv_eq); + ehea_destroy_eq(pr->eq); for (i = 0; i < pr->rq1_skba.len; i++) if (pr->rq1_skba.arr[i]) @@ -1792,6 +1801,22 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev, 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)) && + (skb->nh.iph->protocol == IPPROTO_TCP)) { + tcp = (struct tcphdr*)(skb->nh.raw + (skb->nh.iph->ihl * 4)); + tmp = (tcp->source + (tcp->dest << 16)) % 31; + tmp += skb->nh.iph->daddr % 31; + return tmp % num_qps; + } + else + return 0; +} + static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ehea_port *port = netdev_priv(dev); @@ -1799,9 +1824,18 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; u32 lkey; int swqe_index; - struct ehea_port_res *pr = &port->port_res[0]; + struct ehea_port_res *pr; + + pr = &port->port_res[ehea_hash_skb(skb, port->num_tx_qps)]; + - spin_lock(&pr->xmit_lock); + if (!spin_trylock(&pr->xmit_lock)) + return NETDEV_TX_BUSY; + + if (pr->queue_stopped) { + spin_unlock(&pr->xmit_lock); + return NETDEV_TX_BUSY; + } swqe = ehea_get_swqe(pr->qp, &swqe_index); memset(swqe, 0, SWQE_HEADER_SIZE); @@ -2060,7 +2094,7 @@ static int ehea_port_res_setup(struct ehea_port *port, int def_qps, } pr_cfg.max_entries_rcq = rq1_entries + rq2_entries + rq3_entries; - pr_cfg.max_entries_scq = sq_entries; + pr_cfg.max_entries_scq = sq_entries * 2; pr_cfg.max_entries_sq = sq_entries; pr_cfg.max_entries_rq1 = rq1_entries; pr_cfg.max_entries_rq2 = rq2_entries; @@ -2208,8 +2242,10 @@ static int ehea_down(struct net_device *dev) ehea_drop_multicast_list(dev); ehea_free_interrupts(dev); - for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) - tasklet_kill(&port->port_res[i].send_comp_task); + for (i = 0; i < port->num_def_qps; i++) + while (test_bit(__LINK_STATE_RX_SCHED, + &port->port_res[i].d_netdev->state)) + msleep(1); ehea_broadcast_reg_helper(port, H_DEREG_BCMC); ret = ehea_clean_all_portres(port); -- cgit v1.2.1 From 1eef4e04c95fb52a1a3885c8f53a822206fc9aa5 Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Thu, 22 Mar 2007 17:49:42 +0100 Subject: ehea: fix for dynamic lpar support The patch fixes bugs related to the probe / remove adapter functionality (handling of OFDT nodes) Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea_main.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers/net/ehea/ehea_main.c') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 8d65eb772b28..db0d79ebae81 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -2559,11 +2559,8 @@ static int ehea_setup_ports(struct ehea_adapter *adapter) int i = 0; lhea_dn = adapter->ebus_dev->ofdev.node; - do { - eth_dn = of_get_next_child(lhea_dn, eth_dn); - if (!eth_dn) - break; - + while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) { + dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", NULL); if (!dn_log_port_id) { @@ -2580,9 +2577,7 @@ static int ehea_setup_ports(struct ehea_adapter *adapter) adapter->port[i]->netdev->name, *dn_log_port_id); i++; - } while (eth_dn); - - of_node_put(lhea_dn); + }; /* Check for succesfully set up ports */ for (i = 0; i < EHEA_MAX_PORTS; i++) @@ -2603,21 +2598,14 @@ static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter, u32 *dn_log_port_id; lhea_dn = adapter->ebus_dev->ofdev.node; - do { - eth_dn = of_get_next_child(lhea_dn, eth_dn); - if (!eth_dn) - break; - + while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) { + dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", NULL); - if (dn_log_port_id) if (*dn_log_port_id == logical_port_id) return eth_dn; - - } while (eth_dn); - - of_node_put(lhea_dn); + }; return NULL; } @@ -2653,6 +2641,8 @@ static ssize_t ehea_probe_port(struct device *dev, port = ehea_setup_single_port(adapter, logical_port_id, eth_dn); + of_node_put(eth_dn); + if (port) { for (i=0; i < EHEA_MAX_PORTS; i++) if (!adapter->port[i]) { @@ -2728,6 +2718,11 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, u64 *adapter_handle; int ret; + if (!dev || !dev->ofdev.node) { + ehea_error("Invalid ibmebus device probed"); + return -EINVAL; + } + adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); if (!adapter) { ret = -ENOMEM; @@ -2770,6 +2765,7 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, adapter->neq = ehea_create_eq(adapter, EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1); if (!adapter->neq) { + ret = -EIO; dev_err(&dev->ofdev.dev, "NEQ creation failed"); goto out_free_res; } @@ -2786,10 +2782,13 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, } adapter->ehea_wq = create_workqueue("ehea_wq"); - if (!adapter->ehea_wq) + if (!adapter->ehea_wq) { + ret = -EIO; goto out_free_irq; + } - if (ehea_create_device_sysfs(dev)) + ret = ehea_create_device_sysfs(dev); + if (ret) goto out_kill_wq; ret = ehea_setup_ports(adapter); -- cgit v1.2.1 From e542aa6bd50ba163253e60ba8e7e51c0d56162a7 Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Thu, 22 Mar 2007 17:50:24 +0100 Subject: ehea: code cleanup This patch includes: - code cleanup related to resource management - extended error data gathering for resource management - removing trailing whitespaces Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea_main.c | 95 +++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 59 deletions(-) (limited to 'drivers/net/ehea/ehea_main.c') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index db0d79ebae81..8bceb4e6bb82 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -546,19 +546,19 @@ static int ehea_poll(struct net_device *dev, int *budget) cqe = ehea_poll_rq1(pr->qp, &wqe_index); cqe_skb = ehea_poll_cq(pr->send_cq); - if (!cqe && !cqe_skb) + if (!cqe && !cqe_skb) return 0; - if (!netif_rx_reschedule(dev, dev->quota)) + if (!netif_rx_reschedule(dev, dev->quota)) return 0; } - + cqe = ehea_proc_rwqes(dev, pr, budget); cqe_skb = ehea_proc_cqes(pr, 300); if (cqe || cqe_skb) pr->poll_counter++; - + return 1; } @@ -1011,7 +1011,7 @@ static int ehea_configure_port(struct ehea_port *port) else cb0->default_qpn_arr[i] = port->port_res[0].qp->init_attr.qp_nr; - + if (netif_msg_ifup(port)) ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port"); @@ -1033,52 +1033,35 @@ out: return ret; } -static int ehea_gen_smrs(struct ehea_port_res *pr) +int ehea_gen_smrs(struct ehea_port_res *pr) { - u64 hret; + int ret; struct ehea_adapter *adapter = pr->port->adapter; - hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle, - adapter->mr.vaddr, EHEA_MR_ACC_CTRL, - adapter->pd, &pr->send_mr); - if (hret != H_SUCCESS) + ret = ehea_gen_smr(adapter, &adapter->mr, &pr->send_mr); + if (ret) goto out; - hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle, - adapter->mr.vaddr, EHEA_MR_ACC_CTRL, - adapter->pd, &pr->recv_mr); - if (hret != H_SUCCESS) - goto out_freeres; + ret = ehea_gen_smr(adapter, &adapter->mr, &pr->recv_mr); + if (ret) + goto out_free; return 0; -out_freeres: - hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle); - if (hret != H_SUCCESS) - ehea_error("failed freeing SMR"); +out_free: + ehea_rem_mr(&pr->send_mr); out: + ehea_error("Generating SMRS failed\n"); return -EIO; } -static int ehea_rem_smrs(struct ehea_port_res *pr) +int ehea_rem_smrs(struct ehea_port_res *pr) { - struct ehea_adapter *adapter = pr->port->adapter; - int ret = 0; - u64 hret; - - hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle); - if (hret != H_SUCCESS) { - ret = -EIO; - ehea_error("failed freeing send SMR for pr=%p", pr); - } - - hret = ehea_h_free_resource(adapter->handle, pr->recv_mr.handle); - if (hret != H_SUCCESS) { - ret = -EIO; - ehea_error("failed freeing recv SMR for pr=%p", pr); - } - - return ret; + if ((ehea_rem_mr(&pr->send_mr)) + || (ehea_rem_mr(&pr->recv_mr))) + return -EIO; + else + return 0; } static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries) @@ -2243,7 +2226,7 @@ static int ehea_down(struct net_device *dev) ehea_free_interrupts(dev); for (i = 0; i < port->num_def_qps; i++) - while (test_bit(__LINK_STATE_RX_SCHED, + while (test_bit(__LINK_STATE_RX_SCHED, &port->port_res[i].d_netdev->state)) msleep(1); @@ -2418,7 +2401,7 @@ static struct device *ehea_register_port(struct ehea_port *port, ehea_error("failed to register attributes, ret=%d", ret); goto out_unreg_of_dev; } - + return &port->ofdev.dev; out_unreg_of_dev: @@ -2517,7 +2500,7 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, } ret = ehea_get_jumboframe_status(port, &jumbo); - if (ret) + if (ret) ehea_error("failed determining jumbo frame status for %s", port->netdev->name); @@ -2560,7 +2543,7 @@ static int ehea_setup_ports(struct ehea_adapter *adapter) lhea_dn = adapter->ebus_dev->ofdev.node; while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) { - + dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", NULL); if (!dn_log_port_id) { @@ -2574,7 +2557,7 @@ static int ehea_setup_ports(struct ehea_adapter *adapter) eth_dn); if (adapter->port[i]) ehea_info("%s -> logical port id #%d", - adapter->port[i]->netdev->name, + adapter->port[i]->netdev->name, *dn_log_port_id); i++; }; @@ -2590,8 +2573,8 @@ static int ehea_setup_ports(struct ehea_adapter *adapter) return -EINVAL; } -static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter, - u32 logical_port_id) +static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter, + u32 logical_port_id) { struct device_node *lhea_dn; struct device_node *eth_dn = NULL; @@ -2599,7 +2582,7 @@ static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter, lhea_dn = adapter->ebus_dev->ofdev.node; while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) { - + dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", NULL); if (dn_log_port_id) @@ -2631,14 +2614,14 @@ static ssize_t ehea_probe_port(struct device *dev, port->netdev->name); return -EINVAL; } - + eth_dn = ehea_get_eth_dn(adapter, logical_port_id); if (!eth_dn) { ehea_info("no logical port with id %d found", logical_port_id); return -EINVAL; } - + port = ehea_setup_single_port(adapter, logical_port_id, eth_dn); of_node_put(eth_dn); @@ -2652,8 +2635,8 @@ static ssize_t ehea_probe_port(struct device *dev, ehea_info("added %s (logical port id=%d)", port->netdev->name, logical_port_id); - } else - return -EIO; + } else + return -EIO; return (ssize_t) count; } @@ -2748,7 +2731,7 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, dev->ofdev.dev.driver_data = adapter; - ret = ehea_reg_mr_adapter(adapter); + ret = ehea_reg_kernel_mr(adapter, &adapter->mr); if (ret) { dev_err(&dev->ofdev.dev, "reg_mr_adapter failed\n"); goto out_free_ad; @@ -2813,7 +2796,7 @@ out_kill_eq: ehea_destroy_eq(adapter->neq); out_free_res: - ehea_h_free_resource(adapter->handle, adapter->mr.handle); + ehea_rem_mr(&adapter->mr); out_free_ad: kfree(adapter); @@ -2824,7 +2807,6 @@ out: static int __devexit ehea_remove(struct ibmebus_dev *dev) { struct ehea_adapter *adapter = dev->ofdev.dev.driver_data; - u64 hret; int i; for (i = 0; i < EHEA_MAX_PORTS; i++) @@ -2841,12 +2823,7 @@ static int __devexit ehea_remove(struct ibmebus_dev *dev) tasklet_kill(&adapter->neq_tasklet); ehea_destroy_eq(adapter->neq); - - hret = ehea_h_free_resource(adapter->handle, adapter->mr.handle); - if (hret) { - dev_err(&dev->ofdev.dev, "free_resource_mr failed"); - return -EIO; - } + ehea_rem_mr(&adapter->mr); kfree(adapter); return 0; } -- cgit v1.2.1 From acbddb591ba76bb20204fd6a407cb87d3f5f751e Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Fri, 23 Mar 2007 17:18:53 +0100 Subject: ehea: removing unused functionality This patch includes: - removal of unused fields in structs - ethtool statistics cleanup - removes unsed functionality from send path Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea_main.c | 55 ++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 35 deletions(-) (limited to 'drivers/net/ehea/ehea_main.c') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 8bceb4e6bb82..e6fe2cfbd999 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -327,6 +327,13 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq, { struct sk_buff *skb; + if (cqe->status & EHEA_CQE_STAT_ERR_TCP) + pr->p_stats.err_tcp_cksum++; + if (cqe->status & EHEA_CQE_STAT_ERR_IP) + pr->p_stats.err_ip_cksum++; + if (cqe->status & EHEA_CQE_STAT_ERR_CRC) + pr->p_stats.err_frame_crc++; + if (netif_msg_rx_err(pr->port)) { ehea_error("CQE Error for QP %d", pr->qp->init_attr.qp_nr); ehea_dump(cqe, sizeof(*cqe), "CQE"); @@ -428,7 +435,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, else netif_receive_skb(skb); } else { - pr->p_state.poll_receive_errors++; + pr->p_stats.poll_receive_errors++; port_reset = ehea_treat_poll_error(pr, rq, cqe, &processed_rq2, &processed_rq3); @@ -449,34 +456,15 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, return cqe; } -static void ehea_free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr) -{ - struct sk_buff *skb; - int index, max_index_mask, i; - - index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id); - max_index_mask = pr->sq_skba.len - 1; - for (i = 0; i < EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); i++) { - skb = pr->sq_skba.arr[index]; - if (likely(skb)) { - dev_kfree_skb(skb); - pr->sq_skba.arr[index] = NULL; - } else { - ehea_error("skb=NULL, wr_id=%lX, loop=%d, index=%d", - cqe->wr_id, i, index); - } - index--; - index &= max_index_mask; - } -} - static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) { + struct sk_buff *skb; struct ehea_cq *send_cq = pr->send_cq; struct ehea_cqe *cqe; int quota = my_quota; int cqe_counter = 0; int swqe_av = 0; + int index; unsigned long flags; cqe = ehea_poll_cq(send_cq); @@ -498,8 +486,13 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) ehea_dump(cqe, sizeof(*cqe), "CQE"); if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id) - == EHEA_SWQE2_TYPE)) - ehea_free_sent_skbs(cqe, pr); + == EHEA_SWQE2_TYPE)) { + + index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id); + skb = pr->sq_skba.arr[index]; + dev_kfree_skb(skb); + pr->sq_skba.arr[index] = NULL; + } swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); quota--; @@ -1092,8 +1085,6 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, memset(pr, 0, sizeof(struct ehea_port_res)); pr->port = port; - spin_lock_init(&pr->send_lock); - spin_lock_init(&pr->recv_lock); spin_lock_init(&pr->xmit_lock); spin_lock_init(&pr->netif_queue); @@ -1811,7 +1802,6 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) pr = &port->port_res[ehea_hash_skb(skb, port->num_tx_qps)]; - if (!spin_trylock(&pr->xmit_lock)) return NETDEV_TX_BUSY; @@ -1841,6 +1831,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) swqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE2_TYPE) | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, pr->swqe_id_counter) + | EHEA_BMASK_SET(EHEA_WR_ID_REFILL, 1) | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, pr->sq_skba.index); pr->sq_skba.arr[pr->sq_skba.index] = skb; @@ -1849,14 +1840,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) lkey = pr->send_mr.lkey; ehea_xmit2(skb, dev, swqe, lkey); - - if (pr->swqe_count >= (EHEA_SIG_IV_LONG - 1)) { - swqe->wr_id |= EHEA_BMASK_SET(EHEA_WR_ID_REFILL, - EHEA_SIG_IV_LONG); - swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION; - pr->swqe_count = 0; - } else - pr->swqe_count += 1; + swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION; } pr->swqe_id_counter += 1; @@ -1876,6 +1860,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) 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; } -- cgit v1.2.1 From d1dea38d54311f6b3dd37ce485e794bd133e3593 Mon Sep 17 00:00:00 2001 From: Thomas Klein Date: Thu, 26 Apr 2007 11:56:13 +0200 Subject: ehea: fix for sysfs entries Create symbolic link from each logical port to ehea driver Signed-off-by: Thomas Klein Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea_main.c | 77 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 16 deletions(-) (limited to 'drivers/net/ehea/ehea_main.c') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index e6fe2cfbd999..368f8e3eb4a0 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -78,6 +78,28 @@ MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue " __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")"); MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 "); +static int port_name_cnt = 0; + +static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, + const struct of_device_id *id); + +static int __devexit ehea_remove(struct ibmebus_dev *dev); + +static struct of_device_id ehea_device_table[] = { + { + .name = "lhea", + .compatible = "IBM,lhea", + }, + {}, +}; + +static struct ibmebus_driver ehea_driver = { + .name = "ehea", + .id_table = ehea_device_table, + .probe = ehea_probe_adapter, + .remove = ehea_remove, +}; + void ehea_dump(void *adr, int len, char *msg) { int x; unsigned char *deb = adr; @@ -2364,6 +2386,34 @@ static void __devinit logical_port_release(struct device *dev) of_node_put(port->ofdev.node); } +static int ehea_driver_sysfs_add(struct device *dev, + struct device_driver *driver) +{ + int ret; + + ret = sysfs_create_link(&driver->kobj, &dev->kobj, + kobject_name(&dev->kobj)); + if (ret == 0) { + ret = sysfs_create_link(&dev->kobj, &driver->kobj, + "driver"); + if (ret) + sysfs_remove_link(&driver->kobj, + kobject_name(&dev->kobj)); + } + return ret; +} + +static void ehea_driver_sysfs_remove(struct device *dev, + struct device_driver *driver) +{ + struct device_driver *drv = driver; + + if (drv) { + sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); + sysfs_remove_link(&dev->kobj, "driver"); + } +} + static struct device *ehea_register_port(struct ehea_port *port, struct device_node *dn) { @@ -2371,8 +2421,9 @@ static struct device *ehea_register_port(struct ehea_port *port, port->ofdev.node = of_node_get(dn); port->ofdev.dev.parent = &port->adapter->ebus_dev->ofdev.dev; + port->ofdev.dev.bus = &ibmebus_bus_type; - sprintf(port->ofdev.dev.bus_id, "port%d", port->logical_port_id); + sprintf(port->ofdev.dev.bus_id, "port%d", port_name_cnt++); port->ofdev.dev.release = logical_port_release; ret = of_device_register(&port->ofdev); @@ -2387,8 +2438,16 @@ static struct device *ehea_register_port(struct ehea_port *port, goto out_unreg_of_dev; } + ret = ehea_driver_sysfs_add(&port->ofdev.dev, &ehea_driver.driver); + if (ret) { + ehea_error("failed to register sysfs driver link"); + goto out_rem_dev_file; + } + return &port->ofdev.dev; +out_rem_dev_file: + device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id); out_unreg_of_dev: of_device_unregister(&port->ofdev); out: @@ -2397,6 +2456,7 @@ out: static void ehea_unregister_port(struct ehea_port *port) { + ehea_driver_sysfs_remove(&port->ofdev.dev, &ehea_driver.driver); device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id); of_device_unregister(&port->ofdev); } @@ -2841,21 +2901,6 @@ static int check_module_parm(void) return ret; } -static struct of_device_id ehea_device_table[] = { - { - .name = "lhea", - .compatible = "IBM,lhea", - }, - {}, -}; - -static struct ibmebus_driver ehea_driver = { - .name = "ehea", - .id_table = ehea_device_table, - .probe = ehea_probe_adapter, - .remove = ehea_remove, -}; - int __init ehea_module_init(void) { int ret; -- cgit v1.2.1 From 1211bb6dcd935c48e864d4eecbf8a684e982419a Mon Sep 17 00:00:00 2001 From: Thomas Klein Date: Thu, 26 Apr 2007 11:56:43 +0200 Subject: ehea: fix for dlpar support Certain resources may only be allocated when first logical port is available, and must be removed when last logical port has been removed. Signed-off-by: Thomas Klein Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea_main.c | 67 +++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 22 deletions(-) (limited to 'drivers/net/ehea/ehea_main.c') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 368f8e3eb4a0..c7a5614e66c0 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -2133,6 +2133,28 @@ static int ehea_clean_all_portres(struct ehea_port *port) return ret; } +static void ehea_remove_adapter_mr (struct ehea_adapter *adapter) +{ + int i; + + for (i=0; i < EHEA_MAX_PORTS; i++) + if (adapter->port[i]) + return; + + ehea_rem_mr(&adapter->mr); +} + +static int ehea_add_adapter_mr (struct ehea_adapter *adapter) +{ + int i; + + for (i=0; i < EHEA_MAX_PORTS; i++) + if (adapter->port[i]) + return 0; + + return ehea_reg_kernel_mr(adapter, &adapter->mr); +} + static int ehea_up(struct net_device *dev) { int ret, i; @@ -2583,7 +2605,6 @@ static int ehea_setup_ports(struct ehea_adapter *adapter) struct device_node *eth_dn = NULL; u32 *dn_log_port_id; - int port_setup_ok = 0; int i = 0; lhea_dn = adapter->ebus_dev->ofdev.node; @@ -2597,6 +2618,12 @@ static int ehea_setup_ports(struct ehea_adapter *adapter) continue; } + if (ehea_add_adapter_mr(adapter)) { + ehea_error("creating MR failed"); + of_node_put(eth_dn); + return -EIO; + } + adapter->port[i] = ehea_setup_single_port(adapter, *dn_log_port_id, eth_dn); @@ -2604,18 +2631,13 @@ static int ehea_setup_ports(struct ehea_adapter *adapter) ehea_info("%s -> logical port id #%d", adapter->port[i]->netdev->name, *dn_log_port_id); + else + ehea_remove_adapter_mr(adapter); + i++; }; - /* Check for succesfully set up ports */ - for (i = 0; i < EHEA_MAX_PORTS; i++) - if (adapter->port[i]) - port_setup_ok++; - - if (port_setup_ok) - return 0; /* At least some ports are setup correctly */ - - return -EINVAL; + return 0; } static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter, @@ -2667,6 +2689,11 @@ static ssize_t ehea_probe_port(struct device *dev, return -EINVAL; } + if (ehea_add_adapter_mr(adapter)) { + ehea_error("creating MR failed"); + return -EIO; + } + port = ehea_setup_single_port(adapter, logical_port_id, eth_dn); of_node_put(eth_dn); @@ -2680,8 +2707,10 @@ static ssize_t ehea_probe_port(struct device *dev, ehea_info("added %s (logical port id=%d)", port->netdev->name, logical_port_id); - } else + } else { + ehea_remove_adapter_mr(adapter); return -EIO; + } return (ssize_t) count; } @@ -2716,6 +2745,8 @@ static ssize_t ehea_remove_port(struct device *dev, return -EINVAL; } + ehea_remove_adapter_mr(adapter); + return (ssize_t) count; } @@ -2776,18 +2807,13 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, dev->ofdev.dev.driver_data = adapter; - ret = ehea_reg_kernel_mr(adapter, &adapter->mr); - if (ret) { - dev_err(&dev->ofdev.dev, "reg_mr_adapter failed\n"); - goto out_free_ad; - } /* initialize adapter and ports */ /* get adapter properties */ ret = ehea_sense_adapter_attr(adapter); if (ret) { dev_err(&dev->ofdev.dev, "sense_adapter_attr failed: %d", ret); - goto out_free_res; + goto out_free_ad; } adapter->neq = ehea_create_eq(adapter, @@ -2795,7 +2821,7 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, if (!adapter->neq) { ret = -EIO; dev_err(&dev->ofdev.dev, "NEQ creation failed"); - goto out_free_res; + goto out_free_ad; } tasklet_init(&adapter->neq_tasklet, ehea_neq_tasklet, @@ -2840,9 +2866,6 @@ out_free_irq: out_kill_eq: ehea_destroy_eq(adapter->neq); -out_free_res: - ehea_rem_mr(&adapter->mr); - out_free_ad: kfree(adapter); out: @@ -2868,7 +2891,7 @@ static int __devexit ehea_remove(struct ibmebus_dev *dev) tasklet_kill(&adapter->neq_tasklet); ehea_destroy_eq(adapter->neq); - ehea_rem_mr(&adapter->mr); + ehea_remove_adapter_mr(adapter); kfree(adapter); return 0; } -- cgit v1.2.1