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

Quelle  enetc_cbdr.c   Sprache: C

 
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* Copyright 2017-2019 NXP */

#include "enetc.h"

int enetc_setup_cbdr(struct device *dev, struct enetc_hw *hw, int bd_count,
       struct enetc_cbdr *cbdr)
{
 int size = bd_count * sizeof(struct enetc_cbd);

 cbdr->bd_base = dma_alloc_coherent(dev, size, &cbdr->bd_dma_base,
        GFP_KERNEL);
 if (!cbdr->bd_base)
  return -ENOMEM;

 /* h/w requires 128B alignment */
 if (!IS_ALIGNED(cbdr->bd_dma_base, 128)) {
  dma_free_coherent(dev, size, cbdr->bd_base,
      cbdr->bd_dma_base);
  return -EINVAL;
 }

 cbdr->next_to_clean = 0;
 cbdr->next_to_use = 0;
 cbdr->dma_dev = dev;
 cbdr->bd_count = bd_count;

 cbdr->pir = hw->reg + ENETC_SICBDRPIR;
 cbdr->cir = hw->reg + ENETC_SICBDRCIR;
 cbdr->mr = hw->reg + ENETC_SICBDRMR;

 /* set CBDR cache attributes */
 enetc_wr(hw, ENETC_SICAR2,
   ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT);

 enetc_wr(hw, ENETC_SICBDRBAR0, lower_32_bits(cbdr->bd_dma_base));
 enetc_wr(hw, ENETC_SICBDRBAR1, upper_32_bits(cbdr->bd_dma_base));
 enetc_wr(hw, ENETC_SICBDRLENR, ENETC_RTBLENR_LEN(cbdr->bd_count));

 enetc_wr_reg(cbdr->pir, cbdr->next_to_clean);
 enetc_wr_reg(cbdr->cir, cbdr->next_to_use);
 /* enable ring */
 enetc_wr_reg(cbdr->mr, BIT(31));

 return 0;
}
EXPORT_SYMBOL_GPL(enetc_setup_cbdr);

void enetc_teardown_cbdr(struct enetc_cbdr *cbdr)
{
 int size = cbdr->bd_count * sizeof(struct enetc_cbd);

 /* disable ring */
 enetc_wr_reg(cbdr->mr, 0);

 dma_free_coherent(cbdr->dma_dev, size, cbdr->bd_base,
     cbdr->bd_dma_base);
 cbdr->bd_base = NULL;
 cbdr->dma_dev = NULL;
}
EXPORT_SYMBOL_GPL(enetc_teardown_cbdr);

int enetc4_setup_cbdr(struct enetc_si *si)
{
 struct ntmp_user *user = &si->ntmp_user;
 struct device *dev = &si->pdev->dev;
 struct enetc_hw *hw = &si->hw;
 struct netc_cbdr_regs regs;

 user->cbdr_num = 1;
 user->dev = dev;
 user->ring = devm_kcalloc(dev, user->cbdr_num,
      sizeof(struct netc_cbdr), GFP_KERNEL);
 if (!user->ring)
  return -ENOMEM;

 /* set CBDR cache attributes */
 enetc_wr(hw, ENETC_SICAR2,
   ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT);

 regs.pir = hw->reg + ENETC_SICBDRPIR;
 regs.cir = hw->reg + ENETC_SICBDRCIR;
 regs.mr = hw->reg + ENETC_SICBDRMR;
 regs.bar0 = hw->reg + ENETC_SICBDRBAR0;
 regs.bar1 = hw->reg + ENETC_SICBDRBAR1;
 regs.lenr = hw->reg + ENETC_SICBDRLENR;

 return ntmp_init_cbdr(user->ring, dev, ®s);
}
EXPORT_SYMBOL_GPL(enetc4_setup_cbdr);

void enetc4_teardown_cbdr(struct enetc_si *si)
{
 struct ntmp_user *user = &si->ntmp_user;

 ntmp_free_cbdr(user->ring);
 user->dev = NULL;
}
EXPORT_SYMBOL_GPL(enetc4_teardown_cbdr);

static void enetc_clean_cbdr(struct enetc_cbdr *ring)
{
 struct enetc_cbd *dest_cbd;
 int i, status;

 i = ring->next_to_clean;

 while (enetc_rd_reg(ring->cir) != i) {
  dest_cbd = ENETC_CBD(*ring, i);
  status = dest_cbd->status_flags & ENETC_CBD_STATUS_MASK;
  if (status)
   dev_warn(ring->dma_dev, "CMD err %04x for cmd %04x\n",
     status, dest_cbd->cmd);

  memset(dest_cbd, 0, sizeof(*dest_cbd));

  i = (i + 1) % ring->bd_count;
 }

 ring->next_to_clean = i;
}

static int enetc_cbd_unused(struct enetc_cbdr *r)
{
 return (r->next_to_clean - r->next_to_use - 1 + r->bd_count) %
  r->bd_count;
}

