Including fixes from Netfilter.

Steady stream of fixes. Last two weeks feel comparable to the two
 weeks before the merge window. Lots of AI-aided bug discovery.
 A newer big source is Sashiko/Gemini (Roman Gushchin's system),
 which points out issues in existing code during patch review
 (maybe 25% of fixes here likely originating from Sashiko).
 Nice thing is these are often fixed by the respective maintainers,
 not drive-bys.
 
 Current release - new code bugs:
 
  - kconfig: MDIO_PIC64HPSC should depend on ARCH_MICROCHIP
 
 Previous releases - regressions:
 
  - add async ndo_set_rx_mode and switch drivers which we promised
    to be called under the per-netdev mutex to it
 
  - dsa: remove duplicate netdev_lock_ops() for conduit ethtool ops
 
  - hv_sock: report EOF instead of -EIO for FIN
 
  - vsock/virtio: fix MSG_PEEK calculation on bytes to copy
 
 Previous releases - always broken:
 
  - ipv6: fix possible UAF in icmpv6_rcv()
 
  - icmp: validate reply type before using icmp_pointers
 
  - af_unix: drop all SCM attributes for SOCKMAP
 
  - netfilter: fix a number of bugs in the osf (OS fingerprinting)
 
  - eth: intel: fix timestamp interrupt configuration for E825C
 
 Misc:
 
  - bunch of data-race annotations
 
 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE6jPA+I1ugmIBA4hXMUZtbf5SIrsFAmnqkmMACgkQMUZtbf5S
 Iruqig/+NSg/YwEkZLbSaW+0LqNMIdOVZPdves97YAvNRdcKvgAPB5I13/G+koCz
 bRpmtdDLYTkfMFLaM582DO6XeO3Hsz/BrRRuRbyEz7lTi7PtxTEs1J+6W6NxGOQ2
 30f3J7OGudGlinsFV9VkJe81rvFbKZFZ9fGPmOcVzzzfLvT3rrt20iVvMOyM+PpD
 H0ixFW+myescEx6AQoGcVs/sDveJ4bpLpNG3p4gADh3Laj9HKSl00kudCIOQ1Kdy
 SEHsSZs3A87ueOnGwIBl/x24zVWGTGHyKcmc5ENPUSIaNGOWzmBxvfhb5dZ989RQ
 HQix+FMue21k4JypYwrdhU3MAnMDPLk+FDp4XJuwJ5I/caNLZXS2geIlnXOI5IFJ
 ojuq4pF5njoWtvkWGvxxRM+shIMiDUYUK+k9xTMqmge88O9ahGIAYb2qyKL+P6Sl
 mMuSRcArk6pw3lPbUA4u1wEaU52IdxRJDPQA/Ai3O5UVTfemJO/VqawQfuBE274g
 KZXG4x0lwE+LSyoguTnSqhMCJk1ZXAeHjtpz1Yo3CEHOwCH9MxEEL/dldAXWZiWN
 K0nLcUQ8fg3GnmOEzYw1gzDVJrgkR1eIrh6OCpw+UGCg0Af0HE6C6QBL9q59YhQw
 DjLJAUNM8puBNIh9paCsHf1aIcFpPXBcR5dKoufCQx41x1OOqew=
 =knNy
 -----END PGP SIGNATURE-----

Merge tag 'net-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Pull  networking fixes from Jakub Kicinski:
 "Including fixes from Netfilter.

  Steady stream of fixes. Last two weeks feel comparable to the two
  weeks before the merge window. Lots of AI-aided bug discovery. A newer
  big source is Sashiko/Gemini (Roman Gushchin's system), which points
  out issues in existing code during patch review (maybe 25% of fixes
  here likely originating from Sashiko). Nice thing is these are often
  fixed by the respective maintainers, not drive-bys.

  Current release - new code bugs:

   - kconfig: MDIO_PIC64HPSC should depend on ARCH_MICROCHIP

  Previous releases - regressions:

   - add async ndo_set_rx_mode and switch drivers which we promised to
     be called under the per-netdev mutex to it

   - dsa: remove duplicate netdev_lock_ops() for conduit ethtool ops

   - hv_sock: report EOF instead of -EIO for FIN

   - vsock/virtio: fix MSG_PEEK calculation on bytes to copy

  Previous releases - always broken:

   - ipv6: fix possible UAF in icmpv6_rcv()

   - icmp: validate reply type before using icmp_pointers

   - af_unix: drop all SCM attributes for SOCKMAP

   - netfilter: fix a number of bugs in the osf (OS fingerprinting)

   - eth: intel: fix timestamp interrupt configuration for E825C

  Misc:

   - bunch of data-race annotations"

* tag 'net-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (148 commits)
  rxrpc: Fix error handling in rxgk_extract_token()
  rxrpc: Fix re-decryption of RESPONSE packets
  rxrpc: Fix rxrpc_input_call_event() to only unshare DATA packets
  rxrpc: Fix missing validation of ticket length in non-XDR key preparsing
  rxgk: Fix potential integer overflow in length check
  rxrpc: Fix conn-level packet handling to unshare RESPONSE packets
  rxrpc: Fix potential UAF after skb_unshare() failure
  rxrpc: Fix rxkad crypto unalignment handling
  rxrpc: Fix memory leaks in rxkad_verify_response()
  net: rds: fix MR cleanup on copy error
  m68k: mvme147: Make me the maintainer
  net: txgbe: fix firmware version check
  selftests/bpf: check epoll readiness during reuseport migration
  tcp: call sk_data_ready() after listener migration
  vhost_net: fix sleeping with preempt-disabled in vhost_net_busy_poll()
  ipv6: Cap TLV scan in ip6_tnl_parse_tlv_enc_lim
  tipc: fix double-free in tipc_buf_append()
  llc: Return -EINPROGRESS from llc_ui_connect()
  ipv4: icmp: validate reply type before using icmp_pointers
  selftests/net: packetdrill: cover RFC 5961 5.2 challenge ACK on both edges
  ...
This commit is contained in:
Linus Torvalds 2026-04-23 16:50:42 -07:00
commit e728258deb
172 changed files with 3537 additions and 1417 deletions

View File

@ -289,6 +289,19 @@ ndo_tx_timeout:
ndo_set_rx_mode:
Synchronization: netif_addr_lock spinlock.
Context: BHs disabled
Notes: Deprecated in favor of ndo_set_rx_mode_async which runs
in process context.
ndo_set_rx_mode_async:
Synchronization: rtnl_lock() semaphore. In addition, netdev instance
lock if the driver implements queue management or shaper API.
Context: process (from a work queue)
Notes: Async version of ndo_set_rx_mode which runs in process
context. Receives snapshots of the unicast and multicast address lists.
ndo_change_rx_flags:
Synchronization: rtnl_lock() semaphore. In addition, netdev instance
lock if the driver implements queue management or shaper API.
ndo_setup_tc:
``TC_SETUP_BLOCK`` and ``TC_SETUP_FT`` are running under NFT locks

View File

@ -528,7 +528,7 @@ The exact rules a driver must follow to acquire the ``Supported`` status:
status will be withdrawn.
5. Test failures due to bugs either in the driver or the test itself,
or lack of support for the feature the test is targgeting are
or lack of support for the feature the test is targeting are
*not* a basis for losing the ``Supported`` status.
netdev CI will maintain an official page of supported devices, listing their

View File

@ -15337,6 +15337,13 @@ S: Maintained
W: http://www.tazenda.demon.co.uk/phil/linux-hp
F: arch/m68k/hp300/
M68K ON MVME147
M: Daniel Palmer <daniel@thingy.jp>
S: Maintained
F: arch/m68k/mvme147/
F: drivers/net/ethernet/amd/mvme147.c
F: drivers/scsi/mvme147.*
M88DS3103 MEDIA DRIVER
L: linux-media@vger.kernel.org
S: Orphan

View File

@ -216,7 +216,7 @@
(_extint) == 2 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 : \
0x0)
#define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(_extint) \
(0xF << (((_extint) % 2)))
(0xF << (((_extint) % 2) * 4))
#define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(_extint) \
(((_extint) % 2) * 4)

View File

@ -47,7 +47,9 @@
static int numdummies = 1;
/* fake multicast ability */
static void set_multicast_list(struct net_device *dev)
static void set_multicast_list(struct net_device *dev,
struct netdev_hw_addr_list *uc,
struct netdev_hw_addr_list *mc)
{
}
@ -87,7 +89,7 @@ static const struct net_device_ops dummy_netdev_ops = {
.ndo_init = dummy_dev_init,
.ndo_start_xmit = dummy_xmit,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_rx_mode = set_multicast_list,
.ndo_set_rx_mode_async = set_multicast_list,
.ndo_set_mac_address = eth_mac_addr,
.ndo_get_stats64 = dummy_get_stats64,
.ndo_change_carrier = dummy_change_carrier,

View File

@ -745,14 +745,18 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
dma_addr_t dma_addr;
q->buf_size = PAGE_SIZE / 2;
q->ndesc = ndesc;
q->qdma = qdma;
q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry),
q->entry = devm_kzalloc(eth->dev, ndesc * sizeof(*q->entry),
GFP_KERNEL);
if (!q->entry)
return -ENOMEM;
q->desc = dmam_alloc_coherent(eth->dev, ndesc * sizeof(*q->desc),
&dma_addr, GFP_KERNEL);
if (!q->desc)
return -ENOMEM;
q->page_pool = page_pool_create(&pp_params);
if (IS_ERR(q->page_pool)) {
int err = PTR_ERR(q->page_pool);
@ -761,11 +765,7 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
return err;
}
q->desc = dmam_alloc_coherent(eth->dev, q->ndesc * sizeof(*q->desc),
&dma_addr, GFP_KERNEL);
if (!q->desc)
return -ENOMEM;
q->ndesc = ndesc;
netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll);
airoha_qdma_wr(qdma, REG_RX_RING_BASE(qid), dma_addr);
@ -843,6 +843,21 @@ static int airoha_qdma_init_rx(struct airoha_qdma *qdma)
return 0;
}
static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q)
{
struct airoha_qdma *qdma = q->qdma;
struct airoha_eth *eth = qdma->eth;
int i;
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
if (port && port->qdma == qdma)
netif_tx_wake_all_queues(port->dev);
}
q->txq_stopped = false;
}
static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
{
struct airoha_tx_irq_queue *irq_q;
@ -919,12 +934,21 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
txq = netdev_get_tx_queue(skb->dev, queue);
netdev_tx_completed_queue(txq, 1, skb->len);
if (netif_tx_queue_stopped(txq) &&
q->ndesc - q->queued >= q->free_thr)
netif_tx_wake_queue(txq);
dev_kfree_skb_any(skb);
}
if (q->txq_stopped && q->ndesc - q->queued >= q->free_thr) {
/* Since multiple net_device TX queues can share the
* same hw QDMA TX queue, there is no guarantee we have
* inflight packets queued in hw belonging to a
* net_device TX queue stopped in the xmit path.
* In order to avoid any potential net_device TX queue
* stall, we need to wake all the net_device TX queues
* feeding the same hw QDMA TX queue.
*/
airoha_qdma_wake_netdev_txqs(q);
}
unlock:
spin_unlock_bh(&q->lock);
}
@ -954,27 +978,27 @@ static int airoha_qdma_init_tx_queue(struct airoha_queue *q,
dma_addr_t dma_addr;
spin_lock_init(&q->lock);
q->ndesc = size;
q->qdma = qdma;
q->free_thr = 1 + MAX_SKB_FRAGS;
INIT_LIST_HEAD(&q->tx_list);
q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry),
q->entry = devm_kzalloc(eth->dev, size * sizeof(*q->entry),
GFP_KERNEL);
if (!q->entry)
return -ENOMEM;
q->desc = dmam_alloc_coherent(eth->dev, q->ndesc * sizeof(*q->desc),
q->desc = dmam_alloc_coherent(eth->dev, size * sizeof(*q->desc),
&dma_addr, GFP_KERNEL);
if (!q->desc)
return -ENOMEM;
for (i = 0; i < q->ndesc; i++) {
for (i = 0; i < size; i++) {
u32 val = FIELD_PREP(QDMA_DESC_DONE_MASK, 1);
list_add_tail(&q->entry[i].list, &q->tx_list);
WRITE_ONCE(q->desc[i].ctrl, cpu_to_le32(val));
}
q->ndesc = size;
/* xmit ring drop default setting */
airoha_qdma_set(qdma, REG_TX_RING_BLOCKING(qid),
@ -996,8 +1020,6 @@ static int airoha_qdma_tx_irq_init(struct airoha_tx_irq_queue *irq_q,
struct airoha_eth *eth = qdma->eth;
dma_addr_t dma_addr;
netif_napi_add_tx(eth->napi_dev, &irq_q->napi,
airoha_qdma_tx_napi_poll);
irq_q->q = dmam_alloc_coherent(eth->dev, size * sizeof(u32),
&dma_addr, GFP_KERNEL);
if (!irq_q->q)
@ -1007,6 +1029,9 @@ static int airoha_qdma_tx_irq_init(struct airoha_tx_irq_queue *irq_q,
irq_q->size = size;
irq_q->qdma = qdma;
netif_napi_add_tx(eth->napi_dev, &irq_q->napi,
airoha_qdma_tx_napi_poll);
airoha_qdma_wr(qdma, REG_TX_IRQ_BASE(id), dma_addr);
airoha_qdma_rmw(qdma, REG_TX_IRQ_CFG(id), TX_IRQ_DEPTH_MASK,
FIELD_PREP(TX_IRQ_DEPTH_MASK, size));
@ -1039,12 +1064,15 @@ static int airoha_qdma_init_tx(struct airoha_qdma *qdma)
static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q)
{
struct airoha_eth *eth = q->qdma->eth;
int i;
struct airoha_qdma *qdma = q->qdma;
struct airoha_eth *eth = qdma->eth;
int i, qid = q - &qdma->q_tx[0];
u16 index = 0;
spin_lock_bh(&q->lock);
for (i = 0; i < q->ndesc; i++) {
struct airoha_queue_entry *e = &q->entry[i];
struct airoha_qdma_desc *desc = &q->desc[i];
if (!e->dma_addr)
continue;
@ -1055,8 +1083,33 @@ static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q)
e->dma_addr = 0;
e->skb = NULL;
list_add_tail(&e->list, &q->tx_list);
/* Reset DMA descriptor */
WRITE_ONCE(desc->ctrl, 0);
WRITE_ONCE(desc->addr, 0);
WRITE_ONCE(desc->data, 0);
WRITE_ONCE(desc->msg0, 0);
WRITE_ONCE(desc->msg1, 0);
WRITE_ONCE(desc->msg2, 0);
q->queued--;
}
if (!list_empty(&q->tx_list)) {
struct airoha_queue_entry *e;
e = list_first_entry(&q->tx_list, struct airoha_queue_entry,
list);
index = e - q->entry;
}
/* Set TX_DMA_IDX to TX_CPU_IDX to notify the hw the QDMA TX ring is
* empty.
*/
airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK,
FIELD_PREP(TX_RING_CPU_IDX_MASK, index));
airoha_qdma_rmw(qdma, REG_TX_DMA_IDX(qid), TX_RING_DMA_IDX_MASK,
FIELD_PREP(TX_RING_DMA_IDX_MASK, index));
spin_unlock_bh(&q->lock);
}
@ -1398,8 +1451,12 @@ static void airoha_qdma_cleanup(struct airoha_qdma *qdma)
}
}
for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++)
for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) {
if (!qdma->q_tx_irq[i].size)
continue;
netif_napi_del(&qdma->q_tx_irq[i].napi);
}
for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
if (!qdma->q_tx[i].ndesc)
@ -1727,7 +1784,7 @@ static int airoha_set_gdm2_loopback(struct airoha_gdm_port *port)
{
struct airoha_eth *eth = port->qdma->eth;
u32 val, pse_port, chan;
int src_port;
int i, src_port;
/* Forward the traffic to the proper GDM port */
pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3
@ -1769,6 +1826,9 @@ static int airoha_set_gdm2_loopback(struct airoha_gdm_port *port)
SP_CPORT_MASK(val),
__field_prep(SP_CPORT_MASK(val), FE_PSE_PORT_CDM2));
for (i = 0; i < eth->soc->num_ppe; i++)
airoha_ppe_set_cpu_port(port, i, AIROHA_GDM2_IDX);
if (port->id == AIROHA_GDM4_IDX && airoha_is_7581(eth)) {
u32 mask = FC_ID_OF_SRC_PORT_MASK(port->nbq);
@ -1807,7 +1867,8 @@ static int airoha_dev_init(struct net_device *dev)
}
for (i = 0; i < eth->soc->num_ppe; i++)
airoha_ppe_set_cpu_port(port, i);
airoha_ppe_set_cpu_port(port, i,
airoha_get_fe_port(port));
return 0;
}
@ -1984,6 +2045,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
if (q->queued + nr_frags >= q->ndesc) {
/* not enough space in the queue */
netif_tx_stop_queue(txq);
q->txq_stopped = true;
spin_unlock_bh(&q->lock);
return NETDEV_TX_BUSY;
}
@ -2039,8 +2101,10 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
TX_RING_CPU_IDX_MASK,
FIELD_PREP(TX_RING_CPU_IDX_MASK, index));
if (q->ndesc - q->queued < q->free_thr)
if (q->ndesc - q->queued < q->free_thr) {
netif_tx_stop_queue(txq);
q->txq_stopped = true;
}
spin_unlock_bh(&q->lock);

View File

@ -193,6 +193,7 @@ struct airoha_queue {
int ndesc;
int free_thr;
int buf_size;
bool txq_stopped;
struct napi_struct napi;
struct page_pool *page_pool;
@ -653,7 +654,8 @@ int airoha_get_fe_port(struct airoha_gdm_port *port);
bool airoha_is_valid_gdm_port(struct airoha_eth *eth,
struct airoha_gdm_port *port);
void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id);
void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id,
u8 fport);
bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index);
void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb,
u16 hash, bool rx_wlan);

View File

