1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2 /* Copyright 2017-2019 NXP */
6 int enetc_setup_cbdr(struct device *dev, struct enetc_hw *hw, int bd_count,
7 struct enetc_cbdr *cbdr)
9 int size = bd_count * sizeof(struct enetc_cbd);
11 cbdr->bd_base = dma_alloc_coherent(dev, size, &cbdr->bd_dma_base,
16 /* h/w requires 128B alignment */
17 if (!IS_ALIGNED(cbdr->bd_dma_base, 128)) {
18 dma_free_coherent(dev, size, cbdr->bd_base,
23 cbdr->next_to_clean = 0;
24 cbdr->next_to_use = 0;
26 cbdr->bd_count = bd_count;
28 cbdr->pir = hw->reg + ENETC_SICBDRPIR;
29 cbdr->cir = hw->reg + ENETC_SICBDRCIR;
30 cbdr->mr = hw->reg + ENETC_SICBDRMR;
32 /* set CBDR cache attributes */
33 enetc_wr(hw, ENETC_SICAR2,
34 ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT);
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));
40 enetc_wr_reg(cbdr->pir, cbdr->next_to_clean);
41 enetc_wr_reg(cbdr->cir, cbdr->next_to_use);
43 enetc_wr_reg(cbdr->mr, BIT(31));
47 EXPORT_SYMBOL_GPL(enetc_setup_cbdr);
49 void enetc_teardown_cbdr(struct enetc_cbdr *cbdr)
51 int size = cbdr->bd_count * sizeof(struct enetc_cbd);
54 enetc_wr_reg(cbdr->mr, 0);
56 dma_free_coherent(cbdr->dma_dev, size, cbdr->bd_base,
61 EXPORT_SYMBOL_GPL(enetc_teardown_cbdr);
63 static void enetc_clean_cbdr(struct enetc_cbdr *ring)
65 struct enetc_cbd *dest_cbd;
68 i = ring->next_to_clean;
70 while (enetc_rd_reg(ring->cir) != i) {
71 dest_cbd = ENETC_CBD(*ring, i);
72 status = dest_cbd->status_flags & ENETC_CBD_STATUS_MASK;
74 dev_warn(ring->dma_dev, "CMD err %04x for cmd %04x\n",
75 status, dest_cbd->cmd);
77 memset(dest_cbd, 0, sizeof(*dest_cbd));
79 i = (i + 1) % ring->bd_count;
82 ring->next_to_clean = i;
85 static int enetc_cbd_unused(struct enetc_cbdr *r)
87 return (r->next_to_clean - r->next_to_use - 1 + r->bd_count) %
91 int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
93 struct enetc_cbdr *ring = &si->cbd_ring;
94 int timeout = ENETC_CBDR_TIMEOUT;
95 struct enetc_cbd *dest_cbd;
98 if (unlikely(!ring->bd_base))
101 if (unlikely(!enetc_cbd_unused(ring)))
102 enetc_clean_cbdr(ring);
104 i = ring->next_to_use;
105 dest_cbd = ENETC_CBD(*ring, i);
107 /* copy command to the ring */
109 i = (i + 1) % ring->bd_count;
111 ring->next_to_use = i;
112 /* let H/W know BD ring has been updated */
113 enetc_wr_reg(ring->pir, i);
116 if (enetc_rd_reg(ring->cir) == i)
118 udelay(10); /* cannot sleep, rtnl_lock() */
125 /* CBD may writeback data, feedback up level */
128 enetc_clean_cbdr(ring);
132 EXPORT_SYMBOL_GPL(enetc_send_cmd);
134 int enetc_clear_mac_flt_entry(struct enetc_si *si, int index)
136 struct enetc_cbd cbd;
138 memset(&cbd, 0, sizeof(cbd));
141 cbd.status_flags = ENETC_CBD_FLAGS_SF;
142 cbd.index = cpu_to_le16(index);
144 return enetc_send_cmd(si, &cbd);
146 EXPORT_SYMBOL_GPL(enetc_clear_mac_flt_entry);
148 int enetc_set_mac_flt_entry(struct enetc_si *si, int index,
149 char *mac_addr, int si_map)
151 struct enetc_cbd cbd;
155 memset(&cbd, 0, sizeof(cbd));
157 /* fill up the "set" descriptor */
159 cbd.status_flags = ENETC_CBD_FLAGS_SF;
160 cbd.index = cpu_to_le16(index);
161 cbd.opt[3] = cpu_to_le32(si_map);
163 cbd.opt[0] = cpu_to_le32(BIT(31));
165 upper = *(const u32 *)mac_addr;
166 lower = *(const u16 *)(mac_addr + 4);
167 cbd.addr[0] = cpu_to_le32(upper);
168 cbd.addr[1] = cpu_to_le32(lower);
170 return enetc_send_cmd(si, &cbd);
172 EXPORT_SYMBOL_GPL(enetc_set_mac_flt_entry);
174 /* Set entry in RFS table */
175 int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse,
178 struct enetc_cbdr *ring = &si->cbd_ring;
179 struct enetc_cbd cbd = {.cmd = 0};
180 void *tmp, *tmp_align;
184 /* fill up the "set" descriptor */
187 cbd.index = cpu_to_le16(index);
188 cbd.opt[3] = cpu_to_le32(0); /* SI */
190 tmp = enetc_cbd_alloc_data_mem(si, &cbd, sizeof(*rfse),
195 memcpy(tmp_align, rfse, sizeof(*rfse));
197 err = enetc_send_cmd(si, &cbd);
199 dev_err(ring->dma_dev, "FS entry add failed (%d)!", err);
201 enetc_cbd_free_data_mem(si, sizeof(*rfse), tmp, &dma);
205 EXPORT_SYMBOL_GPL(enetc_set_fs_entry);
207 static int enetc_cmd_rss_table(struct enetc_si *si, u32 *table, int count,
210 struct enetc_cbdr *ring = &si->cbd_ring;
211 struct enetc_cbd cbd = {.cmd = 0};
216 if (count < ENETC_CBD_DATA_MEM_ALIGN)
217 /* HW only takes in a full 64 entry table */
220 tmp = enetc_cbd_alloc_data_mem(si, &cbd, count,
221 &dma, (void *)&tmp_align);
226 for (i = 0; i < count; i++)
227 tmp_align[i] = (u8)(table[i]);
229 /* fill up the descriptor */
230 cbd.cmd = read ? 2 : 1;
233 err = enetc_send_cmd(si, &cbd);
235 dev_err(ring->dma_dev, "RSS cmd failed (%d)!", err);
238 for (i = 0; i < count; i++)
239 table[i] = tmp_align[i];
241 enetc_cbd_free_data_mem(si, count, tmp, &dma);
247 int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count)
249 return enetc_cmd_rss_table(si, table, count, true);
251 EXPORT_SYMBOL_GPL(enetc_get_rss_table);
254 int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count)
256 return enetc_cmd_rss_table(si, (u32 *)table, count, false);
258 EXPORT_SYMBOL_GPL(enetc_set_rss_table);