cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

enetc_cbdr.c (5652B)


      1// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
      2/* Copyright 2017-2019 NXP */
      3
      4#include "enetc.h"
      5
      6int enetc_setup_cbdr(struct device *dev, struct enetc_hw *hw, int bd_count,
      7		     struct enetc_cbdr *cbdr)
      8{
      9	int size = bd_count * sizeof(struct enetc_cbd);
     10
     11	cbdr->bd_base = dma_alloc_coherent(dev, size, &cbdr->bd_dma_base,
     12					   GFP_KERNEL);
     13	if (!cbdr->bd_base)
     14		return -ENOMEM;
     15
     16	/* h/w requires 128B alignment */
     17	if (!IS_ALIGNED(cbdr->bd_dma_base, 128)) {
     18		dma_free_coherent(dev, size, cbdr->bd_base,
     19				  cbdr->bd_dma_base);
     20		return -EINVAL;
     21	}
     22
     23	cbdr->next_to_clean = 0;
     24	cbdr->next_to_use = 0;
     25	cbdr->dma_dev = dev;
     26	cbdr->bd_count = bd_count;
     27
     28	cbdr->pir = hw->reg + ENETC_SICBDRPIR;
     29	cbdr->cir = hw->reg + ENETC_SICBDRCIR;
     30	cbdr->mr = hw->reg + ENETC_SICBDRMR;
     31
     32	/* set CBDR cache attributes */
     33	enetc_wr(hw, ENETC_SICAR2,
     34		 ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT);
     35
     36	enetc_wr(hw, ENETC_SICBDRBAR0, lower_32_bits(cbdr->bd_dma_base));
     37	enetc_wr(hw, ENETC_SICBDRBAR1, upper_32_bits(cbdr->bd_dma_base));
     38	enetc_wr(hw, ENETC_SICBDRLENR, ENETC_RTBLENR_LEN(cbdr->bd_count));
     39
     40	enetc_wr_reg(cbdr->pir, cbdr->next_to_clean);
     41	enetc_wr_reg(cbdr->cir, cbdr->next_to_use);
     42	/* enable ring */
     43	enetc_wr_reg(cbdr->mr, BIT(31));
     44
     45	return 0;
     46}
     47
     48void enetc_teardown_cbdr(struct enetc_cbdr *cbdr)
     49{
     50	int size = cbdr->bd_count * sizeof(struct enetc_cbd);
     51
     52	/* disable ring */
     53	enetc_wr_reg(cbdr->mr, 0);
     54
     55	dma_free_coherent(cbdr->dma_dev, size, cbdr->bd_base,
     56			  cbdr->bd_dma_base);
     57	cbdr->bd_base = NULL;
     58	cbdr->dma_dev = NULL;
     59}
     60
     61static void enetc_clean_cbdr(struct enetc_cbdr *ring)
     62{
     63	struct enetc_cbd *dest_cbd;
     64	int i, status;
     65
     66	i = ring->next_to_clean;
     67
     68	while (enetc_rd_reg(ring->cir) != i) {
     69		dest_cbd = ENETC_CBD(*ring, i);
     70		status = dest_cbd->status_flags & ENETC_CBD_STATUS_MASK;
     71		if (status)
     72			dev_warn(ring->dma_dev, "CMD err %04x for cmd %04x\n",
     73				 status, dest_cbd->cmd);
     74
     75		memset(dest_cbd, 0, sizeof(*dest_cbd));
     76
     77		i = (i + 1) % ring->bd_count;
     78	}
     79
     80	ring->next_to_clean = i;
     81}
     82
     83static int enetc_cbd_unused(struct enetc_cbdr *r)
     84{
     85	return (r->next_to_clean - r->next_to_use - 1 + r->bd_count) %
     86		r->bd_count;
     87}
     88
     89int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
     90{
     91	struct enetc_cbdr *ring = &si->cbd_ring;
     92	int timeout = ENETC_CBDR_TIMEOUT;
     93	struct enetc_cbd *dest_cbd;
     94	int i;
     95
     96	if (unlikely(!ring->bd_base))
     97		return -EIO;
     98
     99	if (unlikely(!enetc_cbd_unused(ring)))
    100		enetc_clean_cbdr(ring);
    101
    102	i = ring->next_to_use;
    103	dest_cbd = ENETC_CBD(*ring, i);
    104
    105	/* copy command to the ring */
    106	*dest_cbd = *cbd;
    107	i = (i + 1) % ring->bd_count;
    108
    109	ring->next_to_use = i;
    110	/* let H/W know BD ring has been updated */
    111	enetc_wr_reg(ring->pir, i);
    112
    113	do {
    114		if (enetc_rd_reg(ring->cir) == i)
    115			break;
    116		udelay(10); /* cannot sleep, rtnl_lock() */
    117		timeout -= 10;
    118	} while (timeout);
    119
    120	if (!timeout)
    121		return -EBUSY;
    122
    123	/* CBD may writeback data, feedback up level */
    124	*cbd = *dest_cbd;
    125
    126	enetc_clean_cbdr(ring);
    127
    128	return 0;
    129}
    130
    131int enetc_clear_mac_flt_entry(struct enetc_si *si, int index)
    132{
    133	struct enetc_cbd cbd;
    134
    135	memset(&cbd, 0, sizeof(cbd));
    136
    137	cbd.cls = 1;
    138	cbd.status_flags = ENETC_CBD_FLAGS_SF;
    139	cbd.index = cpu_to_le16(index);
    140
    141	return enetc_send_cmd(si, &cbd);
    142}
    143
    144int enetc_set_mac_flt_entry(struct enetc_si *si, int index,
    145			    char *mac_addr, int si_map)
    146{
    147	struct enetc_cbd cbd;
    148	u32 upper;
    149	u16 lower;
    150
    151	memset(&cbd, 0, sizeof(cbd));
    152
    153	/* fill up the "set" descriptor */
    154	cbd.cls = 1;
    155	cbd.status_flags = ENETC_CBD_FLAGS_SF;
    156	cbd.index = cpu_to_le16(index);
    157	cbd.opt[3] = cpu_to_le32(si_map);
    158	/* enable entry */
    159	cbd.opt[0] = cpu_to_le32(BIT(31));
    160
    161	upper = *(const u32 *)mac_addr;
    162	lower = *(const u16 *)(mac_addr + 4);
    163	cbd.addr[0] = cpu_to_le32(upper);
    164	cbd.addr[1] = cpu_to_le32(lower);
    165
    166	return enetc_send_cmd(si, &cbd);
    167}
    168
    169/* Set entry in RFS table */
    170int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse,
    171		       int index)
    172{
    173	struct enetc_cbdr *ring = &si->cbd_ring;
    174	struct enetc_cbd cbd = {.cmd = 0};
    175	void *tmp, *tmp_align;
    176	dma_addr_t dma;
    177	int err;
    178
    179	/* fill up the "set" descriptor */
    180	cbd.cmd = 0;
    181	cbd.cls = 4;
    182	cbd.index = cpu_to_le16(index);
    183	cbd.opt[3] = cpu_to_le32(0); /* SI */
    184
    185	tmp = enetc_cbd_alloc_data_mem(si, &cbd, sizeof(*rfse),
    186				       &dma, &tmp_align);
    187	if (!tmp)
    188		return -ENOMEM;
    189
    190	memcpy(tmp_align, rfse, sizeof(*rfse));
    191
    192	err = enetc_send_cmd(si, &cbd);
    193	if (err)
    194		dev_err(ring->dma_dev, "FS entry add failed (%d)!", err);
    195
    196	enetc_cbd_free_data_mem(si, sizeof(*rfse), tmp, &dma);
    197
    198	return err;
    199}
    200
    201static int enetc_cmd_rss_table(struct enetc_si *si, u32 *table, int count,
    202			       bool read)
    203{
    204	struct enetc_cbdr *ring = &si->cbd_ring;
    205	struct enetc_cbd cbd = {.cmd = 0};
    206	u8 *tmp, *tmp_align;
    207	dma_addr_t dma;
    208	int err, i;
    209
    210	if (count < ENETC_CBD_DATA_MEM_ALIGN)
    211		/* HW only takes in a full 64 entry table */
    212		return -EINVAL;
    213
    214	tmp = enetc_cbd_alloc_data_mem(si, &cbd, count,
    215				       &dma, (void *)&tmp_align);
    216	if (!tmp)
    217		return -ENOMEM;
    218
    219	if (!read)
    220		for (i = 0; i < count; i++)
    221			tmp_align[i] = (u8)(table[i]);
    222
    223	/* fill up the descriptor */
    224	cbd.cmd = read ? 2 : 1;
    225	cbd.cls = 3;
    226
    227	err = enetc_send_cmd(si, &cbd);
    228	if (err)
    229		dev_err(ring->dma_dev, "RSS cmd failed (%d)!", err);
    230
    231	if (read)
    232		for (i = 0; i < count; i++)
    233			table[i] = tmp_align[i];
    234
    235	enetc_cbd_free_data_mem(si, count, tmp, &dma);
    236
    237	return err;
    238}
    239
    240/* Get RSS table */
    241int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count)
    242{
    243	return enetc_cmd_rss_table(si, table, count, true);
    244}
    245
    246/* Set RSS table */
    247int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count)
    248{
    249	return enetc_cmd_rss_table(si, (u32 *)table, count, false);
    250}