@ -85,10 +85,9 @@ static u32 airoha_ppe_get_timestamp(struct airoha_ppe *ppe)
return FIELD_GET(AIROHA_FOE_IB1_BIND_TIMESTAMP, timestamp);
}
void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id)
void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id, u8 fport)
{
struct airoha_qdma *qdma = port->qdma;
u8 fport = airoha_get_fe_port(port);
struct airoha_eth *eth = qdma->eth;
u8 qdma_id = qdma - &eth->qdma[0];
u32 fe_cpu_port;
@ -182,7 +181,8 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
if (!port)
continue;
airoha_ppe_set_cpu_port(port, i);
airoha_ppe_set_cpu_port(port, i,
airoha_get_fe_port(port));
}
}
}
@ -1356,6 +1356,29 @@ static struct airoha_npu *airoha_ppe_npu_get(struct airoha_eth *eth)
return npu;
}
static int airoha_ppe_wait_for_npu_init(struct airoha_eth *eth)
{
int err;
u32 val;
/* PPE_FLOW_CFG default register value is 0. Since we reset FE
* during the device probe we can just check the configured value
* is not 0 here.
*/
err = read_poll_timeout(airoha_fe_rr, val, val, USEC_PER_MSEC,
100 * USEC_PER_MSEC, false, eth,
REG_PPE_PPE_FLOW_CFG(0));
if (err)
return err;
if (airoha_ppe_is_enabled(eth, 1))
err = read_poll_timeout(airoha_fe_rr, val, val, USEC_PER_MSEC,
100 * USEC_PER_MSEC, false, eth,
REG_PPE_PPE_FLOW_CFG(1));
return err;
}
static int airoha_ppe_offload_setup(struct airoha_eth *eth)
{
struct airoha_npu *npu = airoha_ppe_npu_get(eth);
@ -1369,6 +1392,11 @@ static int airoha_ppe_offload_setup(struct airoha_eth *eth)
if (err)
goto error_npu_put;
/* Wait for NPU PPE configuration to complete */
err = airoha_ppe_wait_for_npu_init(eth);
if (err)
goto error_npu_put;
ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe);
if (ppe_num_stats_entries > 0) {
err = npu->ops.ppe_init_stats(npu, ppe->foe_stats_dma,

View File

@ -74,6 +74,13 @@ static int bnge_func_qcaps(struct bnge_dev *bd)
return rc;
}
return 0;
}
static int bnge_func_qrcaps_qcfg(struct bnge_dev *bd)
{
int rc;
rc = bnge_hwrm_func_resc_qcaps(bd);
if (rc) {
dev_err(bd->dev, "query resc caps failure rc: %d\n", rc);
@ -133,23 +140,28 @@ static int bnge_fw_register_dev(struct bnge_dev *bd)
bnge_hwrm_fw_set_time(bd);
rc = bnge_hwrm_func_drv_rgtr(bd);
/* Get the resources and configuration from firmware */
rc = bnge_func_qcaps(bd);
if (rc) {
dev_err(bd->dev, "Failed to rgtr with firmware rc: %d\n", rc);
dev_err(bd->dev, "Failed querying caps rc: %d\n", rc);
return rc;
}
rc = bnge_alloc_ctx_mem(bd);
if (rc) {
dev_err(bd->dev, "Failed to allocate ctx mem rc: %d\n", rc);
goto err_func_unrgtr;
goto err_free_ctx_mem;
}
/* Get the resources and configuration from firmware */
rc = bnge_func_qcaps(bd);
rc = bnge_hwrm_func_drv_rgtr(bd);
if (rc) {
dev_err(bd->dev, "Failed initial configuration rc: %d\n", rc);
rc = -ENODEV;
dev_err(bd->dev, "Failed to rgtr with firmware rc: %d\n", rc);
goto err_free_ctx_mem;
}
rc = bnge_func_qrcaps_qcfg(bd);
if (rc) {
dev_err(bd->dev, "Failed querying resources rc: %d\n", rc);
goto err_func_unrgtr;
}
@ -158,7 +170,9 @@ static int bnge_fw_register_dev(struct bnge_dev *bd)
return 0;
err_func_unrgtr:
bnge_fw_unregister_dev(bd);
bnge_hwrm_func_drv_unrgtr(bd);
err_free_ctx_mem:
bnge_free_ctx_mem(bd);
return rc;
}

View File

@ -324,7 +324,6 @@ int bnge_alloc_ctx_mem(struct bnge_dev *bd)
u32 l2_qps, qp1_qps, max_qps;
u32 ena, entries_sp, entries;
u32 srqs, max_srqs, min;
u32 num_mr, num_ah;
u32 extra_srqs = 0;
u32 extra_qps = 0;
u32 fast_qpmd_qps;
@ -390,21 +389,6 @@ int bnge_alloc_ctx_mem(struct bnge_dev *bd)
if (!bnge_is_roce_en(bd))
goto skip_rdma;
ctxm = &ctx->ctx_arr[BNGE_CTX_MRAV];
/* 128K extra is needed to accommodate static AH context
* allocation by f/w.
*/
num_mr = min_t(u32, ctxm->max_entries / 2, 1024 * 256);
num_ah = min_t(u32, num_mr, 1024 * 128);
ctxm->split_entry_cnt = BNGE_CTX_MRAV_AV_SPLIT_ENTRY + 1;
if (!ctxm->mrav_av_entries || ctxm->mrav_av_entries > num_ah)
ctxm->mrav_av_entries = num_ah;
rc = bnge_setup_ctxm_pg_tbls(bd, ctxm, num_mr + num_ah, 2);
if (rc)
return rc;
ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_MRAV;
ctxm = &ctx->ctx_arr[BNGE_CTX_TIM];
rc = bnge_setup_ctxm_pg_tbls(bd, ctxm, l2_qps + qp1_qps + extra_qps, 1);
if (rc)

View File

@ -11132,8 +11132,9 @@ static int bnxt_setup_nitroa0_vnic(struct bnxt *bp)
return rc;
}
static int bnxt_cfg_rx_mode(struct bnxt *);
static bool bnxt_mc_list_updated(struct bnxt *, u32 *);
static int bnxt_cfg_rx_mode(struct bnxt *, struct netdev_hw_addr_list *, bool);
static bool bnxt_mc_list_updated(struct bnxt *, u32 *,
const struct netdev_hw_addr_list *);
static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init)
{
@ -11223,11 +11224,11 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init)
} else if (bp->dev->flags & IFF_MULTICAST) {
u32 mask = 0;
bnxt_mc_list_updated(bp, &mask);
bnxt_mc_list_updated(bp, &mask, &bp->dev->mc);
vnic->rx_mask |= mask;
}
rc = bnxt_cfg_rx_mode(bp);
rc = bnxt_cfg_rx_mode(bp, &bp->dev->uc, true);
if (rc)
goto err_out;
@ -13622,17 +13623,17 @@ void bnxt_get_ring_drv_stats(struct bnxt *bp,
bnxt_get_one_ring_drv_stats(bp, stats, &bp->bnapi[i]->cp_ring);
}
static bool bnxt_mc_list_updated(struct bnxt *bp, u32 *rx_mask)
static bool bnxt_mc_list_updated(struct bnxt *bp, u32 *rx_mask,
const struct netdev_hw_addr_list *mc)
{
struct bnxt_vnic_info *vnic = &bp->vnic_info[BNXT_VNIC_DEFAULT];
struct net_device *dev = bp->dev;
struct netdev_hw_addr *ha;
u8 *haddr;
int mc_count = 0;
bool update = false;
int off = 0;
netdev_for_each_mc_addr(ha, dev) {
netdev_hw_addr_list_for_each(ha, mc) {
if (mc_count >= BNXT_MAX_MC_ADDRS) {
*rx_mask |= CFA_L2_SET_RX_MASK_REQ_MASK_ALL_MCAST;
vnic->mc_list_count = 0;
@ -13656,17 +13657,17 @@ static bool bnxt_mc_list_updated(struct bnxt *bp, u32 *rx_mask)
return update;
}
static bool bnxt_uc_list_updated(struct bnxt *bp)
static bool bnxt_uc_list_updated(struct bnxt *bp,
const struct netdev_hw_addr_list *uc)
{
struct net_device *dev = bp->dev;
struct bnxt_vnic_info *vnic = &bp->vnic_info[BNXT_VNIC_DEFAULT];
struct netdev_hw_addr *ha;
int off = 0;
if (netdev_uc_count(dev) != (vnic->uc_filter_count - 1))
if (netdev_hw_addr_list_count(uc) != (vnic->uc_filter_count - 1))
return true;
netdev_for_each_uc_addr(ha, dev) {
netdev_hw_addr_list_for_each(ha, uc) {
if (!ether_addr_equal(ha->addr, vnic->uc_list + off))
return true;
@ -13675,7 +13676,9 @@ static bool bnxt_uc_list_updated(struct bnxt *bp)
return false;
}
static void bnxt_set_rx_mode(struct net_device *dev)
static void bnxt_set_rx_mode(struct net_device *dev,
struct netdev_hw_addr_list *uc,
struct netdev_hw_addr_list *mc)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vnic_info *vnic;
@ -13696,7 +13699,7 @@ static void bnxt_set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC)
mask |= CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS;
uc_update = bnxt_uc_list_updated(bp);
uc_update = bnxt_uc_list_updated(bp, uc);
if (dev->flags & IFF_BROADCAST)
mask |= CFA_L2_SET_RX_MASK_REQ_MASK_BCAST;
@ -13704,27 +13707,23 @@ static void bnxt_set_rx_mode(struct net_device *dev)
mask |= CFA_L2_SET_RX_MASK_REQ_MASK_ALL_MCAST;
vnic->mc_list_count = 0;
} else if (dev->flags & IFF_MULTICAST) {
mc_update = bnxt_mc_list_updated(bp, &mask);
mc_update = bnxt_mc_list_updated(bp, &mask, mc);
}
if (mask != vnic->rx_mask || uc_update || mc_update) {
vnic->rx_mask = mask;
bnxt_queue_sp_work(bp, BNXT_RX_MASK_SP_EVENT);
bnxt_cfg_rx_mode(bp, uc, uc_update);
}
}
static int bnxt_cfg_rx_mode(struct bnxt *bp)
static int bnxt_cfg_rx_mode(struct bnxt *bp, struct netdev_hw_addr_list *uc,
bool uc_update)
{
struct net_device *dev = bp->dev;
struct bnxt_vnic_info *vnic = &bp->vnic_info[BNXT_VNIC_DEFAULT];
struct netdev_hw_addr *ha;
int i, off = 0, rc;
bool uc_update;
netif_addr_lock_bh(dev);
uc_update = bnxt_uc_list_updated(bp);
netif_addr_unlock_bh(dev);
if (!uc_update)
goto skip_uc;
@ -13739,10 +13738,10 @@ static int bnxt_cfg_rx_mode(struct bnxt *bp)
vnic->uc_filter_count = 1;
netif_addr_lock_bh(dev);
if (netdev_uc_count(dev) > (BNXT_MAX_UC_ADDRS - 1)) {
if (netdev_hw_addr_list_count(uc) > (BNXT_MAX_UC_ADDRS - 1)) {
vnic->rx_mask |= CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS;
} else {
netdev_for_each_uc_addr(ha, dev) {
netdev_hw_addr_list_for_each(ha, uc) {
memcpy(vnic->uc_list + off, ha->addr, ETH_ALEN);
off += ETH_ALEN;
vnic->uc_filter_count++;
@ -14708,6 +14707,7 @@ static void bnxt_ulp_restart(struct bnxt *bp)
static void bnxt_sp_task(struct work_struct *work)
{
struct bnxt *bp = container_of(work, struct bnxt, sp_task);
struct net_device *dev = bp->dev;
set_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
smp_mb__after_atomic();
@ -14721,9 +14721,6 @@ static void bnxt_sp_task(struct work_struct *work)
bnxt_reenable_sriov(bp);
}
if (test_and_clear_bit(BNXT_RX_MASK_SP_EVENT, &bp->sp_event))
bnxt_cfg_rx_mode(bp);
if (test_and_clear_bit(BNXT_RX_NTP_FLTR_SP_EVENT, &bp->sp_event))
bnxt_cfg_ntp_filters(bp);
if (test_and_clear_bit(BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT, &bp->sp_event))
@ -14788,6 +14785,13 @@ static void bnxt_sp_task(struct work_struct *work)
/* These functions below will clear BNXT_STATE_IN_SP_TASK. They
* must be the last functions to be called before exiting.
*/
if (test_and_clear_bit(BNXT_RX_MASK_SP_EVENT, &bp->sp_event)) {
bnxt_lock_sp(bp);
if (test_bit(BNXT_STATE_OPEN, &bp->state))
bnxt_cfg_rx_mode(bp, &dev->uc, true);
bnxt_unlock_sp(bp);
}
if (test_and_clear_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event))
bnxt_reset(bp, false);
@ -15989,7 +15993,7 @@ static const struct net_device_ops bnxt_netdev_ops = {
.ndo_start_xmit = bnxt_start_xmit,
.ndo_stop = bnxt_close,
.ndo_get_stats64 = bnxt_get_stats64,
.ndo_set_rx_mode = bnxt_set_rx_mode,
.ndo_set_rx_mode_async = bnxt_set_rx_mode,
.ndo_eth_ioctl = bnxt_ioctl,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = bnxt_change_mac_addr,

View File

@ -7,6 +7,7 @@
#include <linux/dma-mapping.h>
#include <linux/fsl/netc_global.h>
#include <linux/iopoll.h>
#include <linux/vmalloc.h>
#include "ntmp_private.h"
@ -42,6 +43,12 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
if (!cbdr->addr_base)
return -ENOMEM;
cbdr->swcbd = vcalloc(cbd_num, sizeof(struct netc_swcbd));
if (!cbdr->swcbd) {
dma_free_coherent(dev, size, cbdr->addr_base, cbdr->dma_base);
return -ENOMEM;
}
cbdr->dma_size = size;
cbdr->bd_num = cbd_num;
cbdr->regs = *regs;
@ -52,10 +59,10 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
cbdr->addr_base_align = PTR_ALIGN(cbdr->addr_base,
NTMP_BASE_ADDR_ALIGN);
spin_lock_init(&cbdr->ring_lock);
mutex_init(&cbdr->ring_lock);
cbdr->next_to_use = netc_read(cbdr->regs.pir);
cbdr->next_to_clean = netc_read(cbdr->regs.cir);
cbdr->next_to_clean = netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX;
/* Step 1: Configure the base address of the Control BD Ring */
netc_write(cbdr->regs.bar0, lower_32_bits(cbdr->dma_base_align));
@ -71,10 +78,24 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
}
EXPORT_SYMBOL_GPL(ntmp_init_cbdr);
static void ntmp_free_data_mem(struct device *dev, struct netc_swcbd *swcbd)
{
if (unlikely(!swcbd->buf))
return;
dma_free_coherent(dev, swcbd->size + NTMP_DATA_ADDR_ALIGN,
swcbd->buf, swcbd->dma);
}
void ntmp_free_cbdr(struct netc_cbdr *cbdr)
{
/* Disable the Control BD Ring */
netc_write(cbdr->regs.mr, 0);
for (int i = 0; i < cbdr->bd_num; i++)
ntmp_free_data_mem(cbdr->dev, &cbdr->swcbd[i]);
vfree(cbdr->swcbd);
dma_free_coherent(cbdr->dev, cbdr->dma_size, cbdr->addr_base,
cbdr->dma_base);
memset(cbdr, 0, sizeof(*cbdr));
@ -94,40 +115,59 @@ static union netc_cbd *ntmp_get_cbd(struct netc_cbdr *cbdr, int index)
static void ntmp_clean_cbdr(struct netc_cbdr *cbdr)
{
union netc_cbd *cbd;
int i;
int i = cbdr->next_to_clean;
i = cbdr->next_to_clean;
while (netc_read(cbdr->regs.cir) != i) {
cbd = ntmp_get_cbd(cbdr, i);
while ((netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX) != i) {
union netc_cbd *cbd = ntmp_get_cbd(cbdr, i);
struct netc_swcbd *swcbd = &cbdr->swcbd[i];
ntmp_free_data_mem(cbdr->dev, swcbd);
memset(swcbd, 0, sizeof(*swcbd));
memset(cbd, 0, sizeof(*cbd));
i = (i + 1) % cbdr->bd_num;
}
dma_wmb();
cbdr->next_to_clean = i;
}
static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
static void ntmp_select_and_lock_cbdr(struct ntmp_user *user,
struct netc_cbdr **cbdr)
{
/* Currently only ENETC is supported, and it has only one command
* BD ring.
*/
*cbdr = &user->ring[0];
mutex_lock(&(*cbdr)->ring_lock);
}
static void ntmp_unlock_cbdr(struct netc_cbdr *cbdr)
{
mutex_unlock(&cbdr->ring_lock);
}
static int netc_xmit_ntmp_cmd(struct netc_cbdr *cbdr, union netc_cbd *cbd,
struct netc_swcbd *swcbd)
{
union netc_cbd *cur_cbd;
struct netc_cbdr *cbdr;
int i, err;
int i, err, used_bds;
u16 status;
u32 val;
/* Currently only i.MX95 ENETC is supported, and it only has one
* command BD ring
*/
cbdr = &user->ring[0];
spin_lock_bh(&cbdr->ring_lock);
if (unlikely(!ntmp_get_free_cbd_num(cbdr)))
used_bds = cbdr->bd_num - ntmp_get_free_cbd_num(cbdr);
if (unlikely(used_bds >= NETC_CBDR_CLEAN_WORK)) {
ntmp_clean_cbdr(cbdr);
if (unlikely(!ntmp_get_free_cbd_num(cbdr))) {
ntmp_free_data_mem(cbdr->dev, swcbd);
return -EBUSY;
}
}
i = cbdr->next_to_use;
cur_cbd = ntmp_get_cbd(cbdr, i);
*cur_cbd = *cbd;
cbdr->swcbd[i] = *swcbd;
dma_wmb();
/* Update producer index of both software and hardware */
@ -135,11 +175,17 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
cbdr->next_to_use = i;
netc_write(cbdr->regs.pir, i);
err = read_poll_timeout_atomic(netc_read, val, val == i,
NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT,
true, cbdr->regs.cir);
err = read_poll_timeout(netc_read, val,
(val & NETC_CBDRCIR_INDEX) == i,
NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT,
true, cbdr->regs.cir);
if (unlikely(err))
goto cbdr_unlock;
return err;
if (unlikely(val & NETC_CBDRCIR_SBE)) {
dev_err(cbdr->dev, "Command BD system bus error\n");
return -EIO;
}
dma_rmb();
/* Get the writeback command BD, because the caller may need
@ -150,38 +196,27 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
/* Check the writeback error status */
status = le16_to_cpu(cbd->resp_hdr.error_rr) & NTMP_RESP_ERROR;
if (unlikely(status)) {
err = -EIO;
dev_err(user->dev, "Command BD error: 0x%04x\n", status);
dev_err(cbdr->dev, "Command BD error: 0x%04x\n", status);
return -EIO;
}
ntmp_clean_cbdr(cbdr);
dma_wmb();
cbdr_unlock:
spin_unlock_bh(&cbdr->ring_lock);
return err;
}
static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data, void **buf_align)
{
void *buf;
buf = dma_alloc_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN,
&data->dma, GFP_KERNEL);
if (!buf)
return -ENOMEM;
data->buf = buf;
*buf_align = PTR_ALIGN(buf, NTMP_DATA_ADDR_ALIGN);
return 0;
}
static void ntmp_free_data_mem(struct ntmp_dma_buf *data)
static int ntmp_alloc_data_mem(struct device *dev, struct netc_swcbd *swcbd,
void **buf_align)
{
dma_free_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN,
data->buf, data->dma);
void *buf;
buf = dma_alloc_coherent(dev, swcbd->size + NTMP_DATA_ADDR_ALIGN,
&swcbd->dma, GFP_KERNEL);
if (!buf)
return -ENOMEM;
swcbd->buf = buf;
*buf_align = PTR_ALIGN(buf, NTMP_DATA_ADDR_ALIGN);
return 0;
}
static void ntmp_fill_request_hdr(union netc_cbd *cbd, dma_addr_t dma,
@ -234,37 +269,39 @@ static int ntmp_delete_entry_by_id(struct ntmp_user *user, int tbl_id,
u8 tbl_ver, u32 entry_id, u32 req_len,
u32 resp_len)
{
struct ntmp_dma_buf data = {
.dev = user->dev,
struct netc_swcbd swcbd = {
.size = max(req_len, resp_len),
};
struct ntmp_req_by_eid *req;
struct netc_cbdr *cbdr;
union netc_cbd cbd;
int err;
err = ntmp_alloc_data_mem(&data, (void **)&req);
err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
ntmp_fill_crd_eid(req, tbl_ver, 0, 0, entry_id);
ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(req_len, resp_len),
ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(req_len, resp_len),
tbl_id, NTMP_CMD_DELETE, NTMP_AM_ENTRY_ID);
err = netc_xmit_ntmp_cmd(user, &cbd);
ntmp_select_and_lock_cbdr(user, &cbdr);
err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd);
if (err)
dev_err(user->dev,
"Failed to delete entry 0x%x of %s, err: %pe",
entry_id, ntmp_table_name(tbl_id), ERR_PTR(err));
ntmp_free_data_mem(&data);
ntmp_unlock_cbdr(cbdr);
return err;
}
static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id,
u32 len, struct ntmp_req_by_eid *req,
dma_addr_t dma, bool compare_eid)
static int ntmp_query_entry_by_id(struct netc_cbdr *cbdr, int tbl_id,
struct ntmp_req_by_eid *req,
struct netc_swcbd *swcbd,
bool compare_eid)
{
u32 len = NTMP_LEN(sizeof(*req), swcbd->size);
struct ntmp_cmn_resp_query *resp;
int cmd = NTMP_CMD_QUERY;
union netc_cbd cbd;
@ -276,10 +313,11 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id,
cmd = NTMP_CMD_QU;
/* Request header */
ntmp_fill_request_hdr(&cbd, dma, len, tbl_id, cmd, NTMP_AM_ENTRY_ID);
err = netc_xmit_ntmp_cmd(user, &cbd);
ntmp_fill_request_hdr(&cbd, swcbd->dma, len, tbl_id, cmd,
NTMP_AM_ENTRY_ID);
err = netc_xmit_ntmp_cmd(cbdr, &cbd, swcbd);
if (err) {
dev_err(user->dev,
dev_err(cbdr->dev,
"Failed to query entry 0x%x of %s, err: %pe\n",
entry_id, ntmp_table_name(tbl_id), ERR_PTR(err));
return err;
@ -293,7 +331,7 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id,
resp = (struct ntmp_cmn_resp_query *)req;
if (unlikely(le32_to_cpu(resp->entry_id) != entry_id)) {
dev_err(user->dev,
dev_err(cbdr->dev,
"%s: query EID 0x%x doesn't match response EID 0x%x\n",
ntmp_table_name(tbl_id), entry_id, le32_to_cpu(resp->entry_id));
return -EIO;
@ -305,15 +343,15 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id,
int ntmp_maft_add_entry(struct ntmp_user *user, u32 entry_id,
struct maft_entry_data *maft)
{
struct ntmp_dma_buf data = {
.dev = user->dev,
struct netc_swcbd swcbd = {
.size = sizeof(struct maft_req_add),
};
struct maft_req_add *req;
struct netc_cbdr *cbdr;
union netc_cbd cbd;
int err;
err = ntmp_alloc_data_mem(&data, (void **)&req);
err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
@ -322,14 +360,15 @@ int ntmp_maft_add_entry(struct ntmp_user *user, u32 entry_id,
req->keye = maft->keye;
req->cfge = maft->cfge;
ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(data.size, 0),
ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(swcbd.size, 0),
NTMP_MAFT_ID, NTMP_CMD_ADD, NTMP_AM_ENTRY_ID);
err = netc_xmit_ntmp_cmd(user, &cbd);
ntmp_select_and_lock_cbdr(user, &cbdr);
err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd);
if (err)
dev_err(user->dev, "Failed to add MAFT entry 0x%x, err: %pe\n",
entry_id, ERR_PTR(err));
ntmp_free_data_mem(&data);
ntmp_unlock_cbdr(cbdr);
return err;
}
@ -338,31 +377,31 @@ EXPORT_SYMBOL_GPL(ntmp_maft_add_entry);
int ntmp_maft_query_entry(struct ntmp_user *user, u32 entry_id,
struct maft_entry_data *maft)
{
struct ntmp_dma_buf data = {
.dev = user->dev,
struct netc_swcbd swcbd = {
.size = sizeof(struct maft_resp_query),
};
struct maft_resp_query *resp;
struct ntmp_req_by_eid *req;
struct netc_cbdr *cbdr;
int err;
err = ntmp_alloc_data_mem(&data, (void **)&req);
err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
ntmp_fill_crd_eid(req, user->tbl.maft_ver, 0, 0, entry_id);
err = ntmp_query_entry_by_id(user, NTMP_MAFT_ID,
NTMP_LEN(sizeof(*req), data.size),
req, data.dma, true);
ntmp_select_and_lock_cbdr(user, &cbdr);
err = ntmp_query_entry_by_id(cbdr, NTMP_MAFT_ID, req, &swcbd, true);
if (err)
goto end;
goto unlock_cbdr;
resp = (struct maft_resp_query *)req;
maft->keye = resp->keye;
maft->cfge = resp->cfge;
end:
ntmp_free_data_mem(&data);
unlock_cbdr:
ntmp_unlock_cbdr(cbdr);
return err;
}
@ -378,8 +417,9 @@ EXPORT_SYMBOL_GPL(ntmp_maft_delete_entry);
int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table,
int count)
{
struct ntmp_dma_buf data = {.dev = user->dev};
struct rsst_req_update *req;
struct netc_swcbd swcbd;
struct netc_cbdr *cbdr;
union netc_cbd cbd;
int err, i;
@ -387,8 +427,8 @@ int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table,
/* HW only takes in a full 64 entry table */
return -EINVAL;
data.size = struct_size(req, groups, count);
err = ntmp_alloc_data_mem(&data, (void **)&req);
swcbd.size = struct_size(req, groups, count);
err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
@ -398,15 +438,15 @@ int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table,
for (i = 0; i < count; i++)
req->groups[i] = (u8)(table[i]);
ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(data.size, 0),
ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(swcbd.size, 0),
NTMP_RSST_ID, NTMP_CMD_UPDATE, NTMP_AM_ENTRY_ID);
err = netc_xmit_ntmp_cmd(user, &cbd);
ntmp_select_and_lock_cbdr(user, &cbdr);
err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd);
if (err)
dev_err(user->dev, "Failed to update RSST entry, err: %pe\n",
ERR_PTR(err));
ntmp_free_data_mem(&data);
ntmp_unlock_cbdr(cbdr);
return err;
}
@ -414,8 +454,9 @@ EXPORT_SYMBOL_GPL(ntmp_rsst_update_entry);
int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count)
{
struct ntmp_dma_buf data = {.dev = user->dev};
struct ntmp_req_by_eid *req;
struct netc_swcbd swcbd;
struct netc_cbdr *cbdr;
union netc_cbd cbd;
int err, i;
u8 *group;
@ -424,21 +465,23 @@ int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count)
/* HW only takes in a full 64 entry table */
return -EINVAL;
data.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) +
RSST_CFGE_DATA_SIZE(count);
err = ntmp_alloc_data_mem(&data, (void **)&req);
swcbd.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) +
RSST_CFGE_DATA_SIZE(count);
err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
/* Set the request data buffer */
ntmp_fill_crd_eid(req, user->tbl.rsst_ver, 0, 0, 0);
ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(sizeof(*req), data.size),
ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(sizeof(*req), swcbd.size),
NTMP_RSST_ID, NTMP_CMD_QUERY, NTMP_AM_ENTRY_ID);
err = netc_xmit_ntmp_cmd(user, &cbd);
ntmp_select_and_lock_cbdr(user, &cbdr);
err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd);
if (err) {
dev_err(user->dev, "Failed to query RSST entry, err: %pe\n",
ERR_PTR(err));
goto end;
goto unlock_cbdr;
}
group = (u8 *)req;
@ -446,8 +489,8 @@ int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count)
for (i = 0; i < count; i++)
table[i] = group[i];
end:
ntmp_free_data_mem(&data);
unlock_cbdr:
ntmp_unlock_cbdr(cbdr);
return err;
}

View File

@ -12,6 +12,9 @@
#define NTMP_EID_REQ_LEN 8
#define NETC_CBDR_BD_NUM 256
#define NETC_CBDRCIR_INDEX GENMASK(9, 0)
#define NETC_CBDRCIR_SBE BIT(31)
#define NETC_CBDR_CLEAN_WORK 16
union netc_cbd {
struct {
@ -54,13 +57,6 @@ union netc_cbd {
} resp_hdr; /* NTMP Response Message Header Format */
};
struct ntmp_dma_buf {
struct device *dev;
size_t size;
void *buf;
dma_addr_t dma;
};
struct ntmp_cmn_req_data {
__le16 update_act;
u8 dbg_opt;

View File

@ -7706,6 +7706,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_register:
if (!(adapter->flags & FLAG_HAS_AMT))
e1000e_release_hw_control(adapter);
e1000e_ptp_remove(adapter);
err_eeprom:
if (hw->phy.ops.check_reset_block && !hw->phy.ops.check_reset_block(hw))
e1000_phy_hw_reset(&adapter->hw);

View File

@ -13783,7 +13783,6 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
netdev->neigh_priv_len = sizeof(u32) * 4;
netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->priv_flags |= IFF_SUPP_NOFCS;
/* Setup netdev TC information */
i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc);

View File

@ -1150,14 +1150,18 @@ bool iavf_promiscuous_mode_changed(struct iavf_adapter *adapter)
/**
* iavf_set_rx_mode - NDO callback to set the netdev filters
* @netdev: network interface device structure
* @uc: snapshot of uc address list
* @mc: snapshot of mc address list
**/
static void iavf_set_rx_mode(struct net_device *netdev)
static void iavf_set_rx_mode(struct net_device *netdev,
struct netdev_hw_addr_list *uc,
struct netdev_hw_addr_list *mc)
{
struct iavf_adapter *adapter = netdev_priv(netdev);
spin_lock_bh(&adapter->mac_vlan_list_lock);
__dev_uc_sync(netdev, iavf_addr_sync, iavf_addr_unsync);
__dev_mc_sync(netdev, iavf_addr_sync, iavf_addr_unsync);
__hw_addr_sync_dev(uc, netdev, iavf_addr_sync, iavf_addr_unsync);
__hw_addr_sync_dev(mc, netdev, iavf_addr_sync, iavf_addr_unsync);
spin_unlock_bh(&adapter->mac_vlan_list_lock);
spin_lock_bh(&adapter->current_netdev_promisc_flags_lock);
@ -1210,7 +1214,9 @@ static void iavf_configure(struct iavf_adapter *adapter)
struct net_device *netdev = adapter->netdev;
int i;
iavf_set_rx_mode(netdev);
netif_addr_lock_bh(netdev);
iavf_set_rx_mode(netdev, &netdev->uc, &netdev->mc);
netif_addr_unlock_bh(netdev);
iavf_configure_tx(adapter);
iavf_configure_rx(adapter);
@ -5153,7 +5159,7 @@ static const struct net_device_ops iavf_netdev_ops = {
.ndo_open = iavf_open,
.ndo_stop = iavf_close,
.ndo_start_xmit = iavf_xmit_frame,
.ndo_set_rx_mode = iavf_set_rx_mode,
.ndo_set_rx_mode_async = iavf_set_rx_mode,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = iavf_set_mac,
.ndo_change_mtu = iavf_change_mtu,

View File

@ -277,7 +277,7 @@ struct iavf_rx_desc {
/* L2 Tag 2 Presence */
#define IAVF_RXD_LEGACY_L2TAG2P_M BIT(0)
/* Stripped S-TAG VLAN from the receive packet */
#define IAVF_RXD_LEGACY_L2TAG2_M GENMASK_ULL(63, 32)
#define IAVF_RXD_LEGACY_L2TAG2_M GENMASK_ULL(63, 48)
/* Stripped S-TAG VLAN from the receive packet */
#define IAVF_RXD_FLEX_L2TAG2_2_M GENMASK_ULL(63, 48)
/* The packet is a UDP tunneled packet */

View File

@ -753,7 +753,7 @@ static inline bool ice_is_xdp_ena_vsi(struct ice_vsi *vsi)
static inline void ice_set_ring_xdp(struct ice_tx_ring *ring)
{
ring->flags |= ICE_TX_FLAGS_RING_XDP;
set_bit(ICE_TX_RING_FLAGS_XDP, ring->flags);
}
/**
@ -778,7 +778,7 @@ static inline bool ice_is_txtime_ena(const struct ice_tx_ring *ring)
*/
static inline bool ice_is_txtime_cfg(const struct ice_tx_ring *ring)
{
return !!(ring->flags & ICE_TX_FLAGS_TXTIME);
return test_bit(ICE_TX_RING_FLAGS_TXTIME, ring->flags);
}
/**

View File

@ -1252,7 +1252,7 @@ struct ice_aqc_get_link_status_data {
#define ICE_AQ_LINK_PWR_QSFP_CLASS_3 2
#define ICE_AQ_LINK_PWR_QSFP_CLASS_4 3
__le16 link_speed;
#define ICE_AQ_LINK_SPEED_M 0x7FF
#define ICE_AQ_LINK_SPEED_M GENMASK(11, 0)
#define ICE_AQ_LINK_SPEED_10MB BIT(0)
#define ICE_AQ_LINK_SPEED_100MB BIT(1)
#define ICE_AQ_LINK_SPEED_1000MB BIT(2)

View File

@ -943,7 +943,7 @@ ice_tx_prepare_vlan_flags_dcb(struct ice_tx_ring *tx_ring,
/* if this is not already set it means a VLAN 0 + priority needs
* to be offloaded
*/
if (tx_ring->flags & ICE_TX_FLAGS_RING_VLAN_L2TAG2)
if (test_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, tx_ring->flags))
first->tx_flags |= ICE_TX_FLAGS_HW_OUTER_SINGLE_VLAN;
else
first->tx_flags |= ICE_TX_FLAGS_HW_VLAN;

View File

@ -3290,6 +3290,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
tx_rings[i].desc = NULL;
tx_rings[i].tx_buf = NULL;
tx_rings[i].tstamp_ring = NULL;
clear_bit(ICE_TX_RING_FLAGS_TXTIME, tx_rings[i].flags);
tx_rings[i].tx_tstamps = &pf->ptp.port.tx;
err = ice_setup_tx_ring(&tx_rings[i]);
if (err) {

View File

@ -1412,9 +1412,9 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi)
ring->count = vsi->num_tx_desc;
ring->txq_teid = ICE_INVAL_TEID;
if (dvm_ena)
ring->flags |= ICE_TX_FLAGS_RING_VLAN_L2TAG2;
set_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, ring->flags);
else
ring->flags |= ICE_TX_FLAGS_RING_VLAN_L2TAG1;
set_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG1, ring->flags);
WRITE_ONCE(vsi->tx_rings[i], ring);
}

View File

