Skip to content

Commit f3ce29e

Browse files
vladimirolteankuba-moo
authored andcommitted
net: enetc: split ring resource allocation from assignment
We have a few instances in the enetc driver where the ring resources (BD ring iomem, software BD ring, software TSO headers, basically everything except RX buffers) need to be reallocated. For example, when RX timestamping is enabled, the RX BD format changes to an extended one (twice as large). Currently, this is done using a simplistic enetc_close() -> enetc_open() procedure. But this is quite crude, since it also invokes phylink_stop() -> phylink_start(), the link is lost, and a few seconds need to pass for autoneg to complete again. In fact it's bad also due to the improper (yolo) error checking. In case we fail to allocate new resources, we've already freed the old ones, so the interface is more or less stuck. To avoid that, we need a system where reconfiguration is possible in a way in which resources are allocated upfront. This means that there will be a higher memory usage temporarily, but the assignment of resources to rings can be done when both the old and new resources are still available. Introduce a struct enetc_bdr_resource which holds the resources for a ring, be it RX or TX. This structure duplicates a lot of fields from struct enetc_bdr (and access to the same fields in the ring structure was left duplicated, to not change cache characteristics in the fast path). When enetc_alloc_tx_resources() runs, it returns an array of resource elements (one per TX ring), in addition to the existing priv->tx_res. To populate priv->tx_res with that array, one must call enetc_assign_tx_resources(), and this also frees the old resources. Signed-off-by: Vladimir Oltean <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent d075db5 commit f3ce29e

File tree

2 files changed

+180
-70
lines changed

2 files changed

+180
-70
lines changed

drivers/net/ethernet/freescale/enetc/enetc.c

Lines changed: 161 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1715,157 +1715,238 @@ void enetc_get_si_caps(struct enetc_si *si)
17151715
si->hw_features |= ENETC_SI_F_PSFP;
17161716
}
17171717

