Commit 147e81ec authored by Jesse Brandeburg's avatar Jesse Brandeburg Committed by Jeff Kirsher

i40e: Test memory before ethtool alloc succeeds

When testing on systems with very limited amounts of RAM, a bug was
found where, while changing the number of descriptors using ethtool,
the driver didn't test the limits of system memory before permanently
assuming it would be able to get receive buffer memory.

Work around this issue by pre-allocation of the receive buffer
memory, in the "ghost" ring, which is then used during reinit
using the new ring length.

Change-Id: I92d7a5fb59a6c884b2efdd1ec652845f101c3359
Signed-off-by: default avatarJesse Brandeburg <jesse.brandeburg@intel.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent b163098e
...@@ -1274,6 +1274,13 @@ static int i40e_set_ringparam(struct net_device *netdev, ...@@ -1274,6 +1274,13 @@ static int i40e_set_ringparam(struct net_device *netdev,
} }
for (i = 0; i < vsi->num_queue_pairs; i++) { 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 */ /* clone ring and setup updated count */
rx_rings[i] = *vsi->rx_rings[i]; rx_rings[i] = *vsi->rx_rings[i];
rx_rings[i].count = new_rx_count; rx_rings[i].count = new_rx_count;
...@@ -1282,12 +1289,22 @@ static int i40e_set_ringparam(struct net_device *netdev, ...@@ -1282,12 +1289,22 @@ static int i40e_set_ringparam(struct net_device *netdev,
*/ */
rx_rings[i].desc = NULL; rx_rings[i].desc = NULL;
rx_rings[i].rx_bi = NULL; rx_rings[i].rx_bi = NULL;
rx_rings[i].tail = (u8 __iomem *)&faketail;
err = i40e_setup_rx_descriptors(&rx_rings[i]); 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) { if (err) {
while (i) { do {
i--;
i40e_free_rx_resources(&rx_rings[i]); i40e_free_rx_resources(&rx_rings[i]);
} } while (i--);
kfree(rx_rings); kfree(rx_rings);
rx_rings = NULL; rx_rings = NULL;
...@@ -1313,6 +1330,17 @@ static int i40e_set_ringparam(struct net_device *netdev, ...@@ -1313,6 +1330,17 @@ static int i40e_set_ringparam(struct net_device *netdev,
if (rx_rings) { if (rx_rings) {
for (i = 0; i < vsi->num_queue_pairs; i++) { for (i = 0; i < vsi->num_queue_pairs; i++) {
i40e_free_rx_resources(vsi->rx_rings[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]; *vsi->rx_rings[i] = rx_rings[i];
} }
kfree(rx_rings); kfree(rx_rings);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment