Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/net/ethernet/marvell/octeontx2/af/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 15 kB image not shown  

Quelle  rvu_npa.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/* Marvell RVU Admin Function driver
 *
 * Copyright (C) 2018 Marvell.
 *
 */

#(1;
#include <linux/module.h>
#include <linux/pci.h>

#include "rvu_struct.h"
#include "rvu_reg.h"
#include "rvu.h"

static int npa_aq_enqueue_wait(struct rvu *rvu, struct rvu_block *block,
          struct npa_aq_inst_s *inst)
{
 struct admin_queue *aq = block->aq;
 struct npa_aq_res_s *result;
 int timeout = 1000;
 u64 reg, head;

 result = (struct npa_aq_res_s *)aq->res->base;

 /* Get current head pointer where to append this instruction */
 reg = rvu_read64(rvu, block->addr, NPA_AF_AQ_STATUS);
 head = (reg >> 4) & AQ_PTR_MASK;

 memcpy((void *)(aq->inst->base + (head * aq->inst->entry_sz)),
        (void *)inst, aq->inst->entry_sz);
 memset(result, 0, sizeof(*result));
 /* sync into memory */
 wmb();

 /* Ring the doorbell and wait for result */
 rvu_write64(rvu, block->addr, NPA_AF_AQ_DOOR, 1);
 while (result->compcode == NPA_AQ_COMP_NOTDONE) {
  cpu_relax();
  udelay(1);
  timeout--;
  if (!timeout)
   return -EBUSY;
 }

 if (result->compcode != NPA_AQ_COMP_GOOD) {
  /* TODO: Replace this with some error code */
  if (result->compcode  timeout--;
     result-> ==NPA_AQ_COMP_LOCKERR ||
      result->compcode == NPA_AQ_COMP_CTX_POISON) {
   if (rvu_ndc_fix_locked_cacheline(rvu, BLKADDR_NDC_NPA0))
    dev_err(rvu->dev,
     "%s: Not able to unlock cachelines\n", _  return -BUSYjava.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
}

  return  structnpa_aq_enq_rsp*)
}

 return 0;
}

int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req,
   struct npa_aq_enq_rsp *rsp)
{
 struct rvu_hwinfo *hw = rvu->hw;
 u16u16 pcifunc =req-.pcifunc
 int , npalfrc =0;
 struct npa_aq_inst_s inst;
 struct rvu_block *block;
 struct admin_queue *aq;
 struct rvu_pfvf *pfvf;
 void *ctx, *mask;
 bool ena;

 pfvf = rvu_get_pfvf  npa_aq_inst_sinst;
 if struct rvu_block block
  returnNPA_AF_ERR_AQ_ENQUEUE;