1718-
static int enetc_dma_alloc_bdr(struct enetc_bdr *r, size_t bd_size)
1718+
static int enetc_dma_alloc_bdr(struct enetc_bdr_resource *res)
17191719
{
1720-
r->bd_base = dma_alloc_coherent(r->dev, r->bd_count * bd_size,
1721-
&r->bd_dma_base, GFP_KERNEL);
1722-
if (!r->bd_base)
1720+
size_t bd_base_size = res->bd_count * res->bd_size;
1721+
1722+
res->bd_base = dma_alloc_coherent(res->dev, bd_base_size,
1723+
&res->bd_dma_base, GFP_KERNEL);
1724+
if (!res->bd_base)
17231725
return -ENOMEM;
17241726

17251727
/* h/w requires 128B alignment */
1726-
if (!IS_ALIGNED(r->bd_dma_base, 128)) {
1727-
dma_free_coherent(r->dev, r->bd_count * bd_size, r->bd_base,
1728-
r->bd_dma_base);
1728+
if (!IS_ALIGNED(res->bd_dma_base, 128)) {
1729+
dma_free_coherent(res->dev, bd_base_size, res->bd_base,
1730+
res->bd_dma_base);
17291731
return -EINVAL;
17301732
}
17311733

17321734
return 0;
17331735
}
17341736

1735-
static void enetc_dma_free_bdr(struct enetc_bdr *r, size_t bd_size)
1737+
static void enetc_dma_free_bdr(const struct enetc_bdr_resource *res)
17361738
{
1737-
dma_free_coherent(r->dev, r->bd_count * bd_size, r->bd_base,
1738-
r->bd_dma_base);
1739-
r->bd_base = NULL;
1739+
size_t bd_base_size = res->bd_count * res->bd_size;
1740+
1741+
dma_free_coherent(res->dev, bd_base_size, res->bd_base,
1742+
res->bd_dma_base);
17401743
}
17411744

1742-
static int enetc_alloc_txbdr(struct enetc_bdr *txr)
1745+
static int enetc_alloc_tx_resource(struct enetc_bdr_resource *res,
1746+
struct device *dev, size_t bd_count)
17431747
{
17441748
int err;
17451749

1746-
txr->tx_swbd = vzalloc(txr->bd_count * sizeof(struct enetc_tx_swbd));
1747-
if (!txr->tx_swbd)
1750+
res->dev = dev;
1751+
res->bd_count = bd_count;
1752+
res->bd_size = sizeof(union enetc_tx_bd);
1753+
1754+
res->tx_swbd = vzalloc(bd_count * sizeof(*res->tx_swbd));
1755+
if (!res->tx_swbd)
17481756
return -ENOMEM;
17491757

1750-
err = enetc_dma_alloc_bdr(txr, sizeof(union enetc_tx_bd));
1758+
err = enetc_dma_alloc_bdr(res);
17511759
if (err)
17521760
goto err_alloc_bdr;
17531761

1754-
txr->tso_headers = dma_alloc_coherent(txr->dev,
1755-
txr->bd_count * TSO_HEADER_SIZE,
1756-
&txr->tso_headers_dma,
1762+
res->tso_headers = dma_alloc_coherent(dev, bd_count * TSO_HEADER_SIZE,
1763+
&res->tso_headers_dma,
17571764
GFP_KERNEL);
1758-
if (!txr->tso_headers) {
1765+
if (!res->tso_headers) {
17591766
err = -ENOMEM;
17601767
goto err_alloc_tso;
17611768
}
17621769

17631770
return 0;
17641771

17651772
err_alloc_tso:
1766-
enetc_dma_free_bdr(txr, sizeof(union enetc_tx_bd));
1773+
enetc_dma_free_bdr(res);
17671774
err_alloc_bdr:
1768-
vfree(txr->tx_swbd);
1769-
txr->tx_swbd = NULL;
1775+
vfree(res->tx_swbd);
1776+
res->tx_swbd = NULL;
17701777

17711778
return err;
17721779
}
17731780

1774-
static void enetc_free_txbdr(struct enetc_bdr *txr)
1781+
static void enetc_free_tx_resource(const struct enetc_bdr_resource *res)
17751782
{
1776-
dma_free_coherent(txr->dev, txr->bd_count * TSO_HEADER_SIZE,
1777-
txr->tso_headers, txr->tso_headers_dma);
1778-
txr->tso_headers = NULL;
1779-
1780-
enetc_dma_free_bdr(txr, sizeof(union enetc_tx_bd));
1781-
1782-
vfree(txr->tx_swbd);
1783-
txr->tx_swbd = NULL;
1783+
dma_free_coherent(res->dev, res->bd_count * TSO_HEADER_SIZE,
1784+
res->tso_headers, res->tso_headers_dma);
1785+
enetc_dma_free_bdr(res);
1786+
vfree(res->tx_swbd);
17841787
}
17851788

1786-
static int enetc_alloc_tx_resources(struct enetc_ndev_priv *priv)
1789+
static struct enetc_bdr_resource *
1790+
enetc_alloc_tx_resources(struct enetc_ndev_priv *priv)
17871791
{
1792+
struct enetc_bdr_resource *tx_res;
17881793
int i, err;
17891794

1795+
tx_res = kcalloc(priv->num_tx_rings, sizeof(*tx_res), GFP_KERNEL);
1796+
if (!tx_res)
1797+
return ERR_PTR(-ENOMEM);
1798+
17901799
for (i = 0; i < priv->num_tx_rings; i++) {
1791-
err = enetc_alloc_txbdr(priv->tx_ring[i]);
1800+
struct enetc_bdr *tx_ring = priv->tx_ring[i];
17921801

1802+
err = enetc_alloc_tx_resource(&tx_res[i], tx_ring->dev,
1803+
tx_ring->bd_count);
17931804
if (err)
17941805
goto fail;
17951806
}
17961807

1797-
return 0;
1808+
return tx_res;
17981809

17991810
fail:
18001811
while (i-- > 0)
1801-
enetc_free_txbdr(priv->tx_ring[i]);
1812+
enetc_free_tx_resource(&tx_res[i]);
18021813

1803-
return err;
1814+
kfree(tx_res);
1815+
1816+
return ERR_PTR(err);
18041817
}
18051818

1806-
static void enetc_free_tx_resources(struct enetc_ndev_priv *priv)
1819+
static void enetc_free_tx_resources(const struct enetc_bdr_resource *tx_res,
1820+
size_t num_resources)
18071821
{
1808-
int i;
1822+
size_t i;
18091823

1810-
for (i = 0; i < priv->num_tx_rings; i++)
1811-
enetc_free_txbdr(priv->tx_ring[i]);
1824+
for (i = 0; i < num_resources; i++)
1825+
enetc_free_tx_resource(&tx_res[i]);
1826+
1827+
kfree(tx_res);
18121828
}
18131829

1814-
static int enetc_alloc_rxbdr(struct enetc_bdr *rxr, bool extended)
1830+
static int enetc_alloc_rx_resource(struct enetc_bdr_resource *res,
1831+
struct device *dev, size_t bd_count,
1832+
bool extended)
18151833
{
1816-
size_t size = sizeof(union enetc_rx_bd);
18171834
int err;
18181835

1819-
rxr->rx_swbd = vzalloc(rxr->bd_count * sizeof(struct enetc_rx_swbd));
1820-
if (!rxr->rx_swbd)
1821-
return -ENOMEM;
1822-
1836+
res->dev = dev;
1837+
res->bd_count = bd_count;
1838+
res->bd_size = sizeof(union enetc_rx_bd);
18231839
if (extended)
1824-
size *= 2;
1840+
res->bd_size *= 2;
18251841

1826-
err = enetc_dma_alloc_bdr(rxr, size);
1842+
res->rx_swbd = vzalloc(bd_count * sizeof(struct enetc_rx_swbd));
1843+
if (!res->rx_swbd)
1844+
return -ENOMEM;
1845+
1846+
err = enetc_dma_alloc_bdr(res);
18271847
if (err) {
1828-
vfree(rxr->rx_swbd);
1848+
vfree(res->rx_swbd);
18291849
return err;
18301850
}
18311851

18321852
return 0;
18331853
}
18341854

1835-
static void enetc_free_rxbdr(struct enetc_bdr *rxr)
1855+
static void enetc_free_rx_resource(const struct enetc_bdr_resource *res)
18361856
{
1837-
enetc_dma_free_bdr(rxr, sizeof(union enetc_rx_bd));
1838-
1839-
vfree(rxr->rx_swbd);
1840-
rxr->rx_swbd = NULL;
1857+
enetc_dma_free_bdr(res);
1858+
vfree(res->rx_swbd);
18411859
}
18421860

1843-
static int enetc_alloc_rx_resources(struct enetc_ndev_priv *priv, bool extended)
1861+
static struct enetc_bdr_resource *
1862+
enetc_alloc_rx_resources(struct enetc_ndev_priv *priv, bool extended)
18441863
{
1864+
struct enetc_bdr_resource *rx_res;
18451865
int i, err;
18461866

1867+
rx_res = kcalloc(priv->num_rx_rings, sizeof(*rx_res), GFP_KERNEL);
1868+
if (!rx_res)
1869+
return ERR_PTR(-ENOMEM);
1870+
18471871
for (i = 0; i < priv->num_rx_rings; i++) {
1848-
err = enetc_alloc_rxbdr(priv->rx_ring[i], extended);
1872+
struct enetc_bdr *rx_ring = priv->rx_ring[i];
18491873

1874+
err = enetc_alloc_rx_resource(&rx_res[i], rx_ring->dev,
1875+
rx_ring->bd_count, extended);
18501876
if (err)
18511877
goto fail;
18521878
}
18531879

1854-
return 0;
1880+
return rx_res;
18551881

18561882
fail:
18571883
while (i-- > 0)
1858-
enetc_free_rxbdr(priv->rx_ring[i]);
1884+
enetc_free_rx_resource(&rx_res[i]);
18591885

1860-
return err;
1886+
kfree(rx_res);
1887+
1888+
return ERR_PTR(err);
1889+
}
1890+
1891+
static void enetc_free_rx_resources(const struct enetc_bdr_resource *rx_res,
1892+
size_t num_resources)
1893+
{
1894+
size_t i;
1895+
1896+
for (i = 0; i < num_resources; i++)
1897+
enetc_free_rx_resource(&rx_res[i]);
1898+
1899+
kfree(rx_res);
18611900
}
18621901

1863-
static void enetc_free_rx_resources(struct enetc_ndev_priv *priv)
1902+
static void enetc_assign_tx_resource(struct enetc_bdr *tx_ring,
1903+
const struct enetc_bdr_resource *res)
1904+
{
1905+
tx_ring->bd_base = res ? res->bd_base : NULL;
1906+
tx_ring->bd_dma_base = res ? res->bd_dma_base : 0;
1907+
tx_ring->tx_swbd = res ? res->tx_swbd : NULL;
1908+
tx_ring->tso_headers = res ? res->tso_headers : NULL;
1909+
tx_ring->tso_headers_dma = res ? res->tso_headers_dma : 0;
1910+
}
1911+
1912+
static void enetc_assign_rx_resource(struct enetc_bdr *rx_ring,
1913+
const struct enetc_bdr_resource *res)
1914+
{
1915+
rx_ring->bd_base = res ? res->bd_base : NULL;
1916+
rx_ring->bd_dma_base = res ? res->bd_dma_base : 0;
1917+
rx_ring->rx_swbd = res ? res->rx_swbd : NULL;
1918+
}
1919+
1920+
static void enetc_assign_tx_resources(struct enetc_ndev_priv *priv,
1921+
const struct enetc_bdr_resource *res)
18641922
{
18651923
int i;
18661924

1867-
for (i = 0; i < priv->num_rx_rings; i++)
1868-
enetc_free_rxbdr(priv->rx_ring[i]);
1925+
if (priv->tx_res)
1926+
enetc_free_tx_resources(priv->tx_res, priv->num_tx_rings);
1927+
1928+
for (i = 0; i < priv->num_tx_rings; i++) {
1929+
enetc_assign_tx_resource(priv->tx_ring[i],
1930+
res ? &res[i] : NULL);
1931+
}
1932+
1933+
priv->tx_res = res;
1934+
}
1935+
1936+
static void enetc_assign_rx_resources(struct enetc_ndev_priv *priv,
1937+
const struct enetc_bdr_resource *res)
1938+
{
1939+
int i;
1940+
1941+
if (priv->rx_res)
1942+
enetc_free_rx_resources(priv->rx_res, priv->num_rx_rings);
1943+
1944+
for (i = 0; i < priv->num_rx_rings; i++) {
1945+
enetc_assign_rx_resource(priv->rx_ring[i],
1946+
res ? &res[i] : NULL);
1947+
}
1948+
1949+
priv->rx_res = res;
18691950
}
18701951

18711952
static void enetc_free_tx_ring(struct enetc_bdr *tx_ring)
@@ -2306,6 +2387,7 @@ void enetc_start(struct net_device *ndev)
23062387
int enetc_open(struct net_device *ndev)
23072388
{
23082389
struct enetc_ndev_priv *priv = netdev_priv(ndev);
2390+
struct enetc_bdr_resource *tx_res, *rx_res;
23092391
int num_stack_tx_queues;
23102392
bool extended;
23112393
int err;
@@ -2320,13 +2402,17 @@ int enetc_open(struct net_device *ndev)
23202402
if (err)
23212403
goto err_phy_connect;
23222404

2323-
err = enetc_alloc_tx_resources(priv);
2324-
if (err)
2405+
tx_res = enetc_alloc_tx_resources(priv);
2406+
if (IS_ERR(tx_res)) {
2407+
err = PTR_ERR(tx_res);
23252408
goto err_alloc_tx;
2409+
}
23262410

2327-
err = enetc_alloc_rx_resources(priv, extended);
2328-
if (err)
2411+
rx_res = enetc_alloc_rx_resources(priv, extended);
2412+
if (IS_ERR(rx_res)) {
2413+
err = PTR_ERR(rx_res);
23292414
goto err_alloc_rx;
2415+
}
23302416

23312417
num_stack_tx_queues = enetc_num_stack_tx_queues(priv);
23322418

@@ -2339,15 +2425,17 @@ int enetc_open(struct net_device *ndev)
23392425
goto err_set_queues;
23402426

23412427
enetc_tx_onestep_tstamp_init(priv);
2428+
enetc_assign_tx_resources(priv, tx_res);
2429+
enetc_assign_rx_resources(priv, rx_res);
23422430
enetc_setup_bdrs(priv, extended);
23432431
enetc_start(ndev);
23442432

23452433
return 0;
23462434

23472435
err_set_queues:
2348-
enetc_free_rx_resources(priv);
2436+
enetc_free_rx_resources(rx_res, priv->num_rx_rings);
23492437
err_alloc_rx:
2350-
enetc_free_tx_resources(priv);
2438+
enetc_free_tx_resources(tx_res, priv->num_tx_rings);
23512439
err_alloc_tx:
23522440
if (priv->phylink)
23532441
phylink_disconnect_phy(priv->phylink);
@@ -2391,8 +2479,11 @@ int enetc_close(struct net_device *ndev)
23912479
if (priv->phylink)
23922480
phylink_disconnect_phy(priv->phylink);
23932481
enetc_free_rxtx_rings(priv);
2394-
enetc_free_rx_resources(priv);
2395-
enetc_free_tx_resources(priv);
2482+
2483+
/* Avoids dangling pointers and also frees old resources */
2484+
enetc_assign_rx_resources(priv, NULL);
2485+
enetc_assign_tx_resources(priv, NULL);
2486+
23962487
enetc_free_irqs(priv);
23972488

23982489
return 0;

drivers/net/ethernet/freescale/enetc/enetc.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,23 @@ struct enetc_xdp_data {
8585
#define ENETC_TX_RING_DEFAULT_SIZE 2048
8686
#define ENETC_DEFAULT_TX_WORK (ENETC_TX_RING_DEFAULT_SIZE / 2)
8787

88+
struct enetc_bdr_resource {
89+
/* Input arguments saved for teardown */
90+
struct device *dev; /* for DMA mapping */
91+
size_t bd_count;
92+
size_t bd_size;
93+
94+
/* Resource proper */
95+
void *bd_base; /* points to Rx or Tx BD ring */
96+
dma_addr_t bd_dma_base;
97+
union {
98+
struct enetc_tx_swbd *tx_swbd;
99+
struct enetc_rx_swbd *rx_swbd;
100+
};
101+
char *tso_headers;
102+
dma_addr_t tso_headers_dma;
103+
};
104+
88105
struct enetc_bdr {
89106
struct device *dev; /* for DMA mapping */
90107
struct net_device *ndev;
@@ -344,6 +361,8 @@ struct enetc_ndev_priv {
344361
struct enetc_bdr **xdp_tx_ring;
345362
struct enetc_bdr *tx_ring[16];
346363
struct enetc_bdr *rx_ring[16];
364+
const struct enetc_bdr_resource *tx_res;
365+
const struct enetc_bdr_resource *rx_res;
347366

348367
struct enetc_cls_rule *cls_rules;
349368

0 commit comments

Comments
 (0)