ehea: queue management
Subsystems (2)
PATCH 3/6 ehea: queue management
Signed-off-by Jan-Bernd Themann <[email protected]>
drivers/net/ehea/ehea_ethtool.c | 325 ++++++++++++++++++ drivers/net/ehea/ehea_qmr.c | 719 ++++++++++++++++++++++++++++++++++++++++ drivers/net/ehea/ehea_qmr.h | 390 +++++++++++++++++++++ 3 files changed, 1434 insertions(+)
drivers/net/ehea/ehea_qmr.c +719 -0
@@ -0,0 +1,719 @@ +/* +* linux/drivers/net/ehea/ehea_qmr.c +* +* eHEA ethernet device driver for IBM eServer System p +* +* (C) Copyright IBM Corp. 2006 +* +* Authors: +* Christoph Raisch <[email protected]> +* Jan-Bernd Themann <[email protected]> +* Heiko-Joerg Schick <[email protected]> +* Thomas Klein <[email protected]> +* +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "ehea.h" +#include "ehea_phyp.h" +#include "ehea_qmr.h" + +static void *ipz_qpageit_get_inc (struct ipz_queue *queue) +{ +void *retvalue =ipz_qeit_get (queue); + queue->current_q_offset += queue->pagesize; +if (queue->current_q_offset > queue->queue_length) { + queue->current_q_offset -= queue->pagesize; + retvalue =NULL ; + } +else if ((((u64 ) retvalue) & (EHEA_PAGESIZE -1 )) !=0 ) { +EDEB (4 ,"ERROR!! not at PAGE-Boundary" ); +return NULL ; + } +EDEB (7 ,"queue=%p retvalue=%p" , queue, retvalue); +return retvalue; +} + +static int ipz_queue_ctor (struct ipz_queue *queue, +const u32 nr_of_pages, +const u32 pagesize,const u32 qe_size, +const u32 nr_of_sg) +{ +int f; +EDEB_EN (7 ,"nr_of_pages=%x pagesize=%x qe_size=%x" , + nr_of_pages, pagesize, qe_size); + queue->queue_length = nr_of_pages * pagesize; + queue->queue_pages =vmalloc (nr_of_pages *sizeof (void *)); +if (!queue->queue_pages) { +EDEB (4 ,"ERROR!! didn't get the memory" ); +return 0 ; + } +memset (queue->queue_pages,0 , nr_of_pages *sizeof (void *)); + +for (f =0 ; f < nr_of_pages; f++) { + (queue->queue_pages)[f] = + (struct ipz_page *)get_zeroed_page (GFP_KERNEL ); +if (!(queue->queue_pages)[f]) { +break ; + } + } +if (f < nr_of_pages) { +int g; +EDEB_ERR (4 ,"couldn't get 0ed pages queue=%p f=%x " +"nr_of_pages=%x" , queue, f, nr_of_pages); +for (g =0 ; g < f; g++) { +free_page ((unsigned long )(queue->queue_pages)[g]); + } +return 0 ; + } + queue->current_q_offset =0 ; + queue->qe_size = qe_size; + queue->act_nr_of_sg = nr_of_sg; + queue->pagesize = pagesize; + queue->toggle_state =1 ; +EDEB_EX (7 ,"queue_length=%x queue_pages=%p qe_size=%x" +" act_nr_of_sg=%x" , queue->queue_length, queue->queue_pages, + queue->qe_size, queue->act_nr_of_sg); +return 1 ; +} + +static int ipz_queue_dtor (struct ipz_queue *queue) +{ +int g; +EDEB_EN (7 ,"ipz_queue pointer=%p" , queue); +if (!queue) { +return 0 ; + } +if (!queue->queue_pages) { +return 0 ; + } +EDEB (7 ,"destructing a queue with the following properties:\n" +"queue_length=%x act_nr_of_sg=%x pagesize=%x qe_size=%x" , + queue->queue_length, queue->act_nr_of_sg, queue->pagesize, + queue->qe_size); +for (g =0 ; g < (queue->queue_length / queue->pagesize); g++) { +free_page ((unsigned long )(queue->queue_pages)[g]); + } +vfree (queue->queue_pages); + +EDEB_EX (7 ,"queue freed!" ); +return 1 ; +} + +struct ehea_cq *ehea_cq_new (void ) +{ +struct ehea_cq *cq =vmalloc (sizeof (*cq)); +if (cq) +memset (cq,0 ,sizeof (*cq)); +return cq; +} + +void ehea_cq_delete (struct ehea_cq *cq) +{ +vfree (cq); +} + +struct ehea_cq *ehea_create_cq (struct ehea_adapter *adapter, +int nr_of_cqe,u64 eq_handle,u32 cq_token) +{ +struct ehea_cq *cq =NULL ; +struct h_galpa gal; + +u64 *cq_handle_ref; +u32 act_nr_of_entries; +u32 act_pages; +u64 hret; +int ipz_rc; +u32 counter; +void *vpage =NULL ; +u64 rpage =0 ; + +EDEB_EN (7 ,"adapter=%p nr_of_cqe=%x , eq_handle: %016lX" , + adapter, nr_of_cqe, eq_handle); + + cq =ehea_cq_new (); +if (!cq) { + cq =NULL ; +EDEB_ERR (4 ,"ehea_create_cq ret=%p (-ENOMEM)" , cq); + goto create_cq_exit0; + } + + cq->attr.max_nr_of_cqes = nr_of_cqe; + cq->attr.cq_token = cq_token; + cq->attr.eq_handle = eq_handle; + + cq->adapter = adapter; + + cq_handle_ref = &cq->ipz_cq_handle; + act_nr_of_entries =0 ; + act_pages =0 ; + + hret =ehea_h_alloc_resource_cq (adapter->handle, + cq, + &cq->attr, + &cq->ipz_cq_handle, &cq->galpas); +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"ehea_h_alloc_resource_cq failed. hret=%lx" , hret); + goto create_cq_exit1; + } + + ipz_rc =ipz_queue_ctor (&cq->ipz_queue, cq->attr.nr_pages, +EHEA_PAGESIZE ,sizeof (struct ehea_cqe ),0 ); +if (!ipz_rc) + goto create_cq_exit2; + + hret =H_SUCCESS ; + +for (counter =0 ; counter < cq->attr.nr_pages; counter++) { + vpage =ipz_qpageit_get_inc (&cq->ipz_queue); +if (!vpage) { +EDEB_ERR (4 ,"ipz_qpageit_get_inc() " +"returns NULL adapter=%p" , adapter); + goto create_cq_exit3; + } + + rpage =virt_to_abs (vpage); + + hret =ehea_h_register_rpage_cq (adapter->handle, + cq->ipz_cq_handle, +0 , +HIPZ_CQ_REGISTER_ORIG , + rpage,1 , cq->galpas.kernel); + +if (hret <H_SUCCESS ) { +EDEB_ERR (4 ,"ehea_h_register_rpage_cq() failed " +"ehea_cq=%p hret=%lx " +"counter=%i act_pages=%i" , + cq, hret, counter, cq->attr.nr_pages); + goto create_cq_exit3; + } + +if (counter == (cq->attr.nr_pages -1 )) { + vpage =ipz_qpageit_get_inc (&cq->ipz_queue); + +if ((hret !=H_SUCCESS ) || (vpage)) { +EDEB_ERR (4 ,"Registration of pages not " +"complete ehea_cq=%p hret=%lx" , + cq, hret) + goto create_cq_exit3; + } + }else { +if ((hret !=H_PAGE_REGISTERED ) || (vpage ==0 )) { +EDEB_ERR (4 ,"Registration of page failed " +"ehea_cq=%p hret=%lx" +"counter=%i act_pages=%i" , + cq, hret, counter, cq->attr.nr_pages); + goto create_cq_exit3; + } + } + } + +ipz_qeit_reset (&cq->ipz_queue); + gal = cq->galpas.kernel; +ehea_reset_cq_ep (cq); +ehea_reset_cq_n1 (cq); + +EDEB_EX (7 ,"ret=%p " , cq); +return cq; + +create_cq_exit3: +ipz_queue_dtor (&cq->ipz_queue); + +create_cq_exit2: + hret =ehea_h_destroy_cq (adapter->handle, cq, cq->ipz_cq_handle, + &cq->galpas); +EDEB (7 ,"return code of ehea_cq_destroy=%lx" , hret); + +create_cq_exit1: +ehea_cq_delete (cq); + +create_cq_exit0: +EDEB_EX (7 ,"ret=NULL" ); +return NULL ; +} + +int ehea_destroy_cq (struct ehea_cq *cq) +{ +int ret =0 ; +u64 adapter_handle; +u64 hret; + + adapter_handle = cq->adapter->handle; +EDEB_EN (7 ,"adapter=%p cq=%p" , cq->adapter, cq); + +/* deregister all previous registered pages */ + hret =ehea_h_destroy_cq (adapter_handle, cq, cq->ipz_cq_handle, + &cq->galpas); +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"destroy CQ failed!" ); +return -EINVAL ; + } +ipz_queue_dtor (&cq->ipz_queue); +ehea_cq_delete (cq); + +EDEB_EX (7 ,"ret=%x " , ret); +return ret; +} + +struct ehea_eq *ehea_eq_new (void ) +{ +struct ehea_eq *eq =vmalloc (sizeof (*eq)); +if (eq) +memset (eq,0 ,sizeof (*eq)); +return eq; +} + +void ehea_eq_delete (struct ehea_eq *eq) +{ +vfree (eq); +} + +struct ehea_eq *ehea_create_eq (struct ehea_adapter *adapter, +const enum ehea_eq_type type, +const u32 max_nr_of_eqes,const u8 eqe_gen) +{ +u64 hret =H_HARDWARE ; +int ret =0 ; +u32 i; +void *vpage =NULL ; +struct ehea_eq *eq; + +EDEB_EN (7 ,"adapter=%p, max_nr_of_eqes=%x" , adapter, max_nr_of_eqes); + + eq =ehea_eq_new (); +if (!eq) +return NULL ; + + eq->attr.type = type; + eq->attr.max_nr_of_eqes = max_nr_of_eqes; + eq->attr.eqe_gen = eqe_gen; +spin_lock_init (&eq->spinlock); + + hret =ehea_h_alloc_resource_eq (adapter->handle, + eq, &eq->attr, &eq->ipz_eq_handle); + +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"ehea_h_alloc_resource_eq failed. hret=%lx" , hret); + goto free_eq_mem; + } + + ret =ipz_queue_ctor (&eq->ipz_queue, eq->attr.nr_pages, +EHEA_PAGESIZE ,sizeof (struct ehea_eqe ),0 ); +if (!ret) { +EDEB_ERR (4 ,"can't allocate EQ pages" ); + goto alloc_pages_failed; + } + +for (i =0 ; i < eq->attr.nr_pages; i++) { +u64 rpage; + +if (!(vpage =ipz_qpageit_get_inc (&eq->ipz_queue))) { + hret =H_RESOURCE ; + goto register_page_failed; + } + + rpage =virt_to_abs (vpage); + + hret =ehea_h_register_rpage_eq (adapter->handle, + eq->ipz_eq_handle, +0 , +HIPZ_EQ_REGISTER_ORIG , + rpage,1 ); + +if (i == (eq->attr.nr_pages -1 )) { +/* last page */ + vpage =ipz_qpageit_get_inc (&eq->ipz_queue); +if ((hret !=H_SUCCESS ) || (vpage)) { + goto register_page_failed; + } + }else { +if ((hret !=H_PAGE_REGISTERED ) || (!vpage)) { + goto register_page_failed; + } + } + } + +ipz_qeit_reset (&eq->ipz_queue); + +EDEB_EX (7 ,"hret=%lx" , hret); +return eq; + +register_page_failed: +ipz_queue_dtor (&eq->ipz_queue); + +alloc_pages_failed: +ehea_h_destroy_eq (adapter->handle, eq, eq->ipz_eq_handle, &eq->galpas); +free_eq_mem: +ehea_eq_delete (eq); + +EDEB_EX (7 ,"return with error hret=%lx" , hret); +return NULL ; +} + +void *ehea_poll_eq (struct ehea_adapter *adapter,struct ehea_eq *eq) +{ +void *eqe =NULL ; +unsigned long flags =0 ; + +EDEB_EN (7 ,"adapter=%p eq=%p" , adapter, eq); + +spin_lock_irqsave (&eq->spinlock, flags); + eqe =ipz_eqit_eq_get_inc_valid (&eq->ipz_queue); +spin_unlock_irqrestore (&eq->spinlock, flags); + +EDEB_EX (7 ,"eqe=%p" , eqe); + +return eqe; +} + +int ehea_destroy_eq (struct ehea_adapter *adapter,struct ehea_eq *eq) +{ +unsigned long flags =0 ; +u64 hret =H_HARDWARE ; + +EDEB_EN (7 ,"adapter=%p eq=%p" , adapter, eq); + +spin_lock_irqsave (&eq->spinlock, flags); + + hret =ehea_h_destroy_eq (adapter->handle, eq, eq->ipz_eq_handle, + &eq->galpas); +spin_unlock_irqrestore (&eq->spinlock, flags); + +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"Failed freeing EQ resources. hret=%lx" , hret); +return -EINVAL ; + } +ipz_queue_dtor (&eq->ipz_queue); +ehea_eq_delete (eq); +EDEB_EX (7 ,"" ); + +return 0 ; +} + +struct ehea_qp *ehea_qp_new (void ) { +struct ehea_qp *qp =vmalloc (sizeof (*qp)); +if (qp !=0 ) { +memset (qp,0 ,sizeof (*qp)); + } +return qp; +} + +void ehea_qp_delete (struct ehea_qp *qp) +{ +vfree (qp); +} + +/** +* allocates memory for a queue and registers pages in phyp +*/ +int ehea_qp_alloc_register (struct ehea_qp *qp, +struct ipz_queue *ipz_queue, +int nr_pages, +int wqe_size, +int act_nr_sges, +struct ehea_adapter *adapter,int h_call_q_selector) +{ +u64 hret =H_HARDWARE ; +u64 rpage =0 ; +int iret =0 ; +int cnt =0 ; +void *vpage =NULL ; + + iret =ipz_queue_ctor (ipz_queue, + nr_pages,EHEA_PAGESIZE , wqe_size, act_nr_sges); +if (!iret) { +EDEB_ERR (4 ,"Cannot allocate page for queue. iret=%x" , iret); +return -ENOMEM ; + } + +EDEB (7 ,"queue_size=%x, alloc_len=%x, toggle_state=%d" , + ipz_queue->qe_size, + ipz_queue->queue_length, ipz_queue->toggle_state); + +for (cnt =0 ; cnt < nr_pages; cnt++) { + vpage =ipz_qpageit_get_inc (ipz_queue); +if (!vpage) { +EDEB_ERR (4 ,"SQ ipz_qpageit_get_inc() " +"failed p_vpage= %p" , vpage); + goto qp_alloc_register_exit0; + } + rpage =virt_to_abs (vpage); + + hret =ehea_h_register_rpage_qp (adapter->handle, + qp->ipz_qp_handle, +0 , + h_call_q_selector, + rpage, +1 , qp->galpas.kernel); + +if (hret <H_SUCCESS ) { +EDEB_ERR (4 ,"ehea_h_register_rpage_qp failed. hret=%lx" , + hret); + goto qp_alloc_register_exit0; + } + } +ipz_qeit_reset (ipz_queue); + +return 0 ; + +qp_alloc_register_exit0: +ipz_queue_dtor (ipz_queue); +return -EINVAL ; +} + +static inline u32 map_swqe_size (u8 swqe_enc_size) +{ +return 128 << swqe_enc_size; +} + +static inline u32 map_rwqe_size (u8 rwqe_enc_size) +{ +return 128 << rwqe_enc_size; +} + +struct ehea_qp *ehea_create_qp (struct ehea_adapter *adapter, +u32 pd,struct ehea_qp_init_attr *init_attr) +{ +struct ehea_qp *qp; +u64 hret =H_HARDWARE ; + +u32 wqe_size_in_bytes_sq =0 ; +u32 wqe_size_in_bytes_rq1 =0 ; +u32 wqe_size_in_bytes_rq2 =0 ; +u32 wqe_size_in_bytes_rq3 =0 ; + +int ret =-1 ; + +EDEB_EN (7 ,"init_attr=%p" , init_attr); + + qp =ehea_qp_new (); + +if (!qp) { +EDEB_ERR (4 ,"pd=%X not enough memory to alloc qp" , pd); +return NULL ; + } + qp->adapter = adapter; + +EDEB (7 ,"send_ehea_cq->ipz_cq_handle=0x%lX" +"recv_ehea_cq->ipz_cq_handle=0x%lX" , init_attr->send_cq_handle, + init_attr->recv_cq_handle); + + + hret =ehea_h_alloc_resource_qp (adapter->handle, qp, + init_attr, + pd, + &qp->ipz_qp_handle, + &qp->galpas); + +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"ehea_h_alloc_resource_qp failed. hret=%lx" , hret); + goto create_qp_exit1; + } + + wqe_size_in_bytes_sq =map_swqe_size (init_attr->act_wqe_size_enc_sq); +EDEB (7 ,"SWQE SG %d" , init_attr->wqe_size_enc_sq); + + wqe_size_in_bytes_rq1 =map_rwqe_size (init_attr->act_wqe_size_enc_rq1); + wqe_size_in_bytes_rq2 =map_rwqe_size (init_attr->act_wqe_size_enc_rq2); + wqe_size_in_bytes_rq3 =map_rwqe_size (init_attr->act_wqe_size_enc_rq3); + +EDEB (7 ,"SQ pages: %d, SQ WQE size:%d, max SWQE size enc: %d" , + init_attr->nr_sq_pages, + wqe_size_in_bytes_sq, init_attr->act_wqe_size_enc_sq); + +EDEB (7 ,"RQ1 pages: %d, RQ1 WQE size:%d, max RWQE size enc: %d" , + init_attr->nr_rq1_pages, + wqe_size_in_bytes_rq1, init_attr->act_wqe_size_enc_rq1); + +EDEB (7 ,"RQ2 pages: %d, RQ2 WQE size:%d, max RWQE size enc: %d" , + init_attr->nr_rq2_pages, + wqe_size_in_bytes_rq2, init_attr->act_wqe_size_enc_rq2); + +EDEB (7 ,"RQ3 pages: %d, RQ3 WQE size:%d, max RWQE size enc: %d" , + init_attr->nr_rq3_pages, + wqe_size_in_bytes_rq3, init_attr->act_wqe_size_enc_rq3); + + ret =ehea_qp_alloc_register (qp, + &qp->ipz_squeue, + init_attr->nr_sq_pages, + wqe_size_in_bytes_sq, + init_attr->act_wqe_size_enc_sq, adapter, +0 ); +if (ret <H_SUCCESS ) { +EDEB_ERR (4 ,"can't register for sq hret=%x" , ret); + goto create_qp_exit2; + } + + ret =ehea_qp_alloc_register (qp, + &qp->ipz_rqueue1, + init_attr->nr_rq1_pages, + wqe_size_in_bytes_rq1, + init_attr->act_wqe_size_enc_rq1, + adapter,1 ); + +if (ret <0 ) { +EDEB_ERR (4 ,"can't register for rq1 hret=%x" , ret); + goto create_qp_exit3; + } + +if (init_attr->rq_count >1 ) { + ret =ehea_qp_alloc_register (qp, + &qp->ipz_rqueue2, + init_attr->nr_rq2_pages, + wqe_size_in_bytes_rq2, + init_attr->act_wqe_size_enc_rq2, + adapter,2 ); + +if (ret <0 ) { +EDEB_ERR (4 ,"can't register for rq2 hret=%x" , ret); + goto create_qp_exit4; + } + } + +if (init_attr->rq_count >2 ) { + ret =ehea_qp_alloc_register (qp, + &qp->ipz_rqueue3, + init_attr->nr_rq3_pages, + wqe_size_in_bytes_rq3, + init_attr->act_wqe_size_enc_rq3, + adapter,3 ); + +if (ret !=0 ) { +EDEB_ERR (4 ,"can't register for rq3 hret=%x" , ret); + goto create_qp_exit5; + } + } + + qp->init_attr = *init_attr; + +EDEB_EX (7 ,"" ); +return qp; + +create_qp_exit5: +ipz_queue_dtor (&qp->ipz_rqueue2); + +create_qp_exit4: +ipz_queue_dtor (&qp->ipz_rqueue1); + +create_qp_exit3: +ipz_queue_dtor (&qp->ipz_squeue); + +create_qp_exit2: + hret =ehea_h_destroy_qp (adapter->handle, qp, qp->ipz_qp_handle, + &qp->galpas); + +create_qp_exit1: +ehea_qp_delete (qp); + +EDEB_EX (7 ,"hret=NULL" ); +return NULL ; + +} + +int ehea_destroy_qp (struct ehea_qp *qp) +{ +int ret =0 ; +u64 hret; +struct ehea_qp_init_attr *qp_attr = &qp->init_attr; +EDEB_EX (7 ,"" ); + + hret =ehea_h_destroy_qp (qp->adapter->handle, qp, qp->ipz_qp_handle, + &qp->galpas); +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"destroy QP failed!" ); + ret = -EINVAL ; + } + +ipz_queue_dtor (&qp->ipz_squeue); +ipz_queue_dtor (&qp->ipz_rqueue1); + +if (qp_attr->rq_count >1 ) +ipz_queue_dtor (&qp->ipz_rqueue2); +if (qp_attr->rq_count >2 ) +ipz_queue_dtor (&qp->ipz_rqueue3); +ehea_qp_delete (qp); + +EDEB_EX (7 ,"hret=%lx" , hret); + +return ret; +} + +#define EHEA_MEM_START 0xc000000000000000 +#define EHEA_MEM_ACC_CTRL 0x00800000 + +int ehea_reg_mr_adapter (struct ehea_adapter *adapter) +{ +int i; +u64 hret; +u64 start =EHEA_MEM_START ; +u64 end = (u64 ) high_memory; +u64 nr_pages = (end - start) /PAGE_SIZE ; +u32 acc_ctrl =EHEA_MEM_ACC_CTRL ; + +EDEB_EN (7 ,"adapter=%p" , adapter); + + hret =ehea_h_alloc_resource_mr (adapter->handle, + start, + end - start, + acc_ctrl, + adapter->pd, + &adapter->mr_handle, + &adapter->lkey); +if (hret !=H_SUCCESS ) { +EDEB_EX (4 ,"Error: hret=%lX\n" , hret); +return -EINVAL ; + } + +for (i =0 ; i < nr_pages; i++) { + hret =ehea_h_register_rpage_mr (adapter->handle, + adapter->mr_handle, +0 , +0 , +virt_to_abs ( + (void *)(((u64 ) start) + + (i *PAGE_SIZE ))), +1 ); + +if (((hret !=H_SUCCESS ) && (hret !=H_PAGE_REGISTERED ))) { +ehea_h_free_resource_mr (adapter->handle, adapter->mr_handle); +EDEB_EX (4 ," register rpage_mr: hret=%lX\n" , hret); +return -EINVAL ; + } + } + +if (hret !=H_SUCCESS ) { +ehea_h_free_resource_mr (adapter->handle, adapter->mr_handle); +EDEB_EX (4 ," register rpage_mr failed for last page:" +"hret=%lX\n" , hret); +return -EINVAL ; + } + +EDEB_EX (7 ,"" ); +return 0 ; +} + +int ehea_dereg_mr_adapter (struct ehea_adapter *adapter) +{ +u64 hret; +EDEB_EN (7 ,"adapter=%p" , adapter); + hret =ehea_h_free_resource_mr (adapter->handle, adapter->mr_handle); +if (hret !=H_SUCCESS ) { +EDEB_EX (4 ,"deregistering memory region failed" ); +return -EINVAL ; + } +EDEB_EX (7 ,"" ); +return 0 ; +}
drivers/net/ehea/ehea_qmr.h +390 -0
390 lines not on this page · raw message
drivers/net/ehea/ehea_ethtool.c +325 -0
325 lines not on this page · raw message