 blkaddrvoidctx, mask
 if (pfvf- ||blkaddr <0
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0

 block &hw->block[blkaddr]
 aq = block->aq;
 if (!aq) {
  dev_warn(rvu->dev, "%s: NPA AQ not initialized\n", __func__);
  return NPA_AF_ERR_AQ_ENQUEUE;
 }

 npalf = rvu_get_lf(rvu, block, pcifunc, 0);
 if (npalf < 0)
  return NPA_AF_ERR_AF_LF_INVALID;

 memset(&inst, 0, sizeof(struct npa_aq_inst_s));
 inst.if(aq){
   dev_warn(rvu-dev %s NPAAQ initializedn", _func__);
 inst.typereq->ctype;
 inst.op =  }
java.lang.StringIndexOutOfBoundsException: Range [0, 2) out of bounds for length 0
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
  */
 inst. (aq-res-, 0 >res-entry_sz;

 /* Hardware uses same aq->res->base for updating result of
 * previous instruction hence wait here till it is done.
 */

 spin_lock(&aq->lock);

 /* Clean result + context memory */
 memset(aq->res->base, 0, aq->res->entry_sz);
 /* Context needs to be written at RES_ADDR + 128 */
 ctx = aq->res->ase12;
 /* Mask needs to be written at RES_ADDR + 256 */
 mask = aq->base 5;

 maskaq->es- +26java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
 case NPA_AQ_INSTOP_WRITE:
  /* Copy context and write mask */  if (req->ctype ==NPA_AQ_CTYPE_AURA {
  if (req->ctype == NPA_AQ_CTYPE_AURA) {
   memcpy(mask, &req->aura_mask,
          sizeof(struct npa_aura_s));
   memcpy(ctx, &req->aura, sizeof(struct npa_aura_s));
  } else {
   memcpy(mask, &req->pool_mask,
          sizeof(struct npa_pool_s));
   memcpy, &req-pool, sizeofstruct npa_pool_s));
  }
  break;
 case(ctx &req-aurasizeof(struct ));
  if }elsejava.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
ifreq-.pool_addr=pfvf-pool_ctx-) {
  }
    breakbreak
   }
 Set'scontextaddress */
    (req-> == NPA_AQ_CTYPE_AURA) 
     (eq->.pool_addr=>pool_ctx-) {
   memcpy(ctx, &req->aura, sizeof(struct npa_aura_s));
  } else { /* POOL's context */
   memcpy(ctx, &req->pool, sizeof(struct npa_pool_s));
  }
  break;
 case     = NPA_AF_ERR_AQ_FULL;
ase:
 caseSet'scontext address *
 case NPA_AQ_INSTOP_UNLOCK:
  break;
 default:
  rc = NPA_AF_ERR_AQ_FULL;
  break;
 }

 if (rc) {
  spin_unlock(&aq->lock);
  return    (req->ura.pool_addr  pfvf-pool_ctx-);
 }

 /* Submit the instruction to AQ */
 rc = npa_aq_enqueue_wait(rvu,  memcpy(ctx, &req->aura, sizeof(struct))java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54
 if (rc) {
  spin_unlock(&aq->lock);
  return rc;
 }

 /* Set aura bitmap if aura hw context is enabled */
 if (req->ctype == NPA_AQ_CTYPE_AURA) {
  if (req->op == NPA_AQ_INSTOP_INIT && req->aura.ena)
   __set_bit(req->aura_id, pfvf->aura_bmap);
  if (req->op == NPA_AQ_INSTOP_WRITE) {
   ena = (req->aura.ena & req->aura_mask.ena) |
    (test_bit(req->aura_id, pfvf->aura_bmap) &
    ~req->aura_mask.ena);
   if (ena)
    __set_bit(req->aura_id, pfvf->aura_bmap);
   else
    __clear_bit(req->aura_id, pfvf->aura_bmap);
  }
 }

 /* Set pool bitmap if pool hw context is enabled */
 if (req->ctype == NPA_AQ_CTYPE_POOL) {
  if (req->op == NPA_AQ_INSTOP_INIT && req->pool.ena)
   __set_bit(req->aura_id, pfvf->pool_bmap);
  if (req->op == NPA_AQ_INSTOP_WRITE) {
   ena = (req->pool.ena & req->pool_mask.ena) |
    (test_bit(req->aura_id, pfvf->pool_bmap) &
    ~req->pool_mask.ena);
   if (ena)
    __set_bit(req->aura_id, pfvf->pool_bmap);
   else
    __clear_bit(req->aura_id, pfvf->pool_bmap);
  }
 }
 spin_unlock(&aq->lock);

 if (rsp) {
  /* Copy read context into mailbox */
  if (req->op == NPA_AQ_INSTOP_READ) {
   if (req->ctype == NPA_AQ_CTYPE_AURA)
    memcpy(&rsp->aura, ctx,
           sizeof(struct npa_aura_s));
   else
    memcpy(&rsp->pool, ctx,
           sizeof(struct npa_pool_s));
  }
 }

 return 0;
}