@ -1922,82 +1922,6 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
ice_print_vfs_mdd_events(pf);
}
/**
* ice_force_phys_link_state - Force the physical link state
* @vsi: VSI to force the physical link state to up/down
* @link_up: true/false indicates to set the physical link to up/down
*
* Force the physical link state by getting the current PHY capabilities from
* hardware and setting the PHY config based on the determined capabilities. If
* link changes a link event will be triggered because both the Enable Automatic
* Link Update and LESM Enable bits are set when setting the PHY capabilities.
*
* Returns 0 on success, negative on failure
*/
static int ice_force_phys_link_state(struct ice_vsi *vsi, bool link_up)
{
struct ice_aqc_get_phy_caps_data *pcaps;
struct ice_aqc_set_phy_cfg_data *cfg;
struct ice_port_info *pi;
struct device *dev;
int retcode;
if (!vsi || !vsi->port_info || !vsi->back)
return -EINVAL;
if (vsi->type != ICE_VSI_PF)
return 0;
dev = ice_pf_to_dev(vsi->back);
pi = vsi->port_info;
pcaps = kzalloc_obj(*pcaps);
if (!pcaps)
return -ENOMEM;
retcode = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, pcaps,
NULL);
if (retcode) {
dev_err(dev, "Failed to get phy capabilities, VSI %d error %d\n",
vsi->vsi_num, retcode);
retcode = -EIO;
goto out;
}
/* No change in link */
if (link_up == !!(pcaps->caps & ICE_AQC_PHY_EN_LINK) &&
link_up == !!(pi->phy.link_info.link_info & ICE_AQ_LINK_UP))
goto out;
/* Use the current user PHY configuration. The current user PHY
* configuration is initialized during probe from PHY capabilities
* software mode, and updated on set PHY configuration.
*/
cfg = kmemdup(&pi->phy.curr_user_phy_cfg, sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
retcode = -ENOMEM;
goto out;
}
cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
if (link_up)
cfg->caps |= ICE_AQ_PHY_ENA_LINK;
else
cfg->caps &= ~ICE_AQ_PHY_ENA_LINK;
retcode = ice_aq_set_phy_cfg(&vsi->back->hw, pi, cfg, NULL);
if (retcode) {
dev_err(dev, "Failed to set phy config, VSI %d error %d\n",
vsi->vsi_num, retcode);
retcode = -EIO;
}
kfree(cfg);
out:
kfree(pcaps);
return retcode;
}
/**
* ice_init_nvm_phy_type - Initialize the NVM PHY type
* @pi: port info structure
@ -2066,7 +1990,7 @@ static void ice_init_link_dflt_override(struct ice_port_info *pi)
* first time media is available. The ICE_LINK_DEFAULT_OVERRIDE_PENDING state
* is used to indicate that the user PHY cfg default override is initialized
* and the PHY has not been configured with the default override settings. The
* state is set here, and cleared in ice_configure_phy the first time the PHY is
* state is set here, and cleared in ice_phy_cfg the first time the PHY is
* configured.
*
* This function should be called only if the FW doesn't support default
@ -2172,14 +2096,18 @@ static int ice_init_phy_user_cfg(struct ice_port_info *pi)
}
/**
* ice_configure_phy - configure PHY
* ice_phy_cfg - configure PHY
* @vsi: VSI of PHY
* @link_en: true/false indicates to set link to enable/disable
*
* Set the PHY configuration. If the current PHY configuration is the same as
* the curr_user_phy_cfg, then do nothing to avoid link flap. Otherwise
* configure the based get PHY capabilities for topology with media.
* the curr_user_phy_cfg and link_en hasn't changed, then do nothing to avoid
* link flap. Otherwise configure the PHY based get PHY capabilities for
* topology with media and link_en.
*
* Return: 0 on success, negative on failure
*/
static int ice_configure_phy(struct ice_vsi *vsi)
static int ice_phy_cfg(struct ice_vsi *vsi, bool link_en)
{
struct device *dev = ice_pf_to_dev(vsi->back);
struct ice_port_info *pi = vsi->port_info;
@ -2199,9 +2127,6 @@ static int ice_configure_phy(struct ice_vsi *vsi)
phy->link_info.topo_media_conflict == ICE_AQ_LINK_TOPO_UNSUPP_MEDIA)
return -EPERM;
if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags))
return ice_force_phys_link_state(vsi, true);
pcaps = kzalloc_obj(*pcaps);
if (!pcaps)
return -ENOMEM;
@ -2215,10 +2140,8 @@ static int ice_configure_phy(struct ice_vsi *vsi)
goto done;
}
/* If PHY enable link is configured and configuration has not changed,
* there's nothing to do
*/
if (pcaps->caps & ICE_AQC_PHY_EN_LINK &&
/* Configuration has not changed. There's nothing to do. */
if (link_en == !!(pcaps->caps & ICE_AQC_PHY_EN_LINK) &&
ice_phy_caps_equals_cfg(pcaps, &phy->curr_user_phy_cfg))
goto done;
@ -2282,8 +2205,12 @@ static int ice_configure_phy(struct ice_vsi *vsi)
*/
ice_cfg_phy_fc(pi, cfg, phy->curr_user_fc_req);
/* Enable link and link update */
cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT | ICE_AQ_PHY_ENA_LINK;
/* Enable/Disable link and link update */
cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
if (link_en)
cfg->caps |= ICE_AQ_PHY_ENA_LINK;
else
cfg->caps &= ~ICE_AQ_PHY_ENA_LINK;
err = ice_aq_set_phy_cfg(&pf->hw, pi, cfg, NULL);
if (err)
@ -2336,7 +2263,7 @@ static void ice_check_media_subtask(struct ice_pf *pf)
test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags))
return;
err = ice_configure_phy(vsi);
err = ice_phy_cfg(vsi, true);
if (!err)
clear_bit(ICE_FLAG_NO_MEDIA, pf->flags);
@ -4892,9 +4819,15 @@ static int ice_init_link(struct ice_pf *pf)
if (!test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags)) {
struct ice_vsi *vsi = ice_get_main_vsi(pf);
struct ice_link_default_override_tlv *ldo;
bool link_en;
ldo = &pf->link_dflt_override;
link_en = !(ldo->options &
ICE_LINK_OVERRIDE_AUTO_LINK_DIS);
if (vsi)
ice_configure_phy(vsi);
ice_phy_cfg(vsi, link_en);
}
} else {
set_bit(ICE_FLAG_NO_MEDIA, pf->flags);
@ -9707,7 +9640,7 @@ int ice_open_internal(struct net_device *netdev)
}
}
err = ice_configure_phy(vsi);
err = ice_phy_cfg(vsi, true);
if (err) {
netdev_err(netdev, "Failed to set physical link up, error %d\n",
err);
@ -9748,7 +9681,7 @@ int ice_stop(struct net_device *netdev)
}
if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags)) {
int link_err = ice_force_phys_link_state(vsi, false);
int link_err = ice_phy_cfg(vsi, false);
if (link_err) {
if (link_err == -ENOMEDIUM)

View File

@ -2710,7 +2710,7 @@ static bool ice_any_port_has_timestamps(struct ice_pf *pf)
bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf)
{
struct ice_hw *hw = &pf->hw;
unsigned int i;
int ret;
/* Check software indicator */
switch (pf->ptp.tx_interrupt_mode) {
@ -2731,16 +2731,19 @@ bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf)
}
/* Check hardware indicator */
for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) {
u64 tstamp_ready = 0;
int err;
err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready);
if (err || tstamp_ready)
return true;
ret = ice_check_phy_tx_tstamp_ready(hw);
if (ret < 0) {
dev_dbg(ice_pf_to_dev(pf), "Unable to read PHY Tx timestamp ready bitmap, err %d\n",
ret);
/* Stop triggering IRQs if we're unable to read PHY */
return false;
}
return false;
/* ice_check_phy_tx_tstamp_ready() returns 1 if there are timestamps
* available, 0 if there are no waiting timestamps, and a negative
* value if there was an error (which we checked for above).
*/
return ret > 0;
}
/**
@ -2824,8 +2827,7 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf)
{
struct device *dev = ice_pf_to_dev(pf);
struct ice_hw *hw = &pf->hw;
bool trigger_oicr = false;
unsigned int i;
int ret;
if (!pf->ptp.port.tx.has_ready_bitmap)
return;
@ -2833,21 +2835,11 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf)
if (!ice_pf_src_tmr_owned(pf))
return;
for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) {
u64 tstamp_ready;
int err;
err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready);
if (!err && tstamp_ready) {
trigger_oicr = true;
break;
}
}
if (trigger_oicr) {
/* Trigger a software interrupt, to ensure this data
* gets processed.
*/
ret = ice_check_phy_tx_tstamp_ready(hw);
if (ret < 0) {
dev_dbg(dev, "PTP periodic task unable to read PHY timestamp ready bitmap, err %d\n",
ret);
} else if (ret) {
dev_dbg(dev, "PTP periodic task detected waiting timestamps. Triggering Tx timestamp interrupt now.\n");
wr32(hw, PFINT_OICR, PFINT_OICR_TSYN_TX_M);

View File

@ -78,14 +78,14 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = {
.blktime = 0x666, /* 3.2 */
.tx_offset = {
.serdes = 0x234c, /* 17.6484848 */
.no_fec = 0x8e80, /* 71.25 */
.no_fec = 0x93d9, /* 73 */
.fc = 0xb4a4, /* 90.32 */
.sfd = 0x4a4, /* 2.32 */
.onestep = 0x4ccd /* 38.4 */
},
.rx_offset = {
.serdes = 0xffffeb27, /* -10.42424 */
.no_fec = 0xffffcccd, /* -25.6 */
.no_fec = 0xffffc7b6, /* -28 */
.fc = 0xfffc557b, /* -469.26 */
.sfd = 0x4a4, /* 2.32 */
.bs_ds = 0x32 /* 0.0969697 */
@ -118,17 +118,17 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = {
.mktime = 0x147b, /* 10.24, only if RS-FEC enabled */
.tx_offset = {
.serdes = 0xe1e, /* 7.0593939 */
.no_fec = 0x3857, /* 28.17 */
.no_fec = 0x4266, /* 33 */
.fc = 0x48c3, /* 36.38 */
.rs = 0x8100, /* 64.5 */
.rs = 0x8a00, /* 69 */
.sfd = 0x1dc, /* 0.93 */
.onestep = 0x1eb8 /* 15.36 */
},
.rx_offset = {
.serdes = 0xfffff7a9, /* -4.1697 */
.no_fec = 0xffffe71a, /* -12.45 */
.no_fec = 0xffffe700, /* -12 */
.fc = 0xfffe894d, /* -187.35 */
.rs = 0xfffff8cd, /* -3.6 */
.rs = 0xfffff8cc, /* -3 */
.sfd = 0x1dc, /* 0.93 */
.bs_ds = 0x14 /* 0.0387879, RS-FEC 0 */
}

View File

@ -377,6 +377,31 @@ static void ice_ptp_cfg_sync_delay(const struct ice_hw *hw, u32 delay)
* The following functions operate on devices with the ETH 56G PHY.
*/
/**
* ice_ptp_init_phc_e825c - Perform E825C specific PHC initialization
* @hw: pointer to HW struct
*
* Perform E825C-specific PTP hardware clock initialization steps.
*
* Return: 0 on success, or a negative error value on failure.
*/
static int ice_ptp_init_phc_e825c(struct ice_hw *hw)
{
int err;
/* Soft reset all ports, to ensure everything is at a clean state */
for (int port = 0; port < hw->ptp.num_lports; port++) {
err = ice_ptp_phy_soft_reset_eth56g(hw, port);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to soft reset port %d, err %d\n",
port, err);
return err;
}
}
return 0;
}
/**
* ice_ptp_get_dest_dev_e825 - get destination PHY for given port number
* @hw: pointer to the HW struct
@ -1847,6 +1872,8 @@ static int ice_phy_cfg_mac_eth56g(struct ice_hw *hw, u8 port)
* @ena: enable or disable interrupt
* @threshold: interrupt threshold
*
* The threshold cannot be 0 while the interrupt is enabled.
*
* Configure TX timestamp interrupt for the specified port
*
* Return:
@ -1858,19 +1885,45 @@ int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold)
int err;
u32 val;
if (ena && !threshold)
return -EINVAL;
err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val);
if (err)
return err;
val &= ~PHY_TS_INT_CONFIG_ENA_M;
if (ena) {
val |= PHY_TS_INT_CONFIG_ENA_M;
val &= ~PHY_TS_INT_CONFIG_THRESHOLD_M;
val |= FIELD_PREP(PHY_TS_INT_CONFIG_THRESHOLD_M, threshold);
} else {
val &= ~PHY_TS_INT_CONFIG_ENA_M;
err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG,
val);
if (err) {
ice_debug(hw, ICE_DBG_PTP,
"Failed to update 'threshold' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n",
port, !!ena, threshold);
return err;
}
val |= PHY_TS_INT_CONFIG_ENA_M;
}
return ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val);
err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val);
if (err) {
ice_debug(hw, ICE_DBG_PTP,
"Failed to update 'ena' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n",
port, !!ena, threshold);
return err;
}
err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val);
if (err) {
ice_debug(hw, ICE_DBG_PTP,
"Failed to read PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n",
port, !!ena, threshold);
return err;
}
return 0;
}
/**
@ -2115,6 +2168,35 @@ int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port)
return 0;
}
/**
* ice_check_phy_tx_tstamp_ready_eth56g - Check Tx memory status for all ports
* @hw: pointer to the HW struct
*
* Check the PHY_REG_TX_MEMORY_STATUS for all ports. A set bit indicates
* a waiting timestamp.
*
* Return: 1 if any port has at least one timestamp ready bit set,
* 0 otherwise, and a negative error code if unable to read the bitmap.
*/
static int ice_check_phy_tx_tstamp_ready_eth56g(struct ice_hw *hw)
{
int port;
for (port = 0; port < hw->ptp.num_lports; port++) {
u64 tstamp_ready;
int err;
err = ice_get_phy_tx_tstamp_ready(hw, port, &tstamp_ready);
if (err)
return err;
if (tstamp_ready)
return 1;
}
return 0;
}
/**
* ice_ptp_read_tx_hwtstamp_status_eth56g - Get TX timestamp status
* @hw: pointer to the HW struct
@ -2137,13 +2219,19 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status)
*ts_status = 0;
for (phy = 0; phy < params->num_phys; phy++) {
u8 port;
int err;
err = ice_read_phy_eth56g(hw, phy, PHY_PTP_INT_STATUS, &status);
/* ice_read_phy_eth56g expects a port index, so use the first
* port of the PHY
*/
port = phy * hw->ptp.ports_per_phy;
err = ice_read_phy_eth56g(hw, port, PHY_PTP_INT_STATUS, &status);
if (err)
return err;
*ts_status |= (status & mask) << (phy * hw->ptp.ports_per_phy);
*ts_status |= (status & mask) << port;
}
ice_debug(hw, ICE_DBG_PTP, "PHY interrupt err: %x\n", *ts_status);
@ -2151,6 +2239,69 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status)
return 0;
}
/**
* ice_ptp_phy_soft_reset_eth56g - Perform a PHY soft reset on ETH56G
* @hw: pointer to the HW structure
* @port: PHY port number
*
* Trigger a soft reset of the ETH56G PHY by toggling the soft reset
* bit in the PHY global register. The reset sequence consists of:
* 1. Clearing the soft reset bit
* 2. Asserting the soft reset bit
* 3. Clearing the soft reset bit again
*
* Short delays are inserted between each step to allow the hardware
* to settle. This provides a controlled way to reinitialize the PHY
* without requiring a full device reset.
*
* Return: 0 on success, or a negative error code on failure when
* reading or writing the PHY register.
*/
int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port)
{
u32 global_val;
int err;
err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, &global_val);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read PHY_REG_GLOBAL for port %d, err %d\n",
port, err);
return err;
}
global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M;
ice_debug(hw, ICE_DBG_PTP, "Clearing soft reset bit for port %d, val: 0x%x\n",
port, global_val);
err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n",
port, err);
return err;
}
usleep_range(5000, 6000);
global_val |= PHY_REG_GLOBAL_SOFT_RESET_M;
ice_debug(hw, ICE_DBG_PTP, "Set soft reset bit for port %d, val: 0x%x\n",
port, global_val);
err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n",
port, err);
return err;
}
usleep_range(5000, 6000);
global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M;
ice_debug(hw, ICE_DBG_PTP, "Clear soft reset bit for port %d, val: 0x%x\n",
port, global_val);
err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val);
if (err)
ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n",
port, err);
return err;
}
/**
* ice_get_phy_tx_tstamp_ready_eth56g - Read the Tx memory status register
* @hw: pointer to the HW struct
@ -4202,6 +4353,35 @@ ice_get_phy_tx_tstamp_ready_e82x(struct ice_hw *hw, u8 quad, u64 *tstamp_ready)
return 0;
}
/**
* ice_check_phy_tx_tstamp_ready_e82x - Check Tx memory status for all quads
* @hw: pointer to the HW struct
*
* Check the Q_REG_TX_MEMORY_STATUS for all quads. A set bit indicates
* a waiting timestamp.
*
* Return: 1 if any quad has at least one timestamp ready bit set,
* 0 otherwise, and a negative error value if unable to read the bitmap.
*/
static int ice_check_phy_tx_tstamp_ready_e82x(struct ice_hw *hw)
{
int quad;
for (quad = 0; quad < ICE_GET_QUAD_NUM(hw->ptp.num_lports); quad++) {
u64 tstamp_ready;
int err;
err = ice_get_phy_tx_tstamp_ready(hw, quad, &tstamp_ready);
if (err)
return err;
if (tstamp_ready)
return 1;
}
return 0;
}
/**
* ice_phy_cfg_intr_e82x - Configure TX timestamp interrupt
* @hw: pointer to the HW struct
@ -4755,6 +4935,23 @@ ice_get_phy_tx_tstamp_ready_e810(struct ice_hw *hw, u8 port, u64 *tstamp_ready)
return 0;
}
/**
* ice_check_phy_tx_tstamp_ready_e810 - Check Tx memory status register
* @hw: pointer to the HW struct
*
* The E810 devices do not have a Tx memory status register. Note this is
* intentionally different behavior from ice_get_phy_tx_tstamp_ready_e810
* which always says that all bits are ready. This function is called in cases
* where code will trigger interrupts if timestamps are waiting, and should
* not be called for E810 hardware.
*
* Return: 0.
*/
static int ice_check_phy_tx_tstamp_ready_e810(struct ice_hw *hw)
{
return 0;
}
/* E810 SMA functions
*
* The following functions operate specifically on E810 hardware and are used
@ -5009,6 +5206,21 @@ static void ice_get_phy_tx_tstamp_ready_e830(const struct ice_hw *hw, u8 port,
*tstamp_ready |= rd32(hw, E830_PRTMAC_TS_TX_MEM_VALID_L);
}
/**
* ice_check_phy_tx_tstamp_ready_e830 - Check Tx memory status register
* @hw: pointer to the HW struct
*
* Return: 1 if the device has waiting timestamps, 0 otherwise.
*/
static int ice_check_phy_tx_tstamp_ready_e830(struct ice_hw *hw)
{
u64 tstamp_ready;
ice_get_phy_tx_tstamp_ready_e830(hw, 0, &tstamp_ready);
return !!tstamp_ready;
}
/**
* ice_ptp_init_phy_e830 - initialize PHY parameters
* @ptp: pointer to the PTP HW struct
@ -5381,8 +5593,8 @@ int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval)
*/
int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
{
int err = 0;
u8 tmr_idx;
int err;
tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
@ -5399,8 +5611,8 @@ int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
err = ice_ptp_prep_phy_adj_e810(hw, adj);
break;
case ICE_MAC_E830:
/* E830 sync PHYs automatically after setting GLTSYN_SHADJ */
return 0;
/* E830 sync PHYs automatically after setting cmd register */
break;
case ICE_MAC_GENERIC:
err = ice_ptp_prep_phy_adj_e82x(hw, adj);
break;
@ -5564,7 +5776,7 @@ int ice_ptp_init_phc(struct ice_hw *hw)
case ICE_MAC_GENERIC:
return ice_ptp_init_phc_e82x(hw);
case ICE_MAC_GENERIC_3K_E825:
return 0;
return ice_ptp_init_phc_e825c(hw);
default:
return -EOPNOTSUPP;
}
@ -5601,6 +5813,33 @@ int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready)
}
}
/**
* ice_check_phy_tx_tstamp_ready - Check PHY Tx timestamp memory status
* @hw: pointer to the HW struct
*
* Check the PHY for Tx timestamp memory status on all ports. If you need to
* see individual timestamp status for each index, use
* ice_get_phy_tx_tstamp_ready() instead.
*
* Return: 1 if any port has timestamps available, 0 if there are no timestamps
* available, and a negative error code on failure.
*/
int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw)
{
switch (hw->mac_type) {
case ICE_MAC_E810:
return ice_check_phy_tx_tstamp_ready_e810(hw);
case ICE_MAC_E830:
return ice_check_phy_tx_tstamp_ready_e830(hw);
case ICE_MAC_GENERIC:
return ice_check_phy_tx_tstamp_ready_e82x(hw);
case ICE_MAC_GENERIC_3K_E825:
return ice_check_phy_tx_tstamp_ready_eth56g(hw);
default:
return -EOPNOTSUPP;
}
}
/**
* ice_cgu_get_pin_desc_e823 - get pin description array
* @hw: pointer to the hw struct

View File

@ -300,6 +300,7 @@ void ice_ptp_reset_ts_memory(struct ice_hw *hw);
int ice_ptp_init_phc(struct ice_hw *hw);
void ice_ptp_init_hw(struct ice_hw *hw);
int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready);
int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw);
int ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port,
enum ice_ptp_tmr_cmd configured_cmd);
@ -374,6 +375,7 @@ int ice_stop_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool soft_reset);
int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port);
int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold);
int ice_phy_cfg_ptp_1step_eth56g(struct ice_hw *hw, u8 port);
int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port);
#define ICE_ETH56G_NOMINAL_INCVAL 0x140000000ULL
#define ICE_ETH56G_NOMINAL_PCS_REF_TUS 0x100000000ULL
@ -676,6 +678,9 @@ static inline u64 ice_get_base_incval(struct ice_hw *hw)
#define ICE_P0_GNSS_PRSNT_N BIT(4)
/* ETH56G PHY register addresses */
#define PHY_REG_GLOBAL 0x0
#define PHY_REG_GLOBAL_SOFT_RESET_M BIT(11)
/* Timestamp PHY incval registers */
#define PHY_REG_TIMETUS_L 0x8
#define PHY_REG_TIMETUS_U 0xC

View File

@ -305,6 +305,8 @@ ice_sf_eth_activate(struct ice_dynamic_port *dyn_port,
aux_dev_uninit:
auxiliary_device_uninit(&sf_dev->adev);
return err;
sf_dev_free:
kfree(sf_dev);
xa_erase:

View File

@ -190,9 +190,10 @@ void ice_free_tstamp_ring(struct ice_tx_ring *tx_ring)
void ice_free_tx_tstamp_ring(struct ice_tx_ring *tx_ring)
{
ice_free_tstamp_ring(tx_ring);
clear_bit(ICE_TX_RING_FLAGS_TXTIME, tx_ring->flags);
smp_wmb(); /* order flag clear before pointer NULL */
kfree_rcu(tx_ring->tstamp_ring, rcu);
tx_ring->tstamp_ring = NULL;
tx_ring->flags &= ~ICE_TX_FLAGS_TXTIME;
WRITE_ONCE(tx_ring->tstamp_ring, NULL);
}
/**
@ -405,7 +406,7 @@ static int ice_alloc_tstamp_ring(struct ice_tx_ring *tx_ring)
tx_ring->tstamp_ring = tstamp_ring;
tstamp_ring->desc = NULL;
tstamp_ring->count = ice_calc_ts_ring_count(tx_ring);
tx_ring->flags |= ICE_TX_FLAGS_TXTIME;
set_bit(ICE_TX_RING_FLAGS_TXTIME, tx_ring->flags);
return 0;
}
@ -1521,13 +1522,20 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first,
return;
if (ice_is_txtime_cfg(tx_ring)) {
struct ice_tstamp_ring *tstamp_ring = tx_ring->tstamp_ring;
u32 tstamp_count = tstamp_ring->count;
u32 j = tstamp_ring->next_to_use;
struct ice_tstamp_ring *tstamp_ring;
u32 tstamp_count, j;
struct ice_ts_desc *ts_desc;
struct timespec64 ts;
u32 tstamp;
smp_rmb(); /* order flag read before pointer read */
tstamp_ring = READ_ONCE(tx_ring->tstamp_ring);
if (unlikely(!tstamp_ring))
goto ring_kick;
tstamp_count = tstamp_ring->count;
j = tstamp_ring->next_to_use;
ts = ktime_to_timespec64(first->skb->tstamp);
tstamp = ts.tv_nsec >> ICE_TXTIME_CTX_RESOLUTION_128NS;
@ -1555,6 +1563,7 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first,
tstamp_ring->next_to_use = j;
writel_relaxed(j, tstamp_ring->tail);
} else {
ring_kick:
writel_relaxed(i, tx_ring->tail);
}
return;
@ -1814,7 +1823,7 @@ ice_tx_prepare_vlan_flags(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first)
*/
if (skb_vlan_tag_present(skb)) {
first->vid = skb_vlan_tag_get(skb);
if (tx_ring->flags & ICE_TX_FLAGS_RING_VLAN_L2TAG2)
if (test_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, tx_ring->flags))
first->tx_flags |= ICE_TX_FLAGS_HW_OUTER_SINGLE_VLAN;
else
first->tx_flags |= ICE_TX_FLAGS_HW_VLAN;
@ -2158,6 +2167,9 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
ice_trace(xmit_frame_ring, tx_ring, skb);
/* record the location of the first descriptor for this packet */
first = &tx_ring->tx_buf[tx_ring->next_to_use];
count = ice_xmit_desc_count(skb);
if (ice_chk_linearize(skb, count)) {
if (__skb_linearize(skb))
@ -2183,8 +2195,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
offload.tx_ring = tx_ring;
/* record the location of the first descriptor for this packet */
first = &tx_ring->tx_buf[tx_ring->next_to_use];
first->skb = skb;
first->type = ICE_TX_BUF_SKB;
first->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN);
@ -2249,6 +2259,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
out_drop:
ice_trace(xmit_frame_ring_drop, tx_ring, skb);
dev_kfree_skb_any(skb);
first->type = ICE_TX_BUF_EMPTY;
return NETDEV_TX_OK;
}

View File

