|
@@ -1274,6 +1274,13 @@ static int i40e_set_ringparam(struct net_device *netdev,
|
|
|
}
|
|
|
|
|
|
for (i = 0; i < vsi->num_queue_pairs; i++) {
|
|
|
+ /* this is to allow wr32 to have something to write to
|
|
|
+ * during early allocation of Rx buffers
|
|
|
+ */
|
|
|
+ u32 __iomem faketail = 0;
|
|
|
+ struct i40e_ring *ring;
|
|
|
+ u16 unused;
|
|
|
+
|
|
|
/* clone ring and setup updated count */
|
|
|
rx_rings[i] = *vsi->rx_rings[i];
|
|
|
rx_rings[i].count = new_rx_count;
|
|
@@ -1282,12 +1289,22 @@ static int i40e_set_ringparam(struct net_device *netdev,
|
|
|
*/
|
|
|
rx_rings[i].desc = NULL;
|
|
|
rx_rings[i].rx_bi = NULL;
|
|
|
+ rx_rings[i].tail = (u8 __iomem *)&faketail;
|
|
|
err = i40e_setup_rx_descriptors(&rx_rings[i]);
|
|
|
+ if (err)
|
|
|
+ goto rx_unwind;
|
|
|
+
|
|
|
+ /* now allocate the Rx buffers to make sure the OS
|
|
|
+ * has enough memory, any failure here means abort
|
|
|
+ */
|
|
|
+ ring = &rx_rings[i];
|
|
|
+ unused = I40E_DESC_UNUSED(ring);
|
|
|
+ err = i40e_alloc_rx_buffers(ring, unused);
|
|
|
+rx_unwind:
|
|
|
if (err) {
|
|
|
- while (i) {
|
|
|
- i--;
|
|
|
+ do {
|
|
|
i40e_free_rx_resources(&rx_rings[i]);
|
|
|
- }
|
|
|
+ } while (i--);
|
|
|
kfree(rx_rings);
|
|
|
rx_rings = NULL;
|
|
|
|
|
@@ -1313,6 +1330,17 @@ static int i40e_set_ringparam(struct net_device *netdev,
|
|
|
if (rx_rings) {
|
|
|
for (i = 0; i < vsi->num_queue_pairs; i++) {
|
|
|
i40e_free_rx_resources(vsi->rx_rings[i]);
|
|
|
+ /* get the real tail offset */
|
|
|
+ rx_rings[i].tail = vsi->rx_rings[i]->tail;
|
|
|
+ /* this is to fake out the allocation routine
|
|
|
+ * into thinking it has to realloc everything
|
|
|
+ * but the recycling logic will let us re-use
|
|
|
+ * the buffers allocated above
|
|
|
+ */
|
|
|
+ rx_rings[i].next_to_use = 0;
|
|
|
+ rx_rings[i].next_to_clean = 0;
|
|
|
+ rx_rings[i].next_to_alloc = 0;
|
|
|
+ /* do a struct copy */
|
|
|
*vsi->rx_rings[i] = rx_rings[i];
|
|
|
}
|
|
|
kfree(rx_rings);
|