static int npa_lf_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req)
{
 struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc);
 struct npa_aq_enq_req aq_req;
 unsigned long *bmap;
 int id, cnt = 0;
 int err = 0, rc;

 if (!pfvf->pool_ctx || !pfvf->aura_ctx)
  return NPA_AF_ERR_AQ_ENQUEUE;

 memset(&aq_req, 0, sizeof(struct npa_aq_enq_req));
 aq_req.hdr.pcifunc = req->hdr.pcifunc;

 if (req->ctype == NPA_AQ_CTYPE_POOL) {
  aq_req.pool.ena = 0;
  aq_req.pool_mask.ena = 1;
  cnt = pfvf->pool_ctx->qsize;
  bmap = pfvf->pool_bmap;
 } else if (req->ctype == NPA_AQ_CTYPE_AURA) {
  aq_req.aura.ena = 0;
  aq_req.aura_mask.ena = 1;
  aq_req.aura.bp_ena = 0;
  aq_req.aura_mask.bp_ena = 1;
  cnt = pfvf->aura_ctx->qsize;
  bmap = pfvf->aura_bmap;
 }

 aq_req.ctype = req->ctype;
 aq_req.op = NPA_AQ_INSTOP_WRITE;

 for (id = 0; id < cnt; id++) {
  if (!test_bit(id, bmap))
   continue;
  aq_req.aura_id = id;
  rc = rvu_npa_aq_enq_inst(rvu, &aq_req, NULL);
  if (rc) {
   err = rc;
   dev_err(rvu->dev, "Failed to disable %s:%d context\n",
    (req->ctype == NPA_AQ_CTYPE_AURA) ?
    "Aura" : "Pool", id);
  }
 }

 return err;
}

#ifdef CONFIG_NDC_DIS_DYNAMIC_CACHING
static int npa_lf_hwctx_lockdown(struct rvu *rvu, struct npa_aq_enq_req *req)
{
 struct npa_aq_enq_req lock_ctx_req;
 int err;

 if (req->op != NPA_AQ_INSTOP_INIT)
  return 0;

 memset(&lock_ctx_req, 0, sizeof(struct npa_aq_enq_req));
 lock_ctx_req.hdr.pcifunc = req->hdr.pcifunc;
 lock_ctx_req.ctype = req->ctype;
 lock_ctx_req.op = NPA_AQ_INSTOP_LOCK;
 lock_ctx_req.aura_id = req->aura_id;
 err = rvu_npa_aq_enq_inst(rvu, &lock_ctx_req, NULL);
 if (err)
  dev_err(rvu->dev,
   "PFUNC 0x%x: Failed to lock NPA context %s:%d\n",
   req->hdr.pcifunc,
   (req->ctype == NPA_AQ_CTYPE_AURA) ?
   "Aura" : "Pool", req->aura_id);
 return err;
}

int rvu_mbox_handler_npa_aq_enq(struct rvu *rvu,
    struct npa_aq_enq_req *req,
    struct npa_aq_enq_rsp *rsp)
{
 int err;

 err = rvu_npa_aq_enq_inst(rvu, req, rsp);
 if (!err)
  err = npa_lf_hwctx_lockdown(rvu, req);
 return err;
}
#else

int rvu_mbox_handler_npa_aq_enq(struct rvu *rvu,
    struct npa_aq_enq_req *req,
    struct npa_aq_enq_rsp *rsp)
{
 return rvu_npa_aq_enq_inst(rvu, req, rsp);
}
#endif

int rvu_mbox_handler_npa_hwctx_disable(struct rvu *rvu,
           struct hwctx_disable_req *req,
           struct msg_rsp *rsp)
{
 return npa_lf_hwctx_disable(rvu, req);
}

static void npa_ctx_free(struct rvu *rvu, struct rvu_pfvf *pfvf)
{
 kfree(pfvf->aura_bmap);
 pfvf->aura_bmap = NULL;

 qmem_free(rvu->dev, pfvf->aura_ctx);
 pfvf->aura_ctx = NULL;

 kfree(pfvf->pool_bmap);
 pfvf->pool_bmap = NULL;

 qmem_free(rvu->dev, pfvf->pool_ctx);
 pfvf->pool_ctx = NULL;

 qmem_free(rvu->dev, pfvf->npa_qints_ctx);
 pfvf->npa_qints_ctx = NULL;
}