@ -212,6 +212,14 @@ enum ice_rx_dtype {
ICE_RX_DTYPE_SPLIT_ALWAYS = 2,
};
enum ice_tx_ring_flags {
ICE_TX_RING_FLAGS_XDP,
ICE_TX_RING_FLAGS_VLAN_L2TAG1,
ICE_TX_RING_FLAGS_VLAN_L2TAG2,
ICE_TX_RING_FLAGS_TXTIME,
ICE_TX_RING_FLAGS_NBITS,
};
struct ice_pkt_ctx {
u64 cached_phctime;
__be16 vlan_proto;
@ -352,11 +360,7 @@ struct ice_tx_ring {
u16 count; /* Number of descriptors */
u16 q_index; /* Queue number of ring */
u8 flags;
#define ICE_TX_FLAGS_RING_XDP BIT(0)
#define ICE_TX_FLAGS_RING_VLAN_L2TAG1 BIT(1)
#define ICE_TX_FLAGS_RING_VLAN_L2TAG2 BIT(2)
#define ICE_TX_FLAGS_TXTIME BIT(3)
DECLARE_BITMAP(flags, ICE_TX_RING_FLAGS_NBITS);
struct xsk_buff_pool *xsk_pool;
@ -398,7 +402,7 @@ static inline bool ice_ring_ch_enabled(struct ice_tx_ring *ring)
static inline bool ice_ring_is_xdp(struct ice_tx_ring *ring)
{
return !!(ring->flags & ICE_TX_FLAGS_RING_XDP);
return test_bit(ICE_TX_RING_FLAGS_XDP, ring->flags);
}
enum ice_container_type {

View File

@ -201,7 +201,10 @@ int mlx5e_add_vlan_trap(struct mlx5e_flow_steering *fs, int trap_id, int tir_nu
void mlx5e_remove_vlan_trap(struct mlx5e_flow_steering *fs);
int mlx5e_add_mac_trap(struct mlx5e_flow_steering *fs, int trap_id, int tir_num);
void mlx5e_remove_mac_trap(struct mlx5e_flow_steering *fs);
void mlx5e_fs_set_rx_mode_work(struct mlx5e_flow_steering *fs, struct net_device *netdev);
void mlx5e_fs_set_rx_mode_work(struct mlx5e_flow_steering *fs,
struct net_device *netdev,
struct netdev_hw_addr_list *uc,
struct netdev_hw_addr_list *mc);
int mlx5e_fs_vlan_rx_add_vid(struct mlx5e_flow_steering *fs,
struct net_device *netdev,
__be16 proto, u16 vid);

View File

@ -609,20 +609,26 @@ static void mlx5e_execute_l2_action(struct mlx5e_flow_steering *fs,
}
static void mlx5e_sync_netdev_addr(struct mlx5e_flow_steering *fs,
struct net_device *netdev)
struct net_device *netdev,
struct netdev_hw_addr_list *uc,
struct netdev_hw_addr_list *mc)
{
struct netdev_hw_addr *ha;
netif_addr_lock_bh(netdev);
if (!uc || !mc) {
netif_addr_lock_bh(netdev);
mlx5e_sync_netdev_addr(fs, netdev, &netdev->uc, &netdev->mc);
netif_addr_unlock_bh(netdev);
return;
}
mlx5e_add_l2_to_hash(fs->l2.netdev_uc, netdev->dev_addr);
netdev_for_each_uc_addr(ha, netdev)
netdev_hw_addr_list_for_each(ha, uc)
mlx5e_add_l2_to_hash(fs->l2.netdev_uc, ha->addr);
netdev_for_each_mc_addr(ha, netdev)
netdev_hw_addr_list_for_each(ha, mc)
mlx5e_add_l2_to_hash(fs->l2.netdev_mc, ha->addr);
netif_addr_unlock_bh(netdev);
}
static void mlx5e_fill_addr_array(struct mlx5e_flow_steering *fs, int list_type,
@ -724,7 +730,9 @@ static void mlx5e_apply_netdev_addr(struct mlx5e_flow_steering *fs)
}
static void mlx5e_handle_netdev_addr(struct mlx5e_flow_steering *fs,
struct net_device *netdev)
struct net_device *netdev,
struct netdev_hw_addr_list *uc,
struct netdev_hw_addr_list *mc)
{
struct mlx5e_l2_hash_node *hn;
struct hlist_node *tmp;
@ -736,7 +744,7 @@ static void mlx5e_handle_netdev_addr(struct mlx5e_flow_steering *fs,
hn->action = MLX5E_ACTION_DEL;
if (fs->state_destroy)
mlx5e_sync_netdev_addr(fs, netdev);
mlx5e_sync_netdev_addr(fs, netdev, uc, mc);
mlx5e_apply_netdev_addr(fs);
}
@ -820,13 +828,15 @@ static void mlx5e_destroy_promisc_table(struct mlx5e_flow_steering *fs)
}
void mlx5e_fs_set_rx_mode_work(struct mlx5e_flow_steering *fs,
struct net_device *netdev)
struct net_device *netdev,
struct netdev_hw_addr_list *uc,
struct netdev_hw_addr_list *mc)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5e_l2_table *ea = &fs->l2;
if (mlx5e_is_uplink_rep(priv)) {
mlx5e_handle_netdev_addr(fs, netdev);
mlx5e_handle_netdev_addr(fs, netdev, uc, mc);
goto update_vport_context;
}
@ -856,7 +866,7 @@ void mlx5e_fs_set_rx_mode_work(struct mlx5e_flow_steering *fs,
if (enable_broadcast)
mlx5e_add_l2_flow_rule(fs, &ea->broadcast, MLX5E_FULLMATCH);
mlx5e_handle_netdev_addr(fs, netdev);
mlx5e_handle_netdev_addr(fs, netdev, uc, mc);
if (disable_broadcast)
mlx5e_del_l2_flow_rule(fs, &ea->broadcast);

View File

@ -4145,11 +4145,13 @@ static void mlx5e_nic_set_rx_mode(struct mlx5e_priv *priv)
queue_work(priv->wq, &priv->set_rx_mode_work);
}
static void mlx5e_set_rx_mode(struct net_device *dev)
static void mlx5e_set_rx_mode(struct net_device *dev,
struct netdev_hw_addr_list *uc,
struct netdev_hw_addr_list *mc)
{
struct mlx5e_priv *priv = netdev_priv(dev);
mlx5e_nic_set_rx_mode(priv);
mlx5e_fs_set_rx_mode_work(priv->fs, dev, uc, mc);
}
static int mlx5e_set_mac(struct net_device *netdev, void *addr)
@ -5324,7 +5326,7 @@ const struct net_device_ops mlx5e_netdev_ops = {
.ndo_setup_tc = mlx5e_setup_tc,
.ndo_select_queue = mlx5e_select_queue,
.ndo_get_stats64 = mlx5e_get_stats,
.ndo_set_rx_mode = mlx5e_set_rx_mode,
.ndo_set_rx_mode_async = mlx5e_set_rx_mode,
.ndo_set_mac_address = mlx5e_set_mac,
.ndo_vlan_rx_add_vid = mlx5e_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = mlx5e_vlan_rx_kill_vid,
@ -6309,8 +6311,11 @@ void mlx5e_set_rx_mode_work(struct work_struct *work)
{
struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv,
set_rx_mode_work);
struct net_device *dev = priv->netdev;
return mlx5e_fs_set_rx_mode_work(priv->fs, priv->netdev);
netdev_lock_ops(dev);
mlx5e_fs_set_rx_mode_work(priv->fs, dev, NULL, NULL);
netdev_unlock_ops(dev);
}
/* mlx5e generic netdev management API (move to en_common.c) */

View File

@ -1849,7 +1849,7 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)
err = mlx5_notifiers_init(dev);
if (err)
goto err_hca_caps;
goto err_notifiers_init;
/* The conjunction of sw_vhca_id with sw_owner_id will be a global
* unique id per function which uses mlx5_core.
@ -1865,6 +1865,8 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)
return 0;
err_notifiers_init:
mlx5_hca_caps_free(dev);
err_hca_caps:
mlx5_adev_cleanup(dev);
err_adev_init:

View File

@ -183,7 +183,9 @@ static int fbnic_mc_unsync(struct net_device *netdev, const unsigned char *addr)
return ret;
}
void __fbnic_set_rx_mode(struct fbnic_dev *fbd)
void __fbnic_set_rx_mode(struct fbnic_dev *fbd,
struct netdev_hw_addr_list *uc,
struct netdev_hw_addr_list *mc)
{
bool uc_promisc = false, mc_promisc = false;
struct net_device *netdev = fbd->netdev;
@ -213,10 +215,10 @@ void __fbnic_set_rx_mode(struct fbnic_dev *fbd)
}
/* Synchronize unicast and multicast address lists */
err = __dev_uc_sync(netdev, fbnic_uc_sync, fbnic_uc_unsync);
err = __hw_addr_sync_dev(uc, netdev, fbnic_uc_sync, fbnic_uc_unsync);
if (err == -ENOSPC)
uc_promisc = true;
err = __dev_mc_sync(netdev, fbnic_mc_sync, fbnic_mc_unsync);
err = __hw_addr_sync_dev(mc, netdev, fbnic_mc_sync, fbnic_mc_unsync);
if (err == -ENOSPC)
mc_promisc = true;
@ -238,18 +240,21 @@ void __fbnic_set_rx_mode(struct fbnic_dev *fbd)
fbnic_write_tce_tcam(fbd);
}
static void fbnic_set_rx_mode(struct net_device *netdev)
static void fbnic_set_rx_mode(struct net_device *netdev,
struct netdev_hw_addr_list *uc,
struct netdev_hw_addr_list *mc)
{
struct fbnic_net *fbn = netdev_priv(netdev);
struct fbnic_dev *fbd = fbn->fbd;
/* No need to update the hardware if we are not running */
if (netif_running(netdev))
__fbnic_set_rx_mode(fbd);
__fbnic_set_rx_mode(fbd, uc, mc);
}
static int fbnic_set_mac(struct net_device *netdev, void *p)
{
struct fbnic_net *fbn = netdev_priv(netdev);
struct sockaddr *addr = p;
if (!is_valid_ether_addr(addr->sa_data))
@ -257,7 +262,8 @@ static int fbnic_set_mac(struct net_device *netdev, void *p)
eth_hw_addr_set(netdev, addr->sa_data);
fbnic_set_rx_mode(netdev);
if (netif_running(netdev))
__fbnic_set_rx_mode(fbn->fbd, &netdev->uc, &netdev->mc);
return 0;
}
@ -551,7 +557,7 @@ static const struct net_device_ops fbnic_netdev_ops = {
.ndo_features_check = fbnic_features_check,
.ndo_set_mac_address = fbnic_set_mac,
.ndo_change_mtu = fbnic_change_mtu,
.ndo_set_rx_mode = fbnic_set_rx_mode,
.ndo_set_rx_mode_async = fbnic_set_rx_mode,
.ndo_get_stats64 = fbnic_get_stats64,
.ndo_bpf = fbnic_bpf,
.ndo_hwtstamp_get = fbnic_hwtstamp_get,

View File

@ -97,7 +97,9 @@ void fbnic_time_init(struct fbnic_net *fbn);
int fbnic_time_start(struct fbnic_net *fbn);
void fbnic_time_stop(struct fbnic_net *fbn);
void __fbnic_set_rx_mode(struct fbnic_dev *fbd);
void __fbnic_set_rx_mode(struct fbnic_dev *fbd,
struct netdev_hw_addr_list *uc,
struct netdev_hw_addr_list *mc);
void fbnic_clear_rx_mode(struct fbnic_dev *fbd);
void fbnic_phylink_get_pauseparam(struct net_device *netdev,

View File

@ -135,7 +135,7 @@ void fbnic_up(struct fbnic_net *fbn)
fbnic_rss_reinit_hw(fbn->fbd, fbn);
__fbnic_set_rx_mode(fbn->fbd);
__fbnic_set_rx_mode(fbn->fbd, &fbn->netdev->uc, &fbn->netdev->mc);
/* Enable Tx/Rx processing */
fbnic_napi_enable(fbn);
@ -180,7 +180,7 @@ static int fbnic_fw_config_after_crash(struct fbnic_dev *fbd)
}
fbnic_rpc_reset_valid_entries(fbd);
__fbnic_set_rx_mode(fbd);
__fbnic_set_rx_mode(fbd, &fbd->netdev->uc, &fbd->netdev->mc);
return 0;
}

View File

@ -244,7 +244,7 @@ void fbnic_bmc_rpc_check(struct fbnic_dev *fbd)
if (fbd->fw_cap.need_bmc_tcam_reinit) {
fbnic_bmc_rpc_init(fbd);
__fbnic_set_rx_mode(fbd);
__fbnic_set_rx_mode(fbd, &fbd->netdev->uc, &fbd->netdev->mc);
fbd->fw_cap.need_bmc_tcam_reinit = false;
}

View File

