Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'ibmvnic-ibmvnic-rr-patchset'

Nick Child says:

====================
ibmvnic: ibmvnic rr patchset

v1 - https://lore.kernel.org/netdev/20240801212340.132607-1-nnac123@linux.ibm.com/
v2 - https://lore.kernel.org/netdev/20240806193706.998148-1-nnac123@linux.ibm.com/
====================

Link: https://patch.msgid.link/20240807211809.1259563-1-nnac123@linux.ibm.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+108 -75
+108 -75
drivers/net/ethernet/ibm/ibmvnic.c
··· 117 117 struct ibmvnic_long_term_buff *ltb); 118 118 static void ibmvnic_disable_irqs(struct ibmvnic_adapter *adapter); 119 119 static void flush_reset_queue(struct ibmvnic_adapter *adapter); 120 + static void print_subcrq_error(struct device *dev, int rc, const char *func); 120 121 121 122 struct ibmvnic_stat { 122 123 char name[ETH_GSTRING_LEN]; ··· 2141 2140 } 2142 2141 2143 2142 /** 2144 - * build_hdr_data - creates L2/L3/L4 header data buffer 2143 + * get_hdr_lens - fills list of L2/L3/L4 hdr lens 2145 2144 * @hdr_field: bitfield determining needed headers 2146 2145 * @skb: socket buffer 2147 - * @hdr_len: array of header lengths 2148 - * @hdr_data: buffer to write the header to 2146 + * @hdr_len: array of header lengths to be filled 2149 2147 * 2150 2148 * Reads hdr_field to determine which headers are needed by firmware. 2151 2149 * Builds a buffer containing these headers. Saves individual header 2152 2150 * lengths and total buffer length to be used to build descriptors. 2151 + * 2152 + * Return: total len of all headers 2153 2153 */ 2154 - static int build_hdr_data(u8 hdr_field, struct sk_buff *skb, 2155 - int *hdr_len, u8 *hdr_data) 2154 + static int get_hdr_lens(u8 hdr_field, struct sk_buff *skb, 2155 + int *hdr_len) 2156 2156 { 2157 2157 int len = 0; 2158 - u8 *hdr; 2159 2158 2160 - if (skb_vlan_tagged(skb) && !skb_vlan_tag_present(skb)) 2161 - hdr_len[0] = sizeof(struct vlan_ethhdr); 2162 - else 2163 - hdr_len[0] = sizeof(struct ethhdr); 2159 + 2160 + if ((hdr_field >> 6) & 1) { 2161 + hdr_len[0] = skb_mac_header_len(skb); 2162 + len += hdr_len[0]; 2163 + } 2164 + 2165 + if ((hdr_field >> 5) & 1) { 2166 + hdr_len[1] = skb_network_header_len(skb); 2167 + len += hdr_len[1]; 2168 + } 2169 + 2170 + if (!((hdr_field >> 4) & 1)) 2171 + return len; 2164 2172 2165 2173 if (skb->protocol == htons(ETH_P_IP)) { 2166 - hdr_len[1] = ip_hdr(skb)->ihl * 4; 2167 2174 if (ip_hdr(skb)->protocol == IPPROTO_TCP) 2168 2175 hdr_len[2] = tcp_hdrlen(skb); 2169 2176 else if (ip_hdr(skb)->protocol == IPPROTO_UDP) 2170 2177 hdr_len[2] = sizeof(struct udphdr); 2171 2178 } else if (skb->protocol == htons(ETH_P_IPV6)) { 2172 - hdr_len[1] = sizeof(struct ipv6hdr); 2173 2179 if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) 2174 2180 hdr_len[2] = tcp_hdrlen(skb); 2175 2181 else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP) 2176 2182 hdr_len[2] = sizeof(struct udphdr); 2177 - } else if (skb->protocol == htons(ETH_P_ARP)) { 2178 - hdr_len[1] = arp_hdr_len(skb->dev); 2179 - hdr_len[2] = 0; 2180 2183 } 2181 2184 2182 - memset(hdr_data, 0, 120); 2183 - if ((hdr_field >> 6) & 1) { 2184 - hdr = skb_mac_header(skb); 2185 - memcpy(hdr_data, hdr, hdr_len[0]); 2186 - len += hdr_len[0]; 2187 - } 2188 - 2189 - if ((hdr_field >> 5) & 1) { 2190 - hdr = skb_network_header(skb); 2191 - memcpy(hdr_data + len, hdr, hdr_len[1]); 2192 - len += hdr_len[1]; 2193 - } 2194 - 2195 - if ((hdr_field >> 4) & 1) { 2196 - hdr = skb_transport_header(skb); 2197 - memcpy(hdr_data + len, hdr, hdr_len[2]); 2198 - len += hdr_len[2]; 2199 - } 2200 - return len; 2185 + return len + hdr_len[2]; 2201 2186 } 2202 2187 2203 2188 /** ··· 2196 2209 * 2197 2210 * Creates header and, if needed, header extension descriptors and 2198 2211 * places them in a descriptor array, scrq_arr 2212 + * 2213 + * Return: Number of header descs 2199 2214 */ 2200 2215 2201 2216 static int create_hdr_descs(u8 hdr_field, u8 *hdr_data, int len, int *hdr_len, 2202 2217 union sub_crq *scrq_arr) 2203 2218 { 2204 - union sub_crq hdr_desc; 2219 + union sub_crq *hdr_desc; 2205 2220 int tmp_len = len; 2206 2221 int num_descs = 0; 2207 2222 u8 *data, *cur; ··· 2212 2223 while (tmp_len > 0) { 2213 2224 cur = hdr_data + len - tmp_len; 2214 2225 2215 - memset(&hdr_desc, 0, sizeof(hdr_desc)); 2216 - if (cur != hdr_data) { 2217 - data = hdr_desc.hdr_ext.data; 2226 + hdr_desc = &scrq_arr[num_descs]; 2227 + if (num_descs) { 2228 + data = hdr_desc->hdr_ext.data; 2218 2229 tmp = tmp_len > 29 ? 29 : tmp_len; 2219 - hdr_desc.hdr_ext.first = IBMVNIC_CRQ_CMD; 2220 - hdr_desc.hdr_ext.type = IBMVNIC_HDR_EXT_DESC; 2221 - hdr_desc.hdr_ext.len = tmp; 2230 + hdr_desc->hdr_ext.first = IBMVNIC_CRQ_CMD; 2231 + hdr_desc->hdr_ext.type = IBMVNIC_HDR_EXT_DESC; 2232 + hdr_desc->hdr_ext.len = tmp; 2222 2233 } else { 2223 - data = hdr_desc.hdr.data; 2234 + data = hdr_desc->hdr.data; 2224 2235 tmp = tmp_len > 24 ? 24 : tmp_len; 2225 - hdr_desc.hdr.first = IBMVNIC_CRQ_CMD; 2226 - hdr_desc.hdr.type = IBMVNIC_HDR_DESC; 2227 - hdr_desc.hdr.len = tmp; 2228 - hdr_desc.hdr.l2_len = (u8)hdr_len[0]; 2229 - hdr_desc.hdr.l3_len = cpu_to_be16((u16)hdr_len[1]); 2230 - hdr_desc.hdr.l4_len = (u8)hdr_len[2]; 2231 - hdr_desc.hdr.flag = hdr_field << 1; 2236 + hdr_desc->hdr.first = IBMVNIC_CRQ_CMD; 2237 + hdr_desc->hdr.type = IBMVNIC_HDR_DESC; 2238 + hdr_desc->hdr.len = tmp; 2239 + hdr_desc->hdr.l2_len = (u8)hdr_len[0]; 2240 + hdr_desc->hdr.l3_len = cpu_to_be16((u16)hdr_len[1]); 2241 + hdr_desc->hdr.l4_len = (u8)hdr_len[2]; 2242 + hdr_desc->hdr.flag = hdr_field << 1; 2232 2243 } 2233 2244 memcpy(data, cur, tmp); 2234 2245 tmp_len -= tmp; 2235 - *scrq_arr = hdr_desc; 2236 - scrq_arr++; 2237 2246 num_descs++; 2238 2247 } 2239 2248 ··· 2254 2267 int *num_entries, u8 hdr_field) 2255 2268 { 2256 2269 int hdr_len[3] = {0, 0, 0}; 2257 - u8 hdr_data[140] = {0}; 2258 2270 int tot_len; 2259 2271 2260 - tot_len = build_hdr_data(hdr_field, skb, hdr_len, 2261 - hdr_data); 2262 - *num_entries += create_hdr_descs(hdr_field, hdr_data, tot_len, hdr_len, 2263 - indir_arr + 1); 2272 + tot_len = get_hdr_lens(hdr_field, skb, hdr_len); 2273 + *num_entries += create_hdr_descs(hdr_field, skb_mac_header(skb), 2274 + tot_len, hdr_len, indir_arr + 1); 2264 2275 } 2265 2276 2266 2277 static int ibmvnic_xmit_workarounds(struct sk_buff *skb, ··· 2335 2350 } 2336 2351 } 2337 2352 2353 + static int send_subcrq_direct(struct ibmvnic_adapter *adapter, 2354 + u64 remote_handle, u64 *entry) 2355 + { 2356 + unsigned int ua = adapter->vdev->unit_address; 2357 + struct device *dev = &adapter->vdev->dev; 2358 + int rc; 2359 + 2360 + /* Make sure the hypervisor sees the complete request */ 2361 + dma_wmb(); 2362 + rc = plpar_hcall_norets(H_SEND_SUB_CRQ, ua, 2363 + cpu_to_be64(remote_handle), 2364 + cpu_to_be64(entry[0]), cpu_to_be64(entry[1]), 2365 + cpu_to_be64(entry[2]), cpu_to_be64(entry[3])); 2366 + 2367 + if (rc) 2368 + print_subcrq_error(dev, rc, __func__); 2369 + 2370 + return rc; 2371 + } 2372 + 2338 2373 static int ibmvnic_tx_scrq_flush(struct ibmvnic_adapter *adapter, 2339 - struct ibmvnic_sub_crq_queue *tx_scrq) 2374 + struct ibmvnic_sub_crq_queue *tx_scrq, 2375 + bool indirect) 2340 2376 { 2341 2377 struct ibmvnic_ind_xmit_queue *ind_bufp; 2342 2378 u64 dma_addr; ··· 2372 2366 2373 2367 if (!entries) 2374 2368 return 0; 2375 - rc = send_subcrq_indirect(adapter, handle, dma_addr, entries); 2369 + 2370 + if (indirect) 2371 + rc = send_subcrq_indirect(adapter, handle, dma_addr, entries); 2372 + else 2373 + rc = send_subcrq_direct(adapter, handle, 2374 + (u64 *)ind_bufp->indir_arr); 2375 + 2376 2376 if (rc) 2377 2377 ibmvnic_tx_scrq_clean_buffer(adapter, tx_scrq); 2378 2378 else ··· 2409 2397 unsigned long lpar_rc; 2410 2398 union sub_crq tx_crq; 2411 2399 unsigned int offset; 2400 + bool use_scrq_send_direct = false; 2412 2401 int num_entries = 1; 2413 2402 unsigned char *dst; 2414 2403 int bufidx = 0; ··· 2437 2424 tx_dropped++; 2438 2425 tx_send_failed++; 2439 2426 ret = NETDEV_TX_OK; 2440 - lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq); 2427 + lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq, true); 2441 2428 if (lpar_rc != H_SUCCESS) 2442 2429 goto tx_err; 2443 2430 goto out; ··· 2455 2442 tx_send_failed++; 2456 2443 tx_dropped++; 2457 2444 ret = NETDEV_TX_OK; 2458 - lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq); 2445 + lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq, true); 2459 2446 if (lpar_rc != H_SUCCESS) 2460 2447 goto tx_err; 2461 2448 goto out; ··· 2468 2455 dst = ltb->buff + offset; 2469 2456 memset(dst, 0, tx_pool->buf_size); 2470 2457 data_dma_addr = ltb->addr + offset; 2458 + 2459 + /* if we are going to send_subcrq_direct this then we need to 2460 + * update the checksum before copying the data into ltb. Essentially 2461 + * these packets force disable CSO so that we can guarantee that 2462 + * FW does not need header info and we can send direct. 2463 + */ 2464 + if (!skb_is_gso(skb) && !ind_bufp->index && !netdev_xmit_more()) { 2465 + use_scrq_send_direct = true; 2466 + if (skb->ip_summed == CHECKSUM_PARTIAL && 2467 + skb_checksum_help(skb)) 2468 + use_scrq_send_direct = false; 2469 + } 2471 2470 2472 2471 if (skb_shinfo(skb)->nr_frags) { 2473 2472 int cur, i; ··· 2499 2474 } else { 2500 2475 skb_copy_from_linear_data(skb, dst, skb->len); 2501 2476 } 2502 - 2503 - /* post changes to long_term_buff *dst before VIOS accessing it */ 2504 - dma_wmb(); 2505 2477 2506 2478 tx_pool->consumer_index = 2507 2479 (tx_pool->consumer_index + 1) % tx_pool->num_buffers; ··· 2562 2540 tx_crq.v1.flags1 |= IBMVNIC_TX_LSO; 2563 2541 tx_crq.v1.mss = cpu_to_be16(skb_shinfo(skb)->gso_size); 2564 2542 hdrs += 2; 2543 + } else if (use_scrq_send_direct) { 2544 + /* See above comment, CSO disabled with direct xmit */ 2545 + tx_crq.v1.flags1 &= ~(IBMVNIC_TX_CHKSUM_OFFLOAD); 2546 + ind_bufp->index = 1; 2547 + tx_buff->num_entries = 1; 2548 + netdev_tx_sent_queue(txq, skb->len); 2549 + ind_bufp->indir_arr[0] = tx_crq; 2550 + lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq, false); 2551 + if (lpar_rc != H_SUCCESS) 2552 + goto tx_err; 2553 + 2554 + goto early_exit; 2565 2555 } 2566 2556 2567 2557 if ((*hdrs >> 7) & 1) ··· 2583 2549 tx_buff->num_entries = num_entries; 2584 2550 /* flush buffer if current entry can not fit */ 2585 2551 if (num_entries + ind_bufp->index > IBMVNIC_MAX_IND_DESCS) { 2586 - lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq); 2552 + lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq, true); 2587 2553 if (lpar_rc != H_SUCCESS) 2588 2554 goto tx_flush_err; 2589 2555 } ··· 2591 2557 indir_arr[0] = tx_crq; 2592 2558 memcpy(&ind_bufp->indir_arr[ind_bufp->index], &indir_arr[0], 2593 2559 num_entries * sizeof(struct ibmvnic_generic_scrq)); 2560 + 2594 2561 ind_bufp->index += num_entries; 2595 2562 if (__netdev_tx_sent_queue(txq, skb->len, 2596 2563 netdev_xmit_more() && 2597 2564 ind_bufp->index < IBMVNIC_MAX_IND_DESCS)) { 2598 - lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq); 2565 + lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq, true); 2599 2566 if (lpar_rc != H_SUCCESS) 2600 2567 goto tx_err; 2601 2568 } 2602 2569 2570 + early_exit: 2603 2571 if (atomic_add_return(num_entries, &tx_scrq->used) 2604 2572 >= adapter->req_tx_entries_per_subcrq) { 2605 2573 netdev_dbg(netdev, "Stopping queue %d\n", queue_num); ··· 3563 3527 } 3564 3528 3565 3529 if (adapter->state != VNIC_CLOSING && 3566 - ((atomic_read(&adapter->rx_pool[scrq_num].available) < 3567 - adapter->req_rx_add_entries_per_subcrq / 2) || 3568 - frames_processed < budget)) 3530 + (atomic_read(&adapter->rx_pool[scrq_num].available) < 3531 + adapter->req_rx_add_entries_per_subcrq / 2)) 3569 3532 replenish_rx_pool(adapter, &adapter->rx_pool[scrq_num]); 3570 3533 if (frames_processed < budget) { 3571 3534 if (napi_complete_done(napi, frames_processed)) { ··· 4204 4169 struct ibmvnic_sub_crq_queue *scrq) 4205 4170 { 4206 4171 struct device *dev = &adapter->vdev->dev; 4172 + int num_packets = 0, total_bytes = 0; 4207 4173 struct ibmvnic_tx_pool *tx_pool; 4208 4174 struct ibmvnic_tx_buff *txbuff; 4209 4175 struct netdev_queue *txq; 4210 4176 union sub_crq *next; 4211 - int index; 4212 - int i; 4177 + int index, i; 4213 4178 4214 4179 restart_loop: 4215 4180 while (pending_scrq(adapter, scrq)) { 4216 4181 unsigned int pool = scrq->pool_index; 4217 4182 int num_entries = 0; 4218 - int total_bytes = 0; 4219 - int num_packets = 0; 4220 - 4221 4183 next = ibmvnic_next_scrq(adapter, scrq); 4222 4184 for (i = 0; i < next->tx_comp.num_comps; i++) { 4223 4185 index = be32_to_cpu(next->tx_comp.correlators[i]); ··· 4250 4218 /* remove tx_comp scrq*/ 4251 4219 next->tx_comp.first = 0; 4252 4220 4253 - txq = netdev_get_tx_queue(adapter->netdev, scrq->pool_index); 4254 - netdev_tx_completed_queue(txq, num_packets, total_bytes); 4255 4221 4256 4222 if (atomic_sub_return(num_entries, &scrq->used) <= 4257 4223 (adapter->req_tx_entries_per_subcrq / 2) && ··· 4273 4243 disable_scrq_irq(adapter, scrq); 4274 4244 goto restart_loop; 4275 4245 } 4246 + 4247 + txq = netdev_get_tx_queue(adapter->netdev, scrq->pool_index); 4248 + netdev_tx_completed_queue(txq, num_packets, total_bytes); 4276 4249 4277 4250 return 0; 4278 4251 }