Path: blob/master/drivers/infiniband/hw/ehca/ipz_pt_fn.h
15112 views
/*1* IBM eServer eHCA Infiniband device driver for Linux on POWER2*3* internal queue handling4*5* Authors: Waleri Fomin <[email protected]>6* Reinhard Ernst <[email protected]>7* Christoph Raisch <[email protected]>8*9* Copyright (c) 2005 IBM Corporation10*11* All rights reserved.12*13* This source code is distributed under a dual license of GPL v2.0 and OpenIB14* BSD.15*16* OpenIB BSD License17*18* Redistribution and use in source and binary forms, with or without19* modification, are permitted provided that the following conditions are met:20*21* Redistributions of source code must retain the above copyright notice, this22* list of conditions and the following disclaimer.23*24* Redistributions in binary form must reproduce the above copyright notice,25* this list of conditions and the following disclaimer in the documentation26* and/or other materials27* provided with the distribution.28*29* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"30* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE31* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE32* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE33* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR34* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF35* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR36* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER37* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)38* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE39* POSSIBILITY OF SUCH DAMAGE.40*/4142#ifndef __IPZ_PT_FN_H__43#define __IPZ_PT_FN_H__4445#define EHCA_PAGESHIFT 1246#define EHCA_PAGESIZE 4096UL47#define EHCA_PAGEMASK (~(EHCA_PAGESIZE-1))48#define EHCA_PT_ENTRIES 512UL4950#include "ehca_tools.h"51#include "ehca_qes.h"5253struct ehca_pd;54struct ipz_small_queue_page;5556extern struct kmem_cache *small_qp_cache;5758/* struct generic ehca page */59struct ipz_page {60u8 entries[EHCA_PAGESIZE];61};6263#define IPZ_SPAGE_PER_KPAGE (PAGE_SIZE / 512)6465struct ipz_small_queue_page {66unsigned long page;67unsigned long bitmap[IPZ_SPAGE_PER_KPAGE / BITS_PER_LONG];68int fill;69void *mapped_addr;70u32 mmap_count;71struct list_head list;72};7374/* struct generic queue in linux kernel virtual memory (kv) */75struct ipz_queue {76u64 current_q_offset; /* current queue entry */7778struct ipz_page **queue_pages; /* array of pages belonging to queue */79u32 qe_size; /* queue entry size */80u32 act_nr_of_sg;81u32 queue_length; /* queue length allocated in bytes */82u32 pagesize;83u32 toggle_state; /* toggle flag - per page */84u32 offset; /* save offset within page for small_qp */85struct ipz_small_queue_page *small_page;86};8788/*89* return current Queue Entry for a certain q_offset90* returns address (kv) of Queue Entry91*/92static inline void *ipz_qeit_calc(struct ipz_queue *queue, u64 q_offset)93{94struct ipz_page *current_page;95if (q_offset >= queue->queue_length)96return NULL;97current_page = (queue->queue_pages)[q_offset >> EHCA_PAGESHIFT];98return ¤t_page->entries[q_offset & (EHCA_PAGESIZE - 1)];99}100101/*102* return current Queue Entry103* returns address (kv) of Queue Entry104*/105static inline void *ipz_qeit_get(struct ipz_queue *queue)106{107return ipz_qeit_calc(queue, queue->current_q_offset);108}109110/*111* return current Queue Page , increment Queue Page iterator from112* page to page in struct ipz_queue, last increment will return 0! and113* NOT wrap114* returns address (kv) of Queue Page115* warning don't use in parallel with ipz_QE_get_inc()116*/117void *ipz_qpageit_get_inc(struct ipz_queue *queue);118119/*120* return current Queue Entry, increment Queue Entry iterator by one121* step in struct ipz_queue, will wrap in ringbuffer122* returns address (kv) of Queue Entry BEFORE increment123* warning don't use in parallel with ipz_qpageit_get_inc()124*/125static inline void *ipz_qeit_get_inc(struct ipz_queue *queue)126{127void *ret = ipz_qeit_get(queue);128queue->current_q_offset += queue->qe_size;129if (queue->current_q_offset >= queue->queue_length) {130queue->current_q_offset = 0;131/* toggle the valid flag */132queue->toggle_state = (~queue->toggle_state) & 1;133}134135return ret;136}137138/*139* return a bool indicating whether current Queue Entry is valid140*/141static inline int ipz_qeit_is_valid(struct ipz_queue *queue)142{143struct ehca_cqe *cqe = ipz_qeit_get(queue);144return ((cqe->cqe_flags >> 7) == (queue->toggle_state & 1));145}146147/*148* return current Queue Entry, increment Queue Entry iterator by one149* step in struct ipz_queue, will wrap in ringbuffer150* returns address (kv) of Queue Entry BEFORE increment151* returns 0 and does not increment, if wrong valid state152* warning don't use in parallel with ipz_qpageit_get_inc()153*/154static inline void *ipz_qeit_get_inc_valid(struct ipz_queue *queue)155{156return ipz_qeit_is_valid(queue) ? ipz_qeit_get_inc(queue) : NULL;157}158159/*160* returns and resets Queue Entry iterator161* returns address (kv) of first Queue Entry162*/163static inline void *ipz_qeit_reset(struct ipz_queue *queue)164{165queue->current_q_offset = 0;166return ipz_qeit_get(queue);167}168169/*170* return the q_offset corresponding to an absolute address171*/172int ipz_queue_abs_to_offset(struct ipz_queue *queue, u64 addr, u64 *q_offset);173174/*175* return the next queue offset. don't modify the queue.176*/177static inline u64 ipz_queue_advance_offset(struct ipz_queue *queue, u64 offset)178{179offset += queue->qe_size;180if (offset >= queue->queue_length) offset = 0;181return offset;182}183184/* struct generic page table */185struct ipz_pt {186u64 entries[EHCA_PT_ENTRIES];187};188189/* struct page table for a queue, only to be used in pf */190struct ipz_qpt {191/* queue page tables (kv), use u64 because we know the element length */192u64 *qpts;193u32 n_qpts;194u32 n_ptes; /* number of page table entries */195u64 *current_pte_addr;196};197198/*199* constructor for a ipz_queue_t, placement new for ipz_queue_t,200* new for all dependent datastructors201* all QP Tables are the same202* flow:203* allocate+pin queue204* see ipz_qpt_ctor()205* returns true if ok, false if out of memory206*/207int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue,208const u32 nr_of_pages, const u32 pagesize,209const u32 qe_size, const u32 nr_of_sg,210int is_small);211212/*213* destructor for a ipz_queue_t214* -# free queue215* see ipz_queue_ctor()216* returns true if ok, false if queue was NULL-ptr of free failed217*/218int ipz_queue_dtor(struct ehca_pd *pd, struct ipz_queue *queue);219220/*221* constructor for a ipz_qpt_t,222* placement new for struct ipz_queue, new for all dependent datastructors223* all QP Tables are the same,224* flow:225* -# allocate+pin queue226* -# initialise ptcb227* -# allocate+pin PTs228* -# link PTs to a ring, according to HCA Arch, set bit62 id needed229* -# the ring must have room for exactly nr_of_PTEs230* see ipz_qpt_ctor()231*/232void ipz_qpt_ctor(struct ipz_qpt *qpt,233const u32 nr_of_qes,234const u32 pagesize,235const u32 qe_size,236const u8 lowbyte, const u8 toggle,237u32 * act_nr_of_QEs, u32 * act_nr_of_pages);238239/*240* return current Queue Entry, increment Queue Entry iterator by one241* step in struct ipz_queue, will wrap in ringbuffer242* returns address (kv) of Queue Entry BEFORE increment243* warning don't use in parallel with ipz_qpageit_get_inc()244* warning unpredictable results may occur if steps>act_nr_of_queue_entries245* fix EQ page problems246*/247void *ipz_qeit_eq_get_inc(struct ipz_queue *queue);248249/*250* return current Event Queue Entry, increment Queue Entry iterator251* by one step in struct ipz_queue if valid, will wrap in ringbuffer252* returns address (kv) of Queue Entry BEFORE increment253* returns 0 and does not increment, if wrong valid state254* warning don't use in parallel with ipz_queue_QPageit_get_inc()255* warning unpredictable results may occur if steps>act_nr_of_queue_entries256*/257static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)258{259void *ret = ipz_qeit_get(queue);260u32 qe = *(u8 *)ret;261if ((qe >> 7) != (queue->toggle_state & 1))262return NULL;263ipz_qeit_eq_get_inc(queue); /* this is a good one */264return ret;265}266267static inline void *ipz_eqit_eq_peek_valid(struct ipz_queue *queue)268{269void *ret = ipz_qeit_get(queue);270u32 qe = *(u8 *)ret;271if ((qe >> 7) != (queue->toggle_state & 1))272return NULL;273return ret;274}275276/* returns address (GX) of first queue entry */277static inline u64 ipz_qpt_get_firstpage(struct ipz_qpt *qpt)278{279return be64_to_cpu(qpt->qpts[0]);280}281282/* returns address (kv) of first page of queue page table */283static inline void *ipz_qpt_get_qpt(struct ipz_qpt *qpt)284{285return qpt->qpts;286}287288#endif /* __IPZ_PT_FN_H__ */289290291