1de6cc651SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29aa32835SJeff Kirsher /*
33396c782SPaul Gortmaker * linux/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
49aa32835SJeff Kirsher *
59aa32835SJeff Kirsher * eHEA ethernet device driver for IBM eServer System p
69aa32835SJeff Kirsher *
79aa32835SJeff Kirsher * (C) Copyright IBM Corp. 2006
89aa32835SJeff Kirsher *
99aa32835SJeff Kirsher * Authors:
109aa32835SJeff Kirsher * Christoph Raisch <raisch@de.ibm.com>
119aa32835SJeff Kirsher * Jan-Bernd Themann <themann@de.ibm.com>
129aa32835SJeff Kirsher * Thomas Klein <tklein@de.ibm.com>
139aa32835SJeff Kirsher */
149aa32835SJeff Kirsher
159aa32835SJeff Kirsher #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
169aa32835SJeff Kirsher
179aa32835SJeff Kirsher #include <linux/mm.h>
189aa32835SJeff Kirsher #include <linux/slab.h>
199aa32835SJeff Kirsher #include "ehea.h"
209aa32835SJeff Kirsher #include "ehea_phyp.h"
219aa32835SJeff Kirsher #include "ehea_qmr.h"
229aa32835SJeff Kirsher
231886e5d2SThadeu Lima de Souza Cascardo static struct ehea_bmap *ehea_bmap;
249aa32835SJeff Kirsher
hw_qpageit_get_inc(struct hw_queue * queue)259aa32835SJeff Kirsher static void *hw_qpageit_get_inc(struct hw_queue *queue)
269aa32835SJeff Kirsher {
279aa32835SJeff Kirsher void *retvalue = hw_qeit_get(queue);
289aa32835SJeff Kirsher
299aa32835SJeff Kirsher queue->current_q_offset += queue->pagesize;
309aa32835SJeff Kirsher if (queue->current_q_offset > queue->queue_length) {
319aa32835SJeff Kirsher queue->current_q_offset -= queue->pagesize;
329aa32835SJeff Kirsher retvalue = NULL;
339aa32835SJeff Kirsher } else if (((u64) retvalue) & (EHEA_PAGESIZE-1)) {
349aa32835SJeff Kirsher pr_err("not on pageboundary\n");
359aa32835SJeff Kirsher retvalue = NULL;
369aa32835SJeff Kirsher }
379aa32835SJeff Kirsher return retvalue;
389aa32835SJeff Kirsher }
399aa32835SJeff Kirsher
hw_queue_ctor(struct hw_queue * queue,const u32 nr_of_pages,const u32 pagesize,const u32 qe_size)409aa32835SJeff Kirsher static int hw_queue_ctor(struct hw_queue *queue, const u32 nr_of_pages,
419aa32835SJeff Kirsher const u32 pagesize, const u32 qe_size)
429aa32835SJeff Kirsher {
439aa32835SJeff Kirsher int pages_per_kpage = PAGE_SIZE / pagesize;
449aa32835SJeff Kirsher int i, k;
459aa32835SJeff Kirsher
469aa32835SJeff Kirsher if ((pagesize > PAGE_SIZE) || (!pages_per_kpage)) {
479aa32835SJeff Kirsher pr_err("pagesize conflict! kernel pagesize=%d, ehea pagesize=%d\n",
489aa32835SJeff Kirsher (int)PAGE_SIZE, (int)pagesize);
499aa32835SJeff Kirsher return -EINVAL;
509aa32835SJeff Kirsher }
519aa32835SJeff Kirsher
529aa32835SJeff Kirsher queue->queue_length = nr_of_pages * pagesize;
53b2adaca9SJoe Perches queue->queue_pages = kmalloc_array(nr_of_pages, sizeof(void *),
54b2adaca9SJoe Perches GFP_KERNEL);
55b2adaca9SJoe Perches if (!queue->queue_pages)
569aa32835SJeff Kirsher return -ENOMEM;
579aa32835SJeff Kirsher
589aa32835SJeff Kirsher /*
599aa32835SJeff Kirsher * allocate pages for queue:
609aa32835SJeff Kirsher * outer loop allocates whole kernel pages (page aligned) and
619aa32835SJeff Kirsher * inner loop divides a kernel page into smaller hea queue pages
629aa32835SJeff Kirsher */
639aa32835SJeff Kirsher i = 0;
649aa32835SJeff Kirsher while (i < nr_of_pages) {
659aa32835SJeff Kirsher u8 *kpage = (u8 *)get_zeroed_page(GFP_KERNEL);
669aa32835SJeff Kirsher if (!kpage)
679aa32835SJeff Kirsher goto out_nomem;
689aa32835SJeff Kirsher for (k = 0; k < pages_per_kpage && i < nr_of_pages; k++) {
699aa32835SJeff Kirsher (queue->queue_pages)[i] = (struct ehea_page *)kpage;
709aa32835SJeff Kirsher kpage += pagesize;
719aa32835SJeff Kirsher i++;
729aa32835SJeff Kirsher }
739aa32835SJeff Kirsher }
749aa32835SJeff Kirsher
759aa32835SJeff Kirsher queue->current_q_offset = 0;
769aa32835SJeff Kirsher queue->qe_size = qe_size;
779aa32835SJeff Kirsher queue->pagesize = pagesize;
789aa32835SJeff Kirsher queue->toggle_state = 1;
799aa32835SJeff Kirsher
809aa32835SJeff Kirsher return 0;
819aa32835SJeff Kirsher out_nomem:
829aa32835SJeff Kirsher for (i = 0; i < nr_of_pages; i += pages_per_kpage) {
839aa32835SJeff Kirsher if (!(queue->queue_pages)[i])
849aa32835SJeff Kirsher break;
859aa32835SJeff Kirsher free_page((unsigned long)(queue->queue_pages)[i]);
869aa32835SJeff Kirsher }
879aa32835SJeff Kirsher return -ENOMEM;
889aa32835SJeff Kirsher }
899aa32835SJeff Kirsher
hw_queue_dtor(struct hw_queue * queue)909aa32835SJeff Kirsher static void hw_queue_dtor(struct hw_queue *queue)
919aa32835SJeff Kirsher {
9238ea4e6eSRickard Strandqvist int pages_per_kpage;
939aa32835SJeff Kirsher int i, nr_pages;
949aa32835SJeff Kirsher
959aa32835SJeff Kirsher if (!queue || !queue->queue_pages)
969aa32835SJeff Kirsher return;
979aa32835SJeff Kirsher
9838ea4e6eSRickard Strandqvist pages_per_kpage = PAGE_SIZE / queue->pagesize;
9938ea4e6eSRickard Strandqvist
1009aa32835SJeff Kirsher nr_pages = queue->queue_length / queue->pagesize;
1019aa32835SJeff Kirsher
1029aa32835SJeff Kirsher for (i = 0; i < nr_pages; i += pages_per_kpage)
1039aa32835SJeff Kirsher free_page((unsigned long)(queue->queue_pages)[i]);
1049aa32835SJeff Kirsher
1059aa32835SJeff Kirsher kfree(queue->queue_pages);
1069aa32835SJeff Kirsher }
1079aa32835SJeff Kirsher
ehea_create_cq(struct ehea_adapter * adapter,int nr_of_cqe,u64 eq_handle,u32 cq_token)1089aa32835SJeff Kirsher struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
1099aa32835SJeff Kirsher int nr_of_cqe, u64 eq_handle, u32 cq_token)
1109aa32835SJeff Kirsher {
1119aa32835SJeff Kirsher struct ehea_cq *cq;
112fe1ec0bdSYueHaibing u64 hret, rpage;
113c8c618afSzhong jiang u32 counter;
1149aa32835SJeff Kirsher int ret;
1159aa32835SJeff Kirsher void *vpage;
1169aa32835SJeff Kirsher
1179aa32835SJeff Kirsher cq = kzalloc(sizeof(*cq), GFP_KERNEL);
118b2adaca9SJoe Perches if (!cq)
1199aa32835SJeff Kirsher goto out_nomem;
1209aa32835SJeff Kirsher
1219aa32835SJeff Kirsher cq->attr.max_nr_of_cqes = nr_of_cqe;
1229aa32835SJeff Kirsher cq->attr.cq_token = cq_token;
1239aa32835SJeff Kirsher cq->attr.eq_handle = eq_handle;
1249aa32835SJeff Kirsher
1259aa32835SJeff Kirsher cq->adapter = adapter;
1269aa32835SJeff Kirsher
1279aa32835SJeff Kirsher hret = ehea_h_alloc_resource_cq(adapter->handle, &cq->attr,
1289aa32835SJeff Kirsher &cq->fw_handle, &cq->epas);
1299aa32835SJeff Kirsher if (hret != H_SUCCESS) {
1309aa32835SJeff Kirsher pr_err("alloc_resource_cq failed\n");
1319aa32835SJeff Kirsher goto out_freemem;
1329aa32835SJeff Kirsher }
1339aa32835SJeff Kirsher
1349aa32835SJeff Kirsher ret = hw_queue_ctor(&cq->hw_queue, cq->attr.nr_pages,
1359aa32835SJeff Kirsher EHEA_PAGESIZE, sizeof(struct ehea_cqe));
1369aa32835SJeff Kirsher if (ret)
1379aa32835SJeff Kirsher goto out_freeres;
1389aa32835SJeff Kirsher
1399aa32835SJeff Kirsher for (counter = 0; counter < cq->attr.nr_pages; counter++) {
1409aa32835SJeff Kirsher vpage = hw_qpageit_get_inc(&cq->hw_queue);
1419aa32835SJeff Kirsher if (!vpage) {
1429aa32835SJeff Kirsher pr_err("hw_qpageit_get_inc failed\n");
1439aa32835SJeff Kirsher goto out_kill_hwq;
1449aa32835SJeff Kirsher }
1459aa32835SJeff Kirsher
14667e1dbcbSMichael Ellerman rpage = __pa(vpage);
1479aa32835SJeff Kirsher hret = ehea_h_register_rpage(adapter->handle,
1489aa32835SJeff Kirsher 0, EHEA_CQ_REGISTER_ORIG,
1499aa32835SJeff Kirsher cq->fw_handle, rpage, 1);
1509aa32835SJeff Kirsher if (hret < H_SUCCESS) {
1519aa32835SJeff Kirsher pr_err("register_rpage_cq failed ehea_cq=%p hret=%llx counter=%i act_pages=%i\n",
1529aa32835SJeff Kirsher cq, hret, counter, cq->attr.nr_pages);
1539aa32835SJeff Kirsher goto out_kill_hwq;
1549aa32835SJeff Kirsher }
1559aa32835SJeff Kirsher
1569aa32835SJeff Kirsher if (counter == (cq->attr.nr_pages - 1)) {
1579aa32835SJeff Kirsher vpage = hw_qpageit_get_inc(&cq->hw_queue);
1589aa32835SJeff Kirsher
1599aa32835SJeff Kirsher if ((hret != H_SUCCESS) || (vpage)) {
1609aa32835SJeff Kirsher pr_err("registration of pages not complete hret=%llx\n",
1619aa32835SJeff Kirsher hret);
1629aa32835SJeff Kirsher goto out_kill_hwq;
1639aa32835SJeff Kirsher }
1649aa32835SJeff Kirsher } else {
1659aa32835SJeff Kirsher if (hret != H_PAGE_REGISTERED) {
1669aa32835SJeff Kirsher pr_err("CQ: registration of page failed hret=%llx\n",
1679aa32835SJeff Kirsher hret);
1689aa32835SJeff Kirsher goto out_kill_hwq;
1699aa32835SJeff Kirsher }
1709aa32835SJeff Kirsher }
1719aa32835SJeff Kirsher }
1729aa32835SJeff Kirsher
1739aa32835SJeff Kirsher hw_qeit_reset(&cq->hw_queue);
1749aa32835SJeff Kirsher ehea_reset_cq_ep(cq);
1759aa32835SJeff Kirsher ehea_reset_cq_n1(cq);
1769aa32835SJeff Kirsher
1779aa32835SJeff Kirsher return cq;
1789aa32835SJeff Kirsher
1799aa32835SJeff Kirsher out_kill_hwq:
1809aa32835SJeff Kirsher hw_queue_dtor(&cq->hw_queue);
1819aa32835SJeff Kirsher
1829aa32835SJeff Kirsher out_freeres:
1839aa32835SJeff Kirsher ehea_h_free_resource(adapter->handle, cq->fw_handle, FORCE_FREE);
1849aa32835SJeff Kirsher
1859aa32835SJeff Kirsher out_freemem:
1869aa32835SJeff Kirsher kfree(cq);
1879aa32835SJeff Kirsher
1889aa32835SJeff Kirsher out_nomem:
1899aa32835SJeff Kirsher return NULL;
1909aa32835SJeff Kirsher }
1919aa32835SJeff Kirsher
ehea_destroy_cq_res(struct ehea_cq * cq,u64 force)1921886e5d2SThadeu Lima de Souza Cascardo static u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force)
1939aa32835SJeff Kirsher {
1949aa32835SJeff Kirsher u64 hret;
1959aa32835SJeff Kirsher u64 adapter_handle = cq->adapter->handle;
1969aa32835SJeff Kirsher
1979aa32835SJeff Kirsher /* deregister all previous registered pages */
1989aa32835SJeff Kirsher hret = ehea_h_free_resource(adapter_handle, cq->fw_handle, force);
1999aa32835SJeff Kirsher if (hret != H_SUCCESS)
2009aa32835SJeff Kirsher return hret;
2019aa32835SJeff Kirsher
2029aa32835SJeff Kirsher hw_queue_dtor(&cq->hw_queue);
2039aa32835SJeff Kirsher kfree(cq);
2049aa32835SJeff Kirsher
2059aa32835SJeff Kirsher return hret;
2069aa32835SJeff Kirsher }
2079aa32835SJeff Kirsher
ehea_destroy_cq(struct ehea_cq * cq)2089aa32835SJeff Kirsher int ehea_destroy_cq(struct ehea_cq *cq)
2099aa32835SJeff Kirsher {
2109aa32835SJeff Kirsher u64 hret, aer, aerr;
2119aa32835SJeff Kirsher if (!cq)
2129aa32835SJeff Kirsher return 0;
2139aa32835SJeff Kirsher
2149aa32835SJeff Kirsher hcp_epas_dtor(&cq->epas);
2159aa32835SJeff Kirsher hret = ehea_destroy_cq_res(cq, NORMAL_FREE);
2169aa32835SJeff Kirsher if (hret == H_R_STATE) {
2179aa32835SJeff Kirsher ehea_error_data(cq->adapter, cq->fw_handle, &aer, &aerr);
2189aa32835SJeff Kirsher hret = ehea_destroy_cq_res(cq, FORCE_FREE);
2199aa32835SJeff Kirsher }
2209aa32835SJeff Kirsher
2219aa32835SJeff Kirsher if (hret != H_SUCCESS) {
2229aa32835SJeff Kirsher pr_err("destroy CQ failed\n");
2239aa32835SJeff Kirsher return -EIO;
2249aa32835SJeff Kirsher }
2259aa32835SJeff Kirsher
2269aa32835SJeff Kirsher return 0;
2279aa32835SJeff Kirsher }
2289aa32835SJeff Kirsher
ehea_create_eq(struct ehea_adapter * adapter,const enum ehea_eq_type type,const u32 max_nr_of_eqes,const u8 eqe_gen)2299aa32835SJeff Kirsher struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
2309aa32835SJeff Kirsher const enum ehea_eq_type type,
2319aa32835SJeff Kirsher const u32 max_nr_of_eqes, const u8 eqe_gen)
2329aa32835SJeff Kirsher {
2339aa32835SJeff Kirsher int ret, i;
2349aa32835SJeff Kirsher u64 hret, rpage;
2359aa32835SJeff Kirsher void *vpage;
2369aa32835SJeff Kirsher struct ehea_eq *eq;
2379aa32835SJeff Kirsher
2389aa32835SJeff Kirsher eq = kzalloc(sizeof(*eq), GFP_KERNEL);
239b2adaca9SJoe Perches if (!eq)
2409aa32835SJeff Kirsher return NULL;
2419aa32835SJeff Kirsher
2429aa32835SJeff Kirsher eq->adapter = adapter;
2439aa32835SJeff Kirsher eq->attr.type = type;
2449aa32835SJeff Kirsher eq->attr.max_nr_of_eqes = max_nr_of_eqes;
2459aa32835SJeff Kirsher eq->attr.eqe_gen = eqe_gen;
2469aa32835SJeff Kirsher spin_lock_init(&eq->spinlock);
2479aa32835SJeff Kirsher
2489aa32835SJeff Kirsher hret = ehea_h_alloc_resource_eq(adapter->handle,
2499aa32835SJeff Kirsher &eq->attr, &eq->fw_handle);
2509aa32835SJeff Kirsher if (hret != H_SUCCESS) {
2519aa32835SJeff Kirsher pr_err("alloc_resource_eq failed\n");
2529aa32835SJeff Kirsher goto out_freemem;
2539aa32835SJeff Kirsher }
2549aa32835SJeff Kirsher
2559aa32835SJeff Kirsher ret = hw_queue_ctor(&eq->hw_queue, eq->attr.nr_pages,
2569aa32835SJeff Kirsher EHEA_PAGESIZE, sizeof(struct ehea_eqe));
2579aa32835SJeff Kirsher if (ret) {
2589aa32835SJeff Kirsher pr_err("can't allocate eq pages\n");
2599aa32835SJeff Kirsher goto out_freeres;
2609aa32835SJeff Kirsher }
2619aa32835SJeff Kirsher
2629aa32835SJeff Kirsher for (i = 0; i < eq->attr.nr_pages; i++) {
2639aa32835SJeff Kirsher vpage = hw_qpageit_get_inc(&eq->hw_queue);
2649aa32835SJeff Kirsher if (!vpage) {
2659aa32835SJeff Kirsher pr_err("hw_qpageit_get_inc failed\n");
2669aa32835SJeff Kirsher hret = H_RESOURCE;
2679aa32835SJeff Kirsher goto out_kill_hwq;
2689aa32835SJeff Kirsher }
2699aa32835SJeff Kirsher
27067e1dbcbSMichael Ellerman rpage = __pa(vpage);
2719aa32835SJeff Kirsher
2729aa32835SJeff Kirsher hret = ehea_h_register_rpage(adapter->handle, 0,
2739aa32835SJeff Kirsher EHEA_EQ_REGISTER_ORIG,
2749aa32835SJeff Kirsher eq->fw_handle, rpage, 1);
2759aa32835SJeff Kirsher
2769aa32835SJeff Kirsher if (i == (eq->attr.nr_pages - 1)) {
2779aa32835SJeff Kirsher /* last page */
2789aa32835SJeff Kirsher vpage = hw_qpageit_get_inc(&eq->hw_queue);
2799aa32835SJeff Kirsher if ((hret != H_SUCCESS) || (vpage))
2809aa32835SJeff Kirsher goto out_kill_hwq;
2819aa32835SJeff Kirsher
2829aa32835SJeff Kirsher } else {
2839aa32835SJeff Kirsher if (hret != H_PAGE_REGISTERED)
2849aa32835SJeff Kirsher goto out_kill_hwq;
2859aa32835SJeff Kirsher
2869aa32835SJeff Kirsher }
2879aa32835SJeff Kirsher }
2889aa32835SJeff Kirsher
2899aa32835SJeff Kirsher hw_qeit_reset(&eq->hw_queue);
2909aa32835SJeff Kirsher return eq;
2919aa32835SJeff Kirsher
2929aa32835SJeff Kirsher out_kill_hwq:
2939aa32835SJeff Kirsher hw_queue_dtor(&eq->hw_queue);
2949aa32835SJeff Kirsher
2959aa32835SJeff Kirsher out_freeres:
2969aa32835SJeff Kirsher ehea_h_free_resource(adapter->handle, eq->fw_handle, FORCE_FREE);
2979aa32835SJeff Kirsher
2989aa32835SJeff Kirsher out_freemem:
2999aa32835SJeff Kirsher kfree(eq);
3009aa32835SJeff Kirsher return NULL;
3019aa32835SJeff Kirsher }
3029aa32835SJeff Kirsher
ehea_poll_eq(struct ehea_eq * eq)3039aa32835SJeff Kirsher struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq)
3049aa32835SJeff Kirsher {
3059aa32835SJeff Kirsher struct ehea_eqe *eqe;
3069aa32835SJeff Kirsher unsigned long flags;
3079aa32835SJeff Kirsher
3089aa32835SJeff Kirsher spin_lock_irqsave(&eq->spinlock, flags);
3099aa32835SJeff Kirsher eqe = hw_eqit_eq_get_inc_valid(&eq->hw_queue);
3109aa32835SJeff Kirsher spin_unlock_irqrestore(&eq->spinlock, flags);
3119aa32835SJeff Kirsher
3129aa32835SJeff Kirsher return eqe;
3139aa32835SJeff Kirsher }
3149aa32835SJeff Kirsher
ehea_destroy_eq_res(struct ehea_eq * eq,u64 force)3151886e5d2SThadeu Lima de Souza Cascardo static u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force)
3169aa32835SJeff Kirsher {
3179aa32835SJeff Kirsher u64 hret;
3189aa32835SJeff Kirsher unsigned long flags;
3199aa32835SJeff Kirsher
3209aa32835SJeff Kirsher spin_lock_irqsave(&eq->spinlock, flags);
3219aa32835SJeff Kirsher
3229aa32835SJeff Kirsher hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle, force);
3239aa32835SJeff Kirsher spin_unlock_irqrestore(&eq->spinlock, flags);
3249aa32835SJeff Kirsher
3259aa32835SJeff Kirsher if (hret != H_SUCCESS)
3269aa32835SJeff Kirsher return hret;
3279aa32835SJeff Kirsher
3289aa32835SJeff Kirsher hw_queue_dtor(&eq->hw_queue);
3299aa32835SJeff Kirsher kfree(eq);
3309aa32835SJeff Kirsher
3319aa32835SJeff Kirsher return hret;
3329aa32835SJeff Kirsher }
3339aa32835SJeff Kirsher
ehea_destroy_eq(struct ehea_eq * eq)3349aa32835SJeff Kirsher int ehea_destroy_eq(struct ehea_eq *eq)
3359aa32835SJeff Kirsher {
3369aa32835SJeff Kirsher u64 hret, aer, aerr;
3379aa32835SJeff Kirsher if (!eq)
3389aa32835SJeff Kirsher return 0;
3399aa32835SJeff Kirsher
3409aa32835SJeff Kirsher hcp_epas_dtor(&eq->epas);
3419aa32835SJeff Kirsher
3429aa32835SJeff Kirsher hret = ehea_destroy_eq_res(eq, NORMAL_FREE);
3439aa32835SJeff Kirsher if (hret == H_R_STATE) {
3449aa32835SJeff Kirsher ehea_error_data(eq->adapter, eq->fw_handle, &aer, &aerr);
3459aa32835SJeff Kirsher hret = ehea_destroy_eq_res(eq, FORCE_FREE);
3469aa32835SJeff Kirsher }
3479aa32835SJeff Kirsher
3489aa32835SJeff Kirsher if (hret != H_SUCCESS) {
3499aa32835SJeff Kirsher pr_err("destroy EQ failed\n");
3509aa32835SJeff Kirsher return -EIO;
3519aa32835SJeff Kirsher }
3529aa32835SJeff Kirsher
3539aa32835SJeff Kirsher return 0;
3549aa32835SJeff Kirsher }
3559aa32835SJeff Kirsher
3561aa8b471SBen Hutchings /* allocates memory for a queue and registers pages in phyp */
ehea_qp_alloc_register(struct ehea_qp * qp,struct hw_queue * hw_queue,int nr_pages,int wqe_size,int act_nr_sges,struct ehea_adapter * adapter,int h_call_q_selector)3571886e5d2SThadeu Lima de Souza Cascardo static int ehea_qp_alloc_register(struct ehea_qp *qp, struct hw_queue *hw_queue,
3589aa32835SJeff Kirsher int nr_pages, int wqe_size, int act_nr_sges,
3599aa32835SJeff Kirsher struct ehea_adapter *adapter, int h_call_q_selector)
3609aa32835SJeff Kirsher {
3619aa32835SJeff Kirsher u64 hret, rpage;
3629aa32835SJeff Kirsher int ret, cnt;
3639aa32835SJeff Kirsher void *vpage;
3649aa32835SJeff Kirsher
3659aa32835SJeff Kirsher ret = hw_queue_ctor(hw_queue, nr_pages, EHEA_PAGESIZE, wqe_size);
3669aa32835SJeff Kirsher if (ret)
3679aa32835SJeff Kirsher return ret;
3689aa32835SJeff Kirsher
3699aa32835SJeff Kirsher for (cnt = 0; cnt < nr_pages; cnt++) {
3709aa32835SJeff Kirsher vpage = hw_qpageit_get_inc(hw_queue);
3719aa32835SJeff Kirsher if (!vpage) {
3729aa32835SJeff Kirsher pr_err("hw_qpageit_get_inc failed\n");
3739aa32835SJeff Kirsher goto out_kill_hwq;
3749aa32835SJeff Kirsher }
37567e1dbcbSMichael Ellerman rpage = __pa(vpage);
3769aa32835SJeff Kirsher hret = ehea_h_register_rpage(adapter->handle,
3779aa32835SJeff Kirsher 0, h_call_q_selector,
3789aa32835SJeff Kirsher qp->fw_handle, rpage, 1);
3799aa32835SJeff Kirsher if (hret < H_SUCCESS) {
3809aa32835SJeff Kirsher pr_err("register_rpage_qp failed\n");
3819aa32835SJeff Kirsher goto out_kill_hwq;
3829aa32835SJeff Kirsher }
3839aa32835SJeff Kirsher }
3849aa32835SJeff Kirsher hw_qeit_reset(hw_queue);
3859aa32835SJeff Kirsher return 0;
3869aa32835SJeff Kirsher
3879aa32835SJeff Kirsher out_kill_hwq:
3889aa32835SJeff Kirsher hw_queue_dtor(hw_queue);
3899aa32835SJeff Kirsher return -EIO;
3909aa32835SJeff Kirsher }
3919aa32835SJeff Kirsher
map_wqe_size(u8 wqe_enc_size)3929aa32835SJeff Kirsher static inline u32 map_wqe_size(u8 wqe_enc_size)
3939aa32835SJeff Kirsher {
3949aa32835SJeff Kirsher return 128 << wqe_enc_size;
3959aa32835SJeff Kirsher }
3969aa32835SJeff Kirsher
ehea_create_qp(struct ehea_adapter * adapter,u32 pd,struct ehea_qp_init_attr * init_attr)3979aa32835SJeff Kirsher struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter,
3989aa32835SJeff Kirsher u32 pd, struct ehea_qp_init_attr *init_attr)
3999aa32835SJeff Kirsher {
4009aa32835SJeff Kirsher int ret;
4019aa32835SJeff Kirsher u64 hret;
4029aa32835SJeff Kirsher struct ehea_qp *qp;
4039aa32835SJeff Kirsher u32 wqe_size_in_bytes_sq, wqe_size_in_bytes_rq1;
4049aa32835SJeff Kirsher u32 wqe_size_in_bytes_rq2, wqe_size_in_bytes_rq3;
4059aa32835SJeff Kirsher
4069aa32835SJeff Kirsher
4079aa32835SJeff Kirsher qp = kzalloc(sizeof(*qp), GFP_KERNEL);
408b2adaca9SJoe Perches if (!qp)
4099aa32835SJeff Kirsher return NULL;
4109aa32835SJeff Kirsher
4119aa32835SJeff Kirsher qp->adapter = adapter;
4129aa32835SJeff Kirsher
4139aa32835SJeff Kirsher hret = ehea_h_alloc_resource_qp(adapter->handle, init_attr, pd,
4149aa32835SJeff Kirsher &qp->fw_handle, &qp->epas);
4159aa32835SJeff Kirsher if (hret != H_SUCCESS) {
4169aa32835SJeff Kirsher pr_err("ehea_h_alloc_resource_qp failed\n");
4179aa32835SJeff Kirsher goto out_freemem;
4189aa32835SJeff Kirsher }
4199aa32835SJeff Kirsher
4209aa32835SJeff Kirsher wqe_size_in_bytes_sq = map_wqe_size(init_attr->act_wqe_size_enc_sq);
4219aa32835SJeff Kirsher wqe_size_in_bytes_rq1 = map_wqe_size(init_attr->act_wqe_size_enc_rq1);
4229aa32835SJeff Kirsher wqe_size_in_bytes_rq2 = map_wqe_size(init_attr->act_wqe_size_enc_rq2);
4239aa32835SJeff Kirsher wqe_size_in_bytes_rq3 = map_wqe_size(init_attr->act_wqe_size_enc_rq3);
4249aa32835SJeff Kirsher
4259aa32835SJeff Kirsher ret = ehea_qp_alloc_register(qp, &qp->hw_squeue, init_attr->nr_sq_pages,
4269aa32835SJeff Kirsher wqe_size_in_bytes_sq,
4279aa32835SJeff Kirsher init_attr->act_wqe_size_enc_sq, adapter,
4289aa32835SJeff Kirsher 0);
4299aa32835SJeff Kirsher if (ret) {
4309aa32835SJeff Kirsher pr_err("can't register for sq ret=%x\n", ret);
4319aa32835SJeff Kirsher goto out_freeres;
4329aa32835SJeff Kirsher }
4339aa32835SJeff Kirsher
4349aa32835SJeff Kirsher ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue1,
4359aa32835SJeff Kirsher init_attr->nr_rq1_pages,
4369aa32835SJeff Kirsher wqe_size_in_bytes_rq1,
4379aa32835SJeff Kirsher init_attr->act_wqe_size_enc_rq1,
4389aa32835SJeff Kirsher adapter, 1);
4399aa32835SJeff Kirsher if (ret) {
4409aa32835SJeff Kirsher pr_err("can't register for rq1 ret=%x\n", ret);
4419aa32835SJeff Kirsher goto out_kill_hwsq;
4429aa32835SJeff Kirsher }
4439aa32835SJeff Kirsher
4449aa32835SJeff Kirsher if (init_attr->rq_count > 1) {
4459aa32835SJeff Kirsher ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue2,
4469aa32835SJeff Kirsher init_attr->nr_rq2_pages,
4479aa32835SJeff Kirsher wqe_size_in_bytes_rq2,
4489aa32835SJeff Kirsher init_attr->act_wqe_size_enc_rq2,
4499aa32835SJeff Kirsher adapter, 2);
4509aa32835SJeff Kirsher if (ret) {
4519aa32835SJeff Kirsher pr_err("can't register for rq2 ret=%x\n", ret);
4529aa32835SJeff Kirsher goto out_kill_hwr1q;
4539aa32835SJeff Kirsher }
4549aa32835SJeff Kirsher }
4559aa32835SJeff Kirsher
4569aa32835SJeff Kirsher if (init_attr->rq_count > 2) {
4579aa32835SJeff Kirsher ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue3,
4589aa32835SJeff Kirsher init_attr->nr_rq3_pages,
4599aa32835SJeff Kirsher wqe_size_in_bytes_rq3,
4609aa32835SJeff Kirsher init_attr->act_wqe_size_enc_rq3,
4619aa32835SJeff Kirsher adapter, 3);
4629aa32835SJeff Kirsher if (ret) {
4639aa32835SJeff Kirsher pr_err("can't register for rq3 ret=%x\n", ret);
4649aa32835SJeff Kirsher goto out_kill_hwr2q;
4659aa32835SJeff Kirsher }
4669aa32835SJeff Kirsher }
4679aa32835SJeff Kirsher
4689aa32835SJeff Kirsher qp->init_attr = *init_attr;
4699aa32835SJeff Kirsher
4709aa32835SJeff Kirsher return qp;
4719aa32835SJeff Kirsher
4729aa32835SJeff Kirsher out_kill_hwr2q:
4739aa32835SJeff Kirsher hw_queue_dtor(&qp->hw_rqueue2);
4749aa32835SJeff Kirsher
4759aa32835SJeff Kirsher out_kill_hwr1q:
4769aa32835SJeff Kirsher hw_queue_dtor(&qp->hw_rqueue1);
4779aa32835SJeff Kirsher
4789aa32835SJeff Kirsher out_kill_hwsq:
4799aa32835SJeff Kirsher hw_queue_dtor(&qp->hw_squeue);
4809aa32835SJeff Kirsher
4819aa32835SJeff Kirsher out_freeres:
4829aa32835SJeff Kirsher ehea_h_disable_and_get_hea(adapter->handle, qp->fw_handle);
4839aa32835SJeff Kirsher ehea_h_free_resource(adapter->handle, qp->fw_handle, FORCE_FREE);
4849aa32835SJeff Kirsher
4859aa32835SJeff Kirsher out_freemem:
4869aa32835SJeff Kirsher kfree(qp);
4879aa32835SJeff Kirsher return NULL;
4889aa32835SJeff Kirsher }
4899aa32835SJeff Kirsher
ehea_destroy_qp_res(struct ehea_qp * qp,u64 force)4901886e5d2SThadeu Lima de Souza Cascardo static u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force)
4919aa32835SJeff Kirsher {
4929aa32835SJeff Kirsher u64 hret;
4939aa32835SJeff Kirsher struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
4949aa32835SJeff Kirsher
4959aa32835SJeff Kirsher
4969aa32835SJeff Kirsher ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
4979aa32835SJeff Kirsher hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle, force);
4989aa32835SJeff Kirsher if (hret != H_SUCCESS)
4999aa32835SJeff Kirsher return hret;
5009aa32835SJeff Kirsher
5019aa32835SJeff Kirsher hw_queue_dtor(&qp->hw_squeue);
5029aa32835SJeff Kirsher hw_queue_dtor(&qp->hw_rqueue1);
5039aa32835SJeff Kirsher
5049aa32835SJeff Kirsher if (qp_attr->rq_count > 1)
5059aa32835SJeff Kirsher hw_queue_dtor(&qp->hw_rqueue2);
5069aa32835SJeff Kirsher if (qp_attr->rq_count > 2)
5079aa32835SJeff Kirsher hw_queue_dtor(&qp->hw_rqueue3);
5089aa32835SJeff Kirsher kfree(qp);
5099aa32835SJeff Kirsher
5109aa32835SJeff Kirsher return hret;
5119aa32835SJeff Kirsher }
5129aa32835SJeff Kirsher
ehea_destroy_qp(struct ehea_qp * qp)5139aa32835SJeff Kirsher int ehea_destroy_qp(struct ehea_qp *qp)
5149aa32835SJeff Kirsher {
5159aa32835SJeff Kirsher u64 hret, aer, aerr;
5169aa32835SJeff Kirsher if (!qp)
5179aa32835SJeff Kirsher return 0;
5189aa32835SJeff Kirsher
5199aa32835SJeff Kirsher hcp_epas_dtor(&qp->epas);
5209aa32835SJeff Kirsher
5219aa32835SJeff Kirsher hret = ehea_destroy_qp_res(qp, NORMAL_FREE);
5229aa32835SJeff Kirsher if (hret == H_R_STATE) {
5239aa32835SJeff Kirsher ehea_error_data(qp->adapter, qp->fw_handle, &aer, &aerr);
5249aa32835SJeff Kirsher hret = ehea_destroy_qp_res(qp, FORCE_FREE);
5259aa32835SJeff Kirsher }
5269aa32835SJeff Kirsher
5279aa32835SJeff Kirsher if (hret != H_SUCCESS) {
5289aa32835SJeff Kirsher pr_err("destroy QP failed\n");
5299aa32835SJeff Kirsher return -EIO;
5309aa32835SJeff Kirsher }
5319aa32835SJeff Kirsher
5329aa32835SJeff Kirsher return 0;
5339aa32835SJeff Kirsher }
5349aa32835SJeff Kirsher
ehea_calc_index(unsigned long i,unsigned long s)5359aa32835SJeff Kirsher static inline int ehea_calc_index(unsigned long i, unsigned long s)
5369aa32835SJeff Kirsher {
5379aa32835SJeff Kirsher return (i >> s) & EHEA_INDEX_MASK;
5389aa32835SJeff Kirsher }
5399aa32835SJeff Kirsher
ehea_init_top_bmap(struct ehea_top_bmap * ehea_top_bmap,int dir)5409aa32835SJeff Kirsher static inline int ehea_init_top_bmap(struct ehea_top_bmap *ehea_top_bmap,
5419aa32835SJeff Kirsher int dir)
5429aa32835SJeff Kirsher {
5439aa32835SJeff Kirsher if (!ehea_top_bmap->dir[dir]) {
5449aa32835SJeff Kirsher ehea_top_bmap->dir[dir] =
5459aa32835SJeff Kirsher kzalloc(sizeof(struct ehea_dir_bmap), GFP_KERNEL);
5469aa32835SJeff Kirsher if (!ehea_top_bmap->dir[dir])
5479aa32835SJeff Kirsher return -ENOMEM;
5489aa32835SJeff Kirsher }
5499aa32835SJeff Kirsher return 0;
5509aa32835SJeff Kirsher }
5519aa32835SJeff Kirsher
ehea_init_bmap(struct ehea_bmap * ehea_bmap,int top,int dir)5529aa32835SJeff Kirsher static inline int ehea_init_bmap(struct ehea_bmap *ehea_bmap, int top, int dir)
5539aa32835SJeff Kirsher {
5549aa32835SJeff Kirsher if (!ehea_bmap->top[top]) {
5559aa32835SJeff Kirsher ehea_bmap->top[top] =
5569aa32835SJeff Kirsher kzalloc(sizeof(struct ehea_top_bmap), GFP_KERNEL);
5579aa32835SJeff Kirsher if (!ehea_bmap->top[top])
5589aa32835SJeff Kirsher return -ENOMEM;
5599aa32835SJeff Kirsher }
5609aa32835SJeff Kirsher return ehea_init_top_bmap(ehea_bmap->top[top], dir);
5619aa32835SJeff Kirsher }
5629aa32835SJeff Kirsher
5639aa32835SJeff Kirsher static DEFINE_MUTEX(ehea_busmap_mutex);
5649aa32835SJeff Kirsher static unsigned long ehea_mr_len;
5659aa32835SJeff Kirsher
5669aa32835SJeff Kirsher #define EHEA_BUSMAP_ADD_SECT 1
5679aa32835SJeff Kirsher #define EHEA_BUSMAP_REM_SECT 0
5689aa32835SJeff Kirsher
ehea_rebuild_busmap(void)5699aa32835SJeff Kirsher static void ehea_rebuild_busmap(void)
5709aa32835SJeff Kirsher {
5719aa32835SJeff Kirsher u64 vaddr = EHEA_BUSMAP_START;
5729aa32835SJeff Kirsher int top, dir, idx;
5739aa32835SJeff Kirsher
5749aa32835SJeff Kirsher for (top = 0; top < EHEA_MAP_ENTRIES; top++) {
5759aa32835SJeff Kirsher struct ehea_top_bmap *ehea_top;
5769aa32835SJeff Kirsher int valid_dir_entries = 0;
5779aa32835SJeff Kirsher
5789aa32835SJeff Kirsher if (!ehea_bmap->top[top])
5799aa32835SJeff Kirsher continue;
5809aa32835SJeff Kirsher ehea_top = ehea_bmap->top[top];
5819aa32835SJeff Kirsher for (dir = 0; dir < EHEA_MAP_ENTRIES; dir++) {
5829aa32835SJeff Kirsher struct ehea_dir_bmap *ehea_dir;
5839aa32835SJeff Kirsher int valid_entries = 0;
5849aa32835SJeff Kirsher
5859aa32835SJeff Kirsher if (!ehea_top->dir[dir])
5869aa32835SJeff Kirsher continue;
5879aa32835SJeff Kirsher valid_dir_entries++;
5889aa32835SJeff Kirsher ehea_dir = ehea_top->dir[dir];
5899aa32835SJeff Kirsher for (idx = 0; idx < EHEA_MAP_ENTRIES; idx++) {
5909aa32835SJeff Kirsher if (!ehea_dir->ent[idx])
5919aa32835SJeff Kirsher continue;
5929aa32835SJeff Kirsher valid_entries++;
5939aa32835SJeff Kirsher ehea_dir->ent[idx] = vaddr;
5949aa32835SJeff Kirsher vaddr += EHEA_SECTSIZE;
5959aa32835SJeff Kirsher }
5969aa32835SJeff Kirsher if (!valid_entries) {
5979aa32835SJeff Kirsher ehea_top->dir[dir] = NULL;
5989aa32835SJeff Kirsher kfree(ehea_dir);
5999aa32835SJeff Kirsher }
6009aa32835SJeff Kirsher }
6019aa32835SJeff Kirsher if (!valid_dir_entries) {
6029aa32835SJeff Kirsher ehea_bmap->top[top] = NULL;
6039aa32835SJeff Kirsher kfree(ehea_top);
6049aa32835SJeff Kirsher }
6059aa32835SJeff Kirsher }
6069aa32835SJeff Kirsher }
6079aa32835SJeff Kirsher
ehea_update_busmap(unsigned long pfn,unsigned long nr_pages,int add)6089aa32835SJeff Kirsher static int ehea_update_busmap(unsigned long pfn, unsigned long nr_pages, int add)
6099aa32835SJeff Kirsher {
6109aa32835SJeff Kirsher unsigned long i, start_section, end_section;
6119aa32835SJeff Kirsher
6129aa32835SJeff Kirsher if (!nr_pages)
6139aa32835SJeff Kirsher return 0;
6149aa32835SJeff Kirsher
6159aa32835SJeff Kirsher if (!ehea_bmap) {
6169aa32835SJeff Kirsher ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL);
6179aa32835SJeff Kirsher if (!ehea_bmap)
6189aa32835SJeff Kirsher return -ENOMEM;
6199aa32835SJeff Kirsher }
6209aa32835SJeff Kirsher
6219aa32835SJeff Kirsher start_section = (pfn * PAGE_SIZE) / EHEA_SECTSIZE;
6229aa32835SJeff Kirsher end_section = start_section + ((nr_pages * PAGE_SIZE) / EHEA_SECTSIZE);
6239aa32835SJeff Kirsher /* Mark entries as valid or invalid only; address is assigned later */
6249aa32835SJeff Kirsher for (i = start_section; i < end_section; i++) {
6259aa32835SJeff Kirsher u64 flag;
6269aa32835SJeff Kirsher int top = ehea_calc_index(i, EHEA_TOP_INDEX_SHIFT);
6279aa32835SJeff Kirsher int dir = ehea_calc_index(i, EHEA_DIR_INDEX_SHIFT);
6289aa32835SJeff Kirsher int idx = i & EHEA_INDEX_MASK;
6299aa32835SJeff Kirsher
6309aa32835SJeff Kirsher if (add) {
6319aa32835SJeff Kirsher int ret = ehea_init_bmap(ehea_bmap, top, dir);
6329aa32835SJeff Kirsher if (ret)
6339aa32835SJeff Kirsher return ret;
6349aa32835SJeff Kirsher flag = 1; /* valid */
6359aa32835SJeff Kirsher ehea_mr_len += EHEA_SECTSIZE;
6369aa32835SJeff Kirsher } else {
6379aa32835SJeff Kirsher if (!ehea_bmap->top[top])
6389aa32835SJeff Kirsher continue;
6399aa32835SJeff Kirsher if (!ehea_bmap->top[top]->dir[dir])
6409aa32835SJeff Kirsher continue;
6419aa32835SJeff Kirsher flag = 0; /* invalid */
6429aa32835SJeff Kirsher ehea_mr_len -= EHEA_SECTSIZE;
6439aa32835SJeff Kirsher }
6449aa32835SJeff Kirsher
6459aa32835SJeff Kirsher ehea_bmap->top[top]->dir[dir]->ent[idx] = flag;
6469aa32835SJeff Kirsher }
6479aa32835SJeff Kirsher ehea_rebuild_busmap(); /* Assign contiguous addresses for mr */
6489aa32835SJeff Kirsher return 0;
6499aa32835SJeff Kirsher }
6509aa32835SJeff Kirsher
ehea_add_sect_bmap(unsigned long pfn,unsigned long nr_pages)6519aa32835SJeff Kirsher int ehea_add_sect_bmap(unsigned long pfn, unsigned long nr_pages)
6529aa32835SJeff Kirsher {
6539aa32835SJeff Kirsher int ret;
6549aa32835SJeff Kirsher
6559aa32835SJeff Kirsher mutex_lock(&ehea_busmap_mutex);
6569aa32835SJeff Kirsher ret = ehea_update_busmap(pfn, nr_pages, EHEA_BUSMAP_ADD_SECT);
6579aa32835SJeff Kirsher mutex_unlock(&ehea_busmap_mutex);
6589aa32835SJeff Kirsher return ret;
6599aa32835SJeff Kirsher }
6609aa32835SJeff Kirsher
ehea_rem_sect_bmap(unsigned long pfn,unsigned long nr_pages)6619aa32835SJeff Kirsher int ehea_rem_sect_bmap(unsigned long pfn, unsigned long nr_pages)
6629aa32835SJeff Kirsher {
6639aa32835SJeff Kirsher int ret;
6649aa32835SJeff Kirsher
6659aa32835SJeff Kirsher mutex_lock(&ehea_busmap_mutex);
6669aa32835SJeff Kirsher ret = ehea_update_busmap(pfn, nr_pages, EHEA_BUSMAP_REM_SECT);
6679aa32835SJeff Kirsher mutex_unlock(&ehea_busmap_mutex);
6689aa32835SJeff Kirsher return ret;
6699aa32835SJeff Kirsher }
6709aa32835SJeff Kirsher
ehea_is_hugepage(unsigned long pfn)6719aa32835SJeff Kirsher static int ehea_is_hugepage(unsigned long pfn)
6729aa32835SJeff Kirsher {
6739aa32835SJeff Kirsher if (pfn & EHEA_HUGEPAGE_PFN_MASK)
6749aa32835SJeff Kirsher return 0;
6759aa32835SJeff Kirsher
676*9439bb0fSYunfeng Ye if (page_shift(pfn_to_page(pfn)) != EHEA_HUGEPAGESHIFT)
6779aa32835SJeff Kirsher return 0;
6789aa32835SJeff Kirsher
6799aa32835SJeff Kirsher return 1;
6809aa32835SJeff Kirsher }
6819aa32835SJeff Kirsher
ehea_create_busmap_callback(unsigned long initial_pfn,unsigned long total_nr_pages,void * arg)6829aa32835SJeff Kirsher static int ehea_create_busmap_callback(unsigned long initial_pfn,
6839aa32835SJeff Kirsher unsigned long total_nr_pages, void *arg)
6849aa32835SJeff Kirsher {
6859aa32835SJeff Kirsher int ret;
6869aa32835SJeff Kirsher unsigned long pfn, start_pfn, end_pfn, nr_pages;
6879aa32835SJeff Kirsher
6889aa32835SJeff Kirsher if ((total_nr_pages * PAGE_SIZE) < EHEA_HUGEPAGE_SIZE)
6899aa32835SJeff Kirsher return ehea_update_busmap(initial_pfn, total_nr_pages,
6909aa32835SJeff Kirsher EHEA_BUSMAP_ADD_SECT);
6919aa32835SJeff Kirsher
6929aa32835SJeff Kirsher /* Given chunk is >= 16GB -> check for hugepages */
6939aa32835SJeff Kirsher start_pfn = initial_pfn;
6949aa32835SJeff Kirsher end_pfn = initial_pfn + total_nr_pages;
6959aa32835SJeff Kirsher pfn = start_pfn;
6969aa32835SJeff Kirsher
6979aa32835SJeff Kirsher while (pfn < end_pfn) {
6989aa32835SJeff Kirsher if (ehea_is_hugepage(pfn)) {
6999aa32835SJeff Kirsher /* Add mem found in front of the hugepage */
7009aa32835SJeff Kirsher nr_pages = pfn - start_pfn;
7019aa32835SJeff Kirsher ret = ehea_update_busmap(start_pfn, nr_pages,
7029aa32835SJeff Kirsher EHEA_BUSMAP_ADD_SECT);
7039aa32835SJeff Kirsher if (ret)
7049aa32835SJeff Kirsher return ret;
7059aa32835SJeff Kirsher
7069aa32835SJeff Kirsher /* Skip the hugepage */
7079aa32835SJeff Kirsher pfn += (EHEA_HUGEPAGE_SIZE / PAGE_SIZE);
7089aa32835SJeff Kirsher start_pfn = pfn;
7099aa32835SJeff Kirsher } else
7109aa32835SJeff Kirsher pfn += (EHEA_SECTSIZE / PAGE_SIZE);
7119aa32835SJeff Kirsher }
7129aa32835SJeff Kirsher
7139aa32835SJeff Kirsher /* Add mem found behind the hugepage(s) */
7149aa32835SJeff Kirsher nr_pages = pfn - start_pfn;
7159aa32835SJeff Kirsher return ehea_update_busmap(start_pfn, nr_pages, EHEA_BUSMAP_ADD_SECT);
7169aa32835SJeff Kirsher }
7179aa32835SJeff Kirsher
ehea_create_busmap(void)7189aa32835SJeff Kirsher int ehea_create_busmap(void)
7199aa32835SJeff Kirsher {
7209aa32835SJeff Kirsher int ret;
7219aa32835SJeff Kirsher
7229aa32835SJeff Kirsher mutex_lock(&ehea_busmap_mutex);
7239aa32835SJeff Kirsher ehea_mr_len = 0;
7249aa32835SJeff Kirsher ret = walk_system_ram_range(0, 1ULL << MAX_PHYSMEM_BITS, NULL,
7259aa32835SJeff Kirsher ehea_create_busmap_callback);
7269aa32835SJeff Kirsher mutex_unlock(&ehea_busmap_mutex);
7279aa32835SJeff Kirsher return ret;
7289aa32835SJeff Kirsher }
7299aa32835SJeff Kirsher
ehea_destroy_busmap(void)7309aa32835SJeff Kirsher void ehea_destroy_busmap(void)
7319aa32835SJeff Kirsher {
7329aa32835SJeff Kirsher int top, dir;
7339aa32835SJeff Kirsher mutex_lock(&ehea_busmap_mutex);
7349aa32835SJeff Kirsher if (!ehea_bmap)
7359aa32835SJeff Kirsher goto out_destroy;
7369aa32835SJeff Kirsher
7379aa32835SJeff Kirsher for (top = 0; top < EHEA_MAP_ENTRIES; top++) {
7389aa32835SJeff Kirsher if (!ehea_bmap->top[top])
7399aa32835SJeff Kirsher continue;
7409aa32835SJeff Kirsher
7419aa32835SJeff Kirsher for (dir = 0; dir < EHEA_MAP_ENTRIES; dir++) {
7429aa32835SJeff Kirsher if (!ehea_bmap->top[top]->dir[dir])
7439aa32835SJeff Kirsher continue;
7449aa32835SJeff Kirsher
7459aa32835SJeff Kirsher kfree(ehea_bmap->top[top]->dir[dir]);
7469aa32835SJeff Kirsher }
7479aa32835SJeff Kirsher
7489aa32835SJeff Kirsher kfree(ehea_bmap->top[top]);
7499aa32835SJeff Kirsher }
7509aa32835SJeff Kirsher
7519aa32835SJeff Kirsher kfree(ehea_bmap);
7529aa32835SJeff Kirsher ehea_bmap = NULL;
7539aa32835SJeff Kirsher out_destroy:
7549aa32835SJeff Kirsher mutex_unlock(&ehea_busmap_mutex);
7559aa32835SJeff Kirsher }
7569aa32835SJeff Kirsher
ehea_map_vaddr(void * caddr)7579aa32835SJeff Kirsher u64 ehea_map_vaddr(void *caddr)
7589aa32835SJeff Kirsher {
7599aa32835SJeff Kirsher int top, dir, idx;
7609aa32835SJeff Kirsher unsigned long index, offset;
7619aa32835SJeff Kirsher
7629aa32835SJeff Kirsher if (!ehea_bmap)
7639aa32835SJeff Kirsher return EHEA_INVAL_ADDR;
7649aa32835SJeff Kirsher
76567e1dbcbSMichael Ellerman index = __pa(caddr) >> SECTION_SIZE_BITS;
7669aa32835SJeff Kirsher top = (index >> EHEA_TOP_INDEX_SHIFT) & EHEA_INDEX_MASK;
7679aa32835SJeff Kirsher if (!ehea_bmap->top[top])
7689aa32835SJeff Kirsher return EHEA_INVAL_ADDR;
7699aa32835SJeff Kirsher
7709aa32835SJeff Kirsher dir = (index >> EHEA_DIR_INDEX_SHIFT) & EHEA_INDEX_MASK;
7719aa32835SJeff Kirsher if (!ehea_bmap->top[top]->dir[dir])
7729aa32835SJeff Kirsher return EHEA_INVAL_ADDR;
7739aa32835SJeff Kirsher
7749aa32835SJeff Kirsher idx = index & EHEA_INDEX_MASK;
7759aa32835SJeff Kirsher if (!ehea_bmap->top[top]->dir[dir]->ent[idx])
7769aa32835SJeff Kirsher return EHEA_INVAL_ADDR;
7779aa32835SJeff Kirsher
7789aa32835SJeff Kirsher offset = (unsigned long)caddr & (EHEA_SECTSIZE - 1);
7799aa32835SJeff Kirsher return ehea_bmap->top[top]->dir[dir]->ent[idx] | offset;
7809aa32835SJeff Kirsher }
7819aa32835SJeff Kirsher
ehea_calc_sectbase(int top,int dir,int idx)7829aa32835SJeff Kirsher static inline void *ehea_calc_sectbase(int top, int dir, int idx)
7839aa32835SJeff Kirsher {
7849aa32835SJeff Kirsher unsigned long ret = idx;
7859aa32835SJeff Kirsher ret |= dir << EHEA_DIR_INDEX_SHIFT;
7869aa32835SJeff Kirsher ret |= top << EHEA_TOP_INDEX_SHIFT;
78767e1dbcbSMichael Ellerman return __va(ret << SECTION_SIZE_BITS);
7889aa32835SJeff Kirsher }
7899aa32835SJeff Kirsher
ehea_reg_mr_section(int top,int dir,int idx,u64 * pt,struct ehea_adapter * adapter,struct ehea_mr * mr)7909aa32835SJeff Kirsher static u64 ehea_reg_mr_section(int top, int dir, int idx, u64 *pt,
7919aa32835SJeff Kirsher struct ehea_adapter *adapter,
7929aa32835SJeff Kirsher struct ehea_mr *mr)
7939aa32835SJeff Kirsher {
7949aa32835SJeff Kirsher void *pg;
7959aa32835SJeff Kirsher u64 j, m, hret;
7969aa32835SJeff Kirsher unsigned long k = 0;
79767e1dbcbSMichael Ellerman u64 pt_abs = __pa(pt);
7989aa32835SJeff Kirsher
7999aa32835SJeff Kirsher void *sectbase = ehea_calc_sectbase(top, dir, idx);
8009aa32835SJeff Kirsher
8019aa32835SJeff Kirsher for (j = 0; j < (EHEA_PAGES_PER_SECTION / EHEA_MAX_RPAGE); j++) {
8029aa32835SJeff Kirsher
8039aa32835SJeff Kirsher for (m = 0; m < EHEA_MAX_RPAGE; m++) {
8049aa32835SJeff Kirsher pg = sectbase + ((k++) * EHEA_PAGESIZE);
80567e1dbcbSMichael Ellerman pt[m] = __pa(pg);
8069aa32835SJeff Kirsher }
8079aa32835SJeff Kirsher hret = ehea_h_register_rpage_mr(adapter->handle, mr->handle, 0,
8089aa32835SJeff Kirsher 0, pt_abs, EHEA_MAX_RPAGE);
8099aa32835SJeff Kirsher
8109aa32835SJeff Kirsher if ((hret != H_SUCCESS) &&
8119aa32835SJeff Kirsher (hret != H_PAGE_REGISTERED)) {
8129aa32835SJeff Kirsher ehea_h_free_resource(adapter->handle, mr->handle,
8139aa32835SJeff Kirsher FORCE_FREE);
8149aa32835SJeff Kirsher pr_err("register_rpage_mr failed\n");
8159aa32835SJeff Kirsher return hret;
8169aa32835SJeff Kirsher }
8179aa32835SJeff Kirsher }
8189aa32835SJeff Kirsher return hret;
8199aa32835SJeff Kirsher }
8209aa32835SJeff Kirsher
ehea_reg_mr_sections(int top,int dir,u64 * pt,struct ehea_adapter * adapter,struct ehea_mr * mr)8219aa32835SJeff Kirsher static u64 ehea_reg_mr_sections(int top, int dir, u64 *pt,
8229aa32835SJeff Kirsher struct ehea_adapter *adapter,
8239aa32835SJeff Kirsher struct ehea_mr *mr)
8249aa32835SJeff Kirsher {
8259aa32835SJeff Kirsher u64 hret = H_SUCCESS;
8269aa32835SJeff Kirsher int idx;
8279aa32835SJeff Kirsher
8289aa32835SJeff Kirsher for (idx = 0; idx < EHEA_MAP_ENTRIES; idx++) {
8299aa32835SJeff Kirsher if (!ehea_bmap->top[top]->dir[dir]->ent[idx])
8309aa32835SJeff Kirsher continue;
8319aa32835SJeff Kirsher
8329aa32835SJeff Kirsher hret = ehea_reg_mr_section(top, dir, idx, pt, adapter, mr);
8339aa32835SJeff Kirsher if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
8349aa32835SJeff Kirsher return hret;
8359aa32835SJeff Kirsher }
8369aa32835SJeff Kirsher return hret;
8379aa32835SJeff Kirsher }
8389aa32835SJeff Kirsher
ehea_reg_mr_dir_sections(int top,u64 * pt,struct ehea_adapter * adapter,struct ehea_mr * mr)8399aa32835SJeff Kirsher static u64 ehea_reg_mr_dir_sections(int top, u64 *pt,
8409aa32835SJeff Kirsher struct ehea_adapter *adapter,
8419aa32835SJeff Kirsher struct ehea_mr *mr)
8429aa32835SJeff Kirsher {
8439aa32835SJeff Kirsher u64 hret = H_SUCCESS;
8449aa32835SJeff Kirsher int dir;
8459aa32835SJeff Kirsher
8469aa32835SJeff Kirsher for (dir = 0; dir < EHEA_MAP_ENTRIES; dir++) {
8479aa32835SJeff Kirsher if (!ehea_bmap->top[top]->dir[dir])
8489aa32835SJeff Kirsher continue;
8499aa32835SJeff Kirsher
8509aa32835SJeff Kirsher hret = ehea_reg_mr_sections(top, dir, pt, adapter, mr);
8519aa32835SJeff Kirsher if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
8529aa32835SJeff Kirsher return hret;
8539aa32835SJeff Kirsher }
8549aa32835SJeff Kirsher return hret;
8559aa32835SJeff Kirsher }
8569aa32835SJeff Kirsher
ehea_reg_kernel_mr(struct ehea_adapter * adapter,struct ehea_mr * mr)8579aa32835SJeff Kirsher int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
8589aa32835SJeff Kirsher {
8599aa32835SJeff Kirsher int ret;
8609aa32835SJeff Kirsher u64 *pt;
8619aa32835SJeff Kirsher u64 hret;
8629aa32835SJeff Kirsher u32 acc_ctrl = EHEA_MR_ACC_CTRL;
8639aa32835SJeff Kirsher
8649aa32835SJeff Kirsher unsigned long top;
8659aa32835SJeff Kirsher
8669aa32835SJeff Kirsher pt = (void *)get_zeroed_page(GFP_KERNEL);
8679aa32835SJeff Kirsher if (!pt) {
8689aa32835SJeff Kirsher pr_err("no mem\n");
8699aa32835SJeff Kirsher ret = -ENOMEM;
8709aa32835SJeff Kirsher goto out;
8719aa32835SJeff Kirsher }
8729aa32835SJeff Kirsher
8739aa32835SJeff Kirsher hret = ehea_h_alloc_resource_mr(adapter->handle, EHEA_BUSMAP_START,
8749aa32835SJeff Kirsher ehea_mr_len, acc_ctrl, adapter->pd,
8759aa32835SJeff Kirsher &mr->handle, &mr->lkey);
8769aa32835SJeff Kirsher
8779aa32835SJeff Kirsher if (hret != H_SUCCESS) {
8789aa32835SJeff Kirsher pr_err("alloc_resource_mr failed\n");
8799aa32835SJeff Kirsher ret = -EIO;
8809aa32835SJeff Kirsher goto out;
8819aa32835SJeff Kirsher }
8829aa32835SJeff Kirsher
8839aa32835SJeff Kirsher if (!ehea_bmap) {
8849aa32835SJeff Kirsher ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE);
8859aa32835SJeff Kirsher pr_err("no busmap available\n");
8869aa32835SJeff Kirsher ret = -EIO;
8879aa32835SJeff Kirsher goto out;
8889aa32835SJeff Kirsher }
8899aa32835SJeff Kirsher
8909aa32835SJeff Kirsher for (top = 0; top < EHEA_MAP_ENTRIES; top++) {
8919aa32835SJeff Kirsher if (!ehea_bmap->top[top])
8929aa32835SJeff Kirsher continue;
8939aa32835SJeff Kirsher
8949aa32835SJeff Kirsher hret = ehea_reg_mr_dir_sections(top, pt, adapter, mr);
8959aa32835SJeff Kirsher if((hret != H_PAGE_REGISTERED) && (hret != H_SUCCESS))
8969aa32835SJeff Kirsher break;
8979aa32835SJeff Kirsher }
8989aa32835SJeff Kirsher
8999aa32835SJeff Kirsher if (hret != H_SUCCESS) {
9009aa32835SJeff Kirsher ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE);
9019aa32835SJeff Kirsher pr_err("registering mr failed\n");
9029aa32835SJeff Kirsher ret = -EIO;
9039aa32835SJeff Kirsher goto out;
9049aa32835SJeff Kirsher }
9059aa32835SJeff Kirsher
9069aa32835SJeff Kirsher mr->vaddr = EHEA_BUSMAP_START;
9079aa32835SJeff Kirsher mr->adapter = adapter;
9089aa32835SJeff Kirsher ret = 0;
9099aa32835SJeff Kirsher out:
9109aa32835SJeff Kirsher free_page((unsigned long)pt);
9119aa32835SJeff Kirsher return ret;
9129aa32835SJeff Kirsher }
9139aa32835SJeff Kirsher
ehea_rem_mr(struct ehea_mr * mr)9149aa32835SJeff Kirsher int ehea_rem_mr(struct ehea_mr *mr)
9159aa32835SJeff Kirsher {
9169aa32835SJeff Kirsher u64 hret;
9179aa32835SJeff Kirsher
9189aa32835SJeff Kirsher if (!mr || !mr->adapter)
9199aa32835SJeff Kirsher return -EINVAL;
9209aa32835SJeff Kirsher
9219aa32835SJeff Kirsher hret = ehea_h_free_resource(mr->adapter->handle, mr->handle,
9229aa32835SJeff Kirsher FORCE_FREE);
9239aa32835SJeff Kirsher if (hret != H_SUCCESS) {
9249aa32835SJeff Kirsher pr_err("destroy MR failed\n");
9259aa32835SJeff Kirsher return -EIO;
9269aa32835SJeff Kirsher }
9279aa32835SJeff Kirsher
9289aa32835SJeff Kirsher return 0;
9299aa32835SJeff Kirsher }
9309aa32835SJeff Kirsher
ehea_gen_smr(struct ehea_adapter * adapter,struct ehea_mr * old_mr,struct ehea_mr * shared_mr)9319aa32835SJeff Kirsher int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr,
9329aa32835SJeff Kirsher struct ehea_mr *shared_mr)
9339aa32835SJeff Kirsher {
9349aa32835SJeff Kirsher u64 hret;
9359aa32835SJeff Kirsher
9369aa32835SJeff Kirsher hret = ehea_h_register_smr(adapter->handle, old_mr->handle,
9379aa32835SJeff Kirsher old_mr->vaddr, EHEA_MR_ACC_CTRL,
9389aa32835SJeff Kirsher adapter->pd, shared_mr);
9399aa32835SJeff Kirsher if (hret != H_SUCCESS)
9409aa32835SJeff Kirsher return -EIO;
9419aa32835SJeff Kirsher
9429aa32835SJeff Kirsher shared_mr->adapter = adapter;
9439aa32835SJeff Kirsher
9449aa32835SJeff Kirsher return 0;
9459aa32835SJeff Kirsher }
9469aa32835SJeff Kirsher
print_error_data(u64 * data)9471886e5d2SThadeu Lima de Souza Cascardo static void print_error_data(u64 *data)
9489aa32835SJeff Kirsher {
9499aa32835SJeff Kirsher int length;
9509aa32835SJeff Kirsher u64 type = EHEA_BMASK_GET(ERROR_DATA_TYPE, data[2]);
9519aa32835SJeff Kirsher u64 resource = data[1];
9529aa32835SJeff Kirsher
9539aa32835SJeff Kirsher length = EHEA_BMASK_GET(ERROR_DATA_LENGTH, data[0]);
9549aa32835SJeff Kirsher
9559aa32835SJeff Kirsher if (length > EHEA_PAGESIZE)
9569aa32835SJeff Kirsher length = EHEA_PAGESIZE;
9579aa32835SJeff Kirsher
9589aa32835SJeff Kirsher if (type == EHEA_AER_RESTYPE_QP)
9599aa32835SJeff Kirsher pr_err("QP (resource=%llX) state: AER=0x%llX, AERR=0x%llX, port=%llX\n",
9609aa32835SJeff Kirsher resource, data[6], data[12], data[22]);
9619aa32835SJeff Kirsher else if (type == EHEA_AER_RESTYPE_CQ)
9629aa32835SJeff Kirsher pr_err("CQ (resource=%llX) state: AER=0x%llX\n",
9639aa32835SJeff Kirsher resource, data[6]);
9649aa32835SJeff Kirsher else if (type == EHEA_AER_RESTYPE_EQ)
9659aa32835SJeff Kirsher pr_err("EQ (resource=%llX) state: AER=0x%llX\n",
9669aa32835SJeff Kirsher resource, data[6]);
9679aa32835SJeff Kirsher
9689aa32835SJeff Kirsher ehea_dump(data, length, "error data");
9699aa32835SJeff Kirsher }
9709aa32835SJeff Kirsher
ehea_error_data(struct ehea_adapter * adapter,u64 res_handle,u64 * aer,u64 * aerr)9719aa32835SJeff Kirsher u64 ehea_error_data(struct ehea_adapter *adapter, u64 res_handle,
9729aa32835SJeff Kirsher u64 *aer, u64 *aerr)
9739aa32835SJeff Kirsher {
9749aa32835SJeff Kirsher unsigned long ret;
9759aa32835SJeff Kirsher u64 *rblock;
9769aa32835SJeff Kirsher u64 type = 0;
9779aa32835SJeff Kirsher
9789aa32835SJeff Kirsher rblock = (void *)get_zeroed_page(GFP_KERNEL);
9799aa32835SJeff Kirsher if (!rblock) {
9809aa32835SJeff Kirsher pr_err("Cannot allocate rblock memory\n");
9819aa32835SJeff Kirsher goto out;
9829aa32835SJeff Kirsher }
9839aa32835SJeff Kirsher
9849aa32835SJeff Kirsher ret = ehea_h_error_data(adapter->handle, res_handle, rblock);
9859aa32835SJeff Kirsher
9869aa32835SJeff Kirsher if (ret == H_SUCCESS) {
9879aa32835SJeff Kirsher type = EHEA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]);
9889aa32835SJeff Kirsher *aer = rblock[6];
9899aa32835SJeff Kirsher *aerr = rblock[12];
9909aa32835SJeff Kirsher print_error_data(rblock);
9919aa32835SJeff Kirsher } else if (ret == H_R_STATE) {
9929aa32835SJeff Kirsher pr_err("No error data available: %llX\n", res_handle);
9939aa32835SJeff Kirsher } else
9949aa32835SJeff Kirsher pr_err("Error data could not be fetched: %llX\n", res_handle);
9959aa32835SJeff Kirsher
9969aa32835SJeff Kirsher free_page((unsigned long)rblock);
9979aa32835SJeff Kirsher out:
9989aa32835SJeff Kirsher return type;
9999aa32835SJeff Kirsher }
1000