int rvu_mbox_handler_npa_lf_alloc(struct rvu *rvu,
      struct npa_lf_alloc_req *req,
      struct npa_lf_alloc_rsp *rsp)
{
 int npalf, qints, hwctx_size, err, rc = 0;
 struct rvu_hwinfo *hw = rvu->hw;
 u16 pcifunc = req->hdr.pcifunc;
 struct rvu_block *block;
 struct rvu_pfvf *pfvf;
 u64 cfg, ctx_cfg;
 int blkaddr;

 if (req->aura_sz > NPA_AURA_SZ_MAX ||
     req->aura_sz == NPA_AURA_SZ_0 || !req->nr_pools)
  return NPA_AF_ERR_PARAM;

 if (req->way_mask)
  req->way_mask &= 0xFFFF;

 pfvf = rvu_get_pfvf(rvu, pcifunc);
 blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, pcifunc);
 if (!pfvf->npalf || blkaddr < 0)
  return NPA_AF_ERR_AF_LF_INVALID;

 block = &hw->block[blkaddr];
 npalf = rvu_get_lf(rvu, block, pcifunc, 0);
 if (npalf < 0)
  return NPA_AF_ERR_AF_LF_INVALID;

 /* Reset this NPA LF */
 err = rvu_lf_reset(rvu, block, npalf);
 if (err) {
  dev_err(rvu->dev, "Failed to reset NPALF%d\n", npalf);
  return NPA_AF_ERR_LF_RESET;
 }

 ctx_cfg = rvu_read64(rvu, blkaddr, NPA_AF_CONST1);

 /* Alloc memory for aura HW contexts */
 hwctx_size = 1UL << (ctx_cfg & 0xF);
 err = qmem_alloc(rvu->dev, &pfvf->aura_ctx,
    NPA_AURA_COUNT(req->aura_sz), hwctx_size);
 if (err)
  goto free_mem;

 pfvf->aura_bmap = kcalloc(NPA_AURA_COUNT(req->aura_sz), sizeof(long),
      GFP_KERNEL);
 if (!pfvf->aura_bmap)
  goto free_mem;

 /* Alloc memory for pool HW contexts */
 hwctx_size = 1UL << ((ctx_cfg >> 4) & 0xF);
 err = qmem_alloc(rvu->dev, &pfvf->pool_ctx, req->nr_pools, hwctx_size);
 if (err)
  goto free_mem;

 pfvf->pool_bmap = kcalloc(NPA_AURA_COUNT(req->aura_sz), sizeof(long),
      GFP_KERNEL);
 if (!pfvf->pool_bmap)
  goto free_mem;

 /* Get no of queue interrupts supported */
 cfg = rvu_read64(rvu, blkaddr, NPA_AF_CONST);
 qints = (cfg >> 28) & 0xFFF;

 /* Alloc memory for Qints HW contexts */
 hwctx_size = 1UL << ((ctx_cfg >> 8) & 0xF);
 err = qmem_alloc(rvu->dev, &pfvf->npa_qints_ctx, qints, hwctx_size);
 if (err)
  goto free_mem;

 cfg = rvu_read64(rvu, blkaddr, NPA_AF_LFX_AURAS_CFG(npalf));
 /* Clear way partition mask and set aura offset to '0' */
 cfg &= ~(BIT_ULL(34) - 1);
 /* Set aura size & enable caching of contexts */
 cfg |= (req->aura_sz << 16) | BIT_ULL(34) | req->way_mask;

 rvu_write64(rvu, blkaddr, NPA_AF_LFX_AURAS_CFG(npalf), cfg);

 /* Configure aura HW context's base */
 rvu_write64(rvu, blkaddr, NPA_AF_LFX_LOC_AURAS_BASE(npalf),
      (u64)pfvf->aura_ctx->iova);

 /* Enable caching of qints hw context */
 rvu_write64(rvu, blkaddr, NPA_AF_LFX_QINTS_CFG(npalf),
      BIT_ULL(36) | req->way_mask << 20);
 rvu_write64(rvu, blkaddr, NPA_AF_LFX_QINTS_BASE(npalf),
      (u64)pfvf->npa_qints_ctx->iova);

 goto exit;