int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
{
 struct enetc_cbdr *ring = &si->cbd_ring;
 int timeout = ENETC_CBDR_TIMEOUT;
 struct enetc_cbd *dest_cbd;
 int i;

 if (unlikely(!ring->bd_base))
  return -EIO;

 if (unlikely(!enetc_cbd_unused(ring)))
  enetc_clean_cbdr(ring);

 i = ring->next_to_use;
 dest_cbd = ENETC_CBD(*ring, i);

 /* copy command to the ring */
 *dest_cbd = *cbd;
 i = (i + 1) % ring->bd_count;

 ring->next_to_use = i;
 /* let H/W know BD ring has been updated */
 enetc_wr_reg(ring->pir, i);

 do {
  if (enetc_rd_reg(ring->cir) == i)
   break;
  udelay(10); /* cannot sleep, rtnl_lock() */
  timeout -= 10;
 } while (timeout);

 if (!timeout)
  return -EBUSY;

 /* CBD may writeback data, feedback up level */
 *cbd = *dest_cbd;

 enetc_clean_cbdr(ring);

 return 0;
}
EXPORT_SYMBOL_GPL(enetc_send_cmd);

int enetc_clear_mac_flt_entry(struct enetc_si *si, int index)
{
 struct enetc_cbd cbd;

 memset(&cbd, 0, sizeof(cbd));

 cbd.cls = 1;
 cbd.status_flags = ENETC_CBD_FLAGS_SF;
 cbd.index = cpu_to_le16(index);

 return enetc_send_cmd(si, &cbd);
}
EXPORT_SYMBOL_GPL(enetc_clear_mac_flt_entry);

int enetc_set_mac_flt_entry(struct enetc_si *si, int index,
       char *mac_addr, int si_map)
{
 struct enetc_cbd cbd;
 u32 upper;
 u16 lower;

 memset(&cbd, 0, sizeof(cbd));

 /* fill up the "set" descriptor */
 cbd.cls = 1;
 cbd.status_flags = ENETC_CBD_FLAGS_SF;
 cbd.index = cpu_to_le16(index);
 cbd.opt[3] = cpu_to_le32(si_map);
 /* enable entry */
 cbd.opt[0] = cpu_to_le32(BIT(31));

 upper = *(const u32 *)mac_addr;
 lower = *(const u16 *)(mac_addr + 4);
 cbd.addr[0] = cpu_to_le32(upper);
 cbd.addr[1] = cpu_to_le32(lower);

 return enetc_send_cmd(si, &cbd);
}
EXPORT_SYMBOL_GPL(enetc_set_mac_flt_entry);

/* Set entry in RFS table */
int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse,
         int index)
{
 struct enetc_cbdr *ring = &si->cbd_ring;
 struct enetc_cbd cbd = {.cmd = 0};
 void *tmp, *tmp_align;
 dma_addr_t dma;
 int err;

 /* fill up the "set" descriptor */
 cbd.cmd = 0;
 cbd.cls = 4;
 cbd.index = cpu_to_le16(index);
 cbd.opt[3] = cpu_to_le32(0); /* SI */

 tmp = enetc_cbd_alloc_data_mem(si, &cbd, sizeof(*rfse),
           &dma, &tmp_align);
 if (!tmp)
  return -ENOMEM;

 memcpy(tmp_align, rfse, sizeof(*rfse));

 err = enetc_send_cmd(si, &cbd);
 if (err)
  dev_err(ring->dma_dev, "FS entry add failed (%d)!", err);

 enetc_cbd_free_data_mem(si, sizeof(*rfse), tmp, &dma);

 return err;
}
EXPORT_SYMBOL_GPL(enetc_set_fs_entry);

static int enetc_cmd_rss_table(struct enetc_si *si, u32 *table, int count,
          bool read)
{
 struct enetc_cbdr *ring = &si->cbd_ring;
 struct enetc_cbd cbd = {.cmd = 0};
 u8 *tmp, *tmp_align;
 dma_addr_t dma;
 int err, i;

 if (count < ENETC_CBD_DATA_MEM_ALIGN)
  /* HW only takes in a full 64 entry table */
  return -EINVAL;

 tmp = enetc_cbd_alloc_data_mem(si, &cbd, count,
           &dma, (void *)&tmp_align);
 if (!tmp)
  return -ENOMEM;

 if (!read)
  for (i = 0; i < count; i++)
   tmp_align[i] = (u8)(table[i]);

 /* fill up the descriptor */
 cbd.cmd = read ? 2 : 1;
 cbd.cls = 3;

 err = enetc_send_cmd(si, &cbd);
 if (err)
  dev_err(ring->dma_dev, "RSS cmd failed (%d)!", err);

 if (read)
  for (i = 0; i < count; i++)
   table[i] = tmp_align[i];

 enetc_cbd_free_data_mem(si, count, tmp, &dma);

 return err;
}

/* Get RSS table */
int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count)
{
 return enetc_cmd_rss_table(si, table, count, true);
}
EXPORT_SYMBOL_GPL(enetc_get_rss_table);

/* Set RSS table */
int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count)
{
 return enetc_cmd_rss_table(si, (u32 *)table, count, false);
}
EXPORT_SYMBOL_GPL(enetc_set_rss_table);

int enetc4_get_rss_table(struct enetc_si *si, u32 *table, int count)
{
 return ntmp_rsst_query_entry(&si->ntmp_user, table, count);
}
EXPORT_SYMBOL_GPL(enetc4_get_rss_table);

int enetc4_set_rss_table(struct enetc_si *si, const u32 *table, int count)
{
 return ntmp_rsst_update_entry(&si->ntmp_user, table, count);
}
EXPORT_SYMBOL_GPL(enetc4_set_rss_table);

Messung V0.5
C=96 H=96 G=95

¤ Dauer der Verarbeitung: 0.14 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.