mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'net-6.13-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Pull networking fixes from Paolo Abeni:
"Including fixes from can and netfilter.
Current release - regressions:
- rtnetlink: try the outer netns attribute in rtnl_get_peer_net()
- rust: net::phy fix module autoloading
Current release - new code bugs:
- phy: avoid undefined behavior in *_led_polarity_set()
- eth: octeontx2-pf: fix netdev memory leak in rvu_rep_create()
Previous releases - regressions:
- smc: check sndbuf_space again after NOSPACE flag is set in smc_poll
- ipvs: fix clamp() of ip_vs_conn_tab on small memory systems
- dsa: restore dsa_software_vlan_untag() ability to operate on
VLAN-untagged traffic
- eth:
- tun: fix tun_napi_alloc_frags()
- ionic: no double destroy workqueue
- idpf: trigger SW interrupt when exiting wb_on_itr mode
- rswitch: rework ts tags management
- team: fix feature exposure when no ports are present
Previous releases - always broken:
- core: fix repeated netlink messages in queue dump
- mdiobus: fix an OF node reference leak
- smc: check iparea_offset and ipv6_prefixes_cnt when receiving
proposal msg
- can: fix missed interrupts with m_can_pci
- eth: oa_tc6: fix infinite loop error when tx credits becomes 0"
* tag 'net-6.13-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (45 commits)
net: mctp: handle skb cleanup on sock_queue failures
net: mdiobus: fix an OF node reference leak
octeontx2-pf: fix error handling of devlink port in rvu_rep_create()
octeontx2-pf: fix netdev memory leak in rvu_rep_create()
psample: adjust size if rate_as_probability is set
netdev-genl: avoid empty messages in queue dump
net: dsa: restore dsa_software_vlan_untag() ability to operate on VLAN-untagged traffic
selftests: openvswitch: fix tcpdump execution
net: usb: qmi_wwan: add Quectel RG255C
net: phy: avoid undefined behavior in *_led_polarity_set()
netfilter: ipset: Fix for recursive locking warning
ipvs: Fix clamp() of ip_vs_conn_tab on small memory systems
can: m_can: fix missed interrupts with m_can_pci
can: m_can: set init flag earlier in probe
rtnetlink: Try the outer netns attribute in rtnl_get_peer_net().
net: netdevsim: fix nsim_pp_hold_write()
idpf: trigger SW interrupt when exiting wb_on_itr mode
idpf: add support for SW triggered interrupts
qed: fix possible uninit pointer read in qed_mcp_nvm_info_populate()
net: ethernet: bgmac-platform: fix an OF node reference leak
...
This commit is contained in:
@@ -1220,20 +1220,32 @@ static void m_can_coalescing_update(struct m_can_classdev *cdev, u32 ir)
|
||||
static int m_can_interrupt_handler(struct m_can_classdev *cdev)
|
||||
{
|
||||
struct net_device *dev = cdev->net;
|
||||
u32 ir;
|
||||
u32 ir = 0, ir_read;
|
||||
int ret;
|
||||
|
||||
if (pm_runtime_suspended(cdev->dev))
|
||||
return IRQ_NONE;
|
||||
|
||||
ir = m_can_read(cdev, M_CAN_IR);
|
||||
/* The m_can controller signals its interrupt status as a level, but
|
||||
* depending in the integration the CPU may interpret the signal as
|
||||
* edge-triggered (for example with m_can_pci). For these
|
||||
* edge-triggered integrations, we must observe that IR is 0 at least
|
||||
* once to be sure that the next interrupt will generate an edge.
|
||||
*/
|
||||
while ((ir_read = m_can_read(cdev, M_CAN_IR)) != 0) {
|
||||
ir |= ir_read;
|
||||
|
||||
/* ACK all irqs */
|
||||
m_can_write(cdev, M_CAN_IR, ir);
|
||||
|
||||
if (!cdev->irq_edge_triggered)
|
||||
break;
|
||||
}
|
||||
|
||||
m_can_coalescing_update(cdev, ir);
|
||||
if (!ir)
|
||||
return IRQ_NONE;
|
||||
|
||||
/* ACK all irqs */
|
||||
m_can_write(cdev, M_CAN_IR, ir);
|
||||
|
||||
if (cdev->ops->clear_interrupts)
|
||||
cdev->ops->clear_interrupts(cdev);
|
||||
|
||||
@@ -1695,6 +1707,14 @@ static int m_can_dev_setup(struct m_can_classdev *cdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Write the INIT bit, in case no hardware reset has happened before
|
||||
* the probe (for example, it was observed that the Intel Elkhart Lake
|
||||
* SoCs do not properly reset the CAN controllers on reboot)
|
||||
*/
|
||||
err = m_can_cccr_update_bits(cdev, CCCR_INIT, CCCR_INIT);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!cdev->is_peripheral)
|
||||
netif_napi_add(dev, &cdev->napi, m_can_poll);
|
||||
|
||||
@@ -1746,11 +1766,7 @@ static int m_can_dev_setup(struct m_can_classdev *cdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Forcing standby mode should be redundant, as the chip should be in
|
||||
* standby after a reset. Write the INIT bit anyways, should the chip
|
||||
* be configured by previous stage.
|
||||
*/
|
||||
return m_can_cccr_update_bits(cdev, CCCR_INIT, CCCR_INIT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void m_can_stop(struct net_device *dev)
|
||||
|
||||
@@ -99,6 +99,7 @@ struct m_can_classdev {
|
||||
int pm_clock_support;
|
||||
int pm_wake_source;
|
||||
int is_peripheral;
|
||||
bool irq_edge_triggered;
|
||||
|
||||
// Cached M_CAN_IE register content
|
||||
u32 active_interrupts;
|
||||
|
||||
@@ -127,6 +127,7 @@ static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
|
||||
mcan_class->pm_clock_support = 1;
|
||||
mcan_class->pm_wake_source = 0;
|
||||
mcan_class->can.clock.freq = id->driver_data;
|
||||
mcan_class->irq_edge_triggered = true;
|
||||
mcan_class->ops = &m_can_pci_ops;
|
||||
|
||||
pci_set_drvdata(pci, mcan_class);
|
||||
|
||||
@@ -171,6 +171,7 @@ static int platform_phy_connect(struct bgmac *bgmac)
|
||||
static int bgmac_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *phy_node;
|
||||
struct bgmac *bgmac;
|
||||
struct resource *regs;
|
||||
int ret;
|
||||
@@ -236,7 +237,9 @@ static int bgmac_probe(struct platform_device *pdev)
|
||||
bgmac->cco_ctl_maskset = platform_bgmac_cco_ctl_maskset;
|
||||
bgmac->get_bus_clock = platform_bgmac_get_bus_clock;
|
||||
bgmac->cmn_maskset32 = platform_bgmac_cmn_maskset32;
|
||||
if (of_parse_phandle(np, "phy-handle", 0)) {
|
||||
phy_node = of_parse_phandle(np, "phy-handle", 0);
|
||||
if (phy_node) {
|
||||
of_node_put(phy_node);
|
||||
bgmac->phy_connect = platform_phy_connect;
|
||||
} else {
|
||||
bgmac->phy_connect = bgmac_phy_connect_direct;
|
||||
|
||||
@@ -346,8 +346,9 @@ static struct sk_buff *copy_gl_to_skb_pkt(const struct pkt_gl *gl,
|
||||
* driver. Once driver synthesizes cpl_pass_accept_req the skb will go
|
||||
* through the regular cpl_pass_accept_req processing in TOM.
|
||||
*/
|
||||
skb = alloc_skb(gl->tot_len + sizeof(struct cpl_pass_accept_req)
|
||||
- pktshift, GFP_ATOMIC);
|
||||
skb = alloc_skb(size_add(gl->tot_len,
|
||||
sizeof(struct cpl_pass_accept_req)) -
|
||||
pktshift, GFP_ATOMIC);
|
||||
if (unlikely(!skb))
|
||||
return NULL;
|
||||
__skb_put(skb, gl->tot_len + sizeof(struct cpl_pass_accept_req)
|
||||
|
||||
@@ -172,6 +172,7 @@ err_init_txq:
|
||||
hinic_sq_dbgfs_uninit(nic_dev);
|
||||
|
||||
devm_kfree(&netdev->dev, nic_dev->txqs);
|
||||
nic_dev->txqs = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -268,6 +269,7 @@ err_init_rxq:
|
||||
hinic_rq_dbgfs_uninit(nic_dev);
|
||||
|
||||
devm_kfree(&netdev->dev, nic_dev->rxqs);
|
||||
nic_dev->rxqs = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +101,9 @@ static int idpf_intr_reg_init(struct idpf_vport *vport)
|
||||
intr->dyn_ctl_itridx_s = PF_GLINT_DYN_CTL_ITR_INDX_S;
|
||||
intr->dyn_ctl_intrvl_s = PF_GLINT_DYN_CTL_INTERVAL_S;
|
||||
intr->dyn_ctl_wb_on_itr_m = PF_GLINT_DYN_CTL_WB_ON_ITR_M;
|
||||
intr->dyn_ctl_swint_trig_m = PF_GLINT_DYN_CTL_SWINT_TRIG_M;
|
||||
intr->dyn_ctl_sw_itridx_ena_m =
|
||||
PF_GLINT_DYN_CTL_SW_ITR_INDX_ENA_M;
|
||||
|
||||
spacing = IDPF_ITR_IDX_SPACING(reg_vals[vec_id].itrn_index_spacing,
|
||||
IDPF_PF_ITR_IDX_SPACING);
|
||||
|
||||
@@ -3604,21 +3604,31 @@ static void idpf_vport_intr_dis_irq_all(struct idpf_vport *vport)
|
||||
/**
|
||||
* idpf_vport_intr_buildreg_itr - Enable default interrupt generation settings
|
||||
* @q_vector: pointer to q_vector
|
||||
* @type: itr index
|
||||
* @itr: itr value
|
||||
*/
|
||||
static u32 idpf_vport_intr_buildreg_itr(struct idpf_q_vector *q_vector,
|
||||
const int type, u16 itr)
|
||||
static u32 idpf_vport_intr_buildreg_itr(struct idpf_q_vector *q_vector)
|
||||
{
|
||||
u32 itr_val;
|
||||
u32 itr_val = q_vector->intr_reg.dyn_ctl_intena_m;
|
||||
int type = IDPF_NO_ITR_UPDATE_IDX;
|
||||
u16 itr = 0;
|
||||
|
||||
if (q_vector->wb_on_itr) {
|
||||
/*
|
||||
* Trigger a software interrupt when exiting wb_on_itr, to make
|
||||
* sure we catch any pending write backs that might have been
|
||||
* missed due to interrupt state transition.
|
||||
*/
|
||||
itr_val |= q_vector->intr_reg.dyn_ctl_swint_trig_m |
|
||||
q_vector->intr_reg.dyn_ctl_sw_itridx_ena_m;
|
||||
type = IDPF_SW_ITR_UPDATE_IDX;
|
||||
itr = IDPF_ITR_20K;
|
||||
}
|
||||
|
||||
itr &= IDPF_ITR_MASK;
|
||||
/* Don't clear PBA because that can cause lost interrupts that
|
||||
* came in while we were cleaning/polling
|
||||
*/
|
||||
itr_val = q_vector->intr_reg.dyn_ctl_intena_m |
|
||||
(type << q_vector->intr_reg.dyn_ctl_itridx_s) |
|
||||
(itr << (q_vector->intr_reg.dyn_ctl_intrvl_s - 1));
|
||||
itr_val |= (type << q_vector->intr_reg.dyn_ctl_itridx_s) |
|
||||
(itr << (q_vector->intr_reg.dyn_ctl_intrvl_s - 1));
|
||||
|
||||
return itr_val;
|
||||
}
|
||||
@@ -3716,9 +3726,8 @@ void idpf_vport_intr_update_itr_ena_irq(struct idpf_q_vector *q_vector)
|
||||
/* net_dim() updates ITR out-of-band using a work item */
|
||||
idpf_net_dim(q_vector);
|
||||
|
||||
intval = idpf_vport_intr_buildreg_itr(q_vector);
|
||||
q_vector->wb_on_itr = false;
|
||||
intval = idpf_vport_intr_buildreg_itr(q_vector,
|
||||
IDPF_NO_ITR_UPDATE_IDX, 0);
|
||||
|
||||
writel(intval, q_vector->intr_reg.dyn_ctl);
|
||||
}
|
||||
|
||||
@@ -354,6 +354,8 @@ struct idpf_vec_regs {
|
||||
* @dyn_ctl_itridx_m: Mask for ITR index
|
||||
* @dyn_ctl_intrvl_s: Register bit offset for ITR interval
|
||||
* @dyn_ctl_wb_on_itr_m: Mask for WB on ITR feature
|
||||
* @dyn_ctl_sw_itridx_ena_m: Mask for SW ITR index
|
||||
* @dyn_ctl_swint_trig_m: Mask for dyn_ctl SW triggered interrupt enable
|
||||
* @rx_itr: RX ITR register
|
||||
* @tx_itr: TX ITR register
|
||||
* @icr_ena: Interrupt cause register offset
|
||||
@@ -367,6 +369,8 @@ struct idpf_intr_reg {
|
||||
u32 dyn_ctl_itridx_m;
|
||||
u32 dyn_ctl_intrvl_s;
|
||||
u32 dyn_ctl_wb_on_itr_m;
|
||||
u32 dyn_ctl_sw_itridx_ena_m;
|
||||
u32 dyn_ctl_swint_trig_m;
|
||||
void __iomem *rx_itr;
|
||||
void __iomem *tx_itr;
|
||||
void __iomem *icr_ena;
|
||||
@@ -437,7 +441,7 @@ struct idpf_q_vector {
|
||||
cpumask_var_t affinity_mask;
|
||||
__cacheline_group_end_aligned(cold);
|
||||
};
|
||||
libeth_cacheline_set_assert(struct idpf_q_vector, 112,
|
||||
libeth_cacheline_set_assert(struct idpf_q_vector, 120,
|
||||
24 + sizeof(struct napi_struct) +
|
||||
2 * sizeof(struct dim),
|
||||
8 + sizeof(cpumask_var_t));
|
||||
@@ -471,6 +475,8 @@ struct idpf_tx_queue_stats {
|
||||
#define IDPF_ITR_IS_DYNAMIC(itr_mode) (itr_mode)
|
||||
#define IDPF_ITR_TX_DEF IDPF_ITR_20K
|
||||
#define IDPF_ITR_RX_DEF IDPF_ITR_20K
|
||||
/* Index used for 'SW ITR' update in DYN_CTL register */
|
||||
#define IDPF_SW_ITR_UPDATE_IDX 2
|
||||
/* Index used for 'No ITR' update in DYN_CTL register */
|
||||
#define IDPF_NO_ITR_UPDATE_IDX 3
|
||||
#define IDPF_ITR_IDX_SPACING(spacing, dflt) (spacing ? spacing : dflt)
|
||||
|
||||
@@ -101,6 +101,9 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport)
|
||||
intr->dyn_ctl_itridx_s = VF_INT_DYN_CTLN_ITR_INDX_S;
|
||||
intr->dyn_ctl_intrvl_s = VF_INT_DYN_CTLN_INTERVAL_S;
|
||||
intr->dyn_ctl_wb_on_itr_m = VF_INT_DYN_CTLN_WB_ON_ITR_M;
|
||||
intr->dyn_ctl_swint_trig_m = VF_INT_DYN_CTLN_SWINT_TRIG_M;
|
||||
intr->dyn_ctl_sw_itridx_ena_m =
|
||||
VF_INT_DYN_CTLN_SW_ITR_INDX_ENA_M;
|
||||
|
||||
spacing = IDPF_ITR_IDX_SPACING(reg_vals[vec_id].itrn_index_spacing,
|
||||
IDPF_VF_ITR_IDX_SPACING);
|
||||
|
||||
@@ -680,14 +680,17 @@ int rvu_rep_create(struct otx2_nic *priv, struct netlink_ext_ack *extack)
|
||||
ndev->features |= ndev->hw_features;
|
||||
eth_hw_addr_random(ndev);
|
||||
err = rvu_rep_devlink_port_register(rep);
|
||||
if (err)
|
||||
if (err) {
|
||||
free_netdev(ndev);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
SET_NETDEV_DEVLINK_PORT(ndev, &rep->dl_port);
|
||||
err = register_netdev(ndev);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"PFVF representor registration failed");
|
||||
rvu_rep_devlink_port_unregister(rep);
|
||||
free_netdev(ndev);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -1432,7 +1432,7 @@ void ocelot_ifh_set_basic(void *ifh, struct ocelot *ocelot, int port,
|
||||
|
||||
memset(ifh, 0, OCELOT_TAG_LEN);
|
||||
ocelot_ifh_set_bypass(ifh, 1);
|
||||
ocelot_ifh_set_src(ifh, BIT_ULL(ocelot->num_phys_ports));
|
||||
ocelot_ifh_set_src(ifh, ocelot->num_phys_ports);
|
||||
ocelot_ifh_set_dest(ifh, BIT_ULL(port));
|
||||
ocelot_ifh_set_qos_class(ifh, qos_class);
|
||||
ocelot_ifh_set_tag_type(ifh, tag_type);
|
||||
|
||||
@@ -113,6 +113,7 @@ struct oa_tc6 {
|
||||
struct mii_bus *mdiobus;
|
||||
struct spi_device *spi;
|
||||
struct mutex spi_ctrl_lock; /* Protects spi control transfer */
|
||||
spinlock_t tx_skb_lock; /* Protects tx skb handling */
|
||||
void *spi_ctrl_tx_buf;
|
||||
void *spi_ctrl_rx_buf;
|
||||
void *spi_data_tx_buf;
|
||||
@@ -1004,8 +1005,10 @@ static u16 oa_tc6_prepare_spi_tx_buf_for_tx_skbs(struct oa_tc6 *tc6)
|
||||
for (used_tx_credits = 0; used_tx_credits < tc6->tx_credits;
|
||||
used_tx_credits++) {
|
||||
if (!tc6->ongoing_tx_skb) {
|
||||
spin_lock_bh(&tc6->tx_skb_lock);
|
||||
tc6->ongoing_tx_skb = tc6->waiting_tx_skb;
|
||||
tc6->waiting_tx_skb = NULL;
|
||||
spin_unlock_bh(&tc6->tx_skb_lock);
|
||||
}
|
||||
if (!tc6->ongoing_tx_skb)
|
||||
break;
|
||||
@@ -1111,8 +1114,9 @@ static int oa_tc6_spi_thread_handler(void *data)
|
||||
/* This kthread will be waken up if there is a tx skb or mac-phy
|
||||
* interrupt to perform spi transfer with tx chunks.
|
||||
*/
|
||||
wait_event_interruptible(tc6->spi_wq, tc6->waiting_tx_skb ||
|
||||
tc6->int_flag ||
|
||||
wait_event_interruptible(tc6->spi_wq, tc6->int_flag ||
|
||||
(tc6->waiting_tx_skb &&
|
||||
tc6->tx_credits) ||
|
||||
kthread_should_stop());
|
||||
|
||||
if (kthread_should_stop())
|
||||
@@ -1209,7 +1213,9 @@ netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, struct sk_buff *skb)
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
spin_lock_bh(&tc6->tx_skb_lock);
|
||||
tc6->waiting_tx_skb = skb;
|
||||
spin_unlock_bh(&tc6->tx_skb_lock);
|
||||
|
||||
/* Wake spi kthread to perform spi transfer */
|
||||
wake_up_interruptible(&tc6->spi_wq);
|
||||
@@ -1239,6 +1245,7 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev)
|
||||
tc6->netdev = netdev;
|
||||
SET_NETDEV_DEV(netdev, &spi->dev);
|
||||
mutex_init(&tc6->spi_ctrl_lock);
|
||||
spin_lock_init(&tc6->tx_skb_lock);
|
||||
|
||||
/* Set the SPI controller to pump at realtime priority */
|
||||
tc6->spi->rt = true;
|
||||
|
||||
@@ -277,7 +277,10 @@ void ionic_dev_teardown(struct ionic *ionic)
|
||||
idev->phy_cmb_pages = 0;
|
||||
idev->cmb_npages = 0;
|
||||
|
||||
destroy_workqueue(ionic->wq);
|
||||
if (ionic->wq) {
|
||||
destroy_workqueue(ionic->wq);
|
||||
ionic->wq = NULL;
|
||||
}
|
||||
mutex_destroy(&idev->cmb_inuse_lock);
|
||||
}
|
||||
|
||||
|
||||
@@ -961,8 +961,8 @@ static int ionic_get_module_eeprom(struct net_device *netdev,
|
||||
len = min_t(u32, sizeof(xcvr->sprom), ee->len);
|
||||
|
||||
do {
|
||||
memcpy(data, xcvr->sprom, len);
|
||||
memcpy(tbuf, xcvr->sprom, len);
|
||||
memcpy(data, &xcvr->sprom[ee->offset], len);
|
||||
memcpy(tbuf, &xcvr->sprom[ee->offset], len);
|
||||
|
||||
/* Let's make sure we got a consistent copy */
|
||||
if (!memcmp(data, tbuf, len))
|
||||
|
||||
@@ -3869,8 +3869,8 @@ int ionic_lif_register(struct ionic_lif *lif)
|
||||
/* only register LIF0 for now */
|
||||
err = register_netdev(lif->netdev);
|
||||
if (err) {
|
||||
dev_err(lif->ionic->dev, "Cannot register net device, aborting\n");
|
||||
ionic_lif_unregister_phc(lif);
|
||||
dev_err(lif->ionic->dev, "Cannot register net device: %d, aborting\n", err);
|
||||
ionic_lif_unregister(lif);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -3358,6 +3358,7 @@ int qed_mcp_nvm_info_populate(struct qed_hwfn *p_hwfn)
|
||||
p_ptt, &nvm_info.num_images);
|
||||
if (rc == -EOPNOTSUPP) {
|
||||
DP_INFO(p_hwfn, "DRV_MSG_CODE_BIST_TEST is not supported\n");
|
||||
nvm_info.num_images = 0;
|
||||
goto out;
|
||||
} else if (rc || !nvm_info.num_images) {
|
||||
DP_ERR(p_hwfn, "Failed getting number of images\n");
|
||||
|
||||
@@ -547,7 +547,6 @@ static int rswitch_gwca_ts_queue_alloc(struct rswitch_private *priv)
|
||||
desc = &gq->ts_ring[gq->ring_size];
|
||||
desc->desc.die_dt = DT_LINKFIX;
|
||||
rswitch_desc_set_dptr(&desc->desc, gq->ring_dma);
|
||||
INIT_LIST_HEAD(&priv->gwca.ts_info_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1003,9 +1002,10 @@ static int rswitch_gwca_request_irqs(struct rswitch_private *priv)
|
||||
static void rswitch_ts(struct rswitch_private *priv)
|
||||
{
|
||||
struct rswitch_gwca_queue *gq = &priv->gwca.ts_queue;
|
||||
struct rswitch_gwca_ts_info *ts_info, *ts_info2;
|
||||
struct skb_shared_hwtstamps shhwtstamps;
|
||||
struct rswitch_ts_desc *desc;
|
||||
struct rswitch_device *rdev;
|
||||
struct sk_buff *ts_skb;
|
||||
struct timespec64 ts;
|
||||
unsigned int num;
|
||||
u32 tag, port;
|
||||
@@ -1015,23 +1015,28 @@ static void rswitch_ts(struct rswitch_private *priv)
|
||||
dma_rmb();
|
||||
|
||||
port = TS_DESC_DPN(__le32_to_cpu(desc->desc.dptrl));
|
||||
if (unlikely(port >= RSWITCH_NUM_PORTS))
|
||||
goto next;
|
||||
rdev = priv->rdev[port];
|
||||
|
||||
tag = TS_DESC_TSUN(__le32_to_cpu(desc->desc.dptrl));
|
||||
if (unlikely(tag >= TS_TAGS_PER_PORT))
|
||||
goto next;
|
||||
ts_skb = xchg(&rdev->ts_skb[tag], NULL);
|
||||
smp_mb(); /* order rdev->ts_skb[] read before bitmap update */
|
||||
clear_bit(tag, rdev->ts_skb_used);
|
||||
|
||||
list_for_each_entry_safe(ts_info, ts_info2, &priv->gwca.ts_info_list, list) {
|
||||
if (!(ts_info->port == port && ts_info->tag == tag))
|
||||
continue;
|
||||
if (unlikely(!ts_skb))
|
||||
goto next;
|
||||
|
||||
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
|
||||
ts.tv_sec = __le32_to_cpu(desc->ts_sec);
|
||||
ts.tv_nsec = __le32_to_cpu(desc->ts_nsec & cpu_to_le32(0x3fffffff));
|
||||
shhwtstamps.hwtstamp = timespec64_to_ktime(ts);
|
||||
skb_tstamp_tx(ts_info->skb, &shhwtstamps);
|
||||
dev_consume_skb_irq(ts_info->skb);
|
||||
list_del(&ts_info->list);
|
||||
kfree(ts_info);
|
||||
break;
|
||||
}
|
||||
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
|
||||
ts.tv_sec = __le32_to_cpu(desc->ts_sec);
|
||||
ts.tv_nsec = __le32_to_cpu(desc->ts_nsec & cpu_to_le32(0x3fffffff));
|
||||
shhwtstamps.hwtstamp = timespec64_to_ktime(ts);
|
||||
skb_tstamp_tx(ts_skb, &shhwtstamps);
|
||||
dev_consume_skb_irq(ts_skb);
|
||||
|
||||
next:
|
||||
gq->cur = rswitch_next_queue_index(gq, true, 1);
|
||||
desc = &gq->ts_ring[gq->cur];
|
||||
}
|
||||
@@ -1576,8 +1581,9 @@ static int rswitch_open(struct net_device *ndev)
|
||||
static int rswitch_stop(struct net_device *ndev)
|
||||
{
|
||||
struct rswitch_device *rdev = netdev_priv(ndev);
|
||||
struct rswitch_gwca_ts_info *ts_info, *ts_info2;
|
||||
struct sk_buff *ts_skb;
|
||||
unsigned long flags;
|
||||
unsigned int tag;
|
||||
|
||||
netif_tx_stop_all_queues(ndev);
|
||||
|
||||
@@ -1594,12 +1600,13 @@ static int rswitch_stop(struct net_device *ndev)
|
||||
if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS))
|
||||
iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDID);
|
||||
|
||||
list_for_each_entry_safe(ts_info, ts_info2, &rdev->priv->gwca.ts_info_list, list) {
|
||||
if (ts_info->port != rdev->port)
|
||||
continue;
|
||||
dev_kfree_skb_irq(ts_info->skb);
|
||||
list_del(&ts_info->list);
|
||||
kfree(ts_info);
|
||||
for (tag = find_first_bit(rdev->ts_skb_used, TS_TAGS_PER_PORT);
|
||||
tag < TS_TAGS_PER_PORT;
|
||||
tag = find_next_bit(rdev->ts_skb_used, TS_TAGS_PER_PORT, tag + 1)) {
|
||||
ts_skb = xchg(&rdev->ts_skb[tag], NULL);
|
||||
clear_bit(tag, rdev->ts_skb_used);
|
||||
if (ts_skb)
|
||||
dev_kfree_skb(ts_skb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1612,20 +1619,17 @@ static bool rswitch_ext_desc_set_info1(struct rswitch_device *rdev,
|
||||
desc->info1 = cpu_to_le64(INFO1_DV(BIT(rdev->etha->index)) |
|
||||
INFO1_IPV(GWCA_IPV_NUM) | INFO1_FMT);
|
||||
if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
|
||||
struct rswitch_gwca_ts_info *ts_info;
|
||||
unsigned int tag;
|
||||
|
||||
ts_info = kzalloc(sizeof(*ts_info), GFP_ATOMIC);
|
||||
if (!ts_info)
|
||||
tag = find_first_zero_bit(rdev->ts_skb_used, TS_TAGS_PER_PORT);
|
||||
if (tag == TS_TAGS_PER_PORT)
|
||||
return false;
|
||||
smp_mb(); /* order bitmap read before rdev->ts_skb[] write */
|
||||
rdev->ts_skb[tag] = skb_get(skb);
|
||||
set_bit(tag, rdev->ts_skb_used);
|
||||
|
||||
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
|
||||
rdev->ts_tag++;
|
||||
desc->info1 |= cpu_to_le64(INFO1_TSUN(rdev->ts_tag) | INFO1_TXC);
|
||||
|
||||
ts_info->skb = skb_get(skb);
|
||||
ts_info->port = rdev->port;
|
||||
ts_info->tag = rdev->ts_tag;
|
||||
list_add_tail(&ts_info->list, &rdev->priv->gwca.ts_info_list);
|
||||
desc->info1 |= cpu_to_le64(INFO1_TSUN(tag) | INFO1_TXC);
|
||||
|
||||
skb_tx_timestamp(skb);
|
||||
}
|
||||
|
||||
@@ -972,14 +972,6 @@ struct rswitch_gwca_queue {
|
||||
};
|
||||
};
|
||||
|
||||
struct rswitch_gwca_ts_info {
|
||||
struct sk_buff *skb;
|
||||
struct list_head list;
|
||||
|
||||
int port;
|
||||
u8 tag;
|
||||
};
|
||||
|
||||
#define RSWITCH_NUM_IRQ_REGS (RSWITCH_MAX_NUM_QUEUES / BITS_PER_TYPE(u32))
|
||||
struct rswitch_gwca {
|
||||
unsigned int index;
|
||||
@@ -989,7 +981,6 @@ struct rswitch_gwca {
|
||||
struct rswitch_gwca_queue *queues;
|
||||
int num_queues;
|
||||
struct rswitch_gwca_queue ts_queue;
|
||||
struct list_head ts_info_list;
|
||||
DECLARE_BITMAP(used, RSWITCH_MAX_NUM_QUEUES);
|
||||
u32 tx_irq_bits[RSWITCH_NUM_IRQ_REGS];
|
||||
u32 rx_irq_bits[RSWITCH_NUM_IRQ_REGS];
|
||||
@@ -997,6 +988,7 @@ struct rswitch_gwca {
|
||||
};
|
||||
|
||||
#define NUM_QUEUES_PER_NDEV 2
|
||||
#define TS_TAGS_PER_PORT 256
|
||||
struct rswitch_device {
|
||||
struct rswitch_private *priv;
|
||||
struct net_device *ndev;
|
||||
@@ -1004,7 +996,8 @@ struct rswitch_device {
|
||||
void __iomem *addr;
|
||||
struct rswitch_gwca_queue *tx_queue;
|
||||
struct rswitch_gwca_queue *rx_queue;
|
||||
u8 ts_tag;
|
||||
struct sk_buff *ts_skb[TS_TAGS_PER_PORT];
|
||||
DECLARE_BITMAP(ts_skb_used, TS_TAGS_PER_PORT);
|
||||
bool disabled;
|
||||
|
||||
int port;
|
||||
|
||||
@@ -40,6 +40,7 @@ fwnode_find_pse_control(struct fwnode_handle *fwnode)
|
||||
static struct mii_timestamper *
|
||||
fwnode_find_mii_timestamper(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct mii_timestamper *mii_ts;
|
||||
struct of_phandle_args arg;
|
||||
int err;
|
||||
|
||||
@@ -53,10 +54,16 @@ fwnode_find_mii_timestamper(struct fwnode_handle *fwnode)
|
||||
else if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
if (arg.args_count != 1)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (arg.args_count != 1) {
|
||||
mii_ts = ERR_PTR(-EINVAL);
|
||||
goto put_node;
|
||||
}
|
||||
|
||||
return register_mii_timestamper(arg.np, arg.args[0]);
|
||||
mii_ts = register_mii_timestamper(arg.np, arg.args[0]);
|
||||
|
||||
put_node:
|
||||
of_node_put(arg.np);
|
||||
return mii_ts;
|
||||
}
|
||||
|
||||
int fwnode_mdiobus_phy_device_register(struct mii_bus *mdio,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user