No conflicts.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
F: include/trace/events/afs.h
AGPGART DRIVER
- M: David Airlie <airlied@linux.ie>
+ M: David Airlie <airlied@redhat.com>
+ L: dri-devel@lists.freedesktop.org
S: Maintained
T: git git://anongit.freedesktop.org/drm/drm
F: drivers/char/agp/
S: Maintained
F: drivers/net/ethernet/altera/
+ALTERA TSE PCS
+M: Maxime Chevallier <maxime.chevallier@bootlin.com>
+L: netdev@vger.kernel.org
+S: Supported
+F: drivers/net/pcs/pcs-altera-tse.c
+F: include/linux/pcs-altera-tse.h
+
ALTERA UART/JTAG UART SERIAL DRIVERS
M: Tobias Klauser <tklauser@distanz.ch>
L: linux-serial@vger.kernel.org
AMD MP2 I2C DRIVER
M: Elie Morisse <syniurge@gmail.com>
- M: Nehal Shah <nehal-bakulchandra.shah@amd.com>
M: Shyam Sundar S K <shyam-sundar.s-k@amd.com>
L: linux-i2c@vger.kernel.org
S: Maintained
ARM/Microchip Sparx5 SoC support
M: Lars Povlsen <lars.povlsen@microchip.com>
M: Steen Hegelund <Steen.Hegelund@microchip.com>
+M: Daniel Machon <daniel.machon@microchip.com>
M: UNGLinuxDriver@microchip.com
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Supported
ARM/QUALCOMM SUPPORT
M: Andy Gross <agross@kernel.org>
- M: Bjorn Andersson <bjorn.andersson@linaro.org>
+ M: Bjorn Andersson <andersson@kernel.org>
R: Konrad Dybcio <konrad.dybcio@somainline.org>
L: linux-arm-msm@vger.kernel.org
S: Maintained
F: include/linux/blk-cgroup.h
CONTROL GROUP - CPUSET
+ M: Waiman Long <longman@redhat.com>
M: Zefan Li <lizefan.x@bytedance.com>
L: cgroups@vger.kernel.org
S: Maintained
F: include/uapi/linux/dccp.h
F: net/dccp/
-DECnet NETWORK LAYER
-L: linux-decnet-user@lists.sourceforge.net
-S: Orphan
-W: http://linux-decnet.sourceforge.net
-F: Documentation/networking/decnet.rst
-F: net/decnet/
-
DECSTATION PLATFORM SUPPORT
M: "Maciej W. Rozycki" <macro@orcam.me.uk>
L: linux-mips@vger.kernel.org
F: drivers/gpu/drm/panel/panel-widechips-ws2401.c
DRM DRIVERS
- M: David Airlie <airlied@linux.ie>
+ M: David Airlie <airlied@gmail.com>
M: Daniel Vetter <daniel@ffwll.ch>
L: dri-devel@lists.freedesktop.org
S: Maintained
HARDWARE SPINLOCK CORE
M: Ohad Ben-Cohen <ohad@wizery.com>
- M: Bjorn Andersson <bjorn.andersson@linaro.org>
+ M: Bjorn Andersson <andersson@kernel.org>
R: Baolin Wang <baolin.wang7@gmail.com>
L: linux-remoteproc@vger.kernel.org
S: Maintained
F: net/dsa/tag_ocelot_8021q.c
F: tools/testing/selftests/drivers/net/ocelot/*
+OCELOT EXTERNAL SWITCH CONTROL
+M: Colin Foster <colin.foster@in-advantage.com>
+S: Supported
+F: Documentation/devicetree/bindings/mfd/mscc,ocelot.yaml
+F: drivers/mfd/ocelot*
+F: include/linux/mfd/ocelot.h
+
OCXL (Open Coherent Accelerator Processor Interface OpenCAPI) DRIVER
M: Frederic Barrat <fbarrat@linux.ibm.com>
M: Andrew Donnellan <ajd@linux.ibm.com>
F: drivers/pinctrl/pinctrl-at91*
PIN CONTROLLER - QUALCOMM
- M: Bjorn Andersson <bjorn.andersson@linaro.org>
+ M: Bjorn Andersson <andersson@kernel.org>
L: linux-arm-msm@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/pinctrl/qcom,*.txt
F: drivers/media/platform/qcom/camss/
QUALCOMM CLOCK DRIVERS
- M: Bjorn Andersson <bjorn.andersson@linaro.org>
+ M: Bjorn Andersson <andersson@kernel.org>
L: linux-arm-msm@vger.kernel.org
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git
F: fs/reiserfs/
REMOTE PROCESSOR (REMOTEPROC) SUBSYSTEM
- M: Bjorn Andersson <bjorn.andersson@linaro.org>
+ M: Bjorn Andersson <andersson@kernel.org>
M: Mathieu Poirier <mathieu.poirier@linaro.org>
L: linux-remoteproc@vger.kernel.org
S: Maintained
F: include/linux/remoteproc/
REMOTE PROCESSOR MESSAGING (RPMSG) SUBSYSTEM
- M: Bjorn Andersson <bjorn.andersson@linaro.org>
+ M: Bjorn Andersson <andersson@kernel.org>
M: Mathieu Poirier <mathieu.poirier@linaro.org>
L: linux-remoteproc@vger.kernel.org
S: Maintained
S: Maintained
F: drivers/net/ethernet/dlink/sundance.c
+SUN HAPPY MEAL ETHERNET DRIVER
+M: Sean Anderson <seanga2@gmail.com>
+S: Maintained
+F: drivers/net/ethernet/sun/sunhme.*
+
SUNPLUS ETHERNET DRIVER
M: Wells Lu <wellslutw@gmail.com>
L: netdev@vger.kernel.org
F: drivers/net/team/
F: include/linux/if_team.h
F: include/uapi/linux/if_team.h
- F: tools/testing/selftests/net/team/
+ F: tools/testing/selftests/drivers/net/team/
TECHNOLOGIC SYSTEMS TS-5500 PLATFORM SUPPORT
M: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
F: include/uapi/linux/virtio_gpio.h
VIRTIO GPU DRIVER
- M: David Airlie <airlied@linux.ie>
+ M: David Airlie <airlied@redhat.com>
M: Gerd Hoffmann <kraxel@redhat.com>
R: Gurchetan Singh <gurchetansingh@chromium.org>
R: Chia-I Wu <olvaffe@gmail.com>
WANGXUN ETHERNET DRIVER
M: Jiawen Wu <jiawenwu@trustnetic.com>
+M: Mengyuan Lou <mengyuanlou@net-swift.com>
+W: https://www.net-swift.com
L: netdev@vger.kernel.org
S: Maintained
-F: Documentation/networking/device_drivers/ethernet/wangxun/txgbe.rst
+F: Documentation/networking/device_drivers/ethernet/wangxun/*
F: drivers/net/ethernet/wangxun/
WATCHDOG DEVICE DRIVERS
static int
mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
{
- struct mt7530_priv *priv = ds->priv;
+ return 0;
+ }
+
+ static void
+ mt7531_pll_setup(struct mt7530_priv *priv)
+ {
u32 top_sig;
u32 hwstrap;
u32 xtal;
u32 val;
if (mt7531_dual_sgmii_supported(priv))
- return 0;
+ return;
val = mt7530_read(priv, MT7531_CREV);
top_sig = mt7530_read(priv, MT7531_TOP_SIG_SR);
val |= EN_COREPLL;
mt7530_write(priv, MT7531_PLLGP_EN, val);
usleep_range(25, 35);
-
- return 0;
}
static void
return -ENODEV;
}
+ /* all MACs must be forced link-down before sw reset */
+ for (i = 0; i < MT7530_NUM_PORTS; i++)
+ mt7530_write(priv, MT7530_PMCR_P(i), MT7531_FORCE_LNK);
+
/* Reset the switch through internal reset */
mt7530_write(priv, MT7530_SYS_CTRL,
SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
SYS_CTRL_REG_RST);
+ mt7531_pll_setup(priv);
+
if (mt7531_dual_sgmii_supported(priv)) {
priv->p5_intf_sel = P5_INTF_SEL_GMAC5_SGMII;
case PHY_INTERFACE_MODE_NA:
case PHY_INTERFACE_MODE_1000BASEX:
case PHY_INTERFACE_MODE_2500BASEX:
- if (phylink_autoneg_inband(mode))
- return -EINVAL;
-
return mt7531_sgmii_setup_mode_force(priv, port, interface);
default:
return -EINVAL;
return;
}
- if (phylink_autoneg_inband(mode) &&
- state->interface != PHY_INTERFACE_MODE_SGMII) {
- dev_err(ds->dev, "%s: in-band negotiation unsupported\n",
- __func__);
- return;
- }
-
mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));
mcr_new = mcr_cur;
mcr_new &= ~PMCR_LINK_SETTINGS_MASK;
case 6:
interface = PHY_INTERFACE_MODE_2500BASEX;
- mt7531_pad_setup(ds, interface);
-
priv->p6_interface = interface;
break;
default:
config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
MAC_10 | MAC_100 | MAC_1000FD;
+ if ((priv->id == ID_MT7531) && mt753x_is_mac_port(port))
+ config->mac_capabilities |= MAC_2500FD;
+
/* This driver does not make use of the speed, duplex, pause or the
* advertisement in its mac_config, so it is safe to mark this driver
* as non-legacy.
status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
state->link = !!(status & MT7531_SGMII_LINK_STATUS);
+ state->an_complete = !!(status & MT7531_SGMII_AN_COMPLETE);
if (state->interface == PHY_INTERFACE_MODE_SGMII &&
(status & MT7531_SGMII_AN_ENABLE)) {
val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port));
return 0;
}
+static void
+mt7531_sgmii_pcs_get_state_inband(struct mt7530_priv *priv, int port,
+ struct phylink_link_state *state)
+{
+ unsigned int val;
+
+ val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
+ state->link = !!(val & MT7531_SGMII_LINK_STATUS);
+ if (!state->link)
+ return;
+
+ state->an_complete = state->link;
+
+ if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
+ state->speed = SPEED_2500;
+ else
+ state->speed = SPEED_1000;
+
+ state->duplex = DUPLEX_FULL;
+ state->pause = MLO_PAUSE_NONE;
+}
+
static void mt7531_pcs_get_state(struct phylink_pcs *pcs,
struct phylink_link_state *state)
{
struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv;
int port = pcs_to_mt753x_pcs(pcs)->port;
- if (state->interface == PHY_INTERFACE_MODE_SGMII)
+ if (state->interface == PHY_INTERFACE_MODE_SGMII) {
mt7531_sgmii_pcs_get_state_an(priv, port, state);
- else
- state->link = false;
+ return;
+ } else if ((state->interface == PHY_INTERFACE_MODE_1000BASEX) ||
+ (state->interface == PHY_INTERFACE_MODE_2500BASEX)) {
+ mt7531_sgmii_pcs_get_state_inband(priv, port, state);
+ return;
+ }
+
+ state->link = false;
}
static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
priv->pcs[i].pcs.ops = priv->info->pcs_ops;
priv->pcs[i].priv = priv;
priv->pcs[i].port = i;
+ if (mt753x_is_mac_port(i))
+ priv->pcs[i].pcs.poll = 1;
}
ret = priv->info->sw_setup(ds);
dsa_unregister_switch(priv->ds);
mutex_destroy(&priv->reg_mutex);
-
- dev_set_drvdata(&mdiodev->dev, NULL);
}
static void mt7530_shutdown(struct mdio_device *mdiodev)
#include <linux/pm_runtime.h>
#include <linux/ptp_classify.h>
#include <linux/reset.h>
+#include <linux/firmware/xlnx-zynqmp.h>
#include "macb.h"
/* This structure is only used for MACB on SiFive FU540 devices */
queue = &bp->queues[q];
queue->bp = bp;
spin_lock_init(&queue->tx_ptr_lock);
- netif_napi_add(dev, &queue->napi_rx, macb_rx_poll, NAPI_POLL_WEIGHT);
- netif_napi_add(dev, &queue->napi_tx, macb_tx_poll, NAPI_POLL_WEIGHT);
+ netif_napi_add(dev, &queue->napi_rx, macb_rx_poll);
+ netif_napi_add(dev, &queue->napi_tx, macb_tx_poll);
if (hw_q) {
queue->ISR = GEM_ISR(hw_q - 1);
queue->IER = GEM_IER(hw_q - 1);
"failed to init SGMII PHY\n");
}
+ ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_SET_GEM_CONFIG);
+ if (!ret) {
+ u32 pm_info[2];
+
+ ret = of_property_read_u32_array(pdev->dev.of_node, "power-domains",
+ pm_info, ARRAY_SIZE(pm_info));
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to read power management information\n");
+ goto err_out_phy_exit;
+ }
+ ret = zynqmp_pm_set_gem_config(pm_info[1], GEM_CONFIG_FIXED, 0);
+ if (ret)
+ goto err_out_phy_exit;
+
+ ret = zynqmp_pm_set_gem_config(pm_info[1], GEM_CONFIG_SGMII_MODE, 1);
+ if (ret)
+ goto err_out_phy_exit;
+ }
+
/* Fully reset controller at hardware level if mapped in device tree */
ret = device_reset_optional(&pdev->dev);
if (ret) {
}
ret = macb_init(pdev);
+
+err_out_phy_exit:
if (ret)
phy_exit(bp->sgmii_phy);
if (!(bp->wol & MACB_WOL_ENABLED)) {
rtnl_lock();
phylink_stop(bp->phylink);
+ phy_exit(bp->sgmii_phy);
rtnl_unlock();
spin_lock_irqsave(&bp->lock, flags);
macb_reset_hw(bp);
macb_set_rx_mode(netdev);
macb_restore_features(bp);
rtnl_lock();
+ if (!device_may_wakeup(&bp->dev->dev))
+ phy_init(bp->sgmii_phy);
+
phylink_start(bp->phylink);
rtnl_unlock();
bool wd;
if (tx_ring->xsk_pool)
- wd = ice_xmit_zc(tx_ring, ICE_DESC_UNUSED(tx_ring), budget);
+ wd = ice_xmit_zc(tx_ring);
else if (ice_ring_is_xdp(tx_ring))
wd = true;
else
/* Grab an open timestamp slot */
idx = ice_ptp_request_ts(tx_ring->tx_tstamps, skb);
- if (idx < 0)
+ if (idx < 0) {
+ tx_ring->vsi->back->ptp.tx_hwtstamp_skipped++;
return;
+ }
off->cd_qw1 |= (u64)(ICE_TX_DESC_DTYPE_CTX |
(ICE_TX_CTX_DESC_TSYN << ICE_TXD_CTX_QW1_CMD_S) |
#define MTK_GDMA_TCS_EN BIT(21)
#define MTK_GDMA_UCS_EN BIT(20)
#define MTK_GDMA_TO_PDMA 0x0
-#define MTK_GDMA_TO_PPE 0x4444
#define MTK_GDMA_DROP_ALL 0x7777
/* Unicast Filter MAC Address Register - Low */
#define TX_DMA_FPORT_MASK_V2 0xf
#define TX_DMA_SWC_V2 BIT(30)
-#define MTK_WDMA0_BASE 0x2800
-#define MTK_WDMA1_BASE 0x2c00
-
/* QDMA descriptor txd4 */
#define TX_DMA_CHKSUM (0x7 << 29)
#define TX_DMA_TSO BIT(28)
#define MTK_RXD5_PPE_CPU_REASON GENMASK(22, 18)
#define MTK_RXD5_SRC_PORT GENMASK(29, 26)
- #define RX_DMA_GET_SPORT(x) (((x) >> 19) & 0xf)
- #define RX_DMA_GET_SPORT_V2(x) (((x) >> 26) & 0x7)
+ #define RX_DMA_GET_SPORT(x) (((x) >> 19) & 0x7)
+ #define RX_DMA_GET_SPORT_V2(x) (((x) >> 26) & 0xf)
/* PDMA V2 descriptor rxd3 */
#define RX_DMA_VTAG_V2 BIT(0)
u32 fq_blen; /* fq free page buffer length */
} qdma;
u32 gdm1_cnt;
+ u32 gdma_to_ppe;
+ u32 ppe_base;
+ u32 wdma_base[2];
};
/* struct mtk_eth_data - This is the structure holding all differences
* the target SoC
* @required_pctl A bool value to show whether the SoC requires
* the extra setup for those pins used by GMAC.
+ * @hash_offset Flow table hash offset.
+ * @foe_entry_size Foe table entry size.
* @txd_size Tx DMA descriptor size.
* @rxd_size Rx DMA descriptor size.
* @rx_irq_done_mask Rx irq done register mask.
u32 required_clks;
bool required_pctl;
u8 offload_version;
+ u8 hash_offset;
+ u16 foe_entry_size;
netdev_features_t hw_features;
struct {
u32 txd_size;
int ip_align;
- struct mtk_ppe *ppe;
+ struct mtk_ppe *ppe[2];
struct rhashtable flow_table;
struct bpf_prog __rcu *prog;
/* the struct describing the SoC. these are declared in the soc_xyz.c files */
extern const struct of_device_id of_mtk_match[];
+static inline struct mtk_foe_entry *
+mtk_foe_get_entry(struct mtk_ppe *ppe, u16 hash)
+{
+ const struct mtk_soc_data *soc = ppe->eth->soc;
+
+ return ppe->foe_table + hash * soc->foe_entry_size;
+}
+
+static inline u32 mtk_get_ib1_ts_mask(struct mtk_eth *eth)
+{
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ return MTK_FOE_IB1_BIND_TIMESTAMP_V2;
+
+ return MTK_FOE_IB1_BIND_TIMESTAMP;
+}
+
+static inline u32 mtk_get_ib1_ppoe_mask(struct mtk_eth *eth)
+{
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ return MTK_FOE_IB1_BIND_PPPOE_V2;
+
+ return MTK_FOE_IB1_BIND_PPPOE;
+}
+
+static inline u32 mtk_get_ib1_vlan_tag_mask(struct mtk_eth *eth)
+{
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ return MTK_FOE_IB1_BIND_VLAN_TAG_V2;
+
+ return MTK_FOE_IB1_BIND_VLAN_TAG;
+}
+
+static inline u32 mtk_get_ib1_vlan_layer_mask(struct mtk_eth *eth)
+{
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ return MTK_FOE_IB1_BIND_VLAN_LAYER_V2;
+
+ return MTK_FOE_IB1_BIND_VLAN_LAYER;
+}
+
+static inline u32 mtk_prep_ib1_vlan_layer(struct mtk_eth *eth, u32 val)
+{
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ return FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER_V2, val);
+
+ return FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, val);
+}
+
+static inline u32 mtk_get_ib1_vlan_layer(struct mtk_eth *eth, u32 val)
+{
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ return FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER_V2, val);
+
+ return FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER, val);
+}
+
+static inline u32 mtk_get_ib1_pkt_type_mask(struct mtk_eth *eth)
+{
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ return MTK_FOE_IB1_PACKET_TYPE_V2;
+
+ return MTK_FOE_IB1_PACKET_TYPE;
+}
+
+static inline u32 mtk_get_ib1_pkt_type(struct mtk_eth *eth, u32 val)
+{
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ return FIELD_GET(MTK_FOE_IB1_PACKET_TYPE_V2, val);
+
+ return FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, val);
+}
+
+static inline u32 mtk_get_ib2_multicast_mask(struct mtk_eth *eth)
+{
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ return MTK_FOE_IB2_MULTICAST_V2;
+
+ return MTK_FOE_IB2_MULTICAST;
+}
+
/* read the hardware status register */
void mtk_stats_update_mac(struct mtk_mac *mac);
*/
#include <linux/dsa/ocelot.h>
#include <linux/if_bridge.h>
-#include <linux/ptp_classify.h>
#include <soc/mscc/ocelot_vcap.h>
#include "ocelot.h"
#include "ocelot_vcap.h"
if (!(vlan->portmask & BIT(port)))
continue;
+ /* Ignore the VLAN added by ocelot_add_vlan_unaware_pvid(),
+ * because this is never active in hardware at the same time as
+ * the bridge VLANs, which only matter in VLAN-aware mode.
+ */
+ if (vlan->vid >= OCELOT_RSV_VLAN_RANGE_START)
+ continue;
+
if (vlan->untagged & BIT(port))
num_untagged++;
}
}
EXPORT_SYMBOL_GPL(ocelot_phylink_mac_link_up);
-static int ocelot_port_add_txtstamp_skb(struct ocelot *ocelot, int port,
- struct sk_buff *clone)
-{
- struct ocelot_port *ocelot_port = ocelot->ports[port];
- unsigned long flags;
-
- spin_lock_irqsave(&ocelot->ts_id_lock, flags);
-
- if (ocelot_port->ptp_skbs_in_flight == OCELOT_MAX_PTP_ID ||
- ocelot->ptp_skbs_in_flight == OCELOT_PTP_FIFO_SIZE) {
- spin_unlock_irqrestore(&ocelot->ts_id_lock, flags);
- return -EBUSY;
- }
-
- skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS;
- /* Store timestamp ID in OCELOT_SKB_CB(clone)->ts_id */
- OCELOT_SKB_CB(clone)->ts_id = ocelot_port->ts_id;
-
- ocelot_port->ts_id++;
- if (ocelot_port->ts_id == OCELOT_MAX_PTP_ID)
- ocelot_port->ts_id = 0;
-
- ocelot_port->ptp_skbs_in_flight++;
- ocelot->ptp_skbs_in_flight++;
-
- skb_queue_tail(&ocelot_port->tx_skbs, clone);
-
- spin_unlock_irqrestore(&ocelot->ts_id_lock, flags);
-
- return 0;
-}
-
-static bool ocelot_ptp_is_onestep_sync(struct sk_buff *skb,
- unsigned int ptp_class)
-{
- struct ptp_header *hdr;
- u8 msgtype, twostep;
-
- hdr = ptp_parse_header(skb, ptp_class);
- if (!hdr)
- return false;
-
- msgtype = ptp_get_msgtype(hdr, ptp_class);
- twostep = hdr->flag_field[0] & 0x2;
-
- if (msgtype == PTP_MSGTYPE_SYNC && twostep == 0)
- return true;
-
- return false;
-}
-
-int ocelot_port_txtstamp_request(struct ocelot *ocelot, int port,
- struct sk_buff *skb,
- struct sk_buff **clone)
-{
- struct ocelot_port *ocelot_port = ocelot->ports[port];
- u8 ptp_cmd = ocelot_port->ptp_cmd;
- unsigned int ptp_class;
- int err;
-
- /* Don't do anything if PTP timestamping not enabled */
- if (!ptp_cmd)
- return 0;
-
- ptp_class = ptp_classify_raw(skb);
- if (ptp_class == PTP_CLASS_NONE)
- return -EINVAL;
-
- /* Store ptp_cmd in OCELOT_SKB_CB(skb)->ptp_cmd */
- if (ptp_cmd == IFH_REW_OP_ORIGIN_PTP) {
- if (ocelot_ptp_is_onestep_sync(skb, ptp_class)) {
- OCELOT_SKB_CB(skb)->ptp_cmd = ptp_cmd;
- return 0;
- }
-
- /* Fall back to two-step timestamping */
- ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
- }
-
- if (ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
- *clone = skb_clone_sk(skb);
- if (!(*clone))
- return -ENOMEM;
-
- err = ocelot_port_add_txtstamp_skb(ocelot, port, *clone);
- if (err)
- return err;
-
- OCELOT_SKB_CB(skb)->ptp_cmd = ptp_cmd;
- OCELOT_SKB_CB(*clone)->ptp_class = ptp_class;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(ocelot_port_txtstamp_request);
-
-static void ocelot_get_hwtimestamp(struct ocelot *ocelot,
- struct timespec64 *ts)
-{
- unsigned long flags;
- u32 val;
-
- spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
-
- /* Read current PTP time to get seconds */
- val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
-
- val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
- val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_SAVE);
- ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
- ts->tv_sec = ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN);
-
- /* Read packet HW timestamp from FIFO */
- val = ocelot_read(ocelot, SYS_PTP_TXSTAMP);
- ts->tv_nsec = SYS_PTP_TXSTAMP_PTP_TXSTAMP(val);
-
- /* Sec has incremented since the ts was registered */
- if ((ts->tv_sec & 0x1) != !!(val & SYS_PTP_TXSTAMP_PTP_TXSTAMP_SEC))
- ts->tv_sec--;
-
- spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
-}
-
-static bool ocelot_validate_ptp_skb(struct sk_buff *clone, u16 seqid)
-{
- struct ptp_header *hdr;
-
- hdr = ptp_parse_header(clone, OCELOT_SKB_CB(clone)->ptp_class);
- if (WARN_ON(!hdr))
- return false;
-
- return seqid == ntohs(hdr->sequence_id);
-}
-
-void ocelot_get_txtstamp(struct ocelot *ocelot)
-{
- int budget = OCELOT_PTP_QUEUE_SZ;
-
- while (budget--) {
- struct sk_buff *skb, *skb_tmp, *skb_match = NULL;
- struct skb_shared_hwtstamps shhwtstamps;
- u32 val, id, seqid, txport;
- struct ocelot_port *port;
- struct timespec64 ts;
- unsigned long flags;
-
- val = ocelot_read(ocelot, SYS_PTP_STATUS);
-
- /* Check if a timestamp can be retrieved */
- if (!(val & SYS_PTP_STATUS_PTP_MESS_VLD))
- break;
-
- WARN_ON(val & SYS_PTP_STATUS_PTP_OVFL);
-
- /* Retrieve the ts ID and Tx port */
- id = SYS_PTP_STATUS_PTP_MESS_ID_X(val);
- txport = SYS_PTP_STATUS_PTP_MESS_TXPORT_X(val);
- seqid = SYS_PTP_STATUS_PTP_MESS_SEQ_ID(val);
-
- port = ocelot->ports[txport];
-
- spin_lock(&ocelot->ts_id_lock);
- port->ptp_skbs_in_flight--;
- ocelot->ptp_skbs_in_flight--;
- spin_unlock(&ocelot->ts_id_lock);
-
- /* Retrieve its associated skb */
-try_again:
- spin_lock_irqsave(&port->tx_skbs.lock, flags);
-
- skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) {
- if (OCELOT_SKB_CB(skb)->ts_id != id)
- continue;
- __skb_unlink(skb, &port->tx_skbs);
- skb_match = skb;
- break;
- }
-
- spin_unlock_irqrestore(&port->tx_skbs.lock, flags);
-
- if (WARN_ON(!skb_match))
- continue;
-
- if (!ocelot_validate_ptp_skb(skb_match, seqid)) {
- dev_err_ratelimited(ocelot->dev,
- "port %d received stale TX timestamp for seqid %d, discarding\n",
- txport, seqid);
- dev_kfree_skb_any(skb);
- goto try_again;
- }
-
- /* Get the h/w timestamp */
- ocelot_get_hwtimestamp(ocelot, &ts);
-
- /* Set the timestamp into the skb */
- memset(&shhwtstamps, 0, sizeof(shhwtstamps));
- shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
- skb_complete_tx_timestamp(skb_match, &shhwtstamps);
-
- /* Next ts */
- ocelot_write(ocelot, SYS_PTP_NXT_PTP_NXT, SYS_PTP_NXT);
- }
-}
-EXPORT_SYMBOL(ocelot_get_txtstamp);
-
static int ocelot_rx_frame_word(struct ocelot *ocelot, u8 grp, bool ifh,
u32 *rval)
{
}
EXPORT_SYMBOL(ocelot_fdb_del);
-int ocelot_port_fdb_do_dump(const unsigned char *addr, u16 vid,
- bool is_static, void *data)
-{
- struct ocelot_dump_ctx *dump = data;
- u32 portid = NETLINK_CB(dump->cb->skb).portid;
- u32 seq = dump->cb->nlh->nlmsg_seq;
- struct nlmsghdr *nlh;
- struct ndmsg *ndm;
-
- if (dump->idx < dump->cb->args[2])
- goto skip;
-
- nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH,
- sizeof(*ndm), NLM_F_MULTI);
- if (!nlh)
- return -EMSGSIZE;
-
- ndm = nlmsg_data(nlh);
- ndm->ndm_family = AF_BRIDGE;
- ndm->ndm_pad1 = 0;
- ndm->ndm_pad2 = 0;
- ndm->ndm_flags = NTF_SELF;
- ndm->ndm_type = 0;
- ndm->ndm_ifindex = dump->dev->ifindex;
- ndm->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE;
-
- if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, addr))
- goto nla_put_failure;
-
- if (vid && nla_put_u16(dump->skb, NDA_VLAN, vid))
- goto nla_put_failure;
-
- nlmsg_end(dump->skb, nlh);
-
-skip:
- dump->idx++;
- return 0;
-
-nla_put_failure:
- nlmsg_cancel(dump->skb, nlh);
- return -EMSGSIZE;
-}
-EXPORT_SYMBOL(ocelot_port_fdb_do_dump);
-
/* Caller must hold &ocelot->mact_lock */
static int ocelot_mact_read(struct ocelot *ocelot, int port, int row, int col,
struct ocelot_mact_entry *entry)
}
EXPORT_SYMBOL(ocelot_fdb_dump);
-static void ocelot_populate_l2_ptp_trap_key(struct ocelot_vcap_filter *trap)
-{
- trap->key_type = OCELOT_VCAP_KEY_ETYPE;
- *(__be16 *)trap->key.etype.etype.value = htons(ETH_P_1588);
- *(__be16 *)trap->key.etype.etype.mask = htons(0xffff);
-}
-
-static void
-ocelot_populate_ipv4_ptp_event_trap_key(struct ocelot_vcap_filter *trap)
-{
- trap->key_type = OCELOT_VCAP_KEY_IPV4;
- trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
- trap->key.ipv4.proto.mask[0] = 0xff;
- trap->key.ipv4.dport.value = PTP_EV_PORT;
- trap->key.ipv4.dport.mask = 0xffff;
-}
-
-static void
-ocelot_populate_ipv6_ptp_event_trap_key(struct ocelot_vcap_filter *trap)
-{
- trap->key_type = OCELOT_VCAP_KEY_IPV6;
- trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
- trap->key.ipv4.proto.mask[0] = 0xff;
- trap->key.ipv6.dport.value = PTP_EV_PORT;
- trap->key.ipv6.dport.mask = 0xffff;
-}
-
-static void
-ocelot_populate_ipv4_ptp_general_trap_key(struct ocelot_vcap_filter *trap)
-{
- trap->key_type = OCELOT_VCAP_KEY_IPV4;
- trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
- trap->key.ipv4.proto.mask[0] = 0xff;
- trap->key.ipv4.dport.value = PTP_GEN_PORT;
- trap->key.ipv4.dport.mask = 0xffff;
-}
-
-static void
-ocelot_populate_ipv6_ptp_general_trap_key(struct ocelot_vcap_filter *trap)
-{
- trap->key_type = OCELOT_VCAP_KEY_IPV6;
- trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
- trap->key.ipv4.proto.mask[0] = 0xff;
- trap->key.ipv6.dport.value = PTP_GEN_PORT;
- trap->key.ipv6.dport.mask = 0xffff;
-}
-
int ocelot_trap_add(struct ocelot *ocelot, int port,
unsigned long cookie, bool take_ts,
void (*populate)(struct ocelot_vcap_filter *f))
return ocelot_vcap_filter_replace(ocelot, trap);
}
-static int ocelot_l2_ptp_trap_add(struct ocelot *ocelot, int port)
-{
- unsigned long l2_cookie = OCELOT_VCAP_IS2_L2_PTP_TRAP(ocelot);
-
- return ocelot_trap_add(ocelot, port, l2_cookie, true,
- ocelot_populate_l2_ptp_trap_key);
-}
-
-static int ocelot_l2_ptp_trap_del(struct ocelot *ocelot, int port)
-{
- unsigned long l2_cookie = OCELOT_VCAP_IS2_L2_PTP_TRAP(ocelot);
-
- return ocelot_trap_del(ocelot, port, l2_cookie);
-}
-
-static int ocelot_ipv4_ptp_trap_add(struct ocelot *ocelot, int port)
-{
- unsigned long ipv4_gen_cookie = OCELOT_VCAP_IS2_IPV4_GEN_PTP_TRAP(ocelot);
- unsigned long ipv4_ev_cookie = OCELOT_VCAP_IS2_IPV4_EV_PTP_TRAP(ocelot);
- int err;
-
- err = ocelot_trap_add(ocelot, port, ipv4_ev_cookie, true,
- ocelot_populate_ipv4_ptp_event_trap_key);
- if (err)
- return err;
-
- err = ocelot_trap_add(ocelot, port, ipv4_gen_cookie, false,
- ocelot_populate_ipv4_ptp_general_trap_key);
- if (err)
- ocelot_trap_del(ocelot, port, ipv4_ev_cookie);
-
- return err;
-}
-
-static int ocelot_ipv4_ptp_trap_del(struct ocelot *ocelot, int port)
-{
- unsigned long ipv4_gen_cookie = OCELOT_VCAP_IS2_IPV4_GEN_PTP_TRAP(ocelot);
- unsigned long ipv4_ev_cookie = OCELOT_VCAP_IS2_IPV4_EV_PTP_TRAP(ocelot);
- int err;
-
- err = ocelot_trap_del(ocelot, port, ipv4_ev_cookie);
- err |= ocelot_trap_del(ocelot, port, ipv4_gen_cookie);
- return err;
-}
-
-static int ocelot_ipv6_ptp_trap_add(struct ocelot *ocelot, int port)
-{
- unsigned long ipv6_gen_cookie = OCELOT_VCAP_IS2_IPV6_GEN_PTP_TRAP(ocelot);
- unsigned long ipv6_ev_cookie = OCELOT_VCAP_IS2_IPV6_EV_PTP_TRAP(ocelot);
- int err;
-
- err = ocelot_trap_add(ocelot, port, ipv6_ev_cookie, true,
- ocelot_populate_ipv6_ptp_event_trap_key);
- if (err)
- return err;
-
- err = ocelot_trap_add(ocelot, port, ipv6_gen_cookie, false,
- ocelot_populate_ipv6_ptp_general_trap_key);
- if (err)
- ocelot_trap_del(ocelot, port, ipv6_ev_cookie);
-
- return err;
-}
-
-static int ocelot_ipv6_ptp_trap_del(struct ocelot *ocelot, int port)
-{
- unsigned long ipv6_gen_cookie = OCELOT_VCAP_IS2_IPV6_GEN_PTP_TRAP(ocelot);
- unsigned long ipv6_ev_cookie = OCELOT_VCAP_IS2_IPV6_EV_PTP_TRAP(ocelot);
- int err;
-
- err = ocelot_trap_del(ocelot, port, ipv6_ev_cookie);
- err |= ocelot_trap_del(ocelot, port, ipv6_gen_cookie);
- return err;
-}
-
-static int ocelot_setup_ptp_traps(struct ocelot *ocelot, int port,
- bool l2, bool l4)
-{
- int err;
-
- if (l2)
- err = ocelot_l2_ptp_trap_add(ocelot, port);
- else
- err = ocelot_l2_ptp_trap_del(ocelot, port);
- if (err)
- return err;
-
- if (l4) {
- err = ocelot_ipv4_ptp_trap_add(ocelot, port);
- if (err)
- goto err_ipv4;
-
- err = ocelot_ipv6_ptp_trap_add(ocelot, port);
- if (err)
- goto err_ipv6;
- } else {
- err = ocelot_ipv4_ptp_trap_del(ocelot, port);
-
- err |= ocelot_ipv6_ptp_trap_del(ocelot, port);
- }
- if (err)
- return err;
-
- return 0;
-
-err_ipv6:
- ocelot_ipv4_ptp_trap_del(ocelot, port);
-err_ipv4:
- if (l2)
- ocelot_l2_ptp_trap_del(ocelot, port);
- return err;
-}
-
-int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr)
-{
- return copy_to_user(ifr->ifr_data, &ocelot->hwtstamp_config,
- sizeof(ocelot->hwtstamp_config)) ? -EFAULT : 0;
-}
-EXPORT_SYMBOL(ocelot_hwstamp_get);
-
-int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr)
-{
- struct ocelot_port *ocelot_port = ocelot->ports[port];
- bool l2 = false, l4 = false;
- struct hwtstamp_config cfg;
- int err;
-
- if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
- return -EFAULT;
-
- /* Tx type sanity check */
- switch (cfg.tx_type) {
- case HWTSTAMP_TX_ON:
- ocelot_port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
- break;
- case HWTSTAMP_TX_ONESTEP_SYNC:
- /* IFH_REW_OP_ONE_STEP_PTP updates the correctional field, we
- * need to update the origin time.
- */
- ocelot_port->ptp_cmd = IFH_REW_OP_ORIGIN_PTP;
- break;
- case HWTSTAMP_TX_OFF:
- ocelot_port->ptp_cmd = 0;
- break;
- default:
- return -ERANGE;
- }
-
- mutex_lock(&ocelot->ptp_lock);
-
- switch (cfg.rx_filter) {
- case HWTSTAMP_FILTER_NONE:
- break;
- case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
- case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
- case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
- l4 = true;
- break;
- case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
- case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
- case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
- l2 = true;
- break;
- case HWTSTAMP_FILTER_PTP_V2_EVENT:
- case HWTSTAMP_FILTER_PTP_V2_SYNC:
- case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
- l2 = true;
- l4 = true;
- break;
- default:
- mutex_unlock(&ocelot->ptp_lock);
- return -ERANGE;
- }
-
- err = ocelot_setup_ptp_traps(ocelot, port, l2, l4);
- if (err) {
- mutex_unlock(&ocelot->ptp_lock);
- return err;
- }
-
- if (l2 && l4)
- cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
- else if (l2)
- cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
- else if (l4)
- cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
- else
- cfg.rx_filter = HWTSTAMP_FILTER_NONE;
-
- /* Commit back the result & save it */
- memcpy(&ocelot->hwtstamp_config, &cfg, sizeof(cfg));
- mutex_unlock(&ocelot->ptp_lock);
-
- return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
-}
-EXPORT_SYMBOL(ocelot_hwstamp_set);
-
-void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
-{
- int i;
-
- if (sset != ETH_SS_STATS)
- return;
-
- for (i = 0; i < OCELOT_NUM_STATS; i++) {
- if (ocelot->stats_layout[i].name[0] == '\0')
- continue;
-
- memcpy(data + i * ETH_GSTRING_LEN, ocelot->stats_layout[i].name,
- ETH_GSTRING_LEN);
- }
-}
-EXPORT_SYMBOL(ocelot_get_strings);
-
-/* Caller must hold &ocelot->stats_lock */
-static int ocelot_port_update_stats(struct ocelot *ocelot, int port)
-{
- unsigned int idx = port * OCELOT_NUM_STATS;
- struct ocelot_stats_region *region;
- int err, j;
-
- /* Configure the port to read the stats from */
- ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port), SYS_STAT_CFG);
-
- list_for_each_entry(region, &ocelot->stats_regions, node) {
- err = ocelot_bulk_read(ocelot, region->base, region->buf,
- region->count);
- if (err)
- return err;
-
- for (j = 0; j < region->count; j++) {
- u64 *stat = &ocelot->stats[idx + j];
- u64 val = region->buf[j];
-
- if (val < (*stat & U32_MAX))
- *stat += (u64)1 << 32;
-
- *stat = (*stat & ~(u64)U32_MAX) + val;
- }
-
- idx += region->count;
- }
-
- return err;
-}
-
-static void ocelot_check_stats_work(struct work_struct *work)
-{
- struct delayed_work *del_work = to_delayed_work(work);
- struct ocelot *ocelot = container_of(del_work, struct ocelot,
- stats_work);
- int i, err;
-
- spin_lock(&ocelot->stats_lock);
- for (i = 0; i < ocelot->num_phys_ports; i++) {
- err = ocelot_port_update_stats(ocelot, i);
- if (err)
- break;
- }
- spin_unlock(&ocelot->stats_lock);
-
- if (err)
- dev_err(ocelot->dev, "Error %d updating ethtool stats\n", err);
-
- queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
- OCELOT_STATS_CHECK_DELAY);
-}
-
-void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
-{
- int i, err;
-
- spin_lock(&ocelot->stats_lock);
-
- /* check and update now */
- err = ocelot_port_update_stats(ocelot, port);
-
- /* Copy all supported counters */
- for (i = 0; i < OCELOT_NUM_STATS; i++) {
- int index = port * OCELOT_NUM_STATS + i;
-
- if (ocelot->stats_layout[i].name[0] == '\0')
- continue;
-
- *data++ = ocelot->stats[index];
- }
-
- spin_unlock(&ocelot->stats_lock);
-
- if (err)
- dev_err(ocelot->dev, "Error %d updating ethtool stats\n", err);
-}
-EXPORT_SYMBOL(ocelot_get_ethtool_stats);
-
-int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
-{
- int i, num_stats = 0;
-
- if (sset != ETH_SS_STATS)
- return -EOPNOTSUPP;
-
- for (i = 0; i < OCELOT_NUM_STATS; i++)
- if (ocelot->stats_layout[i].name[0] != '\0')
- num_stats++;
-
- return num_stats;
-}
-EXPORT_SYMBOL(ocelot_get_sset_count);
-
-static int ocelot_prepare_stats_regions(struct ocelot *ocelot)
-{
- struct ocelot_stats_region *region = NULL;
- unsigned int last;
- int i;
-
- INIT_LIST_HEAD(&ocelot->stats_regions);
-
- for (i = 0; i < OCELOT_NUM_STATS; i++) {
- if (ocelot->stats_layout[i].name[0] == '\0')
- continue;
-
- if (region && ocelot->stats_layout[i].reg == last + 4) {
- region->count++;
- } else {
- region = devm_kzalloc(ocelot->dev, sizeof(*region),
- GFP_KERNEL);
- if (!region)
- return -ENOMEM;
-
- region->base = ocelot->stats_layout[i].reg;
- region->count = 1;
- list_add_tail(®ion->node, &ocelot->stats_regions);
- }
-
- last = ocelot->stats_layout[i].reg;
- }
-
- list_for_each_entry(region, &ocelot->stats_regions, node) {
- region->buf = devm_kcalloc(ocelot->dev, region->count,
- sizeof(*region->buf), GFP_KERNEL);
- if (!region->buf)
- return -ENOMEM;
- }
-
- return 0;
-}
-
-int ocelot_get_ts_info(struct ocelot *ocelot, int port,
- struct ethtool_ts_info *info)
-{
- info->phc_index = ocelot->ptp_clock ?
- ptp_clock_index(ocelot->ptp_clock) : -1;
- if (info->phc_index == -1) {
- info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE |
- SOF_TIMESTAMPING_RX_SOFTWARE |
- SOF_TIMESTAMPING_SOFTWARE;
- return 0;
- }
- info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE |
- SOF_TIMESTAMPING_RX_SOFTWARE |
- SOF_TIMESTAMPING_SOFTWARE |
- SOF_TIMESTAMPING_TX_HARDWARE |
- SOF_TIMESTAMPING_RX_HARDWARE |
- SOF_TIMESTAMPING_RAW_HARDWARE;
- info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON) |
- BIT(HWTSTAMP_TX_ONESTEP_SYNC);
- info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
- BIT(HWTSTAMP_FILTER_PTP_V2_EVENT) |
- BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
- BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT);
-
- return 0;
-}
-EXPORT_SYMBOL(ocelot_get_ts_info);
-
static u32 ocelot_get_bond_mask(struct ocelot *ocelot, struct net_device *bond)
{
u32 mask = 0;
/* The logical port number of a LAG is equal to the lowest numbered physical
* port ID present in that LAG. It may change if that port ever leaves the LAG.
*/
-static int ocelot_bond_get_id(struct ocelot *ocelot, struct net_device *bond)
+int ocelot_bond_get_id(struct ocelot *ocelot, struct net_device *bond)
{
int bond_mask = ocelot_get_bond_mask(ocelot, bond);
return __ffs(bond_mask);
}
+EXPORT_SYMBOL_GPL(ocelot_bond_get_id);
+/* Returns the mask of user ports assigned to this DSA tag_8021q CPU port.
+ * Note that when CPU ports are in a LAG, the user ports are assigned to the
+ * 'primary' CPU port, the one whose physical port number gives the logical
+ * port number of the LAG.
+ *
+ * We leave PGID_SRC poorly configured for the 'secondary' CPU port in the LAG
+ * (to which no user port is assigned), but it appears that forwarding from
+ * this secondary CPU port looks at the PGID_SRC associated with the logical
+ * port ID that it's assigned to, which *is* configured properly.
+ */
static u32 ocelot_dsa_8021q_cpu_assigned_ports(struct ocelot *ocelot,
struct ocelot_port *cpu)
{
mask |= BIT(port);
}
+ if (cpu->bond)
+ mask &= ~ocelot_get_bond_mask(ocelot, cpu->bond);
+
return mask;
}
+/* Returns the DSA tag_8021q CPU port that the given port is assigned to,
+ * or the bit mask of CPU ports if said CPU port is in a LAG.
+ */
u32 ocelot_port_assigned_dsa_8021q_cpu_mask(struct ocelot *ocelot, int port)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
if (!cpu_port)
return 0;
+ if (cpu_port->bond)
+ return ocelot_get_bond_mask(ocelot, cpu_port->bond);
+
return BIT(cpu_port->index);
}
EXPORT_SYMBOL_GPL(ocelot_port_assigned_dsa_8021q_cpu_mask);
ocelot_write_rix(ocelot, pgid_cpu, ANA_PGID_PGID, PGID_CPU);
}
-void ocelot_port_assign_dsa_8021q_cpu(struct ocelot *ocelot, int port,
- int cpu)
+void ocelot_port_setup_dsa_8021q_cpu(struct ocelot *ocelot, int cpu)
{
struct ocelot_port *cpu_port = ocelot->ports[cpu];
u16 vid;
mutex_lock(&ocelot->fwd_domain_lock);
- ocelot->ports[port]->dsa_8021q_cpu = cpu_port;
-
- if (!cpu_port->is_dsa_8021q_cpu) {
- cpu_port->is_dsa_8021q_cpu = true;
+ cpu_port->is_dsa_8021q_cpu = true;
- for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++)
- ocelot_vlan_member_add(ocelot, cpu, vid, true);
+ for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++)
+ ocelot_vlan_member_add(ocelot, cpu, vid, true);
- ocelot_update_pgid_cpu(ocelot);
- }
-
- ocelot_apply_bridge_fwd_mask(ocelot, true);
+ ocelot_update_pgid_cpu(ocelot);
mutex_unlock(&ocelot->fwd_domain_lock);
}
-EXPORT_SYMBOL_GPL(ocelot_port_assign_dsa_8021q_cpu);
+EXPORT_SYMBOL_GPL(ocelot_port_setup_dsa_8021q_cpu);
-void ocelot_port_unassign_dsa_8021q_cpu(struct ocelot *ocelot, int port)
+void ocelot_port_teardown_dsa_8021q_cpu(struct ocelot *ocelot, int cpu)
{
- struct ocelot_port *cpu_port = ocelot->ports[port]->dsa_8021q_cpu;
- bool keep = false;
+ struct ocelot_port *cpu_port = ocelot->ports[cpu];
u16 vid;
- int p;
mutex_lock(&ocelot->fwd_domain_lock);
- ocelot->ports[port]->dsa_8021q_cpu = NULL;
+ cpu_port->is_dsa_8021q_cpu = false;
- for (p = 0; p < ocelot->num_phys_ports; p++) {
- if (!ocelot->ports[p])
- continue;
+ for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++)
+ ocelot_vlan_member_del(ocelot, cpu_port->index, vid);
- if (ocelot->ports[p]->dsa_8021q_cpu == cpu_port) {
- keep = true;
- break;
- }
- }
+ ocelot_update_pgid_cpu(ocelot);
- if (!keep) {
- cpu_port->is_dsa_8021q_cpu = false;
+ mutex_unlock(&ocelot->fwd_domain_lock);
+}
+EXPORT_SYMBOL_GPL(ocelot_port_teardown_dsa_8021q_cpu);
- for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++)
- ocelot_vlan_member_del(ocelot, cpu_port->index, vid);
+void ocelot_port_assign_dsa_8021q_cpu(struct ocelot *ocelot, int port,
+ int cpu)
+{
+ struct ocelot_port *cpu_port = ocelot->ports[cpu];
- ocelot_update_pgid_cpu(ocelot);
- }
+ mutex_lock(&ocelot->fwd_domain_lock);
+
+ ocelot->ports[port]->dsa_8021q_cpu = cpu_port;
+ ocelot_apply_bridge_fwd_mask(ocelot, true);
+
+ mutex_unlock(&ocelot->fwd_domain_lock);
+}
+EXPORT_SYMBOL_GPL(ocelot_port_assign_dsa_8021q_cpu);
+
+void ocelot_port_unassign_dsa_8021q_cpu(struct ocelot *ocelot, int port)
+{
+ mutex_lock(&ocelot->fwd_domain_lock);
+ ocelot->ports[port]->dsa_8021q_cpu = NULL;
ocelot_apply_bridge_fwd_mask(ocelot, true);
mutex_unlock(&ocelot->fwd_domain_lock);
int ocelot_port_lag_join(struct ocelot *ocelot, int port,
struct net_device *bond,
- struct netdev_lag_upper_info *info)
+ struct netdev_lag_upper_info *info,
+ struct netlink_ext_ack *extack)
{
- if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH)
+ if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Can only offload LAG using hash TX type");
return -EOPNOTSUPP;
+ }
mutex_lock(&ocelot->fwd_domain_lock);
int ocelot_init(struct ocelot *ocelot)
{
- char queue_name[32];
int i, ret;
u32 port;
}
}
- ocelot->stats = devm_kcalloc(ocelot->dev,
- ocelot->num_phys_ports * OCELOT_NUM_STATS,
- sizeof(u64), GFP_KERNEL);
- if (!ocelot->stats)
- return -ENOMEM;
-
- spin_lock_init(&ocelot->stats_lock);
mutex_init(&ocelot->ptp_lock);
mutex_init(&ocelot->mact_lock);
mutex_init(&ocelot->fwd_domain_lock);
mutex_init(&ocelot->tas_lock);
spin_lock_init(&ocelot->ptp_clock_lock);
spin_lock_init(&ocelot->ts_id_lock);
- snprintf(queue_name, sizeof(queue_name), "%s-stats",
- dev_name(ocelot->dev));
- ocelot->stats_queue = create_singlethread_workqueue(queue_name);
- if (!ocelot->stats_queue)
- return -ENOMEM;
ocelot->owq = alloc_ordered_workqueue("ocelot-owq", 0);
- if (!ocelot->owq) {
- destroy_workqueue(ocelot->stats_queue);
+ if (!ocelot->owq)
return -ENOMEM;
+
+ ret = ocelot_stats_init(ocelot);
+ if (ret) {
+ destroy_workqueue(ocelot->owq);
+ return ret;
}
INIT_LIST_HEAD(&ocelot->multicast);
ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL(6),
ANA_CPUQ_8021_CFG, i);
- ret = ocelot_prepare_stats_regions(ocelot);
- if (ret) {
- destroy_workqueue(ocelot->stats_queue);
- destroy_workqueue(ocelot->owq);
- return ret;
- }
-
- INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats_work);
- queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
- OCELOT_STATS_CHECK_DELAY);
-
return 0;
}
EXPORT_SYMBOL(ocelot_init);
void ocelot_deinit(struct ocelot *ocelot)
{
- cancel_delayed_work(&ocelot->stats_work);
- destroy_workqueue(ocelot->stats_queue);
+ ocelot_stats_deinit(ocelot);
destroy_workqueue(ocelot->owq);
}
EXPORT_SYMBOL(ocelot_deinit);
stmmac_reset_queues_param(priv);
+ if (priv->plat->serdes_powerup) {
+ ret = priv->plat->serdes_powerup(dev, priv->plat->bsp_priv);
+ if (ret < 0) {
+ netdev_err(priv->dev, "%s: Serdes powerup failed\n",
+ __func__);
+ goto init_error;
+ }
+ }
+
ret = stmmac_hw_setup(dev, true);
if (ret < 0) {
netdev_err(priv->dev, "%s: Hw setup failed\n", __func__);
/* Disable the MAC Rx/Tx */
stmmac_mac_set(priv, priv->ioaddr, false);
+ /* Powerdown Serdes if there is */
+ if (priv->plat->serdes_powerdown)
+ priv->plat->serdes_powerdown(dev, priv->plat->bsp_priv);
+
netif_carrier_off(dev);
stmmac_release_ptp(priv);
buf1_len = stmmac_rx_buf1_len(priv, p, status, len);
len += buf1_len;
- /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
- * Type frames (LLC/LLC-SNAP)
- *
- * llc_snap is never checked in GMAC >= 4, so this ACS
- * feature is always disabled and packets need to be
- * stripped manually.
- */
- if (likely(!(status & rx_not_ls)) &&
- (likely(priv->synopsys_id >= DWMAC_CORE_4_00) ||
- unlikely(status != llc_snap))) {
+ /* ACS is disabled; strip manually. */
+ if (likely(!(status & rx_not_ls))) {
buf1_len -= ETH_FCS_LEN;
len -= ETH_FCS_LEN;
}
buf2_len = stmmac_rx_buf2_len(priv, p, status, len);
len += buf2_len;
- /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
- * Type frames (LLC/LLC-SNAP)
- *
- * llc_snap is never checked in GMAC >= 4, so this ACS
- * feature is always disabled and packets need to be
- * stripped manually.
- */
- if (likely(!(status & rx_not_ls)) &&
- (likely(priv->synopsys_id >= DWMAC_CORE_4_00) ||
- unlikely(status != llc_snap))) {
+ /* ACS is disabled; strip manually. */
+ if (likely(!(status & rx_not_ls))) {
if (buf2_len) {
buf2_len -= ETH_FCS_LEN;
len -= ETH_FCS_LEN;
spin_lock_init(&ch->lock);
if (queue < priv->plat->rx_queues_to_use) {
- netif_napi_add(dev, &ch->rx_napi, stmmac_napi_poll_rx,
- NAPI_POLL_WEIGHT);
+ netif_napi_add(dev, &ch->rx_napi, stmmac_napi_poll_rx);
}
if (queue < priv->plat->tx_queues_to_use) {
netif_napi_add_tx(dev, &ch->tx_napi,
if (queue < priv->plat->rx_queues_to_use &&
queue < priv->plat->tx_queues_to_use) {
netif_napi_add(dev, &ch->rxtx_napi,
- stmmac_napi_poll_rxtx,
- NAPI_POLL_WEIGHT);
+ stmmac_napi_poll_rxtx);
}
}
}
goto error_netdev_register;
}
- if (priv->plat->serdes_powerup) {
- ret = priv->plat->serdes_powerup(ndev,
- priv->plat->bsp_priv);
-
- if (ret < 0)
- goto error_serdes_powerup;
- }
-
#ifdef CONFIG_DEBUG_FS
stmmac_init_fs(ndev);
#endif
return ret;
- error_serdes_powerup:
- unregister_netdev(ndev);
error_netdev_register:
phylink_destroy(priv->phylink);
error_xpcs_setup:
phydev->suspended_by_mdio_bus = 0;
- /* If we manged to get here with the PHY state machine in a state neither
- * PHY_HALTED nor PHY_READY this is an indication that something went wrong
- * and we should most likely be using MAC managed PM and we are not.
+ /* If we managed to get here with the PHY state machine in a state
+ * neither PHY_HALTED, PHY_READY nor PHY_UP, this is an indication
+ * that something went wrong and we should most likely be using
+ * MAC managed PM, but we are not.
*/
- WARN_ON(phydev->state != PHY_HALTED && phydev->state != PHY_READY);
+ WARN_ON(phydev->state != PHY_HALTED && phydev->state != PHY_READY &&
+ phydev->state != PHY_UP);
ret = phy_init_hw(phydev);
if (ret < 0)
if (!fixup)
return -ENOMEM;
- strlcpy(fixup->bus_id, bus_id, sizeof(fixup->bus_id));
+ strscpy(fixup->bus_id, bus_id, sizeof(fixup->bus_id));
fixup->phy_uid = phy_uid;
fixup->phy_uid_mask = phy_uid_mask;
fixup->run = run;
rcu_assign_pointer(tfile->tun, tun);
}
- netif_carrier_on(tun->dev);
+ if (ifr->ifr_flags & IFF_NO_CARRIER)
+ netif_carrier_off(tun->dev);
+ else
+ netif_carrier_on(tun->dev);
/* Make sure persistent devices do not get stuck in
* xoff state.
* This is needed because we never checked for invalid flags on
* TUNSETIFF.
*/
- return put_user(IFF_TUN | IFF_TAP | TUN_FEATURES,
- (unsigned int __user*)argp);
+ return put_user(IFF_TUN | IFF_TAP | IFF_NO_CARRIER |
+ TUN_FEATURES, (unsigned int __user*)argp);
} else if (cmd == TUNSETQUEUE) {
return tun_set_queue(file, &ifr);
} else if (cmd == SIOCGSKNS) {
{
struct tun_struct *tun = netdev_priv(dev);
- strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
- strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strscpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strscpy(info->version, DRV_VERSION, sizeof(info->version));
switch (tun->flags & TUN_TYPE_MASK) {
case IFF_TUN:
- strlcpy(info->bus_info, "tun", sizeof(info->bus_info));
+ strscpy(info->bus_info, "tun", sizeof(info->bus_info));
break;
case IFF_TAP:
- strlcpy(info->bus_info, "tap", sizeof(info->bus_info));
+ strscpy(info->bus_info, "tap", sizeof(info->bus_info));
break;
}
}
{
struct usbnet *dev = netdev_priv(net);
- strlcpy (info->driver, dev->driver_name, sizeof info->driver);
- strlcpy (info->fw_version, dev->driver_info->description,
- sizeof info->fw_version);
+ strscpy(info->driver, dev->driver_name, sizeof(info->driver));
+ strscpy(info->fw_version, dev->driver_info->description,
+ sizeof(info->fw_version));
usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info);
}
EXPORT_SYMBOL_GPL(usbnet_get_drvinfo);
struct usbnet *dev;
struct usb_device *xdev;
struct net_device *net;
+ struct urb *urb;
dev = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
net = dev->net;
unregister_netdev (net);
- usb_scuttle_anchored_urbs(&dev->deferred);
+ while ((urb = usb_get_from_anchor(&dev->deferred))) {
+ dev_kfree_skb(urb->context);
+ kfree(urb->sg);
+ usb_free_urb(urb);
+ }
if (dev->driver_info->unbind)
dev->driver_info->unbind(dev, intf);
if (!kn)
goto out;
+ if (kernfs_type(kn) != KERNFS_DIR)
+ goto put;
+
rcu_read_lock();
cgrp = rcu_dereference(*(void __rcu __force **)&kn->priv);
cgrp = NULL;
rcu_read_unlock();
-
+ put:
kernfs_put(kn);
out:
return cgrp;
return ERR_CAST(css);
cgrp = css->cgroup;
- if (!cgroup_on_dfl(cgrp)) {
- cgroup_put(cgrp);
- return ERR_PTR(-EBADF);
- }
-
return cgrp;
}
if (eht_oper && (eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) {
struct cfg80211_chan_def eht_chandef = *chandef;
- ieee80211_chandef_eht_oper(sdata, eht_oper,
+ ieee80211_chandef_eht_oper(eht_oper,
eht_chandef.width ==
NL80211_CHAN_WIDTH_160,
false, &eht_chandef);
static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb,
struct ieee80211_supported_band *sband,
+ enum ieee80211_smps_mode smps_mode,
ieee80211_conn_flags_t conn_flags)
{
u8 *pos, *pre_he_pos;
/* trim excess if any */
skb_trim(skb, skb->len - (pre_he_pos + he_cap_size - pos));
- ieee80211_ie_build_he_6ghz_cap(sdata, skb);
+ ieee80211_ie_build_he_6ghz_cap(sdata, smps_mode, skb);
}
static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata,
eht_cap_size =
2 + 1 + sizeof(eht_cap->eht_cap_elem) +
ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem,
- &eht_cap->eht_cap_elem) +
+ &eht_cap->eht_cap_elem,
+ false) +
ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0],
eht_cap->eht_cap_elem.phy_cap_info);
pos = skb_put(skb, eht_cap_size);
- ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, pos + eht_cap_size);
+ ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, pos + eht_cap_size,
+ false);
}
static void ieee80211_assoc_add_rates(struct sk_buff *skb,
offset);
if (!(assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_HE)) {
- ieee80211_add_he_ie(sdata, skb, sband,
+ ieee80211_add_he_ie(sdata, skb, sband, smps_mode,
assoc_data->link[link_id].conn_flags);
ADD_PRESENT_EXT_ELEM(WLAN_EID_EXT_HE_CAPABILITY);
}
ml_elem = skb_put(skb, sizeof(*ml_elem));
ml_elem->control =
cpu_to_le16(IEEE80211_ML_CONTROL_TYPE_BASIC |
- IEEE80211_MLC_BASIC_PRES_EML_CAPA |
IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP);
common = skb_put(skb, sizeof(*common));
common->len = sizeof(*common) +
- 2 + /* EML capabilities */
2; /* MLD capa/ops */
memcpy(common->mld_mac_addr, sdata->vif.addr, ETH_ALEN);
- skb_put_data(skb, &eml_capa, sizeof(eml_capa));
+
+ /* add EML_CAPA only if needed, see Draft P802.11be_D2.1, 35.3.17 */
+ if (eml_capa &
+ cpu_to_le16((IEEE80211_EML_CAP_EMLSR_SUPP |
+ IEEE80211_EML_CAP_EMLMR_SUPPORT))) {
+ common->len += 2; /* EML capabilities */
+ ml_elem->control |=
+ cpu_to_le16(IEEE80211_MLC_BASIC_PRES_EML_CAPA);
+ skb_put_data(skb, &eml_capa, sizeof(eml_capa));
+ }
/* need indication from userspace to support this */
mld_capa_ops &= ~cpu_to_le16(IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP);
skb_put_data(skb, &mld_capa_ops, sizeof(mld_capa_ops));
IEEE80211_QUEUE_STOP_REASON_CSA);
mutex_unlock(&local->mtx);
- cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chandef,
+ cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chandef, 0,
csa_ie.count, csa_ie.mode);
if (local->ops->channel_switch) {
ieee80211_sta_handle_tspec_ac_params(sdata);
}
+void ieee80211_mgd_set_link_qos_params(struct ieee80211_link_data *link)
+{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ struct ieee80211_tx_queue_params *params = link->tx_conf;
+ u8 ac;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ mlme_dbg(sdata,
+ "WMM AC=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n",
+ ac, params[ac].acm,
+ params[ac].aifs, params[ac].cw_min, params[ac].cw_max,
+ params[ac].txop, params[ac].uapsd,
+ ifmgd->tx_tspec[ac].downgraded);
+ if (!ifmgd->tx_tspec[ac].downgraded &&
+ drv_conf_tx(local, link, ac, ¶ms[ac]))
+ link_err(link,
+ "failed to set TX queue parameters for AC %d\n",
+ ac);
+ }
+}
+
/* MLME */
static bool
ieee80211_sta_wmm_params(struct ieee80211_local *local,
}
}
- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
- mlme_dbg(sdata,
- "WMM AC=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n",
- ac, params[ac].acm,
- params[ac].aifs, params[ac].cw_min, params[ac].cw_max,
- params[ac].txop, params[ac].uapsd,
- ifmgd->tx_tspec[ac].downgraded);
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
link->tx_conf[ac] = params[ac];
- if (!ifmgd->tx_tspec[ac].downgraded &&
- drv_conf_tx(local, link, ac, ¶ms[ac]))
- link_err(link,
- "failed to set TX queue parameters for AC %d\n",
- ac);
- }
+
+ ieee80211_mgd_set_link_qos_params(link);
/* enable WMM or activate new settings */
link->conf->qos = true;
.len = elem_len,
.bss = cbss,
.link_id = link == &sdata->deflink ? -1 : link->link_id,
+ .from_ap = true,
};
bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
bool is_s1g = cbss->channel->band == NL80211_BAND_S1GHZ;
if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
(!elems->he_cap || !elems->he_operation)) {
- mutex_unlock(&sdata->local->sta_mtx);
sdata_info(sdata,
"HE AP is missing HE capability/operation\n");
ret = false;
bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
bool is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ;
struct ieee80211_bss *bss = (void *)cbss->priv;
+ struct ieee80211_elems_parse_params parse_params = {
+ .bss = cbss,
+ .link_id = -1,
+ .from_ap = true,
+ };
struct ieee802_11_elems *elems;
const struct cfg80211_bss_ies *ies;
int ret;
rcu_read_lock();
ies = rcu_dereference(cbss->ies);
- elems = ieee802_11_parse_elems(ies->data, ies->len, false, cbss);
+ parse_params.start = ies->data;
+ parse_params.len = ies->len;
+ elems = ieee802_11_parse_elems_full(&parse_params);
if (!elems) {
rcu_read_unlock();
return -ENOMEM;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
u16 capab_info, status_code, aid;
+ struct ieee80211_elems_parse_params parse_params = {
+ .bss = NULL,
+ .link_id = -1,
+ .from_ap = true,
+ };
struct ieee802_11_elems *elems;
int ac;
const u8 *elem_start;
return;
elem_len = len - (elem_start - (u8 *)mgmt);
- elems = ieee802_11_parse_elems(elem_start, elem_len, false, NULL);
+ parse_params.start = elem_start;
+ parse_params.len = elem_len;
+ elems = ieee802_11_parse_elems_full(&parse_params);
if (!elems)
goto notify_driver;
resp.req_ies = ifmgd->assoc_req_ies;
resp.req_ies_len = ifmgd->assoc_req_ies_len;
if (sdata->vif.valid_links)
- resp.ap_mld_addr = assoc_data->ap_addr;
+ resp.ap_mld_addr = sdata->vif.cfg.ap_addr;
cfg80211_rx_assoc_resp(sdata->dev, &resp);
notify_driver:
drv_mgd_complete_tx(sdata->local, sdata, &info);
u32 ncrc = 0;
u8 *bssid, *variable = mgmt->u.beacon.variable;
u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN];
+ struct ieee80211_elems_parse_params parse_params = {
+ .link_id = -1,
+ .from_ap = true,
+ };
sdata_assert_lock(sdata);
if (baselen > len)
return;
+ parse_params.start = variable;
+ parse_params.len = len - baselen;
+
rcu_read_lock();
chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
if (!chanctx_conf) {
if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
!WARN_ON(sdata->vif.valid_links) &&
ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->link[0].bss)) {
- elems = ieee802_11_parse_elems(variable, len - baselen, false,
- ifmgd->assoc_data->link[0].bss);
+ parse_params.bss = ifmgd->assoc_data->link[0].bss;
+ elems = ieee802_11_parse_elems_full(&parse_params);
if (!elems)
return;
*/
if (!ieee80211_is_s1g_beacon(hdr->frame_control))
ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
- elems = ieee802_11_parse_elems_crc(variable, len - baselen,
- false, care_about_ies, ncrc,
- link->u.mgd.bss);
+ parse_params.bss = link->u.mgd.bss;
+ parse_params.filter = care_about_ies;
+ parse_params.crc = ncrc;
+ elems = ieee802_11_parse_elems_full(&parse_params);
if (!elems)
return;
ncrc = elems->crc;
mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);
- if (WARN_ON(!sta))
+ if (WARN_ON(!sta)) {
+ mutex_unlock(&local->sta_mtx);
goto free;
+ }
link_sta = rcu_dereference_protected(sta->link[link->link_id],
lockdep_is_held(&local->sta_mtx));
- if (WARN_ON(!link_sta))
+ if (WARN_ON(!link_sta)) {
+ mutex_unlock(&local->sta_mtx);
goto free;
+ }
changed |= ieee80211_recalc_twt_req(link, link_sta, elems);
sdata_lock(sdata);
+ if (rx_status->link_valid) {
+ link = sdata_dereference(sdata->link[rx_status->link_id],
+ sdata);
+ if (!link)
+ goto out;
+ }
+
switch (fc & IEEE80211_FCTL_STYPE) {
case IEEE80211_STYPE_BEACON:
ieee80211_rx_mgmt_beacon(link, (void *)mgmt,
}
break;
}
+out:
sdata_unlock(sdata);
}
if (sdata->u.mgd.assoc_data)
ether_addr_copy(link->conf->addr,
sdata->u.mgd.assoc_data->link[link_id].addr);
+ else if (!is_valid_ether_addr(link->conf->addr))
+ eth_random_addr(link->conf->addr);
}
/* scan finished notification */
goto out_err;
}
- if (mlo && !is_valid_ether_addr(link->conf->addr))
- eth_random_addr(link->conf->addr);
-
if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) {
err = -EINVAL;
goto out_err;
}
}
+ /* FIXME: no support for 4-addr MLO yet */
+ if (sdata->u.mgd.use_4addr && req->link_id >= 0)
+ return -EOPNOTSUPP;
+
assoc_data = kzalloc(size, GFP_KERNEL);
if (!assoc_data)
return -ENOMEM;
return TX_CONTINUE;
}
+static struct ieee80211_key *
+ieee80211_select_link_key(struct ieee80211_tx_data *tx)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+ enum {
+ USE_NONE,
+ USE_MGMT_KEY,
+ USE_MCAST_KEY,
+ } which_key = USE_NONE;
+ struct ieee80211_link_data *link;
+ unsigned int link_id;
+
+ if (ieee80211_is_group_privacy_action(tx->skb))
+ which_key = USE_MCAST_KEY;
+ else if (ieee80211_is_mgmt(hdr->frame_control) &&
+ is_multicast_ether_addr(hdr->addr1) &&
+ ieee80211_is_robust_mgmt_frame(tx->skb))
+ which_key = USE_MGMT_KEY;
+ else if (is_multicast_ether_addr(hdr->addr1))
+ which_key = USE_MCAST_KEY;
+ else
+ return NULL;
+
+ link_id = u32_get_bits(info->control.flags, IEEE80211_TX_CTRL_MLO_LINK);
+ if (link_id == IEEE80211_LINK_UNSPECIFIED) {
+ link = &tx->sdata->deflink;
+ } else {
+ link = rcu_dereference(tx->sdata->link[link_id]);
+ if (!link)
+ return NULL;
+ }
+
+ switch (which_key) {
+ case USE_NONE:
+ break;
+ case USE_MGMT_KEY:
+ return rcu_dereference(link->default_mgmt_key);
+ case USE_MCAST_KEY:
+ return rcu_dereference(link->default_multicast_key);
+ }
+
+ return NULL;
+}
+
static ieee80211_tx_result debug_noinline
ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
{
if (tx->sta &&
(key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx])))
tx->key = key;
- else if (ieee80211_is_group_privacy_action(tx->skb) &&
- (key = rcu_dereference(tx->sdata->deflink.default_multicast_key)))
- tx->key = key;
- else if (ieee80211_is_mgmt(hdr->frame_control) &&
- is_multicast_ether_addr(hdr->addr1) &&
- ieee80211_is_robust_mgmt_frame(tx->skb) &&
- (key = rcu_dereference(tx->sdata->deflink.default_mgmt_key)))
- tx->key = key;
- else if (is_multicast_ether_addr(hdr->addr1) &&
- (key = rcu_dereference(tx->sdata->deflink.default_multicast_key)))
+ else if ((key = ieee80211_select_link_key(tx)))
tx->key = key;
else if (!is_multicast_ether_addr(hdr->addr1) &&
(key = rcu_dereference(tx->sdata->default_unicast_key)))
goto free;
}
memcpy(hdr.addr2, link->conf->addr, ETH_ALEN);
- } else if (link_id == IEEE80211_LINK_UNSPECIFIED) {
+ } else if (link_id == IEEE80211_LINK_UNSPECIFIED ||
+ (sta && sta->sta.mlo)) {
memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
} else {
struct ieee80211_bss_conf *conf;
!test_sta_flag(tx.sta, WLAN_STA_AUTHORIZED) &&
(!(info->control.flags &
IEEE80211_TX_CTRL_PORT_CTRL_PROTO) ||
- !ether_addr_equal(tx.sdata->vif.addr,
- hdr->addr2)))) {
+ !ieee80211_is_our_addr(tx.sdata, hdr->addr2,
+ NULL)))) {
I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
ieee80211_free_txskb(&local->hw, skb);
goto begin;
rate_control_get_rate(sdata, NULL, &txrc);
info->control.vif = vif;
+ info->control.flags |= u32_encode_bits(link->link_id,
+ IEEE80211_TX_CTRL_MLO_LINK);
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT |
IEEE80211_TX_CTL_ASSIGN_SEQ |
IEEE80211_TX_CTL_FIRST_FRAGMENT;
skb_reset_network_header(skb);
skb_reset_mac_header(skb);
+ if (local->hw.queues < IEEE80211_NUM_ACS)
+ goto start_xmit;
+
/* update QoS header to prioritize control port frames if possible,
* priorization also happens for control port frames send over
* AF_PACKET
}
rcu_read_unlock();
+ start_xmit:
/* mutex lock is only needed for incrementing the cookie counter */
mutex_lock(&local->mtx);
local_bh_disable();
spin_lock(&fq->lock);
+ sdata->vif.txqs_stopped[ac] = false;
+
if (!test_bit(SDATA_STATE_RUNNING, &sdata->state))
goto out;
if (sdata->vif.type == NL80211_IFTYPE_AP)
ps = &sdata->bss->ps;
- sdata->vif.txqs_stopped[ac] = false;
-
list_for_each_entry_rcu(sta, &local->sta_list, list) {
if (sdata != sta->sdata)
continue;
}
EXPORT_SYMBOL(ieee80211_queue_delayed_work);
-static void ieee80211_parse_extension_element(u32 *crc,
- const struct element *elem,
- struct ieee802_11_elems *elems)
+static void
+ieee80211_parse_extension_element(u32 *crc,
+ const struct element *elem,
+ struct ieee802_11_elems *elems,
+ struct ieee80211_elems_parse_params *params)
{
const void *data = elem->data + 1;
u8 len;
break;
case WLAN_EID_EXT_EHT_CAPABILITY:
if (ieee80211_eht_capa_size_ok(elems->he_cap,
- data, len)) {
+ data, len,
+ params->from_ap)) {
elems->eht_cap = data;
elems->eht_cap_len = len;
}
case WLAN_EID_EXTENSION:
ieee80211_parse_extension_element(calc_crc ?
&crc : NULL,
- elem, elems);
+ elem, elems, params);
break;
case WLAN_EID_S1G_CAPABILITIES:
if (elen >= sizeof(*elems->s1g_capab))
cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band),
IEEE80211_CHAN_NO_HE |
IEEE80211_CHAN_NO_EHT)) {
- pos = ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, end);
+ pos = ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, end,
+ sdata->vif.type == NL80211_IFTYPE_AP);
if (!pos)
goto out_err;
}
if (link)
ieee80211_assign_chanctx(local, sdata, link);
}
- sdata_unlock(sdata);
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
&sdata->deflink.tx_conf[i]);
break;
}
+ sdata_unlock(sdata);
/* common change flags for all interface types */
changed = BSS_CHANGED_ERP_CTS_PROT |
}
/* APs are now beaconing, add back stations */
- mutex_lock(&local->sta_mtx);
- list_for_each_entry(sta, &local->sta_list, list) {
- enum ieee80211_sta_state state;
-
- if (!sta->uploaded)
- continue;
-
- if (sta->sdata->vif.type != NL80211_IFTYPE_AP &&
- sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (!ieee80211_sdata_running(sdata))
continue;
- for (state = IEEE80211_STA_NOTEXIST;
- state < sta->sta_state; state++)
- WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
- state + 1));
+ sdata_lock(sdata);
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_AP:
+ ieee80211_reconfig_stations(sdata);
+ break;
+ default:
+ break;
+ }
+ sdata_unlock(sdata);
}
- mutex_unlock(&local->sta_mtx);
/* add back keys */
list_for_each_entry(sdata, &local->interfaces, list)
}
void ieee80211_ie_build_he_6ghz_cap(struct ieee80211_sub_if_data *sdata,
+ enum ieee80211_smps_mode smps_mode,
struct sk_buff *skb)
{
struct ieee80211_supported_band *sband;
cap = le16_to_cpu(iftd->he_6ghz_capa.capa);
cap &= ~IEEE80211_HE_6GHZ_CAP_SM_PS;
- switch (sdata->deflink.smps_mode) {
+ switch (smps_mode) {
case IEEE80211_SMPS_AUTOMATIC:
case IEEE80211_SMPS_NUM_MODES:
WARN_ON(1);
return true;
}
-void ieee80211_chandef_eht_oper(struct ieee80211_sub_if_data *sdata,
- const struct ieee80211_eht_operation *eht_oper,
+void ieee80211_chandef_eht_oper(const struct ieee80211_eht_operation *eht_oper,
bool support_160, bool support_320,
struct cfg80211_chan_def *chandef)
{
support_320 =
eht_phy_cap & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
- ieee80211_chandef_eht_oper(sdata, eht_oper, support_160,
+ ieee80211_chandef_eht_oper(eht_oper, support_160,
support_320, &he_chandef);
}
const struct ieee80211_sta_he_cap *he_cap;
const struct ieee80211_sta_eht_cap *eht_cap;
struct ieee80211_supported_band *sband;
+ bool is_ap;
u8 n;
sband = ieee80211_get_sband(sdata);
if (!he_cap || !eht_cap)
return 0;
+ is_ap = iftype == NL80211_IFTYPE_AP ||
+ iftype == NL80211_IFTYPE_P2P_GO;
+
n = ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem,
- &eht_cap->eht_cap_elem);
+ &eht_cap->eht_cap_elem,
+ is_ap);
return 2 + 1 +
sizeof(he_cap->he_cap_elem) + n +
ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0],
u8 *ieee80211_ie_build_eht_cap(u8 *pos,
const struct ieee80211_sta_he_cap *he_cap,
const struct ieee80211_sta_eht_cap *eht_cap,
- u8 *end)
+ u8 *end,
+ bool for_ap)
{
u8 mcs_nss_len, ppet_len;
u8 ie_len;
return orig_pos;
mcs_nss_len = ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem,
- &eht_cap->eht_cap_elem);
+ &eht_cap->eht_cap_elem,
+ for_ap);
ppet_len = ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0],
eht_cap->eht_cap_elem.phy_cap_info);
struct mptcp_sendmsg_info info = {
.flags = flags,
};
+ bool do_check_data_fin = false;
struct mptcp_data_frag *dfrag;
- int len, copied = 0;
+ int len;
while ((dfrag = mptcp_send_head(sk))) {
info.sent = dfrag->already_sent;
goto out;
}
+ do_check_data_fin = true;
info.sent += ret;
- copied += ret;
len -= ret;
mptcp_update_post_push(msk, dfrag, ret);
/* ensure the rtx timer is running */
if (!mptcp_timer_pending(sk))
mptcp_reset_timer(sk);
- if (copied)
+ if (do_check_data_fin)
__mptcp_check_send_data_fin(sk);
}
{
struct mptcp_sock *msk = mptcp_sk(sk);
struct page_frag *pfrag;
+ struct socket *ssock;
size_t copied = 0;
int ret = 0;
long timeo;
lock_sock(sk);
+ ssock = __mptcp_nmpc_socket(msk);
+ if (unlikely(ssock && inet_sk(ssock->sk)->defer_connect)) {
+ struct sock *ssk = ssock->sk;
+ int copied_syn = 0;
+
+ lock_sock(ssk);
+
+ ret = tcp_sendmsg_fastopen(ssk, msg, &copied_syn, len, NULL);
+ copied += copied_syn;
+ if (ret == -EINPROGRESS && copied_syn > 0) {
+ /* reflect the new state on the MPTCP socket */
+ inet_sk_state_store(sk, inet_sk_state_load(ssk));
+ release_sock(ssk);
+ goto out;
+ } else if (ret) {
+ release_sock(ssk);
+ goto out;
+ }
+ release_sock(ssk);
+ }
+
timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) {
might_sleep();
- list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node) {
+ mptcp_for_each_subflow_safe(msk, subflow, tmp) {
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
if (inet_sk_state_load(ssk) != TCP_CLOSE)
mptcp_token_destroy(msk);
- list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node) {
+ mptcp_for_each_subflow_safe(msk, subflow, tmp) {
struct sock *tcp_sk = mptcp_subflow_tcp_sock(subflow);
bool slow;
dfrag_clear(sk, dfrag);
}
- static void mptcp_cancel_work(struct sock *sk)
+ void mptcp_cancel_work(struct sock *sk)
{
struct mptcp_sock *msk = mptcp_sk(sk);
sock_put(sk);
}
- static void mptcp_close(struct sock *sk, long timeout)
+ bool __mptcp_close(struct sock *sk, long timeout)
{
struct mptcp_subflow_context *subflow;
struct mptcp_sock *msk = mptcp_sk(sk);
bool do_cancel_work = false;
- lock_sock(sk);
sk->sk_shutdown = SHUTDOWN_MASK;
if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) {
} else {
mptcp_reset_timeout(msk, 0);
}
+
+ return do_cancel_work;
+ }
+
+ static void mptcp_close(struct sock *sk, long timeout)
+ {
+ bool do_cancel_work;
+
+ lock_sock(sk);
+
+ do_cancel_work = __mptcp_close(sk, timeout);
release_sock(sk);
if (do_cancel_work)
mptcp_cancel_work(sk);
__mptcp_clear_xmit(sk);
/* join list will be eventually flushed (with rst) at sock lock release time */
- list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node)
+ mptcp_for_each_subflow_safe(msk, subflow, tmp)
__mptcp_close_ssk(sk, mptcp_subflow_tcp_sock(subflow), subflow, flags);
/* move to sk_receive_queue, sk_stream_kill_queues will purge it */
do_connect:
err = ssock->ops->connect(ssock, uaddr, addr_len, flags);
+ inet_sk(sock->sk)->defer_connect = inet_sk(ssock->sk)->defer_connect;
sock->state = ssock->state;
/* on successful connect, the msk state will be moved to established by
if (state != TCP_SYN_SENT && state != TCP_SYN_RECV) {
mask |= mptcp_check_readable(msk);
mask |= mptcp_check_writeable(msk);
+ } else if (state == TCP_SYN_SENT && inet_sk(sk)->defer_connect) {
+ /* cf tcp_poll() note about TFO */
+ mask |= EPOLLOUT | EPOLLWRNORM;
}
if (sk->sk_shutdown == SHUTDOWN_MASK || state == TCP_CLOSE)
mask |= EPOLLHUP;
#define mptcp_for_each_subflow(__msk, __subflow) \
list_for_each_entry(__subflow, &((__msk)->conn_list), node)
+#define mptcp_for_each_subflow_safe(__msk, __subflow, __tmp) \
+ list_for_each_entry_safe(__subflow, __tmp, &((__msk)->conn_list), node)
static inline void msk_owned_by_me(const struct mptcp_sock *msk)
{
void mptcp_subflow_queue_clean(struct sock *ssk);
void mptcp_sock_graft(struct sock *sk, struct socket *parent);
struct socket *__mptcp_nmpc_socket(const struct mptcp_sock *msk);
+ bool __mptcp_close(struct sock *sk, long timeout);
+ void mptcp_cancel_work(struct sock *sk);
bool mptcp_addresses_equal(const struct mptcp_addr_info *a,
const struct mptcp_addr_info *b, bool use_port);
}
static struct tc_action_ops act_ct_ops;
-static unsigned int ct_net_id;
struct tc_ct_action_net {
struct tc_action_net tn; /* Must be first */
static int tcf_ct_skb_network_trim(struct sk_buff *skb, int family)
{
unsigned int len;
- int err;
switch (family) {
case NFPROTO_IPV4:
len = skb->len;
}
- err = pskb_trim_rcsum(skb, len);
-
- return err;
+ return pskb_trim_rcsum(skb, len);
}
static u8 tcf_ct_skb_nf_family(struct sk_buff *skb)
struct nlattr **tb,
struct netlink_ext_ack *extack)
{
- struct tc_ct_action_net *tn = net_generic(net, ct_net_id);
+ struct tc_ct_action_net *tn = net_generic(net, act_ct_ops.net_id);
struct nf_conntrack_zone zone;
struct nf_conn *tmpl;
int err;
struct tcf_proto *tp, u32 flags,
struct netlink_ext_ack *extack)
{
- struct tc_action_net *tn = net_generic(net, ct_net_id);
+ struct tc_action_net *tn = net_generic(net, act_ct_ops.net_id);
bool bind = flags & TCA_ACT_FLAGS_BIND;
struct tcf_ct_params *params = NULL;
struct nlattr *tb[TCA_CT_MAX + 1];
err = tcf_ct_flow_table_get(net, params);
if (err)
- goto cleanup;
+ goto cleanup_params;
spin_lock_bh(&c->tcf_lock);
goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
return res;
+ cleanup_params:
+ if (params->tmpl)
+ nf_ct_put(params->tmpl);
cleanup:
if (goto_ch)
tcf_chain_put_by_act(goto_ch);
return -1;
}
-static int tcf_ct_walker(struct net *net, struct sk_buff *skb,
- struct netlink_callback *cb, int type,
- const struct tc_action_ops *ops,
- struct netlink_ext_ack *extack)
-{
- struct tc_action_net *tn = net_generic(net, ct_net_id);
-
- return tcf_generic_walker(tn, skb, cb, type, ops, extack);
-}
-
-static int tcf_ct_search(struct net *net, struct tc_action **a, u32 index)
-{
- struct tc_action_net *tn = net_generic(net, ct_net_id);
-
- return tcf_idr_search(tn, a, index);
-}
-
static void tcf_stats_update(struct tc_action *a, u64 bytes, u64 packets,
u64 drops, u64 lastuse, bool hw)
{
.dump = tcf_ct_dump,
.init = tcf_ct_init,
.cleanup = tcf_ct_cleanup,
- .walk = tcf_ct_walker,
- .lookup = tcf_ct_search,
.stats_update = tcf_stats_update,
.offload_act_setup = tcf_ct_offload_act_setup,
.size = sizeof(struct tcf_ct),
static __net_init int ct_init_net(struct net *net)
{
unsigned int n_bits = sizeof_field(struct tcf_ct_params, labels) * 8;
- struct tc_ct_action_net *tn = net_generic(net, ct_net_id);
+ struct tc_ct_action_net *tn = net_generic(net, act_ct_ops.net_id);
if (nf_connlabels_get(net, n_bits - 1)) {
tn->labels = false;
rtnl_lock();
list_for_each_entry(net, net_list, exit_list) {
- struct tc_ct_action_net *tn = net_generic(net, ct_net_id);
+ struct tc_ct_action_net *tn = net_generic(net, act_ct_ops.net_id);
if (tn->labels)
nf_connlabels_put(net);
}
rtnl_unlock();
- tc_action_net_exit(net_list, ct_net_id);
+ tc_action_net_exit(net_list, act_ct_ops.net_id);
}
static struct pernet_operations ct_net_ops = {
.init = ct_init_net,
.exit_batch = ct_exit_net,
- .id = &ct_net_id,
+ .id = &act_ct_ops.net_id,
.size = sizeof(struct tc_ct_action_net),
};
for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++) {
if (!wdev->connect_keys->params[i].cipher)
continue;
- if (rdev_add_key(rdev, dev, i, false, NULL,
+ if (rdev_add_key(rdev, dev, -1, i, false, NULL,
&wdev->connect_keys->params[i])) {
netdev_err(dev, "failed to set key %d\n", i);
continue;
}
if (wdev->connect_keys->def == i &&
- rdev_set_default_key(rdev, dev, i, true, true)) {
+ rdev_set_default_key(rdev, dev, -1, i, true, true)) {
netdev_err(dev, "failed to set defkey %d\n", i);
continue;
}
25599, /* 4.166666... */
17067, /* 2.777777... */
12801, /* 2.083333... */
- 11769, /* 1.851851... */
+ 11377, /* 1.851725... */
10239, /* 1.666666... */
8532, /* 1.388888... */
7680, /* 1.250000... */
25599, /* 4.166666... */
17067, /* 2.777777... */
12801, /* 2.083333... */
- 11769, /* 1.851851... */
+ 11377, /* 1.851725... */
10239, /* 1.666666... */
8532, /* 1.388888... */
7680, /* 1.250000... */