@ -408,10 +408,8 @@ struct ks8851_net {
struct gpio_desc *gpio;
struct mii_bus *mii_bus;
void (*lock)(struct ks8851_net *ks,
unsigned long *flags);
void (*unlock)(struct ks8851_net *ks,
unsigned long *flags);
void (*lock)(struct ks8851_net *ks);
void (*unlock)(struct ks8851_net *ks);
unsigned int (*rdreg16)(struct ks8851_net *ks,
unsigned int reg);
void (*wrreg16)(struct ks8851_net *ks,

View File

@ -28,25 +28,23 @@
/**
* ks8851_lock - register access lock
* @ks: The chip state
* @flags: Spinlock flags
*
* Claim chip register access lock
*/
static void ks8851_lock(struct ks8851_net *ks, unsigned long *flags)
static void ks8851_lock(struct ks8851_net *ks)
{
ks->lock(ks, flags);
ks->lock(ks);
}
/**
* ks8851_unlock - register access unlock
* @ks: The chip state
* @flags: Spinlock flags
*
* Release chip register access lock
*/
static void ks8851_unlock(struct ks8851_net *ks, unsigned long *flags)
static void ks8851_unlock(struct ks8851_net *ks)
{
ks->unlock(ks, flags);
ks->unlock(ks);
}
/**
@ -129,11 +127,10 @@ static void ks8851_set_powermode(struct ks8851_net *ks, unsigned pwrmode)
static int ks8851_write_mac_addr(struct net_device *dev)
{
struct ks8851_net *ks = netdev_priv(dev);
unsigned long flags;
u16 val;
int i;
ks8851_lock(ks, &flags);
ks8851_lock(ks);
/*
* Wake up chip in case it was powered off when stopped; otherwise,
@ -149,7 +146,7 @@ static int ks8851_write_mac_addr(struct net_device *dev)
if (!netif_running(dev))
ks8851_set_powermode(ks, PMECR_PM_SOFTDOWN);
ks8851_unlock(ks, &flags);
ks8851_unlock(ks);
return 0;
}
@ -163,12 +160,11 @@ static int ks8851_write_mac_addr(struct net_device *dev)
static void ks8851_read_mac_addr(struct net_device *dev)
{
struct ks8851_net *ks = netdev_priv(dev);
unsigned long flags;
u8 addr[ETH_ALEN];
u16 reg;
int i;
ks8851_lock(ks, &flags);
ks8851_lock(ks);
for (i = 0; i < ETH_ALEN; i += 2) {
reg = ks8851_rdreg16(ks, KS_MAR(i));
@ -177,7 +173,7 @@ static void ks8851_read_mac_addr(struct net_device *dev)
}
eth_hw_addr_set(dev, addr);
ks8851_unlock(ks, &flags);
ks8851_unlock(ks);
}
/**
@ -312,11 +308,10 @@ static irqreturn_t ks8851_irq(int irq, void *_ks)
{
struct ks8851_net *ks = _ks;
struct sk_buff_head rxq;
unsigned long flags;
unsigned int status;
struct sk_buff *skb;
ks8851_lock(ks, &flags);
ks8851_lock(ks);
status = ks8851_rdreg16(ks, KS_ISR);
ks8851_wrreg16(ks, KS_ISR, status);
@ -373,14 +368,17 @@ static irqreturn_t ks8851_irq(int irq, void *_ks)
ks8851_wrreg16(ks, KS_RXCR1, rxc->rxcr1);
}
ks8851_unlock(ks, &flags);
ks8851_unlock(ks);
if (status & IRQ_LCI)
mii_check_link(&ks->mii);
if (status & IRQ_RXI)
if (status & IRQ_RXI) {
local_bh_disable();
while ((skb = __skb_dequeue(&rxq)))
netif_rx(skb);
local_bh_enable();
}
return IRQ_HANDLED;
}
@ -405,7 +403,6 @@ static void ks8851_flush_tx_work(struct ks8851_net *ks)
static int ks8851_net_open(struct net_device *dev)
{
struct ks8851_net *ks = netdev_priv(dev);
unsigned long flags;
int ret;
ret = request_threaded_irq(dev->irq, NULL, ks8851_irq,
@ -418,7 +415,7 @@ static int ks8851_net_open(struct net_device *dev)
/* lock the card, even if we may not actually be doing anything
* else at the moment */
ks8851_lock(ks, &flags);
ks8851_lock(ks);
netif_dbg(ks, ifup, ks->netdev, "opening\n");
@ -471,7 +468,7 @@ static int ks8851_net_open(struct net_device *dev)
netif_dbg(ks, ifup, ks->netdev, "network device up\n");
ks8851_unlock(ks, &flags);
ks8851_unlock(ks);
mii_check_link(&ks->mii);
return 0;
}
@ -487,23 +484,22 @@ static int ks8851_net_open(struct net_device *dev)
static int ks8851_net_stop(struct net_device *dev)
{
struct ks8851_net *ks = netdev_priv(dev);
unsigned long flags;
netif_info(ks, ifdown, dev, "shutting down\n");
netif_stop_queue(dev);
ks8851_lock(ks, &flags);
ks8851_lock(ks);
/* turn off the IRQs and ack any outstanding */
ks8851_wrreg16(ks, KS_IER, 0x0000);
ks8851_wrreg16(ks, KS_ISR, 0xffff);
ks8851_unlock(ks, &flags);
ks8851_unlock(ks);
/* stop any outstanding work */
ks8851_flush_tx_work(ks);
flush_work(&ks->rxctrl_work);
ks8851_lock(ks, &flags);
ks8851_lock(ks);
/* shutdown RX process */
ks8851_wrreg16(ks, KS_RXCR1, 0x0000);
@ -512,7 +508,7 @@ static int ks8851_net_stop(struct net_device *dev)
/* set powermode to soft power down to save power */
ks8851_set_powermode(ks, PMECR_PM_SOFTDOWN);
ks8851_unlock(ks, &flags);
ks8851_unlock(ks);
/* ensure any queued tx buffers are dumped */
while (!skb_queue_empty(&ks->txq)) {
@ -566,14 +562,13 @@ static netdev_tx_t ks8851_start_xmit(struct sk_buff *skb,
static void ks8851_rxctrl_work(struct work_struct *work)
{
struct ks8851_net *ks = container_of(work, struct ks8851_net, rxctrl_work);
unsigned long flags;
ks8851_lock(ks, &flags);
ks8851_lock(ks);
/* need to shutdown RXQ before modifying filter parameters */
ks8851_wrreg16(ks, KS_RXCR1, 0x00);
ks8851_unlock(ks, &flags);
ks8851_unlock(ks);
}
static void ks8851_set_rx_mode(struct net_device *dev)
@ -780,7 +775,6 @@ static int ks8851_set_eeprom(struct net_device *dev,
{
struct ks8851_net *ks = netdev_priv(dev);
int offset = ee->offset;
unsigned long flags;
int len = ee->len;
u16 tmp;
@ -794,7 +788,7 @@ static int ks8851_set_eeprom(struct net_device *dev,
if (!(ks->rc_ccr & CCR_EEPROM))
return -ENOENT;
ks8851_lock(ks, &flags);
ks8851_lock(ks);
ks8851_eeprom_claim(ks);
@ -817,7 +811,7 @@ static int ks8851_set_eeprom(struct net_device *dev,
eeprom_93cx6_wren(&ks->eeprom, false);
ks8851_eeprom_release(ks);
ks8851_unlock(ks, &flags);
ks8851_unlock(ks);
return 0;
}
@ -827,7 +821,6 @@ static int ks8851_get_eeprom(struct net_device *dev,
{
struct ks8851_net *ks = netdev_priv(dev);
int offset = ee->offset;
unsigned long flags;
int len = ee->len;
/* must be 2 byte aligned */
@ -837,7 +830,7 @@ static int ks8851_get_eeprom(struct net_device *dev,
if (!(ks->rc_ccr & CCR_EEPROM))
return -ENOENT;
ks8851_lock(ks, &flags);
ks8851_lock(ks);
ks8851_eeprom_claim(ks);
@ -845,7 +838,7 @@ static int ks8851_get_eeprom(struct net_device *dev,
eeprom_93cx6_multiread(&ks->eeprom, offset/2, (__le16 *)data, len/2);
ks8851_eeprom_release(ks);
ks8851_unlock(ks, &flags);
ks8851_unlock(ks);
return 0;
}
@ -904,7 +897,6 @@ static int ks8851_phy_reg(int reg)
static int ks8851_phy_read_common(struct net_device *dev, int phy_addr, int reg)
{
struct ks8851_net *ks = netdev_priv(dev);
unsigned long flags;
int result;
int ksreg;
@ -912,9 +904,9 @@ static int ks8851_phy_read_common(struct net_device *dev, int phy_addr, int reg)
if (ksreg < 0)
return ksreg;
ks8851_lock(ks, &flags);
ks8851_lock(ks);
result = ks8851_rdreg16(ks, ksreg);
ks8851_unlock(ks, &flags);
ks8851_unlock(ks);
return result;
}
@ -949,14 +941,13 @@ static void ks8851_phy_write(struct net_device *dev,
int phy, int reg, int value)
{
struct ks8851_net *ks = netdev_priv(dev);
unsigned long flags;
int ksreg;
ksreg = ks8851_phy_reg(reg);
if (ksreg >= 0) {
ks8851_lock(ks, &flags);
ks8851_lock(ks);
ks8851_wrreg16(ks, ksreg, value);
ks8851_unlock(ks, &flags);
ks8851_unlock(ks);
}
}

View File

@ -55,29 +55,27 @@ struct ks8851_net_par {
/**
* ks8851_lock_par - register access lock
* @ks: The chip state
* @flags: Spinlock flags
*
* Claim chip register access lock
*/
static void ks8851_lock_par(struct ks8851_net *ks, unsigned long *flags)
static void ks8851_lock_par(struct ks8851_net *ks)
{
struct ks8851_net_par *ksp = to_ks8851_par(ks);
spin_lock_irqsave(&ksp->lock, *flags);
spin_lock_bh(&ksp->lock);
}
/**
* ks8851_unlock_par - register access unlock
* @ks: The chip state
* @flags: Spinlock flags
*
* Release chip register access lock
*/
static void ks8851_unlock_par(struct ks8851_net *ks, unsigned long *flags)
static void ks8851_unlock_par(struct ks8851_net *ks)
{
struct ks8851_net_par *ksp = to_ks8851_par(ks);
spin_unlock_irqrestore(&ksp->lock, *flags);
spin_unlock_bh(&ksp->lock);
}
/**
@ -233,7 +231,6 @@ static netdev_tx_t ks8851_start_xmit_par(struct sk_buff *skb,
{
struct ks8851_net *ks = netdev_priv(dev);
netdev_tx_t ret = NETDEV_TX_OK;
unsigned long flags;
unsigned int txqcr;
u16 txmir;
int err;
@ -241,7 +238,7 @@ static netdev_tx_t ks8851_start_xmit_par(struct sk_buff *skb,
netif_dbg(ks, tx_queued, ks->netdev,
"%s: skb %p, %d@%p\n", __func__, skb, skb->len, skb->data);
ks8851_lock_par(ks, &flags);
ks8851_lock_par(ks);
txmir = ks8851_rdreg16_par(ks, KS_TXMIR) & 0x1fff;
@ -262,7 +259,7 @@ static netdev_tx_t ks8851_start_xmit_par(struct sk_buff *skb,
ret = NETDEV_TX_BUSY;
}
ks8851_unlock_par(ks, &flags);
ks8851_unlock_par(ks);
return ret;
}

View File

@ -71,11 +71,10 @@ struct ks8851_net_spi {
/**
* ks8851_lock_spi - register access lock
* @ks: The chip state
* @flags: Spinlock flags
*
* Claim chip register access lock
*/
static void ks8851_lock_spi(struct ks8851_net *ks, unsigned long *flags)
static void ks8851_lock_spi(struct ks8851_net *ks)
{
struct ks8851_net_spi *kss = to_ks8851_spi(ks);
@ -85,11 +84,10 @@ static void ks8851_lock_spi(struct ks8851_net *ks, unsigned long *flags)
/**
* ks8851_unlock_spi - register access unlock
* @ks: The chip state
* @flags: Spinlock flags
*
* Release chip register access lock
*/
static void ks8851_unlock_spi(struct ks8851_net *ks, unsigned long *flags)
static void ks8851_unlock_spi(struct ks8851_net *ks)
{
struct ks8851_net_spi *kss = to_ks8851_spi(ks);
@ -309,7 +307,6 @@ static void ks8851_tx_work(struct work_struct *work)
struct ks8851_net_spi *kss;
unsigned short tx_space;
struct ks8851_net *ks;
unsigned long flags;
struct sk_buff *txb;
bool last;
@ -317,7 +314,7 @@ static void ks8851_tx_work(struct work_struct *work)
ks = &kss->ks8851;
last = skb_queue_empty(&ks->txq);
ks8851_lock_spi(ks, &flags);
ks8851_lock_spi(ks);
while (!last) {
txb = skb_dequeue(&ks->txq);
@ -343,7 +340,7 @@ static void ks8851_tx_work(struct work_struct *work)
ks->tx_space = tx_space;
spin_unlock_bh(&ks->statelock);
ks8851_unlock_spi(ks, &flags);
ks8851_unlock_spi(ks);
}
/**

View File

@ -3640,8 +3640,12 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
ac->gdma_dev = gd;
gd->driver_data = ac;
INIT_WORK(&ac->link_change_work, mana_link_state_handle);
}
INIT_DELAYED_WORK(&ac->gf_stats_work, mana_gf_stats_work_handler);
err = mana_create_eq(ac);
if (err) {
dev_err(dev, "Failed to create EQs: %d\n", err);
@ -3657,8 +3661,6 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
if (!resuming) {
ac->num_ports = num_ports;
INIT_WORK(&ac->link_change_work, mana_link_state_handle);
} else {
if (ac->num_ports != num_ports) {
dev_err(dev, "The number of vPorts changed: %d->%d\n",
@ -3687,10 +3689,9 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
if (!resuming) {
for (i = 0; i < ac->num_ports; i++) {
err = mana_probe_port(ac, i, &ac->ports[i]);
/* we log the port for which the probe failed and stop
* probes for subsequent ports.
* Note that we keep running ports, for which the probes
* were successful, unless add_adev fails too
/* Log the port for which the probe failed, stop probing
* subsequent ports, and skip add_adev.
* mana_remove() will clean up already-probed ports.
*/
if (err) {
dev_err(dev, "Probe Failed for port %d\n", i);
@ -3704,10 +3705,9 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
enable_work(&apc->queue_reset_work);
err = mana_attach(ac->ports[i]);
rtnl_unlock();
/* we log the port for which the attach failed and stop
* attach for subsequent ports
* Note that we keep running ports, for which the attach
* were successful, unless add_adev fails too
/* Log the port for which the attach failed, stop
* attaching subsequent ports, and skip add_adev.
* mana_remove() will clean up already-attached ports.
*/
if (err) {
dev_err(dev, "Attach Failed for port %d\n", i);
@ -3716,9 +3716,9 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
}
}
err = add_adev(gd, "eth");
if (!err)
err = add_adev(gd, "eth");
INIT_DELAYED_WORK(&ac->gf_stats_work, mana_gf_stats_work_handler);
schedule_delayed_work(&ac->gf_stats_work, MANA_GF_STATS_PERIOD);
out:
@ -3739,11 +3739,16 @@ void mana_remove(struct gdma_dev *gd, bool suspending)
struct gdma_context *gc = gd->gdma_context;
struct mana_context *ac = gd->driver_data;
struct mana_port_context *apc;
struct device *dev = gc->dev;
struct device *dev;
struct net_device *ndev;
int err;
int i;
if (!gc || !ac)
return;
dev = gc->dev;
disable_work_sync(&ac->link_change_work);
cancel_delayed_work_sync(&ac->gf_stats_work);
@ -3756,7 +3761,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending)
if (!ndev) {
if (i == 0)
dev_err(dev, "No net device to remove\n");
goto out;
break;
}
apc = netdev_priv(ndev);
@ -3787,7 +3792,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending)
}
mana_destroy_eq(ac);
out:
if (ac->per_port_queue_reset_wq) {
destroy_workqueue(ac->per_port_queue_reset_wq);
ac->per_port_queue_reset_wq = NULL;

View File

@ -435,12 +435,17 @@ static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt,
/* Full Island ID and channel bits overlap? */
ret = nfp_decode_basic(addr, &v, cpp_tgt, mode, addr40, isld1, isld0);
if (ret)
if (ret) {
pr_warn("%s: decode dest_island failed: %d\n", __func__, ret);
return ret;
}
/* The current address won't go where expected? */
if (dest_island != -1 && dest_island != v)
if (dest_island != -1 && dest_island != v) {
pr_warn("%s: dest_island mismatch: current (%d) != decoded (%d)\n",
__func__, dest_island, v);
return -EINVAL;
}
/* If dest_island was -1, we don't care where it goes. */
return 0;
@ -493,7 +498,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,
* the address but we can verify if the existing
* contents will point to a valid island.
*/
return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt,
mode, addr40, isld1, isld0);
iid_lsb = addr40 ? 34 : 26;
@ -504,7 +509,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,
return 0;
case 1:
if (cpp_tgt == NFP_CPP_TARGET_QDR && !addr40)
return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt,
mode, addr40, isld1, isld0);
idx_lsb = addr40 ? 39 : 31;
@ -530,7 +535,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,
* be set before hand and with them select an island.
* So we need to confirm that it's at least plausible.
*/
return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt,
mode, addr40, isld1, isld0);
/* Make sure we compare against isldN values
@ -551,7 +556,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,
* iid<1> = addr<30> = channel<0>
* channel<1> = addr<31> = Index
*/
return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt,
mode, addr40, isld1, isld0);
isld[0] &= ~3;

View File

@ -1410,8 +1410,6 @@ static int stmmac_phylink_setup(struct stmmac_priv *priv)
priv->tx_lpi_clk_stop = priv->plat->flags &
STMMAC_FLAG_EN_TX_LPI_CLOCKGATING;
config->default_an_inband = priv->plat->default_an_inband;
/* Get the PHY interface modes (at the PHY end of the link) that
* are supported by the platform.
*/
@ -1419,6 +1417,8 @@ static int stmmac_phylink_setup(struct stmmac_priv *priv)
priv->plat->get_interfaces(priv, priv->plat->bsp_priv,
config->supported_interfaces);
config->default_an_inband = priv->plat->default_an_inband;
/* Set the platform/firmware specified interface mode if the
* supported interfaces have not already been provided using
* phy_interface as a last resort.

View File

@ -864,7 +864,8 @@ static int txgbe_probe(struct pci_dev *pdev,
"0x%08x", etrack_id);
}
if (etrack_id < 0x20010)
if (wx->mac.type == wx_mac_sp &&
((etrack_id & 0xfffff) < 0x20010))
dev_warn(&pdev->dev, "Please upgrade the firmware to 0x20010 or above.\n");
err = txgbe_test_hostif(wx);

View File

@ -2400,6 +2400,7 @@ static int gtp_genl_send_echo_req(struct sk_buff *skb, struct genl_info *info)
return -ENODEV;
}
local_bh_disable();
udp_tunnel_xmit_skb(rt, sk, skb_to_send,
fl4.saddr, fl4.daddr,
inet_dscp_to_dsfield(fl4.flowi4_dscp),
@ -2409,6 +2410,7 @@ static int gtp_genl_send_echo_req(struct sk_buff *skb, struct genl_info *info)
!net_eq(sock_net(sk),
dev_net(gtp->dev)),
false, 0);
local_bh_enable();
return 0;
}

View File

@ -1689,6 +1689,7 @@ static size_t macvlan_get_size(const struct net_device *dev)
+ macvlan_get_size_mac(vlan) /* IFLA_MACVLAN_MACADDR */
+ nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN */
+ nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN_USED */
+ nla_total_size(4) /* IFLA_MACVLAN_BC_CUTOFF */
);
}

View File

@ -147,6 +147,7 @@ config MDIO_OCTEON
config MDIO_PIC64HPSC
tristate "PIC64-HPSC/HX MDIO interface support"
depends on ARCH_MICROCHIP || COMPILE_TEST
depends on HAS_IOMEM && OF_MDIO
help
This driver supports the MDIO interface found on the PIC64-HPSC/HX

View File

@ -497,6 +497,8 @@ static void trim_newline(char *s, size_t maxlen)
size_t len;
len = strnlen(s, maxlen);
if (!len)
return;
if (s[len - 1] == '\n')
s[len - 1] = '\0';
}

View File

@ -185,7 +185,9 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
static void nsim_set_rx_mode(struct net_device *dev)
static void nsim_set_rx_mode(struct net_device *dev,
struct netdev_hw_addr_list *uc,
struct netdev_hw_addr_list *mc)
{
}
@ -623,7 +625,7 @@ static const struct net_shaper_ops nsim_shaper_ops = {
static const struct net_device_ops nsim_netdev_ops = {
.ndo_start_xmit = nsim_start_xmit,
.ndo_set_rx_mode = nsim_set_rx_mode,
.ndo_set_rx_mode_async = nsim_set_rx_mode,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = nsim_change_mtu,
@ -648,7 +650,7 @@ static const struct net_device_ops nsim_netdev_ops = {
static const struct net_device_ops nsim_vf_netdev_ops = {
.ndo_start_xmit = nsim_start_xmit,
.ndo_set_rx_mode = nsim_set_rx_mode,
.ndo_set_rx_mode_async = nsim_set_rx_mode,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = nsim_change_mtu,

View File

@ -186,7 +186,9 @@ static int netkit_get_iflink(const struct net_device *dev)
return iflink;
}
static void netkit_set_multicast(struct net_device *dev)
static void netkit_set_multicast(struct net_device *dev,
struct netdev_hw_addr_list *uc,
struct netdev_hw_addr_list *mc)
{
/* Nothing to do, we receive whatever gets pushed to us! */
}
@ -330,7 +332,7 @@ static const struct net_device_ops netkit_netdev_ops = {
.ndo_open = netkit_open,
.ndo_stop = netkit_close,
.ndo_start_xmit = netkit_xmit,
.ndo_set_rx_mode = netkit_set_multicast,
.ndo_set_rx_mode_async = netkit_set_multicast,
.ndo_set_rx_headroom = netkit_set_headroom,
.ndo_set_mac_address = netkit_set_macaddr,
.ndo_get_iflink = netkit_get_iflink,

View File

@ -2245,7 +2245,7 @@ ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
*/
static void __ppp_decompress_proto(struct sk_buff *skb)
{
if (skb->data[0] & 0x01)
if (ppp_skb_is_compressed_proto(skb))
*(u8 *)skb_push(skb, 1) = 0x00;
}

View File

@ -393,7 +393,7 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev,
if (skb_mac_header_len(skb) < ETH_HLEN)
goto drop;
if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
if (!pskb_may_pull(skb, PPPOE_SES_HLEN))
goto drop;
ph = pppoe_hdr(skb);
@ -403,6 +403,12 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev,
if (skb->len < len)
goto drop;
/* skb->data points to the PPP protocol header after skb_pull_rcsum.
* Drop PFC frames.
*/
if (ppp_skb_is_compressed_proto(skb))
goto drop;
if (pskb_trim_rcsum(skb, len))
goto drop;

View File

@ -1170,6 +1170,7 @@ struct pse_irq {
struct pse_controller_dev *pcdev;
struct pse_irq_desc desc;
unsigned long *notifs;
unsigned long *notifs_mask;
};
/**
@ -1247,7 +1248,6 @@ static int pse_set_config_isr(struct pse_controller_dev *pcdev, int id,
static irqreturn_t pse_isr(int irq, void *data)
{
struct pse_controller_dev *pcdev;
unsigned long notifs_mask = 0;
struct pse_irq_desc *desc;
struct pse_irq *h = data;
int ret, i;
@ -1257,14 +1257,15 @@ static irqreturn_t pse_isr(int irq, void *data)
/* Clear notifs mask */
memset(h->notifs, 0, pcdev->nr_lines * sizeof(*h->notifs));
bitmap_zero(h->notifs_mask, pcdev->nr_lines);
mutex_lock(&pcdev->lock);
ret = desc->map_event(irq, pcdev, h->notifs, &notifs_mask);
if (ret || !notifs_mask) {
ret = desc->map_event(irq, pcdev, h->notifs, h->notifs_mask);
if (ret || bitmap_empty(h->notifs_mask, pcdev->nr_lines)) {
mutex_unlock(&pcdev->lock);
return IRQ_NONE;
}
for_each_set_bit(i, &notifs_mask, pcdev->nr_lines) {
for_each_set_bit(i, h->notifs_mask, pcdev->nr_lines) {
unsigned long notifs, rnotifs;
struct pse_ntf ntf = {};
@ -1340,6 +1341,10 @@ int devm_pse_irq_helper(struct pse_controller_dev *pcdev, int irq,
if (!h->notifs)
return -ENOMEM;
h->notifs_mask = devm_bitmap_zalloc(dev, pcdev->nr_lines, GFP_KERNEL);
if (!h->notifs_mask)
return -ENOMEM;
ret = devm_request_threaded_irq(dev, irq, NULL, pse_isr,
IRQF_ONESHOT | irq_flags,
irq_name, h);

View File

@ -80,9 +80,9 @@
#include <linux/unaligned.h>
static unsigned char *encode(unsigned char *cp, unsigned short n);
static long decode(unsigned char **cpp);
static long decode(unsigned char **cpp, const unsigned char *end);
static unsigned char * put16(unsigned char *cp, unsigned short x);
static unsigned short pull16(unsigned char **cpp);
static long pull16(unsigned char **cpp, const unsigned char *end);
/* Allocate compression data structure
* slots must be in range 0 to 255 (zero meaning no compression)
@ -190,30 +190,34 @@ encode(unsigned char *cp, unsigned short n)
return cp;
}
/* Pull a 16-bit integer in host order from buffer in network byte order */
static unsigned short
pull16(unsigned char **cpp)
/* Pull a 16-bit integer in host order from buffer in network byte order.
* Returns -1 if the buffer is exhausted, otherwise the 16-bit value.
*/
static long
pull16(unsigned char **cpp, const unsigned char *end)
{
short rval;
long rval;
if (*cpp + 2 > end)
return -1;
rval = *(*cpp)++;
rval <<= 8;
rval |= *(*cpp)++;
return rval;
}
/* Decode a number */
/* Decode a number. Returns -1 if the buffer is exhausted. */
static long
decode(unsigned char **cpp)
decode(unsigned char **cpp, const unsigned char *end)
{
int x;
if (*cpp >= end)
return -1;
x = *(*cpp)++;
if(x == 0){
return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */
} else {
return x & 0xff; /* -1 if PULLCHAR returned error */
}
if (x == 0)
return pull16(cpp, end);
return x & 0xff;
}
/*
@ -499,6 +503,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
struct cstate *cs;
int len, hdrlen;
unsigned char *cp = icp;
const unsigned char *end = icp + isize;
/* We've got a compressed packet; read the change byte */
comp->sls_i_compressed++;
@ -506,6 +511,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
comp->sls_i_error++;
return 0;
}
if (!comp->rstate)
goto bad;
changes = *cp++;
if(changes & NEW_C){
/* Make sure the state index is in range, then grab the state.
@ -534,6 +541,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
thp = &cs->cs_tcp;
ip = &cs->cs_ip;
if (cp + 2 > end)
goto bad;
thp->check = *(__sum16 *)cp;
cp += 2;
@ -564,26 +573,26 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
default:
if(changes & NEW_U){
thp->urg = 1;
if((x = decode(&cp)) == -1) {
if((x = decode(&cp, end)) == -1) {
goto bad;
}
thp->urg_ptr = htons(x);
} else
thp->urg = 0;
if(changes & NEW_W){
if((x = decode(&cp)) == -1) {
if((x = decode(&cp, end)) == -1) {
goto bad;
}
thp->window = htons( ntohs(thp->window) + x);
}
if(changes & NEW_A){
if((x = decode(&cp)) == -1) {
if((x = decode(&cp, end)) == -1) {
goto bad;
}
thp->ack_seq = htonl( ntohl(thp->ack_seq) + x);
}
if(changes & NEW_S){
if((x = decode(&cp)) == -1) {
if((x = decode(&cp, end)) == -1) {
goto bad;
}
thp->seq = htonl( ntohl(thp->seq) + x);
@ -591,7 +600,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
break;
}
if(changes & NEW_I){
if((x = decode(&cp)) == -1) {
if((x = decode(&cp, end)) == -1) {
goto bad;
}
ip->id = htons (ntohs (ip->id) + x);
@ -649,6 +658,10 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
struct cstate *cs;
unsigned int ihl;
if (!comp->rstate) {
comp->sls_i_error++;
return slhc_toss(comp);
}
/* The packet is shorter than a legal IP header.
* Also make sure isize is positive.
*/

View File

@ -3759,6 +3759,12 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
queue_pairs);
return -EINVAL;
}
/* Keep max_tx_vq in sync so that a later RSS command does not
* revert queue_pairs to a stale value.
*/
if (vi->has_rss)
vi->rss_trailer.max_tx_vq = cpu_to_le16(queue_pairs);
succ:
vi->curr_queue_pairs = queue_pairs;
if (dev->flags & IFF_UP) {

View File

@ -560,7 +560,7 @@ static void vhost_net_busy_poll(struct vhost_net *net,
busyloop_timeout = poll_rx ? rvq->busyloop_timeout:
tvq->busyloop_timeout;
preempt_disable();
migrate_disable();
endtime = busy_clock() + busyloop_timeout;
while (vhost_can_busy_poll(endtime)) {
@ -577,7 +577,7 @@ static void vhost_net_busy_poll(struct vhost_net *net,
cpu_relax();
}
preempt_enable();
migrate_enable();
if (poll_rx || sock_has_rx_data(sock))
vhost_net_busy_poll_try_queue(net, vq);

View File

@ -31,6 +31,12 @@ struct netc_tbl_vers {
u8 rsst_ver;
};
struct netc_swcbd {
void *buf;
dma_addr_t dma;
size_t size;
};
struct netc_cbdr {
struct device *dev;
struct netc_cbdr_regs regs;
@ -44,9 +50,10 @@ struct netc_cbdr {
void *addr_base_align;
dma_addr_t dma_base;
dma_addr_t dma_base_align;
struct netc_swcbd *swcbd;
/* Serialize the order of command BD ring */
spinlock_t ring_lock;
struct mutex ring_lock;
};
struct ntmp_user {

View File

@ -147,11 +147,13 @@ extern __be16 vlan_dev_vlan_proto(const struct net_device *dev);
* @priority: skb priority
* @vlan_qos: vlan priority: (skb->priority << 13) & 0xE000
* @next: pointer to next struct
* @rcu: used for deferred freeing of mapping nodes
*/
struct vlan_priority_tci_mapping {
u32 priority;
u16 vlan_qos;
struct vlan_priority_tci_mapping *next;
struct vlan_priority_tci_mapping __rcu *next;
struct rcu_head rcu;
};
struct proc_dir_entry;
@ -177,7 +179,7 @@ struct vlan_dev_priv {
unsigned int nr_ingress_mappings;
u32 ingress_priority_map[8];
unsigned int nr_egress_mappings;
struct vlan_priority_tci_mapping *egress_priority_map[16];
struct vlan_priority_tci_mapping __rcu *egress_priority_map[16];
__be16 vlan_proto;
u16 vlan_id;
@ -209,19 +211,24 @@ static inline u16
vlan_dev_get_egress_qos_mask(struct net_device *dev, u32 skprio)
{
struct vlan_priority_tci_mapping *mp;
u16 vlan_qos = 0;
smp_rmb(); /* coupled with smp_wmb() in vlan_dev_set_egress_priority() */
rcu_read_lock();
mp = vlan_dev_priv(dev)->egress_priority_map[(skprio & 0xF)];
mp = rcu_dereference(vlan_dev_priv(dev)->egress_priority_map[skprio & 0xF]);
while (mp) {
if (mp->priority == skprio) {
return mp->vlan_qos; /* This should already be shifted
* to mask correctly with the
* VLAN's TCI */
vlan_qos = READ_ONCE(mp->vlan_qos);
break;
}
mp = mp->next;
mp = rcu_dereference(mp->next);
}
return 0;
rcu_read_unlock();
/* This should already be shifted to mask correctly with
* the VLAN's TCI.
*/
return vlan_qos;
}
extern bool vlan_do_receive(struct sk_buff **skb);

View File

@ -1119,6 +1119,16 @@ struct netdev_net_notifier {
* This function is called device changes address list filtering.
* If driver handles unicast address filtering, it should set
* IFF_UNICAST_FLT in its priv_flags.
* Cannot sleep, called with netif_addr_lock_bh held.
* Deprecated in favor of ndo_set_rx_mode_async.
*
* void (*ndo_set_rx_mode_async)(struct net_device *dev,
* struct netdev_hw_addr_list *uc,
* struct netdev_hw_addr_list *mc);
* Async version of ndo_set_rx_mode which runs in process context
* with rtnl_lock and netdev_lock_ops(dev) held. The uc/mc parameters
* are snapshots of the address lists - iterate with
* netdev_hw_addr_list_for_each(ha, uc).
*
* int (*ndo_set_mac_address)(struct net_device *dev, void *addr);
* This function is called when the Media Access Control address
@ -1439,6 +1449,10 @@ struct net_device_ops {
void (*ndo_change_rx_flags)(struct net_device *dev,
int flags);
void (*ndo_set_rx_mode)(struct net_device *dev);
void (*ndo_set_rx_mode_async)(
struct net_device *dev,
struct netdev_hw_addr_list *uc,
struct netdev_hw_addr_list *mc);
int (*ndo_set_mac_address)(struct net_device *dev,
void *addr);
int (*ndo_validate_addr)(struct net_device *dev);
@ -1903,6 +1917,9 @@ enum netdev_reg_state {
* has been enabled due to the need to listen to
* additional unicast addresses in a device that
* does not implement ndo_set_rx_mode()
* @rx_mode_node: List entry for rx_mode work processing
* @rx_mode_tracker: Refcount tracker for rx_mode work
* @rx_mode_addr_cache: Recycled snapshot entries for rx_mode work
* @uc: unicast mac addresses
* @mc: multicast mac addresses
* @dev_addrs: list of device hw addresses
@ -2294,6 +2311,9 @@ struct net_device {
unsigned int promiscuity;
unsigned int allmulti;
bool uc_promisc;
struct list_head rx_mode_node;
netdevice_tracker rx_mode_tracker;
struct netdev_hw_addr_list rx_mode_addr_cache;
#ifdef CONFIG_LOCKDEP
unsigned char nested_level;
#endif
@ -5004,6 +5024,14 @@ void __hw_addr_unsync_dev(struct netdev_hw_addr_list *list,
int (*unsync)(struct net_device *,
const unsigned char *));
void __hw_addr_init(struct netdev_hw_addr_list *list);
void __hw_addr_flush(struct netdev_hw_addr_list *list);
int __hw_addr_list_snapshot(struct netdev_hw_addr_list *snap,
const struct netdev_hw_addr_list *list,
int addr_len, struct netdev_hw_addr_list *cache);
void __hw_addr_list_reconcile(struct netdev_hw_addr_list *real_list,
struct netdev_hw_addr_list *work,
struct netdev_hw_addr_list *ref, int addr_len,
struct netdev_hw_addr_list *cache);
/* Functions used for device addresses handling */
void dev_addr_mod(struct net_device *dev, unsigned int offset,

View File

@ -8,6 +8,7 @@
#define _PPP_DEFS_H_
#include <linux/crc-ccitt.h>
#include <linux/skbuff.h>
#include <uapi/linux/ppp_defs.h>
#define PPP_FCS(fcs, c) crc_ccitt_byte(fcs, c)
@ -25,4 +26,19 @@ static inline bool ppp_proto_is_valid(u16 proto)
return !!((proto & 0x0101) == 0x0001);
}
/**
* ppp_skb_is_compressed_proto - checks if PPP protocol in a skb is compressed
* @skb: skb to check
*
* Check if the PPP protocol field is compressed (the least significant
* bit of the most significant octet is 1). skb->data must point to the PPP
* protocol header.
*
* Return: Whether the PPP protocol field is compressed.
*/
static inline bool ppp_skb_is_compressed_proto(const struct sk_buff *skb)
{
return unlikely(skb->data[0] & 0x01);
}
#endif /* _PPP_DEFS_H_ */

View File

@ -26,6 +26,9 @@ struct mctp_hdr {
#define MCTP_VER_MIN 1
#define MCTP_VER_MAX 1
/* Definitions for ver field */
#define MCTP_HDR_VER_MASK GENMASK(3, 0)
/* Definitions for flags_seq_tag field */
#define MCTP_HDR_FLAG_SOM BIT(7)
#define MCTP_HDR_FLAG_EOM BIT(6)

View File

@ -104,7 +104,7 @@ static inline void pie_vars_init(struct pie_vars *vars)
vars->dq_tstamp = DTIME_INVALID;
vars->accu_prob = 0;
vars->dq_count = DQCOUNT_INVALID;
vars->avg_dq_rate = 0;
WRITE_ONCE(vars->avg_dq_rate, 0);
}
static inline struct pie_skb_cb *get_pie_cb(const struct sk_buff *skb)

View File

@ -1513,7 +1513,7 @@ static inline u32 tcp_snd_cwnd(const struct tcp_sock *tp)
static inline void tcp_snd_cwnd_set(struct tcp_sock *tp, u32 val)
{
WARN_ON_ONCE((int)val <= 0);
tp->snd_cwnd = val;
WRITE_ONCE(tp->snd_cwnd, val);
}
static inline bool tcp_in_slow_start(const struct tcp_sock *tp)
@ -2208,10 +2208,14 @@ static inline void tcp_chrono_set(struct tcp_sock *tp, const enum tcp_chrono new
const u32 now = tcp_jiffies32;
enum tcp_chrono old = tp->chrono_type;
/* Following WRITE_ONCE()s pair with READ_ONCE()s in
* tcp_get_info_chrono_stats().
*/
if (old > TCP_CHRONO_UNSPEC)
tp->chrono_stat[old - 1] += now - tp->chrono_start;
tp->chrono_start = now;
tp->chrono_type = new;
WRITE_ONCE(tp->chrono_stat[old - 1],
tp->chrono_stat[old - 1] + now - tp->chrono_start);
WRITE_ONCE(tp->chrono_start, now);
WRITE_ONCE(tp->chrono_type, new);
}
static inline void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type)

View File

@ -181,7 +181,7 @@ static inline void tcp_accecn_third_ack(struct sock *sk,
tcp_accecn_validate_syn_feedback(sk, ace, sent_ect)) {
if ((tcp_accecn_extract_syn_ect(ace) == INET_ECN_CE) &&
!tp->delivered_ce)
tp->delivered_ce++;
WRITE_ONCE(tp->delivered_ce, 1);
}
break;
}

View File

@ -10,6 +10,7 @@
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/tracepoint.h>
#include <net/busy_poll.h>
TRACE_EVENT(net_dev_start_xmit,
@ -208,7 +209,8 @@ DECLARE_EVENT_CLASS(net_dev_rx_verbose_template,
TP_fast_assign(
__assign_str(name);
#ifdef CONFIG_NET_RX_BUSY_POLL
__entry->napi_id = skb->napi_id;
__entry->napi_id = napi_id_valid(skb->napi_id) ?
skb->napi_id : 0;
#else
__entry->napi_id = 0;
#endif

View File

@ -37,6 +37,7 @@
EM(rxkad_abort_1_short_encdata, "rxkad1-short-encdata") \
EM(rxkad_abort_1_short_header, "rxkad1-short-hdr") \
EM(rxkad_abort_2_short_check, "rxkad2-short-check") \
EM(rxkad_abort_2_crypto_unaligned, "rxkad2-crypto-unaligned") \
EM(rxkad_abort_2_short_data, "rxkad2-short-data") \
EM(rxkad_abort_2_short_header, "rxkad2-short-hdr") \
EM(rxkad_abort_2_short_len, "rxkad2-short-len") \
@ -161,8 +162,6 @@
E_(rxrpc_call_poke_timer_now, "Timer-now")
#define rxrpc_skb_traces \
EM(rxrpc_skb_eaten_by_unshare, "ETN unshare ") \
EM(rxrpc_skb_eaten_by_unshare_nomem, "ETN unshar-nm") \
EM(rxrpc_skb_get_call_rx, "GET call-rx ") \
EM(rxrpc_skb_get_conn_secured, "GET conn-secd") \
EM(rxrpc_skb_get_conn_work, "GET conn-work") \
@ -189,6 +188,7 @@
EM(rxrpc_skb_put_purge, "PUT purge ") \
EM(rxrpc_skb_put_purge_oob, "PUT purge-oob") \
EM(rxrpc_skb_put_response, "PUT response ") \
EM(rxrpc_skb_put_response_copy, "PUT resp-cpy ") \
EM(rxrpc_skb_put_rotate, "PUT rotate ") \
EM(rxrpc_skb_put_unknown, "PUT unknown ") \
EM(rxrpc_skb_see_conn_work, "SEE conn-work") \
@ -197,6 +197,7 @@
EM(rxrpc_skb_see_recvmsg_oob, "SEE recvm-oob") \
EM(rxrpc_skb_see_reject, "SEE reject ") \
EM(rxrpc_skb_see_rotate, "SEE rotate ") \
EM(rxrpc_skb_see_unshare_nomem, "SEE unshar-nm") \
E_(rxrpc_skb_see_version, "SEE version ")
#define rxrpc_local_traces \
@ -284,7 +285,6 @@
EM(rxrpc_conn_put_unidle, "PUT unidle ") \
EM(rxrpc_conn_put_work, "PUT work ") \
EM(rxrpc_conn_queue_challenge, "QUE chall ") \
EM(rxrpc_conn_queue_retry_work, "QUE retry-wk") \
EM(rxrpc_conn_queue_rx_work, "QUE rx-work ") \
EM(rxrpc_conn_see_new_service_conn, "SEE new-svc ") \
EM(rxrpc_conn_see_reap_service, "SEE reap-svc") \

View File

@ -172,39 +172,42 @@ int vlan_dev_set_egress_priority(const struct net_device *dev,
u32 skb_prio, u16 vlan_prio)
{
struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
struct vlan_priority_tci_mapping *mp = NULL;
struct vlan_priority_tci_mapping __rcu **mpp;
struct vlan_priority_tci_mapping *mp;
struct vlan_priority_tci_mapping *np;
u32 bucket = skb_prio & 0xF;
u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK;
/* See if a priority mapping exists.. */
mp = vlan->egress_priority_map[skb_prio & 0xF];
mpp = &vlan->egress_priority_map[bucket];
mp = rtnl_dereference(*mpp);
while (mp) {
if (mp->priority == skb_prio) {
if (mp->vlan_qos && !vlan_qos)
if (!vlan_qos) {
rcu_assign_pointer(*mpp, rtnl_dereference(mp->next));
vlan->nr_egress_mappings--;
else if (!mp->vlan_qos && vlan_qos)
vlan->nr_egress_mappings++;
mp->vlan_qos = vlan_qos;
kfree_rcu(mp, rcu);
} else {
WRITE_ONCE(mp->vlan_qos, vlan_qos);
}
return 0;
}
mp = mp->next;
mpp = &mp->next;
mp = rtnl_dereference(*mpp);
}
/* Create a new mapping then. */
mp = vlan->egress_priority_map[skb_prio & 0xF];
if (!vlan_qos)
return 0;
np = kmalloc_obj(struct vlan_priority_tci_mapping);
if (!np)
return -ENOBUFS;
np->next = mp;
np->priority = skb_prio;
np->vlan_qos = vlan_qos;
/* Before inserting this element in hash table, make sure all its fields
* are committed to memory.
* coupled with smp_rmb() in vlan_dev_get_egress_qos_mask()
*/
smp_wmb();
vlan->egress_priority_map[skb_prio & 0xF] = np;
RCU_INIT_POINTER(np->next, rtnl_dereference(vlan->egress_priority_map[bucket]));
rcu_assign_pointer(vlan->egress_priority_map[bucket], np);
if (vlan_qos)
vlan->nr_egress_mappings++;
return 0;
@ -604,11 +607,17 @@ void vlan_dev_free_egress_priority(const struct net_device *dev)
int i;
for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
while ((pm = vlan->egress_priority_map[i]) != NULL) {
vlan->egress_priority_map[i] = pm->next;
kfree(pm);
pm = rtnl_dereference(vlan->egress_priority_map[i]);
RCU_INIT_POINTER(vlan->egress_priority_map[i], NULL);
while (pm) {
struct vlan_priority_tci_mapping *next;
next = rtnl_dereference(pm->next);
kfree_rcu(pm, rcu);
pm = next;
}
}
vlan->nr_egress_mappings = 0;
}
static void vlan_dev_uninit(struct net_device *dev)

View File

@ -260,13 +260,11 @@ static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
goto nla_put_failure;
for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
for (pm = vlan->egress_priority_map[i]; pm;
pm = pm->next) {
if (!pm->vlan_qos)
continue;
for (pm = rcu_dereference_rtnl(vlan->egress_priority_map[i]); pm;
pm = rcu_dereference_rtnl(pm->next)) {
u16 vlan_qos = READ_ONCE(pm->vlan_qos);
m.from = pm->priority;
m.to = (pm->vlan_qos >> 13) & 0x7;
m.to = (vlan_qos >> 13) & 0x7;
if (nla_put(skb, IFLA_VLAN_QOS_MAPPING,
sizeof(m), &m))
goto nla_put_failure;

View File

@ -262,15 +262,19 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset)
vlan->ingress_priority_map[7]);
seq_printf(seq, " EGRESS priority mappings: ");
rcu_read_lock();
for (i = 0; i < 16; i++) {
const struct vlan_priority_tci_mapping *mp
= vlan->egress_priority_map[i];
const struct vlan_priority_tci_mapping *mp =
rcu_dereference(vlan->egress_priority_map[i]);
while (mp) {
u16 vlan_qos = READ_ONCE(mp->vlan_qos);
seq_printf(seq, "%u:%d ",
mp->priority, ((mp->vlan_qos >> 13) & 0x7));
mp = mp->next;
mp->priority, ((vlan_qos >> 13) & 0x7));
mp = rcu_dereference(mp->next);
}
}
rcu_read_unlock();
seq_puts(seq, "\n");
return 0;

View File

@ -201,11 +201,12 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br,
f = br_fdb_find_rcu(br, n->ha, vid);
if (f) {
const struct net_bridge_port *dst = READ_ONCE(f->dst);
bool replied = false;
if ((p && (p->flags & BR_PROXYARP)) ||
(f->dst && (f->dst->flags & BR_PROXYARP_WIFI)) ||
br_is_neigh_suppress_enabled(f->dst, vid)) {
(dst && (dst->flags & BR_PROXYARP_WIFI)) ||
br_is_neigh_suppress_enabled(dst, vid)) {
if (!vid)
br_arp_send(br, p, skb->dev, sip, tip,
sha, n->ha, sha, 0, 0);
@ -469,9 +470,10 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
f = br_fdb_find_rcu(br, n->ha, vid);
if (f) {
const struct net_bridge_port *dst = READ_ONCE(f->dst);
bool replied = false;
if (br_is_neigh_suppress_enabled(f->dst, vid)) {
if (br_is_neigh_suppress_enabled(dst, vid)) {
if (vid != 0)
br_nd_send(br, p, skb, n,
skb->vlan_proto,

View File

@ -236,6 +236,7 @@ struct net_device *br_fdb_find_port(const struct net_device *br_dev,
const unsigned char *addr,
__u16 vid)
{
const struct net_bridge_port *dst;
struct net_bridge_fdb_entry *f;
struct net_device *dev = NULL;
struct net_bridge *br;
@ -248,8 +249,11 @@ struct net_device *br_fdb_find_port(const struct net_device *br_dev,
br = netdev_priv(br_dev);
rcu_read_lock();
f = br_fdb_find_rcu(br, addr, vid);
if (f && f->dst)
dev = f->dst->dev;
if (f) {
dst = READ_ONCE(f->dst);
if (dst)
dev = dst->dev;
}
rcu_read_unlock();
return dev;
@ -346,7 +350,7 @@ static void fdb_delete_local(struct net_bridge *br,
vg = nbp_vlan_group(op);
if (op != p && ether_addr_equal(op->dev->dev_addr, addr) &&
(!vid || br_vlan_find(vg, vid))) {
f->dst = op;
WRITE_ONCE(f->dst, op);
clear_bit(BR_FDB_ADDED_BY_USER, &f->flags);
return;
}
@ -357,7 +361,7 @@ static void fdb_delete_local(struct net_bridge *br,
/* Maybe bridge device has same hw addr? */
if (p && ether_addr_equal(br->dev->dev_addr, addr) &&
(!vid || (v && br_vlan_should_use(v)))) {
f->dst = NULL;
WRITE_ONCE(f->dst, NULL);
clear_bit(BR_FDB_ADDED_BY_USER, &f->flags);
return;
}
@ -928,6 +932,7 @@ int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
int br_fdb_fillbuf(struct net_bridge *br, void *buf,
unsigned long maxnum, unsigned long skip)
{
const struct net_bridge_port *dst;
struct net_bridge_fdb_entry *f;
struct __fdb_entry *fe = buf;
unsigned long delta;
@ -944,7 +949,8 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
continue;
/* ignore pseudo entry for local MAC address */
if (!f->dst)
dst = READ_ONCE(f->dst);
if (!dst)
continue;
if (skip) {
@ -956,8 +962,8 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
memcpy(fe->mac_addr, f->key.addr.addr, ETH_ALEN);
/* due to ABI compat need to split into hi/lo */
fe->port_no = f->dst->port_no;
fe->port_hi = f->dst->port_no >> 8;
fe->port_no = dst->port_no;
fe->port_hi = dst->port_no >> 8;
fe->is_local = test_bit(BR_FDB_LOCAL, &f->flags);
if (!test_bit(BR_FDB_STATIC, &f->flags)) {
@ -1083,9 +1089,11 @@ int br_fdb_dump(struct sk_buff *skb,
rcu_read_lock();
hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
const struct net_bridge_port *dst = READ_ONCE(f->dst);
if (*idx < ctx->fdb_idx)
goto skip;
if (filter_dev && (!f->dst || f->dst->dev != filter_dev)) {
if (filter_dev && (!dst || dst->dev != filter_dev)) {
if (filter_dev != dev)
goto skip;
/* !f->dst is a special case for bridge
@ -1093,10 +1101,10 @@ int br_fdb_dump(struct sk_buff *skb,
* Therefore need a little more filtering
* we only want to dump the !f->dst case
*/
if (f->dst)
if (dst)
goto skip;
}
if (!filter_dev && f->dst)
if (!filter_dev && dst)
goto skip;
err = fdb_fill_info(skb, br, f,

View File

@ -9593,14 +9593,14 @@ static void dev_change_rx_flags(struct net_device *dev, int flags)
ops->ndo_change_rx_flags(dev, flags);
}
static int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify)
int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify)
{
unsigned int old_flags = dev->flags;
unsigned int promiscuity, flags;
kuid_t uid;
kgid_t gid;
ASSERT_RTNL();
netdev_ops_assert_locked(dev);
promiscuity = dev->promiscuity + inc;
if (promiscuity == 0) {
@ -9636,16 +9636,8 @@ static int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify)
dev_change_rx_flags(dev, IFF_PROMISC);
}
if (notify) {
/* The ops lock is only required to ensure consistent locking
* for `NETDEV_CHANGE` notifiers. This function is sometimes
* called without the lock, even for devices that are ops
* locked, such as in `dev_uc_sync_multiple` when using
* bonding or teaming.
*/
netdev_ops_assert_locked(dev);
if (notify)
__dev_notify_flags(dev, old_flags, IFF_PROMISC, 0, NULL);
}
return 0;
}
@ -9667,7 +9659,7 @@ int netif_set_allmulti(struct net_device *dev, int inc, bool notify)
unsigned int old_flags = dev->flags, old_gflags = dev->gflags;
unsigned int allmulti, flags;
ASSERT_RTNL();
netdev_ops_assert_locked(dev);
allmulti = dev->allmulti + inc;
if (allmulti == 0) {
@ -9697,46 +9689,6 @@ int netif_set_allmulti(struct net_device *dev, int inc, bool notify)
return 0;
}
/*
* Upload unicast and multicast address lists to device and
* configure RX filtering. When the device doesn't support unicast
* filtering it is put in promiscuous mode while unicast addresses
* are present.
*/
void __dev_set_rx_mode(struct net_device *dev)
{
const struct net_device_ops *ops = dev->netdev_ops;
/* dev_open will call this function so the list will stay sane. */
if (!(dev->flags&IFF_UP))
return;
if (!netif_device_present(dev))
return;
if (!(dev->priv_flags & IFF_UNICAST_FLT)) {
/* Unicast addresses changes may only happen under the rtnl,
* therefore calling __dev_set_promiscuity here is safe.
*/
if (!netdev_uc_empty(dev) && !dev->uc_promisc) {
__dev_set_promiscuity(dev, 1, false);
dev->uc_promisc = true;
} else if (netdev_uc_empty(dev) && dev->uc_promisc) {
__dev_set_promiscuity(dev, -1, false);
dev->uc_promisc = false;
}
}
if (ops->ndo_set_rx_mode)
ops->ndo_set_rx_mode(dev);
}
void dev_set_rx_mode(struct net_device *dev)
{
netif_addr_lock_bh(dev);
__dev_set_rx_mode(dev);
netif_addr_unlock_bh(dev);
}
/**
* netif_get_flags() - get flags reported to userspace
@ -9775,7 +9727,7 @@ int __dev_change_flags(struct net_device *dev, unsigned int flags,
unsigned int old_flags = dev->flags;
int ret;
ASSERT_RTNL();
netdev_ops_assert_locked(dev);
/*
* Set the flags on our device.
@ -11408,6 +11360,11 @@ int register_netdevice(struct net_device *dev)
goto err_uninit;
}
if (netdev_need_ops_lock(dev) &&
dev->netdev_ops->ndo_set_rx_mode &&
!dev->netdev_ops->ndo_set_rx_mode_async)
netdev_WARN(dev, "ops-locked drivers should use ndo_set_rx_mode_async\n");
ret = netdev_do_alloc_pcpu_stats(dev);
if (ret)
goto err_uninit;
@ -12127,6 +12084,8 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
#endif
mutex_init(&dev->lock);
INIT_LIST_HEAD(&dev->rx_mode_node);
__hw_addr_init(&dev->rx_mode_addr_cache);
dev->priv_flags = IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM;
setup(dev);
@ -12231,6 +12190,8 @@ void free_netdev(struct net_device *dev)
kfree(rcu_dereference_protected(dev->ingress_queue, 1));
__hw_addr_flush(&dev->rx_mode_addr_cache);
/* Flush device addresses */
dev_addr_flush(dev);

View File

@ -78,6 +78,7 @@ void linkwatch_run_queue(void);
void dev_addr_flush(struct net_device *dev);
int dev_addr_init(struct net_device *dev);
void dev_addr_check(struct net_device *dev);
void __hw_addr_flush(struct netdev_hw_addr_list *list);
#if IS_ENABLED(CONFIG_NET_SHAPER)
void net_shaper_flush_netdev(struct net_device *dev);
@ -164,6 +165,9 @@ int netif_change_carrier(struct net_device *dev, bool new_carrier);
int dev_change_carrier(struct net_device *dev, bool new_carrier);
void __dev_set_rx_mode(struct net_device *dev);
int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify);
bool netif_rx_mode_clean(struct net_device *dev);
void netif_rx_mode_sync(struct net_device *dev);
void __dev_notify_flags(struct net_device *dev, unsigned int old_flags,
unsigned int gchanges, u32 portid,

View File

@ -11,9 +11,18 @@
#include <linux/rtnetlink.h>
#include <linux/export.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <kunit/visibility.h>
#include "dev.h"
static void netdev_rx_mode_work(struct work_struct *work);
static LIST_HEAD(rx_mode_list);
static DEFINE_SPINLOCK(rx_mode_lock);
static DECLARE_WORK(rx_mode_work, netdev_rx_mode_work);
/*
* General list handling functions
*/
@ -481,7 +490,7 @@ void __hw_addr_unsync_dev(struct netdev_hw_addr_list *list,
}
EXPORT_SYMBOL(__hw_addr_unsync_dev);
static void __hw_addr_flush(struct netdev_hw_addr_list *list)
void __hw_addr_flush(struct netdev_hw_addr_list *list)
{
struct netdev_hw_addr *ha, *tmp;
@ -492,6 +501,7 @@ static void __hw_addr_flush(struct netdev_hw_addr_list *list)
}
list->count = 0;
}
EXPORT_SYMBOL_IF_KUNIT(__hw_addr_flush);
void __hw_addr_init(struct netdev_hw_addr_list *list)
{
@ -501,6 +511,133 @@ void __hw_addr_init(struct netdev_hw_addr_list *list)
}
EXPORT_SYMBOL(__hw_addr_init);
static void __hw_addr_splice(struct netdev_hw_addr_list *dst,
struct netdev_hw_addr_list *src)
{
src->tree = RB_ROOT;
list_splice_init(&src->list, &dst->list);
dst->count += src->count;
src->count = 0;
}
/**
* __hw_addr_list_snapshot - create a snapshot copy of an address list
* @snap: destination snapshot list (needs to be __hw_addr_init-initialized)
* @list: source address list to snapshot
* @addr_len: length of addresses
* @cache: entry cache to reuse entries from; falls back to GFP_ATOMIC
*
* Creates a copy of @list reusing entries from @cache when available.
* Must be called under a spinlock.
*
* Return: 0 on success, -errno on failure.
*/
int __hw_addr_list_snapshot(struct netdev_hw_addr_list *snap,
const struct netdev_hw_addr_list *list,
int addr_len, struct netdev_hw_addr_list *cache)
{
struct netdev_hw_addr *ha, *entry;
list_for_each_entry(ha, &list->list, list) {
if (cache->count) {
entry = list_first_entry(&cache->list,
struct netdev_hw_addr, list);
list_del(&entry->list);
cache->count--;
memcpy(entry->addr, ha->addr, addr_len);
entry->type = ha->type;
entry->global_use = false;
entry->synced = 0;
} else {
entry = __hw_addr_create(ha->addr, addr_len, ha->type,
false, false);
if (!entry) {
__hw_addr_flush(snap);
return -ENOMEM;
}
}
entry->sync_cnt = ha->sync_cnt;
entry->refcount = ha->refcount;
list_add_tail(&entry->list, &snap->list);
__hw_addr_insert(snap, entry, addr_len);
snap->count++;
}
return 0;
}
EXPORT_SYMBOL_IF_KUNIT(__hw_addr_list_snapshot);
/**
* __hw_addr_list_reconcile - sync snapshot changes back and free snapshots
* @real_list: the real address list to update
* @work: the working snapshot (modified by driver via __hw_addr_sync_dev)
* @ref: the reference snapshot (untouched copy of original state)
* @addr_len: length of addresses
* @cache: entry cache to return snapshot entries to for reuse
*
* Walks the reference snapshot and compares each entry against the work
* snapshot to compute sync_cnt deltas. Applies those deltas to @real_list.
* Returns snapshot entries to @cache for reuse; frees both snapshots.
* Caller must hold netif_addr_lock_bh.
*/
void __hw_addr_list_reconcile(struct netdev_hw_addr_list *real_list,
struct netdev_hw_addr_list *work,
struct netdev_hw_addr_list *ref, int addr_len,
struct netdev_hw_addr_list *cache)
{
struct netdev_hw_addr *ref_ha, *tmp, *work_ha, *real_ha;
int delta;
list_for_each_entry_safe(ref_ha, tmp, &ref->list, list) {
work_ha = __hw_addr_lookup(work, ref_ha->addr, addr_len,
ref_ha->type);
if (work_ha)
delta = work_ha->sync_cnt - ref_ha->sync_cnt;
else
delta = -1;
if (delta == 0)
continue;
real_ha = __hw_addr_lookup(real_list, ref_ha->addr, addr_len,
ref_ha->type);
if (!real_ha) {
/* The real entry was concurrently removed. If the
* driver synced this addr to hardware (delta > 0),
* re-insert it as a stale entry so the next work
* run unsyncs it from hardware.
*/
if (delta > 0) {
rb_erase(&ref_ha->node, &ref->tree);
list_del(&ref_ha->list);
ref->count--;
ref_ha->sync_cnt = delta;
ref_ha->refcount = delta;
list_add_tail_rcu(&ref_ha->list,
&real_list->list);
__hw_addr_insert(real_list, ref_ha,
addr_len);
real_list->count++;
}
continue;
}
real_ha->sync_cnt += delta;
real_ha->refcount += delta;
if (!real_ha->refcount) {
rb_erase(&real_ha->node, &real_list->tree);
list_del_rcu(&real_ha->list);
kfree_rcu(real_ha, rcu_head);
real_list->count--;
}
}
__hw_addr_splice(cache, work);
__hw_addr_splice(cache, ref);
}
EXPORT_SYMBOL_IF_KUNIT(__hw_addr_list_reconcile);
/*
* Device addresses handling functions
*/
@ -1049,3 +1186,249 @@ void dev_mc_init(struct net_device *dev)
__hw_addr_init(&dev->mc);
}
EXPORT_SYMBOL(dev_mc_init);
static int netif_addr_lists_snapshot(struct net_device *dev,
struct netdev_hw_addr_list *uc_snap,
struct netdev_hw_addr_list *mc_snap,
struct netdev_hw_addr_list *uc_ref,
struct netdev_hw_addr_list *mc_ref)
{
int err;
err = __hw_addr_list_snapshot(uc_snap, &dev->uc, dev->addr_len,
&dev->rx_mode_addr_cache);
if (!err)
err = __hw_addr_list_snapshot(uc_ref, &dev->uc, dev->addr_len,
&dev->rx_mode_addr_cache);
if (!err)
err = __hw_addr_list_snapshot(mc_snap, &dev->mc,
dev->addr_len,
&dev->rx_mode_addr_cache);
if (!err)
err = __hw_addr_list_snapshot(mc_ref, &dev->mc, dev->addr_len,
&dev->rx_mode_addr_cache);
if (err) {
__hw_addr_flush(uc_snap);
__hw_addr_flush(uc_ref);
__hw_addr_flush(mc_snap);
}
return err;
}
static void netif_addr_lists_reconcile(struct net_device *dev,
struct netdev_hw_addr_list *uc_snap,
struct netdev_hw_addr_list *mc_snap,
struct netdev_hw_addr_list *uc_ref,
struct netdev_hw_addr_list *mc_ref)
{
__hw_addr_list_reconcile(&dev->uc, uc_snap, uc_ref, dev->addr_len,
&dev->rx_mode_addr_cache);
__hw_addr_list_reconcile(&dev->mc, mc_snap, mc_ref, dev->addr_len,
&dev->rx_mode_addr_cache);
}
/**
* netif_uc_promisc_update() - evaluate whether uc_promisc should be toggled.
* @dev: device
*
* Must be called under netif_addr_lock_bh.
* Return: +1 to enter promisc, -1 to leave, 0 for no change.
*/
static int netif_uc_promisc_update(struct net_device *dev)
{
if (dev->priv_flags & IFF_UNICAST_FLT)
return 0;
if (!netdev_uc_empty(dev) && !dev->uc_promisc) {
dev->uc_promisc = true;
return 1;
}
if (netdev_uc_empty(dev) && dev->uc_promisc) {
dev->uc_promisc = false;
return -1;
}
return 0;
}
static void netif_rx_mode_run(struct net_device *dev)
{
struct netdev_hw_addr_list uc_snap, mc_snap, uc_ref, mc_ref;
const struct net_device_ops *ops = dev->netdev_ops;
int promisc_inc;
int err;
might_sleep();
netdev_ops_assert_locked(dev);
__hw_addr_init(&uc_snap);
__hw_addr_init(&mc_snap);
__hw_addr_init(&uc_ref);
__hw_addr_init(&mc_ref);
if (!(dev->flags & IFF_UP) || !netif_device_present(dev))
return;
if (ops->ndo_set_rx_mode_async) {
netif_addr_lock_bh(dev);
err = netif_addr_lists_snapshot(dev, &uc_snap, &mc_snap,
&uc_ref, &mc_ref);
if (err) {
netdev_WARN(dev, "failed to sync uc/mc addresses\n");
netif_addr_unlock_bh(dev);
return;
}
promisc_inc = netif_uc_promisc_update(dev);
netif_addr_unlock_bh(dev);
} else {
netif_addr_lock_bh(dev);
promisc_inc = netif_uc_promisc_update(dev);
netif_addr_unlock_bh(dev);
}
if (promisc_inc)
__dev_set_promiscuity(dev, promisc_inc, false);
if (ops->ndo_set_rx_mode_async) {
ops->ndo_set_rx_mode_async(dev, &uc_snap, &mc_snap);
netif_addr_lock_bh(dev);
netif_addr_lists_reconcile(dev, &uc_snap, &mc_snap,
&uc_ref, &mc_ref);
netif_addr_unlock_bh(dev);
} else if (ops->ndo_set_rx_mode) {
netif_addr_lock_bh(dev);
ops->ndo_set_rx_mode(dev);
netif_addr_unlock_bh(dev);
}
}
static void netdev_rx_mode_work(struct work_struct *work)
{
struct net_device *dev;
rtnl_lock();
while (true) {
spin_lock_bh(&rx_mode_lock);
if (list_empty(&rx_mode_list)) {
spin_unlock_bh(&rx_mode_lock);
break;
}
dev = list_first_entry(&rx_mode_list, struct net_device,
rx_mode_node);
list_del_init(&dev->rx_mode_node);
/* We must free netdev tracker under
* the spinlock protection.
*/
netdev_tracker_free(dev, &dev->rx_mode_tracker);
spin_unlock_bh(&rx_mode_lock);
netdev_lock_ops(dev);
netif_rx_mode_run(dev);
netdev_unlock_ops(dev);
/* Use __dev_put() because netdev_tracker_free() was already
* called above. Must be after netdev_unlock_ops() to prevent
* netdev_run_todo() from freeing the device while still in use.
*/
__dev_put(dev);
}
rtnl_unlock();
}
static void netif_rx_mode_queue(struct net_device *dev)
{
spin_lock_bh(&rx_mode_lock);
if (list_empty(&dev->rx_mode_node)) {
list_add_tail(&dev->rx_mode_node, &rx_mode_list);
netdev_hold(dev, &dev->rx_mode_tracker, GFP_ATOMIC);
}
spin_unlock_bh(&rx_mode_lock);
schedule_work(&rx_mode_work);
}
/**
* __dev_set_rx_mode() - upload unicast and multicast address lists to device
* and configure RX filtering.
* @dev: device
*
* When the device doesn't support unicast filtering it is put in promiscuous
* mode while unicast addresses are present.
*/
void __dev_set_rx_mode(struct net_device *dev)
{
const struct net_device_ops *ops = dev->netdev_ops;
int promisc_inc;
/* dev_open will call this function so the list will stay sane. */
if (!(dev->flags & IFF_UP))
return;
if (!netif_device_present(dev))
return;
if (ops->ndo_set_rx_mode_async || ops->ndo_change_rx_flags ||
netdev_need_ops_lock(dev)) {
netif_rx_mode_queue(dev);
return;
}
/* Legacy path for non-ops-locked HW devices. */
promisc_inc = netif_uc_promisc_update(dev);
if (promisc_inc)
__dev_set_promiscuity(dev, promisc_inc, false);
if (ops->ndo_set_rx_mode)
ops->ndo_set_rx_mode(dev);
}
void dev_set_rx_mode(struct net_device *dev)
{
netif_addr_lock_bh(dev);
__dev_set_rx_mode(dev);
netif_addr_unlock_bh(dev);
}
bool netif_rx_mode_clean(struct net_device *dev)
{
bool clean = false;
spin_lock_bh(&rx_mode_lock);
if (!list_empty(&dev->rx_mode_node)) {
list_del_init(&dev->rx_mode_node);
clean = true;
/* We must release netdev tracker under
* the spinlock protection.
*/
netdev_tracker_free(dev, &dev->rx_mode_tracker);
}
spin_unlock_bh(&rx_mode_lock);
return clean;
}
/**
* netif_rx_mode_sync() - sync rx mode inline
* @dev: network device
*
* Drivers implementing ndo_set_rx_mode_async() have their rx mode callback
* executed from a workqueue. This allows the callback to sleep, but means
* the hardware update is deferred and may not be visible to userspace
* by the time the initiating syscall returns. netif_rx_mode_sync() steals
* workqueue update and executes it inline. This preserves the atomicity of
* operations to the userspace.
*/
void netif_rx_mode_sync(struct net_device *dev)
{
if (netif_rx_mode_clean(dev)) {
netif_rx_mode_run(dev);
/* Use __dev_put() because netdev_tracker_free() was already
* called inside netif_rx_mode_clean().
*/
__dev_put(dev);
}
}

View File

@ -2,22 +2,31 @@
#include <kunit/test.h>
#include <linux/etherdevice.h>
#include <linux/math64.h>
#include <linux/netdevice.h>
#include <linux/rtnetlink.h>
static const struct net_device_ops dummy_netdev_ops = {
};
#define ADDR_A 1
#define ADDR_B 2
#define ADDR_C 3
struct dev_addr_test_priv {
u32 addr_seen;
u32 addr_synced;
u32 addr_unsynced;
};
static int dev_addr_test_sync(struct net_device *netdev, const unsigned char *a)
{
struct dev_addr_test_priv *datp = netdev_priv(netdev);
if (a[0] < 31 && !memchr_inv(a, a[0], ETH_ALEN))
if (a[0] < 31 && !memchr_inv(a, a[0], ETH_ALEN)) {
datp->addr_seen |= 1 << a[0];
datp->addr_synced |= 1 << a[0];
}
return 0;
}
@ -26,11 +35,22 @@ static int dev_addr_test_unsync(struct net_device *netdev,
{
struct dev_addr_test_priv *datp = netdev_priv(netdev);
if (a[0] < 31 && !memchr_inv(a, a[0], ETH_ALEN))
if (a[0] < 31 && !memchr_inv(a, a[0], ETH_ALEN)) {
datp->addr_seen &= ~(1 << a[0]);
datp->addr_unsynced |= 1 << a[0];
}
return 0;
}
static void dev_addr_test_reset(struct net_device *netdev)
{
struct dev_addr_test_priv *datp = netdev_priv(netdev);
datp->addr_seen = 0;
datp->addr_synced = 0;
datp->addr_unsynced = 0;
}
static int dev_addr_test_init(struct kunit *test)
{
struct dev_addr_test_priv *datp;
@ -225,6 +245,363 @@ static void dev_addr_test_add_excl(struct kunit *test)
rtnl_unlock();
}
/* Snapshot test: basic sync with no concurrent modifications.
* Add one address, snapshot, driver syncs it, reconcile propagates
* sync_cnt delta back to real list.
*/
static void dev_addr_test_snapshot_sync(struct kunit *test)
{
struct netdev_hw_addr_list snap, ref, cache;
struct net_device *netdev = test->priv;
struct dev_addr_test_priv *datp;
struct netdev_hw_addr *ha;
u8 addr[ETH_ALEN];
datp = netdev_priv(netdev);
rtnl_lock();
memset(addr, ADDR_A, sizeof(addr));
KUNIT_EXPECT_EQ(test, 0, dev_uc_add(netdev, addr));
/* Snapshot: ADDR_A has sync_cnt=0, refcount=1 (new) */
netif_addr_lock_bh(netdev);
__hw_addr_init(&snap);
__hw_addr_init(&ref);
__hw_addr_init(&cache);
KUNIT_EXPECT_EQ(test, 0,
__hw_addr_list_snapshot(&snap, &netdev->uc, ETH_ALEN,
&cache));
KUNIT_EXPECT_EQ(test, 0,
__hw_addr_list_snapshot(&ref, &netdev->uc, ETH_ALEN,
&cache));
netif_addr_unlock_bh(netdev);
/* Driver syncs ADDR_A to hardware */
dev_addr_test_reset(netdev);
__hw_addr_sync_dev(&snap, netdev, dev_addr_test_sync,
dev_addr_test_unsync);
KUNIT_EXPECT_EQ(test, 1 << ADDR_A, datp->addr_synced);
KUNIT_EXPECT_EQ(test, 0, datp->addr_unsynced);
/* Reconcile: delta=+1 applied to real entry */
netif_addr_lock_bh(netdev);
__hw_addr_list_reconcile(&netdev->uc, &snap, &ref, ETH_ALEN,
&cache);
netif_addr_unlock_bh(netdev);
/* Real entry should now reflect the sync: sync_cnt=1, refcount=2 */
KUNIT_EXPECT_EQ(test, 1, netdev->uc.count);
ha = list_first_entry(&netdev->uc.list, struct netdev_hw_addr, list);
KUNIT_EXPECT_MEMEQ(test, ha->addr, addr, ETH_ALEN);
KUNIT_EXPECT_EQ(test, 1, ha->sync_cnt);
KUNIT_EXPECT_EQ(test, 2, ha->refcount);
/* Second work run: already synced, nothing to do */
dev_addr_test_reset(netdev);
__hw_addr_sync_dev(&netdev->uc, netdev, dev_addr_test_sync,
dev_addr_test_unsync);
KUNIT_EXPECT_EQ(test, 0, datp->addr_synced);
KUNIT_EXPECT_EQ(test, 0, datp->addr_unsynced);
KUNIT_EXPECT_EQ(test, 1, netdev->uc.count);
__hw_addr_flush(&cache);
rtnl_unlock();
}
/* Snapshot test: ADDR_A synced to hardware, then concurrently removed
* from the real list before reconcile runs. Reconcile re-inserts ADDR_A as
* a stale entry so the next work run unsyncs it from hardware.
*/
static void dev_addr_test_snapshot_remove_during_sync(struct kunit *test)
{
struct netdev_hw_addr_list snap, ref, cache;
struct net_device *netdev = test->priv;
struct dev_addr_test_priv *datp;
struct netdev_hw_addr *ha;
u8 addr[ETH_ALEN];
datp = netdev_priv(netdev);
rtnl_lock();
memset(addr, ADDR_A, sizeof(addr));
KUNIT_EXPECT_EQ(test, 0, dev_uc_add(netdev, addr));
/* Snapshot: ADDR_A is new (sync_cnt=0, refcount=1) */
netif_addr_lock_bh(netdev);
__hw_addr_init(&snap);
__hw_addr_init(&ref);
__hw_addr_init(&cache);
KUNIT_EXPECT_EQ(test, 0,
__hw_addr_list_snapshot(&snap, &netdev->uc, ETH_ALEN,
&cache));
KUNIT_EXPECT_EQ(test, 0,
__hw_addr_list_snapshot(&ref, &netdev->uc, ETH_ALEN,
&cache));
netif_addr_unlock_bh(netdev);
/* Driver syncs ADDR_A to hardware */
dev_addr_test_reset(netdev);
__hw_addr_sync_dev(&snap, netdev, dev_addr_test_sync,
dev_addr_test_unsync);
KUNIT_EXPECT_EQ(test, 1 << ADDR_A, datp->addr_synced);
KUNIT_EXPECT_EQ(test, 0, datp->addr_unsynced);
/* Concurrent removal: user deletes ADDR_A while driver was working */
memset(addr, ADDR_A, sizeof(addr));
KUNIT_EXPECT_EQ(test, 0, dev_uc_del(netdev, addr));
KUNIT_EXPECT_EQ(test, 0, netdev->uc.count);
/* Reconcile: ADDR_A gone from real list but driver synced it,
* so it gets re-inserted as stale (sync_cnt=1, refcount=1).
*/
netif_addr_lock_bh(netdev);
__hw_addr_list_reconcile(&netdev->uc, &snap, &ref, ETH_ALEN,
&cache);
netif_addr_unlock_bh(netdev);
KUNIT_EXPECT_EQ(test, 1, netdev->uc.count);
ha = list_first_entry(&netdev->uc.list, struct netdev_hw_addr, list);
KUNIT_EXPECT_MEMEQ(test, ha->addr, addr, ETH_ALEN);
KUNIT_EXPECT_EQ(test, 1, ha->sync_cnt);
KUNIT_EXPECT_EQ(test, 1, ha->refcount);
/* Second work run: stale entry gets unsynced from HW and removed */
dev_addr_test_reset(netdev);
__hw_addr_sync_dev(&netdev->uc, netdev, dev_addr_test_sync,
dev_addr_test_unsync);
KUNIT_EXPECT_EQ(test, 0, datp->addr_synced);
KUNIT_EXPECT_EQ(test, 1 << ADDR_A, datp->addr_unsynced);
KUNIT_EXPECT_EQ(test, 0, netdev->uc.count);
__hw_addr_flush(&cache);
rtnl_unlock();
}
/* Snapshot test: ADDR_A was stale (unsynced from hardware by driver),
* but concurrently re-added by the user. The re-add bumps refcount of
* the existing stale entry. Reconcile applies delta=-1, leaving ADDR_A
* as a fresh entry (sync_cnt=0, refcount=1) for the next work run.
*/
static void dev_addr_test_snapshot_readd_during_unsync(struct kunit *test)
{
struct netdev_hw_addr_list snap, ref, cache;
struct net_device *netdev = test->priv;
struct dev_addr_test_priv *datp;
struct netdev_hw_addr *ha;
u8 addr[ETH_ALEN];
datp = netdev_priv(netdev);
rtnl_lock();
memset(addr, ADDR_A, sizeof(addr));
KUNIT_EXPECT_EQ(test, 0, dev_uc_add(netdev, addr));
/* Sync ADDR_A to hardware: sync_cnt=1, refcount=2 */
dev_addr_test_reset(netdev);
__hw_addr_sync_dev(&netdev->uc, netdev, dev_addr_test_sync,
dev_addr_test_unsync);
KUNIT_EXPECT_EQ(test, 1 << ADDR_A, datp->addr_synced);
KUNIT_EXPECT_EQ(test, 0, datp->addr_unsynced);
/* User removes ADDR_A: refcount=1, sync_cnt=1 -> stale */
KUNIT_EXPECT_EQ(test, 0, dev_uc_del(netdev, addr));
/* Snapshot: ADDR_A is stale (sync_cnt=1, refcount=1) */
netif_addr_lock_bh(netdev);
__hw_addr_init(&snap);
__hw_addr_init(&ref);
__hw_addr_init(&cache);
KUNIT_EXPECT_EQ(test, 0,
__hw_addr_list_snapshot(&snap, &netdev->uc, ETH_ALEN,
&cache));
KUNIT_EXPECT_EQ(test, 0,
__hw_addr_list_snapshot(&ref, &netdev->uc, ETH_ALEN,
&cache));
netif_addr_unlock_bh(netdev);
/* Driver unsyncs stale ADDR_A from hardware */
dev_addr_test_reset(netdev);
__hw_addr_sync_dev(&snap, netdev, dev_addr_test_sync,
dev_addr_test_unsync);
KUNIT_EXPECT_EQ(test, 0, datp->addr_synced);
KUNIT_EXPECT_EQ(test, 1 << ADDR_A, datp->addr_unsynced);
/* Concurrent: user re-adds ADDR_A. dev_uc_add finds the existing
* stale entry and bumps refcount from 1 -> 2. sync_cnt stays 1.
*/
KUNIT_EXPECT_EQ(test, 0, dev_uc_add(netdev, addr));
KUNIT_EXPECT_EQ(test, 1, netdev->uc.count);
/* Reconcile: ref sync_cnt=1 matches real sync_cnt=1, delta=-1
* applied. Result: sync_cnt=0, refcount=1 (fresh).
*/
netif_addr_lock_bh(netdev);
__hw_addr_list_reconcile(&netdev->uc, &snap, &ref, ETH_ALEN,
&cache);
netif_addr_unlock_bh(netdev);
/* Entry survives as fresh: needs re-sync to HW */
KUNIT_EXPECT_EQ(test, 1, netdev->uc.count);
ha = list_first_entry(&netdev->uc.list, struct netdev_hw_addr, list);
KUNIT_EXPECT_MEMEQ(test, ha->addr, addr, ETH_ALEN);
KUNIT_EXPECT_EQ(test, 0, ha->sync_cnt);
KUNIT_EXPECT_EQ(test, 1, ha->refcount);
/* Second work run: fresh entry gets synced to HW */
dev_addr_test_reset(netdev);
__hw_addr_sync_dev(&netdev->uc, netdev, dev_addr_test_sync,
dev_addr_test_unsync);
KUNIT_EXPECT_EQ(test, 1 << ADDR_A, datp->addr_synced);
KUNIT_EXPECT_EQ(test, 0, datp->addr_unsynced);
__hw_addr_flush(&cache);
rtnl_unlock();
}
/* Snapshot test: ADDR_A is new (synced by driver), and independent ADDR_B
* is concurrently removed from the real list. A's sync delta propagates
* normally; B's absence doesn't interfere.
*/
static void dev_addr_test_snapshot_add_and_remove(struct kunit *test)
{
struct netdev_hw_addr_list snap, ref, cache;
struct net_device *netdev = test->priv;
struct dev_addr_test_priv *datp;
struct netdev_hw_addr *ha;
u8 addr[ETH_ALEN];
datp = netdev_priv(netdev);
rtnl_lock();
/* Add ADDR_A and ADDR_B (will be synced then removed) */
memset(addr, ADDR_A, sizeof(addr));
KUNIT_EXPECT_EQ(test, 0, dev_uc_add(netdev, addr));
memset(addr, ADDR_B, sizeof(addr));
KUNIT_EXPECT_EQ(test, 0, dev_uc_add(netdev, addr));
/* Sync both to hardware: sync_cnt=1, refcount=2 */
__hw_addr_sync_dev(&netdev->uc, netdev, dev_addr_test_sync,
dev_addr_test_unsync);
/* Add ADDR_C (new, will be synced by snapshot) */
memset(addr, ADDR_C, sizeof(addr));
KUNIT_EXPECT_EQ(test, 0, dev_uc_add(netdev, addr));
/* Snapshot: A,B synced (sync_cnt=1,refcount=2); C new (0,1) */
netif_addr_lock_bh(netdev);
__hw_addr_init(&snap);
__hw_addr_init(&ref);
__hw_addr_init(&cache);
KUNIT_EXPECT_EQ(test, 0,
__hw_addr_list_snapshot(&snap, &netdev->uc, ETH_ALEN,
&cache));
KUNIT_EXPECT_EQ(test, 0,
__hw_addr_list_snapshot(&ref, &netdev->uc, ETH_ALEN,
&cache));
netif_addr_unlock_bh(netdev);
/* Driver syncs snapshot: ADDR_C is new -> synced; A,B already synced */
dev_addr_test_reset(netdev);
__hw_addr_sync_dev(&snap, netdev, dev_addr_test_sync,
dev_addr_test_unsync);
KUNIT_EXPECT_EQ(test, 1 << ADDR_C, datp->addr_synced);
KUNIT_EXPECT_EQ(test, 0, datp->addr_unsynced);
/* Concurrent: user removes addr B while driver was working */
memset(addr, ADDR_B, sizeof(addr));
KUNIT_EXPECT_EQ(test, 0, dev_uc_del(netdev, addr));
/* Reconcile: ADDR_C's delta=+1 applied to real list.
* ADDR_B's delta=0 (unchanged in snapshot),
* so nothing to apply to ADDR_B.
*/
netif_addr_lock_bh(netdev);
__hw_addr_list_reconcile(&netdev->uc, &snap, &ref, ETH_ALEN,
&cache);
netif_addr_unlock_bh(netdev);
/* ADDR_A: unchanged (sync_cnt=1, refcount=2)
* ADDR_B: refcount went from 2->1 via dev_uc_del (still present, stale)
* ADDR_C: sync propagated (sync_cnt=1, refcount=2)
*/
KUNIT_EXPECT_EQ(test, 3, netdev->uc.count);
netdev_hw_addr_list_for_each(ha, &netdev->uc) {
u8 id = ha->addr[0];
if (!memchr_inv(ha->addr, id, ETH_ALEN)) {
if (id == ADDR_A) {
KUNIT_EXPECT_EQ(test, 1, ha->sync_cnt);
KUNIT_EXPECT_EQ(test, 2, ha->refcount);
} else if (id == ADDR_B) {
/* B: still present but now stale */
KUNIT_EXPECT_EQ(test, 1, ha->sync_cnt);
KUNIT_EXPECT_EQ(test, 1, ha->refcount);
} else if (id == ADDR_C) {
KUNIT_EXPECT_EQ(test, 1, ha->sync_cnt);
KUNIT_EXPECT_EQ(test, 2, ha->refcount);
}
}
}
/* Second work run: ADDR_B is stale, gets unsynced and removed */
dev_addr_test_reset(netdev);
__hw_addr_sync_dev(&netdev->uc, netdev, dev_addr_test_sync,
dev_addr_test_unsync);
KUNIT_EXPECT_EQ(test, 0, datp->addr_synced);
KUNIT_EXPECT_EQ(test, 1 << ADDR_B, datp->addr_unsynced);
KUNIT_EXPECT_EQ(test, 2, netdev->uc.count);
__hw_addr_flush(&cache);
rtnl_unlock();
}
static void dev_addr_test_snapshot_benchmark(struct kunit *test)
{
struct net_device *netdev = test->priv;
struct netdev_hw_addr_list snap, cache;
u8 addr[ETH_ALEN];
s64 duration = 0;
ktime_t start;
int i, iter;
rtnl_lock();
for (i = 0; i < 1024; i++) {
memset(addr, 0, sizeof(addr));
addr[0] = (i >> 8) & 0xff;
addr[1] = i & 0xff;
KUNIT_EXPECT_EQ(test, 0, dev_uc_add(netdev, addr));
}
__hw_addr_init(&cache);
for (iter = 0; iter < 1000; iter++) {
netif_addr_lock_bh(netdev);
__hw_addr_init(&snap);
start = ktime_get();
KUNIT_EXPECT_EQ(test, 0,
__hw_addr_list_snapshot(&snap, &netdev->uc,
ETH_ALEN, &cache));
duration += ktime_to_ns(ktime_sub(ktime_get(), start));
netif_addr_unlock_bh(netdev);
__hw_addr_flush(&snap);
}
__hw_addr_flush(&cache);
kunit_info(test,
"1024 addrs x 1000 snapshots: %lld ns total, %lld ns/iter",
duration, div_s64(duration, 1000));
rtnl_unlock();
}
static struct kunit_case dev_addr_test_cases[] = {
KUNIT_CASE(dev_addr_test_basic),
KUNIT_CASE(dev_addr_test_sync_one),
@ -232,6 +609,11 @@ static struct kunit_case dev_addr_test_cases[] = {
KUNIT_CASE(dev_addr_test_del_main),
KUNIT_CASE(dev_addr_test_add_set),
KUNIT_CASE(dev_addr_test_add_excl),
KUNIT_CASE(dev_addr_test_snapshot_sync),
KUNIT_CASE(dev_addr_test_snapshot_remove_during_sync),
KUNIT_CASE(dev_addr_test_snapshot_readd_during_unsync),
KUNIT_CASE(dev_addr_test_snapshot_add_and_remove),
KUNIT_CASE_SLOW(dev_addr_test_snapshot_benchmark),
{}
};
@ -243,5 +625,6 @@ static struct kunit_suite dev_addr_test_suite = {
};
kunit_test_suite(dev_addr_test_suite);
MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
MODULE_DESCRIPTION("KUnit tests for struct netdev_hw_addr_list");
MODULE_LICENSE("GPL");

View File

@ -66,6 +66,7 @@ int dev_change_flags(struct net_device *dev, unsigned int flags,
netdev_lock_ops(dev);
ret = netif_change_flags(dev, flags, extack);
netif_rx_mode_sync(dev);
netdev_unlock_ops(dev);
return ret;
@ -285,6 +286,7 @@ int dev_set_promiscuity(struct net_device *dev, int inc)
netdev_lock_ops(dev);
ret = netif_set_promiscuity(dev, inc);
netif_rx_mode_sync(dev);
netdev_unlock_ops(dev);
return ret;
@ -311,6 +313,7 @@ int dev_set_allmulti(struct net_device *dev, int inc)
netdev_lock_ops(dev);
ret = netif_set_allmulti(dev, inc, true);
netif_rx_mode_sync(dev);
netdev_unlock_ops(dev);
return ret;

View File

@ -586,24 +586,26 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data,
return err;
case SIOCADDMULTI:
if (!ops->ndo_set_rx_mode ||
if ((!ops->ndo_set_rx_mode && !ops->ndo_set_rx_mode_async) ||
ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
return -EINVAL;
if (!netif_device_present(dev))
return -ENODEV;
netdev_lock_ops(dev);
err = dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data);
netif_rx_mode_sync(dev);
netdev_unlock_ops(dev);
return err;
case SIOCDELMULTI:
if (!ops->ndo_set_rx_mode ||
if ((!ops->ndo_set_rx_mode && !ops->ndo_set_rx_mode_async) ||
ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
return -EINVAL;
if (!netif_device_present(dev))
return -ENODEV;
netdev_lock_ops(dev);
err = dev_mc_del_global(dev, ifr->ifr_hwaddr.sa_data);
netif_rx_mode_sync(dev);
netdev_unlock_ops(dev);
return err;

View File

@ -5396,7 +5396,7 @@ static int bpf_sol_tcp_setsockopt(struct sock *sk, int optname,
if (val <= 0)
return -EINVAL;
tp->snd_cwnd_clamp = val;
tp->snd_ssthresh = val;
WRITE_ONCE(tp->snd_ssthresh, val);
break;
case TCP_BPF_DELACK_MAX:
timeout = usecs_to_jiffies(val);

View File

@ -1374,16 +1374,13 @@ bool __skb_flow_dissect(const struct net *net,
break;
}
/* least significant bit of the most significant octet
* indicates if protocol field was compressed
/* PFC (compressed 1-byte protocol) frames are not processed.
* A compressed protocol field has the least significant bit of
* the most significant octet set, which will fail the following
* ppp_proto_is_valid(), returning FLOW_DISSECT_RET_OUT_BAD.
*/
ppp_proto = ntohs(hdr->proto);
if (ppp_proto & 0x0100) {
ppp_proto = ppp_proto >> 8;
nhoff += PPPOE_SES_HLEN - 1;
} else {
nhoff += PPPOE_SES_HLEN;
}
nhoff += PPPOE_SES_HLEN;
if (ppp_proto == PPP_IP) {
proto = htons(ETH_P_IP);

View File

@ -3431,6 +3431,7 @@ static int do_setlink(const struct sk_buff *skb, struct net_device *dev,
dev->name);
}
netif_rx_mode_sync(dev);
netdev_unlock_ops(dev);
return err;

View File

@ -27,9 +27,7 @@ static int dsa_conduit_get_regs_len(struct net_device *dev)
int len;
if (ops && ops->get_regs_len) {
netdev_lock_ops(dev);
len = ops->get_regs_len(dev);
netdev_unlock_ops(dev);
if (len < 0)
return len;
ret += len;
@ -60,15 +58,11 @@ static void dsa_conduit_get_regs(struct net_device *dev,
int len;
if (ops && ops->get_regs_len && ops->get_regs) {
netdev_lock_ops(dev);
len = ops->get_regs_len(dev);
if (len < 0) {
netdev_unlock_ops(dev);
if (len < 0)
return;
}
regs->len = len;
ops->get_regs(dev, regs, data);
netdev_unlock_ops(dev);
data += regs->len;
}
@ -115,10 +109,8 @@ static void dsa_conduit_get_ethtool_stats(struct net_device *dev,
int count, mcount = 0;
if (ops && ops->get_sset_count && ops->get_ethtool_stats) {
netdev_lock_ops(dev);
mcount = ops->get_sset_count(dev, ETH_SS_STATS);
ops->get_ethtool_stats(dev, stats, data);
netdev_unlock_ops(dev);
}
list_for_each_entry(dp, &dst->ports, list) {
@ -149,10 +141,8 @@ static void dsa_conduit_get_ethtool_phy_stats(struct net_device *dev,
if (count >= 0)
phy_ethtool_get_stats(dev->phydev, stats, data);
} else if (ops && ops->get_sset_count && ops->get_ethtool_phy_stats) {
netdev_lock_ops(dev);
count = ops->get_sset_count(dev, ETH_SS_PHY_STATS);
ops->get_ethtool_phy_stats(dev, stats, data);
netdev_unlock_ops(dev);
}
if (count < 0)
@ -176,13 +166,11 @@ static int dsa_conduit_get_sset_count(struct net_device *dev, int sset)
struct dsa_switch_tree *dst = cpu_dp->dst;
int count = 0;
netdev_lock_ops(dev);
if (sset == ETH_SS_PHY_STATS && dev->phydev &&
(!ops || !ops->get_ethtool_phy_stats))
count = phy_ethtool_get_sset_count(dev->phydev);
else if (ops && ops->get_sset_count)
count = ops->get_sset_count(dev, sset);
netdev_unlock_ops(dev);
if (count < 0)
count = 0;
@ -239,7 +227,6 @@ static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset,
struct dsa_switch_tree *dst = cpu_dp->dst;
int count, mcount = 0;
netdev_lock_ops(dev);
if (stringset == ETH_SS_PHY_STATS && dev->phydev &&
!ops->get_ethtool_phy_stats) {
mcount = phy_ethtool_get_sset_count(dev->phydev);
@ -253,7 +240,6 @@ static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset,
mcount = 0;
ops->get_strings(dev, stringset, data);
}
netdev_unlock_ops(dev);
list_for_each_entry(dp, &dst->ports, list) {
if (!dsa_port_is_dsa(dp) && !dsa_port_is_cpu(dp))

View File

@ -64,6 +64,7 @@
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/fcntl.h>
#include <linux/nospec.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/inet.h>
@ -371,7 +372,9 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,
to, len);
skb->csum = csum_block_add(skb->csum, csum, odd);
if (icmp_pointers[icmp_param->data.icmph.type].error)
if (icmp_param->data.icmph.type <= NR_ICMP_TYPES &&
icmp_pointers[array_index_nospec(icmp_param->data.icmph.type,
NR_ICMP_TYPES + 1)].error)
nf_ct_attach(skb, icmp_param->skb);
return 0;
}

View File

@ -1479,16 +1479,19 @@ void inet_csk_listen_stop(struct sock *sk)
if (nreq) {
refcount_set(&nreq->rsk_refcnt, 1);
rcu_read_lock();
if (inet_csk_reqsk_queue_add(nsk, nreq, child)) {
__NET_INC_STATS(sock_net(nsk),
LINUX_MIB_TCPMIGRATEREQSUCCESS);
reqsk_migrate_reset(req);
READ_ONCE(nsk->sk_data_ready)(nsk);
} else {
__NET_INC_STATS(sock_net(nsk),
LINUX_MIB_TCPMIGRATEREQFAILURE);
reqsk_migrate_reset(nreq);
__reqsk_free(nreq);
}
rcu_read_unlock();
/* inet_csk_reqsk_queue_add() has already
* called inet_child_forget() on failure case.

View File

@ -79,7 +79,7 @@ static int ipt_nat_register_lookups(struct net *net)
while (i)
nf_nat_ipv4_unregister_fn(net, &ops[--i]);
kfree(ops);
kfree_rcu(ops, rcu);
return ret;
}
}
@ -100,7 +100,7 @@ static void ipt_nat_unregister_lookups(struct net *net)
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++)
nf_nat_ipv4_unregister_fn(net, &ops[i]);
kfree(ops);
kfree_rcu(ops, rcu);
}
static int iptable_nat_table_init(struct net *net)

View File

@ -2469,10 +2469,10 @@ static int replace_nexthop_single(struct net *net, struct nexthop *old,
goto err_notify;
}
/* When replacing an IPv4 nexthop with an IPv6 nexthop, potentially
/* When replacing a nexthop with one of a different family, potentially
* update IPv4 indication in all the groups using the nexthop.
*/
if (oldi->family == AF_INET && newi->family == AF_INET6) {
if (oldi->family != newi->family) {
list_for_each_entry(nhge, &old->grp_list, nh_list) {
struct nexthop *nhp = nhge->nh_parent;
struct nh_group *nhg;

View File

@ -3424,7 +3424,7 @@ int tcp_disconnect(struct sock *sk, int flags)
icsk->icsk_rto = TCP_TIMEOUT_INIT;
WRITE_ONCE(icsk->icsk_rto_min, TCP_RTO_MIN);
WRITE_ONCE(icsk->icsk_delack_max, TCP_DELACK_MAX);
tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
WRITE_ONCE(tp->snd_ssthresh, TCP_INFINITE_SSTHRESH);
tcp_snd_cwnd_set(tp, TCP_INIT_CWND);
tp->snd_cwnd_cnt = 0;
tp->is_cwnd_limited = 0;
@ -3622,7 +3622,8 @@ static void tcp_enable_tx_delay(struct sock *sk, int val)
if (delta && sk->sk_state == TCP_ESTABLISHED) {
s64 srtt = (s64)tp->srtt_us + delta;
tp->srtt_us = clamp_t(s64, srtt, 1, ~0U);
WRITE_ONCE(tp->srtt_us,
clamp_t(s64, srtt, 1, ~0U));
/* Note: does not deal with non zero icsk_backoff */
tcp_set_rto(sk);
@ -4190,12 +4191,18 @@ static void tcp_get_info_chrono_stats(const struct tcp_sock *tp,
struct tcp_info *info)
{
u64 stats[__TCP_CHRONO_MAX], total = 0;
enum tcp_chrono i;
enum tcp_chrono i, cur;
/* Following READ_ONCE()s pair with WRITE_ONCE()s in tcp_chrono_set().
* This is because socket lock might not be owned by us at this point.
* This is best effort, tcp_get_timestamping_opt_stats() can
* see wrong values. A real fix would be too costly for TCP fast path.
*/
cur = READ_ONCE(tp->chrono_type);
for (i = TCP_CHRONO_BUSY; i < __TCP_CHRONO_MAX; ++i) {
stats[i] = tp->chrono_stat[i - 1];
if (i == tp->chrono_type)
stats[i] += tcp_jiffies32 - tp->chrono_start;
stats[i] = READ_ONCE(tp->chrono_stat[i - 1]);
if (i == cur)
stats[i] += tcp_jiffies32 - READ_ONCE(tp->chrono_start);
stats[i] *= USEC_PER_SEC / HZ;
total += stats[i];
}
@ -4427,9 +4434,9 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,
nla_put_u64_64bit(stats, TCP_NLA_SNDBUF_LIMITED,
info.tcpi_sndbuf_limited, TCP_NLA_PAD);
nla_put_u64_64bit(stats, TCP_NLA_DATA_SEGS_OUT,
tp->data_segs_out, TCP_NLA_PAD);
READ_ONCE(tp->data_segs_out), TCP_NLA_PAD);
nla_put_u64_64bit(stats, TCP_NLA_TOTAL_RETRANS,
tp->total_retrans, TCP_NLA_PAD);
READ_ONCE(tp->total_retrans), TCP_NLA_PAD);
rate = READ_ONCE(sk->sk_pacing_rate);
rate64 = (rate != ~0UL) ? rate : ~0ULL;
@ -4438,37 +4445,42 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,
rate64 = tcp_compute_delivery_rate(tp);
nla_put_u64_64bit(stats, TCP_NLA_DELIVERY_RATE, rate64, TCP_NLA_PAD);
nla_put_u32(stats, TCP_NLA_SND_CWND, tcp_snd_cwnd(tp));
nla_put_u32(stats, TCP_NLA_REORDERING, tp->reordering);
nla_put_u32(stats, TCP_NLA_MIN_RTT, tcp_min_rtt(tp));
nla_put_u32(stats, TCP_NLA_SND_CWND, READ_ONCE(tp->snd_cwnd));
nla_put_u32(stats, TCP_NLA_REORDERING, READ_ONCE(tp->reordering));
nla_put_u32(stats, TCP_NLA_MIN_RTT, data_race(tcp_min_rtt(tp)));
nla_put_u8(stats, TCP_NLA_RECUR_RETRANS,
READ_ONCE(inet_csk(sk)->icsk_retransmits));
nla_put_u8(stats, TCP_NLA_DELIVERY_RATE_APP_LMT, !!tp->rate_app_limited);
nla_put_u32(stats, TCP_NLA_SND_SSTHRESH, tp->snd_ssthresh);
nla_put_u32(stats, TCP_NLA_DELIVERED, tp->delivered);
nla_put_u32(stats, TCP_NLA_DELIVERED_CE, tp->delivered_ce);
nla_put_u8(stats, TCP_NLA_DELIVERY_RATE_APP_LMT, data_race(!!tp->rate_app_limited));
nla_put_u32(stats, TCP_NLA_SND_SSTHRESH, READ_ONCE(tp->snd_ssthresh));
nla_put_u32(stats, TCP_NLA_DELIVERED, READ_ONCE(tp->delivered));
nla_put_u32(stats, TCP_NLA_DELIVERED_CE, READ_ONCE(tp->delivered_ce));
nla_put_u32(stats, TCP_NLA_SNDQ_SIZE, tp->write_seq - tp->snd_una);
nla_put_u32(stats, TCP_NLA_SNDQ_SIZE,
max_t(int, 0,
READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_una)));
nla_put_u8(stats, TCP_NLA_CA_STATE, inet_csk(sk)->icsk_ca_state);
nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, tp->bytes_sent,
nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, READ_ONCE(tp->bytes_sent),
TCP_NLA_PAD);
nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, tp->bytes_retrans,
TCP_NLA_PAD);
nla_put_u32(stats, TCP_NLA_DSACK_DUPS, tp->dsack_dups);
nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen);
nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3);
nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash);
nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS,
READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD);
nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups));
nla_put_u32(stats, TCP_NLA_REORD_SEEN, READ_ONCE(tp->reord_seen));
nla_put_u32(stats, TCP_NLA_SRTT, READ_ONCE(tp->srtt_us) >> 3);
nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH,
READ_ONCE(tp->timeout_rehash));
nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT,
max_t(int, 0, tp->write_seq - tp->snd_nxt));
max_t(int, 0,
READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_nxt)));
nla_put_u64_64bit(stats, TCP_NLA_EDT, orig_skb->skb_mstamp_ns,
TCP_NLA_PAD);
if (ack_skb)
nla_put_u8(stats, TCP_NLA_TTL,
tcp_skb_ttl_or_hop_limit(ack_skb));
nla_put_u32(stats, TCP_NLA_REHASH, tp->plb_rehash + tp->timeout_rehash);
nla_put_u32(stats, TCP_NLA_REHASH,
READ_ONCE(tp->plb_rehash) + READ_ONCE(tp->timeout_rehash));
return stats;
}

View File

@ -897,8 +897,8 @@ static void bbr_check_drain(struct sock *sk, const struct rate_sample *rs)
if (bbr->mode == BBR_STARTUP && bbr_full_bw_reached(sk)) {
bbr->mode = BBR_DRAIN; /* drain queue we created */
tcp_sk(sk)->snd_ssthresh =
bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT);
WRITE_ONCE(tcp_sk(sk)->snd_ssthresh,
bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT));
} /* fall through to check if in-flight is already small: */
if (bbr->mode == BBR_DRAIN &&
bbr_packets_in_net_at_edt(sk, tcp_packets_in_flight(tcp_sk(sk))) <=
@ -1043,7 +1043,7 @@ __bpf_kfunc static void bbr_init(struct sock *sk)
struct bbr *bbr = inet_csk_ca(sk);
bbr->prior_cwnd = 0;
tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
WRITE_ONCE(tp->snd_ssthresh, TCP_INFINITE_SSTHRESH);
bbr->rtt_cnt = 0;
bbr->next_rtt_delivered = tp->delivered;
bbr->prev_ca_state = TCP_CA_Open;

View File

@ -74,7 +74,7 @@ static void bictcp_init(struct sock *sk)
bictcp_reset(ca);
if (initial_ssthresh)
tcp_sk(sk)->snd_ssthresh = initial_ssthresh;
WRITE_ONCE(tcp_sk(sk)->snd_ssthresh, initial_ssthresh);
}
/*

View File

@ -162,7 +162,7 @@ static void tcp_cdg_hystart_update(struct sock *sk)
NET_ADD_STATS(sock_net(sk),
LINUX_MIB_TCPHYSTARTTRAINCWND,
tcp_snd_cwnd(tp));
tp->snd_ssthresh = tcp_snd_cwnd(tp);
WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp));
return;
}
}
@ -181,7 +181,7 @@ static void tcp_cdg_hystart_update(struct sock *sk)
NET_ADD_STATS(sock_net(sk),
LINUX_MIB_TCPHYSTARTDELAYCWND,
tcp_snd_cwnd(tp));
tp->snd_ssthresh = tcp_snd_cwnd(tp);
WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp));
}
}
}

View File

@ -136,7 +136,7 @@ __bpf_kfunc static void cubictcp_init(struct sock *sk)
bictcp_hystart_reset(sk);
if (!hystart && initial_ssthresh)
tcp_sk(sk)->snd_ssthresh = initial_ssthresh;
WRITE_ONCE(tcp_sk(sk)->snd_ssthresh, initial_ssthresh);
}
__bpf_kfunc static void cubictcp_cwnd_event_tx_start(struct sock *sk)
@ -420,7 +420,7 @@ static void hystart_update(struct sock *sk, u32 delay)
NET_ADD_STATS(sock_net(sk),
LINUX_MIB_TCPHYSTARTTRAINCWND,
tcp_snd_cwnd(tp));
tp->snd_ssthresh = tcp_snd_cwnd(tp);
WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp));
}
}
}
@ -440,7 +440,7 @@ static void hystart_update(struct sock *sk, u32 delay)
NET_ADD_STATS(sock_net(sk),
LINUX_MIB_TCPHYSTARTDELAYCWND,
tcp_snd_cwnd(tp));
tp->snd_ssthresh = tcp_snd_cwnd(tp);
WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp));
}
}
}

View File

@ -177,7 +177,7 @@ static void dctcp_react_to_loss(struct sock *sk)
struct tcp_sock *tp = tcp_sk(sk);
ca->loss_cwnd = tcp_snd_cwnd(tp);
tp->snd_ssthresh = max(tcp_snd_cwnd(tp) >> 1U, 2U);
WRITE_ONCE(tp->snd_ssthresh, max(tcp_snd_cwnd(tp) >> 1U, 2U));
}
__bpf_kfunc static void dctcp_state(struct sock *sk, u8 new_state)

View File

@ -476,14 +476,14 @@ static bool tcp_accecn_process_option(struct tcp_sock *tp,
static void tcp_count_delivered_ce(struct tcp_sock *tp, u32 ecn_count)
{
tp->delivered_ce += ecn_count;
WRITE_ONCE(tp->delivered_ce, tp->delivered_ce + ecn_count);
}
/* Updates the delivered and delivered_ce counts */
static void tcp_count_delivered(struct tcp_sock *tp, u32 delivered,
bool ece_ack)
{
tp->delivered += delivered;
WRITE_ONCE(tp->delivered, tp->delivered + delivered);
if (tcp_ecn_mode_rfc3168(tp) && ece_ack)
tcp_count_delivered_ce(tp, delivered);
}
@ -1132,7 +1132,7 @@ static void tcp_rtt_estimator(struct sock *sk, long mrtt_us)
tcp_bpf_rtt(sk, mrtt_us, srtt);
}
tp->srtt_us = max(1U, srtt);
WRITE_ONCE(tp->srtt_us, max(1U, srtt));
}
void tcp_update_pacing_rate(struct sock *sk)
@ -1246,7 +1246,7 @@ static u32 tcp_dsack_seen(struct tcp_sock *tp, u32 start_seq,
else if (tp->tlp_high_seq && tp->tlp_high_seq == end_seq)
state->flag |= FLAG_DSACK_TLP;
tp->dsack_dups += dup_segs;
WRITE_ONCE(tp->dsack_dups, tp->dsack_dups + dup_segs);
/* Skip the DSACK if dup segs weren't retransmitted by sender */
if (tp->dsack_dups > tp->total_retrans)
return 0;
@ -1293,12 +1293,13 @@ static void tcp_check_sack_reordering(struct sock *sk, const u32 low_seq,
tp->sacked_out,
tp->undo_marker ? tp->undo_retrans : 0);
#endif
tp->reordering = min_t(u32, (metric + mss - 1) / mss,
READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering));
WRITE_ONCE(tp->reordering,
min_t(u32, (metric + mss - 1) / mss,
READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering)));
}
/* This exciting event is worth to be remembered. 8) */
tp->reord_seen++;
WRITE_ONCE(tp->reord_seen, tp->reord_seen + 1);
NET_INC_STATS(sock_net(sk),
ts ? LINUX_MIB_TCPTSREORDER : LINUX_MIB_TCPSACKREORDER);
}
@ -2439,9 +2440,10 @@ static void tcp_check_reno_reordering(struct sock *sk, const int addend)
if (!tcp_limit_reno_sacked(tp))
return;
tp->reordering = min_t(u32, tp->packets_out + addend,
READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering));
tp->reord_seen++;
WRITE_ONCE(tp->reordering,
min_t(u32, tp->packets_out + addend,
READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering)));
WRITE_ONCE(tp->reord_seen, tp->reord_seen + 1);
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRENOREORDER);
}
@ -2565,7 +2567,7 @@ void tcp_enter_loss(struct sock *sk)
(icsk->icsk_ca_state == TCP_CA_Loss && !icsk->icsk_retransmits)) {
tp->prior_ssthresh = tcp_current_ssthresh(sk);
tp->prior_cwnd = tcp_snd_cwnd(tp);
tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
WRITE_ONCE(tp->snd_ssthresh, icsk->icsk_ca_ops->ssthresh(sk));
tcp_ca_event(sk, CA_EVENT_LOSS);
tcp_init_undo(tp);
}
@ -2579,8 +2581,8 @@ void tcp_enter_loss(struct sock *sk)
reordering = READ_ONCE(net->ipv4.sysctl_tcp_reordering);
if (icsk->icsk_ca_state <= TCP_CA_Disorder &&
tp->sacked_out >= reordering)
tp->reordering = min_t(unsigned int, tp->reordering,
reordering);
WRITE_ONCE(tp->reordering,
min_t(unsigned int, tp->reordering, reordering));
tcp_set_ca_state(sk, TCP_CA_Loss);
tp->high_seq = tp->snd_nxt;
@ -2858,7 +2860,7 @@ static void tcp_undo_cwnd_reduction(struct sock *sk, bool unmark_loss)
tcp_snd_cwnd_set(tp, icsk->icsk_ca_ops->undo_cwnd(sk));
if (tp->prior_ssthresh > tp->snd_ssthresh) {
tp->snd_ssthresh = tp->prior_ssthresh;
WRITE_ONCE(tp->snd_ssthresh, tp->prior_ssthresh);
tcp_ecn_withdraw_cwr(tp);
}
}
@ -2976,7 +2978,7 @@ static void tcp_init_cwnd_reduction(struct sock *sk)
tp->prior_cwnd = tcp_snd_cwnd(tp);
tp->prr_delivered = 0;
tp->prr_out = 0;
tp->snd_ssthresh = inet_csk(sk)->icsk_ca_ops->ssthresh(sk);
WRITE_ONCE(tp->snd_ssthresh, inet_csk(sk)->icsk_ca_ops->ssthresh(sk));
tcp_ecn_queue_cwr(tp);
}
@ -3118,7 +3120,7 @@ static void tcp_non_congestion_loss_retransmit(struct sock *sk)
if (icsk->icsk_ca_state != TCP_CA_Loss) {
tp->high_seq = tp->snd_nxt;
tp->snd_ssthresh = tcp_current_ssthresh(sk);
WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk));
tp->prior_ssthresh = 0;
tp->undo_marker = 0;
tcp_set_ca_state(sk, TCP_CA_Loss);
@ -3910,7 +3912,7 @@ static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack)
sock_owned_by_me((struct sock *)tp);
tp->bytes_acked += delta;
tcp_snd_sne_update(tp, ack);
tp->snd_una = ack;
WRITE_ONCE(tp->snd_una, ack);
}
static void tcp_rcv_sne_update(struct tcp_sock *tp, u32 seq)
@ -4284,11 +4286,15 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
goto old_ack;
}
/* If the ack includes data we haven't sent yet, discard
* this segment (RFC793 Section 3.9).
/* If the ack includes data we haven't sent yet, drop the
* segment. RFC 793 Section 3.9 and RFC 5961 Section 5.2
* require us to send an ACK back in that case.
*/
if (after(ack, tp->snd_nxt))
if (after(ack, tp->snd_nxt)) {
if (!(flag & FLAG_NO_CHALLENGE_ACK))
tcp_send_challenge_ack(sk, false);
return -SKB_DROP_REASON_TCP_ACK_UNSENT_DATA;
}
if (after(ack, prior_snd_una)) {
flag |= FLAG_SND_UNA_ADVANCED;
@ -6777,7 +6783,7 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFASTOPENACTIVE);
/* SYN-data is counted as two separate packets in tcp_ack() */
if (tp->delivered > 1)
--tp->delivered;
WRITE_ONCE(tp->delivered, tp->delivered - 1);
}
tcp_fastopen_add_skb(sk, synack);
@ -7210,7 +7216,7 @@ tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb)
SKB_DR_SET(reason, NOT_SPECIFIED);
switch (sk->sk_state) {
case TCP_SYN_RECV:
tp->delivered++; /* SYN-ACK delivery isn't tracked in tcp_ack */
WRITE_ONCE(tp->delivered, tp->delivered + 1); /* SYN-ACK delivery isn't tracked in tcp_ack */
if (!tp->srtt_us)
tcp_synack_rtt_meas(sk, req);
@ -7238,7 +7244,7 @@ tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb)
if (sk->sk_socket)
sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT);
tp->snd_una = TCP_SKB_CB(skb)->ack_seq;
WRITE_ONCE(tp->snd_una, TCP_SKB_CB(skb)->ack_seq);
tp->snd_wnd = ntohs(th->window) << tp->rx_opt.snd_wscale;
tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);

View File

@ -490,13 +490,13 @@ void tcp_init_metrics(struct sock *sk)
val = READ_ONCE(net->ipv4.sysctl_tcp_no_ssthresh_metrics_save) ?
0 : tcp_metric_get(tm, TCP_METRIC_SSTHRESH);
if (val) {
tp->snd_ssthresh = val;
WRITE_ONCE(tp->snd_ssthresh, val);
if (tp->snd_ssthresh > tp->snd_cwnd_clamp)
tp->snd_ssthresh = tp->snd_cwnd_clamp;
WRITE_ONCE(tp->snd_ssthresh, tp->snd_cwnd_clamp);
}
val = tcp_metric_get(tm, TCP_METRIC_REORDERING);
if (val && tp->reordering != val)
tp->reordering = val;
WRITE_ONCE(tp->reordering, val);
crtt = tcp_metric_get(tm, TCP_METRIC_RTT);
rcu_read_unlock();

View File

@ -396,8 +396,8 @@ static void tcpnv_acked(struct sock *sk, const struct ack_sample *sample)
/* We have enough data to determine we are congested */
ca->nv_allow_cwnd_growth = 0;
tp->snd_ssthresh =
(nv_ssthresh_factor * max_win) >> 3;
WRITE_ONCE(tp->snd_ssthresh,
(nv_ssthresh_factor * max_win) >> 3);
if (tcp_snd_cwnd(tp) - max_win > 2) {
/* gap > 2, we do exponential cwnd decrease */
int dec;

View File

@ -171,7 +171,7 @@ void tcp_cwnd_restart(struct sock *sk, s32 delta)
tcp_ca_event(sk, CA_EVENT_CWND_RESTART);
tp->snd_ssthresh = tcp_current_ssthresh(sk);
WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk));
restart_cwnd = min(restart_cwnd, cwnd);
while ((delta -= inet_csk(sk)->icsk_rto) > 0 && cwnd > restart_cwnd)
@ -1688,8 +1688,10 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb,
if (skb->len != tcp_header_size) {
tcp_event_data_sent(tp, sk);
tp->data_segs_out += tcp_skb_pcount(skb);
tp->bytes_sent += skb->len - tcp_header_size;
WRITE_ONCE(tp->data_segs_out,
tp->data_segs_out + tcp_skb_pcount(skb));
WRITE_ONCE(tp->bytes_sent,
tp->bytes_sent + skb->len - tcp_header_size);
}
if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq)
@ -2142,7 +2144,7 @@ static void tcp_cwnd_application_limited(struct sock *sk)
u32 init_win = tcp_init_cwnd(tp, __sk_dst_get(sk));
u32 win_used = max(tp->snd_cwnd_used, init_win);
if (win_used < tcp_snd_cwnd(tp)) {
tp->snd_ssthresh = tcp_current_ssthresh(sk);
WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk));
tcp_snd_cwnd_set(tp, (tcp_snd_cwnd(tp) + win_used) >> 1);
}
tp->snd_cwnd_used = 0;
@ -3642,8 +3644,8 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs)
TCP_ADD_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS, segs);
if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)
__NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS);
tp->total_retrans += segs;
tp->bytes_retrans += skb->len;
WRITE_ONCE(tp->total_retrans, tp->total_retrans + segs);
WRITE_ONCE(tp->bytes_retrans, tp->bytes_retrans + skb->len);
/* make sure skb->data is aligned on arches that require it
* and check if ack-trimming & collapsing extended the headroom
@ -4152,7 +4154,7 @@ static void tcp_connect_init(struct sock *sk)
tp->snd_wnd = 0;
tcp_init_wl(tp, 0);
tcp_write_queue_purge(sk);
tp->snd_una = tp->write_seq;
WRITE_ONCE(tp->snd_una, tp->write_seq);
tp->snd_sml = tp->write_seq;
tp->snd_up = tp->write_seq;
WRITE_ONCE(tp->snd_nxt, tp->write_seq);
@ -4646,7 +4648,8 @@ int tcp_rtx_synack(const struct sock *sk, struct request_sock *req)
* However in this case, we are dealing with a passive fastopen
* socket thus we can change total_retrans value.
*/
tcp_sk_rw(sk)->total_retrans++;
WRITE_ONCE(tcp_sk_rw(sk)->total_retrans,
tcp_sk_rw(sk)->total_retrans + 1);
}
trace_tcp_retransmit_synack(sk, req);
WRITE_ONCE(req->num_retrans, req->num_retrans + 1);

