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