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 + -
显示快捷键?