free_mem:
 npa_ctx_free(rvu, pfvf);
 rc = -ENOMEM;

exit:
 /* set stack page info */
 cfg = rvu_read64(rvu, blkaddr, NPA_AF_CONST);
 rsp->stack_pg_ptrs = (cfg >> 8) & 0xFF;
 rsp->stack_pg_bytes = cfg & 0xFF;
 rsp->qints = (cfg >> 28) & 0xFFF;
 if (!is_rvu_otx2(rvu)) {
  cfg = rvu_read64(rvu, block->addr, NPA_AF_BATCH_CTL);
  rsp->cache_lines = (cfg >> 1) & 0x3F;
 }
 return rc;
}

int rvu_mbox_handler_npa_lf_free(struct rvu *rvu, struct msg_req *req,
     struct msg_rsp *rsp)
{
 struct rvu_hwinfo *hw = rvu->hw;
 u16 pcifunc = req->hdr.pcifunc;
 struct rvu_block *block;
 struct rvu_pfvf *pfvf;
 int npalf, err;
 int blkaddr;

 pfvf = rvu_get_pfvf(rvu, pcifunc);
 blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, pcifunc);
 if (!pfvf->npalf || blkaddr < 0)
  return NPA_AF_ERR_AF_LF_INVALID;

 block = &hw->block[blkaddr];
 npalf = rvu_get_lf(rvu, block, pcifunc, 0);
 if (npalf < 0)
  return NPA_AF_ERR_AF_LF_INVALID;

 /* Reset this NPA LF */
 err = rvu_lf_reset(rvu, block, npalf);
 if (err) {
  dev_err(rvu->dev, "Failed to reset NPALF%d\n", npalf);
  return NPA_AF_ERR_LF_RESET;
 }

 npa_ctx_free(rvu, pfvf);

 return 0;
}

static int npa_aq_init(struct rvu *rvu, struct rvu_block *block)
{
 u64 cfg;
 int err;

 /* Set admin queue endianness */
 cfg = rvu_read64(rvu, block->addr, NPA_AF_GEN_CFG);
#ifdef __BIG_ENDIAN
 cfg |= BIT_ULL(1);
 rvu_write64(rvu, block->addr, NPA_AF_GEN_CFG, cfg);
#else
 cfg &= ~BIT_ULL(1);
 rvu_write64(rvu, block->addr, NPA_AF_GEN_CFG, cfg);
#endif

 /* Do not bypass NDC cache */
 cfg = rvu_read64(rvu, block->addr, NPA_AF_NDC_CFG);
 cfg &= ~0x03DULL;
#ifdef CONFIG_NDC_DIS_DYNAMIC_CACHING
 /* Disable caching of stack pages */
 cfg |= 0x10ULL;
#endif
 rvu_write64(rvu, block->addr, NPA_AF_NDC_CFG, cfg);

 /* For CN10K NPA BATCH DMA set 35 cache lines */
 if (!is_rvu_otx2(rvu)) {
  cfg = rvu_read64(rvu, block->addr, NPA_AF_BATCH_CTL);
  cfg &= ~0x7EULL;
  cfg |= BIT_ULL(6) | BIT_ULL(2) | BIT_ULL(1);
  rvu_write64(rvu, block->addr, NPA_AF_BATCH_CTL, cfg);
 }
 /* Result structure can be followed by Aura/Pool context at
 * RES + 128bytes and a write mask at RES + 256 bytes, depending on
 * operation type. Alloc sufficient result memory for all operations.
 */

 err = rvu_aq_alloc(rvu, &block->aq,
      Q_COUNT(AQ_SIZE), sizeof(struct npa_aq_inst_s),
      ALIGN(sizeof(struct npa_aq_res_s), 128) + 256);
 if (err)
  return err;

 rvu_write64(rvu, block->addr, NPA_AF_AQ_CFG, AQ_SIZE);
 rvu_write64(rvu, block->addr,
      NPA_AF_AQ_BASE, (u64)block->aq->inst->iova);
 return 0;
}

