diff options
Diffstat (limited to 'drivers/net/ehea')
-rw-r--r-- | drivers/net/ehea/ehea.h | 2 | ||||
-rw-r--r-- | drivers/net/ehea/ehea_main.c | 78 | ||||
-rw-r--r-- | drivers/net/ehea/ehea_qmr.c | 43 | ||||
-rw-r--r-- | drivers/net/ehea/ehea_qmr.h | 14 |
4 files changed, 89 insertions, 48 deletions
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index fa311a95099..0630980a272 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -40,7 +40,7 @@ #include <asm/io.h> #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0102" +#define DRV_VERSION "EHEA_0103" /* eHEA capability flags */ #define DLPAR_PORT_ADD_REM 1 diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index b23173864c6..f547894ff48 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -794,11 +794,17 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) cqe_counter++; rmb(); if (cqe->status & EHEA_CQE_STAT_ERR_MASK) { - ehea_error("Send Completion Error: Resetting port"); + ehea_error("Bad send completion status=0x%04X", + cqe->status); + if (netif_msg_tx_err(pr->port)) ehea_dump(cqe, sizeof(*cqe), "Send CQE"); - ehea_schedule_port_reset(pr->port); - break; + + if (cqe->status & EHEA_CQE_STAT_RESET_MASK) { + ehea_error("Resetting port"); + ehea_schedule_port_reset(pr->port); + break; + } } if (netif_msg_tx_done(pr->port)) @@ -817,7 +823,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) quota--; cqe = ehea_poll_cq(send_cq); - }; + } ehea_update_feca(send_cq, cqe_counter); atomic_add(swqe_av, &pr->swqe_avail); @@ -904,6 +910,8 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) struct ehea_eqe *eqe; struct ehea_qp *qp; u32 qp_token; + u64 resource_type, aer, aerr; + int reset_port = 0; eqe = ehea_poll_eq(port->qp_eq); @@ -913,11 +921,24 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) eqe->entry, qp_token); qp = port->port_res[qp_token].qp; - ehea_error_data(port->adapter, qp->fw_handle); + + resource_type = ehea_error_data(port->adapter, qp->fw_handle, + &aer, &aerr); + + if (resource_type == EHEA_AER_RESTYPE_QP) { + if ((aer & EHEA_AER_RESET_MASK) || + (aerr & EHEA_AERR_RESET_MASK)) + reset_port = 1; + } else + reset_port = 1; /* Reset in case of CQ or EQ error */ + eqe = ehea_poll_eq(port->qp_eq); } - ehea_schedule_port_reset(port); + if (reset_port) { + ehea_error("Resetting port"); + ehea_schedule_port_reset(port); + } return IRQ_HANDLED; } @@ -1621,7 +1642,7 @@ static void write_swqe2_TSO(struct sk_buff *skb, { 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->len - skb->data_len; + int skb_data_size = skb_headlen(skb); int headersize; /* Packet is TCP with TSO enabled */ @@ -1632,7 +1653,7 @@ static void write_swqe2_TSO(struct sk_buff *skb, */ headersize = ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb); - skb_data_size = skb->len - skb->data_len; + skb_data_size = skb_headlen(skb); if (skb_data_size >= headersize) { /* copy immediate data */ @@ -1654,7 +1675,7 @@ static void write_swqe2_TSO(struct sk_buff *skb, static void write_swqe2_nonTSO(struct sk_buff *skb, struct ehea_swqe *swqe, u32 lkey) { - int skb_data_size = skb->len - skb->data_len; + 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; @@ -1863,7 +1884,6 @@ static void ehea_promiscuous(struct net_device *dev, int enable) port->promisc = enable; out: free_page((unsigned long)cb7); - return; } static u64 ehea_multicast_reg_helper(struct ehea_port *port, u64 mc_mac_addr, @@ -1970,7 +1990,7 @@ static void ehea_add_multicast_entry(struct ehea_port *port, u8 *mc_mac_addr) static void ehea_set_multicast_list(struct net_device *dev) { struct ehea_port *port = netdev_priv(dev); - struct dev_mc_list *k_mcl_entry; + struct netdev_hw_addr *ha; int ret; if (dev->flags & IFF_PROMISC) { @@ -2001,13 +2021,12 @@ static void ehea_set_multicast_list(struct net_device *dev) goto out; } - netdev_for_each_mc_addr(k_mcl_entry, dev) - ehea_add_multicast_entry(port, k_mcl_entry->dmi_addr); + netdev_for_each_mc_addr(ha, dev) + ehea_add_multicast_entry(port, ha->addr); } out: ehea_update_bcmc_registrations(); - return; } static int ehea_change_mtu(struct net_device *dev, int new_mtu) @@ -2111,8 +2130,8 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev, } else { /* first copy data from the skb->data buffer ... */ skb_copy_from_linear_data(skb, imm_data, - skb->len - skb->data_len); - imm_data += skb->len - skb->data_len; + skb_headlen(skb)); + imm_data += skb_headlen(skb); /* ... then copy data from the fragments */ for (i = 0; i < nfrags; i++) { @@ -2223,7 +2242,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) } spin_unlock_irqrestore(&pr->netif_queue, flags); } - dev->trans_start = jiffies; + dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */ spin_unlock(&pr->xmit_lock); return NETDEV_TX_OK; @@ -2320,7 +2339,6 @@ static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) ehea_error("modify_ehea_port failed"); out: free_page((unsigned long)cb1); - return; } int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp) @@ -2863,7 +2881,6 @@ static void ehea_reset_port(struct work_struct *work) netif_wake_queue(dev); out: mutex_unlock(&port->port_lock); - return; } static void ehea_rereg_mrs(struct work_struct *work) @@ -2871,7 +2888,6 @@ static void ehea_rereg_mrs(struct work_struct *work) int ret, i; struct ehea_adapter *adapter; - mutex_lock(&dlpar_mem_lock); ehea_info("LPAR memory changed - re-initializing driver"); list_for_each_entry(adapter, &adapter_list, list) @@ -2941,7 +2957,6 @@ static void ehea_rereg_mrs(struct work_struct *work) } ehea_info("re-initializing driver complete"); out: - mutex_unlock(&dlpar_mem_lock); return; } @@ -3241,7 +3256,7 @@ static int ehea_setup_ports(struct ehea_adapter *adapter) ehea_remove_adapter_mr(adapter); i++; - }; + } return 0; } @@ -3260,7 +3275,7 @@ static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter, if (dn_log_port_id) if (*dn_log_port_id == logical_port_id) return eth_dn; - }; + } return NULL; } @@ -3524,7 +3539,14 @@ void ehea_crash_handler(void) static int ehea_mem_notifier(struct notifier_block *nb, unsigned long action, void *data) { + int ret = NOTIFY_BAD; struct memory_notify *arg = data; + + if (!mutex_trylock(&dlpar_mem_lock)) { + ehea_info("ehea_mem_notifier must not be called parallelized"); + goto out; + } + switch (action) { case MEM_CANCEL_OFFLINE: ehea_info("memory offlining canceled"); @@ -3533,14 +3555,14 @@ static int ehea_mem_notifier(struct notifier_block *nb, ehea_info("memory is going online"); set_bit(__EHEA_STOP_XFER, &ehea_driver_flags); if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages)) - return NOTIFY_BAD; + goto out_unlock; ehea_rereg_mrs(NULL); break; case MEM_GOING_OFFLINE: ehea_info("memory is going offline"); set_bit(__EHEA_STOP_XFER, &ehea_driver_flags); if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages)) - return NOTIFY_BAD; + goto out_unlock; ehea_rereg_mrs(NULL); break; default: @@ -3548,8 +3570,12 @@ static int ehea_mem_notifier(struct notifier_block *nb, } ehea_update_firmware_handles(); + ret = NOTIFY_OK; - return NOTIFY_OK; +out_unlock: + mutex_unlock(&dlpar_mem_lock); +out: + return ret; } static struct notifier_block ehea_mem_nb = { diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index a1b4c7e5636..89128b6373e 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -229,14 +229,14 @@ u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force) int ehea_destroy_cq(struct ehea_cq *cq) { - u64 hret; + u64 hret, aer, aerr; if (!cq) return 0; hcp_epas_dtor(&cq->epas); hret = ehea_destroy_cq_res(cq, NORMAL_FREE); if (hret == H_R_STATE) { - ehea_error_data(cq->adapter, cq->fw_handle); + ehea_error_data(cq->adapter, cq->fw_handle, &aer, &aerr); hret = ehea_destroy_cq_res(cq, FORCE_FREE); } @@ -357,7 +357,7 @@ u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force) int ehea_destroy_eq(struct ehea_eq *eq) { - u64 hret; + u64 hret, aer, aerr; if (!eq) return 0; @@ -365,7 +365,7 @@ int ehea_destroy_eq(struct ehea_eq *eq) hret = ehea_destroy_eq_res(eq, NORMAL_FREE); if (hret == H_R_STATE) { - ehea_error_data(eq->adapter, eq->fw_handle); + ehea_error_data(eq->adapter, eq->fw_handle, &aer, &aerr); hret = ehea_destroy_eq_res(eq, FORCE_FREE); } @@ -540,7 +540,7 @@ u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force) int ehea_destroy_qp(struct ehea_qp *qp) { - u64 hret; + u64 hret, aer, aerr; if (!qp) return 0; @@ -548,7 +548,7 @@ int ehea_destroy_qp(struct ehea_qp *qp) hret = ehea_destroy_qp_res(qp, NORMAL_FREE); if (hret == H_R_STATE) { - ehea_error_data(qp->adapter, qp->fw_handle); + ehea_error_data(qp->adapter, qp->fw_handle, &aer, &aerr); hret = ehea_destroy_qp_res(qp, FORCE_FREE); } @@ -986,42 +986,45 @@ void print_error_data(u64 *data) if (length > EHEA_PAGESIZE) length = EHEA_PAGESIZE; - if (type == 0x8) /* Queue Pair */ + if (type == EHEA_AER_RESTYPE_QP) ehea_error("QP (resource=%llX) state: AER=0x%llX, AERR=0x%llX, " "port=%llX", resource, data[6], data[12], data[22]); - - if (type == 0x4) /* Completion Queue */ + else if (type == EHEA_AER_RESTYPE_CQ) ehea_error("CQ (resource=%llX) state: AER=0x%llX", resource, data[6]); - - if (type == 0x3) /* Event Queue */ + else if (type == EHEA_AER_RESTYPE_EQ) ehea_error("EQ (resource=%llX) state: AER=0x%llX", resource, data[6]); ehea_dump(data, length, "error data"); } -void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle) +u64 ehea_error_data(struct ehea_adapter *adapter, u64 res_handle, + u64 *aer, u64 *aerr) { unsigned long ret; u64 *rblock; + u64 type = 0; rblock = (void *)get_zeroed_page(GFP_KERNEL); if (!rblock) { ehea_error("Cannot allocate rblock memory."); - return; + goto out; } - ret = ehea_h_error_data(adapter->handle, - res_handle, - rblock); + ret = ehea_h_error_data(adapter->handle, res_handle, rblock); - if (ret == H_R_STATE) - ehea_error("No error data is available: %llX.", res_handle); - else if (ret == H_SUCCESS) + if (ret == H_SUCCESS) { + type = EHEA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]); + *aer = rblock[6]; + *aerr = rblock[12]; print_error_data(rblock); - else + } else if (ret == H_R_STATE) { + ehea_error("No error data available: %llX.", res_handle); + } else ehea_error("Error data could not be fetched: %llX", res_handle); free_page((unsigned long)rblock); +out: + return type; } diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h index 0817c1e74a1..882c50c9c34 100644 --- a/drivers/net/ehea/ehea_qmr.h +++ b/drivers/net/ehea/ehea_qmr.h @@ -154,6 +154,9 @@ struct ehea_rwqe { #define EHEA_CQE_STAT_ERR_IP 0x2000 #define EHEA_CQE_STAT_ERR_CRC 0x1000 +/* Defines which bad send cqe stati lead to a port reset */ +#define EHEA_CQE_STAT_RESET_MASK 0x0002 + struct ehea_cqe { u64 wr_id; /* work request ID from WQE */ u8 type; @@ -187,6 +190,14 @@ struct ehea_cqe { #define EHEA_EQE_SM_MECH_NUMBER EHEA_BMASK_IBM(48, 55) #define EHEA_EQE_SM_PORT_NUMBER EHEA_BMASK_IBM(56, 63) +#define EHEA_AER_RESTYPE_QP 0x8 +#define EHEA_AER_RESTYPE_CQ 0x4 +#define EHEA_AER_RESTYPE_EQ 0x3 + +/* Defines which affiliated errors lead to a port reset */ +#define EHEA_AER_RESET_MASK 0xFFFFFFFFFEFFFFFFULL +#define EHEA_AERR_RESET_MASK 0xFFFFFFFFFFFFFFFFULL + struct ehea_eqe { u64 entry; }; @@ -379,7 +390,8 @@ int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr, int ehea_rem_mr(struct ehea_mr *mr); -void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle); +u64 ehea_error_data(struct ehea_adapter *adapter, u64 res_handle, + u64 *aer, u64 *aerr); int ehea_add_sect_bmap(unsigned long pfn, unsigned long nr_pages); int ehea_rem_sect_bmap(unsigned long pfn, unsigned long nr_pages); |