View File

@ -80,7 +80,7 @@ void tcp_plb_check_rehash(struct sock *sk, struct tcp_plb_state *plb)
sk_rethink_txhash(sk);
plb->consec_cong_rounds = 0;
tcp_sk(sk)->plb_rehash++;
WRITE_ONCE(tcp_sk(sk)->plb_rehash, tcp_sk(sk)->plb_rehash + 1);
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPPLBREHASH);
}
EXPORT_SYMBOL_GPL(tcp_plb_check_rehash);

View File

@ -297,7 +297,7 @@ static int tcp_write_timeout(struct sock *sk)
}
if (sk_rethink_txhash(sk)) {
tp->timeout_rehash++;
WRITE_ONCE(tp->timeout_rehash, tp->timeout_rehash + 1);
__NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPTIMEOUTREHASH);
}

View File

@ -245,7 +245,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)
*/
tcp_snd_cwnd_set(tp, min(tcp_snd_cwnd(tp),
(u32)target_cwnd + 1));
tp->snd_ssthresh = tcp_vegas_ssthresh(tp);
WRITE_ONCE(tp->snd_ssthresh,
tcp_vegas_ssthresh(tp));
} else if (tcp_in_slow_start(tp)) {
/* Slow start. */
@ -261,8 +262,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)
* we slow down.
*/
tcp_snd_cwnd_set(tp, tcp_snd_cwnd(tp) - 1);
tp->snd_ssthresh
= tcp_vegas_ssthresh(tp);
WRITE_ONCE(tp->snd_ssthresh,
tcp_vegas_ssthresh(tp));
} else if (diff < alpha) {
/* We don't have enough extra packets
* in the network, so speed up.
@ -280,7 +281,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)
else if (tcp_snd_cwnd(tp) > tp->snd_cwnd_clamp)
tcp_snd_cwnd_set(tp, tp->snd_cwnd_clamp);
tp->snd_ssthresh = tcp_current_ssthresh(sk);
WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk));
}
/* Wipe the slate clean for the next RTT. */

Some files were not shown because too many files have changed in this diff Show More