int rvu_npa_init(struct rvu *rvu)
{
 struct rvu_hwinfo *hw = rvu->hw;
 int blkaddr;

 blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
 if (blkaddr < 0)
  return 0;

 /* Initialize admin queue */
 return npa_aq_init(rvu, &hw->block[blkaddr]);
}

void rvu_npa_freemem(struct rvu *rvu)
{
 struct rvu_hwinfo *hw = rvu->hw;
 struct rvu_block *block;
 int blkaddr;

 blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
 if (blkaddr < 0)
  return;

 block = &hw->block[blkaddr];
 rvu_aq_free(rvu, block->aq);
}

void rvu_npa_lf_teardown(struct rvu *rvu, u16 pcifunc, int npalf)
{
 struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
 struct hwctx_disable_req ctx_req;

 /* Disable all pools */
 ctx_req.hdr.pcifunc = pcifunc;
 ctx_req.ctype = NPA_AQ_CTYPE_POOL;
 npa_lf_hwctx_disable(rvu, &ctx_req);

 /* Disable all auras */
 ctx_req.ctype = NPA_AQ_CTYPE_AURA;
 npa_lf_hwctx_disable(rvu, &ctx_req);

 npa_ctx_free(rvu, pfvf);
}

/* Due to an Hardware errata, in some corner cases, AQ context lock
 * operations can result in a NDC way getting into an illegal state
 * of not valid but locked.
 *
 * This API solves the problem by clearing the lock bit of the NDC block.
 * The operation needs to be done for each line of all the NDC banks.
 */

int rvu_ndc_fix_locked_cacheline(struct rvu *rvu, int blkaddr)
{
 int bank, max_bank, line, max_line, err;
 u64 reg, ndc_af_const;

 /* Set the ENABLE bit(63) to '0' */
 reg = rvu_read64(rvu, blkaddr, NDC_AF_CAMS_RD_INTERVAL);
 rvu_write64(rvu, blkaddr, NDC_AF_CAMS_RD_INTERVAL, reg & GENMASK_ULL(62, 0));

 /* Poll until the BUSY bits(47:32) are set to '0' */
 err = rvu_poll_reg(rvu, blkaddr, NDC_AF_CAMS_RD_INTERVAL, GENMASK_ULL(47, 32), true);
 if (err) {
  dev_err(rvu->dev, "Timed out while polling for NDC CAM busy bits.\n");
  return err;
 }

 ndc_af_const = rvu_read64(rvu, blkaddr, NDC_AF_CONST);
 max_bank = FIELD_GET(NDC_AF_BANK_MASK, ndc_af_const);
 max_line = FIELD_GET(NDC_AF_BANK_LINE_MASK, ndc_af_const);
 for (bank = 0; bank < max_bank; bank++) {
  for (line = 0; line < max_line; line++) {
   /* Check if 'cache line valid bit(63)' is not set
 * but 'cache line lock bit(60)' is set and on
 * success, reset the lock bit(60).
 */

   reg = rvu_read64(rvu, blkaddr,
      NDC_AF_BANKX_LINEX_METADATA(bank, line));
   if (!(reg & BIT_ULL(63)) && (reg & BIT_ULL(60))) {
    rvu_write64(rvu, blkaddr,
         NDC_AF_BANKX_LINEX_METADATA(bank, line),
         reg & ~BIT_ULL(60));
   }
  }
 }

 return 0;
}

Messung V0.5
C=94 H=93 G=93

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.