ehea_main.c
来自「linux 内核源代码」· C语言 代码 · 共 2,668 行 · 第 1/5 页
C
2,668 行
cqe->num_bytes_transfered - 4); ehea_fill_skb(dev, skb, cqe); } else if (rq == 2) { /* RQ2 */ skb = get_skb_by_index(skb_arr_rq2, skb_arr_rq2_len, cqe); if (unlikely(!skb)) { if (netif_msg_rx_err(port)) ehea_error("rq2: skb=NULL"); break; } ehea_fill_skb(dev, skb, cqe); processed_rq2++; } else { /* RQ3 */ skb = get_skb_by_index(skb_arr_rq3, skb_arr_rq3_len, cqe); if (unlikely(!skb)) { if (netif_msg_rx_err(port)) ehea_error("rq3: skb=NULL"); break; } ehea_fill_skb(dev, skb, cqe); processed_rq3++; } ehea_proc_skb(pr, cqe, skb); dev->last_rx = jiffies; } else { pr->p_stats.poll_receive_errors++; port_reset = ehea_treat_poll_error(pr, rq, cqe, &processed_rq2, &processed_rq3); if (port_reset) break; } cqe = ehea_poll_rq1(qp, &wqe_index); } if (use_lro) lro_flush_all(&pr->lro_mgr); pr->rx_packets += processed; ehea_refill_rq1(pr, last_wqe_index, processed_rq1); ehea_refill_rq2(pr, processed_rq2); ehea_refill_rq3(pr, processed_rq3); return processed;}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); while(cqe && (quota > 0)) { ehea_inc_cq(send_cq); cqe_counter++; rmb(); if (cqe->status & EHEA_CQE_STAT_ERR_MASK) { ehea_error("Send Completion Error: Resetting port"); if (netif_msg_tx_err(pr->port)) ehea_dump(cqe, sizeof(*cqe), "Send CQE"); schedule_work(&pr->port->reset_task); break; } if (netif_msg_tx_done(pr->port)) ehea_dump(cqe, sizeof(*cqe), "CQE"); if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id) == 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--; 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); pr->queue_stopped = 0; } spin_unlock_irqrestore(&pr->netif_queue, flags); return cqe;}#define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16#define EHEA_POLL_MAX_CQES 65535static int ehea_poll(struct napi_struct *napi, int budget){ struct ehea_port_res *pr = container_of(napi, struct ehea_port_res, napi); struct net_device *dev = pr->port->netdev; struct ehea_cqe *cqe; struct ehea_cqe *cqe_skb = NULL; int force_irq, 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); if (!force_irq) rx += ehea_proc_rwqes(dev, pr, budget - rx); while ((rx != budget) || force_irq) { pr->poll_counter = 0; force_irq = 0; netif_rx_complete(dev, napi); 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 rx; if (!netif_rx_reschedule(dev, napi)) return rx; cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES); rx += ehea_proc_rwqes(dev, pr, budget - rx); } pr->poll_counter++; return rx;}#ifdef CONFIG_NET_POLL_CONTROLLERstatic void ehea_netpoll(struct net_device *dev){ struct ehea_port *port = netdev_priv(dev); int i; for (i = 0; i < port->num_def_qps; i++) netif_rx_schedule(dev, &port->port_res[i].napi);}#endifstatic irqreturn_t ehea_recv_irq_handler(int irq, void *param){ struct ehea_port_res *pr = param; netif_rx_schedule(pr->port->netdev, &pr->napi); return IRQ_HANDLED;}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); while (eqe) { 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); } schedule_work(&port->reset_task); return IRQ_HANDLED;}static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter, int logical_port){ int 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]; return NULL;}int ehea_sense_port_attr(struct ehea_port *port){ int ret; u64 hret; struct hcp_ehea_port_cb0 *cb0; cb0 = kzalloc(PAGE_SIZE, GFP_ATOMIC); /* May be called via */ if (!cb0) { /* ehea_neq_tasklet() */ ehea_error("no mem for cb0"); ret = -ENOMEM; goto out; } hret = ehea_h_query_ehea_port(port->adapter->handle, port->logical_port_id, H_PORT_CB0, EHEA_BMASK_SET(H_PORT_CB0_ALL, 0xFFFF), cb0); if (hret != H_SUCCESS) { ret = -EIO; goto out_free; } /* MAC address */ port->mac_addr = cb0->port_mac_addr << 16; if (!is_valid_ether_addr((u8*)&port->mac_addr)) { ret = -EADDRNOTAVAIL; goto out_free; } /* Port speed */ switch (cb0->port_speed) { case H_SPEED_10M_H: port->port_speed = EHEA_SPEED_10M; port->full_duplex = 0; break; case H_SPEED_10M_F: port->port_speed = EHEA_SPEED_10M; port->full_duplex = 1; break; case H_SPEED_100M_H: port->port_speed = EHEA_SPEED_100M; port->full_duplex = 0; break; case H_SPEED_100M_F: port->port_speed = EHEA_SPEED_100M; port->full_duplex = 1; break; case H_SPEED_1G_F: port->port_speed = EHEA_SPEED_1G; port->full_duplex = 1; break; case H_SPEED_10G_F: port->port_speed = EHEA_SPEED_10G; port->full_duplex = 1; break; default: port->port_speed = 0; port->full_duplex = 0; break; } port->autoneg = 1; port->num_mcs = cb0->num_default_qps; /* Number of 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; } 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)) ehea_dump(cb0, sizeof(*cb0), "ehea_sense_port_attr"); kfree(cb0);out: return ret;}int ehea_set_portspeed(struct ehea_port *port, u32 port_speed){ struct hcp_ehea_port_cb4 *cb4; u64 hret; int ret = 0; cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb4) { ehea_error("no mem for cb4"); ret = -ENOMEM; goto out; } cb4->port_speed = port_speed; netif_carrier_off(port->netdev); hret = ehea_h_modify_ehea_port(port->adapter->handle, port->logical_port_id, H_PORT_CB4, H_PORT_CB4_SPEED, cb4); if (hret == H_SUCCESS) { port->autoneg = port_speed == EHEA_SPEED_AUTONEG ? 1 : 0; hret = ehea_h_query_ehea_port(port->adapter->handle, port->logical_port_id, H_PORT_CB4, H_PORT_CB4_SPEED, cb4); if (hret == H_SUCCESS) { switch (cb4->port_speed) { case H_SPEED_10M_H: port->port_speed = EHEA_SPEED_10M; port->full_duplex = 0; break; case H_SPEED_10M_F: port->port_speed = EHEA_SPEED_10M; port->full_duplex = 1; break; case H_SPEED_100M_H: port->port_speed = EHEA_SPEED_100M; port->full_duplex = 0; break; case H_SPEED_100M_F: port->port_speed = EHEA_SPEED_100M; port->full_duplex = 1; break; case H_SPEED_1G_F: port->port_speed = EHEA_SPEED_1G; port->full_duplex = 1; break; case H_SPEED_10G_F: port->port_speed = EHEA_SPEED_10G; port->full_duplex = 1; break; default: port->port_speed = 0; port->full_duplex = 0; break; } } else { ehea_error("Failed sensing port speed"); ret = -EIO; } } else { if (hret == H_AUTHORITY) { ehea_info("Hypervisor denied setting port speed"); ret = -EPERM; } else { ret = -EIO; ehea_error("Failed setting port speed"); } } if (!prop_carrier_state || (port->phy_link == EHEA_PHY_LINK_UP)) netif_carrier_on(port->netdev); kfree(cb4);out: return ret;}static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe){ int ret; u8 ec; u8 portnum; struct ehea_port *port; ec = EHEA_BMASK_GET(NEQE_EVENT_CODE, eqe); portnum = EHEA_BMASK_GET(NEQE_PORTNUM, eqe); port = ehea_get_port(adapter, portnum); switch (ec) { case EHEA_EC_PORTSTATE_CHG: /* port state change */ if (!port) { ehea_error("unknown portnum %x", portnum); break; } if (EHEA_BMASK_GET(NEQE_PORT_UP, eqe)) { if (!netif_carrier_ok(port->netdev)) { ret = ehea_sense_port_attr(port); if (ret) { ehea_error("failed resensing port " "attributes"); break; } if (netif_msg_link(port)) ehea_info("%s: Logical port up: %dMbps " "%s Duplex", port->netdev->name, port->port_speed, port->full_duplex == 1 ? "Full" : "Half"); netif_carrier_on(port->netdev); netif_wake_queue(port->netdev); } } else if (netif_carrier_ok(port->netdev)) { if (netif_msg_link(port)) ehea_info("%s: Logical port down", port->netdev->name); netif_carrier_off(port->netdev); netif_stop_queue(port->netdev); } if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PORT_UP, eqe)) { port->phy_link = EHEA_PHY_LINK_UP; if (netif_msg_link(port)) ehea_info("%s: Physical port up", port->netdev->name); if (prop_carrier_state) netif_carrier_on(port->netdev); } else { port->phy_link = EHEA_PHY_LINK_DOWN; if (netif_msg_link(port)) ehea_info("%s: Physical port down", port->netdev->name); if (prop_carrier_state) netif_carrier_off(port->netdev); } if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PRIMARY, eqe)) ehea_info("External switch port is primary port"); else ehea_info("External switch port is backup port"); break; case EHEA_EC_ADAPTER_MALFUNC: ehea_error("Adapter malfunction"); break; case EHEA_EC_PORT_MALFUNC: ehea_info("Port malfunction: Device: %s", port->netdev->name); netif_carrier_off(port->netdev); netif_stop_queue(port->netdev); break; default: ehea_error("unknown event code %x, eqe=0x%lX", ec, eqe); break; }}static void ehea_neq_tasklet(unsigned long data){ struct ehea_adapter *adapter = (struct ehea_adapter*)data; struct ehea_eqe *eqe; u64 event_mask; eqe = ehea_poll_eq(adapter->neq); ehea_debug("eqe=%p", eqe); while (eqe) { ehea_debug("*eqe=%lx", eqe->entry); ehea_parse_eqe(adapter, eqe->entry); eqe = ehea_poll_eq(adapter->neq); ehea_debug("next eqe=%p", eqe); } event_mask = EHEA_BMASK_SET(NELR_PORTSTATE_CHG, 1) | EHEA_BMASK_SET(NELR_ADAPTER_MALFUNC, 1) | EHEA_BMASK_SET(NELR_PORT_MALFUNC, 1); ehea_h_reset_events(adapter->handle, adapter->neq->fw_handle, event_mask);}static irqreturn_t ehea_interrupt_neq(int irq, void *param){ struct ehea_adapter *adapter = param; tasklet_hi_schedule(&adapter->neq_tasklet); return IRQ_HANDLED;}static int ehea_fill_port_res(struct ehea_port_res *pr){ int ret; struct ehea_qp_init_attr *init_attr = &pr->qp->init_attr; ret = ehea_init_fill_rq1(pr, init_attr->act_nr_rwqes_rq1 - init_attr->act_nr_rwqes_rq2 - init_attr->act_nr_rwqes_rq3 - 1); ret |= ehea_refill_rq2(pr, init_attr->act_nr_rwqes_rq2 - 1); ret |= ehea_refill_rq3(pr, init_attr->act_nr_rwqes_rq3 - 1); return ret;}static int ehea_reg_interrupts(struct net_device *dev){ struct ehea_port *port = netdev_priv(dev); struct ehea_port_res *pr; int i, ret; snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1, "%s-aff", dev->name); ret = ibmebus_request_irq(port->qp_eq->attr.ist1, ehea_qp_aff_irq_handler, IRQF_DISABLED, port->int_aff_name, port); if (ret) { ehea_error("failed registering irq for qp_aff_irq_handler:" "ist=%X", port->qp_eq->attr.ist1); goto out_free_qpeq; } if (netif_msg_ifup(port)) 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];
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?